diff options
590 files changed, 78876 insertions, 38 deletions
diff --git a/3rdparty/elfutils/AUTHORS b/3rdparty/elfutils/AUTHORS new file mode 100644 index 0000000..ef3c543 --- /dev/null +++ b/3rdparty/elfutils/AUTHORS @@ -0,0 +1,4 @@ +For Now: +Ulrich Drepper. +Roland McGrath +Petr Machata diff --git a/3rdparty/elfutils/COPYING b/3rdparty/elfutils/COPYING new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/3rdparty/elfutils/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) <year> <name of author> + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<http://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<http://www.gnu.org/philosophy/why-not-lgpl.html>. diff --git a/3rdparty/elfutils/COPYING-GPLV2 b/3rdparty/elfutils/COPYING-GPLV2 new file mode 100644 index 0000000..d159169 --- /dev/null +++ b/3rdparty/elfutils/COPYING-GPLV2 @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/3rdparty/elfutils/COPYING-LGPLV3 b/3rdparty/elfutils/COPYING-LGPLV3 new file mode 100644 index 0000000..65c5ca8 --- /dev/null +++ b/3rdparty/elfutils/COPYING-LGPLV3 @@ -0,0 +1,165 @@ + GNU LESSER 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. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser 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 +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/3rdparty/elfutils/THANKS b/3rdparty/elfutils/THANKS new file mode 100644 index 0000000..887c067 --- /dev/null +++ b/3rdparty/elfutils/THANKS @@ -0,0 +1,6 @@ +At least the following have submitted valuable patches: + +Jeff Johnson building. rpm wrestling +Alexander Larsson separate debug info +Jakub Jelinek bug fixes, testing +Denys Vlasenko bug fuxes diff --git a/3rdparty/elfutils/backends/aarch64/aarch64.pro b/3rdparty/elfutils/backends/aarch64/aarch64.pro new file mode 100644 index 0000000..28a34f6 --- /dev/null +++ b/3rdparty/elfutils/backends/aarch64/aarch64.pro @@ -0,0 +1,15 @@ +TEMPLATE = lib +include(../backends.pri) +TARGET = ../ebl_aarch64 + +SOURCES += \ + ../aarch64_cfi.c \ + ../aarch64_corenote.c \ + ../aarch64_init.c \ + ../aarch64_initreg.c \ + ../aarch64_regs.c \ + ../aarch64_retval.c \ + ../aarch64_symbol.c + +HEADERS += \ + ../aarch64_reloc.def diff --git a/3rdparty/elfutils/backends/aarch64_cfi.c b/3rdparty/elfutils/backends/aarch64_cfi.c new file mode 100644 index 0000000..acbb9b6 --- /dev/null +++ b/3rdparty/elfutils/backends/aarch64_cfi.c @@ -0,0 +1,82 @@ +/* arm ABI-specified defaults for DWARF CFI. + Copyright (C) 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> + +#define BACKEND aarch64_ +#include "libebl_CPU.h" + + +/* ABI-specified state of DWARF CFI based on: + + "DWARF for the ARM 64 bit architecture (AArch64) 1.0" +http://infocenter.arm.com/help/topic/com.arm.doc.ihi0057b/IHI0057B_aadwarf64.pdf + + "Procedure Call Standard for the ARM 64 bit Architecture 1.0" +http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf +*/ + +int +aarch64_abi_cfi (Ebl *ebl __attribute__ ((unused)), Dwarf_CIE *abi_info) +{ + static const uint8_t abi_cfi[] = + { + /* The initial Canonical Frame Address is the value of the + Stack Pointer (r31) as setup in the previous frame. */ + DW_CFA_def_cfa, ULEB128_7 (30), ULEB128_7 (0), + +#define SV(n) DW_CFA_same_value, ULEB128_7 (n) + /* Callee-saved regs r19-r28. */ + SV (19), SV (20), SV (21), SV (22), SV (23), + SV (24), SV (25), SV (26), SV (27), SV (28), + + /* The Frame Pointer (FP, r29) and Link Register (LR, r30). */ + SV (29), SV (30), + + /* Callee-saved fpregs v8-v15. v0 == 64. */ + SV (72), SV (73), SV (74), SV (75), + SV (76), SV (77), SV (78), SV (79), +#undef SV + + /* XXX Note: registers intentionally unused by the program, + for example as a consequence of the procedure call standard + should be initialized as if by DW_CFA_same_value. */ + }; + + abi_info->initial_instructions = abi_cfi; + abi_info->initial_instructions_end = &abi_cfi[sizeof abi_cfi]; + abi_info->data_alignment_factor = -4; + + abi_info->return_address_register = 30; /* lr. */ + + return 0; +} diff --git a/3rdparty/elfutils/backends/aarch64_corenote.c b/3rdparty/elfutils/backends/aarch64_corenote.c new file mode 100644 index 0000000..9b42485 --- /dev/null +++ b/3rdparty/elfutils/backends/aarch64_corenote.c @@ -0,0 +1,163 @@ +/* AArch64 specific core note handling. + Copyright (C) 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <elf.h> +#include <inttypes.h> +#include <stddef.h> +#include <stdio.h> +#include <sys/time.h> + +#define BACKEND aarch64_ +#include "libebl_CPU.h" + +#define ULONG uint64_t +#define PID_T int32_t +#define UID_T uint32_t +#define GID_T uint32_t +#define ALIGN_ULONG 8 +#define ALIGN_PID_T 4 +#define ALIGN_UID_T 4 +#define ALIGN_GID_T 4 +#define TYPE_ULONG ELF_T_XWORD +#define TYPE_PID_T ELF_T_SWORD +#define TYPE_UID_T ELF_T_WORD +#define TYPE_GID_T ELF_T_WORD + +#define PRSTATUS_REGS_SIZE (34 * 8) + +static const Ebl_Register_Location prstatus_regs[] = + { + { .offset = 0, .regno = 0, .count = 32, .bits = 64 }, /* x0..x30, sp */ + }; + +#define PRSTATUS_REGSET_ITEMS \ + { \ + .name = "pc", .type = ELF_T_XWORD, .format = 'x', \ + .offset = (offsetof (struct EBLHOOK(prstatus), pr_reg) \ + + PRSTATUS_REGS_SIZE - 16), \ + .group = "register", \ + .pc_register = true \ + }, \ + { \ + .name = "pstate", .type = ELF_T_XWORD, .format = 'x', \ + .offset = (offsetof (struct EBLHOOK(prstatus), pr_reg) \ + + PRSTATUS_REGS_SIZE - 8), \ + .group = "register" \ + } + +static const Ebl_Register_Location aarch64_fpregset_regs[] = + { + { .offset = 0, .regno = 64, .count = 32, .bits = 128 }, /* v0..v31 */ + }; + +static const Ebl_Core_Item aarch64_fpregset_items[] = + { + { + .name = "fpsr", .type = ELF_T_WORD, .format = 'x', + .offset = 512, .group = "register" + }, + { + .name = "fpcr", .type = ELF_T_WORD, .format = 'x', + .offset = 516, .group = "register" + } + }; + +static const Ebl_Core_Item aarch64_tls_items[] = + { + { + .name = "tls", .type = ELF_T_XWORD, .format = 'x', + .offset = 0, .group = "register" + } + }; + +#define AARCH64_HWBP_REG(KIND, N) \ + { \ + .name = "DBG" KIND "VR" #N "_EL1", .type = ELF_T_XWORD, .format = 'x', \ + .offset = 8 + N * 16, .group = "register" \ + }, \ + { \ + .name = "DBG" KIND "CR" #N "_EL1", .type = ELF_T_WORD, .format = 'x', \ + .offset = 16 + N * 16, .group = "register" \ + } + +#define AARCH64_BP_WP_GROUP(KIND, NAME) \ + static const Ebl_Core_Item NAME[] = \ + { \ + { \ + .name = "dbg_info", .type = ELF_T_WORD, .format = 'x', \ + .offset = 0, .group = "control" \ + }, \ + /* N.B.: 4 bytes of padding here. */ \ + \ + AARCH64_HWBP_REG(KIND, 0), \ + AARCH64_HWBP_REG(KIND, 1), \ + AARCH64_HWBP_REG(KIND, 2), \ + AARCH64_HWBP_REG(KIND, 3), \ + AARCH64_HWBP_REG(KIND, 4), \ + AARCH64_HWBP_REG(KIND, 5), \ + AARCH64_HWBP_REG(KIND, 6), \ + AARCH64_HWBP_REG(KIND, 7), \ + AARCH64_HWBP_REG(KIND, 8), \ + AARCH64_HWBP_REG(KIND, 9), \ + AARCH64_HWBP_REG(KIND, 10), \ + AARCH64_HWBP_REG(KIND, 11), \ + AARCH64_HWBP_REG(KIND, 12), \ + AARCH64_HWBP_REG(KIND, 13), \ + AARCH64_HWBP_REG(KIND, 14), \ + AARCH64_HWBP_REG(KIND, 15), \ + \ + /* The DBGBVR+DBGBCR pair only takes 12 bytes. There are 4 bytes \ + of padding at the end of each pair. The item formatter in \ + readelf can skip those, but the missing 4 bytes at the end of \ + the whole block cause it to assume the whole item bunch \ + repeats, so it loops around to read more. Insert an explicit \ + (but invisible) padding word. */ \ + { \ + .name = "", .type = ELF_T_WORD, .format = 'h', \ + .offset = 260, .group = "register" \ + } \ + } + +AARCH64_BP_WP_GROUP ("B", aarch64_hw_bp_items); +AARCH64_BP_WP_GROUP ("W", aarch64_hw_wp_items); + +#undef AARCH64_BP_WP_GROUP +#undef AARCH64_HWBP_REG + +#define EXTRA_NOTES \ + EXTRA_REGSET_ITEMS (NT_FPREGSET, 528, \ + aarch64_fpregset_regs, aarch64_fpregset_items) \ + EXTRA_ITEMS (NT_ARM_TLS, 8, aarch64_tls_items) \ + EXTRA_ITEMS (NT_ARM_HW_BREAK, 264, aarch64_hw_bp_items) \ + EXTRA_ITEMS (NT_ARM_HW_WATCH, 264, aarch64_hw_wp_items) + +#include "linux-core-note.c" diff --git a/3rdparty/elfutils/backends/aarch64_init.c b/3rdparty/elfutils/backends/aarch64_init.c new file mode 100644 index 0000000..b0fd17a --- /dev/null +++ b/3rdparty/elfutils/backends/aarch64_init.c @@ -0,0 +1,69 @@ +/* Initialization of AArch64 specific backend library. + Copyright (C) 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND aarch64_ +#define RELOC_PREFIX R_AARCH64_ +#include "libebl_CPU.h" + +/* This defines the common reloc hooks based on aarch64_reloc.def. */ +#include "common-reloc.c" + + +const char * +aarch64_init (elf, machine, eh, ehlen) + Elf *elf __attribute__ ((unused)); + GElf_Half machine __attribute__ ((unused)); + Ebl *eh; + size_t ehlen; +{ + /* Check whether the Elf_BH object has a sufficent size. */ + if (ehlen < sizeof (Ebl)) + return NULL; + + /* We handle it. */ + eh->name = "AARCH64"; + aarch64_init_reloc (eh); + HOOK (eh, register_info); + HOOK (eh, core_note); + HOOK (eh, reloc_simple_type); + HOOK (eh, return_value_location); + HOOK (eh, check_special_symbol); + HOOK (eh, abi_cfi); + + /* X0-X30 (31 regs) + SP + 1 Reserved + ELR, 30 Reserved regs (34-43) + + V0-V31 (32 regs, least significant 64 bits only) + + ALT_FRAME_RETURN_COLUMN (used when LR isn't used) = 97 DWARF regs. */ + eh->frame_nregs = 97; + HOOK (eh, set_initial_registers_tid); + + return MODVERSION; +} diff --git a/3rdparty/elfutils/backends/aarch64_initreg.c b/3rdparty/elfutils/backends/aarch64_initreg.c new file mode 100644 index 0000000..9706205 --- /dev/null +++ b/3rdparty/elfutils/backends/aarch64_initreg.c @@ -0,0 +1,92 @@ +/* Fetch live process registers from TID. + Copyright (C) 2013, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "system.h" +#include <assert.h> +#ifdef __aarch64__ +# include <linux/uio.h> +# include <sys/user.h> +# include <sys/ptrace.h> +/* Deal with old glibc defining user_pt_regs instead of user_regs_struct. */ +# ifndef HAVE_SYS_USER_REGS +# define user_regs_struct user_pt_regs +# define user_fpsimd_struct user_fpsimd_state +# endif +#endif + +#define BACKEND aarch64_ +#include "libebl_CPU.h" + +bool +aarch64_set_initial_registers_tid (pid_t tid __attribute__ ((unused)), + ebl_tid_registers_t *setfunc __attribute__ ((unused)), + void *arg __attribute__ ((unused))) +{ +#ifndef __aarch64__ + return false; +#else /* __aarch64__ */ + + /* General registers. */ + struct user_regs_struct gregs; + struct iovec iovec; + iovec.iov_base = &gregs; + iovec.iov_len = sizeof (gregs); + if (ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS, &iovec) != 0) + return false; + + /* X0..X30 plus SP. */ + if (! setfunc (0, 32, (Dwarf_Word *) &gregs.regs[0], arg)) + return false; + + /* PC. */ + if (! setfunc (-1, 1, (Dwarf_Word *) &gregs.pc, arg)) + return false; + + /* ELR cannot be found. */ + + /* FP registers (only 64bits are used). */ + struct user_fpsimd_struct fregs; + iovec.iov_base = &fregs; + iovec.iov_len = sizeof (fregs); + if (ptrace (PTRACE_GETREGSET, tid, NT_FPREGSET, &iovec) != 0) + return false; + + Dwarf_Word dwarf_fregs[32]; + for (int r = 0; r < 32; r++) + dwarf_fregs[r] = fregs.vregs[r] & 0xFFFFFFFF; + + if (! setfunc (64, 32, dwarf_fregs, arg)) + return false; + + return true; +#endif /* __aarch64__ */ +} diff --git a/3rdparty/elfutils/backends/aarch64_regs.c b/3rdparty/elfutils/backends/aarch64_regs.c new file mode 100644 index 0000000..7a8a678 --- /dev/null +++ b/3rdparty/elfutils/backends/aarch64_regs.c @@ -0,0 +1,102 @@ +/* Register names and numbers for AArch64 DWARF. + Copyright (C) 2013, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> +#include <string.h> +#include <dwarf.h> +#include <stdarg.h> + +#define BACKEND aarch64_ +#include "libebl_CPU.h" + +ssize_t +aarch64_register_info (Ebl *ebl __attribute__ ((unused)), + int regno, char *name, size_t namelen, + const char **prefix, const char **setnamep, + int *bits, int *typep) +{ + if (name == NULL) + return 128; + + __attribute__ ((format (printf, 3, 4))) + ssize_t + regtype (const char *setname, int type, const char *fmt, ...) + { + *setnamep = setname; + *typep = type; + + va_list ap; + va_start (ap, fmt); + int s = vsnprintf (name, namelen, fmt, ap); + va_end(ap); + + if (s < 0 || (unsigned) s >= namelen) + return -1; + return s + 1; + } + + *prefix = ""; + *bits = 64; + + switch (regno) + { + case 0 ... 30: + return regtype ("integer", DW_ATE_signed, "x%d", regno); + + case 31: + return regtype ("integer", DW_ATE_address, "sp"); + + case 32: + return 0; + + case 33: + return regtype ("integer", DW_ATE_address, "elr"); + + case 34 ... 63: + return 0; + + case 64 ... 95: + /* FP/SIMD register file supports a variety of data types--it + can be thought of as a register holding a single integer or + floating-point value, or a vector of 8-, 16-, 32- or 64-bit + integers. 128-bit quad-word is the only singular value that + covers the whole register, so mark the register thus. */ + *bits = 128; + return regtype ("FP/SIMD", DW_ATE_unsigned, "v%d", regno - 64); + + case 96 ... 127: + return 0; + + default: + return -1; + } +} diff --git a/3rdparty/elfutils/backends/aarch64_reloc.def b/3rdparty/elfutils/backends/aarch64_reloc.def new file mode 100644 index 0000000..36d29e6 --- /dev/null +++ b/3rdparty/elfutils/backends/aarch64_reloc.def @@ -0,0 +1,157 @@ +/* List the relocation types for AArch64. -*- C -*- + Copyright (C) 2013, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +/* NAME, REL|EXEC|DYN */ + +RELOC_TYPE (ABS64, REL|EXEC|DYN) +RELOC_TYPE (ABS32, REL|EXEC|DYN) +RELOC_TYPE (COPY, EXEC) +RELOC_TYPE (GLOB_DAT, EXEC|DYN) +RELOC_TYPE (JUMP_SLOT, EXEC|DYN) +RELOC_TYPE (RELATIVE, EXEC|DYN) +RELOC_TYPE (TLS_DTPMOD64, EXEC|DYN) +RELOC_TYPE (TLS_DTPREL64, EXEC|DYN) +RELOC_TYPE (TLS_TPREL64, EXEC|DYN) +RELOC_TYPE (TLSDESC, EXEC|DYN) + +/* R_AARCH64_NONE records that the section containing the place to be + relocated depends on the section defining the symbol mentioned in + the relocation directive[.] (ARM IHI 0056B). */ +RELOC_TYPE (NONE, REL) + +RELOC_TYPE (ABS16, REL) +RELOC_TYPE (PREL64, REL) +RELOC_TYPE (PREL32, REL) +RELOC_TYPE (PREL16, REL) +RELOC_TYPE (MOVW_UABS_G0, REL) +RELOC_TYPE (MOVW_UABS_G0_NC, REL) +RELOC_TYPE (MOVW_UABS_G1, REL) +RELOC_TYPE (MOVW_UABS_G1_NC, REL) +RELOC_TYPE (MOVW_UABS_G2, REL) +RELOC_TYPE (MOVW_UABS_G2_NC, REL) +RELOC_TYPE (MOVW_UABS_G3, REL) +RELOC_TYPE (MOVW_SABS_G0, REL) +RELOC_TYPE (MOVW_SABS_G1, REL) +RELOC_TYPE (MOVW_SABS_G2, REL) +RELOC_TYPE (LD_PREL_LO19, REL) +RELOC_TYPE (ADR_PREL_LO21, REL) +RELOC_TYPE (ADR_PREL_PG_HI21, REL) +RELOC_TYPE (ADR_PREL_PG_HI21_NC, REL) +RELOC_TYPE (ADD_ABS_LO12_NC, REL) +RELOC_TYPE (LDST8_ABS_LO12_NC, REL) +RELOC_TYPE (LDST16_ABS_LO12_NC, REL) +RELOC_TYPE (LDST32_ABS_LO12_NC, REL) +RELOC_TYPE (LDST64_ABS_LO12_NC, REL) +RELOC_TYPE (LDST128_ABS_LO12_NC, REL) +RELOC_TYPE (TSTBR14, REL) +RELOC_TYPE (CONDBR19, REL) +RELOC_TYPE (JUMP26, REL) +RELOC_TYPE (CALL26, REL) +RELOC_TYPE (MOVW_PREL_G0, REL) +RELOC_TYPE (MOVW_PREL_G0_NC, REL) +RELOC_TYPE (MOVW_PREL_G1, REL) +RELOC_TYPE (MOVW_PREL_G1_NC, REL) +RELOC_TYPE (MOVW_PREL_G2, REL) +RELOC_TYPE (MOVW_PREL_G2_NC, REL) +RELOC_TYPE (MOVW_PREL_G3, REL) +RELOC_TYPE (MOVW_GOTOFF_G0, REL) +RELOC_TYPE (MOVW_GOTOFF_G0_NC, REL) +RELOC_TYPE (MOVW_GOTOFF_G1, REL) +RELOC_TYPE (MOVW_GOTOFF_G1_NC, REL) +RELOC_TYPE (MOVW_GOTOFF_G2, REL) +RELOC_TYPE (MOVW_GOTOFF_G2_NC, REL) +RELOC_TYPE (MOVW_GOTOFF_G3, REL) +RELOC_TYPE (GOTREL64, REL) +RELOC_TYPE (GOTREL32, REL) +RELOC_TYPE (GOT_LD_PREL19, REL) +RELOC_TYPE (LD64_GOTOFF_LO15, REL) +RELOC_TYPE (ADR_GOT_PAGE, REL) +RELOC_TYPE (LD64_GOT_LO12_NC, REL) +RELOC_TYPE (LD64_GOTPAGE_LO15, REL) +RELOC_TYPE (TLSGD_ADR_PREL21, REL) +RELOC_TYPE (TLSGD_ADR_PAGE21, REL) +RELOC_TYPE (TLSGD_ADD_LO12_NC, REL) +RELOC_TYPE (TLSGD_MOVW_G1, REL) +RELOC_TYPE (TLSGD_MOVW_G0_NC, REL) +RELOC_TYPE (TLSLD_ADR_PREL21, REL) +RELOC_TYPE (TLSLD_ADR_PAGE21, REL) +RELOC_TYPE (TLSLD_ADD_LO12_NC, REL) +RELOC_TYPE (TLSLD_MOVW_G1, REL) +RELOC_TYPE (TLSLD_MOVW_G0_NC, REL) +RELOC_TYPE (TLSLD_LD_PREL19, REL) +RELOC_TYPE (TLSLD_MOVW_DTPREL_G2, REL) +RELOC_TYPE (TLSLD_MOVW_DTPREL_G1, REL) +RELOC_TYPE (TLSLD_MOVW_DTPREL_G1_NC, REL) +RELOC_TYPE (TLSLD_MOVW_DTPREL_G0, REL) +RELOC_TYPE (TLSLD_MOVW_DTPREL_G0_NC, REL) +RELOC_TYPE (TLSLD_ADD_DTPREL_HI12, REL) +RELOC_TYPE (TLSLD_ADD_DTPREL_LO12, REL) +RELOC_TYPE (TLSLD_ADD_DTPREL_LO12_NC, REL) +RELOC_TYPE (TLSLD_LDST8_DTPREL_LO12, REL) +RELOC_TYPE (TLSLD_LDST8_DTPREL_LO12_NC, REL) +RELOC_TYPE (TLSLD_LDST16_DTPREL_LO12, REL) +RELOC_TYPE (TLSLD_LDST16_DTPREL_LO12_NC, REL) +RELOC_TYPE (TLSLD_LDST32_DTPREL_LO12, REL) +RELOC_TYPE (TLSLD_LDST32_DTPREL_LO12_NC, REL) +RELOC_TYPE (TLSLD_LDST64_DTPREL_LO12, REL) +RELOC_TYPE (TLSLD_LDST64_DTPREL_LO12_NC, REL) +RELOC_TYPE (TLSLD_LDST128_DTPREL_LO12, REL) +RELOC_TYPE (TLSLD_LDST128_DTPREL_LO12_NC, REL) +RELOC_TYPE (TLSIE_MOVW_GOTTPREL_G1, REL) +RELOC_TYPE (TLSIE_MOVW_GOTTPREL_G0_NC, REL) +RELOC_TYPE (TLSIE_ADR_GOTTPREL_PAGE21, REL) +RELOC_TYPE (TLSIE_LD64_GOTTPREL_LO12_NC, REL) +RELOC_TYPE (TLSIE_LD_GOTTPREL_PREL19, REL) +RELOC_TYPE (TLSLE_MOVW_TPREL_G2, REL) +RELOC_TYPE (TLSLE_MOVW_TPREL_G1, REL) +RELOC_TYPE (TLSLE_MOVW_TPREL_G1_NC, REL) +RELOC_TYPE (TLSLE_MOVW_TPREL_G0, REL) +RELOC_TYPE (TLSLE_MOVW_TPREL_G0_NC, REL) +RELOC_TYPE (TLSLE_ADD_TPREL_HI12, REL) +RELOC_TYPE (TLSLE_ADD_TPREL_LO12, REL) +RELOC_TYPE (TLSLE_ADD_TPREL_LO12_NC, REL) +RELOC_TYPE (TLSLE_LDST8_TPREL_LO12, REL) +RELOC_TYPE (TLSLE_LDST8_TPREL_LO12_NC, REL) +RELOC_TYPE (TLSLE_LDST16_TPREL_LO12, REL) +RELOC_TYPE (TLSLE_LDST16_TPREL_LO12_NC, REL) +RELOC_TYPE (TLSLE_LDST32_TPREL_LO12, REL) +RELOC_TYPE (TLSLE_LDST32_TPREL_LO12_NC, REL) +RELOC_TYPE (TLSLE_LDST64_TPREL_LO12, REL) +RELOC_TYPE (TLSLE_LDST64_TPREL_LO12_NC, REL) +RELOC_TYPE (TLSLE_LDST128_TPREL_LO12, REL) +RELOC_TYPE (TLSLE_LDST128_TPREL_LO12_NC, REL) +RELOC_TYPE (TLSDESC_LD_PREL19, REL) +RELOC_TYPE (TLSDESC_ADR_PREL21, REL) +RELOC_TYPE (TLSDESC_ADR_PAGE21, REL) +RELOC_TYPE (TLSDESC_LD64_LO12, REL) +RELOC_TYPE (TLSDESC_ADD_LO12, REL) +RELOC_TYPE (TLSDESC_OFF_G1, REL) +RELOC_TYPE (TLSDESC_OFF_G0_NC, REL) +RELOC_TYPE (TLSDESC_LDR, REL) +RELOC_TYPE (TLSDESC_ADD, REL) +RELOC_TYPE (TLSDESC_CALL, REL) diff --git a/3rdparty/elfutils/backends/aarch64_retval.c b/3rdparty/elfutils/backends/aarch64_retval.c new file mode 100644 index 0000000..68de307 --- /dev/null +++ b/3rdparty/elfutils/backends/aarch64_retval.c @@ -0,0 +1,376 @@ +/* Function return value location for Linux/AArch64 ABI. + Copyright (C) 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> +#include <inttypes.h> + +#include <assert.h> +#include <dwarf.h> + +#define BACKEND aarch64_ +#include "libebl_CPU.h" + +static int +skip_until (Dwarf_Die *child, int tag) +{ + int i; + while (DWARF_TAG_OR_RETURN (child) != tag) + if ((i = dwarf_siblingof (child, child)) != 0) + /* If there are no members, then this is not a HFA. Errors + are propagated. */ + return i; + return 0; +} + +static int +dwarf_bytesize_aux (Dwarf_Die *die, Dwarf_Word *sizep) +{ + int bits; + if (((bits = 8 * dwarf_bytesize (die)) < 0 + && (bits = dwarf_bitsize (die)) < 0) + || bits % 8 != 0) + return -1; + + *sizep = bits / 8; + return 0; +} + +/* HFA (Homogeneous Floating-point Aggregate) is an aggregate type + whose members are all of the same floating-point type, which is + then base type of this HFA. Instead of being floating-point types + directly, members can instead themselves be HFA. Such HFA fields + are handled as if their type were HFA base type. + + This function returns 0 if TYPEDIE is HFA, 1 if it is not, or -1 if + there were errors. In the former case, *SIZEP contains byte size + of the base type (e.g. 8 for IEEE double). *COUNT is set to the + number of leaf members of the HFA. */ +static int hfa_type (Dwarf_Die *ftypedie, int tag, + Dwarf_Word *sizep, Dwarf_Word *countp); + +/* Return 0 if MEMBDIE refers to a member with a floating-point or HFA + type, or 1 if it's not. Return -1 for errors. The meaning of the + remaining arguments is as documented at hfa_type. */ +static int +member_is_fp (Dwarf_Die *membdie, Dwarf_Word *sizep, Dwarf_Word *countp) +{ + Dwarf_Die typedie; + int tag = dwarf_peeled_die_type (membdie, &typedie); + switch (tag) + { + case DW_TAG_base_type:; + Dwarf_Word encoding; + Dwarf_Attribute attr_mem; + if (dwarf_attr_integrate (&typedie, DW_AT_encoding, &attr_mem) == NULL + || dwarf_formudata (&attr_mem, &encoding) != 0) + return -1; + + switch (encoding) + { + case DW_ATE_complex_float: + *countp = 2; + break; + + case DW_ATE_float: + *countp = 1; + break; + + default: + return 1; + } + + if (dwarf_bytesize_aux (&typedie, sizep) < 0) + return -1; + + *sizep /= *countp; + return 0; + + case DW_TAG_structure_type: + case DW_TAG_union_type: + case DW_TAG_array_type: + return hfa_type (&typedie, tag, sizep, countp); + } + + return 1; +} + +static int +hfa_type (Dwarf_Die *ftypedie, int tag, Dwarf_Word *sizep, Dwarf_Word *countp) +{ + assert (tag == DW_TAG_structure_type || tag == DW_TAG_class_type + || tag == DW_TAG_union_type || tag == DW_TAG_array_type); + + int i; + if (tag == DW_TAG_array_type) + { + Dwarf_Word tot_size; + if (dwarf_aggregate_size (ftypedie, &tot_size) < 0) + return -1; + + /* For vector types, we don't care about the underlying + type, but only about the vector type itself. */ + bool vec; + Dwarf_Attribute attr_mem; + if (dwarf_formflag (dwarf_attr_integrate (ftypedie, DW_AT_GNU_vector, + &attr_mem), &vec) == 0 + && vec) + { + *sizep = tot_size; + *countp = 1; + + return 0; + } + + if ((i = member_is_fp (ftypedie, sizep, countp)) == 0) + { + *countp = tot_size / *sizep; + return 0; + } + + return i; + } + + /* Find first DW_TAG_member and determine its type. */ + Dwarf_Die member; + if ((i = dwarf_child (ftypedie, &member) != 0)) + return i; + + if ((i = skip_until (&member, DW_TAG_member)) != 0) + return i; + + *countp = 0; + if ((i = member_is_fp (&member, sizep, countp)) != 0) + return i; + + while ((i = dwarf_siblingof (&member, &member)) == 0 + && (i = skip_until (&member, DW_TAG_member)) == 0) + { + Dwarf_Word size, count; + if ((i = member_is_fp (&member, &size, &count)) != 0) + return i; + + if (*sizep != size) + return 1; + + *countp += count; + } + + /* At this point we already have at least one FP member, which means + FTYPEDIE is an HFA. So either return 0, or propagate error. */ + return i < 0 ? i : 0; +} + +static int +pass_in_gpr (const Dwarf_Op **locp, Dwarf_Word size) +{ + static const Dwarf_Op loc[] = + { + { .atom = DW_OP_reg0 }, { .atom = DW_OP_piece, .number = 8 }, + { .atom = DW_OP_reg1 }, { .atom = DW_OP_piece, .number = 8 } + }; + + *locp = loc; + return size <= 8 ? 1 : 4; +} + +static int +pass_by_ref (const Dwarf_Op **locp) +{ + static const Dwarf_Op loc[] = { { .atom = DW_OP_breg0 } }; + + *locp = loc; + return 1; +} + +static int +pass_hfa (const Dwarf_Op **locp, Dwarf_Word size, Dwarf_Word count) +{ + assert (count >= 1 && count <= 4); + assert (size == 2 || size == 4 || size == 8 || size == 16); + +#define DEFINE_FPREG(NAME, SIZE) \ + static const Dwarf_Op NAME[] = { \ + { .atom = DW_OP_regx, .number = 64 }, \ + { .atom = DW_OP_piece, .number = SIZE }, \ + { .atom = DW_OP_regx, .number = 65 }, \ + { .atom = DW_OP_piece, .number = SIZE }, \ + { .atom = DW_OP_regx, .number = 66 }, \ + { .atom = DW_OP_piece, .number = SIZE }, \ + { .atom = DW_OP_regx, .number = 67 }, \ + { .atom = DW_OP_piece, .number = SIZE } \ + } + + switch (size) + { + case 2:; + DEFINE_FPREG (loc_hfa_2, 2); + *locp = loc_hfa_2; + break; + + case 4:; + DEFINE_FPREG (loc_hfa_4, 4); + *locp = loc_hfa_4; + break; + + case 8:; + DEFINE_FPREG (loc_hfa_8, 8); + *locp = loc_hfa_8; + break; + + case 16:; + DEFINE_FPREG (loc_hfa_16, 16); + *locp = loc_hfa_16; + break; + } +#undef DEFINE_FPREG + + return count == 1 ? 1 : 2 * count; +} + +static int +pass_in_simd (const Dwarf_Op **locp) +{ + /* This is like passing single-element HFA. Size doesn't matter, so + pretend it's for example double. */ + return pass_hfa (locp, 8, 1); +} + +int +aarch64_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp) +{ + /* Start with the function's type, and get the DW_AT_type attribute, + which is the type of the return value. */ + Dwarf_Die typedie; + int tag = dwarf_peeled_die_type (functypedie, &typedie); + if (tag <= 0) + return tag; + + Dwarf_Word size = (Dwarf_Word)-1; + + /* If the argument type is a Composite Type that is larger than 16 + bytes, then the argument is copied to memory allocated by the + caller and the argument is replaced by a pointer to the copy. */ + if (tag == DW_TAG_structure_type || tag == DW_TAG_union_type + || tag == DW_TAG_class_type || tag == DW_TAG_array_type) + { + Dwarf_Word base_size, count; + switch (hfa_type (&typedie, tag, &base_size, &count)) + { + default: + return -1; + + case 0: + assert (count > 0); + if (count <= 4) + return pass_hfa (locp, base_size, count); + /* Fall through. */ + + case 1: + /* Not a HFA. */ + if (dwarf_aggregate_size (&typedie, &size) < 0) + return -1; + if (size > 16) + return pass_by_ref (locp); + } + } + + if (tag == DW_TAG_base_type + || tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type) + { + if (dwarf_bytesize_aux (&typedie, &size) < 0) + { + if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type) + size = 8; + else + return -1; + } + + Dwarf_Attribute attr_mem; + if (tag == DW_TAG_base_type) + { + Dwarf_Word encoding; + if (dwarf_formudata (dwarf_attr_integrate (&typedie, DW_AT_encoding, + &attr_mem), + &encoding) != 0) + return -1; + + switch (encoding) + { + /* If the argument is a Half-, Single-, Double- or Quad- + precision Floating-point [...] the argument is allocated + to the least significant bits of register v[NSRN]. */ + case DW_ATE_float: + switch (size) + { + case 2: /* half */ + case 4: /* sigle */ + case 8: /* double */ + case 16: /* quad */ + return pass_in_simd (locp); + + default: + return -2; + } + + case DW_ATE_complex_float: + switch (size) + { + case 8: /* float _Complex */ + case 16: /* double _Complex */ + case 32: /* long double _Complex */ + return pass_hfa (locp, size / 2, 2); + + default: + return -2; + } + + /* If the argument is an Integral or Pointer Type, the + size of the argument is less than or equal to 8 bytes + [...] the argument is copied to the least significant + bits in x[NGRN]. */ + case DW_ATE_boolean: + case DW_ATE_signed: + case DW_ATE_unsigned: + case DW_ATE_unsigned_char: + case DW_ATE_signed_char: + return pass_in_gpr (locp, size); + } + + return -2; + } + else + return pass_in_gpr (locp, size); + } + + *locp = NULL; + return 0; +} diff --git a/3rdparty/elfutils/backends/aarch64_symbol.c b/3rdparty/elfutils/backends/aarch64_symbol.c new file mode 100644 index 0000000..3fdc9cf --- /dev/null +++ b/3rdparty/elfutils/backends/aarch64_symbol.c @@ -0,0 +1,87 @@ +/* AArch64 specific symbolic name handling. + Copyright (C) 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <elf.h> +#include <stddef.h> +#include <string.h> + +#define BACKEND aarch64_ +#include "libebl_CPU.h" + + +/* Check for the simple reloc types. */ +Elf_Type +aarch64_reloc_simple_type (Ebl *ebl __attribute__ ((unused)), int type) +{ + switch (type) + { + case R_AARCH64_ABS64: + return ELF_T_XWORD; + case R_AARCH64_ABS32: + return ELF_T_WORD; + case R_AARCH64_ABS16: + return ELF_T_HALF; + + default: + return ELF_T_NUM; + } +} + +/* If this is the _GLOBAL_OFFSET_TABLE_ symbol, then it should point to + .got[0] even if there is a .got.plt section. */ +bool +aarch64_check_special_symbol (Elf *elf, GElf_Ehdr *ehdr, const GElf_Sym *sym, + const char *name, const GElf_Shdr *destshdr) +{ + if (name != NULL + && strcmp (name, "_GLOBAL_OFFSET_TABLE_") == 0) + { + const char *sname = elf_strptr (elf, ehdr->e_shstrndx, destshdr->sh_name); + if (sname != NULL && strcmp (sname, ".got.plt") == 0) + { + Elf_Scn *scn = NULL; + while ((scn = elf_nextscn (elf, scn)) != NULL) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + if (shdr != NULL) + { + sname = elf_strptr (elf, ehdr->e_shstrndx, shdr->sh_name); + if (sname != NULL && strcmp (sname, ".got") == 0) + return sym->st_value == shdr->sh_addr; + } + } + } + } + + return false; +} diff --git a/3rdparty/elfutils/backends/alpha/alpha.pro b/3rdparty/elfutils/backends/alpha/alpha.pro new file mode 100644 index 0000000..0f72400 --- /dev/null +++ b/3rdparty/elfutils/backends/alpha/alpha.pro @@ -0,0 +1,14 @@ +TEMPLATE = lib +include(../backends.pri) +TARGET = ../ebl_alpha + +SOURCES += \ + ../alpha_auxv.c \ + ../alpha_corenote.c \ + ../alpha_init.c \ + ../alpha_regs.c \ + ../alpha_retval.c \ + ../alpha_symbol.c + +HEADERS += \ + ../alpha_reloc.def diff --git a/3rdparty/elfutils/backends/alpha_auxv.c b/3rdparty/elfutils/backends/alpha_auxv.c new file mode 100644 index 0000000..83e7199 --- /dev/null +++ b/3rdparty/elfutils/backends/alpha_auxv.c @@ -0,0 +1,49 @@ +/* Alpha-specific auxv handling. + Copyright (C) 2008 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND alpha_ +#include "libebl_CPU.h" + +int +EBLHOOK(auxv_info) (GElf_Xword a_type, const char **name, const char **format) +{ + if (a_type != AT_HWCAP) + return 0; + + *name = "HWCAP"; + *format = "b" + "bwx\0" "fix\0" "cix\0" "0x08\0" + "0x10\0" "0x20\0" "0x40\0" "0x80\0" + "max\0" "precise_trap\0" + "\0"; + return 1; +} diff --git a/3rdparty/elfutils/backends/alpha_corenote.c b/3rdparty/elfutils/backends/alpha_corenote.c new file mode 100644 index 0000000..6190df3 --- /dev/null +++ b/3rdparty/elfutils/backends/alpha_corenote.c @@ -0,0 +1,70 @@ +/* PowerPC specific core note handling. + Copyright (C) 2007 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <elf.h> +#include <inttypes.h> +#include <stddef.h> +#include <stdio.h> +#include <sys/time.h> + +#define BACKEND alpha_ +#include "libebl_CPU.h" + +static const Ebl_Register_Location prstatus_regs[] = + { + { .offset = 0, .regno = 0, .count = 31, .bits = 64 }, /* r0-r30 */ + { .offset = 32 * 8, .regno = 64, .count = 1, .bits = 64 }, /* pc */ + { .offset = 33 * 8, .regno = 66, .count = 1, .bits = 64 }, /* unique */ + }; +#define PRSTATUS_REGS_SIZE (33 * 8) + +static const Ebl_Register_Location fpregset_regs[] = + { + { .offset = 0, .regno = 32, .count = 32, .bits = 64 }, /* f0-f30, fpcr */ + }; +#define FPREGSET_SIZE (32 * 8) + +#define ULONG uint64_t +#define ALIGN_ULONG 8 +#define TYPE_ULONG ELF_T_XWORD +#define TYPE_LONG ELF_T_SXWORD +#define PID_T int32_t +#define UID_T uint32_t +#define GID_T uint32_t +#define ALIGN_PID_T 4 +#define ALIGN_UID_T 4 +#define ALIGN_GID_T 4 +#define TYPE_PID_T ELF_T_SWORD +#define TYPE_UID_T ELF_T_WORD +#define TYPE_GID_T ELF_T_WORD + +#include "linux-core-note.c" diff --git a/3rdparty/elfutils/backends/alpha_init.c b/3rdparty/elfutils/backends/alpha_init.c new file mode 100644 index 0000000..a3307d8 --- /dev/null +++ b/3rdparty/elfutils/backends/alpha_init.c @@ -0,0 +1,70 @@ +/* Initialization of Alpha specific backend library. + Copyright (C) 2002-2011 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND alpha_ +#define RELOC_PREFIX R_ALPHA_ +#include "libebl_CPU.h" + +/* This defines the common reloc hooks based on alpha_reloc.def. */ +#include "common-reloc.c" + + +const char * +alpha_init (elf, machine, eh, ehlen) + Elf *elf __attribute__ ((unused)); + GElf_Half machine __attribute__ ((unused)); + Ebl *eh; + size_t ehlen; +{ + /* Check whether the Elf_BH object has a sufficent size. */ + if (ehlen < sizeof (Ebl)) + return NULL; + + /* We handle it. */ + eh->name = "Alpha"; + alpha_init_reloc (eh); + HOOK (eh, dynamic_tag_name); + HOOK (eh, dynamic_tag_check); + HOOK (eh, reloc_simple_type); + HOOK (eh, return_value_location); + HOOK (eh, machine_section_flag_check); + HOOK (eh, check_special_section); + HOOK (eh, check_special_symbol); + HOOK (eh, check_st_other_bits); + HOOK (eh, register_info); + HOOK (eh, core_note); + HOOK (eh, auxv_info); + eh->sysvhash_entrysize = sizeof (Elf64_Xword); + + return MODVERSION; +} diff --git a/3rdparty/elfutils/backends/alpha_regs.c b/3rdparty/elfutils/backends/alpha_regs.c new file mode 100644 index 0000000..436af3b --- /dev/null +++ b/3rdparty/elfutils/backends/alpha_regs.c @@ -0,0 +1,164 @@ +/* Register names and numbers for Alpha DWARF. + Copyright (C) 2007 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> +#include <dwarf.h> + +#define BACKEND alpha_ +#include "libebl_CPU.h" + +ssize_t +alpha_register_info (Ebl *ebl __attribute__ ((unused)), + int regno, char *name, size_t namelen, + const char **prefix, const char **setname, + int *bits, int *type) +{ + if (name == NULL) + return 67; + + if (regno < 0 || regno > 66 || namelen < 7) + return -1; + + *prefix = "$"; + + *bits = 64; + *type = DW_ATE_signed; + *setname = "integer"; + if (regno >= 32 && regno < 64) + { + *setname = "FPU"; + *type = DW_ATE_float; + } + + switch (regno) + { + case 0: + name[0] = 'v'; + name[1] = '0'; + namelen = 2; + break; + + case 1 ... 8: + name[0] = 't'; + name[1] = regno - 1 + '0'; + namelen = 2; + break; + + case 9 ... 15: + name[0] = 's'; + name[1] = regno - 9 + '0'; + namelen = 2; + break; + + case 16 ... 21: + name[0] = 'a'; + name[1] = regno - 16 + '0'; + namelen = 2; + break; + + case 22 ... 23: + name[0] = 't'; + name[1] = regno - 22 + '8'; + namelen = 2; + break; + + case 24 ... 25: + name[0] = 't'; + name[1] = '1'; + name[2] = regno - 24 + '0'; + namelen = 3; + break; + + case 26: + *type = DW_ATE_address; + return stpcpy (name, "ra") + 1 - name; + + case 27: + return stpcpy (name, "t12") + 1 - name; + + case 28: + return stpcpy (name, "at") + 1 - name; + + case 29: + *type = DW_ATE_address; + return stpcpy (name, "gp") + 1 - name; + + case 30: + *type = DW_ATE_address; + return stpcpy (name, "sp") + 1 - name; + + case 31: + return stpcpy (name, "zero") + 1 - name; + + case 32 ... 32 + 9: + name[0] = 'f'; + name[1] = regno - 32 + '0'; + namelen = 2; + break; + + case 32 + 10 ... 32 + 19: + name[0] = 'f'; + name[1] = '1'; + name[2] = regno - 32 - 10 + '0'; + namelen = 3; + break; + + case 32 + 20 ... 32 + 29: + name[0] = 'f'; + name[1] = '2'; + name[2] = regno - 32 - 20 + '0'; + namelen = 3; + break; + + case 32 + 30: + return stpcpy (name, "f30") + 1 - name; + + case 32 + 31: + *type = DW_ATE_unsigned; + return stpcpy (name, "fpcr") + 1 - name; + + case 64: + *type = DW_ATE_address; + return stpcpy (name, "pc") + 1 - name; + + case 66: + *type = DW_ATE_address; + return stpcpy (name, "unique") + 1 - name; + + default: + *setname = NULL; + return 0; + } + + name[namelen++] = '\0'; + return namelen; +} diff --git a/3rdparty/elfutils/backends/alpha_reloc.def b/3rdparty/elfutils/backends/alpha_reloc.def new file mode 100644 index 0000000..ed7e5c3 --- /dev/null +++ b/3rdparty/elfutils/backends/alpha_reloc.def @@ -0,0 +1,63 @@ +/* List the relocation types for alpha. -*- C -*- + Copyright (C) 2005 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +/* NAME, REL|EXEC|DYN */ + +RELOC_TYPE (NONE, 0) +RELOC_TYPE (REFLONG, REL|EXEC|DYN) +RELOC_TYPE (REFQUAD, REL|EXEC|DYN) +RELOC_TYPE (GPREL32, REL) +RELOC_TYPE (LITERAL, REL) +RELOC_TYPE (LITUSE, REL) +RELOC_TYPE (GPDISP, REL) +RELOC_TYPE (BRADDR, REL) +RELOC_TYPE (HINT, REL) +RELOC_TYPE (SREL16, REL) +RELOC_TYPE (SREL32, REL) +RELOC_TYPE (SREL64, REL) +RELOC_TYPE (GPRELHIGH, REL) +RELOC_TYPE (GPRELLOW, REL) +RELOC_TYPE (GPREL16, REL) +RELOC_TYPE (COPY, 0) +RELOC_TYPE (GLOB_DAT, EXEC|DYN) +RELOC_TYPE (JMP_SLOT, EXEC|DYN) +RELOC_TYPE (RELATIVE, EXEC|DYN) +RELOC_TYPE (TLS_GD_HI, REL) +RELOC_TYPE (TLSGD, REL) +RELOC_TYPE (TLS_LDM, REL) +RELOC_TYPE (DTPMOD64, REL|EXEC|DYN) +RELOC_TYPE (GOTDTPREL, REL) +RELOC_TYPE (DTPREL64, REL|EXEC|DYN) +RELOC_TYPE (DTPRELHI, REL) +RELOC_TYPE (DTPRELLO, REL) +RELOC_TYPE (DTPREL16, REL) +RELOC_TYPE (GOTTPREL, REL) +RELOC_TYPE (TPREL64, REL|EXEC|DYN) +RELOC_TYPE (TPRELHI, REL) +RELOC_TYPE (TPRELLO, REL) +RELOC_TYPE (TPREL16, REL) diff --git a/3rdparty/elfutils/backends/alpha_retval.c b/3rdparty/elfutils/backends/alpha_retval.c new file mode 100644 index 0000000..53dbfa4 --- /dev/null +++ b/3rdparty/elfutils/backends/alpha_retval.c @@ -0,0 +1,150 @@ +/* Function return value location for Alpha ELF ABI. + Copyright (C) 2005, 2007, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> + +#define BACKEND alpha_ +#include "libebl_CPU.h" + + +/* $0. */ +static const Dwarf_Op loc_intreg[] = + { + { .atom = DW_OP_reg0 } + }; +#define nloc_intreg 1 + +/* $f0, or pair $f0, $f1. */ +static const Dwarf_Op loc_fpreg[] = + { + { .atom = DW_OP_regx, .number = 32 }, { .atom = DW_OP_piece, .number = 4 }, + { .atom = DW_OP_regx, .number = 33 }, { .atom = DW_OP_piece, .number = 4 }, + }; +#define nloc_fpreg 1 +#define nloc_fpregpair 4 + +/* The return value is a structure and is actually stored in stack space + passed in a hidden argument by the caller. But, the compiler + helpfully returns the address of that space in $0. */ +static const Dwarf_Op loc_aggregate[] = + { + { .atom = DW_OP_breg0, .number = 0 } + }; +#define nloc_aggregate 1 + +int +alpha_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp) +{ + /* Start with the function's type, and get the DW_AT_type attribute, + which is the type of the return value. */ + Dwarf_Die die_mem, *typedie = &die_mem; + int tag = dwarf_peeled_die_type (functypedie, typedie); + if (tag <= 0) + return tag; + + switch (tag) + { + case -1: + return -1; + + case DW_TAG_subrange_type: + if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size)) + { + Dwarf_Attribute attr_mem, *attr; + attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem); + typedie = dwarf_formref_die (attr, &die_mem); + tag = DWARF_TAG_OR_RETURN (typedie); + } + /* Fall through. */ + + case DW_TAG_base_type: + case DW_TAG_enumeration_type: + case DW_TAG_pointer_type: + case DW_TAG_ptr_to_member_type: + { + Dwarf_Attribute attr_mem; + Dwarf_Word size; + if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size, + &attr_mem), &size) != 0) + { + if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type) + size = 8; + else + return -1; + } + if (tag == DW_TAG_base_type) + { + Dwarf_Word encoding; + if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding, + &attr_mem), + &encoding) != 0) + return -1; + + *locp = loc_fpreg; + if (encoding == DW_ATE_float) + { + if (size <= 8) + return nloc_fpreg; + goto aggregate; + } + if (encoding == DW_ATE_complex_float) + { + if (size <= 8 * 2) + return nloc_fpregpair; + goto aggregate; + } + } + if (size <= 8) + { + *locp = loc_intreg; + return nloc_intreg; + } + } + + /* Else fall through. */ + + case DW_TAG_structure_type: + case DW_TAG_class_type: + case DW_TAG_union_type: + case DW_TAG_string_type: + case DW_TAG_array_type: + aggregate: + *locp = loc_aggregate; + return nloc_aggregate; + } + + /* XXX We don't have a good way to return specific errors from ebl calls. + This value means we do not understand the type, but it is well-formed + DWARF and might be valid. */ + return -2; +} diff --git a/3rdparty/elfutils/backends/alpha_symbol.c b/3rdparty/elfutils/backends/alpha_symbol.c new file mode 100644 index 0000000..657d9ee --- /dev/null +++ b/3rdparty/elfutils/backends/alpha_symbol.c @@ -0,0 +1,156 @@ +/* Alpha specific symbolic name handling. + Copyright (C) 2002-2011 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <elf.h> +#include <stddef.h> +#include <string.h> + +#define BACKEND alpha_ +#include "libebl_CPU.h" + + +const char * +alpha_dynamic_tag_name (int64_t tag, char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + switch (tag) + { + case DT_ALPHA_PLTRO: + return "ALPHA_PLTRO"; + default: + break; + } + return NULL; +} + +bool +alpha_dynamic_tag_check (int64_t tag) +{ + return tag == DT_ALPHA_PLTRO; +} + +/* Check for the simple reloc types. */ +Elf_Type +alpha_reloc_simple_type (Ebl *ebl __attribute__ ((unused)), int type) +{ + switch (type) + { + case R_ALPHA_REFLONG: + return ELF_T_WORD; + case R_ALPHA_REFQUAD: + return ELF_T_XWORD; + default: + return ELF_T_NUM; + } +} + + +/* Check whether SHF_MASKPROC flags are valid. */ +bool +alpha_machine_section_flag_check (GElf_Xword sh_flags) +{ + return (sh_flags &~ (SHF_ALPHA_GPREL)) == 0; +} + +bool +alpha_check_special_section (Ebl *ebl, + int ndx __attribute__ ((unused)), + const GElf_Shdr *shdr, + const char *sname __attribute__ ((unused))) +{ + if ((shdr->sh_flags + & (SHF_WRITE | SHF_EXECINSTR)) == (SHF_WRITE | SHF_EXECINSTR) + && shdr->sh_addr != 0) + { + /* This is ordinarily flagged, but is valid for an old-style PLT. + + Look for the SHT_DYNAMIC section and the DT_PLTGOT tag in it. + Its d_ptr should match the .plt section's sh_addr. */ + + Elf_Scn *scn = NULL; + while ((scn = elf_nextscn (ebl->elf, scn)) != NULL) + { + GElf_Shdr scn_shdr; + if (likely (gelf_getshdr (scn, &scn_shdr) != NULL) + && scn_shdr.sh_type == SHT_DYNAMIC + && scn_shdr.sh_entsize != 0) + { + GElf_Addr pltgot = 0; + Elf_Data *data = elf_getdata (scn, NULL); + if (data != NULL) + for (size_t i = 0; i < data->d_size / scn_shdr.sh_entsize; ++i) + { + GElf_Dyn dyn; + if (unlikely (gelf_getdyn (data, i, &dyn) == NULL)) + break; + if (dyn.d_tag == DT_PLTGOT) + pltgot = dyn.d_un.d_ptr; + else if (dyn.d_tag == DT_ALPHA_PLTRO && dyn.d_un.d_val != 0) + return false; /* This PLT should not be writable. */ + } + return pltgot == shdr->sh_addr; + } + } + } + + return false; +} + +/* Check whether given symbol's st_value and st_size are OK despite failing + normal checks. */ +bool +alpha_check_special_symbol (Elf *elf __attribute__ ((unused)), + GElf_Ehdr *ehdr __attribute__ ((unused)), + const GElf_Sym *sym __attribute__ ((unused)), + const char *name, + const GElf_Shdr *destshdr __attribute__ ((unused))) +{ + if (name == NULL) + return false; + + if (strcmp (name, "_GLOBAL_OFFSET_TABLE_") == 0) + /* On Alpha any place in the section is valid. */ + return true; + + return false; +} + +/* Check whether only valid bits are set on the st_other symbol flag. + Standard ST_VISIBILITY have already been masked off. */ +bool +alpha_check_st_other_bits (unsigned char st_other) +{ + return ((((st_other & STO_ALPHA_STD_GPLOAD) == STO_ALPHA_NOPV) + || ((st_other & STO_ALPHA_STD_GPLOAD) == STO_ALPHA_STD_GPLOAD)) + && (st_other &~ STO_ALPHA_STD_GPLOAD) == 0); +} diff --git a/3rdparty/elfutils/backends/arm/arm.pro b/3rdparty/elfutils/backends/arm/arm.pro new file mode 100644 index 0000000..89aa3c8 --- /dev/null +++ b/3rdparty/elfutils/backends/arm/arm.pro @@ -0,0 +1,17 @@ +TEMPLATE = lib +include(../backends.pri) +TARGET = ../ebl_arm + +SOURCES += \ + ../arm_attrs.c \ + ../arm_auxv.c \ + ../arm_cfi.c \ + ../arm_corenote.c \ + ../arm_init.c \ + ../arm_initreg.c \ + ../arm_regs.c \ + ../arm_retval.c \ + ../arm_symbol.c + +HEADERS += \ + ../arm_reloc.def diff --git a/3rdparty/elfutils/backends/arm_attrs.c b/3rdparty/elfutils/backends/arm_attrs.c new file mode 100644 index 0000000..c858715 --- /dev/null +++ b/3rdparty/elfutils/backends/arm_attrs.c @@ -0,0 +1,245 @@ +/* Object attribute tags for ARM. + Copyright (C) 2009 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> +#include <dwarf.h> + +#define BACKEND arm_ +#include "libebl_CPU.h" + +#define KNOWN_VALUES(...) do \ + { \ + static const char *table[] = { __VA_ARGS__ }; \ + if (value < sizeof table / sizeof table[0]) \ + *value_name = table[value]; \ + } while (0) + +bool +arm_check_object_attribute (ebl, vendor, tag, value, tag_name, value_name) + Ebl *ebl __attribute__ ((unused)); + const char *vendor; + int tag; + uint64_t value __attribute__ ((unused)); + const char **tag_name; + const char **value_name; +{ + if (!strcmp (vendor, "aeabi")) + switch (tag) + { + case 4: + *tag_name = "CPU_raw_name"; + return true; + case 5: + *tag_name = "CPU_name"; + return true; + case 6: + *tag_name = "CPU_arch"; + KNOWN_VALUES ("Pre-v4", + "v4", + "v4T", + "v5T", + "v5TE", + "v5TEJ", + "v6", + "v6KZ", + "v6T2", + "v6K", + "v7", + "v6-M", + "v6S-M"); + return true; + case 7: + *tag_name = "CPU_arch_profile"; + switch (value) + { + case 'A': + *value_name = "Application"; + break; + case 'R': + *value_name = "Realtime"; + break; + case 'M': + *value_name = "Microcontroller"; + break; + } + return true; + case 8: + *tag_name = "ARM_ISA_use"; + KNOWN_VALUES ("No", "Yes"); + return true; + case 9: + *tag_name = "THUMB_ISA_use"; + KNOWN_VALUES ("No", "Thumb-1", "Thumb-2"); + return true; + case 10: + *tag_name = "VFP_arch"; + KNOWN_VALUES ("No", "VFPv1", "VFPv2", "VFPv3", "VFPv3-D16"); + return true; + case 11: + *tag_name = "WMMX_arch"; + KNOWN_VALUES ("No", "WMMXv1", "WMMXv2"); + return true; + case 12: + *tag_name = "Advanced_SIMD_arch"; + KNOWN_VALUES ("No", "NEONv1"); + return true; + case 13: + *tag_name = "PCS_config"; + KNOWN_VALUES ("None", + "Bare platform", + "Linux application", + "Linux DSO", + "PalmOS 2004", + "PalmOS (reserved)", + "SymbianOS 2004", + "SymbianOS (reserved)"); + return true; + case 14: + *tag_name = "ABI_PCS_R9_use"; + KNOWN_VALUES ("V6", "SB", "TLS", "Unused"); + return true; + case 15: + *tag_name = "ABI_PCS_RW_data"; + KNOWN_VALUES ("Absolute", "PC-relative", "SB-relative", "None"); + return true; + case 16: + *tag_name = "ABI_PCS_RO_data"; + KNOWN_VALUES ("Absolute", "PC-relative", "None"); + return true; + case 17: + *tag_name = "ABI_PCS_GOT_use"; + KNOWN_VALUES ("None", "direct", "GOT-indirect"); + return true; + case 18: + *tag_name = "ABI_PCS_wchar_t"; + return true; + case 19: + *tag_name = "ABI_FP_rounding"; + KNOWN_VALUES ("Unused", "Needed"); + return true; + case 20: + *tag_name = "ABI_FP_denormal"; + KNOWN_VALUES ("Unused", "Needed", "Sign only"); + return true; + case 21: + *tag_name = "ABI_FP_exceptions"; + KNOWN_VALUES ("Unused", "Needed"); + return true; + case 22: + *tag_name = "ABI_FP_user_exceptions"; + KNOWN_VALUES ("Unused", "Needed"); + return true; + case 23: + *tag_name = "ABI_FP_number_model"; + KNOWN_VALUES ("Unused", "Finite", "RTABI", "IEEE 754"); + return true; + case 24: + *tag_name = "ABI_align8_needed"; + KNOWN_VALUES ("No", "Yes", "4-byte"); + return true; + case 25: + *tag_name = "ABI_align8_preserved"; + KNOWN_VALUES ("No", "Yes, except leaf SP", "Yes"); + return true; + case 26: + *tag_name = "ABI_enum_size"; + KNOWN_VALUES ("Unused", "small", "int", "forced to int"); + return true; + case 27: + *tag_name = "ABI_HardFP_use"; + KNOWN_VALUES ("as VFP_arch", "SP only", "DP only", "SP and DP"); + return true; + case 28: + *tag_name = "ABI_VFP_args"; + KNOWN_VALUES ("AAPCS", "VFP registers", "custom"); + return true; + case 29: + *tag_name = "ABI_WMMX_args"; + KNOWN_VALUES ("AAPCS", "WMMX registers", "custom"); + return true; + case 30: + *tag_name = "ABI_optimization_goals"; + KNOWN_VALUES ("None", + "Prefer Speed", + "Aggressive Speed", + "Prefer Size", + "Aggressive Size", + "Prefer Debug", + "Aggressive Debug"); + return true; + case 31: + *tag_name = "ABI_FP_optimization_goals"; + KNOWN_VALUES ("None", + "Prefer Speed", + "Aggressive Speed", + "Prefer Size", + "Aggressive Size", + "Prefer Accuracy", + "Aggressive Accuracy"); + return true; + case 34: + *tag_name = "CPU_unaligned_access"; + KNOWN_VALUES ("None", "v6"); + return true; + case 36: + *tag_name = "VFP_HP_extension"; + KNOWN_VALUES ("Not Allowed", "Allowed"); + return true; + case 38: + *tag_name = "ABI_FP_16bit_format"; + KNOWN_VALUES ("None", "IEEE 754", "Alternative Format"); + return true; + case 64: + *tag_name = "nodefaults"; + return true; + case 65: + *tag_name = "also_compatible_with"; + return true; + case 66: + *tag_name = "T2EE_use"; + KNOWN_VALUES ("Not Allowed", "Allowed"); + return true; + case 67: + *tag_name = "conformance"; + return true; + case 68: + *tag_name = "Virtualization_use"; + KNOWN_VALUES ("Not Allowed", "Allowed"); + return true; + case 70: + *tag_name = "MPextension_use"; + KNOWN_VALUES ("Not Allowed", "Allowed"); + return true; + } + + return false; +} diff --git a/3rdparty/elfutils/backends/arm_auxv.c b/3rdparty/elfutils/backends/arm_auxv.c new file mode 100644 index 0000000..3282baf --- /dev/null +++ b/3rdparty/elfutils/backends/arm_auxv.c @@ -0,0 +1,49 @@ +/* ARM-specific auxv handling. + Copyright (C) 2009 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND arm_ +#include "libebl_CPU.h" + +int +EBLHOOK(auxv_info) (GElf_Xword a_type, const char **name, const char **format) +{ + if (a_type != AT_HWCAP) + return 0; + + *name = "HWCAP"; + *format = "b" + "swp\0" "half\0" "thumb\0" "26bit\0" + "fast-mult\0" "fpa\0" "vfp\0" "edsp\0" + "java\0" "iwmmxt\0" + "\0"; + return 1; +} diff --git a/3rdparty/elfutils/backends/arm_cfi.c b/3rdparty/elfutils/backends/arm_cfi.c new file mode 100644 index 0000000..971a1fc --- /dev/null +++ b/3rdparty/elfutils/backends/arm_cfi.c @@ -0,0 +1,90 @@ +/* arm ABI-specified defaults for DWARF CFI. + Copyright (C) 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> + +#define BACKEND arm_ +#include "libebl_CPU.h" + + +/* ABI-specified state of DWARF CFI based on: + + "DWARF for the ARM Architecture ABI r2.09" +http://infocenter.arm.com/help/topic/com.arm.doc.ihi0040b/IHI0040B_aadwarf.pdf + + "Procedure Call Standard for the ARM Architecture ABI r2.09" +http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042e/IHI0042E_aapcs.pdf +*/ + +int +arm_abi_cfi (Ebl *ebl __attribute__ ((unused)), Dwarf_CIE *abi_info) +{ + static const uint8_t abi_cfi[] = + { + /* The initial Canonical Frame Address is the value of the + Stack Pointer (r13) as setup in the previous frame. */ + DW_CFA_def_cfa, ULEB128_7 (13), ULEB128_7 (0), + + /* The Stack Pointer (r13) is restored from CFA address by default. */ + DW_CFA_val_offset, ULEB128_7 (13), ULEB128_7 (0), + +#define SV(n) DW_CFA_same_value, ULEB128_7 (n) + /* Callee-saved regs r4-r8, r10, r11. */ + SV (4), SV (5), SV (6), SV (7), SV (8), SV (10), SV (11), + + /* The link register contains the return address setup by caller. */ + SV (14), + DW_CFA_register, ULEB128_7 (15), ULEB128_7 (14), /* pc = lr */ +#undef SV + + /* VFP S16-S31/D8-D15/Q4-Q7 are callee saved. + And uleb128 encoded with two bytes. */ +#define ULEB128_8_2(x) ((x & 0x7f) | 0x80), 0x02 +#define SV(n) DW_CFA_same_value, ULEB128_8_2 (n) + SV (264), SV (265), SV (266), SV (267), + SV (268), SV (269), SV (270), SV (271), + + /* XXX Note: registers intentionally unused by the program, + for example as a consequence of the procedure call standard + should be initialized as if by DW_CFA_same_value. */ + }; +#undef ULEB128_8_2 +#undef SV + + abi_info->initial_instructions = abi_cfi; + abi_info->initial_instructions_end = &abi_cfi[sizeof abi_cfi]; + abi_info->data_alignment_factor = 4; + + abi_info->return_address_register = 15; /* pc. */ + + return 0; +} diff --git a/3rdparty/elfutils/backends/arm_corenote.c b/3rdparty/elfutils/backends/arm_corenote.c new file mode 100644 index 0000000..c5d8d88 --- /dev/null +++ b/3rdparty/elfutils/backends/arm_corenote.c @@ -0,0 +1,94 @@ +/* ARM specific core note handling. + Copyright (C) 2009, 2012 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <elf.h> +#include <inttypes.h> +#include <stddef.h> +#include <stdio.h> +#include <sys/time.h> + +#define BACKEND arm_ +#include "libebl_CPU.h" + + +static const Ebl_Register_Location prstatus_regs[] = + { + { .offset = 0, .regno = 0, .count = 16, .bits = 32 }, /* r0..r15 */ + { .offset = 16 * 4, .regno = 128, .count = 1, .bits = 32 }, /* cpsr */ + }; +#define PRSTATUS_REGS_SIZE (18 * 4) + +#define PRSTATUS_REGSET_ITEMS \ + { \ + .name = "orig_r0", .type = ELF_T_SWORD, .format = 'd', \ + .offset = offsetof (struct EBLHOOK(prstatus), pr_reg) + (4 * 17), \ + .group = "register" \ + } + +static const Ebl_Register_Location fpregset_regs[] = + { + { .offset = 0, .regno = 96, .count = 8, .bits = 96 }, /* f0..f7 */ + }; +#define FPREGSET_SIZE 116 + +#define ULONG uint32_t +#define PID_T int32_t +#define UID_T uint16_t +#define GID_T uint16_t +#define ALIGN_ULONG 4 +#define ALIGN_PID_T 4 +#define ALIGN_UID_T 2 +#define ALIGN_GID_T 2 +#define TYPE_ULONG ELF_T_WORD +#define TYPE_PID_T ELF_T_SWORD +#define TYPE_UID_T ELF_T_HALF +#define TYPE_GID_T ELF_T_HALF + +#define ARM_VFPREGS_SIZE ( 32 * 8 /*fpregs*/ + 4 /*fpscr*/ ) +static const Ebl_Register_Location vfp_regs[] = + { + { .offset = 0, .regno = 256, .count = 32, .bits = 64 }, /* fpregs */ + }; + +static const Ebl_Core_Item vfp_items[] = + { + { + .name = "fpscr", .group = "register", + .offset = 0, + .type = ELF_T_WORD, .format = 'x', + }, + }; + +#define EXTRA_NOTES \ + EXTRA_REGSET_ITEMS (NT_ARM_VFP, ARM_VFPREGS_SIZE, vfp_regs, vfp_items) + +#include "linux-core-note.c" diff --git a/3rdparty/elfutils/backends/arm_init.c b/3rdparty/elfutils/backends/arm_init.c new file mode 100644 index 0000000..3283c97 --- /dev/null +++ b/3rdparty/elfutils/backends/arm_init.c @@ -0,0 +1,76 @@ +/* Initialization of Arm specific backend library. + Copyright (C) 2002, 2005, 2009, 2013, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND arm_ +#define RELOC_PREFIX R_ARM_ +#include "libebl_CPU.h" + +/* This defines the common reloc hooks based on arm_reloc.def. */ +#include "common-reloc.c" + + +const char * +arm_init (elf, machine, eh, ehlen) + Elf *elf __attribute__ ((unused)); + GElf_Half machine __attribute__ ((unused)); + Ebl *eh; + size_t ehlen; +{ + /* Check whether the Elf_BH object has a sufficent size. */ + if (ehlen < sizeof (Ebl)) + return NULL; + + /* We handle it. */ + eh->name = "ARM"; + arm_init_reloc (eh); + HOOK (eh, segment_type_name); + HOOK (eh, section_type_name); + HOOK (eh, machine_flag_check); + HOOK (eh, reloc_simple_type); + HOOK (eh, register_info); + HOOK (eh, core_note); + HOOK (eh, auxv_info); + HOOK (eh, check_object_attribute); + HOOK (eh, return_value_location); + HOOK (eh, abi_cfi); + HOOK (eh, check_reloc_target_type); + + /* We only unwind the core integer registers. */ + eh->frame_nregs = 16; + HOOK (eh, set_initial_registers_tid); + + /* Bit zero encodes whether an function address is THUMB or ARM. */ + eh->func_addr_mask = ~(GElf_Addr)1; + + return MODVERSION; +} diff --git a/3rdparty/elfutils/backends/arm_initreg.c b/3rdparty/elfutils/backends/arm_initreg.c new file mode 100644 index 0000000..a0a9be9 --- /dev/null +++ b/3rdparty/elfutils/backends/arm_initreg.c @@ -0,0 +1,92 @@ +/* Fetch live process registers from TID. + Copyright (C) 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#if defined __arm__ +# include <sys/types.h> +# include <sys/user.h> +# include <sys/ptrace.h> +#endif + +#ifdef __aarch64__ +# include <linux/uio.h> +# include <sys/user.h> +# include <sys/ptrace.h> +/* Deal with old glibc defining user_pt_regs instead of user_regs_struct. */ +# ifndef HAVE_SYS_USER_REGS +# define user_regs_struct user_pt_regs +# endif +#endif + +#define BACKEND arm_ +#include "libebl_CPU.h" + +bool +arm_set_initial_registers_tid (pid_t tid __attribute__ ((unused)), + ebl_tid_registers_t *setfunc __attribute__ ((unused)), + void *arg __attribute__ ((unused))) +{ +#if !defined __arm__ && !defined __aarch64__ + return false; +#else /* __arm__ || __aarch64__ */ +#if defined __arm__ + struct user_regs user_regs; + if (ptrace (PTRACE_GETREGS, tid, NULL, &user_regs) != 0) + return false; + + Dwarf_Word dwarf_regs[16]; + /* R0..R12 SP LR PC */ + for (int i = 0; i < 16; i++) + dwarf_regs[i] = user_regs.uregs[i]; + + return setfunc (0, 16, dwarf_regs, arg); +#elif defined __aarch64__ + /* Compat mode: arm compatible code running on aarch64 */ + int i; + struct user_regs_struct gregs; + struct iovec iovec; + iovec.iov_base = &gregs; + iovec.iov_len = sizeof (gregs); + if (ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS, &iovec) != 0) + return false; + + Dwarf_Word dwarf_regs[16]; + /* R0..R12 SP LR PC, encoded as 32 bit quantities */ + uint32_t *u32_ptr = (uint32_t *) &gregs.regs[0]; + for (i = 0; i < 16; i++) + dwarf_regs[i] = u32_ptr[i]; + + return setfunc (0, 16, dwarf_regs, arg); +#else +# error "source file error, it cannot happen" +#endif +#endif +} diff --git a/3rdparty/elfutils/backends/arm_regs.c b/3rdparty/elfutils/backends/arm_regs.c new file mode 100644 index 0000000..21c5ad3 --- /dev/null +++ b/3rdparty/elfutils/backends/arm_regs.c @@ -0,0 +1,120 @@ +/* Register names and numbers for ARM DWARF. + Copyright (C) 2009 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> +#include <dwarf.h> + +#define BACKEND arm_ +#include "libebl_CPU.h" + +ssize_t +arm_register_info (Ebl *ebl __attribute__ ((unused)), + int regno, char *name, size_t namelen, + const char **prefix, const char **setname, + int *bits, int *type) +{ + if (name == NULL) + return 320; + + if (regno < 0 || regno > 320 || namelen < 5) + return -1; + + *prefix = ""; + *bits = 32; + *type = DW_ATE_signed; + *setname = "integer"; + + switch (regno) + { + case 0 ... 9: + name[0] = 'r'; + name[1] = regno + '0'; + namelen = 2; + break; + + case 10 ... 12: + name[0] = 'r'; + name[1] = '1'; + name[2] = regno % 10 + '0'; + namelen = 3; + break; + + case 13 ... 15: + *type = DW_ATE_address; + name[0] = "slp"[regno - 13]; + name[1] = "prc"[regno - 13]; + namelen = 2; + break; + + case 16 + 0 ... 16 + 7: + regno += 96 - 16; + /* Fall through. */ + case 96 + 0 ... 96 + 7: + *setname = "FPA"; + *type = DW_ATE_float; + *bits = 96; + name[0] = 'f'; + name[1] = regno - 96 + '0'; + namelen = 2; + break; + + case 128: + *type = DW_ATE_unsigned; + return stpcpy (name, "spsr") + 1 - name; + + case 256 + 0 ... 256 + 9: + *setname = "VFP"; + *type = DW_ATE_float; + *bits = 64; + name[0] = 'd'; + name[1] = regno - 256 + '0'; + namelen = 2; + break; + + case 256 + 10 ... 256 + 31: + *setname = "VFP"; + *type = DW_ATE_float; + *bits = 64; + name[0] = 'd'; + name[1] = (regno - 256) / 10 + '0'; + name[2] = (regno - 256) % 10 + '0'; + namelen = 3; + break; + + default: + *setname = NULL; + return 0; + } + + name[namelen++] = '\0'; + return namelen; +} diff --git a/3rdparty/elfutils/backends/arm_reloc.def b/3rdparty/elfutils/backends/arm_reloc.def new file mode 100644 index 0000000..4b7894b --- /dev/null +++ b/3rdparty/elfutils/backends/arm_reloc.def @@ -0,0 +1,157 @@ +/* List the relocation types for arm. -*- C -*- + Copyright (C) 2005-2010, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +/* NAME, REL|EXEC|DYN */ + +RELOC_TYPE (NONE, REL) /* It really is used in ET_REL on ARM. */ +RELOC_TYPE (PC24, REL|EXEC|DYN) +RELOC_TYPE (ABS32, REL|EXEC|DYN) +RELOC_TYPE (REL32, REL) +RELOC_TYPE (PC13, REL) +RELOC_TYPE (ABS16, REL) +RELOC_TYPE (ABS12, REL) +RELOC_TYPE (THM_ABS5, REL) +RELOC_TYPE (ABS8, REL) +RELOC_TYPE (SBREL32, REL) +RELOC_TYPE (THM_PC22, REL) +RELOC_TYPE (THM_PC8, REL) +RELOC_TYPE (AMP_VCALL9, REL) +RELOC_TYPE (TLS_DESC, EXEC|DYN) +RELOC_TYPE (THM_SWI8, REL) +RELOC_TYPE (XPC25, REL) +RELOC_TYPE (THM_XPC22, REL) +RELOC_TYPE (TLS_DTPMOD32, EXEC|DYN) +RELOC_TYPE (TLS_DTPOFF32, EXEC|DYN) +RELOC_TYPE (TLS_TPOFF32, EXEC|DYN) +RELOC_TYPE (COPY, EXEC) +RELOC_TYPE (GLOB_DAT, EXEC|DYN) +RELOC_TYPE (JUMP_SLOT, EXEC|DYN) +RELOC_TYPE (RELATIVE, EXEC|DYN) +RELOC_TYPE (GOTOFF, REL) +RELOC_TYPE (GOTPC, REL) +RELOC_TYPE (GOT32, REL) +RELOC_TYPE (PLT32, REL) +RELOC_TYPE (CALL, REL) +RELOC_TYPE (JUMP24, REL) +RELOC_TYPE (THM_JUMP24, REL) +RELOC_TYPE (BASE_ABS, REL) +RELOC_TYPE (ALU_PCREL_7_0, REL) +RELOC_TYPE (ALU_PCREL_15_8, REL) +RELOC_TYPE (ALU_PCREL_23_15, REL) +RELOC_TYPE (LDR_SBREL_11_0, REL) +RELOC_TYPE (ALU_SBREL_19_12, REL) +RELOC_TYPE (ALU_SBREL_27_20, REL) +RELOC_TYPE (TARGET1, REL) +RELOC_TYPE (SBREL31, REL) +RELOC_TYPE (V4BX, REL) +RELOC_TYPE (TARGET2, REL) +RELOC_TYPE (PREL31, REL) +RELOC_TYPE (MOVW_ABS_NC, REL) +RELOC_TYPE (MOVT_ABS, REL) +RELOC_TYPE (MOVW_PREL_NC, REL) +RELOC_TYPE (MOVT_PREL, REL) +RELOC_TYPE (THM_MOVW_ABS_NC, REL) +RELOC_TYPE (THM_MOVT_ABS, REL) +RELOC_TYPE (THM_MOVW_PREL_NC, REL) +RELOC_TYPE (THM_MOVT_PREL, REL) +RELOC_TYPE (THM_JUMP19, REL) +RELOC_TYPE (THM_JUMP6, REL) +RELOC_TYPE (THM_ALU_PREL_11_0, REL) +RELOC_TYPE (THM_PC12, REL) +RELOC_TYPE (ABS32_NOI, REL) +RELOC_TYPE (REL32_NOI, REL) +RELOC_TYPE (ALU_PC_G0_NC, REL) +RELOC_TYPE (ALU_PC_G0, REL) +RELOC_TYPE (ALU_PC_G1_NC, REL) +RELOC_TYPE (ALU_PC_G1, REL) +RELOC_TYPE (ALU_PC_G2, REL) +RELOC_TYPE (LDR_PC_G1, REL) +RELOC_TYPE (LDR_PC_G2, REL) +RELOC_TYPE (LDRS_PC_G0, REL) +RELOC_TYPE (LDRS_PC_G1, REL) +RELOC_TYPE (LDRS_PC_G2, REL) +RELOC_TYPE (LDC_PC_G0, REL) +RELOC_TYPE (LDC_PC_G1, REL) +RELOC_TYPE (LDC_PC_G2, REL) +RELOC_TYPE (ALU_SB_G0_NC, REL) +RELOC_TYPE (ALU_SB_G0, REL) +RELOC_TYPE (ALU_SB_G1_NC, REL) +RELOC_TYPE (ALU_SB_G1, REL) +RELOC_TYPE (ALU_SB_G2, REL) +RELOC_TYPE (LDR_SB_G0, REL) +RELOC_TYPE (LDR_SB_G1, REL) +RELOC_TYPE (LDR_SB_G2, REL) +RELOC_TYPE (LDRS_SB_G0, REL) +RELOC_TYPE (LDRS_SB_G1, REL) +RELOC_TYPE (LDRS_SB_G2, REL) +RELOC_TYPE (LDC_SB_G0, REL) +RELOC_TYPE (LDC_SB_G1, REL) +RELOC_TYPE (LDC_SB_G2, REL) +RELOC_TYPE (MOVW_BREL_NC, REL) +RELOC_TYPE (MOVT_BREL, REL) +RELOC_TYPE (MOVW_BREL, REL) +RELOC_TYPE (THM_MOVW_BREL_NC, REL) +RELOC_TYPE (THM_MOVT_BREL, REL) +RELOC_TYPE (THM_MOVW_BREL, REL) +RELOC_TYPE (TLS_GOTDESC, REL) +RELOC_TYPE (TLS_CALL, REL) +RELOC_TYPE (TLS_DESCSEQ, REL) +RELOC_TYPE (THM_TLS_CALL, REL) +RELOC_TYPE (PLT32_ABS, REL) +RELOC_TYPE (GOT_ABS, REL) +RELOC_TYPE (GOT_PREL, REL) +RELOC_TYPE (GOT_BREL12, REL) +RELOC_TYPE (GOTOFF12, REL) +RELOC_TYPE (GOTRELAX, REL) +RELOC_TYPE (GNU_VTENTRY, REL) +RELOC_TYPE (GNU_VTINHERIT, REL) +RELOC_TYPE (THM_PC11, REL) +RELOC_TYPE (THM_PC9, REL) +RELOC_TYPE (TLS_GD32, REL) +RELOC_TYPE (TLS_LDM32, REL) +RELOC_TYPE (TLS_LDO32, REL) +RELOC_TYPE (TLS_IE32, REL) +RELOC_TYPE (TLS_LE32, REL) +RELOC_TYPE (TLS_LDO12, REL) +RELOC_TYPE (TLS_LE12, REL) +RELOC_TYPE (TLS_IE12GP, REL) + +RELOC_TYPE (ME_TOO, REL) +RELOC_TYPE (THM_TLS_DESCSEQ16, REL) +RELOC_TYPE (THM_TLS_DESCSEQ32, REL) +RELOC_TYPE (THM_GOT_BREL12, REL) + +RELOC_TYPE (IRELATIVE, EXEC|DYN) + +RELOC_TYPE (RXPC25, REL) +RELOC_TYPE (RSBREL32, REL) +RELOC_TYPE (THM_RPC22, REL) +RELOC_TYPE (RREL32, REL) +RELOC_TYPE (RABS22, REL) +RELOC_TYPE (RPC24, REL) +RELOC_TYPE (RBASE, REL) diff --git a/3rdparty/elfutils/backends/arm_retval.c b/3rdparty/elfutils/backends/arm_retval.c new file mode 100644 index 0000000..7aced74 --- /dev/null +++ b/3rdparty/elfutils/backends/arm_retval.c @@ -0,0 +1,127 @@ +/* Function return value location for ARM EABI. + Copyright (C) 2009-2010, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> + +#define BACKEND arm_ +#include "libebl_CPU.h" + + +/* r0, or pair r0, r1, or aggregate up to r0-r3. */ +static const Dwarf_Op loc_intreg[] = + { + { .atom = DW_OP_reg0 }, { .atom = DW_OP_piece, .number = 4 }, + { .atom = DW_OP_reg1 }, { .atom = DW_OP_piece, .number = 4 }, + { .atom = DW_OP_reg2 }, { .atom = DW_OP_piece, .number = 4 }, + { .atom = DW_OP_reg3 }, { .atom = DW_OP_piece, .number = 4 }, + }; +#define nloc_intreg 1 +#define nloc_intregs(n) (2 * (n)) + +/* The return value is a structure and is actually stored in stack space + passed in a hidden argument by the caller. But, the compiler + helpfully returns the address of that space in r0. */ +static const Dwarf_Op loc_aggregate[] = + { + { .atom = DW_OP_breg0, .number = 0 } + }; +#define nloc_aggregate 1 + + +int +arm_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp) +{ + /* Start with the function's type, and get the DW_AT_type attribute, + which is the type of the return value. */ + Dwarf_Die die_mem, *typedie = &die_mem; + int tag = dwarf_peeled_die_type (functypedie, typedie); + if (tag <= 0) + return tag; + + Dwarf_Word size; + switch (tag) + { + case -1: + return -1; + + case DW_TAG_subrange_type: + if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size)) + { + Dwarf_Attribute attr_mem, *attr; + attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem); + typedie = dwarf_formref_die (attr, &die_mem); + tag = DWARF_TAG_OR_RETURN (typedie); + } + /* Fall through. */ + + case DW_TAG_base_type: + case DW_TAG_enumeration_type: + case DW_TAG_pointer_type: + case DW_TAG_ptr_to_member_type: + { + Dwarf_Attribute attr_mem; + if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size, + &attr_mem), &size) != 0) + { + if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type) + size = 4; + else + return -1; + } + if (size <= 16) + { + intreg: + *locp = loc_intreg; + return size <= 4 ? nloc_intreg : nloc_intregs ((size + 3) / 4); + } + + aggregate: + *locp = loc_aggregate; + return nloc_aggregate; + } + + case DW_TAG_structure_type: + case DW_TAG_class_type: + case DW_TAG_union_type: + case DW_TAG_array_type: + if (dwarf_aggregate_size (typedie, &size) == 0 + && size > 0 && size <= 4) + goto intreg; + goto aggregate; + } + + /* XXX We don't have a good way to return specific errors from ebl calls. + This value means we do not understand the type, but it is well-formed + DWARF and might be valid. */ + return -2; +} diff --git a/3rdparty/elfutils/backends/arm_symbol.c b/3rdparty/elfutils/backends/arm_symbol.c new file mode 100644 index 0000000..cd467ff --- /dev/null +++ b/3rdparty/elfutils/backends/arm_symbol.c @@ -0,0 +1,131 @@ +/* Arm specific symbolic name handling. + Copyright (C) 2002-2009, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <elf.h> +#include <stddef.h> + +#define BACKEND arm_ +#include "libebl_CPU.h" + + +const char * +arm_segment_type_name (int segment, char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + switch (segment) + { + case PT_ARM_EXIDX: + return "ARM_EXIDX"; + } + return NULL; +} + +/* Return symbolic representation of section type. */ +const char * +arm_section_type_name (int type, + char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + switch (type) + { + case SHT_ARM_EXIDX: + return "ARM_EXIDX"; + case SHT_ARM_PREEMPTMAP: + return "ARM_PREEMPTMAP"; + case SHT_ARM_ATTRIBUTES: + return "ARM_ATTRIBUTES"; + } + + return NULL; +} + +/* Check whether machine flags are valid. */ +bool +arm_machine_flag_check (GElf_Word flags) +{ + switch (flags & EF_ARM_EABIMASK) + { + case EF_ARM_EABI_UNKNOWN: + case EF_ARM_EABI_VER1: + case EF_ARM_EABI_VER2: + case EF_ARM_EABI_VER3: + case EF_ARM_EABI_VER4: + case EF_ARM_EABI_VER5: + break; + default: + return false; + } + + return ((flags &~ (EF_ARM_EABIMASK + | EF_ARM_RELEXEC + | EF_ARM_HASENTRY + | EF_ARM_INTERWORK + | EF_ARM_APCS_26 + | EF_ARM_APCS_FLOAT + | EF_ARM_PIC + | EF_ARM_ALIGN8 + | EF_ARM_NEW_ABI + | EF_ARM_OLD_ABI + | EF_ARM_SOFT_FLOAT + | EF_ARM_VFP_FLOAT + | EF_ARM_MAVERICK_FLOAT + | EF_ARM_SYMSARESORTED + | EF_ARM_DYNSYMSUSESEGIDX + | EF_ARM_MAPSYMSFIRST + | EF_ARM_EABIMASK + | EF_ARM_BE8 + | EF_ARM_LE8)) == 0); +} + +/* Check for the simple reloc types. */ +Elf_Type +arm_reloc_simple_type (Ebl *ebl __attribute__ ((unused)), int type) +{ + switch (type) + { + case R_ARM_ABS32: + return ELF_T_WORD; + case R_ARM_ABS16: + return ELF_T_HALF; + case R_ARM_ABS8: + return ELF_T_BYTE; + default: + return ELF_T_NUM; + } +} + +/* The SHT_ARM_EXIDX section type is a valid target for relocation. */ +bool +arm_check_reloc_target_type (Ebl *ebl __attribute__ ((unused)), Elf64_Word sh_type) +{ + return sh_type == SHT_ARM_EXIDX; +} diff --git a/3rdparty/elfutils/backends/backends.pri b/3rdparty/elfutils/backends/backends.pri new file mode 100644 index 0000000..2295037 --- /dev/null +++ b/3rdparty/elfutils/backends/backends.pri @@ -0,0 +1,10 @@ +include(../elfutils.pri) +include(../libebl/eblheaders.pri) + +HEADERS += \ + $$PWD/libebl_CPU.h \ + $$PWD/linux-core-note.c \ + $$PWD/x86_corenote.c \ + $$PWD/common-reloc.c + +INCLUDEPATH += $$PWD diff --git a/3rdparty/elfutils/backends/backends.pro b/3rdparty/elfutils/backends/backends.pro new file mode 100644 index 0000000..0d71325 --- /dev/null +++ b/3rdparty/elfutils/backends/backends.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs + +SUBDIRS = aarch64 alpha arm i386 ia64 ppc ppc64 s390 sh sparc tilegx x86_64 diff --git a/3rdparty/elfutils/backends/common-reloc.c b/3rdparty/elfutils/backends/common-reloc.c new file mode 100644 index 0000000..2667ec4 --- /dev/null +++ b/3rdparty/elfutils/backends/common-reloc.c @@ -0,0 +1,146 @@ +/* Common code for ebl reloc functions. + Copyright (C) 2005, 2006 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libebl_CPU.h" +#include <assert.h> + +#define R_TYPE(name) PASTE (RELOC_PREFIX, name) +#define PASTE(a, b) PASTE_1 (a, b) +#define PASTE_1(a, b) a##b +#define R_NAME(name) R_NAME_1 (RELOC_PREFIX, name) +#define R_NAME_1(prefix, type) R_NAME_2 (prefix, type) +#define R_NAME_2(prefix, type) #prefix #type + +#define RELOC_TYPES STRINGIFIED_PASTE (BACKEND, reloc.def) +#define STRINGIFIED_PASTE(a, b) STRINGIFY (PASTE (a, b)) +#define STRINGIFY(x) STRINGIFY_1 (x) +#define STRINGIFY_1(x) #x + +/* Provide a table of reloc type names, in a PIC-friendly fashion. */ + +static const struct EBLHOOK(reloc_nametable) +{ + char zero; +#define RELOC_TYPE(type, uses) \ + char name_##type[sizeof R_NAME (type)]; +#include RELOC_TYPES +#undef RELOC_TYPE +} EBLHOOK(reloc_nametable) = + { + '\0', +#define RELOC_TYPE(type, uses) R_NAME (type), +#include RELOC_TYPES +#undef RELOC_TYPE + }; +#define reloc_namestr (&EBLHOOK(reloc_nametable).zero) + +static const uint_fast16_t EBLHOOK(reloc_nameidx)[] = +{ +#define RELOC_TYPE(type, uses) \ + [R_TYPE (type)] = offsetof (struct EBLHOOK(reloc_nametable), name_##type), +#include RELOC_TYPES +#undef RELOC_TYPE +}; +#define nreloc \ + ((int) (sizeof EBLHOOK(reloc_nameidx) / sizeof EBLHOOK(reloc_nameidx)[0])) + +#define REL (1 << (ET_REL - 1)) +#define EXEC (1 << (ET_EXEC - 1)) +#define DYN (1 << (ET_DYN - 1)) +static const uint8_t EBLHOOK(reloc_valid)[] = +{ +#define RELOC_TYPE(type, uses) [R_TYPE (type)] = uses, +#include RELOC_TYPES +#undef RELOC_TYPE +}; +#undef REL +#undef EXEC +#undef DYN + +const char * +EBLHOOK(reloc_type_name) (int reloc, + char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + if (reloc >= 0 && reloc < nreloc && EBLHOOK(reloc_nameidx)[reloc] != 0) + return &reloc_namestr[EBLHOOK(reloc_nameidx)[reloc]]; + return NULL; +} + +bool +EBLHOOK(reloc_type_check) (int reloc) +{ + return reloc >= 0 && reloc < nreloc && EBLHOOK(reloc_nameidx)[reloc] != 0; +} + +bool +EBLHOOK(reloc_valid_use) (Elf *elf, int reloc) +{ + uint8_t uses = EBLHOOK(reloc_valid)[reloc]; + + GElf_Ehdr ehdr_mem; + GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem); + assert (ehdr != NULL); + uint8_t type = ehdr->e_type; + + return type > ET_NONE && type < ET_CORE && (uses & (1 << (type - 1))); +} + + +bool +EBLHOOK(copy_reloc_p) (int reloc) +{ + return reloc == R_TYPE (COPY); +} + +bool +EBLHOOK(none_reloc_p) (int reloc) +{ + return reloc == R_TYPE (NONE); +} + +#ifndef NO_RELATIVE_RELOC +bool +EBLHOOK(relative_reloc_p) (int reloc) +{ + return reloc == R_TYPE (RELATIVE); +} +#endif + +static void +EBLHOOK(init_reloc) (Ebl *ebl) +{ + ebl->reloc_type_name = EBLHOOK(reloc_type_name); + ebl->reloc_type_check = EBLHOOK(reloc_type_check); + ebl->reloc_valid_use = EBLHOOK(reloc_valid_use); + ebl->copy_reloc_p = EBLHOOK(copy_reloc_p); + ebl->none_reloc_p = EBLHOOK(none_reloc_p); +#ifndef NO_RELATIVE_RELOC + ebl->relative_reloc_p = EBLHOOK(relative_reloc_p); +#endif +} diff --git a/3rdparty/elfutils/backends/i386/i386.pro b/3rdparty/elfutils/backends/i386/i386.pro new file mode 100644 index 0000000..a731e04 --- /dev/null +++ b/3rdparty/elfutils/backends/i386/i386.pro @@ -0,0 +1,17 @@ +TEMPLATE = lib +include(../backends.pri) +TARGET = ../ebl_i386 + +SOURCES += \ + ../i386_auxv.c \ + ../i386_cfi.c \ + ../i386_corenote.c \ + ../i386_init.c \ + ../i386_initreg.c \ + ../i386_regs.c \ + ../i386_retval.c \ + ../i386_symbol.c \ + ../i386_syscall.c + +HEADERS += \ + ../i386_reloc.def diff --git a/3rdparty/elfutils/backends/i386_auxv.c b/3rdparty/elfutils/backends/i386_auxv.c new file mode 100644 index 0000000..dba63fe --- /dev/null +++ b/3rdparty/elfutils/backends/i386_auxv.c @@ -0,0 +1,52 @@ +/* i386 specific auxv handling. + Copyright (C) 2007 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND i386_ +#include "libebl_CPU.h" + +int +EBLHOOK(auxv_info) (GElf_Xword a_type, const char **name, const char **format) +{ + if (a_type != AT_HWCAP) + return 0; + + *name = "HWCAP"; + *format = "b" + "fpu\0" "vme\0" "de\0" "pse\0" "tsc\0" "msr\0" "pae\0" "mce\0" + "cx8\0" "apic\0" "10\0" "sep\0" "mtrr\0" "pge\0" "mca\0" "cmov\0" + "pat\0" "pse36\0" "pn\0" "clflush\0" "20\0" "dts\0" "acpi\0" "mmx\0" + "fxsr\0" "sse\0" "sse2\0" "ss\0" "ht\0" "tm\0" "ia64\0" "pbe\0" "\0"; + return 1; +} + +__typeof (i386_auxv_info) x86_64_auxv_info + __attribute__ ((alias ("i386_auxv_info"))); diff --git a/3rdparty/elfutils/backends/i386_cfi.c b/3rdparty/elfutils/backends/i386_cfi.c new file mode 100644 index 0000000..31f85f7 --- /dev/null +++ b/3rdparty/elfutils/backends/i386_cfi.c @@ -0,0 +1,68 @@ +/* i386 ABI-specified defaults for DWARF CFI. + Copyright (C) 2009 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> + +#define BACKEND i386_ +#include "libebl_CPU.h" + +int +i386_abi_cfi (Ebl *ebl __attribute__ ((unused)), Dwarf_CIE *abi_info) +{ + static const uint8_t abi_cfi[] = + { + /* Call-saved regs. */ + DW_CFA_same_value, ULEB128_7 (3), /* %ebx */ + DW_CFA_same_value, ULEB128_7 (5), /* %ebp */ + DW_CFA_same_value, ULEB128_7 (6), /* %esi */ + DW_CFA_same_value, ULEB128_7 (7), /* %edi */ + + /* The CFA is the SP. */ + DW_CFA_val_offset, ULEB128_7 (4), ULEB128_7 (0), + + /* Segment registers are call-saved if ever used at all. */ + DW_CFA_same_value, ULEB128_7 (40), /* %es */ + DW_CFA_same_value, ULEB128_7 (41), /* %cs */ + DW_CFA_same_value, ULEB128_7 (42), /* %ss */ + DW_CFA_same_value, ULEB128_7 (43), /* %ds */ + DW_CFA_same_value, ULEB128_7 (44), /* %fs */ + DW_CFA_same_value, ULEB128_7 (45), /* %gs */ + }; + + abi_info->initial_instructions = abi_cfi; + abi_info->initial_instructions_end = &abi_cfi[sizeof abi_cfi]; + abi_info->data_alignment_factor = 4; + + abi_info->return_address_register = 8; /* %eip */ + + return 0; +} diff --git a/3rdparty/elfutils/backends/i386_corenote.c b/3rdparty/elfutils/backends/i386_corenote.c new file mode 100644 index 0000000..15cd66b --- /dev/null +++ b/3rdparty/elfutils/backends/i386_corenote.c @@ -0,0 +1,138 @@ +/* i386 specific core note handling. + Copyright (C) 2007-2010 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <elf.h> +#include <inttypes.h> +#include <stddef.h> +#include <stdio.h> +#include <sys/time.h> + +#define BACKEND i386_ +#include "libebl_CPU.h" + + +static const Ebl_Register_Location prstatus_regs[] = + { +#define GR(at, n, dwreg) \ + { .offset = at * 4, .regno = dwreg, .count = n, .bits = 32 } +#define SR(at, n, dwreg) \ + { .offset = at * 4, .regno = dwreg, .count = n, .bits = 16, .pad = 2 } + + GR (0, 1, 3), /* %ebx */ + GR (1, 2, 1), /* %ecx-%edx */ + GR (3, 2, 6), /* %esi-%edi */ + GR (5, 1, 5), /* %ebp */ + GR (6, 1, 0), /* %eax */ + SR (7, 1, 43), /* %ds */ + SR (8, 1, 40), /* %es */ + SR (9, 1, 44), /* %fs */ + SR (10, 1, 45), /* %gs */ + /* 11, 1, orig_eax */ + GR (12, 1, 8), /* %eip */ + SR (13, 1, 41), /* %cs */ + GR (14, 1, 9), /* eflags */ + GR (15, 1, 4), /* %esp */ + SR (16, 1, 42), /* %ss */ + +#undef GR +#undef SR + }; +#define PRSTATUS_REGS_SIZE (17 * 4) + +#define ULONG uint32_t +#define PID_T int32_t +#define UID_T uint16_t +#define GID_T uint16_t +#define ALIGN_ULONG 4 +#define ALIGN_PID_T 4 +#define ALIGN_UID_T 2 +#define ALIGN_GID_T 2 +#define TYPE_ULONG ELF_T_WORD +#define TYPE_PID_T ELF_T_SWORD +#define TYPE_UID_T ELF_T_HALF +#define TYPE_GID_T ELF_T_HALF + +#define PRSTATUS_REGSET_ITEMS \ + { \ + .name = "orig_eax", .type = ELF_T_SWORD, .format = 'd', \ + .offset = offsetof (struct EBLHOOK(prstatus), pr_reg) + (4 * 11), \ + .group = "register" \ + } + +static const Ebl_Register_Location fpregset_regs[] = + { + { .offset = 0, .regno = 37, .count = 2, .bits = 32 }, /* fctrl-fstat */ + { .offset = 7 * 4, .regno = 11, .count = 8, .bits = 80 }, /* stN */ + }; +#define FPREGSET_SIZE 108 + +static const Ebl_Register_Location prxfpreg_regs[] = + { + { .offset = 0, .regno = 37, .count = 2, .bits = 16 }, /* fctrl-fstat */ + { .offset = 24, .regno = 39, .count = 1, .bits = 32 }, /* mxcsr */ + { .offset = 32, .regno = 11, .count = 8, .bits = 80, .pad = 6 }, /* stN */ + { .offset = 32 + 128, .regno = 21, .count = 8, .bits = 128 }, /* xmm */ + }; + +#define EXTRA_NOTES \ + EXTRA_REGSET (NT_PRXFPREG, 512, prxfpreg_regs) \ + case NT_386_TLS: \ + return tls_info (nhdr->n_descsz, regs_offset, nregloc, reglocs, \ + nitems, items); \ + EXTRA_NOTES_IOPERM + +static const Ebl_Core_Item tls_items[] = + { + { .type = ELF_T_WORD, .offset = 0x0, .format = 'd', .name = "index" }, + { .type = ELF_T_WORD, .offset = 0x4, .format = 'x', .name = "base" }, + { .type = ELF_T_WORD, .offset = 0x8, .format = 'x', .name = "limit" }, + { .type = ELF_T_WORD, .offset = 0xc, .format = 'x', .name = "flags" }, + }; + +static int +tls_info (GElf_Word descsz, GElf_Word *regs_offset, + size_t *nregloc, const Ebl_Register_Location **reglocs, + size_t *nitems, const Ebl_Core_Item **items) +{ + if (descsz % 16 != 0) + return 0; + + *regs_offset = 0; + *nregloc = 0; + *reglocs = NULL; + *nitems = sizeof tls_items / sizeof tls_items[0]; + *items = tls_items; + return 1; +} + +#include "x86_corenote.c" +#include "linux-core-note.c" diff --git a/3rdparty/elfutils/backends/i386_init.c b/3rdparty/elfutils/backends/i386_init.c new file mode 100644 index 0000000..1e0b486 --- /dev/null +++ b/3rdparty/elfutils/backends/i386_init.c @@ -0,0 +1,71 @@ +/* Initialization of i386 specific backend library. + Copyright (C) 2000-2009, 2013 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND i386_ +#define RELOC_PREFIX R_386_ +#include "libebl_CPU.h" + +/* This defines the common reloc hooks based on i386_reloc.def. */ +#include "common-reloc.c" + +const char * +i386_init (elf, machine, eh, ehlen) + Elf *elf __attribute__ ((unused)); + GElf_Half machine __attribute__ ((unused)); + Ebl *eh; + size_t ehlen; +{ + /* Check whether the Elf_BH object has a sufficent size. */ + if (ehlen < sizeof (Ebl)) + return NULL; + + /* We handle it. */ + eh->name = "Intel 80386"; + i386_init_reloc (eh); + HOOK (eh, reloc_simple_type); + HOOK (eh, gotpc_reloc_check); + HOOK (eh, core_note); + generic_debugscn_p = eh->debugscn_p; + HOOK (eh, debugscn_p); + HOOK (eh, return_value_location); + HOOK (eh, register_info); + HOOK (eh, syscall_abi); + HOOK (eh, auxv_info); + HOOK (eh, disasm); + HOOK (eh, abi_cfi); + /* gcc/config/ #define DWARF_FRAME_REGISTERS. For i386 it is 17, why? */ + eh->frame_nregs = 9; + HOOK (eh, set_initial_registers_tid); + + return MODVERSION; +} diff --git a/3rdparty/elfutils/backends/i386_initreg.c b/3rdparty/elfutils/backends/i386_initreg.c new file mode 100644 index 0000000..51fd9ea --- /dev/null +++ b/3rdparty/elfutils/backends/i386_initreg.c @@ -0,0 +1,79 @@ +/* Fetch live process registers from TID. + Copyright (C) 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#if defined __i386__ || defined __x86_64__ +# include <sys/types.h> +# include <sys/user.h> +# include <sys/ptrace.h> +#endif + +#define BACKEND i386_ +#include "libebl_CPU.h" + +bool +i386_set_initial_registers_tid (pid_t tid __attribute__ ((unused)), + ebl_tid_registers_t *setfunc __attribute__ ((unused)), + void *arg __attribute__ ((unused))) +{ +#if (!defined __i386__ && !defined __x86_64__) || !defined(__linux__) + return false; +#else /* __i386__ || __x86_64__ */ + struct user_regs_struct user_regs; + if (ptrace (PTRACE_GETREGS, tid, NULL, &user_regs) != 0) + return false; + Dwarf_Word dwarf_regs[9]; +# if defined __i386__ + dwarf_regs[0] = user_regs.eax; + dwarf_regs[1] = user_regs.ecx; + dwarf_regs[2] = user_regs.edx; + dwarf_regs[3] = user_regs.ebx; + dwarf_regs[4] = user_regs.esp; + dwarf_regs[5] = user_regs.ebp; + dwarf_regs[6] = user_regs.esi; + dwarf_regs[7] = user_regs.edi; + dwarf_regs[8] = user_regs.eip; +# elif defined __x86_64__ + dwarf_regs[0] = user_regs.rax; + dwarf_regs[1] = user_regs.rcx; + dwarf_regs[2] = user_regs.rdx; + dwarf_regs[3] = user_regs.rbx; + dwarf_regs[4] = user_regs.rsp; + dwarf_regs[5] = user_regs.rbp; + dwarf_regs[6] = user_regs.rsi; + dwarf_regs[7] = user_regs.rdi; + dwarf_regs[8] = user_regs.rip; +# else /* (__i386__ || __x86_64__) && (!__i386__ && !__x86_64__) */ +# error "source file error, it cannot happen" +# endif /* (__i386__ || __x86_64__) && (!__i386__ && !__x86_64__) */ + return setfunc (0, 9, dwarf_regs, arg); +#endif /* __i386__ || __x86_64__ */ +} diff --git a/3rdparty/elfutils/backends/i386_regs.c b/3rdparty/elfutils/backends/i386_regs.c new file mode 100644 index 0000000..fb8ded3 --- /dev/null +++ b/3rdparty/elfutils/backends/i386_regs.c @@ -0,0 +1,152 @@ +/* Register names and numbers for i386 DWARF. + Copyright (C) 2005, 2006, 2007 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> +#include <dwarf.h> + +#define BACKEND i386_ +#include "libebl_CPU.h" + +ssize_t +i386_register_info (Ebl *ebl __attribute__ ((unused)), + int regno, char *name, size_t namelen, + const char **prefix, const char **setname, + int *bits, int *type) +{ + if (name == NULL) + return 46; + + if (regno < 0 || regno > 45 || namelen < 6) + return -1; + + *prefix = "%"; + *bits = 32; + *type = DW_ATE_unsigned; + if (regno < 11) + { + *setname = "integer"; + if (regno < 9) + *type = DW_ATE_signed; + } + else if (regno < 19) + { + *setname = "x87"; + *type = DW_ATE_float; + *bits = 80; + } + else if (regno < 29) + { + *setname = "SSE"; + *bits = 128; + } + else if (regno < 37) + { + *setname = "MMX"; + *bits = 64; + } + else if (regno < 40) + *setname = "FPU-control"; + else + { + *setname = "segment"; + *bits = 16; + } + + switch (regno) + { + static const char baseregs[][2] = + { + "ax", "cx", "dx", "bx", "sp", "bp", "si", "di", "ip" + }; + + case 4: + case 5: + case 8: + *type = DW_ATE_address; + case 0 ... 3: + case 6 ... 7: + name[0] = 'e'; + name[1] = baseregs[regno][0]; + name[2] = baseregs[regno][1]; + namelen = 3; + break; + + case 9: + return stpcpy (name, "eflags") + 1 - name; + case 10: + return stpcpy (name, "trapno") + 1 - name; + + case 11 ... 18: + name[0] = 's'; + name[1] = 't'; + name[2] = regno - 11 + '0'; + namelen = 3; + break; + + case 21 ... 28: + name[0] = 'x'; + name[1] = 'm'; + name[2] = 'm'; + name[3] = regno - 21 + '0'; + namelen = 4; + break; + + case 29 ... 36: + name[0] = 'm'; + name[1] = 'm'; + name[2] = regno - 29 + '0'; + namelen = 3; + break; + + case 37: + *bits = 16; + return stpcpy (name, "fctrl") + 1 - name; + case 38: + *bits = 16; + return stpcpy (name, "fstat") + 1 - name; + case 39: + return stpcpy (name, "mxcsr") + 1 - name; + + case 40 ... 45: + name[0] = "ecsdfg"[regno - 40]; + name[1] = 's'; + namelen = 2; + break; + + default: + *setname = NULL; + return 0; + } + + name[namelen++] = '\0'; + return namelen; +} diff --git a/3rdparty/elfutils/backends/i386_reloc.def b/3rdparty/elfutils/backends/i386_reloc.def new file mode 100644 index 0000000..bd273b3 --- /dev/null +++ b/3rdparty/elfutils/backends/i386_reloc.def @@ -0,0 +1,70 @@ +/* List the relocation types for i386. -*- C -*- + Copyright (C) 2000, 2001, 2002, 2003, 2005, 2009 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +/* NAME, REL|EXEC|DYN */ + +RELOC_TYPE (NONE, 0) +RELOC_TYPE (COPY, EXEC) +RELOC_TYPE (32, REL|EXEC|DYN) +RELOC_TYPE (PC32, REL|EXEC|DYN) +RELOC_TYPE (GOT32, REL) +RELOC_TYPE (PLT32, REL) +RELOC_TYPE (GLOB_DAT, EXEC|DYN) +RELOC_TYPE (JMP_SLOT, EXEC|DYN) +RELOC_TYPE (RELATIVE, EXEC|DYN) +RELOC_TYPE (GOTOFF, REL) +RELOC_TYPE (GOTPC, REL) +RELOC_TYPE (32PLT, REL) +RELOC_TYPE (TLS_TPOFF, EXEC|DYN) +RELOC_TYPE (TLS_IE, REL) +RELOC_TYPE (TLS_GOTIE, REL) +RELOC_TYPE (TLS_LE, REL) +RELOC_TYPE (TLS_GD, REL) +RELOC_TYPE (TLS_LDM, REL) +RELOC_TYPE (16, REL) +RELOC_TYPE (PC16, REL) +RELOC_TYPE (8, REL) +RELOC_TYPE (PC8, REL) +RELOC_TYPE (TLS_GD_32, REL) +RELOC_TYPE (TLS_GD_PUSH, REL) +RELOC_TYPE (TLS_GD_CALL, REL) +RELOC_TYPE (TLS_GD_POP, REL) +RELOC_TYPE (TLS_LDM_32, REL) +RELOC_TYPE (TLS_LDM_PUSH, REL) +RELOC_TYPE (TLS_LDM_CALL, REL) +RELOC_TYPE (TLS_LDM_POP, REL) +RELOC_TYPE (TLS_LDO_32, REL) +RELOC_TYPE (TLS_IE_32, REL) +RELOC_TYPE (TLS_LE_32, REL) +RELOC_TYPE (TLS_DTPMOD32, EXEC|DYN) +RELOC_TYPE (TLS_DTPOFF32, EXEC|DYN) +RELOC_TYPE (TLS_TPOFF32, EXEC|DYN) +RELOC_TYPE (TLS_GOTDESC, REL) +RELOC_TYPE (TLS_DESC_CALL, REL) +RELOC_TYPE (TLS_DESC, EXEC) +RELOC_TYPE (IRELATIVE, EXEC|DYN) diff --git a/3rdparty/elfutils/backends/i386_retval.c b/3rdparty/elfutils/backends/i386_retval.c new file mode 100644 index 0000000..9da797d --- /dev/null +++ b/3rdparty/elfutils/backends/i386_retval.c @@ -0,0 +1,141 @@ +/* Function return value location for Linux/i386 ABI. + Copyright (C) 2005-2010, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> + +#define BACKEND i386_ +#include "libebl_CPU.h" + + +/* %eax, or pair %eax, %edx. */ +static const Dwarf_Op loc_intreg[] = + { + { .atom = DW_OP_reg0 }, { .atom = DW_OP_piece, .number = 4 }, + { .atom = DW_OP_reg2 }, { .atom = DW_OP_piece, .number = 4 }, + }; +#define nloc_intreg 1 +#define nloc_intregpair 4 + +/* %st(0). */ +static const Dwarf_Op loc_fpreg[] = + { + { .atom = DW_OP_reg11 } + }; +#define nloc_fpreg 1 + +/* The return value is a structure and is actually stored in stack space + passed in a hidden argument by the caller. But, the compiler + helpfully returns the address of that space in %eax. */ +static const Dwarf_Op loc_aggregate[] = + { + { .atom = DW_OP_breg0, .number = 0 } + }; +#define nloc_aggregate 1 + +int +i386_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp) +{ + /* Start with the function's type, and get the DW_AT_type attribute, + which is the type of the return value. */ + Dwarf_Die die_mem, *typedie = &die_mem; + int tag = dwarf_peeled_die_type (functypedie, typedie); + if (tag <= 0) + return tag; + + switch (tag) + { + case -1: + return -1; + + case DW_TAG_subrange_type: + if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size)) + { + Dwarf_Attribute attr_mem, *attr; + attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem); + typedie = dwarf_formref_die (attr, &die_mem); + tag = DWARF_TAG_OR_RETURN (typedie); + } + /* Fall through. */ + + case DW_TAG_base_type: + case DW_TAG_enumeration_type: + case DW_TAG_pointer_type: + case DW_TAG_ptr_to_member_type: + { + Dwarf_Word size; + Dwarf_Attribute attr_mem; + if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size, + &attr_mem), &size) != 0) + { + if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type) + size = 4; + else + return -1; + } + if (tag == DW_TAG_base_type) + { + Dwarf_Word encoding; + if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding, + &attr_mem), + &encoding) != 0) + return -1; + if (encoding == DW_ATE_float) + { + if (size > 16) + return -2; + *locp = loc_fpreg; + return nloc_fpreg; + } + } + *locp = loc_intreg; + if (size <= 4) + return nloc_intreg; + if (size <= 8) + return nloc_intregpair; + + /* Else fall through. */ + } + + case DW_TAG_structure_type: + case DW_TAG_class_type: + case DW_TAG_union_type: + case DW_TAG_array_type: + *locp = loc_aggregate; + return nloc_aggregate; + } + + /* XXX We don't have a good way to return specific errors from ebl calls. + This value means we do not understand the type, but it is well-formed + DWARF and might be valid. */ + return -2; +} diff --git a/3rdparty/elfutils/backends/i386_symbol.c b/3rdparty/elfutils/backends/i386_symbol.c new file mode 100644 index 0000000..7dbf899 --- /dev/null +++ b/3rdparty/elfutils/backends/i386_symbol.c @@ -0,0 +1,75 @@ +/* i386 specific symbolic name handling. + Copyright (C) 2000, 2001, 2002, 2005 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <elf.h> +#include <stddef.h> +#include <string.h> + +#define BACKEND i386_ +#include "libebl_CPU.h" + + +/* Return true if the symbol type is that referencing the GOT. */ +bool +i386_gotpc_reloc_check (Elf *elf __attribute__ ((unused)), int type) +{ + return type == R_386_GOTPC; +} + +/* Check for the simple reloc types. */ +Elf_Type +i386_reloc_simple_type (Ebl *ebl __attribute__ ((unused)), int type) +{ + switch (type) + { + case R_386_32: + return ELF_T_SWORD; + case R_386_16: + return ELF_T_HALF; + case R_386_8: + return ELF_T_BYTE; + default: + return ELF_T_NUM; + } +} + +/* Check section name for being that of a debug information section. */ +bool (*generic_debugscn_p) (const char *); +bool +i386_debugscn_p (const char *name) +{ + return (generic_debugscn_p (name) + || strcmp (name, ".stab") == 0 + || strcmp (name, ".stabstr") == 0); +} diff --git a/3rdparty/elfutils/backends/i386_syscall.c b/3rdparty/elfutils/backends/i386_syscall.c new file mode 100644 index 0000000..535dcd8 --- /dev/null +++ b/3rdparty/elfutils/backends/i386_syscall.c @@ -0,0 +1,50 @@ +/* Linux/i386 system call ABI in DWARF register numbers. + Copyright (C) 2008 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND i386_ +#include "libebl_CPU.h" + +int +i386_syscall_abi (Ebl *ebl __attribute__ ((unused)), + int *sp, int *pc, int *callno, int args[6]) +{ + *sp = 4; /* %esp */ + *pc = 8; /* %eip */ + *callno = 0; /* %eax */ + args[0] = 3; /* %ebx */ + args[1] = 1; /* %ecx */ + args[2] = 2; /* %edx */ + args[3] = 6; /* %esi */ + args[4] = 7; /* %edi */ + args[5] = 5; /* %ebp */ + return 0; +} diff --git a/3rdparty/elfutils/backends/ia64/ia64.pro b/3rdparty/elfutils/backends/ia64/ia64.pro new file mode 100644 index 0000000..383e869 --- /dev/null +++ b/3rdparty/elfutils/backends/ia64/ia64.pro @@ -0,0 +1,12 @@ +TEMPLATE = lib +include(../backends.pri) +TARGET = ../ebl_ia64 + +SOURCES += \ + ../ia64_init.c \ + ../ia64_regs.c \ + ../ia64_retval.c \ + ../ia64_symbol.c + +HEADERS += \ + ../ia64_reloc.def diff --git a/3rdparty/elfutils/backends/ia64_init.c b/3rdparty/elfutils/backends/ia64_init.c new file mode 100644 index 0000000..91da748 --- /dev/null +++ b/3rdparty/elfutils/backends/ia64_init.c @@ -0,0 +1,67 @@ +/* Initialization of IA-64 specific backend library. + Copyright (C) 2002, 2003, 2005, 2006, 2007, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND ia64_ +#define RELOC_PREFIX R_IA64_ +#include "libebl_CPU.h" + +/* This defines the common reloc hooks based on ia64_reloc.def. */ +#include "common-reloc.c" + +const char * +ia64_init (elf, machine, eh, ehlen) + Elf *elf __attribute__ ((unused)); + GElf_Half machine __attribute__ ((unused)); + Ebl *eh; + size_t ehlen; +{ + /* Check whether the Elf_BH object has a sufficent size. */ + if (ehlen < sizeof (Ebl)) + return NULL; + + /* We handle it. */ + eh->name = "Intel IA-64"; + ia64_init_reloc (eh); + HOOK (eh, reloc_simple_type); + HOOK (eh, segment_type_name); + HOOK (eh, section_type_name); + HOOK (eh, dynamic_tag_name); + HOOK (eh, dynamic_tag_check); + HOOK (eh, machine_flag_check); + HOOK (eh, machine_section_flag_check); + HOOK (eh, register_info); + HOOK (eh, return_value_location); + HOOK (eh, check_reloc_target_type); + + return MODVERSION; +} diff --git a/3rdparty/elfutils/backends/ia64_regs.c b/3rdparty/elfutils/backends/ia64_regs.c new file mode 100644 index 0000000..a27fe63 --- /dev/null +++ b/3rdparty/elfutils/backends/ia64_regs.c @@ -0,0 +1,273 @@ +/* Register names and numbers for IA64 DWARF. + Copyright (C) 2006 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> +#include <dwarf.h> + +#define BACKEND i386_ +#include "libebl_CPU.h" + +ssize_t +ia64_register_info (Ebl *ebl __attribute__ ((unused)), + int regno, char *name, size_t namelen, + const char **prefix, const char **setname, + int *bits, int *type) +{ + if (name == NULL) + return 687 + 64; + + if (regno < 0 || regno > 687 + 63 || namelen < 12) + return -1; + + *prefix = "ar."; + *setname = "application"; + *bits = 64; + *type = DW_ATE_signed; + switch (regno) + { + case 0 ... 9: + name[0] = 'r'; + name[1] = (regno - 0) + '0'; + namelen = 2; + *setname = "integer"; + *prefix = ""; + break; + + case 10 ... 99: + name[0] = 'r'; + name[1] = (regno - 0) / 10 + '0'; + name[2] = (regno - 0) % 10 + '0'; + namelen = 3; + *setname = "integer"; + *prefix = ""; + break; + + case 100 ... 127: + name[0] = 'r'; + name[1] = '1'; + name[2] = (regno - 100) / 10 + '0'; + name[3] = (regno - 0) % 10 + '0'; + namelen = 4; + *setname = "integer"; + *prefix = ""; + break; + + case 128 + 0 ... 128 + 9: + name[0] = 'f'; + name[1] = (regno - 128) + '0'; + namelen = 2; + *type = DW_ATE_float; + *bits = 128; + *setname = "FPU"; + *prefix = ""; + break; + + case 128 + 10 ... 128 + 99: + name[0] = 'f'; + name[1] = (regno - 128) / 10 + '0'; + name[2] = (regno - 128) % 10 + '0'; + namelen = 3; + *setname = "FPU"; + *prefix = ""; + break; + + case 128 + 100 ... 128 + 127: + name[0] = 'f'; + name[1] = '1'; + name[2] = (regno - 128 - 100) / 10 + '0'; + name[3] = (regno - 128) % 10 + '0'; + namelen = 4; + *type = DW_ATE_float; + *bits = 128; + *setname = "FPU"; + *prefix = ""; + break; + + case 320 + 0 ... 320 + 7: + name[0] = 'b'; + name[1] = (regno - 320) + '0'; + namelen = 2; + *type = DW_ATE_address; + *setname = "branch"; + *prefix = ""; + break; + + case 328 ... 333: + { + static const char named_special[][5] = + { + "vfp", "vrap", "pr", "ip", "psr", "cfm" + }; + *setname = "special"; + *prefix = ""; + *type = regno == 331 ? DW_ATE_address : DW_ATE_unsigned; + return stpcpy (name, named_special[regno - 328]) + 1 - name; + } + + case 590: + *setname = "special"; + *prefix = ""; + *type = DW_ATE_unsigned; + return stpcpy (name, "bof") + 1 - name; + + case 334 + 0 ... 334 + 7: + name[0] = 'k'; + name[1] = 'r'; + name[2] = (regno - 334) + '0'; + namelen = 3; + *prefix = ""; + break; + + case 334 + 8 ... 334 + 127: + { + static const char named_ar[][9] = + { + [16 - 8] = "rsc", + [17 - 8] = "bsp", + [18 - 8] = "bspstore", + [19 - 8] = "rnat", + [21 - 8] = "fcr", + [24 - 8] = "eflag", + [25 - 8] = "csd", + [26 - 8] = "ssd", + [27 - 8] = "cflg", + [28 - 8] = "fsr", + [29 - 8] = "fir", + [30 - 8] = "fdr", + [32 - 8] = "ccv", + [36 - 8] = "unat", + [40 - 8] = "fpsr", + [44 - 8] = "itc", + [64 - 8] = "pfs", + [65 - 8] = "lc", + [66 - 8] = "ec", + }; + const size_t idx = regno - (334 + 8); + *type = DW_ATE_unsigned; + if (idx == 1 || idx == 2) + *type = DW_ATE_address; + if (idx < sizeof named_ar / sizeof named_ar[0] + && named_ar[idx][0] != '\0') + return stpcpy (name, named_ar[idx]) + 1 - name; + + name[0] = 'a'; + name[1] = 'r'; + switch (regno - 334) + { + case 0 ... 9: + name[2] = (regno - 334) + '0'; + namelen = 3; + break; + case 10 ... 99: + name[2] = (regno - 334) / 10 + '0'; + name[3] = (regno - 334) % 10 + '0'; + namelen = 4; + break; + case 100 ... 127: + name[2] = '1'; + name[3] = (regno - 334 - 100) / 10 + '0'; + name[4] = (regno - 334) % 10 + '0'; + namelen = 5; + break; + } + *prefix = ""; + break; + } + + case 462 + 0 ... 462 + 9: + name[0] = 'n'; + name[1] = 'a'; + name[2] = 't'; + name[3] = (regno - 462) + '0'; + namelen = 4; + *setname = "NAT"; + *type = DW_ATE_boolean; + *bits = 1; + *prefix = ""; + break; + + case 462 + 10 ... 462 + 99: + name[0] = 'n'; + name[1] = 'a'; + name[2] = 't'; + name[3] = (regno - 462) / 10 + '0'; + name[4] = (regno - 462) % 10 + '0'; + namelen = 5; + *setname = "NAT"; + *type = DW_ATE_boolean; + *bits = 1; + *prefix = ""; + break; + + case 462 + 100 ... 462 + 127: + name[0] = 'n'; + name[1] = 'a'; + name[2] = 't'; + name[3] = '1'; + name[4] = (regno - 462 - 100) / 10 + '0'; + name[5] = (regno - 462) % 10 + '0'; + namelen = 6; + *setname = "NAT"; + *type = DW_ATE_boolean; + *bits = 1; + *prefix = ""; + break; + + case 687 + 0 ... 687 + 9: + name[0] = 'p'; + name[1] = (regno - 687) + '0'; + namelen = 2; + *setname = "predicate"; + *type = DW_ATE_boolean; + *bits = 1; + *prefix = ""; + break; + + case 687 + 10 ... 687 + 63: + name[0] = 'p'; + name[1] = (regno - 687) / 10 + '0'; + name[2] = (regno - 687) % 10 + '0'; + namelen = 3; + *setname = "predicate"; + *type = DW_ATE_boolean; + *bits = 1; + *prefix = ""; + break; + + default: + *setname = NULL; + return 0; + } + + name[namelen++] = '\0'; + return namelen; +} diff --git a/3rdparty/elfutils/backends/ia64_reloc.def b/3rdparty/elfutils/backends/ia64_reloc.def new file mode 100644 index 0000000..9e058c8 --- /dev/null +++ b/3rdparty/elfutils/backends/ia64_reloc.def @@ -0,0 +1,113 @@ +/* List the relocation types for ia64. -*- C -*- + Copyright (C) 2005, 2006 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +/* NAME, REL|EXEC|DYN */ + +RELOC_TYPE (NONE, 0) +RELOC_TYPE (IMM14, REL) +RELOC_TYPE (IMM22, REL) +RELOC_TYPE (IMM64, REL) +RELOC_TYPE (DIR32MSB, REL|EXEC|DYN) +RELOC_TYPE (DIR32LSB, REL|EXEC|DYN) +RELOC_TYPE (DIR64MSB, REL|EXEC|DYN) +RELOC_TYPE (DIR64LSB, REL|EXEC|DYN) +RELOC_TYPE (GPREL22, REL) +RELOC_TYPE (GPREL64I, REL) +RELOC_TYPE (GPREL32MSB, REL) +RELOC_TYPE (GPREL32LSB, REL) +RELOC_TYPE (GPREL64MSB, REL) +RELOC_TYPE (GPREL64LSB, REL) +RELOC_TYPE (LTOFF22, REL) +RELOC_TYPE (LTOFF64I, REL) +RELOC_TYPE (PLTOFF22, REL) +RELOC_TYPE (PLTOFF64I, REL) +RELOC_TYPE (PLTOFF64MSB, REL) +RELOC_TYPE (PLTOFF64LSB, REL) +RELOC_TYPE (FPTR64I, REL) +RELOC_TYPE (FPTR32MSB, REL|EXEC|DYN) +RELOC_TYPE (FPTR32LSB, REL|EXEC|DYN) +RELOC_TYPE (FPTR64MSB, REL|EXEC|DYN) +RELOC_TYPE (FPTR64LSB, REL|EXEC|DYN) +RELOC_TYPE (PCREL60B, REL) +RELOC_TYPE (PCREL21B, REL) +RELOC_TYPE (PCREL21M, REL) +RELOC_TYPE (PCREL21F, REL) +RELOC_TYPE (PCREL32MSB, REL|EXEC|DYN) +RELOC_TYPE (PCREL32LSB, REL|EXEC|DYN) +RELOC_TYPE (PCREL64MSB, REL|EXEC|DYN) +RELOC_TYPE (PCREL64LSB, REL|EXEC|DYN) +RELOC_TYPE (LTOFF_FPTR22, REL) +RELOC_TYPE (LTOFF_FPTR64I, REL) +RELOC_TYPE (LTOFF_FPTR32MSB, REL) +RELOC_TYPE (LTOFF_FPTR32LSB, REL) +RELOC_TYPE (LTOFF_FPTR64MSB, REL) +RELOC_TYPE (LTOFF_FPTR64LSB, REL) +RELOC_TYPE (SEGREL32MSB, REL) +RELOC_TYPE (SEGREL32LSB, REL) +RELOC_TYPE (SEGREL64MSB, REL) +RELOC_TYPE (SEGREL64LSB, REL) +RELOC_TYPE (SECREL32MSB, REL) +RELOC_TYPE (SECREL32LSB, REL) +RELOC_TYPE (SECREL64MSB, REL) +RELOC_TYPE (SECREL64LSB, REL) +RELOC_TYPE (REL32MSB, EXEC|DYN) +RELOC_TYPE (REL32LSB, EXEC|DYN) +RELOC_TYPE (REL64MSB, EXEC|DYN) +RELOC_TYPE (REL64LSB, EXEC|DYN) +RELOC_TYPE (LTV32MSB, REL) +RELOC_TYPE (LTV32LSB, REL) +RELOC_TYPE (LTV64MSB, REL) +RELOC_TYPE (LTV64LSB, REL) +RELOC_TYPE (PCREL21BI, REL) +RELOC_TYPE (PCREL22, REL) +RELOC_TYPE (PCREL64I, REL) +RELOC_TYPE (IPLTMSB, REL|EXEC|DYN) +RELOC_TYPE (IPLTLSB, REL|EXEC|DYN) +RELOC_TYPE (COPY, EXEC) +RELOC_TYPE (SUB, 0) +RELOC_TYPE (LTOFF22X, REL) +RELOC_TYPE (LDXMOV, REL) +RELOC_TYPE (TPREL14, REL) +RELOC_TYPE (TPREL22, REL) +RELOC_TYPE (TPREL64I, REL) +RELOC_TYPE (TPREL64MSB, REL|EXEC|DYN) +RELOC_TYPE (TPREL64LSB, REL|EXEC|DYN) +RELOC_TYPE (LTOFF_TPREL22, REL) +RELOC_TYPE (DTPMOD64MSB, REL|EXEC|DYN) +RELOC_TYPE (DTPMOD64LSB, REL|EXEC|DYN) +RELOC_TYPE (LTOFF_DTPMOD22, REL) +RELOC_TYPE (DTPREL14, REL) +RELOC_TYPE (DTPREL22, REL) +RELOC_TYPE (DTPREL64I, REL) +RELOC_TYPE (DTPREL32MSB, REL|EXEC|DYN) +RELOC_TYPE (DTPREL32LSB, REL|EXEC|DYN) +RELOC_TYPE (DTPREL64MSB, REL|EXEC|DYN) +RELOC_TYPE (DTPREL64LSB, REL|EXEC|DYN) +RELOC_TYPE (LTOFF_DTPREL22, REL) + +#define NO_RELATIVE_RELOC 1 diff --git a/3rdparty/elfutils/backends/ia64_retval.c b/3rdparty/elfutils/backends/ia64_retval.c new file mode 100644 index 0000000..b5928c5 --- /dev/null +++ b/3rdparty/elfutils/backends/ia64_retval.c @@ -0,0 +1,363 @@ +/* Function return value location for IA64 ABI. + Copyright (C) 2006-2010, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> + +#define BACKEND ia64_ +#include "libebl_CPU.h" + + +/* r8, or pair r8, r9, or aggregate up to r8-r11. */ +static const Dwarf_Op loc_intreg[] = + { + { .atom = DW_OP_reg8 }, { .atom = DW_OP_piece, .number = 8 }, + { .atom = DW_OP_reg9 }, { .atom = DW_OP_piece, .number = 8 }, + { .atom = DW_OP_reg10 }, { .atom = DW_OP_piece, .number = 8 }, + { .atom = DW_OP_reg11 }, { .atom = DW_OP_piece, .number = 8 }, + }; +#define nloc_intreg 1 +#define nloc_intregs(n) (2 * (n)) + +/* f8, or aggregate up to f8-f15. */ +#define DEFINE_FPREG(size) \ + static const Dwarf_Op loc_fpreg_##size[] = \ + { \ + { .atom = DW_OP_regx, .number = 128 + 8 }, \ + { .atom = DW_OP_piece, .number = size }, \ + { .atom = DW_OP_regx, .number = 128 + 9 }, \ + { .atom = DW_OP_piece, .number = size }, \ + { .atom = DW_OP_regx, .number = 128 + 10 }, \ + { .atom = DW_OP_piece, .number = size }, \ + { .atom = DW_OP_regx, .number = 128 + 11 }, \ + { .atom = DW_OP_piece, .number = size }, \ + { .atom = DW_OP_regx, .number = 128 + 12 }, \ + { .atom = DW_OP_piece, .number = size }, \ + { .atom = DW_OP_regx, .number = 128 + 13 }, \ + { .atom = DW_OP_piece, .number = size }, \ + { .atom = DW_OP_regx, .number = 128 + 14 }, \ + { .atom = DW_OP_piece, .number = size }, \ + { .atom = DW_OP_regx, .number = 128 + 15 }, \ + { .atom = DW_OP_piece, .number = size }, \ + } +#define nloc_fpreg 1 +#define nloc_fpregs(n) (2 * (n)) + +DEFINE_FPREG (4); +DEFINE_FPREG (8); +DEFINE_FPREG (10); + +#undef DEFINE_FPREG + + +/* The return value is a structure and is actually stored in stack space + passed in a hidden argument by the caller. But, the compiler + helpfully returns the address of that space in r8. */ +static const Dwarf_Op loc_aggregate[] = + { + { .atom = DW_OP_breg8, .number = 0 } + }; +#define nloc_aggregate 1 + + +/* If this type is an HFA small enough to be returned in FP registers, + return the number of registers to use. Otherwise 9, or -1 for errors. */ +static int +hfa_type (Dwarf_Die *typedie, Dwarf_Word size, + const Dwarf_Op **locp, int fpregs_used) +{ + /* Descend the type structure, counting elements and finding their types. + If we find a datum that's not an FP type (and not quad FP), punt. + If we find a datum that's not the same FP type as the first datum, punt. + If we count more than eight total homogeneous FP data, punt. */ + + inline int hfa (const Dwarf_Op *loc, int nregs) + { + if (fpregs_used == 0) + *locp = loc; + else if (*locp != loc) + return 9; + return fpregs_used + nregs; + } + + int tag = DWARF_TAG_OR_RETURN (typedie); + switch (tag) + { + Dwarf_Attribute attr_mem; + + case -1: + return -1; + + case DW_TAG_base_type:; + Dwarf_Word encoding; + if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding, + &attr_mem), &encoding) != 0) + return -1; + + switch (encoding) + { + case DW_ATE_float: + switch (size) + { + case 4: /* float */ + return hfa (loc_fpreg_4, 1); + case 8: /* double */ + return hfa (loc_fpreg_8, 1); + case 10: /* x86-style long double, not really used */ + return hfa (loc_fpreg_10, 1); + } + break; + + case DW_ATE_complex_float: + switch (size) + { + case 4 * 2: /* complex float */ + return hfa (loc_fpreg_4, 2); + case 8 * 2: /* complex double */ + return hfa (loc_fpreg_8, 2); + case 10 * 2: /* complex long double (x86-style) */ + return hfa (loc_fpreg_10, 2); + } + break; + } + break; + + case DW_TAG_structure_type: + case DW_TAG_class_type: + case DW_TAG_union_type:; + Dwarf_Die child_mem; + switch (dwarf_child (typedie, &child_mem)) + { + default: + return -1; + + case 1: /* No children: empty struct. */ + break; + + case 0:; /* Look at each element. */ + int max_used = fpregs_used; + do + switch (dwarf_tag (&child_mem)) + { + case -1: + return -1; + + case DW_TAG_member:; + Dwarf_Die child_type_mem; + Dwarf_Die *child_typedie + = dwarf_formref_die (dwarf_attr_integrate (&child_mem, + DW_AT_type, + &attr_mem), + &child_type_mem); + Dwarf_Word child_size; + if (dwarf_aggregate_size (child_typedie, &child_size) != 0) + return -1; + if (tag == DW_TAG_union_type) + { + int used = hfa_type (child_typedie, child_size, + locp, fpregs_used); + if (used < 0 || used > 8) + return used; + if (used > max_used) + max_used = used; + } + else + { + fpregs_used = hfa_type (child_typedie, child_size, + locp, fpregs_used); + if (fpregs_used < 0 || fpregs_used > 8) + return fpregs_used; + } + } + while (dwarf_siblingof (&child_mem, &child_mem) == 0); + if (tag == DW_TAG_union_type) + fpregs_used = max_used; + break; + } + break; + + case DW_TAG_array_type: + if (size == 0) + break; + + Dwarf_Die base_type_mem; + Dwarf_Die *base_typedie + = dwarf_formref_die (dwarf_attr_integrate (typedie, DW_AT_type, + &attr_mem), + &base_type_mem); + Dwarf_Word base_size; + if (dwarf_aggregate_size (base_typedie, &base_size) != 0) + return -1; + + int used = hfa_type (base_typedie, base_size, locp, 0); + if (used < 0 || used > 8) + return used; + if (size % (*locp)[1].number != 0) + return 0; + fpregs_used += used * (size / (*locp)[1].number); + break; + + default: + return 9; + } + + return fpregs_used; +} + +int +ia64_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp) +{ + /* Start with the function's type, and get the DW_AT_type attribute, + which is the type of the return value. */ + Dwarf_Die die_mem, *typedie = &die_mem; + int tag = dwarf_peeled_die_type (functypedie, typedie); + if (tag <= 0) + return tag; + + Dwarf_Word size; + switch (tag) + { + case -1: + return -1; + + case DW_TAG_subrange_type: + if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size)) + { + Dwarf_Attribute attr_mem, *attr; + attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem); + typedie = dwarf_formref_die (attr, &die_mem); + tag = DWARF_TAG_OR_RETURN (typedie); + } + /* Fall through. */ + + case DW_TAG_base_type: + case DW_TAG_enumeration_type: + case DW_TAG_pointer_type: + case DW_TAG_ptr_to_member_type: + { + Dwarf_Attribute attr_mem; + if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size, + &attr_mem), &size) != 0) + { + if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type) + size = 8; + else + return -1; + } + } + + if (tag == DW_TAG_base_type) + { + Dwarf_Attribute attr_mem; + Dwarf_Word encoding; + if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding, + &attr_mem), + &encoding) != 0) + return -1; + + switch (encoding) + { + case DW_ATE_float: + switch (size) + { + case 4: /* float */ + *locp = loc_fpreg_4; + return nloc_fpreg; + case 8: /* double */ + *locp = loc_fpreg_8; + return nloc_fpreg; + case 10: /* x86-style long double, not really used */ + *locp = loc_fpreg_10; + return nloc_fpreg; + case 16: /* long double, IEEE quad format */ + *locp = loc_intreg; + return nloc_intregs (2); + } + return -2; + + case DW_ATE_complex_float: + switch (size) + { + case 4 * 2: /* complex float */ + *locp = loc_fpreg_4; + return nloc_fpregs (2); + case 8 * 2: /* complex double */ + *locp = loc_fpreg_8; + return nloc_fpregs (2); + case 10 * 2: /* complex long double (x86-style) */ + *locp = loc_fpreg_10; + return nloc_fpregs (2); + case 16 * 2: /* complex long double (IEEE quad) */ + *locp = loc_intreg; + return nloc_intregs (4); + } + return -2; + } + } + + intreg: + *locp = loc_intreg; + if (size <= 8) + return nloc_intreg; + if (size <= 32) + return nloc_intregs ((size + 7) / 8); + + large: + *locp = loc_aggregate; + return nloc_aggregate; + + case DW_TAG_structure_type: + case DW_TAG_class_type: + case DW_TAG_union_type: + case DW_TAG_array_type: + if (dwarf_aggregate_size (typedie, &size) != 0) + return -1; + + /* If this qualifies as an homogeneous floating-point aggregate + (HFA), then it should be returned in FP regs. */ + int nfpreg = hfa_type (typedie, size, locp, 0); + if (nfpreg < 0) + return nfpreg; + else if (nfpreg > 0 && nfpreg <= 8) + return nfpreg == 1 ? nloc_fpreg : nloc_fpregs (nfpreg); + + if (size > 32) + goto large; + + goto intreg; + } + + /* XXX We don't have a good way to return specific errors from ebl calls. + This value means we do not understand the type, but it is well-formed + DWARF and might be valid. */ + return -2; +} diff --git a/3rdparty/elfutils/backends/ia64_symbol.c b/3rdparty/elfutils/backends/ia64_symbol.c new file mode 100644 index 0000000..f928b0b --- /dev/null +++ b/3rdparty/elfutils/backends/ia64_symbol.c @@ -0,0 +1,157 @@ +/* IA-64 specific symbolic name handling. + Copyright (C) 2002-2009, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <elf.h> +#include <stddef.h> +#include <assert.h> + +#define BACKEND ia64_ +#include "libebl_CPU.h" + + +const char * +ia64_segment_type_name (int segment, char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + switch (segment) + { + case PT_IA_64_ARCHEXT: + return "IA_64_ARCHEXT"; + case PT_IA_64_UNWIND: + return "IA_64_UNWIND"; + case PT_IA_64_HP_OPT_ANOT: + return "IA_64_HP_OPT_ANOT"; + case PT_IA_64_HP_HSL_ANOT: + return "IA_64_HP_HSL_ANOT"; + case PT_IA_64_HP_STACK: + return "IA_64_HP_STACK"; + default: + break; + } + return NULL; +} + +const char * +ia64_dynamic_tag_name (int64_t tag, char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + switch (tag) + { + case DT_IA_64_PLT_RESERVE: + return "IA_64_PLT_RESERVE"; + default: + break; + } + return NULL; +} + +/* Check dynamic tag. */ +bool +ia64_dynamic_tag_check (int64_t tag) +{ + return tag == DT_IA_64_PLT_RESERVE; +} + +/* Check whether machine flags are valid. */ +bool +ia64_machine_flag_check (GElf_Word flags) +{ + return ((flags &~ EF_IA_64_ABI64) == 0); +} + +/* Check whether SHF_MASKPROC flags are valid. */ +bool +ia64_machine_section_flag_check (GElf_Xword sh_flags) +{ + return (sh_flags &~ (SHF_IA_64_SHORT | SHF_IA_64_NORECOV)) == 0; +} + +/* Return symbolic representation of section type. */ +const char * +ia64_section_type_name (int type, + char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + switch (type) + { + case SHT_IA_64_EXT: + return "IA_64_EXT"; + case SHT_IA_64_UNWIND: + return "IA_64_UNWIND"; + } + + return NULL; +} + +/* Check for the simple reloc types. */ +Elf_Type +ia64_reloc_simple_type (Ebl *ebl, int type) +{ + switch (type) + { + /* The SECREL types when used with non-allocated sections + like .debug_* are the same as direct absolute relocs + applied to those sections, since a 0 section address is assumed. + So we treat them the same here. */ + + case R_IA64_SECREL32MSB: + case R_IA64_DIR32MSB: + if (ebl->data == ELFDATA2MSB) + return ELF_T_WORD; + break; + case R_IA64_SECREL32LSB: + case R_IA64_DIR32LSB: + if (ebl->data == ELFDATA2LSB) + return ELF_T_WORD; + break; + case R_IA64_DIR64MSB: + case R_IA64_SECREL64MSB: + if (ebl->data == ELFDATA2MSB) + return ELF_T_XWORD; + break; + case R_IA64_SECREL64LSB: + case R_IA64_DIR64LSB: + if (ebl->data == ELFDATA2LSB) + return ELF_T_XWORD; + break; + } + + return ELF_T_NUM; +} + +/* The SHT_IA_64_UNWIND section type is a valid target for relocation. */ +bool +ia64_check_reloc_target_type (Ebl *ebl __attribute__ ((unused)), Elf64_Word sh_type) +{ + return sh_type == SHT_IA_64_UNWIND; +} diff --git a/3rdparty/elfutils/backends/libebl_CPU.h b/3rdparty/elfutils/backends/libebl_CPU.h new file mode 100644 index 0000000..ef2b922 --- /dev/null +++ b/3rdparty/elfutils/backends/libebl_CPU.h @@ -0,0 +1,76 @@ +/* Common interface for libebl modules. + Copyright (C) 2000, 2001, 2002, 2003, 2005, 2013, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifndef _LIBEBL_CPU_H +#define _LIBEBL_CPU_H 1 + +#include <dwarf.h> +#include <libeblP.h> + +#define EBLHOOK(name) EBLHOOK_1(BACKEND, name) +#define EBLHOOK_1(a, b) EBLHOOK_2(a, b) +#define EBLHOOK_2(a, b) a##b + +/* Constructor. */ +extern const char *EBLHOOK(init) (Elf *elf, GElf_Half machine, + Ebl *eh, size_t ehlen); + +#include "ebl-hooks.h" + +#define HOOK(eh, name) eh->name = EBLHOOK(name) + +extern bool (*generic_debugscn_p) (const char *) attribute_hidden; + +/* Helper for retval. Return dwarf_tag (die), but calls return -1 + if there where previous errors that leave die NULL. */ +#define DWARF_TAG_OR_RETURN(die) \ + ({ Dwarf_Die *_die = (die); \ + if (_die == NULL) return -1; \ + dwarf_tag (_die); }) + +/* Get a type die corresponding to DIE. Peel CV qualifiers off + it. */ +static inline int +dwarf_peeled_die_type (Dwarf_Die *die, Dwarf_Die *result) +{ + Dwarf_Attribute attr_mem; + Dwarf_Attribute *attr = dwarf_attr_integrate (die, DW_AT_type, &attr_mem); + if (attr == NULL) + /* The function has no return value, like a `void' function in C. */ + return 0; + + if (dwarf_formref_die (attr, result) == NULL) + return -1; + + if (dwarf_peel_type (result, result) != 0) + return -1; + + return DWARF_TAG_OR_RETURN (result); +} + +#endif /* libebl_CPU.h */ diff --git a/3rdparty/elfutils/backends/linux-core-note.c b/3rdparty/elfutils/backends/linux-core-note.c new file mode 100644 index 0000000..e3c0109 --- /dev/null +++ b/3rdparty/elfutils/backends/linux-core-note.c @@ -0,0 +1,299 @@ +/* Common core note type descriptions for Linux. + Copyright (C) 2007-2010 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include <string.h> + +/* The including CPU_corenote.c file provides prstatus_regs and + defines macros ULONG, [PUG]ID_T, and ALIGN_*, TYPE_*. + + Here we describe the common layout used in <linux/elfcore.h>. */ + +#define CHAR int8_t +#define ALIGN_CHAR 1 +#define TYPE_CHAR ELF_T_BYTE +#define SHORT uint16_t +#define ALIGN_SHORT 2 +#define TYPE_SHORT ELF_T_HALF +#define INT int32_t +#define ALIGN_INT 4 +#define TYPE_INT ELF_T_SWORD +#ifndef ALIGN_PR_REG +# define ALIGN_PR_REG ALIGN_ULONG +#endif + +#define FIELD(type, name) type name __attribute__ ((aligned (ALIGN_##type))) + +struct EBLHOOK(siginfo) +{ + FIELD (INT, si_signo); + FIELD (INT, si_code); + FIELD (INT, si_errno); +}; + +struct EBLHOOK(timeval) +{ + FIELD (ULONG, tv_sec); + FIELD (ULONG, tv_usec); +}; + +/* On sparc64, tv_usec (suseconds_t) is actually 32 bits with 32 bits padding. + The 'T'|0x80 value for .format indicates this as a special kludge. */ +#if SUSECONDS_HALF +# define TIMEVAL_FIELD(name) FIELD (time, ULONG, name, 'T'|0x80, .count = 2) +#else +# define TIMEVAL_FIELD(name) FIELD (time, ULONG, name, 'T', .count = 2) +#endif + + +struct EBLHOOK(prstatus) +{ + struct EBLHOOK(siginfo) pr_info; + FIELD (SHORT, pr_cursig); + FIELD (ULONG, pr_sigpend); + FIELD (ULONG, pr_sighold); + FIELD (PID_T, pr_pid); + FIELD (PID_T, pr_ppid); + FIELD (PID_T, pr_pgrp); + FIELD (PID_T, pr_sid); + struct EBLHOOK(timeval) pr_utime; + struct EBLHOOK(timeval) pr_stime; + struct EBLHOOK(timeval) pr_cutime; + struct EBLHOOK(timeval) pr_cstime; + struct + { + FIELD (ULONG, pr_reg[PRSTATUS_REGS_SIZE / sizeof (ULONG)]); + } +#ifdef ALIGN_PR_REG + __attribute__ ((aligned (ALIGN_PR_REG))) +#endif + ; + FIELD (INT, pr_fpvalid); +}; + +#define FNAMESZ 16 +#define PRARGSZ 80 + +struct EBLHOOK(prpsinfo) +{ + FIELD (CHAR, pr_state); + FIELD (CHAR, pr_sname); + FIELD (CHAR, pr_zomb); + FIELD (CHAR, pr_nice); + FIELD (ULONG, pr_flag); + FIELD (UID_T, pr_uid); + FIELD (GID_T, pr_gid); + FIELD (PID_T, pr_pid); + FIELD (PID_T, pr_ppid); + FIELD (PID_T, pr_pgrp); + FIELD (PID_T, pr_sid); + FIELD (CHAR, pr_fname[FNAMESZ]); + FIELD (CHAR, pr_psargs[PRARGSZ]); +}; + +#undef FIELD + +#define FIELD(igroup, itype, item, fmt, ...) \ + { \ + .name = #item, \ + .group = #igroup, \ + .offset = offsetof (struct EBLHOOK(prstatus), pr_##item), \ + .type = TYPE_##itype, \ + .format = fmt, \ + __VA_ARGS__ \ + } + +static const Ebl_Core_Item prstatus_items[] = + { + FIELD (signal, INT, info.si_signo, 'd'), + FIELD (signal, INT, info.si_code, 'd'), + FIELD (signal, INT, info.si_errno, 'd'), + FIELD (signal, SHORT, cursig, 'd'), + + /* Use different group name for a newline delimiter. */ + FIELD (signal2, ULONG, sigpend, 'B'), + FIELD (signal3, ULONG, sighold, 'B'), + FIELD (identity, PID_T, pid, 'd', .thread_identifier = true), + FIELD (identity, PID_T, ppid, 'd'), + FIELD (identity, PID_T, pgrp, 'd'), + FIELD (identity, PID_T, sid, 'd'), + TIMEVAL_FIELD (utime), + TIMEVAL_FIELD (stime), + TIMEVAL_FIELD (cutime), + TIMEVAL_FIELD (cstime), +#ifdef PRSTATUS_REGSET_ITEMS + PRSTATUS_REGSET_ITEMS, +#endif + FIELD (register, INT, fpvalid, 'd'), + }; + +#undef FIELD + +#define FIELD(igroup, itype, item, fmt, ...) \ + { \ + .name = #item, \ + .group = #igroup, \ + .offset = offsetof (struct EBLHOOK(prpsinfo), pr_##item), \ + .type = TYPE_##itype, \ + .format = fmt, \ + __VA_ARGS__ \ + } + +static const Ebl_Core_Item prpsinfo_items[] = + { + FIELD (state, CHAR, state, 'd'), + FIELD (state, CHAR, sname, 'c'), + FIELD (state, CHAR, zomb, 'd'), + FIELD (state, CHAR, nice, 'd'), + FIELD (state, ULONG, flag, 'x'), + FIELD (identity, UID_T, uid, 'd'), + FIELD (identity, GID_T, gid, 'd'), + FIELD (identity, PID_T, pid, 'd'), + FIELD (identity, PID_T, ppid, 'd'), + FIELD (identity, PID_T, pgrp, 'd'), + FIELD (identity, PID_T, sid, 'd'), + FIELD (command, CHAR, fname, 's', .count = FNAMESZ), + FIELD (command, CHAR, psargs, 's', .count = PRARGSZ), + }; + +static const Ebl_Core_Item vmcoreinfo_items[] = + { + { + .type = ELF_T_BYTE, .format = '\n' + } + }; + +#undef FIELD + +int +EBLHOOK(core_note) (nhdr, name, regs_offset, nregloc, reglocs, nitems, items) + const GElf_Nhdr *nhdr; + const char *name; + GElf_Word *regs_offset; + size_t *nregloc; + const Ebl_Register_Location **reglocs; + size_t *nitems; + const Ebl_Core_Item **items; +{ + switch (nhdr->n_namesz) + { + case sizeof "CORE" - 1: /* Buggy old Linux kernels. */ + if (memcmp (name, "CORE", nhdr->n_namesz) == 0) + break; + return 0; + + case sizeof "CORE": + if (memcmp (name, "CORE", nhdr->n_namesz) == 0) + break; + /* Buggy old Linux kernels didn't terminate "LINUX". + Fall through. */ + + case sizeof "LINUX": + if (memcmp (name, "LINUX", nhdr->n_namesz) == 0) + break; + return 0; + + case sizeof "VMCOREINFO": + if (nhdr->n_type != 0 + || memcmp (name, "VMCOREINFO", sizeof "VMCOREINFO") != 0) + return 0; + *regs_offset = 0; + *nregloc = 0; + *nitems = 1; + *items = vmcoreinfo_items; + return 1; + + default: + return 0; + } + + switch (nhdr->n_type) + { + case NT_PRSTATUS: + if (nhdr->n_descsz != sizeof (struct EBLHOOK(prstatus))) + return 0; + *regs_offset = offsetof (struct EBLHOOK(prstatus), pr_reg); + *nregloc = sizeof prstatus_regs / sizeof prstatus_regs[0]; + *reglocs = prstatus_regs; + *nitems = sizeof prstatus_items / sizeof prstatus_items[0]; + *items = prstatus_items; + return 1; + + case NT_PRPSINFO: + if (nhdr->n_descsz != sizeof (struct EBLHOOK(prpsinfo))) + return 0; + *regs_offset = 0; + *nregloc = 0; + *reglocs = NULL; + *nitems = sizeof prpsinfo_items / sizeof prpsinfo_items[0]; + *items = prpsinfo_items; + return 1; + +#define EXTRA_REGSET(type, size, table) \ + case type: \ + if (nhdr->n_descsz != size) \ + return 0; \ + *regs_offset = 0; \ + *nregloc = sizeof table / sizeof table[0]; \ + *reglocs = table; \ + *nitems = 0; \ + *items = NULL; \ + return 1; + +#define EXTRA_REGSET_ITEMS(type, size, table, extra_items) \ + case type: \ + if (nhdr->n_descsz != size) \ + return 0; \ + *regs_offset = 0; \ + *nregloc = sizeof table / sizeof table[0]; \ + *reglocs = table; \ + *nitems = sizeof extra_items / sizeof extra_items[0]; \ + *items = extra_items; \ + return 1; + +#define EXTRA_ITEMS(type, size, extra_items) \ + case type: \ + if (nhdr->n_descsz != size) \ + return 0; \ + *regs_offset = 0; \ + *nregloc = 0; \ + *reglocs = NULL; \ + *nitems = sizeof extra_items / sizeof extra_items[0]; \ + *items = extra_items; \ + return 1; + +#ifdef FPREGSET_SIZE + EXTRA_REGSET (NT_FPREGSET, FPREGSET_SIZE, fpregset_regs) +#endif + +#ifdef EXTRA_NOTES + EXTRA_NOTES +#endif + } + + return 0; +} diff --git a/3rdparty/elfutils/backends/ppc/ppc.pro b/3rdparty/elfutils/backends/ppc/ppc.pro new file mode 100644 index 0000000..cb202fd --- /dev/null +++ b/3rdparty/elfutils/backends/ppc/ppc.pro @@ -0,0 +1,18 @@ +TEMPLATE = lib +include(../backends.pri) +TARGET = ../ebl_ppc + +SOURCES += \ + ../ppc_attrs.c \ + ../ppc_auxv.c \ + ../ppc_cfi.c \ + ../ppc_corenote.c \ + ../ppc_init.c \ + ../ppc_initreg.c \ + ../ppc_regs.c \ + ../ppc_retval.c \ + ../ppc_symbol.c \ + ../ppc_syscall.c + +HEADERS += \ + ../ppc_reloc.def diff --git a/3rdparty/elfutils/backends/ppc64/ppc64.pro b/3rdparty/elfutils/backends/ppc64/ppc64.pro new file mode 100644 index 0000000..32078a9 --- /dev/null +++ b/3rdparty/elfutils/backends/ppc64/ppc64.pro @@ -0,0 +1,13 @@ +TEMPLATE = lib +include(../backends.pri) +TARGET = ../ebl_ppc64 + +SOURCES += \ + ../ppc64_corenote.c \ + ../ppc64_init.c \ + ../ppc64_resolve_sym.c \ + ../ppc64_retval.c \ + ../ppc64_symbol.c + +HEADERS += \ + ../ppc64_reloc.def diff --git a/3rdparty/elfutils/backends/ppc64_corenote.c b/3rdparty/elfutils/backends/ppc64_corenote.c new file mode 100644 index 0000000..9d6a6a4 --- /dev/null +++ b/3rdparty/elfutils/backends/ppc64_corenote.c @@ -0,0 +1,2 @@ +#define BITS 64 +#include "ppc_corenote.c" diff --git a/3rdparty/elfutils/backends/ppc64_init.c b/3rdparty/elfutils/backends/ppc64_init.c new file mode 100644 index 0000000..56e1828 --- /dev/null +++ b/3rdparty/elfutils/backends/ppc64_init.c @@ -0,0 +1,109 @@ +/* Initialization of PPC64 specific backend library. + Copyright (C) 2004, 2005, 2006, 2007, 2008, 2013, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> + +#define BACKEND ppc64_ +#define RELOC_PREFIX R_PPC64_ +#include "libebl_CPU.h" + +/* This defines the common reloc hooks based on ppc64_reloc.def. */ +#include "common-reloc.c" + + +const char * +ppc64_init (elf, machine, eh, ehlen) + Elf *elf __attribute__ ((unused)); + GElf_Half machine __attribute__ ((unused)); + Ebl *eh; + size_t ehlen; +{ + /* Check whether the Elf_BH object has a sufficent size. */ + if (ehlen < sizeof (Ebl)) + return NULL; + + /* We handle it. */ + eh->name = "PowerPC 64-bit"; + ppc64_init_reloc (eh); + HOOK (eh, reloc_simple_type); + HOOK (eh, dynamic_tag_name); + HOOK (eh, dynamic_tag_check); + HOOK (eh, machine_flag_check); + HOOK (eh, copy_reloc_p); + HOOK (eh, check_special_symbol); + HOOK (eh, check_st_other_bits); + HOOK (eh, bss_plt_p); + HOOK (eh, return_value_location); + HOOK (eh, register_info); + HOOK (eh, syscall_abi); + HOOK (eh, core_note); + HOOK (eh, auxv_info); + HOOK (eh, abi_cfi); + /* gcc/config/ #define DWARF_FRAME_REGISTERS. */ + eh->frame_nregs = (114 - 1) + 32; + HOOK (eh, set_initial_registers_tid); + HOOK (eh, dwarf_to_regno); + HOOK (eh, resolve_sym_value); + + /* Find the function descriptor .opd table for resolve_sym_value. */ + if (elf != NULL) + { + GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem); + if (ehdr != NULL && ehdr->e_type != ET_REL) + { + /* We could also try through DT_PPC64_OPD and DT_PPC64_OPDSZ. */ + GElf_Shdr opd_shdr_mem, *opd_shdr; + Elf_Scn *scn = NULL; + while ((scn = elf_nextscn (elf, scn)) != NULL) + { + opd_shdr = gelf_getshdr (scn, &opd_shdr_mem); + if (opd_shdr != NULL + && (opd_shdr->sh_flags & SHF_ALLOC) != 0 + && opd_shdr->sh_type == SHT_PROGBITS + && opd_shdr->sh_size > 0) + { + const char *name = elf_strptr (elf, ehdr->e_shstrndx, + opd_shdr->sh_name); + if (name != NULL && strcmp (name, ".opd") == 0) + { + eh->fd_addr = opd_shdr->sh_addr; + eh->fd_data = elf_getdata (scn, NULL); + break; + } + } + } + } + } + + return MODVERSION; +} diff --git a/3rdparty/elfutils/backends/ppc64_reloc.def b/3rdparty/elfutils/backends/ppc64_reloc.def new file mode 100644 index 0000000..3a693cf --- /dev/null +++ b/3rdparty/elfutils/backends/ppc64_reloc.def @@ -0,0 +1,161 @@ +/* List the relocation types for ppc64. -*- C -*- + Copyright (C) 2005 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +/* NAME, REL|EXEC|DYN */ + +RELOC_TYPE (NONE, 0) +RELOC_TYPE (ADDR32, REL|EXEC|DYN) +RELOC_TYPE (ADDR24, REL) +RELOC_TYPE (ADDR16, REL) /* note 1 */ +RELOC_TYPE (ADDR16_LO, REL) /* note 1 */ +RELOC_TYPE (ADDR16_HI, REL) /* note 1 */ +RELOC_TYPE (ADDR16_HA, REL) /* note 1 */ +RELOC_TYPE (ADDR14, REL) /* note 1 */ +RELOC_TYPE (ADDR14_BRTAKEN, REL) /* note 1 */ +RELOC_TYPE (ADDR14_BRNTAKEN, REL) /* note 1 */ +RELOC_TYPE (REL24, REL) +RELOC_TYPE (REL14, REL) +RELOC_TYPE (REL14_BRTAKEN, REL) +RELOC_TYPE (REL14_BRNTAKEN, REL) +RELOC_TYPE (GOT16, REL) +RELOC_TYPE (GOT16_LO, REL) +RELOC_TYPE (GOT16_HI, REL) +RELOC_TYPE (GOT16_HA, REL) +RELOC_TYPE (COPY, EXEC) +RELOC_TYPE (GLOB_DAT, EXEC|DYN) +RELOC_TYPE (JMP_SLOT, EXEC|DYN) +RELOC_TYPE (RELATIVE, EXEC|DYN) +RELOC_TYPE (UADDR32, REL|EXEC|DYN) +RELOC_TYPE (UADDR16, REL) +RELOC_TYPE (REL32, REL|EXEC|DYN) +RELOC_TYPE (PLT32, REL) +RELOC_TYPE (PLTREL32, REL) +RELOC_TYPE (PLT16_LO, REL) +RELOC_TYPE (PLT16_HI, REL) +RELOC_TYPE (PLT16_HA, REL) +RELOC_TYPE (SECTOFF, REL) +RELOC_TYPE (SECTOFF_LO, REL) +RELOC_TYPE (SECTOFF_HI, REL) +RELOC_TYPE (SECTOFF_HA, REL) +RELOC_TYPE (ADDR30, REL) /* note 1 */ +RELOC_TYPE (ADDR64, REL|EXEC|DYN) +RELOC_TYPE (ADDR16_HIGHER, REL) /* note 1 */ +RELOC_TYPE (ADDR16_HIGHERA, REL) /* note 1 */ +RELOC_TYPE (ADDR16_HIGHEST, REL) /* note 1 */ +RELOC_TYPE (ADDR16_HIGHESTA, REL) /* note 1 */ +RELOC_TYPE (UADDR64, REL|EXEC|DYN) +RELOC_TYPE (REL64, REL|EXEC|DYN) +RELOC_TYPE (PLT64, REL) +RELOC_TYPE (PLTREL64, REL) +RELOC_TYPE (TOC16, REL) +RELOC_TYPE (TOC16_LO, REL) +RELOC_TYPE (TOC16_HI, REL) +RELOC_TYPE (TOC16_HA, REL) +RELOC_TYPE (TOC, REL) +RELOC_TYPE (PLTGOT16, REL) +RELOC_TYPE (PLTGOT16_LO, REL) +RELOC_TYPE (PLTGOT16_HI, REL) +RELOC_TYPE (PLTGOT16_HA, REL) +RELOC_TYPE (ADDR16_DS, REL) /* note 1 */ +RELOC_TYPE (ADDR16_LO_DS, REL) /* note 1 */ +RELOC_TYPE (GOT16_DS, REL) +RELOC_TYPE (GOT16_LO_DS, REL) +RELOC_TYPE (PLT16_LO_DS, REL) +RELOC_TYPE (SECTOFF_DS, REL) +RELOC_TYPE (SECTOFF_LO_DS, REL) +RELOC_TYPE (TOC16_DS, REL) +RELOC_TYPE (TOC16_LO_DS, REL) +RELOC_TYPE (PLTGOT16_DS, REL) +RELOC_TYPE (PLTGOT16_LO_DS, REL) +RELOC_TYPE (TLS, REL) +RELOC_TYPE (DTPMOD64, REL|EXEC|DYN) /* note 3 */ +RELOC_TYPE (TPREL16, REL) /* note 2 */ +RELOC_TYPE (TPREL16_LO, REL) /* note 2 */ +RELOC_TYPE (TPREL16_HI, REL) /* note 2 */ +RELOC_TYPE (TPREL16_HA, REL) /* note 2 */ +RELOC_TYPE (TPREL64, REL|EXEC|DYN) /* note 3 */ +RELOC_TYPE (DTPREL16, REL) +RELOC_TYPE (DTPREL16_LO, REL) +RELOC_TYPE (DTPREL16_HI, REL) +RELOC_TYPE (DTPREL16_HA, REL) +RELOC_TYPE (DTPREL64, REL|EXEC|DYN) /* note 3 */ +RELOC_TYPE (GOT_TLSGD16, REL) +RELOC_TYPE (GOT_TLSGD16_LO, REL) +RELOC_TYPE (GOT_TLSGD16_HI, REL) +RELOC_TYPE (GOT_TLSGD16_HA, REL) +RELOC_TYPE (GOT_TLSLD16, REL) +RELOC_TYPE (GOT_TLSLD16_LO, REL) +RELOC_TYPE (GOT_TLSLD16_HI, REL) +RELOC_TYPE (GOT_TLSLD16_HA, REL) +RELOC_TYPE (GOT_TPREL16_DS, REL) +RELOC_TYPE (GOT_TPREL16_LO_DS, REL) +RELOC_TYPE (GOT_TPREL16_HI, REL) +RELOC_TYPE (GOT_TPREL16_HA, REL) +RELOC_TYPE (GOT_DTPREL16_DS, REL) +RELOC_TYPE (GOT_DTPREL16_LO_DS, REL) +RELOC_TYPE (GOT_DTPREL16_HI, REL) +RELOC_TYPE (GOT_DTPREL16_HA, REL) +RELOC_TYPE (TPREL16_DS, REL) /* note 2 */ +RELOC_TYPE (TPREL16_LO_DS, REL) /* note 2 */ +RELOC_TYPE (TPREL16_HIGHER, REL) /* note 2 */ +RELOC_TYPE (TPREL16_HIGHERA, REL) /* note 2 */ +RELOC_TYPE (TPREL16_HIGHEST, REL) /* note 2 */ +RELOC_TYPE (TPREL16_HIGHESTA, REL) /* note 2 */ +RELOC_TYPE (DTPREL16_DS, REL) +RELOC_TYPE (DTPREL16_LO_DS, REL) +RELOC_TYPE (DTPREL16_HIGHER, REL) +RELOC_TYPE (DTPREL16_HIGHERA, REL) +RELOC_TYPE (DTPREL16_HIGHEST, REL) +RELOC_TYPE (DTPREL16_HIGHESTA, REL) +RELOC_TYPE (TLSGD, REL) +RELOC_TYPE (TLSLD, REL) +RELOC_TYPE (TOCSAVE, REL) +RELOC_TYPE (ADDR16_HIGH, REL) +RELOC_TYPE (ADDR16_HIGHA, REL) +RELOC_TYPE (TPREL16_HIGH, REL) +RELOC_TYPE (TPREL16_HIGHA, REL) +RELOC_TYPE (DTPREL16_HIGH, REL) +RELOC_TYPE (DTPREL16_HIGHA, REL) +RELOC_TYPE (JMP_IREL, REL) +RELOC_TYPE (IRELATIVE, REL) +RELOC_TYPE (REL16, REL) +RELOC_TYPE (REL16_LO, REL) +RELOC_TYPE (REL16_HI, REL) +RELOC_TYPE (REL16_HA, REL) + +/* Notes from Alan Modra: + + 1) These can appear in DYN and EXEC with improper assembly, but they + aren't really kosher. + + 2) These can appear in DYN with improper assembly (or silly gcc + attributes, I think). Again, not kosher. + + 3) These are legal in REL for PowerOpen compatible assembler syntax, + ie. TOC managed by compiler. +*/ diff --git a/3rdparty/elfutils/backends/ppc64_resolve_sym.c b/3rdparty/elfutils/backends/ppc64_resolve_sym.c new file mode 100644 index 0000000..03f6558 --- /dev/null +++ b/3rdparty/elfutils/backends/ppc64_resolve_sym.c @@ -0,0 +1,63 @@ +/* Resolve symbol values through .opd function descriptors. + Copyright (C) 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND ppc64_ +#include "libebl_CPU.h" + +/* Resolve a function descriptor if addr points into the .opd section. + The .opd section contains function descriptors consisting of 3 addresses. + function, toc and chain. We are just interested in the first. + http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.html#FUNC-DES + + Returns true if the given address could be resolved, false otherwise. +*/ +bool +ppc64_resolve_sym_value (Ebl *ebl, GElf_Addr *addr) +{ + if (ebl->fd_data != NULL && *addr >= ebl->fd_addr + && *addr + sizeof (Elf64_Addr) <= ebl->fd_addr + ebl->fd_data->d_size) + { + GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (ebl->elf, &ehdr_mem); + if (ehdr != NULL) + { + Elf_Data opd_in, opd_out; + opd_in.d_buf = ebl->fd_data->d_buf + (*addr - ebl->fd_addr); + opd_out.d_buf = addr; + opd_out.d_size = opd_in.d_size = sizeof (Elf64_Addr); + opd_out.d_type = opd_in.d_type = ELF_T_ADDR; + if (elf64_xlatetom (&opd_out, &opd_in, + ehdr->e_ident[EI_DATA]) != NULL) + return true; + } + } + return false; +} diff --git a/3rdparty/elfutils/backends/ppc64_retval.c b/3rdparty/elfutils/backends/ppc64_retval.c new file mode 100644 index 0000000..a251983 --- /dev/null +++ b/3rdparty/elfutils/backends/ppc64_retval.c @@ -0,0 +1,195 @@ +/* Function return value location for Linux/PPC64 ABI. + Copyright (C) 2005-2010, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> + +#define BACKEND ppc64_ +#include "libebl_CPU.h" + + +/* r3. */ +static const Dwarf_Op loc_intreg[] = + { + { .atom = DW_OP_reg3 } + }; +#define nloc_intreg 1 + +/* f1, or f1:f2, or f1:f4. */ +static const Dwarf_Op loc_fpreg[] = + { + { .atom = DW_OP_regx, .number = 33 }, { .atom = DW_OP_piece, .number = 8 }, + { .atom = DW_OP_regx, .number = 34 }, { .atom = DW_OP_piece, .number = 8 }, + { .atom = DW_OP_regx, .number = 35 }, { .atom = DW_OP_piece, .number = 8 }, + { .atom = DW_OP_regx, .number = 36 }, { .atom = DW_OP_piece, .number = 8 }, + }; +#define nloc_fpreg 1 +#define nloc_fp2regs 4 +#define nloc_fp4regs 8 + +/* vr2. */ +static const Dwarf_Op loc_vmxreg[] = + { + { .atom = DW_OP_regx, .number = 1124 + 2 } + }; +#define nloc_vmxreg 1 + +/* The return value is a structure and is actually stored in stack space + passed in a hidden argument by the caller. But, the compiler + helpfully returns the address of that space in r3. */ +static const Dwarf_Op loc_aggregate[] = + { + { .atom = DW_OP_breg3, .number = 0 } + }; +#define nloc_aggregate 1 + +int +ppc64_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp) +{ + /* Start with the function's type, and get the DW_AT_type attribute, + which is the type of the return value. */ + Dwarf_Die die_mem, *typedie = &die_mem; + int tag = dwarf_peeled_die_type (functypedie, typedie); + if (tag <= 0) + return tag; + + Dwarf_Word size; + switch (tag) + { + case -1: + return -1; + + case DW_TAG_subrange_type: + if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size)) + { + Dwarf_Attribute attr_mem, *attr; + attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem); + typedie = dwarf_formref_die (attr, &die_mem); + tag = DWARF_TAG_OR_RETURN (typedie); + } + /* Fall through. */ + + case DW_TAG_base_type: + case DW_TAG_enumeration_type: + case DW_TAG_pointer_type: + case DW_TAG_ptr_to_member_type: + { + Dwarf_Attribute attr_mem; + if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size, + &attr_mem), &size) != 0) + { + if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type) + size = 8; + else + return -1; + } + } + + if (tag == DW_TAG_base_type) + { + Dwarf_Attribute attr_mem; + Dwarf_Word encoding; + if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding, + &attr_mem), + &encoding) != 0) + return -1; + + if (encoding == DW_ATE_float || encoding == DW_ATE_complex_float) + { + *locp = loc_fpreg; + if (size <= 8) + return nloc_fpreg; + if (size <= 16) + return nloc_fp2regs; + if (size <= 32) + return nloc_fp4regs; + } + } + if (size <= 8) + { + intreg: + *locp = loc_intreg; + return nloc_intreg; + } + + /* Else fall through. */ + case DW_TAG_structure_type: + case DW_TAG_class_type: + case DW_TAG_union_type: + aggregate: + *locp = loc_aggregate; + return nloc_aggregate; + + case DW_TAG_array_type: + { + Dwarf_Attribute attr_mem; + bool is_vector; + if (dwarf_formflag (dwarf_attr_integrate (typedie, DW_AT_GNU_vector, + &attr_mem), &is_vector) == 0 + && is_vector) + { + *locp = loc_vmxreg; + return nloc_vmxreg; + } + } + /* Fall through. */ + + case DW_TAG_string_type: + if (dwarf_aggregate_size (typedie, &size) == 0 && size <= 8) + { + if (tag == DW_TAG_array_type) + { + /* Check if it's a character array. */ + Dwarf_Attribute attr_mem, *attr; + attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem); + typedie = dwarf_formref_die (attr, &die_mem); + tag = DWARF_TAG_OR_RETURN (typedie); + if (tag != DW_TAG_base_type) + goto aggregate; + if (dwarf_formudata (dwarf_attr_integrate (typedie, + DW_AT_byte_size, + &attr_mem), + &size) != 0) + return -1; + if (size != 1) + goto aggregate; + } + goto intreg; + } + goto aggregate; + } + + /* XXX We don't have a good way to return specific errors from ebl calls. + This value means we do not understand the type, but it is well-formed + DWARF and might be valid. */ + return -2; +} diff --git a/3rdparty/elfutils/backends/ppc64_symbol.c b/3rdparty/elfutils/backends/ppc64_symbol.c new file mode 100644 index 0000000..0feddce --- /dev/null +++ b/3rdparty/elfutils/backends/ppc64_symbol.c @@ -0,0 +1,130 @@ +/* PPC64 specific symbolic name handling. + Copyright (C) 2004, 2005, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <elf.h> +#include <stddef.h> +#include <string.h> + +#define BACKEND ppc64_ +#include "libebl_CPU.h" + + +/* Check for the simple reloc types. */ +Elf_Type +ppc64_reloc_simple_type (Ebl *ebl __attribute__ ((unused)), int type) +{ + switch (type) + { + case R_PPC64_ADDR64: + case R_PPC64_UADDR64: + return ELF_T_XWORD; + case R_PPC64_ADDR32: + case R_PPC64_UADDR32: + return ELF_T_WORD; + case R_PPC64_UADDR16: + return ELF_T_HALF; + default: + return ELF_T_NUM; + } +} + + +const char * +ppc64_dynamic_tag_name (int64_t tag, char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + switch (tag) + { + case DT_PPC64_GLINK: + return "PPC64_GLINK"; + case DT_PPC64_OPD: + return "PPC64_OPD"; + case DT_PPC64_OPDSZ: + return "PPC64_OPDSZ"; + case DT_PPC64_OPT: + return "PPC64_OPT"; + default: + break; + } + return NULL; +} + + +bool +ppc64_dynamic_tag_check (int64_t tag) +{ + return (tag == DT_PPC64_GLINK + || tag == DT_PPC64_OPD + || tag == DT_PPC64_OPDSZ + || tag == DT_PPC64_OPT); +} + + +/* Check whether given symbol's st_value and st_size are OK despite failing + normal checks. */ +bool +ppc64_check_special_symbol (Elf *elf, GElf_Ehdr *ehdr, + const GElf_Sym *sym __attribute__ ((unused)), + const char *name __attribute__ ((unused)), + const GElf_Shdr *destshdr) +{ + const char *sname = elf_strptr (elf, ehdr->e_shstrndx, destshdr->sh_name); + if (sname == NULL) + return false; + return strcmp (sname, ".opd") == 0; +} + + +/* Check if backend uses a bss PLT in this file. */ +bool +ppc64_bss_plt_p (Elf *elf __attribute__ ((unused))) +{ + return true; +} + +/* Check whether machine flags are valid. PPC64 has three possible values: + 0 - for unspecified ABI, or not using any specific ABI features. + 1 - for the original ELF PPC64 ABI using function descriptors. + 2 - for the revised ELFv2 PPC64 ABI without function descriptors. */ +bool +ppc64_machine_flag_check (GElf_Word flags) +{ + return flags == 0 || flags == 1 || flags == 2; +} + +bool +ppc64_check_st_other_bits (unsigned char st_other) +{ + return (PPC64_LOCAL_ENTRY_OFFSET (st_other) != 0); +} diff --git a/3rdparty/elfutils/backends/ppc_attrs.c b/3rdparty/elfutils/backends/ppc_attrs.c new file mode 100644 index 0000000..ebeafe5 --- /dev/null +++ b/3rdparty/elfutils/backends/ppc_attrs.c @@ -0,0 +1,89 @@ +/* Object attribute tags for PowerPC. + Copyright (C) 2008, 2009 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> +#include <dwarf.h> + +#define BACKEND ppc_ +#include "libebl_CPU.h" + +bool +ppc_check_object_attribute (ebl, vendor, tag, value, tag_name, value_name) + Ebl *ebl __attribute__ ((unused)); + const char *vendor; + int tag; + uint64_t value; + const char **tag_name; + const char **value_name; +{ + if (!strcmp (vendor, "gnu")) + switch (tag) + { + case 4: + *tag_name = "GNU_Power_ABI_FP"; + static const char *fp_kinds[] = + { + "Hard or soft float", + "Hard float", + "Soft float", + }; + if (value < sizeof fp_kinds / sizeof fp_kinds[0]) + *value_name = fp_kinds[value]; + return true; + + case 8: + *tag_name = "GNU_Power_ABI_Vector"; + static const char *vector_kinds[] = + { + "Any", "Generic", "AltiVec", "SPE" + }; + if (value < sizeof vector_kinds / sizeof vector_kinds[0]) + *value_name = vector_kinds[value]; + return true; + + case 12: + *tag_name = "GNU_Power_ABI_Struct_Return"; + static const char *struct_return_kinds[] = + { + "Any", "r3/r4", "Memory" + }; + if (value < sizeof struct_return_kinds / sizeof struct_return_kinds[0]) + *value_name = struct_return_kinds[value]; + return true; + } + + return false; +} + +__typeof (ppc_check_object_attribute) + ppc64_check_object_attribute + __attribute__ ((alias ("ppc_check_object_attribute"))); diff --git a/3rdparty/elfutils/backends/ppc_auxv.c b/3rdparty/elfutils/backends/ppc_auxv.c new file mode 100644 index 0000000..a27a1da --- /dev/null +++ b/3rdparty/elfutils/backends/ppc_auxv.c @@ -0,0 +1,55 @@ +/* i386 specific auxv handling. + Copyright (C) 2007 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND ppc_ +#include "libebl_CPU.h" + +int +EBLHOOK(auxv_info) (GElf_Xword a_type, const char **name, const char **format) +{ + if (a_type != AT_HWCAP) + return 0; + + *name = "HWCAP"; + *format = "b" + "ppcle\0" "truele\0" "3\0" "4\0" "5\0" "6\0" "7\0" "8\0" "9\0" + "power6x\0" "dfp\0" "pa6t\0" "arch_2_05\0" + "ic_snoop\0" "smt\0" "booke\0" "cellbe\0" + "power5+\0" "power5\0" "power4\0" "notb\0" + "efpdouble\0" "efpsingle\0" "spe\0" "ucache\0" + "4xxmac\0" "mmu\0" "fpu\0" "altivec\0" + "ppc601\0" "ppc64\0" "ppc32\0" "\0"; + return 1; +} + +__typeof (ppc_auxv_info) ppc64_auxv_info + __attribute__ ((alias ("ppc_auxv_info"))); diff --git a/3rdparty/elfutils/backends/ppc_cfi.c b/3rdparty/elfutils/backends/ppc_cfi.c new file mode 100644 index 0000000..55169ae --- /dev/null +++ b/3rdparty/elfutils/backends/ppc_cfi.c @@ -0,0 +1,77 @@ +/* ppc ABI-specified defaults for DWARF CFI. + Copyright (C) 2012, 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> + +#define BACKEND ppc_ +#include "libebl_CPU.h" + +int +ppc_abi_cfi (Ebl *ebl __attribute__ ((unused)), Dwarf_CIE *abi_info) +{ + static const uint8_t abi_cfi[] = + { + /* This instruction is provided in every CIE. It is not repeated here: + DW_CFA_def_cfa, ULEB128_7 (1), ULEB128_7 (0) */ + /* r1 is assumed to be restored from cfa adress, + r1 acts as a stack frame pointer. */ + DW_CFA_val_offset, ULEB128_7 (1), ULEB128_7 (0), + /* lr is not callee-saved but it needs to be preserved as it is pre-set + by the caller. */ + DW_CFA_same_value, ULEB128_7 (65), /* lr */ + + /* Callee-saved regs. */ +#define SV(n) DW_CFA_same_value, ULEB128_7 (n) + SV (2), /* r2 is TOC pointer. */ + SV (13), /* Reserved as system thread id (is it for CFI?). */ + /* r14-r31 are non-volatile registers. */ + SV (14), SV (15), SV (16), SV (17), SV (18), SV (19), SV (20), SV (21), + SV (22), SV (23), SV (24), SV (25), SV (26), SV (27), SV (28), SV (29), + SV (30), SV (31) + /* VMX registers v20-v31 and vrsave are non-volatile but they are + assigned DWARF registers 1144-1156 (v20-v31) which is outside of the + CFI supported range. */ +#undef SV + }; + + abi_info->initial_instructions = abi_cfi; + abi_info->initial_instructions_end = &abi_cfi[sizeof abi_cfi]; + abi_info->data_alignment_factor = ebl->class == ELFCLASS64 ? 8 : 4; + + abi_info->return_address_register = 65; + + return 0; +} + +__typeof (ppc_abi_cfi) + ppc64_abi_cfi + __attribute__ ((alias ("ppc_abi_cfi"))); diff --git a/3rdparty/elfutils/backends/ppc_corenote.c b/3rdparty/elfutils/backends/ppc_corenote.c new file mode 100644 index 0000000..9ac8871 --- /dev/null +++ b/3rdparty/elfutils/backends/ppc_corenote.c @@ -0,0 +1,134 @@ +/* PowerPC specific core note handling. + Copyright (C) 2007, 2008 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <elf.h> +#include <inttypes.h> +#include <stddef.h> +#include <stdio.h> +#include <sys/time.h> + +#ifndef BITS +# define BITS 32 +# define BACKEND ppc_ +#else +# define BITS 64 +# define BACKEND ppc64_ +#endif +#include "libebl_CPU.h" + +static const Ebl_Register_Location prstatus_regs[] = + { +#define GR(at, n, dwreg) \ + { .offset = at * BITS/8, .regno = dwreg, .count = n, .bits = BITS } + + GR (0, 32, 0), /* r0-r31 */ + /* 32, 1, nip */ + GR (33, 1, 66), /* msr */ + /* 34, 1, orig_gpr3 */ + GR (35, 1, 109), /* ctr */ + GR (36, 1, 108), /* lr */ + GR (37, 1, 101), /* xer */ + GR (38, 1, 64), /* cr */ + GR (39, 1, 100), /* mq */ + /* 40, 1, trap */ + GR (41, 1, 119), /* dar */ + GR (42, 1, 118), /* dsisr */ + +#undef GR + }; +#define PRSTATUS_REGS_SIZE (BITS / 8 * 48) + +static const Ebl_Register_Location fpregset_regs[] = + { + { .offset = 0, .regno = 32, .count = 32, .bits = 64 }, /* f0-f31 */ + { .offset = 32 * 8 + 4, .regno = 65, .count = 1, .bits = 32 } /* fpscr */ + }; +#define FPREGSET_SIZE (33 * 8) + +static const Ebl_Register_Location altivec_regs[] = + { + /* vr0-vr31 */ + { .offset = 0, .regno = 1124, .count = 32, .bits = 128 }, + /* vscr XXX 67 is an unofficial assignment */ + { .offset = 32 * 16, .regno = 67, .count = 1, .bits = 32, .pad = 12 }, + /* vrsave */ + { .offset = 33 * 16, .regno = 356, .count = 1, .bits = 32, .pad = 12 } + }; + +static const Ebl_Register_Location spe_regs[] = + { + /* evr0-evr31 + { .offset = 0, .regno = ???, .count = 32, .bits = 32 }, + * acc * + { .offset = 32 * 4, .regno = ???, .count = 1, .bits = 64 }, */ + /* spefscr */ + { .offset = 34 * 4, .regno = 612, .count = 1, .bits = 32 } + }; + +#define EXTRA_NOTES \ + EXTRA_REGSET (NT_PPC_VMX, 34 * 16, altivec_regs) \ + EXTRA_REGSET (NT_PPC_SPE, 35 * 4, spe_regs) + +#if BITS == 32 +# define ULONG uint32_t +# define ALIGN_ULONG 4 +# define TYPE_ULONG ELF_T_WORD +# define TYPE_LONG ELF_T_SWORD +#else +# define ULONG uint64_t +# define ALIGN_ULONG 8 +# define TYPE_ULONG ELF_T_XWORD +# define TYPE_LONG ELF_T_SXWORD +#endif +#define PID_T int32_t +#define UID_T uint32_t +#define GID_T uint32_t +#define ALIGN_PID_T 4 +#define ALIGN_UID_T 4 +#define ALIGN_GID_T 4 +#define TYPE_PID_T ELF_T_SWORD +#define TYPE_UID_T ELF_T_WORD +#define TYPE_GID_T ELF_T_WORD + +#define PRSTATUS_REGSET_ITEMS \ + { \ + .name = "nip", .type = ELF_T_ADDR, .format = 'x', \ + .offset = offsetof (struct EBLHOOK(prstatus), pr_reg[32]), \ + .group = "register", .pc_register = true \ + }, \ + { \ + .name = "orig_gpr3", .type = TYPE_LONG, .format = 'd', \ + .offset = offsetof (struct EBLHOOK(prstatus), pr_reg[34]), \ + .group = "register" \ + } + +#include "linux-core-note.c" diff --git a/3rdparty/elfutils/backends/ppc_init.c b/3rdparty/elfutils/backends/ppc_init.c new file mode 100644 index 0000000..ad92765 --- /dev/null +++ b/3rdparty/elfutils/backends/ppc_init.c @@ -0,0 +1,74 @@ +/* Initialization of PPC specific backend library. + Copyright (C) 2004, 2005, 2006, 2007, 2008, 2013 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND ppc_ +#define RELOC_PREFIX R_PPC_ +#include "libebl_CPU.h" + +/* This defines the common reloc hooks based on ppc_reloc.def. */ +#include "common-reloc.c" + + +const char * +ppc_init (elf, machine, eh, ehlen) + Elf *elf __attribute__ ((unused)); + GElf_Half machine __attribute__ ((unused)); + Ebl *eh; + size_t ehlen; +{ + /* Check whether the Elf_BH object has a sufficent size. */ + if (ehlen < sizeof (Ebl)) + return NULL; + + /* We handle it. */ + eh->name = "PowerPC"; + ppc_init_reloc (eh); + HOOK (eh, reloc_simple_type); + HOOK (eh, dynamic_tag_name); + HOOK (eh, dynamic_tag_check); + HOOK (eh, check_special_symbol); + HOOK (eh, bss_plt_p); + HOOK (eh, return_value_location); + HOOK (eh, register_info); + HOOK (eh, syscall_abi); + HOOK (eh, core_note); + HOOK (eh, auxv_info); + HOOK (eh, check_object_attribute); + HOOK (eh, abi_cfi); + /* gcc/config/ #define DWARF_FRAME_REGISTERS. */ + eh->frame_nregs = (114 - 1) + 32; + HOOK (eh, set_initial_registers_tid); + HOOK (eh, dwarf_to_regno); + + return MODVERSION; +} diff --git a/3rdparty/elfutils/backends/ppc_initreg.c b/3rdparty/elfutils/backends/ppc_initreg.c new file mode 100644 index 0000000..64f5379 --- /dev/null +++ b/3rdparty/elfutils/backends/ppc_initreg.c @@ -0,0 +1,114 @@ +/* Fetch live process registers from TID. + Copyright (C) 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "system.h" +#include <stdlib.h> +#ifdef __powerpc__ +# include <sys/user.h> +# include <sys/ptrace.h> +#endif + +#define BACKEND ppc_ +#include "libebl_CPU.h" + +bool +ppc_dwarf_to_regno (Ebl *ebl __attribute__ ((unused)), unsigned *regno) +{ + switch (*regno) + { + case 108: + // LR uses both 65 and 108 numbers, there is no consistency for it. + *regno = 65; + return true; + case 0 ... 107: + case 109 ... (114 - 1) -1: + return true; + case 1200 ... 1231: + *regno = *regno - 1200 + (114 - 1); + return true; + default: + return false; + } + abort (); +} + +__typeof (ppc_dwarf_to_regno) + ppc64_dwarf_to_regno + __attribute__ ((alias ("ppc_dwarf_to_regno"))); + +bool +ppc_set_initial_registers_tid (pid_t tid __attribute__ ((unused)), + ebl_tid_registers_t *setfunc __attribute__ ((unused)), + void *arg __attribute__ ((unused))) +{ +#ifndef __powerpc__ + return false; +#else /* __powerpc__ */ + union + { + struct pt_regs r; + long l[sizeof (struct pt_regs) / sizeof (long)]; + } + user_regs; + eu_static_assert (sizeof (struct pt_regs) % sizeof (long) == 0); + /* PTRACE_GETREGS is EIO on kernel-2.6.18-308.el5.ppc64. */ + errno = 0; + for (unsigned regno = 0; regno < sizeof (user_regs) / sizeof (long); + regno++) + { + user_regs.l[regno] = ptrace (PTRACE_PEEKUSER, tid, + (void *) (uintptr_t) (regno + * sizeof (long)), + NULL); + if (errno != 0) + return false; + } + const size_t gprs = sizeof (user_regs.r.gpr) / sizeof (*user_regs.r.gpr); + Dwarf_Word dwarf_regs[gprs]; + for (unsigned gpr = 0; gpr < gprs; gpr++) + dwarf_regs[gpr] = user_regs.r.gpr[gpr]; + if (! setfunc (0, gprs, dwarf_regs, arg)) + return false; + dwarf_regs[0] = user_regs.r.link; + // LR uses both 65 and 108 numbers, there is no consistency for it. + if (! setfunc (65, 1, dwarf_regs, arg)) + return false; + /* Registers like msr, ctr, xer, dar, dsisr etc. are probably irrelevant + for CFI. */ + dwarf_regs[0] = user_regs.r.nip; + return setfunc (-1, 1, dwarf_regs, arg); +#endif /* __powerpc__ */ +} + +__typeof (ppc_set_initial_registers_tid) + ppc64_set_initial_registers_tid + __attribute__ ((alias ("ppc_set_initial_registers_tid"))); diff --git a/3rdparty/elfutils/backends/ppc_regs.c b/3rdparty/elfutils/backends/ppc_regs.c new file mode 100644 index 0000000..4b92a9a --- /dev/null +++ b/3rdparty/elfutils/backends/ppc_regs.c @@ -0,0 +1,200 @@ +/* Register names and numbers for PowerPC DWARF. + Copyright (C) 2005, 2006, 2007 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> +#include <dwarf.h> + +#define BACKEND ppc_ +#include "libebl_CPU.h" + +ssize_t +ppc_register_info (Ebl *ebl __attribute__ ((unused)), + int regno, char *name, size_t namelen, + const char **prefix, const char **setname, + int *bits, int *type) +{ + if (name == NULL) + return 1156; + + if (regno < 0 || regno > 1155 || namelen < 8) + return -1; + + *prefix = ""; + *bits = ebl->machine == EM_PPC64 ? 64 : 32; + *type = (regno < 32 ? DW_ATE_signed + : regno < 64 ? DW_ATE_float : DW_ATE_unsigned); + + if (regno < 32 || regno == 64 || regno == 66) + *setname = "integer"; + else if (regno < 64 || regno == 65) + { + *setname = "FPU"; + if (ebl->machine != EM_PPC64 && regno < 64) + *bits = 64; + } + else if (regno == 67 || regno == 356 || regno == 612 || regno >= 1124) + { + *setname = "vector"; + *bits = regno >= 1124 ? 128 : 32; + } + else + *setname = "privileged"; + + switch (regno) + { + case 0 ... 9: + name[0] = 'r'; + name[1] = regno + '0'; + namelen = 2; + break; + + case 10 ... 31: + name[0] = 'r'; + name[1] = regno / 10 + '0'; + name[2] = regno % 10 + '0'; + namelen = 3; + break; + + case 32 + 0 ... 32 + 9: + name[0] = 'f'; + name[1] = (regno - 32) + '0'; + namelen = 2; + break; + + case 32 + 10 ... 32 + 31: + name[0] = 'f'; + name[1] = (regno - 32) / 10 + '0'; + name[2] = (regno - 32) % 10 + '0'; + namelen = 3; + break; + + case 64: + return stpcpy (name, "cr") + 1 - name; + case 65: + return stpcpy (name, "fpscr") + 1 - name; + case 66: + return stpcpy (name, "msr") + 1 - name; + case 67: /* XXX unofficial assignment */ + return stpcpy (name, "vscr") + 1 - name; + + case 70 + 0 ... 70 + 9: + name[0] = 's'; + name[1] = 'r'; + name[2] = (regno - 70) + '0'; + namelen = 3; + break; + + case 70 + 10 ... 70 + 15: + name[0] = 's'; + name[1] = 'r'; + name[2] = (regno - 70) / 10 + '0'; + name[3] = (regno - 70) % 10 + '0'; + namelen = 4; + break; + + case 101: + return stpcpy (name, "xer") + 1 - name; + case 108: + return stpcpy (name, "lr") + 1 - name; + case 109: + return stpcpy (name, "ctr") + 1 - name; + case 118: + return stpcpy (name, "dsisr") + 1 - name; + case 119: + return stpcpy (name, "dar") + 1 - name; + case 122: + return stpcpy (name, "dec") + 1 - name; + case 356: + return stpcpy (name, "vrsave") + 1 - name; + case 612: + return stpcpy (name, "spefscr") + 1 - name; + case 100: + if (*bits == 32) + return stpcpy (name, "mq") + 1 - name; + + case 102 ... 107: + name[0] = 's'; + name[1] = 'p'; + name[2] = 'r'; + name[3] = (regno - 100) + '0'; + namelen = 4; + break; + + case 110 ... 117: + case 120 ... 121: + case 123 ... 199: + name[0] = 's'; + name[1] = 'p'; + name[2] = 'r'; + name[3] = (regno - 100) / 10 + '0'; + name[4] = (regno - 100) % 10 + '0'; + namelen = 5; + break; + + case 200 ... 355: + case 357 ... 611: + case 613 ... 999: + name[0] = 's'; + name[1] = 'p'; + name[2] = 'r'; + name[3] = (regno - 100) / 100 + '0'; + name[4] = ((regno - 100) % 100 / 10) + '0'; + name[5] = (regno - 100) % 10 + '0'; + namelen = 6; + break; + + case 1124 + 0 ... 1124 + 9: + name[0] = 'v'; + name[1] = 'r'; + name[2] = (regno - 1124) + '0'; + namelen = 3; + break; + + case 1124 + 10 ... 1124 + 31: + name[0] = 'v'; + name[1] = 'r'; + name[2] = (regno - 1124) / 10 + '0'; + name[3] = (regno - 1124) % 10 + '0'; + namelen = 4; + break; + + default: + *setname = NULL; + return 0; + } + + name[namelen++] = '\0'; + return namelen; +} + +__typeof (ppc_register_info) + ppc64_register_info __attribute__ ((alias ("ppc_register_info"))); diff --git a/3rdparty/elfutils/backends/ppc_reloc.def b/3rdparty/elfutils/backends/ppc_reloc.def new file mode 100644 index 0000000..dc963a0 --- /dev/null +++ b/3rdparty/elfutils/backends/ppc_reloc.def @@ -0,0 +1,137 @@ +/* List the relocation types for ppc. -*- C -*- + Copyright (C) 2005 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +/* NAME, REL|EXEC|DYN */ + +RELOC_TYPE (NONE, 0) +RELOC_TYPE (ADDR32, REL|EXEC|DYN) +RELOC_TYPE (ADDR24, REL) +RELOC_TYPE (ADDR16, REL|EXEC|DYN) /* note 1 */ +RELOC_TYPE (ADDR16_LO, REL|EXEC|DYN) /* note 1 */ +RELOC_TYPE (ADDR16_HI, REL|EXEC|DYN) /* note 1 */ +RELOC_TYPE (ADDR16_HA, REL|EXEC|DYN) /* note 1 */ +RELOC_TYPE (ADDR14, REL|EXEC|DYN) /* note 1 */ +RELOC_TYPE (ADDR14_BRTAKEN, REL|EXEC|DYN) /* note 1 */ +RELOC_TYPE (ADDR14_BRNTAKEN, REL|EXEC|DYN) /* note 1 */ +RELOC_TYPE (REL24, REL|EXEC|DYN) /* note 1 */ +RELOC_TYPE (REL14, REL|EXEC|DYN) /* note 1 */ +RELOC_TYPE (REL14_BRTAKEN, REL|EXEC|DYN) /* note 1 */ +RELOC_TYPE (REL14_BRNTAKEN, REL|EXEC|DYN) /* note 1 */ +RELOC_TYPE (GOT16, REL) +RELOC_TYPE (GOT16_LO, REL) +RELOC_TYPE (GOT16_HI, REL) +RELOC_TYPE (GOT16_HA, REL) +RELOC_TYPE (PLTREL24, REL) +RELOC_TYPE (COPY, EXEC) +RELOC_TYPE (GLOB_DAT, EXEC|DYN) +RELOC_TYPE (JMP_SLOT, EXEC|DYN) +RELOC_TYPE (RELATIVE, EXEC|DYN) +RELOC_TYPE (LOCAL24PC, REL) +RELOC_TYPE (UADDR32, REL|EXEC|DYN) +RELOC_TYPE (UADDR16, REL) /* note 2 */ +RELOC_TYPE (REL32, REL|EXEC|DYN) +RELOC_TYPE (PLT32, REL) +RELOC_TYPE (PLTREL32, REL) +RELOC_TYPE (PLT16_LO, REL) +RELOC_TYPE (PLT16_HI, REL) +RELOC_TYPE (PLT16_HA, REL) +RELOC_TYPE (SDAREL16, REL) +RELOC_TYPE (SECTOFF, REL) +RELOC_TYPE (SECTOFF_LO, REL) +RELOC_TYPE (SECTOFF_HI, REL) +RELOC_TYPE (SECTOFF_HA, REL) +RELOC_TYPE (TLS, REL) +RELOC_TYPE (DTPMOD32, EXEC|DYN) /* note 2 */ +RELOC_TYPE (TPREL16, REL) /* note 2 */ +RELOC_TYPE (TPREL16_LO, REL) /* note 2 */ +RELOC_TYPE (TPREL16_HI, REL) /* note 2 */ +RELOC_TYPE (TPREL16_HA, REL) /* note 2 */ +RELOC_TYPE (TPREL32, EXEC|DYN) /* note 2 */ +RELOC_TYPE (DTPREL16, REL) +RELOC_TYPE (DTPREL16_LO, REL) +RELOC_TYPE (DTPREL16_HI, REL) +RELOC_TYPE (DTPREL16_HA, REL) +RELOC_TYPE (DTPREL32, EXEC|DYN) /* note 2 */ +RELOC_TYPE (GOT_TLSGD16, REL) +RELOC_TYPE (GOT_TLSGD16_LO, REL) +RELOC_TYPE (GOT_TLSGD16_HI, REL) +RELOC_TYPE (GOT_TLSGD16_HA, REL) +RELOC_TYPE (GOT_TLSLD16, REL) +RELOC_TYPE (GOT_TLSLD16_LO, REL) +RELOC_TYPE (GOT_TLSLD16_HI, REL) +RELOC_TYPE (GOT_TLSLD16_HA, REL) +RELOC_TYPE (GOT_TPREL16, REL) +RELOC_TYPE (GOT_TPREL16_LO, REL) +RELOC_TYPE (GOT_TPREL16_HI, REL) +RELOC_TYPE (GOT_TPREL16_HA, REL) +RELOC_TYPE (GOT_DTPREL16, REL) +RELOC_TYPE (GOT_DTPREL16_LO, REL) +RELOC_TYPE (GOT_DTPREL16_HI, REL) +RELOC_TYPE (GOT_DTPREL16_HA, REL) +RELOC_TYPE (EMB_NADDR32, REL) /* note 3 */ +RELOC_TYPE (EMB_NADDR16, REL) /* note 3 */ +RELOC_TYPE (EMB_NADDR16_LO, REL) /* note 3 */ +RELOC_TYPE (EMB_NADDR16_HI, REL) /* note 3 */ +RELOC_TYPE (EMB_NADDR16_HA, REL) /* note 3 */ +RELOC_TYPE (EMB_SDAI16, REL) /* note 3 */ +RELOC_TYPE (EMB_SDA2I16, REL) /* note 3 */ +RELOC_TYPE (EMB_SDA2REL, REL) /* note 3 */ +RELOC_TYPE (EMB_SDA21, REL) /* note 3 */ +RELOC_TYPE (EMB_MRKREF, REL) /* note 3 */ +RELOC_TYPE (EMB_RELSEC16, REL) /* note 3 */ +RELOC_TYPE (EMB_RELST_LO, REL) /* note 3 */ +RELOC_TYPE (EMB_RELST_HI, REL) /* note 3 */ +RELOC_TYPE (EMB_RELST_HA, REL) /* note 3 */ +RELOC_TYPE (EMB_BIT_FLD, REL) /* note 3 */ +RELOC_TYPE (EMB_RELSDA, REL) /* note 3 */ +RELOC_TYPE (DIAB_SDA21_LO, REL) /* note 3 */ +RELOC_TYPE (DIAB_SDA21_HI, REL) /* note 3 */ +RELOC_TYPE (DIAB_SDA21_HA, REL) /* note 3 */ +RELOC_TYPE (DIAB_RELSDA_LO, REL) /* note 3 */ +RELOC_TYPE (DIAB_RELSDA_HI, REL) /* note 3 */ +RELOC_TYPE (DIAB_RELSDA_HA, REL) /* note 3 */ +RELOC_TYPE (REL16, REL) /* note 2 */ +RELOC_TYPE (REL16_LO, REL) /* note 2 */ +RELOC_TYPE (REL16_HI, REL) /* note 2 */ +RELOC_TYPE (REL16_HA, REL) /* note 2 */ +RELOC_TYPE (TOC16, REL) /* note 2 */ + +/* Notes from Alan Modra: + + 1) These relocs should not really appear in EXEC or DYN, but they do, + primarily due to improper assembly or non-pic shared objects. They + will cause TEXTREL to be set. I marked them in the table, because + numerous people seem to think non-pic shared libs are a good idea. + + 2) As for (1), these relocs can appear anywhere with improper + assembler. I should probably make ld reject anything other than the + cases allowed in this table. Not seen in the wild, so I haven't + added the other cases. + + 3) Not used in SYSV4 +*/ diff --git a/3rdparty/elfutils/backends/ppc_retval.c b/3rdparty/elfutils/backends/ppc_retval.c new file mode 100644 index 0000000..b14a99f --- /dev/null +++ b/3rdparty/elfutils/backends/ppc_retval.c @@ -0,0 +1,191 @@ +/* Function return value location for Linux/PPC ABI. + Copyright (C) 2005, 2006, 2007, 2010, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> + +#define BACKEND ppc_ +#include "libebl_CPU.h" + + +/* This is the SVR4 ELF ABI convention, but AIX and Linux do not use it. */ +#define SVR4_STRUCT_RETURN 0 + + +/* r3, or pair r3, r4, or quad r3-r6. */ +static const Dwarf_Op loc_intreg[] = + { + { .atom = DW_OP_reg3 }, { .atom = DW_OP_piece, .number = 4 }, + { .atom = DW_OP_reg4 }, { .atom = DW_OP_piece, .number = 4 }, + { .atom = DW_OP_reg5 }, { .atom = DW_OP_piece, .number = 4 }, + { .atom = DW_OP_reg6 }, { .atom = DW_OP_piece, .number = 4 }, + }; +#define nloc_intreg 1 +#define nloc_intregpair 4 +#define nloc_intregquad 8 + +/* f1. */ +static const Dwarf_Op loc_fpreg[] = + { + { .atom = DW_OP_regx, .number = 33 } + }; +#define nloc_fpreg 1 + +/* vr2. */ +static const Dwarf_Op loc_vmxreg[] = + { + { .atom = DW_OP_regx, .number = 1124 + 2 } + }; +#define nloc_vmxreg 1 + +/* The return value is a structure and is actually stored in stack space + passed in a hidden argument by the caller. But, the compiler + helpfully returns the address of that space in r3. */ +static const Dwarf_Op loc_aggregate[] = + { + { .atom = DW_OP_breg3, .number = 0 } + }; +#define nloc_aggregate 1 + + +/* XXX We should check the SHT_GNU_ATTRIBUTES bits here (or in ppc_init). */ +static bool +ppc_altivec_abi (void) +{ + return true; +} + +int +ppc_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp) +{ + /* Start with the function's type, and get the DW_AT_type attribute, + which is the type of the return value. */ + Dwarf_Die die_mem, *typedie = &die_mem; + int tag = dwarf_peeled_die_type (functypedie, typedie); + if (tag <= 0) + return tag; + + Dwarf_Word size; + switch (tag) + { + case -1: + return -1; + + case DW_TAG_subrange_type: + if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size)) + { + Dwarf_Attribute attr_mem, *attr; + attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem); + typedie = dwarf_formref_die (attr, &die_mem); + tag = DWARF_TAG_OR_RETURN (typedie); + } + /* Fall through. */ + + case DW_TAG_base_type: + case DW_TAG_enumeration_type: + case DW_TAG_pointer_type: + case DW_TAG_ptr_to_member_type: + { + Dwarf_Attribute attr_mem; + if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size, + &attr_mem), &size) != 0) + { + if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type) + size = 4; + else + return -1; + } + } + + if (size <= 8) + { + if (tag == DW_TAG_base_type) + { + Dwarf_Attribute attr_mem; + Dwarf_Word encoding; + if (dwarf_formudata (dwarf_attr_integrate (typedie, + DW_AT_encoding, + &attr_mem), + &encoding) != 0) + return -1; + if (encoding == DW_ATE_float) + { + *locp = loc_fpreg; + return nloc_fpreg; + } + } + intreg: + *locp = loc_intreg; + return size <= 4 ? nloc_intreg : nloc_intregpair; + } + + aggregate: + *locp = loc_aggregate; + return nloc_aggregate; + + case DW_TAG_array_type: + { + Dwarf_Attribute attr_mem; + bool is_vector; + if (dwarf_formflag (dwarf_attr_integrate (typedie, DW_AT_GNU_vector, + &attr_mem), &is_vector) == 0 + && is_vector + && dwarf_aggregate_size (typedie, &size) == 0) + switch (size) + { + case 16: + if (ppc_altivec_abi ()) + { + *locp = loc_vmxreg; + return nloc_vmxreg; + } + *locp = loc_intreg; + return nloc_intregquad; + } + } + /* Fall through. */ + + case DW_TAG_structure_type: + case DW_TAG_class_type: + case DW_TAG_union_type: + if (SVR4_STRUCT_RETURN + && dwarf_aggregate_size (typedie, &size) == 0 + && size > 0 && size <= 8) + goto intreg; + goto aggregate; + } + + /* XXX We don't have a good way to return specific errors from ebl calls. + This value means we do not understand the type, but it is well-formed + DWARF and might be valid. */ + return -2; +} diff --git a/3rdparty/elfutils/backends/ppc_symbol.c b/3rdparty/elfutils/backends/ppc_symbol.c new file mode 100644 index 0000000..c17ab37 --- /dev/null +++ b/3rdparty/elfutils/backends/ppc_symbol.c @@ -0,0 +1,165 @@ +/* PPC specific symbolic name handling. + Copyright (C) 2004, 2005, 2007, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <elf.h> +#include <stddef.h> +#include <string.h> + +#define BACKEND ppc_ +#include "libebl_CPU.h" + + +/* Check for the simple reloc types. */ +Elf_Type +ppc_reloc_simple_type (Ebl *ebl __attribute__ ((unused)), int type) +{ + switch (type) + { + case R_PPC_ADDR32: + case R_PPC_UADDR32: + return ELF_T_WORD; + case R_PPC_UADDR16: + return ELF_T_HALF; + default: + return ELF_T_NUM; + } +} + + +const char * +ppc_dynamic_tag_name (int64_t tag, char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + switch (tag) + { + case DT_PPC_GOT: + return "PPC_GOT"; + default: + break; + } + return NULL; +} + + +bool +ppc_dynamic_tag_check (int64_t tag) +{ + return tag == DT_PPC_GOT; +} + + +/* Look for DT_PPC_GOT. */ +static bool +find_dyn_got (Elf *elf, GElf_Addr *addr) +{ + size_t phnum; + if (elf_getphdrnum (elf, &phnum) != 0) + return false; + + for (size_t i = 0; i < phnum; ++i) + { + GElf_Phdr phdr_mem; + GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem); + if (phdr == NULL || phdr->p_type != PT_DYNAMIC) + continue; + + Elf_Scn *scn = gelf_offscn (elf, phdr->p_offset); + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + Elf_Data *data = elf_getdata (scn, NULL); + if (shdr != NULL && shdr->sh_type == SHT_DYNAMIC && data != NULL) + for (unsigned int j = 0; j < shdr->sh_size / shdr->sh_entsize; ++j) + { + GElf_Dyn dyn_mem; + GElf_Dyn *dyn = gelf_getdyn (data, j, &dyn_mem); + if (dyn != NULL && dyn->d_tag == DT_PPC_GOT) + { + *addr = dyn->d_un.d_ptr; + return true; + } + } + + /* There is only one PT_DYNAMIC entry. */ + break; + } + + return false; +} + + +/* Check whether given symbol's st_value and st_size are OK despite failing + normal checks. */ +bool +ppc_check_special_symbol (Elf *elf, GElf_Ehdr *ehdr, const GElf_Sym *sym, + const char *name, const GElf_Shdr *destshdr) +{ + if (name == NULL) + return false; + + if (strcmp (name, "_GLOBAL_OFFSET_TABLE_") == 0) + { + /* In -msecure-plt mode, DT_PPC_GOT is present and must match. */ + GElf_Addr gotaddr; + if (find_dyn_got (elf, &gotaddr)) + return sym->st_value == gotaddr; + + /* In -mbss-plt mode, any place in the section is valid. */ + return true; + } + + const char *sname = elf_strptr (elf, ehdr->e_shstrndx, destshdr->sh_name); + if (sname == NULL) + return false; + + if (strcmp (name, "_SDA_BASE_") == 0) + return (strcmp (sname, ".sdata") == 0 + && sym->st_value == destshdr->sh_addr + 0x8000 + && sym->st_size == 0); + + if (strcmp (name, "_SDA2_BASE_") == 0) + return (strcmp (sname, ".sdata2") == 0 + && sym->st_value == destshdr->sh_addr + 0x8000 + && sym->st_size == 0); + + return false; +} + + +/* Check if backend uses a bss PLT in this file. */ +bool +ppc_bss_plt_p (Elf *elf) +{ + GElf_Addr addr; + return ! find_dyn_got (elf, &addr); +} diff --git a/3rdparty/elfutils/backends/ppc_syscall.c b/3rdparty/elfutils/backends/ppc_syscall.c new file mode 100644 index 0000000..b1b9c52 --- /dev/null +++ b/3rdparty/elfutils/backends/ppc_syscall.c @@ -0,0 +1,53 @@ +/* Linux/PPC system call ABI in DWARF register numbers. + Copyright (C) 2008 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND ppc_ +#include "libebl_CPU.h" + +int +ppc_syscall_abi (Ebl *ebl __attribute__ ((unused)), + int *sp, int *pc, int *callno, int args[6]) +{ + *sp = 1; + *pc = -1; + *callno = 0; + args[0] = 3; + args[1] = 4; + args[2] = 5; + args[3] = 6; + args[4] = 7; + args[5] = 8; + return 0; +} + +__typeof (ppc_syscall_abi) +ppc64_syscall_abi __attribute__ ((alias ("ppc_syscall_abi"))); diff --git a/3rdparty/elfutils/backends/s390/s390.pro b/3rdparty/elfutils/backends/s390/s390.pro new file mode 100644 index 0000000..73d3bec --- /dev/null +++ b/3rdparty/elfutils/backends/s390/s390.pro @@ -0,0 +1,17 @@ +TEMPLATE = lib +include(../backends.pri) +TARGET = ../ebl_s390 + +SOURCES += \ + ../s390_cfi.c \ + ../s390_corenote.c \ + ../s390_init.c \ + ../s390_initreg.c \ + ../s390_regs.c \ + ../s390_retval.c \ + ../s390_symbol.c \ + ../s390_unwind.c \ + ../s390x_corenote.c + +HEADERS += \ + ../s390_reloc.def diff --git a/3rdparty/elfutils/backends/s390_cfi.c b/3rdparty/elfutils/backends/s390_cfi.c new file mode 100644 index 0000000..cb49486 --- /dev/null +++ b/3rdparty/elfutils/backends/s390_cfi.c @@ -0,0 +1,65 @@ +/* s390 ABI-specified defaults for DWARF CFI. + Copyright (C) 2012, 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> + +#define BACKEND s390_ +#include "libebl_CPU.h" + +int +s390_abi_cfi (Ebl *ebl, Dwarf_CIE *abi_info) +{ + static const uint8_t abi_cfi[] = + { + /* This instruction is provided in every CIE. It is not repeated here: + DW_CFA_def_cfa, ULEB128_7 (15), ULEB128_7 (96) */ + /* r14 is not callee-saved but it needs to be preserved as it is pre-set + by the caller. */ + DW_CFA_same_value, ULEB128_7 (14), /* r14 */ + + /* Callee-saved regs. */ +#define SV(n) DW_CFA_same_value, ULEB128_7 (n) + SV (6), SV (7), SV (8), SV (9), SV (10), /* r6-r13, r15 */ + SV (11), SV (12), SV (13), SV (15), + SV (16 + 8), SV (16 + 9), SV (16 + 10), SV (16 + 11), /* f8-f15 */ + SV (16 + 12), SV (16 + 13), SV (16 + 14), SV (16 + 15) +#undef SV + }; + + abi_info->initial_instructions = abi_cfi; + abi_info->initial_instructions_end = &abi_cfi[sizeof abi_cfi]; + abi_info->data_alignment_factor = ebl->class == ELFCLASS64 ? 8 : 4; + + abi_info->return_address_register = 14; + + return 0; +} diff --git a/3rdparty/elfutils/backends/s390_corenote.c b/3rdparty/elfutils/backends/s390_corenote.c new file mode 100644 index 0000000..7ca3516 --- /dev/null +++ b/3rdparty/elfutils/backends/s390_corenote.c @@ -0,0 +1,189 @@ +/* S390-specific core note handling. + Copyright (C) 2012 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <elf.h> +#include <inttypes.h> +#include <stddef.h> +#include <stdio.h> +#include <sys/time.h> + +#ifndef BITS +# define BITS 32 +# define BACKEND s390_ +#else +# define BITS 64 +# define BACKEND s390x_ +#endif +#include "libebl_CPU.h" + +static const Ebl_Register_Location prstatus_regs[] = + { +#define GR(at, n, dwreg, b...) \ + { .offset = at * BITS/8, .regno = dwreg, .count = n, .bits = b } + + GR ( 0, 1, 64, BITS), /* pswm */ + GR ( 1, 1, 65, BITS, .pc_register = true ), /* pswa */ + GR ( 2, 16, 0, BITS), /* r0-r15 */ + GR (18, 16, 48, 32), /* ar0-ar15 */ + +#undef GR + }; + + /* orig_r2 is at offset (BITS == 32 ? 34 * 4 : 26 * 8). */ +#define PRSTATUS_REGS_SIZE (BITS / 8 * (BITS == 32 ? 35 : 27)) + +static const Ebl_Register_Location fpregset_regs[] = + { +#define FPR(at, n, dwreg) \ + { .offset = at * 64/8, .regno = dwreg, .count = n, .bits = 64 } + + /* fpc is at offset 0, see fpregset_items, it has no assigned DWARF regno. + Bytes at offsets 4 to 7 are unused. */ + FPR (1 + 0, 1, 16), /* f0 */ + FPR (1 + 1, 1, 20), /* f1 */ + FPR (1 + 2, 1, 17), /* f2 */ + FPR (1 + 3, 1, 21), /* f3 */ + FPR (1 + 4, 1, 18), /* f4 */ + FPR (1 + 5, 1, 22), /* f5 */ + FPR (1 + 6, 1, 19), /* f6 */ + FPR (1 + 7, 1, 23), /* f7 */ + FPR (1 + 8, 1, 24), /* f8 */ + FPR (1 + 9, 1, 28), /* f9 */ + FPR (1 + 10, 1, 25), /* f10 */ + FPR (1 + 11, 1, 29), /* f11 */ + FPR (1 + 12, 1, 26), /* f12 */ + FPR (1 + 13, 1, 30), /* f13 */ + FPR (1 + 14, 1, 27), /* f14 */ + FPR (1 + 15, 1, 31), /* f15 */ + +#undef FPR + }; + +static const Ebl_Core_Item fpregset_items[] = + { + { + .name = "fpc", .group = "register", .offset = 0, .type = ELF_T_WORD, + .format = 'x', + }, + }; + +/* Do not set FPREGSET_SIZE so that we can supply fpregset_items. */ +#define EXTRA_NOTES_FPREGSET \ + EXTRA_REGSET_ITEMS (NT_FPREGSET, 17 * 8, fpregset_regs, fpregset_items) + +#if BITS == 32 +# define ULONG uint32_t +# define ALIGN_ULONG 4 +# define TYPE_ULONG ELF_T_WORD +# define TYPE_LONG ELF_T_SWORD +# define UID_T uint16_t +# define GID_T uint16_t +# define ALIGN_UID_T 2 +# define ALIGN_GID_T 2 +# define TYPE_UID_T ELF_T_HALF +# define TYPE_GID_T ELF_T_HALF +#else +# define ULONG uint64_t +# define ALIGN_ULONG 8 +# define TYPE_ULONG ELF_T_XWORD +# define TYPE_LONG ELF_T_SXWORD +# define UID_T uint32_t +# define GID_T uint32_t +# define ALIGN_UID_T 4 +# define ALIGN_GID_T 4 +# define TYPE_UID_T ELF_T_WORD +# define TYPE_GID_T ELF_T_WORD +#endif +#define PID_T int32_t +#define ALIGN_PID_T 4 +#define TYPE_PID_T ELF_T_SWORD +/* s390 psw_compat_t has alignment 8 bytes where it is inherited from. */ +#define ALIGN_PR_REG 8 + +#define PRSTATUS_REGSET_ITEMS \ + { \ + .name = "orig_r2", .type = TYPE_LONG, .format = 'd', \ + .offset = offsetof (struct EBLHOOK(prstatus), \ + pr_reg[BITS == 32 ? 34 : 26]), \ + .group = "register" \ + } + +#if BITS == 32 + +static const Ebl_Core_Item high_regs_items[] = + { +#define HR(n) \ + { \ + .name = "high_r" #n , .group = "register", .offset = (n) * 4, \ + .type = ELF_T_WORD, .format = 'x', \ + } + + /* Upper halves of r0-r15 are stored here. + FIXME: They are currently not combined with the r0-r15 lower halves. */ + HR (0), HR (1), HR (2), HR (3), HR (4), HR (5), HR (6), HR (7), + HR (8), HR (9), HR (10), HR (11), HR (12), HR (13), HR (14), HR (15) + +#undef HR + }; + +#define EXTRA_NOTES_HIGH_GPRS \ + EXTRA_ITEMS (NT_S390_HIGH_GPRS, 16 * 4, high_regs_items) + +#else /* BITS == 64 */ + +#define EXTRA_NOTES_HIGH_GPRS + +#endif /* BITS == 64 */ + +static const Ebl_Core_Item last_break_items[] = + { + { + .name = "last_break", .group = "system", .offset = BITS == 32 ? 4 : 0, + .type = BITS == 32 ? ELF_T_WORD : ELF_T_XWORD, .format = 'x', + }, + }; + +static const Ebl_Core_Item system_call_items[] = + { + { + .name = "system_call", .group = "system", .offset = 0, .type = ELF_T_WORD, + .format = 'd', + }, + }; + +#define EXTRA_NOTES \ + EXTRA_NOTES_FPREGSET \ + EXTRA_NOTES_HIGH_GPRS \ + EXTRA_ITEMS (NT_S390_LAST_BREAK, 8, last_break_items) \ + EXTRA_ITEMS (NT_S390_SYSTEM_CALL, 4, system_call_items) + +#include "linux-core-note.c" diff --git a/3rdparty/elfutils/backends/s390_init.c b/3rdparty/elfutils/backends/s390_init.c new file mode 100644 index 0000000..26b20b4 --- /dev/null +++ b/3rdparty/elfutils/backends/s390_init.c @@ -0,0 +1,80 @@ +/* Initialization of S/390 specific backend library. + Copyright (C) 2005, 2006, 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND s390_ +#define RELOC_PREFIX R_390_ +#include "libebl_CPU.h" + +/* This defines the common reloc hooks based on arm_reloc.def. */ +#include "common-reloc.c" + +extern __typeof (s390_core_note) s390x_core_note; + + +const char * +s390_init (elf, machine, eh, ehlen) + Elf *elf __attribute__ ((unused)); + GElf_Half machine __attribute__ ((unused)); + Ebl *eh; + size_t ehlen; +{ + /* Check whether the Elf_BH object has a sufficent size. */ + if (ehlen < sizeof (Ebl)) + return NULL; + + /* We handle it. */ + eh->name = "IBM S/390"; + s390_init_reloc (eh); + HOOK (eh, reloc_simple_type); + HOOK (eh, register_info); + HOOK (eh, return_value_location); + if (eh->class == ELFCLASS64) + eh->core_note = s390x_core_note; + else + HOOK (eh, core_note); + HOOK (eh, abi_cfi); + /* gcc/config/ #define DWARF_FRAME_REGISTERS 34. + But from the gcc/config/s390/s390.h "Register usage." comment it looks as + if #32 (Argument pointer) and #33 (Condition code) are not used for + unwinding. */ + eh->frame_nregs = 32; + HOOK (eh, set_initial_registers_tid); + if (eh->class == ELFCLASS32) + HOOK (eh, normalize_pc); + HOOK (eh, unwind); + + /* Only the 64-bit format uses the incorrect hash table entry size. */ + if (eh->class == ELFCLASS64) + eh->sysvhash_entrysize = sizeof (Elf64_Xword); + + return MODVERSION; +} diff --git a/3rdparty/elfutils/backends/s390_initreg.c b/3rdparty/elfutils/backends/s390_initreg.c new file mode 100644 index 0000000..b4c4b67 --- /dev/null +++ b/3rdparty/elfutils/backends/s390_initreg.c @@ -0,0 +1,95 @@ +/* Fetch live process registers from TID. + Copyright (C) 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "system.h" +#include <assert.h> +#ifdef __s390__ +# include <sys/user.h> +# include <asm/ptrace.h> +# include <sys/ptrace.h> +#endif + +#define BACKEND s390_ +#include "libebl_CPU.h" + +bool +s390_set_initial_registers_tid (pid_t tid __attribute__ ((unused)), + ebl_tid_registers_t *setfunc __attribute__ ((unused)), + void *arg __attribute__ ((unused))) +{ +#ifndef __s390__ + return false; +#else /* __s390__ */ + struct user user_regs; + ptrace_area parea; + parea.process_addr = (uintptr_t) &user_regs; + parea.kernel_addr = 0; + parea.len = sizeof (user_regs); + if (ptrace (PTRACE_PEEKUSR_AREA, tid, &parea, NULL) != 0) + return false; + /* If we run as s390x we get the 64-bit registers of tid. + But -m31 executable seems to use only the 32-bit parts of its + registers so we ignore the upper half. */ + Dwarf_Word dwarf_regs[16]; + for (unsigned u = 0; u < 16; u++) + dwarf_regs[u] = user_regs.regs.gprs[u]; + if (! setfunc (0, 16, dwarf_regs, arg)) + return false; + /* Avoid conversion double -> integer. */ + eu_static_assert (sizeof user_regs.regs.fp_regs.fprs[0] + == sizeof dwarf_regs[0]); + for (unsigned u = 0; u < 16; u++) + { + // Store the double bits as is in the Dwarf_Word without conversion. + union + { + double d; + Dwarf_Word w; + } fpr = { .d = user_regs.regs.fp_regs.fprs[u] }; + dwarf_regs[u] = fpr.w; + } + + if (! setfunc (16, 16, dwarf_regs, arg)) + return false; + dwarf_regs[0] = user_regs.regs.psw.addr; + return setfunc (-1, 1, dwarf_regs, arg); +#endif /* __s390__ */ +} + +void +s390_normalize_pc (Ebl *ebl __attribute__ ((unused)), Dwarf_Addr *pc) +{ + assert (ebl->class == ELFCLASS32); + + /* Clear S390 bit 31. */ + *pc &= (1U << 31) - 1; +} diff --git a/3rdparty/elfutils/backends/s390_regs.c b/3rdparty/elfutils/backends/s390_regs.c new file mode 100644 index 0000000..ba6178a --- /dev/null +++ b/3rdparty/elfutils/backends/s390_regs.c @@ -0,0 +1,146 @@ +/* Register names and numbers for S/390 DWARF. + Copyright (C) 2006 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> +#include <dwarf.h> + +#define BACKEND s390_ +#include "libebl_CPU.h" + + +/* +zseries (64) + +0-15 gpr0-gpr15 x +16-19 fpr[0246] +20-24 fpr[13578] +25-27 fpr1[024] +28 fpr9 +29-31 fpr1[135] +32-47 cr0-cr15 x +48-63 ar0-ar15 x +64 psw_mask +65 psw_address +*/ + + +ssize_t +s390_register_info (Ebl *ebl __attribute__ ((unused)), + int regno, char *name, size_t namelen, + const char **prefix, const char **setname, + int *bits, int *type) +{ + if (name == NULL) + return 66; + + if (regno < 0 || regno > 65 || namelen < 7) + return -1; + + *prefix = "%"; + + *bits = ebl->class == ELFCLASS64 ? 64 : 32; + *type = DW_ATE_unsigned; + if (regno < 16) + { + *setname = "integer"; + *type = DW_ATE_signed; + } + else if (regno < 32) + { + *setname = "FPU"; + *type = DW_ATE_float; + *bits = 64; + } + else if (regno < 48 || regno > 63) + *setname = "control"; + else + { + *setname = "access"; + *bits = 32; + } + + switch (regno) + { + case 0 ... 9: + name[0] = 'r'; + name[1] = regno + '0'; + namelen = 2; + break; + + case 10 ... 15: + name[0] = 'r'; + name[1] = '1'; + name[2] = regno - 10 + '0'; + namelen = 3; + break; + + case 16 ... 31: + name[0] = 'f'; + regno = (regno & 8) | ((regno & 4) >> 2) | ((regno & 3) << 1); + namelen = 1; + if (regno >= 10) + { + regno -= 10; + name[namelen++] = '1'; + } + name[namelen++] = regno + '0'; + break; + + case 32 + 0 ... 32 + 9: + case 48 + 0 ... 48 + 9: + name[0] = regno < 48 ? 'c' : 'a'; + name[1] = (regno & 15) + '0'; + namelen = 2; + break; + + case 32 + 10 ... 32 + 15: + case 48 + 10 ... 48 + 15: + name[0] = regno < 48 ? 'c' : 'a'; + name[1] = '1'; + name[2] = (regno & 15) - 10 + '0'; + namelen = 3; + break; + + case 64: + return stpcpy (name, "pswm") + 1 - name; + case 65: + *type = DW_ATE_address; + return stpcpy (name, "pswa") + 1 - name; + + default: + *setname = NULL; + return 0; + } + + name[namelen++] = '\0'; + return namelen; +} diff --git a/3rdparty/elfutils/backends/s390_reloc.def b/3rdparty/elfutils/backends/s390_reloc.def new file mode 100644 index 0000000..b4686a3 --- /dev/null +++ b/3rdparty/elfutils/backends/s390_reloc.def @@ -0,0 +1,91 @@ +/* List the relocation types for s390. -*- C -*- + Copyright (C) 2005, 2006 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +/* NAME, REL|EXEC|DYN */ + +RELOC_TYPE (NONE, 0) +RELOC_TYPE (8, REL|EXEC|DYN) +RELOC_TYPE (12, REL|EXEC|DYN) +RELOC_TYPE (16, REL|EXEC|DYN) +RELOC_TYPE (32, REL|EXEC|DYN) +RELOC_TYPE (PC32, REL|EXEC|DYN) +RELOC_TYPE (GOT12, REL) +RELOC_TYPE (GOT32, REL) +RELOC_TYPE (PLT32, REL) +RELOC_TYPE (COPY, EXEC) +RELOC_TYPE (GLOB_DAT, EXEC|DYN) +RELOC_TYPE (JMP_SLOT, EXEC|DYN) +RELOC_TYPE (RELATIVE, EXEC|DYN) +RELOC_TYPE (GOTOFF32, REL) +RELOC_TYPE (GOTPC, REL) +RELOC_TYPE (GOT16, REL) +RELOC_TYPE (PC16, REL|EXEC|DYN) +RELOC_TYPE (PC16DBL, REL|EXEC|DYN) +RELOC_TYPE (PLT16DBL, REL) +RELOC_TYPE (PC32DBL, REL|EXEC|DYN) +RELOC_TYPE (PLT32DBL, REL) +RELOC_TYPE (GOTPCDBL, REL) +RELOC_TYPE (64, REL|EXEC|DYN) +RELOC_TYPE (PC64, REL|EXEC|DYN) +RELOC_TYPE (GOT64, REL) +RELOC_TYPE (PLT64, REL) +RELOC_TYPE (GOTENT, REL) +RELOC_TYPE (GOTOFF16, REL) +RELOC_TYPE (GOTOFF64, REL) +RELOC_TYPE (GOTPLT12, REL) +RELOC_TYPE (GOTPLT16, REL) +RELOC_TYPE (GOTPLT32, REL) +RELOC_TYPE (GOTPLT64, REL) +RELOC_TYPE (GOTPLTENT, REL) +RELOC_TYPE (PLTOFF16, REL) +RELOC_TYPE (PLTOFF32, REL) +RELOC_TYPE (PLTOFF64, REL) +RELOC_TYPE (TLS_LOAD, REL) +RELOC_TYPE (TLS_GDCALL, REL) +RELOC_TYPE (TLS_LDCALL, REL) +RELOC_TYPE (TLS_GD32, REL) +RELOC_TYPE (TLS_GD64, REL) +RELOC_TYPE (TLS_GOTIE12, REL) +RELOC_TYPE (TLS_GOTIE32, REL) +RELOC_TYPE (TLS_GOTIE64, REL) +RELOC_TYPE (TLS_LDM32, REL) +RELOC_TYPE (TLS_LDM64, REL) +RELOC_TYPE (TLS_IE32, REL) +RELOC_TYPE (TLS_IE64, REL) +RELOC_TYPE (TLS_IEENT, REL) +RELOC_TYPE (TLS_LE32, REL) +RELOC_TYPE (TLS_LE64, REL) +RELOC_TYPE (TLS_LDO32, REL) +RELOC_TYPE (TLS_LDO64, REL) +RELOC_TYPE (TLS_DTPMOD, DYN) +RELOC_TYPE (TLS_DTPOFF, DYN) +RELOC_TYPE (TLS_TPOFF, DYN) +RELOC_TYPE (20, REL|EXEC|DYN) +RELOC_TYPE (GOT20, REL) +RELOC_TYPE (GOTPLT20, REL) +RELOC_TYPE (TLS_GOTIE20, REL) diff --git a/3rdparty/elfutils/backends/s390_retval.c b/3rdparty/elfutils/backends/s390_retval.c new file mode 100644 index 0000000..a927d46 --- /dev/null +++ b/3rdparty/elfutils/backends/s390_retval.c @@ -0,0 +1,144 @@ +/* Function return value location for S/390 ABI. + Copyright (C) 2006, 2007, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> + +#define BACKEND s390_ +#include "libebl_CPU.h" + + +/* %r2, or pair %r2, %r3. */ +static const Dwarf_Op loc_intreg[] = + { + { .atom = DW_OP_reg2 }, { .atom = DW_OP_piece, .number = 4 }, + { .atom = DW_OP_reg3 }, { .atom = DW_OP_piece, .number = 4 }, + }; +#define nloc_intreg 1 +#define nloc_intregpair 4 + +/* %f0. */ +static const Dwarf_Op loc_fpreg[] = + { + { .atom = DW_OP_reg16 }, + }; +#define nloc_fpreg 1 + +/* The return value is a structure and is actually stored in stack space + passed in a hidden argument by the caller. But, the compiler + helpfully returns the address of that space in %r2. */ +static const Dwarf_Op loc_aggregate[] = + { + { .atom = DW_OP_breg2, .number = 0 } + }; +#define nloc_aggregate 1 + + +int +s390_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp) +{ + /* Start with the function's type, and get the DW_AT_type attribute, + which is the type of the return value. */ + Dwarf_Die die_mem, *typedie = &die_mem; + int tag = dwarf_peeled_die_type (functypedie, typedie); + if (tag <= 0) + return tag; + + Dwarf_Word size; + switch (tag) + { + case -1: + return -1; + + case DW_TAG_subrange_type: + if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size)) + { + Dwarf_Attribute attr_mem, *attr; + attr = dwarf_attr (typedie, DW_AT_type, &attr_mem); + typedie = dwarf_formref_die (attr, &die_mem); + tag = DWARF_TAG_OR_RETURN (typedie); + } + /* Fall through. */ + + case DW_TAG_base_type: + case DW_TAG_enumeration_type: + case DW_TAG_pointer_type: + case DW_TAG_ptr_to_member_type: + { + Dwarf_Die cudie; + uint8_t asize; + if (dwarf_diecu (typedie, &cudie, &asize, NULL) == NULL) + return -1; + + Dwarf_Attribute attr_mem; + if (dwarf_formudata (dwarf_attr (typedie, DW_AT_byte_size, + &attr_mem), &size) != 0) + { + if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type) + size = asize; + else + return -1; + } + if (tag == DW_TAG_base_type) + { + Dwarf_Word encoding; + if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding, + &attr_mem), + &encoding) != 0) + return -1; + if (encoding == DW_ATE_float && size <= 8) + { + *locp = loc_fpreg; + return nloc_fpreg; + } + } + if (size <= 8) + { + *locp = loc_intreg; + return size <= asize ? nloc_intreg : nloc_intregpair; + } + } + /* Fall through. */ + + case DW_TAG_structure_type: + case DW_TAG_class_type: + case DW_TAG_union_type: + case DW_TAG_array_type: + *locp = loc_aggregate; + return nloc_aggregate; + } + + /* XXX We don't have a good way to return specific errors from ebl calls. + This value means we do not understand the type, but it is well-formed + DWARF and might be valid. */ + return -2; +} diff --git a/3rdparty/elfutils/backends/s390_symbol.c b/3rdparty/elfutils/backends/s390_symbol.c new file mode 100644 index 0000000..a0a4faf --- /dev/null +++ b/3rdparty/elfutils/backends/s390_symbol.c @@ -0,0 +1,56 @@ +/* S/390-specific symbolic name handling. + Copyright (C) 2005 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <elf.h> +#include <stddef.h> + +#define BACKEND s390_ +#include "libebl_CPU.h" + +/* Check for the simple reloc types. */ +Elf_Type +s390_reloc_simple_type (Ebl *ebl __attribute__ ((unused)), int type) +{ + switch (type) + { + case R_390_64: + return ELF_T_SXWORD; + case R_390_32: + return ELF_T_SWORD; + case R_390_16: + return ELF_T_HALF; + case R_390_8: + return ELF_T_BYTE; + default: + return ELF_T_NUM; + } +} diff --git a/3rdparty/elfutils/backends/s390_unwind.c b/3rdparty/elfutils/backends/s390_unwind.c new file mode 100644 index 0000000..752bc28 --- /dev/null +++ b/3rdparty/elfutils/backends/s390_unwind.c @@ -0,0 +1,139 @@ +/* Get previous frame state for an existing frame state. + Copyright (C) 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> +#include <assert.h> + +#define BACKEND s390_ +#include "libebl_CPU.h" + +/* s390/s390x do not annotate signal handler frame by CFI. It would be also + difficult as PC points into a stub built on stack. Function below is called + only if unwinder could not find CFI. Function then verifies the register + state for this frame really belongs to a signal frame. In such case it + fetches original registers saved by the signal frame. */ + +bool +s390_unwind (Ebl *ebl, Dwarf_Addr pc, ebl_tid_registers_t *setfunc, + ebl_tid_registers_get_t *getfunc, ebl_pid_memory_read_t *readfunc, + void *arg, bool *signal_framep) +{ + /* Caller already assumed caller adjustment but S390 instructions are 4 bytes + long. Undo it. */ + if ((pc & 0x3) != 0x3) + return false; + pc++; + /* We can assume big-endian read here. */ + Dwarf_Word instr; + if (! readfunc (pc, &instr, arg)) + return false; + /* Fetch only the very first two bytes. */ + instr = (instr >> (ebl->class == ELFCLASS64 ? 48 : 16)) & 0xffff; + /* See GDB s390_sigtramp_frame_sniffer. */ + /* Check for 'svc' as the first instruction. */ + if (((instr >> 8) & 0xff) != 0x0a) + return false; + /* Check for 'sigreturn' or 'rt_sigreturn' as the second instruction. */ + if ((instr & 0xff) != 119 && (instr & 0xff) != 173) + return false; + /* See GDB s390_sigtramp_frame_unwind_cache. */ + Dwarf_Word this_sp; + if (! getfunc (0 + 15, 1, &this_sp, arg)) + return false; + unsigned word_size = ebl->class == ELFCLASS64 ? 8 : 4; + Dwarf_Addr next_cfa = this_sp + 16 * word_size + 32; + /* "New-style RT frame" is not supported, + assuming "Old-style RT frame and all non-RT frames". + Pointer to the array of saved registers is at NEXT_CFA + 8. */ + Dwarf_Word sigreg_ptr; + if (! readfunc (next_cfa + 8, &sigreg_ptr, arg)) + return false; + /* Skip PSW mask. */ + sigreg_ptr += word_size; + /* Read PSW address. */ + Dwarf_Word val; + if (! readfunc (sigreg_ptr, &val, arg)) + return false; + if (! setfunc (-1, 1, &val, arg)) + return false; + sigreg_ptr += word_size; + /* Then the GPRs. */ + Dwarf_Word gprs[16]; + for (int i = 0; i < 16; i++) + { + if (! readfunc (sigreg_ptr, &gprs[i], arg)) + return false; + sigreg_ptr += word_size; + } + /* Then the ACRs. Skip them, they are not used in CFI. */ + for (int i = 0; i < 16; i++) + sigreg_ptr += 4; + /* The floating-point control word. */ + sigreg_ptr += 8; + /* And finally the FPRs. */ + Dwarf_Word fprs[16]; + for (int i = 0; i < 16; i++) + { + if (! readfunc (sigreg_ptr, &val, arg)) + return false; + if (ebl->class == ELFCLASS32) + { + Dwarf_Addr val_low; + if (! readfunc (sigreg_ptr + 4, &val_low, arg)) + return false; + val = (val << 32) | val_low; + } + fprs[i] = val; + sigreg_ptr += 8; + } + /* If we have them, the GPR upper halves are appended at the end. */ + if (ebl->class == ELFCLASS32) + { + /* Skip signal number. */ + sigreg_ptr += 4; + for (int i = 0; i < 16; i++) + { + if (! readfunc (sigreg_ptr, &val, arg)) + return false; + Dwarf_Word val_low = gprs[i]; + val = (val << 32) | val_low; + gprs[i] = val; + sigreg_ptr += 4; + } + } + if (! setfunc (0, 16, gprs, arg)) + return false; + if (! setfunc (16, 16, fprs, arg)) + return false; + *signal_framep = true; + return true; +} diff --git a/3rdparty/elfutils/backends/s390x_corenote.c b/3rdparty/elfutils/backends/s390x_corenote.c new file mode 100644 index 0000000..427bf7d --- /dev/null +++ b/3rdparty/elfutils/backends/s390x_corenote.c @@ -0,0 +1,2 @@ +#define BITS 64 +#include "s390_corenote.c" diff --git a/3rdparty/elfutils/backends/sh/sh.pro b/3rdparty/elfutils/backends/sh/sh.pro new file mode 100644 index 0000000..af42586 --- /dev/null +++ b/3rdparty/elfutils/backends/sh/sh.pro @@ -0,0 +1,13 @@ +TEMPLATE = lib +include(../backends.pri) +TARGET = ../ebl_sh + +SOURCES += \ + ../sh_corenote.c \ + ../sh_init.c \ + ../sh_regs.c \ + ../sh_retval.c \ + ../sh_symbol.c + +HEADERS += \ + ../sh_reloc.def diff --git a/3rdparty/elfutils/backends/sh_corenote.c b/3rdparty/elfutils/backends/sh_corenote.c new file mode 100644 index 0000000..9268f56 --- /dev/null +++ b/3rdparty/elfutils/backends/sh_corenote.c @@ -0,0 +1,88 @@ +/* SH specific core note handling. + Copyright (C) 2010 Red Hat, Inc. + This file is part of elfutils. + Contributed Matt Fleming <matt@console-pimps.org>. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <elf.h> +#include <inttypes.h> +#include <stddef.h> +#include <stdio.h> +#include <sys/time.h> + +#define BACKEND sh_ +#include "libebl_CPU.h" + +static const Ebl_Register_Location prstatus_regs[] = + { +#define GR(at, n, dwreg) \ + { .offset = at * 4, .regno = dwreg, .count = n, .bits = 32 } + GR (0, 16, 0), /* r0-r15 */ + GR (16, 1, 16), /* pc */ + GR (17, 1, 17), /* pr */ + GR (18, 1, 22), /* sr */ + GR (19, 1, 18), /* gbr */ + GR (20, 1, 20), /* mach */ + GR (21, 1, 21), /* macl */ + /* 22, 1, tra */ +#undef GR + }; +#define PRSTATUS_REGS_SIZE (23 * 4) + +#define ULONG uint32_t +#define PID_T int32_t +#define UID_T uint16_t +#define GID_T uint16_t +#define ALIGN_ULONG 4 +#define ALIGN_PID_T 4 +#define ALIGN_UID_T 2 +#define ALIGN_GID_T 2 +#define TYPE_ULONG ELF_T_WORD +#define TYPE_PID_T ELF_T_SWORD +#define TYPE_UID_T ELF_T_HALF +#define TYPE_GID_T ELF_T_HALF + +#define PRSTATUS_REGSET_ITEMS \ + { \ + .name = "tra", .type = ELF_T_ADDR, .format = 'x', \ + .offset = offsetof (struct EBLHOOK(prstatus), pr_reg[22]), \ + .group = "register" \ + } + +static const Ebl_Register_Location fpregset_regs[] = + { + { .offset = 0, .regno = 25, .count = 16, .bits = 32 }, /* fr0-fr15 */ + { .offset = 16, .regno = 87, .count = 16, .bits = 32 }, /* xf0-xf15 */ + { .offset = 32, .regno = 24, .count = 1, .bits = 32 }, /* fpscr */ + { .offset = 33, .regno = 23, .count = 1, .bits = 32 } /* fpul */ + }; +#define FPREGSET_SIZE (50 * 4) + +#include "linux-core-note.c" diff --git a/3rdparty/elfutils/backends/sh_init.c b/3rdparty/elfutils/backends/sh_init.c new file mode 100644 index 0000000..90ddcb2 --- /dev/null +++ b/3rdparty/elfutils/backends/sh_init.c @@ -0,0 +1,64 @@ +/* Initialization of SH specific backend library. + Copyright (C) 2000, 2001, 2002, 2005 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND sh_ +#define RELOC_PREFIX R_SH_ +#include "libebl_CPU.h" + +/* This defines the common reloc hooks based on sh_reloc.def. */ +#include "common-reloc.c" + + +const char * +sh_init (elf, machine, eh, ehlen) + Elf *elf __attribute__ ((unused)); + GElf_Half machine __attribute__ ((unused)); + Ebl *eh; + size_t ehlen; +{ + /* Check whether the Elf_BH object has a sufficent size. */ + if (ehlen < sizeof (Ebl)) + return NULL; + + /* We handle it. */ + eh->name = "Hitachi SH"; + sh_init_reloc (eh); + HOOK (eh, reloc_simple_type); + HOOK (eh, gotpc_reloc_check); + HOOK (eh, machine_flag_check); + HOOK (eh, core_note); + HOOK (eh, register_info); + HOOK (eh, return_value_location); + + return MODVERSION; +} diff --git a/3rdparty/elfutils/backends/sh_regs.c b/3rdparty/elfutils/backends/sh_regs.c new file mode 100644 index 0000000..d433236 --- /dev/null +++ b/3rdparty/elfutils/backends/sh_regs.c @@ -0,0 +1,191 @@ +/* Register names and numbers for SH DWARF. + Copyright (C) 2010 Red Hat, Inc. + This file is part of elfutils. + Contributed by Matt Fleming <matt@console-pimps.org>. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> +#include <string.h> + +#define BACKEND sh_ +#include "libebl_CPU.h" + +ssize_t +sh_register_info (Ebl *ebl __attribute__ ((unused)), + int regno, char *name, size_t namelen, + const char **prefix, const char **setname, + int *bits, int *type) +{ + if (name == NULL) + return 104; + + if (regno < 0 || regno > 103 || namelen < 6) + return -1; + + *prefix = ""; + *bits = 32; + *type = DW_ATE_signed; + + switch (regno) + { + case 0 ... 9: + *setname = "integer"; + name[0] = 'r'; + name[1] = regno + '0'; + namelen = 2; + break; + + case 10 ... 15: + *setname = "integer"; + name[0] = 'r'; + name[1] = '1'; + name[2] = regno - 10 + '0'; + namelen = 3; + break; + + case 16: + *setname = "system"; + *type = DW_ATE_address; + name[0] = 'p'; + name[1] = 'c'; + namelen = 2; + break; + + case 17: + *setname = "system"; + *type = DW_ATE_address; + name[0] = 'p'; + name[1] = 'r'; + namelen = 2; + break; + + case 18: + *setname = "control"; + *type = DW_ATE_unsigned; + name[0] = 's'; + name[1] = 'r'; + namelen = 2; + break; + + case 19: + *setname = "control"; + *type = DW_ATE_unsigned; + name[0] = 'g'; + name[1] = 'b'; + name[2] = 'r'; + namelen = 3; + break; + + case 20: + *setname = "system"; + name[0] = 'm'; + name[1] = 'a'; + name[2] = 'c'; + name[3] = 'h'; + namelen = 4; + break; + + case 21: + *setname = "system"; + name[0] = 'm'; + name[1] = 'a'; + name[2] = 'c'; + name[3] = 'l'; + namelen = 4; + + break; + + case 23: + *setname = "system"; + *type = DW_ATE_unsigned; + name[0] = 'f'; + name[1] = 'p'; + name[2] = 'u'; + name[3] = 'l'; + namelen = 4; + break; + + case 24: + *setname = "system"; + *type = DW_ATE_unsigned; + name[0] = 'f'; + name[1] = 'p'; + name[2] = 's'; + name[3] = 'c'; + name[4] = 'r'; + namelen = 5; + break; + + case 25 ... 34: + *setname = "fpu"; + *type = DW_ATE_float; + name[0] = 'f'; + name[1] = 'r'; + name[2] = regno - 25 + '0'; + namelen = 3; + break; + + case 35 ... 40: + *setname = "fpu"; + *type = DW_ATE_float; + name[0] = 'f'; + name[1] = 'r'; + name[2] = '1'; + name[3] = regno - 35 + '0'; + namelen = 4; + break; + + case 87 ... 96: + *type = DW_ATE_float; + *setname = "fpu"; + name[0] = 'x'; + name[1] = 'f'; + name[2] = regno - 87 + '0'; + namelen = 3; + break; + + case 97 ... 103: + *type = DW_ATE_float; + *setname = "fpu"; + name[0] = 'x'; + name[1] = 'f'; + name[2] = '1'; + name[3] = regno - 97 + '0'; + namelen = 4; + break; + + default: + return 0; + } + + name[namelen++] = '\0'; + return namelen; +} diff --git a/3rdparty/elfutils/backends/sh_reloc.def b/3rdparty/elfutils/backends/sh_reloc.def new file mode 100644 index 0000000..66a5a9d --- /dev/null +++ b/3rdparty/elfutils/backends/sh_reloc.def @@ -0,0 +1,67 @@ +/* List the relocation types for SH. -*- C -*- + Copyright (C) 2005 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +/* NAME, REL|EXEC|DYN */ + +RELOC_TYPE (NONE, 0) +RELOC_TYPE (DIR32, REL|DYN) +RELOC_TYPE (REL32, REL|DYN) +RELOC_TYPE (DIR8WPN, REL) +RELOC_TYPE (IND12W, REL) +RELOC_TYPE (DIR8WPL, REL) +RELOC_TYPE (DIR8WPZ, REL) +RELOC_TYPE (DIR8BP, REL) +RELOC_TYPE (DIR8W, REL) +RELOC_TYPE (DIR8L, REL) +RELOC_TYPE (SWITCH16, REL) +RELOC_TYPE (SWITCH32, REL) +RELOC_TYPE (USES, REL) +RELOC_TYPE (COUNT, REL) +RELOC_TYPE (ALIGN, REL) +RELOC_TYPE (CODE, REL) +RELOC_TYPE (DATA, REL) +RELOC_TYPE (LABEL, REL) +RELOC_TYPE (SWITCH8, REL) +RELOC_TYPE (GNU_VTINHERIT, REL) +RELOC_TYPE (GNU_VTENTRY, REL) +RELOC_TYPE (TLS_GD_32, REL) +RELOC_TYPE (TLS_LD_32, REL) +RELOC_TYPE (TLS_LDO_32, REL) +RELOC_TYPE (TLS_IE_32, REL) +RELOC_TYPE (TLS_LE_32, REL) +RELOC_TYPE (TLS_DTPMOD32, DYN) +RELOC_TYPE (TLS_DTPOFF32, DYN) +RELOC_TYPE (TLS_TPOFF32, DYN) +RELOC_TYPE (GOT32, REL) +RELOC_TYPE (PLT32, REL) +RELOC_TYPE (COPY, EXEC) +RELOC_TYPE (GLOB_DAT, EXEC|DYN) +RELOC_TYPE (JMP_SLOT, EXEC|DYN) +RELOC_TYPE (RELATIVE, EXEC|DYN) +RELOC_TYPE (GOTOFF, REL) +RELOC_TYPE (GOTPC, REL) diff --git a/3rdparty/elfutils/backends/sh_retval.c b/3rdparty/elfutils/backends/sh_retval.c new file mode 100644 index 0000000..d44f260 --- /dev/null +++ b/3rdparty/elfutils/backends/sh_retval.c @@ -0,0 +1,131 @@ +/* Function return value location for Linux/SH ABI. + Copyright (C) 2010, 2014 Red Hat, Inc. + This file is part of elfutils. + Contributed by Matt Fleming <matt@console-pimps.org>. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> + +#define BACKEND sh_ +#include "libebl_CPU.h" + + +/* This is the SVR4 ELF ABI convention, but AIX and Linux do not use it. */ +#define SVR4_STRUCT_RETURN 0 + + +/* r0, or pair r0, r1. */ +static const Dwarf_Op loc_intreg[] = + { + { .atom = DW_OP_reg0 }, { .atom = DW_OP_piece, .number = 4 }, + { .atom = DW_OP_reg1 }, { .atom = DW_OP_piece, .number = 4 }, + }; +#define nloc_intreg 1 +#define nloc_intregpair 4 + +/* fr0 or fr1. */ +static const Dwarf_Op loc_fpreg[] = + { + { .atom = DW_OP_reg25 }, { .atom = DW_OP_piece, .number = 4 }, + { .atom = DW_OP_reg26 }, { .atom = DW_OP_piece, .number = 4 }, + }; +#define nloc_fpreg 1 +#define nloc_fpregpair 2 + +int +sh_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp) +{ + /* Start with the function's type, and get the DW_AT_type attribute, + which is the type of the return value. */ + Dwarf_Die die_mem, *typedie = &die_mem; + int tag = dwarf_peeled_die_type (functypedie, typedie); + if (tag <= 0) + return tag; + + Dwarf_Word size; + switch (tag) + { + case -1: + return -1; + + case DW_TAG_subrange_type: + if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size)) + { + Dwarf_Attribute attr_mem, *attr; + attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem); + typedie = dwarf_formref_die (attr, &die_mem); + tag = DWARF_TAG_OR_RETURN (typedie); + } + /* Fall through. */ + + case DW_TAG_base_type: + case DW_TAG_enumeration_type: + case DW_TAG_pointer_type: + case DW_TAG_ptr_to_member_type: + { + Dwarf_Attribute attr_mem; + if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size, + &attr_mem), &size) != 0) + { + if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type) + size = 4; + else + return -1; + } + } + + if (size <= 8) + { + if (tag == DW_TAG_base_type) + { + Dwarf_Attribute attr_mem; + Dwarf_Word encoding; + if (dwarf_formudata (dwarf_attr_integrate (typedie, + DW_AT_encoding, + &attr_mem), + &encoding) != 0) + return -1; + if (encoding == DW_ATE_float) + { + *locp = loc_fpreg; + return size <= 4 ? nloc_fpreg : nloc_fpregpair; + } + } + *locp = loc_intreg; + return size <= 4 ? nloc_intreg : nloc_intregpair; + } + } + + /* XXX We don't have a good way to return specific errors from ebl calls. + This value means we do not understand the type, but it is well-formed + DWARF and might be valid. */ + return -2; +} diff --git a/3rdparty/elfutils/backends/sh_symbol.c b/3rdparty/elfutils/backends/sh_symbol.c new file mode 100644 index 0000000..8101e96 --- /dev/null +++ b/3rdparty/elfutils/backends/sh_symbol.c @@ -0,0 +1,94 @@ +/* SH specific relocation handling. + Copyright (C) 2000, 2001, 2002, 2005 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <elf.h> +#include <stddef.h> + +#define BACKEND sh_ +#include "libebl_CPU.h" + + +/* Return true if the symbol type is that referencing the GOT. */ +bool +sh_gotpc_reloc_check (Elf *elf __attribute__ ((unused)), int type) +{ + return type == R_SH_GOTPC; +} + +/* Check for the simple reloc types. */ +Elf_Type +sh_reloc_simple_type (Ebl *ebl __attribute__ ((unused)), int type) +{ + switch (type) + { + case R_SH_DIR32: + return ELF_T_WORD; + default: + return ELF_T_NUM; + } +} + +/* Check whether machine flags are valid. */ +bool +sh_machine_flag_check (GElf_Word flags) +{ + switch (flags & EF_SH_MACH_MASK) + { + case EF_SH_UNKNOWN: + case EF_SH1: + case EF_SH2: + case EF_SH3: + case EF_SH_DSP: + case EF_SH3_DSP: + case EF_SH4AL_DSP: + case EF_SH3E: + case EF_SH4: + case EF_SH2E: + case EF_SH4A: + case EF_SH2A: + case EF_SH4_NOFPU: + case EF_SH4A_NOFPU: + case EF_SH4_NOMMU_NOFPU: + case EF_SH2A_NOFPU: + case EF_SH3_NOMMU: + case EF_SH2A_SH4_NOFPU: + case EF_SH2A_SH3_NOFPU: + case EF_SH2A_SH4: + case EF_SH2A_SH3E: + break; + default: + return false; + } + + return ((flags &~ (EF_SH_MACH_MASK)) == 0); +} diff --git a/3rdparty/elfutils/backends/sparc/sparc.pro b/3rdparty/elfutils/backends/sparc/sparc.pro new file mode 100644 index 0000000..4ffe731 --- /dev/null +++ b/3rdparty/elfutils/backends/sparc/sparc.pro @@ -0,0 +1,15 @@ +TEMPLATE = lib +include(../backends.pri) +TARGET = ../ebl_sparc + +SOURCES += \ + ../sparc_auxv.c \ + ../sparc_corenote.c \ + ../sparc_init.c \ + ../sparc_regs.c \ + ../sparc_retval.c \ + ../sparc_symbol.c \ + ../sparc64_corenote.c + +HEADERS += \ + ../sparc_reloc.def diff --git a/3rdparty/elfutils/backends/sparc64/sparc64.pro b/3rdparty/elfutils/backends/sparc64/sparc64.pro new file mode 100644 index 0000000..ee9051b --- /dev/null +++ b/3rdparty/elfutils/backends/sparc64/sparc64.pro @@ -0,0 +1,5 @@ +TEMPLATE = lib +include(../backends.pri) + +SOURCES += \ + diff --git a/3rdparty/elfutils/backends/sparc64_corenote.c b/3rdparty/elfutils/backends/sparc64_corenote.c new file mode 100644 index 0000000..cef6431 --- /dev/null +++ b/3rdparty/elfutils/backends/sparc64_corenote.c @@ -0,0 +1,2 @@ +#define BITS 64 +#include "sparc_corenote.c" diff --git a/3rdparty/elfutils/backends/sparc_auxv.c b/3rdparty/elfutils/backends/sparc_auxv.c new file mode 100644 index 0000000..2da349c --- /dev/null +++ b/3rdparty/elfutils/backends/sparc_auxv.c @@ -0,0 +1,46 @@ +/* SPARC-specific auxv handling. + Copyright (C) 2007 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND sparc_ +#include "libebl_CPU.h" + +int +EBLHOOK(auxv_info) (GElf_Xword a_type, const char **name, const char **format) +{ + if (a_type != AT_HWCAP) + return 0; + + *name = "HWCAP"; + *format = "b" + "flush\0" "stbar\0" "swap\0" "muldiv\0" "v9\0" "ultra3\0" "v9v\0" "\0"; + return 1; +} diff --git a/3rdparty/elfutils/backends/sparc_corenote.c b/3rdparty/elfutils/backends/sparc_corenote.c new file mode 100644 index 0000000..7912539 --- /dev/null +++ b/3rdparty/elfutils/backends/sparc_corenote.c @@ -0,0 +1,112 @@ +/* PowerPC specific core note handling. + Copyright (C) 2007 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <elf.h> +#include <inttypes.h> +#include <stddef.h> +#include <stdio.h> +#include <sys/time.h> + +#ifndef BITS +# define BITS 32 +# define BACKEND sparc_ +#else +# define BITS 64 +# define BACKEND sparc64_ +#endif +#include "libebl_CPU.h" + +#define GR(at, n, dwreg) \ + { .offset = at * BITS/8, .regno = dwreg, .count = n, .bits = BITS } + +static const Ebl_Register_Location prstatus_regs[] = + { + GR (0, 32, 0), /* %g0-%g7, %o0-%o7, %i0-%i7 */ +#if BITS == 32 + GR (32, 1, 65), /* %psr */ + GR (33, 2, 68), /* %pc, %npc */ + GR (35, 1, 64), /* %y */ + GR (36, 1, 66), /* %wim, %tbr */ +#else + GR (32, 1, 82), /* %state */ + GR (33, 2, 80), /* %pc, %npc */ + GR (35, 1, 85), /* %y */ +#endif + }; +#define PRSTATUS_REGS_SIZE (BITS / 8 * (32 + (BITS == 32 ? 6 : 4))) + +static const Ebl_Register_Location fpregset_regs[] = + { +#if BITS == 32 + GR (0, 32, 32), /* %f0-%f31 */ + /* padding word */ + GR (33, 1, 70), /* %fsr */ + /* qcnt, q_entrysize, en, q, padding */ +# define FPREGSET_SIZE (34 * 4 + 4 + 64 * 4 + 4) +#else + GR (0, 32, 32), /* %f0-%f31 */ + GR (32, 1, 83), /* %fsr */ + /* 33, 1, %gsr */ + GR (34, 1, 84), /* %fprs */ +# define FPREGSET_SIZE (35 * 8) +#endif + }; + +#if BITS == 32 +# define ULONG uint32_t +# define ALIGN_ULONG 4 +# define TYPE_ULONG ELF_T_WORD +# define TYPE_LONG ELF_T_SWORD +# define UID_T uint16_t +# define GID_T uint16_t +# define ALIGN_UID_T 2 +# define ALIGN_GID_T 2 +# define TYPE_UID_T ELF_T_HALF +# define TYPE_GID_T ELF_T_HALF +#else +# define ULONG uint64_t +# define ALIGN_ULONG 8 +# define TYPE_ULONG ELF_T_XWORD +# define TYPE_LONG ELF_T_SXWORD +# define UID_T uint32_t +# define GID_T uint32_t +# define ALIGN_UID_T 4 +# define ALIGN_GID_T 4 +# define TYPE_UID_T ELF_T_WORD +# define TYPE_GID_T ELF_T_WORD +# define SUSECONDS_HALF 1 +#endif +#define PID_T int32_t +#define ALIGN_PID_T 4 +#define TYPE_PID_T ELF_T_SWORD + +#include "linux-core-note.c" diff --git a/3rdparty/elfutils/backends/sparc_init.c b/3rdparty/elfutils/backends/sparc_init.c new file mode 100644 index 0000000..7d22998 --- /dev/null +++ b/3rdparty/elfutils/backends/sparc_init.c @@ -0,0 +1,76 @@ +/* Initialization of SPARC specific backend library. + Copyright (C) 2002, 2005, 2006, 2007, 2008 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND sparc_ +#define RELOC_PREFIX R_SPARC_ +#include "libebl_CPU.h" + +/* This defines the common reloc hooks based on sparc_reloc.def. */ +#include "common-reloc.c" + +extern __typeof (EBLHOOK (core_note)) sparc64_core_note attribute_hidden; + +const char * +sparc_init (elf, machine, eh, ehlen) + Elf *elf __attribute__ ((unused)); + GElf_Half machine __attribute__ ((unused)); + Ebl *eh; + size_t ehlen; +{ + /* Check whether the Elf_BH object has a sufficent size. */ + if (ehlen < sizeof (Ebl)) + return NULL; + + /* We handle it. */ + if (machine == EM_SPARCV9) + eh->name = "SPARC v9"; + else if (machine == EM_SPARC32PLUS) + eh->name = "SPARC v8+"; + else + eh->name = "SPARC"; + sparc_init_reloc (eh); + HOOK (eh, reloc_simple_type); + HOOK (eh, machine_flag_check); + HOOK (eh, check_special_section); + HOOK (eh, symbol_type_name); + HOOK (eh, dynamic_tag_name); + HOOK (eh, dynamic_tag_check); + if (eh->class == ELFCLASS64) + eh->core_note = sparc64_core_note; + else + HOOK (eh, core_note); + HOOK (eh, auxv_info); + HOOK (eh, register_info); + HOOK (eh, return_value_location); + + return MODVERSION; +} diff --git a/3rdparty/elfutils/backends/sparc_regs.c b/3rdparty/elfutils/backends/sparc_regs.c new file mode 100644 index 0000000..f9709bb --- /dev/null +++ b/3rdparty/elfutils/backends/sparc_regs.c @@ -0,0 +1,111 @@ +/* Register names and numbers for SPARC DWARF. + Copyright (C) 2005, 2006 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> +#include <dwarf.h> + +#define BACKEND sparc_ +#include "libebl_CPU.h" + +ssize_t +sparc_register_info (Ebl *ebl, + int regno, char *name, size_t namelen, + const char **prefix, const char **setname, + int *bits, int *type) +{ + const int nfp = 32 + (ebl->machine == EM_SPARC ? 0 : 16); + const int nspec = ebl->machine == EM_SPARC ? 8 : 6; + + if (name == NULL) + return 32 + nfp + nspec; + + if (regno < 0 || regno >= 32 + nfp + nspec || namelen < 6) + return -1; + + *bits = ebl->machine == EM_SPARC ? 32 : 64; + *type = DW_ATE_signed; + + *prefix = "%"; + + if (regno >= 32 + nfp) + { + regno -= 32 + nfp; + static const char names[2][8][6] = + { + { "y", "psr", "wim", "tbr", "pc", "npc", "fsr", "csr" }, /* v8 */ + { "pc", "npc", "state", "fsr", "fprs", "y" } /* v9 */ + }; + *setname = "control"; + *type = DW_ATE_unsigned; + if ((ebl->machine != EM_SPARC ? 0 : 4) + 1 - (unsigned int) regno <= 1) + *type = DW_ATE_address; + return stpncpy (name, names[ebl->machine != EM_SPARC][regno], + namelen) + 1 - name; + } + + if (regno < 32) + { + *setname = "integer"; + name[0] = "goli"[regno >> 3]; + name[1] = (regno & 7) + '0'; + namelen = 2; + if ((regno & 8) && (regno & 7) == 6) + *type = DW_ATE_address; + } + else + { + *setname = "FPU"; + *type = DW_ATE_float; + + regno -= 32; + if (regno >= 32) + regno = 32 + 2 * (regno - 32); + else + *bits = 32; + + name[0] = 'f'; + if (regno < 10) + { + name[1] = regno + '0'; + namelen = 2; + } + else + { + name[1] = regno / 10 + '0'; + name[2] = regno % 10 + '0'; + namelen = 3; + } + } + + name[namelen++] = '\0'; + return namelen; +} diff --git a/3rdparty/elfutils/backends/sparc_reloc.def b/3rdparty/elfutils/backends/sparc_reloc.def new file mode 100644 index 0000000..c39b0fa --- /dev/null +++ b/3rdparty/elfutils/backends/sparc_reloc.def @@ -0,0 +1,121 @@ +/* List the relocation types for sparc. -*- C -*- + Copyright (C) 2009 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +/* NAME, REL|EXEC|DYN */ + +RELOC_TYPE (NONE, REL) +RELOC_TYPE (8, REL) +RELOC_TYPE (16, REL) +RELOC_TYPE (32, REL|DYN) +RELOC_TYPE (DISP8, REL) +RELOC_TYPE (DISP16, REL) +RELOC_TYPE (DISP32, REL) +RELOC_TYPE (WDISP30, REL) +RELOC_TYPE (WDISP22, REL) +RELOC_TYPE (HI22, REL) +RELOC_TYPE (22, REL) +RELOC_TYPE (13, REL) +RELOC_TYPE (LO10, REL) +RELOC_TYPE (GOT10, REL) +RELOC_TYPE (GOT13, REL) +RELOC_TYPE (GOT22, REL) +RELOC_TYPE (PC10, REL) +RELOC_TYPE (PC22, REL) +RELOC_TYPE (WPLT30, REL) +RELOC_TYPE (COPY, EXEC) +RELOC_TYPE (GLOB_DAT, EXEC|DYN) +RELOC_TYPE (JMP_SLOT, EXEC|DYN) +RELOC_TYPE (RELATIVE, EXEC|DYN) +RELOC_TYPE (UA32, REL) +RELOC_TYPE (PLT32, REL) +RELOC_TYPE (HIPLT22, REL) +RELOC_TYPE (LOPLT10, REL) +RELOC_TYPE (PCPLT32, REL) +RELOC_TYPE (PCPLT22, REL) +RELOC_TYPE (PCPLT10, REL) +RELOC_TYPE (10, REL) +RELOC_TYPE (11, REL) +RELOC_TYPE (64, REL|DYN) +RELOC_TYPE (OLO10, REL) +RELOC_TYPE (HH22, REL) +RELOC_TYPE (HM10, REL) +RELOC_TYPE (LM22, REL) +RELOC_TYPE (PC_HH22, REL) +RELOC_TYPE (PC_HM10, REL) +RELOC_TYPE (PC_LM22, REL) +RELOC_TYPE (WDISP16, REL) +RELOC_TYPE (WDISP19, REL) +RELOC_TYPE (GLOB_JMP, EXEC|DYN) +RELOC_TYPE (7, REL) +RELOC_TYPE (5, REL) +RELOC_TYPE (6, REL) +RELOC_TYPE (DISP64, REL) +RELOC_TYPE (PLT64, REL) +RELOC_TYPE (HIX22, REL) +RELOC_TYPE (LOX10, REL) +RELOC_TYPE (H44, REL) +RELOC_TYPE (M44, REL) +RELOC_TYPE (L44, REL) +RELOC_TYPE (REGISTER, REL) +RELOC_TYPE (UA64, REL) +RELOC_TYPE (UA16, REL) +RELOC_TYPE (TLS_GD_HI22, REL) +RELOC_TYPE (TLS_GD_LO10, REL) +RELOC_TYPE (TLS_GD_ADD, REL) +RELOC_TYPE (TLS_GD_CALL, REL) +RELOC_TYPE (TLS_LDM_HI22, REL) +RELOC_TYPE (TLS_LDM_LO10, REL) +RELOC_TYPE (TLS_LDM_ADD, REL) +RELOC_TYPE (TLS_LDM_CALL, REL) +RELOC_TYPE (TLS_LDO_HIX22, REL) +RELOC_TYPE (TLS_LDO_LOX10, REL) +RELOC_TYPE (TLS_LDO_ADD, REL) +RELOC_TYPE (TLS_IE_HI22, REL) +RELOC_TYPE (TLS_IE_LO10, REL) +RELOC_TYPE (TLS_IE_LD, REL) +RELOC_TYPE (TLS_IE_LDX, REL) +RELOC_TYPE (TLS_IE_ADD, REL) +RELOC_TYPE (TLS_LE_HIX22, REL) +RELOC_TYPE (TLS_LE_LOX10, REL) +RELOC_TYPE (TLS_DTPMOD32, DYN) +RELOC_TYPE (TLS_DTPMOD64, DYN) +RELOC_TYPE (TLS_DTPOFF32, DYN) +RELOC_TYPE (TLS_DTPOFF64, DYN) +RELOC_TYPE (TLS_TPOFF32, DYN) +RELOC_TYPE (TLS_TPOFF64, DYN) +RELOC_TYPE (GOTDATA_HIX22, REL) +RELOC_TYPE (GOTDATA_LOX10, REL) +RELOC_TYPE (GOTDATA_OP_HIX22, DYN) +RELOC_TYPE (GOTDATA_OP_LOX10, DYN) +RELOC_TYPE (GOTDATA_OP, DYN) +RELOC_TYPE (H34, REL) +RELOC_TYPE (SIZE32, REL) +RELOC_TYPE (SIZE64, REL) +RELOC_TYPE (GNU_VTINHERIT, REL) +RELOC_TYPE (GNU_VTENTRY, REL) +RELOC_TYPE (REV32, REL) diff --git a/3rdparty/elfutils/backends/sparc_retval.c b/3rdparty/elfutils/backends/sparc_retval.c new file mode 100644 index 0000000..e1b1775 --- /dev/null +++ b/3rdparty/elfutils/backends/sparc_retval.c @@ -0,0 +1,159 @@ +/* Function return value location for SPARC. + Copyright (C) 2006-2010, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> + +#define BACKEND sparc_ +#include "libebl_CPU.h" + + +/* %o0, or pair %o0, %o1. */ +static const Dwarf_Op loc_intreg[] = + { + { .atom = DW_OP_reg8 }, { .atom = DW_OP_piece, .number = 4 }, + { .atom = DW_OP_reg9 }, { .atom = DW_OP_piece, .number = 4 }, + }; +#define nloc_intreg 1 +#define nloc_intregpair 4 + +/* %f0 or pair %f0, %f1, or quad %f0..%f3. */ +static const Dwarf_Op loc_fpreg[] = + { + { .atom = DW_OP_regx, .number = 32 }, { .atom = DW_OP_piece, .number = 4 }, + { .atom = DW_OP_regx, .number = 33 }, { .atom = DW_OP_piece, .number = 4 }, + { .atom = DW_OP_regx, .number = 34 }, { .atom = DW_OP_piece, .number = 4 }, + { .atom = DW_OP_regx, .number = 35 }, { .atom = DW_OP_piece, .number = 4 }, + }; +#define nloc_fpreg 1 +#define nloc_fpregpair 4 +#define nloc_fpregquad 8 + +/* The return value is a structure and is actually stored in stack space + passed in a hidden argument by the caller. But, the compiler + helpfully returns the address of that space in %o0. */ +static const Dwarf_Op loc_aggregate[] = + { + { .atom = DW_OP_breg8, .number = 0 } + }; +#define nloc_aggregate 1 + +int +sparc_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp) +{ + /* Start with the function's type, and get the DW_AT_type attribute, + which is the type of the return value. */ + Dwarf_Die die_mem, *typedie = &die_mem; + int tag = dwarf_peeled_die_type (functypedie, typedie); + if (tag <= 0) + return tag; + + Dwarf_Word size; + switch (tag) + { + case -1: + return -1; + + case DW_TAG_subrange_type: + if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size)) + { + Dwarf_Attribute attr_mem, *attr; + attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem); + typedie = dwarf_formref_die (attr, &die_mem); + tag = DWARF_TAG_OR_RETURN (typedie); + } + /* Fall through. */ + + case DW_TAG_base_type: + case DW_TAG_enumeration_type: + case DW_TAG_pointer_type: + case DW_TAG_ptr_to_member_type: + { + Dwarf_Attribute attr_mem; + if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size, + &attr_mem), &size) != 0) + { + uint8_t asize; + Dwarf_Die cudie; + if ((tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type) + && dwarf_diecu (typedie, &cudie, &asize, NULL) != NULL) + size = asize; + else + return -1; + } + } + + if (tag == DW_TAG_base_type) + { + Dwarf_Attribute attr_mem; + Dwarf_Word encoding; + if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding, + &attr_mem), + &encoding) != 0) + return -1; + if (encoding == DW_ATE_float) + { + *locp = loc_fpreg; + if (size <= 4) + return nloc_fpreg; + if (size <= 8) + return nloc_fpregpair; + if (size <= 16) + return nloc_fpregquad; + } + } + if (size <= 8) + { + intreg: + *locp = loc_intreg; + return size <= 4 ? nloc_intreg : nloc_intregpair; + } + + aggregate: + *locp = loc_aggregate; + return nloc_aggregate; + + case DW_TAG_structure_type: + case DW_TAG_class_type: + case DW_TAG_union_type: + case DW_TAG_array_type: + if (dwarf_aggregate_size (typedie, &size) == 0 + && size > 0 && size <= 8) + goto intreg; + goto aggregate; + } + + /* XXX We don't have a good way to return specific errors from ebl calls. + This value means we do not understand the type, but it is well-formed + DWARF and might be valid. */ + return -2; +} diff --git a/3rdparty/elfutils/backends/sparc_symbol.c b/3rdparty/elfutils/backends/sparc_symbol.c new file mode 100644 index 0000000..ec11dc9 --- /dev/null +++ b/3rdparty/elfutils/backends/sparc_symbol.c @@ -0,0 +1,148 @@ +/* SPARC specific symbolic name handling. + Copyright (C) 2002, 2003, 2005, 2007, 2008 Red Hat, Inc. + This file is part of elfutils. + Written by Jakub Jelinek <jakub@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <elf.h> +#include <stddef.h> + +#define BACKEND sparc_ +#include "libebl_CPU.h" + +/* Check for the simple reloc types. */ +Elf_Type +sparc_reloc_simple_type (Ebl *ebl __attribute__ ((unused)), int type) +{ + switch (type) + { + case R_SPARC_8: + return ELF_T_BYTE; + case R_SPARC_16: + case R_SPARC_UA16: + return ELF_T_HALF; + case R_SPARC_32: + case R_SPARC_UA32: + return ELF_T_WORD; + case R_SPARC_64: + case R_SPARC_UA64: + return ELF_T_XWORD; + default: + return ELF_T_NUM; + } +} + +/* Check whether machine flags are valid. */ +bool +sparc_machine_flag_check (GElf_Word flags) +{ + return ((flags &~ (EF_SPARCV9_MM + | EF_SPARC_LEDATA + | EF_SPARC_32PLUS + | EF_SPARC_SUN_US1 + | EF_SPARC_SUN_US3)) == 0); +} + +bool +sparc_check_special_section (Ebl *ebl, + int ndx __attribute__ ((unused)), + const GElf_Shdr *shdr, + const char *sname __attribute__ ((unused))) +{ + if ((shdr->sh_flags & (SHF_WRITE | SHF_EXECINSTR)) + == (SHF_WRITE | SHF_EXECINSTR)) + { + /* This is ordinarily flagged, but is valid for a PLT on SPARC. + + Look for the SHT_DYNAMIC section and the DT_PLTGOT tag in it. + Its d_ptr should match the .plt section's sh_addr. */ + + Elf_Scn *scn = NULL; + while ((scn = elf_nextscn (ebl->elf, scn)) != NULL) + { + GElf_Shdr scn_shdr; + if (likely (gelf_getshdr (scn, &scn_shdr) != NULL) + && scn_shdr.sh_type == SHT_DYNAMIC + && scn_shdr.sh_entsize != 0) + { + Elf_Data *data = elf_getdata (scn, NULL); + if (data != NULL) + for (size_t i = 0; i < data->d_size / scn_shdr.sh_entsize; ++i) + { + GElf_Dyn dyn; + if (unlikely (gelf_getdyn (data, i, &dyn) == NULL)) + break; + if (dyn.d_tag == DT_PLTGOT) + return dyn.d_un.d_ptr == shdr->sh_addr; + } + break; + } + } + } + + return false; +} + +const char * +sparc_symbol_type_name (int type, + char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + switch (type) + { + case STT_SPARC_REGISTER: + return "SPARC_REGISTER"; + } + return NULL; +} + +const char * +sparc_dynamic_tag_name (int64_t tag, + char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + switch (tag) + { + case DT_SPARC_REGISTER: + return "SPARC_REGISTER"; + } + return NULL; +} + +bool +sparc_dynamic_tag_check (int64_t tag) +{ + switch (tag) + { + case DT_SPARC_REGISTER: + return true; + } + return false; +} diff --git a/3rdparty/elfutils/backends/tilegx/tilegx.pro b/3rdparty/elfutils/backends/tilegx/tilegx.pro new file mode 100644 index 0000000..ee751b5 --- /dev/null +++ b/3rdparty/elfutils/backends/tilegx/tilegx.pro @@ -0,0 +1,13 @@ +TEMPLATE = lib +include(../backends.pri) +TARGET = ../ebl_tilegx + +SOURCES += \ + ../tilegx_corenote.c \ + ../tilegx_init.c \ + ../tilegx_regs.c \ + ../tilegx_retval.c \ + ../tilegx_symbol.c + +HEADERS += \ + ../tilegx_reloc.def diff --git a/3rdparty/elfutils/backends/tilegx_corenote.c b/3rdparty/elfutils/backends/tilegx_corenote.c new file mode 100644 index 0000000..be3e7db --- /dev/null +++ b/3rdparty/elfutils/backends/tilegx_corenote.c @@ -0,0 +1,64 @@ +/* TILE-Gx specific core note handling. + Copyright (C) 2012 Tilera Corporation + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <elf.h> +#include <inttypes.h> +#include <stddef.h> +#include <stdio.h> +#include <sys/time.h> + +#define BACKEND tilegx_ +#include "libebl_CPU.h" + +static const Ebl_Register_Location prstatus_regs[] = + { + { .offset = 0, .regno = 0, .count = 56, .bits = 64 }, /* r0-r55 */ + { .offset = 56 * 8, .regno = 64, .count = 1, .bits = 64 } /* pc */ + }; +#define PRSTATUS_REGS_SIZE (57 * 8) + +#define ULONG uint64_t +#define ALIGN_ULONG 8 +#define TYPE_ULONG ELF_T_XWORD +#define TYPE_LONG ELF_T_SXWORD +#define PID_T int32_t +#define UID_T uint32_t +#define GID_T uint32_t +#define ALIGN_PID_T 4 +#define ALIGN_UID_T 4 +#define ALIGN_GID_T 4 +#define TYPE_PID_T ELF_T_SWORD +#define TYPE_UID_T ELF_T_WORD +#define TYPE_GID_T ELF_T_WORD + +#include "linux-core-note.c" diff --git a/3rdparty/elfutils/backends/tilegx_init.c b/3rdparty/elfutils/backends/tilegx_init.c new file mode 100644 index 0000000..858798b --- /dev/null +++ b/3rdparty/elfutils/backends/tilegx_init.c @@ -0,0 +1,60 @@ +/* Initialization of TILE-Gx specific backend library. + Copyright (C) 2012 Tilera Corporation + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND tilegx_ +#define RELOC_PREFIX R_TILEGX_ +#include "libebl_CPU.h" + +/* This defines the common reloc hooks based on tilegx_reloc.def. */ +#include "common-reloc.c" + +const char * +tilegx_init (elf, machine, eh, ehlen) + Elf *elf __attribute__ ((unused)); + GElf_Half machine __attribute__ ((unused)); + Ebl *eh; + size_t ehlen; +{ + /* Check whether the Elf_BH object has a sufficent size. */ + if (ehlen < sizeof (Ebl)) + return NULL; + + /* We handle it. */ + eh->name = "TILE-Gx"; + tilegx_init_reloc (eh); + HOOK (eh, reloc_simple_type); + HOOK (eh, return_value_location); + HOOK (eh, register_info); + HOOK (eh, core_note); + + return MODVERSION; +} diff --git a/3rdparty/elfutils/backends/tilegx_regs.c b/3rdparty/elfutils/backends/tilegx_regs.c new file mode 100644 index 0000000..b1e1743 --- /dev/null +++ b/3rdparty/elfutils/backends/tilegx_regs.c @@ -0,0 +1,129 @@ +/* Register names and numbers for TILE-Gx DWARF. + Copyright (C) 2012 Tilera Corporation + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> +#include <string.h> +#include <dwarf.h> + +#define BACKEND tilegx_ +#include "libebl_CPU.h" + +ssize_t +tilegx_register_info (Ebl *ebl __attribute__ ((unused)), + int regno, char *name, size_t namelen, + const char **prefix, const char **setname, + int *bits, int *type) +{ + if (name == NULL) + return 65; + + if (regno < 0 || regno > 64 || namelen < 5) + return -1; + + *prefix = ""; + *setname = "integer"; + *bits = 64; + + switch (regno) + { + case 0 ... 9: + *type = DW_ATE_signed; + name[0] = 'r'; + name[1] = regno + '0'; + namelen = 2; + break; + + case 10 ... 52: + *type = DW_ATE_signed; + name[0] = 'r'; + name[1] = regno / 10 + '0'; + name[2] = regno % 10 + '0'; + namelen = 3; + break; + + case 53: + *type = DW_ATE_address; + return stpcpy (name, "tp") + 1 - name; + + case 54: + *type = DW_ATE_address; + return stpcpy (name, "sp") + 1 - name; + + case 55: + *type = DW_ATE_address; + return stpcpy (name, "lr") + 1 - name; + + case 56: + *type = DW_ATE_unsigned; + return stpcpy (name, "sn") + 1 - name; + + case 57: + *type = DW_ATE_unsigned; + return stpcpy (name, "idn0") + 1 - name; + + case 58: + *type = DW_ATE_unsigned; + return stpcpy (name, "idn1") + 1 - name; + + case 59: + *type = DW_ATE_unsigned; + return stpcpy (name, "udn0") + 1 - name; + + case 60: + *type = DW_ATE_unsigned; + return stpcpy (name, "udn1") + 1 - name; + + case 61: + *type = DW_ATE_unsigned; + return stpcpy (name, "udn2") + 1 - name; + + case 62: + *type = DW_ATE_unsigned; + return stpcpy (name, "udn3") + 1 - name; + + case 63: + *type = DW_ATE_unsigned; + return stpcpy (name, "zero") + 1 - name; + + case 64: + *type = DW_ATE_address; + return stpcpy (name, "pc") + 1 - name; + + /* Can't happen. */ + default: + *setname = NULL; + return 0; + } + + name[namelen++] = '\0'; + return namelen; +} diff --git a/3rdparty/elfutils/backends/tilegx_reloc.def b/3rdparty/elfutils/backends/tilegx_reloc.def new file mode 100644 index 0000000..9736286 --- /dev/null +++ b/3rdparty/elfutils/backends/tilegx_reloc.def @@ -0,0 +1,120 @@ +/* List the relocation types for tilegx. -*- C -*- + Copyright (C) 2012 Tilera Corporation + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +/* NAME, REL|EXEC|DYN */ + +RELOC_TYPE (NONE, 0) +RELOC_TYPE (64, REL|EXEC|DYN) +RELOC_TYPE (32, REL|EXEC|DYN) +RELOC_TYPE (16, REL|EXEC|DYN) +RELOC_TYPE (8, REL|EXEC|DYN) +RELOC_TYPE (64_PCREL, REL) +RELOC_TYPE (32_PCREL, REL) +RELOC_TYPE (16_PCREL, REL) +RELOC_TYPE (8_PCREL, REL) +RELOC_TYPE (HW0, REL) +RELOC_TYPE (HW1, REL) +RELOC_TYPE (HW2, REL) +RELOC_TYPE (HW3, REL) +RELOC_TYPE (HW0_LAST, REL) +RELOC_TYPE (HW1_LAST, REL) +RELOC_TYPE (HW2_LAST, REL) +RELOC_TYPE (COPY, EXEC) +RELOC_TYPE (GLOB_DAT, EXEC|DYN) +RELOC_TYPE (JMP_SLOT, EXEC|DYN) +RELOC_TYPE (RELATIVE, EXEC|DYN) +RELOC_TYPE (BROFF_X1, REL) +RELOC_TYPE (JUMPOFF_X1, REL) +RELOC_TYPE (JUMPOFF_X1_PLT, REL) +RELOC_TYPE (IMM8_X0, REL) +RELOC_TYPE (IMM8_Y0, REL) +RELOC_TYPE (IMM8_X1, REL) +RELOC_TYPE (IMM8_Y1, REL) +RELOC_TYPE (DEST_IMM8_X1, REL) +RELOC_TYPE (MT_IMM14_X1, REL) +RELOC_TYPE (MF_IMM14_X1, REL) +RELOC_TYPE (MMSTART_X0, REL) +RELOC_TYPE (MMEND_X0, REL) +RELOC_TYPE (SHAMT_X0, REL) +RELOC_TYPE (SHAMT_X1, REL) +RELOC_TYPE (SHAMT_Y0, REL) +RELOC_TYPE (SHAMT_Y1, REL) +RELOC_TYPE (IMM16_X0_HW0, REL) +RELOC_TYPE (IMM16_X1_HW0, REL) +RELOC_TYPE (IMM16_X0_HW1, REL) +RELOC_TYPE (IMM16_X1_HW1, REL) +RELOC_TYPE (IMM16_X0_HW2, REL) +RELOC_TYPE (IMM16_X1_HW2, REL) +RELOC_TYPE (IMM16_X0_HW3, REL) +RELOC_TYPE (IMM16_X1_HW3, REL) +RELOC_TYPE (IMM16_X0_HW0_LAST, REL) +RELOC_TYPE (IMM16_X1_HW0_LAST, REL) +RELOC_TYPE (IMM16_X0_HW1_LAST, REL) +RELOC_TYPE (IMM16_X1_HW1_LAST, REL) +RELOC_TYPE (IMM16_X0_HW2_LAST, REL) +RELOC_TYPE (IMM16_X1_HW2_LAST, REL) +RELOC_TYPE (IMM16_X0_HW0_PCREL, REL) +RELOC_TYPE (IMM16_X1_HW0_PCREL, REL) +RELOC_TYPE (IMM16_X0_HW1_PCREL, REL) +RELOC_TYPE (IMM16_X1_HW1_PCREL, REL) +RELOC_TYPE (IMM16_X0_HW2_PCREL, REL) +RELOC_TYPE (IMM16_X1_HW2_PCREL, REL) +RELOC_TYPE (IMM16_X0_HW3_PCREL, REL) +RELOC_TYPE (IMM16_X1_HW3_PCREL, REL) +RELOC_TYPE (IMM16_X0_HW0_LAST_PCREL, REL) +RELOC_TYPE (IMM16_X1_HW0_LAST_PCREL, REL) +RELOC_TYPE (IMM16_X0_HW1_LAST_PCREL, REL) +RELOC_TYPE (IMM16_X1_HW1_LAST_PCREL, REL) +RELOC_TYPE (IMM16_X0_HW2_LAST_PCREL, REL) +RELOC_TYPE (IMM16_X1_HW2_LAST_PCREL, REL) +RELOC_TYPE (IMM16_X0_HW0_GOT, REL) +RELOC_TYPE (IMM16_X1_HW0_GOT, REL) +RELOC_TYPE (IMM16_X0_HW0_LAST_GOT, REL) +RELOC_TYPE (IMM16_X1_HW0_LAST_GOT, REL) +RELOC_TYPE (IMM16_X0_HW1_LAST_GOT, REL) +RELOC_TYPE (IMM16_X1_HW1_LAST_GOT, REL) +RELOC_TYPE (IMM16_X0_HW0_TLS_GD, REL) +RELOC_TYPE (IMM16_X1_HW0_TLS_GD, REL) +RELOC_TYPE (IMM16_X0_HW0_LAST_TLS_GD, REL) +RELOC_TYPE (IMM16_X1_HW0_LAST_TLS_GD, REL) +RELOC_TYPE (IMM16_X0_HW1_LAST_TLS_GD, REL) +RELOC_TYPE (IMM16_X1_HW1_LAST_TLS_GD, REL) +RELOC_TYPE (IMM16_X0_HW0_TLS_IE, REL) +RELOC_TYPE (IMM16_X1_HW0_TLS_IE, REL) +RELOC_TYPE (IMM16_X0_HW0_LAST_TLS_IE, REL) +RELOC_TYPE (IMM16_X1_HW0_LAST_TLS_IE, REL) +RELOC_TYPE (IMM16_X0_HW1_LAST_TLS_IE, REL) +RELOC_TYPE (IMM16_X1_HW1_LAST_TLS_IE, REL) +RELOC_TYPE (TLS_DTPMOD64, EXEC|DYN) +RELOC_TYPE (TLS_DTPOFF64, EXEC|DYN) +RELOC_TYPE (TLS_TPOFF64, EXEC|DYN) +RELOC_TYPE (TLS_DTPMOD32, EXEC|DYN) +RELOC_TYPE (TLS_DTPOFF32, EXEC|DYN) +RELOC_TYPE (TLS_TPOFF32, EXEC|DYN) +RELOC_TYPE (GNU_VTINHERIT, REL) +RELOC_TYPE (GNU_VTENTRY, REL) diff --git a/3rdparty/elfutils/backends/tilegx_retval.c b/3rdparty/elfutils/backends/tilegx_retval.c new file mode 100644 index 0000000..db81a20 --- /dev/null +++ b/3rdparty/elfutils/backends/tilegx_retval.c @@ -0,0 +1,154 @@ +/* Function return value location for Linux/TILE-Gx ABI. + Copyright (C) 2012 Tilera Corporation + Copyright (C) 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> + +#define BACKEND tilegx_ +#include "libebl_CPU.h" + + +/* r0. */ +static const Dwarf_Op loc_intreg[] = + { + { .atom = DW_OP_reg0 } + }; +#define nloc_intreg 1 + +/* The return value is a structure and is actually stored in stack space + passed in a hidden argument by the caller. But, the compiler + helpfully returns the address of that space in r0. */ +static const Dwarf_Op loc_aggregate[] = + { + { .atom = DW_OP_breg0, .number = 0 } + }; +#define nloc_aggregate 1 + +int +tilegx_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp) +{ + /* Start with the function's type, and get the DW_AT_type attribute, + which is the type of the return value. */ + Dwarf_Die die_mem, *typedie = &die_mem; + int tag = dwarf_peeled_die_type (functypedie, typedie); + if (tag <= 0) + return tag; + + Dwarf_Word size; + switch (tag) + { + case -1: + return -1; + + case DW_TAG_subrange_type: + if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size)) + { + Dwarf_Attribute attr_mem, *attr; + attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem); + typedie = dwarf_formref_die (attr, &die_mem); + tag = DWARF_TAG_OR_RETURN (typedie); + } + /* Fall through. */ + + case DW_TAG_base_type: + case DW_TAG_enumeration_type: + case DW_TAG_pointer_type: + case DW_TAG_ptr_to_member_type: + { + Dwarf_Attribute attr_mem; + if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size, + &attr_mem), &size) != 0) + { + if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type) + size = 8; + else + return -1; + } + if (tag == DW_TAG_base_type) + { + Dwarf_Word encoding; + if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding, + &attr_mem), + &encoding) != 0) + return -1; + } + } + + /* Small enough structs are passed directly in registers R0 ... R7. */ + if (size <= 8) + { + intreg: + *locp = loc_intreg; + return nloc_intreg; + } + + /* Else fall through. */ + case DW_TAG_structure_type: + case DW_TAG_class_type: + case DW_TAG_union_type: + aggregate: + *locp = loc_aggregate; + return nloc_aggregate; + + case DW_TAG_array_type: + case DW_TAG_string_type: + if (dwarf_aggregate_size (typedie, &size) == 0 && size <= 8) + { + if (tag == DW_TAG_array_type) + { + Dwarf_Attribute attr_mem, *attr; + /* Check if it's a character array. */ + attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem); + typedie = dwarf_formref_die (attr, &die_mem); + tag = DWARF_TAG_OR_RETURN (typedie); + if (tag != DW_TAG_base_type) + goto aggregate; + if (dwarf_formudata (dwarf_attr_integrate (typedie, + DW_AT_byte_size, + &attr_mem), + &size) != 0) + return -1; + if (size != 1) + goto aggregate; + } + goto intreg; + } + goto aggregate; + } + + /* XXX We don't have a good way to return specific errors from ebl calls. + This value means we do not understand the type, but it is well-formed + DWARF and might be valid. */ + return -2; +} diff --git a/3rdparty/elfutils/backends/tilegx_symbol.c b/3rdparty/elfutils/backends/tilegx_symbol.c new file mode 100644 index 0000000..b653326 --- /dev/null +++ b/3rdparty/elfutils/backends/tilegx_symbol.c @@ -0,0 +1,57 @@ +/* TILEGX-specific symbolic name handling. + Copyright (C) 2012 Tilera Corporation + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <elf.h> +#include <stddef.h> + +#define BACKEND tilegx_ +#include "libebl_CPU.h" + +/* Check for the simple reloc types. */ +Elf_Type +tilegx_reloc_simple_type (Ebl *ebl __attribute__ ((unused)), int type) +{ + switch (type) + { + case R_TILEGX_64: + return ELF_T_SXWORD; + case R_TILEGX_32: + return ELF_T_SWORD; + case R_TILEGX_16: + return ELF_T_HALF; + case R_TILEGX_8: + return ELF_T_BYTE; + default: + return ELF_T_NUM; + } +} diff --git a/3rdparty/elfutils/backends/x86_64/x86_64.pro b/3rdparty/elfutils/backends/x86_64/x86_64.pro new file mode 100644 index 0000000..fa6060f --- /dev/null +++ b/3rdparty/elfutils/backends/x86_64/x86_64.pro @@ -0,0 +1,17 @@ +TEMPLATE = lib +include(../backends.pri) +TARGET = ../ebl_x86_64 + +SOURCES += \ + ../x86_64_cfi.c \ + ../x86_64_corenote.c \ + ../x86_64_init.c \ + ../x86_64_initreg.c \ + ../x86_64_regs.c \ + ../x86_64_retval.c \ + ../x86_64_symbol.c \ + ../x86_64_syscall.c \ + ../x86_corenote.c + +HEADERS += \ + ../x86_64_reloc.def diff --git a/3rdparty/elfutils/backends/x86_64_cfi.c b/3rdparty/elfutils/backends/x86_64_cfi.c new file mode 100644 index 0000000..6db8ac4 --- /dev/null +++ b/3rdparty/elfutils/backends/x86_64_cfi.c @@ -0,0 +1,63 @@ +/* x86-64 ABI-specified defaults for DWARF CFI. + Copyright (C) 2009 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> + +#define BACKEND x86_64_ +#include "libebl_CPU.h" + +int +x86_64_abi_cfi (Ebl *ebl __attribute__ ((unused)), Dwarf_CIE *abi_info) +{ + static const uint8_t abi_cfi[] = + { + /* Call-saved regs. */ + DW_CFA_same_value, ULEB128_7 (0), /* %rbx */ + DW_CFA_same_value, ULEB128_7 (6), /* %rbp */ + DW_CFA_same_value, ULEB128_7 (12), /* %r12 */ + DW_CFA_same_value, ULEB128_7 (13), /* %r13 */ + DW_CFA_same_value, ULEB128_7 (14), /* %r14 */ + DW_CFA_same_value, ULEB128_7 (15), /* %r15 */ + DW_CFA_same_value, ULEB128_7 (16), /* %r16 */ + + /* The CFA is the SP. */ + DW_CFA_val_offset, ULEB128_7 (7), ULEB128_7 (0), + }; + + abi_info->initial_instructions = abi_cfi; + abi_info->initial_instructions_end = &abi_cfi[sizeof abi_cfi]; + abi_info->data_alignment_factor = 8; + + abi_info->return_address_register = 16; /* %rip */ + + return 0; +} diff --git a/3rdparty/elfutils/backends/x86_64_corenote.c b/3rdparty/elfutils/backends/x86_64_corenote.c new file mode 100644 index 0000000..f9d8db4 --- /dev/null +++ b/3rdparty/elfutils/backends/x86_64_corenote.c @@ -0,0 +1,112 @@ +/* x86-64 specific core note handling. + Copyright (C) 2005, 2007, 2008 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <elf.h> +#include <inttypes.h> +#include <stddef.h> +#include <stdio.h> +#include <sys/time.h> + +#define BACKEND x86_64_ +#include "libebl_CPU.h" + + +static const Ebl_Register_Location prstatus_regs[] = + { +#define GR(at, n, dwreg) \ + { .offset = at * 8, .regno = dwreg, .count = n, .bits = 64 } +#define SR(at, n, dwreg) \ + { .offset = at * 8, .regno = dwreg, .count = n, .bits = 16, .pad = 6 } + + GR (0, 1, 15), /* %r15 */ + GR (1, 1, 14), /* %r14 */ + GR (2, 1, 13), /* %r13 */ + GR (3, 1, 12), /* %r12 */ + GR (4, 1, 6), /* %rbp */ + GR (5, 1, 3), /* %rbx */ + GR (6, 1, 11), /* %r11 */ + GR (7, 1, 10), /* %r10 */ + GR (8, 1, 9), /* %r9 */ + GR (9, 1, 8), /* %r8 */ + GR (10,1, 0), /* %rax */ + GR (11,1, 2), /* %rcx */ + GR (12,1, 1), /* %rdx */ + GR (13,2, 4), /* %rsi-%rdi */ + /* 15,1, orig_rax */ + GR (16,1, 16), /* %rip */ + SR (17,1, 51), /* %cs */ + GR (18,1, 49), /* %rFLAGS */ + GR (19,1, 7), /* %rsp */ + SR (20,1, 52), /* %ss */ + GR (21,2, 58), /* %fs.base-%gs.base */ + SR (23,1, 53), /* %ds */ + SR (24,1, 50), /* %es */ + SR (25,2, 54), /* %fs-%gs */ + +#undef GR +#undef SR + }; +#define PRSTATUS_REGS_SIZE (27 * 8) + +#define ULONG uint64_t +#define PID_T int32_t +#define UID_T uint32_t +#define GID_T uint32_t +#define ALIGN_ULONG 8 +#define ALIGN_PID_T 4 +#define ALIGN_UID_T 4 +#define ALIGN_GID_T 4 +#define TYPE_ULONG ELF_T_XWORD +#define TYPE_PID_T ELF_T_SWORD +#define TYPE_UID_T ELF_T_SWORD +#define TYPE_GID_T ELF_T_SWORD + +#define PRSTATUS_REGSET_ITEMS \ + { \ + .name = "orig_rax", .type = ELF_T_SXWORD, .format = 'd', \ + .offset = offsetof (struct EBLHOOK(prstatus), pr_reg) + (8 * 15), \ + .group = "register" \ + } + +static const Ebl_Register_Location fpregset_regs[] = + { + { .offset = 0, .regno = 65, .count = 2, .bits = 16 }, /* fcw-fsw */ + { .offset = 24, .regno = 64, .count = 1, .bits = 32 }, /* mxcsr */ + { .offset = 32, .regno = 33, .count = 8, .bits = 80, .pad = 6 }, /* stN */ + { .offset = 32 + 128, .regno = 17, .count = 16, .bits = 128 }, /* xmm */ + }; +#define FPREGSET_SIZE 512 + +#define EXTRA_NOTES EXTRA_NOTES_IOPERM + +#include "x86_corenote.c" +#include "linux-core-note.c" diff --git a/3rdparty/elfutils/backends/x86_64_init.c b/3rdparty/elfutils/backends/x86_64_init.c new file mode 100644 index 0000000..b885558 --- /dev/null +++ b/3rdparty/elfutils/backends/x86_64_init.c @@ -0,0 +1,68 @@ +/* Initialization of x86-64 specific backend library. + Copyright (C) 2002-2009, 2013 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND x86_64_ +#define RELOC_PREFIX R_X86_64_ +#include "libebl_CPU.h" + +/* This defines the common reloc hooks based on x86_64_reloc.def. */ +#include "common-reloc.c" + +const char * +x86_64_init (elf, machine, eh, ehlen) + Elf *elf __attribute__ ((unused)); + GElf_Half machine __attribute__ ((unused)); + Ebl *eh; + size_t ehlen; +{ + /* Check whether the Elf_BH object has a sufficent size. */ + if (ehlen < sizeof (Ebl)) + return NULL; + + /* We handle it. */ + eh->name = "AMD x86-64"; + x86_64_init_reloc (eh); + HOOK (eh, reloc_simple_type); + HOOK (eh, core_note); + HOOK (eh, return_value_location); + HOOK (eh, register_info); + HOOK (eh, syscall_abi); + HOOK (eh, auxv_info); + HOOK (eh, disasm); + HOOK (eh, abi_cfi); + /* gcc/config/ #define DWARF_FRAME_REGISTERS. */ + eh->frame_nregs = 17; + HOOK (eh, set_initial_registers_tid); + + return MODVERSION; +} diff --git a/3rdparty/elfutils/backends/x86_64_initreg.c b/3rdparty/elfutils/backends/x86_64_initreg.c new file mode 100644 index 0000000..db9216e --- /dev/null +++ b/3rdparty/elfutils/backends/x86_64_initreg.c @@ -0,0 +1,73 @@ +/* Fetch live process registers from TID. + Copyright (C) 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> +#ifdef __x86_64__ +# include <sys/user.h> +# include <sys/ptrace.h> +#endif + +#define BACKEND x86_64_ +#include "libebl_CPU.h" + +bool +x86_64_set_initial_registers_tid (pid_t tid __attribute__ ((unused)), + ebl_tid_registers_t *setfunc __attribute__ ((unused)), + void *arg __attribute__ ((unused))) +{ +#if !defined(__x86_64__) || !defined(__linux__) + return false; +#else /* __x86_64__ */ + struct user_regs_struct user_regs; + if (ptrace (PTRACE_GETREGS, tid, NULL, &user_regs) != 0) + return false; + Dwarf_Word dwarf_regs[17]; + dwarf_regs[0] = user_regs.rax; + dwarf_regs[1] = user_regs.rdx; + dwarf_regs[2] = user_regs.rcx; + dwarf_regs[3] = user_regs.rbx; + dwarf_regs[4] = user_regs.rsi; + dwarf_regs[5] = user_regs.rdi; + dwarf_regs[6] = user_regs.rbp; + dwarf_regs[7] = user_regs.rsp; + dwarf_regs[8] = user_regs.r8; + dwarf_regs[9] = user_regs.r9; + dwarf_regs[10] = user_regs.r10; + dwarf_regs[11] = user_regs.r11; + dwarf_regs[12] = user_regs.r12; + dwarf_regs[13] = user_regs.r13; + dwarf_regs[14] = user_regs.r14; + dwarf_regs[15] = user_regs.r15; + dwarf_regs[16] = user_regs.rip; + return setfunc (0, 17, dwarf_regs, arg); +#endif /* __x86_64__ */ +} diff --git a/3rdparty/elfutils/backends/x86_64_regs.c b/3rdparty/elfutils/backends/x86_64_regs.c new file mode 100644 index 0000000..2172d9f --- /dev/null +++ b/3rdparty/elfutils/backends/x86_64_regs.c @@ -0,0 +1,185 @@ +/* Register names and numbers for x86-64 DWARF. + Copyright (C) 2005, 2006, 2007 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> +#include <string.h> + +#define BACKEND x86_64_ +#include "libebl_CPU.h" + +ssize_t +x86_64_register_info (Ebl *ebl __attribute__ ((unused)), + int regno, char *name, size_t namelen, + const char **prefix, const char **setname, + int *bits, int *type) +{ + if (name == NULL) + return 67; + + if (regno < 0 || regno > 66 || namelen < 7) + return -1; + + *prefix = "%"; + *bits = 64; + *type = DW_ATE_unsigned; + if (regno < 17) + { + *setname = "integer"; + *type = DW_ATE_signed; + } + else if (regno < 33) + { + *setname = "SSE"; + *bits = 128; + } + else if (regno < 41) + { + *setname = "x87"; + *type = DW_ATE_float; + *bits = 80; + } + else if (regno < 49) + *setname = "MMX"; + else if (regno > 49 && regno < 60) + { + *setname = "segment"; + *bits = 16; + } + else + *setname = "control"; + + switch (regno) + { + static const char baseregs[][2] = + { + "ax", "dx", "cx", "bx", "si", "di", "bp", "sp" + }; + + case 6 ... 7: + *type = DW_ATE_address; + case 0 ... 5: + name[0] = 'r'; + name[1] = baseregs[regno][0]; + name[2] = baseregs[regno][1]; + namelen = 3; + break; + + case 8 ... 9: + name[0] = 'r'; + name[1] = regno - 8 + '8'; + namelen = 2; + break; + + case 10 ... 15: + name[0] = 'r'; + name[1] = '1'; + name[2] = regno - 10 + '0'; + namelen = 3; + break; + + case 16: + *type = DW_ATE_address; + name[0] = 'r'; + name[1] = 'i'; + name[2] = 'p'; + namelen = 3; + break; + + case 17 ... 26: + name[0] = 'x'; + name[1] = 'm'; + name[2] = 'm'; + name[3] = regno - 17 + '0'; + namelen = 4; + break; + + case 27 ... 32: + name[0] = 'x'; + name[1] = 'm'; + name[2] = 'm'; + name[3] = '1'; + name[4] = regno - 27 + '0'; + namelen = 5; + break; + + case 33 ... 40: + name[0] = 's'; + name[1] = 't'; + name[2] = regno - 33 + '0'; + namelen = 3; + break; + + case 41 ... 48: + name[0] = 'm'; + name[1] = 'm'; + name[2] = regno - 41 + '0'; + namelen = 3; + break; + + case 50 ... 55: + name[0] = "ecsdfg"[regno - 50]; + name[1] = 's'; + namelen = 2; + break; + + case 58 ... 59: + *type = DW_ATE_address; + *bits = 64; + name[0] = regno - 58 + 'f'; + return stpcpy (&name[1], "s.base") + 1 - name; + + case 49: + *setname = "integer"; + return stpcpy (name, "rflags") + 1 - name; + case 62: + return stpcpy (name, "tr") + 1 - name; + case 63: + return stpcpy (name, "ldtr") + 1 - name; + case 64: + return stpcpy (name, "mxcsr") + 1 - name; + + case 65 ... 66: + *bits = 16; + name[0] = 'f'; + name[1] = "cs"[regno - 65]; + name[2] = 'w'; + namelen = 3; + break; + + default: + return 0; + } + + name[namelen++] = '\0'; + return namelen; +} diff --git a/3rdparty/elfutils/backends/x86_64_reloc.def b/3rdparty/elfutils/backends/x86_64_reloc.def new file mode 100644 index 0000000..8ed98f6 --- /dev/null +++ b/3rdparty/elfutils/backends/x86_64_reloc.def @@ -0,0 +1,63 @@ +/* List the relocation types for x86-64. -*- C -*- + Copyright (C) 2000, 2001, 2002, 2003, 2005, 2009 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +/* NAME, REL|EXEC|DYN */ + +RELOC_TYPE (NONE, 0) +RELOC_TYPE (64, REL|EXEC|DYN) +RELOC_TYPE (PC32, REL|EXEC|DYN) +RELOC_TYPE (GOT32, REL) +RELOC_TYPE (PLT32, REL) +RELOC_TYPE (COPY, EXEC) +RELOC_TYPE (GLOB_DAT, EXEC|DYN) +RELOC_TYPE (JUMP_SLOT, EXEC|DYN) +RELOC_TYPE (RELATIVE, EXEC|DYN) +RELOC_TYPE (GOTPCREL, REL) +RELOC_TYPE (32, REL|EXEC|DYN) +RELOC_TYPE (32S, REL) +RELOC_TYPE (16, REL) +RELOC_TYPE (PC16, REL) +RELOC_TYPE (8, REL) +RELOC_TYPE (PC8, REL) +RELOC_TYPE (DTPMOD64, EXEC|DYN) +RELOC_TYPE (DTPOFF64, EXEC|DYN) +RELOC_TYPE (TPOFF64, EXEC|DYN) +RELOC_TYPE (TLSGD, REL) +RELOC_TYPE (TLSLD, REL) +RELOC_TYPE (DTPOFF32, REL) +RELOC_TYPE (GOTTPOFF, REL) +RELOC_TYPE (TPOFF32, REL) +RELOC_TYPE (PC64, REL|EXEC|DYN) +RELOC_TYPE (GOTOFF64, REL) +RELOC_TYPE (GOTPC32, REL) +RELOC_TYPE (SIZE32, REL|EXEC|DYN) +RELOC_TYPE (SIZE64, REL|EXEC|DYN) +RELOC_TYPE (GOTPC32_TLSDESC, REL) +RELOC_TYPE (TLSDESC_CALL, REL) +RELOC_TYPE (TLSDESC, REL|EXEC|DYN) +RELOC_TYPE (IRELATIVE, EXEC|DYN) diff --git a/3rdparty/elfutils/backends/x86_64_retval.c b/3rdparty/elfutils/backends/x86_64_retval.c new file mode 100644 index 0000000..b3799ae --- /dev/null +++ b/3rdparty/elfutils/backends/x86_64_retval.c @@ -0,0 +1,194 @@ +/* Function return value location for Linux/x86-64 ABI. + Copyright (C) 2005-2010, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> + +#define BACKEND x86_64_ +#include "libebl_CPU.h" + + +/* %rax, or pair %rax, %rdx. */ +static const Dwarf_Op loc_intreg[] = + { + { .atom = DW_OP_reg0 }, { .atom = DW_OP_piece, .number = 8 }, + { .atom = DW_OP_reg1 }, { .atom = DW_OP_piece, .number = 8 }, + }; +#define nloc_intreg 1 +#define nloc_intregpair 4 + +/* %st(0), or pair %st(0), %st(1). */ +static const Dwarf_Op loc_x87reg[] = + { + { .atom = DW_OP_regx, .number = 33 }, + { .atom = DW_OP_piece, .number = 10 }, + { .atom = DW_OP_regx, .number = 34 }, + { .atom = DW_OP_piece, .number = 10 }, + }; +#define nloc_x87reg 1 +#define nloc_x87regpair 4 + +/* %xmm0, or pair %xmm0, %xmm1. */ +static const Dwarf_Op loc_ssereg[] = + { + { .atom = DW_OP_reg17 }, { .atom = DW_OP_piece, .number = 16 }, + { .atom = DW_OP_reg18 }, { .atom = DW_OP_piece, .number = 16 }, + }; +#define nloc_ssereg 1 +#define nloc_sseregpair 4 + +/* The return value is a structure and is actually stored in stack space + passed in a hidden argument by the caller. But, the compiler + helpfully returns the address of that space in %rax. */ +static const Dwarf_Op loc_aggregate[] = + { + { .atom = DW_OP_breg0, .number = 0 } + }; +#define nloc_aggregate 1 + + +int +x86_64_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp) +{ + /* Start with the function's type, and get the DW_AT_type attribute, + which is the type of the return value. */ + Dwarf_Die die_mem, *typedie = &die_mem; + int tag = dwarf_peeled_die_type (functypedie, typedie); + if (tag <= 0) + return tag; + + Dwarf_Word size; + switch (tag) + { + case -1: + return -1; + + case DW_TAG_subrange_type: + if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size)) + { + Dwarf_Attribute attr_mem, *attr; + attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem); + typedie = dwarf_formref_die (attr, &die_mem); + tag = DWARF_TAG_OR_RETURN (typedie); + } + /* Fall through. */ + + case DW_TAG_base_type: + case DW_TAG_enumeration_type: + case DW_TAG_pointer_type: + case DW_TAG_ptr_to_member_type: + { + Dwarf_Attribute attr_mem; + if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size, + &attr_mem), &size) != 0) + { + if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type) + size = 8; + else + return -1; + } + } + + if (tag == DW_TAG_base_type) + { + Dwarf_Attribute attr_mem; + Dwarf_Word encoding; + if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding, + &attr_mem), + &encoding) != 0) + return -1; + + switch (encoding) + { + case DW_ATE_complex_float: + switch (size) + { + case 4 * 2: /* complex float */ + case 8 * 2: /* complex double */ + *locp = loc_ssereg; + return nloc_sseregpair; + case 16 * 2: /* complex long double */ + *locp = loc_x87reg; + return nloc_x87regpair; + } + return -2; + + case DW_ATE_float: + switch (size) + { + case 4: /* float */ + case 8: /* double */ + *locp = loc_ssereg; + return nloc_ssereg; + case 16: /* long double */ + /* XXX distinguish __float128, which is sseregpair?? */ + *locp = loc_x87reg; + return nloc_x87reg; + } + return -2; + } + } + + intreg: + *locp = loc_intreg; + if (size <= 8) + return nloc_intreg; + if (size <= 16) + return nloc_intregpair; + + large: + *locp = loc_aggregate; + return nloc_aggregate; + + case DW_TAG_structure_type: + case DW_TAG_class_type: + case DW_TAG_union_type: + case DW_TAG_array_type: + if (dwarf_aggregate_size (typedie, &size) != 0) + goto large; + if (size > 16) + goto large; + + /* XXX + Must examine the fields in picayune ways to determine the + actual answer. This will be right for small C structs + containing integer types and similarly simple cases. + */ + + goto intreg; + } + + /* XXX We don't have a good way to return specific errors from ebl calls. + This value means we do not understand the type, but it is well-formed + DWARF and might be valid. */ + return -2; +} diff --git a/3rdparty/elfutils/backends/x86_64_symbol.c b/3rdparty/elfutils/backends/x86_64_symbol.c new file mode 100644 index 0000000..1622461 --- /dev/null +++ b/3rdparty/elfutils/backends/x86_64_symbol.c @@ -0,0 +1,60 @@ +/* x86_64 specific symbolic name handling. + Copyright (C) 2002, 2005 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <elf.h> +#include <stddef.h> + +#define BACKEND x86_64_ +#include "libebl_CPU.h" + +/* Check for the simple reloc types. */ +Elf_Type +x86_64_reloc_simple_type (Ebl *ebl __attribute__ ((unused)), int type) +{ + switch (type) + { + case R_X86_64_64: + return ELF_T_XWORD; + case R_X86_64_32: + return ELF_T_WORD; + case R_X86_64_32S: + return ELF_T_SWORD; + case R_X86_64_16: + return ELF_T_HALF; + case R_X86_64_8: + return ELF_T_BYTE; + default: + return ELF_T_NUM; + } +} diff --git a/3rdparty/elfutils/backends/x86_64_syscall.c b/3rdparty/elfutils/backends/x86_64_syscall.c new file mode 100644 index 0000000..0deb8ba --- /dev/null +++ b/3rdparty/elfutils/backends/x86_64_syscall.c @@ -0,0 +1,50 @@ +/* Linux/x86-64 system call ABI in DWARF register numbers. + Copyright (C) 2008 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND x86_64_ +#include "libebl_CPU.h" + +int +x86_64_syscall_abi (Ebl *ebl __attribute__ ((unused)), + int *sp, int *pc, int *callno, int args[6]) +{ + *sp = 7; /* %rsp */ + *pc = 16; /* %rip */ + *callno = 0; /* %rax */ + args[0] = 5; /* %rdi */ + args[1] = 4; /* %rsi */ + args[2] = 1; /* %rdx */ + args[3] = 10; /* %r10 */ + args[4] = 8; /* %r8 */ + args[5] = 9; /* %r9 */ + return 0; +} diff --git a/3rdparty/elfutils/backends/x86_corenote.c b/3rdparty/elfutils/backends/x86_corenote.c new file mode 100644 index 0000000..629462c --- /dev/null +++ b/3rdparty/elfutils/backends/x86_corenote.c @@ -0,0 +1,51 @@ +/* x86-specific core note handling, pieces common to x86-64 and i386. + Copyright (C) 2005-2010 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#define EXTRA_NOTES_IOPERM \ + case NT_386_IOPERM: \ + return ioperm_info (nhdr->n_descsz, \ + regs_offset, nregloc, reglocs, nitems, items); + +static int +ioperm_info (GElf_Word descsz, GElf_Word *regs_offset, + size_t *nregloc, const Ebl_Register_Location **reglocs, + size_t *nitems, const Ebl_Core_Item **items) +{ + static const Ebl_Core_Item ioperm_item = + { .type = ELF_T_WORD, .format = 'b', .name = "ioperm" }; + + if (descsz % 4 != 0) + return 0; + + *regs_offset = 0; + *nregloc = 0; + *reglocs = NULL; + *nitems = 1; + *items = &ioperm_item; + return 1; +} diff --git a/3rdparty/elfutils/config.h b/3rdparty/elfutils/config.h new file mode 100644 index 0000000..fbf5f8e --- /dev/null +++ b/3rdparty/elfutils/config.h @@ -0,0 +1,106 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Should ar and ranlib use -D behavior by default? */ +#define DEFAULT_AR_DETERMINISTIC false + +/* Define to 1 if you have the <inttypes.h> header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the <memory.h> header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the <stdint.h> header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the <stdlib.h> header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the <strings.h> header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the <string.h> header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the <sys/types.h> header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if <sys/user.h> defines struct user_regs_struct */ +#define HAVE_SYS_USER_REGS 1 + +/* Define to 1 if you have the <unistd.h> header file. */ +#define HAVE_UNISTD_H 1 + +/* $libdir subdirectory containing libebl modules. */ +#define LIBEBL_SUBDIR "elfutils" + +/* Identifier for modules in the build. */ +#define MODVERSION "Build on zebra 2015-02-03T13:51:12+0100" + +/* Define to 32 or 64 if a specific implementation is wanted. */ +/* #undef NATIVE_ELF */ + +/* Name of package */ +#define PACKAGE "elfutils" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "https://bugzilla.redhat.com/" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "elfutils" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "elfutils 0.161" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "elfutils" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "0.161" + +/* The size of `long', as computed by sizeof. */ +#define SIZEOF_LONG 8 + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Support bzip2 decompression via -lbz2. */ +/* #undef USE_BZLIB */ + +/* Defined if demangling is enabled */ +#define USE_DEMANGLE 1 + +/* Defined if libraries should be thread-safe. */ +/* #undef USE_LOCKS */ + +/* Support LZMA (xz) decompression via -llzma. */ +/* #undef USE_LZMA */ + +/* Support gzip decompression via -lz. */ +#define USE_ZLIB 1 + +/* Version number of package */ +#define VERSION "0.161" + +/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a + `char[]'. */ +#define YYTEXT_POINTER 1 + +/* Enable large inode numbers on Mac OS X 10.5. */ +#ifndef _DARWIN_USE_64_BIT_INODE +# define _DARWIN_USE_64_BIT_INODE 1 +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +/* #undef _FILE_OFFSET_BITS */ + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +#include <eu-config.h> diff --git a/3rdparty/elfutils/elfutils.pri b/3rdparty/elfutils/elfutils.pri new file mode 100644 index 0000000..bdbf5db --- /dev/null +++ b/3rdparty/elfutils/elfutils.pri @@ -0,0 +1,10 @@ +VERSION = 0.161 +QMAKE_CFLAGS += -std=gnu99 +DEFINES += HAVE_CONFIG_H _GNU_SOURCE + +HEADERS += \ + $$PWD/version.h \ + $$PWD/config.h + +INCLUDEPATH += $$PWD +include(lib/libheaders.pri) diff --git a/3rdparty/elfutils/elfutils.pro b/3rdparty/elfutils/elfutils.pro new file mode 100644 index 0000000..78d3798 --- /dev/null +++ b/3rdparty/elfutils/elfutils.pro @@ -0,0 +1,24 @@ +TEMPLATE = subdirs + +# split out libelf's 32bit and 64bit specific parts as qmake will see the include directives in +# the 64bit versions and then not compile the 32bit ones + +SUBDIRS = \ + backends \ + lib \ + libasm \ + libebl \ + libelf \ + libelf/elf32 \ + libelf/elf64 \ + libdw \ + libdwelf \ + libdwfl + +OTHER_FILES += \ + COPYING \ + COPYING-GPLV2 \ + COPYING-LGPLV3 \ + AUTHORS \ + THANKS + diff --git a/3rdparty/elfutils/lib/color.c b/3rdparty/elfutils/lib/color.c new file mode 100644 index 0000000..d1309ed --- /dev/null +++ b/3rdparty/elfutils/lib/color.c @@ -0,0 +1,230 @@ +/* Handling of color output. + Copyright (C) 2011 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2011. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <argp.h> +#include <error.h> +#include <libintl.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "system.h" + + +/* Prototype for option handler. */ +static error_t parse_opt (int key, char *arg, struct argp_state *state); + +/* Option values. */ +#define OPT_COLOR 0x100100 + +/* Definitions of arguments for argp functions. */ +static const struct argp_option options[] = +{ + { "color", OPT_COLOR, "WHEN", OPTION_ARG_OPTIONAL, + N_("colorize the output. WHEN defaults to 'always' or can be 'auto' or 'never'"), 0 }, + + { NULL, 0, NULL, 0, NULL, 0 } +}; + +/* Parser data structure. */ +const struct argp color_argp = + { + options, parse_opt, NULL, NULL, NULL, NULL, NULL + }; + +/* Coloring mode. */ +enum color_enum color_mode; + +/* Colors to use for the various components. */ +char *color_address = ""; +char *color_bytes = ""; +char *color_mnemonic = ""; +char *color_operand = NULL; +char *color_operand1 = ""; +char *color_operand2 = ""; +char *color_operand3 = ""; +char *color_label = ""; +char *color_undef = ""; +char *color_undef_tls = ""; +char *color_undef_weak = ""; +char *color_symbol = ""; +char *color_tls = ""; +char *color_weak = ""; + +const char color_off[] = "\e[0m"; + + +/* Handle program arguments. */ +static error_t +parse_opt (int key, char *arg, + struct argp_state *state __attribute__ ((unused))) +{ + switch (key) + { + case OPT_COLOR: + if (arg == NULL) + color_mode = color_always; + else + { + static const struct + { + const char str[7]; + enum color_enum mode; + } values[] = + { + { "always", color_always }, + { "yes", color_always }, + { "force", color_always }, + { "never", color_never }, + { "no", color_never }, + { "none", color_never }, + { "auto", color_auto }, + { "tty", color_auto }, + { "if-tty", color_auto } + }; + const int nvalues = sizeof (values) / sizeof (values[0]); + int i; + for (i = 0; i < nvalues; ++i) + if (strcmp (arg, values[i].str) == 0) + { + color_mode = values[i].mode; + if (color_mode == color_auto) + color_mode + = isatty (STDOUT_FILENO) ? color_always : color_never; + break; + } + if (i == nvalues) + { + error (0, 0, dgettext ("elfutils", "\ +%s: invalid argument '%s' for '--color'\n\ +valid arguments are:\n\ + - 'always', 'yes', 'force'\n\ + - 'never', 'no', 'none'\n\ + - 'auto', 'tty', 'if-tty'\n"), + program_invocation_short_name, arg); + argp_help (&color_argp, stderr, ARGP_HELP_SEE, + program_invocation_short_name); + exit (EXIT_FAILURE); + } + } + + if (color_mode == color_always) + { + const char *env = getenv ("ELFUTILS_COLORS"); + if (env != NULL) + { + do + { + const char *start = env; + while (*env != '=' && *env != '\0') + ++env; + if (*env == '=' && env != start) + { + size_t name_len = env - start; + const char *val = ++env; + env = strchrnul (env, ':'); + if (val != env) + { + static const struct + { + unsigned char len; + const char name[sizeof (char *) - 1]; + char **varp; + } known[] = + { +#define E(name, var) { sizeof (#name) - 1, #name, &color_##var } + E (a, address), + E (b, bytes), + E (m, mnemonic), + E (o, operand), + E (o1, operand1), + E (o1, operand2), + E (o1, operand3), + E (l, label), + E (u, undef), + E (ut, undef_tls), + E (uw, undef_weak), + E (sy, symbol), + E (st, tls), + E (sw, weak), + }; + const size_t nknown = (sizeof (known) + / sizeof (known[0])); + + for (size_t i = 0; i < nknown; ++i) + if (name_len == known[i].len + && memcmp (start, known[i].name, name_len) == 0) + { + if (asprintf (known[i].varp, "\e[%.*sm", + (int) (env - val), val) < 0) + error (EXIT_FAILURE, errno, + gettext ("cannot allocate memory")); + break; + } + } + if (*env == ':') + ++env; + } + } + while (*env != '\0'); + + if (color_operand != NULL) + { + if (color_operand1[0] == '\0') + color_operand1 = color_operand; + if (color_operand2[0] == '\0') + color_operand2 = color_operand; + if (color_operand3[0] == '\0') + color_operand3 = color_operand; + } + } +#if 0 + else + { + // XXX Just for testing. + color_address = xstrdup ("\e[38;5;166;1m"); + color_bytes = xstrdup ("\e[38;5;141m"); + color_mnemonic = xstrdup ("\e[38;5;202;1m"); + color_operand1 = xstrdup ("\e[38;5;220m"); + color_operand2 = xstrdup ("\e[38;5;48m"); + color_operand3 = xstrdup ("\e[38;5;112m"); + color_label = xstrdup ("\e[38;5;21m"); + } +#endif + } + break; + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} diff --git a/3rdparty/elfutils/lib/crc32.c b/3rdparty/elfutils/lib/crc32.c new file mode 100644 index 0000000..1a76b1b --- /dev/null +++ b/3rdparty/elfutils/lib/crc32.c @@ -0,0 +1,98 @@ +/* Copyright (C) 2002 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include <stdint.h> +#include "system.h" + + +/* Table computed with Mark Adler's makecrc.c utility. */ +static const uint32_t crc32_table[256] = +{ + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, + 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, + 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, + 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, + 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, + 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, + 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, + 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, + 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, + 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, + 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, + 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, + 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, + 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, + 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, + 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, + 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, + 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, + 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, + 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, + 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, + 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, + 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, + 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, + 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, + 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, + 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, + 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, + 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, + 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, + 0x2d02ef8d +}; + +uint32_t +crc32 (uint32_t crc, unsigned char *buf, size_t len) +{ + unsigned char *end; + + crc = ~crc; + for (end = buf + len; buf < end; ++buf) + crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8); + return ~crc; +} diff --git a/3rdparty/elfutils/lib/crc32_file.c b/3rdparty/elfutils/lib/crc32_file.c new file mode 100644 index 0000000..c0b18e9 --- /dev/null +++ b/3rdparty/elfutils/lib/crc32_file.c @@ -0,0 +1,91 @@ +/* Compute CRC32 checksum of file contents. + Copyright (C) 2006 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "system.h" +#include <errno.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/mman.h> + +int +crc32_file (int fd, uint32_t *resp) +{ + unsigned char buffer[1024 * 8]; + uint32_t crc = 0; + off_t off = 0; + ssize_t count; + + struct stat st; + if (fstat (fd, &st) == 0) + { + /* Try mapping in the file data. */ + size_t mapsize = st.st_size; + void *mapped = mmap (NULL, mapsize, PROT_READ, MAP_PRIVATE, fd, 0); + if (mapped == MAP_FAILED && errno == ENOMEM) + { + const size_t pagesize = sysconf (_SC_PAGE_SIZE); + mapsize = ((mapsize / 2) + pagesize - 1) & -pagesize; + while (mapsize >= pagesize + && (mapped = mmap (NULL, mapsize, PROT_READ, MAP_PRIVATE, + fd, 0)) == MAP_FAILED && errno == ENOMEM) + mapsize /= 2; + } + if (mapped != MAP_FAILED) + { + do + { + if (st.st_size <= (off_t) mapsize) + { + *resp = crc32 (crc, mapped, st.st_size); + munmap (mapped, mapsize); + return 0; + } + crc = crc32 (crc, mapped, mapsize); + off += mapsize; + st.st_size -= mapsize; + } while (mmap (mapped, mapsize, PROT_READ, MAP_FIXED|MAP_PRIVATE, + fd, off) == mapped); + munmap (mapped, mapsize); + } + } + + while ((count = TEMP_FAILURE_RETRY (pread (fd, buffer, sizeof buffer, + off))) > 0) + { + off += count; + crc = crc32 (crc, buffer, count); + } + + *resp = crc; + + return count == 0 ? 0 : -1; +} diff --git a/3rdparty/elfutils/lib/dynamicsizehash.c b/3rdparty/elfutils/lib/dynamicsizehash.c new file mode 100644 index 0000000..1fdff1b --- /dev/null +++ b/3rdparty/elfutils/lib/dynamicsizehash.c @@ -0,0 +1,332 @@ +/* Copyright (C) 2000-2010 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include <assert.h> +#include <stdlib.h> +#include <system.h> + +/* Before including this file the following macros must be defined: + + NAME name of the hash table structure. + TYPE data type of the hash table entries + COMPARE comparison function taking two pointers to TYPE objects + + The following macros if present select features: + + ITERATE iterating over the table entries is possible + REVERSE iterate in reverse order of insert + */ + + +static size_t +lookup (htab, hval, val) + NAME *htab; + HASHTYPE hval; + TYPE val __attribute__ ((unused)); +{ + /* First hash function: simply take the modul but prevent zero. Small values + can skip the division, which helps performance when this is common. */ + size_t idx = 1 + (hval < htab->size ? hval : hval % htab->size); + + if (htab->table[idx].hashval != 0) + { + HASHTYPE hash; + + if (htab->table[idx].hashval == hval + && COMPARE (htab->table[idx].data, val) == 0) + return idx; + + /* Second hash function as suggested in [Knuth]. */ + hash = 1 + hval % (htab->size - 2); + + do + { + if (idx <= hash) + idx = htab->size + idx - hash; + else + idx -= hash; + + /* If entry is found use it. */ + if (htab->table[idx].hashval == hval + && COMPARE (htab->table[idx].data, val) == 0) + return idx; + } + while (htab->table[idx].hashval); + } + return idx; +} + + +static void +insert_entry_2 (NAME *htab, HASHTYPE hval, size_t idx, TYPE data) +{ +#ifdef ITERATE + if (htab->table[idx].hashval == 0) + { +# ifdef REVERSE + htab->table[idx].next = htab->first; + htab->first = &htab->table[idx]; +# else + /* Add the new value to the list. */ + if (htab->first == NULL) + htab->first = htab->table[idx].next = &htab->table[idx]; + else + { + htab->table[idx].next = htab->first->next; + htab->first = htab->first->next = &htab->table[idx]; + } +# endif + } +#endif + + htab->table[idx].hashval = hval; + htab->table[idx].data = data; + + ++htab->filled; + if (100 * htab->filled > 90 * htab->size) + { + /* Table is filled more than 90%. Resize the table. */ +#ifdef ITERATE + __typeof__ (htab->first) first; +# ifndef REVERSE + __typeof__ (htab->first) runp; +# endif +#else + size_t old_size = htab->size; +#endif +#define _TABLE(name) \ + name##_ent *table = htab->table +#define TABLE(name) _TABLE (name) + TABLE(NAME); + + htab->size = next_prime (htab->size * 2); + htab->filled = 0; +#ifdef ITERATE + first = htab->first; + htab->first = NULL; +#endif + htab->table = calloc ((1 + htab->size), sizeof (htab->table[0])); + if (htab->table == NULL) + { + /* We cannot enlarge the table. Live with what we got. This + might lead to an infinite loop at some point, though. */ + htab->table = table; + return; + } + + /* Add the old entries to the new table. When iteration is + supported we maintain the order. */ +#ifdef ITERATE +# ifdef REVERSE + while (first != NULL) + { + insert_entry_2 (htab, first->hashval, + lookup (htab, first->hashval, first->data), + first->data); + + first = first->next; + } +# else + assert (first != NULL); + runp = first = first->next; + do + insert_entry_2 (htab, runp->hashval, + lookup (htab, runp->hashval, runp->data), runp->data); + while ((runp = runp->next) != first); +# endif +#else + for (idx = 1; idx <= old_size; ++idx) + if (table[idx].hashval != 0) + insert_entry_2 (htab, table[idx].hashval, + lookup (htab, table[idx].hashval, table[idx].data), + table[idx].data); +#endif + + free (table); + } +} + + +int +#define INIT(name) _INIT (name) +#define _INIT(name) \ + name##_init +INIT(NAME) (htab, init_size) + NAME *htab; + size_t init_size; +{ + /* We need the size to be a prime. */ + init_size = next_prime (init_size); + + /* Initialize the data structure. */ + htab->size = init_size; + htab->filled = 0; +#ifdef ITERATE + htab->first = NULL; +#endif + htab->table = (void *) calloc ((init_size + 1), sizeof (htab->table[0])); + if (htab->table == NULL) + return -1; + + return 0; +} + + +int +#define FREE(name) _FREE (name) +#define _FREE(name) \ + name##_free +FREE(NAME) (htab) + NAME *htab; +{ + free (htab->table); + return 0; +} + + +int +#define INSERT(name) _INSERT (name) +#define _INSERT(name) \ + name##_insert +INSERT(NAME) (htab, hval, data) + NAME *htab; + HASHTYPE hval; + TYPE data; +{ + size_t idx; + + /* Make the hash value nonzero. */ + hval = hval ?: 1; + + idx = lookup (htab, hval, data); + + if (htab->table[idx].hashval != 0) + /* We don't want to overwrite the old value. */ + return -1; + + /* An empty bucket has been found. */ + insert_entry_2 (htab, hval, idx, data); + return 0; +} + + +#ifdef OVERWRITE +int +#define INSERT(name) _INSERT (name) +#define _INSERT(name) \ + name##_overwrite +INSERT(NAME) (htab, hval, data) + NAME *htab; + HASHTYPE hval; + TYPE data; +{ + size_t idx; + + /* Make the hash value nonzero. */ + hval = hval ?: 1; + + idx = lookup (htab, hval, data); + + /* The correct bucket has been found. */ + insert_entry_2 (htab, hval, idx, data); + return 0; +} +#endif + + +TYPE +#define FIND(name) _FIND (name) +#define _FIND(name) \ + name##_find +FIND(NAME) (htab, hval, val) + NAME *htab; + HASHTYPE hval; + TYPE val; +{ + size_t idx; + + /* Make the hash value nonzero. */ + hval = hval ?: 1; + + idx = lookup (htab, hval, val); + + if (htab->table[idx].hashval == 0) + return NULL; + + return htab->table[idx].data; +} + + +#ifdef ITERATE +# define ITERATEFCT(name) _ITERATEFCT (name) +# define _ITERATEFCT(name) \ + name##_iterate +TYPE +ITERATEFCT(NAME) (htab, ptr) + NAME *htab; + void **ptr; +{ + void *p = *ptr; + +# define TYPENAME(name) _TYPENAME (name) +# define _TYPENAME(name) name##_ent + +# ifdef REVERSE + if (p == NULL) + p = htab->first; + else + p = ((TYPENAME(NAME) *) p)->next; + + if (p == NULL) + { + *ptr = NULL; + return NULL; + } +# else + if (p == NULL) + { + if (htab->first == NULL) + return NULL; + p = htab->first->next; + } + else + { + if (p == htab->first) + return NULL; + + p = ((TYPENAME(NAME) *) p)->next; + } +# endif + + /* Prepare the next element. If possible this will pull the data + into the cache, for reading. */ + __builtin_prefetch (((TYPENAME(NAME) *) p)->next, 0, 2); + + return ((TYPENAME(NAME) *) (*ptr = p))->data; +} +#endif diff --git a/3rdparty/elfutils/lib/dynamicsizehash.h b/3rdparty/elfutils/lib/dynamicsizehash.h new file mode 100644 index 0000000..ccd41d0 --- /dev/null +++ b/3rdparty/elfutils/lib/dynamicsizehash.h @@ -0,0 +1,127 @@ +/* Copyright (C) 2000-2010 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include <stddef.h> + +/* Before including this file the following macros must be defined: + + NAME name of the hash table structure. + TYPE data type of the hash table entries + + The following macros if present select features: + + ITERATE iterating over the table entries is possible + HASHTYPE integer type for hash values, default unsigned long int + */ + + +/* Optionally include an entry pointing to the first used entry. */ +#ifdef ITERATE +# define FIRST(name) name##_ent *first; +# define NEXT(name) struct name##_ent *next; +#else +# define FIRST(name) +# define NEXT(name) +#endif + +#ifndef HASHTYPE +# define HASHTYPE unsigned long int +#endif + + +/* Defined separately. */ +extern size_t next_prime (size_t seed); + + +/* Table entry type. */ +#define _DYNHASHENTTYPE(name) \ + typedef struct name##_ent \ + { \ + HASHTYPE hashval; \ + TYPE data; \ + NEXT (name) \ + } name##_ent +#define DYNHASHENTTYPE(name) _DYNHASHENTTYPE (name) +DYNHASHENTTYPE (NAME); + + +/* Type of the dynamic hash table data structure. */ +#define _DYNHASHTYPE(name) \ +typedef struct \ +{ \ + size_t size; \ + size_t filled; \ + name##_ent *table; \ + FIRST (name) \ +} name +#define DYNHASHTYPE(name) _DYNHASHTYPE (name) +DYNHASHTYPE (NAME); + + + +#define _FUNCTIONS(name) \ +/* Initialize the hash table. */ \ +extern int name##_init (name *htab, size_t init_size); \ + \ +/* Free resources allocated for hash table. */ \ +extern int name##_free (name *htab); \ + \ +/* Insert new entry. */ \ +extern int name##_insert (name *htab, HASHTYPE hval, TYPE data); \ + \ +/* Insert new entry, possibly overwrite old entry. */ \ +extern int name##_overwrite (name *htab, HASHTYPE hval, TYPE data); \ + \ +/* Find entry in hash table. */ \ +extern TYPE name##_find (name *htab, HASHTYPE hval, TYPE val); +#define FUNCTIONS(name) _FUNCTIONS (name) +FUNCTIONS (NAME) + + +#ifdef ITERATE +# define _XFUNCTIONS(name) \ +/* Get next element in table. */ \ +extern TYPE name##_iterate (name *htab, void **ptr); +# define XFUNCTIONS(name) _XFUNCTIONS (name) +XFUNCTIONS (NAME) +#endif + +#ifndef NO_UNDEF +# undef DYNHASHENTTYPE +# undef DYNHASHTYPE +# undef FUNCTIONS +# undef _FUNCTIONS +# undef XFUNCTIONS +# undef _XFUNCTIONS +# undef NAME +# undef TYPE +# undef ITERATE +# undef COMPARE +# undef FIRST +# undef NEXT +#endif diff --git a/3rdparty/elfutils/lib/eu-config.h b/3rdparty/elfutils/lib/eu-config.h new file mode 100644 index 0000000..3afff26 --- /dev/null +++ b/3rdparty/elfutils/lib/eu-config.h @@ -0,0 +1,189 @@ +/* Configuration definitions. + Copyright (C) 2008, 2009 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifndef EU_CONFIG_H +#define EU_CONFIG_H 1 + +#ifdef USE_LOCKS +# include <pthread.h> +# include <assert.h> +# define rwlock_define(class,name) class pthread_rwlock_t name +# define RWLOCK_CALL(call) \ + ({ int _err = pthread_rwlock_ ## call; assert_perror (_err); }) +# define rwlock_init(lock) RWLOCK_CALL (init (&lock, NULL)) +# define rwlock_fini(lock) RWLOCK_CALL (destroy (&lock)) +# define rwlock_rdlock(lock) RWLOCK_CALL (rdlock (&lock)) +# define rwlock_wrlock(lock) RWLOCK_CALL (wrlock (&lock)) +# define rwlock_unlock(lock) RWLOCK_CALL (unlock (&lock)) +#else +/* Eventually we will allow multi-threaded applications to use the + libraries. Therefore we will add the necessary locking although + the macros used expand to nothing for now. */ +# define rwlock_define(class,name) class int name +# define rwlock_init(lock) ((void) (lock)) +# define rwlock_fini(lock) ((void) (lock)) +# define rwlock_rdlock(lock) ((void) (lock)) +# define rwlock_wrlock(lock) ((void) (lock)) +# define rwlock_unlock(lock) ((void) (lock)) +#endif /* USE_LOCKS */ + +/* gettext helper macro. */ +#define N_(Str) Str + +/* Compiler-specific definitions. */ +#define strong_alias(name, aliasname) \ + extern __typeof (name) aliasname __attribute__ ((alias (#name))); + +#ifdef __i386__ +# define internal_function __attribute__ ((regparm (3), stdcall)) +#else +# define internal_function /* nothing */ +#endif + +#define internal_strong_alias(name, aliasname) \ + extern __typeof (name) aliasname __attribute__ ((alias (#name))) internal_function; + +#define attribute_hidden \ + __attribute__ ((visibility ("hidden"))) + +/* Define ALLOW_UNALIGNED if the architecture allows operations on + unaligned memory locations. */ +#if defined __i386__ || defined __x86_64__ +# define ALLOW_UNALIGNED 1 +#else +# define ALLOW_UNALIGNED 0 +#endif + +#if DEBUGPRED +# ifdef __x86_64__ +asm (".section predict_data, \"aw\"; .previous\n" + ".section predict_line, \"a\"; .previous\n" + ".section predict_file, \"a\"; .previous"); +# ifndef PIC +# define debugpred__(e, E) \ + ({ long int _e = !!(e); \ + asm volatile (".pushsection predict_data; ..predictcnt%=: .quad 0; .quad 0\n" \ + ".section predict_line; .quad %c1\n" \ + ".section predict_file; .quad %c2; .popsection\n" \ + "addq $1,..predictcnt%=(,%0,8)" \ + : : "r" (_e == E), "i" (__LINE__), "i" (__FILE__)); \ + __builtin_expect (_e, E); \ + }) +# endif +# elif defined __i386__ +asm (".section predict_data, \"aw\"; .previous\n" + ".section predict_line, \"a\"; .previous\n" + ".section predict_file, \"a\"; .previous"); +# ifndef PIC +# define debugpred__(e, E) \ + ({ long int _e = !!(e); \ + asm volatile (".pushsection predict_data; ..predictcnt%=: .long 0; .long 0\n" \ + ".section predict_line; .long %c1\n" \ + ".section predict_file; .long %c2; .popsection\n" \ + "incl ..predictcnt%=(,%0,8)" \ + : : "r" (_e == E), "i" (__LINE__), "i" (__FILE__)); \ + __builtin_expect (_e, E); \ + }) +# endif +# endif +# ifdef debugpred__ +# define unlikely(e) debugpred__ (e,0) +# define likely(e) debugpred__ (e,1) +# endif +#endif +#ifndef likely +# define unlikely(expr) __builtin_expect (!!(expr), 0) +# define likely(expr) __builtin_expect (!!(expr), 1) +#endif + +#define obstack_calloc(ob, size) \ + ({ size_t _s = (size); memset (obstack_alloc (ob, _s), '\0', _s); }) +#define obstack_strdup(ob, str) \ + ({ const char *_s = (str); obstack_copy0 (ob, _s, strlen (_s)); }) +#define obstack_strndup(ob, str, n) \ + ({ const char *_s = (str); obstack_copy0 (ob, _s, strnlen (_s, n)); }) + +#if __STDC_VERSION__ >= 199901L +# define flexarr_size /* empty */ +#else +# define flexarr_size 0 +#endif + +/* Calling conventions. */ +#ifdef __i386__ +# define CALLING_CONVENTION regparm (3), stdcall +# define AND_CALLING_CONVENTION , regparm (3), stdcall +#else +# define CALLING_CONVENTION +# define AND_CALLING_CONVENTION +#endif + +/* Avoid PLT entries. */ +#ifdef PIC +# define INTUSE(name) _INTUSE(name) +# define _INTUSE(name) __##name##_internal +# define INTDEF(name) _INTDEF(name) +# define _INTDEF(name) \ + extern __typeof__ (name) __##name##_internal __attribute__ ((alias (#name))); +# define INTDECL(name) _INTDECL(name) +# define _INTDECL(name) \ + extern __typeof__ (name) __##name##_internal attribute_hidden; +#else +# define INTUSE(name) name +# define INTDEF(name) /* empty */ +# define INTDECL(name) /* empty */ +#endif + +/* This macro is used by the tests conditionalize for standalone building. */ +#define ELFUTILS_HEADER(name) <lib##name.h> + + +#ifdef SHARED +# define OLD_VERSION(name, version) \ + asm (".globl _compat." #version "." #name "\n" \ + "_compat." #version "." #name " = " #name "\n" \ + ".symver _compat." #version "." #name "," #name "@" #version); +# define NEW_VERSION(name, version) \ + asm (".symver " #name "," #name "@@@" #version); +# define COMPAT_VERSION_NEWPROTO(name, version, prefix) \ + asm (".symver _compat." #version "." #name "," #name "@" #version); \ + __typeof (_compat_##prefix##_##name) _compat_##prefix##_##name \ + asm ("_compat." #version "." #name); +# define COMPAT_VERSION(name, version, prefix) \ + asm (".symver _compat." #version "." #name "," #name "@" #version); \ + __typeof (name) _compat_##prefix##_##name asm ("_compat." #version "." #name); +#else +# define OLD_VERSION(name, version) /* Nothing for static linking. */ +# define NEW_VERSION(name, version) /* Nothing for static linking. */ +# define COMPAT_VERSION_NEWPROTO(name, version, prefix) \ + error "should use #ifdef SHARED" +# define COMPAT_VERSION(name, version, prefix) error "should use #ifdef SHARED" +#endif + + +#endif /* eu-config.h */ diff --git a/3rdparty/elfutils/lib/fixedsizehash.h b/3rdparty/elfutils/lib/fixedsizehash.h new file mode 100644 index 0000000..06ce6a2 --- /dev/null +++ b/3rdparty/elfutils/lib/fixedsizehash.h @@ -0,0 +1,267 @@ +/* Fixed size hash table with internal linking. + Copyright (C) 2000, 2001, 2002, 2004, 2005 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <sys/cdefs.h> +#include <sys/param.h> + +#include <system.h> + +#define CONCAT(t1,t2) __CONCAT (t1,t2) + +/* Before including this file the following macros must be defined: + + TYPE data type of the hash table entries + HASHFCT name of the hashing function to use + HASHTYPE type used for the hashing value + COMPARE comparison function taking two pointers to TYPE objects + CLASS can be defined to `static' to avoid exporting the functions + PREFIX prefix to be used for function and data type names + STORE_POINTER if defined the table stores a pointer and not an element + of type TYPE + INSERT_HASH if defined alternate insert function which takes a hash + value is defined + NO_FINI_FCT if defined the fini function is not defined +*/ + + +/* Defined separately. */ +extern size_t next_prime (size_t seed); + + +/* Set default values. */ +#ifndef HASHTYPE +# define HASHTYPE size_t +#endif + +#ifndef CLASS +# define CLASS +#endif + +#ifndef PREFIX +# define PREFIX +#endif + + +/* The data structure. */ +struct CONCAT(PREFIX,fshash) +{ + size_t nslots; + struct CONCAT(PREFIX,fshashent) + { + HASHTYPE hval; +#ifdef STORE_POINTER +# define ENTRYP(el) (el).entry + TYPE *entry; +#else +# define ENTRYP(el) &(el).entry + TYPE entry; +#endif + } table[0]; +}; + + +/* Constructor for the hashing table. */ +CLASS struct CONCAT(PREFIX,fshash) * +CONCAT(PREFIX,fshash_init) (size_t nelems) +{ + struct CONCAT(PREFIX,fshash) *result; + /* We choose a size for the hashing table 150% over the number of + entries. This will guarantee short medium search lengths. */ + const size_t max_size_t = ~((size_t) 0); + + if (nelems >= (max_size_t / 3) * 2) + { + errno = EINVAL; + return NULL; + } + + /* Adjust the size to be used for the hashing table. */ + nelems = next_prime (MAX ((nelems * 3) / 2, 10)); + + /* Allocate the data structure for the result. */ + result = (struct CONCAT(PREFIX,fshash) *) + xcalloc (sizeof (struct CONCAT(PREFIX,fshash)) + + (nelems + 1) * sizeof (struct CONCAT(PREFIX,fshashent)), 1); + if (result == NULL) + return NULL; + + result->nslots = nelems; + + return result; +} + + +#ifndef NO_FINI_FCT +CLASS void +CONCAT(PREFIX,fshash_fini) (struct CONCAT(PREFIX,fshash) *htab) +{ + free (htab); +} +#endif + + +static struct CONCAT(PREFIX,fshashent) * +CONCAT(PREFIX,fshash_lookup) (struct CONCAT(PREFIX,fshash) *htab, + HASHTYPE hval, TYPE *data) +{ + size_t idx = 1 + hval % htab->nslots; + + if (htab->table[idx].hval != 0) + { + HASHTYPE hash; + + /* See whether this is the same entry. */ + if (htab->table[idx].hval == hval + && COMPARE (data, ENTRYP (htab->table[idx])) == 0) + return &htab->table[idx]; + + /* Second hash function as suggested in [Knuth]. */ + hash = 1 + hval % (htab->nslots - 2); + + do + { + if (idx <= hash) + idx = htab->nslots + idx - hash; + else + idx -= hash; + + if (htab->table[idx].hval == hval + && COMPARE (data, ENTRYP(htab->table[idx])) == 0) + return &htab->table[idx]; + } + while (htab->table[idx].hval != 0); + } + + return &htab->table[idx]; +} + + +CLASS int +__attribute__ ((unused)) +CONCAT(PREFIX,fshash_insert) (struct CONCAT(PREFIX,fshash) *htab, + const char *str, + size_t len __attribute__ ((unused)), TYPE *data) +{ + HASHTYPE hval = HASHFCT (str, len ?: strlen (str)); + struct CONCAT(PREFIX,fshashent) *slot; + + slot = CONCAT(PREFIX,fshash_lookup) (htab, hval, data); + if (slot->hval != 0) + /* We don't want to overwrite the old value. */ + return -1; + + slot->hval = hval; +#ifdef STORE_POINTER + slot->entry = data; +#else + slot->entry = *data; +#endif + + return 0; +} + + +#ifdef INSERT_HASH +CLASS int +__attribute__ ((unused)) +CONCAT(PREFIX,fshash_insert_hash) (struct CONCAT(PREFIX,fshash) *htab, + HASHTYPE hval, TYPE *data) +{ + struct CONCAT(PREFIX,fshashent) *slot; + + slot = CONCAT(PREFIX,fshash_lookup) (htab, hval, data); + if (slot->hval != 0) + /* We don't want to overwrite the old value. */ + return -1; + + slot->hval = hval; +#ifdef STORE_POINTER + slot->entry = data; +#else + slot->entry = *data; +#endif + + return 0; +} +#endif + + +CLASS int +__attribute__ ((unused)) +CONCAT(PREFIX,fshash_overwrite) (struct CONCAT(PREFIX,fshash) *htab, + const char *str, + size_t len __attribute__ ((unused)), + TYPE *data) +{ + HASHTYPE hval = HASHFCT (str, len ?: strlen (str)); + struct CONCAT(PREFIX,fshashent) *slot; + + slot = CONCAT(PREFIX,fshash_lookup) (htab, hval, data); + slot->hval = hval; +#ifdef STORE_POINTER + slot->entry = data; +#else + slot->entry = *data; +#endif + + return 0; +} + + +CLASS const TYPE * +CONCAT(PREFIX,fshash_find) (const struct CONCAT(PREFIX,fshash) *htab, + const char *str, + size_t len __attribute__ ((unused)), TYPE *data) +{ + HASHTYPE hval = HASHFCT (str, len ?: strlen (str)); + struct CONCAT(PREFIX,fshashent) *slot; + + slot = CONCAT(PREFIX,fshash_lookup) ((struct CONCAT(PREFIX,fshash) *) htab, + hval, data); + if (slot->hval == 0) + /* Not found. */ + return NULL; + + return ENTRYP(*slot); +} + + +/* Unset the macros we expect. */ +#undef TYPE +#undef HASHFCT +#undef HASHTYPE +#undef COMPARE +#undef CLASS +#undef PREFIX +#undef INSERT_HASH +#undef STORE_POINTER +#undef NO_FINI_FCT diff --git a/3rdparty/elfutils/lib/lib.pro b/3rdparty/elfutils/lib/lib.pro new file mode 100644 index 0000000..f1663f8 --- /dev/null +++ b/3rdparty/elfutils/lib/lib.pro @@ -0,0 +1,17 @@ +TEMPLATE = lib +CONFIG += staticlib +TARGET = ../eu + +include(../elfutils.pri) + +SOURCES += \ + $$PWD/color.c \ + $$PWD/crc32_file.c \ + $$PWD/crc32.c \ + $$PWD/md5.c \ + $$PWD/next_prime.c \ + $$PWD/sha1.c \ + $$PWD/xmalloc.c \ + $$PWD/xstrdup.c \ + $$PWD/xstrndup.c + diff --git a/3rdparty/elfutils/lib/libheaders.pri b/3rdparty/elfutils/lib/libheaders.pri new file mode 100644 index 0000000..66f022e --- /dev/null +++ b/3rdparty/elfutils/lib/libheaders.pri @@ -0,0 +1,11 @@ +HEADERS += \ + $$PWD/eu-config.h \ + $$PWD/dynamicsizehash.h \ + $$PWD/dynamicsizehash.c \ + $$PWD/fixedsizehash.h \ + $$PWD/list.h \ + $$PWD/md5.h \ + $$PWD/sha1.h \ + $$PWD/system.h + +INCLUDEPATH += $$PWD diff --git a/3rdparty/elfutils/lib/list.h b/3rdparty/elfutils/lib/list.h new file mode 100644 index 0000000..fc5c73c --- /dev/null +++ b/3rdparty/elfutils/lib/list.h @@ -0,0 +1,100 @@ +/* Copyright (C) 2001, 2002, 2003 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2001. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifndef LIST_H +#define LIST_H 1 + +/* Add element to the end of a circular, double-linked list. */ +#define CDBL_LIST_ADD_REAR(first, newp) \ + do { \ + __typeof (newp) _newp = (newp); \ + assert (_newp->next == NULL); \ + assert (_newp->previous == NULL); \ + if (unlikely ((first) == NULL)) \ + (first) = _newp->next = _newp->previous = _newp; \ + else \ + { \ + _newp->next = (first); \ + _newp->previous = (first)->previous; \ + _newp->previous->next = _newp->next->previous = _newp; \ + } \ + } while (0) + +/* Remove element from circular, double-linked list. */ +#define CDBL_LIST_DEL(first, elem) \ + do { \ + __typeof (elem) _elem = (elem); \ + /* Check whether the element is indeed on the list. */ \ + assert (first != NULL && _elem != NULL \ + && (first != elem \ + || ({ __typeof (elem) _runp = first->next; \ + while (_runp != first) \ + if (_runp == _elem) \ + break; \ + else \ + _runp = _runp->next; \ + _runp == _elem; }))); \ + if (unlikely (_elem->next == _elem)) \ + first = NULL; \ + else \ + { \ + _elem->next->previous = _elem->previous; \ + _elem->previous->next = _elem->next; \ + if (unlikely (first == _elem)) \ + first = _elem->next; \ + } \ + assert ((_elem->next = _elem->previous = NULL, 1)); \ + } while (0) + + +/* Add element to the front of a single-linked list. */ +#define SNGL_LIST_PUSH(first, newp) \ + do { \ + __typeof (newp) _newp = (newp); \ + assert (_newp->next == NULL); \ + _newp->next = first; \ + first = _newp; \ + } while (0) + + +/* Add element to the rear of a circular single-linked list. */ +#define CSNGL_LIST_ADD_REAR(first, newp) \ + do { \ + __typeof (newp) _newp = (newp); \ + assert (_newp->next == NULL); \ + if (unlikely ((first) == NULL)) \ + (first) = _newp->next = _newp; \ + else \ + { \ + _newp->next = (first)->next; \ + (first) = (first)->next = _newp; \ + } \ + } while (0) + + +#endif /* list.h */ diff --git a/3rdparty/elfutils/lib/md5.c b/3rdparty/elfutils/lib/md5.c new file mode 100644 index 0000000..1c27549 --- /dev/null +++ b/3rdparty/elfutils/lib/md5.c @@ -0,0 +1,454 @@ +/* Functions to compute MD5 message digest of files or memory blocks. + according to the definition of MD5 in RFC 1321 from April 1992. + Copyright (C) 1995-2011 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1995. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#include "md5.h" +#include "system.h" + +#define SWAP(n) LE32 (n) + +/* This array contains the bytes used to pad the buffer to the next + 64-byte boundary. (RFC 1321, 3.1: Step 1) */ +static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; + + +/* Initialize structure containing state of computation. + (RFC 1321, 3.3: Step 3) */ +void +md5_init_ctx (ctx) + struct md5_ctx *ctx; +{ + ctx->A = 0x67452301; + ctx->B = 0xefcdab89; + ctx->C = 0x98badcfe; + ctx->D = 0x10325476; + + ctx->total[0] = ctx->total[1] = 0; + ctx->buflen = 0; +} + +/* Put result from CTX in first 16 bytes following RESBUF. The result + must be in little endian byte order. + + IMPORTANT: On some systems it is required that RESBUF is correctly + aligned for a 32 bits value. */ +void * +md5_read_ctx (ctx, resbuf) + const struct md5_ctx *ctx; + void *resbuf; +{ + ((md5_uint32 *) resbuf)[0] = SWAP (ctx->A); + ((md5_uint32 *) resbuf)[1] = SWAP (ctx->B); + ((md5_uint32 *) resbuf)[2] = SWAP (ctx->C); + ((md5_uint32 *) resbuf)[3] = SWAP (ctx->D); + + return resbuf; +} + +static void +le64_copy (char *dest, uint64_t x) +{ + for (size_t i = 0; i < 8; ++i) + { + dest[i] = (uint8_t) x; + x >>= 8; + } +} + +/* Process the remaining bytes in the internal buffer and the usual + prolog according to the standard and write the result to RESBUF. + + IMPORTANT: On some systems it is required that RESBUF is correctly + aligned for a 32 bits value. */ +void * +md5_finish_ctx (ctx, resbuf) + struct md5_ctx *ctx; + void *resbuf; +{ + /* Take yet unprocessed bytes into account. */ + md5_uint32 bytes = ctx->buflen; + size_t pad; + + /* Now count remaining bytes. */ + ctx->total[0] += bytes; + if (ctx->total[0] < bytes) + ++ctx->total[1]; + + pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes; + memcpy (&ctx->buffer[bytes], fillbuf, pad); + + /* Put the 64-bit file length in *bits* at the end of the buffer. */ + const uint64_t bit_length = ((ctx->total[0] << 3) + + ((uint64_t) ((ctx->total[1] << 3) | + (ctx->total[0] >> 29)) << 32)); + le64_copy (&ctx->buffer[bytes + pad], bit_length); + + /* Process last bytes. */ + md5_process_block (ctx->buffer, bytes + pad + 8, ctx); + + return md5_read_ctx (ctx, resbuf); +} + + +#ifdef NEED_MD5_STREAM +/* Compute MD5 message digest for bytes read from STREAM. The + resulting message digest number will be written into the 16 bytes + beginning at RESBLOCK. */ +int +md5_stream (stream, resblock) + FILE *stream; + void *resblock; +{ + /* Important: BLOCKSIZE must be a multiple of 64. */ +#define BLOCKSIZE 4096 + struct md5_ctx ctx; + char buffer[BLOCKSIZE + 72]; + size_t sum; + + /* Initialize the computation context. */ + md5_init_ctx (&ctx); + + /* Iterate over full file contents. */ + while (1) + { + /* We read the file in blocks of BLOCKSIZE bytes. One call of the + computation function processes the whole buffer so that with the + next round of the loop another block can be read. */ + size_t n; + sum = 0; + + /* Read block. Take care for partial reads. */ + do + { + n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); + + sum += n; + } + while (sum < BLOCKSIZE && n != 0); + if (n == 0 && ferror (stream)) + return 1; + + /* If end of file is reached, end the loop. */ + if (n == 0) + break; + + /* Process buffer with BLOCKSIZE bytes. Note that + BLOCKSIZE % 64 == 0 + */ + md5_process_block (buffer, BLOCKSIZE, &ctx); + } + + /* Add the last bytes if necessary. */ + if (sum > 0) + md5_process_bytes (buffer, sum, &ctx); + + /* Construct result in desired memory. */ + md5_finish_ctx (&ctx, resblock); + return 0; +} +#endif + + +#ifdef NEED_MD5_BUFFER +/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +void * +md5_buffer (buffer, len, resblock) + const char *buffer; + size_t len; + void *resblock; +{ + struct md5_ctx ctx; + + /* Initialize the computation context. */ + md5_init_ctx (&ctx); + + /* Process whole buffer but last len % 64 bytes. */ + md5_process_bytes (buffer, len, &ctx); + + /* Put result in desired memory area. */ + return md5_finish_ctx (&ctx, resblock); +} +#endif + + +void +md5_process_bytes (buffer, len, ctx) + const void *buffer; + size_t len; + struct md5_ctx *ctx; +{ + /* When we already have some bits in our internal buffer concatenate + both inputs first. */ + if (ctx->buflen != 0) + { + size_t left_over = ctx->buflen; + size_t add = 128 - left_over > len ? len : 128 - left_over; + + memcpy (&ctx->buffer[left_over], buffer, add); + ctx->buflen += add; + + if (ctx->buflen > 64) + { + md5_process_block (ctx->buffer, ctx->buflen & ~63, ctx); + + ctx->buflen &= 63; + /* The regions in the following copy operation cannot overlap. */ + memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63], + ctx->buflen); + } + + buffer = (const char *) buffer + add; + len -= add; + } + + /* Process available complete blocks. */ + if (len >= 64) + { +#if !_STRING_ARCH_unaligned +/* To check alignment gcc has an appropriate operator. Other + compilers don't. */ +# if __GNUC__ >= 2 +# define UNALIGNED_P(p) (((md5_uintptr) p) % __alignof__ (md5_uint32) != 0) +# else +# define UNALIGNED_P(p) (((md5_uintptr) p) % sizeof (md5_uint32) != 0) +# endif + if (UNALIGNED_P (buffer)) + while (len > 64) + { + md5_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx); + buffer = (const char *) buffer + 64; + len -= 64; + } + else +#endif + { + md5_process_block (buffer, len & ~63, ctx); + buffer = (const char *) buffer + (len & ~63); + len &= 63; + } + } + + /* Move remaining bytes in internal buffer. */ + if (len > 0) + { + size_t left_over = ctx->buflen; + + memcpy (&ctx->buffer[left_over], buffer, len); + left_over += len; + if (left_over >= 64) + { + md5_process_block (ctx->buffer, 64, ctx); + left_over -= 64; + memcpy (ctx->buffer, &ctx->buffer[64], left_over); + } + ctx->buflen = left_over; + } +} + + +/* These are the four functions used in the four steps of the MD5 algorithm + and defined in the RFC 1321. The first function is a little bit optimized + (as found in Colin Plumbs public domain implementation). */ +/* #define FF(b, c, d) ((b & c) | (~b & d)) */ +#define FF(b, c, d) (d ^ (b & (c ^ d))) +#define FG(b, c, d) FF (d, b, c) +#define FH(b, c, d) (b ^ c ^ d) +#define FI(b, c, d) (c ^ (b | ~d)) + +/* Process LEN bytes of BUFFER, accumulating context into CTX. + It is assumed that LEN % 64 == 0. */ + +void +md5_process_block (buffer, len, ctx) + const void *buffer; + size_t len; + struct md5_ctx *ctx; +{ + md5_uint32 correct_words[16]; + const md5_uint32 *words = buffer; + size_t nwords = len / sizeof (md5_uint32); + const md5_uint32 *endp = words + nwords; + md5_uint32 A = ctx->A; + md5_uint32 B = ctx->B; + md5_uint32 C = ctx->C; + md5_uint32 D = ctx->D; + + /* First increment the byte count. RFC 1321 specifies the possible + length of the file up to 2^64 bits. Here we only compute the + number of bytes. Do a double word increment. */ + ctx->total[0] += len; + if (ctx->total[0] < len) + ++ctx->total[1]; + + /* Process all bytes in the buffer with 64 bytes in each round of + the loop. */ + while (words < endp) + { + md5_uint32 *cwp = correct_words; + md5_uint32 A_save = A; + md5_uint32 B_save = B; + md5_uint32 C_save = C; + md5_uint32 D_save = D; + + /* First round: using the given function, the context and a constant + the next context is computed. Because the algorithms processing + unit is a 32-bit word and it is determined to work on words in + little endian byte order we perhaps have to change the byte order + before the computation. To reduce the work for the next steps + we store the swapped words in the array CORRECT_WORDS. */ + +#define OP(a, b, c, d, s, T) \ + do \ + { \ + a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \ + ++words; \ + CYCLIC (a, s); \ + a += b; \ + } \ + while (0) + + /* It is unfortunate that C does not provide an operator for + cyclic rotation. Hope the C compiler is smart enough. */ +#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s))) + + /* Before we start, one word to the strange constants. + They are defined in RFC 1321 as + + T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64 + */ + + /* Round 1. */ + OP (A, B, C, D, 7, 0xd76aa478); + OP (D, A, B, C, 12, 0xe8c7b756); + OP (C, D, A, B, 17, 0x242070db); + OP (B, C, D, A, 22, 0xc1bdceee); + OP (A, B, C, D, 7, 0xf57c0faf); + OP (D, A, B, C, 12, 0x4787c62a); + OP (C, D, A, B, 17, 0xa8304613); + OP (B, C, D, A, 22, 0xfd469501); + OP (A, B, C, D, 7, 0x698098d8); + OP (D, A, B, C, 12, 0x8b44f7af); + OP (C, D, A, B, 17, 0xffff5bb1); + OP (B, C, D, A, 22, 0x895cd7be); + OP (A, B, C, D, 7, 0x6b901122); + OP (D, A, B, C, 12, 0xfd987193); + OP (C, D, A, B, 17, 0xa679438e); + OP (B, C, D, A, 22, 0x49b40821); + + /* For the second to fourth round we have the possibly swapped words + in CORRECT_WORDS. Redefine the macro to take an additional first + argument specifying the function to use. */ +#undef OP +#define OP(f, a, b, c, d, k, s, T) \ + do \ + { \ + a += f (b, c, d) + correct_words[k] + T; \ + CYCLIC (a, s); \ + a += b; \ + } \ + while (0) + + /* Round 2. */ + OP (FG, A, B, C, D, 1, 5, 0xf61e2562); + OP (FG, D, A, B, C, 6, 9, 0xc040b340); + OP (FG, C, D, A, B, 11, 14, 0x265e5a51); + OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa); + OP (FG, A, B, C, D, 5, 5, 0xd62f105d); + OP (FG, D, A, B, C, 10, 9, 0x02441453); + OP (FG, C, D, A, B, 15, 14, 0xd8a1e681); + OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8); + OP (FG, A, B, C, D, 9, 5, 0x21e1cde6); + OP (FG, D, A, B, C, 14, 9, 0xc33707d6); + OP (FG, C, D, A, B, 3, 14, 0xf4d50d87); + OP (FG, B, C, D, A, 8, 20, 0x455a14ed); + OP (FG, A, B, C, D, 13, 5, 0xa9e3e905); + OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8); + OP (FG, C, D, A, B, 7, 14, 0x676f02d9); + OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a); + + /* Round 3. */ + OP (FH, A, B, C, D, 5, 4, 0xfffa3942); + OP (FH, D, A, B, C, 8, 11, 0x8771f681); + OP (FH, C, D, A, B, 11, 16, 0x6d9d6122); + OP (FH, B, C, D, A, 14, 23, 0xfde5380c); + OP (FH, A, B, C, D, 1, 4, 0xa4beea44); + OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9); + OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60); + OP (FH, B, C, D, A, 10, 23, 0xbebfbc70); + OP (FH, A, B, C, D, 13, 4, 0x289b7ec6); + OP (FH, D, A, B, C, 0, 11, 0xeaa127fa); + OP (FH, C, D, A, B, 3, 16, 0xd4ef3085); + OP (FH, B, C, D, A, 6, 23, 0x04881d05); + OP (FH, A, B, C, D, 9, 4, 0xd9d4d039); + OP (FH, D, A, B, C, 12, 11, 0xe6db99e5); + OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8); + OP (FH, B, C, D, A, 2, 23, 0xc4ac5665); + + /* Round 4. */ + OP (FI, A, B, C, D, 0, 6, 0xf4292244); + OP (FI, D, A, B, C, 7, 10, 0x432aff97); + OP (FI, C, D, A, B, 14, 15, 0xab9423a7); + OP (FI, B, C, D, A, 5, 21, 0xfc93a039); + OP (FI, A, B, C, D, 12, 6, 0x655b59c3); + OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92); + OP (FI, C, D, A, B, 10, 15, 0xffeff47d); + OP (FI, B, C, D, A, 1, 21, 0x85845dd1); + OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f); + OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0); + OP (FI, C, D, A, B, 6, 15, 0xa3014314); + OP (FI, B, C, D, A, 13, 21, 0x4e0811a1); + OP (FI, A, B, C, D, 4, 6, 0xf7537e82); + OP (FI, D, A, B, C, 11, 10, 0xbd3af235); + OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb); + OP (FI, B, C, D, A, 9, 21, 0xeb86d391); + + /* Add the starting values of the context. */ + A += A_save; + B += B_save; + C += C_save; + D += D_save; + } + + /* Put checksum in context given as argument. */ + ctx->A = A; + ctx->B = B; + ctx->C = C; + ctx->D = D; +} diff --git a/3rdparty/elfutils/lib/md5.h b/3rdparty/elfutils/lib/md5.h new file mode 100644 index 0000000..f2d0f30 --- /dev/null +++ b/3rdparty/elfutils/lib/md5.h @@ -0,0 +1,110 @@ +/* Declaration of functions and data types used for MD5 sum computing + library functions. + Copyright (C) 1995,1996,1997,1999-2001,2004,2005,2008 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1995. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifndef _MD5_H +#define _MD5_H 1 + +#include <limits.h> +#include <stdint.h> +#include <stdio.h> + +#define MD5_DIGEST_SIZE 16 +#define MD5_BLOCK_SIZE 64 + +typedef uint32_t md5_uint32; +typedef uintptr_t md5_uintptr; + +/* Structure to save state of computation between the single steps. */ +struct md5_ctx +{ + md5_uint32 A; + md5_uint32 B; + md5_uint32 C; + md5_uint32 D; + + md5_uint32 total[2]; + md5_uint32 buflen; + char buffer[128] __attribute__ ((__aligned__ (__alignof__ (md5_uint32)))); +}; + +/* + * The following three functions are build up the low level used in + * the functions `md5_stream' and `md5_buffer'. + */ + +/* Initialize structure containing state of computation. + (RFC 1321, 3.3: Step 3) */ +extern void md5_init_ctx (struct md5_ctx *ctx); + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is necessary that LEN is a multiple of 64!!! */ +extern void md5_process_block (const void *buffer, size_t len, + struct md5_ctx *ctx); + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is NOT required that LEN is a multiple of 64. */ +extern void md5_process_bytes (const void *buffer, size_t len, + struct md5_ctx *ctx); + +/* Process the remaining bytes in the buffer and put result from CTX + in first 16 bytes following RESBUF. The result is always in little + endian byte order, so that a byte-wise output yields to the wanted + ASCII representation of the message digest. + + IMPORTANT: On some systems it is required that RESBUF is correctly + aligned for a 32 bits value. */ +extern void *md5_finish_ctx (struct md5_ctx *ctx, void *resbuf); + + +/* Put result from CTX in first 16 bytes following RESBUF. The result is + always in little endian byte order, so that a byte-wise output yields + to the wanted ASCII representation of the message digest. + + IMPORTANT: On some systems it is required that RESBUF is correctly + aligned for a 32 bits value. */ +extern void *md5_read_ctx (const struct md5_ctx *ctx, void *resbuf); + + +/* Compute MD5 message digest for bytes read from STREAM. The + resulting message digest number will be written into the 16 bytes + beginning at RESBLOCK. */ +extern int md5_stream (FILE *stream, void *resblock); + +/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +extern void *md5_buffer (const char *buffer, size_t len, void *resblock); + +#endif /* md5.h */ diff --git a/3rdparty/elfutils/lib/next_prime.c b/3rdparty/elfutils/lib/next_prime.c new file mode 100644 index 0000000..f2c921e --- /dev/null +++ b/3rdparty/elfutils/lib/next_prime.c @@ -0,0 +1,66 @@ +/* Determine prime number. + Copyright (C) 2006 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include <stddef.h> + + +/* Test whether CANDIDATE is a prime. */ +static int +is_prime (size_t candidate) +{ + /* No even number and none less than 10 will be passed here. */ + size_t divn = 3; + size_t sq = divn * divn; + + while (sq < candidate && candidate % divn != 0) + { + size_t old_sq = sq; + ++divn; + sq += 4 * divn; + if (sq < old_sq) + return 1; + ++divn; + } + + return candidate % divn != 0; +} + + +/* We need primes for the table size. */ +size_t +next_prime (size_t seed) +{ + /* Make it definitely odd. */ + seed |= 1; + + while (!is_prime (seed)) + seed += 2; + + return seed; +} diff --git a/3rdparty/elfutils/lib/sha1.c b/3rdparty/elfutils/lib/sha1.c new file mode 100644 index 0000000..0e84562 --- /dev/null +++ b/3rdparty/elfutils/lib/sha1.c @@ -0,0 +1,391 @@ +/* Functions to compute SHA1 message digest of files or memory blocks. + according to the definition of SHA1 in FIPS 180-1 from April 1997. + Copyright (C) 2008-2011 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2008. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#include "sha1.h" +#include "system.h" + +#define SWAP(n) BE32 (n) + +/* This array contains the bytes used to pad the buffer to the next + 64-byte boundary. */ +static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; + + +/* Initialize structure containing state of computation. */ +void +sha1_init_ctx (ctx) + struct sha1_ctx *ctx; +{ + ctx->A = 0x67452301; + ctx->B = 0xefcdab89; + ctx->C = 0x98badcfe; + ctx->D = 0x10325476; + ctx->E = 0xc3d2e1f0; + + ctx->total[0] = ctx->total[1] = 0; + ctx->buflen = 0; +} + +/* Put result from CTX in first 20 bytes following RESBUF. The result + must be in little endian byte order. + + IMPORTANT: On some systems it is required that RESBUF is correctly + aligned for a 32 bits value. */ +void * +sha1_read_ctx (ctx, resbuf) + const struct sha1_ctx *ctx; + void *resbuf; +{ + ((sha1_uint32 *) resbuf)[0] = SWAP (ctx->A); + ((sha1_uint32 *) resbuf)[1] = SWAP (ctx->B); + ((sha1_uint32 *) resbuf)[2] = SWAP (ctx->C); + ((sha1_uint32 *) resbuf)[3] = SWAP (ctx->D); + ((sha1_uint32 *) resbuf)[4] = SWAP (ctx->E); + + return resbuf; +} + +static void +be64_copy (char *dest, uint64_t x) +{ + for (size_t i = 8; i-- > 0; x >>= 8) + dest[i] = (uint8_t) x; +} + +/* Process the remaining bytes in the internal buffer and the usual + prolog according to the standard and write the result to RESBUF. + + IMPORTANT: On some systems it is required that RESBUF is correctly + aligned for a 32 bits value. */ +void * +sha1_finish_ctx (ctx, resbuf) + struct sha1_ctx *ctx; + void *resbuf; +{ + /* Take yet unprocessed bytes into account. */ + sha1_uint32 bytes = ctx->buflen; + size_t pad; + + /* Now count remaining bytes. */ + ctx->total[0] += bytes; + if (ctx->total[0] < bytes) + ++ctx->total[1]; + + pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes; + memcpy (&ctx->buffer[bytes], fillbuf, pad); + + /* Put the 64-bit file length in *bits* at the end of the buffer. */ + const uint64_t bit_length = ((ctx->total[0] << 3) + + ((uint64_t) ((ctx->total[1] << 3) | + (ctx->total[0] >> 29)) << 32)); + be64_copy (&ctx->buffer[bytes + pad], bit_length); + + /* Process last bytes. */ + sha1_process_block (ctx->buffer, bytes + pad + 8, ctx); + + return sha1_read_ctx (ctx, resbuf); +} + + +void +sha1_process_bytes (buffer, len, ctx) + const void *buffer; + size_t len; + struct sha1_ctx *ctx; +{ + /* When we already have some bits in our internal buffer concatenate + both inputs first. */ + if (ctx->buflen != 0) + { + size_t left_over = ctx->buflen; + size_t add = 128 - left_over > len ? len : 128 - left_over; + + memcpy (&ctx->buffer[left_over], buffer, add); + ctx->buflen += add; + + if (ctx->buflen > 64) + { + sha1_process_block (ctx->buffer, ctx->buflen & ~63, ctx); + + ctx->buflen &= 63; + /* The regions in the following copy operation cannot overlap. */ + memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63], + ctx->buflen); + } + + buffer = (const char *) buffer + add; + len -= add; + } + + /* Process available complete blocks. */ + if (len >= 64) + { +#if !_STRING_ARCH_unaligned +/* To check alignment gcc has an appropriate operator. Other + compilers don't. */ +# if __GNUC__ >= 2 +# define UNALIGNED_P(p) (((sha1_uintptr) p) % __alignof__ (sha1_uint32) != 0) +# else +# define UNALIGNED_P(p) (((sha1_uintptr) p) % sizeof (sha1_uint32) != 0) +# endif + if (UNALIGNED_P (buffer)) + while (len > 64) + { + sha1_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx); + buffer = (const char *) buffer + 64; + len -= 64; + } + else +#endif + { + sha1_process_block (buffer, len & ~63, ctx); + buffer = (const char *) buffer + (len & ~63); + len &= 63; + } + } + + /* Move remaining bytes in internal buffer. */ + if (len > 0) + { + size_t left_over = ctx->buflen; + + memcpy (&ctx->buffer[left_over], buffer, len); + left_over += len; + if (left_over >= 64) + { + sha1_process_block (ctx->buffer, 64, ctx); + left_over -= 64; + memcpy (ctx->buffer, &ctx->buffer[64], left_over); + } + ctx->buflen = left_over; + } +} + + +/* These are the four functions used in the four steps of the SHA1 algorithm + and defined in the FIPS 180-1. */ +/* #define FF(b, c, d) ((b & c) | (~b & d)) */ +#define FF(b, c, d) (d ^ (b & (c ^ d))) +#define FG(b, c, d) (b ^ c ^ d) +/* define FH(b, c, d) ((b & c) | (b & d) | (c & d)) */ +#define FH(b, c, d) (((b | c) & d) | (b & c)) + +/* It is unfortunate that C does not provide an operator for cyclic + rotation. Hope the C compiler is smart enough. */ +#define CYCLIC(w, s) (((w) << s) | ((w) >> (32 - s))) + +/* Magic constants. */ +#define K0 0x5a827999 +#define K1 0x6ed9eba1 +#define K2 0x8f1bbcdc +#define K3 0xca62c1d6 + + +/* Process LEN bytes of BUFFER, accumulating context into CTX. + It is assumed that LEN % 64 == 0. */ + +void +sha1_process_block (buffer, len, ctx) + const void *buffer; + size_t len; + struct sha1_ctx *ctx; +{ + sha1_uint32 computed_words[16]; +#define W(i) computed_words[(i) % 16] + const sha1_uint32 *words = buffer; + size_t nwords = len / sizeof (sha1_uint32); + const sha1_uint32 *endp = words + nwords; + sha1_uint32 A = ctx->A; + sha1_uint32 B = ctx->B; + sha1_uint32 C = ctx->C; + sha1_uint32 D = ctx->D; + sha1_uint32 E = ctx->E; + + /* First increment the byte count. FIPS 180-1 specifies the possible + length of the file up to 2^64 bits. Here we only compute the + number of bytes. Do a double word increment. */ + ctx->total[0] += len; + if (ctx->total[0] < len) + ++ctx->total[1]; + + /* Process all bytes in the buffer with 64 bytes in each round of + the loop. */ + while (words < endp) + { + sha1_uint32 A_save = A; + sha1_uint32 B_save = B; + sha1_uint32 C_save = C; + sha1_uint32 D_save = D; + sha1_uint32 E_save = E; + + /* First round: using the given function, the context and a constant + the next context is computed. Because the algorithms processing + unit is a 32-bit word and it is determined to work on words in + little endian byte order we perhaps have to change the byte order + before the computation. */ + +#define OP(i, a, b, c, d, e) \ + do \ + { \ + W (i) = SWAP (*words); \ + e = CYCLIC (a, 5) + FF (b, c, d) + e + W (i) + K0; \ + ++words; \ + b = CYCLIC (b, 30); \ + } \ + while (0) + + /* Steps 0 to 15. */ + OP (0, A, B, C, D, E); + OP (1, E, A, B, C, D); + OP (2, D, E, A, B, C); + OP (3, C, D, E, A, B); + OP (4, B, C, D, E, A); + OP (5, A, B, C, D, E); + OP (6, E, A, B, C, D); + OP (7, D, E, A, B, C); + OP (8, C, D, E, A, B); + OP (9, B, C, D, E, A); + OP (10, A, B, C, D, E); + OP (11, E, A, B, C, D); + OP (12, D, E, A, B, C); + OP (13, C, D, E, A, B); + OP (14, B, C, D, E, A); + OP (15, A, B, C, D, E); + + /* For the remaining 64 steps we have a more complicated + computation of the input data-derived values. Redefine the + macro to take an additional second argument specifying the + function to use and a new last parameter for the magic + constant. */ +#undef OP +#define OP(i, f, a, b, c, d, e, K) \ + do \ + { \ + W (i) = CYCLIC (W (i - 3) ^ W (i - 8) ^ W (i - 14) ^ W (i - 16), 1);\ + e = CYCLIC (a, 5) + f (b, c, d) + e + W (i) + K; \ + b = CYCLIC (b, 30); \ + } \ + while (0) + + /* Steps 16 to 19. */ + OP (16, FF, E, A, B, C, D, K0); + OP (17, FF, D, E, A, B, C, K0); + OP (18, FF, C, D, E, A, B, K0); + OP (19, FF, B, C, D, E, A, K0); + + /* Steps 20 to 39. */ + OP (20, FG, A, B, C, D, E, K1); + OP (21, FG, E, A, B, C, D, K1); + OP (22, FG, D, E, A, B, C, K1); + OP (23, FG, C, D, E, A, B, K1); + OP (24, FG, B, C, D, E, A, K1); + OP (25, FG, A, B, C, D, E, K1); + OP (26, FG, E, A, B, C, D, K1); + OP (27, FG, D, E, A, B, C, K1); + OP (28, FG, C, D, E, A, B, K1); + OP (29, FG, B, C, D, E, A, K1); + OP (30, FG, A, B, C, D, E, K1); + OP (31, FG, E, A, B, C, D, K1); + OP (32, FG, D, E, A, B, C, K1); + OP (33, FG, C, D, E, A, B, K1); + OP (34, FG, B, C, D, E, A, K1); + OP (35, FG, A, B, C, D, E, K1); + OP (36, FG, E, A, B, C, D, K1); + OP (37, FG, D, E, A, B, C, K1); + OP (38, FG, C, D, E, A, B, K1); + OP (39, FG, B, C, D, E, A, K1); + + /* Steps 40 to 59. */ + OP (40, FH, A, B, C, D, E, K2); + OP (41, FH, E, A, B, C, D, K2); + OP (42, FH, D, E, A, B, C, K2); + OP (43, FH, C, D, E, A, B, K2); + OP (44, FH, B, C, D, E, A, K2); + OP (45, FH, A, B, C, D, E, K2); + OP (46, FH, E, A, B, C, D, K2); + OP (47, FH, D, E, A, B, C, K2); + OP (48, FH, C, D, E, A, B, K2); + OP (49, FH, B, C, D, E, A, K2); + OP (50, FH, A, B, C, D, E, K2); + OP (51, FH, E, A, B, C, D, K2); + OP (52, FH, D, E, A, B, C, K2); + OP (53, FH, C, D, E, A, B, K2); + OP (54, FH, B, C, D, E, A, K2); + OP (55, FH, A, B, C, D, E, K2); + OP (56, FH, E, A, B, C, D, K2); + OP (57, FH, D, E, A, B, C, K2); + OP (58, FH, C, D, E, A, B, K2); + OP (59, FH, B, C, D, E, A, K2); + + /* Steps 60 to 79. */ + OP (60, FG, A, B, C, D, E, K3); + OP (61, FG, E, A, B, C, D, K3); + OP (62, FG, D, E, A, B, C, K3); + OP (63, FG, C, D, E, A, B, K3); + OP (64, FG, B, C, D, E, A, K3); + OP (65, FG, A, B, C, D, E, K3); + OP (66, FG, E, A, B, C, D, K3); + OP (67, FG, D, E, A, B, C, K3); + OP (68, FG, C, D, E, A, B, K3); + OP (69, FG, B, C, D, E, A, K3); + OP (70, FG, A, B, C, D, E, K3); + OP (71, FG, E, A, B, C, D, K3); + OP (72, FG, D, E, A, B, C, K3); + OP (73, FG, C, D, E, A, B, K3); + OP (74, FG, B, C, D, E, A, K3); + OP (75, FG, A, B, C, D, E, K3); + OP (76, FG, E, A, B, C, D, K3); + OP (77, FG, D, E, A, B, C, K3); + OP (78, FG, C, D, E, A, B, K3); + OP (79, FG, B, C, D, E, A, K3); + + /* Add the starting values of the context. */ + A += A_save; + B += B_save; + C += C_save; + D += D_save; + E += E_save; + } + + /* Put checksum in context given as argument. */ + ctx->A = A; + ctx->B = B; + ctx->C = C; + ctx->D = D; + ctx->E = E; +} diff --git a/3rdparty/elfutils/lib/sha1.h b/3rdparty/elfutils/lib/sha1.h new file mode 100644 index 0000000..05301c8 --- /dev/null +++ b/3rdparty/elfutils/lib/sha1.h @@ -0,0 +1,93 @@ +/* Declaration of functions and data types used for SHA1 sum computing + library functions. + Copyright (C) 2008 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2008. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifndef _SHA1_H +#define _SHA1_H 1 + +#include <limits.h> +#include <stdint.h> +#include <stdio.h> + +#define SHA1_DIGEST_SIZE 20 +#define SHA1_BLOCK_SIZE 64 + +typedef uint32_t sha1_uint32; +typedef uintptr_t sha1_uintptr; + +/* Structure to save state of computation between the single steps. */ +struct sha1_ctx +{ + sha1_uint32 A; + sha1_uint32 B; + sha1_uint32 C; + sha1_uint32 D; + sha1_uint32 E; + + sha1_uint32 total[2]; + sha1_uint32 buflen; + char buffer[128] __attribute__ ((__aligned__ (__alignof__ (sha1_uint32)))); +}; + +/* Initialize structure containing state of computation. */ +extern void sha1_init_ctx (struct sha1_ctx *ctx); + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is necessary that LEN is a multiple of 64!!! */ +extern void sha1_process_block (const void *buffer, size_t len, + struct sha1_ctx *ctx); + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is NOT required that LEN is a multiple of 64. */ +extern void sha1_process_bytes (const void *buffer, size_t len, + struct sha1_ctx *ctx); + +/* Process the remaining bytes in the buffer and put result from CTX + in first 20 bytes following RESBUF. The result is always in little + endian byte order, so that a byte-wise output yields to the wanted + ASCII representation of the message digest. + + IMPORTANT: On some systems it is required that RESBUF is correctly + aligned for a 32 bits value. */ +extern void *sha1_finish_ctx (struct sha1_ctx *ctx, void *resbuf); + + +/* Put result from CTX in first 20 bytes following RESBUF. The result is + always in little endian byte order, so that a byte-wise output yields + to the wanted ASCII representation of the message digest. + + IMPORTANT: On some systems it is required that RESBUF is correctly + aligned for a 32 bits value. */ +extern void *sha1_read_ctx (const struct sha1_ctx *ctx, void *resbuf); + +#endif /* sha1.h */ diff --git a/3rdparty/elfutils/lib/system.h b/3rdparty/elfutils/lib/system.h new file mode 100644 index 0000000..f31cfd0 --- /dev/null +++ b/3rdparty/elfutils/lib/system.h @@ -0,0 +1,185 @@ +/* Declarations for common convenience functions. + Copyright (C) 2006-2011 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifndef LIB_SYSTEM_H +#define LIB_SYSTEM_H 1 + +#include <argp.h> +#include <stddef.h> +#include <stdint.h> +#include <endian.h> +#include <byteswap.h> +#include <unistd.h> + +#if __BYTE_ORDER == __LITTLE_ENDIAN +# define LE32(n) (n) +# define LE64(n) (n) +# define BE32(n) bswap_32 (n) +# define BE64(n) bswap_64 (n) +#elif __BYTE_ORDER == __BIG_ENDIAN +# define BE32(n) (n) +# define BE64(n) (n) +# define LE32(n) bswap_32 (n) +# define LE64(n) bswap_64 (n) +#else +# error "Unknown byte order" +#endif + +extern void *xmalloc (size_t) __attribute__ ((__malloc__)); +extern void *xcalloc (size_t, size_t) __attribute__ ((__malloc__)); +extern void *xrealloc (void *, size_t) __attribute__ ((__malloc__)); + +extern char *xstrdup (const char *) __attribute__ ((__malloc__)); +extern char *xstrndup (const char *, size_t) __attribute__ ((__malloc__)); + + +extern uint32_t crc32 (uint32_t crc, unsigned char *buf, size_t len); +extern int crc32_file (int fd, uint32_t *resp); + +/* A special gettext function we use if the strings are too short. */ +#define sgettext(Str) \ + ({ const char *__res = strrchr (gettext (Str), '|'); \ + __res ? __res + 1 : Str; }) + +#define gettext_noop(Str) Str + + +static inline ssize_t __attribute__ ((unused)) +pwrite_retry (int fd, const void *buf, size_t len, off_t off) +{ + ssize_t recvd = 0; + + do + { + ssize_t ret = TEMP_FAILURE_RETRY (pwrite (fd, buf + recvd, len - recvd, + off + recvd)); + if (ret <= 0) + return ret < 0 ? ret : recvd; + + recvd += ret; + } + while ((size_t) recvd < len); + + return recvd; +} + +static inline ssize_t __attribute__ ((unused)) +write_retry (int fd, const void *buf, size_t len) +{ + ssize_t recvd = 0; + + do + { + ssize_t ret = TEMP_FAILURE_RETRY (write (fd, buf + recvd, len - recvd)); + if (ret <= 0) + return ret < 0 ? ret : recvd; + + recvd += ret; + } + while ((size_t) recvd < len); + + return recvd; +} + +static inline ssize_t __attribute__ ((unused)) +pread_retry (int fd, void *buf, size_t len, off_t off) +{ + ssize_t recvd = 0; + + do + { + ssize_t ret = TEMP_FAILURE_RETRY (pread (fd, buf + recvd, len - recvd, + off + recvd)); + if (ret <= 0) + return ret < 0 ? ret : recvd; + + recvd += ret; + } + while ((size_t) recvd < len); + + return recvd; +} + + +/* We need define two variables, argp_program_version_hook and + argp_program_bug_address, in all programs. argp.h declares these + variables as non-const (which is correct in general). But we can + do better, it is not going to change. So we want to move them into + the .rodata section. Define macros to do the trick. */ +#define ARGP_PROGRAM_VERSION_HOOK_DEF \ + void (*const apvh) (FILE *, struct argp_state *) \ + __asm ("argp_program_version_hook") +#define ARGP_PROGRAM_BUG_ADDRESS_DEF \ + const char *const apba__ __asm ("argp_program_bug_address") + + +/* The demangler from libstdc++. */ +extern char *__cxa_demangle (const char *mangled_name, char *output_buffer, + size_t *length, int *status); + + + +/* Color handling. */ + +/* Command line parser. */ +extern const struct argp color_argp; + +/* Coloring mode. */ +enum color_enum + { + color_never = 0, + color_always, + color_auto + } __attribute__ ((packed)); +extern enum color_enum color_mode; + +/* Colors to use for the various components. */ +extern char *color_address; +extern char *color_bytes; +extern char *color_mnemonic; +extern char *color_operand1; +extern char *color_operand2; +extern char *color_operand3; +extern char *color_label; +extern char *color_undef; +extern char *color_undef_tls; +extern char *color_undef_weak; +extern char *color_symbol; +extern char *color_tls; +extern char *color_weak; + +extern const char color_off[]; + +/* A static assertion. This will cause a compile-time error if EXPR, + which must be a compile-time constant, is false. */ + +#define eu_static_assert(expr) \ + extern int never_defined_just_used_for_checking[(expr) ? 1 : -1] \ + __attribute__ ((unused)) + +#endif /* system.h */ diff --git a/3rdparty/elfutils/lib/xmalloc.c b/3rdparty/elfutils/lib/xmalloc.c new file mode 100644 index 0000000..27ccab9 --- /dev/null +++ b/3rdparty/elfutils/lib/xmalloc.c @@ -0,0 +1,84 @@ +/* Convenience functions for allocation. + Copyright (C) 2006 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <error.h> +#include <libintl.h> +#include <stddef.h> +#include <stdlib.h> +#include <sys/types.h> +#include "system.h" + +#ifndef _ +# define _(str) gettext (str) +#endif + + +/* Allocate N bytes of memory dynamically, with error checking. */ +void * +xmalloc (n) + size_t n; +{ + void *p; + + p = malloc (n); + if (p == NULL) + error (EXIT_FAILURE, 0, _("memory exhausted")); + return p; +} + + +/* Allocate memory for N elements of S bytes, with error checking. */ +void * +xcalloc (n, s) + size_t n, s; +{ + void *p; + + p = calloc (n, s); + if (p == NULL) + error (EXIT_FAILURE, 0, _("memory exhausted")); + return p; +} + + +/* Change the size of an allocated block of memory P to N bytes, + with error checking. */ +void * +xrealloc (p, n) + void *p; + size_t n; +{ + p = realloc (p, n); + if (p == NULL) + error (EXIT_FAILURE, 0, _("memory exhausted")); + return p; +} diff --git a/3rdparty/elfutils/lib/xstrdup.c b/3rdparty/elfutils/lib/xstrdup.c new file mode 100644 index 0000000..d9d6010 --- /dev/null +++ b/3rdparty/elfutils/lib/xstrdup.c @@ -0,0 +1,43 @@ +/* Convenience function for string allocation. + Copyright (C) 2006 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> +#include "system.h" + + +/* Return a newly allocated copy of STRING. */ +char * +xstrdup (string) + const char *string; +{ + return strcpy (xmalloc (strlen (string) + 1), string); +} diff --git a/3rdparty/elfutils/lib/xstrndup.c b/3rdparty/elfutils/lib/xstrndup.c new file mode 100644 index 0000000..52304e6 --- /dev/null +++ b/3rdparty/elfutils/lib/xstrndup.c @@ -0,0 +1,47 @@ +/* Convenience function for string allocation. + Copyright (C) 2006 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> +#include "system.h" + + +/* Return a newly allocated copy of STRING. */ +char * +xstrndup (string, n) + const char *string; + size_t n; +{ + char *res; + size_t len = strnlen (string, n); + *((char *) mempcpy ((res = xmalloc (len + 1)), string, len)) = '\0'; + return res; +} diff --git a/3rdparty/elfutils/libasm/asm_abort.c b/3rdparty/elfutils/libasm/asm_abort.c new file mode 100644 index 0000000..ef55ee9 --- /dev/null +++ b/3rdparty/elfutils/libasm/asm_abort.c @@ -0,0 +1,61 @@ +/* Abort operations on the assembler context, free all resources. + Copyright (C) 2002, 2005 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> +#include <unistd.h> + +#include <libasmP.h> +#include <libelf.h> + + +int +asm_abort (ctx) + AsmCtx_t *ctx; +{ + if (ctx == NULL) + /* Something went wrong earlier. */ + return -1; + + if (likely (! ctx->textp)) + /* First free the ELF file. We don't care about the result. */ + (void) elf_end (ctx->out.elf); + + /* Now close the temporary file and remove it. */ + if (ctx->fd != -1) + (void) unlink (ctx->tmp_fname); + + /* Free the resources. */ + __libasm_finictx (ctx); + + return 0; +} diff --git a/3rdparty/elfutils/libasm/asm_addint16.c b/3rdparty/elfutils/libasm/asm_addint16.c new file mode 100644 index 0000000..4ae4597 --- /dev/null +++ b/3rdparty/elfutils/libasm/asm_addint16.c @@ -0,0 +1,32 @@ +/* Add integer to a section. + Copyright (C) 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#define SIZE 16 + +#include "asm_addint8.c" diff --git a/3rdparty/elfutils/libasm/asm_addint32.c b/3rdparty/elfutils/libasm/asm_addint32.c new file mode 100644 index 0000000..776cf6f --- /dev/null +++ b/3rdparty/elfutils/libasm/asm_addint32.c @@ -0,0 +1,32 @@ +/* Add integer to a section. + Copyright (C) 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#define SIZE 32 + +#include "asm_addint8.c" diff --git a/3rdparty/elfutils/libasm/asm_addint64.c b/3rdparty/elfutils/libasm/asm_addint64.c new file mode 100644 index 0000000..ee33834 --- /dev/null +++ b/3rdparty/elfutils/libasm/asm_addint64.c @@ -0,0 +1,32 @@ +/* Add integer to a section. + Copyright (C) 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#define SIZE 64 + +#include "asm_addint8.c" diff --git a/3rdparty/elfutils/libasm/asm_addint8.c b/3rdparty/elfutils/libasm/asm_addint8.c new file mode 100644 index 0000000..ec05b8d --- /dev/null +++ b/3rdparty/elfutils/libasm/asm_addint8.c @@ -0,0 +1,123 @@ +/* Add integer to a section. + Copyright (C) 2002, 2005 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <byteswap.h> +#include <endian.h> +#include <inttypes.h> +#include <string.h> + +#include <libasmP.h> + +#ifndef SIZE +# define SIZE 8 +#endif + +#define FCT(size) _FCT(size) +#define _FCT(size) asm_addint##size +#define TYPE(size) _TYPE(size) +#define _TYPE(size) int##size##_t +#define BSWAP(size) _BSWAP(size) +#define _BSWAP(size) bswap_##size + + +int +FCT(SIZE) (asmscn, num) + AsmScn_t *asmscn; + TYPE(SIZE) num; +{ + if (asmscn == NULL) + return -1; + + if (asmscn->type == SHT_NOBITS && unlikely (num != 0)) + { + __libasm_seterrno (ASM_E_TYPE); + return -1; + } + + if (unlikely (asmscn->ctx->textp)) + { + // XXX Needs to use backend specified pseudo-ops + if (SIZE == 8) + fprintf (asmscn->ctx->out.file, "\t.byte\t%" PRId8 "\n", (int8_t) num); + else if (SIZE == 16) + fprintf (asmscn->ctx->out.file, "\t.value\t%" PRId16 "\n", + (int16_t) num); + else if (SIZE == 32) + fprintf (asmscn->ctx->out.file, "\t.long\t%" PRId32 "\n", + (int32_t) num); + else + { + // XXX This is not necessary for 64-bit machines + bool is_leb = (elf_getident (asmscn->ctx->out.elf, NULL)[EI_DATA] + == ELFDATA2LSB); + + fprintf (asmscn->ctx->out.file, + "\t.long\t%" PRId32 "\n\t.long\t%" PRId32 "\n", + (int32_t) (is_leb + ? num % 0x100000000ll : num / 0x100000000ll), + (int32_t) (is_leb + ? num / 0x100000000ll : num % 0x100000000ll)); + } + } + else + { +#if SIZE > 8 + bool is_leb = (elf_getident (asmscn->ctx->out.elf, NULL)[EI_DATA] + == ELFDATA2LSB); +#endif + TYPE(SIZE) var = num; + + /* Make sure we have enough room. */ + if (__libasm_ensure_section_space (asmscn, SIZE / 8) != 0) + return -1; + +#if SIZE > 8 + if ((BYTE_ORDER == LITTLE_ENDIAN && !is_leb) + || (BYTE_ORDER == BIG_ENDIAN && is_leb)) + var = BSWAP(SIZE) (var); +#endif + + /* Copy the variable value. */ + if (likely (asmscn->type == SHT_NOBITS)) + memcpy (&asmscn->content->data[asmscn->content->len], &var, SIZE / 8); + + /* Adjust the pointer in the data buffer. */ + asmscn->content->len += SIZE / 8; + + /* Increment the offset in the (sub)section. */ + asmscn->offset += SIZE / 8; + } + + return 0; +} +INTDEF(FCT(SIZE)) diff --git a/3rdparty/elfutils/libasm/asm_addsleb128.c b/3rdparty/elfutils/libasm/asm_addsleb128.c new file mode 100644 index 0000000..3692789 --- /dev/null +++ b/3rdparty/elfutils/libasm/asm_addsleb128.c @@ -0,0 +1,99 @@ +/* Add signed little endian base 128 integer to a section. + Copyright (C) 2002, 2005 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <inttypes.h> +#include <string.h> + +#include <libasmP.h> + + +int +asm_addsleb128 (asmscn, num) + AsmScn_t *asmscn; + int32_t num; +{ + if (asmscn == NULL) + return -1; + + if (asmscn->type == SHT_NOBITS && unlikely (num != 0)) + { + __libasm_seterrno (ASM_E_TYPE); + return -1; + } + + if (unlikely (asmscn->ctx->textp)) + fprintf (asmscn->ctx->out.file, "\t.sleb128\t%" PRId32 "\n", num); + else + { + char tmpbuf[(sizeof (num) * 8 + 6) / 7]; + char *dest = tmpbuf; + uint32_t byte; + int32_t endval = num >> 31; + + if (num == 0) + byte = 0; + else + while (1) + { + byte = num & 0x7f; + + num >>= 7; + if (num == endval) + /* This is the last byte. */ + break; + + *dest++ = byte | 0x80; + } + + *dest++ = byte; + + /* Number of bytes produced. */ + size_t nbytes = dest - tmpbuf; + + /* Make sure we have enough room. */ + if (__libasm_ensure_section_space (asmscn, nbytes) != 0) + return -1; + + /* Copy the bytes. */ + if (likely (asmscn->type != SHT_NOBITS)) + memcpy (&asmscn->content->data[asmscn->content->len], tmpbuf, nbytes); + + /* Adjust the pointer in the data buffer. */ + asmscn->content->len += nbytes; + + /* Increment the offset in the (sub)section. */ + asmscn->offset += nbytes; + } + + return 0; +} diff --git a/3rdparty/elfutils/libasm/asm_addstrz.c b/3rdparty/elfutils/libasm/asm_addstrz.c new file mode 100644 index 0000000..87663f3 --- /dev/null +++ b/3rdparty/elfutils/libasm/asm_addstrz.c @@ -0,0 +1,128 @@ +/* Add string to a section. + Copyright (C) 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <ctype.h> +#include <stdio.h> +#include <string.h> + +#include <libasmP.h> + + +/* Add zero terminated string STR of size LEN to (sub)section ASMSCN. */ +int +asm_addstrz (asmscn, str, len) + AsmScn_t *asmscn; + const char *str; + size_t len; +{ + if (asmscn == NULL) + return -1; + + if (unlikely (asmscn->type == SHT_NOBITS)) + { + if (len == 0) + { + if (str[0] != '\0') + { + __libasm_seterrno (ASM_E_TYPE); + return -1; + } + } + else + { + size_t cnt; + + for (cnt = 0; cnt < len; ++cnt) + if (str[cnt] != '\0') + { + __libasm_seterrno (ASM_E_TYPE); + return -1; + } + } + } + + if (len == 0) + len = strlen (str) + 1; + + if (unlikely (asmscn->ctx->textp)) + { + bool nextline = true; + + do + { + if (nextline) + { + fputs ("\t.string\t\"", asmscn->ctx->out.file); + nextline = false; + } + + if (*str == '\0') + fputs ("\\000", asmscn->ctx->out.file); + else if (! isascii (*str)) + fprintf (asmscn->ctx->out.file, "\\%03o", + (unsigned int) *((unsigned char *)str)); + else if (*str == '\\') + fputs ("\\\\", asmscn->ctx->out.file); + else if (*str == '\n') + { + fputs ("\\n\"", asmscn->ctx->out.file); + nextline = true; + } + else + fputc (*str, asmscn->ctx->out.file); + + ++str; + } + while (--len > 0 && (len > 1 || *str != '\0')); + + if (! nextline) + fputs ("\"\n", asmscn->ctx->out.file); + } + else + { + /* Make sure there is enough room. */ + if (__libasm_ensure_section_space (asmscn, len) != 0) + return -1; + + /* Copy the string. */ + memcpy (&asmscn->content->data[asmscn->content->len], str, len); + + /* Adjust the pointer in the data buffer. */ + asmscn->content->len += len; + + /* Increment the offset in the (sub)section. */ + asmscn->offset += len; + } + + return 0; +} diff --git a/3rdparty/elfutils/libasm/asm_adduint16.c b/3rdparty/elfutils/libasm/asm_adduint16.c new file mode 100644 index 0000000..65a1303 --- /dev/null +++ b/3rdparty/elfutils/libasm/asm_adduint16.c @@ -0,0 +1,32 @@ +/* Add unsigned integer to a section. + Copyright (C) 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#define SIZE 16 + +#include "asm_adduint8.c" diff --git a/3rdparty/elfutils/libasm/asm_adduint32.c b/3rdparty/elfutils/libasm/asm_adduint32.c new file mode 100644 index 0000000..9a3ec6d --- /dev/null +++ b/3rdparty/elfutils/libasm/asm_adduint32.c @@ -0,0 +1,32 @@ +/* Add unsigned integer to a section. + Copyright (C) 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#define SIZE 32 + +#include "asm_adduint8.c" diff --git a/3rdparty/elfutils/libasm/asm_adduint64.c b/3rdparty/elfutils/libasm/asm_adduint64.c new file mode 100644 index 0000000..b2c57a4 --- /dev/null +++ b/3rdparty/elfutils/libasm/asm_adduint64.c @@ -0,0 +1,32 @@ +/* Add unsigned integer to a section. + Copyright (C) 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#define SIZE 64 + +#include "asm_adduint8.c" diff --git a/3rdparty/elfutils/libasm/asm_adduint8.c b/3rdparty/elfutils/libasm/asm_adduint8.c new file mode 100644 index 0000000..30641b8 --- /dev/null +++ b/3rdparty/elfutils/libasm/asm_adduint8.c @@ -0,0 +1,56 @@ +/* Add unsigned integer to a section. + Copyright (C) 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libasmP.h> + +#ifndef SIZE +# define SIZE 8 +#endif + +#define UFCT(size) _UFCT(size) +#define _UFCT(size) asm_adduint##size +#define FCT(size) _FCT(size) +#define _FCT(size) asm_addint##size +#define UTYPE(size) _UTYPE(size) +#define _UTYPE(size) uint##size##_t +#define TYPE(size) _TYPE(size) +#define _TYPE(size) int##size##_t + + +int +UFCT(SIZE) (asmscn, num) + AsmScn_t *asmscn; + UTYPE(SIZE) num; +{ + return INTUSE(FCT(SIZE)) (asmscn, (TYPE(SIZE)) num); +} diff --git a/3rdparty/elfutils/libasm/asm_adduleb128.c b/3rdparty/elfutils/libasm/asm_adduleb128.c new file mode 100644 index 0000000..a3a8573 --- /dev/null +++ b/3rdparty/elfutils/libasm/asm_adduleb128.c @@ -0,0 +1,95 @@ +/* Add integer to a section. + Copyright (C) 2002, 2005 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <inttypes.h> +#include <string.h> + +#include "libasmP.h" + + +int +asm_adduleb128 (asmscn, num) + AsmScn_t *asmscn; + uint32_t num; +{ + if (asmscn == NULL) + return -1; + + if (asmscn->type == SHT_NOBITS && unlikely (num != 0)) + { + __libasm_seterrno (ASM_E_TYPE); + return -1; + } + + if (unlikely (asmscn->ctx->textp)) + fprintf (asmscn->ctx->out.file, "\t.uleb128\t%" PRIu32 "\n", num); + else + { + char tmpbuf[(sizeof (num) * 8 + 6) / 7]; + char *dest = tmpbuf; + uint32_t byte; + + while (1) + { + byte = num & 0x7f; + + num >>= 7; + if (num == 0) + /* This is the last byte. */ + break; + + *dest++ = byte | 0x80; + } + + *dest++ = byte; + + /* Number of bytes produced. */ + size_t nbytes = dest - tmpbuf; + + /* Make sure we have enough room. */ + if (__libasm_ensure_section_space (asmscn, nbytes) != 0) + return -1; + + /* Copy the bytes. */ + if (likely (asmscn->type != SHT_NOBITS)) + memcpy (&asmscn->content->data[asmscn->content->len], tmpbuf, nbytes); + + /* Adjust the pointer in the data buffer. */ + asmscn->content->len += nbytes; + + /* Increment the offset in the (sub)section. */ + asmscn->offset += nbytes; + } + + return 0; +} diff --git a/3rdparty/elfutils/libasm/asm_align.c b/3rdparty/elfutils/libasm/asm_align.c new file mode 100644 index 0000000..2025b02 --- /dev/null +++ b/3rdparty/elfutils/libasm/asm_align.c @@ -0,0 +1,179 @@ +/* Align section. + Copyright (C) 2002, 2005 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <inttypes.h> +#include <stdlib.h> +#include <sys/param.h> + +#include <libasmP.h> +#include <system.h> + + +int +asm_align (asmscn, value) + AsmScn_t *asmscn; + GElf_Word value; +{ + if (asmscn == NULL) + /* An earlier error. */ + return -1; + + /* The alignment value must be a power of two. */ + if (unlikely (! powerof2 (value))) + { + __libasm_seterrno (ASM_E_INVALID); + return -1; + } + + if (unlikely (asmscn->ctx->textp)) + { + fprintf (asmscn->ctx->out.file, "\t.align %" PRId32 ", ", + (int32_t) value); + if (asmscn->pattern->len == 1) + fprintf (asmscn->ctx->out.file, "%02hhx\n", asmscn->pattern->bytes[0]); + else + { + fputc_unlocked ('"', asmscn->ctx->out.file); + + for (size_t cnt = 0; cnt < asmscn->pattern->len; ++cnt) + fprintf (asmscn->ctx->out.file, "\\x%02hhx", + asmscn->pattern->bytes[cnt]); + + fputs_unlocked ("\"\n", asmscn->ctx->out.file); + } + return 0; + } + + rwlock_wrlock (asmscn->ctx->lock); + + int result = 0; + + /* Fillbytes necessary? */ + if ((asmscn->offset & (value - 1)) != 0) + { + /* Add fillbytes. */ + size_t cnt = value - (asmscn->offset & (value - 1)); + + /* Ensure there is enough room to add the fill bytes. */ + result = __libasm_ensure_section_space (asmscn, cnt); + if (result != 0) + goto out; + + /* Fill in the bytes. We align the pattern according to the + current offset. */ + size_t byteptr = asmscn->offset % asmscn->pattern->len; + + /* Update the total size. */ + asmscn->offset += cnt; + + do + { + asmscn->content->data[asmscn->content->len++] + = asmscn->pattern->bytes[byteptr++]; + + if (byteptr == asmscn->pattern->len) + byteptr = 0; + } + while (--cnt > 0); + } + + /* Remember the maximum alignment for this subsection. */ + if (asmscn->max_align < value) + { + asmscn->max_align = value; + + /* Update the parent as well (if it exists). */ + if (asmscn->subsection_id != 0) + { + rwlock_wrlock (asmscn->data.up->ctx->lock); + + if (asmscn->data.up->max_align < value) + asmscn->data.up->max_align = value; + + rwlock_unlock (asmscn->data.up->ctx->lock); + } + } + + out: + rwlock_unlock (asmscn->ctx->lock); + + return result; +} + + +/* Ensure there are at least LEN bytes available in the output buffer + for ASMSCN. */ +int +__libasm_ensure_section_space (asmscn, len) + AsmScn_t *asmscn; + size_t len; +{ + /* The blocks with the section content are kept in a circular + single-linked list. */ + size_t size; + + if (asmscn->content == NULL) + { + /* This is the first block. */ + size = MAX (2 * len, 960); + + asmscn->content = (struct AsmData *) malloc (sizeof (struct AsmData) + + size); + if (asmscn->content == NULL) + return -1; + + asmscn->content->next = asmscn->content; + } + else + { + struct AsmData *newp; + + if (asmscn->content->maxlen - asmscn->content->len >= len) + /* Nothing to do, there is enough space. */ + return 0; + + size = MAX (2 *len, MIN (32768, 2 * asmscn->offset)); + + newp = (struct AsmData *) malloc (sizeof (struct AsmData) + size); + if (newp == NULL) + return -1; + + newp->next = asmscn->content->next; + asmscn->content = asmscn->content->next = newp; + } + + asmscn->content->len = 0; + asmscn->content->maxlen = size; + + return 0; +} diff --git a/3rdparty/elfutils/libasm/asm_begin.c b/3rdparty/elfutils/libasm/asm_begin.c new file mode 100644 index 0000000..48842d3 --- /dev/null +++ b/3rdparty/elfutils/libasm/asm_begin.c @@ -0,0 +1,184 @@ +/* Create descriptor for assembling. + Copyright (C) 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <errno.h> +#include <stdio.h> +#include <stdio_ext.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <gelf.h> +#include "libasmP.h" +#include <system.h> + + +static AsmCtx_t * +prepare_text_output (AsmCtx_t *result) +{ + if (result->fd == -1) + result->out.file = stdout; + else + { + result->out.file = fdopen (result->fd, "a"); + if (result->out.file == NULL) + { + close (result->fd); + free (result); + result = NULL; + } + + __fsetlocking (result->out.file, FSETLOCKING_BYCALLER); + } + + return result; +} + + +static AsmCtx_t * +prepare_binary_output (AsmCtx_t *result, Ebl *ebl) +{ + GElf_Ehdr *ehdr; + GElf_Ehdr ehdr_mem; + + /* Create the ELF descriptor for the file. */ + result->out.elf = elf_begin (result->fd, ELF_C_WRITE_MMAP, NULL); + if (result->out.elf == NULL) + { + err_libelf: + unlink (result->tmp_fname); + close (result->fd); + free (result); + __libasm_seterrno (ASM_E_LIBELF); + return NULL; + } + + /* Create the ELF header for the output file. */ + int class = ebl_get_elfclass (ebl); + if (gelf_newehdr (result->out.elf, class) == 0) + goto err_libelf; + + ehdr = gelf_getehdr (result->out.elf, &ehdr_mem); + /* If this failed we are in trouble. */ + assert (ehdr != NULL); + + /* We create an object file. */ + ehdr->e_type = ET_REL; + /* Set the ELF version. */ + ehdr->e_version = EV_CURRENT; + + /* Use the machine, class, and endianess values from the Ebl descriptor. */ + ehdr->e_machine = ebl_get_elfmachine (ebl); + ehdr->e_ident[EI_CLASS] = class; + ehdr->e_ident[EI_DATA] = ebl_get_elfdata (ebl); + + memcpy (&ehdr->e_ident[EI_MAG0], ELFMAG, SELFMAG); + + /* Write the ELF header information back. */ + (void) gelf_update_ehdr (result->out.elf, ehdr); + + /* No section so far. */ + result->section_list = NULL; + + /* Initialize the hash table. */ + asm_symbol_tab_init (&result->symbol_tab, 67); + result->nsymbol_tab = 0; + /* And the string tables. */ + result->section_strtab = ebl_strtabinit (true); + result->symbol_strtab = ebl_strtabinit (true); + + /* We have no section groups so far. */ + result->groups = NULL; + result->ngroups = 0; + + return result; +} + + +AsmCtx_t * +asm_begin (fname, ebl, textp) + const char *fname; + Ebl *ebl; + bool textp; +{ + if (fname == NULL && ! textp) + return NULL; + + size_t fname_len = fname != NULL ? strlen (fname) : 0; + + /* Create the file descriptor. We do not generate the output file + right away. Instead we create a temporary file in the same + directory which, if everything goes alright, will replace a + possibly existing file with the given name. */ + AsmCtx_t *result + = (AsmCtx_t *) malloc (sizeof (AsmCtx_t) + 2 * fname_len + 9); + if (result == NULL) + return NULL; + + /* Initialize the lock. */ + rwlock_init (result->lock); + + if (fname != NULL) + { + /* Create the name of the temporary file. */ + result->fname = stpcpy (mempcpy (result->tmp_fname, fname, fname_len), + ".XXXXXX") + 1; + memcpy (result->fname, fname, fname_len + 1); + + /* Create the temporary file. */ + result->fd = mkstemp (result->tmp_fname); + if (result->fd == -1) + { + int save_errno = errno; + free (result); + __libasm_seterrno (ASM_E_CANNOT_CREATE); + errno = save_errno; + return NULL; + } + } + else + result->fd = -1; + + /* Initialize the counter for temporary symbols. */ + result->tempsym_count = 0; + + /* Now we differentiate between textual and binary output. */ + result->textp = textp; + if (textp) + result = prepare_text_output (result); + else + result = prepare_binary_output (result, ebl); + + return result; +} diff --git a/3rdparty/elfutils/libasm/asm_end.c b/3rdparty/elfutils/libasm/asm_end.c new file mode 100644 index 0000000..f4145a7 --- /dev/null +++ b/3rdparty/elfutils/libasm/asm_end.c @@ -0,0 +1,613 @@ +/* Finalize operations on the assembler context, free all resources. + Copyright (C) 2002, 2003, 2005 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <error.h> +#include <libintl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/stat.h> + +#include <libasmP.h> +#include <libelf.h> +#include <system.h> + + +static int +text_end (AsmCtx_t *ctx __attribute__ ((unused))) +{ + if (fclose (ctx->out.file) != 0) + { + __libasm_seterrno (ASM_E_IOERROR); + return -1; + } + + return 0; +} + + +static int +binary_end (AsmCtx_t *ctx) +{ + void *symtab = NULL; + struct Ebl_Strent *symscn_strent = NULL; + struct Ebl_Strent *strscn_strent = NULL; + struct Ebl_Strent *xndxscn_strent = NULL; + Elf_Scn *shstrscn; + struct Ebl_Strent *shstrscn_strent; + size_t shstrscnndx; + size_t symscnndx = 0; + size_t strscnndx = 0; + size_t xndxscnndx = 0; + Elf_Data *data; + Elf_Data *shstrtabdata; + Elf_Data *strtabdata = NULL; + Elf_Data *xndxdata = NULL; + GElf_Shdr shdr_mem; + GElf_Shdr *shdr; + GElf_Ehdr ehdr_mem; + GElf_Ehdr *ehdr; + AsmScn_t *asmscn; + int result = 0; + + /* Iterate over the created sections and compute the offsets of the + various subsections and fill in the content. */ + for (asmscn = ctx->section_list; asmscn != NULL; asmscn = asmscn->allnext) + { +#if 0 + Elf_Scn *scn = elf_getscn (ctx->out.elf, asmscn->data.main.scnndx); +#else + Elf_Scn *scn = asmscn->data.main.scn; +#endif + off_t offset = 0; + AsmScn_t *asmsubscn = asmscn; + + do + { + struct AsmData *content = asmsubscn->content; + bool first = true; + + offset = ((offset + asmsubscn->max_align - 1) + & ~(asmsubscn->max_align - 1)); + + /* Update the offset for this subsection. This field now + stores the offset of the first by in this subsection. */ + asmsubscn->offset = offset; + + /* Note that the content list is circular. */ + if (content != NULL) + do + { + Elf_Data *newdata = elf_newdata (scn); + + if (newdata == NULL) + { + __libasm_seterrno (ASM_E_LIBELF); + return -1; + } + + newdata->d_buf = content->data; + newdata->d_type = ELF_T_BYTE; + newdata->d_size = content->len; + newdata->d_off = offset; + newdata->d_align = first ? asmsubscn->max_align : 1; + + offset += content->len; + } + while ((content = content->next) != asmsubscn->content); + } + while ((asmsubscn = asmsubscn->subnext) != NULL); + } + + + /* Create the symbol table if necessary. */ + if (ctx->nsymbol_tab > 0) + { + /* Create the symbol table and string table section names. */ + symscn_strent = ebl_strtabadd (ctx->section_strtab, ".symtab", 8); + strscn_strent = ebl_strtabadd (ctx->section_strtab, ".strtab", 8); + + /* Create the symbol string table section. */ + Elf_Scn *strscn = elf_newscn (ctx->out.elf); + strtabdata = elf_newdata (strscn); + shdr = gelf_getshdr (strscn, &shdr_mem); + if (strtabdata == NULL || shdr == NULL) + { + __libasm_seterrno (ASM_E_LIBELF); + return -1; + } + strscnndx = elf_ndxscn (strscn); + + ebl_strtabfinalize (ctx->symbol_strtab, strtabdata); + + shdr->sh_type = SHT_STRTAB; + assert (shdr->sh_entsize == 0); + + (void) gelf_update_shdr (strscn, shdr); + + /* Create the symbol table section. */ + Elf_Scn *symscn = elf_newscn (ctx->out.elf); + data = elf_newdata (symscn); + shdr = gelf_getshdr (symscn, &shdr_mem); + if (data == NULL || shdr == NULL) + { + __libasm_seterrno (ASM_E_LIBELF); + return -1; + } + symscnndx = elf_ndxscn (symscn); + + /* We know how many symbols there will be in the symbol table. */ + data->d_size = gelf_fsize (ctx->out.elf, ELF_T_SYM, + ctx->nsymbol_tab + 1, EV_CURRENT); + symtab = malloc (data->d_size); + if (symtab == NULL) + return -1; + data->d_buf = symtab; + data->d_type = ELF_T_SYM; + data->d_off = 0; + + /* Clear the first entry. */ + GElf_Sym syment; + memset (&syment, '\0', sizeof (syment)); + (void) gelf_update_sym (data, 0, &syment); + + /* Iterate over the symbol table. */ + void *runp = NULL; + int ptr_local = 1; /* Start with index 1; zero remains unused. */ + int ptr_nonlocal = ctx->nsymbol_tab; + uint32_t *xshndx = NULL; + AsmSym_t *sym; + while ((sym = asm_symbol_tab_iterate (&ctx->symbol_tab, &runp)) != NULL) + if (asm_emit_symbol_p (ebl_string (sym->strent))) + { + assert (ptr_local <= ptr_nonlocal); + + syment.st_name = ebl_strtaboffset (sym->strent); + syment.st_info = GELF_ST_INFO (sym->binding, sym->type); + syment.st_other = 0; + syment.st_value = sym->scn->offset + sym->offset; + syment.st_size = sym->size; + + /* Add local symbols at the beginning, the other from + the end. */ + int ptr = sym->binding == STB_LOCAL ? ptr_local++ : ptr_nonlocal--; + + /* Determine the section index. We have to handle the + overflow correctly. */ + Elf_Scn *scn = (sym->scn->subsection_id == 0 + ? sym->scn->data.main.scn + : sym->scn->data.up->data.main.scn); + + Elf32_Word ndx; + if (unlikely (scn == ASM_ABS_SCN)) + ndx = SHN_ABS; + else if (unlikely (scn == ASM_COM_SCN)) + ndx = SHN_COMMON; + else if (unlikely ((ndx = elf_ndxscn (scn)) >= SHN_LORESERVE)) + { + if (unlikely (xshndx == NULL)) + { + /* The extended section index section does not yet + exist. */ + Elf_Scn *xndxscn; + + xndxscn = elf_newscn (ctx->out.elf); + xndxdata = elf_newdata (xndxscn); + shdr = gelf_getshdr (xndxscn, &shdr_mem); + if (xndxdata == NULL || shdr == NULL) + { + __libasm_seterrno (ASM_E_LIBELF); + return -1; + } + xndxscnndx = elf_ndxscn (xndxscn); + + shdr->sh_type = SHT_SYMTAB_SHNDX; + shdr->sh_entsize = sizeof (Elf32_Word); + shdr->sh_addralign = sizeof (Elf32_Word); + shdr->sh_link = symscnndx; + + (void) gelf_update_shdr (xndxscn, shdr); + + xndxscn_strent = ebl_strtabadd (ctx->section_strtab, + ".symtab_shndx", 14); + + /* Note that using 'elf32_fsize' instead of + 'gelf_fsize' here is correct. */ + xndxdata->d_size = elf32_fsize (ELF_T_WORD, + ctx->nsymbol_tab + 1, + EV_CURRENT); + xshndx = xndxdata->d_buf = calloc (1, xndxdata->d_size); + if (xshndx == NULL) + return -1; + /* Using ELF_T_WORD here relies on the fact that the + 32- and 64-bit types are the same size. */ + xndxdata->d_type = ELF_T_WORD; + xndxdata->d_off = 0; + } + + /* Store the real section index in the extended setion + index table. */ + assert ((size_t) ptr < ctx->nsymbol_tab + 1); + xshndx[ptr] = ndx; + + /* And signal that this happened. */ + ndx = SHN_XINDEX; + } + syment.st_shndx = ndx; + + /* Remember where we put the symbol. */ + sym->symidx = ptr; + + (void) gelf_update_sym (data, ptr, &syment); + } + + assert (ptr_local == ptr_nonlocal + 1); + + shdr->sh_type = SHT_SYMTAB; + shdr->sh_link = strscnndx; + shdr->sh_info = ptr_local; + shdr->sh_entsize = gelf_fsize (ctx->out.elf, ELF_T_SYM, 1, EV_CURRENT); + shdr->sh_addralign = gelf_fsize (ctx->out.elf, ELF_T_ADDR, 1, + EV_CURRENT); + + (void) gelf_update_shdr (symscn, shdr); + } + + + /* Create the section header string table section and fill in the + references in the section headers. */ + shstrscn = elf_newscn (ctx->out.elf); + shstrtabdata = elf_newdata (shstrscn); + shdr = gelf_getshdr (shstrscn, &shdr_mem); + if (shstrscn == NULL || shstrtabdata == NULL || shdr == NULL) + { + __libasm_seterrno (ASM_E_LIBELF); + return -1; + } + + + /* Add the name of the section header string table. */ + shstrscn_strent = ebl_strtabadd (ctx->section_strtab, ".shstrtab", 10); + + ebl_strtabfinalize (ctx->section_strtab, shstrtabdata); + + shdr->sh_type = SHT_STRTAB; + assert (shdr->sh_entsize == 0); + shdr->sh_name = ebl_strtaboffset (shstrscn_strent); + + (void) gelf_update_shdr (shstrscn, shdr); + + + /* Create the section groups. */ + if (ctx->groups != NULL) + { + AsmScnGrp_t *runp = ctx->groups->next; + + do + { + Elf_Scn *scn; + Elf32_Word *grpdata; + + scn = runp->scn; + assert (scn != NULL); + shdr = gelf_getshdr (scn, &shdr_mem); + assert (shdr != NULL); + + data = elf_newdata (scn); + if (data == NULL) + { + __libasm_seterrno (ASM_E_LIBELF); + return -1; + } + + /* It is correct to use 'elf32_fsize' instead of 'gelf_fsize' + here. */ + data->d_size = elf32_fsize (ELF_T_WORD, runp->nmembers + 1, + EV_CURRENT); + grpdata = data->d_buf = malloc (data->d_size); + if (grpdata == NULL) + return -1; + data->d_type = ELF_T_WORD; + data->d_off = 0; + data->d_align = elf32_fsize (ELF_T_WORD, 1, EV_CURRENT); + + /* The first word of the section is filled with the flag word. */ + *grpdata++ = runp->flags; + + if (runp->members != NULL) + { + AsmScn_t *member = runp->members->data.main.next_in_group; + + do + { + /* Only sections, not subsections, can be registered + as member of a group. The subsections get + automatically included. */ + assert (member->subsection_id == 0); + + *grpdata++ = elf_ndxscn (member->data.main.scn); + } + while ((member = member->data.main.next_in_group) + != runp->members->data.main.next_in_group); + } + + /* Construct the section header. */ + shdr->sh_name = ebl_strtaboffset (runp->strent); + shdr->sh_type = SHT_GROUP; + shdr->sh_flags = 0; + shdr->sh_link = symscnndx; + /* If the user did not specify a signature we use the initial + empty symbol in the symbol table as the signature. */ + shdr->sh_info = (runp->signature != NULL + ? runp->signature->symidx : 0); + + (void) gelf_update_shdr (scn, shdr); + } + while ((runp = runp->next) != ctx->groups->next); + } + + + /* Add the name to the symbol section. */ + if (likely (symscnndx != 0)) + { + Elf_Scn *scn = elf_getscn (ctx->out.elf, symscnndx); + + shdr = gelf_getshdr (scn, &shdr_mem); + + shdr->sh_name = ebl_strtaboffset (symscn_strent); + + (void) gelf_update_shdr (scn, shdr); + + + /* Add the name to the string section. */ + assert (strscnndx != 0); + scn = elf_getscn (ctx->out.elf, strscnndx); + + shdr = gelf_getshdr (scn, &shdr_mem); + + shdr->sh_name = ebl_strtaboffset (strscn_strent); + + (void) gelf_update_shdr (scn, shdr); + + + /* Add the name to the extended symbol index section. */ + if (xndxscnndx != 0) + { + scn = elf_getscn (ctx->out.elf, xndxscnndx); + + shdr = gelf_getshdr (scn, &shdr_mem); + + shdr->sh_name = ebl_strtaboffset (xndxscn_strent); + + (void) gelf_update_shdr (scn, shdr); + } + } + + + /* Iterate over the created sections and fill in the names. */ + for (asmscn = ctx->section_list; asmscn != NULL; asmscn = asmscn->allnext) + { + shdr = gelf_getshdr (asmscn->data.main.scn, &shdr_mem); + /* This better should not fail. */ + assert (shdr != NULL); + + shdr->sh_name = ebl_strtaboffset (asmscn->data.main.strent); + + /* We now know the maximum alignment. */ + shdr->sh_addralign = asmscn->max_align; + + (void) gelf_update_shdr (asmscn->data.main.scn, shdr); + } + + /* Put the reference to the section header string table in the ELF + header. */ + ehdr = gelf_getehdr (ctx->out.elf, &ehdr_mem); + assert (ehdr != NULL); + + shstrscnndx = elf_ndxscn (shstrscn); + if (unlikely (shstrscnndx > SHN_HIRESERVE) + || unlikely (shstrscnndx == SHN_XINDEX)) + { + /* The index of the section header string sectio is too large. */ + Elf_Scn *scn = elf_getscn (ctx->out.elf, 0); + + /* Get the header for the zeroth section. */ + shdr = gelf_getshdr (scn, &shdr_mem); + /* This better does not fail. */ + assert (shdr != NULL); + + /* The sh_link field of the zeroth section header contains the value. */ + shdr->sh_link = shstrscnndx; + + (void) gelf_update_shdr (scn, shdr); + + /* This is the sign for the overflow. */ + ehdr->e_shstrndx = SHN_XINDEX; + } + else + ehdr->e_shstrndx = elf_ndxscn (shstrscn); + + gelf_update_ehdr (ctx->out.elf, ehdr); + + /* Write out the ELF file. */ + if (unlikely (elf_update (ctx->out.elf, ELF_C_WRITE_MMAP)) < 0) + { + __libasm_seterrno (ASM_E_LIBELF); + result = -1; + } + + /* We do not need the section header and symbol string tables anymore. */ + free (shstrtabdata->d_buf); + if (strtabdata != NULL) + free (strtabdata->d_buf); + /* We might have allocated the extended symbol table index. */ + if (xndxdata != NULL) + free (xndxdata->d_buf); + + /* Free section groups memory. */ + AsmScnGrp_t *scngrp = ctx->groups; + if (scngrp != NULL) + do + free (elf_getdata (scngrp->scn, NULL)->d_buf); + while ((scngrp = scngrp->next) != ctx->groups); + + /* Finalize the ELF handling. */ + if (unlikely (elf_end (ctx->out.elf)) != 0) + { + __libasm_seterrno (ASM_E_LIBELF); + result = -1; + } + + /* Free the temporary resources. */ + free (symtab); + + return result; +} + + +int +asm_end (ctx) + AsmCtx_t *ctx; +{ + int result; + + if (ctx == NULL) + /* Something went wrong earlier. */ + return -1; + + result = unlikely (ctx->textp) ? text_end (ctx) : binary_end (ctx); + if (result != 0) + return result; + + /* Make the new file globally readable and user/group-writable. */ + if (fchmod (ctx->fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH) != 0) + { + __libasm_seterrno (ASM_E_CANNOT_CHMOD); + return -1; + } + + /* Rename output file. */ + if (rename (ctx->tmp_fname, ctx->fname) != 0) + { + __libasm_seterrno (ASM_E_CANNOT_RENAME); + return -1; + } + + /* Free the resources. */ + __libasm_finictx (ctx); + + return 0; +} + + +static void +free_section (AsmScn_t *scnp) +{ + void *oldp; + + if (scnp->subnext != NULL) + free_section (scnp->subnext); + + struct AsmData *data = scnp->content; + if (data != NULL) + do + { + oldp = data; + data = data->next; + free (oldp); + } + while (oldp != scnp->content); + + free (scnp); +} + + +void +__libasm_finictx (ctx) + AsmCtx_t *ctx; +{ + /* Iterate through section table and free individual entries. */ + AsmScn_t *scn = ctx->section_list; + while (scn != NULL) + { + AsmScn_t *oldp = scn; + scn = scn->allnext; + free_section (oldp); + } + + /* Free the resources of the symbol table. */ + void *runp = NULL; + AsmSym_t *sym; + while ((sym = asm_symbol_tab_iterate (&ctx->symbol_tab, &runp)) != NULL) + free (sym); + asm_symbol_tab_free (&ctx->symbol_tab); + + + /* Free section groups. */ + AsmScnGrp_t *scngrp = ctx->groups; + if (scngrp != NULL) + do + { + AsmScnGrp_t *oldp = scngrp; + + scngrp = scngrp->next; + free (oldp); + } + while (scngrp != ctx->groups); + + + if (unlikely (ctx->textp)) + { + /* Close the stream. */ + fclose (ctx->out.file); + } + else + { + /* Close the output file. */ + /* XXX We should test for errors here but what would we do if we'd + find any. */ + (void) close (ctx->fd); + + /* And the string tables. */ + ebl_strtabfree (ctx->section_strtab); + ebl_strtabfree (ctx->symbol_strtab); + } + + /* Initialize the lock. */ + rwlock_fini (ctx->lock); + + /* Finally free the data structure. */ + free (ctx); +} diff --git a/3rdparty/elfutils/libasm/asm_error.c b/3rdparty/elfutils/libasm/asm_error.c new file mode 100644 index 0000000..300a798 --- /dev/null +++ b/3rdparty/elfutils/libasm/asm_error.c @@ -0,0 +1,96 @@ +/* Error handling in libasm. + Copyright (C) 2002, 2004, 2005, 2009 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libintl.h> +#include <stdbool.h> +#include <stdlib.h> + +#include "libasmP.h" + + +/* This is the key for the thread specific memory. */ +static __thread int global_error; + + +int +asm_errno (void) +{ + int result = global_error; + global_error = ASM_E_NOERROR; + return result; +} + + +void +__libasm_seterrno (value) + int value; +{ + global_error = value; +} + + +/* Return the appropriate message for the error. */ +static const char *msgs[ASM_E_NUM] = +{ + [ASM_E_NOERROR] = N_("no error"), + [ASM_E_NOMEM] = N_("out of memory"), + [ASM_E_CANNOT_CREATE] = N_("cannot create output file"), + [ASM_E_INVALID] = N_("invalid parameter"), + [ASM_E_CANNOT_CHMOD] = N_("cannot change mode of output file"), + [ASM_E_CANNOT_RENAME] = N_("cannot rename output file"), + [ASM_E_DUPLSYM] = N_("duplicate symbol"), + [ASM_E_TYPE] = N_("invalid section type for operation"), + [ASM_E_IOERROR] = N_("error during output of data"), + [ASM_E_ENOSUP] = N_("no backend support available"), +}; + +const char * +asm_errmsg (error) + int error; +{ + int last_error = global_error; + + if (error < -1) + return _("unknown error"); + if (error == 0 && last_error == 0) + /* No error. */ + return NULL; + + if (error != -1) + last_error = error; + + if (last_error == ASM_E_LIBELF) + return elf_errmsg (-1); + + return _(msgs[last_error]); +} diff --git a/3rdparty/elfutils/libasm/asm_fill.c b/3rdparty/elfutils/libasm/asm_fill.c new file mode 100644 index 0000000..6b92bc3 --- /dev/null +++ b/3rdparty/elfutils/libasm/asm_fill.c @@ -0,0 +1,77 @@ +/* Determine fill pattern for a section. + Copyright (C) 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> +#include <string.h> + +#include <libasmP.h> +#include <system.h> + + +int +asm_fill (asmscn, bytes, len) + AsmScn_t *asmscn; + void *bytes; + size_t len; +{ + struct FillPattern *pattern; + struct FillPattern *old_pattern; + + if (asmscn == NULL) + /* Some earlier error. */ + return -1; + + if (bytes == NULL) + /* Use the default pattern. */ + pattern = (struct FillPattern *) __libasm_default_pattern; + else + { + /* Allocate appropriate memory. */ + pattern = (struct FillPattern *) malloc (sizeof (struct FillPattern) + + len); + if (pattern == NULL) + return -1; + + pattern->len = len; + memcpy (pattern->bytes, bytes, len); + } + + old_pattern = asmscn->pattern; + asmscn->pattern = pattern; + + /* Free the old data structure if we have allocated it. */ + if (old_pattern != __libasm_default_pattern) + free (old_pattern); + + return 0; +} diff --git a/3rdparty/elfutils/libasm/asm_getelf.c b/3rdparty/elfutils/libasm/asm_getelf.c new file mode 100644 index 0000000..edeff13 --- /dev/null +++ b/3rdparty/elfutils/libasm/asm_getelf.c @@ -0,0 +1,44 @@ +/* Return ELF descriptor associated with the assembler context. + Copyright (C) 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stddef.h> + +#include <libasmP.h> + + +Elf * +asm_getelf (ctx) + AsmCtx_t *ctx; +{ + return ctx != NULL ? ctx->out.elf : NULL; +} diff --git a/3rdparty/elfutils/libasm/asm_newabssym.c b/3rdparty/elfutils/libasm/asm_newabssym.c new file mode 100644 index 0000000..4e59901 --- /dev/null +++ b/3rdparty/elfutils/libasm/asm_newabssym.c @@ -0,0 +1,136 @@ +/* Create new ABS symbol. + Copyright (C) 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <inttypes.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <libasmP.h> +#include <system.h> + + +/* Object for special COMMON section. */ +static const AsmScn_t __libasm_abs_scn = + { + .data = { + .main = { + .scn = ASM_ABS_SCN + } + } + }; + + +AsmSym_t * +asm_newabssym (ctx, name, size, value, type, binding) + AsmCtx_t *ctx; + const char *name; + GElf_Xword size; + GElf_Addr value; + int type; + int binding; +{ + AsmSym_t *result; + + if (ctx == NULL) + /* Something went wrong before. */ + return NULL; + + /* Common symbols are public. Therefore the user must provide a + name. */ + if (name == NULL) + { + __libasm_seterrno (ASM_E_INVALID); + return NULL; + } + + rwlock_wrlock (ctx->lock); + + result = (AsmSym_t *) malloc (sizeof (AsmSym_t)); + if (result == NULL) + return NULL; + + result->scn = (AsmScn_t *) &__libasm_abs_scn; + result->size = size; + result->type = type; + result->binding = binding; + result->symidx = 0; + result->strent = ebl_strtabadd (ctx->symbol_strtab, name, 0); + + /* The value of an ABS symbol must not be modified. Since there are + no subsection and the initial offset of the section is 0 we can + get the alignment recorded by storing it into the offset + field. */ + result->offset = value; + + if (unlikely (ctx->textp)) + { + /* An absolute symbol can be defined by giving a symbol a + specific value. */ + if (binding == STB_GLOBAL) + fprintf (ctx->out.file, "\t.globl %s\n", name); + else if (binding == STB_WEAK) + fprintf (ctx->out.file, "\t.weak %s\n", name); + + if (type == STT_OBJECT) + fprintf (ctx->out.file, "\t.type %s,@object\n", name); + else if (type == STT_FUNC) + fprintf (ctx->out.file, "\t.type %s,@function\n", name); + + fprintf (ctx->out.file, "%s = %llu\n", + name, (unsigned long long int) value); + + if (size != 0) + fprintf (ctx->out.file, "\t.size %s, %llu\n", + name, (unsigned long long int) size); + } + else + { + /* Put the symbol in the hash table so that we can later find it. */ + if (asm_symbol_tab_insert (&ctx->symbol_tab, elf_hash (name), result) + != 0) + { + /* The symbol already exists. */ + __libasm_seterrno (ASM_E_DUPLSYM); + free (result); + result = NULL; + } + else if (name != NULL && asm_emit_symbol_p (name)) + /* Only count non-private symbols. */ + ++ctx->nsymbol_tab; + } + + rwlock_unlock (ctx->lock); + + return result; +} diff --git a/3rdparty/elfutils/libasm/asm_newcomsym.c b/3rdparty/elfutils/libasm/asm_newcomsym.c new file mode 100644 index 0000000..7a578e0 --- /dev/null +++ b/3rdparty/elfutils/libasm/asm_newcomsym.c @@ -0,0 +1,117 @@ +/* Create new COMMON symbol. + Copyright (C) 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <inttypes.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <libasmP.h> +#include <system.h> + + +/* Object for special COMMON section. */ +static const AsmScn_t __libasm_com_scn = + { + .data = { + .main = { + .scn = ASM_COM_SCN + } + } + }; + + +AsmSym_t * +asm_newcomsym (ctx, name, size, align) + AsmCtx_t *ctx; + const char *name; + GElf_Xword size; + GElf_Addr align; +{ + AsmSym_t *result; + + if (ctx == NULL) + /* Something went wrong before. */ + return NULL; + + /* Common symbols are public. Therefore the user must provide a + name. */ + if (name == NULL) + { + __libasm_seterrno (ASM_E_INVALID); + return NULL; + } + + rwlock_wrlock (ctx->lock); + + result = (AsmSym_t *) malloc (sizeof (AsmSym_t)); + if (result == NULL) + return NULL; + + result->scn = (AsmScn_t *) &__libasm_com_scn; + result->size = size; + /* XXX Do we have to allow a different type? */ + result->type = STT_OBJECT; + /* XXX Do we have to allow a different binding? */ + result->binding = STB_GLOBAL; + result->symidx = 0; + result->strent = ebl_strtabadd (ctx->symbol_strtab, name, 0); + + /* The value of a COM symbol is the alignment. Since there are no + subsection and the initial offset of the section is 0 we can get + the alignment recorded by storing it into the offset field. */ + result->offset = align; + + if (unlikely (ctx->textp)) + fprintf (ctx->out.file, "\t.comm %s, %" PRIuMAX ", %" PRIuMAX "\n", + name, (uintmax_t) size, (uintmax_t) align); + else + { + /* Put the symbol in the hash table so that we can later find it. */ + if (asm_symbol_tab_insert (&ctx->symbol_tab, elf_hash (name), result) + != 0) + { + /* The symbol already exists. */ + __libasm_seterrno (ASM_E_DUPLSYM); + free (result); + result = NULL; + } + else if (name != NULL && asm_emit_symbol_p (name)) + /* Only count non-private symbols. */ + ++ctx->nsymbol_tab; + } + + rwlock_unlock (ctx->lock); + + return result; +} diff --git a/3rdparty/elfutils/libasm/asm_newscn.c b/3rdparty/elfutils/libasm/asm_newscn.c new file mode 100644 index 0000000..ece7f5c --- /dev/null +++ b/3rdparty/elfutils/libasm/asm_newscn.c @@ -0,0 +1,215 @@ +/* Create new section in output file. + Copyright (C) 2002-2011 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <error.h> +#include <libintl.h> +#include <stdlib.h> +#include <string.h> + +#include <libasmP.h> +#include <libelf.h> +#include <system.h> + + +/* Memory for the default pattern. The type uses a flexible array + which does work well with a static initializer. So we play some + dirty tricks here. */ +static const struct +{ + struct FillPattern pattern; + char zero; +} xdefault_pattern = + { + .pattern = + { + .len = 1 + }, + .zero = '\0' + }; +const struct FillPattern *__libasm_default_pattern = &xdefault_pattern.pattern; + + +static AsmScn_t * +text_newscn (AsmScn_t *result, GElf_Word type, GElf_Xword flags) +{ + /* Buffer where we construct the flag string. */ + char flagstr[sizeof (GElf_Xword) * 8 + 5]; + char *wp = flagstr; + const char *typestr = ""; + + /* Only write out the flag string if this is the first time the + section is selected. Some assemblers cannot cope with the + .section pseudo-op otherwise. */ + wp = stpcpy (wp, ", \""); + + if (flags & SHF_WRITE) + *wp++ = 'w'; + if (flags & SHF_ALLOC) + *wp++ = 'a'; + if (flags & SHF_EXECINSTR) + *wp++ = 'x'; + if (flags & SHF_MERGE) + *wp++ = 'M'; + if (flags & SHF_STRINGS) + *wp++ = 'S'; + if (flags & SHF_LINK_ORDER) + *wp++ = 'L'; + + *wp++ = '"'; + + if (type == SHT_PROGBITS) + typestr = ",@progbits"; + else if (type == SHT_NOBITS) + typestr = ",@nobits"; + + /* Terminate the string. */ + *wp = '\0'; + + fprintf (result->ctx->out.file, "\t.section \"%s\"%s%s\n", + result->name, flagstr, typestr); + + return result; +} + + +static AsmScn_t * +binary_newscn (AsmScn_t *result, GElf_Word type, GElf_Xword flags, + size_t scnname_len) +{ + GElf_Shdr shdr_mem; + GElf_Shdr *shdr; + Elf_Scn *scn; + + /* The initial subsection has the number zero. */ + result->subsection_id = 0; + + /* We start at offset zero. */ + result->offset = 0; + /* And generic alignment. */ + result->max_align = 1; + + /* No output yet. */ + result->content = NULL; + + /* Put the default fill pattern in place. */ + result->pattern = (struct FillPattern *) __libasm_default_pattern; + + /* There are no subsections so far. */ + result->subnext = NULL; + + /* Add the name to the section header string table. */ + result->data.main.strent = ebl_strtabadd (result->ctx->section_strtab, + result->name, scnname_len); + assert (result->data.main.strent != NULL); + + /* Create the new ELF section. */ + result->data.main.scn = scn = elf_newscn (result->ctx->out.elf); + if (scn == NULL) + { + free (result); + __libasm_seterrno (ASM_E_LIBELF); + return NULL; + } + + /* Not part of a section group (yet). */ + result->data.main.next_in_group = NULL; + + /* Remember the flags. */ + shdr = gelf_getshdr (scn, &shdr_mem); + + shdr->sh_flags = flags; + result->type = shdr->sh_type = type; + + (void) gelf_update_shdr (scn, shdr); + + return result; +} + + +AsmScn_t * +asm_newscn (ctx, scnname, type, flags) + AsmCtx_t *ctx; + const char *scnname; + GElf_Word type; + GElf_Xword flags; +{ + size_t scnname_len = strlen (scnname) + 1; + AsmScn_t *result; + + /* If no context is given there might be an earlier error. */ + if (ctx == NULL) + return NULL; + + /* Check whether only flags are set which areselectable by the user. */ + if (unlikely ((flags & ~(SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR | SHF_MERGE + | SHF_STRINGS | SHF_LINK_ORDER)) != 0) + /* We allow only two section types: data and data without file + representation. */ + || (type != SHT_PROGBITS && unlikely (type != SHT_NOBITS))) + { + __libasm_seterrno (ASM_E_INVALID); + return NULL; + } + + rwlock_wrlock (ctx->lock); + + /* This is a new section. */ + result = (AsmScn_t *) malloc (sizeof (AsmScn_t) + scnname_len); + if (result != NULL) + { + /* Add the name. */ + memcpy (result->name, scnname, scnname_len); + + /* Add the reference to the context. */ + result->ctx = ctx; + + /* Perform operations according to output mode. */ + result = (unlikely (ctx->textp) + ? text_newscn (result, type, flags) + : binary_newscn (result, type, flags, scnname_len)); + + /* If everything went well finally add the new section to the hash + table. */ + if (result != NULL) + { + result->allnext = ctx->section_list; + ctx->section_list = result; + } + } + + rwlock_unlock (ctx->lock); + + return result; +} +INTDEF(asm_newscn) diff --git a/3rdparty/elfutils/libasm/asm_newscn_ingrp.c b/3rdparty/elfutils/libasm/asm_newscn_ingrp.c new file mode 100644 index 0000000..6ef7cb9 --- /dev/null +++ b/3rdparty/elfutils/libasm/asm_newscn_ingrp.c @@ -0,0 +1,81 @@ +/* Create new section, which is member of a group, in output file. + Copyright (C) 2002, 2005 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> + +#include "libasmP.h" + + +AsmScn_t * +asm_newscn_ingrp (ctx, scnname, type, flags, grp) + AsmCtx_t *ctx; + const char *scnname; + GElf_Word type; + GElf_Xword flags; + AsmScnGrp_t *grp; +{ + AsmScn_t *result = INTUSE (asm_newscn) (ctx, scnname, type, flags); + + if (likely (result != NULL)) + { + /* We managed to create a section group. Add it to the section + group. */ + if (grp->nmembers == 0) + { + assert (grp->members == NULL); + grp->members = result->data.main.next_in_group = result; + } + else + { + result->data.main.next_in_group + = grp->members->data.main.next_in_group; + grp->members = grp->members->data.main.next_in_group = result; + } + + ++grp->nmembers; + + /* Set the SHF_GROUP flag. */ + if (likely (! ctx->textp)) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (result->data.main.scn, &shdr_mem); + + assert (shdr != NULL); + shdr->sh_flags |= SHF_GROUP; + + (void) gelf_update_shdr (result->data.main.scn, shdr); + } + } + + return result; +} diff --git a/3rdparty/elfutils/libasm/asm_newscngrp.c b/3rdparty/elfutils/libasm/asm_newscngrp.c new file mode 100644 index 0000000..2808e69 --- /dev/null +++ b/3rdparty/elfutils/libasm/asm_newscngrp.c @@ -0,0 +1,105 @@ +/* Create new section group. + Copyright (C) 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +#include "libasmP.h" +#include <system.h> + + + +AsmScnGrp_t * +asm_newscngrp (ctx, grpname, signature, flags) + AsmCtx_t *ctx; + const char *grpname; + AsmSym_t *signature; + Elf32_Word flags; +{ + AsmScnGrp_t *result; + size_t grpname_len = strlen (grpname) + 1; + + if (ctx == NULL) + return NULL; + + if ((flags & ~GRP_COMDAT) != 0) + { + /* This is not a supported flag. */ + __libasm_seterrno (ASM_E_INVALID); + return NULL; + } + + result = (AsmScnGrp_t *) malloc (sizeof (AsmScnGrp_t) + grpname_len); + if (result == NULL) + return NULL; + + result->signature = signature; + result->members = NULL; + result->nmembers = 0; + result->flags = flags; + + memcpy (result->name, grpname, grpname_len); + result->strent = ebl_strtabadd (ctx->section_strtab, result->name, + grpname_len); + + if (unlikely (ctx->textp)) + // XXX TBI. What is the format? + abort (); + else + { + result->scn = elf_newscn (ctx->out.elf); + if (result->scn == NULL) + { + /* Couldn't allocate a new section. */ + __libasm_seterrno (ASM_E_LIBELF); + free (result); + return NULL; + } + } + + /* Enqueue is the context data structure. */ + if (ctx->ngroups == 0) + { + assert (ctx->groups == NULL); + ctx->groups = result->next = result; + } + else + { + result->next = ctx->groups->next; + ctx->groups = ctx->groups->next = result; + } + ++ctx->ngroups; + + return result; +} diff --git a/3rdparty/elfutils/libasm/asm_newsubscn.c b/3rdparty/elfutils/libasm/asm_newsubscn.c new file mode 100644 index 0000000..a83607a --- /dev/null +++ b/3rdparty/elfutils/libasm/asm_newsubscn.c @@ -0,0 +1,99 @@ +/* Create new subsection section in given section. + Copyright (C) 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> + +#include <libasmP.h> +#include <system.h> + + +AsmScn_t * +asm_newsubscn (asmscn, nr) + AsmScn_t *asmscn; + unsigned int nr; +{ + AsmScn_t *runp; + AsmScn_t *newp; + + /* Just return if no section is given. The error must have been + somewhere else. */ + if (asmscn == NULL) + return NULL; + + /* Determine whether there is already a subsection with this number. */ + runp = asmscn->subsection_id == 0 ? asmscn : asmscn->data.up; + while (1) + { + if (runp->subsection_id == nr) + /* Found it. */ + return runp; + + if (runp->subnext == NULL || runp->subnext->subsection_id > nr) + break; + + runp = runp->subnext; + } + + newp = (AsmScn_t *) malloc (sizeof (AsmScn_t)); + if (newp == NULL) + return NULL; + + /* Same assembler context than the original section. */ + newp->ctx = runp->ctx; + + /* User provided the subsectio nID. */ + newp->subsection_id = nr; + + /* Inherit the parent's type. */ + newp->type = runp->type; + + /* Pointer to the zeroth subsection. */ + newp->data.up = runp->subsection_id == 0 ? runp : runp->data.up; + + /* We start at offset zero. */ + newp->offset = 0; + /* And generic alignment. */ + newp->max_align = 1; + + /* No output yet. */ + newp->content = NULL; + + /* Inherit the fill pattern from the section this one is derived from. */ + newp->pattern = asmscn->pattern; + + /* Enqueue at the right position in the list. */ + newp->subnext = runp->subnext; + runp->subnext = newp; + + return newp; +} diff --git a/3rdparty/elfutils/libasm/asm_newsym.c b/3rdparty/elfutils/libasm/asm_newsym.c new file mode 100644 index 0000000..deca08a --- /dev/null +++ b/3rdparty/elfutils/libasm/asm_newsym.c @@ -0,0 +1,138 @@ +/* Define new symbol for current position in given section. + Copyright (C) 2002, 2005 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <inttypes.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <libasmP.h> +#include <system.h> + + +AsmSym_t * +asm_newsym (asmscn, name, size, type, binding) + AsmScn_t *asmscn; + const char *name; + GElf_Xword size; + int type; + int binding; +{ +#define TEMPSYMLEN 10 + char tempsym[TEMPSYMLEN]; + AsmSym_t *result; + + if (asmscn == NULL) + /* Something went wrong before. */ + return NULL; + + /* Generate a temporary symbol if necessary. */ + if (name == NULL) + { + /* If a local symbol name is created the symbol better have + local binding. */ + if (binding != STB_LOCAL) + { + __libasm_seterrno (ASM_E_INVALID); + return NULL; + } + + // XXX This requires getting the format from the machine backend. */ + snprintf (tempsym, TEMPSYMLEN, ".L%07u", asmscn->ctx->tempsym_count++); + + name = tempsym; + } + + size_t name_len = strlen (name) + 1; + + result = (AsmSym_t *) malloc (sizeof (AsmSym_t) + name_len); + if (result == NULL) + return NULL; + + rwlock_wrlock (asmscn->ctx->lock); + + result->scn = asmscn; + result->offset = asmscn->offset; + result->size = size; + result->type = type; + result->binding = binding; + result->symidx = 0; + result->strent = ebl_strtabadd (asmscn->ctx->symbol_strtab, + memcpy (result + 1, name, name_len), 0); + + if (unlikely (asmscn->ctx->textp)) + { + /* We are only interested in the name and don't need to know whether + it is a local name or not. */ + /* First print the binding pseudo-op. */ + if (binding == STB_GLOBAL) + fprintf (asmscn->ctx->out.file, "\t.globl\t%s\n", name); + else if (binding == STB_WEAK) + fprintf (asmscn->ctx->out.file, "\t.weak\t%s\n", name); + + /* Next the symbol type. */ + if (type == STT_OBJECT) + fprintf (asmscn->ctx->out.file, "\t.type\t%s,@object\n", name); + else if (type == STT_FUNC) + fprintf (asmscn->ctx->out.file, "\t.type\t%s,@function\n", name); + + /* Finally the size and the label. */ + fprintf (asmscn->ctx->out.file, "\t.size\t%s,%" PRIuMAX "\n%s:\n", + name, (uintmax_t) size, name); + } + else + { + /* Put the symbol in the hash table so that we can later find it. */ + if (asm_symbol_tab_insert (&asmscn->ctx->symbol_tab, elf_hash (name), + result) != 0) + { + /* The symbol already exists. */ + __libasm_seterrno (ASM_E_DUPLSYM); + /* Note that we can free the entry since there must be no + reference in the string table to the string. We can only + fail to insert the symbol into the symbol table if there + is already a symbol with this name. In this case the + ebl_strtabadd function would use the previously provided + name. */ + free (result); + result = NULL; + } + else if (name != tempsym && asm_emit_symbol_p (name)) + /* Only count non-private symbols. */ + ++asmscn->ctx->nsymbol_tab; + } + + rwlock_unlock (asmscn->ctx->lock); + + return result; +} diff --git a/3rdparty/elfutils/libasm/asm_scngrp_newsignature.c b/3rdparty/elfutils/libasm/asm_scngrp_newsignature.c new file mode 100644 index 0000000..d87f4a4 --- /dev/null +++ b/3rdparty/elfutils/libasm/asm_scngrp_newsignature.c @@ -0,0 +1,48 @@ +/* Update signature of section group. + Copyright (C) 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libasmP.h" + + +int +asm_scngrp_newsignature (grp, signature) + AsmScnGrp_t *grp; + AsmSym_t *signature; +{ + if (grp == NULL || signature == NULL) + return 1; + + grp->signature = signature; + + return 0; +} diff --git a/3rdparty/elfutils/libasm/asmheaders.pri b/3rdparty/elfutils/libasm/asmheaders.pri new file mode 100644 index 0000000..5107045 --- /dev/null +++ b/3rdparty/elfutils/libasm/asmheaders.pri @@ -0,0 +1,6 @@ +HEADERS += \ + $$PWD/libasm.h \ + $$PWD/libasmP.h \ + $$PWD/symbolhash.h + +INCLUDEPATH += $$PWD diff --git a/3rdparty/elfutils/libasm/disasm_begin.c b/3rdparty/elfutils/libasm/disasm_begin.c new file mode 100644 index 0000000..d00852b --- /dev/null +++ b/3rdparty/elfutils/libasm/disasm_begin.c @@ -0,0 +1,64 @@ +/* Create context descriptor for disassembler. + Copyright (C) 2005, 2008 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2005. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> + +#include "libasmP.h" +#include "../libebl/libeblP.h" + + +DisasmCtx_t * +disasm_begin (Ebl *ebl, Elf *elf, DisasmGetSymCB_t symcb) +{ + if (ebl == NULL) + return NULL; + + if (ebl->disasm == NULL) + { + __libasm_seterrno (ASM_E_ENOSUP); + return NULL; + } + + DisasmCtx_t *ctx = (DisasmCtx_t *) malloc (sizeof (DisasmCtx_t)); + if (ctx == NULL) + { + __libasm_seterrno (ASM_E_NOMEM); + return NULL; + } + + ctx->ebl = ebl; + ctx->elf = elf; + ctx->symcb = symcb; + + return ctx; +} diff --git a/3rdparty/elfutils/libasm/disasm_cb.c b/3rdparty/elfutils/libasm/disasm_cb.c new file mode 100644 index 0000000..eb3689c --- /dev/null +++ b/3rdparty/elfutils/libasm/disasm_cb.c @@ -0,0 +1,179 @@ +/* Copyright (C) 2005, 2007, 2008 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2005. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> + +#include "libasmP.h" +#include "../libebl/libeblP.h" + + +struct symtoken +{ + DisasmCtx_t *ctx; + void *symcbarg; +}; + + +static int +default_elf_getsym (GElf_Addr addr, Elf32_Word scnndx, GElf_Addr value, + char **buf, size_t *buflen, void *arg) +{ + struct symtoken *symtoken = (struct symtoken *) arg; + + /* First try the user provided function. */ + if (symtoken->ctx->symcb != NULL) + { + int res = symtoken->ctx->symcb (addr, scnndx, value, buf, buflen, + symtoken->symcbarg); + if (res >= 0) + return res; + } + + // XXX Look up in ELF file. + + return -1; +} + + +struct symaddrpair +{ + GElf_Addr addr; + const char *name; +}; + + +static void +read_symtab_exec (DisasmCtx_t *ctx) +{ + /* We simply use all we can get our hands on. This will produce + some duplicate information but this is no problem, we simply + ignore the latter definitions. */ + Elf_Scn *scn= NULL; + while ((scn = elf_nextscn (ctx->elf, scn)) != NULL) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + Elf_Data *data; + if (shdr == NULL || shdr->sh_type != SHT_SYMTAB + || (data = elf_getdata (scn, NULL)) == NULL) + continue; + + int xndxscnidx = elf_scnshndx (scn); + Elf_Data *xndxdata = NULL; + if (xndxscnidx > 0) + xndxdata = elf_getdata (elf_getscn (ctx->elf, xndxscnidx), NULL); + + /* Iterate over all symbols. Add all defined symbols. */ + int nsyms = shdr->sh_size / shdr->sh_entsize; + for (int cnt = 1; cnt < nsyms; ++cnt) + { + Elf32_Word xshndx; + GElf_Sym sym_mem; + GElf_Sym *sym = gelf_getsymshndx (data, xndxdata, cnt, &sym_mem, + &xshndx); + if (sym == NULL) + continue; + + /* Undefined symbols are useless here. */ + if (sym->st_shndx == SHN_UNDEF) + continue; + + + } + } +} + + +static void +read_symtab (DisasmCtx_t *ctx) +{ + /* Find the symbol table(s). */ + GElf_Ehdr ehdr_mem; + GElf_Ehdr *ehdr = gelf_getehdr (ctx->elf, &ehdr_mem); + if (ehdr == NULL) + return; + + switch (ehdr->e_type) + { + case ET_EXEC: + case ET_DYN: + read_symtab_exec (ctx); + break; + + case ET_REL: + // XXX Handle + break; + + default: + break; + } +} + + +static int +null_elf_getsym (GElf_Addr addr __attribute__ ((unused)), + Elf32_Word scnndx __attribute__ ((unused)), + GElf_Addr value __attribute__ ((unused)), + char **buf __attribute__ ((unused)), + size_t *buflen __attribute__ ((unused)), + void *arg __attribute__ ((unused))) +{ + return -1; +} + + +int +disasm_cb (DisasmCtx_t *ctx, const uint8_t **startp, const uint8_t *end, + GElf_Addr addr, const char *fmt, DisasmOutputCB_t outcb, + void *outcbarg, void *symcbarg) +{ + struct symtoken symtoken; + DisasmGetSymCB_t getsym = ctx->symcb ?: null_elf_getsym; + + if (ctx->elf != NULL) + { + /* Read all symbols of the ELF file and stuff them into a hash + table. The key is the address and the section index. */ + read_symtab (ctx); + + symtoken.ctx = ctx; + symtoken.symcbarg = symcbarg; + + symcbarg = &symtoken; + + getsym = default_elf_getsym; + } + + return ctx->ebl->disasm (startp, end, addr, fmt, outcb, getsym, outcbarg, + symcbarg); +} +INTDEF (disasm_cb) diff --git a/3rdparty/elfutils/libasm/disasm_end.c b/3rdparty/elfutils/libasm/disasm_end.c new file mode 100644 index 0000000..6878030 --- /dev/null +++ b/3rdparty/elfutils/libasm/disasm_end.c @@ -0,0 +1,45 @@ +/* Release descriptor for disassembler. + Copyright (C) 2005, 2008 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2005. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> + +#include "libasmP.h" + + +int +disasm_end (DisasmCtx_t *ctx) +{ + free (ctx); + + return 0; +} diff --git a/3rdparty/elfutils/libasm/disasm_str.c b/3rdparty/elfutils/libasm/disasm_str.c new file mode 100644 index 0000000..5b0bb29 --- /dev/null +++ b/3rdparty/elfutils/libasm/disasm_str.c @@ -0,0 +1,72 @@ +/* Copyright (C) 2005, 2008 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2007. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> + +#include "libasmP.h" + + +struct buffer +{ + char *buf; + size_t len; +}; + + +static int +buffer_cb (char *str, size_t len, void *arg) +{ + struct buffer *buffer = (struct buffer *) arg; + + if (len > buffer->len) + /* Return additional needed space. */ + return len - buffer->len; + + buffer->buf = mempcpy (buffer->buf, str, len); + buffer->len = len; + + return 0; +} + + +int +disasm_str (DisasmCtx_t *ctx, const uint8_t **startp, const uint8_t *end, + GElf_Addr addr, const char *fmt, char **bufp, size_t len, + void *symcbarg) +{ + struct buffer buffer = { .buf = *bufp, .len = len }; + + int res = INTUSE(disasm_cb) (ctx, startp, end, addr, fmt, buffer_cb, &buffer, + symcbarg); + *bufp = buffer.buf; + return res; +} diff --git a/3rdparty/elfutils/libasm/libasm.h b/3rdparty/elfutils/libasm/libasm.h new file mode 100644 index 0000000..5c61224 --- /dev/null +++ b/3rdparty/elfutils/libasm/libasm.h @@ -0,0 +1,202 @@ +/* Interface for libasm. + Copyright (C) 2002, 2005, 2008 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifndef _LIBASM_H +#define _LIBASM_H 1 + +#include <stdbool.h> +#include <stdint.h> + +#include <libebl.h> + + +/* Opaque type for the assembler context descriptor. */ +typedef struct AsmCtx AsmCtx_t; + +/* Opaque type for a section. */ +typedef struct AsmScn AsmScn_t; + +/* Opaque type for a section group. */ +typedef struct AsmScnGrp AsmScnGrp_t; + +/* Opaque type for a symbol. */ +typedef struct AsmSym AsmSym_t; + + +/* Opaque type for the disassembler context descriptor. */ +typedef struct DisasmCtx DisasmCtx_t; + +/* Type used for callback functions to retrieve symbol name. The + symbol reference is in the section designated by the second parameter + at an offset described by the first parameter. The value is the + third parameter. */ +typedef int (*DisasmGetSymCB_t) (GElf_Addr, Elf32_Word, GElf_Addr, char **, + size_t *, void *); + +/* Output function callback. */ +typedef int (*DisasmOutputCB_t) (char *, size_t, void *); + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Create output file and return descriptor for assembler context. If + TEXTP is true the output is an assembler format text file. + Otherwise an object file is created. The MACHINE parameter + corresponds to an EM_ constant from <elf.h>, KLASS specifies the + class (32- or 64-bit), and DATA specifies the byte order (little or + big endian). */ +extern AsmCtx_t *asm_begin (const char *fname, Ebl *ebl, bool textp); + +/* Abort the operation on the assembler context and free all resources. */ +extern int asm_abort (AsmCtx_t *ctx); + +/* Finalize output file and free all resources. */ +extern int asm_end (AsmCtx_t *ctx); + + +/* Return handle for the named section. If it was not used before + create it. */ +extern AsmScn_t *asm_newscn (AsmCtx_t *ctx, const char *scnname, + GElf_Word type, GElf_Xword flags); + + +/* Similar to 'asm_newscn', but make it part of section group GRP. */ +extern AsmScn_t *asm_newscn_ingrp (AsmCtx_t *ctx, const char *scnname, + GElf_Word type, GElf_Xword flags, + AsmScnGrp_t *grp); + +/* Create new subsection NR in the given section. */ +extern AsmScn_t *asm_newsubscn (AsmScn_t *asmscn, unsigned int nr); + + +/* Return handle for new section group. The signature symbol can be + set later. */ +extern AsmScnGrp_t *asm_newscngrp (AsmCtx_t *ctx, const char *grpname, + AsmSym_t *signature, Elf32_Word flags); + +/* Set or overwrite signature symbol for group. */ +extern int asm_scngrp_newsignature (AsmScnGrp_t *grp, AsmSym_t *signature); + + +/* Add zero terminated string STR of size LEN to (sub)section ASMSCN. */ +extern int asm_addstrz (AsmScn_t *asmscn, const char *str, size_t len); + +/* Add 8-bit signed integer NUM to (sub)section ASMSCN. */ +extern int asm_addint8 (AsmScn_t *asmscn, int8_t num); + +/* Add 8-bit unsigned integer NUM to (sub)section ASMSCN. */ +extern int asm_adduint8 (AsmScn_t *asmscn, uint8_t num); + +/* Add 16-bit signed integer NUM to (sub)section ASMSCN. */ +extern int asm_addint16 (AsmScn_t *asmscn, int16_t num); + +/* Add 16-bit unsigned integer NUM to (sub)section ASMSCN. */ +extern int asm_adduint16 (AsmScn_t *asmscn, uint16_t num); + +/* Add 32-bit signed integer NUM to (sub)section ASMSCN. */ +extern int asm_addint32 (AsmScn_t *asmscn, int32_t num); + +/* Add 32-bit unsigned integer NUM to (sub)section ASMSCN. */ +extern int asm_adduint32 (AsmScn_t *asmscn, uint32_t num); + +/* Add 64-bit signed integer NUM to (sub)section ASMSCN. */ +extern int asm_addint64 (AsmScn_t *asmscn, int64_t num); + +/* Add 64-bit unsigned integer NUM to (sub)section ASMSCN. */ +extern int asm_adduint64 (AsmScn_t *asmscn, uint64_t num); + + +/* Add signed little endian base 128 integer NUM to (sub)section ASMSCN. */ +extern int asm_addsleb128 (AsmScn_t *asmscn, int32_t num); + +/* Add unsigned little endian base 128 integer NUM to (sub)section ASMSCN. */ +extern int asm_adduleb128 (AsmScn_t *asmscn, uint32_t num); + + +/* Define new symbol NAME for current position in given section ASMSCN. */ +extern AsmSym_t *asm_newsym (AsmScn_t *asmscn, const char *name, + GElf_Xword size, int type, int binding); + + +/* Define new common symbol NAME with given SIZE and alignment. */ +extern AsmSym_t *asm_newcomsym (AsmCtx_t *ctx, const char *name, + GElf_Xword size, GElf_Addr align); + +/* Define new common symbol NAME with given SIZE, VALUE, TYPE, and BINDING. */ +extern AsmSym_t *asm_newabssym (AsmCtx_t *ctx, const char *name, + GElf_Xword size, GElf_Addr value, + int type, int binding); + + +/* Align (sub)section offset according to VALUE. */ +extern int asm_align (AsmScn_t *asmscn, GElf_Word value); + +/* Set the byte pattern used to fill gaps created by alignment. */ +extern int asm_fill (AsmScn_t *asmscn, void *bytes, size_t len); + + +/* Return ELF descriptor created for the output file of the given context. */ +extern Elf *asm_getelf (AsmCtx_t *ctx); + + +/* Return error code of last failing function call. This value is kept + separately for each thread. */ +extern int asm_errno (void); + +/* Return error string for ERROR. If ERROR is zero, return error string + for most recent error or NULL is none occurred. If ERROR is -1 the + behaviour is similar to the last case except that not NULL but a legal + string is returned. */ +extern const char *asm_errmsg (int __error); + + +/* Create context descriptor for disassembler. */ +extern DisasmCtx_t *disasm_begin (Ebl *ebl, Elf *elf, DisasmGetSymCB_t symcb); + +/* Release descriptor for disassembler. */ +extern int disasm_end (DisasmCtx_t *ctx); + +/* Produce of disassembly output for given memory, store text in + provided buffer. */ +extern int disasm_str (DisasmCtx_t *ctx, const uint8_t **startp, + const uint8_t *end, GElf_Addr addr, const char *fmt, + char **bufp, size_t len, void *symcbarg); + +/* Produce disassembly output for given memory and output it using the + given callback functions. */ +extern int disasm_cb (DisasmCtx_t *ctx, const uint8_t **startp, + const uint8_t *end, GElf_Addr addr, const char *fmt, + DisasmOutputCB_t outcb, void *outcbarg, void *symcbarg); + +#ifdef __cplusplus +} +#endif + +#endif /* libasm.h */ diff --git a/3rdparty/elfutils/libasm/libasm.pro b/3rdparty/elfutils/libasm/libasm.pro new file mode 100644 index 0000000..a6e9f1a --- /dev/null +++ b/3rdparty/elfutils/libasm/libasm.pro @@ -0,0 +1,40 @@ +TEMPLATE = lib +CONFIG += staticlib +TARGET = ../asm + +include(../elfutils.pri) +include(../libebl/eblheaders.pri) +include(asmheaders.pri) + +SOURCES += \ + $$PWD/asm_abort.c \ + $$PWD/asm_addint8.c \ + $$PWD/asm_addint16.c \ + $$PWD/asm_addint32.c \ + $$PWD/asm_addint64.c \ + $$PWD/asm_addsleb128.c \ + $$PWD/asm_addstrz.c \ + $$PWD/asm_adduint8.c \ + $$PWD/asm_adduint16.c \ + $$PWD/asm_adduint32.c \ + $$PWD/asm_adduint64.c \ + $$PWD/asm_adduleb128.c \ + $$PWD/asm_align.c \ + $$PWD/asm_begin.c \ + $$PWD/asm_end.c \ + $$PWD/asm_error.c \ + $$PWD/asm_fill.c \ + $$PWD/asm_getelf.c \ + $$PWD/asm_newabssym.c \ + $$PWD/asm_newcomsym.c \ + $$PWD/asm_newscn_ingrp.c \ + $$PWD/asm_newscn.c \ + $$PWD/asm_newscngrp.c \ + $$PWD/asm_newsubscn.c \ + $$PWD/asm_newsym.c \ + $$PWD/asm_scngrp_newsignature.c \ + $$PWD/disasm_begin.c \ + $$PWD/disasm_cb.c \ + $$PWD/disasm_end.c \ + $$PWD/disasm_str.c \ + $$PWD/symbolhash.c diff --git a/3rdparty/elfutils/libasm/libasmP.h b/3rdparty/elfutils/libasm/libasmP.h new file mode 100644 index 0000000..49b6484 --- /dev/null +++ b/3rdparty/elfutils/libasm/libasmP.h @@ -0,0 +1,307 @@ +/* Internal definitions for libasm. + Copyright (C) 2002, 2004, 2005 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifndef _LIBASMP_H +#define _LIBASMP_H 1 + +#include <stdio.h> + +#include <libasm.h> + +/* gettext helper macros. */ +#define _(Str) dgettext ("elfutils", Str) + + +/* Known error codes. */ +enum + { + ASM_E_NOERROR, + ASM_E_NOMEM, /* No more memory. */ + ASM_E_CANNOT_CREATE, /* Output file cannot be created. */ + ASM_E_INVALID, /* Invalid parameters. */ + ASM_E_CANNOT_CHMOD, /* Cannot change mode of output file. */ + ASM_E_CANNOT_RENAME, /* Cannot rename output file. */ + ASM_E_DUPLSYM, /* Duplicate symbol definition. */ + ASM_E_LIBELF, /* Refer to error in libelf. */ + ASM_E_TYPE, /* Invalid section type for operation. */ + ASM_E_IOERROR, /* Error during output of data. */ + ASM_E_ENOSUP, /* No backend support. */ + ASM_E_NUM /* Keep this entry as the last. */ + }; + + +/* Special sections. */ +#define ASM_ABS_SCN ((Elf_Scn *) 1) +#define ASM_COM_SCN ((Elf_Scn *) 2) + + +/* And the hash table for symbols. */ +#include <symbolhash.h> + + +/* Descriptor for a section. */ +struct AsmScn +{ + /* The underlying assembler context. */ + AsmCtx_t *ctx; + + /* Subsection ID. */ + unsigned int subsection_id; + + /* Section type. */ + GElf_Word type; + + union + { + /* Data only stored in the record for subsection zero. */ + struct + { + /* The ELF section. */ + Elf_Scn *scn; + + /* Entry in the section header string table. */ + struct Ebl_Strent *strent; + + /* Next member of group. */ + struct AsmScn *next_in_group; + } main; + + /* Pointer to the record for subsection zero. */ + AsmScn_t *up; + } data; + + /* Current offset in the (sub)section. */ + GElf_Off offset; + /* Maximum alignment of the section so far. */ + GElf_Word max_align; + + /* Section content. */ + struct AsmData + { + /* Currently used number of bytes in the block. */ + size_t len; + + /* Number of bytes allocated. */ + size_t maxlen; + + /* Pointer to the next block. */ + struct AsmData *next; + + /* The actual data. */ + char data[flexarr_size]; + } *content; + + /* Fill pattern. */ + struct FillPattern + { + size_t len; + char bytes[flexarr_size]; + } *pattern; + + /* Next subsection. */ + AsmScn_t *subnext; + + /* List of all allocated sections. */ + AsmScn_t *allnext; + + /* Name of the section. */ + char name[flexarr_size]; +}; + + +/* Descriptor used for the assembling session. */ +struct AsmCtx +{ + /* File descriptor of the temporary file. */ + int fd; + + /* True if text output is wanted. */ + bool textp; + + /* Output file handle. */ + union + { + /* ELF descriptor of the temporary file. */ + Elf *elf; + /* I/O stream for text output. */ + FILE *file; + } out; + + + /* List with defined sections. */ + AsmScn_t *section_list; + /* Section header string table. */ + struct Ebl_Strtab *section_strtab; + + /* Table with defined symbols. */ + asm_symbol_tab symbol_tab; + /* Number of symbols in the table. */ + unsigned int nsymbol_tab; + /* Symbol string table. */ + struct Ebl_Strtab *symbol_strtab; + + /* List of section groups. */ + struct AsmScnGrp *groups; + /* Number of section groups. */ + size_t ngroups; + + /* Current required alignment for common symbols. */ + GElf_Word common_align; + + /* Lock to handle multithreaded programs. */ + rwlock_define (,lock); + + /* Counter for temporary symbols. */ + unsigned int tempsym_count; + + /* Name of the output file. */ + char *fname; + /* The name of the temporary file. */ + char tmp_fname[flexarr_size]; +}; + + +/* Descriptor for a symbol. */ +struct AsmSym +{ + /* Reference to the section which contains the symbol. */ + AsmScn_t *scn; + + /* Type of the symbol. */ + int8_t type; + /* Binding of the symbol. */ + int8_t binding; + + /* Size of the symbol. */ + GElf_Xword size; + + /* Offset in the section. */ + GElf_Off offset; + + /* Symbol table index of the symbol in the symbol table. */ + size_t symidx; + + /* Reference to name of the symbol. */ + struct Ebl_Strent *strent; +}; + + +/* Descriptor for section group. */ +struct AsmScnGrp +{ + /* Entry in the section header string table. */ + struct Ebl_Strent *strent; + + /* The ELF section. */ + Elf_Scn *scn; + + /* The signature. */ + struct AsmSym *signature; + + /* First member. */ + struct AsmScn *members; + /* Number of members. */ + size_t nmembers; + + /* Flags. */ + Elf32_Word flags; + + /* Next group. */ + struct AsmScnGrp *next; + + /* Name of the section group. */ + char name[flexarr_size]; +}; + + +/* Descriptor for disassembler. */ +struct DisasmCtx +{ + /* Handle for the backend library with the disassembler routine. */ + Ebl *ebl; + + /* ELF file containing all the data passed to the function. This + allows to look up symbols. */ + Elf *elf; + + /* Callback function to determine symbol names. */ + DisasmGetSymCB_t symcb; +}; + + +/* The default fill pattern: one zero byte. */ +extern const struct FillPattern *__libasm_default_pattern + attribute_hidden; + + +/* Ensure there are at least LEN bytes available in the output buffer + for ASMSCN. */ +extern int __libasm_ensure_section_space (AsmScn_t *asmscn, size_t len) + internal_function; + +/* Free all resources associated with the assembler context. */ +extern void __libasm_finictx (AsmCtx_t *ctx) internal_function; + +/* Set error code. */ +extern void __libasm_seterrno (int err) internal_function; + +/* Return handle for the named section. If it was not used before + create it. */ +extern AsmScn_t *__asm_newscn_internal (AsmCtx_t *ctx, const char *scnname, + GElf_Word type, GElf_Xword flags) + attribute_hidden; + + +/* Internal aliases of the asm_addintXX functions. */ +extern int __asm_addint8_internal (AsmScn_t *asmscn, int8_t num) + attribute_hidden; +extern int __asm_addint16_internal (AsmScn_t *asmscn, int16_t num) + attribute_hidden; +extern int __asm_addint32_internal (AsmScn_t *asmscn, int32_t num) + attribute_hidden; +extern int __asm_addint64_internal (AsmScn_t *asmscn, int64_t num) + attribute_hidden; + + +/* Produce disassembly output for given memory and output it using the + given callback functions. */ +extern int __disasm_cb_internal (DisasmCtx_t *ctx, const uint8_t **startp, + const uint8_t *end, GElf_Addr addr, + const char *fmt, DisasmOutputCB_t outcb, + void *outcbarp, void *symcbarg) + attribute_hidden; + + +/* Test whether given symbol is an internal symbol and if yes, whether + we should nevertheless emit it in the symbol table. */ +// XXX The second part should probably be controlled by an option which +// isn't implemented yet +// XXX Also, the format will change with the backend. +#define asm_emit_symbol_p(name) (strncmp (name, ".L", 2) != 0) + +#endif /* libasmP.h */ diff --git a/3rdparty/elfutils/libasm/symbolhash.c b/3rdparty/elfutils/libasm/symbolhash.c new file mode 100644 index 0000000..1c95418 --- /dev/null +++ b/3rdparty/elfutils/libasm/symbolhash.c @@ -0,0 +1,54 @@ +/* Symbol hash table implementation. + Copyright (C) 2001, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2001. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> + +#include <libasmP.h> +#include <libebl.h> + +/* Definitions for the symbol hash table. */ +#define TYPE AsmSym_t * +#define NAME asm_symbol_tab +#define ITERATE 1 +#define REVERSE 1 +#define COMPARE(a, b) \ + strcmp (ebl_string ((a)->strent), ebl_string ((b)->strent)) + +#define next_prime __libasm_next_prime +extern size_t next_prime (size_t) attribute_hidden; + +#include "../lib/dynamicsizehash.c" + +#undef next_prime +#define next_prime attribute_hidden __libasm_next_prime +#include "../lib/next_prime.c" diff --git a/3rdparty/elfutils/libasm/symbolhash.h b/3rdparty/elfutils/libasm/symbolhash.h new file mode 100644 index 0000000..a5bceff --- /dev/null +++ b/3rdparty/elfutils/libasm/symbolhash.h @@ -0,0 +1,40 @@ +/* Copyright (C) 2001, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2001. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifndef SYMBOLHASH_H +#define SYMBOLHASH_H 1 + +/* Definitions for the symbol hash table. */ +#define TYPE AsmSym_t * +#define NAME asm_symbol_tab +#define ITERATE 1 +#define COMPARE(a, b) \ + strcmp (ebl_string ((a)->strent), ebl_string ((b)->strent)) +#include <dynamicsizehash.h> + +#endif /* symbolhash.h */ diff --git a/3rdparty/elfutils/libdw/cfi.c b/3rdparty/elfutils/libdw/cfi.c new file mode 100644 index 0000000..632e91d --- /dev/null +++ b/3rdparty/elfutils/libdw/cfi.c @@ -0,0 +1,504 @@ +/* CFI program execution. + Copyright (C) 2009-2010, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "../libebl/libebl.h" +#include "cfi.h" +#include "memory-access.h" +#include "encoded-value.h" +#include "system.h" +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +#define CFI_PRIMARY_MAX 0x3f + +static Dwarf_Frame * +duplicate_frame_state (const Dwarf_Frame *original, + Dwarf_Frame *prev) +{ + size_t size = offsetof (Dwarf_Frame, regs[original->nregs]); + Dwarf_Frame *copy = malloc (size); + if (likely (copy != NULL)) + { + memcpy (copy, original, size); + copy->prev = prev; + } + return copy; +} + +/* Returns a DWARF_E_* error code, usually NOERROR or INVALID_CFI. + Frees *STATE on failure. */ +static int +execute_cfi (Dwarf_CFI *cache, + const struct dwarf_cie *cie, + Dwarf_Frame **state, + const uint8_t *program, const uint8_t *const end, bool abi_cfi, + Dwarf_Addr loc, Dwarf_Addr find_pc) +{ + /* The caller should not give us anything out of range. */ + assert (loc <= find_pc); + + int result = DWARF_E_NOERROR; + +#define cfi_assert(ok) do { \ + if (likely (ok)) break; \ + result = DWARF_E_INVALID_CFI; \ + goto out; \ + } while (0) + + Dwarf_Frame *fs = *state; + inline bool enough_registers (Dwarf_Word reg) + { + if (fs->nregs <= reg) + { + size_t size = offsetof (Dwarf_Frame, regs[reg + 1]); + Dwarf_Frame *bigger = realloc (fs, size); + if (unlikely (bigger == NULL)) + { + result = DWARF_E_NOMEM; + return false; + } + else + { + eu_static_assert (reg_unspecified == 0); + memset (bigger->regs + bigger->nregs, 0, + (reg + 1 - bigger->nregs) * sizeof bigger->regs[0]); + bigger->nregs = reg + 1; + fs = bigger; + } + } + return true; + } + + inline void require_cfa_offset (void) + { + if (unlikely (fs->cfa_rule != cfa_offset)) + fs->cfa_rule = cfa_invalid; + } + +#define register_rule(regno, r_rule, r_value) do { \ + if (unlikely (! enough_registers (regno))) \ + goto out; \ + fs->regs[regno].rule = reg_##r_rule; \ + fs->regs[regno].value = (r_value); \ + } while (0) + + while (program < end) + { + uint8_t opcode = *program++; + Dwarf_Word regno; + Dwarf_Word offset; + Dwarf_Word sf_offset; + Dwarf_Word operand = opcode & CFI_PRIMARY_MAX; + switch (opcode) + { + /* These cases move LOC, i.e. "create a new table row". */ + + case DW_CFA_advance_loc1: + operand = *program++; + case DW_CFA_advance_loc + 0 ... DW_CFA_advance_loc + CFI_PRIMARY_MAX: + advance_loc: + loc += operand * cie->code_alignment_factor; + break; + + case DW_CFA_advance_loc2: + cfi_assert (program + 2 <= end); + operand = read_2ubyte_unaligned_inc (cache, program); + goto advance_loc; + case DW_CFA_advance_loc4: + cfi_assert (program + 4 <= end); + operand = read_4ubyte_unaligned_inc (cache, program); + goto advance_loc; + case DW_CFA_MIPS_advance_loc8: + cfi_assert (program + 8 <= end); + operand = read_8ubyte_unaligned_inc (cache, program); + goto advance_loc; + + case DW_CFA_set_loc: + if (likely (!read_encoded_value (cache, cie->fde_encoding, + &program, &loc))) + break; + result = INTUSE(dwarf_errno) (); + goto out; + + /* Now all following cases affect this row, but do not touch LOC. + These cases end with 'continue'. We only get out of the + switch block for the row-copying (LOC-moving) cases above. */ + + case DW_CFA_def_cfa: + get_uleb128 (operand, program, end); + cfi_assert (program < end); + get_uleb128 (offset, program, end); + def_cfa: + fs->cfa_rule = cfa_offset; + fs->cfa_val_reg = operand; + fs->cfa_val_offset = offset; + /* Prime the rest of the Dwarf_Op so dwarf_frame_cfa can use it. */ + fs->cfa_data.offset.atom = DW_OP_bregx; + fs->cfa_data.offset.offset = 0; + continue; + + case DW_CFA_def_cfa_register: + get_uleb128 (regno, program, end); + require_cfa_offset (); + fs->cfa_val_reg = regno; + continue; + + case DW_CFA_def_cfa_sf: + get_uleb128 (operand, program, end); + cfi_assert (program < end); + get_sleb128 (sf_offset, program, end); + offset = sf_offset * cie->data_alignment_factor; + goto def_cfa; + + case DW_CFA_def_cfa_offset: + get_uleb128 (offset, program, end); + def_cfa_offset: + require_cfa_offset (); + fs->cfa_val_offset = offset; + continue; + + case DW_CFA_def_cfa_offset_sf: + get_sleb128 (sf_offset, program, end); + offset = sf_offset * cie->data_alignment_factor; + goto def_cfa_offset; + + case DW_CFA_def_cfa_expression: + /* DW_FORM_block is a ULEB128 length followed by that many bytes. */ + get_uleb128 (operand, program, end); + cfi_assert (operand <= (Dwarf_Word) (end - program)); + fs->cfa_rule = cfa_expr; + fs->cfa_data.expr.data = (unsigned char *) program; + fs->cfa_data.expr.length = operand; + program += operand; + continue; + + case DW_CFA_undefined: + get_uleb128 (regno, program, end); + register_rule (regno, undefined, 0); + continue; + + case DW_CFA_same_value: + get_uleb128 (regno, program, end); + register_rule (regno, same_value, 0); + continue; + + case DW_CFA_offset_extended: + get_uleb128 (operand, program, end); + cfi_assert (program < end); + case DW_CFA_offset + 0 ... DW_CFA_offset + CFI_PRIMARY_MAX: + get_uleb128 (offset, program, end); + offset *= cie->data_alignment_factor; + offset_extended: + register_rule (operand, offset, offset); + continue; + + case DW_CFA_offset_extended_sf: + get_uleb128 (operand, program, end); + get_sleb128 (sf_offset, program, end); + offset_extended_sf: + offset = sf_offset * cie->data_alignment_factor; + goto offset_extended; + + case DW_CFA_GNU_negative_offset_extended: + /* GNU extension obsoleted by DW_CFA_offset_extended_sf. */ + get_uleb128 (operand, program, end); + cfi_assert (program < end); + get_uleb128 (offset, program, end); + sf_offset = -offset; + goto offset_extended_sf; + + case DW_CFA_val_offset: + get_uleb128 (operand, program, end); + cfi_assert (program < end); + get_uleb128 (offset, program, end); + offset *= cie->data_alignment_factor; + val_offset: + register_rule (operand, val_offset, offset); + continue; + + case DW_CFA_val_offset_sf: + get_uleb128 (operand, program, end); + cfi_assert (program < end); + get_sleb128 (sf_offset, program, end); + offset = sf_offset * cie->data_alignment_factor; + goto val_offset; + + case DW_CFA_register: + get_uleb128 (regno, program, end); + cfi_assert (program < end); + get_uleb128 (operand, program, end); + register_rule (regno, register, operand); + continue; + + case DW_CFA_expression: + /* Expression rule relies on section data, abi_cfi cannot use it. */ + assert (! abi_cfi); + get_uleb128 (regno, program, end); + offset = program - (const uint8_t *) cache->data->d.d_buf; + /* DW_FORM_block is a ULEB128 length followed by that many bytes. */ + cfi_assert (program < end); + get_uleb128 (operand, program, end); + cfi_assert (operand <= (Dwarf_Word) (end - program)); + program += operand; + register_rule (regno, expression, offset); + continue; + + case DW_CFA_val_expression: + /* Expression rule relies on section data, abi_cfi cannot use it. */ + assert (! abi_cfi); + get_uleb128 (regno, program, end); + /* DW_FORM_block is a ULEB128 length followed by that many bytes. */ + offset = program - (const uint8_t *) cache->data->d.d_buf; + get_uleb128 (operand, program, end); + cfi_assert (operand <= (Dwarf_Word) (end - program)); + program += operand; + register_rule (regno, val_expression, offset); + continue; + + case DW_CFA_restore_extended: + get_uleb128 (operand, program, end); + case DW_CFA_restore + 0 ... DW_CFA_restore + CFI_PRIMARY_MAX: + + if (unlikely (abi_cfi) && likely (opcode == DW_CFA_restore)) + { + /* Special case hack to give backend abi_cfi a shorthand. */ + cache->default_same_value = true; + continue; + } + + /* This can't be used in the CIE's own initial instructions. */ + cfi_assert (cie->initial_state != NULL); + + /* Restore the CIE's initial rule for this register. */ + if (unlikely (! enough_registers (operand))) + goto out; + if (cie->initial_state->nregs > operand) + fs->regs[operand] = cie->initial_state->regs[operand]; + else + fs->regs[operand].rule = reg_unspecified; + continue; + + case DW_CFA_remember_state: + { + /* Duplicate the state and chain the copy on. */ + Dwarf_Frame *copy = duplicate_frame_state (fs, fs); + if (unlikely (copy == NULL)) + { + result = DWARF_E_NOMEM; + goto out; + } + fs = copy; + continue; + } + + case DW_CFA_restore_state: + { + /* Pop the current state off and use the old one instead. */ + Dwarf_Frame *prev = fs->prev; + cfi_assert (prev != NULL); + free (fs); + fs = prev; + continue; + } + + case DW_CFA_nop: + continue; + + case DW_CFA_GNU_window_save: + /* This is magic shorthand used only by SPARC. It's equivalent + to a bunch of DW_CFA_register and DW_CFA_offset operations. */ + if (unlikely (! enough_registers (31))) + goto out; + for (regno = 8; regno < 16; ++regno) + { + /* Find each %oN in %iN. */ + fs->regs[regno].rule = reg_register; + fs->regs[regno].value = regno + 16; + } + unsigned int address_size = (cache->e_ident[EI_CLASS] == ELFCLASS32 + ? 4 : 8); + for (; regno < 32; ++regno) + { + /* Find %l0..%l7 and %i0..%i7 in a block at the CFA. */ + fs->regs[regno].rule = reg_offset; + fs->regs[regno].value = (regno - 16) * address_size; + } + continue; + + case DW_CFA_GNU_args_size: + /* XXX is this useful for anything? */ + get_uleb128 (operand, program, end); + continue; + + default: + cfi_assert (false); + continue; + } + + /* We get here only for the cases that have just moved LOC. */ + cfi_assert (cie->initial_state != NULL); + if (find_pc >= loc) + /* This advance has not yet reached FIND_PC. */ + fs->start = loc; + else + { + /* We have just advanced past the address we're looking for. + The state currently described is what we want to see. */ + fs->end = loc; + break; + } + } + + /* "The end of the instruction stream can be thought of as a + DW_CFA_set_loc (initial_location + address_range) instruction." + (DWARF 3.0 Section 6.4.3) + + When we fall off the end of the program without an advance_loc/set_loc + that put us past FIND_PC, the final state left by the FDE program + applies to this address (the caller ensured it was inside the FDE). + This address (FDE->end) is already in FS->end as set by the caller. */ + +#undef register_rule +#undef cfi_assert + + out: + + /* Pop any remembered states left on the stack. */ + while (fs->prev != NULL) + { + Dwarf_Frame *prev = fs->prev; + fs->prev = prev->prev; + free (prev); + } + + if (likely (result == DWARF_E_NOERROR)) + *state = fs; + else + free (fs); + + return result; +} + +static int +cie_cache_initial_state (Dwarf_CFI *cache, struct dwarf_cie *cie) +{ + int result = DWARF_E_NOERROR; + + if (likely (cie->initial_state != NULL)) + return result; + + /* This CIE has not been used before. Play out its initial + instructions and cache the initial state that results. + First we'll let the backend fill in the default initial + state for this machine's ABI. */ + + Dwarf_CIE abi_info = { DW_CIE_ID_64, NULL, NULL, 1, 1, -1, "", NULL, 0, 0 }; + + /* Make sure we have a backend handle cached. */ + if (unlikely (cache->ebl == NULL)) + { + cache->ebl = ebl_openbackend (cache->data->s->elf); + if (unlikely (cache->ebl == NULL)) + cache->ebl = (void *) -1l; + } + + /* Fetch the ABI's default CFI program. */ + if (likely (cache->ebl != (void *) -1l) + && unlikely (ebl_abi_cfi (cache->ebl, &abi_info) < 0)) + return DWARF_E_UNKNOWN_ERROR; + + Dwarf_Frame *cie_fs = calloc (1, sizeof (Dwarf_Frame)); + if (unlikely (cie_fs == NULL)) + return DWARF_E_NOMEM; + + /* If the default state of any register is not "undefined" + (i.e. call-clobbered), then the backend supplies instructions + for the standard initial state. */ + if (abi_info.initial_instructions_end > abi_info.initial_instructions) + { + /* Dummy CIE for backend's instructions. */ + struct dwarf_cie abi_cie = + { + .code_alignment_factor = abi_info.code_alignment_factor, + .data_alignment_factor = abi_info.data_alignment_factor, + }; + result = execute_cfi (cache, &abi_cie, &cie_fs, + abi_info.initial_instructions, + abi_info.initial_instructions_end, true, + 0, (Dwarf_Addr) -1l); + } + + /* Now run the CIE's initial instructions. */ + if (cie->initial_instructions_end > cie->initial_instructions + && likely (result == DWARF_E_NOERROR)) + result = execute_cfi (cache, cie, &cie_fs, + cie->initial_instructions, + cie->initial_instructions_end, false, + 0, (Dwarf_Addr) -1l); + + if (likely (result == DWARF_E_NOERROR)) + { + /* Now we have the initial state of things that all + FDEs using this CIE will start from. */ + cie_fs->cache = cache; + cie->initial_state = cie_fs; + } + + return result; +} + +int +internal_function +__libdw_frame_at_address (Dwarf_CFI *cache, struct dwarf_fde *fde, + Dwarf_Addr address, Dwarf_Frame **frame) +{ + int result = cie_cache_initial_state (cache, fde->cie); + if (likely (result == DWARF_E_NOERROR)) + { + Dwarf_Frame *fs = duplicate_frame_state (fde->cie->initial_state, NULL); + if (unlikely (fs == NULL)) + return DWARF_E_NOMEM; + + fs->fde = fde; + fs->start = fde->start; + fs->end = fde->end; + + result = execute_cfi (cache, fde->cie, &fs, + fde->instructions, fde->instructions_end, false, + fde->start, address); + if (likely (result == DWARF_E_NOERROR)) + *frame = fs; + } + return result; +} diff --git a/3rdparty/elfutils/libdw/cfi.h b/3rdparty/elfutils/libdw/cfi.h new file mode 100644 index 0000000..98ac6cf --- /dev/null +++ b/3rdparty/elfutils/libdw/cfi.h @@ -0,0 +1,235 @@ +/* Internal definitions for libdw CFI interpreter. + Copyright (C) 2009-2010, 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifndef _UNWINDP_H +#define _UNWINDP_H 1 + +#include "libdwP.h" +#include "libelfP.h" +struct ebl; + +/* Cached CIE representation. */ +struct dwarf_cie +{ + Dwarf_Off offset; /* Our position, as seen in FDEs' CIE_pointer. */ + + Dwarf_Word code_alignment_factor; + Dwarf_Sword data_alignment_factor; + Dwarf_Word return_address_register; + + size_t fde_augmentation_data_size; + + // play out to initial state + const uint8_t *initial_instructions; + const uint8_t *initial_instructions_end; + + const Dwarf_Frame *initial_state; + + uint8_t fde_encoding; /* DW_EH_PE_* for addresses in FDEs. */ + uint8_t lsda_encoding; /* DW_EH_PE_* for LSDA in FDE augmentation. */ + + bool sized_augmentation_data; /* Saw 'z': FDEs have self-sized data. */ + bool signal_frame; /* Saw 'S': FDE is for a signal frame. */ +}; + +/* Cached FDE representation. */ +struct dwarf_fde +{ + struct dwarf_cie *cie; + + /* This FDE describes PC values in [start, end). */ + Dwarf_Addr start; + Dwarf_Addr end; + + const uint8_t *instructions; + const uint8_t *instructions_end; +}; + +/* This holds everything we cache about the CFI from each ELF file's + .debug_frame or .eh_frame section. */ +struct Dwarf_CFI_s +{ + /* Dwarf handle we came from. If null, this is .eh_frame data. */ + Dwarf *dbg; +#define CFI_IS_EH(cfi) ((cfi)->dbg == NULL) + + /* Data of the .debug_frame or .eh_frame section. */ + Elf_Data_Scn *data; + const unsigned char *e_ident; /* For EI_DATA and EI_CLASS. */ + + Dwarf_Addr frame_vaddr; /* DW_EH_PE_pcrel, address of frame section. */ + Dwarf_Addr textrel; /* DW_EH_PE_textrel base address. */ + Dwarf_Addr datarel; /* DW_EH_PE_datarel base address. */ + + /* Location of next unread entry in the section. */ + Dwarf_Off next_offset; + + /* Search tree for the CIEs, indexed by CIE_pointer (section offset). */ + void *cie_tree; + + /* Search tree for the FDEs, indexed by PC address. */ + void *fde_tree; + + /* Search tree for parsed DWARF expressions, indexed by raw pointer. */ + void *expr_tree; + + /* Backend hook. */ + struct ebl *ebl; + + /* Binary search table in .eh_frame_hdr section. */ + const uint8_t *search_table; + Dwarf_Addr search_table_vaddr; + size_t search_table_entries; + uint8_t search_table_encoding; + + /* True if the file has a byte order different from the host. */ + bool other_byte_order; + + /* Default rule for registers not previously mentioned + is same_value, not undefined. */ + bool default_same_value; +}; + + +enum dwarf_frame_rule + { + reg_unspecified, /* Uninitialized state. */ + reg_undefined, /* DW_CFA_undefined */ + reg_same_value, /* DW_CFA_same_value */ + reg_offset, /* DW_CFA_offset_extended et al */ + reg_val_offset, /* DW_CFA_val_offset et al */ + reg_register, /* DW_CFA_register */ + reg_expression, /* DW_CFA_expression */ + reg_val_expression, /* DW_CFA_val_expression */ + }; + +/* This describes what we know about an individual register. */ +struct dwarf_frame_register +{ + enum dwarf_frame_rule rule:3; + + /* The meaning of the value bits depends on the rule: + + Rule Value + ---- ----- + undefined unused + same_value unused + offset(N) N (register saved at CFA + value) + val_offset(N) N (register = CFA + value) + register(R) R (register = register #value) + expression(E) section offset of DW_FORM_block containing E + (register saved at address E computes) + val_expression(E) section offset of DW_FORM_block containing E + (register = value E computes) + */ + Dwarf_Sword value:(sizeof (Dwarf_Sword) * 8 - 3); +}; + +/* This holds instructions for unwinding frame at a particular PC location + described by an FDE. */ +struct Dwarf_Frame_s +{ + /* This frame description covers PC values in [start, end). */ + Dwarf_Addr start; + Dwarf_Addr end; + + Dwarf_CFI *cache; + + /* Previous state saved by DW_CFA_remember_state, or .cie->initial_state, + or NULL in an initial_state pseudo-frame. */ + Dwarf_Frame *prev; + + /* The FDE that generated this frame state. This points to its CIE, + which has the return_address_register and signal_frame flag. */ + struct dwarf_fde *fde; + + /* The CFA is unknown, is R+N, or is computed by a DWARF expression. + A bogon in the CFI can indicate an invalid/incalculable rule. + We store that as cfa_invalid rather than barfing when processing it, + so callers can ignore the bogon unless they really need that CFA. */ + enum { cfa_undefined, cfa_offset, cfa_expr, cfa_invalid } cfa_rule; + union + { + Dwarf_Op offset; + Dwarf_Block expr; + } cfa_data; + /* We store an offset rule as a DW_OP_bregx operation. */ +#define cfa_val_reg cfa_data.offset.number +#define cfa_val_offset cfa_data.offset.number2 + + size_t nregs; + struct dwarf_frame_register regs[]; +}; + + +/* Clean up the data structure and all it points to. */ +extern void __libdw_destroy_frame_cache (Dwarf_CFI *cache) + __nonnull_attribute__ (1) internal_function; + +/* Enter a CIE encountered while reading through for FDEs. */ +extern void __libdw_intern_cie (Dwarf_CFI *cache, Dwarf_Off offset, + const Dwarf_CIE *info) + __nonnull_attribute__ (1, 3) internal_function; + +/* Look up a CIE_pointer for random access. */ +extern struct dwarf_cie *__libdw_find_cie (Dwarf_CFI *cache, Dwarf_Off offset) + __nonnull_attribute__ (1) internal_function; + + +/* Look for an FDE covering the given PC address. */ +extern struct dwarf_fde *__libdw_find_fde (Dwarf_CFI *cache, + Dwarf_Addr address) + __nonnull_attribute__ (1) internal_function; + +/* Look for an FDE by its offset in the section. */ +extern struct dwarf_fde *__libdw_fde_by_offset (Dwarf_CFI *cache, + Dwarf_Off offset) + __nonnull_attribute__ (1) internal_function; + +/* Process the FDE that contains the given PC address, + to yield the frame state when stopped there. + The return value is a DWARF_E_* error code. */ +extern int __libdw_frame_at_address (Dwarf_CFI *cache, struct dwarf_fde *fde, + Dwarf_Addr address, Dwarf_Frame **frame) + __nonnull_attribute__ (1, 2, 4) internal_function; + + +/* Dummy struct for memory-access.h macros. */ +#define BYTE_ORDER_DUMMY(var, e_ident) \ + const struct { bool other_byte_order; } var = \ + { ((BYTE_ORDER == LITTLE_ENDIAN && e_ident[EI_DATA] == ELFDATA2MSB) \ + || (BYTE_ORDER == BIG_ENDIAN && e_ident[EI_DATA] == ELFDATA2LSB)) } + + +INTDECL (dwarf_next_cfi) +INTDECL (dwarf_getcfi) +INTDECL (dwarf_getcfi_elf) +INTDECL (dwarf_cfi_end) +INTDECL (dwarf_cfi_addrframe) + +#endif /* unwindP.h */ diff --git a/3rdparty/elfutils/libdw/cie.c b/3rdparty/elfutils/libdw/cie.c new file mode 100644 index 0000000..1b0aae7 --- /dev/null +++ b/3rdparty/elfutils/libdw/cie.c @@ -0,0 +1,196 @@ +/* CIE reading. + Copyright (C) 2009-2010 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "cfi.h" +#include "encoded-value.h" +#include <assert.h> +#include <search.h> +#include <stdlib.h> + + +static int +compare_cie (const void *a, const void *b) +{ + const struct dwarf_cie *cie1 = a; + const struct dwarf_cie *cie2 = b; + if (cie1->offset < cie2->offset) + return -1; + if (cie1->offset > cie2->offset) + return 1; + return 0; +} + +/* There is no CIE at OFFSET in the tree. Add it. */ +static struct dwarf_cie * +intern_new_cie (Dwarf_CFI *cache, Dwarf_Off offset, const Dwarf_CIE *info) +{ + struct dwarf_cie *cie = malloc (sizeof (struct dwarf_cie)); + if (cie == NULL) + { + __libdw_seterrno (DWARF_E_NOMEM); + return NULL; + } + + cie->offset = offset; + cie->code_alignment_factor = info->code_alignment_factor; + cie->data_alignment_factor = info->data_alignment_factor; + cie->return_address_register = info->return_address_register; + + cie->fde_augmentation_data_size = 0; + cie->sized_augmentation_data = false; + cie->signal_frame = false; + + cie->fde_encoding = DW_EH_PE_absptr; + cie->lsda_encoding = DW_EH_PE_omit; + + /* Grok the augmentation string and its data. */ + const uint8_t *data = info->augmentation_data; + for (const char *ap = info->augmentation; *ap != '\0'; ++ap) + { + uint8_t encoding; + switch (*ap) + { + case 'z': + cie->sized_augmentation_data = true; + continue; + + case 'S': + cie->signal_frame = true; + continue; + + case 'L': /* LSDA pointer encoding byte. */ + cie->lsda_encoding = *data++; + if (!cie->sized_augmentation_data) + cie->fde_augmentation_data_size + += encoded_value_size (&cache->data->d, cache->e_ident, + cie->lsda_encoding, NULL); + continue; + + case 'R': /* FDE address encoding byte. */ + cie->fde_encoding = *data++; + continue; + + case 'P': /* Skip personality routine. */ + encoding = *data++; + data += encoded_value_size (&cache->data->d, cache->e_ident, + encoding, data); + continue; + + default: + /* Unknown augmentation string. If we have 'z' we can ignore it, + otherwise we must bail out. */ + if (cie->sized_augmentation_data) + continue; + } + /* We only get here when we need to bail out. */ + break; + } + + if ((cie->fde_encoding & 0x0f) == DW_EH_PE_absptr) + { + /* Canonicalize encoding to a specific size. */ + assert (DW_EH_PE_absptr == 0); + + /* XXX should get from dwarf_next_cfi with v4 header. */ + uint_fast8_t address_size + = cache->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8; + switch (address_size) + { + case 8: + cie->fde_encoding |= DW_EH_PE_udata8; + break; + case 4: + cie->fde_encoding |= DW_EH_PE_udata4; + break; + default: + free (cie); + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; + } + } + + /* Save the initial instructions to be played out into initial state. */ + cie->initial_instructions = info->initial_instructions; + cie->initial_instructions_end = info->initial_instructions_end; + cie->initial_state = NULL; + + /* Add the new entry to the search tree. */ + if (tsearch (cie, &cache->cie_tree, &compare_cie) == NULL) + { + free (cie); + __libdw_seterrno (DWARF_E_NOMEM); + return NULL; + } + + return cie; +} + +/* Look up a CIE_pointer for random access. */ +struct dwarf_cie * +internal_function +__libdw_find_cie (Dwarf_CFI *cache, Dwarf_Off offset) +{ + const struct dwarf_cie cie_key = { .offset = offset }; + struct dwarf_cie **found = tfind (&cie_key, &cache->cie_tree, &compare_cie); + if (found != NULL) + return *found; + + /* We have not read this CIE yet. Go find it. */ + Dwarf_Off next_offset = offset; + Dwarf_CFI_Entry entry; + int result = INTUSE(dwarf_next_cfi) (cache->e_ident, + &cache->data->d, CFI_IS_EH (cache), + offset, &next_offset, &entry); + if (result != 0 || entry.cie.CIE_id != DW_CIE_ID_64) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; + } + + /* If this happened to be what we would have read next, notice it. */ + if (cache->next_offset == offset) + cache->next_offset = next_offset; + + return intern_new_cie (cache, offset, &entry.cie); +} + +/* Enter a CIE encountered while reading through for FDEs. */ +void +internal_function +__libdw_intern_cie (Dwarf_CFI *cache, Dwarf_Off offset, const Dwarf_CIE *info) +{ + const struct dwarf_cie cie_key = { .offset = offset }; + struct dwarf_cie **found = tfind (&cie_key, &cache->cie_tree, &compare_cie); + if (found == NULL) + /* We have not read this CIE yet. Enter it. */ + (void) intern_new_cie (cache, offset, info); +} diff --git a/3rdparty/elfutils/libdw/dwarf.h b/3rdparty/elfutils/libdw/dwarf.h new file mode 100644 index 0000000..da8cf3a --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf.h @@ -0,0 +1,798 @@ +/* This file defines standard DWARF types, structures, and macros. + Copyright (C) 2000-2011, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifndef _DWARF_H +#define _DWARF_H 1 + +/* DWARF tags. */ +enum + { + DW_TAG_array_type = 0x01, + DW_TAG_class_type = 0x02, + DW_TAG_entry_point = 0x03, + DW_TAG_enumeration_type = 0x04, + DW_TAG_formal_parameter = 0x05, + DW_TAG_imported_declaration = 0x08, + DW_TAG_label = 0x0a, + DW_TAG_lexical_block = 0x0b, + DW_TAG_member = 0x0d, + DW_TAG_pointer_type = 0x0f, + DW_TAG_reference_type = 0x10, + DW_TAG_compile_unit = 0x11, + DW_TAG_string_type = 0x12, + DW_TAG_structure_type = 0x13, + DW_TAG_subroutine_type = 0x15, + DW_TAG_typedef = 0x16, + DW_TAG_union_type = 0x17, + DW_TAG_unspecified_parameters = 0x18, + DW_TAG_variant = 0x19, + DW_TAG_common_block = 0x1a, + DW_TAG_common_inclusion = 0x1b, + DW_TAG_inheritance = 0x1c, + DW_TAG_inlined_subroutine = 0x1d, + DW_TAG_module = 0x1e, + DW_TAG_ptr_to_member_type = 0x1f, + DW_TAG_set_type = 0x20, + DW_TAG_subrange_type = 0x21, + DW_TAG_with_stmt = 0x22, + DW_TAG_access_declaration = 0x23, + DW_TAG_base_type = 0x24, + DW_TAG_catch_block = 0x25, + DW_TAG_const_type = 0x26, + DW_TAG_constant = 0x27, + DW_TAG_enumerator = 0x28, + DW_TAG_file_type = 0x29, + DW_TAG_friend = 0x2a, + DW_TAG_namelist = 0x2b, + DW_TAG_namelist_item = 0x2c, + DW_TAG_packed_type = 0x2d, + DW_TAG_subprogram = 0x2e, + DW_TAG_template_type_parameter = 0x2f, + DW_TAG_template_value_parameter = 0x30, + DW_TAG_thrown_type = 0x31, + DW_TAG_try_block = 0x32, + DW_TAG_variant_part = 0x33, + DW_TAG_variable = 0x34, + DW_TAG_volatile_type = 0x35, + DW_TAG_dwarf_procedure = 0x36, + DW_TAG_restrict_type = 0x37, + DW_TAG_interface_type = 0x38, + DW_TAG_namespace = 0x39, + DW_TAG_imported_module = 0x3a, + DW_TAG_unspecified_type = 0x3b, + DW_TAG_partial_unit = 0x3c, + DW_TAG_imported_unit = 0x3d, + /* 0x3e reserved. */ + DW_TAG_condition = 0x3f, + DW_TAG_shared_type = 0x40, + DW_TAG_type_unit = 0x41, + DW_TAG_rvalue_reference_type = 0x42, + DW_TAG_template_alias = 0x43, + + DW_TAG_lo_user = 0x4080, + + DW_TAG_MIPS_loop = 0x4081, + DW_TAG_format_label = 0x4101, + DW_TAG_function_template = 0x4102, + DW_TAG_class_template = 0x4103, + + DW_TAG_GNU_BINCL = 0x4104, + DW_TAG_GNU_EINCL = 0x4105, + + DW_TAG_GNU_template_template_param = 0x4106, + DW_TAG_GNU_template_parameter_pack = 0x4107, + DW_TAG_GNU_formal_parameter_pack = 0x4108, + DW_TAG_GNU_call_site = 0x4109, + DW_TAG_GNU_call_site_parameter = 0x410a, + + DW_TAG_hi_user = 0xffff + }; + + +/* Children determination encodings. */ +enum + { + DW_CHILDREN_no = 0, + DW_CHILDREN_yes = 1 + }; + + +/* DWARF attributes encodings. */ +enum + { + DW_AT_sibling = 0x01, + DW_AT_location = 0x02, + DW_AT_name = 0x03, + DW_AT_ordering = 0x09, + DW_AT_subscr_data = 0x0a, + DW_AT_byte_size = 0x0b, + DW_AT_bit_offset = 0x0c, + DW_AT_bit_size = 0x0d, + DW_AT_element_list = 0x0f, + DW_AT_stmt_list = 0x10, + DW_AT_low_pc = 0x11, + DW_AT_high_pc = 0x12, + DW_AT_language = 0x13, + DW_AT_member = 0x14, + DW_AT_discr = 0x15, + DW_AT_discr_value = 0x16, + DW_AT_visibility = 0x17, + DW_AT_import = 0x18, + DW_AT_string_length = 0x19, + DW_AT_common_reference = 0x1a, + DW_AT_comp_dir = 0x1b, + DW_AT_const_value = 0x1c, + DW_AT_containing_type = 0x1d, + DW_AT_default_value = 0x1e, + DW_AT_inline = 0x20, + DW_AT_is_optional = 0x21, + DW_AT_lower_bound = 0x22, + DW_AT_producer = 0x25, + DW_AT_prototyped = 0x27, + DW_AT_return_addr = 0x2a, + DW_AT_start_scope = 0x2c, + DW_AT_bit_stride = 0x2e, + DW_AT_upper_bound = 0x2f, + DW_AT_abstract_origin = 0x31, + DW_AT_accessibility = 0x32, + DW_AT_address_class = 0x33, + DW_AT_artificial = 0x34, + DW_AT_base_types = 0x35, + DW_AT_calling_convention = 0x36, + DW_AT_count = 0x37, + DW_AT_data_member_location = 0x38, + DW_AT_decl_column = 0x39, + DW_AT_decl_file = 0x3a, + DW_AT_decl_line = 0x3b, + DW_AT_declaration = 0x3c, + DW_AT_discr_list = 0x3d, + DW_AT_encoding = 0x3e, + DW_AT_external = 0x3f, + DW_AT_frame_base = 0x40, + DW_AT_friend = 0x41, + DW_AT_identifier_case = 0x42, + DW_AT_macro_info = 0x43, + DW_AT_namelist_item = 0x44, + DW_AT_priority = 0x45, + DW_AT_segment = 0x46, + DW_AT_specification = 0x47, + DW_AT_static_link = 0x48, + DW_AT_type = 0x49, + DW_AT_use_location = 0x4a, + DW_AT_variable_parameter = 0x4b, + DW_AT_virtuality = 0x4c, + DW_AT_vtable_elem_location = 0x4d, + DW_AT_allocated = 0x4e, + DW_AT_associated = 0x4f, + DW_AT_data_location = 0x50, + DW_AT_byte_stride = 0x51, + DW_AT_entry_pc = 0x52, + DW_AT_use_UTF8 = 0x53, + DW_AT_extension = 0x54, + DW_AT_ranges = 0x55, + DW_AT_trampoline = 0x56, + DW_AT_call_column = 0x57, + DW_AT_call_file = 0x58, + DW_AT_call_line = 0x59, + DW_AT_description = 0x5a, + DW_AT_binary_scale = 0x5b, + DW_AT_decimal_scale = 0x5c, + DW_AT_small = 0x5d, + DW_AT_decimal_sign = 0x5e, + DW_AT_digit_count = 0x5f, + DW_AT_picture_string = 0x60, + DW_AT_mutable = 0x61, + DW_AT_threads_scaled = 0x62, + DW_AT_explicit = 0x63, + DW_AT_object_pointer = 0x64, + DW_AT_endianity = 0x65, + DW_AT_elemental = 0x66, + DW_AT_pure = 0x67, + DW_AT_recursive = 0x68, + DW_AT_signature = 0x69, + DW_AT_main_subprogram = 0x6a, + DW_AT_data_bit_offset = 0x6b, + DW_AT_const_expr = 0x6c, + DW_AT_enum_class = 0x6d, + DW_AT_linkage_name = 0x6e, + + /* DWARF5 attribute values. */ + DW_AT_noreturn = 0x87, + + DW_AT_lo_user = 0x2000, + + DW_AT_MIPS_fde = 0x2001, + DW_AT_MIPS_loop_begin = 0x2002, + DW_AT_MIPS_tail_loop_begin = 0x2003, + DW_AT_MIPS_epilog_begin = 0x2004, + DW_AT_MIPS_loop_unroll_factor = 0x2005, + DW_AT_MIPS_software_pipeline_depth = 0x2006, + DW_AT_MIPS_linkage_name = 0x2007, + DW_AT_MIPS_stride = 0x2008, + DW_AT_MIPS_abstract_name = 0x2009, + DW_AT_MIPS_clone_origin = 0x200a, + DW_AT_MIPS_has_inlines = 0x200b, + DW_AT_MIPS_stride_byte = 0x200c, + DW_AT_MIPS_stride_elem = 0x200d, + DW_AT_MIPS_ptr_dopetype = 0x200e, + DW_AT_MIPS_allocatable_dopetype = 0x200f, + DW_AT_MIPS_assumed_shape_dopetype = 0x2010, + DW_AT_MIPS_assumed_size = 0x2011, + + /* GNU extensions. */ + DW_AT_sf_names = 0x2101, + DW_AT_src_info = 0x2102, + DW_AT_mac_info = 0x2103, + DW_AT_src_coords = 0x2104, + DW_AT_body_begin = 0x2105, + DW_AT_body_end = 0x2106, + DW_AT_GNU_vector = 0x2107, + DW_AT_GNU_guarded_by = 0x2108, + DW_AT_GNU_pt_guarded_by = 0x2109, + DW_AT_GNU_guarded = 0x210a, + DW_AT_GNU_pt_guarded = 0x210b, + DW_AT_GNU_locks_excluded = 0x210c, + DW_AT_GNU_exclusive_locks_required = 0x210d, + DW_AT_GNU_shared_locks_required = 0x210e, + DW_AT_GNU_odr_signature = 0x210f, + DW_AT_GNU_template_name = 0x2110, + DW_AT_GNU_call_site_value = 0x2111, + DW_AT_GNU_call_site_data_value = 0x2112, + DW_AT_GNU_call_site_target = 0x2113, + DW_AT_GNU_call_site_target_clobbered = 0x2114, + DW_AT_GNU_tail_call = 0x2115, + DW_AT_GNU_all_tail_call_sites = 0x2116, + DW_AT_GNU_all_call_sites = 0x2117, + DW_AT_GNU_all_source_call_sites = 0x2118, + DW_AT_GNU_macros = 0x2119, + DW_AT_GNU_deleted = 0x211a, + + DW_AT_hi_user = 0x3fff + }; + + +/* DWARF form encodings. */ +enum + { + DW_FORM_addr = 0x01, + DW_FORM_block2 = 0x03, + DW_FORM_block4 = 0x04, + DW_FORM_data2 = 0x05, + DW_FORM_data4 = 0x06, + DW_FORM_data8 = 0x07, + DW_FORM_string = 0x08, + DW_FORM_block = 0x09, + DW_FORM_block1 = 0x0a, + DW_FORM_data1 = 0x0b, + DW_FORM_flag = 0x0c, + DW_FORM_sdata = 0x0d, + DW_FORM_strp = 0x0e, + DW_FORM_udata = 0x0f, + DW_FORM_ref_addr = 0x10, + DW_FORM_ref1 = 0x11, + DW_FORM_ref2 = 0x12, + DW_FORM_ref4 = 0x13, + DW_FORM_ref8 = 0x14, + DW_FORM_ref_udata = 0x15, + DW_FORM_indirect = 0x16, + DW_FORM_sec_offset = 0x17, + DW_FORM_exprloc = 0x18, + DW_FORM_flag_present = 0x19, + DW_FORM_ref_sig8 = 0x20, + + DW_FORM_GNU_ref_alt = 0x1f20, /* offset in alternate .debuginfo. */ + DW_FORM_GNU_strp_alt = 0x1f21 /* offset in alternate .debug_str. */ + }; + + +/* DWARF location operation encodings. */ +enum + { + DW_OP_addr = 0x03, /* Constant address. */ + DW_OP_deref = 0x06, + DW_OP_const1u = 0x08, /* Unsigned 1-byte constant. */ + DW_OP_const1s = 0x09, /* Signed 1-byte constant. */ + DW_OP_const2u = 0x0a, /* Unsigned 2-byte constant. */ + DW_OP_const2s = 0x0b, /* Signed 2-byte constant. */ + DW_OP_const4u = 0x0c, /* Unsigned 4-byte constant. */ + DW_OP_const4s = 0x0d, /* Signed 4-byte constant. */ + DW_OP_const8u = 0x0e, /* Unsigned 8-byte constant. */ + DW_OP_const8s = 0x0f, /* Signed 8-byte constant. */ + DW_OP_constu = 0x10, /* Unsigned LEB128 constant. */ + DW_OP_consts = 0x11, /* Signed LEB128 constant. */ + DW_OP_dup = 0x12, + DW_OP_drop = 0x13, + DW_OP_over = 0x14, + DW_OP_pick = 0x15, /* 1-byte stack index. */ + DW_OP_swap = 0x16, + DW_OP_rot = 0x17, + DW_OP_xderef = 0x18, + DW_OP_abs = 0x19, + DW_OP_and = 0x1a, + DW_OP_div = 0x1b, + DW_OP_minus = 0x1c, + DW_OP_mod = 0x1d, + DW_OP_mul = 0x1e, + DW_OP_neg = 0x1f, + DW_OP_not = 0x20, + DW_OP_or = 0x21, + DW_OP_plus = 0x22, + DW_OP_plus_uconst = 0x23, /* Unsigned LEB128 addend. */ + DW_OP_shl = 0x24, + DW_OP_shr = 0x25, + DW_OP_shra = 0x26, + DW_OP_xor = 0x27, + DW_OP_bra = 0x28, /* Signed 2-byte constant. */ + DW_OP_eq = 0x29, + DW_OP_ge = 0x2a, + DW_OP_gt = 0x2b, + DW_OP_le = 0x2c, + DW_OP_lt = 0x2d, + DW_OP_ne = 0x2e, + DW_OP_skip = 0x2f, /* Signed 2-byte constant. */ + DW_OP_lit0 = 0x30, /* Literal 0. */ + DW_OP_lit1 = 0x31, /* Literal 1. */ + DW_OP_lit2 = 0x32, /* Literal 2. */ + DW_OP_lit3 = 0x33, /* Literal 3. */ + DW_OP_lit4 = 0x34, /* Literal 4. */ + DW_OP_lit5 = 0x35, /* Literal 5. */ + DW_OP_lit6 = 0x36, /* Literal 6. */ + DW_OP_lit7 = 0x37, /* Literal 7. */ + DW_OP_lit8 = 0x38, /* Literal 8. */ + DW_OP_lit9 = 0x39, /* Literal 9. */ + DW_OP_lit10 = 0x3a, /* Literal 10. */ + DW_OP_lit11 = 0x3b, /* Literal 11. */ + DW_OP_lit12 = 0x3c, /* Literal 12. */ + DW_OP_lit13 = 0x3d, /* Literal 13. */ + DW_OP_lit14 = 0x3e, /* Literal 14. */ + DW_OP_lit15 = 0x3f, /* Literal 15. */ + DW_OP_lit16 = 0x40, /* Literal 16. */ + DW_OP_lit17 = 0x41, /* Literal 17. */ + DW_OP_lit18 = 0x42, /* Literal 18. */ + DW_OP_lit19 = 0x43, /* Literal 19. */ + DW_OP_lit20 = 0x44, /* Literal 20. */ + DW_OP_lit21 = 0x45, /* Literal 21. */ + DW_OP_lit22 = 0x46, /* Literal 22. */ + DW_OP_lit23 = 0x47, /* Literal 23. */ + DW_OP_lit24 = 0x48, /* Literal 24. */ + DW_OP_lit25 = 0x49, /* Literal 25. */ + DW_OP_lit26 = 0x4a, /* Literal 26. */ + DW_OP_lit27 = 0x4b, /* Literal 27. */ + DW_OP_lit28 = 0x4c, /* Literal 28. */ + DW_OP_lit29 = 0x4d, /* Literal 29. */ + DW_OP_lit30 = 0x4e, /* Literal 30. */ + DW_OP_lit31 = 0x4f, /* Literal 31. */ + DW_OP_reg0 = 0x50, /* Register 0. */ + DW_OP_reg1 = 0x51, /* Register 1. */ + DW_OP_reg2 = 0x52, /* Register 2. */ + DW_OP_reg3 = 0x53, /* Register 3. */ + DW_OP_reg4 = 0x54, /* Register 4. */ + DW_OP_reg5 = 0x55, /* Register 5. */ + DW_OP_reg6 = 0x56, /* Register 6. */ + DW_OP_reg7 = 0x57, /* Register 7. */ + DW_OP_reg8 = 0x58, /* Register 8. */ + DW_OP_reg9 = 0x59, /* Register 9. */ + DW_OP_reg10 = 0x5a, /* Register 10. */ + DW_OP_reg11 = 0x5b, /* Register 11. */ + DW_OP_reg12 = 0x5c, /* Register 12. */ + DW_OP_reg13 = 0x5d, /* Register 13. */ + DW_OP_reg14 = 0x5e, /* Register 14. */ + DW_OP_reg15 = 0x5f, /* Register 15. */ + DW_OP_reg16 = 0x60, /* Register 16. */ + DW_OP_reg17 = 0x61, /* Register 17. */ + DW_OP_reg18 = 0x62, /* Register 18. */ + DW_OP_reg19 = 0x63, /* Register 19. */ + DW_OP_reg20 = 0x64, /* Register 20. */ + DW_OP_reg21 = 0x65, /* Register 21. */ + DW_OP_reg22 = 0x66, /* Register 22. */ + DW_OP_reg23 = 0x67, /* Register 24. */ + DW_OP_reg24 = 0x68, /* Register 24. */ + DW_OP_reg25 = 0x69, /* Register 25. */ + DW_OP_reg26 = 0x6a, /* Register 26. */ + DW_OP_reg27 = 0x6b, /* Register 27. */ + DW_OP_reg28 = 0x6c, /* Register 28. */ + DW_OP_reg29 = 0x6d, /* Register 29. */ + DW_OP_reg30 = 0x6e, /* Register 30. */ + DW_OP_reg31 = 0x6f, /* Register 31. */ + DW_OP_breg0 = 0x70, /* Base register 0. */ + DW_OP_breg1 = 0x71, /* Base register 1. */ + DW_OP_breg2 = 0x72, /* Base register 2. */ + DW_OP_breg3 = 0x73, /* Base register 3. */ + DW_OP_breg4 = 0x74, /* Base register 4. */ + DW_OP_breg5 = 0x75, /* Base register 5. */ + DW_OP_breg6 = 0x76, /* Base register 6. */ + DW_OP_breg7 = 0x77, /* Base register 7. */ + DW_OP_breg8 = 0x78, /* Base register 8. */ + DW_OP_breg9 = 0x79, /* Base register 9. */ + DW_OP_breg10 = 0x7a, /* Base register 10. */ + DW_OP_breg11 = 0x7b, /* Base register 11. */ + DW_OP_breg12 = 0x7c, /* Base register 12. */ + DW_OP_breg13 = 0x7d, /* Base register 13. */ + DW_OP_breg14 = 0x7e, /* Base register 14. */ + DW_OP_breg15 = 0x7f, /* Base register 15. */ + DW_OP_breg16 = 0x80, /* Base register 16. */ + DW_OP_breg17 = 0x81, /* Base register 17. */ + DW_OP_breg18 = 0x82, /* Base register 18. */ + DW_OP_breg19 = 0x83, /* Base register 19. */ + DW_OP_breg20 = 0x84, /* Base register 20. */ + DW_OP_breg21 = 0x85, /* Base register 21. */ + DW_OP_breg22 = 0x86, /* Base register 22. */ + DW_OP_breg23 = 0x87, /* Base register 23. */ + DW_OP_breg24 = 0x88, /* Base register 24. */ + DW_OP_breg25 = 0x89, /* Base register 25. */ + DW_OP_breg26 = 0x8a, /* Base register 26. */ + DW_OP_breg27 = 0x8b, /* Base register 27. */ + DW_OP_breg28 = 0x8c, /* Base register 28. */ + DW_OP_breg29 = 0x8d, /* Base register 29. */ + DW_OP_breg30 = 0x8e, /* Base register 30. */ + DW_OP_breg31 = 0x8f, /* Base register 31. */ + DW_OP_regx = 0x90, /* Unsigned LEB128 register. */ + DW_OP_fbreg = 0x91, /* Signed LEB128 offset. */ + DW_OP_bregx = 0x92, /* ULEB128 register followed by SLEB128 off. */ + DW_OP_piece = 0x93, /* ULEB128 size of piece addressed. */ + DW_OP_deref_size = 0x94, /* 1-byte size of data retrieved. */ + DW_OP_xderef_size = 0x95, /* 1-byte size of data retrieved. */ + DW_OP_nop = 0x96, + DW_OP_push_object_address = 0x97, + DW_OP_call2 = 0x98, + DW_OP_call4 = 0x99, + DW_OP_call_ref = 0x9a, + DW_OP_form_tls_address = 0x9b,/* TLS offset to address in current thread */ + DW_OP_call_frame_cfa = 0x9c,/* CFA as determined by CFI. */ + DW_OP_bit_piece = 0x9d, /* ULEB128 size and ULEB128 offset in bits. */ + DW_OP_implicit_value = 0x9e, /* DW_FORM_block follows opcode. */ + DW_OP_stack_value = 0x9f, /* No operands, special like DW_OP_piece. */ + + /* GNU extensions. */ + DW_OP_GNU_push_tls_address = 0xe0, + DW_OP_GNU_uninit = 0xf0, + DW_OP_GNU_encoded_addr = 0xf1, + DW_OP_GNU_implicit_pointer = 0xf2, + DW_OP_GNU_entry_value = 0xf3, + DW_OP_GNU_const_type = 0xf4, + DW_OP_GNU_regval_type = 0xf5, + DW_OP_GNU_deref_type = 0xf6, + DW_OP_GNU_convert = 0xf7, + DW_OP_GNU_reinterpret = 0xf9, + DW_OP_GNU_parameter_ref = 0xfa, + + DW_OP_lo_user = 0xe0, /* Implementation-defined range start. */ + DW_OP_hi_user = 0xff /* Implementation-defined range end. */ + }; + + +/* DWARF base type encodings. */ +enum + { + DW_ATE_void = 0x0, + DW_ATE_address = 0x1, + DW_ATE_boolean = 0x2, + DW_ATE_complex_float = 0x3, + DW_ATE_float = 0x4, + DW_ATE_signed = 0x5, + DW_ATE_signed_char = 0x6, + DW_ATE_unsigned = 0x7, + DW_ATE_unsigned_char = 0x8, + DW_ATE_imaginary_float = 0x9, + DW_ATE_packed_decimal = 0xa, + DW_ATE_numeric_string = 0xb, + DW_ATE_edited = 0xc, + DW_ATE_signed_fixed = 0xd, + DW_ATE_unsigned_fixed = 0xe, + DW_ATE_decimal_float = 0xf, + DW_ATE_UTF = 0x10, + + DW_ATE_lo_user = 0x80, + DW_ATE_hi_user = 0xff + }; + + +/* DWARF decimal sign encodings. */ +enum + { + DW_DS_unsigned = 1, + DW_DS_leading_overpunch = 2, + DW_DS_trailing_overpunch = 3, + DW_DS_leading_separate = 4, + DW_DS_trailing_separate = 5, + }; + + +/* DWARF endianity encodings. */ +enum + { + DW_END_default = 0, + DW_END_big = 1, + DW_END_little = 2, + + DW_END_lo_user = 0x40, + DW_END_hi_user = 0xff + }; + + +/* DWARF accessibility encodings. */ +enum + { + DW_ACCESS_public = 1, + DW_ACCESS_protected = 2, + DW_ACCESS_private = 3 + }; + + +/* DWARF visibility encodings. */ +enum + { + DW_VIS_local = 1, + DW_VIS_exported = 2, + DW_VIS_qualified = 3 + }; + + +/* DWARF virtuality encodings. */ +enum + { + DW_VIRTUALITY_none = 0, + DW_VIRTUALITY_virtual = 1, + DW_VIRTUALITY_pure_virtual = 2 + }; + + +/* DWARF language encodings. */ +enum + { + DW_LANG_C89 = 0x0001, /* ISO C:1989 */ + DW_LANG_C = 0x0002, /* C */ + DW_LANG_Ada83 = 0x0003, /* ISO Ada:1983 */ + DW_LANG_C_plus_plus = 0x0004, /* ISO C++:1998 */ + DW_LANG_Cobol74 = 0x0005, /* ISO Cobol:1974 */ + DW_LANG_Cobol85 = 0x0006, /* ISO Cobol:1985 */ + DW_LANG_Fortran77 = 0x0007, /* ISO FORTRAN 77 */ + DW_LANG_Fortran90 = 0x0008, /* ISO Fortran 90 */ + DW_LANG_Pascal83 = 0x0009, /* ISO Pascal:1983 */ + DW_LANG_Modula2 = 0x000a, /* ISO Modula-2:1996 */ + DW_LANG_Java = 0x000b, /* Java */ + DW_LANG_C99 = 0x000c, /* ISO C:1999 */ + DW_LANG_Ada95 = 0x000d, /* ISO Ada:1995 */ + DW_LANG_Fortran95 = 0x000e, /* ISO Fortran 95 */ + DW_LANG_PL1 = 0x000f, /* ISO PL/1:1976 */ + DW_LANG_ObjC = 0x0010, /* Objective-C */ + DW_LANG_ObjC_plus_plus = 0x0011, /* Objective-C++ */ + DW_LANG_UPC = 0x0012, /* Unified Parallel C */ + DW_LANG_D = 0x0013, /* D */ + DW_LANG_Python = 0x0014, /* Python */ + DW_LANG_Go = 0x0016, /* Go */ + DW_LANG_C_plus_plus_11 = 0x001a, /* ISO C++:2011 */ + DW_LANG_C11 = 0x001d, /* ISO C:2011 */ + DW_LANG_C_plus_plus_14 = 0x0021, /* ISO C++:2014 */ + + + DW_LANG_lo_user = 0x8000, + DW_LANG_Mips_Assembler = 0x8001, /* Assembler */ + DW_LANG_hi_user = 0xffff + }; + + +/* DWARF identifier case encodings. */ +enum + { + DW_ID_case_sensitive = 0, + DW_ID_up_case = 1, + DW_ID_down_case = 2, + DW_ID_case_insensitive = 3 + }; + + +/* DWARF calling conventions encodings. */ +enum + { + DW_CC_normal = 0x1, + DW_CC_program = 0x2, + DW_CC_nocall = 0x3, + DW_CC_lo_user = 0x40, + DW_CC_hi_user = 0xff + }; + + +/* DWARF inline encodings. */ +enum + { + DW_INL_not_inlined = 0, + DW_INL_inlined = 1, + DW_INL_declared_not_inlined = 2, + DW_INL_declared_inlined = 3 + }; + + +/* DWARF ordering encodings. */ +enum + { + DW_ORD_row_major = 0, + DW_ORD_col_major = 1 + }; + + +/* DWARF discriminant descriptor encodings. */ +enum + { + DW_DSC_label = 0, + DW_DSC_range = 1 + }; + + +/* DWARF standard opcode encodings. */ +enum + { + DW_LNS_copy = 1, + DW_LNS_advance_pc = 2, + DW_LNS_advance_line = 3, + DW_LNS_set_file = 4, + DW_LNS_set_column = 5, + DW_LNS_negate_stmt = 6, + DW_LNS_set_basic_block = 7, + DW_LNS_const_add_pc = 8, + DW_LNS_fixed_advance_pc = 9, + DW_LNS_set_prologue_end = 10, + DW_LNS_set_epilogue_begin = 11, + DW_LNS_set_isa = 12 + }; + + +/* DWARF extended opcode encodings. */ +enum + { + DW_LNE_end_sequence = 1, + DW_LNE_set_address = 2, + DW_LNE_define_file = 3, + DW_LNE_set_discriminator = 4, + + DW_LNE_lo_user = 128, + DW_LNE_hi_user = 255 + }; + + +/* DWARF macinfo type encodings. */ +enum + { + DW_MACINFO_define = 1, + DW_MACINFO_undef = 2, + DW_MACINFO_start_file = 3, + DW_MACINFO_end_file = 4, + DW_MACINFO_vendor_ext = 255 + }; + + +/* DWARF debug_macro type encodings. GNU/DWARF5 extension. */ +enum + { + DW_MACRO_GNU_define = 0x01, + DW_MACRO_GNU_undef = 0x02, + DW_MACRO_GNU_start_file = 0x03, + DW_MACRO_GNU_end_file = 0x04, + DW_MACRO_GNU_define_indirect = 0x05, + DW_MACRO_GNU_undef_indirect = 0x06, + DW_MACRO_GNU_transparent_include = 0x07, + DW_MACRO_GNU_lo_user = 0xe0, + DW_MACRO_GNU_hi_user = 0xff + }; + + +/* DWARF call frame instruction encodings. */ +enum + { + DW_CFA_advance_loc = 0x40, + DW_CFA_offset = 0x80, + DW_CFA_restore = 0xc0, + DW_CFA_extended = 0, + + DW_CFA_nop = 0x00, + DW_CFA_set_loc = 0x01, + DW_CFA_advance_loc1 = 0x02, + DW_CFA_advance_loc2 = 0x03, + DW_CFA_advance_loc4 = 0x04, + DW_CFA_offset_extended = 0x05, + DW_CFA_restore_extended = 0x06, + DW_CFA_undefined = 0x07, + DW_CFA_same_value = 0x08, + DW_CFA_register = 0x09, + DW_CFA_remember_state = 0x0a, + DW_CFA_restore_state = 0x0b, + DW_CFA_def_cfa = 0x0c, + DW_CFA_def_cfa_register = 0x0d, + DW_CFA_def_cfa_offset = 0x0e, + DW_CFA_def_cfa_expression = 0x0f, + DW_CFA_expression = 0x10, + DW_CFA_offset_extended_sf = 0x11, + DW_CFA_def_cfa_sf = 0x12, + DW_CFA_def_cfa_offset_sf = 0x13, + DW_CFA_val_offset = 0x14, + DW_CFA_val_offset_sf = 0x15, + DW_CFA_val_expression = 0x16, + + DW_CFA_low_user = 0x1c, + DW_CFA_MIPS_advance_loc8 = 0x1d, + DW_CFA_GNU_window_save = 0x2d, + DW_CFA_GNU_args_size = 0x2e, + DW_CFA_GNU_negative_offset_extended = 0x2f, + DW_CFA_high_user = 0x3f + }; + +/* ID indicating CIE as opposed to FDE in .debug_frame. */ +enum + { + DW_CIE_ID_32 = 0xffffffffU, /* In 32-bit format CIE header. */ + DW_CIE_ID_64 = 0xffffffffffffffffULL /* In 64-bit format CIE header. */ + }; + + +/* Information for GNU unwind information. */ +enum + { + DW_EH_PE_absptr = 0x00, + DW_EH_PE_omit = 0xff, + + /* FDE data encoding. */ + DW_EH_PE_uleb128 = 0x01, + DW_EH_PE_udata2 = 0x02, + DW_EH_PE_udata4 = 0x03, + DW_EH_PE_udata8 = 0x04, + DW_EH_PE_sleb128 = 0x09, + DW_EH_PE_sdata2 = 0x0a, + DW_EH_PE_sdata4 = 0x0b, + DW_EH_PE_sdata8 = 0x0c, + DW_EH_PE_signed = 0x08, + + /* FDE flags. */ + DW_EH_PE_pcrel = 0x10, + DW_EH_PE_textrel = 0x20, + DW_EH_PE_datarel = 0x30, + DW_EH_PE_funcrel = 0x40, + DW_EH_PE_aligned = 0x50, + + DW_EH_PE_indirect = 0x80 + }; + + +/* DWARF XXX. */ +#define DW_ADDR_none 0 + +/* Section 7.2.2 of the DWARF3 specification defines a range of escape + codes that can appear in the length field of certain DWARF structures. + + These defines enumerate the minium and maximum values of this range. + Currently only the maximum value is used (to indicate that 64-bit + values are going to be used in the dwarf data that accompanies the + structure). The other values are reserved. + + Note: There is a typo in DWARF3 spec (published Dec 20, 2005). In + sections 7.4, 7.5.1, 7.19, 7.20 the minimum escape code is referred to + as 0xffffff00 whereas in fact it should be 0xfffffff0. */ +#define DWARF3_LENGTH_MIN_ESCAPE_CODE 0xfffffff0u +#define DWARF3_LENGTH_MAX_ESCAPE_CODE 0xffffffffu +#define DWARF3_LENGTH_64_BIT DWARF3_LENGTH_MAX_ESCAPE_CODE + +#endif /* dwarf.h */ diff --git a/3rdparty/elfutils/libdw/dwarf_abbrev_hash.c b/3rdparty/elfutils/libdw/dwarf_abbrev_hash.c new file mode 100644 index 0000000..f52f5ad --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_abbrev_hash.c @@ -0,0 +1,45 @@ +/* Implementation of hash table for DWARF .debug_abbrev section content. + Copyright (C) 2000-2010 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "dwarf_sig8_hash.h" +#define NO_UNDEF +#include "libdwP.h" + +#define next_prime __libdwarf_next_prime +extern size_t next_prime (size_t) attribute_hidden; + +#include <dynamicsizehash.c> + +#undef next_prime +#define next_prime attribute_hidden __libdwarf_next_prime +#include "../lib/next_prime.c" diff --git a/3rdparty/elfutils/libdw/dwarf_abbrev_hash.h b/3rdparty/elfutils/libdw/dwarf_abbrev_hash.h new file mode 100644 index 0000000..d2f02cc --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_abbrev_hash.h @@ -0,0 +1,39 @@ +/* Hash table for DWARF .debug_abbrev section content. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifndef _DWARF_ABBREV_HASH_H +#define _DWARF_ABBREV_HASH_H 1 + +#define NAME Dwarf_Abbrev_Hash +#define TYPE Dwarf_Abbrev * +#define COMPARE(a, b) (0) + +#include <dynamicsizehash.h> + +#endif /* dwarf_abbrev_hash.h */ diff --git a/3rdparty/elfutils/libdw/dwarf_abbrevhaschildren.c b/3rdparty/elfutils/libdw/dwarf_abbrevhaschildren.c new file mode 100644 index 0000000..4a83e31 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_abbrevhaschildren.c @@ -0,0 +1,44 @@ +/* Return true if abbreviation is children flag set. + Copyright (C) 2003 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> +#include "libdwP.h" + + +int +dwarf_abbrevhaschildren (abbrev) + Dwarf_Abbrev *abbrev; +{ + return abbrev == NULL ? -1 : abbrev->has_children; +} diff --git a/3rdparty/elfutils/libdw/dwarf_addrdie.c b/3rdparty/elfutils/libdw/dwarf_addrdie.c new file mode 100644 index 0000000..94eb148 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_addrdie.c @@ -0,0 +1,54 @@ +/* Return CU DIE containing given address. + Copyright (C) 2005 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2005. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +Dwarf_Die * +dwarf_addrdie (dbg, addr, result) + Dwarf *dbg; + Dwarf_Addr addr; + Dwarf_Die *result; +{ + Dwarf_Aranges *aranges; + size_t naranges; + Dwarf_Off off; + + if (INTUSE(dwarf_getaranges) (dbg, &aranges, &naranges) != 0 + || INTUSE(dwarf_getarangeinfo) (INTUSE(dwarf_getarange_addr) (aranges, + addr), + NULL, NULL, &off) != 0) + return NULL; + + return INTUSE(dwarf_offdie) (dbg, off, result); +} diff --git a/3rdparty/elfutils/libdw/dwarf_aggregate_size.c b/3rdparty/elfutils/libdw/dwarf_aggregate_size.c new file mode 100644 index 0000000..667c274 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_aggregate_size.c @@ -0,0 +1,244 @@ +/* Compute size of an aggregate type from DWARF. + Copyright (C) 2010, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +static Dwarf_Die * +get_type (Dwarf_Die *die, Dwarf_Attribute *attr_mem, Dwarf_Die *type_mem) +{ + Dwarf_Die *type = INTUSE(dwarf_formref_die) + (INTUSE(dwarf_attr_integrate) (die, DW_AT_type, attr_mem), type_mem); + + if (INTUSE(dwarf_peel_type) (type, type) != 0) + return NULL; + + return type; +} + +static int +array_size (Dwarf_Die *die, Dwarf_Word *size, + Dwarf_Attribute *attr_mem, Dwarf_Die *type_mem) +{ + Dwarf_Word eltsize; + if (INTUSE(dwarf_aggregate_size) (get_type (die, attr_mem, type_mem), + &eltsize) != 0) + return -1; + + /* An array can have DW_TAG_subrange_type or DW_TAG_enumeration_type + children instead that give the size of each dimension. */ + + Dwarf_Die child; + if (INTUSE(dwarf_child) (die, &child) != 0) + return -1; + + bool any = false; + Dwarf_Word total = 0; + do + { + Dwarf_Word count; + switch (INTUSE(dwarf_tag) (&child)) + { + case DW_TAG_subrange_type: + /* This has either DW_AT_count or DW_AT_upper_bound. */ + if (INTUSE(dwarf_attr_integrate) (&child, DW_AT_count, + attr_mem) != NULL) + { + if (INTUSE(dwarf_formudata) (attr_mem, &count) != 0) + return -1; + } + else + { + Dwarf_Sword upper; + Dwarf_Sword lower; + if (INTUSE(dwarf_formsdata) (INTUSE(dwarf_attr_integrate) + (&child, DW_AT_upper_bound, + attr_mem), &upper) != 0) + return -1; + + /* Having DW_AT_lower_bound is optional. */ + if (INTUSE(dwarf_attr_integrate) (&child, DW_AT_lower_bound, + attr_mem) != NULL) + { + if (INTUSE(dwarf_formsdata) (attr_mem, &lower) != 0) + return -1; + } + else + { + /* Determine default lower bound from language, + as per "4.12 Subrange Type Entries". */ + Dwarf_Die cu = CUDIE (die->cu); + switch (INTUSE(dwarf_srclang) (&cu)) + { + case DW_LANG_C: + case DW_LANG_C89: + case DW_LANG_C99: + case DW_LANG_C11: + case DW_LANG_C_plus_plus: + case DW_LANG_C_plus_plus_11: + case DW_LANG_C_plus_plus_14: + case DW_LANG_ObjC: + case DW_LANG_ObjC_plus_plus: + case DW_LANG_Java: + case DW_LANG_D: + case DW_LANG_UPC: + case DW_LANG_Go: + lower = 0; + break; + + case DW_LANG_Ada83: + case DW_LANG_Ada95: + case DW_LANG_Cobol74: + case DW_LANG_Cobol85: + case DW_LANG_Fortran77: + case DW_LANG_Fortran90: + case DW_LANG_Fortran95: + case DW_LANG_Pascal83: + case DW_LANG_Modula2: + case DW_LANG_PL1: + lower = 1; + break; + + default: + return -1; + } + } + if (unlikely (lower > upper)) + return -1; + count = upper - lower + 1; + } + break; + + case DW_TAG_enumeration_type: + /* We have to find the DW_TAG_enumerator child with the + highest value to know the array's element count. */ + count = 0; + Dwarf_Die enum_child; + int has_children = INTUSE(dwarf_child) (die, &enum_child); + if (has_children < 0) + return -1; + if (has_children > 0) + do + if (INTUSE(dwarf_tag) (&enum_child) == DW_TAG_enumerator) + { + Dwarf_Word value; + if (INTUSE(dwarf_formudata) (INTUSE(dwarf_attr_integrate) + (&enum_child, DW_AT_const_value, + attr_mem), &value) != 0) + return -1; + if (value >= count) + count = value + 1; + } + while (INTUSE(dwarf_siblingof) (&enum_child, &enum_child) > 0); + break; + + default: + continue; + } + + /* This is a subrange_type or enumeration_type and we've set COUNT. + Now determine the stride for this array dimension. */ + Dwarf_Word stride = eltsize; + if (INTUSE(dwarf_attr_integrate) (&child, DW_AT_byte_stride, + attr_mem) != NULL) + { + if (INTUSE(dwarf_formudata) (attr_mem, &stride) != 0) + return -1; + } + else if (INTUSE(dwarf_attr_integrate) (&child, DW_AT_bit_stride, + attr_mem) != NULL) + { + if (INTUSE(dwarf_formudata) (attr_mem, &stride) != 0) + return -1; + if (stride % 8) /* XXX maybe compute in bits? */ + return -1; + stride /= 8; + } + + any = true; + total += stride * count; + } + while (INTUSE(dwarf_siblingof) (&child, &child) == 0); + + if (!any) + return -1; + + *size = total; + return 0; +} + +static int +aggregate_size (Dwarf_Die *die, Dwarf_Word *size, Dwarf_Die *type_mem) +{ + Dwarf_Attribute attr_mem; + + if (INTUSE(dwarf_attr_integrate) (die, DW_AT_byte_size, &attr_mem) != NULL) + return INTUSE(dwarf_formudata) (&attr_mem, size); + + switch (INTUSE(dwarf_tag) (die)) + { + case DW_TAG_subrange_type: + return aggregate_size (get_type (die, &attr_mem, type_mem), + size, type_mem); /* Tail call. */ + + case DW_TAG_array_type: + return array_size (die, size, &attr_mem, type_mem); + + /* Assume references and pointers have pointer size if not given an + explicit DW_AT_byte_size. */ + case DW_TAG_pointer_type: + case DW_TAG_reference_type: + case DW_TAG_rvalue_reference_type: + *size = die->cu->address_size; + return 0; + } + + /* Most types must give their size directly. */ + return -1; +} + +int +dwarf_aggregate_size (die, size) + Dwarf_Die *die; + Dwarf_Word *size; +{ + Dwarf_Die type_mem; + + if (INTUSE (dwarf_peel_type) (die, die) != 0) + return -1; + + return aggregate_size (die, size, &type_mem); +} +INTDEF (dwarf_aggregate_size) +OLD_VERSION (dwarf_aggregate_size, ELFUTILS_0.144) +NEW_VERSION (dwarf_aggregate_size, ELFUTILS_0.161) diff --git a/3rdparty/elfutils/libdw/dwarf_arrayorder.c b/3rdparty/elfutils/libdw/dwarf_arrayorder.c new file mode 100644 index 0000000..759fa4d --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_arrayorder.c @@ -0,0 +1,50 @@ +/* Return array order attribute of DIE. + Copyright (C) 2003, 2005, 2009 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +int +dwarf_arrayorder (die) + Dwarf_Die *die; +{ + Dwarf_Attribute attr_mem; + Dwarf_Word value; + + return INTUSE(dwarf_formudata) (INTUSE(dwarf_attr_integrate) + (die, DW_AT_ordering, &attr_mem), + &value) == 0 ? (int) value : -1; +} +OLD_VERSION (dwarf_arrayorder, ELFUTILS_0.122) +NEW_VERSION (dwarf_arrayorder, ELFUTILS_0.143) diff --git a/3rdparty/elfutils/libdw/dwarf_attr.c b/3rdparty/elfutils/libdw/dwarf_attr.c new file mode 100644 index 0000000..f247c1a --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_attr.c @@ -0,0 +1,55 @@ +/* Return specific DWARF attribute of a DIE. + Copyright (C) 2003, 2005, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +Dwarf_Attribute * +dwarf_attr (die, search_name, result) + Dwarf_Die *die; + unsigned int search_name; + Dwarf_Attribute *result; +{ + if (die == NULL) + return NULL; + + /* Search for the attribute with the given name. */ + result->valp = __libdw_find_attr (die, search_name, &result->code, + &result->form); + /* Always fill in the CU information. */ + result->cu = die->cu; + + return result->valp != NULL && result->code == search_name ? result : NULL; +} +INTDEF(dwarf_attr) diff --git a/3rdparty/elfutils/libdw/dwarf_attr_integrate.c b/3rdparty/elfutils/libdw/dwarf_attr_integrate.c new file mode 100644 index 0000000..812d74b --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_attr_integrate.c @@ -0,0 +1,60 @@ +/* Return specific DWARF attribute of a DIE, integrating indirections. + Copyright (C) 2005 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + +Dwarf_Attribute * +dwarf_attr_integrate (Dwarf_Die *die, unsigned int search_name, + Dwarf_Attribute *result) +{ + Dwarf_Die die_mem; + + do + { + Dwarf_Attribute *attr = INTUSE(dwarf_attr) (die, search_name, result); + if (attr != NULL) + return attr; + + attr = INTUSE(dwarf_attr) (die, DW_AT_abstract_origin, result); + if (attr == NULL) + attr = INTUSE(dwarf_attr) (die, DW_AT_specification, result); + if (attr == NULL) + break; + + die = INTUSE(dwarf_formref_die) (attr, &die_mem); + } + while (die != NULL); + + return NULL; +} +INTDEF (dwarf_attr_integrate) diff --git a/3rdparty/elfutils/libdw/dwarf_begin.c b/3rdparty/elfutils/libdw/dwarf_begin.c new file mode 100644 index 0000000..9f3050f --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_begin.c @@ -0,0 +1,101 @@ +/* Create descriptor from file descriptor for processing file. + Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <errno.h> +#include <stddef.h> +#include <sys/stat.h> + +#include <libdwP.h> + + +Dwarf * +dwarf_begin (fd, cmd) + int fd; + Dwarf_Cmd cmd; +{ + Elf *elf; + Elf_Cmd elfcmd; + Dwarf *result = NULL; + + switch (cmd) + { + case DWARF_C_READ: + elfcmd = ELF_C_READ_MMAP; + break; + case DWARF_C_WRITE: + elfcmd = ELF_C_WRITE; + break; + case DWARF_C_RDWR: + elfcmd = ELF_C_RDWR; + break; + default: + /* No valid mode. */ + __libdw_seterrno (DWARF_E_INVALID_CMD); + return NULL; + } + + /* We have to call `elf_version' here since the user might have not + done it or initialized libelf with a different version. This + would break libdwarf since we are using the ELF data structures + in a certain way. */ + elf_version (EV_CURRENT); + + /* Get an ELF descriptor. */ + elf = elf_begin (fd, elfcmd, NULL); + if (elf == NULL) + { + /* Test why the `elf_begin" call failed. */ + struct stat64 st; + + if (fstat64 (fd, &st) == 0 && ! S_ISREG (st.st_mode)) + __libdw_seterrno (DWARF_E_NO_REGFILE); + else if (errno == EBADF) + __libdw_seterrno (DWARF_E_INVALID_FILE); + else + __libdw_seterrno (DWARF_E_IO_ERROR); + } + else + { + /* Do the real work now that we have an ELF descriptor. */ + result = INTUSE(dwarf_begin_elf) (elf, cmd, NULL); + + /* If this failed, free the resources. */ + if (result == NULL) + elf_end (elf); + else + result->free_elf = true; + } + + return result; +} +INTDEF(dwarf_begin) diff --git a/3rdparty/elfutils/libdw/dwarf_begin_elf.c b/3rdparty/elfutils/libdw/dwarf_begin_elf.c new file mode 100644 index 0000000..4c49ce2 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_begin_elf.c @@ -0,0 +1,395 @@ +/* Create descriptor from ELF descriptor for processing file. + Copyright (C) 2002-2011, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include "libdwP.h" + +#if USE_ZLIB +# include <endian.h> +# define crc32 loser_crc32 +# include <zlib.h> +# undef crc32 +#endif + + +/* Section names. */ +static const char dwarf_scnnames[IDX_last][18] = +{ + [IDX_debug_info] = ".debug_info", + [IDX_debug_types] = ".debug_types", + [IDX_debug_abbrev] = ".debug_abbrev", + [IDX_debug_aranges] = ".debug_aranges", + [IDX_debug_line] = ".debug_line", + [IDX_debug_frame] = ".debug_frame", + [IDX_debug_loc] = ".debug_loc", + [IDX_debug_pubnames] = ".debug_pubnames", + [IDX_debug_str] = ".debug_str", + [IDX_debug_macinfo] = ".debug_macinfo", + [IDX_debug_macro] = ".debug_macro", + [IDX_debug_ranges] = ".debug_ranges", + [IDX_gnu_debugaltlink] = ".gnu_debugaltlink" +}; +#define ndwarf_scnnames (sizeof (dwarf_scnnames) / sizeof (dwarf_scnnames[0])) + +static Dwarf * +check_section (Dwarf *result, GElf_Ehdr *ehdr, Elf_Scn *scn, bool inscngrp) +{ + GElf_Shdr shdr_mem; + GElf_Shdr *shdr; + + /* Get the section header data. */ + shdr = gelf_getshdr (scn, &shdr_mem); + if (shdr == NULL) + /* We may read /proc/PID/mem with only program headers mapped and section + headers out of the mapped pages. */ + goto err; + + /* Ignore any SHT_NOBITS sections. Debugging sections should not + have been stripped, but in case of a corrupt file we won't try + to look at the missing data. */ + if (unlikely (shdr->sh_type == SHT_NOBITS)) + return result; + + /* Make sure the section is part of a section group only iff we + really need it. If we are looking for the global (= non-section + group debug info) we have to ignore all the info in section + groups. If we are looking into a section group we cannot look at + a section which isn't part of the section group. */ + if (! inscngrp && (shdr->sh_flags & SHF_GROUP) != 0) + /* Ignore the section. */ + return result; + + + /* We recognize the DWARF section by their names. This is not very + safe and stable but the best we can do. */ + const char *scnname = elf_strptr (result->elf, ehdr->e_shstrndx, + shdr->sh_name); + if (scnname == NULL) + { + /* The section name must be valid. Otherwise is the ELF file + invalid. */ + err: + __libdw_free_zdata (result); + Dwarf_Sig8_Hash_free (&result->sig8_hash); + __libdw_seterrno (DWARF_E_INVALID_ELF); + free (result); + return NULL; + } + + /* Recognize the various sections. Most names start with .debug_. */ + size_t cnt; + for (cnt = 0; cnt < ndwarf_scnnames; ++cnt) + if (strcmp (scnname, dwarf_scnnames[cnt]) == 0) + { + /* Found it. Remember where the data is. */ + if (unlikely (result->sectiondata[cnt] != NULL)) + /* A section appears twice. That's bad. We ignore the section. */ + break; + + /* Get the section data. */ + Elf_Data *data = elf_getdata (scn, NULL); + if (data != NULL && data->d_size != 0) + /* Yep, there is actually data available. */ + result->sectiondata[cnt] = data; + + break; + } +#if USE_ZLIB + else if (scnname[0] == '.' && scnname[1] == 'z' + && strcmp (&scnname[2], &dwarf_scnnames[cnt][1]) == 0) + { + /* A compressed section. */ + + if (unlikely (result->sectiondata[cnt] != NULL)) + /* A section appears twice. That's bad. We ignore the section. */ + break; + + /* Get the section data. */ + Elf_Data *data = elf_getdata (scn, NULL); + if (data != NULL && data->d_size != 0) + { + /* There is a 12-byte header of "ZLIB" followed by + an 8-byte big-endian size. */ + + if (unlikely (data->d_size < 4 + 8) + || unlikely (memcmp (data->d_buf, "ZLIB", 4) != 0)) + break; + + uint64_t size; + memcpy (&size, data->d_buf + 4, sizeof size); + size = be64toh (size); + + /* Check for unsigned overflow so malloc always allocated + enough memory for both the Elf_Data header and the + uncompressed section data. */ + if (unlikely (sizeof (Elf_Data) + size < size)) + break; + + Elf_Data *zdata = malloc (sizeof (Elf_Data) + size); + if (unlikely (zdata == NULL)) + break; + + zdata->d_buf = &zdata[1]; + zdata->d_type = ELF_T_BYTE; + zdata->d_version = EV_CURRENT; + zdata->d_size = size; + zdata->d_off = 0; + zdata->d_align = 1; + + z_stream z = + { + .next_in = data->d_buf + 4 + 8, + .avail_in = data->d_size - 4 - 8, + .next_out = zdata->d_buf, + .avail_out = zdata->d_size + }; + int zrc = inflateInit (&z); + while (z.avail_in > 0 && likely (zrc == Z_OK)) + { + z.next_out = zdata->d_buf + (zdata->d_size - z.avail_out); + zrc = inflate (&z, Z_FINISH); + if (unlikely (zrc != Z_STREAM_END)) + { + zrc = Z_DATA_ERROR; + break; + } + zrc = inflateReset (&z); + } + if (likely (zrc == Z_OK)) + zrc = inflateEnd (&z); + + if (unlikely (zrc != Z_OK) || unlikely (z.avail_out != 0)) + free (zdata); + else + { + result->sectiondata[cnt] = zdata; + result->sectiondata_gzip_mask |= 1U << cnt; + } + } + + break; + } +#endif + + return result; +} + + +/* Check whether all the necessary DWARF information is available. */ +static Dwarf * +valid_p (Dwarf *result) +{ + /* We looked at all the sections. Now determine whether all the + sections with debugging information we need are there. + + XXX Which sections are absolutely necessary? Add tests if + necessary. For now we require only .debug_info. Hopefully this + is correct. */ + if (likely (result != NULL) + && unlikely (result->sectiondata[IDX_debug_info] == NULL)) + { + __libdw_free_zdata (result); + Dwarf_Sig8_Hash_free (&result->sig8_hash); + __libdw_seterrno (DWARF_E_NO_DWARF); + free (result); + result = NULL; + } + + if (result != NULL && result->sectiondata[IDX_debug_loc] != NULL) + { + result->fake_loc_cu = (Dwarf_CU *) calloc (1, sizeof (Dwarf_CU)); + if (unlikely (result->fake_loc_cu == NULL)) + { + __libdw_free_zdata (result); + Dwarf_Sig8_Hash_free (&result->sig8_hash); + __libdw_seterrno (DWARF_E_NOMEM); + free (result); + result = NULL; + } + else + { + result->fake_loc_cu->dbg = result; + result->fake_loc_cu->startp + = result->sectiondata[IDX_debug_loc]->d_buf; + result->fake_loc_cu->endp + = (result->sectiondata[IDX_debug_loc]->d_buf + + result->sectiondata[IDX_debug_loc]->d_size); + } + } + + return result; +} + + +static Dwarf * +global_read (Dwarf *result, Elf *elf, GElf_Ehdr *ehdr) +{ + Elf_Scn *scn = NULL; + + while (result != NULL && (scn = elf_nextscn (elf, scn)) != NULL) + result = check_section (result, ehdr, scn, false); + + return valid_p (result); +} + + +static Dwarf * +scngrp_read (Dwarf *result, Elf *elf, GElf_Ehdr *ehdr, Elf_Scn *scngrp) +{ + /* SCNGRP is the section descriptor for a section group which might + contain debug sections. */ + Elf_Data *data = elf_getdata (scngrp, NULL); + if (data == NULL) + { + /* We cannot read the section content. Fail! */ + __libdw_free_zdata (result); + Dwarf_Sig8_Hash_free (&result->sig8_hash); + free (result); + return NULL; + } + + /* The content of the section is a number of 32-bit words which + represent section indices. The first word is a flag word. */ + Elf32_Word *scnidx = (Elf32_Word *) data->d_buf; + size_t cnt; + for (cnt = 1; cnt * sizeof (Elf32_Word) <= data->d_size; ++cnt) + { + Elf_Scn *scn = elf_getscn (elf, scnidx[cnt]); + if (scn == NULL) + { + /* A section group refers to a non-existing section. Should + never happen. */ + __libdw_free_zdata (result); + Dwarf_Sig8_Hash_free (&result->sig8_hash); + __libdw_seterrno (DWARF_E_INVALID_ELF); + free (result); + return NULL; + } + + result = check_section (result, ehdr, scn, true); + if (result == NULL) + break; + } + + return valid_p (result); +} + + +Dwarf * +dwarf_begin_elf (elf, cmd, scngrp) + Elf *elf; + Dwarf_Cmd cmd; + Elf_Scn *scngrp; +{ + GElf_Ehdr *ehdr; + GElf_Ehdr ehdr_mem; + + /* Get the ELF header of the file. We need various pieces of + information from it. */ + ehdr = gelf_getehdr (elf, &ehdr_mem); + if (ehdr == NULL) + { + if (elf_kind (elf) != ELF_K_ELF) + __libdw_seterrno (DWARF_E_NOELF); + else + __libdw_seterrno (DWARF_E_GETEHDR_ERROR); + + return NULL; + } + + + /* Default memory allocation size. */ + size_t mem_default_size = sysconf (_SC_PAGESIZE) - 4 * sizeof (void *); + + /* Allocate the data structure. */ + Dwarf *result = (Dwarf *) calloc (1, sizeof (Dwarf) + mem_default_size); + if (unlikely (result == NULL) + || unlikely (Dwarf_Sig8_Hash_init (&result->sig8_hash, 11) < 0)) + { + free (result); + __libdw_seterrno (DWARF_E_NOMEM); + return NULL; + } + + /* Fill in some values. */ + if ((BYTE_ORDER == LITTLE_ENDIAN && ehdr->e_ident[EI_DATA] == ELFDATA2MSB) + || (BYTE_ORDER == BIG_ENDIAN && ehdr->e_ident[EI_DATA] == ELFDATA2LSB)) + result->other_byte_order = true; + + result->elf = elf; + + /* Initialize the memory handling. */ + result->mem_default_size = mem_default_size; + result->oom_handler = __libdw_oom; + result->mem_tail = (struct libdw_memblock *) (result + 1); + result->mem_tail->size = (result->mem_default_size + - offsetof (struct libdw_memblock, mem)); + result->mem_tail->remaining = result->mem_tail->size; + result->mem_tail->prev = NULL; + + if (cmd == DWARF_C_READ || cmd == DWARF_C_RDWR) + { + /* If the caller provides a section group we get the DWARF + sections only from this setion group. Otherwise we search + for the first section with the required name. Further + sections with the name are ignored. The DWARF specification + does not really say this is allowed. */ + if (scngrp == NULL) + return global_read (result, elf, ehdr); + else + return scngrp_read (result, elf, ehdr, scngrp); + } + else if (cmd == DWARF_C_WRITE) + { + Dwarf_Sig8_Hash_free (&result->sig8_hash); + __libdw_seterrno (DWARF_E_UNIMPL); + free (result); + return NULL; + } + + Dwarf_Sig8_Hash_free (&result->sig8_hash); + __libdw_seterrno (DWARF_E_INVALID_CMD); + free (result); + return NULL; +} +INTDEF(dwarf_begin_elf) diff --git a/3rdparty/elfutils/libdw/dwarf_bitoffset.c b/3rdparty/elfutils/libdw/dwarf_bitoffset.c new file mode 100644 index 0000000..1648ecd --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_bitoffset.c @@ -0,0 +1,50 @@ +/* Return bit offset attribute of DIE. + Copyright (C) 2003, 2005, 2009 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +int +dwarf_bitoffset (die) + Dwarf_Die *die; +{ + Dwarf_Attribute attr_mem; + Dwarf_Word value; + + return INTUSE(dwarf_formudata) (INTUSE(dwarf_attr_integrate) + (die, DW_AT_bit_offset, &attr_mem), + &value) == 0 ? (int) value : -1; +} +OLD_VERSION (dwarf_bitoffset, ELFUTILS_0.122) +NEW_VERSION (dwarf_bitoffset, ELFUTILS_0.143) diff --git a/3rdparty/elfutils/libdw/dwarf_bitsize.c b/3rdparty/elfutils/libdw/dwarf_bitsize.c new file mode 100644 index 0000000..ea9946b --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_bitsize.c @@ -0,0 +1,50 @@ +/* Return bit size attribute of DIE. + Copyright (C) 2003, 2005, 2009 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +int +dwarf_bitsize (die) + Dwarf_Die *die; +{ + Dwarf_Attribute attr_mem; + Dwarf_Word value; + + return INTUSE(dwarf_formudata) (INTUSE(dwarf_attr_integrate) + (die, DW_AT_bit_size, &attr_mem), + &value) == 0 ? (int) value : -1; +} +OLD_VERSION (dwarf_bitsize, ELFUTILS_0.122) +NEW_VERSION (dwarf_bitsize, ELFUTILS_0.143) diff --git a/3rdparty/elfutils/libdw/dwarf_bytesize.c b/3rdparty/elfutils/libdw/dwarf_bytesize.c new file mode 100644 index 0000000..6499a0a --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_bytesize.c @@ -0,0 +1,50 @@ +/* Return byte size attribute of DIE. + Copyright (C) 2003, 2005, 2009 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +int +dwarf_bytesize (die) + Dwarf_Die *die; +{ + Dwarf_Attribute attr_mem; + Dwarf_Word value; + + return INTUSE(dwarf_formudata) (INTUSE(dwarf_attr_integrate) + (die, DW_AT_byte_size, &attr_mem), + &value) == 0 ? (int) value : -1; +} +OLD_VERSION (dwarf_bytesize, ELFUTILS_0.122) +NEW_VERSION (dwarf_bytesize, ELFUTILS_0.143) diff --git a/3rdparty/elfutils/libdw/dwarf_cfi_addrframe.c b/3rdparty/elfutils/libdw/dwarf_cfi_addrframe.c new file mode 100644 index 0000000..1c0da03 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_cfi_addrframe.c @@ -0,0 +1,57 @@ +/* Compute frame state at PC. + Copyright (C) 2009 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "cfi.h" + +int +dwarf_cfi_addrframe (cache, address, frame) + Dwarf_CFI *cache; + Dwarf_Addr address; + Dwarf_Frame **frame; +{ + /* Maybe there was a previous error. */ + if (cache == NULL) + return -1; + + struct dwarf_fde *fde = __libdw_find_fde (cache, address); + if (fde == NULL) + return -1; + + int error = __libdw_frame_at_address (cache, fde, address, frame); + if (error != DWARF_E_NOERROR) + { + __libdw_seterrno (error); + return -1; + } + return 0; +} +INTDEF (dwarf_cfi_addrframe) diff --git a/3rdparty/elfutils/libdw/dwarf_cfi_end.c b/3rdparty/elfutils/libdw/dwarf_cfi_end.c new file mode 100644 index 0000000..6eb2ade --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_cfi_end.c @@ -0,0 +1,49 @@ +/* Clean up Dwarf_CFI structure. + Copyright (C) 2009 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" +#include "cfi.h" +#include <stdlib.h> + +int +dwarf_cfi_end (cache) + Dwarf_CFI *cache; +{ + if (cache != NULL) + { + __libdw_destroy_frame_cache (cache); + free (cache); + } + + return 0; +} +INTDEF (dwarf_cfi_end) diff --git a/3rdparty/elfutils/libdw/dwarf_child.c b/3rdparty/elfutils/libdw/dwarf_child.c new file mode 100644 index 0000000..58a438b --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_child.c @@ -0,0 +1,176 @@ +/* Return child of current DIE. + Copyright (C) 2003-2011, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" +#include <string.h> + +/* Some arbitrary value not conflicting with any existing code. */ +#define INVALID 0xffffe444 + + +unsigned char * +internal_function +__libdw_find_attr (Dwarf_Die *die, unsigned int search_name, + unsigned int *codep, unsigned int *formp) +{ + Dwarf *dbg = die->cu->dbg; + const unsigned char *readp; + + /* Find the abbreviation entry. */ + Dwarf_Abbrev *abbrevp = __libdw_dieabbrev (die, &readp); + if (unlikely (abbrevp == DWARF_END_ABBREV)) + { + invalid_dwarf: + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; + } + + /* Search the name attribute. */ + unsigned char *const endp + = ((unsigned char *) dbg->sectiondata[IDX_debug_abbrev]->d_buf + + dbg->sectiondata[IDX_debug_abbrev]->d_size); + + const unsigned char *attrp = abbrevp->attrp; + while (1) + { + /* Get attribute name and form. */ + if (unlikely (attrp >= endp)) + goto invalid_dwarf; + unsigned int attr_name; + get_uleb128 (attr_name, attrp, endp); + + if (unlikely (attrp >= endp)) + goto invalid_dwarf; + unsigned int attr_form; + get_uleb128 (attr_form, attrp, endp); + + /* We can stop if we found the attribute with value zero. */ + if (attr_name == 0 && attr_form == 0) + break; + + /* Is this the name attribute? */ + if (attr_name == search_name && search_name != INVALID) + { + if (codep != NULL) + *codep = attr_name; + if (formp != NULL) + *formp = attr_form; + + return (unsigned char *) readp; + } + + /* Skip over the rest of this attribute (if there is any). */ + if (attr_form != 0) + { + size_t len = __libdw_form_val_len (die->cu, attr_form, readp); + if (unlikely (len == (size_t) -1l)) + { + readp = NULL; + break; + } + + // __libdw_form_val_len will have done a bounds check. + readp += len; + } + } + + // XXX Do we need other values? + if (codep != NULL) + *codep = INVALID; + if (formp != NULL) + *formp = INVALID; + + return (unsigned char *) readp; +} + + +int +dwarf_child (die, result) + Dwarf_Die *die; + Dwarf_Die *result; +{ + /* Ignore previous errors. */ + if (die == NULL) + return -1; + + /* Find the abbreviation entry. */ + Dwarf_Abbrev *abbrevp = __libdw_dieabbrev (die, NULL); + if (unlikely (abbrevp == DWARF_END_ABBREV)) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } + + /* If there are no children, do not search. */ + if (! abbrevp->has_children) + return 1; + + /* Skip past the last attribute. */ + void *addr = __libdw_find_attr (die, INVALID, NULL, NULL); + + if (addr == NULL) + return -1; + + /* RESULT can be the same as DIE. So preserve what we need. */ + struct Dwarf_CU *cu = die->cu; + + /* It's kosher (just suboptimal) to have a null entry first thing (7.5.3). + So if this starts with ULEB128 of 0 (even with silly encoding of 0), + it is a kosher null entry and we do not really have any children. */ + const unsigned char *code = addr; + const unsigned char *endp = cu->endp; + while (1) + { + if (unlikely (code >= endp)) /* Truncated section. */ + return 1; + if (unlikely (*code == 0x80)) + ++code; + else + break; + } + if (unlikely (*code == '\0')) + return 1; + + /* Clear the entire DIE structure. This signals we have not yet + determined any of the information. */ + memset (result, '\0', sizeof (Dwarf_Die)); + + /* We have the address. */ + result->addr = addr; + + /* Same CU as the parent. */ + result->cu = cu; + + return 0; +} +INTDEF(dwarf_child) diff --git a/3rdparty/elfutils/libdw/dwarf_cu_die.c b/3rdparty/elfutils/libdw/dwarf_cu_die.c new file mode 100644 index 0000000..48f4176 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_cu_die.c @@ -0,0 +1,68 @@ +/* Internal definitions for libdwarf. + Copyright (C) 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stddef.h> +#include "libdwP.h" + + +Dwarf_Die * +dwarf_cu_die (cu, result, versionp, abbrev_offsetp, address_sizep, + offset_sizep, type_signaturep, type_offsetp) + Dwarf_CU *cu; + Dwarf_Die *result; + Dwarf_Half *versionp; + Dwarf_Off *abbrev_offsetp; + uint8_t *address_sizep; + uint8_t *offset_sizep; + uint64_t *type_signaturep; + Dwarf_Off *type_offsetp; +{ + if (cu == NULL) + return NULL; + + *result = CUDIE (cu); + + if (versionp != NULL) + *versionp = cu->version; + if (abbrev_offsetp != NULL) + *abbrev_offsetp = cu->orig_abbrev_offset; + if (address_sizep != NULL) + *address_sizep = cu->address_size; + if (offset_sizep != NULL) + *offset_sizep = cu->offset_size; + if (type_signaturep != NULL) + *type_signaturep = cu->type_sig8; + if (type_offsetp != NULL) + *type_offsetp = cu->type_offset; + + return result; +} diff --git a/3rdparty/elfutils/libdw/dwarf_cu_getdwarf.c b/3rdparty/elfutils/libdw/dwarf_cu_getdwarf.c new file mode 100644 index 0000000..f8a2e9b --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_cu_getdwarf.c @@ -0,0 +1,47 @@ +/* Retrieve Dwarf descriptor underlying a Dwarf_CU. + Copyright (C) 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stddef.h> + +#include "libdwP.h" + + +Dwarf * +dwarf_cu_getdwarf (cu) + Dwarf_CU *cu; +{ + if (cu == NULL) + /* Some error occurred before. */ + return NULL; + + return cu->dbg; +} diff --git a/3rdparty/elfutils/libdw/dwarf_cuoffset.c b/3rdparty/elfutils/libdw/dwarf_cuoffset.c new file mode 100644 index 0000000..3ceffdb --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_cuoffset.c @@ -0,0 +1,45 @@ +/* Return offset of DIE in CU. + Copyright (C) 2003-2010, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +Dwarf_Off +dwarf_cuoffset (die) + Dwarf_Die *die; +{ + return (die == NULL + ? (Dwarf_Off) -1l + : (Dwarf_Off) (die->addr - die->cu->startp)); +} diff --git a/3rdparty/elfutils/libdw/dwarf_decl_column.c b/3rdparty/elfutils/libdw/dwarf_decl_column.c new file mode 100644 index 0000000..08d36b8 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_decl_column.c @@ -0,0 +1,44 @@ +/* Get column number of beginning of given declaration. + Copyright (C) 2005-2009 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2005. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +int +dwarf_decl_column (Dwarf_Die *decl, int *colp) +{ + return __libdw_attr_intval (decl, colp, DW_AT_decl_column); +} +OLD_VERSION (dwarf_decl_column, ELFUTILS_0.122) +NEW_VERSION (dwarf_decl_column, ELFUTILS_0.143) diff --git a/3rdparty/elfutils/libdw/dwarf_decl_file.c b/3rdparty/elfutils/libdw/dwarf_decl_file.c new file mode 100644 index 0000000..5657132 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_decl_file.c @@ -0,0 +1,89 @@ +/* Return file name containing definition of the given function. + Copyright (C) 2005, 2009 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2005. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> +#include "libdwP.h" + + +const char * +dwarf_decl_file (Dwarf_Die *die) +{ + Dwarf_Attribute attr_mem; + Dwarf_Word idx = 0; + + if (INTUSE(dwarf_formudata) (INTUSE(dwarf_attr_integrate) + (die, DW_AT_decl_file, &attr_mem), + &idx) != 0) + return NULL; + + /* Zero means no source file information available. */ + if (idx == 0) + { + __libdw_seterrno (DWARF_E_NO_ENTRY); + return NULL; + } + + /* Get the array of source files for the CU. */ + struct Dwarf_CU *cu = die->cu; + if (cu->lines == NULL) + { + Dwarf_Lines *lines; + size_t nlines; + + /* Let the more generic function do the work. It'll create more + data but that will be needed in an real program anyway. */ + (void) INTUSE(dwarf_getsrclines) (&CUDIE (cu), &lines, &nlines); + assert (cu->lines != NULL); + } + + if (cu->lines == (void *) -1l) + { + /* If the file index is not zero, there must be file information + available. */ + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; + } + + assert (cu->files != NULL && cu->files != (void *) -1l); + + if (idx >= cu->files->nfiles) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; + } + + return cu->files->info[idx].name; +} +OLD_VERSION (dwarf_decl_file, ELFUTILS_0.122) +NEW_VERSION (dwarf_decl_file, ELFUTILS_0.143) diff --git a/3rdparty/elfutils/libdw/dwarf_decl_line.c b/3rdparty/elfutils/libdw/dwarf_decl_line.c new file mode 100644 index 0000000..80fae6c --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_decl_line.c @@ -0,0 +1,70 @@ +/* Get line number of beginning of given function. + Copyright (C) 2005, 2009 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2005. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> +#include <limits.h> +#include "libdwP.h" + + +int +dwarf_decl_line (Dwarf_Die *func, int *linep) +{ + return __libdw_attr_intval (func, linep, DW_AT_decl_line); +} +OLD_VERSION (dwarf_decl_line, ELFUTILS_0.122) +NEW_VERSION (dwarf_decl_line, ELFUTILS_0.143) + + +int internal_function +__libdw_attr_intval (Dwarf_Die *die, int *linep, int attval) +{ + Dwarf_Attribute attr_mem; + Dwarf_Word line; + + int res = INTUSE(dwarf_formudata) (INTUSE(dwarf_attr_integrate) + (die, attval, &attr_mem), + &line); + if (res == 0) + { + if (line > INT_MAX) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + res = -1; + } + else + *linep = line; + } + + return res; +} diff --git a/3rdparty/elfutils/libdw/dwarf_diecu.c b/3rdparty/elfutils/libdw/dwarf_diecu.c new file mode 100644 index 0000000..bd9a37a --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_diecu.c @@ -0,0 +1,55 @@ +/* Return CU DIE containing given DIE. + Copyright (C) 2005-2010 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> +#include "libdwP.h" + + +Dwarf_Die * +dwarf_diecu (die, result, address_sizep, offset_sizep) + Dwarf_Die *die; + Dwarf_Die *result; + uint8_t *address_sizep; + uint8_t *offset_sizep; +{ + if (die == NULL) + return NULL; + + *result = CUDIE (die->cu); + + if (address_sizep != NULL) + *address_sizep = die->cu->address_size; + if (offset_sizep != NULL) + *offset_sizep = die->cu->offset_size; + + return result; +} diff --git a/3rdparty/elfutils/libdw/dwarf_diename.c b/3rdparty/elfutils/libdw/dwarf_diename.c new file mode 100644 index 0000000..050d8f1 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_diename.c @@ -0,0 +1,48 @@ +/* Return string in name attribute of DIE. + Copyright (C) 2002, 2005 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +const char * +dwarf_diename (die) + Dwarf_Die *die; +{ + Dwarf_Attribute attr_mem; + + return INTUSE(dwarf_formstring) (INTUSE(dwarf_attr_integrate) (die, + DW_AT_name, + &attr_mem)); +} +INTDEF (dwarf_diename) diff --git a/3rdparty/elfutils/libdw/dwarf_dieoffset.c b/3rdparty/elfutils/libdw/dwarf_dieoffset.c new file mode 100644 index 0000000..965b2c8 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_dieoffset.c @@ -0,0 +1,46 @@ +/* Return offset of DIE. + Copyright (C) 2003-2010, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +Dwarf_Off +dwarf_dieoffset (die) + Dwarf_Die *die; +{ + return (die == NULL + ? ~0ul + : (Dwarf_Off) (die->addr - die->cu->startp + die->cu->start)); +} +INTDEF(dwarf_dieoffset) diff --git a/3rdparty/elfutils/libdw/dwarf_end.c b/3rdparty/elfutils/libdw/dwarf_end.c new file mode 100644 index 0000000..922dc8f --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_end.c @@ -0,0 +1,129 @@ +/* Release debugging handling context. + Copyright (C) 2002-2011, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <search.h> +#include <stdlib.h> +#include <assert.h> +#include <string.h> + +#include "libdwP.h" +#include "cfi.h" + + +static void +noop_free (void *arg __attribute__ ((unused))) +{ +} + + +static void +cu_free (void *arg) +{ + struct Dwarf_CU *p = (struct Dwarf_CU *) arg; + + Dwarf_Abbrev_Hash_free (&p->abbrev_hash); + + tdestroy (p->locs, noop_free); +} + + +#if USE_ZLIB +void +internal_function +__libdw_free_zdata (Dwarf *dwarf) +{ + unsigned int gzip_mask = dwarf->sectiondata_gzip_mask; + while (gzip_mask != 0) + { + int i = ffs (gzip_mask); + assert (i > 0); + --i; + assert (i < IDX_last); + free (dwarf->sectiondata[i]); + gzip_mask &= ~(1U << i); + } +} +#endif + +int +dwarf_end (dwarf) + Dwarf *dwarf; +{ + if (dwarf != NULL) + { + if (dwarf->cfi != NULL) + /* Clean up the CFI cache. */ + __libdw_destroy_frame_cache (dwarf->cfi); + + Dwarf_Sig8_Hash_free (&dwarf->sig8_hash); + + /* The search tree for the CUs. NB: the CU data itself is + allocated separately, but the abbreviation hash tables need + to be handled. */ + tdestroy (dwarf->cu_tree, cu_free); + tdestroy (dwarf->tu_tree, cu_free); + + /* Search tree for macro opcode tables. */ + tdestroy (dwarf->macro_ops, noop_free); + + /* Search tree for decoded .debug_lines units. */ + tdestroy (dwarf->files_lines, noop_free); + + struct libdw_memblock *memp = dwarf->mem_tail; + /* The first block is allocated together with the Dwarf object. */ + while (memp->prev != NULL) + { + struct libdw_memblock *prevp = memp->prev; + free (memp); + memp = prevp; + } + + /* Free the pubnames helper structure. */ + free (dwarf->pubnames_sets); + + __libdw_free_zdata (dwarf); + + /* Free the ELF descriptor if necessary. */ + if (dwarf->free_elf) + elf_end (dwarf->elf); + + /* Free the fake location list CU. */ + free (dwarf->fake_loc_cu); + + /* Free the context descriptor. */ + free (dwarf); + } + + return 0; +} +INTDEF(dwarf_end) diff --git a/3rdparty/elfutils/libdw/dwarf_entry_breakpoints.c b/3rdparty/elfutils/libdw/dwarf_entry_breakpoints.c new file mode 100644 index 0000000..ffd5169 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_entry_breakpoints.c @@ -0,0 +1,157 @@ +/* Find entry breakpoint locations for a function. + Copyright (C) 2005-2009 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include "libdwP.h" +#include <dwarf.h> +#include <stdlib.h> + + +int +dwarf_entry_breakpoints (die, bkpts) + Dwarf_Die *die; + Dwarf_Addr **bkpts; +{ + int nbkpts = 0; + *bkpts = NULL; + + /* Add one breakpoint location to the result vector. */ + inline int add_bkpt (Dwarf_Addr pc) + { + Dwarf_Addr *newlist = realloc (*bkpts, ++nbkpts * sizeof newlist[0]); + if (newlist == NULL) + { + free (*bkpts); + *bkpts = NULL; + __libdw_seterrno (DWARF_E_NOMEM); + return -1; + } + newlist[nbkpts - 1] = pc; + *bkpts = newlist; + return nbkpts; + } + + /* Fallback result, break at the entrypc/lowpc value. */ + inline int entrypc_bkpt (void) + { + Dwarf_Addr pc; + return INTUSE(dwarf_entrypc) (die, &pc) < 0 ? -1 : add_bkpt (pc); + } + + /* Fetch the CU's line records to look for this DIE's addresses. */ + Dwarf_Die cudie = CUDIE (die->cu); + Dwarf_Lines *lines; + size_t nlines; + if (INTUSE(dwarf_getsrclines) (&cudie, &lines, &nlines) < 0) + { + int error = INTUSE (dwarf_errno) (); + if (error == 0) /* CU has no DW_AT_stmt_list. */ + return entrypc_bkpt (); + __libdw_seterrno (error); + return -1; + } + + /* Search a contiguous PC range for prologue-end markers. + If DWARF, look for proper markers. + Failing that, if ADHOC, look for the ad hoc convention. */ + inline int search_range (Dwarf_Addr low, Dwarf_Addr high, + bool dwarf, bool adhoc) + { + size_t l = 0, u = nlines; + while (l < u) + { + size_t idx = (l + u) / 2; + if (lines->info[idx].addr < low) + l = idx + 1; + else if (lines->info[idx].addr > low) + u = idx; + else if (lines->info[idx].end_sequence) + l = idx + 1; + else + { + l = idx; + break; + } + } + if (l < u) + { + if (dwarf) + for (size_t i = l; i < u && lines->info[i].addr < high; ++i) + if (lines->info[i].prologue_end + && add_bkpt (lines->info[i].addr) < 0) + return -1; + if (adhoc && nbkpts == 0) + while (++l < nlines && lines->info[l].addr < high) + if (!lines->info[l].end_sequence) + return add_bkpt (lines->info[l].addr); + return nbkpts; + } + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } + + /* Search each contiguous address range for DWARF prologue_end markers. */ + + Dwarf_Addr base; + Dwarf_Addr begin; + Dwarf_Addr end; + ptrdiff_t offset = INTUSE(dwarf_ranges) (die, 0, &base, &begin, &end); + if (offset < 0) + return -1; + + /* Most often there is a single contiguous PC range for the DIE. */ + if (offset == 1) + return search_range (begin, end, true, true) ?: entrypc_bkpt (); + + Dwarf_Addr lowpc = (Dwarf_Addr) -1l; + Dwarf_Addr highpc = (Dwarf_Addr) -1l; + while (offset > 0) + { + /* We have an address range entry. */ + if (search_range (begin, end, true, false) < 0) + return -1; + + if (begin < lowpc) + { + lowpc = begin; + highpc = end; + } + + offset = INTUSE(dwarf_ranges) (die, offset, &base, &begin, &end); + } + + /* If we didn't find any proper DWARF markers, then look in the + lowest-addressed range for an ad hoc marker. Failing that, + fall back to just using the entrypc value. */ + return (nbkpts + ?: (lowpc == (Dwarf_Addr) -1l ? 0 + : search_range (lowpc, highpc, false, true)) + ?: entrypc_bkpt ()); +} diff --git a/3rdparty/elfutils/libdw/dwarf_entrypc.c b/3rdparty/elfutils/libdw/dwarf_entrypc.c new file mode 100644 index 0000000..8eb39db --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_entrypc.c @@ -0,0 +1,50 @@ +/* Return entry PC attribute of DIE. + Copyright (C) 2003, 2005 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +int +dwarf_entrypc (die, return_addr) + Dwarf_Die *die; + Dwarf_Addr *return_addr; +{ + Dwarf_Attribute attr_mem; + + return INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (die, DW_AT_entry_pc, + &attr_mem) + ?: INTUSE(dwarf_attr) (die, DW_AT_low_pc, + &attr_mem), + return_addr); +} +INTDEF(dwarf_entrypc) diff --git a/3rdparty/elfutils/libdw/dwarf_error.c b/3rdparty/elfutils/libdw/dwarf_error.c new file mode 100644 index 0000000..08b691a --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_error.c @@ -0,0 +1,122 @@ +/* Retrieve ELF descriptor used for DWARF access. + Copyright (C) 2002, 2003, 2004, 2005, 2009, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <stddef.h> + +#include "libdwP.h" + + +/* The error number. */ +static __thread int global_error; + + +int +dwarf_errno (void) +{ + int result = global_error; + global_error = DWARF_E_NOERROR; + return result; +} +INTDEF(dwarf_errno) + + +/* XXX For now we use string pointers. Once the table stablelizes + make it more DSO-friendly. */ +static const char *errmsgs[] = + { + [DWARF_E_NOERROR] = N_("no error"), + [DWARF_E_UNKNOWN_ERROR] = N_("unknown error"), + [DWARF_E_INVALID_ACCESS] = N_("invalid access"), + [DWARF_E_NO_REGFILE] = N_("no regular file"), + [DWARF_E_IO_ERROR] = N_("I/O error"), + [DWARF_E_INVALID_ELF] = N_("invalid ELF file"), + [DWARF_E_NO_DWARF] = N_("no DWARF information"), + [DWARF_E_NOELF] = N_("no ELF file"), + [DWARF_E_GETEHDR_ERROR] = N_("cannot get ELF header"), + [DWARF_E_NOMEM] = N_("out of memory"), + [DWARF_E_UNIMPL] = N_("not implemented"), + [DWARF_E_INVALID_CMD] = N_("invalid command"), + [DWARF_E_INVALID_VERSION] = N_("invalid version"), + [DWARF_E_INVALID_FILE] = N_("invalid file"), + [DWARF_E_NO_ENTRY] = N_("no entries found"), + [DWARF_E_INVALID_DWARF] = N_("invalid DWARF"), + [DWARF_E_NO_STRING] = N_("no string data"), + [DWARF_E_NO_ADDR] = N_("no address value"), + [DWARF_E_NO_CONSTANT] = N_("no constant value"), + [DWARF_E_NO_REFERENCE] = N_("no reference value"), + [DWARF_E_INVALID_REFERENCE] = N_("invalid reference value"), + [DWARF_E_NO_DEBUG_LINE] = N_(".debug_line section missing"), + [DWARF_E_INVALID_DEBUG_LINE] = N_("invalid .debug_line section"), + [DWARF_E_TOO_BIG] = N_("debug information too big"), + [DWARF_E_VERSION] = N_("invalid DWARF version"), + [DWARF_E_INVALID_DIR_IDX] = N_("invalid directory index"), + [DWARF_E_ADDR_OUTOFRANGE] = N_("address out of range"), + [DWARF_E_NO_LOCLIST] = N_("no location list value"), + [DWARF_E_NO_BLOCK] = N_("no block data"), + [DWARF_E_INVALID_LINE_IDX] = N_("invalid line index"), + [DWARF_E_INVALID_ARANGE_IDX] = N_("invalid address range index"), + [DWARF_E_NO_MATCH] = N_("no matching address range"), + [DWARF_E_NO_FLAG] = N_("no flag value"), + [DWARF_E_INVALID_OFFSET] = N_("invalid offset"), + [DWARF_E_NO_DEBUG_RANGES] = N_(".debug_ranges section missing"), + [DWARF_E_INVALID_CFI] = N_("invalid CFI section"), + [DWARF_E_NO_ALT_DEBUGLINK] = N_("no alternative debug link found"), + [DWARF_E_INVALID_OPCODE] = N_("invalid opcode"), + }; +#define nerrmsgs (sizeof (errmsgs) / sizeof (errmsgs[0])) + + +void +__libdw_seterrno (value) + int value; +{ + global_error = (value >= 0 && value < (int) nerrmsgs + ? value : DWARF_E_UNKNOWN_ERROR); +} + + +const char * +dwarf_errmsg (error) + int error; +{ + int last_error = global_error; + + if (error == 0) + return last_error != 0 ? _(errmsgs[last_error]) : NULL; + else if (error < -1 || error >= (int) nerrmsgs) + return _(errmsgs[DWARF_E_UNKNOWN_ERROR]); + + return _(errmsgs[error == -1 ? last_error : error]); +} +INTDEF(dwarf_errmsg) diff --git a/3rdparty/elfutils/libdw/dwarf_filesrc.c b/3rdparty/elfutils/libdw/dwarf_filesrc.c new file mode 100644 index 0000000..d866ce7 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_filesrc.c @@ -0,0 +1,51 @@ +/* Find source file information. + Copyright (C) 2004 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +const char * +dwarf_filesrc (Dwarf_Files *file, size_t idx, Dwarf_Word *mtime, + Dwarf_Word *length) +{ + if (file == NULL || idx >= file->nfiles) + return NULL; + + if (mtime != NULL) + *mtime = file->info[idx].mtime; + + if (length != NULL) + *length = file->info[idx].length; + + return file->info[idx].name; +} diff --git a/3rdparty/elfutils/libdw/dwarf_formaddr.c b/3rdparty/elfutils/libdw/dwarf_formaddr.c new file mode 100644 index 0000000..9d4a388 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_formaddr.c @@ -0,0 +1,59 @@ +/* Return address represented by attribute. + Copyright (C) 2003-2010 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +int +dwarf_formaddr (attr, return_addr) + Dwarf_Attribute *attr; + Dwarf_Addr *return_addr; +{ + if (attr == NULL) + return -1; + + if (unlikely (attr->form != DW_FORM_addr)) + { + __libdw_seterrno (DWARF_E_NO_ADDR); + return -1; + } + + if (__libdw_read_address (attr->cu->dbg, + cu_sec_idx (attr->cu), attr->valp, + attr->cu->address_size, return_addr)) + return -1; + + return 0; +} +INTDEF(dwarf_formaddr) diff --git a/3rdparty/elfutils/libdw/dwarf_formblock.c b/3rdparty/elfutils/libdw/dwarf_formblock.c new file mode 100644 index 0000000..3d56f22 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_formblock.c @@ -0,0 +1,95 @@ +/* Return block represented by attribute. + Copyright (C) 2004-2010, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +int +dwarf_formblock (attr, return_block) + Dwarf_Attribute *attr; + Dwarf_Block *return_block; +{ + if (attr == NULL) + return -1; + + const unsigned char *datap = attr->valp; + const unsigned char *endp = attr->cu->endp; + + switch (attr->form) + { + case DW_FORM_block1: + if (unlikely (endp - datap < 1)) + goto invalid; + return_block->length = *(uint8_t *) attr->valp; + return_block->data = attr->valp + 1; + break; + + case DW_FORM_block2: + if (unlikely (endp - datap < 2)) + goto invalid; + return_block->length = read_2ubyte_unaligned (attr->cu->dbg, attr->valp); + return_block->data = attr->valp + 2; + break; + + case DW_FORM_block4: + if (unlikely (endp - datap < 4)) + goto invalid; + return_block->length = read_4ubyte_unaligned (attr->cu->dbg, attr->valp); + return_block->data = attr->valp + 4; + break; + + case DW_FORM_block: + case DW_FORM_exprloc: + if (unlikely (endp - datap < 1)) + goto invalid; + get_uleb128 (return_block->length, datap, endp); + return_block->data = (unsigned char *) datap; + break; + + default: + __libdw_seterrno (DWARF_E_NO_BLOCK); + return -1; + } + + if (unlikely (return_block->length > (size_t) (endp - return_block->data))) + { + /* Block does not fit. */ + invalid: + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } + + return 0; +} +INTDEF(dwarf_formblock) diff --git a/3rdparty/elfutils/libdw/dwarf_formflag.c b/3rdparty/elfutils/libdw/dwarf_formflag.c new file mode 100644 index 0000000..bdc2267 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_formflag.c @@ -0,0 +1,61 @@ +/* Return flag represented by attribute. + Copyright (C) 2004-2009 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +int +dwarf_formflag (attr, return_bool) + Dwarf_Attribute *attr; + bool *return_bool; +{ + if (attr == NULL) + return -1; + + if (attr->form == DW_FORM_flag_present) + { + *return_bool = true; + return 0; + } + + if (unlikely (attr->form != DW_FORM_flag)) + { + __libdw_seterrno (DWARF_E_NO_FLAG); + return -1; + } + + *return_bool = *attr->valp != 0; + + return 0; +} diff --git a/3rdparty/elfutils/libdw/dwarf_formref.c b/3rdparty/elfutils/libdw/dwarf_formref.c new file mode 100644 index 0000000..2592437 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_formref.c @@ -0,0 +1,113 @@ +/* Return reference offset represented by attribute. + Copyright (C) 2003-2010, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + +int +__libdw_formref (attr, return_offset) + Dwarf_Attribute *attr; + Dwarf_Off *return_offset; +{ + const unsigned char *datap = attr->valp; + const unsigned char *endp = attr->cu->endp; + + if (attr->valp == NULL) + { + __libdw_seterrno (DWARF_E_INVALID_REFERENCE); + return -1; + } + + switch (attr->form) + { + case DW_FORM_ref1: + if (datap + 1 > endp) + { + invalid: + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } + *return_offset = *attr->valp; + break; + + case DW_FORM_ref2: + if (datap + 2 > endp) + goto invalid; + *return_offset = read_2ubyte_unaligned (attr->cu->dbg, attr->valp); + break; + + case DW_FORM_ref4: + if (datap + 4 > endp) + goto invalid; + *return_offset = read_4ubyte_unaligned (attr->cu->dbg, attr->valp); + break; + + case DW_FORM_ref8: + if (datap + 8 > endp) + goto invalid; + *return_offset = read_8ubyte_unaligned (attr->cu->dbg, attr->valp); + break; + + case DW_FORM_ref_udata: + if (datap + 1 > endp) + goto invalid; + get_uleb128 (*return_offset, datap, endp); + break; + + case DW_FORM_ref_addr: + case DW_FORM_ref_sig8: + case DW_FORM_GNU_ref_alt: + /* These aren't handled by dwarf_formref, only by dwarf_formref_die. */ + __libdw_seterrno (DWARF_E_INVALID_REFERENCE); + return -1; + + default: + __libdw_seterrno (DWARF_E_NO_REFERENCE); + return -1; + } + + return 0; +} + +/* This is the old public entry point. + It is now deprecated in favor of dwarf_formref_die. */ +int +dwarf_formref (attr, return_offset) + Dwarf_Attribute *attr; + Dwarf_Off *return_offset; +{ + if (attr == NULL) + return -1; + + return __libdw_formref (attr, return_offset); +} diff --git a/3rdparty/elfutils/libdw/dwarf_formref_die.c b/3rdparty/elfutils/libdw/dwarf_formref_die.c new file mode 100644 index 0000000..63f6697 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_formref_die.c @@ -0,0 +1,121 @@ +/* Look up the DIE in a reference-form attribute. + Copyright (C) 2005-2010 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> +#include "libdwP.h" +#include <dwarf.h> + + +Dwarf_Die * +dwarf_formref_die (attr, result) + Dwarf_Attribute *attr; + Dwarf_Die *result; +{ + if (attr == NULL) + return NULL; + + struct Dwarf_CU *cu = attr->cu; + + Dwarf_Off offset; + if (attr->form == DW_FORM_ref_addr || attr->form == DW_FORM_GNU_ref_alt) + { + /* This has an absolute offset. */ + + uint8_t ref_size = (cu->version == 2 && attr->form == DW_FORM_ref_addr + ? cu->address_size + : cu->offset_size); + + Dwarf *dbg_ret = (attr->form == DW_FORM_GNU_ref_alt + ? cu->dbg->alt_dwarf : cu->dbg); + + if (dbg_ret == NULL) + { + __libdw_seterrno (DWARF_E_NO_ALT_DEBUGLINK); + return NULL; + } + + if (__libdw_read_offset (cu->dbg, dbg_ret, IDX_debug_info, attr->valp, + ref_size, &offset, IDX_debug_info, 0)) + return NULL; + + return INTUSE(dwarf_offdie) (dbg_ret, offset, result); + } + + const unsigned char *datap; + size_t size; + if (attr->form == DW_FORM_ref_sig8) + { + /* This doesn't have an offset, but instead a value we + have to match in the .debug_types type unit headers. */ + + uint64_t sig = read_8ubyte_unaligned (cu->dbg, attr->valp); + cu = Dwarf_Sig8_Hash_find (&cu->dbg->sig8_hash, sig, NULL); + if (cu == NULL) + /* Not seen before. We have to scan through the type units. */ + do + { + cu = __libdw_intern_next_unit (attr->cu->dbg, true); + if (cu == NULL) + { + __libdw_seterrno (INTUSE(dwarf_errno) () + ?: DWARF_E_INVALID_REFERENCE); + return NULL; + } + } + while (cu->type_sig8 != sig); + + datap = cu->dbg->sectiondata[IDX_debug_types]->d_buf; + size = cu->dbg->sectiondata[IDX_debug_types]->d_size; + offset = cu->type_offset; + } + else + { + /* Other forms produce an offset from the CU. */ + if (unlikely (__libdw_formref (attr, &offset) != 0)) + return NULL; + + datap = cu->startp; + size = cu->endp - cu->startp; + } + + if (unlikely (offset >= size)) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; + } + + memset (result, '\0', sizeof (Dwarf_Die)); + result->addr = (char *) datap + offset; + result->cu = cu; + return result; +} +INTDEF (dwarf_formref_die) diff --git a/3rdparty/elfutils/libdw/dwarf_formsdata.c b/3rdparty/elfutils/libdw/dwarf_formsdata.c new file mode 100644 index 0000000..2380bf4 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_formsdata.c @@ -0,0 +1,98 @@ +/* Return signed constant represented by attribute. + Copyright (C) 2003, 2005, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +int +dwarf_formsdata (attr, return_sval) + Dwarf_Attribute *attr; + Dwarf_Sword *return_sval; +{ + if (attr == NULL) + return -1; + + const unsigned char *datap = attr->valp; + const unsigned char *endp = attr->cu->endp; + + switch (attr->form) + { + case DW_FORM_data1: + if (datap + 1 > endp) + { + invalid: + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } + *return_sval = *attr->valp; + break; + + case DW_FORM_data2: + if (datap + 2 > endp) + goto invalid; + *return_sval = read_2ubyte_unaligned (attr->cu->dbg, attr->valp); + break; + + case DW_FORM_data4: + if (datap + 4 > endp) + goto invalid; + *return_sval = read_4ubyte_unaligned (attr->cu->dbg, attr->valp); + break; + + case DW_FORM_data8: + if (datap + 8 > endp) + goto invalid; + *return_sval = read_8ubyte_unaligned (attr->cu->dbg, attr->valp); + break; + + case DW_FORM_sdata: + if (datap + 1 > endp) + goto invalid; + get_sleb128 (*return_sval, datap, endp); + break; + + case DW_FORM_udata: + if (datap + 1 > endp) + goto invalid; + get_uleb128 (*return_sval, datap, endp); + break; + + default: + __libdw_seterrno (DWARF_E_NO_CONSTANT); + return -1; + } + + return 0; +} +INTDEF(dwarf_formsdata) diff --git a/3rdparty/elfutils/libdw/dwarf_formstring.c b/3rdparty/elfutils/libdw/dwarf_formstring.c new file mode 100644 index 0000000..02b56d4 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_formstring.c @@ -0,0 +1,76 @@ +/* Return string associated with given attribute. + Copyright (C) 2003-2010, 2013 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +const char * +dwarf_formstring (attrp) + Dwarf_Attribute *attrp; +{ + /* Ignore earlier errors. */ + if (attrp == NULL) + return NULL; + + /* We found it. Now determine where the string is stored. */ + if (attrp->form == DW_FORM_string) + /* A simple inlined string. */ + return (const char *) attrp->valp; + + Dwarf *dbg = attrp->cu->dbg; + Dwarf *dbg_ret = attrp->form == DW_FORM_GNU_strp_alt ? dbg->alt_dwarf : dbg; + + if (unlikely (dbg_ret == NULL)) + { + __libdw_seterrno (DWARF_E_NO_ALT_DEBUGLINK); + return NULL; + } + + + if (unlikely (attrp->form != DW_FORM_strp + && attrp->form != DW_FORM_GNU_strp_alt) + || dbg_ret->sectiondata[IDX_debug_str] == NULL) + { + __libdw_seterrno (DWARF_E_NO_STRING); + return NULL; + } + + uint64_t off; + if (__libdw_read_offset (dbg, dbg_ret, cu_sec_idx (attrp->cu), attrp->valp, + attrp->cu->offset_size, &off, IDX_debug_str, 1)) + return NULL; + + return (const char *) dbg_ret->sectiondata[IDX_debug_str]->d_buf + off; +} +INTDEF(dwarf_formstring) diff --git a/3rdparty/elfutils/libdw/dwarf_formudata.c b/3rdparty/elfutils/libdw/dwarf_formudata.c new file mode 100644 index 0000000..a01ff31 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_formudata.c @@ -0,0 +1,233 @@ +/* Return unsigned constant represented by attribute. + Copyright (C) 2003-2012, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + +internal_function unsigned char * +__libdw_formptr (Dwarf_Attribute *attr, int sec_index, + int err_nodata, unsigned char **endpp, + Dwarf_Off *offsetp) +{ + if (attr == NULL) + return NULL; + + const Elf_Data *d = attr->cu->dbg->sectiondata[sec_index]; + if (unlikely (d == NULL)) + { + __libdw_seterrno (err_nodata); + return NULL; + } + + Dwarf_Word offset; + if (attr->form == DW_FORM_sec_offset) + { + if (__libdw_read_offset (attr->cu->dbg, attr->cu->dbg, + cu_sec_idx (attr->cu), attr->valp, + attr->cu->offset_size, &offset, sec_index, 0)) + return NULL; + } + else if (attr->cu->version > 3) + goto invalid; + else + switch (attr->form) + { + case DW_FORM_data4: + case DW_FORM_data8: + if (__libdw_read_offset (attr->cu->dbg, attr->cu->dbg, + cu_sec_idx (attr->cu), + attr->valp, + attr->form == DW_FORM_data4 ? 4 : 8, + &offset, sec_index, 0)) + return NULL; + break; + + default: + if (INTUSE(dwarf_formudata) (attr, &offset)) + return NULL; + }; + + unsigned char *readp = d->d_buf + offset; + unsigned char *endp = d->d_buf + d->d_size; + if (unlikely (readp >= endp)) + { + invalid: + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; + } + + if (endpp != NULL) + *endpp = endp; + if (offsetp != NULL) + *offsetp = offset; + return readp; +} + +int +dwarf_formudata (attr, return_uval) + Dwarf_Attribute *attr; + Dwarf_Word *return_uval; +{ + if (attr == NULL) + return -1; + + const unsigned char *datap = attr->valp; + const unsigned char *endp = attr->cu->endp; + + switch (attr->form) + { + case DW_FORM_data1: + if (datap + 1 > endp) + { + invalid: + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } + *return_uval = *attr->valp; + break; + + case DW_FORM_data2: + if (datap + 2 > endp) + goto invalid; + *return_uval = read_2ubyte_unaligned (attr->cu->dbg, attr->valp); + break; + + case DW_FORM_data4: + case DW_FORM_data8: + case DW_FORM_sec_offset: + /* Before DWARF4 data4 and data8 are pure constants unless the + attribute also allows offsets (*ptr classes), since DWARF4 + they are always just constants (start_scope is special though, + since it only could express a rangelist since DWARF4). */ + if (attr->form == DW_FORM_sec_offset + || (attr->cu->version < 4 && attr->code != DW_AT_start_scope)) + { + switch (attr->code) + { + case DW_AT_data_member_location: + case DW_AT_frame_base: + case DW_AT_location: + case DW_AT_return_addr: + case DW_AT_segment: + case DW_AT_static_link: + case DW_AT_string_length: + case DW_AT_use_location: + case DW_AT_vtable_elem_location: + /* loclistptr */ + if (__libdw_formptr (attr, IDX_debug_loc, + DWARF_E_NO_LOCLIST, NULL, + return_uval) == NULL) + return -1; + break; + + case DW_AT_macro_info: + /* macptr into .debug_macinfo */ + if (__libdw_formptr (attr, IDX_debug_macinfo, + DWARF_E_NO_ENTRY, NULL, + return_uval) == NULL) + return -1; + break; + + case DW_AT_GNU_macros: + /* macptr into .debug_macro */ + if (__libdw_formptr (attr, IDX_debug_macro, + DWARF_E_NO_ENTRY, NULL, + return_uval) == NULL) + return -1; + break; + + case DW_AT_ranges: + case DW_AT_start_scope: + /* rangelistptr */ + if (__libdw_formptr (attr, IDX_debug_ranges, + DWARF_E_NO_DEBUG_RANGES, NULL, + return_uval) == NULL) + return -1; + break; + + case DW_AT_stmt_list: + /* lineptr */ + if (__libdw_formptr (attr, IDX_debug_line, + DWARF_E_NO_DEBUG_LINE, NULL, + return_uval) == NULL) + return -1; + break; + + default: + /* sec_offset can only be used by one of the above attrs. */ + if (attr->form == DW_FORM_sec_offset) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } + + /* Not one of the special attributes, just a constant. */ + if (__libdw_read_address (attr->cu->dbg, cu_sec_idx (attr->cu), + attr->valp, + attr->form == DW_FORM_data4 ? 4 : 8, + return_uval)) + return -1; + break; + } + } + else + { + /* We are dealing with a constant data4 or data8. */ + if (__libdw_read_address (attr->cu->dbg, cu_sec_idx (attr->cu), + attr->valp, + attr->form == DW_FORM_data4 ? 4 : 8, + return_uval)) + return -1; + } + break; + + case DW_FORM_sdata: + if (datap + 1 > endp) + goto invalid; + get_sleb128 (*return_uval, datap, endp); + break; + + case DW_FORM_udata: + if (datap + 1 > endp) + goto invalid; + get_uleb128 (*return_uval, datap, endp); + break; + + default: + __libdw_seterrno (DWARF_E_NO_CONSTANT); + return -1; + } + + return 0; +} +INTDEF(dwarf_formudata) diff --git a/3rdparty/elfutils/libdw/dwarf_frame_cfa.c b/3rdparty/elfutils/libdw/dwarf_frame_cfa.c new file mode 100644 index 0000000..a9ae7e7 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_frame_cfa.c @@ -0,0 +1,80 @@ +/* Get CFA expression for frame. + Copyright (C) 2009-2010 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "cfi.h" +#include <dwarf.h> +#include <stdlib.h> + +int +dwarf_frame_cfa (fs, ops, nops) + Dwarf_Frame *fs; + Dwarf_Op **ops; + size_t *nops; +{ + /* Maybe there was a previous error. */ + if (fs == NULL) + return -1; + + int result = 0; + switch (fs->cfa_rule) + { + case cfa_undefined: + *ops = NULL; + *nops = 0; + break; + + case cfa_offset: + /* The Dwarf_Op was already fully initialized by execute_cfi. */ + *ops = &fs->cfa_data.offset; + *nops = 1; + break; + + case cfa_expr: + /* Parse the expression into internal form. */ + result = __libdw_intern_expression + (NULL, fs->cache->other_byte_order, + fs->cache->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8, 4, + &fs->cache->expr_tree, &fs->cfa_data.expr, false, false, + ops, nops, IDX_debug_frame); + break; + + case cfa_invalid: + __libdw_seterrno (DWARF_E_INVALID_CFI); + result = -1; + break; + + default: + abort (); + } + + return result; +} diff --git a/3rdparty/elfutils/libdw/dwarf_frame_info.c b/3rdparty/elfutils/libdw/dwarf_frame_info.c new file mode 100644 index 0000000..7da46fb --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_frame_info.c @@ -0,0 +1,53 @@ +/* Get return address register for frame. + Copyright (C) 2009 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "cfi.h" + +int +dwarf_frame_info (fs, start, end, signalp) + Dwarf_Frame *fs; + Dwarf_Addr *start; + Dwarf_Addr *end; + bool *signalp; +{ + /* Maybe there was a previous error. */ + if (fs == NULL) + return -1; + + if (start != NULL) + *start = fs->start; + if (end != NULL) + *end = fs->end; + if (signalp != NULL) + *signalp = fs->fde->cie->signal_frame; + return fs->fde->cie->return_address_register; +} diff --git a/3rdparty/elfutils/libdw/dwarf_frame_register.c b/3rdparty/elfutils/libdw/dwarf_frame_register.c new file mode 100644 index 0000000..10d2fe4 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_frame_register.c @@ -0,0 +1,123 @@ +/* Get register location expression for frame. + Copyright (C) 2009-2010, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "cfi.h" +#include <dwarf.h> + +int +dwarf_frame_register (fs, regno, ops_mem, ops, nops) + Dwarf_Frame *fs; + int regno; + Dwarf_Op ops_mem[3]; + Dwarf_Op **ops; + size_t *nops; +{ + /* Maybe there was a previous error. */ + if (fs == NULL) + return -1; + + if (unlikely (regno < 0)) + { + __libdw_seterrno (DWARF_E_INVALID_ACCESS); + return -1; + } + + *ops = ops_mem; + *nops = 0; + + if (unlikely ((size_t) regno >= fs->nregs)) + goto default_rule; + + const struct dwarf_frame_register *reg = &fs->regs[regno]; + + switch (reg->rule) + { + case reg_unspecified: + default_rule: + /* Use the default rule for registers not yet mentioned in CFI. */ + if (fs->cache->default_same_value) + goto same_value; + /*FALLTHROUGH*/ + case reg_undefined: + /* The value is known to be unavailable. */ + break; + + case reg_same_value: + same_value: + /* The location is not known here, but the caller might know it. */ + *ops = NULL; + break; + + case reg_offset: + case reg_val_offset: + ops_mem[(*nops)++] = (Dwarf_Op) { .atom = DW_OP_call_frame_cfa }; + if (reg->value != 0) + ops_mem[(*nops)++] = (Dwarf_Op) { .atom = DW_OP_plus_uconst, + .number = reg->value }; + if (reg->rule == reg_val_offset) + /* A value, not a location. */ + ops_mem[(*nops)++] = (Dwarf_Op) { .atom = DW_OP_stack_value }; + *ops = ops_mem; + break; + + case reg_register: + ops_mem[(*nops)++] = (Dwarf_Op) { .atom = DW_OP_regx, + .number = reg->value }; + break; + + case reg_val_expression: + case reg_expression: + { + unsigned int address_size = (fs->cache->e_ident[EI_CLASS] == ELFCLASS32 + ? 4 : 8); + + Dwarf_Block block; + const uint8_t *p = fs->cache->data->d.d_buf + reg->value; + const uint8_t *end = (fs->cache->data->d.d_buf + + fs->cache->data->d.d_size); + get_uleb128 (block.length, p, end); + block.data = (void *) p; + + /* Parse the expression into internal form. */ + if (__libdw_intern_expression (NULL, + fs->cache->other_byte_order, + address_size, 4, + &fs->cache->expr_tree, &block, + true, reg->rule == reg_val_expression, + ops, nops, IDX_debug_frame) < 0) + return -1; + break; + } + } + + return 0; +} diff --git a/3rdparty/elfutils/libdw/dwarf_func_inline.c b/3rdparty/elfutils/libdw/dwarf_func_inline.c new file mode 100644 index 0000000..bc9db1c --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_func_inline.c @@ -0,0 +1,101 @@ +/* Convenience functions for handling DWARF descriptions of inline functions. + Copyright (C) 2005,2006 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" +#include <dwarf.h> + +struct visitor_info +{ + void *die_addr; + int (*callback) (Dwarf_Die *, void *); + void *arg; +}; + +static int +scope_visitor (unsigned int depth __attribute__ ((unused)), + struct Dwarf_Die_Chain *die, void *arg) +{ + struct visitor_info *const v = arg; + + if (INTUSE(dwarf_tag) (&die->die) != DW_TAG_inlined_subroutine) + return DWARF_CB_OK; + + Dwarf_Attribute attr_mem; + Dwarf_Attribute *attr = INTUSE(dwarf_attr) (&die->die, DW_AT_abstract_origin, + &attr_mem); + if (attr == NULL) + return DWARF_CB_OK; + + Dwarf_Die origin_mem; + Dwarf_Die *origin = INTUSE(dwarf_formref_die) (attr, &origin_mem); + if (origin == NULL) + return DWARF_CB_ABORT; + + if (origin->addr != v->die_addr) + return DWARF_CB_OK; + + return (*v->callback) (&die->die, v->arg); +} + +int +dwarf_func_inline (Dwarf_Die *func) +{ + Dwarf_Attribute attr_mem; + Dwarf_Word val; + if (INTUSE(dwarf_formudata) (INTUSE(dwarf_attr) (func, DW_AT_inline, + &attr_mem), + &val) == 0) + switch (val) + { + case DW_INL_not_inlined: + return 0; + + case DW_INL_declared_not_inlined: + return -1; + + case DW_INL_inlined: + case DW_INL_declared_inlined: + return 1; + } + + return 0; +} + +int +dwarf_func_inline_instances (Dwarf_Die *func, + int (*callback) (Dwarf_Die *, void *), + void *arg) +{ + struct visitor_info v = { func->addr, callback, arg }; + struct Dwarf_Die_Chain cu = { .die = CUDIE (func->cu), .parent = NULL }; + return __libdw_visit_scopes (0, &cu, &scope_visitor, NULL, &v); +} diff --git a/3rdparty/elfutils/libdw/dwarf_getabbrev.c b/3rdparty/elfutils/libdw/dwarf_getabbrev.c new file mode 100644 index 0000000..0efde45 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_getabbrev.c @@ -0,0 +1,165 @@ +/* Get abbreviation at given offset. + Copyright (C) 2003, 2004, 2005, 2006, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +Dwarf_Abbrev * +internal_function +__libdw_getabbrev (dbg, cu, offset, lengthp, result) + Dwarf *dbg; + struct Dwarf_CU *cu; + Dwarf_Off offset; + size_t *lengthp; + Dwarf_Abbrev *result; +{ + /* Don't fail if there is not .debug_abbrev section. */ + if (dbg->sectiondata[IDX_debug_abbrev] == NULL) + return NULL; + + if (offset >= dbg->sectiondata[IDX_debug_abbrev]->d_size) + { + __libdw_seterrno (DWARF_E_INVALID_OFFSET); + return NULL; + } + + const unsigned char *abbrevp + = (unsigned char *) dbg->sectiondata[IDX_debug_abbrev]->d_buf + offset; + + if (*abbrevp == '\0') + /* We are past the last entry. */ + return DWARF_END_ABBREV; + + /* 7.5.3 Abbreviations Tables + + [...] Each declaration begins with an unsigned LEB128 number + representing the abbreviation code itself. [...] The + abbreviation code is followed by another unsigned LEB128 + number that encodes the entry's tag. [...] + + [...] Following the tag encoding is a 1-byte value that + determines whether a debugging information entry using this + abbreviation has child entries or not. [...] + + [...] Finally, the child encoding is followed by a series of + attribute specifications. Each attribute specification + consists of two parts. The first part is an unsigned LEB128 + number representing the attribute's name. The second part is + an unsigned LEB128 number representing the attribute's form. */ + const unsigned char *end = (dbg->sectiondata[IDX_debug_abbrev]->d_buf + + dbg->sectiondata[IDX_debug_abbrev]->d_size); + const unsigned char *start_abbrevp = abbrevp; + unsigned int code; + get_uleb128 (code, abbrevp, end); + + /* Check whether this code is already in the hash table. */ + bool foundit = false; + Dwarf_Abbrev *abb = NULL; + if (cu == NULL + || (abb = Dwarf_Abbrev_Hash_find (&cu->abbrev_hash, code, NULL)) == NULL) + { + if (result == NULL) + abb = libdw_typed_alloc (dbg, Dwarf_Abbrev); + else + abb = result; + } + else + { + foundit = true; + + if (unlikely (abb->offset != offset)) + { + /* A duplicate abbrev code at a different offset, + that should never happen. */ + invalid: + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; + } + + /* If the caller doesn't need the length we are done. */ + if (lengthp == NULL) + goto out; + } + + /* If there is already a value in the hash table we are going to + overwrite its content. This must not be a problem, since the + content better be the same. */ + abb->code = code; + if (abbrevp >= end) + goto invalid; + get_uleb128 (abb->tag, abbrevp, end); + if (abbrevp + 1 >= end) + goto invalid; + abb->has_children = *abbrevp++ == DW_CHILDREN_yes; + abb->attrp = (unsigned char *) abbrevp; + abb->offset = offset; + + /* Skip over all the attributes and count them while doing so. */ + abb->attrcnt = 0; + unsigned int attrname; + unsigned int attrform; + do + { + if (abbrevp >= end) + goto invalid; + get_uleb128 (attrname, abbrevp, end); + if (abbrevp >= end) + goto invalid; + get_uleb128 (attrform, abbrevp, end); + } + while (attrname != 0 && attrform != 0 && ++abb->attrcnt); + + /* Return the length to the caller if she asked for it. */ + if (lengthp != NULL) + *lengthp = abbrevp - start_abbrevp; + + /* Add the entry to the hash table. */ + if (cu != NULL && ! foundit) + (void) Dwarf_Abbrev_Hash_insert (&cu->abbrev_hash, abb->code, abb); + + out: + return abb; +} + + +Dwarf_Abbrev * +dwarf_getabbrev (die, offset, lengthp) + Dwarf_Die *die; + Dwarf_Off offset; + size_t *lengthp; +{ + return __libdw_getabbrev (die->cu->dbg, die->cu, + die->cu->orig_abbrev_offset + offset, lengthp, + NULL); +} diff --git a/3rdparty/elfutils/libdw/dwarf_getabbrevattr.c b/3rdparty/elfutils/libdw/dwarf_getabbrevattr.c new file mode 100644 index 0000000..574467c --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_getabbrevattr.c @@ -0,0 +1,80 @@ +/* Get specific attribute of abbreviation. + Copyright (C) 2003, 2004, 2005, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> +#include "libdwP.h" + + +int +dwarf_getabbrevattr (abbrev, idx, namep, formp, offsetp) + Dwarf_Abbrev *abbrev; + size_t idx; + unsigned int *namep; + unsigned int *formp; + Dwarf_Off *offsetp; +{ + if (abbrev == NULL) + return -1; + + size_t cnt = 0; + const unsigned char *attrp = abbrev->attrp; + const unsigned char *start_attrp; + unsigned int name; + unsigned int form; + + do + { + start_attrp = attrp; + + /* Attribute code and form are encoded as ULEB128 values.i + XXX We have no way to bounds check. */ + get_uleb128 (name, attrp, attrp + len_leb128 (name)); + get_uleb128 (form, attrp, attrp + len_leb128 (form)); + + /* If both values are zero the index is out of range. */ + if (name == 0 && form == 0) + return -1; + } + while (cnt++ < idx); + + /* Store the result if requested. */ + if (namep != NULL) + *namep = name; + if (formp != NULL) + *formp = form; + if (offsetp != NULL) + *offsetp = (start_attrp - abbrev->attrp) + abbrev->offset; + + return 0; +} diff --git a/3rdparty/elfutils/libdw/dwarf_getabbrevcode.c b/3rdparty/elfutils/libdw/dwarf_getabbrevcode.c new file mode 100644 index 0000000..0df9064 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_getabbrevcode.c @@ -0,0 +1,44 @@ +/* Get abbreviation code. + Copyright (C) 2003 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> +#include "libdwP.h" + + +unsigned int +dwarf_getabbrevcode (abbrev) + Dwarf_Abbrev *abbrev; +{ + return abbrev == NULL ? 0 : abbrev->code; +} diff --git a/3rdparty/elfutils/libdw/dwarf_getabbrevtag.c b/3rdparty/elfutils/libdw/dwarf_getabbrevtag.c new file mode 100644 index 0000000..36a5262 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_getabbrevtag.c @@ -0,0 +1,44 @@ +/* Get abbreviation tag. + Copyright (C) 2003 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> +#include "libdwP.h" + + +unsigned int +dwarf_getabbrevtag (abbrev) + Dwarf_Abbrev *abbrev; +{ + return abbrev == NULL ? 0 : abbrev->tag; +} diff --git a/3rdparty/elfutils/libdw/dwarf_getalt.c b/3rdparty/elfutils/libdw/dwarf_getalt.c new file mode 100644 index 0000000..cc434f0 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_getalt.c @@ -0,0 +1,42 @@ +/* Retrieves the DWARF descriptor for debugaltlink data. + Copyright (C) 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + +Dwarf * +dwarf_getalt (Dwarf *main) +{ + if (main == NULL) + return NULL; + return main->alt_dwarf; +} +INTDEF (dwarf_getalt) diff --git a/3rdparty/elfutils/libdw/dwarf_getarange_addr.c b/3rdparty/elfutils/libdw/dwarf_getarange_addr.c new file mode 100644 index 0000000..fc143de --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_getarange_addr.c @@ -0,0 +1,62 @@ +/* Get address range which includes given address. + Copyright (C) 2004, 2005 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libdwP.h> + + +Dwarf_Arange * +dwarf_getarange_addr (aranges, addr) + Dwarf_Aranges *aranges; + Dwarf_Addr addr; +{ + if (aranges == NULL) + return NULL; + + /* The ranges are sorted by address, so we can use binary search. */ + size_t l = 0, u = aranges->naranges; + while (l < u) + { + size_t idx = (l + u) / 2; + if (addr < aranges->info[idx].addr) + u = idx; + else if (addr > aranges->info[idx].addr + && addr - aranges->info[idx].addr >= aranges->info[idx].length) + l = idx + 1; + else + return &aranges->info[idx]; + } + + __libdw_seterrno (DWARF_E_NO_MATCH); + return NULL; +} +INTDEF(dwarf_getarange_addr) diff --git a/3rdparty/elfutils/libdw/dwarf_getarangeinfo.c b/3rdparty/elfutils/libdw/dwarf_getarangeinfo.c new file mode 100644 index 0000000..67b6e67 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_getarangeinfo.c @@ -0,0 +1,53 @@ +/* Return list address ranges. + Copyright (C) 2000, 2001, 2002, 2004, 2005 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libdwP.h> + + +int +dwarf_getarangeinfo (Dwarf_Arange *arange, Dwarf_Addr *addrp, + Dwarf_Word *lengthp, Dwarf_Off *offsetp) +{ + if (arange == NULL) + return -1; + + if (addrp != NULL) + *addrp = arange->addr; + if (lengthp != NULL) + *lengthp = arange->length; + if (offsetp != NULL) + *offsetp = arange->offset; + + return 0; +} +INTDEF(dwarf_getarangeinfo) diff --git a/3rdparty/elfutils/libdw/dwarf_getaranges.c b/3rdparty/elfutils/libdw/dwarf_getaranges.c new file mode 100644 index 0000000..4953af5 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_getaranges.c @@ -0,0 +1,265 @@ +/* Return list address ranges. + Copyright (C) 2000-2010 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> +#include <assert.h> +#include "libdwP.h" +#include <dwarf.h> + +struct arangelist +{ + Dwarf_Arange arange; + struct arangelist *next; +}; + +/* Compare by Dwarf_Arange.addr, given pointers into an array of pointeers. */ +static int +compare_aranges (const void *a, const void *b) +{ + struct arangelist *const *p1 = a, *const *p2 = b; + struct arangelist *l1 = *p1, *l2 = *p2; + if (l1->arange.addr != l2->arange.addr) + return (l1->arange.addr < l2->arange.addr) ? -1 : 1; + return 0; +} + +int +dwarf_getaranges (dbg, aranges, naranges) + Dwarf *dbg; + Dwarf_Aranges **aranges; + size_t *naranges; +{ + if (dbg == NULL) + return -1; + + if (dbg->aranges != NULL) + { + *aranges = dbg->aranges; + if (naranges != NULL) + *naranges = dbg->aranges->naranges; + return 0; + } + + if (dbg->sectiondata[IDX_debug_aranges] == NULL) + { + /* No such section. */ + *aranges = NULL; + if (naranges != NULL) + *naranges = 0; + return 0; + } + + if (dbg->sectiondata[IDX_debug_aranges]->d_buf == NULL) + return -1; + + struct arangelist *arangelist = NULL; + unsigned int narangelist = 0; + + const unsigned char *readp = dbg->sectiondata[IDX_debug_aranges]->d_buf; + const unsigned char *readendp + = readp + dbg->sectiondata[IDX_debug_aranges]->d_size; + + while (readp < readendp) + { + const unsigned char *hdrstart = readp; + + /* Each entry starts with a header: + + 1. A 4-byte or 12-byte length containing the length of the + set of entries for this compilation unit, not including the + length field itself. [...] + + 2. A 2-byte version identifier containing the value 2 for + DWARF Version 2.1. + + 3. A 4-byte or 8-byte offset into the .debug_info section. [...] + + 4. A 1-byte unsigned integer containing the size in bytes of + an address (or the offset portion of an address for segmented + addressing) on the target system. + + 5. A 1-byte unsigned integer containing the size in bytes of + a segment descriptor on the target system. */ + Dwarf_Word length = read_4ubyte_unaligned_inc (dbg, readp); + unsigned int length_bytes = 4; + if (length == DWARF3_LENGTH_64_BIT) + { + length = read_8ubyte_unaligned_inc (dbg, readp); + length_bytes = 8; + } + else if (unlikely (length >= DWARF3_LENGTH_MIN_ESCAPE_CODE + && length <= DWARF3_LENGTH_MAX_ESCAPE_CODE)) + goto invalid; + + unsigned int version = read_2ubyte_unaligned_inc (dbg, readp); + if (version != 2) + { + invalid: + __libdw_seterrno (DWARF_E_INVALID_DWARF); + fail: + while (arangelist != NULL) + { + struct arangelist *next = arangelist->next; + free (arangelist); + arangelist = next; + } + return -1; + } + + Dwarf_Word offset; + if (__libdw_read_offset_inc (dbg, + IDX_debug_aranges, &readp, + length_bytes, &offset, IDX_debug_info, 4)) + goto fail; + + unsigned int address_size = *readp++; + if (address_size != 4 && address_size != 8) + goto invalid; + + /* We don't actually support segment selectors. */ + unsigned int segment_size = *readp++; + if (segment_size != 0) + goto invalid; + + /* Round the address to the next multiple of 2*address_size. */ + readp += ((2 * address_size - ((readp - hdrstart) % (2 * address_size))) + % (2 * address_size)); + + while (1) + { + Dwarf_Word range_address; + Dwarf_Word range_length; + + if (__libdw_read_address_inc (dbg, IDX_debug_aranges, &readp, + address_size, &range_address)) + goto fail; + + if (address_size == 4) + range_length = read_4ubyte_unaligned_inc (dbg, readp); + else + range_length = read_8ubyte_unaligned_inc (dbg, readp); + + /* Two zero values mark the end. */ + if (range_address == 0 && range_length == 0) + break; + + /* We don't use alloca for these temporary structures because + the total number of them can be quite large. */ + struct arangelist *new_arange = malloc (sizeof *new_arange); + if (unlikely (new_arange == NULL)) + { + __libdw_seterrno (DWARF_E_NOMEM); + goto fail; + } + + new_arange->arange.addr = range_address; + new_arange->arange.length = range_length; + + /* We store the actual CU DIE offset, not the CU header offset. */ + const char *cu_header = (dbg->sectiondata[IDX_debug_info]->d_buf + + offset); + unsigned int offset_size; + if (read_4ubyte_unaligned_noncvt (cu_header) == DWARF3_LENGTH_64_BIT) + offset_size = 8; + else + offset_size = 4; + new_arange->arange.offset = DIE_OFFSET_FROM_CU_OFFSET (offset, + offset_size, + false); + + new_arange->next = arangelist; + arangelist = new_arange; + ++narangelist; + + /* Sanity-check the data. */ + if (unlikely (new_arange->arange.offset + >= dbg->sectiondata[IDX_debug_info]->d_size)) + goto invalid; + } + } + + if (narangelist == 0) + { + assert (arangelist == NULL); + if (naranges != NULL) + *naranges = 0; + *aranges = NULL; + return 0; + } + + /* Allocate the array for the result. */ + void *buf = libdw_alloc (dbg, Dwarf_Aranges, + sizeof (Dwarf_Aranges) + + narangelist * sizeof (Dwarf_Arange), 1); + + /* First use the buffer for the pointers, and sort the entries. + We'll write the pointers in the end of the buffer, and then + copy into the buffer from the beginning so the overlap works. */ + assert (sizeof (Dwarf_Arange) >= sizeof (Dwarf_Arange *)); + struct arangelist **sortaranges + = (buf + sizeof (Dwarf_Aranges) + + ((sizeof (Dwarf_Arange) - sizeof sortaranges[0]) * narangelist)); + + /* The list is in LIFO order and usually they come in clumps with + ascending addresses. So fill from the back to probably start with + runs already in order before we sort. */ + unsigned int i = narangelist; + while (i-- > 0) + { + sortaranges[i] = arangelist; + arangelist = arangelist->next; + } + assert (arangelist == NULL); + + /* Sort by ascending address. */ + qsort (sortaranges, narangelist, sizeof sortaranges[0], &compare_aranges); + + /* Now that they are sorted, put them in the final array. + The buffers overlap, so we've clobbered the early elements + of SORTARANGES by the time we're reading the later ones. */ + *aranges = buf; + (*aranges)->dbg = dbg; + (*aranges)->naranges = narangelist; + dbg->aranges = *aranges; + if (naranges != NULL) + *naranges = narangelist; + for (i = 0; i < narangelist; ++i) + { + struct arangelist *elt = sortaranges[i]; + (*aranges)->info[i] = elt->arange; + free (elt); + } + + return 0; +} +INTDEF(dwarf_getaranges) diff --git a/3rdparty/elfutils/libdw/dwarf_getattrcnt.c b/3rdparty/elfutils/libdw/dwarf_getattrcnt.c new file mode 100644 index 0000000..72be766 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_getattrcnt.c @@ -0,0 +1,48 @@ +/* Get number of attributes of abbreviation. + Copyright (C) 2003, 2004 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +int +dwarf_getattrcnt (abbrev, attrcntp) + Dwarf_Abbrev *abbrev; + size_t *attrcntp; +{ + if (abbrev == NULL) + return -1; + + *attrcntp = abbrev->attrcnt; + + return 0; +} diff --git a/3rdparty/elfutils/libdw/dwarf_getattrs.c b/3rdparty/elfutils/libdw/dwarf_getattrs.c new file mode 100644 index 0000000..0da8b5b --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_getattrs.c @@ -0,0 +1,120 @@ +/* Get attributes of the DIE. + Copyright (C) 2004, 2005, 2008, 2009, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +ptrdiff_t +dwarf_getattrs (Dwarf_Die *die, int (*callback) (Dwarf_Attribute *, void *), + void *arg, ptrdiff_t offset) +{ + if (die == NULL) + return -1l; + + if (unlikely (offset == 1)) + return 1; + + const unsigned char *die_addr; + + /* Find the abbreviation entry. */ + Dwarf_Abbrev *abbrevp = __libdw_dieabbrev (die, &die_addr); + + if (unlikely (abbrevp == DWARF_END_ABBREV)) + { + invalid_dwarf: + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1l; + } + + /* This is where the attributes start. */ + const unsigned char *attrp = abbrevp->attrp; + const unsigned char *const offset_attrp = abbrevp->attrp + offset; + + /* Go over the list of attributes. */ + Dwarf *dbg = die->cu->dbg; + const unsigned char *endp; + endp = ((const unsigned char *) dbg->sectiondata[IDX_debug_abbrev]->d_buf + + dbg->sectiondata[IDX_debug_abbrev]->d_size); + while (1) + { + /* Are we still in bounds? */ + if (unlikely (attrp >= endp)) + goto invalid_dwarf; + + /* Get attribute name and form. */ + Dwarf_Attribute attr; + const unsigned char *remembered_attrp = attrp; + + get_uleb128 (attr.code, attrp, endp); + if (unlikely (attrp >= endp)) + goto invalid_dwarf; + get_uleb128 (attr.form, attrp, endp); + + /* We can stop if we found the attribute with value zero. */ + if (attr.code == 0 && attr.form == 0) + /* Do not return 0 here - there would be no way to + distinguish this value from the attribute at offset 0. + Instead we return +1 which would never be a valid + offset of an attribute. */ + return 1l; + + /* If we are not to OFFSET_ATTRP yet, we just have to skip + the values of the intervening attributes. */ + if (remembered_attrp >= offset_attrp) + { + /* Fill in the rest. */ + attr.valp = (unsigned char *) die_addr; + attr.cu = die->cu; + + /* Now call the callback function. */ + if (callback (&attr, arg) != DWARF_CB_OK) + /* Return the offset of the start of the attribute, so that + dwarf_getattrs() can be restarted from this point if the + caller so desires. */ + return remembered_attrp - abbrevp->attrp; + } + + /* Skip over the rest of this attribute (if there is any). */ + if (attr.form != 0) + { + size_t len = __libdw_form_val_len (die->cu, attr.form, die_addr); + if (unlikely (len == (size_t) -1l)) + /* Something wrong with the file. */ + return -1l; + + // __libdw_form_val_len will have done a bounds check. + die_addr += len; + } + } + /* NOTREACHED */ +} diff --git a/3rdparty/elfutils/libdw/dwarf_getcfi.c b/3rdparty/elfutils/libdw/dwarf_getcfi.c new file mode 100644 index 0000000..a49a9f0 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_getcfi.c @@ -0,0 +1,73 @@ +/* Get CFI from DWARF file. + Copyright (C) 2009 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" +#include "cfi.h" +#include <dwarf.h> + +Dwarf_CFI * +dwarf_getcfi (dbg) + Dwarf *dbg; +{ + if (dbg == NULL) + return NULL; + + if (dbg->cfi == NULL && dbg->sectiondata[IDX_debug_frame] != NULL) + { + Dwarf_CFI *cfi = libdw_typed_alloc (dbg, Dwarf_CFI); + + cfi->dbg = dbg; + cfi->data = (Elf_Data_Scn *) dbg->sectiondata[IDX_debug_frame]; + + cfi->search_table = NULL; + cfi->search_table_vaddr = 0; + cfi->search_table_entries = 0; + cfi->search_table_encoding = DW_EH_PE_omit; + + cfi->frame_vaddr = 0; + cfi->textrel = 0; + cfi->datarel = 0; + + cfi->e_ident = (unsigned char *) elf_getident (dbg->elf, NULL); + cfi->other_byte_order = dbg->other_byte_order; + + cfi->next_offset = 0; + cfi->cie_tree = cfi->fde_tree = cfi->expr_tree = NULL; + + cfi->ebl = NULL; + + dbg->cfi = cfi; + } + + return dbg->cfi; +} +INTDEF (dwarf_getcfi) diff --git a/3rdparty/elfutils/libdw/dwarf_getcfi_elf.c b/3rdparty/elfutils/libdw/dwarf_getcfi_elf.c new file mode 100644 index 0000000..61ca60d --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_getcfi_elf.c @@ -0,0 +1,320 @@ +/* Get CFI from ELF file's exception-handling info. + Copyright (C) 2009-2010, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#include "libdwP.h" +#include "cfi.h" +#include "encoded-value.h" +#include <dwarf.h> + + +static Dwarf_CFI * +allocate_cfi (Elf *elf, GElf_Addr vaddr) +{ + Dwarf_CFI *cfi = calloc (1, sizeof *cfi); + if (cfi == NULL) + { + __libdw_seterrno (DWARF_E_NOMEM); + return NULL; + } + + cfi->e_ident = (unsigned char *) elf_getident (elf, NULL); + if (cfi->e_ident == NULL) + { + free (cfi); + __libdw_seterrno (DWARF_E_GETEHDR_ERROR); + return NULL; + } + + if ((BYTE_ORDER == LITTLE_ENDIAN && cfi->e_ident[EI_DATA] == ELFDATA2MSB) + || (BYTE_ORDER == BIG_ENDIAN && cfi->e_ident[EI_DATA] == ELFDATA2LSB)) + cfi->other_byte_order = true; + + cfi->frame_vaddr = vaddr; + cfi->textrel = 0; /* XXX ? */ + cfi->datarel = 0; /* XXX ? */ + + return cfi; +} + +static const uint8_t * +parse_eh_frame_hdr (const uint8_t *hdr, size_t hdr_size, GElf_Addr hdr_vaddr, + const GElf_Ehdr *ehdr, GElf_Addr *eh_frame_vaddr, + size_t *table_entries, uint8_t *table_encoding) +{ + const uint8_t *h = hdr; + + if (*h++ != 1) /* version */ + return (void *) -1l; + + uint8_t eh_frame_ptr_encoding = *h++; + uint8_t fde_count_encoding = *h++; + uint8_t fde_table_encoding = *h++; + + if (eh_frame_ptr_encoding == DW_EH_PE_omit) + return (void *) -1l; + + /* Dummy used by read_encoded_value. */ + Elf_Data_Scn dummy_cfi_hdr_data = + { + .d = { .d_buf = (void *) hdr, .d_size = hdr_size } + }; + Dwarf_CFI dummy_cfi = + { + .e_ident = ehdr->e_ident, + .datarel = hdr_vaddr, + .frame_vaddr = hdr_vaddr, + .data = &dummy_cfi_hdr_data, + }; + + if (unlikely (read_encoded_value (&dummy_cfi, eh_frame_ptr_encoding, &h, + eh_frame_vaddr))) + return (void *) -1l; + + if (fde_count_encoding != DW_EH_PE_omit) + { + Dwarf_Word fde_count; + if (unlikely (read_encoded_value (&dummy_cfi, fde_count_encoding, &h, + &fde_count))) + return (void *) -1l; + if (fde_count != 0 && (size_t) fde_count == fde_count + && fde_table_encoding != DW_EH_PE_omit + && (fde_table_encoding &~ DW_EH_PE_signed) != DW_EH_PE_uleb128) + { + *table_entries = fde_count; + *table_encoding = fde_table_encoding; + return h; + } + } + + return NULL; +} + +static Dwarf_CFI * +getcfi_gnu_eh_frame (Elf *elf, const GElf_Ehdr *ehdr, const GElf_Phdr *phdr) +{ + if (unlikely (phdr->p_filesz < 4)) + goto invalid; + + Elf_Data *data = elf_getdata_rawchunk (elf, phdr->p_offset, phdr->p_filesz, + ELF_T_BYTE); + if (data == NULL) + { + invalid_hdr: + invalid: + /* XXX might be read error or corrupt phdr */ + __libdw_seterrno (DWARF_E_INVALID_CFI); + return NULL; + } + + Dwarf_Addr eh_frame_ptr; + size_t search_table_entries = 0; + uint8_t search_table_encoding = 0; + const uint8_t *search_table = parse_eh_frame_hdr (data->d_buf, phdr->p_filesz, + phdr->p_vaddr, ehdr, + &eh_frame_ptr, + &search_table_entries, + &search_table_encoding); + if (search_table == (void *) -1l) + goto invalid_hdr; + + Dwarf_Off eh_frame_offset = eh_frame_ptr - phdr->p_vaddr + phdr->p_offset; + Dwarf_Word eh_frame_size = 0; + + /* XXX we have no way without section headers to know the size + of the .eh_frame data. Calculate the largest it might possibly be. + This won't be wasteful if the file is already mmap'd, but if it isn't + it might be quite excessive. */ + size_t filesize; + if (elf_rawfile (elf, &filesize) != NULL) + eh_frame_size = filesize - eh_frame_offset; + + data = elf_getdata_rawchunk (elf, eh_frame_offset, eh_frame_size, ELF_T_BYTE); + if (data == NULL) + { + __libdw_seterrno (DWARF_E_INVALID_ELF); /* XXX might be read error */ + return NULL; + } + Dwarf_CFI *cfi = allocate_cfi (elf, eh_frame_ptr); + if (cfi != NULL) + { + cfi->data = (Elf_Data_Scn *) data; + + if (search_table != NULL) + { + cfi->search_table = search_table; + cfi->search_table_vaddr = phdr->p_vaddr; + cfi->search_table_encoding = search_table_encoding; + cfi->search_table_entries = search_table_entries; + } + } + return cfi; +} + +/* Search the phdrs for PT_GNU_EH_FRAME. */ +static Dwarf_CFI * +getcfi_phdr (Elf *elf, const GElf_Ehdr *ehdr) +{ + size_t phnum; + if (unlikely (elf_getphdrnum (elf, &phnum) != 0)) + return NULL; + + for (size_t i = 0; i < phnum; ++i) + { + GElf_Phdr phdr_mem; + GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem); + if (unlikely (phdr == NULL)) + return NULL; + if (phdr->p_type == PT_GNU_EH_FRAME) + return getcfi_gnu_eh_frame (elf, ehdr, phdr); + } + + __libdw_seterrno (DWARF_E_NO_DWARF); + return NULL; +} + +static Dwarf_CFI * +getcfi_scn_eh_frame (Elf *elf, const GElf_Ehdr *ehdr, + Elf_Scn *scn, GElf_Shdr *shdr, + Elf_Scn *hdr_scn, GElf_Addr hdr_vaddr) +{ + Elf_Data *data = elf_rawdata (scn, NULL); + if (data == NULL) + { + __libdw_seterrno (DWARF_E_INVALID_ELF); + return NULL; + } + Dwarf_CFI *cfi = allocate_cfi (elf, shdr->sh_addr); + if (cfi != NULL) + { + cfi->data = (Elf_Data_Scn *) data; + if (hdr_scn != NULL) + { + Elf_Data *hdr_data = elf_rawdata (hdr_scn, NULL); + if (hdr_data != NULL) + { + GElf_Addr eh_frame_vaddr; + cfi->search_table_vaddr = hdr_vaddr; + cfi->search_table + = parse_eh_frame_hdr (hdr_data->d_buf, hdr_data->d_size, + hdr_vaddr, ehdr, &eh_frame_vaddr, + &cfi->search_table_entries, + &cfi->search_table_encoding); + if (cfi->search_table == (void *) -1l) + { + free (cfi); + /* XXX might be read error or corrupt phdr */ + __libdw_seterrno (DWARF_E_INVALID_CFI); + return NULL; + } + + /* Sanity check. */ + if (unlikely (eh_frame_vaddr != shdr->sh_addr)) + cfi->search_table = NULL; + } + } + } + return cfi; +} + +/* Search for the sections named ".eh_frame" and ".eh_frame_hdr". */ +static Dwarf_CFI * +getcfi_shdr (Elf *elf, const GElf_Ehdr *ehdr) +{ + size_t shstrndx; + if (elf_getshdrstrndx (elf, &shstrndx) != 0) + { + __libdw_seterrno (DWARF_E_GETEHDR_ERROR); + return NULL; + } + + if (shstrndx != 0) + { + Elf_Scn *hdr_scn = NULL; + GElf_Addr hdr_vaddr = 0; + Elf_Scn *scn = NULL; + while ((scn = elf_nextscn (elf, scn)) != NULL) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + if (shdr == NULL) + continue; + const char *name = elf_strptr (elf, shstrndx, shdr->sh_name); + if (name == NULL) + continue; + if (!strcmp (name, ".eh_frame_hdr")) + { + hdr_scn = scn; + hdr_vaddr = shdr->sh_addr; + } + else if (!strcmp (name, ".eh_frame")) + { + if (shdr->sh_type == SHT_PROGBITS) + return getcfi_scn_eh_frame (elf, ehdr, scn, shdr, + hdr_scn, hdr_vaddr); + else + return NULL; + } + } + } + + return (void *) -1l; +} + +Dwarf_CFI * +dwarf_getcfi_elf (elf) + Elf *elf; +{ + if (elf_kind (elf) != ELF_K_ELF) + { + __libdw_seterrno (DWARF_E_NOELF); + return NULL; + } + + GElf_Ehdr ehdr_mem; + GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem); + if (unlikely (ehdr == NULL)) + { + __libdw_seterrno (DWARF_E_INVALID_ELF); + return NULL; + } + + Dwarf_CFI *result = getcfi_shdr (elf, ehdr); + if (result == (void *) -1l) + result = getcfi_phdr (elf, ehdr); + + return result; +} +INTDEF (dwarf_getcfi_elf) diff --git a/3rdparty/elfutils/libdw/dwarf_getelf.c b/3rdparty/elfutils/libdw/dwarf_getelf.c new file mode 100644 index 0000000..ecd1859 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_getelf.c @@ -0,0 +1,48 @@ +/* Retrieve ELF descriptor used for DWARF access. + Copyright (C) 2002, 2004, 2007 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stddef.h> + +#include "libdwP.h" + + +Elf * +dwarf_getelf (dwarf) + Dwarf *dwarf; +{ + if (dwarf == NULL) + /* Some error occurred before. */ + return NULL; + + return dwarf->elf; +} diff --git a/3rdparty/elfutils/libdw/dwarf_getfuncs.c b/3rdparty/elfutils/libdw/dwarf_getfuncs.c new file mode 100644 index 0000000..f79b0a7 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_getfuncs.c @@ -0,0 +1,118 @@ +/* Get function information. + Copyright (C) 2005, 2013 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2005. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +struct visitor_info +{ + /* The user callback of dwarf_getfuncs. */ + int (*callback) (Dwarf_Die *, void *); + + /* The user arg value to dwarf_getfuncs. */ + void *arg; + + /* Addr of the DIE offset where to (re)start the search. Zero for all. */ + void *start_addr; + + /* Last subprogram DIE addr seen. */ + void *last_addr; + + /* The CU only contains C functions. Allows pruning of most subtrees. */ + bool c_cu; +}; + +static int +tree_visitor (unsigned int depth __attribute__ ((unused)), + struct Dwarf_Die_Chain *chain, void *arg) +{ + struct visitor_info *const v = arg; + Dwarf_Die *die = &chain->die; + void *start_addr = v->start_addr; + void *die_addr = die->addr; + + /* Pure C CUs can only contain defining subprogram DIEs as direct + children of the CU DIE or as nested function inside a normal C + code constructs. */ + int tag = INTUSE(dwarf_tag) (die); + if (v->c_cu + && tag != DW_TAG_subprogram + && tag != DW_TAG_lexical_block + && tag != DW_TAG_inlined_subroutine) + { + chain->prune = true; + return DWARF_CB_OK; + } + + /* Skip all DIEs till we found the (re)start addr. */ + if (start_addr != NULL) + { + if (die_addr == start_addr) + v->start_addr = NULL; + return DWARF_CB_OK; + } + + /* If this isn't a (defining) subprogram entity, skip DIE. */ + if (tag != DW_TAG_subprogram + || INTUSE(dwarf_hasattr) (die, DW_AT_declaration)) + return DWARF_CB_OK; + + v->last_addr = die_addr; + return (*v->callback) (die, v->arg); +} + +ptrdiff_t +dwarf_getfuncs (Dwarf_Die *cudie, int (*callback) (Dwarf_Die *, void *), + void *arg, ptrdiff_t offset) +{ + if (unlikely (cudie == NULL + || INTUSE(dwarf_tag) (cudie) != DW_TAG_compile_unit)) + return -1; + + int lang = INTUSE(dwarf_srclang) (cudie); + bool c_cu = (lang == DW_LANG_C89 + || lang == DW_LANG_C + || lang == DW_LANG_C99 + || lang == DW_LANG_C11); + + struct visitor_info v = { callback, arg, (void *) offset, NULL, c_cu }; + struct Dwarf_Die_Chain chain = { .die = CUDIE (cudie->cu), + .parent = NULL }; + int res = __libdw_visit_scopes (0, &chain, &tree_visitor, NULL, &v); + + if (res == DWARF_CB_ABORT) + return (ptrdiff_t) v.last_addr; + else + return res; +} diff --git a/3rdparty/elfutils/libdw/dwarf_getlocation.c b/3rdparty/elfutils/libdw/dwarf_getlocation.c new file mode 100644 index 0000000..068f385 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_getlocation.c @@ -0,0 +1,853 @@ +/* Return location expression list. + Copyright (C) 2000-2010, 2013, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include <search.h> +#include <stdlib.h> +#include <assert.h> + +#include <libdwP.h> + + +static bool +attr_ok (Dwarf_Attribute *attr) +{ + if (attr == NULL) + return false; + + /* Must be one of the attributes listed below. */ + switch (attr->code) + { + case DW_AT_location: + case DW_AT_data_member_location: + case DW_AT_vtable_elem_location: + case DW_AT_string_length: + case DW_AT_use_location: + case DW_AT_frame_base: + case DW_AT_return_addr: + case DW_AT_static_link: + case DW_AT_segment: + case DW_AT_GNU_call_site_value: + case DW_AT_GNU_call_site_data_value: + case DW_AT_GNU_call_site_target: + case DW_AT_GNU_call_site_target_clobbered: + break; + + default: + __libdw_seterrno (DWARF_E_NO_LOCLIST); + return false; + } + + return true; +} + + +struct loclist +{ + uint8_t atom; + Dwarf_Word number; + Dwarf_Word number2; + Dwarf_Word offset; + struct loclist *next; +}; + + +static int +loc_compare (const void *p1, const void *p2) +{ + const struct loc_s *l1 = (const struct loc_s *) p1; + const struct loc_s *l2 = (const struct loc_s *) p2; + + if ((uintptr_t) l1->addr < (uintptr_t) l2->addr) + return -1; + if ((uintptr_t) l1->addr > (uintptr_t) l2->addr) + return 1; + + return 0; +} + +/* For each DW_OP_implicit_value, we store a special entry in the cache. + This points us directly to the block data for later fetching. */ +static void +store_implicit_value (Dwarf *dbg, void **cache, Dwarf_Op *op) +{ + struct loc_block_s *block = libdw_alloc (dbg, struct loc_block_s, + sizeof (struct loc_block_s), 1); + const unsigned char *data = (const unsigned char *) (uintptr_t) op->number2; + // Ignored, equal to op->number. And data length already checked. + (void) __libdw_get_uleb128 (&data, data + len_leb128 (Dwarf_Word)); + block->addr = op; + block->data = (unsigned char *) data; + block->length = op->number; + (void) tsearch (block, cache, loc_compare); +} + +int +dwarf_getlocation_implicit_value (attr, op, return_block) + Dwarf_Attribute *attr; + const Dwarf_Op *op; + Dwarf_Block *return_block; +{ + if (attr == NULL) + return -1; + + struct loc_block_s fake = { .addr = (void *) op }; + struct loc_block_s **found = tfind (&fake, &attr->cu->locs, loc_compare); + if (unlikely (found == NULL)) + { + __libdw_seterrno (DWARF_E_NO_BLOCK); + return -1; + } + + return_block->length = (*found)->length; + return_block->data = (*found)->data; + return 0; +} + +/* DW_AT_data_member_location can be a constant as well as a loclistptr. + Only data[48] indicate a loclistptr. */ +static int +check_constant_offset (Dwarf_Attribute *attr, + Dwarf_Op **llbuf, size_t *listlen) +{ + if (attr->code != DW_AT_data_member_location) + return 1; + + switch (attr->form) + { + /* Punt for any non-constant form. */ + default: + return 1; + + case DW_FORM_data1: + case DW_FORM_data2: + case DW_FORM_data4: + case DW_FORM_data8: + case DW_FORM_sdata: + case DW_FORM_udata: + break; + } + + /* Check whether we already cached this location. */ + struct loc_s fake = { .addr = attr->valp }; + struct loc_s **found = tfind (&fake, &attr->cu->locs, loc_compare); + + if (found == NULL) + { + Dwarf_Word offset; + if (INTUSE(dwarf_formudata) (attr, &offset) != 0) + return -1; + + Dwarf_Op *result = libdw_alloc (attr->cu->dbg, + Dwarf_Op, sizeof (Dwarf_Op), 1); + + result->atom = DW_OP_plus_uconst; + result->number = offset; + result->number2 = 0; + result->offset = 0; + + /* Insert a record in the search tree so we can find it again later. */ + struct loc_s *newp = libdw_alloc (attr->cu->dbg, + struct loc_s, sizeof (struct loc_s), + 1); + newp->addr = attr->valp; + newp->loc = result; + newp->nloc = 1; + + found = tsearch (newp, &attr->cu->locs, loc_compare); + } + + assert ((*found)->nloc == 1); + + if (llbuf != NULL) + { + *llbuf = (*found)->loc; + *listlen = 1; + } + + return 0; +} + +int +internal_function +__libdw_intern_expression (Dwarf *dbg, bool other_byte_order, + unsigned int address_size, unsigned int ref_size, + void **cache, const Dwarf_Block *block, + bool cfap, bool valuep, + Dwarf_Op **llbuf, size_t *listlen, int sec_index) +{ + /* Empty location expressions don't have any ops to intern. */ + if (block->length == 0) + { + *listlen = 0; + return 0; + } + + /* Check whether we already looked at this list. */ + struct loc_s fake = { .addr = block->data }; + struct loc_s **found = tfind (&fake, cache, loc_compare); + if (found != NULL) + { + /* We already saw it. */ + *llbuf = (*found)->loc; + *listlen = (*found)->nloc; + + if (valuep) + { + assert (*listlen > 1); + assert ((*llbuf)[*listlen - 1].atom == DW_OP_stack_value); + } + + return 0; + } + + const unsigned char *data = block->data; + const unsigned char *const end_data = data + block->length; + + const struct { bool other_byte_order; } bo = { other_byte_order }; + + struct loclist *loclist = NULL; + unsigned int n = 0; + + if (cfap) + { + /* Synthesize the operation to push the CFA before the expression. */ + struct loclist *newloc; + newloc = (struct loclist *) alloca (sizeof (struct loclist)); + newloc->atom = DW_OP_call_frame_cfa; + newloc->number = 0; + newloc->number2 = 0; + newloc->offset = -1; + newloc->next = loclist; + loclist = newloc; + ++n; + } + + /* Decode the opcodes. It is possible in some situations to have a + block of size zero. */ + while (data < end_data) + { + struct loclist *newloc; + newloc = (struct loclist *) alloca (sizeof (struct loclist)); + newloc->number = 0; + newloc->number2 = 0; + newloc->offset = data - block->data; + newloc->next = loclist; + loclist = newloc; + ++n; + + switch ((newloc->atom = *data++)) + { + case DW_OP_addr: + /* Address, depends on address size of CU. */ + if (__libdw_read_address_inc (dbg, sec_index, &data, + address_size, &newloc->number)) + return -1; + break; + + case DW_OP_call_ref: + /* DW_FORM_ref_addr, depends on offset size of CU. */ + if (__libdw_read_offset_inc (dbg, sec_index, &data, ref_size, + &newloc->number, IDX_debug_info, 0)) + return -1; + break; + + case DW_OP_deref: + case DW_OP_dup: + case DW_OP_drop: + case DW_OP_over: + case DW_OP_swap: + case DW_OP_rot: + case DW_OP_xderef: + case DW_OP_abs: + case DW_OP_and: + case DW_OP_div: + case DW_OP_minus: + case DW_OP_mod: + case DW_OP_mul: + case DW_OP_neg: + case DW_OP_not: + case DW_OP_or: + case DW_OP_plus: + case DW_OP_shl: + case DW_OP_shr: + case DW_OP_shra: + case DW_OP_xor: + case DW_OP_eq: + case DW_OP_ge: + case DW_OP_gt: + case DW_OP_le: + case DW_OP_lt: + case DW_OP_ne: + case DW_OP_lit0 ... DW_OP_lit31: + case DW_OP_reg0 ... DW_OP_reg31: + case DW_OP_nop: + case DW_OP_push_object_address: + case DW_OP_call_frame_cfa: + case DW_OP_form_tls_address: + case DW_OP_GNU_push_tls_address: + case DW_OP_stack_value: + /* No operand. */ + break; + + case DW_OP_const1u: + case DW_OP_pick: + case DW_OP_deref_size: + case DW_OP_xderef_size: + if (unlikely (data >= end_data)) + { + invalid: + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } + + newloc->number = *data++; + break; + + case DW_OP_const1s: + if (unlikely (data >= end_data)) + goto invalid; + + newloc->number = *((int8_t *) data); + ++data; + break; + + case DW_OP_const2u: + if (unlikely (data + 2 > end_data)) + goto invalid; + + newloc->number = read_2ubyte_unaligned_inc (&bo, data); + break; + + case DW_OP_const2s: + case DW_OP_skip: + case DW_OP_bra: + case DW_OP_call2: + if (unlikely (data + 2 > end_data)) + goto invalid; + + newloc->number = read_2sbyte_unaligned_inc (&bo, data); + break; + + case DW_OP_const4u: + if (unlikely (data + 4 > end_data)) + goto invalid; + + newloc->number = read_4ubyte_unaligned_inc (&bo, data); + break; + + case DW_OP_const4s: + case DW_OP_call4: + case DW_OP_GNU_parameter_ref: + if (unlikely (data + 4 > end_data)) + goto invalid; + + newloc->number = read_4sbyte_unaligned_inc (&bo, data); + break; + + case DW_OP_const8u: + if (unlikely (data + 8 > end_data)) + goto invalid; + + newloc->number = read_8ubyte_unaligned_inc (&bo, data); + break; + + case DW_OP_const8s: + if (unlikely (data + 8 > end_data)) + goto invalid; + + newloc->number = read_8sbyte_unaligned_inc (&bo, data); + break; + + case DW_OP_constu: + case DW_OP_plus_uconst: + case DW_OP_regx: + case DW_OP_piece: + case DW_OP_GNU_convert: + case DW_OP_GNU_reinterpret: + get_uleb128 (newloc->number, data, end_data); + break; + + case DW_OP_consts: + case DW_OP_breg0 ... DW_OP_breg31: + case DW_OP_fbreg: + get_sleb128 (newloc->number, data, end_data); + break; + + case DW_OP_bregx: + get_uleb128 (newloc->number, data, end_data); + if (unlikely (data >= end_data)) + goto invalid; + get_sleb128 (newloc->number2, data, end_data); + break; + + case DW_OP_bit_piece: + case DW_OP_GNU_regval_type: + get_uleb128 (newloc->number, data, end_data); + if (unlikely (data >= end_data)) + goto invalid; + get_uleb128 (newloc->number2, data, end_data); + break; + + case DW_OP_implicit_value: + case DW_OP_GNU_entry_value: + /* This cannot be used in a CFI expression. */ + if (unlikely (dbg == NULL)) + goto invalid; + + /* start of block inc. len. */ + newloc->number2 = (Dwarf_Word) (uintptr_t) data; + get_uleb128 (newloc->number, data, end_data); /* Block length. */ + if (unlikely ((Dwarf_Word) (end_data - data) < newloc->number)) + goto invalid; + data += newloc->number; /* Skip the block. */ + break; + + case DW_OP_GNU_implicit_pointer: + /* DW_FORM_ref_addr, depends on offset size of CU. */ + if (__libdw_read_offset_inc (dbg, sec_index, &data, ref_size, + &newloc->number, IDX_debug_info, 0)) + return -1; + if (unlikely (data >= end_data)) + goto invalid; + get_uleb128 (newloc->number2, data, end_data); /* Byte offset. */ + break; + + case DW_OP_GNU_deref_type: + if (unlikely (data + 1 >= end_data)) + goto invalid; + newloc->number = *data++; + get_uleb128 (newloc->number2, data, end_data); + break; + + case DW_OP_GNU_const_type: + { + size_t size; + get_uleb128 (newloc->number, data, end_data); + if (unlikely (data >= end_data)) + goto invalid; + + /* start of block inc. len. */ + newloc->number2 = (Dwarf_Word) (uintptr_t) data; + size = *data++; + if (unlikely ((Dwarf_Word) (end_data - data) < size)) + goto invalid; + data += size; /* Skip the block. */ + } + break; + + default: + goto invalid; + } + } + + if (unlikely (n == 0)) + { + /* This is not allowed. + It would mean an empty location expression, which we handled + already as a special case above. */ + goto invalid; + } + + if (valuep) + { + struct loclist *newloc; + newloc = (struct loclist *) alloca (sizeof (struct loclist)); + newloc->atom = DW_OP_stack_value; + newloc->number = 0; + newloc->number2 = 0; + newloc->offset = data - block->data; + newloc->next = loclist; + loclist = newloc; + ++n; + } + + /* Allocate the array. */ + Dwarf_Op *result; + if (dbg != NULL) + result = libdw_alloc (dbg, Dwarf_Op, sizeof (Dwarf_Op), n); + else + { + result = malloc (sizeof *result * n); + if (result == NULL) + { + nomem: + __libdw_seterrno (DWARF_E_NOMEM); + return -1; + } + } + + /* Store the result. */ + *llbuf = result; + *listlen = n; + + do + { + /* We populate the array from the back since the list is backwards. */ + --n; + result[n].atom = loclist->atom; + result[n].number = loclist->number; + result[n].number2 = loclist->number2; + result[n].offset = loclist->offset; + + if (result[n].atom == DW_OP_implicit_value) + store_implicit_value (dbg, cache, &result[n]); + + loclist = loclist->next; + } + while (n > 0); + + /* Insert a record in the search tree so that we can find it again later. */ + struct loc_s *newp; + if (dbg != NULL) + newp = libdw_alloc (dbg, struct loc_s, sizeof (struct loc_s), 1); + else + { + newp = malloc (sizeof *newp); + if (newp == NULL) + { + free (result); + goto nomem; + } + } + + newp->addr = block->data; + newp->loc = result; + newp->nloc = *listlen; + (void) tsearch (newp, cache, loc_compare); + + /* We did it. */ + return 0; +} + +static int +getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block, + Dwarf_Op **llbuf, size_t *listlen, int sec_index) +{ + /* Empty location expressions don't have any ops to intern. + Note that synthetic empty_cu doesn't have an associated DWARF dbg. */ + if (block->length == 0) + { + *listlen = 0; + return 0; + } + + return __libdw_intern_expression (cu->dbg, cu->dbg->other_byte_order, + cu->address_size, (cu->version == 2 + ? cu->address_size + : cu->offset_size), + &cu->locs, block, + false, false, + llbuf, listlen, sec_index); +} + +int +dwarf_getlocation (attr, llbuf, listlen) + Dwarf_Attribute *attr; + Dwarf_Op **llbuf; + size_t *listlen; +{ + if (! attr_ok (attr)) + return -1; + + int result = check_constant_offset (attr, llbuf, listlen); + if (result != 1) + return result; + + /* If it has a block form, it's a single location expression. */ + Dwarf_Block block; + if (INTUSE(dwarf_formblock) (attr, &block) != 0) + return -1; + + return getlocation (attr->cu, &block, llbuf, listlen, cu_sec_idx (attr->cu)); +} + +static int +attr_base_address (attr, basep) + Dwarf_Attribute *attr; + Dwarf_Addr *basep; +{ + /* Fetch the CU's base address. */ + Dwarf_Die cudie = CUDIE (attr->cu); + + /* Find the base address of the compilation unit. It will + normally be specified by DW_AT_low_pc. In DWARF-3 draft 4, + the base address could be overridden by DW_AT_entry_pc. It's + been removed, but GCC emits DW_AT_entry_pc and not DW_AT_lowpc + for compilation units with discontinuous ranges. */ + Dwarf_Attribute attr_mem; + if (unlikely (INTUSE(dwarf_lowpc) (&cudie, basep) != 0) + && INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (&cudie, + DW_AT_entry_pc, + &attr_mem), + basep) != 0) + { + if (INTUSE(dwarf_errno) () != 0) + return -1; + + /* The compiler provided no base address when it should + have. Buggy GCC does this when it used absolute + addresses in the location list and no DW_AT_ranges. */ + *basep = 0; + } + return 0; +} + +static int +initial_offset_base (attr, offset, basep) + Dwarf_Attribute *attr; + ptrdiff_t *offset; + Dwarf_Addr *basep; +{ + if (attr_base_address (attr, basep) != 0) + return -1; + + Dwarf_Word start_offset; + if (__libdw_formptr (attr, IDX_debug_loc, + DWARF_E_NO_LOCLIST, + NULL, &start_offset) == NULL) + return -1; + + *offset = start_offset; + return 0; +} + +static ptrdiff_t +getlocations_addr (attr, offset, basep, startp, endp, address, + locs, expr, exprlen) + Dwarf_Attribute *attr; + ptrdiff_t offset; + Dwarf_Addr *basep; + Dwarf_Addr *startp; + Dwarf_Addr *endp; + Dwarf_Addr address; + Elf_Data *locs; + Dwarf_Op **expr; + size_t *exprlen; +{ + unsigned char *readp = locs->d_buf + offset; + unsigned char *readendp = locs->d_buf + locs->d_size; + + next: + if (readendp - readp < attr->cu->address_size * 2) + { + invalid: + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } + + Dwarf_Addr begin; + Dwarf_Addr end; + + switch (__libdw_read_begin_end_pair_inc (attr->cu->dbg, IDX_debug_loc, + &readp, attr->cu->address_size, + &begin, &end, basep)) + { + case 0: /* got location range. */ + break; + case 1: /* base address setup. */ + goto next; + case 2: /* end of loclist */ + return 0; + default: /* error */ + return -1; + } + + if (readendp - readp < 2) + goto invalid; + + /* We have a location expression. */ + Dwarf_Block block; + block.length = read_2ubyte_unaligned_inc (attr->cu->dbg, readp); + block.data = readp; + if (readendp - readp < (ptrdiff_t) block.length) + goto invalid; + readp += block.length; + + *startp = *basep + begin; + *endp = *basep + end; + + /* If address is minus one we want them all, otherwise only matching. */ + if (address != (Dwarf_Word) -1 && (address < *startp || address >= *endp)) + goto next; + + if (getlocation (attr->cu, &block, expr, exprlen, IDX_debug_loc) != 0) + return -1; + + return readp - (unsigned char *) locs->d_buf; +} + +int +dwarf_getlocation_addr (attr, address, llbufs, listlens, maxlocs) + Dwarf_Attribute *attr; + Dwarf_Addr address; + Dwarf_Op **llbufs; + size_t *listlens; + size_t maxlocs; +{ + if (! attr_ok (attr)) + return -1; + + if (llbufs == NULL) + maxlocs = SIZE_MAX; + + /* If it has a block form, it's a single location expression. */ + Dwarf_Block block; + if (INTUSE(dwarf_formblock) (attr, &block) == 0) + { + if (maxlocs == 0) + return 0; + if (llbufs != NULL && + getlocation (attr->cu, &block, &llbufs[0], &listlens[0], + cu_sec_idx (attr->cu)) != 0) + return -1; + return listlens[0] == 0 ? 0 : 1; + } + + int error = INTUSE(dwarf_errno) (); + if (unlikely (error != DWARF_E_NO_BLOCK)) + { + __libdw_seterrno (error); + return -1; + } + + int result = check_constant_offset (attr, &llbufs[0], &listlens[0]); + if (result != 1) + return result ?: 1; + + Dwarf_Addr base, start, end; + Dwarf_Op *expr; + size_t expr_len; + ptrdiff_t off = 0; + size_t got = 0; + + /* This is a true loclistptr, fetch the initial base address and offset. */ + if (initial_offset_base (attr, &off, &base) != 0) + return -1; + + const Elf_Data *d = attr->cu->dbg->sectiondata[IDX_debug_loc]; + if (d == NULL) + { + __libdw_seterrno (DWARF_E_NO_LOCLIST); + return -1; + } + + while (got < maxlocs + && (off = getlocations_addr (attr, off, &base, &start, &end, + address, d, &expr, &expr_len)) > 0) + { + /* This one matches the address. */ + if (llbufs != NULL) + { + llbufs[got] = expr; + listlens[got] = expr_len; + } + ++got; + } + + /* We might stop early, so off can be zero or positive on success. */ + if (off < 0) + return -1; + + return got; +} + +ptrdiff_t +dwarf_getlocations (attr, offset, basep, startp, endp, expr, exprlen) + Dwarf_Attribute *attr; + ptrdiff_t offset; + Dwarf_Addr *basep; + Dwarf_Addr *startp; + Dwarf_Addr *endp; + Dwarf_Op **expr; + size_t *exprlen; +{ + if (! attr_ok (attr)) + return -1; + + /* 1 is an invalid offset, meaning no more locations. */ + if (offset == 1) + return 0; + + if (offset == 0) + { + /* If it has a block form, it's a single location expression. */ + Dwarf_Block block; + if (INTUSE(dwarf_formblock) (attr, &block) == 0) + { + if (getlocation (attr->cu, &block, expr, exprlen, + cu_sec_idx (attr->cu)) != 0) + return -1; + + /* This is the one and only location covering everything. */ + *startp = 0; + *endp = -1; + return 1; + } + + int error = INTUSE(dwarf_errno) (); + if (unlikely (error != DWARF_E_NO_BLOCK)) + { + __libdw_seterrno (error); + return -1; + } + + int result = check_constant_offset (attr, expr, exprlen); + if (result != 1) + { + if (result == 0) + { + /* This is the one and only location covering everything. */ + *startp = 0; + *endp = -1; + return 1; + } + return result; + } + + /* We must be looking at a true loclistptr, fetch the initial + base address and offset. */ + if (initial_offset_base (attr, &offset, basep) != 0) + return -1; + } + + const Elf_Data *d = attr->cu->dbg->sectiondata[IDX_debug_loc]; + if (d == NULL) + { + __libdw_seterrno (DWARF_E_NO_LOCLIST); + return -1; + } + + return getlocations_addr (attr, offset, basep, startp, endp, + (Dwarf_Word) -1, d, expr, exprlen); +} diff --git a/3rdparty/elfutils/libdw/dwarf_getlocation_attr.c b/3rdparty/elfutils/libdw/dwarf_getlocation_attr.c new file mode 100644 index 0000000..3229baf --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_getlocation_attr.c @@ -0,0 +1,122 @@ +/* Return DWARF attribute associated with a location expression op. + Copyright (C) 2013, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include <libdwP.h> + +static Dwarf_CU * +attr_form_cu (Dwarf_Attribute *attr) +{ + /* If the attribute has block/expr form the data comes from the + .debug_info from the same cu as the attr. Otherwise it comes from + the .debug_loc data section. */ + switch (attr->form) + { + case DW_FORM_block1: + case DW_FORM_block2: + case DW_FORM_block4: + case DW_FORM_block: + case DW_FORM_exprloc: + return attr->cu; + default: + return attr->cu->dbg->fake_loc_cu; + } +} + +int +dwarf_getlocation_attr (attr, op, result) + Dwarf_Attribute *attr; + const Dwarf_Op *op; + Dwarf_Attribute *result; +{ + if (attr == NULL) + return -1; + + switch (op->atom) + { + case DW_OP_implicit_value: + result->code = DW_AT_const_value; + result->form = DW_FORM_block; + result->valp = (unsigned char *) (uintptr_t) op->number2; + result->cu = attr_form_cu (attr); + break; + + case DW_OP_GNU_entry_value: + result->code = DW_AT_location; + result->form = DW_FORM_exprloc; + result->valp = (unsigned char *) (uintptr_t) op->number2; + result->cu = attr_form_cu (attr); + break; + + case DW_OP_GNU_const_type: + result->code = DW_AT_const_value; + result->form = DW_FORM_block1; + result->valp = (unsigned char *) (uintptr_t) op->number2; + result->cu = attr_form_cu (attr); + break; + + case DW_OP_call2: + case DW_OP_call4: + case DW_OP_call_ref: + { + Dwarf_Die die; + if (INTUSE(dwarf_getlocation_die) (attr, op, &die) != 0) + return -1; + if (INTUSE(dwarf_attr) (&die, DW_AT_location, result) == NULL) + { + __libdw_empty_loc_attr (result); + return 0; + } + } + break; + + case DW_OP_GNU_implicit_pointer: + { + Dwarf_Die die; + if (INTUSE(dwarf_getlocation_die) (attr, op, &die) != 0) + return -1; + if (INTUSE(dwarf_attr) (&die, DW_AT_location, result) == NULL + && INTUSE(dwarf_attr) (&die, DW_AT_const_value, result) == NULL) + { + __libdw_empty_loc_attr (result); + return 0; + } + } + break; + + default: + __libdw_seterrno (DWARF_E_INVALID_ACCESS); + return -1; + } + + return 0; +} diff --git a/3rdparty/elfutils/libdw/dwarf_getlocation_die.c b/3rdparty/elfutils/libdw/dwarf_getlocation_die.c new file mode 100644 index 0000000..fa03aac --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_getlocation_die.c @@ -0,0 +1,78 @@ +/* Return DIE associated with a location expression op. + Copyright (C) 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include <libdwP.h> + +int +dwarf_getlocation_die (attr, op, result) + Dwarf_Attribute *attr; + const Dwarf_Op *op; + Dwarf_Die *result; +{ + if (attr == NULL) + return -1; + + Dwarf_Off dieoff; + switch (op->atom) + { + case DW_OP_GNU_implicit_pointer: + case DW_OP_call_ref: + dieoff = op->number; + break; + + case DW_OP_GNU_parameter_ref: + case DW_OP_GNU_convert: + case DW_OP_GNU_reinterpret: + case DW_OP_GNU_const_type: + case DW_OP_call2: + case DW_OP_call4: + dieoff = attr->cu->start + op->number; + break; + + case DW_OP_GNU_regval_type: + case DW_OP_GNU_deref_type: + dieoff = attr->cu->start + op->number2; + break; + + default: + __libdw_seterrno (DWARF_E_INVALID_ACCESS); + return -1; + } + + if (__libdw_offdie (attr->cu->dbg, dieoff, result, + attr->cu->type_offset != 0) == NULL) + return -1; + + return 0; +} +INTDEF(dwarf_getlocation_die); diff --git a/3rdparty/elfutils/libdw/dwarf_getlocation_implicit_pointer.c b/3rdparty/elfutils/libdw/dwarf_getlocation_implicit_pointer.c new file mode 100644 index 0000000..f1c16be --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_getlocation_implicit_pointer.c @@ -0,0 +1,79 @@ +/* Return associated attribute for DW_OP_GNU_implicit_pointer. + Copyright (C) 2010 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" +#include <dwarf.h> + + +static unsigned char empty_exprloc = 0; +static Dwarf_CU empty_cu = { .startp = &empty_exprloc, + .endp = &empty_exprloc + 1 }; + +void +internal_function +__libdw_empty_loc_attr (Dwarf_Attribute *attr) +{ + attr->code = DW_AT_location; + attr->form = DW_FORM_exprloc; + attr->valp = &empty_exprloc; + attr->cu = &empty_cu; +} + +int +dwarf_getlocation_implicit_pointer (attr, op, result) + Dwarf_Attribute *attr; + const Dwarf_Op *op; + Dwarf_Attribute *result; +{ + if (attr == NULL) + return -1; + + if (unlikely (op->atom != DW_OP_GNU_implicit_pointer)) + { + __libdw_seterrno (DWARF_E_INVALID_ACCESS); + return -1; + } + + Dwarf_Die die; + if (__libdw_offdie (attr->cu->dbg, op->number, &die, + attr->cu->type_offset != 0) == NULL) + return -1; + + if (INTUSE(dwarf_attr) (&die, DW_AT_location, result) == NULL + && INTUSE(dwarf_attr) (&die, DW_AT_const_value, result) == NULL) + { + __libdw_empty_loc_attr (result); + return 0; + } + + return 0; +} diff --git a/3rdparty/elfutils/libdw/dwarf_getmacros.c b/3rdparty/elfutils/libdw/dwarf_getmacros.c new file mode 100644 index 0000000..f9f2996 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_getmacros.c @@ -0,0 +1,548 @@ +/* Get macro information. + Copyright (C) 2002-2009, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> +#include <search.h> +#include <stdlib.h> +#include <string.h> + +#include <libdwP.h> + +static int +get_offset_from (Dwarf_Die *die, int name, Dwarf_Word *retp) +{ + /* Get the appropriate attribute. */ + Dwarf_Attribute attr; + if (INTUSE(dwarf_attr) (die, name, &attr) == NULL) + return -1; + + /* Offset into the corresponding section. */ + return INTUSE(dwarf_formudata) (&attr, retp); +} + +static int +macro_op_compare (const void *p1, const void *p2) +{ + const Dwarf_Macro_Op_Table *t1 = (const Dwarf_Macro_Op_Table *) p1; + const Dwarf_Macro_Op_Table *t2 = (const Dwarf_Macro_Op_Table *) p2; + + if (t1->offset < t2->offset) + return -1; + if (t1->offset > t2->offset) + return 1; + + if (t1->sec_index < t2->sec_index) + return -1; + if (t1->sec_index > t2->sec_index) + return 1; + + return 0; +} + +static void +build_table (Dwarf_Macro_Op_Table *table, + Dwarf_Macro_Op_Proto op_protos[static 255]) +{ + unsigned ct = 0; + for (unsigned i = 1; i < 256; ++i) + if (op_protos[i - 1].forms != NULL) + table->table[table->opcodes[i - 1] = ct++] = op_protos[i - 1]; + else + table->opcodes[i - 1] = 0xff; +} + +#define MACRO_PROTO(NAME, ...) \ + Dwarf_Macro_Op_Proto NAME = ({ \ + static const uint8_t proto[] = {__VA_ARGS__}; \ + (Dwarf_Macro_Op_Proto) {sizeof proto, proto}; \ + }) + +enum { macinfo_data_size = offsetof (Dwarf_Macro_Op_Table, table[5]) }; +static unsigned char macinfo_data[macinfo_data_size] + __attribute__ ((aligned (__alignof (Dwarf_Macro_Op_Table)))); + +static __attribute__ ((constructor)) void +init_macinfo_table (void) +{ + MACRO_PROTO (p_udata_str, DW_FORM_udata, DW_FORM_string); + MACRO_PROTO (p_udata_udata, DW_FORM_udata, DW_FORM_udata); + MACRO_PROTO (p_none); + + Dwarf_Macro_Op_Proto op_protos[255] = + { + [DW_MACINFO_define - 1] = p_udata_str, + [DW_MACINFO_undef - 1] = p_udata_str, + [DW_MACINFO_vendor_ext - 1] = p_udata_str, + [DW_MACINFO_start_file - 1] = p_udata_udata, + [DW_MACINFO_end_file - 1] = p_none, + /* If you are adding more elements to this array, increase + MACINFO_DATA_SIZE above. */ + }; + + Dwarf_Macro_Op_Table *macinfo_table = (void *) macinfo_data; + memset (macinfo_table, 0, sizeof macinfo_data); + build_table (macinfo_table, op_protos); + macinfo_table->sec_index = IDX_debug_macinfo; +} + +static Dwarf_Macro_Op_Table * +get_macinfo_table (Dwarf *dbg, Dwarf_Word macoff, Dwarf_Die *cudie) +{ + assert (cudie != NULL); + + Dwarf_Attribute attr_mem, *attr + = INTUSE(dwarf_attr) (cudie, DW_AT_stmt_list, &attr_mem); + Dwarf_Off line_offset = (Dwarf_Off) -1; + if (attr != NULL) + INTUSE(dwarf_formudata) (attr, &line_offset); + + Dwarf_Macro_Op_Table *table = libdw_alloc (dbg, Dwarf_Macro_Op_Table, + macinfo_data_size, 1); + memcpy (table, macinfo_data, macinfo_data_size); + + table->offset = macoff; + table->sec_index = IDX_debug_macinfo; + table->line_offset = line_offset; + table->is_64bit = cudie->cu->address_size == 8; + table->comp_dir = __libdw_getcompdir (cudie); + + return table; +} + +static Dwarf_Macro_Op_Table * +get_table_for_offset (Dwarf *dbg, Dwarf_Word macoff, + const unsigned char *readp, + const unsigned char *const endp, + Dwarf_Die *cudie) +{ + const unsigned char *startp = readp; + + /* Request at least 3 bytes for header. */ + if (readp + 3 > endp) + { + invalid_dwarf: + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; + } + + uint16_t version = read_2ubyte_unaligned_inc (dbg, readp); + if (version != 4) + { + __libdw_seterrno (DWARF_E_INVALID_VERSION); + return NULL; + } + + uint8_t flags = *readp++; + bool is_64bit = (flags & 0x1) != 0; + + Dwarf_Off line_offset = (Dwarf_Off) -1; + if ((flags & 0x2) != 0) + { + line_offset = read_addr_unaligned_inc (is_64bit ? 8 : 4, dbg, readp); + if (readp > endp) + goto invalid_dwarf; + } + else if (cudie != NULL) + { + Dwarf_Attribute attr_mem, *attr + = INTUSE(dwarf_attr) (cudie, DW_AT_stmt_list, &attr_mem); + if (attr != NULL) + INTUSE(dwarf_formudata) (attr, &line_offset); + } + + /* """The macinfo entry types defined in this standard may, but + might not, be described in the table""". + + I.e. these may be present. It's tempting to simply skip them, + but it's probably more correct to tolerate that a producer tweaks + the way certain opcodes are encoded, for whatever reasons. */ + + MACRO_PROTO (p_udata_str, DW_FORM_udata, DW_FORM_string); + MACRO_PROTO (p_udata_strp, DW_FORM_udata, DW_FORM_strp); + MACRO_PROTO (p_udata_udata, DW_FORM_udata, DW_FORM_udata); + MACRO_PROTO (p_secoffset, DW_FORM_sec_offset); + MACRO_PROTO (p_none); + + Dwarf_Macro_Op_Proto op_protos[255] = + { + [DW_MACRO_GNU_define - 1] = p_udata_str, + [DW_MACRO_GNU_undef - 1] = p_udata_str, + [DW_MACRO_GNU_define_indirect - 1] = p_udata_strp, + [DW_MACRO_GNU_undef_indirect - 1] = p_udata_strp, + [DW_MACRO_GNU_start_file - 1] = p_udata_udata, + [DW_MACRO_GNU_end_file - 1] = p_none, + [DW_MACRO_GNU_transparent_include - 1] = p_secoffset, + /* N.B. DW_MACRO_undef_indirectx, DW_MACRO_define_indirectx + should be added when 130313.1 is supported. */ + }; + + if ((flags & 0x4) != 0) + { + unsigned count = *readp++; + for (unsigned i = 0; i < count; ++i) + { + unsigned opcode = *readp++; + + Dwarf_Macro_Op_Proto e; + if (readp >= endp) + goto invalid; + get_uleb128 (e.nforms, readp, endp); + e.forms = readp; + op_protos[opcode - 1] = e; + + readp += e.nforms; + if (readp > endp) + { + invalid: + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; + } + } + } + + size_t ct = 0; + for (unsigned i = 1; i < 256; ++i) + if (op_protos[i - 1].forms != NULL) + ++ct; + + /* We support at most 0xfe opcodes defined in the table, as 0xff is + a value that means that given opcode is not stored at all. But + that should be fine, as opcode 0 is not allocated. */ + assert (ct < 0xff); + + size_t macop_table_size = offsetof (Dwarf_Macro_Op_Table, table[ct]); + + Dwarf_Macro_Op_Table *table = libdw_alloc (dbg, Dwarf_Macro_Op_Table, + macop_table_size, 1); + + *table = (Dwarf_Macro_Op_Table) { + .offset = macoff, + .sec_index = IDX_debug_macro, + .line_offset = line_offset, + .header_len = readp - startp, + .version = version, + .is_64bit = is_64bit, + + /* NULL if CUDIE is NULL or DW_AT_comp_dir is absent. */ + .comp_dir = __libdw_getcompdir (cudie), + }; + build_table (table, op_protos); + + return table; +} + +static Dwarf_Macro_Op_Table * +cache_op_table (Dwarf *dbg, int sec_index, Dwarf_Off macoff, + const unsigned char *startp, + const unsigned char *const endp, + Dwarf_Die *cudie) +{ + Dwarf_Macro_Op_Table fake = { .offset = macoff, .sec_index = sec_index }; + Dwarf_Macro_Op_Table **found = tfind (&fake, &dbg->macro_ops, + macro_op_compare); + if (found != NULL) + return *found; + + Dwarf_Macro_Op_Table *table = sec_index == IDX_debug_macro + ? get_table_for_offset (dbg, macoff, startp, endp, cudie) + : get_macinfo_table (dbg, macoff, cudie); + + if (table == NULL) + return NULL; + + Dwarf_Macro_Op_Table **ret = tsearch (table, &dbg->macro_ops, + macro_op_compare); + if (unlikely (ret == NULL)) + { + __libdw_seterrno (DWARF_E_NOMEM); + return NULL; + } + + return *ret; +} + +static ptrdiff_t +read_macros (Dwarf *dbg, int sec_index, + Dwarf_Off macoff, int (*callback) (Dwarf_Macro *, void *), + void *arg, ptrdiff_t offset, bool accept_0xff, + Dwarf_Die *cudie) +{ + Elf_Data *d = dbg->sectiondata[sec_index]; + if (unlikely (d == NULL || d->d_buf == NULL)) + { + __libdw_seterrno (DWARF_E_NO_ENTRY); + return -1; + } + + if (unlikely (macoff >= d->d_size)) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } + + const unsigned char *const startp = d->d_buf + macoff; + const unsigned char *const endp = d->d_buf + d->d_size; + + Dwarf_Macro_Op_Table *table = cache_op_table (dbg, sec_index, macoff, + startp, endp, cudie); + if (table == NULL) + return -1; + + if (offset == 0) + offset = table->header_len; + + assert (offset >= 0); + assert (offset < endp - startp); + const unsigned char *readp = startp + offset; + + while (readp < endp) + { + unsigned int opcode = *readp++; + if (opcode == 0) + /* Nothing more to do. */ + return 0; + + if (unlikely (opcode == 0xff && ! accept_0xff)) + { + /* See comment below at dwarf_getmacros for explanation of + why we are doing this. */ + __libdw_seterrno (DWARF_E_INVALID_OPCODE); + return -1; + } + + unsigned int idx = table->opcodes[opcode - 1]; + if (idx == 0xff) + { + __libdw_seterrno (DWARF_E_INVALID_OPCODE); + return -1; + } + + Dwarf_Macro_Op_Proto *proto = &table->table[idx]; + + /* A fake CU with bare minimum data to fool dwarf_formX into + doing the right thing with the attributes that we put out. + We arbitrarily pretend it's version 4. */ + Dwarf_CU fake_cu = { + .dbg = dbg, + .version = 4, + .offset_size = table->is_64bit ? 8 : 4, + .startp = (void *) startp + offset, + .endp = (void *) endp, + }; + + Dwarf_Attribute attributes[proto->nforms]; + for (Dwarf_Word i = 0; i < proto->nforms; ++i) + { + /* We pretend this is a DW_AT_GNU_macros attribute so that + DW_FORM_sec_offset forms get correctly interpreted as + offset into .debug_macro. */ + attributes[i].code = DW_AT_GNU_macros; + attributes[i].form = proto->forms[i]; + attributes[i].valp = (void *) readp; + attributes[i].cu = &fake_cu; + + size_t len = __libdw_form_val_len (&fake_cu, proto->forms[i], readp); + if (len == (size_t) -1) + return -1; + + readp += len; + } + + Dwarf_Macro macro = { + .table = table, + .opcode = opcode, + .attributes = attributes, + }; + + if (callback (¯o, arg) != DWARF_CB_OK) + return readp - startp; + } + + return 0; +} + +/* Token layout: + + - The highest bit is used for distinguishing between callers that + know that opcode 0xff may have one of two incompatible meanings. + The mask that we use for selecting this bit is + DWARF_GETMACROS_START. + + - The rest of the token (31 or 63 bits) encodes address inside the + macro unit. + + Besides, token value of 0 signals end of iteration and -1 is + reserved for signaling errors. That means it's impossible to + represent maximum offset of a .debug_macro unit to new-style + callers (which in practice decreases the permissible macro unit + size by another 1 byte). */ + +static ptrdiff_t +token_from_offset (ptrdiff_t offset, bool accept_0xff) +{ + if (offset == -1 || offset == 0) + return offset; + + /* Make sure the offset didn't overflow into the flag bit. */ + if ((offset & DWARF_GETMACROS_START) != 0) + { + __libdw_seterrno (DWARF_E_TOO_BIG); + return -1; + } + + if (accept_0xff) + offset |= DWARF_GETMACROS_START; + + return offset; +} + +static ptrdiff_t +offset_from_token (ptrdiff_t token, bool *accept_0xffp) +{ + *accept_0xffp = (token & DWARF_GETMACROS_START) != 0; + token &= ~DWARF_GETMACROS_START; + + return token; +} + +static ptrdiff_t +gnu_macros_getmacros_off (Dwarf *dbg, Dwarf_Off macoff, + int (*callback) (Dwarf_Macro *, void *), + void *arg, ptrdiff_t offset, bool accept_0xff, + Dwarf_Die *cudie) +{ + assert (offset >= 0); + + if (macoff >= dbg->sectiondata[IDX_debug_macro]->d_size) + { + __libdw_seterrno (DWARF_E_INVALID_OFFSET); + return -1; + } + + return read_macros (dbg, IDX_debug_macro, macoff, + callback, arg, offset, accept_0xff, cudie); +} + +static ptrdiff_t +macro_info_getmacros_off (Dwarf *dbg, Dwarf_Off macoff, + int (*callback) (Dwarf_Macro *, void *), + void *arg, ptrdiff_t offset, Dwarf_Die *cudie) +{ + assert (offset >= 0); + + return read_macros (dbg, IDX_debug_macinfo, macoff, + callback, arg, offset, true, cudie); +} + +ptrdiff_t +dwarf_getmacros_off (Dwarf *dbg, Dwarf_Off macoff, + int (*callback) (Dwarf_Macro *, void *), + void *arg, ptrdiff_t token) +{ + if (dbg == NULL) + { + __libdw_seterrno (DWARF_E_NO_DWARF); + return -1; + } + + bool accept_0xff; + ptrdiff_t offset = offset_from_token (token, &accept_0xff); + assert (accept_0xff); + + offset = gnu_macros_getmacros_off (dbg, macoff, callback, arg, offset, + accept_0xff, NULL); + + return token_from_offset (offset, accept_0xff); +} + +ptrdiff_t +dwarf_getmacros (cudie, callback, arg, token) + Dwarf_Die *cudie; + int (*callback) (Dwarf_Macro *, void *); + void *arg; + ptrdiff_t token; +{ + if (cudie == NULL) + { + __libdw_seterrno (DWARF_E_NO_DWARF); + return -1; + } + + /* This function might be called from a code that expects to see + DW_MACINFO_* opcodes, not DW_MACRO_{GNU_,}* ones. It is fine to + serve most DW_MACRO_{GNU_,}* opcodes to such code, because those + whose values are the same as DW_MACINFO_* ones also have the same + behavior. It is not very likely that a .debug_macro section + would only use the part of opcode space that it shares with + .debug_macinfo, but it is possible. Serving the opcodes that are + only valid in DW_MACRO_{GNU_,}* domain is OK as well, because + clients in general need to be ready that newer standards define + more opcodes, and have coping mechanisms for unfamiliar opcodes. + + The one exception to the above rule is opcode 0xff, which has + concrete semantics in .debug_macinfo, but falls into vendor block + in .debug_macro, and can be assigned to do whatever. There is + some small probability that the two opcodes would look + superficially similar enough that a client would be confused and + misbehave as a result. For this reason, we refuse to serve + through this interface 0xff's originating from .debug_macro + unless the TOKEN that we obtained indicates the call originates + from a new-style caller. See above for details on what + information is encoded into tokens. */ + + bool accept_0xff; + ptrdiff_t offset = offset_from_token (token, &accept_0xff); + + /* DW_AT_macro_info */ + if (dwarf_hasattr (cudie, DW_AT_macro_info)) + { + Dwarf_Word macoff; + if (get_offset_from (cudie, DW_AT_macro_info, &macoff) != 0) + return -1; + offset = macro_info_getmacros_off (cudie->cu->dbg, macoff, + callback, arg, offset, cudie); + } + else + { + /* DW_AT_GNU_macros, DW_AT_macros */ + Dwarf_Word macoff; + if (get_offset_from (cudie, DW_AT_GNU_macros, &macoff) != 0) + return -1; + offset = gnu_macros_getmacros_off (cudie->cu->dbg, macoff, + callback, arg, offset, accept_0xff, + cudie); + } + + return token_from_offset (offset, accept_0xff); +} diff --git a/3rdparty/elfutils/libdw/dwarf_getpubnames.c b/3rdparty/elfutils/libdw/dwarf_getpubnames.c new file mode 100644 index 0000000..19f4eae --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_getpubnames.c @@ -0,0 +1,245 @@ +/* Get public symbol information. + Copyright (C) 2002, 2003, 2004, 2005, 2008 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <sys/param.h> + +#include <libdwP.h> +#include <dwarf.h> + + +static int +get_offsets (Dwarf *dbg) +{ + size_t allocated = 0; + size_t cnt = 0; + struct pubnames_s *mem = NULL; + const size_t entsize = sizeof (struct pubnames_s); + unsigned char *const startp = dbg->sectiondata[IDX_debug_pubnames]->d_buf; + unsigned char *readp = startp; + unsigned char *endp = readp + dbg->sectiondata[IDX_debug_pubnames]->d_size; + + while (readp + 14 < endp) + { + /* If necessary, allocate more entries. */ + if (cnt >= allocated) + { + allocated = MAX (10, 2 * allocated); + struct pubnames_s *newmem + = (struct pubnames_s *) realloc (mem, allocated * entsize); + if (newmem == NULL) + { + __libdw_seterrno (DWARF_E_NOMEM); + err_return: + free (mem); + return -1; + } + + mem = newmem; + } + + /* Read the set header. */ + int len_bytes = 4; + Dwarf_Off len = read_4ubyte_unaligned_inc (dbg, readp); + if (len == DWARF3_LENGTH_64_BIT) + { + len = read_8ubyte_unaligned_inc (dbg, readp); + len_bytes = 8; + } + else if (unlikely (len >= DWARF3_LENGTH_MIN_ESCAPE_CODE + && len <= DWARF3_LENGTH_MAX_ESCAPE_CODE)) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + goto err_return; + } + + /* Now we know the offset of the first offset/name pair. */ + mem[cnt].set_start = readp + 2 + 2 * len_bytes - startp; + mem[cnt].address_len = len_bytes; + size_t max_size = dbg->sectiondata[IDX_debug_pubnames]->d_size; + if (mem[cnt].set_start >= max_size + || len - (2 + 2 * len_bytes) > max_size - mem[cnt].set_start) + /* Something wrong, the first entry is beyond the end of + the section. Or the length of the whole unit is too big. */ + break; + + /* Read the version. It better be two for now. */ + uint16_t version = read_2ubyte_unaligned (dbg, readp); + if (unlikely (version != 2)) + { + __libdw_seterrno (DWARF_E_INVALID_VERSION); + goto err_return; + } + + /* Get the CU offset. */ + if (__libdw_read_offset (dbg, dbg, IDX_debug_pubnames, + readp + 2, len_bytes, + &mem[cnt].cu_offset, IDX_debug_info, 3)) + /* Error has been already set in reader. */ + goto err_return; + + /* Determine the size of the CU header. */ + unsigned char *infop + = ((unsigned char *) dbg->sectiondata[IDX_debug_info]->d_buf + + mem[cnt].cu_offset); + if (read_4ubyte_unaligned_noncvt (infop) == DWARF3_LENGTH_64_BIT) + mem[cnt].cu_header_size = 23; + else + mem[cnt].cu_header_size = 11; + + ++cnt; + + /* Advance to the next set. */ + readp += len; + } + + if (mem == NULL || cnt == 0) + { + __libdw_seterrno (DWARF_E_NO_ENTRY); + return -1; + } + + dbg->pubnames_sets = (struct pubnames_s *) realloc (mem, cnt * entsize); + dbg->pubnames_nsets = cnt; + + return 0; +} + + +ptrdiff_t +dwarf_getpubnames (dbg, callback, arg, offset) + Dwarf *dbg; + int (*callback) (Dwarf *, Dwarf_Global *, void *); + void *arg; + ptrdiff_t offset; +{ + if (dbg == NULL) + return -1l; + + if (unlikely (offset < 0)) + { + __libdw_seterrno (DWARF_E_INVALID_OFFSET); + return -1l; + } + + /* Make sure it is a valid offset. */ + if (unlikely (dbg->sectiondata[IDX_debug_pubnames] == NULL + || ((size_t) offset + >= dbg->sectiondata[IDX_debug_pubnames]->d_size))) + /* No (more) entry. */ + return 0; + + /* If necessary read the set information. */ + if (dbg->pubnames_nsets == 0 && unlikely (get_offsets (dbg) != 0)) + return -1l; + + /* Find the place where to start. */ + size_t cnt; + if (offset == 0) + { + cnt = 0; + offset = dbg->pubnames_sets[0].set_start; + } + else + { + for (cnt = 0; cnt + 1 < dbg->pubnames_nsets; ++cnt) + if ((Dwarf_Off) offset >= dbg->pubnames_sets[cnt].set_start) + { + assert ((Dwarf_Off) offset + < dbg->pubnames_sets[cnt + 1].set_start); + break; + } + assert (cnt + 1 < dbg->pubnames_nsets); + } + + unsigned char *startp + = (unsigned char *) dbg->sectiondata[IDX_debug_pubnames]->d_buf; + unsigned char *endp + = startp + dbg->sectiondata[IDX_debug_pubnames]->d_size; + unsigned char *readp = startp + offset; + while (1) + { + Dwarf_Global gl; + + gl.cu_offset = (dbg->pubnames_sets[cnt].cu_offset + + dbg->pubnames_sets[cnt].cu_header_size); + + while (1) + { + /* READP points to the next offset/name pair. */ + if (readp + dbg->pubnames_sets[cnt].address_len > endp) + goto invalid_dwarf; + if (dbg->pubnames_sets[cnt].address_len == 4) + gl.die_offset = read_4ubyte_unaligned_inc (dbg, readp); + else + gl.die_offset = read_8ubyte_unaligned_inc (dbg, readp); + + /* If the offset is zero we reached the end of the set. */ + if (gl.die_offset == 0) + break; + + /* Add the CU offset. */ + gl.die_offset += dbg->pubnames_sets[cnt].cu_offset; + + gl.name = (char *) readp; + readp = (unsigned char *) memchr (gl.name, '\0', endp - readp); + if (unlikely (readp == NULL)) + { + invalid_dwarf: + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1l; + } + readp++; + + /* We found name and DIE offset. Report it. */ + if (callback (dbg, &gl, arg) != DWARF_CB_OK) + { + /* The user wants us to stop. Return the offset of the + next entry. */ + return readp - startp; + } + } + + if (++cnt == dbg->pubnames_nsets) + /* This was the last set. */ + break; + + startp = (unsigned char *) dbg->sectiondata[IDX_debug_pubnames]->d_buf; + readp = startp + dbg->pubnames_sets[cnt].set_start; + } + + /* We are done. No more entries. */ + return 0; +} diff --git a/3rdparty/elfutils/libdw/dwarf_getscopes.c b/3rdparty/elfutils/libdw/dwarf_getscopes.c new file mode 100644 index 0000000..0ca6da0 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_getscopes.c @@ -0,0 +1,201 @@ +/* Return scope DIEs containing PC address. + Copyright (C) 2005, 2007 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <stdlib.h> +#include "libdwP.h" +#include <dwarf.h> + + +struct args +{ + Dwarf_Addr pc; + Dwarf_Die *scopes; + unsigned int inlined, nscopes; + Dwarf_Die inlined_origin; +}; + +/* Preorder visitor: prune the traversal if this DIE does not contain PC. */ +static int +pc_match (unsigned int depth, struct Dwarf_Die_Chain *die, void *arg) +{ + struct args *a = arg; + + if (a->scopes != NULL) + die->prune = true; + else + { + /* dwarf_haspc returns an error if there are no appropriate attributes. + But we use it indiscriminantly instead of presuming which tags can + have PC attributes. So when it fails for that reason, treat it just + as a nonmatching return. */ + int result = INTUSE(dwarf_haspc) (&die->die, a->pc); + if (result < 0) + { + int error = INTUSE(dwarf_errno) (); + if (error != DWARF_E_NOERROR && error != DWARF_E_NO_DEBUG_RANGES) + { + __libdw_seterrno (error); + return -1; + } + result = 0; + } + if (result == 0) + die->prune = true; + + if (!die->prune + && INTUSE (dwarf_tag) (&die->die) == DW_TAG_inlined_subroutine) + a->inlined = depth; + } + + return 0; +} + +/* Preorder visitor for second partial traversal after finding a + concrete inlined instance. */ +static int +origin_match (unsigned int depth, struct Dwarf_Die_Chain *die, void *arg) +{ + struct args *a = arg; + + if (die->die.addr != a->inlined_origin.addr) + return 0; + + /* We have a winner! This is the abstract definition of the inline + function of which A->scopes[A->nscopes - 1] is a concrete instance. + */ + + unsigned int nscopes = a->nscopes + depth; + Dwarf_Die *scopes = realloc (a->scopes, nscopes * sizeof scopes[0]); + if (scopes == NULL) + { + free (a->scopes); + __libdw_seterrno (DWARF_E_NOMEM); + return -1; + } + + a->scopes = scopes; + do + { + die = die->parent; + scopes[a->nscopes++] = die->die; + } + while (a->nscopes < nscopes); + assert (die->parent == NULL); + return a->nscopes; +} + +/* Postorder visitor: first (innermost) call wins. */ +static int +pc_record (unsigned int depth, struct Dwarf_Die_Chain *die, void *arg) +{ + struct args *a = arg; + + if (die->prune) + return 0; + + if (a->scopes == NULL) + { + /* We have hit the innermost DIE that contains the target PC. */ + + a->nscopes = depth + 1 - a->inlined; + a->scopes = malloc (a->nscopes * sizeof a->scopes[0]); + if (a->scopes == NULL) + { + __libdw_seterrno (DWARF_E_NOMEM); + return -1; + } + + for (unsigned int i = 0; i < a->nscopes; ++i) + { + a->scopes[i] = die->die; + die = die->parent; + } + + if (a->inlined == 0) + { + assert (die == NULL); + return a->nscopes; + } + + /* This is the concrete inlined instance itself. + Record its abstract_origin pointer. */ + Dwarf_Die *const inlinedie = &a->scopes[depth - a->inlined]; + + assert (INTUSE (dwarf_tag) (inlinedie) == DW_TAG_inlined_subroutine); + Dwarf_Attribute attr_mem; + Dwarf_Attribute *attr = INTUSE (dwarf_attr) (inlinedie, + DW_AT_abstract_origin, + &attr_mem); + if (INTUSE (dwarf_formref_die) (attr, &a->inlined_origin) == NULL) + return -1; + return 0; + } + + + /* We've recorded the scopes back to one that is a concrete inlined + instance. Now return out of the traversal back to the scope + containing that instance. */ + + assert (a->inlined); + if (depth >= a->inlined) + /* Not there yet. */ + return 0; + + /* Now we are in a scope that contains the concrete inlined instance. + Search it for the inline function's abstract definition. + If we don't find it, return to search the containing scope. + If we do find it, the nonzero return value will bail us out + of the postorder traversal. */ + return __libdw_visit_scopes (depth, die, &origin_match, NULL, a); +} + + +int +dwarf_getscopes (Dwarf_Die *cudie, Dwarf_Addr pc, Dwarf_Die **scopes) +{ + if (cudie == NULL) + return -1; + + struct Dwarf_Die_Chain cu = { .parent = NULL, .die = *cudie }; + struct args a = { .pc = pc }; + + int result = __libdw_visit_scopes (0, &cu, &pc_match, &pc_record, &a); + + if (result == 0 && a.scopes != NULL) + result = __libdw_visit_scopes (0, &cu, &origin_match, NULL, &a); + + if (result > 0) + *scopes = a.scopes; + + return result; +} diff --git a/3rdparty/elfutils/libdw/dwarf_getscopes_die.c b/3rdparty/elfutils/libdw/dwarf_getscopes_die.c new file mode 100644 index 0000000..d361585 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_getscopes_die.c @@ -0,0 +1,74 @@ +/* Return scope DIEs containing given DIE. + Copyright (C) 2005 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include "libdwP.h" +#include <assert.h> +#include <stdlib.h> + +static int +scope_visitor (unsigned int depth, struct Dwarf_Die_Chain *die, void *arg) +{ + if (die->die.addr != *(void **) arg) + return 0; + + Dwarf_Die *scopes = malloc (depth * sizeof scopes[0]); + if (scopes == NULL) + { + __libdw_seterrno (DWARF_E_NOMEM); + return -1; + } + + unsigned int i = 0; + do + { + scopes[i++] = die->die; + die = die->parent; + } + while (die != NULL); + assert (i == depth); + + *(void **) arg = scopes; + return depth; +} + +int +dwarf_getscopes_die (Dwarf_Die *die, Dwarf_Die **scopes) +{ + if (die == NULL) + return -1; + + struct Dwarf_Die_Chain cu = { .die = CUDIE (die->cu), .parent = NULL }; + void *info = die->addr; + int result = __libdw_visit_scopes (1, &cu, &scope_visitor, NULL, &info); + if (result > 0) + *scopes = info; + return result; +} diff --git a/3rdparty/elfutils/libdw/dwarf_getscopevar.c b/3rdparty/elfutils/libdw/dwarf_getscopevar.c new file mode 100644 index 0000000..eb50c0a --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_getscopevar.c @@ -0,0 +1,154 @@ +/* Find a named variable or parameter within given scopes. + Copyright (C) 2005-2009 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdbool.h> +#include <string.h> +#include "libdwP.h" +#include <dwarf.h> + + +/* Find the containing CU's files. */ +static int +getfiles (Dwarf_Die *die, Dwarf_Files **files) +{ + return INTUSE(dwarf_getsrcfiles) (&CUDIE (die->cu), files, NULL); +} + +/* Fetch an attribute that should have a constant integer form. */ +static int +getattr (Dwarf_Die *die, int search_name, Dwarf_Word *value) +{ + Dwarf_Attribute attr_mem; + return INTUSE(dwarf_formudata) (INTUSE(dwarf_attr) (die, search_name, + &attr_mem), value); +} + +/* Search SCOPES[0..NSCOPES-1] for a variable called NAME. + Ignore the first SKIP_SHADOWS scopes that match the name. + If MATCH_FILE is not null, accept only declaration in that source file; + if MATCH_LINENO or MATCH_LINECOL are also nonzero, accept only declaration + at that line and column. + + If successful, fill in *RESULT with the DIE of the variable found, + and return N where SCOPES[N] is the scope defining the variable. + Return -1 for errors or -2 for no matching variable found. */ + +int +dwarf_getscopevar (Dwarf_Die *scopes, int nscopes, + const char *name, int skip_shadows, + const char *match_file, int match_lineno, int match_linecol, + Dwarf_Die *result) +{ + /* Match against the given file name. */ + size_t match_file_len = match_file == NULL ? 0 : strlen (match_file); + bool lastfile_matches = false; + const char *lastfile = NULL; + inline bool file_matches (Dwarf_Files *files, size_t idx) + { + if (idx >= files->nfiles) + return false; + + const char *file = files->info[idx].name; + if (file != lastfile) + { + size_t len = strlen (file); + lastfile_matches = (len >= match_file_len + && !memcmp (match_file, file, match_file_len) + && (len == match_file_len + || file[len - match_file_len - 1] == '/')); + } + return lastfile_matches; + } + + /* Start with the innermost scope and move out. */ + for (int out = 0; out < nscopes; ++out) + if (INTUSE(dwarf_haschildren) (&scopes[out])) + { + if (INTUSE(dwarf_child) (&scopes[out], result) != 0) + return -1; + do + { + switch (INTUSE(dwarf_tag) (result)) + { + case DW_TAG_variable: + case DW_TAG_formal_parameter: + break; + + default: + continue; + } + + /* Only get here for a variable or parameter. Check the name. */ + const char *diename = INTUSE(dwarf_diename) (result); + if (diename != NULL && !strcmp (name, diename)) + { + /* We have a matching name. */ + + if (skip_shadows > 0) + { + /* Punt this scope for the one it shadows. */ + --skip_shadows; + break; + } + + if (match_file != NULL) + { + /* Check its decl_file. */ + + Dwarf_Word i; + Dwarf_Files *files; + if (getattr (result, DW_AT_decl_file, &i) != 0 + || getfiles (&scopes[out], &files) != 0) + break; + + if (!file_matches (files, i)) + break; + + if (match_lineno > 0 + && (getattr (result, DW_AT_decl_line, &i) != 0 + || (int) i != match_lineno)) + break; + if (match_linecol > 0 + && (getattr (result, DW_AT_decl_column, &i) != 0 + || (int) i != match_linecol)) + break; + } + + /* We have a winner! */ + return out; + } + } + while (INTUSE(dwarf_siblingof) (result, result) == 0); + } + + return -2; +} diff --git a/3rdparty/elfutils/libdw/dwarf_getsrc_die.c b/3rdparty/elfutils/libdw/dwarf_getsrc_die.c new file mode 100644 index 0000000..1914cdf --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_getsrc_die.c @@ -0,0 +1,78 @@ +/* Find line information for address. + Copyright (C) 2004, 2005 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" +#include <assert.h> + + +Dwarf_Line * +dwarf_getsrc_die (Dwarf_Die *cudie, Dwarf_Addr addr) +{ + Dwarf_Lines *lines; + size_t nlines; + + if (INTUSE(dwarf_getsrclines) (cudie, &lines, &nlines) != 0) + return NULL; + + /* The lines are sorted by address, so we can use binary search. */ + size_t l = 0, u = nlines; + while (l < u) + { + size_t idx = (l + u) / 2; + if (addr < lines->info[idx].addr) + u = idx; + else if (addr > lines->info[idx].addr || lines->info[idx].end_sequence) + l = idx + 1; + else + return &lines->info[idx]; + } + + if (nlines > 0) + assert (lines->info[nlines - 1].end_sequence); + + /* If none were equal, the closest one below is what we want. We + never want the last one, because it's the end-sequence marker + with an address at the high bound of the CU's code. If the debug + information is faulty and no end-sequence marker is present, we + still ignore it. */ + if (u > 0 && u < nlines && addr > lines->info[u - 1].addr) + { + while (lines->info[u - 1].end_sequence && u > 0) + --u; + if (u > 0) + return &lines->info[u - 1]; + } + + __libdw_seterrno (DWARF_E_ADDR_OUTOFRANGE); + return NULL; +} diff --git a/3rdparty/elfutils/libdw/dwarf_getsrc_file.c b/3rdparty/elfutils/libdw/dwarf_getsrc_file.c new file mode 100644 index 0000000..5289c7d --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_getsrc_file.c @@ -0,0 +1,178 @@ +/* Find line information for given file/line/column triple. + Copyright (C) 2005-2009 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2005. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <limits.h> +#include <stdlib.h> +#include <string.h> + +#include "libdwP.h" + + +int +dwarf_getsrc_file (Dwarf *dbg, const char *fname, int lineno, int column, + Dwarf_Line ***srcsp, size_t *nsrcs) +{ + if (dbg == NULL) + return -1; + + bool is_basename = strchr (fname, '/') == NULL; + + size_t max_match = *nsrcs ?: ~0u; + size_t act_match = *nsrcs; + size_t cur_match = 0; + Dwarf_Line **match = *nsrcs == 0 ? NULL : *srcsp; + + size_t cuhl; + Dwarf_Off noff; + for (Dwarf_Off off = 0; + INTUSE(dwarf_nextcu) (dbg, off, &noff, &cuhl, NULL, NULL, NULL) == 0; + off = noff) + { + Dwarf_Die cudie_mem; + Dwarf_Die *cudie = INTUSE(dwarf_offdie) (dbg, off + cuhl, &cudie_mem); + if (cudie == NULL) + continue; + + /* Get the line number information for this file. */ + Dwarf_Lines *lines; + size_t nlines; + if (INTUSE(dwarf_getsrclines) (cudie, &lines, &nlines) != 0) + { + /* Ignore a CU that just has no DW_AT_stmt_list at all. */ + int error = INTUSE(dwarf_errno) (); + if (error == 0) + continue; + __libdw_seterrno (error); + return -1; + } + + /* Search through all the line number records for a matching + file and line/column number. If any of the numbers is zero, + no match is performed. */ + unsigned int lastfile = UINT_MAX; + bool lastmatch = false; + for (size_t cnt = 0; cnt < nlines; ++cnt) + { + Dwarf_Line *line = &lines->info[cnt]; + + if (lastfile != line->file) + { + lastfile = line->file; + if (lastfile >= line->files->nfiles) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } + + /* Match the name with the name the user provided. */ + const char *fname2 = line->files->info[lastfile].name; + if (is_basename) + lastmatch = strcmp (basename (fname2), fname) == 0; + else + lastmatch = strcmp (fname2, fname) == 0; + } + if (!lastmatch) + continue; + + /* See whether line and possibly column match. */ + if (lineno != 0 + && (lineno > line->line + || (column != 0 && column > line->column))) + /* Cannot match. */ + continue; + + /* Determine whether this is the best match so far. */ + size_t inner; + for (inner = 0; inner < cur_match; ++inner) + if (match[inner]->files == line->files + && match[inner]->file == line->file) + break; + if (inner < cur_match + && (match[inner]->line != line->line + || match[inner]->line != lineno + || (column != 0 + && (match[inner]->column != line->column + || match[inner]->column != column)))) + { + /* We know about this file already. If this is a better + match for the line number, use it. */ + if (match[inner]->line >= line->line + && (match[inner]->line != line->line + || match[inner]->column >= line->column)) + /* Use the new line. Otherwise the old one. */ + match[inner] = line; + continue; + } + + if (cur_match < max_match) + { + if (cur_match == act_match) + { + /* Enlarge the array for the results. */ + act_match += 10; + Dwarf_Line **newp = realloc (match, + act_match + * sizeof (Dwarf_Line *)); + if (newp == NULL) + { + free (match); + __libdw_seterrno (DWARF_E_NOMEM); + return -1; + } + match = newp; + } + + match[cur_match++] = line; + } + } + + /* If we managed to find as many matches as the user requested + already, there is no need to go on to the next CU. */ + if (cur_match == max_match) + break; + } + + if (cur_match > 0) + { + assert (*nsrcs == 0 || *srcsp == match); + + *nsrcs = cur_match; + *srcsp = match; + + return 0; + } + + __libdw_seterrno (DWARF_E_NO_MATCH); + return -1; +} diff --git a/3rdparty/elfutils/libdw/dwarf_getsrcdirs.c b/3rdparty/elfutils/libdw/dwarf_getsrcdirs.c new file mode 100644 index 0000000..47283ec --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_getsrcdirs.c @@ -0,0 +1,48 @@ +/* Find include directories in source file information. + Copyright (C) 2007 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +int +dwarf_getsrcdirs (files, result, ndirs) + Dwarf_Files *files; + const char *const **result; + size_t *ndirs; +{ + if (files == NULL) + return -1; + + *result = (void *) &files->info[files->nfiles]; + *ndirs = files->ndirs; + return 0; +} diff --git a/3rdparty/elfutils/libdw/dwarf_getsrcfiles.c b/3rdparty/elfutils/libdw/dwarf_getsrcfiles.c new file mode 100644 index 0000000..4bfc34b --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_getsrcfiles.c @@ -0,0 +1,76 @@ +/* Return source file information of CU. + Copyright (C) 2004, 2005, 2013 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> +#include "libdwP.h" + + +int +dwarf_getsrcfiles (Dwarf_Die *cudie, Dwarf_Files **files, size_t *nfiles) +{ + if (unlikely (cudie == NULL + || (INTUSE(dwarf_tag) (cudie) != DW_TAG_compile_unit + && INTUSE(dwarf_tag) (cudie) != DW_TAG_partial_unit))) + return -1; + + int res = -1; + + /* Get the information if it is not already known. */ + struct Dwarf_CU *const cu = cudie->cu; + if (cu->lines == NULL) + { + Dwarf_Lines *lines; + size_t nlines; + + /* Let the more generic function do the work. It'll create more + data but that will be needed in an real program anyway. */ + res = INTUSE(dwarf_getsrclines) (cudie, &lines, &nlines); + } + else if (cu->files != (void *) -1l) + /* We already have the information. */ + res = 0; + + if (likely (res == 0)) + { + assert (cu->files != NULL && cu->files != (void *) -1l); + *files = cu->files; + if (nfiles != NULL) + *nfiles = cu->files->nfiles; + } + + // XXX Eventually: unlocking here. + + return res; +} +INTDEF (dwarf_getsrcfiles) diff --git a/3rdparty/elfutils/libdw/dwarf_getsrclines.c b/3rdparty/elfutils/libdw/dwarf_getsrclines.c new file mode 100644 index 0000000..053b30f --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_getsrclines.c @@ -0,0 +1,881 @@ +/* Return line number information of CU. + Copyright (C) 2004-2010, 2013, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <search.h> + +#include "dwarf.h" +#include "libdwP.h" + + +struct filelist +{ + Dwarf_Fileinfo info; + struct filelist *next; +}; + +struct linelist +{ + Dwarf_Line line; + struct linelist *next; + size_t sequence; +}; + + +/* Compare by Dwarf_Line.addr, given pointers into an array of pointers. */ +static int +compare_lines (const void *a, const void *b) +{ + struct linelist *const *p1 = a; + struct linelist *const *p2 = b; + struct linelist *list1 = *p1; + struct linelist *list2 = *p2; + Dwarf_Line *line1 = &list1->line; + Dwarf_Line *line2 = &list2->line; + + if (line1->addr != line2->addr) + return (line1->addr < line2->addr) ? -1 : 1; + + /* An end_sequence marker precedes a normal record at the same address. */ + if (line1->end_sequence != line2->end_sequence) + return line2->end_sequence - line1->end_sequence; + + /* Otherwise, the linelist sequence maintains a stable sort. */ + return (list1->sequence < list2->sequence) ? -1 + : (list1->sequence > list2->sequence) ? 1 + : 0; +} + +static int +read_srclines (Dwarf *dbg, + const unsigned char *linep, const unsigned char *lineendp, + const char *comp_dir, unsigned address_size, + Dwarf_Lines **linesp, Dwarf_Files **filesp) +{ + int res = -1; + + struct linelist *linelist = NULL; + size_t nlinelist = 0; + + /* If there are a large number of lines don't blow up the stack. + Keep track of the last malloced linelist record and free them + through the next pointer at the end. */ +#define MAX_STACK_ALLOC 4096 + struct linelist *malloc_linelist = NULL; + + if (unlikely (linep + 4 > lineendp)) + { + invalid_data: + __libdw_seterrno (DWARF_E_INVALID_DEBUG_LINE); + goto out; + } + + Dwarf_Word unit_length = read_4ubyte_unaligned_inc (dbg, linep); + unsigned int length = 4; + if (unlikely (unit_length == DWARF3_LENGTH_64_BIT)) + { + if (unlikely (linep + 8 > lineendp)) + goto invalid_data; + unit_length = read_8ubyte_unaligned_inc (dbg, linep); + length = 8; + } + + /* Check whether we have enough room in the section. */ + if (unlikely (unit_length > (size_t) (lineendp - linep) + || unit_length < 2 + length + 5 * 1)) + goto invalid_data; + lineendp = linep + unit_length; + + /* The next element of the header is the version identifier. */ + uint_fast16_t version = read_2ubyte_unaligned_inc (dbg, linep); + if (unlikely (version < 2) || unlikely (version > 4)) + { + __libdw_seterrno (DWARF_E_VERSION); + goto out; + } + + /* Next comes the header length. */ + Dwarf_Word header_length; + if (length == 4) + header_length = read_4ubyte_unaligned_inc (dbg, linep); + else + header_length = read_8ubyte_unaligned_inc (dbg, linep); + const unsigned char *header_start = linep; + + /* Next the minimum instruction length. */ + uint_fast8_t minimum_instr_len = *linep++; + + /* Next the maximum operations per instruction, in version 4 format. */ + uint_fast8_t max_ops_per_instr = 1; + if (version >= 4) + { + if (unlikely (lineendp - linep < 5)) + goto invalid_data; + max_ops_per_instr = *linep++; + if (unlikely (max_ops_per_instr == 0)) + goto invalid_data; + } + + /* Then the flag determining the default value of the is_stmt + register. */ + uint_fast8_t default_is_stmt = *linep++; + + /* Now the line base. */ + int_fast8_t line_base = (int8_t) *linep++; + + /* And the line range. */ + uint_fast8_t line_range = *linep++; + + /* The opcode base. */ + uint_fast8_t opcode_base = *linep++; + + /* Remember array with the standard opcode length (-1 to account for + the opcode with value zero not being mentioned). */ + const uint8_t *standard_opcode_lengths = linep - 1; + if (unlikely (lineendp - linep < opcode_base - 1)) + goto invalid_data; + linep += opcode_base - 1; + + /* First comes the list of directories. Add the compilation + directory first since the index zero is used for it. */ + struct dirlist + { + const char *dir; + size_t len; + struct dirlist *next; + } comp_dir_elem = + { + .dir = comp_dir, + .len = comp_dir ? strlen (comp_dir) : 0, + .next = NULL + }; + struct dirlist *dirlist = &comp_dir_elem; + unsigned int ndirlist = 1; + + // XXX Directly construct array to conserve memory? + while (*linep != 0) + { + struct dirlist *new_dir = + (struct dirlist *) alloca (sizeof (*new_dir)); + + new_dir->dir = (char *) linep; + uint8_t *endp = memchr (linep, '\0', lineendp - linep); + if (endp == NULL) + goto invalid_data; + new_dir->len = endp - linep; + new_dir->next = dirlist; + dirlist = new_dir; + ++ndirlist; + linep = endp + 1; + } + /* Skip the final NUL byte. */ + ++linep; + + /* Rearrange the list in array form. */ + struct dirlist **dirarray + = (struct dirlist **) alloca (ndirlist * sizeof (*dirarray)); + for (unsigned int n = ndirlist; n-- > 0; dirlist = dirlist->next) + dirarray[n] = dirlist; + + /* Now read the files. */ + struct filelist null_file = + { + .info = + { + .name = "???", + .mtime = 0, + .length = 0 + }, + .next = NULL + }; + struct filelist *filelist = &null_file; + unsigned int nfilelist = 1; + + if (unlikely (linep >= lineendp)) + goto invalid_data; + while (*linep != 0) + { + struct filelist *new_file = + (struct filelist *) alloca (sizeof (*new_file)); + + /* First comes the file name. */ + char *fname = (char *) linep; + uint8_t *endp = memchr (fname, '\0', lineendp - linep); + if (endp == NULL) + goto invalid_data; + size_t fnamelen = endp - (uint8_t *) fname; + linep = endp + 1; + + /* Then the index. */ + Dwarf_Word diridx; + if (unlikely (linep >= lineendp)) + goto invalid_data; + get_uleb128 (diridx, linep, lineendp); + if (unlikely (diridx >= ndirlist)) + { + __libdw_seterrno (DWARF_E_INVALID_DIR_IDX); + goto out; + } + + if (*fname == '/') + /* It's an absolute path. */ + new_file->info.name = fname; + else + { + new_file->info.name = libdw_alloc (dbg, char, 1, + dirarray[diridx]->len + 1 + + fnamelen + 1); + char *cp = new_file->info.name; + + if (dirarray[diridx]->dir != NULL) + { + /* This value could be NULL in case the DW_AT_comp_dir + was not present. We cannot do much in this case. + The easiest thing is to convert the path in an + absolute path. */ + cp = stpcpy (cp, dirarray[diridx]->dir); + } + *cp++ = '/'; + strcpy (cp, fname); + assert (strlen (new_file->info.name) + < dirarray[diridx]->len + 1 + fnamelen + 1); + } + + /* Next comes the modification time. */ + if (unlikely (linep >= lineendp)) + goto invalid_data; + get_uleb128 (new_file->info.mtime, linep, lineendp); + + /* Finally the length of the file. */ + if (unlikely (linep >= lineendp)) + goto invalid_data; + get_uleb128 (new_file->info.length, linep, lineendp); + + new_file->next = filelist; + filelist = new_file; + ++nfilelist; + } + /* Skip the final NUL byte. */ + ++linep; + + /* Consistency check. */ + if (unlikely (linep != header_start + header_length)) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + goto out; + } + + /* We are about to process the statement program. Initialize the + state machine registers (see 6.2.2 in the v2.1 specification). */ + Dwarf_Word addr = 0; + unsigned int op_index = 0; + unsigned int file = 1; + int line = 1; + unsigned int column = 0; + uint_fast8_t is_stmt = default_is_stmt; + bool basic_block = false; + bool prologue_end = false; + bool epilogue_begin = false; + unsigned int isa = 0; + unsigned int discriminator = 0; + + /* Apply the "operation advance" from a special opcode or + DW_LNS_advance_pc (as per DWARF4 6.2.5.1). */ + inline void advance_pc (unsigned int op_advance) + { + addr += minimum_instr_len * ((op_index + op_advance) + / max_ops_per_instr); + op_index = (op_index + op_advance) % max_ops_per_instr; + } + + /* Process the instructions. */ + + /* Adds a new line to the matrix. + We cannot simply define a function because we want to use alloca. */ +#define NEW_LINE(end_seq) \ + do { \ + struct linelist *ll = (nlinelist < MAX_STACK_ALLOC \ + ? alloca (sizeof (struct linelist)) \ + : malloc (sizeof (struct linelist))); \ + if (nlinelist >= MAX_STACK_ALLOC) \ + malloc_linelist = ll; \ + if (unlikely (add_new_line (ll, end_seq))) \ + goto invalid_data; \ + } while (0) + + inline bool add_new_line (struct linelist *new_line, bool end_sequence) + { + new_line->next = linelist; + new_line->sequence = nlinelist; + linelist = new_line; + ++nlinelist; + + /* Set the line information. For some fields we use bitfields, + so we would lose information if the encoded values are too large. + Check just for paranoia, and call the data "invalid" if it + violates our assumptions on reasonable limits for the values. */ +#define SET(field) \ + do { \ + new_line->line.field = field; \ + if (unlikely (new_line->line.field != field)) \ + return true; \ + } while (0) + + SET (addr); + SET (op_index); + SET (file); + SET (line); + SET (column); + SET (is_stmt); + SET (basic_block); + SET (end_sequence); + SET (prologue_end); + SET (epilogue_begin); + SET (isa); + SET (discriminator); + +#undef SET + + return false; + } + + while (linep < lineendp) + { + unsigned int opcode; + unsigned int u128; + int s128; + + /* Read the opcode. */ + opcode = *linep++; + + /* Is this a special opcode? */ + if (likely (opcode >= opcode_base)) + { + if (unlikely (line_range == 0)) + goto invalid_data; + + /* Yes. Handling this is quite easy since the opcode value + is computed with + + opcode = (desired line increment - line_base) + + (line_range * address advance) + opcode_base + */ + int line_increment = (line_base + + (opcode - opcode_base) % line_range); + + /* Perform the increments. */ + line += line_increment; + advance_pc ((opcode - opcode_base) / line_range); + + /* Add a new line with the current state machine values. */ + NEW_LINE (0); + + /* Reset the flags. */ + basic_block = false; + prologue_end = false; + epilogue_begin = false; + discriminator = 0; + } + else if (opcode == 0) + { + /* This an extended opcode. */ + if (unlikely (lineendp - linep < 2)) + goto invalid_data; + + /* The length. */ + uint_fast8_t len = *linep++; + + if (unlikely ((size_t) (lineendp - linep) < len)) + goto invalid_data; + + /* The sub-opcode. */ + opcode = *linep++; + + switch (opcode) + { + case DW_LNE_end_sequence: + /* Add a new line with the current state machine values. + The is the end of the sequence. */ + NEW_LINE (1); + + /* Reset the registers. */ + addr = 0; + op_index = 0; + file = 1; + line = 1; + column = 0; + is_stmt = default_is_stmt; + basic_block = false; + prologue_end = false; + epilogue_begin = false; + isa = 0; + discriminator = 0; + break; + + case DW_LNE_set_address: + /* The value is an address. The size is defined as + apporiate for the target machine. We use the + address size field from the CU header. */ + op_index = 0; + if (unlikely (lineendp - linep < (uint8_t) address_size)) + goto invalid_data; + if (__libdw_read_address_inc (dbg, IDX_debug_line, &linep, + address_size, &addr)) + goto out; + break; + + case DW_LNE_define_file: + { + char *fname = (char *) linep; + uint8_t *endp = memchr (linep, '\0', lineendp - linep); + if (endp == NULL) + goto invalid_data; + size_t fnamelen = endp - linep; + linep = endp + 1; + + unsigned int diridx; + if (unlikely (linep >= lineendp)) + goto invalid_data; + get_uleb128 (diridx, linep, lineendp); + if (unlikely (diridx >= ndirlist)) + { + __libdw_seterrno (DWARF_E_INVALID_DIR_IDX); + goto invalid_data; + } + Dwarf_Word mtime; + if (unlikely (linep >= lineendp)) + goto invalid_data; + get_uleb128 (mtime, linep, lineendp); + Dwarf_Word filelength; + if (unlikely (linep >= lineendp)) + goto invalid_data; + get_uleb128 (filelength, linep, lineendp); + + struct filelist *new_file = + (struct filelist *) alloca (sizeof (*new_file)); + if (fname[0] == '/') + new_file->info.name = fname; + else + { + new_file->info.name = + libdw_alloc (dbg, char, 1, (dirarray[diridx]->len + 1 + + fnamelen + 1)); + char *cp = new_file->info.name; + + if (dirarray[diridx]->dir != NULL) + /* This value could be NULL in case the + DW_AT_comp_dir was not present. We + cannot do much in this case. The easiest + thing is to convert the path in an + absolute path. */ + cp = stpcpy (cp, dirarray[diridx]->dir); + *cp++ = '/'; + strcpy (cp, fname); + } + + new_file->info.mtime = mtime; + new_file->info.length = filelength; + new_file->next = filelist; + filelist = new_file; + ++nfilelist; + } + break; + + case DW_LNE_set_discriminator: + /* Takes one ULEB128 parameter, the discriminator. */ + if (unlikely (standard_opcode_lengths[opcode] != 1)) + goto invalid_data; + + if (unlikely (linep >= lineendp)) + goto invalid_data; + get_uleb128 (discriminator, linep, lineendp); + break; + + default: + /* Unknown, ignore it. */ + if (unlikely ((size_t) (lineendp - (linep - 1)) < len)) + goto invalid_data; + linep += len - 1; + break; + } + } + else if (opcode <= DW_LNS_set_isa) + { + /* This is a known standard opcode. */ + switch (opcode) + { + case DW_LNS_copy: + /* Takes no argument. */ + if (unlikely (standard_opcode_lengths[opcode] != 0)) + goto invalid_data; + + /* Add a new line with the current state machine values. */ + NEW_LINE (0); + + /* Reset the flags. */ + basic_block = false; + prologue_end = false; + epilogue_begin = false; + discriminator = 0; + break; + + case DW_LNS_advance_pc: + /* Takes one uleb128 parameter which is added to the + address. */ + if (unlikely (standard_opcode_lengths[opcode] != 1)) + goto invalid_data; + + if (unlikely (linep >= lineendp)) + goto invalid_data; + get_uleb128 (u128, linep, lineendp); + advance_pc (u128); + break; + + case DW_LNS_advance_line: + /* Takes one sleb128 parameter which is added to the + line. */ + if (unlikely (standard_opcode_lengths[opcode] != 1)) + goto invalid_data; + + if (unlikely (linep >= lineendp)) + goto invalid_data; + get_sleb128 (s128, linep, lineendp); + line += s128; + break; + + case DW_LNS_set_file: + /* Takes one uleb128 parameter which is stored in file. */ + if (unlikely (standard_opcode_lengths[opcode] != 1)) + goto invalid_data; + + if (unlikely (linep >= lineendp)) + goto invalid_data; + get_uleb128 (u128, linep, lineendp); + file = u128; + break; + + case DW_LNS_set_column: + /* Takes one uleb128 parameter which is stored in column. */ + if (unlikely (standard_opcode_lengths[opcode] != 1)) + goto invalid_data; + + if (unlikely (linep >= lineendp)) + goto invalid_data; + get_uleb128 (u128, linep, lineendp); + column = u128; + break; + + case DW_LNS_negate_stmt: + /* Takes no argument. */ + if (unlikely (standard_opcode_lengths[opcode] != 0)) + goto invalid_data; + + is_stmt = 1 - is_stmt; + break; + + case DW_LNS_set_basic_block: + /* Takes no argument. */ + if (unlikely (standard_opcode_lengths[opcode] != 0)) + goto invalid_data; + + basic_block = true; + break; + + case DW_LNS_const_add_pc: + /* Takes no argument. */ + if (unlikely (standard_opcode_lengths[opcode] != 0)) + goto invalid_data; + + if (unlikely (line_range == 0)) + goto invalid_data; + + advance_pc ((255 - opcode_base) / line_range); + break; + + case DW_LNS_fixed_advance_pc: + /* Takes one 16 bit parameter which is added to the + address. */ + if (unlikely (standard_opcode_lengths[opcode] != 1) + || unlikely (lineendp - linep < 2)) + goto invalid_data; + + addr += read_2ubyte_unaligned_inc (dbg, linep); + op_index = 0; + break; + + case DW_LNS_set_prologue_end: + /* Takes no argument. */ + if (unlikely (standard_opcode_lengths[opcode] != 0)) + goto invalid_data; + + prologue_end = true; + break; + + case DW_LNS_set_epilogue_begin: + /* Takes no argument. */ + if (unlikely (standard_opcode_lengths[opcode] != 0)) + goto invalid_data; + + epilogue_begin = true; + break; + + case DW_LNS_set_isa: + /* Takes one uleb128 parameter which is stored in isa. */ + if (unlikely (standard_opcode_lengths[opcode] != 1)) + goto invalid_data; + + if (unlikely (linep >= lineendp)) + goto invalid_data; + get_uleb128 (isa, linep, lineendp); + break; + } + } + else + { + /* This is a new opcode the generator but not we know about. + Read the parameters associated with it but then discard + everything. Read all the parameters for this opcode. */ + for (int n = standard_opcode_lengths[opcode]; n > 0; --n) + { + if (unlikely (linep >= lineendp)) + goto invalid_data; + get_uleb128 (u128, linep, lineendp); + } + + /* Next round, ignore this opcode. */ + continue; + } + } + + /* Put all the files in an array. */ + Dwarf_Files *files = libdw_alloc (dbg, Dwarf_Files, + sizeof (Dwarf_Files) + + nfilelist * sizeof (Dwarf_Fileinfo) + + (ndirlist + 1) * sizeof (char *), + 1); + const char **dirs = (void *) &files->info[nfilelist]; + + files->nfiles = nfilelist; + while (nfilelist-- > 0) + { + files->info[nfilelist] = filelist->info; + filelist = filelist->next; + } + assert (filelist == NULL); + + /* Put all the directory strings in an array. */ + files->ndirs = ndirlist; + for (unsigned int i = 0; i < ndirlist; ++i) + dirs[i] = dirarray[i]->dir; + dirs[ndirlist] = NULL; + + /* Pass the file data structure to the caller. */ + if (filesp != NULL) + *filesp = files; + + size_t buf_size = (sizeof (Dwarf_Lines) + (sizeof (Dwarf_Line) * nlinelist)); + void *buf = libdw_alloc (dbg, Dwarf_Lines, buf_size, 1); + + /* First use the buffer for the pointers, and sort the entries. + We'll write the pointers in the end of the buffer, and then + copy into the buffer from the beginning so the overlap works. */ + assert (sizeof (Dwarf_Line) >= sizeof (struct linelist *)); + struct linelist **sortlines = (buf + buf_size + - sizeof (struct linelist **) * nlinelist); + + /* The list is in LIFO order and usually they come in clumps with + ascending addresses. So fill from the back to probably start with + runs already in order before we sort. */ + for (size_t i = nlinelist; i-- > 0; ) + { + sortlines[i] = linelist; + linelist = linelist->next; + } + assert (linelist == NULL); + + /* Sort by ascending address. */ + qsort (sortlines, nlinelist, sizeof sortlines[0], &compare_lines); + + /* Now that they are sorted, put them in the final array. + The buffers overlap, so we've clobbered the early elements + of SORTLINES by the time we're reading the later ones. */ + Dwarf_Lines *lines = buf; + lines->nlines = nlinelist; + for (size_t i = 0; i < nlinelist; ++i) + { + lines->info[i] = sortlines[i]->line; + lines->info[i].files = files; + } + + /* Make sure the highest address for the CU is marked as end_sequence. + This is required by the DWARF spec, but some compilers forget and + dwfl_module_getsrc depends on it. */ + if (nlinelist > 0) + lines->info[nlinelist - 1].end_sequence = 1; + + /* Pass the line structure back to the caller. */ + if (linesp != NULL) + *linesp = lines; + + /* Success. */ + res = 0; + + out: + /* Free malloced line records, if any. */ + for (size_t i = MAX_STACK_ALLOC; i < nlinelist; i++) + { + struct linelist *ll = malloc_linelist->next; + free (malloc_linelist); + malloc_linelist = ll; + } + + return res; +} + +static int +files_lines_compare (const void *p1, const void *p2) +{ + const struct files_lines_s *t1 = p1; + const struct files_lines_s *t2 = p2; + + if (t1->debug_line_offset < t2->debug_line_offset) + return -1; + if (t1->debug_line_offset > t2->debug_line_offset) + return 1; + + return 0; +} + +int +internal_function +__libdw_getsrclines (Dwarf *dbg, Dwarf_Off debug_line_offset, + const char *comp_dir, unsigned address_size, + Dwarf_Lines **linesp, Dwarf_Files **filesp) +{ + struct files_lines_s fake = { .debug_line_offset = debug_line_offset }; + struct files_lines_s **found = tfind (&fake, &dbg->files_lines, + files_lines_compare); + if (found == NULL) + { + Elf_Data *data = __libdw_checked_get_data (dbg, IDX_debug_line); + if (data == NULL + || __libdw_offset_in_section (dbg, IDX_debug_line, + debug_line_offset, 1) != 0) + return -1; + + const unsigned char *linep = data->d_buf + debug_line_offset; + const unsigned char *lineendp = data->d_buf + data->d_size; + + struct files_lines_s *node = libdw_alloc (dbg, struct files_lines_s, + sizeof *node, 1); + + if (read_srclines (dbg, linep, lineendp, comp_dir, address_size, + &node->lines, &node->files) != 0) + return -1; + + node->debug_line_offset = debug_line_offset; + + found = tsearch (node, &dbg->files_lines, files_lines_compare); + if (found == NULL) + { + __libdw_seterrno (DWARF_E_NOMEM); + return -1; + } + } + + if (linesp != NULL) + *linesp = (*found)->lines; + + if (filesp != NULL) + *filesp = (*found)->files; + + return 0; +} + +/* Get the compilation directory, if any is set. */ +const char * +__libdw_getcompdir (Dwarf_Die *cudie) +{ + Dwarf_Attribute compdir_attr_mem; + Dwarf_Attribute *compdir_attr = INTUSE(dwarf_attr) (cudie, + DW_AT_comp_dir, + &compdir_attr_mem); + return INTUSE(dwarf_formstring) (compdir_attr); +} + +int +dwarf_getsrclines (Dwarf_Die *cudie, Dwarf_Lines **lines, size_t *nlines) +{ + if (unlikely (cudie == NULL + || (INTUSE(dwarf_tag) (cudie) != DW_TAG_compile_unit + && INTUSE(dwarf_tag) (cudie) != DW_TAG_partial_unit))) + return -1; + + /* Get the information if it is not already known. */ + struct Dwarf_CU *const cu = cudie->cu; + if (cu->lines == NULL) + { + /* Failsafe mode: no data found. */ + cu->lines = (void *) -1l; + cu->files = (void *) -1l; + + /* The die must have a statement list associated. */ + Dwarf_Attribute stmt_list_mem; + Dwarf_Attribute *stmt_list = INTUSE(dwarf_attr) (cudie, DW_AT_stmt_list, + &stmt_list_mem); + + /* Get the offset into the .debug_line section. NB: this call + also checks whether the previous dwarf_attr call failed. */ + Dwarf_Off debug_line_offset; + if (__libdw_formptr (stmt_list, IDX_debug_line, DWARF_E_NO_DEBUG_LINE, + NULL, &debug_line_offset) == NULL) + return -1; + + if (__libdw_getsrclines (cu->dbg, debug_line_offset, + __libdw_getcompdir (cudie), + cu->address_size, &cu->lines, &cu->files) < 0) + return -1; + } + else if (cu->lines == (void *) -1l) + return -1; + + *lines = cu->lines; + *nlines = cu->lines->nlines; + + // XXX Eventually: unlocking here. + + return 0; +} +INTDEF(dwarf_getsrclines) diff --git a/3rdparty/elfutils/libdw/dwarf_getstring.c b/3rdparty/elfutils/libdw/dwarf_getstring.c new file mode 100644 index 0000000..672bb27 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_getstring.c @@ -0,0 +1,66 @@ +/* Get string. + Copyright (C) 2004 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> +#include "libdwP.h" + + +const char * +dwarf_getstring (dbg, offset, lenp) + Dwarf *dbg; + Dwarf_Off offset; + size_t *lenp; +{ + if (dbg == NULL) + return NULL; + + if (dbg->sectiondata[IDX_debug_str] == NULL + || offset >= dbg->sectiondata[IDX_debug_str]->d_size) + { + no_string: + __libdw_seterrno (DWARF_E_NO_STRING); + return NULL; + } + + const char *result = ((const char *) dbg->sectiondata[IDX_debug_str]->d_buf + + offset); + const char *endp = memchr (result, '\0', + dbg->sectiondata[IDX_debug_str]->d_size - offset); + if (endp == NULL) + goto no_string; + + if (lenp != NULL) + *lenp = endp - result; + + return result; +} diff --git a/3rdparty/elfutils/libdw/dwarf_hasattr.c b/3rdparty/elfutils/libdw/dwarf_hasattr.c new file mode 100644 index 0000000..812c09b --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_hasattr.c @@ -0,0 +1,85 @@ +/* Check whether given DIE has specific attribute. + Copyright (C) 2003, 2005, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +int +dwarf_hasattr (die, search_name) + Dwarf_Die *die; + unsigned int search_name; +{ + if (die == NULL) + return 0; + + /* Find the abbreviation entry. */ + Dwarf_Abbrev *abbrevp = __libdw_dieabbrev (die, NULL); + if (unlikely (abbrevp == DWARF_END_ABBREV)) + { + invalid_dwarf: + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return 0; + } + + Dwarf *dbg = die->cu->dbg; + + /* Search the name attribute. */ + unsigned char *const endp + = ((unsigned char *) dbg->sectiondata[IDX_debug_abbrev]->d_buf + + dbg->sectiondata[IDX_debug_abbrev]->d_size); + + const unsigned char *attrp = abbrevp->attrp; + while (1) + { + /* Are we still in bounds? This test needs to be refined. */ + if (unlikely (attrp >= endp)) + goto invalid_dwarf; + + /* Get attribute name and form. */ + unsigned int attr_name; + get_uleb128 (attr_name, attrp, endp); + unsigned int attr_form; + if (unlikely (attrp >= endp)) + goto invalid_dwarf; + get_uleb128 (attr_form, attrp, endp); + + /* We can stop if we found the attribute with value zero. */ + if (attr_name == 0 || attr_form == 0) + return 0; + + if (attr_name == search_name) + return 1; + } +} +INTDEF (dwarf_hasattr) diff --git a/3rdparty/elfutils/libdw/dwarf_hasattr_integrate.c b/3rdparty/elfutils/libdw/dwarf_hasattr_integrate.c new file mode 100644 index 0000000..2d5348c --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_hasattr_integrate.c @@ -0,0 +1,59 @@ +/* Check whether DIE has specific attribute, integrating DW_AT_abstract_origin. + Copyright (C) 2005 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + +int +dwarf_hasattr_integrate (Dwarf_Die *die, unsigned int search_name) +{ + Dwarf_Die die_mem; + + do + { + if (INTUSE(dwarf_hasattr) (die, search_name)) + return 1; + + Dwarf_Attribute attr_mem; + Dwarf_Attribute *attr = INTUSE(dwarf_attr) (die, DW_AT_abstract_origin, + &attr_mem); + if (attr == NULL) + attr = INTUSE(dwarf_attr) (die, DW_AT_specification, &attr_mem); + if (attr == NULL) + break; + + die = INTUSE(dwarf_formref_die) (attr, &die_mem); + } + while (die != NULL); + + return 0; +} diff --git a/3rdparty/elfutils/libdw/dwarf_haschildren.c b/3rdparty/elfutils/libdw/dwarf_haschildren.c new file mode 100644 index 0000000..d0ce51e --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_haschildren.c @@ -0,0 +1,52 @@ +/* Return string associated with given attribute. + Copyright (C) 2003, 2005, 2008, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" +#include <string.h> + + +int +dwarf_haschildren (die) + Dwarf_Die *die; +{ + /* Find the abbreviation entry. */ + Dwarf_Abbrev *abbrevp = __libdw_dieabbrev (die, NULL); + if (unlikely (abbrevp == DWARF_END_ABBREV)) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } + + return abbrevp->has_children; +} +INTDEF (dwarf_haschildren) diff --git a/3rdparty/elfutils/libdw/dwarf_hasform.c b/3rdparty/elfutils/libdw/dwarf_hasform.c new file mode 100644 index 0000000..a95ca9e --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_hasform.c @@ -0,0 +1,47 @@ +/* Check whether given attribute has specific form. + Copyright (C) 2003 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +int +dwarf_hasform (attr, search_form) + Dwarf_Attribute *attr; + unsigned int search_form; +{ + if (attr == NULL) + return 0; + + return attr->form == search_form; +} diff --git a/3rdparty/elfutils/libdw/dwarf_haspc.c b/3rdparty/elfutils/libdw/dwarf_haspc.c new file mode 100644 index 0000000..47e2b05 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_haspc.c @@ -0,0 +1,54 @@ +/* Determine whether a DIE covers a PC address. + Copyright (C) 2005 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" +#include <dwarf.h> + + +int +dwarf_haspc (Dwarf_Die *die, Dwarf_Addr pc) +{ + if (die == NULL) + return -1; + + Dwarf_Addr base; + Dwarf_Addr begin; + Dwarf_Addr end; + ptrdiff_t offset = 0; + while ((offset = INTUSE(dwarf_ranges) (die, offset, &base, + &begin, &end)) > 0) + if (pc >= begin && pc < end) + return 1; + + return offset; +} +INTDEF (dwarf_haspc) diff --git a/3rdparty/elfutils/libdw/dwarf_highpc.c b/3rdparty/elfutils/libdw/dwarf_highpc.c new file mode 100644 index 0000000..8bf93f0 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_highpc.c @@ -0,0 +1,68 @@ +/* Return high PC attribute of DIE. + Copyright (C) 2003, 2005, 2012 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +int +dwarf_highpc (die, return_addr) + Dwarf_Die *die; + Dwarf_Addr *return_addr; +{ + Dwarf_Attribute attr_high_mem; + Dwarf_Attribute *attr_high = INTUSE(dwarf_attr) (die, DW_AT_high_pc, + &attr_high_mem); + if (attr_high == NULL) + return -1; + + if (attr_high->form == DW_FORM_addr) + return INTUSE(dwarf_formaddr) (attr_high, return_addr); + + /* DWARF 4 allows high_pc to be a constant offset from low_pc. */ + Dwarf_Attribute attr_low_mem; + if (INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (die, DW_AT_low_pc, + &attr_low_mem), + return_addr) == 0) + { + Dwarf_Word uval; + if (INTUSE(dwarf_formudata) (attr_high, &uval) == 0) + { + *return_addr += uval; + return 0; + } + __libdw_seterrno (DWARF_E_NO_ADDR); + } + return -1; +} +INTDEF(dwarf_highpc) diff --git a/3rdparty/elfutils/libdw/dwarf_lineaddr.c b/3rdparty/elfutils/libdw/dwarf_lineaddr.c new file mode 100644 index 0000000..4e1952d --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_lineaddr.c @@ -0,0 +1,46 @@ +/* Return line address. + Copyright (C) 2004 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +int +dwarf_lineaddr (Dwarf_Line *line, Dwarf_Addr *addrp) +{ + if (line == NULL) + return -1; + + *addrp = line->addr; + + return 0; +} diff --git a/3rdparty/elfutils/libdw/dwarf_linebeginstatement.c b/3rdparty/elfutils/libdw/dwarf_linebeginstatement.c new file mode 100644 index 0000000..4854c56 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_linebeginstatement.c @@ -0,0 +1,46 @@ +/* Return true if record is for beginning of a statement. + Copyright (C) 2004 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +int +dwarf_linebeginstatement (Dwarf_Line *line, bool *flagp) +{ + if (line == NULL) + return -1; + + *flagp = line->is_stmt; + + return 0; +} diff --git a/3rdparty/elfutils/libdw/dwarf_lineblock.c b/3rdparty/elfutils/libdw/dwarf_lineblock.c new file mode 100644 index 0000000..e3c7f41 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_lineblock.c @@ -0,0 +1,46 @@ +/* Return true if record is for beginning of a basic block. + Copyright (C) 2004 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +int +dwarf_lineblock (Dwarf_Line *line, bool *flagp) +{ + if (line == NULL) + return -1; + + *flagp = line->basic_block; + + return 0; +} diff --git a/3rdparty/elfutils/libdw/dwarf_linecol.c b/3rdparty/elfutils/libdw/dwarf_linecol.c new file mode 100644 index 0000000..c667b1b --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_linecol.c @@ -0,0 +1,46 @@ +/* Return column in line. + Copyright (C) 2004 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +int +dwarf_linecol (Dwarf_Line *line, int *colp) +{ + if (line == NULL) + return -1; + + *colp = line->column; + + return 0; +} diff --git a/3rdparty/elfutils/libdw/dwarf_linediscriminator.c b/3rdparty/elfutils/libdw/dwarf_linediscriminator.c new file mode 100644 index 0000000..552205a --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_linediscriminator.c @@ -0,0 +1,45 @@ +/* Return code path discriminator in line record. + Copyright (C) 2010 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +int +dwarf_linediscriminator (Dwarf_Line *line, unsigned int *discp) +{ + if (line == NULL) + return -1; + + *discp = line->discriminator; + + return 0; +} diff --git a/3rdparty/elfutils/libdw/dwarf_lineendsequence.c b/3rdparty/elfutils/libdw/dwarf_lineendsequence.c new file mode 100644 index 0000000..61bde93 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_lineendsequence.c @@ -0,0 +1,46 @@ +/* Return true if record is for end of sequence. + Copyright (C) 2004 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +int +dwarf_lineendsequence (Dwarf_Line *line, bool *flagp) +{ + if (line == NULL) + return -1; + + *flagp = line->end_sequence; + + return 0; +} diff --git a/3rdparty/elfutils/libdw/dwarf_lineepiloguebegin.c b/3rdparty/elfutils/libdw/dwarf_lineepiloguebegin.c new file mode 100644 index 0000000..b914787 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_lineepiloguebegin.c @@ -0,0 +1,46 @@ +/* Return true if record is for beginning of epilogue. + Copyright (C) 2004 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +int +dwarf_lineepiloguebegin (Dwarf_Line *line, bool *flagp) +{ + if (line == NULL) + return -1; + + *flagp = line->epilogue_begin; + + return 0; +} diff --git a/3rdparty/elfutils/libdw/dwarf_lineisa.c b/3rdparty/elfutils/libdw/dwarf_lineisa.c new file mode 100644 index 0000000..30181fc --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_lineisa.c @@ -0,0 +1,45 @@ +/* Return ISA in line. + Copyright (C) 2010 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +int +dwarf_lineisa (Dwarf_Line *line, unsigned int *isap) +{ + if (line == NULL) + return -1; + + *isap = line->isa; + + return 0; +} diff --git a/3rdparty/elfutils/libdw/dwarf_lineno.c b/3rdparty/elfutils/libdw/dwarf_lineno.c new file mode 100644 index 0000000..009999c --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_lineno.c @@ -0,0 +1,46 @@ +/* Return line number. + Copyright (C) 2004 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +int +dwarf_lineno (Dwarf_Line *line, int *linep) +{ + if (line == NULL) + return -1; + + *linep = line->line; + + return 0; +} diff --git a/3rdparty/elfutils/libdw/dwarf_lineop_index.c b/3rdparty/elfutils/libdw/dwarf_lineop_index.c new file mode 100644 index 0000000..9ea4ef4 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_lineop_index.c @@ -0,0 +1,45 @@ +/* Return line VLIW operation index. + Copyright (C) 2010 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +int +dwarf_lineop_index (Dwarf_Line *line, unsigned int *idxp) +{ + if (line == NULL) + return -1; + + *idxp = line->op_index; + + return 0; +} diff --git a/3rdparty/elfutils/libdw/dwarf_lineprologueend.c b/3rdparty/elfutils/libdw/dwarf_lineprologueend.c new file mode 100644 index 0000000..6ba8be2 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_lineprologueend.c @@ -0,0 +1,46 @@ +/* Return true if record is for end of prologue. + Copyright (C) 2004 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +int +dwarf_lineprologueend (Dwarf_Line *line, bool *flagp) +{ + if (line == NULL) + return -1; + + *flagp = line->prologue_end; + + return 0; +} diff --git a/3rdparty/elfutils/libdw/dwarf_linesrc.c b/3rdparty/elfutils/libdw/dwarf_linesrc.c new file mode 100644 index 0000000..27b5990 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_linesrc.c @@ -0,0 +1,56 @@ +/* Find line information for address. + Copyright (C) 2004 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +const char * +dwarf_linesrc (Dwarf_Line *line, Dwarf_Word *mtime, Dwarf_Word *length) +{ + if (line == NULL) + return NULL; + + if (line->file >= line->files->nfiles) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; + } + + if (mtime != NULL) + *mtime = line->files->info[line->file].mtime; + + if (length != NULL) + *length = line->files->info[line->file].length; + + return line->files->info[line->file].name; +} diff --git a/3rdparty/elfutils/libdw/dwarf_lowpc.c b/3rdparty/elfutils/libdw/dwarf_lowpc.c new file mode 100644 index 0000000..4677aed --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_lowpc.c @@ -0,0 +1,49 @@ +/* Return low PC attribute of DIE. + Copyright (C) 2003, 2005 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +int +dwarf_lowpc (die, return_addr) + Dwarf_Die *die; + Dwarf_Addr *return_addr; +{ + Dwarf_Attribute attr_mem; + + return INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (die, DW_AT_low_pc, + &attr_mem), + return_addr); +} +INTDEF(dwarf_lowpc) diff --git a/3rdparty/elfutils/libdw/dwarf_macro_getparamcnt.c b/3rdparty/elfutils/libdw/dwarf_macro_getparamcnt.c new file mode 100644 index 0000000..e218eb1 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_macro_getparamcnt.c @@ -0,0 +1,43 @@ +/* Return number of parameters of a macro. + Copyright (C) 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + +int +dwarf_macro_getparamcnt (Dwarf_Macro *macro, size_t *paramcntp) +{ + if (macro == NULL) + return -1; + + *paramcntp = libdw_macro_nforms (macro); + return 0; +} diff --git a/3rdparty/elfutils/libdw/dwarf_macro_getsrcfiles.c b/3rdparty/elfutils/libdw/dwarf_macro_getsrcfiles.c new file mode 100644 index 0000000..cc19043 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_macro_getsrcfiles.c @@ -0,0 +1,88 @@ +/* Find line information for a given macro. + Copyright (C) 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + +int +dwarf_macro_getsrcfiles (Dwarf *dbg, Dwarf_Macro *macro, + Dwarf_Files **files, size_t *nfiles) +{ + if (macro == NULL) + return -1; + + Dwarf_Macro_Op_Table *const table = macro->table; + if (table->files == NULL) + { + Dwarf_Off line_offset = table->line_offset; + if (line_offset == (Dwarf_Off) -1) + { + *files = NULL; + *nfiles = 0; + return 0; + } + + /* If TABLE->comp_dir is NULL that could mean any of the + following: + + - The macro unit is not bound to a CU. It's an auxiliary + unit used purely for import from other units. In that case + there's actually no COMP_DIR value that we could use. + + - The macro unit is bound to a CU, but there's no + DW_AT_comp_dir attribute at the CU DIE. + + - The macro unit is bound to a CU, but we don't know that, + likely because its iteration was requested through + dwarf_getmacros_off interface. This might be legitimate if + one macro unit imports another CU's macro unit, but that is + unlikely to happen in practice. Most probably this is not + legitimate use of the interfaces. + + So when the interfaces are used correctly, COMP_DIR value is + always right. That means that we can cache the parsed + .debug_line unit without fear that later on someone requests + the same unit through dwarf_getsrcfiles, and the file names + will be broken. */ + + if (__libdw_getsrclines (dbg, line_offset, table->comp_dir, + table->is_64bit ? 8 : 4, + NULL, &table->files) < 0) + table->files = (void *) -1; + } + + if (table->files == (void *) -1) + return -1; + + *files = table->files; + *nfiles = table->files->nfiles; + return 0; +} diff --git a/3rdparty/elfutils/libdw/dwarf_macro_opcode.c b/3rdparty/elfutils/libdw/dwarf_macro_opcode.c new file mode 100644 index 0000000..8607777 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_macro_opcode.c @@ -0,0 +1,46 @@ +/* Return macro opcode. + Copyright (C) 2005 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2005. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +int +dwarf_macro_opcode (Dwarf_Macro *macro, unsigned int *opcodep) +{ + if (macro == NULL) + return -1; + + *opcodep = macro->opcode; + + return 0; +} diff --git a/3rdparty/elfutils/libdw/dwarf_macro_param.c b/3rdparty/elfutils/libdw/dwarf_macro_param.c new file mode 100644 index 0000000..bd846a7 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_macro_param.c @@ -0,0 +1,46 @@ +/* Return a given parameter of a macro. + Copyright (C) 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + +int +dwarf_macro_param (Dwarf_Macro *macro, size_t idx, Dwarf_Attribute *ret) +{ + if (macro == NULL) + return -1; + + if (idx >= libdw_macro_nforms (macro)) + return -1; + + *ret = macro->attributes[idx]; + return 0; +} diff --git a/3rdparty/elfutils/libdw/dwarf_macro_param1.c b/3rdparty/elfutils/libdw/dwarf_macro_param1.c new file mode 100644 index 0000000..87ce003 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_macro_param1.c @@ -0,0 +1,48 @@ +/* Return first macro parameter. + Copyright (C) 2005, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2005. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +int +dwarf_macro_param1 (Dwarf_Macro *macro, Dwarf_Word *paramp) +{ + if (macro == NULL) + return -1; + + Dwarf_Attribute param; + if (dwarf_macro_param (macro, 0, ¶m) != 0) + return -1; + + return dwarf_formudata (¶m, paramp); +} diff --git a/3rdparty/elfutils/libdw/dwarf_macro_param2.c b/3rdparty/elfutils/libdw/dwarf_macro_param2.c new file mode 100644 index 0000000..cc902c9 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_macro_param2.c @@ -0,0 +1,55 @@ +/* Return second macro parameter. + Copyright (C) 2005, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2005. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +int +dwarf_macro_param2 (Dwarf_Macro *macro, Dwarf_Word *paramp, const char **strp) +{ + if (macro == NULL) + return -1; + + Dwarf_Attribute param; + if (dwarf_macro_param (macro, 1, ¶m) != 0) + return -1; + + if (param.form == DW_FORM_string + || param.form == DW_FORM_strp) + { + *strp = dwarf_formstring (¶m); + return 0; + } + else + return dwarf_formudata (¶m, paramp); +} diff --git a/3rdparty/elfutils/libdw/dwarf_next_cfi.c b/3rdparty/elfutils/libdw/dwarf_next_cfi.c new file mode 100644 index 0000000..b5af49e --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_next_cfi.c @@ -0,0 +1,246 @@ +/* Advance to next CFI entry. + Copyright (C) 2009-2010, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "cfi.h" +#include "encoded-value.h" + +#include <string.h> + + +int +dwarf_next_cfi (e_ident, data, eh_frame_p, off, next_off, entry) + const unsigned char e_ident[]; + Elf_Data *data; + bool eh_frame_p; + Dwarf_Off off; + Dwarf_Off *next_off; + Dwarf_CFI_Entry *entry; +{ + /* Dummy struct for memory-access.h macros. */ + BYTE_ORDER_DUMMY (dw, e_ident); + + /* If we reached the end before don't do anything. */ + if (off == (Dwarf_Off) -1l + /* Make sure there is enough space in the .debug_frame section + for at least the initial word. We cannot test the rest since + we don't know yet whether this is a 64-bit object or not. */ + || unlikely (off + 4 >= data->d_size)) + { + *next_off = (Dwarf_Off) -1l; + return 1; + } + + /* This points into the .debug_frame section at the start of the entry. */ + const uint8_t *bytes = data->d_buf + off; + const uint8_t *limit = data->d_buf + data->d_size; + + /* The format of a CFI entry is described in DWARF3 6.4.1: + */ + + uint64_t length = read_4ubyte_unaligned_inc (&dw, bytes); + size_t offset_size = 4; + if (length == DWARF3_LENGTH_64_BIT) + { + /* This is the 64-bit DWARF format. */ + offset_size = 8; + if (unlikely (limit - bytes < 8)) + { + invalid: + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } + length = read_8ubyte_unaligned_inc (&dw, bytes); + } + if (unlikely ((uint64_t) (limit - bytes) < length) + || unlikely (length < offset_size + 1)) + goto invalid; + + /* Now we know how large the entry is. Note the trick in the + computation. If the offset_size is 4 the '- 4' term undoes the + '2 *'. If offset_size is 8 this term computes the size of the + escape value plus the 8 byte offset. */ + *next_off = off + (2 * offset_size - 4) + length; + + limit = bytes + length; + + const uint8_t *const cie_pointer_start = bytes; + if (offset_size == 8) + entry->cie.CIE_id = read_8ubyte_unaligned_inc (&dw, bytes); + else + { + entry->cie.CIE_id = read_4ubyte_unaligned_inc (&dw, bytes); + /* Canonicalize the 32-bit CIE_ID value to 64 bits. */ + if (!eh_frame_p && entry->cie.CIE_id == DW_CIE_ID_32) + entry->cie.CIE_id = DW_CIE_ID_64; + } + if (eh_frame_p) + { + /* Canonicalize the .eh_frame CIE pointer to .debug_frame format. */ + if (entry->cie.CIE_id == 0) + entry->cie.CIE_id = DW_CIE_ID_64; + else + { + /* In .eh_frame format, a CIE pointer is the distance from where + it appears back to the beginning of the CIE. */ + ptrdiff_t pos = cie_pointer_start - (const uint8_t *) data->d_buf; + if (unlikely (entry->cie.CIE_id > (Dwarf_Off) pos) + || unlikely (pos <= (ptrdiff_t) offset_size)) + goto invalid; + entry->cie.CIE_id = pos - entry->cie.CIE_id; + } + } + + if (entry->cie.CIE_id == DW_CIE_ID_64) + { + /* Read the version stamp. Always an 8-bit value. */ + uint8_t version = *bytes++; + + if (version != 1 && (unlikely (version < 3) || unlikely (version > 4))) + goto invalid; + + entry->cie.augmentation = (const char *) bytes; + + bytes = memchr (bytes, '\0', limit - bytes); + if (unlikely (bytes == NULL)) + goto invalid; + ++bytes; + + /* The address size for CFI is implicit in the ELF class. */ + uint_fast8_t address_size = e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8; + uint_fast8_t segment_size = 0; + if (version >= 4) + { + if (unlikely (limit - bytes < 5)) + goto invalid; + /* XXX We don't actually support address_size not matching the class. + To do so, we'd have to return it here so that intern_new_cie + could use it choose a specific fde_encoding. */ + if (unlikely (*bytes != address_size)) + { + __libdw_seterrno (DWARF_E_VERSION); + return -1; + } + address_size = *bytes++; + segment_size = *bytes++; + /* We don't actually support segment selectors. We'd have to + roll this into the fde_encoding bits or something. */ + if (unlikely (segment_size != 0)) + { + __libdw_seterrno (DWARF_E_VERSION); + return -1; + } + } + + const char *ap = entry->cie.augmentation; + + /* g++ v2 "eh" has pointer immediately following augmentation string, + so it must be handled first. */ + if (unlikely (ap[0] == 'e' && ap[1] == 'h')) + { + ap += 2; + bytes += address_size; + } + + if (bytes >= limit) + goto invalid; + get_uleb128 (entry->cie.code_alignment_factor, bytes, limit); + + if (bytes >= limit) + goto invalid; + get_sleb128 (entry->cie.data_alignment_factor, bytes, limit); + + if (bytes >= limit) + goto invalid; + + if (version >= 3) /* DWARF 3+ */ + get_uleb128 (entry->cie.return_address_register, bytes, limit); + else /* DWARF 2 */ + entry->cie.return_address_register = *bytes++; + + /* If we have sized augmentation data, + we don't need to grok it all. */ + entry->cie.fde_augmentation_data_size = 0; + bool sized_augmentation = *ap == 'z'; + if (sized_augmentation) + { + if (bytes >= limit) + goto invalid; + get_uleb128 (entry->cie.augmentation_data_size, bytes, limit); + if ((Dwarf_Word) (limit - bytes) < entry->cie.augmentation_data_size) + goto invalid; + entry->cie.augmentation_data = bytes; + bytes += entry->cie.augmentation_data_size; + } + else + { + entry->cie.augmentation_data = bytes; + + for (; *ap != '\0'; ++ap) + { + uint8_t encoding; + switch (*ap) + { + case 'L': /* Skip LSDA pointer encoding byte. */ + case 'R': /* Skip FDE address encoding byte. */ + encoding = *bytes++; + entry->cie.fde_augmentation_data_size + += encoded_value_size (data, e_ident, encoding, NULL); + continue; + case 'P': /* Skip encoded personality routine pointer. */ + encoding = *bytes++; + bytes += encoded_value_size (data, e_ident, encoding, bytes); + continue; + case 'S': /* Skip signal-frame flag. */ + continue; + default: + /* Unknown augmentation string. initial_instructions might + actually start with some augmentation data. */ + break; + } + break; + } + entry->cie.augmentation_data_size + = bytes - entry->cie.augmentation_data; + } + + entry->cie.initial_instructions = bytes; + entry->cie.initial_instructions_end = limit; + } + else + { + entry->fde.start = bytes; + entry->fde.end = limit; + } + + return 0; +} +INTDEF (dwarf_next_cfi) diff --git a/3rdparty/elfutils/libdw/dwarf_nextcu.c b/3rdparty/elfutils/libdw/dwarf_nextcu.c new file mode 100644 index 0000000..875d869 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_nextcu.c @@ -0,0 +1,199 @@ +/* Advance to next CU header. + Copyright (C) 2002-2010 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libdwP.h> +#include <dwarf.h> + + +int +dwarf_next_unit (dwarf, off, next_off, header_sizep, versionp, abbrev_offsetp, + address_sizep, offset_sizep, type_signaturep, type_offsetp) + Dwarf *dwarf; + Dwarf_Off off; + Dwarf_Off *next_off; + size_t *header_sizep; + Dwarf_Half *versionp; + Dwarf_Off *abbrev_offsetp; + uint8_t *address_sizep; + uint8_t *offset_sizep; + uint64_t *type_signaturep; + Dwarf_Off *type_offsetp; +{ + const bool debug_types = type_signaturep != NULL; + const size_t sec_idx = debug_types ? IDX_debug_types : IDX_debug_info; + + /* Maybe there has been an error before. */ + if (dwarf == NULL) + return -1; + + /* If we reached the end before don't do anything. */ + if (off == (Dwarf_Off) -1l + || unlikely (dwarf->sectiondata[sec_idx] == NULL) + /* Make sure there is enough space in the .debug_info section + for at least the initial word. We cannot test the rest since + we don't know yet whether this is a 64-bit object or not. */ + || unlikely (off + 4 >= dwarf->sectiondata[sec_idx]->d_size)) + { + *next_off = (Dwarf_Off) -1l; + return 1; + } + + /* This points into the .debug_info section to the beginning of the + CU entry. */ + const unsigned char *data = dwarf->sectiondata[sec_idx]->d_buf; + const unsigned char *bytes = data + off; + + /* The format of the CU header is described in dwarf2p1 7.5.1: + + 1. A 4-byte or 12-byte unsigned integer representing the length + of the .debug_info contribution for that compilation unit, not + including the length field itself. In the 32-bit DWARF format, + this is a 4-byte unsigned integer (which must be less than + 0xfffffff0); in the 64-bit DWARF format, this consists of the + 4-byte value 0xffffffff followed by an 8-byte unsigned integer + that gives the actual length (see Section 7.2.2). + + 2. A 2-byte unsigned integer representing the version of the + DWARF information for that compilation unit. For DWARF Version + 2.1, the value in this field is 2. + + 3. A 4-byte or 8-byte unsigned offset into the .debug_abbrev + section. This offset associates the compilation unit with a + particular set of debugging information entry abbreviations. In + the 32-bit DWARF format, this is a 4-byte unsigned length; in + the 64-bit DWARF format, this is an 8-byte unsigned length (see + Section 7.4). + + 4. A 1-byte unsigned integer representing the size in bytes of + an address on the target architecture. If the system uses + segmented addressing, this value represents the size of the + offset portion of an address. */ + uint64_t length = read_4ubyte_unaligned_inc (dwarf, bytes); + size_t offset_size = 4; + /* Lengths of 0xfffffff0 - 0xffffffff are escape codes. Oxffffffff is + used to indicate that 64-bit dwarf information is being used, the + other values are currently reserved. */ + if (length == DWARF3_LENGTH_64_BIT) + offset_size = 8; + else if (unlikely (length >= DWARF3_LENGTH_MIN_ESCAPE_CODE + && length <= DWARF3_LENGTH_MAX_ESCAPE_CODE)) + { + invalid: + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } + + /* Now we know how large the header is. */ + if (unlikely (DIE_OFFSET_FROM_CU_OFFSET (off, offset_size, debug_types) + >= dwarf->sectiondata[sec_idx]->d_size)) + { + *next_off = -1; + return 1; + } + + if (length == DWARF3_LENGTH_64_BIT) + /* This is a 64-bit DWARF format. */ + length = read_8ubyte_unaligned_inc (dwarf, bytes); + + /* Read the version stamp. Always a 16-bit value. */ + uint_fast16_t version = read_2ubyte_unaligned_inc (dwarf, bytes); + + /* Get offset in .debug_abbrev. Note that the size of the entry + depends on whether this is a 32-bit or 64-bit DWARF definition. */ + uint64_t abbrev_offset; + if (__libdw_read_offset_inc (dwarf, sec_idx, &bytes, offset_size, + &abbrev_offset, IDX_debug_abbrev, 0)) + return -1; + + /* The address size. Always an 8-bit value. */ + uint8_t address_size = *bytes++; + + if (debug_types) + { + uint64_t type_sig8 = read_8ubyte_unaligned_inc (dwarf, bytes); + + Dwarf_Off type_offset; + if (__libdw_read_offset_inc (dwarf, sec_idx, &bytes, offset_size, + &type_offset, sec_idx, 0)) + return -1; + + /* Validate that the TYPE_OFFSET points past the header. */ + if (unlikely (type_offset < (size_t) (bytes - (data + off)))) + goto invalid; + + *type_signaturep = type_sig8; + if (type_offsetp != NULL) + *type_offsetp = type_offset; + } + + /* Store the header length. */ + if (header_sizep != NULL) + *header_sizep = bytes - (data + off); + + if (versionp != NULL) + *versionp = version; + + if (abbrev_offsetp != NULL) + *abbrev_offsetp = abbrev_offset; + + if (address_sizep != NULL) + *address_sizep = address_size; + + /* Store the offset size. */ + if (offset_sizep != NULL) + *offset_sizep = offset_size; + + /* See definition of DIE_OFFSET_FROM_CU_OFFSET macro + for an explanation of the trick in this expression. */ + *next_off = off + 2 * offset_size - 4 + length; + + return 0; +} +INTDEF(dwarf_next_unit) + +int +dwarf_nextcu (dwarf, off, next_off, header_sizep, abbrev_offsetp, + address_sizep, offset_sizep) + Dwarf *dwarf; + Dwarf_Off off; + Dwarf_Off *next_off; + size_t *header_sizep; + Dwarf_Off *abbrev_offsetp; + uint8_t *address_sizep; + uint8_t *offset_sizep; +{ + return INTUSE(dwarf_next_unit) (dwarf, off, next_off, header_sizep, NULL, + abbrev_offsetp, address_sizep, offset_sizep, + NULL, NULL); +} +INTDEF(dwarf_nextcu) diff --git a/3rdparty/elfutils/libdw/dwarf_offabbrev.c b/3rdparty/elfutils/libdw/dwarf_offabbrev.c new file mode 100644 index 0000000..27cdad6 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_offabbrev.c @@ -0,0 +1,51 @@ +/* Get abbreviation at given offset. + Copyright (C) 2004, 2005 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +int +dwarf_offabbrev (Dwarf *dbg, Dwarf_Off offset, size_t *lengthp, + Dwarf_Abbrev *abbrevp) +{ + if (dbg == NULL) + return -1; + + Dwarf_Abbrev *abbrev = __libdw_getabbrev (dbg, NULL, offset, lengthp, + abbrevp); + + if (abbrev == NULL) + return -1; + + return abbrev == DWARF_END_ABBREV ? 1 : 0; +} diff --git a/3rdparty/elfutils/libdw/dwarf_offdie.c b/3rdparty/elfutils/libdw/dwarf_offdie.c new file mode 100644 index 0000000..b5dd405 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_offdie.c @@ -0,0 +1,90 @@ +/* Return DIE at given offset. + Copyright (C) 2002-2010 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> +#include "libdwP.h" + + +Dwarf_Die * +internal_function +__libdw_offdie (Dwarf *dbg, Dwarf_Off offset, Dwarf_Die *result, + bool debug_types) +{ + if (dbg == NULL) + return NULL; + + Elf_Data *const data = dbg->sectiondata[debug_types ? IDX_debug_types + : IDX_debug_info]; + if (offset >= data->d_size) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; + } + + /* Clear the entire DIE structure. This signals we have not yet + determined any of the information. */ + memset (result, '\0', sizeof (Dwarf_Die)); + + result->addr = (char *) data->d_buf + offset; + + /* Get the CU. */ + result->cu = __libdw_findcu (dbg, offset, debug_types); + if (result->cu == NULL) + { + /* This should never happen. The input file is malformed. */ + __libdw_seterrno (DWARF_E_INVALID_DWARF); + result = NULL; + } + + return result; +} + + +Dwarf_Die * +dwarf_offdie (dbg, offset, result) + Dwarf *dbg; + Dwarf_Off offset; + Dwarf_Die *result; +{ + return __libdw_offdie (dbg, offset, result, false); +} +INTDEF(dwarf_offdie) + +Dwarf_Die * +dwarf_offdie_types (dbg, offset, result) + Dwarf *dbg; + Dwarf_Off offset; + Dwarf_Die *result; +{ + return __libdw_offdie (dbg, offset, result, true); +} diff --git a/3rdparty/elfutils/libdw/dwarf_onearange.c b/3rdparty/elfutils/libdw/dwarf_onearange.c new file mode 100644 index 0000000..de49f6c --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_onearange.c @@ -0,0 +1,50 @@ +/* Return one of the address range entries. + Copyright (C) 2004 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +Dwarf_Arange * +dwarf_onearange (Dwarf_Aranges *aranges, size_t idx) +{ + if (aranges == NULL) + return NULL; + + if (idx >= aranges->naranges) + { + __libdw_seterrno (DWARF_E_INVALID_ARANGE_IDX); + return NULL; + } + + return &aranges->info[idx]; +} diff --git a/3rdparty/elfutils/libdw/dwarf_onesrcline.c b/3rdparty/elfutils/libdw/dwarf_onesrcline.c new file mode 100644 index 0000000..5d3c3de --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_onesrcline.c @@ -0,0 +1,50 @@ +/* Return one of the sources lines of a CU. + Copyright (C) 2004 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +Dwarf_Line * +dwarf_onesrcline (Dwarf_Lines *lines, size_t idx) +{ + if (lines == NULL) + return NULL; + + if (idx >= lines->nlines) + { + __libdw_seterrno (DWARF_E_INVALID_LINE_IDX); + return NULL; + } + + return &lines->info[idx]; +} diff --git a/3rdparty/elfutils/libdw/dwarf_peel_type.c b/3rdparty/elfutils/libdw/dwarf_peel_type.c new file mode 100644 index 0000000..a110bc5 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_peel_type.c @@ -0,0 +1,74 @@ +/* Peel type aliases and qualifier tags from a type DIE. + Copyright (C) 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" +#include <dwarf.h> +#include <string.h> + + +int +dwarf_peel_type (die, result) + Dwarf_Die *die; + Dwarf_Die *result; +{ + int tag; + + /* Ignore previous errors. */ + if (die == NULL) + return -1; + + *result = *die; + tag = INTUSE (dwarf_tag) (result); + while (tag == DW_TAG_typedef + || tag == DW_TAG_const_type + || tag == DW_TAG_volatile_type + || tag == DW_TAG_restrict_type) + { + Dwarf_Attribute attr_mem; + Dwarf_Attribute *attr = INTUSE (dwarf_attr_integrate) (die, DW_AT_type, + &attr_mem); + if (attr == NULL) + return 1; + + result = INTUSE (dwarf_formref_die) (attr, result); + if (result == NULL) + return -1; + + tag = INTUSE (dwarf_tag) (result); + } + + if (tag == DW_TAG_invalid) + return -1; + + return 0; +} +INTDEF(dwarf_peel_type) diff --git a/3rdparty/elfutils/libdw/dwarf_ranges.c b/3rdparty/elfutils/libdw/dwarf_ranges.c new file mode 100644 index 0000000..d9b7293 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_ranges.c @@ -0,0 +1,190 @@ +/* Enumerate the PC ranges covered by a DIE. + Copyright (C) 2005, 2007, 2009 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" +#include <dwarf.h> +#include <assert.h> + +/* Read up begin/end pair and increment read pointer. + - If it's normal range record, set up `*beginp' and `*endp' and return 0. + - If it's base address selection record, set up `*basep' and return 1. + - If it's end of rangelist, don't set anything and return 2 + - If an error occurs, don't set anything and return -1. */ +internal_function int +__libdw_read_begin_end_pair_inc (Dwarf *dbg, int sec_index, + unsigned char **addrp, int width, + Dwarf_Addr *beginp, Dwarf_Addr *endp, + Dwarf_Addr *basep) +{ + Dwarf_Addr escape = (width == 8 ? (Elf64_Addr) -1 + : (Elf64_Addr) (Elf32_Addr) -1); + Dwarf_Addr begin; + Dwarf_Addr end; + + unsigned char *addr = *addrp; + bool begin_relocated = READ_AND_RELOCATE (__libdw_relocate_address, begin); + bool end_relocated = READ_AND_RELOCATE (__libdw_relocate_address, end); + *addrp = addr; + + /* Unrelocated escape for begin means base address selection. */ + if (begin == escape && !begin_relocated) + { + if (unlikely (end == escape)) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } + + if (basep != NULL) + *basep = end; + return 1; + } + + /* Unrelocated pair of zeroes means end of range list. */ + if (begin == 0 && end == 0 && !begin_relocated && !end_relocated) + return 2; + + /* Don't check for begin_relocated == end_relocated. Serve the data + to the client even though it may be buggy. */ + *beginp = begin; + *endp = end; + + return 0; +} + +ptrdiff_t +dwarf_ranges (Dwarf_Die *die, ptrdiff_t offset, Dwarf_Addr *basep, + Dwarf_Addr *startp, Dwarf_Addr *endp) +{ + if (die == NULL) + return -1; + + if (offset == 0 + /* Usually there is a single contiguous range. */ + && INTUSE(dwarf_highpc) (die, endp) == 0 + && INTUSE(dwarf_lowpc) (die, startp) == 0) + /* A offset into .debug_ranges will never be 1, it must be at least a + multiple of 4. So we can return 1 as a special case value to mark + there are no ranges to look for on the next call. */ + return 1; + + if (offset == 1) + return 0; + + /* We have to look for a noncontiguous range. */ + + const Elf_Data *d = die->cu->dbg->sectiondata[IDX_debug_ranges]; + if (d == NULL && offset != 0) + { + __libdw_seterrno (DWARF_E_NO_DEBUG_RANGES); + return -1; + } + + unsigned char *readp; + unsigned char *readendp; + if (offset == 0) + { + Dwarf_Attribute attr_mem; + Dwarf_Attribute *attr = INTUSE(dwarf_attr) (die, DW_AT_ranges, + &attr_mem); + if (attr == NULL) + /* No PC attributes in this DIE at all, so an empty range list. */ + return 0; + + Dwarf_Word start_offset; + if ((readp = __libdw_formptr (attr, IDX_debug_ranges, + DWARF_E_NO_DEBUG_RANGES, + &readendp, &start_offset)) == NULL) + return -1; + + offset = start_offset; + assert ((Dwarf_Word) offset == start_offset); + + /* Fetch the CU's base address. */ + Dwarf_Die cudie = CUDIE (attr->cu); + + /* Find the base address of the compilation unit. It will + normally be specified by DW_AT_low_pc. In DWARF-3 draft 4, + the base address could be overridden by DW_AT_entry_pc. It's + been removed, but GCC emits DW_AT_entry_pc and not DW_AT_lowpc + for compilation units with discontinuous ranges. */ + if (unlikely (INTUSE(dwarf_lowpc) (&cudie, basep) != 0) + && INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (&cudie, + DW_AT_entry_pc, + &attr_mem), + basep) != 0) + { + if (INTUSE(dwarf_errno) () == 0) + { + invalid: + __libdw_seterrno (DWARF_E_INVALID_DWARF); + } + return -1; + } + } + else + { + if (__libdw_offset_in_section (die->cu->dbg, + IDX_debug_ranges, offset, 1)) + return -1l; + + readp = d->d_buf + offset; + readendp = d->d_buf + d->d_size; + } + + next: + if (readendp - readp < die->cu->address_size * 2) + goto invalid; + + Dwarf_Addr begin; + Dwarf_Addr end; + + switch (__libdw_read_begin_end_pair_inc (die->cu->dbg, IDX_debug_ranges, + &readp, die->cu->address_size, + &begin, &end, basep)) + { + case 0: + break; + case 1: + goto next; + case 2: + return 0; + default: + return -1l; + } + + /* We have an address range entry. */ + *startp = *basep + begin; + *endp = *basep + end; + return readp - (unsigned char *) d->d_buf; +} +INTDEF (dwarf_ranges) diff --git a/3rdparty/elfutils/libdw/dwarf_setalt.c b/3rdparty/elfutils/libdw/dwarf_setalt.c new file mode 100644 index 0000000..9bd566f --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_setalt.c @@ -0,0 +1,40 @@ +/* Provides the data referenced by the .gnu_debugaltlink section. + Copyright (C) 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + +void +dwarf_setalt (Dwarf *main, Dwarf *alt) +{ + main->alt_dwarf = alt; +} +INTDEF (dwarf_setalt) diff --git a/3rdparty/elfutils/libdw/dwarf_siblingof.c b/3rdparty/elfutils/libdw/dwarf_siblingof.c new file mode 100644 index 0000000..27830ea --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_siblingof.c @@ -0,0 +1,136 @@ +/* Return sibling of given DIE. + Copyright (C) 2003-2010, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" +#include <dwarf.h> +#include <string.h> + + +int +dwarf_siblingof (die, result) + Dwarf_Die *die; + Dwarf_Die *result; +{ + /* Ignore previous errors. */ + if (die == NULL) + return -1; + + if (result == NULL) + return -1; + + if (result != die) + result->addr = NULL; + + unsigned int level = 0; + + /* Copy of the current DIE. */ + Dwarf_Die this_die = *die; + /* Temporary attributes we create. */ + Dwarf_Attribute sibattr; + /* Copy of the CU in the request. */ + sibattr.cu = this_die.cu; + /* That's the address we start looking. */ + unsigned char *addr = this_die.addr; + /* End of the buffer. */ + unsigned char *endp = sibattr.cu->endp; + + /* Search for the beginning of the next die on this level. We + must not return the dies for children of the given die. */ + do + { + /* Find the end of the DIE or the sibling attribute. */ + addr = __libdw_find_attr (&this_die, DW_AT_sibling, &sibattr.code, + &sibattr.form); + if (addr != NULL && sibattr.code == DW_AT_sibling) + { + Dwarf_Off offset; + sibattr.valp = addr; + if (unlikely (__libdw_formref (&sibattr, &offset) != 0)) + /* Something went wrong. */ + return -1; + + /* Compute the next address. */ + addr = sibattr.cu->startp + offset; + } + else if (unlikely (addr == NULL) + || unlikely (this_die.abbrev == DWARF_END_ABBREV)) + return -1; + else if (this_die.abbrev->has_children) + /* This abbreviation has children. */ + ++level; + + + while (1) + { + /* Make sure we are still in range. Some producers might skip + the trailing NUL bytes. */ + if (addr >= endp) + return 1; + + if (*addr != '\0') + break; + + if (level-- == 0) + { + if (result != die) + result->addr = addr; + /* No more sibling at all. */ + return 1; + } + + ++addr; + } + + /* Initialize the 'current DIE'. */ + this_die.addr = addr; + this_die.abbrev = NULL; + } + while (level > 0); + + /* Maybe we reached the end of the CU. */ + if (addr >= endp) + return 1; + + /* Clear the entire DIE structure. This signals we have not yet + determined any of the information. */ + memset (result, '\0', sizeof (Dwarf_Die)); + + /* We have the address. */ + result->addr = addr; + + /* Same CU as the parent. */ + result->cu = sibattr.cu; + + return 0; +} +INTDEF(dwarf_siblingof) diff --git a/3rdparty/elfutils/libdw/dwarf_sig8_hash.c b/3rdparty/elfutils/libdw/dwarf_sig8_hash.c new file mode 100644 index 0000000..043cac7 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_sig8_hash.c @@ -0,0 +1,41 @@ +/* Implementation of hash table for DWARF .debug_types section content. + Copyright (C) 2010 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define NO_UNDEF +#include "dwarf_sig8_hash.h" +#undef NO_UNDEF + +/* This is defined in dwarf_abbrev_hash.c, we can just use it here. */ +#define next_prime __libdwarf_next_prime +extern size_t next_prime (size_t) attribute_hidden; + +#include <dynamicsizehash.c> diff --git a/3rdparty/elfutils/libdw/dwarf_sig8_hash.h b/3rdparty/elfutils/libdw/dwarf_sig8_hash.h new file mode 100644 index 0000000..705ffbc --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_sig8_hash.h @@ -0,0 +1,38 @@ +/* Hash table for DWARF .debug_types section content. + Copyright (C) 2010 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifndef _DWARF_SIG8_HASH_H +#define _DWARF_SIG8_HASH_H 1 + +#define NAME Dwarf_Sig8_Hash +#define TYPE struct Dwarf_CU * +#define COMPARE(a, b) (0) + +#include <dynamicsizehash.h> + +#endif /* dwarf_sig8_hash.h */ diff --git a/3rdparty/elfutils/libdw/dwarf_srclang.c b/3rdparty/elfutils/libdw/dwarf_srclang.c new file mode 100644 index 0000000..6cc06ff --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_srclang.c @@ -0,0 +1,51 @@ +/* Return source language attribute of DIE. + Copyright (C) 2003-2010 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +int +dwarf_srclang (die) + Dwarf_Die *die; +{ + Dwarf_Attribute attr_mem; + Dwarf_Word value; + + return INTUSE(dwarf_formudata) (INTUSE(dwarf_attr_integrate) + (die, DW_AT_language, &attr_mem), + &value) == 0 ? (int) value : -1; +} +INTDEF (dwarf_srclang) +OLD_VERSION (dwarf_srclang, ELFUTILS_0.122) +NEW_VERSION (dwarf_srclang, ELFUTILS_0.143) diff --git a/3rdparty/elfutils/libdw/dwarf_tag.c b/3rdparty/elfutils/libdw/dwarf_tag.c new file mode 100644 index 0000000..0b1a4b0 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_tag.c @@ -0,0 +1,95 @@ +/* Return tag of given DIE. + Copyright (C) 2003-2011, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" + + +Dwarf_Abbrev * +internal_function +__libdw_findabbrev (struct Dwarf_CU *cu, unsigned int code) +{ + Dwarf_Abbrev *abb; + + /* Abbreviation code can never have a value of 0. */ + if (unlikely (code == 0)) + return DWARF_END_ABBREV; + + /* See whether the entry is already in the hash table. */ + abb = Dwarf_Abbrev_Hash_find (&cu->abbrev_hash, code, NULL); + if (abb == NULL) + while (cu->last_abbrev_offset != (size_t) -1l) + { + size_t length; + + /* Find the next entry. It gets automatically added to the + hash table. */ + abb = __libdw_getabbrev (cu->dbg, cu, cu->last_abbrev_offset, &length, + NULL); + if (abb == NULL || abb == DWARF_END_ABBREV) + { + /* Make sure we do not try to search for it again. */ + cu->last_abbrev_offset = (size_t) -1l; + return DWARF_END_ABBREV; + } + + cu->last_abbrev_offset += length; + + /* Is this the code we are looking for? */ + if (abb->code == code) + break; + } + + /* This is our second (or third, etc.) call to __libdw_findabbrev + and the code is invalid. */ + if (unlikely (abb == NULL)) + abb = DWARF_END_ABBREV; + + return abb; +} + + +int +dwarf_tag (die) + Dwarf_Die *die; +{ + /* Find the abbreviation entry. */ + Dwarf_Abbrev *abbrevp = __libdw_dieabbrev (die, NULL); + if (unlikely (abbrevp == DWARF_END_ABBREV)) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return DW_TAG_invalid; + } + + return abbrevp->tag; +} +INTDEF(dwarf_tag) diff --git a/3rdparty/elfutils/libdw/dwarf_whatattr.c b/3rdparty/elfutils/libdw/dwarf_whatattr.c new file mode 100644 index 0000000..8fe5535 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_whatattr.c @@ -0,0 +1,43 @@ +/* Return attribute code of given attribute. + Copyright (C) 2003 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +unsigned int +dwarf_whatattr (attr) + Dwarf_Attribute *attr; +{ + return attr == NULL ? 0 : attr->code; +} diff --git a/3rdparty/elfutils/libdw/dwarf_whatform.c b/3rdparty/elfutils/libdw/dwarf_whatform.c new file mode 100644 index 0000000..1d0d14b --- /dev/null +++ b/3rdparty/elfutils/libdw/dwarf_whatform.c @@ -0,0 +1,43 @@ +/* Return form code of given attribute. + Copyright (C) 2003 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include "libdwP.h" + + +unsigned int +dwarf_whatform (attr) + Dwarf_Attribute *attr; +{ + return attr == NULL ? 0 : attr->form; +} diff --git a/3rdparty/elfutils/libdw/dwheaders.pri b/3rdparty/elfutils/libdw/dwheaders.pri new file mode 100644 index 0000000..254b586 --- /dev/null +++ b/3rdparty/elfutils/libdw/dwheaders.pri @@ -0,0 +1,12 @@ +HEADERS += \ + $$PWD/cfi.h \ + $$PWD/dwarf_abbrev_hash.h \ + $$PWD/dwarf_sig8_hash.h \ + $$PWD/dwarf.h \ + $$PWD/encoded-value.h \ + $$PWD/known-dwarf.h \ + $$PWD/libdw.h \ + $$PWD/libdwP.h \ + $$PWD/memory-access.h + +INCLUDEPATH += $$PWD diff --git a/3rdparty/elfutils/libdw/encoded-value.h b/3rdparty/elfutils/libdw/encoded-value.h new file mode 100644 index 0000000..ae9a38f --- /dev/null +++ b/3rdparty/elfutils/libdw/encoded-value.h @@ -0,0 +1,197 @@ +/* DW_EH_PE_* support for libdw unwinder. + Copyright (C) 2009-2010, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifndef _ENCODED_VALUE_H +#define _ENCODED_VALUE_H 1 + +#include <dwarf.h> +#include <stdlib.h> +#include "libdwP.h" + + +static size_t __attribute__ ((unused)) +encoded_value_size (const Elf_Data *data, const unsigned char e_ident[], + uint8_t encoding, const uint8_t *p) +{ + if (encoding == DW_EH_PE_omit) + return 0; + + switch (encoding & 0x07) + { + case DW_EH_PE_udata2: + return 2; + case DW_EH_PE_udata4: + return 4; + case DW_EH_PE_udata8: + return 8; + + case DW_EH_PE_absptr: + return e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8; + + case DW_EH_PE_uleb128: + if (p != NULL) + { + const uint8_t *end = p; + while (end < (uint8_t *) data->d_buf + data->d_size) + if (*end++ & 0x80u) + return end - p; + } + + default: + abort (); + return 0; + } +} + +static inline int __attribute__ ((unused)) +__libdw_cfi_read_address_inc (const Dwarf_CFI *cache, + const unsigned char **addrp, + int width, Dwarf_Addr *ret) +{ + width = width ?: cache->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8; + + if (cache->dbg != NULL) + return __libdw_read_address_inc (cache->dbg, IDX_debug_frame, + addrp, width, ret); + + /* Only .debug_frame might have relocation to consider. + Read plain values from .eh_frame data. */ + + if (width == 4) + *ret = read_4ubyte_unaligned_inc (cache, *addrp); + else + *ret = read_8ubyte_unaligned_inc (cache, *addrp); + return 0; +} + +static bool __attribute__ ((unused)) +read_encoded_value (const Dwarf_CFI *cache, uint8_t encoding, const uint8_t **p, + Dwarf_Addr *result) +{ + *result = 0; + switch (encoding & 0x70) + { + case DW_EH_PE_absptr: + break; + case DW_EH_PE_pcrel: + *result = (cache->frame_vaddr + + (*p - (const uint8_t *) cache->data->d.d_buf)); + break; + case DW_EH_PE_textrel: + // ia64: segrel + *result = cache->textrel; + break; + case DW_EH_PE_datarel: + // i386: GOTOFF + // ia64: gprel + *result = cache->datarel; + break; + case DW_EH_PE_funcrel: /* XXX */ + break; + case DW_EH_PE_aligned: + { + const size_t size = encoded_value_size (&cache->data->d, cache->e_ident, + encoding, *p); + size_t align = ((cache->frame_vaddr + + (*p - (const uint8_t *) cache->data->d.d_buf)) + & (size - 1)); + if (align != 0) + *p += size - align; + break; + } + + default: + abort (); + } + + Dwarf_Addr value; + switch (encoding & 0x0f) + { + case DW_EH_PE_udata2: + value = read_2ubyte_unaligned_inc (cache, *p); + break; + + case DW_EH_PE_sdata2: + value = read_2sbyte_unaligned_inc (cache, *p); + break; + + case DW_EH_PE_udata4: + if (__libdw_cfi_read_address_inc (cache, p, 4, &value)) + return true; + break; + + case DW_EH_PE_sdata4: + if (__libdw_cfi_read_address_inc (cache, p, 4, &value)) + return true; + value = (Dwarf_Sword) (Elf32_Sword) value; /* Sign-extend. */ + break; + + case DW_EH_PE_udata8: + case DW_EH_PE_sdata8: + if (__libdw_cfi_read_address_inc (cache, p, 8, &value)) + return true; + break; + + case DW_EH_PE_absptr: + if (__libdw_cfi_read_address_inc (cache, p, 0, &value)) + return true; + break; + + case DW_EH_PE_uleb128: + // XXX we trust there is enough data. + get_uleb128 (value, *p, *p + len_leb128 (Dwarf_Addr)); + break; + + case DW_EH_PE_sleb128: + // XXX we trust there is enough data. + get_sleb128 (value, *p, *p + len_leb128 (Dwarf_Addr)); + break; + + default: + abort (); + } + + *result += value; + + if (encoding & DW_EH_PE_indirect) + { + if (unlikely (*result < cache->frame_vaddr)) + return true; + *result -= cache->frame_vaddr; + if (unlikely (*result > (cache->data->d.d_size + - encoded_value_size (NULL, cache->e_ident, + DW_EH_PE_absptr, NULL)))) + return true; + const uint8_t *ptr = cache->data->d.d_buf + *result; + return __libdw_cfi_read_address_inc (cache, &ptr, 0, result); + } + + return false; +} + +#endif /* encoded-value.h */ diff --git a/3rdparty/elfutils/libdw/fde.c b/3rdparty/elfutils/libdw/fde.c new file mode 100644 index 0000000..18a522b --- /dev/null +++ b/3rdparty/elfutils/libdw/fde.c @@ -0,0 +1,297 @@ +/* FDE reading. + Copyright (C) 2009-2010, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "cfi.h" +#include <search.h> +#include <stdlib.h> + +#include "encoded-value.h" + +static int +compare_fde (const void *a, const void *b) +{ + const struct dwarf_fde *fde1 = a; + const struct dwarf_fde *fde2 = b; + + /* Find out which of the two arguments is the search value. + It has end offset 0. */ + if (fde1->end == 0) + { + if (fde1->start < fde2->start) + return -1; + if (fde1->start >= fde2->end) + return 1; + } + else + { + if (fde2->start < fde1->start) + return 1; + if (fde2->start >= fde1->end) + return -1; + } + + return 0; +} + +static struct dwarf_fde * +intern_fde (Dwarf_CFI *cache, const Dwarf_FDE *entry) +{ + /* Look up the new entry's CIE. */ + struct dwarf_cie *cie = __libdw_find_cie (cache, entry->CIE_pointer); + if (cie == NULL) + return (void *) -1l; + + struct dwarf_fde *fde = malloc (sizeof (struct dwarf_fde)); + if (fde == NULL) + { + __libdw_seterrno (DWARF_E_NOMEM); + return NULL; + } + + fde->instructions = entry->start; + fde->instructions_end = entry->end; + if (unlikely (read_encoded_value (cache, cie->fde_encoding, + &fde->instructions, &fde->start)) + || unlikely (read_encoded_value (cache, cie->fde_encoding & 0x0f, + &fde->instructions, &fde->end))) + { + free (fde); + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; + } + fde->end += fde->start; + + fde->cie = cie; + + if (cie->sized_augmentation_data) + { + /* The CIE augmentation says the FDE has a DW_FORM_block + before its actual instruction stream. */ + Dwarf_Word len; + get_uleb128 (len, fde->instructions, fde->instructions_end); + if ((Dwarf_Word) (fde->instructions_end - fde->instructions) < len) + { + free (fde); + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; + } + fde->instructions += len; + } + else + /* We had to understand all of the CIE augmentation string. + We've recorded the number of data bytes in FDEs. */ + fde->instructions += cie->fde_augmentation_data_size; + + /* Add the new entry to the search tree. */ + if (tsearch (fde, &cache->fde_tree, &compare_fde) == NULL) + { + free (fde); + __libdw_seterrno (DWARF_E_NOMEM); + return NULL; + } + + return fde; +} + +struct dwarf_fde * +internal_function +__libdw_fde_by_offset (Dwarf_CFI *cache, Dwarf_Off offset) +{ + Dwarf_CFI_Entry entry; + Dwarf_Off next_offset; + int result = INTUSE(dwarf_next_cfi) (cache->e_ident, + &cache->data->d, CFI_IS_EH (cache), + offset, &next_offset, &entry); + if (result != 0) + { + if (result > 0) + invalid: + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; + } + + if (unlikely (dwarf_cfi_cie_p (&entry))) + goto invalid; + + /* We have a new FDE to consider. */ + struct dwarf_fde *fde = intern_fde (cache, &entry.fde); + if (fde == (void *) -1l || fde == NULL) + return NULL; + + /* If this happened to be what we would have read next, notice it. */ + if (cache->next_offset == offset) + cache->next_offset = next_offset; + + return fde; +} + +/* Use a binary search table in .eh_frame_hdr format, yield an FDE offset. */ +static Dwarf_Off +binary_search_fde (Dwarf_CFI *cache, Dwarf_Addr address) +{ + const size_t size = 2 * encoded_value_size (&cache->data->d, cache->e_ident, + cache->search_table_encoding, + NULL); + + /* Dummy used by read_encoded_value. */ + Dwarf_CFI dummy_cfi = + { + .e_ident = cache->e_ident, + .datarel = cache->search_table_vaddr, + .frame_vaddr = cache->search_table_vaddr, + }; + + size_t l = 0, u = cache->search_table_entries; + while (l < u) + { + size_t idx = (l + u) / 2; + + const uint8_t *p = &cache->search_table[idx * size]; + Dwarf_Addr start; + if (unlikely (read_encoded_value (&dummy_cfi, + cache->search_table_encoding, &p, + &start))) + break; + if (address < start) + u = idx; + else + { + l = idx + 1; + + Dwarf_Addr fde; + if (unlikely (read_encoded_value (&dummy_cfi, + cache->search_table_encoding, &p, + &fde))) + break; + + /* If this is the last entry, its upper bound is assumed to be + the end of the module. + XXX really should be end of containing PT_LOAD segment */ + if (l < cache->search_table_entries) + { + /* Look at the start address in the following entry. */ + Dwarf_Addr end; + if (unlikely (read_encoded_value + (&dummy_cfi, cache->search_table_encoding, &p, + &end))) + break; + if (address >= end) + continue; + } + + return fde - cache->frame_vaddr; + } + } + + return (Dwarf_Off) -1l; +} + +struct dwarf_fde * +internal_function +__libdw_find_fde (Dwarf_CFI *cache, Dwarf_Addr address) +{ + /* Look for a cached FDE covering this address. */ + + const struct dwarf_fde fde_key = { .start = address, .end = 0 }; + struct dwarf_fde **found = tfind (&fde_key, &cache->fde_tree, &compare_fde); + if (found != NULL) + return *found; + + /* Use .eh_frame_hdr binary search table if possible. */ + if (cache->search_table != NULL) + { + Dwarf_Off offset = binary_search_fde (cache, address); + if (offset == (Dwarf_Off) -1l) + goto no_match; + struct dwarf_fde *fde = __libdw_fde_by_offset (cache, offset); + if (likely (fde != NULL)) + { + /* Sanity check the address range. */ + if (unlikely (address < fde->start)) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; + } + /* .eh_frame_hdr does not indicate length covered by FDE. */ + if (unlikely (address >= fde->end)) + goto no_match; + } + return fde; + } + + /* It's not there. Read more CFI entries until we find it. */ + while (1) + { + Dwarf_Off last_offset = cache->next_offset; + Dwarf_CFI_Entry entry; + int result = INTUSE(dwarf_next_cfi) (cache->e_ident, + &cache->data->d, CFI_IS_EH (cache), + last_offset, &cache->next_offset, + &entry); + if (result > 0) + break; + if (result < 0) + { + if (cache->next_offset == last_offset) + /* We couldn't progress past the bogus FDE. */ + break; + /* Skip the loser and look at the next entry. */ + continue; + } + + if (dwarf_cfi_cie_p (&entry)) + { + /* This is a CIE, not an FDE. We eagerly intern these + because the next FDE will usually refer to this CIE. */ + __libdw_intern_cie (cache, last_offset, &entry.cie); + continue; + } + + /* We have a new FDE to consider. */ + struct dwarf_fde *fde = intern_fde (cache, &entry.fde); + + if (fde == (void *) -1l) /* Bad FDE, but we can keep looking. */ + continue; + + if (fde == NULL) /* Bad data. */ + return NULL; + + /* Is this the one we're looking for? */ + if (fde->start <= address && fde->end > address) + return fde; + } + + no_match: + /* We found no FDE covering this address. */ + __libdw_seterrno (DWARF_E_NO_MATCH); + return NULL; +} diff --git a/3rdparty/elfutils/libdw/frame-cache.c b/3rdparty/elfutils/libdw/frame-cache.c new file mode 100644 index 0000000..54a1cc9 --- /dev/null +++ b/3rdparty/elfutils/libdw/frame-cache.c @@ -0,0 +1,66 @@ +/* Frame cache handling. + Copyright (C) 2009 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "cfi.h" +#include <search.h> +#include <stdlib.h> + + +static void +free_cie (void *arg) +{ + struct dwarf_cie *cie = arg; + + free ((Dwarf_Frame *) cie->initial_state); + free (cie); +} + +#define free_fde free + +static void +free_expr (void *arg) +{ + struct loc_s *loc = arg; + + free (loc->loc); + free (loc); +} + +void +internal_function +__libdw_destroy_frame_cache (Dwarf_CFI *cache) +{ + /* Most of the data is in our two search trees. */ + tdestroy (cache->fde_tree, free_fde); + tdestroy (cache->cie_tree, free_cie); + tdestroy (cache->expr_tree, free_expr); +} diff --git a/3rdparty/elfutils/libdw/known-dwarf.h b/3rdparty/elfutils/libdw/known-dwarf.h new file mode 100644 index 0000000..2aeada9 --- /dev/null +++ b/3rdparty/elfutils/libdw/known-dwarf.h @@ -0,0 +1,629 @@ +/* Generated by config/known-dwarf.awk from libdw/dwarf.h contents. */ + +#define ALL_KNOWN_DW_ACCESS \ + ONE_KNOWN_DW_ACCESS (private, DW_ACCESS_private) \ + ONE_KNOWN_DW_ACCESS (protected, DW_ACCESS_protected) \ + ONE_KNOWN_DW_ACCESS (public, DW_ACCESS_public) \ + /* End of DW_ACCESS_*. */ + +#define ALL_KNOWN_DW_AT \ + ONE_KNOWN_DW_AT (GNU_all_call_sites, DW_AT_GNU_all_call_sites) \ + ONE_KNOWN_DW_AT (GNU_all_source_call_sites, DW_AT_GNU_all_source_call_sites) \ + ONE_KNOWN_DW_AT (GNU_all_tail_call_sites, DW_AT_GNU_all_tail_call_sites) \ + ONE_KNOWN_DW_AT (GNU_call_site_data_value, DW_AT_GNU_call_site_data_value) \ + ONE_KNOWN_DW_AT (GNU_call_site_target, DW_AT_GNU_call_site_target) \ + ONE_KNOWN_DW_AT (GNU_call_site_target_clobbered, DW_AT_GNU_call_site_target_clobbered) \ + ONE_KNOWN_DW_AT (GNU_call_site_value, DW_AT_GNU_call_site_value) \ + ONE_KNOWN_DW_AT (GNU_deleted, DW_AT_GNU_deleted) \ + ONE_KNOWN_DW_AT (GNU_exclusive_locks_required, DW_AT_GNU_exclusive_locks_required) \ + ONE_KNOWN_DW_AT (GNU_guarded, DW_AT_GNU_guarded) \ + ONE_KNOWN_DW_AT (GNU_guarded_by, DW_AT_GNU_guarded_by) \ + ONE_KNOWN_DW_AT (GNU_locks_excluded, DW_AT_GNU_locks_excluded) \ + ONE_KNOWN_DW_AT (GNU_macros, DW_AT_GNU_macros) \ + ONE_KNOWN_DW_AT (GNU_odr_signature, DW_AT_GNU_odr_signature) \ + ONE_KNOWN_DW_AT (GNU_pt_guarded, DW_AT_GNU_pt_guarded) \ + ONE_KNOWN_DW_AT (GNU_pt_guarded_by, DW_AT_GNU_pt_guarded_by) \ + ONE_KNOWN_DW_AT (GNU_shared_locks_required, DW_AT_GNU_shared_locks_required) \ + ONE_KNOWN_DW_AT (GNU_tail_call, DW_AT_GNU_tail_call) \ + ONE_KNOWN_DW_AT (GNU_template_name, DW_AT_GNU_template_name) \ + ONE_KNOWN_DW_AT (GNU_vector, DW_AT_GNU_vector) \ + ONE_KNOWN_DW_AT (MIPS_abstract_name, DW_AT_MIPS_abstract_name) \ + ONE_KNOWN_DW_AT (MIPS_allocatable_dopetype, DW_AT_MIPS_allocatable_dopetype) \ + ONE_KNOWN_DW_AT (MIPS_assumed_shape_dopetype, DW_AT_MIPS_assumed_shape_dopetype) \ + ONE_KNOWN_DW_AT (MIPS_assumed_size, DW_AT_MIPS_assumed_size) \ + ONE_KNOWN_DW_AT (MIPS_clone_origin, DW_AT_MIPS_clone_origin) \ + ONE_KNOWN_DW_AT (MIPS_epilog_begin, DW_AT_MIPS_epilog_begin) \ + ONE_KNOWN_DW_AT (MIPS_fde, DW_AT_MIPS_fde) \ + ONE_KNOWN_DW_AT (MIPS_has_inlines, DW_AT_MIPS_has_inlines) \ + ONE_KNOWN_DW_AT (MIPS_linkage_name, DW_AT_MIPS_linkage_name) \ + ONE_KNOWN_DW_AT (MIPS_loop_begin, DW_AT_MIPS_loop_begin) \ + ONE_KNOWN_DW_AT (MIPS_loop_unroll_factor, DW_AT_MIPS_loop_unroll_factor) \ + ONE_KNOWN_DW_AT (MIPS_ptr_dopetype, DW_AT_MIPS_ptr_dopetype) \ + ONE_KNOWN_DW_AT (MIPS_software_pipeline_depth, DW_AT_MIPS_software_pipeline_depth) \ + ONE_KNOWN_DW_AT (MIPS_stride, DW_AT_MIPS_stride) \ + ONE_KNOWN_DW_AT (MIPS_stride_byte, DW_AT_MIPS_stride_byte) \ + ONE_KNOWN_DW_AT (MIPS_stride_elem, DW_AT_MIPS_stride_elem) \ + ONE_KNOWN_DW_AT (MIPS_tail_loop_begin, DW_AT_MIPS_tail_loop_begin) \ + ONE_KNOWN_DW_AT (abstract_origin, DW_AT_abstract_origin) \ + ONE_KNOWN_DW_AT (accessibility, DW_AT_accessibility) \ + ONE_KNOWN_DW_AT (address_class, DW_AT_address_class) \ + ONE_KNOWN_DW_AT (allocated, DW_AT_allocated) \ + ONE_KNOWN_DW_AT (artificial, DW_AT_artificial) \ + ONE_KNOWN_DW_AT (associated, DW_AT_associated) \ + ONE_KNOWN_DW_AT (base_types, DW_AT_base_types) \ + ONE_KNOWN_DW_AT (binary_scale, DW_AT_binary_scale) \ + ONE_KNOWN_DW_AT (bit_offset, DW_AT_bit_offset) \ + ONE_KNOWN_DW_AT (bit_size, DW_AT_bit_size) \ + ONE_KNOWN_DW_AT (bit_stride, DW_AT_bit_stride) \ + ONE_KNOWN_DW_AT (body_begin, DW_AT_body_begin) \ + ONE_KNOWN_DW_AT (body_end, DW_AT_body_end) \ + ONE_KNOWN_DW_AT (byte_size, DW_AT_byte_size) \ + ONE_KNOWN_DW_AT (byte_stride, DW_AT_byte_stride) \ + ONE_KNOWN_DW_AT (call_column, DW_AT_call_column) \ + ONE_KNOWN_DW_AT (call_file, DW_AT_call_file) \ + ONE_KNOWN_DW_AT (call_line, DW_AT_call_line) \ + ONE_KNOWN_DW_AT (calling_convention, DW_AT_calling_convention) \ + ONE_KNOWN_DW_AT (common_reference, DW_AT_common_reference) \ + ONE_KNOWN_DW_AT (comp_dir, DW_AT_comp_dir) \ + ONE_KNOWN_DW_AT (const_expr, DW_AT_const_expr) \ + ONE_KNOWN_DW_AT (const_value, DW_AT_const_value) \ + ONE_KNOWN_DW_AT (containing_type, DW_AT_containing_type) \ + ONE_KNOWN_DW_AT (count, DW_AT_count) \ + ONE_KNOWN_DW_AT (data_bit_offset, DW_AT_data_bit_offset) \ + ONE_KNOWN_DW_AT (data_location, DW_AT_data_location) \ + ONE_KNOWN_DW_AT (data_member_location, DW_AT_data_member_location) \ + ONE_KNOWN_DW_AT (decimal_scale, DW_AT_decimal_scale) \ + ONE_KNOWN_DW_AT (decimal_sign, DW_AT_decimal_sign) \ + ONE_KNOWN_DW_AT (decl_column, DW_AT_decl_column) \ + ONE_KNOWN_DW_AT (decl_file, DW_AT_decl_file) \ + ONE_KNOWN_DW_AT (decl_line, DW_AT_decl_line) \ + ONE_KNOWN_DW_AT (declaration, DW_AT_declaration) \ + ONE_KNOWN_DW_AT (default_value, DW_AT_default_value) \ + ONE_KNOWN_DW_AT (description, DW_AT_description) \ + ONE_KNOWN_DW_AT (digit_count, DW_AT_digit_count) \ + ONE_KNOWN_DW_AT (discr, DW_AT_discr) \ + ONE_KNOWN_DW_AT (discr_list, DW_AT_discr_list) \ + ONE_KNOWN_DW_AT (discr_value, DW_AT_discr_value) \ + ONE_KNOWN_DW_AT (element_list, DW_AT_element_list) \ + ONE_KNOWN_DW_AT (elemental, DW_AT_elemental) \ + ONE_KNOWN_DW_AT (encoding, DW_AT_encoding) \ + ONE_KNOWN_DW_AT (endianity, DW_AT_endianity) \ + ONE_KNOWN_DW_AT (entry_pc, DW_AT_entry_pc) \ + ONE_KNOWN_DW_AT (enum_class, DW_AT_enum_class) \ + ONE_KNOWN_DW_AT (explicit, DW_AT_explicit) \ + ONE_KNOWN_DW_AT (extension, DW_AT_extension) \ + ONE_KNOWN_DW_AT (external, DW_AT_external) \ + ONE_KNOWN_DW_AT (frame_base, DW_AT_frame_base) \ + ONE_KNOWN_DW_AT (friend, DW_AT_friend) \ + ONE_KNOWN_DW_AT (high_pc, DW_AT_high_pc) \ + ONE_KNOWN_DW_AT (identifier_case, DW_AT_identifier_case) \ + ONE_KNOWN_DW_AT (import, DW_AT_import) \ + ONE_KNOWN_DW_AT (inline, DW_AT_inline) \ + ONE_KNOWN_DW_AT (is_optional, DW_AT_is_optional) \ + ONE_KNOWN_DW_AT (language, DW_AT_language) \ + ONE_KNOWN_DW_AT (linkage_name, DW_AT_linkage_name) \ + ONE_KNOWN_DW_AT (location, DW_AT_location) \ + ONE_KNOWN_DW_AT (low_pc, DW_AT_low_pc) \ + ONE_KNOWN_DW_AT (lower_bound, DW_AT_lower_bound) \ + ONE_KNOWN_DW_AT (mac_info, DW_AT_mac_info) \ + ONE_KNOWN_DW_AT (macro_info, DW_AT_macro_info) \ + ONE_KNOWN_DW_AT (main_subprogram, DW_AT_main_subprogram) \ + ONE_KNOWN_DW_AT (member, DW_AT_member) \ + ONE_KNOWN_DW_AT (mutable, DW_AT_mutable) \ + ONE_KNOWN_DW_AT (name, DW_AT_name) \ + ONE_KNOWN_DW_AT (namelist_item, DW_AT_namelist_item) \ + ONE_KNOWN_DW_AT (noreturn, DW_AT_noreturn) \ + ONE_KNOWN_DW_AT (object_pointer, DW_AT_object_pointer) \ + ONE_KNOWN_DW_AT (ordering, DW_AT_ordering) \ + ONE_KNOWN_DW_AT (picture_string, DW_AT_picture_string) \ + ONE_KNOWN_DW_AT (priority, DW_AT_priority) \ + ONE_KNOWN_DW_AT (producer, DW_AT_producer) \ + ONE_KNOWN_DW_AT (prototyped, DW_AT_prototyped) \ + ONE_KNOWN_DW_AT (pure, DW_AT_pure) \ + ONE_KNOWN_DW_AT (ranges, DW_AT_ranges) \ + ONE_KNOWN_DW_AT (recursive, DW_AT_recursive) \ + ONE_KNOWN_DW_AT (return_addr, DW_AT_return_addr) \ + ONE_KNOWN_DW_AT (segment, DW_AT_segment) \ + ONE_KNOWN_DW_AT (sf_names, DW_AT_sf_names) \ + ONE_KNOWN_DW_AT (sibling, DW_AT_sibling) \ + ONE_KNOWN_DW_AT (signature, DW_AT_signature) \ + ONE_KNOWN_DW_AT (small, DW_AT_small) \ + ONE_KNOWN_DW_AT (specification, DW_AT_specification) \ + ONE_KNOWN_DW_AT (src_coords, DW_AT_src_coords) \ + ONE_KNOWN_DW_AT (src_info, DW_AT_src_info) \ + ONE_KNOWN_DW_AT (start_scope, DW_AT_start_scope) \ + ONE_KNOWN_DW_AT (static_link, DW_AT_static_link) \ + ONE_KNOWN_DW_AT (stmt_list, DW_AT_stmt_list) \ + ONE_KNOWN_DW_AT (string_length, DW_AT_string_length) \ + ONE_KNOWN_DW_AT (subscr_data, DW_AT_subscr_data) \ + ONE_KNOWN_DW_AT (threads_scaled, DW_AT_threads_scaled) \ + ONE_KNOWN_DW_AT (trampoline, DW_AT_trampoline) \ + ONE_KNOWN_DW_AT (type, DW_AT_type) \ + ONE_KNOWN_DW_AT (upper_bound, DW_AT_upper_bound) \ + ONE_KNOWN_DW_AT (use_UTF8, DW_AT_use_UTF8) \ + ONE_KNOWN_DW_AT (use_location, DW_AT_use_location) \ + ONE_KNOWN_DW_AT (variable_parameter, DW_AT_variable_parameter) \ + ONE_KNOWN_DW_AT (virtuality, DW_AT_virtuality) \ + ONE_KNOWN_DW_AT (visibility, DW_AT_visibility) \ + ONE_KNOWN_DW_AT (vtable_elem_location, DW_AT_vtable_elem_location) \ + /* End of DW_AT_*. */ + +#define ALL_KNOWN_DW_ATE \ + ONE_KNOWN_DW_ATE (UTF, DW_ATE_UTF) \ + ONE_KNOWN_DW_ATE (address, DW_ATE_address) \ + ONE_KNOWN_DW_ATE (boolean, DW_ATE_boolean) \ + ONE_KNOWN_DW_ATE (complex_float, DW_ATE_complex_float) \ + ONE_KNOWN_DW_ATE (decimal_float, DW_ATE_decimal_float) \ + ONE_KNOWN_DW_ATE (edited, DW_ATE_edited) \ + ONE_KNOWN_DW_ATE (float, DW_ATE_float) \ + ONE_KNOWN_DW_ATE (imaginary_float, DW_ATE_imaginary_float) \ + ONE_KNOWN_DW_ATE (numeric_string, DW_ATE_numeric_string) \ + ONE_KNOWN_DW_ATE (packed_decimal, DW_ATE_packed_decimal) \ + ONE_KNOWN_DW_ATE (signed, DW_ATE_signed) \ + ONE_KNOWN_DW_ATE (signed_char, DW_ATE_signed_char) \ + ONE_KNOWN_DW_ATE (signed_fixed, DW_ATE_signed_fixed) \ + ONE_KNOWN_DW_ATE (unsigned, DW_ATE_unsigned) \ + ONE_KNOWN_DW_ATE (unsigned_char, DW_ATE_unsigned_char) \ + ONE_KNOWN_DW_ATE (unsigned_fixed, DW_ATE_unsigned_fixed) \ + ONE_KNOWN_DW_ATE (void, DW_ATE_void) \ + /* End of DW_ATE_*. */ + +#define ALL_KNOWN_DW_CC \ + ONE_KNOWN_DW_CC (nocall, DW_CC_nocall) \ + ONE_KNOWN_DW_CC (normal, DW_CC_normal) \ + ONE_KNOWN_DW_CC (program, DW_CC_program) \ + /* End of DW_CC_*. */ + +#define ALL_KNOWN_DW_CFA \ + ONE_KNOWN_DW_CFA (GNU_args_size, DW_CFA_GNU_args_size) \ + ONE_KNOWN_DW_CFA (GNU_negative_offset_extended, DW_CFA_GNU_negative_offset_extended) \ + ONE_KNOWN_DW_CFA (GNU_window_save, DW_CFA_GNU_window_save) \ + ONE_KNOWN_DW_CFA (MIPS_advance_loc8, DW_CFA_MIPS_advance_loc8) \ + ONE_KNOWN_DW_CFA (advance_loc, DW_CFA_advance_loc) \ + ONE_KNOWN_DW_CFA (advance_loc1, DW_CFA_advance_loc1) \ + ONE_KNOWN_DW_CFA (advance_loc2, DW_CFA_advance_loc2) \ + ONE_KNOWN_DW_CFA (advance_loc4, DW_CFA_advance_loc4) \ + ONE_KNOWN_DW_CFA (def_cfa, DW_CFA_def_cfa) \ + ONE_KNOWN_DW_CFA (def_cfa_expression, DW_CFA_def_cfa_expression) \ + ONE_KNOWN_DW_CFA (def_cfa_offset, DW_CFA_def_cfa_offset) \ + ONE_KNOWN_DW_CFA (def_cfa_offset_sf, DW_CFA_def_cfa_offset_sf) \ + ONE_KNOWN_DW_CFA (def_cfa_register, DW_CFA_def_cfa_register) \ + ONE_KNOWN_DW_CFA (def_cfa_sf, DW_CFA_def_cfa_sf) \ + ONE_KNOWN_DW_CFA (expression, DW_CFA_expression) \ + ONE_KNOWN_DW_CFA (extended, DW_CFA_extended) \ + ONE_KNOWN_DW_CFA (nop, DW_CFA_nop) \ + ONE_KNOWN_DW_CFA (offset, DW_CFA_offset) \ + ONE_KNOWN_DW_CFA (offset_extended, DW_CFA_offset_extended) \ + ONE_KNOWN_DW_CFA (offset_extended_sf, DW_CFA_offset_extended_sf) \ + ONE_KNOWN_DW_CFA (register, DW_CFA_register) \ + ONE_KNOWN_DW_CFA (remember_state, DW_CFA_remember_state) \ + ONE_KNOWN_DW_CFA (restore, DW_CFA_restore) \ + ONE_KNOWN_DW_CFA (restore_extended, DW_CFA_restore_extended) \ + ONE_KNOWN_DW_CFA (restore_state, DW_CFA_restore_state) \ + ONE_KNOWN_DW_CFA (same_value, DW_CFA_same_value) \ + ONE_KNOWN_DW_CFA (set_loc, DW_CFA_set_loc) \ + ONE_KNOWN_DW_CFA (undefined, DW_CFA_undefined) \ + ONE_KNOWN_DW_CFA (val_expression, DW_CFA_val_expression) \ + ONE_KNOWN_DW_CFA (val_offset, DW_CFA_val_offset) \ + ONE_KNOWN_DW_CFA (val_offset_sf, DW_CFA_val_offset_sf) \ + /* End of DW_CFA_*. */ + +#define ALL_KNOWN_DW_CHILDREN \ + ONE_KNOWN_DW_CHILDREN (no, DW_CHILDREN_no) \ + ONE_KNOWN_DW_CHILDREN (yes, DW_CHILDREN_yes) \ + /* End of DW_CHILDREN_*. */ + +#define ALL_KNOWN_DW_CIE_ID \ + ONE_KNOWN_DW_CIE_ID_DESC (32, DW_CIE_ID_32, "In 32-bit format CIE header.") \ + ONE_KNOWN_DW_CIE_ID_DESC (64, DW_CIE_ID_64, "In 64-bit format CIE header.") \ + /* End of DW_CIE_ID_*. */ + +#define ALL_KNOWN_DW_DS \ + ONE_KNOWN_DW_DS (leading_overpunch, DW_DS_leading_overpunch) \ + ONE_KNOWN_DW_DS (leading_separate, DW_DS_leading_separate) \ + ONE_KNOWN_DW_DS (trailing_overpunch, DW_DS_trailing_overpunch) \ + ONE_KNOWN_DW_DS (trailing_separate, DW_DS_trailing_separate) \ + ONE_KNOWN_DW_DS (unsigned, DW_DS_unsigned) \ + /* End of DW_DS_*. */ + +#define ALL_KNOWN_DW_DSC \ + ONE_KNOWN_DW_DSC (label, DW_DSC_label) \ + ONE_KNOWN_DW_DSC (range, DW_DSC_range) \ + /* End of DW_DSC_*. */ + +#define ALL_KNOWN_DW_EH_PE \ + ONE_KNOWN_DW_EH_PE (absptr, DW_EH_PE_absptr) \ + ONE_KNOWN_DW_EH_PE (aligned, DW_EH_PE_aligned) \ + ONE_KNOWN_DW_EH_PE (datarel, DW_EH_PE_datarel) \ + ONE_KNOWN_DW_EH_PE (funcrel, DW_EH_PE_funcrel) \ + ONE_KNOWN_DW_EH_PE (indirect, DW_EH_PE_indirect) \ + ONE_KNOWN_DW_EH_PE (omit, DW_EH_PE_omit) \ + ONE_KNOWN_DW_EH_PE (pcrel, DW_EH_PE_pcrel) \ + ONE_KNOWN_DW_EH_PE (sdata2, DW_EH_PE_sdata2) \ + ONE_KNOWN_DW_EH_PE (sdata4, DW_EH_PE_sdata4) \ + ONE_KNOWN_DW_EH_PE (sdata8, DW_EH_PE_sdata8) \ + ONE_KNOWN_DW_EH_PE (signed, DW_EH_PE_signed) \ + ONE_KNOWN_DW_EH_PE (sleb128, DW_EH_PE_sleb128) \ + ONE_KNOWN_DW_EH_PE (textrel, DW_EH_PE_textrel) \ + ONE_KNOWN_DW_EH_PE (udata2, DW_EH_PE_udata2) \ + ONE_KNOWN_DW_EH_PE (udata4, DW_EH_PE_udata4) \ + ONE_KNOWN_DW_EH_PE (udata8, DW_EH_PE_udata8) \ + ONE_KNOWN_DW_EH_PE (uleb128, DW_EH_PE_uleb128) \ + /* End of DW_EH_PE_*. */ + +#define ALL_KNOWN_DW_END \ + ONE_KNOWN_DW_END (big, DW_END_big) \ + ONE_KNOWN_DW_END (default, DW_END_default) \ + ONE_KNOWN_DW_END (little, DW_END_little) \ + /* End of DW_END_*. */ + +#define ALL_KNOWN_DW_FORM \ + ONE_KNOWN_DW_FORM_DESC (GNU_ref_alt, DW_FORM_GNU_ref_alt, "offset in alternate .debuginfo.") \ + ONE_KNOWN_DW_FORM_DESC (GNU_strp_alt, DW_FORM_GNU_strp_alt, "offset in alternate .debug_str.") \ + ONE_KNOWN_DW_FORM (addr, DW_FORM_addr) \ + ONE_KNOWN_DW_FORM (block, DW_FORM_block) \ + ONE_KNOWN_DW_FORM (block1, DW_FORM_block1) \ + ONE_KNOWN_DW_FORM (block2, DW_FORM_block2) \ + ONE_KNOWN_DW_FORM (block4, DW_FORM_block4) \ + ONE_KNOWN_DW_FORM (data1, DW_FORM_data1) \ + ONE_KNOWN_DW_FORM (data2, DW_FORM_data2) \ + ONE_KNOWN_DW_FORM (data4, DW_FORM_data4) \ + ONE_KNOWN_DW_FORM (data8, DW_FORM_data8) \ + ONE_KNOWN_DW_FORM (exprloc, DW_FORM_exprloc) \ + ONE_KNOWN_DW_FORM (flag, DW_FORM_flag) \ + ONE_KNOWN_DW_FORM (flag_present, DW_FORM_flag_present) \ + ONE_KNOWN_DW_FORM (indirect, DW_FORM_indirect) \ + ONE_KNOWN_DW_FORM (ref1, DW_FORM_ref1) \ + ONE_KNOWN_DW_FORM (ref2, DW_FORM_ref2) \ + ONE_KNOWN_DW_FORM (ref4, DW_FORM_ref4) \ + ONE_KNOWN_DW_FORM (ref8, DW_FORM_ref8) \ + ONE_KNOWN_DW_FORM (ref_addr, DW_FORM_ref_addr) \ + ONE_KNOWN_DW_FORM (ref_sig8, DW_FORM_ref_sig8) \ + ONE_KNOWN_DW_FORM (ref_udata, DW_FORM_ref_udata) \ + ONE_KNOWN_DW_FORM (sdata, DW_FORM_sdata) \ + ONE_KNOWN_DW_FORM (sec_offset, DW_FORM_sec_offset) \ + ONE_KNOWN_DW_FORM (string, DW_FORM_string) \ + ONE_KNOWN_DW_FORM (strp, DW_FORM_strp) \ + ONE_KNOWN_DW_FORM (udata, DW_FORM_udata) \ + /* End of DW_FORM_*. */ + +#define ALL_KNOWN_DW_ID \ + ONE_KNOWN_DW_ID (case_insensitive, DW_ID_case_insensitive) \ + ONE_KNOWN_DW_ID (case_sensitive, DW_ID_case_sensitive) \ + ONE_KNOWN_DW_ID (down_case, DW_ID_down_case) \ + ONE_KNOWN_DW_ID (up_case, DW_ID_up_case) \ + /* End of DW_ID_*. */ + +#define ALL_KNOWN_DW_INL \ + ONE_KNOWN_DW_INL (declared_inlined, DW_INL_declared_inlined) \ + ONE_KNOWN_DW_INL (declared_not_inlined, DW_INL_declared_not_inlined) \ + ONE_KNOWN_DW_INL (inlined, DW_INL_inlined) \ + ONE_KNOWN_DW_INL (not_inlined, DW_INL_not_inlined) \ + /* End of DW_INL_*. */ + +#define ALL_KNOWN_DW_LANG \ + ONE_KNOWN_DW_LANG_DESC (Ada83, DW_LANG_Ada83, "ISO Ada:1983") \ + ONE_KNOWN_DW_LANG_DESC (Ada95, DW_LANG_Ada95, "ISO Ada:1995") \ + ONE_KNOWN_DW_LANG_DESC (C, DW_LANG_C, "C") \ + ONE_KNOWN_DW_LANG_DESC (C11, DW_LANG_C11, "ISO C:2011") \ + ONE_KNOWN_DW_LANG_DESC (C89, DW_LANG_C89, "ISO C:1989") \ + ONE_KNOWN_DW_LANG_DESC (C99, DW_LANG_C99, "ISO C:1999") \ + ONE_KNOWN_DW_LANG_DESC (C_plus_plus, DW_LANG_C_plus_plus, "ISO C++:1998") \ + ONE_KNOWN_DW_LANG_DESC (C_plus_plus_11, DW_LANG_C_plus_plus_11, "ISO C++:2011") \ + ONE_KNOWN_DW_LANG_DESC (C_plus_plus_14, DW_LANG_C_plus_plus_14, "ISO C++:2014") \ + ONE_KNOWN_DW_LANG_DESC (Cobol74, DW_LANG_Cobol74, "ISO Cobol:1974") \ + ONE_KNOWN_DW_LANG_DESC (Cobol85, DW_LANG_Cobol85, "ISO Cobol:1985") \ + ONE_KNOWN_DW_LANG_DESC (D, DW_LANG_D, "D") \ + ONE_KNOWN_DW_LANG_DESC (Fortran77, DW_LANG_Fortran77, "ISO FORTRAN 77") \ + ONE_KNOWN_DW_LANG_DESC (Fortran90, DW_LANG_Fortran90, "ISO Fortran 90") \ + ONE_KNOWN_DW_LANG_DESC (Fortran95, DW_LANG_Fortran95, "ISO Fortran 95") \ + ONE_KNOWN_DW_LANG_DESC (Go, DW_LANG_Go, "Go") \ + ONE_KNOWN_DW_LANG_DESC (Java, DW_LANG_Java, "Java") \ + ONE_KNOWN_DW_LANG_DESC (Mips_Assembler, DW_LANG_Mips_Assembler, "Assembler") \ + ONE_KNOWN_DW_LANG_DESC (Modula2, DW_LANG_Modula2, "ISO Modula-2:1996") \ + ONE_KNOWN_DW_LANG_DESC (ObjC, DW_LANG_ObjC, "Objective-C") \ + ONE_KNOWN_DW_LANG_DESC (ObjC_plus_plus, DW_LANG_ObjC_plus_plus, "Objective-C++") \ + ONE_KNOWN_DW_LANG_DESC (PL1, DW_LANG_PL1, "ISO PL/1:1976") \ + ONE_KNOWN_DW_LANG_DESC (Pascal83, DW_LANG_Pascal83, "ISO Pascal:1983") \ + ONE_KNOWN_DW_LANG_DESC (Python, DW_LANG_Python, "Python") \ + ONE_KNOWN_DW_LANG_DESC (UPC, DW_LANG_UPC, "Unified Parallel C") \ + /* End of DW_LANG_*. */ + +#define ALL_KNOWN_DW_LNE \ + ONE_KNOWN_DW_LNE (define_file, DW_LNE_define_file) \ + ONE_KNOWN_DW_LNE (end_sequence, DW_LNE_end_sequence) \ + ONE_KNOWN_DW_LNE (set_address, DW_LNE_set_address) \ + ONE_KNOWN_DW_LNE (set_discriminator, DW_LNE_set_discriminator) \ + /* End of DW_LNE_*. */ + +#define ALL_KNOWN_DW_LNS \ + ONE_KNOWN_DW_LNS (advance_line, DW_LNS_advance_line) \ + ONE_KNOWN_DW_LNS (advance_pc, DW_LNS_advance_pc) \ + ONE_KNOWN_DW_LNS (const_add_pc, DW_LNS_const_add_pc) \ + ONE_KNOWN_DW_LNS (copy, DW_LNS_copy) \ + ONE_KNOWN_DW_LNS (fixed_advance_pc, DW_LNS_fixed_advance_pc) \ + ONE_KNOWN_DW_LNS (negate_stmt, DW_LNS_negate_stmt) \ + ONE_KNOWN_DW_LNS (set_basic_block, DW_LNS_set_basic_block) \ + ONE_KNOWN_DW_LNS (set_column, DW_LNS_set_column) \ + ONE_KNOWN_DW_LNS (set_epilogue_begin, DW_LNS_set_epilogue_begin) \ + ONE_KNOWN_DW_LNS (set_file, DW_LNS_set_file) \ + ONE_KNOWN_DW_LNS (set_isa, DW_LNS_set_isa) \ + ONE_KNOWN_DW_LNS (set_prologue_end, DW_LNS_set_prologue_end) \ + /* End of DW_LNS_*. */ + +#define ALL_KNOWN_DW_MACINFO \ + ONE_KNOWN_DW_MACINFO (define, DW_MACINFO_define) \ + ONE_KNOWN_DW_MACINFO (end_file, DW_MACINFO_end_file) \ + ONE_KNOWN_DW_MACINFO (start_file, DW_MACINFO_start_file) \ + ONE_KNOWN_DW_MACINFO (undef, DW_MACINFO_undef) \ + ONE_KNOWN_DW_MACINFO (vendor_ext, DW_MACINFO_vendor_ext) \ + /* End of DW_MACINFO_*. */ + +#define ALL_KNOWN_DW_MACRO_GNU \ + ONE_KNOWN_DW_MACRO_GNU (define, DW_MACRO_GNU_define) \ + ONE_KNOWN_DW_MACRO_GNU (define_indirect, DW_MACRO_GNU_define_indirect) \ + ONE_KNOWN_DW_MACRO_GNU (end_file, DW_MACRO_GNU_end_file) \ + ONE_KNOWN_DW_MACRO_GNU (start_file, DW_MACRO_GNU_start_file) \ + ONE_KNOWN_DW_MACRO_GNU (transparent_include, DW_MACRO_GNU_transparent_include) \ + ONE_KNOWN_DW_MACRO_GNU (undef, DW_MACRO_GNU_undef) \ + ONE_KNOWN_DW_MACRO_GNU (undef_indirect, DW_MACRO_GNU_undef_indirect) \ + /* End of DW_MACRO_GNU_*. */ + +#define ALL_KNOWN_DW_OP \ + ONE_KNOWN_DW_OP (GNU_const_type, DW_OP_GNU_const_type) \ + ONE_KNOWN_DW_OP (GNU_convert, DW_OP_GNU_convert) \ + ONE_KNOWN_DW_OP (GNU_deref_type, DW_OP_GNU_deref_type) \ + ONE_KNOWN_DW_OP (GNU_encoded_addr, DW_OP_GNU_encoded_addr) \ + ONE_KNOWN_DW_OP (GNU_entry_value, DW_OP_GNU_entry_value) \ + ONE_KNOWN_DW_OP (GNU_implicit_pointer, DW_OP_GNU_implicit_pointer) \ + ONE_KNOWN_DW_OP (GNU_parameter_ref, DW_OP_GNU_parameter_ref) \ + ONE_KNOWN_DW_OP (GNU_push_tls_address, DW_OP_GNU_push_tls_address) \ + ONE_KNOWN_DW_OP (GNU_regval_type, DW_OP_GNU_regval_type) \ + ONE_KNOWN_DW_OP (GNU_reinterpret, DW_OP_GNU_reinterpret) \ + ONE_KNOWN_DW_OP (GNU_uninit, DW_OP_GNU_uninit) \ + ONE_KNOWN_DW_OP (abs, DW_OP_abs) \ + ONE_KNOWN_DW_OP_DESC (addr, DW_OP_addr, "Constant address.") \ + ONE_KNOWN_DW_OP (and, DW_OP_and) \ + ONE_KNOWN_DW_OP_DESC (bit_piece, DW_OP_bit_piece, "ULEB128 size and ULEB128 offset in bits.") \ + ONE_KNOWN_DW_OP_DESC (bra, DW_OP_bra, "Signed 2-byte constant.") \ + ONE_KNOWN_DW_OP_DESC (breg0, DW_OP_breg0, "Base register 0.") \ + ONE_KNOWN_DW_OP_DESC (breg1, DW_OP_breg1, "Base register 1.") \ + ONE_KNOWN_DW_OP_DESC (breg10, DW_OP_breg10, "Base register 10.") \ + ONE_KNOWN_DW_OP_DESC (breg11, DW_OP_breg11, "Base register 11.") \ + ONE_KNOWN_DW_OP_DESC (breg12, DW_OP_breg12, "Base register 12.") \ + ONE_KNOWN_DW_OP_DESC (breg13, DW_OP_breg13, "Base register 13.") \ + ONE_KNOWN_DW_OP_DESC (breg14, DW_OP_breg14, "Base register 14.") \ + ONE_KNOWN_DW_OP_DESC (breg15, DW_OP_breg15, "Base register 15.") \ + ONE_KNOWN_DW_OP_DESC (breg16, DW_OP_breg16, "Base register 16.") \ + ONE_KNOWN_DW_OP_DESC (breg17, DW_OP_breg17, "Base register 17.") \ + ONE_KNOWN_DW_OP_DESC (breg18, DW_OP_breg18, "Base register 18.") \ + ONE_KNOWN_DW_OP_DESC (breg19, DW_OP_breg19, "Base register 19.") \ + ONE_KNOWN_DW_OP_DESC (breg2, DW_OP_breg2, "Base register 2.") \ + ONE_KNOWN_DW_OP_DESC (breg20, DW_OP_breg20, "Base register 20.") \ + ONE_KNOWN_DW_OP_DESC (breg21, DW_OP_breg21, "Base register 21.") \ + ONE_KNOWN_DW_OP_DESC (breg22, DW_OP_breg22, "Base register 22.") \ + ONE_KNOWN_DW_OP_DESC (breg23, DW_OP_breg23, "Base register 23.") \ + ONE_KNOWN_DW_OP_DESC (breg24, DW_OP_breg24, "Base register 24.") \ + ONE_KNOWN_DW_OP_DESC (breg25, DW_OP_breg25, "Base register 25.") \ + ONE_KNOWN_DW_OP_DESC (breg26, DW_OP_breg26, "Base register 26.") \ + ONE_KNOWN_DW_OP_DESC (breg27, DW_OP_breg27, "Base register 27.") \ + ONE_KNOWN_DW_OP_DESC (breg28, DW_OP_breg28, "Base register 28.") \ + ONE_KNOWN_DW_OP_DESC (breg29, DW_OP_breg29, "Base register 29.") \ + ONE_KNOWN_DW_OP_DESC (breg3, DW_OP_breg3, "Base register 3.") \ + ONE_KNOWN_DW_OP_DESC (breg30, DW_OP_breg30, "Base register 30.") \ + ONE_KNOWN_DW_OP_DESC (breg31, DW_OP_breg31, "Base register 31.") \ + ONE_KNOWN_DW_OP_DESC (breg4, DW_OP_breg4, "Base register 4.") \ + ONE_KNOWN_DW_OP_DESC (breg5, DW_OP_breg5, "Base register 5.") \ + ONE_KNOWN_DW_OP_DESC (breg6, DW_OP_breg6, "Base register 6.") \ + ONE_KNOWN_DW_OP_DESC (breg7, DW_OP_breg7, "Base register 7.") \ + ONE_KNOWN_DW_OP_DESC (breg8, DW_OP_breg8, "Base register 8.") \ + ONE_KNOWN_DW_OP_DESC (breg9, DW_OP_breg9, "Base register 9.") \ + ONE_KNOWN_DW_OP_DESC (bregx, DW_OP_bregx, "ULEB128 register followed by SLEB128 off.") \ + ONE_KNOWN_DW_OP (call2, DW_OP_call2) \ + ONE_KNOWN_DW_OP (call4, DW_OP_call4) \ + ONE_KNOWN_DW_OP (call_frame_cfa, DW_OP_call_frame_cfa) \ + ONE_KNOWN_DW_OP (call_ref, DW_OP_call_ref) \ + ONE_KNOWN_DW_OP_DESC (const1s, DW_OP_const1s, "Signed 1-byte constant.") \ + ONE_KNOWN_DW_OP_DESC (const1u, DW_OP_const1u, "Unsigned 1-byte constant.") \ + ONE_KNOWN_DW_OP_DESC (const2s, DW_OP_const2s, "Signed 2-byte constant.") \ + ONE_KNOWN_DW_OP_DESC (const2u, DW_OP_const2u, "Unsigned 2-byte constant.") \ + ONE_KNOWN_DW_OP_DESC (const4s, DW_OP_const4s, "Signed 4-byte constant.") \ + ONE_KNOWN_DW_OP_DESC (const4u, DW_OP_const4u, "Unsigned 4-byte constant.") \ + ONE_KNOWN_DW_OP_DESC (const8s, DW_OP_const8s, "Signed 8-byte constant.") \ + ONE_KNOWN_DW_OP_DESC (const8u, DW_OP_const8u, "Unsigned 8-byte constant.") \ + ONE_KNOWN_DW_OP_DESC (consts, DW_OP_consts, "Signed LEB128 constant.") \ + ONE_KNOWN_DW_OP_DESC (constu, DW_OP_constu, "Unsigned LEB128 constant.") \ + ONE_KNOWN_DW_OP (deref, DW_OP_deref) \ + ONE_KNOWN_DW_OP_DESC (deref_size, DW_OP_deref_size, "1-byte size of data retrieved.") \ + ONE_KNOWN_DW_OP (div, DW_OP_div) \ + ONE_KNOWN_DW_OP (drop, DW_OP_drop) \ + ONE_KNOWN_DW_OP (dup, DW_OP_dup) \ + ONE_KNOWN_DW_OP (eq, DW_OP_eq) \ + ONE_KNOWN_DW_OP_DESC (fbreg, DW_OP_fbreg, "Signed LEB128 offset.") \ + ONE_KNOWN_DW_OP (form_tls_address, DW_OP_form_tls_address) \ + ONE_KNOWN_DW_OP (ge, DW_OP_ge) \ + ONE_KNOWN_DW_OP (gt, DW_OP_gt) \ + ONE_KNOWN_DW_OP_DESC (implicit_value, DW_OP_implicit_value, "DW_FORM_block follows opcode.") \ + ONE_KNOWN_DW_OP (le, DW_OP_le) \ + ONE_KNOWN_DW_OP_DESC (lit0, DW_OP_lit0, "Literal 0.") \ + ONE_KNOWN_DW_OP_DESC (lit1, DW_OP_lit1, "Literal 1.") \ + ONE_KNOWN_DW_OP_DESC (lit10, DW_OP_lit10, "Literal 10.") \ + ONE_KNOWN_DW_OP_DESC (lit11, DW_OP_lit11, "Literal 11.") \ + ONE_KNOWN_DW_OP_DESC (lit12, DW_OP_lit12, "Literal 12.") \ + ONE_KNOWN_DW_OP_DESC (lit13, DW_OP_lit13, "Literal 13.") \ + ONE_KNOWN_DW_OP_DESC (lit14, DW_OP_lit14, "Literal 14.") \ + ONE_KNOWN_DW_OP_DESC (lit15, DW_OP_lit15, "Literal 15.") \ + ONE_KNOWN_DW_OP_DESC (lit16, DW_OP_lit16, "Literal 16.") \ + ONE_KNOWN_DW_OP_DESC (lit17, DW_OP_lit17, "Literal 17.") \ + ONE_KNOWN_DW_OP_DESC (lit18, DW_OP_lit18, "Literal 18.") \ + ONE_KNOWN_DW_OP_DESC (lit19, DW_OP_lit19, "Literal 19.") \ + ONE_KNOWN_DW_OP_DESC (lit2, DW_OP_lit2, "Literal 2.") \ + ONE_KNOWN_DW_OP_DESC (lit20, DW_OP_lit20, "Literal 20.") \ + ONE_KNOWN_DW_OP_DESC (lit21, DW_OP_lit21, "Literal 21.") \ + ONE_KNOWN_DW_OP_DESC (lit22, DW_OP_lit22, "Literal 22.") \ + ONE_KNOWN_DW_OP_DESC (lit23, DW_OP_lit23, "Literal 23.") \ + ONE_KNOWN_DW_OP_DESC (lit24, DW_OP_lit24, "Literal 24.") \ + ONE_KNOWN_DW_OP_DESC (lit25, DW_OP_lit25, "Literal 25.") \ + ONE_KNOWN_DW_OP_DESC (lit26, DW_OP_lit26, "Literal 26.") \ + ONE_KNOWN_DW_OP_DESC (lit27, DW_OP_lit27, "Literal 27.") \ + ONE_KNOWN_DW_OP_DESC (lit28, DW_OP_lit28, "Literal 28.") \ + ONE_KNOWN_DW_OP_DESC (lit29, DW_OP_lit29, "Literal 29.") \ + ONE_KNOWN_DW_OP_DESC (lit3, DW_OP_lit3, "Literal 3.") \ + ONE_KNOWN_DW_OP_DESC (lit30, DW_OP_lit30, "Literal 30.") \ + ONE_KNOWN_DW_OP_DESC (lit31, DW_OP_lit31, "Literal 31.") \ + ONE_KNOWN_DW_OP_DESC (lit4, DW_OP_lit4, "Literal 4.") \ + ONE_KNOWN_DW_OP_DESC (lit5, DW_OP_lit5, "Literal 5.") \ + ONE_KNOWN_DW_OP_DESC (lit6, DW_OP_lit6, "Literal 6.") \ + ONE_KNOWN_DW_OP_DESC (lit7, DW_OP_lit7, "Literal 7.") \ + ONE_KNOWN_DW_OP_DESC (lit8, DW_OP_lit8, "Literal 8.") \ + ONE_KNOWN_DW_OP_DESC (lit9, DW_OP_lit9, "Literal 9.") \ + ONE_KNOWN_DW_OP (lt, DW_OP_lt) \ + ONE_KNOWN_DW_OP (minus, DW_OP_minus) \ + ONE_KNOWN_DW_OP (mod, DW_OP_mod) \ + ONE_KNOWN_DW_OP (mul, DW_OP_mul) \ + ONE_KNOWN_DW_OP (ne, DW_OP_ne) \ + ONE_KNOWN_DW_OP (neg, DW_OP_neg) \ + ONE_KNOWN_DW_OP (nop, DW_OP_nop) \ + ONE_KNOWN_DW_OP (not, DW_OP_not) \ + ONE_KNOWN_DW_OP (or, DW_OP_or) \ + ONE_KNOWN_DW_OP (over, DW_OP_over) \ + ONE_KNOWN_DW_OP_DESC (pick, DW_OP_pick, "1-byte stack index.") \ + ONE_KNOWN_DW_OP_DESC (piece, DW_OP_piece, "ULEB128 size of piece addressed.") \ + ONE_KNOWN_DW_OP (plus, DW_OP_plus) \ + ONE_KNOWN_DW_OP_DESC (plus_uconst, DW_OP_plus_uconst, "Unsigned LEB128 addend.") \ + ONE_KNOWN_DW_OP (push_object_address, DW_OP_push_object_address) \ + ONE_KNOWN_DW_OP_DESC (reg0, DW_OP_reg0, "Register 0.") \ + ONE_KNOWN_DW_OP_DESC (reg1, DW_OP_reg1, "Register 1.") \ + ONE_KNOWN_DW_OP_DESC (reg10, DW_OP_reg10, "Register 10.") \ + ONE_KNOWN_DW_OP_DESC (reg11, DW_OP_reg11, "Register 11.") \ + ONE_KNOWN_DW_OP_DESC (reg12, DW_OP_reg12, "Register 12.") \ + ONE_KNOWN_DW_OP_DESC (reg13, DW_OP_reg13, "Register 13.") \ + ONE_KNOWN_DW_OP_DESC (reg14, DW_OP_reg14, "Register 14.") \ + ONE_KNOWN_DW_OP_DESC (reg15, DW_OP_reg15, "Register 15.") \ + ONE_KNOWN_DW_OP_DESC (reg16, DW_OP_reg16, "Register 16.") \ + ONE_KNOWN_DW_OP_DESC (reg17, DW_OP_reg17, "Register 17.") \ + ONE_KNOWN_DW_OP_DESC (reg18, DW_OP_reg18, "Register 18.") \ + ONE_KNOWN_DW_OP_DESC (reg19, DW_OP_reg19, "Register 19.") \ + ONE_KNOWN_DW_OP_DESC (reg2, DW_OP_reg2, "Register 2.") \ + ONE_KNOWN_DW_OP_DESC (reg20, DW_OP_reg20, "Register 20.") \ + ONE_KNOWN_DW_OP_DESC (reg21, DW_OP_reg21, "Register 21.") \ + ONE_KNOWN_DW_OP_DESC (reg22, DW_OP_reg22, "Register 22.") \ + ONE_KNOWN_DW_OP_DESC (reg23, DW_OP_reg23, "Register 24.") \ + ONE_KNOWN_DW_OP_DESC (reg24, DW_OP_reg24, "Register 24.") \ + ONE_KNOWN_DW_OP_DESC (reg25, DW_OP_reg25, "Register 25.") \ + ONE_KNOWN_DW_OP_DESC (reg26, DW_OP_reg26, "Register 26.") \ + ONE_KNOWN_DW_OP_DESC (reg27, DW_OP_reg27, "Register 27.") \ + ONE_KNOWN_DW_OP_DESC (reg28, DW_OP_reg28, "Register 28.") \ + ONE_KNOWN_DW_OP_DESC (reg29, DW_OP_reg29, "Register 29.") \ + ONE_KNOWN_DW_OP_DESC (reg3, DW_OP_reg3, "Register 3.") \ + ONE_KNOWN_DW_OP_DESC (reg30, DW_OP_reg30, "Register 30.") \ + ONE_KNOWN_DW_OP_DESC (reg31, DW_OP_reg31, "Register 31.") \ + ONE_KNOWN_DW_OP_DESC (reg4, DW_OP_reg4, "Register 4.") \ + ONE_KNOWN_DW_OP_DESC (reg5, DW_OP_reg5, "Register 5.") \ + ONE_KNOWN_DW_OP_DESC (reg6, DW_OP_reg6, "Register 6.") \ + ONE_KNOWN_DW_OP_DESC (reg7, DW_OP_reg7, "Register 7.") \ + ONE_KNOWN_DW_OP_DESC (reg8, DW_OP_reg8, "Register 8.") \ + ONE_KNOWN_DW_OP_DESC (reg9, DW_OP_reg9, "Register 9.") \ + ONE_KNOWN_DW_OP_DESC (regx, DW_OP_regx, "Unsigned LEB128 register.") \ + ONE_KNOWN_DW_OP (rot, DW_OP_rot) \ + ONE_KNOWN_DW_OP (shl, DW_OP_shl) \ + ONE_KNOWN_DW_OP (shr, DW_OP_shr) \ + ONE_KNOWN_DW_OP (shra, DW_OP_shra) \ + ONE_KNOWN_DW_OP_DESC (skip, DW_OP_skip, "Signed 2-byte constant.") \ + ONE_KNOWN_DW_OP_DESC (stack_value, DW_OP_stack_value, "No operands, special like DW_OP_piece.") \ + ONE_KNOWN_DW_OP (swap, DW_OP_swap) \ + ONE_KNOWN_DW_OP (xderef, DW_OP_xderef) \ + ONE_KNOWN_DW_OP_DESC (xderef_size, DW_OP_xderef_size, "1-byte size of data retrieved.") \ + ONE_KNOWN_DW_OP (xor, DW_OP_xor) \ + /* End of DW_OP_*. */ + +#define ALL_KNOWN_DW_ORD \ + ONE_KNOWN_DW_ORD (col_major, DW_ORD_col_major) \ + ONE_KNOWN_DW_ORD (row_major, DW_ORD_row_major) \ + /* End of DW_ORD_*. */ + +#define ALL_KNOWN_DW_TAG \ + ONE_KNOWN_DW_TAG (GNU_BINCL, DW_TAG_GNU_BINCL) \ + ONE_KNOWN_DW_TAG (GNU_EINCL, DW_TAG_GNU_EINCL) \ + ONE_KNOWN_DW_TAG (GNU_call_site, DW_TAG_GNU_call_site) \ + ONE_KNOWN_DW_TAG (GNU_call_site_parameter, DW_TAG_GNU_call_site_parameter) \ + ONE_KNOWN_DW_TAG (GNU_formal_parameter_pack, DW_TAG_GNU_formal_parameter_pack) \ + ONE_KNOWN_DW_TAG (GNU_template_parameter_pack, DW_TAG_GNU_template_parameter_pack) \ + ONE_KNOWN_DW_TAG (GNU_template_template_param, DW_TAG_GNU_template_template_param) \ + ONE_KNOWN_DW_TAG (MIPS_loop, DW_TAG_MIPS_loop) \ + ONE_KNOWN_DW_TAG (access_declaration, DW_TAG_access_declaration) \ + ONE_KNOWN_DW_TAG (array_type, DW_TAG_array_type) \ + ONE_KNOWN_DW_TAG (base_type, DW_TAG_base_type) \ + ONE_KNOWN_DW_TAG (catch_block, DW_TAG_catch_block) \ + ONE_KNOWN_DW_TAG (class_template, DW_TAG_class_template) \ + ONE_KNOWN_DW_TAG (class_type, DW_TAG_class_type) \ + ONE_KNOWN_DW_TAG (common_block, DW_TAG_common_block) \ + ONE_KNOWN_DW_TAG (common_inclusion, DW_TAG_common_inclusion) \ + ONE_KNOWN_DW_TAG (compile_unit, DW_TAG_compile_unit) \ + ONE_KNOWN_DW_TAG (condition, DW_TAG_condition) \ + ONE_KNOWN_DW_TAG (const_type, DW_TAG_const_type) \ + ONE_KNOWN_DW_TAG (constant, DW_TAG_constant) \ + ONE_KNOWN_DW_TAG (dwarf_procedure, DW_TAG_dwarf_procedure) \ + ONE_KNOWN_DW_TAG (entry_point, DW_TAG_entry_point) \ + ONE_KNOWN_DW_TAG (enumeration_type, DW_TAG_enumeration_type) \ + ONE_KNOWN_DW_TAG (enumerator, DW_TAG_enumerator) \ + ONE_KNOWN_DW_TAG (file_type, DW_TAG_file_type) \ + ONE_KNOWN_DW_TAG (formal_parameter, DW_TAG_formal_parameter) \ + ONE_KNOWN_DW_TAG (format_label, DW_TAG_format_label) \ + ONE_KNOWN_DW_TAG (friend, DW_TAG_friend) \ + ONE_KNOWN_DW_TAG (function_template, DW_TAG_function_template) \ + ONE_KNOWN_DW_TAG (imported_declaration, DW_TAG_imported_declaration) \ + ONE_KNOWN_DW_TAG (imported_module, DW_TAG_imported_module) \ + ONE_KNOWN_DW_TAG (imported_unit, DW_TAG_imported_unit) \ + ONE_KNOWN_DW_TAG (inheritance, DW_TAG_inheritance) \ + ONE_KNOWN_DW_TAG (inlined_subroutine, DW_TAG_inlined_subroutine) \ + ONE_KNOWN_DW_TAG (interface_type, DW_TAG_interface_type) \ + ONE_KNOWN_DW_TAG (label, DW_TAG_label) \ + ONE_KNOWN_DW_TAG (lexical_block, DW_TAG_lexical_block) \ + ONE_KNOWN_DW_TAG (member, DW_TAG_member) \ + ONE_KNOWN_DW_TAG (module, DW_TAG_module) \ + ONE_KNOWN_DW_TAG (namelist, DW_TAG_namelist) \ + ONE_KNOWN_DW_TAG (namelist_item, DW_TAG_namelist_item) \ + ONE_KNOWN_DW_TAG (namespace, DW_TAG_namespace) \ + ONE_KNOWN_DW_TAG (packed_type, DW_TAG_packed_type) \ + ONE_KNOWN_DW_TAG (partial_unit, DW_TAG_partial_unit) \ + ONE_KNOWN_DW_TAG (pointer_type, DW_TAG_pointer_type) \ + ONE_KNOWN_DW_TAG (ptr_to_member_type, DW_TAG_ptr_to_member_type) \ + ONE_KNOWN_DW_TAG (reference_type, DW_TAG_reference_type) \ + ONE_KNOWN_DW_TAG (restrict_type, DW_TAG_restrict_type) \ + ONE_KNOWN_DW_TAG (rvalue_reference_type, DW_TAG_rvalue_reference_type) \ + ONE_KNOWN_DW_TAG (set_type, DW_TAG_set_type) \ + ONE_KNOWN_DW_TAG (shared_type, DW_TAG_shared_type) \ + ONE_KNOWN_DW_TAG (string_type, DW_TAG_string_type) \ + ONE_KNOWN_DW_TAG (structure_type, DW_TAG_structure_type) \ + ONE_KNOWN_DW_TAG (subprogram, DW_TAG_subprogram) \ + ONE_KNOWN_DW_TAG (subrange_type, DW_TAG_subrange_type) \ + ONE_KNOWN_DW_TAG (subroutine_type, DW_TAG_subroutine_type) \ + ONE_KNOWN_DW_TAG (template_alias, DW_TAG_template_alias) \ + ONE_KNOWN_DW_TAG (template_type_parameter, DW_TAG_template_type_parameter) \ + ONE_KNOWN_DW_TAG (template_value_parameter, DW_TAG_template_value_parameter) \ + ONE_KNOWN_DW_TAG (thrown_type, DW_TAG_thrown_type) \ + ONE_KNOWN_DW_TAG (try_block, DW_TAG_try_block) \ + ONE_KNOWN_DW_TAG (type_unit, DW_TAG_type_unit) \ + ONE_KNOWN_DW_TAG (typedef, DW_TAG_typedef) \ + ONE_KNOWN_DW_TAG (union_type, DW_TAG_union_type) \ + ONE_KNOWN_DW_TAG (unspecified_parameters, DW_TAG_unspecified_parameters) \ + ONE_KNOWN_DW_TAG (unspecified_type, DW_TAG_unspecified_type) \ + ONE_KNOWN_DW_TAG (variable, DW_TAG_variable) \ + ONE_KNOWN_DW_TAG (variant, DW_TAG_variant) \ + ONE_KNOWN_DW_TAG (variant_part, DW_TAG_variant_part) \ + ONE_KNOWN_DW_TAG (volatile_type, DW_TAG_volatile_type) \ + ONE_KNOWN_DW_TAG (with_stmt, DW_TAG_with_stmt) \ + /* End of DW_TAG_*. */ + +#define ALL_KNOWN_DW_VIRTUALITY \ + ONE_KNOWN_DW_VIRTUALITY (none, DW_VIRTUALITY_none) \ + ONE_KNOWN_DW_VIRTUALITY (pure_virtual, DW_VIRTUALITY_pure_virtual) \ + ONE_KNOWN_DW_VIRTUALITY (virtual, DW_VIRTUALITY_virtual) \ + /* End of DW_VIRTUALITY_*. */ + +#define ALL_KNOWN_DW_VIS \ + ONE_KNOWN_DW_VIS (exported, DW_VIS_exported) \ + ONE_KNOWN_DW_VIS (local, DW_VIS_local) \ + ONE_KNOWN_DW_VIS (qualified, DW_VIS_qualified) \ + /* End of DW_VIS_*. */ diff --git a/3rdparty/elfutils/libdw/libdw.h b/3rdparty/elfutils/libdw/libdw.h new file mode 100644 index 0000000..b2b2282 --- /dev/null +++ b/3rdparty/elfutils/libdw/libdw.h @@ -0,0 +1,1026 @@ +/* Interfaces for libdw. + Copyright (C) 2002-2010, 2013, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifndef _LIBDW_H +#define _LIBDW_H 1 + +#include <gelf.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> + + +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) +# define __nonnull_attribute__(...) __attribute__ ((__nonnull__ (__VA_ARGS__))) +# define __deprecated_attribute__ __attribute__ ((__deprecated__)) +#else +# define __nonnull_attribute__(args...) +# define __deprecated_attribute__ +#endif + + +#ifdef __GNUC_STDC_INLINE__ +# define __libdw_extern_inline extern __inline __attribute__ ((__gnu_inline__)) +#else +# define __libdw_extern_inline extern __inline +#endif + + +/* Mode for the session. */ +typedef enum + { + DWARF_C_READ, /* Read .. */ + DWARF_C_RDWR, /* Read and write .. */ + DWARF_C_WRITE, /* Write .. */ + } +Dwarf_Cmd; + + +/* Callback results. */ +enum +{ + DWARF_CB_OK = 0, + DWARF_CB_ABORT +}; + + +/* Error values. */ +enum + { + DW_TAG_invalid = 0 +#define DW_TAG_invalid DW_TAG_invalid + }; + + +/* Type for offset in DWARF file. */ +typedef GElf_Off Dwarf_Off; + +/* Type for address in DWARF file. */ +typedef GElf_Addr Dwarf_Addr; + +/* Integer types. Big enough to hold any numeric value. */ +typedef GElf_Xword Dwarf_Word; +typedef GElf_Sxword Dwarf_Sword; +/* For the times we know we do not need that much. */ +typedef GElf_Half Dwarf_Half; + + +/* DWARF abbreviation record. */ +typedef struct Dwarf_Abbrev Dwarf_Abbrev; + +/* Returned to show the last DIE has be returned. */ +#define DWARF_END_ABBREV ((Dwarf_Abbrev *) -1l) + +/* Source code line information for CU. */ +typedef struct Dwarf_Lines_s Dwarf_Lines; + +/* One source code line information. */ +typedef struct Dwarf_Line_s Dwarf_Line; + +/* Source file information. */ +typedef struct Dwarf_Files_s Dwarf_Files; + +/* One address range record. */ +typedef struct Dwarf_Arange_s Dwarf_Arange; + +/* Address ranges of a file. */ +typedef struct Dwarf_Aranges_s Dwarf_Aranges; + +/* CU representation. */ +struct Dwarf_CU; +typedef struct Dwarf_CU Dwarf_CU; + +/* Macro information. */ +typedef struct Dwarf_Macro_s Dwarf_Macro; + +/* Attribute representation. */ +typedef struct +{ + unsigned int code; + unsigned int form; + unsigned char *valp; + struct Dwarf_CU *cu; +} Dwarf_Attribute; + + +/* Data block representation. */ +typedef struct +{ + Dwarf_Word length; + unsigned char *data; +} Dwarf_Block; + + +/* DIE information. */ +typedef struct +{ + /* The offset can be computed from the address. */ + void *addr; + struct Dwarf_CU *cu; + Dwarf_Abbrev *abbrev; + // XXX We'll see what other information will be needed. + long int padding__; +} Dwarf_Die; + +/* Returned to show the last DIE has be returned. */ +#define DWARF_END_DIE ((Dwarf_Die *) -1l) + + +/* Global symbol information. */ +typedef struct +{ + Dwarf_Off cu_offset; + Dwarf_Off die_offset; + const char *name; +} Dwarf_Global; + + +/* One operation in a DWARF location expression. + A location expression is an array of these. */ +typedef struct +{ + uint8_t atom; /* Operation */ + Dwarf_Word number; /* Operand */ + Dwarf_Word number2; /* Possible second operand */ + Dwarf_Word offset; /* Offset in location expression */ +} Dwarf_Op; + + +/* This describes one Common Information Entry read from a CFI section. + Pointers here point into the DATA->d_buf block passed to dwarf_next_cfi. */ +typedef struct +{ + Dwarf_Off CIE_id; /* Always DW_CIE_ID_64 in Dwarf_CIE structures. */ + + /* Instruction stream describing initial state used by FDEs. If + we did not understand the whole augmentation string and it did + not use 'z', then there might be more augmentation data here + (and in FDEs) before the actual instructions. */ + const uint8_t *initial_instructions; + const uint8_t *initial_instructions_end; + + Dwarf_Word code_alignment_factor; + Dwarf_Sword data_alignment_factor; + Dwarf_Word return_address_register; + + const char *augmentation; /* Augmentation string. */ + + /* Augmentation data, might be NULL. The size is correct only if + we understood the augmentation string sufficiently. */ + const uint8_t *augmentation_data; + size_t augmentation_data_size; + size_t fde_augmentation_data_size; +} Dwarf_CIE; + +/* This describes one Frame Description Entry read from a CFI section. + Pointers here point into the DATA->d_buf block passed to dwarf_next_cfi. */ +typedef struct +{ + /* Section offset of CIE this FDE refers to. This will never be + DW_CIE_ID_64 in an FDE. If this value is DW_CIE_ID_64, this is + actually a Dwarf_CIE structure. */ + Dwarf_Off CIE_pointer; + + /* We can't really decode anything further without looking up the CIE + and checking its augmentation string. Here follows the encoded + initial_location and address_range, then any augmentation data, + then the instruction stream. This FDE describes PC locations in + the byte range [initial_location, initial_location+address_range). + When the CIE augmentation string uses 'z', the augmentation data is + a DW_FORM_block (self-sized). Otherwise, when we understand the + augmentation string completely, fde_augmentation_data_size gives + the number of bytes of augmentation data before the instructions. */ + const uint8_t *start; + const uint8_t *end; +} Dwarf_FDE; + +/* Each entry in a CFI section is either a CIE described by Dwarf_CIE or + an FDE described by Dward_FDE. Check CIE_id to see which you have. */ +typedef union +{ + Dwarf_Off CIE_id; /* Always DW_CIE_ID_64 in Dwarf_CIE structures. */ + Dwarf_CIE cie; + Dwarf_FDE fde; +} Dwarf_CFI_Entry; + +#define dwarf_cfi_cie_p(entry) ((entry)->cie.CIE_id == DW_CIE_ID_64) + +/* Opaque type representing a frame state described by CFI. */ +typedef struct Dwarf_Frame_s Dwarf_Frame; + +/* Opaque type representing a CFI section found in a DWARF or ELF file. */ +typedef struct Dwarf_CFI_s Dwarf_CFI; + + +/* Handle for debug sessions. */ +typedef struct Dwarf Dwarf; + + +/* Out-Of-Memory handler. */ +#if __GNUC__ < 4 +typedef void (*Dwarf_OOM) (void); +#else +typedef void (*__attribute__ ((noreturn)) Dwarf_OOM) (void); +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Create a handle for a new debug session. */ +extern Dwarf *dwarf_begin (int fildes, Dwarf_Cmd cmd); + +/* Create a handle for a new debug session for an ELF file. */ +extern Dwarf *dwarf_begin_elf (Elf *elf, Dwarf_Cmd cmd, Elf_Scn *scngrp); + +/* Retrieve ELF descriptor used for DWARF access. */ +extern Elf *dwarf_getelf (Dwarf *dwarf); + +/* Retieve DWARF descriptor used for a Dwarf_Die or Dwarf_Attribute. + A Dwarf_Die or a Dwarf_Attribute is associated with a particular + Dwarf_CU handle. This function returns the DWARF descriptor for + that Dwarf_CU. */ +extern Dwarf *dwarf_cu_getdwarf (Dwarf_CU *cu); + +/* Retrieves the DWARF descriptor for debugaltlink data. Returns NULL + if no alternate debug data has been supplied. */ +extern Dwarf *dwarf_getalt (Dwarf *main); + +/* Provides the data referenced by the .gnu_debugaltlink section. The + caller should check that MAIN and ALT match (i.e., they have the + same build ID). It is the responsibility of the caller to ensure + that the data referenced by ALT stays valid while it is used by + MAIN, until dwarf_setalt is called on MAIN with a different + descriptor, or dwarf_end. */ +extern void dwarf_setalt (Dwarf *main, Dwarf *alt); + +/* Release debugging handling context. */ +extern int dwarf_end (Dwarf *dwarf); + + +/* Get the data block for the .debug_info section. */ +extern Elf_Data *dwarf_getscn_info (Dwarf *dwarf); + +/* Read the header for the DWARF CU. */ +extern int dwarf_nextcu (Dwarf *dwarf, Dwarf_Off off, Dwarf_Off *next_off, + size_t *header_sizep, Dwarf_Off *abbrev_offsetp, + uint8_t *address_sizep, uint8_t *offset_sizep) + __nonnull_attribute__ (3); + +/* Read the header of a DWARF CU or type unit. If TYPE_SIGNATUREP is not + null, this reads a type unit from the .debug_types section; otherwise + this reads a CU from the .debug_info section. */ +extern int dwarf_next_unit (Dwarf *dwarf, Dwarf_Off off, Dwarf_Off *next_off, + size_t *header_sizep, Dwarf_Half *versionp, + Dwarf_Off *abbrev_offsetp, + uint8_t *address_sizep, uint8_t *offset_sizep, + uint64_t *type_signaturep, Dwarf_Off *type_offsetp) + __nonnull_attribute__ (3); + + +/* Decode one DWARF CFI entry (CIE or FDE) from the raw section data. + The E_IDENT from the originating ELF file indicates the address + size and byte order used in the CFI section contained in DATA; + EH_FRAME_P should be true for .eh_frame format and false for + .debug_frame format. OFFSET is the byte position in the section + to start at; on return *NEXT_OFFSET is filled in with the byte + position immediately after this entry. + + On success, returns 0 and fills in *ENTRY; use dwarf_cfi_cie_p to + see whether ENTRY->cie or ENTRY->fde is valid. + + On errors, returns -1. Some format errors will permit safely + skipping to the next CFI entry though the current one is unusable. + In that case, *NEXT_OFF will be updated before a -1 return. + + If there are no more CFI entries left in the section, + returns 1 and sets *NEXT_OFFSET to (Dwarf_Off) -1. */ +extern int dwarf_next_cfi (const unsigned char e_ident[], + Elf_Data *data, bool eh_frame_p, + Dwarf_Off offset, Dwarf_Off *next_offset, + Dwarf_CFI_Entry *entry) + __nonnull_attribute__ (1, 2, 5, 6); + +/* Use the CFI in the DWARF .debug_frame section. + Returns NULL if there is no such section (not an error). + The pointer returned can be used until dwarf_end is called on DWARF, + and must not be passed to dwarf_cfi_end. + Calling this more than once returns the same pointer. */ +extern Dwarf_CFI *dwarf_getcfi (Dwarf *dwarf); + +/* Use the CFI in the ELF file's exception-handling data. + Returns NULL if there is no such data. + The pointer returned can be used until elf_end is called on ELF, + and must be passed to dwarf_cfi_end before then. + Calling this more than once allocates independent data structures. */ +extern Dwarf_CFI *dwarf_getcfi_elf (Elf *elf); + +/* Release resources allocated by dwarf_getcfi_elf. */ +extern int dwarf_cfi_end (Dwarf_CFI *cache); + + +/* Return DIE at given offset in .debug_info section. */ +extern Dwarf_Die *dwarf_offdie (Dwarf *dbg, Dwarf_Off offset, + Dwarf_Die *result) __nonnull_attribute__ (3); + +/* Return DIE at given offset in .debug_types section. */ +extern Dwarf_Die *dwarf_offdie_types (Dwarf *dbg, Dwarf_Off offset, + Dwarf_Die *result) + __nonnull_attribute__ (3); + +/* Return offset of DIE. */ +extern Dwarf_Off dwarf_dieoffset (Dwarf_Die *die); + +/* Return offset of DIE in CU. */ +extern Dwarf_Off dwarf_cuoffset (Dwarf_Die *die); + +/* Return CU DIE containing given DIE. */ +extern Dwarf_Die *dwarf_diecu (Dwarf_Die *die, Dwarf_Die *result, + uint8_t *address_sizep, uint8_t *offset_sizep) + __nonnull_attribute__ (2); + +/* Return the CU DIE and the header info associated with a Dwarf_Die + or Dwarf_Attribute. A Dwarf_Die or a Dwarf_Attribute is associated + with a particular Dwarf_CU handle. This function returns the CU or + type unit DIE and header information for that Dwarf_CU. The + returned DIE is either a compile_unit, partial_unit or type_unit. + If it is a type_unit, then the type signature and type offset are + also provided, otherwise type_offset will be set to zero. See also + dwarf_diecu and dwarf_next_unit. */ +extern Dwarf_Die *dwarf_cu_die (Dwarf_CU *cu, Dwarf_Die *result, + Dwarf_Half *versionp, + Dwarf_Off *abbrev_offsetp, + uint8_t *address_sizep, + uint8_t *offset_sizep, + uint64_t *type_signaturep, + Dwarf_Off *type_offsetp) + __nonnull_attribute__ (2); + +/* Return CU DIE containing given address. */ +extern Dwarf_Die *dwarf_addrdie (Dwarf *dbg, Dwarf_Addr addr, + Dwarf_Die *result) __nonnull_attribute__ (3); + +/* Return child of current DIE. */ +extern int dwarf_child (Dwarf_Die *die, Dwarf_Die *result) + __nonnull_attribute__ (2); + +/* Locates the first sibling of DIE and places it in RESULT. + Returns 0 if a sibling was found, -1 if something went wrong. + Returns 1 if no sibling could be found and, if RESULT is not + the same as DIE, it sets RESULT->addr to the address of the + (non-sibling) DIE that follows this one, or NULL if this DIE + was the last one in the compilation unit. */ +extern int dwarf_siblingof (Dwarf_Die *die, Dwarf_Die *result) + __nonnull_attribute__ (2); + +/* For type aliases and qualifier type DIEs follow the DW_AT_type + attribute (recursively) and return the underlying type Dwarf_Die. + Returns 0 when RESULT contains a Dwarf_Die (possibly equal to the + given DIE) that isn't a type alias or qualifier type. Returns 1 + when RESULT contains a type alias or qualifier Dwarf_Die that + couldn't be peeled further (it doesn't have a DW_TAG_type + attribute). Returns -1 when an error occured. + + The current DWARF specification defines one type alias tag + (DW_TAG_typedef) and three qualifier type tags (DW_TAG_const_type, + DW_TAG_volatile_type, DW_TAG_restrict_type). A future version of + this function might peel other alias or qualifier type tags if a + future DWARF version or GNU extension defines other type aliases or + qualifier type tags that don't modify or change the structural + layout of the underlying type. */ +extern int dwarf_peel_type (Dwarf_Die *die, Dwarf_Die *result) + __nonnull_attribute__ (2); + +/* Check whether the DIE has children. */ +extern int dwarf_haschildren (Dwarf_Die *die) __nonnull_attribute__ (1); + +/* Walks the attributes of DIE, starting at the one OFFSET bytes in, + calling the CALLBACK function for each one. Stops if the callback + function ever returns a value other than DWARF_CB_OK and returns the + offset of the offending attribute. If the end of the attributes + is reached 1 is returned. If something goes wrong -1 is returned and + the dwarf error number is set. */ +extern ptrdiff_t dwarf_getattrs (Dwarf_Die *die, + int (*callback) (Dwarf_Attribute *, void *), + void *arg, ptrdiff_t offset) + __nonnull_attribute__ (2); + +/* Return tag of given DIE. */ +extern int dwarf_tag (Dwarf_Die *die) __nonnull_attribute__ (1); + + +/* Return specific attribute of DIE. */ +extern Dwarf_Attribute *dwarf_attr (Dwarf_Die *die, unsigned int search_name, + Dwarf_Attribute *result) + __nonnull_attribute__ (3); + +/* Check whether given DIE has specific attribute. */ +extern int dwarf_hasattr (Dwarf_Die *die, unsigned int search_name); + +/* These are the same as dwarf_attr and dwarf_hasattr, respectively, + but they resolve an indirect attribute through DW_AT_abstract_origin. */ +extern Dwarf_Attribute *dwarf_attr_integrate (Dwarf_Die *die, + unsigned int search_name, + Dwarf_Attribute *result) + __nonnull_attribute__ (3); +extern int dwarf_hasattr_integrate (Dwarf_Die *die, unsigned int search_name); + + + + +/* Check whether given attribute has specific form. */ +extern int dwarf_hasform (Dwarf_Attribute *attr, unsigned int search_form); + +/* Return attribute code of given attribute. */ +extern unsigned int dwarf_whatattr (Dwarf_Attribute *attr); + +/* Return form code of given attribute. */ +extern unsigned int dwarf_whatform (Dwarf_Attribute *attr); + + +/* Return string associated with given attribute. */ +extern const char *dwarf_formstring (Dwarf_Attribute *attrp); + +/* Return unsigned constant represented by attribute. */ +extern int dwarf_formudata (Dwarf_Attribute *attr, Dwarf_Word *return_uval) + __nonnull_attribute__ (2); + +/* Return signed constant represented by attribute. */ +extern int dwarf_formsdata (Dwarf_Attribute *attr, Dwarf_Sword *return_uval) + __nonnull_attribute__ (2); + +/* Return address represented by attribute. */ +extern int dwarf_formaddr (Dwarf_Attribute *attr, Dwarf_Addr *return_addr) + __nonnull_attribute__ (2); + +/* This function is deprecated. Always use dwarf_formref_die instead. + Return reference offset represented by attribute. */ +extern int dwarf_formref (Dwarf_Attribute *attr, Dwarf_Off *return_offset) + __nonnull_attribute__ (2) __deprecated_attribute__; + +/* Look up the DIE in a reference-form attribute. */ +extern Dwarf_Die *dwarf_formref_die (Dwarf_Attribute *attr, Dwarf_Die *die_mem) + __nonnull_attribute__ (2); + +/* Return block represented by attribute. */ +extern int dwarf_formblock (Dwarf_Attribute *attr, Dwarf_Block *return_block) + __nonnull_attribute__ (2); + +/* Return flag represented by attribute. */ +extern int dwarf_formflag (Dwarf_Attribute *attr, bool *return_bool) + __nonnull_attribute__ (2); + + +/* Simplified attribute value access functions. */ + +/* Return string in name attribute of DIE. */ +extern const char *dwarf_diename (Dwarf_Die *die); + +/* Return high PC attribute of DIE. */ +extern int dwarf_highpc (Dwarf_Die *die, Dwarf_Addr *return_addr) + __nonnull_attribute__ (2); + +/* Return low PC attribute of DIE. */ +extern int dwarf_lowpc (Dwarf_Die *die, Dwarf_Addr *return_addr) + __nonnull_attribute__ (2); + +/* Return entry_pc or low_pc attribute of DIE. */ +extern int dwarf_entrypc (Dwarf_Die *die, Dwarf_Addr *return_addr) + __nonnull_attribute__ (2); + +/* Return 1 if DIE's lowpc/highpc or ranges attributes match the PC address, + 0 if not, or -1 for errors. */ +extern int dwarf_haspc (Dwarf_Die *die, Dwarf_Addr pc); + +/* Enumerate the PC address ranges covered by this DIE, covering all + addresses where dwarf_haspc returns true. In the first call OFFSET + should be zero and *BASEP need not be initialized. Returns -1 for + errors, zero when there are no more address ranges to report, or a + nonzero OFFSET value to pass to the next call. Each subsequent call + must preserve *BASEP from the prior call. Successful calls fill in + *STARTP and *ENDP with a contiguous address range. */ +extern ptrdiff_t dwarf_ranges (Dwarf_Die *die, + ptrdiff_t offset, Dwarf_Addr *basep, + Dwarf_Addr *startp, Dwarf_Addr *endp); + + +/* Return byte size attribute of DIE. */ +extern int dwarf_bytesize (Dwarf_Die *die); + +/* Return bit size attribute of DIE. */ +extern int dwarf_bitsize (Dwarf_Die *die); + +/* Return bit offset attribute of DIE. */ +extern int dwarf_bitoffset (Dwarf_Die *die); + +/* Return array order attribute of DIE. */ +extern int dwarf_arrayorder (Dwarf_Die *die); + +/* Return source language attribute of DIE. */ +extern int dwarf_srclang (Dwarf_Die *die); + + +/* Get abbreviation at given offset for given DIE. */ +extern Dwarf_Abbrev *dwarf_getabbrev (Dwarf_Die *die, Dwarf_Off offset, + size_t *lengthp); + +/* Get abbreviation at given offset in .debug_abbrev section. */ +extern int dwarf_offabbrev (Dwarf *dbg, Dwarf_Off offset, size_t *lengthp, + Dwarf_Abbrev *abbrevp) + __nonnull_attribute__ (4); + +/* Get abbreviation code. */ +extern unsigned int dwarf_getabbrevcode (Dwarf_Abbrev *abbrev); + +/* Get abbreviation tag. */ +extern unsigned int dwarf_getabbrevtag (Dwarf_Abbrev *abbrev); + +/* Return true if abbreviation is children flag set. */ +extern int dwarf_abbrevhaschildren (Dwarf_Abbrev *abbrev); + +/* Get number of attributes of abbreviation. */ +extern int dwarf_getattrcnt (Dwarf_Abbrev *abbrev, size_t *attrcntp) + __nonnull_attribute__ (2); + +/* Get specific attribute of abbreviation. */ +extern int dwarf_getabbrevattr (Dwarf_Abbrev *abbrev, size_t idx, + unsigned int *namep, unsigned int *formp, + Dwarf_Off *offset); + + +/* Get string from-debug_str section. */ +extern const char *dwarf_getstring (Dwarf *dbg, Dwarf_Off offset, + size_t *lenp); + + +/* Get public symbol information. */ +extern ptrdiff_t dwarf_getpubnames (Dwarf *dbg, + int (*callback) (Dwarf *, Dwarf_Global *, + void *), + void *arg, ptrdiff_t offset) + __nonnull_attribute__ (2); + + +/* Get source file information for CU. */ +extern int dwarf_getsrclines (Dwarf_Die *cudie, Dwarf_Lines **lines, + size_t *nlines) __nonnull_attribute__ (2, 3); + +/* Return one of the source lines of the CU. */ +extern Dwarf_Line *dwarf_onesrcline (Dwarf_Lines *lines, size_t idx); + +/* Get the file source files used in the CU. */ +extern int dwarf_getsrcfiles (Dwarf_Die *cudie, Dwarf_Files **files, + size_t *nfiles) + __nonnull_attribute__ (2); + + +/* Get source for address in CU. */ +extern Dwarf_Line *dwarf_getsrc_die (Dwarf_Die *cudie, Dwarf_Addr addr); + +/* Get source for file and line number. */ +extern int dwarf_getsrc_file (Dwarf *dbg, const char *fname, int line, int col, + Dwarf_Line ***srcsp, size_t *nsrcs) + __nonnull_attribute__ (2, 5, 6); + + +/* Return line address. */ +extern int dwarf_lineaddr (Dwarf_Line *line, Dwarf_Addr *addrp); + +/* Return line VLIW operation index. */ +extern int dwarf_lineop_index (Dwarf_Line *line, unsigned int *op_indexp); + +/* Return line number. */ +extern int dwarf_lineno (Dwarf_Line *line, int *linep) + __nonnull_attribute__ (2); + +/* Return column in line. */ +extern int dwarf_linecol (Dwarf_Line *line, int *colp) + __nonnull_attribute__ (2); + +/* Return true if record is for beginning of a statement. */ +extern int dwarf_linebeginstatement (Dwarf_Line *line, bool *flagp) + __nonnull_attribute__ (2); + +/* Return true if record is for end of sequence. */ +extern int dwarf_lineendsequence (Dwarf_Line *line, bool *flagp) + __nonnull_attribute__ (2); + +/* Return true if record is for beginning of a basic block. */ +extern int dwarf_lineblock (Dwarf_Line *line, bool *flagp) + __nonnull_attribute__ (2); + +/* Return true if record is for end of prologue. */ +extern int dwarf_lineprologueend (Dwarf_Line *line, bool *flagp) + __nonnull_attribute__ (2); + +/* Return true if record is for beginning of epilogue. */ +extern int dwarf_lineepiloguebegin (Dwarf_Line *line, bool *flagp) + __nonnull_attribute__ (2); + +/* Return instruction-set architecture in this record. */ +extern int dwarf_lineisa (Dwarf_Line *line, unsigned int *isap) + __nonnull_attribute__ (2); + +/* Return code path discriminator in this record. */ +extern int dwarf_linediscriminator (Dwarf_Line *line, unsigned int *discp) + __nonnull_attribute__ (2); + + +/* Find line information for address. */ +extern const char *dwarf_linesrc (Dwarf_Line *line, + Dwarf_Word *mtime, Dwarf_Word *length); + +/* Return file information. */ +extern const char *dwarf_filesrc (Dwarf_Files *file, size_t idx, + Dwarf_Word *mtime, Dwarf_Word *length); + +/* Return the directory list used in the file information extracted. + (*RESULT)[0] is the CU's DW_AT_comp_dir value, and may be null. + (*RESULT)[0..*NDIRS-1] are the compile-time include directory path + encoded by the compiler. */ +extern int dwarf_getsrcdirs (Dwarf_Files *files, + const char *const **result, size_t *ndirs) + __nonnull_attribute__ (2, 3); + + +/* Return location expression, decoded as a list of operations. */ +extern int dwarf_getlocation (Dwarf_Attribute *attr, Dwarf_Op **expr, + size_t *exprlen) __nonnull_attribute__ (2, 3); + +/* Return location expressions. If the attribute uses a location list, + ADDRESS selects the relevant location expressions from the list. + There can be multiple matches, resulting in multiple expressions to + return. EXPRS and EXPRLENS are parallel arrays of NLOCS slots to + fill in. Returns the number of locations filled in, or -1 for + errors. If EXPRS is a null pointer, stores nothing and returns the + total number of locations. A return value of zero means that the + location list indicated no value is accessible. */ +extern int dwarf_getlocation_addr (Dwarf_Attribute *attr, Dwarf_Addr address, + Dwarf_Op **exprs, size_t *exprlens, + size_t nlocs); + +/* Enumerate the locations ranges and descriptions covered by the + given attribute. In the first call OFFSET should be zero and + *BASEP need not be initialized. Returns -1 for errors, zero when + there are no more locations to report, or a nonzero OFFSET + value to pass to the next call. Each subsequent call must preserve + *BASEP from the prior call. Successful calls fill in *STARTP and + *ENDP with a contiguous address range and *EXPR with a pointer to + an array of operations with length *EXPRLEN. If the attribute + describes a single location description and not a location list the + first call (with OFFSET zero) will return the location description + in *EXPR with *STARTP set to zero and *ENDP set to minus one. */ +extern ptrdiff_t dwarf_getlocations (Dwarf_Attribute *attr, + ptrdiff_t offset, Dwarf_Addr *basep, + Dwarf_Addr *startp, Dwarf_Addr *endp, + Dwarf_Op **expr, size_t *exprlen); + +/* Return the block associated with a DW_OP_implicit_value operation. + The OP pointer must point into an expression that dwarf_getlocation + or dwarf_getlocation_addr has returned given the same ATTR. */ +extern int dwarf_getlocation_implicit_value (Dwarf_Attribute *attr, + const Dwarf_Op *op, + Dwarf_Block *return_block) + __nonnull_attribute__ (2, 3); + +/* Return the attribute indicated by a DW_OP_GNU_implicit_pointer operation. + The OP pointer must point into an expression that dwarf_getlocation + or dwarf_getlocation_addr has returned given the same ATTR. + The result is the DW_AT_location or DW_AT_const_value attribute + of the OP->number DIE. */ +extern int dwarf_getlocation_implicit_pointer (Dwarf_Attribute *attr, + const Dwarf_Op *op, + Dwarf_Attribute *result) + __nonnull_attribute__ (2, 3); + +/* Return the DIE associated with an operation such as + DW_OP_GNU_implicit_pointer, DW_OP_GNU_parameter_ref, DW_OP_GNU_convert, + DW_OP_GNU_reinterpret, DW_OP_GNU_const_type, DW_OP_GNU_regval_type or + DW_OP_GNU_deref_type. The OP pointer must point into an expression that + dwarf_getlocation or dwarf_getlocation_addr has returned given the same + ATTR. The RESULT is a DIE that expresses a type or value needed by the + given OP. */ +extern int dwarf_getlocation_die (Dwarf_Attribute *attr, + const Dwarf_Op *op, + Dwarf_Die *result) + __nonnull_attribute__ (2, 3); + +/* Return the attribute expressing a value associated with an operation such + as DW_OP_implicit_value, DW_OP_GNU_entry_value or DW_OP_GNU_const_type. + The OP pointer must point into an expression that dwarf_getlocation + or dwarf_getlocation_addr has returned given the same ATTR. + The RESULT is a value expressed by an attribute such as DW_AT_location + or DW_AT_const_value. */ +extern int dwarf_getlocation_attr (Dwarf_Attribute *attr, + const Dwarf_Op *op, + Dwarf_Attribute *result) + __nonnull_attribute__ (2, 3); + + +/* Compute the byte-size of a type DIE according to DWARF rules. + For most types, this is just DW_AT_byte_size. + For DW_TAG_array_type it can apply much more complex rules. */ +extern int dwarf_aggregate_size (Dwarf_Die *die, Dwarf_Word *size); + + +/* Return scope DIEs containing PC address. + Sets *SCOPES to a malloc'd array of Dwarf_Die structures, + and returns the number of elements in the array. + (*SCOPES)[0] is the DIE for the innermost scope containing PC, + (*SCOPES)[1] is the DIE for the scope containing that scope, and so on. + Returns -1 for errors or 0 if no scopes match PC. */ +extern int dwarf_getscopes (Dwarf_Die *cudie, Dwarf_Addr pc, + Dwarf_Die **scopes); + +/* Return scope DIEs containing the given DIE. + Sets *SCOPES to a malloc'd array of Dwarf_Die structures, + and returns the number of elements in the array. + (*SCOPES)[0] is a copy of DIE. + (*SCOPES)[1] is the DIE for the scope containing that scope, and so on. + Returns -1 for errors or 0 if DIE is not found in any scope entry. */ +extern int dwarf_getscopes_die (Dwarf_Die *die, Dwarf_Die **scopes); + + +/* Search SCOPES[0..NSCOPES-1] for a variable called NAME. + Ignore the first SKIP_SHADOWS scopes that match the name. + If MATCH_FILE is not null, accept only declaration in that source file; + if MATCH_LINENO or MATCH_LINECOL are also nonzero, accept only declaration + at that line and column. + + If successful, fill in *RESULT with the DIE of the variable found, + and return N where SCOPES[N] is the scope defining the variable. + Return -1 for errors or -2 for no matching variable found. */ +extern int dwarf_getscopevar (Dwarf_Die *scopes, int nscopes, + const char *name, int skip_shadows, + const char *match_file, + int match_lineno, int match_linecol, + Dwarf_Die *result); + + + +/* Return list address ranges. */ +extern int dwarf_getaranges (Dwarf *dbg, Dwarf_Aranges **aranges, + size_t *naranges) + __nonnull_attribute__ (2); + +/* Return one of the address range entries. */ +extern Dwarf_Arange *dwarf_onearange (Dwarf_Aranges *aranges, size_t idx); + +/* Return information in address range record. */ +extern int dwarf_getarangeinfo (Dwarf_Arange *arange, Dwarf_Addr *addrp, + Dwarf_Word *lengthp, Dwarf_Off *offsetp); + +/* Get address range which includes given address. */ +extern Dwarf_Arange *dwarf_getarange_addr (Dwarf_Aranges *aranges, + Dwarf_Addr addr); + + + +/* Get functions in CUDIE. The given callback will be called for all + defining DW_TAG_subprograms in the CU DIE tree. If the callback + returns DWARF_CB_ABORT the return value can be used as offset argument + to resume the function to find all remaining functions (this is not + really recommended, since it needs to rewalk the CU DIE tree first till + that offset is found again). If the callback returns DWARF_CB_OK + dwarf_getfuncs will not return but keep calling the callback for each + function DIE it finds. Pass zero for offset on the first call to walk + the full CU DIE tree. If no more functions can be found and the callback + returned DWARF_CB_OK then the function returns zero. */ +extern ptrdiff_t dwarf_getfuncs (Dwarf_Die *cudie, + int (*callback) (Dwarf_Die *, void *), + void *arg, ptrdiff_t offset); + + +/* Return file name containing definition of the given declaration. */ +extern const char *dwarf_decl_file (Dwarf_Die *decl); + +/* Get line number of beginning of given declaration. */ +extern int dwarf_decl_line (Dwarf_Die *decl, int *linep) + __nonnull_attribute__ (2); + +/* Get column number of beginning of given declaration. */ +extern int dwarf_decl_column (Dwarf_Die *decl, int *colp) + __nonnull_attribute__ (2); + + +/* Return nonzero if given function is an abstract inline definition. */ +extern int dwarf_func_inline (Dwarf_Die *func); + +/* Find each concrete inlined instance of the abstract inline definition. */ +extern int dwarf_func_inline_instances (Dwarf_Die *func, + int (*callback) (Dwarf_Die *, void *), + void *arg); + + +/* Find the appropriate PC location or locations for function entry + breakpoints for the given DW_TAG_subprogram DIE. Returns -1 for errors. + On success, returns the number of breakpoint locations (never zero) + and sets *BKPTS to a malloc'd vector of addresses. */ +extern int dwarf_entry_breakpoints (Dwarf_Die *die, Dwarf_Addr **bkpts); + + +/* Iterate through the macro unit referenced by CUDIE and call + CALLBACK for each macro information entry. To start the iteration, + one would pass DWARF_GETMACROS_START for TOKEN. + + The iteration continues while CALLBACK returns DWARF_CB_OK. If the + callback returns DWARF_CB_ABORT, the iteration stops and a + continuation token is returned, which can be used to restart the + iteration at the point where it ended. Returns -1 for errors or 0 + if there are no more macro entries. + + Note that the Dwarf_Macro pointer passed to the callback is only + valid for the duration of the callback invocation. + + For backward compatibility, a token of 0 is accepted for starting + the iteration as well, but in that case this interface will refuse + to serve opcode 0xff from .debug_macro sections. Such opcode would + be considered invalid and would cause dwarf_getmacros to return + with error. */ +#define DWARF_GETMACROS_START PTRDIFF_MIN +extern ptrdiff_t dwarf_getmacros (Dwarf_Die *cudie, + int (*callback) (Dwarf_Macro *, void *), + void *arg, ptrdiff_t token) + __nonnull_attribute__ (2); + +/* This is similar in operation to dwarf_getmacros, but selects the + unit to iterate through by offset instead of by CU, and always + iterates .debug_macro. This can be used for handling + DW_MACRO_GNU_transparent_include's or similar opcodes. + + TOKEN value of DWARF_GETMACROS_START can be used to start the + iteration. + + It is not appropriate to obtain macro unit offset by hand from a CU + DIE and then request iteration through this interface. The reason + for this is that if a dwarf_macro_getsrcfiles is later called, + there would be no way to figure out what DW_AT_comp_dir was present + on the CU DIE, and file names referenced in either the macro unit + itself, or the .debug_line unit that it references, might be wrong. + Use dwarf_getmacros. */ +extern ptrdiff_t dwarf_getmacros_off (Dwarf *dbg, Dwarf_Off macoff, + int (*callback) (Dwarf_Macro *, void *), + void *arg, ptrdiff_t token) + __nonnull_attribute__ (3); + +/* Get the source files used by the macro entry. You shouldn't assume + that Dwarf_Files references will remain valid after MACRO becomes + invalid. (Which is to say it's only valid within the + dwarf_getmacros* callback.) Returns 0 for success or a negative + value in case of an error. */ +extern int dwarf_macro_getsrcfiles (Dwarf *dbg, Dwarf_Macro *macro, + Dwarf_Files **files, size_t *nfiles) + __nonnull_attribute__ (2, 3, 4); + +/* Return macro opcode. That's a constant that can be either from + DW_MACINFO_* domain or DW_MACRO_GNU_* domain. The two domains have + compatible values, so it's OK to use either of them for + comparisons. The only differences is 0xff, which could be either + DW_MACINFO_vendor_ext or a vendor-defined DW_MACRO_* constant. One + would need to look if the CU DIE which the iteration was requested + for has attribute DW_AT_macro_info, or either of DW_AT_GNU_macros + or DW_AT_macros to differentiate the two interpretations. */ +extern int dwarf_macro_opcode (Dwarf_Macro *macro, unsigned int *opcodep) + __nonnull_attribute__ (2); + +/* Get number of parameters of MACRO and store it to *PARAMCNTP. */ +extern int dwarf_macro_getparamcnt (Dwarf_Macro *macro, size_t *paramcntp); + +/* Get IDX-th parameter of MACRO (numbered from zero), and stores it + to *ATTRIBUTE. Returns 0 on success or -1 for errors. + + After a successful call, you can query ATTRIBUTE by dwarf_whatform + to determine which of the dwarf_formX calls to make to get actual + value out of ATTRIBUTE. Note that calling dwarf_whatattr is not + meaningful for pseudo-attributes formed this way. */ +extern int dwarf_macro_param (Dwarf_Macro *macro, size_t idx, + Dwarf_Attribute *attribute); + +/* Return macro parameter with index 0. This will return -1 if the + parameter is not an integral value. Use dwarf_macro_param for more + general access. */ +extern int dwarf_macro_param1 (Dwarf_Macro *macro, Dwarf_Word *paramp) + __nonnull_attribute__ (2); + +/* Return macro parameter with index 1. This will return -1 if the + parameter is not an integral or string value. Use + dwarf_macro_param for more general access. */ +extern int dwarf_macro_param2 (Dwarf_Macro *macro, Dwarf_Word *paramp, + const char **strp); + +/* Compute what's known about a call frame when the PC is at ADDRESS. + Returns 0 for success or -1 for errors. + On success, *FRAME is a malloc'd pointer. */ +extern int dwarf_cfi_addrframe (Dwarf_CFI *cache, + Dwarf_Addr address, Dwarf_Frame **frame) + __nonnull_attribute__ (3); + +/* Return the DWARF register number used in FRAME to denote + the return address in FRAME's caller frame. The remaining + arguments can be non-null to fill in more information. + + Fill [*START, *END) with the PC range to which FRAME's information applies. + Fill in *SIGNALP to indicate whether this is a signal-handling frame. + If true, this is the implicit call frame that calls a signal handler. + This frame's "caller" is actually the interrupted state, not a call; + its return address is an exact PC, not a PC after a call instruction. */ +extern int dwarf_frame_info (Dwarf_Frame *frame, + Dwarf_Addr *start, Dwarf_Addr *end, bool *signalp); + +/* Return a DWARF expression that yields the Canonical Frame Address at + this frame state. Returns -1 for errors, or zero for success, with + *NOPS set to the number of operations stored at *OPS. That pointer + can be used only as long as FRAME is alive and unchanged. *NOPS is + zero if the CFA cannot be determined here. Note that if nonempty, + *OPS is a DWARF expression, not a location description--append + DW_OP_stack_value to a get a location description for the CFA. */ +extern int dwarf_frame_cfa (Dwarf_Frame *frame, Dwarf_Op **ops, size_t *nops) + __nonnull_attribute__ (2); + +/* Deliver a DWARF location description that yields the location or + value of DWARF register number REGNO in the state described by FRAME. + + Returns -1 for errors or zero for success, setting *NOPS to the + number of operations in the array stored at *OPS. Note the last + operation is DW_OP_stack_value if there is no mutable location but + only a computable value. + + *NOPS zero with *OPS set to OPS_MEM means CFI says the caller's + REGNO is "undefined", i.e. it's call-clobbered and cannot be recovered. + + *NOPS zero with *OPS set to a null pointer means CFI says the + caller's REGNO is "same_value", i.e. this frame did not change it; + ask the caller frame where to find it. + + For common simple expressions *OPS is OPS_MEM. For arbitrary DWARF + expressions in the CFI, *OPS is an internal pointer that can be used as + long as the Dwarf_CFI used to create FRAME remains alive. */ +extern int dwarf_frame_register (Dwarf_Frame *frame, int regno, + Dwarf_Op ops_mem[3], + Dwarf_Op **ops, size_t *nops) + __nonnull_attribute__ (3, 4, 5); + + +/* Return error code of last failing function call. This value is kept + separately for each thread. */ +extern int dwarf_errno (void); + +/* Return error string for ERROR. If ERROR is zero, return error string + for most recent error or NULL is none occurred. If ERROR is -1 the + behaviour is similar to the last case except that not NULL but a legal + string is returned. */ +extern const char *dwarf_errmsg (int err); + + +/* Register new Out-Of-Memory handler. The old handler is returned. */ +extern Dwarf_OOM dwarf_new_oom_handler (Dwarf *dbg, Dwarf_OOM handler); + + +/* Inline optimizations. */ +#ifdef __OPTIMIZE__ +/* Return attribute code of given attribute. */ +__libdw_extern_inline unsigned int +dwarf_whatattr (Dwarf_Attribute *attr) +{ + return attr == NULL ? 0 : attr->code; +} + +/* Return attribute code of given attribute. */ +__libdw_extern_inline unsigned int +dwarf_whatform (Dwarf_Attribute *attr) +{ + return attr == NULL ? 0 : attr->form; +} +#endif /* Optimize. */ + +#ifdef __cplusplus +} +#endif + +#endif /* libdw.h */ diff --git a/3rdparty/elfutils/libdw/libdw.pro b/3rdparty/elfutils/libdw/libdw.pro new file mode 100644 index 0000000..f31cc71 --- /dev/null +++ b/3rdparty/elfutils/libdw/libdw.pro @@ -0,0 +1,127 @@ +TEMPLATE = lib +CONFIG += staticlib +TARGET = ../dw + +include(../elfutils.pri) +include(../libelf/elfheaders.pri) +include(dwheaders.pri) + +SOURCES += \ + $$PWD/cfi.c \ + $$PWD/cie.c \ + $$PWD/dwarf_abbrev_hash.c \ + $$PWD/dwarf_abbrevhaschildren.c \ + $$PWD/dwarf_addrdie.c \ + $$PWD/dwarf_aggregate_size.c \ + $$PWD/dwarf_arrayorder.c \ + $$PWD/dwarf_attr_integrate.c \ + $$PWD/dwarf_attr.c \ + $$PWD/dwarf_begin_elf.c \ + $$PWD/dwarf_begin.c \ + $$PWD/dwarf_bitoffset.c \ + $$PWD/dwarf_bitsize.c \ + $$PWD/dwarf_bytesize.c \ + $$PWD/dwarf_cfi_addrframe.c \ + $$PWD/dwarf_cfi_end.c \ + $$PWD/dwarf_child.c \ + $$PWD/dwarf_cu_die.c \ + $$PWD/dwarf_cu_getdwarf.c \ + $$PWD/dwarf_cuoffset.c \ + $$PWD/dwarf_decl_column.c \ + $$PWD/dwarf_decl_file.c \ + $$PWD/dwarf_decl_line.c \ + $$PWD/dwarf_diecu.c \ + $$PWD/dwarf_diename.c \ + $$PWD/dwarf_dieoffset.c \ + $$PWD/dwarf_end.c \ + $$PWD/dwarf_entry_breakpoints.c \ + $$PWD/dwarf_entrypc.c \ + $$PWD/dwarf_error.c \ + $$PWD/dwarf_filesrc.c \ + $$PWD/dwarf_formaddr.c \ + $$PWD/dwarf_formblock.c \ + $$PWD/dwarf_formflag.c \ + $$PWD/dwarf_formref_die.c \ + $$PWD/dwarf_formref.c \ + $$PWD/dwarf_formsdata.c \ + $$PWD/dwarf_formstring.c \ + $$PWD/dwarf_formudata.c \ + $$PWD/dwarf_frame_cfa.c \ + $$PWD/dwarf_frame_info.c \ + $$PWD/dwarf_frame_register.c \ + $$PWD/dwarf_func_inline.c \ + $$PWD/dwarf_getabbrev.c \ + $$PWD/dwarf_getabbrevattr.c \ + $$PWD/dwarf_getabbrevcode.c \ + $$PWD/dwarf_getabbrevtag.c \ + $$PWD/dwarf_getalt.c \ + $$PWD/dwarf_getarange_addr.c \ + $$PWD/dwarf_getarangeinfo.c \ + $$PWD/dwarf_getaranges.c \ + $$PWD/dwarf_getattrcnt.c \ + $$PWD/dwarf_getattrs.c \ + $$PWD/dwarf_getcfi_elf.c \ + $$PWD/dwarf_getcfi.c \ + $$PWD/dwarf_getelf.c \ + $$PWD/dwarf_getfuncs.c \ + $$PWD/dwarf_getlocation_attr.c \ + $$PWD/dwarf_getlocation_die.c \ + $$PWD/dwarf_getlocation_implicit_pointer.c \ + $$PWD/dwarf_getlocation.c \ + $$PWD/dwarf_getmacros.c \ + $$PWD/dwarf_getpubnames.c \ + $$PWD/dwarf_getscopes_die.c \ + $$PWD/dwarf_getscopes.c \ + $$PWD/dwarf_getscopevar.c \ + $$PWD/dwarf_getsrc_die.c \ + $$PWD/dwarf_getsrc_file.c \ + $$PWD/dwarf_getsrcdirs.c \ + $$PWD/dwarf_getsrcfiles.c \ + $$PWD/dwarf_getsrclines.c \ + $$PWD/dwarf_getstring.c \ + $$PWD/dwarf_hasattr_integrate.c \ + $$PWD/dwarf_hasattr.c \ + $$PWD/dwarf_haschildren.c \ + $$PWD/dwarf_hasform.c \ + $$PWD/dwarf_haspc.c \ + $$PWD/dwarf_highpc.c \ + $$PWD/dwarf_lineaddr.c \ + $$PWD/dwarf_linebeginstatement.c \ + $$PWD/dwarf_lineblock.c \ + $$PWD/dwarf_linecol.c \ + $$PWD/dwarf_linediscriminator.c \ + $$PWD/dwarf_lineendsequence.c \ + $$PWD/dwarf_lineepiloguebegin.c \ + $$PWD/dwarf_lineisa.c \ + $$PWD/dwarf_lineno.c \ + $$PWD/dwarf_lineop_index.c \ + $$PWD/dwarf_lineprologueend.c \ + $$PWD/dwarf_linesrc.c \ + $$PWD/dwarf_lowpc.c \ + $$PWD/dwarf_macro_getparamcnt.c \ + $$PWD/dwarf_macro_getsrcfiles.c \ + $$PWD/dwarf_macro_opcode.c \ + $$PWD/dwarf_macro_param.c \ + $$PWD/dwarf_macro_param1.c \ + $$PWD/dwarf_macro_param2.c \ + $$PWD/dwarf_next_cfi.c \ + $$PWD/dwarf_nextcu.c \ + $$PWD/dwarf_offabbrev.c \ + $$PWD/dwarf_offdie.c \ + $$PWD/dwarf_onearange.c \ + $$PWD/dwarf_onesrcline.c \ + $$PWD/dwarf_peel_type.c \ + $$PWD/dwarf_ranges.c \ + $$PWD/dwarf_setalt.c \ + $$PWD/dwarf_siblingof.c \ + $$PWD/dwarf_sig8_hash.c \ + $$PWD/dwarf_srclang.c \ + $$PWD/dwarf_tag.c \ + $$PWD/dwarf_whatattr.c \ + $$PWD/dwarf_whatform.c \ + $$PWD/fde.c \ + $$PWD/frame-cache.c \ + $$PWD/libdw_alloc.c \ + $$PWD/libdw_findcu.c \ + $$PWD/libdw_form.c \ + $$PWD/libdw_visit_scopes.c diff --git a/3rdparty/elfutils/libdw/libdwP.h b/3rdparty/elfutils/libdw/libdwP.h new file mode 100644 index 0000000..5ab7219 --- /dev/null +++ b/3rdparty/elfutils/libdw/libdwP.h @@ -0,0 +1,802 @@ +/* Internal definitions for libdwarf. + Copyright (C) 2002-2011, 2013, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifndef _LIBDWP_H +#define _LIBDWP_H 1 + +#include <libintl.h> +#include <stdbool.h> + +#include <libdw.h> +#include <dwarf.h> + + +/* gettext helper macros. */ +#define _(Str) dgettext ("elfutils", Str) + + +/* Known location expressions already decoded. */ +struct loc_s +{ + void *addr; + Dwarf_Op *loc; + size_t nloc; +}; + +/* Known DW_OP_implicit_value blocks already decoded. + This overlaps struct loc_s exactly, but only the + first member really has to match. */ +struct loc_block_s +{ + void *addr; + unsigned char *data; + size_t length; +}; + +/* Already decoded .debug_line units. */ +struct files_lines_s +{ + Dwarf_Off debug_line_offset; + Dwarf_Files *files; + Dwarf_Lines *lines; +}; + +/* Valid indeces for the section data. */ +enum + { + IDX_debug_info = 0, + IDX_debug_types, + IDX_debug_abbrev, + IDX_debug_aranges, + IDX_debug_line, + IDX_debug_frame, + IDX_debug_loc, + IDX_debug_pubnames, + IDX_debug_str, + IDX_debug_macinfo, + IDX_debug_macro, + IDX_debug_ranges, + IDX_gnu_debugaltlink, + IDX_last + }; + + +/* Error values. */ +enum +{ + DWARF_E_NOERROR = 0, + DWARF_E_UNKNOWN_ERROR, + DWARF_E_INVALID_ACCESS, + DWARF_E_NO_REGFILE, + DWARF_E_IO_ERROR, + DWARF_E_INVALID_ELF, + DWARF_E_NO_DWARF, + DWARF_E_NOELF, + DWARF_E_GETEHDR_ERROR, + DWARF_E_NOMEM, + DWARF_E_UNIMPL, + DWARF_E_INVALID_CMD, + DWARF_E_INVALID_VERSION, + DWARF_E_INVALID_FILE, + DWARF_E_NO_ENTRY, + DWARF_E_INVALID_DWARF, + DWARF_E_NO_STRING, + DWARF_E_NO_ADDR, + DWARF_E_NO_CONSTANT, + DWARF_E_NO_REFERENCE, + DWARF_E_INVALID_REFERENCE, + DWARF_E_NO_DEBUG_LINE, + DWARF_E_INVALID_DEBUG_LINE, + DWARF_E_TOO_BIG, + DWARF_E_VERSION, + DWARF_E_INVALID_DIR_IDX, + DWARF_E_ADDR_OUTOFRANGE, + DWARF_E_NO_LOCLIST, + DWARF_E_NO_BLOCK, + DWARF_E_INVALID_LINE_IDX, + DWARF_E_INVALID_ARANGE_IDX, + DWARF_E_NO_MATCH, + DWARF_E_NO_FLAG, + DWARF_E_INVALID_OFFSET, + DWARF_E_NO_DEBUG_RANGES, + DWARF_E_INVALID_CFI, + DWARF_E_NO_ALT_DEBUGLINK, + DWARF_E_INVALID_OPCODE, +}; + + +#include "dwarf_sig8_hash.h" + +/* This is the structure representing the debugging state. */ +struct Dwarf +{ + /* The underlying ELF file. */ + Elf *elf; + + /* dwz alternate DWARF file. */ + Dwarf *alt_dwarf; + + /* The section data. */ + Elf_Data *sectiondata[IDX_last]; + +#if USE_ZLIB + /* The 1 << N bit is set if sectiondata[N] is malloc'd decompressed data. */ + unsigned int sectiondata_gzip_mask:IDX_last; +#endif + + /* True if the file has a byte order different from the host. */ + bool other_byte_order; + + /* If true, we allocated the ELF descriptor ourselves. */ + bool free_elf; + + /* Information for traversing the .debug_pubnames section. This is + an array and separately allocated with malloc. */ + struct pubnames_s + { + Dwarf_Off cu_offset; + Dwarf_Off set_start; + unsigned int cu_header_size; + int address_len; + } *pubnames_sets; + size_t pubnames_nsets; + + /* Search tree for the CUs. */ + void *cu_tree; + Dwarf_Off next_cu_offset; + + /* Search tree and sig8 hash table for .debug_types type units. */ + void *tu_tree; + Dwarf_Off next_tu_offset; + Dwarf_Sig8_Hash sig8_hash; + + /* Search tree for .debug_macro operator tables. */ + void *macro_ops; + + /* Search tree for decoded .debug_line units. */ + void *files_lines; + + /* Address ranges. */ + Dwarf_Aranges *aranges; + + /* Cached info from the CFI section. */ + struct Dwarf_CFI_s *cfi; + + /* Fake loc CU. Used when synthesizing attributes for Dwarf_Ops that + came from a location list entry in dwarf_getlocation_attr. */ + struct Dwarf_CU *fake_loc_cu; + + /* Internal memory handling. This is basically a simplified + reimplementation of obstacks. Unfortunately the standard obstack + implementation is not usable in libraries. */ + struct libdw_memblock + { + size_t size; + size_t remaining; + struct libdw_memblock *prev; + char mem[0]; + } *mem_tail; + + /* Default size of allocated memory blocks. */ + size_t mem_default_size; + + /* Registered OOM handler. */ + Dwarf_OOM oom_handler; +}; + + +/* Abbreviation representation. */ +struct Dwarf_Abbrev +{ + Dwarf_Off offset; + unsigned char *attrp; + unsigned int attrcnt; + unsigned int code; + unsigned int tag; + bool has_children; +}; + +#include "dwarf_abbrev_hash.h" + + +/* Files in line information records. */ +struct Dwarf_Files_s + { + unsigned int ndirs; + unsigned int nfiles; + struct Dwarf_Fileinfo_s + { + char *name; + Dwarf_Word mtime; + Dwarf_Word length; + } info[0]; + /* nfiles of those, followed by char *[ndirs]. */ + }; +typedef struct Dwarf_Fileinfo_s Dwarf_Fileinfo; + + +/* Representation of a row in the line table. */ + +struct Dwarf_Line_s +{ + Dwarf_Files *files; + + Dwarf_Addr addr; + unsigned int file; + int line; + unsigned short int column; + unsigned int is_stmt:1; + unsigned int basic_block:1; + unsigned int end_sequence:1; + unsigned int prologue_end:1; + unsigned int epilogue_begin:1; + /* The remaining bit fields are not flags, but hold values presumed to be + small. All the flags and other bit fields should add up to 48 bits + to give the whole struct a nice round size. */ + unsigned int op_index:8; + unsigned int isa:8; + unsigned int discriminator:24; +}; + +struct Dwarf_Lines_s +{ + size_t nlines; + struct Dwarf_Line_s info[0]; +}; + +/* Representation of address ranges. */ +struct Dwarf_Aranges_s +{ + Dwarf *dbg; + size_t naranges; + + struct Dwarf_Arange_s + { + Dwarf_Addr addr; + Dwarf_Word length; + Dwarf_Off offset; + } info[0]; +}; + + +/* CU representation. */ +struct Dwarf_CU +{ + Dwarf *dbg; + Dwarf_Off start; + Dwarf_Off end; + uint8_t address_size; + uint8_t offset_size; + uint16_t version; + + /* Zero if this is a normal CU. Nonzero if it is a type unit. */ + size_t type_offset; + uint64_t type_sig8; + + /* Hash table for the abbreviations. */ + Dwarf_Abbrev_Hash abbrev_hash; + /* Offset of the first abbreviation. */ + size_t orig_abbrev_offset; + /* Offset past last read abbreviation. */ + size_t last_abbrev_offset; + + /* The srcline information. */ + Dwarf_Lines *lines; + + /* The source file information. */ + Dwarf_Files *files; + + /* Known location lists. */ + void *locs; + + /* Memory boundaries of this CU. */ + void *startp; + void *endp; +}; + +/* Compute the offset of a CU's first DIE from its offset. This + is either: + LEN VER OFFSET ADDR + 4-bytes + 2-bytes + 4-bytes + 1-byte for 32-bit dwarf + 12-bytes + 2-bytes + 8-bytes + 1-byte for 64-bit dwarf + or in .debug_types, SIGNATURE TYPE-OFFSET + 4-bytes + 2-bytes + 4-bytes + 1-byte + 8-bytes + 4-bytes for 32-bit + 12-bytes + 2-bytes + 8-bytes + 1-byte + 8-bytes + 8-bytes for 64-bit + + Note the trick in the computation. If the offset_size is 4 + the '- 4' term changes the '3 *' into a '2 *'. If the + offset_size is 8 it accounts for the 4-byte escape value + used at the start of the length. */ +#define DIE_OFFSET_FROM_CU_OFFSET(cu_offset, offset_size, type_unit) \ + ((type_unit) ? ((cu_offset) + 4 * (offset_size) - 4 + 3 + 8) \ + : ((cu_offset) + 3 * (offset_size) - 4 + 3)) + +#define CUDIE(fromcu) \ + ((Dwarf_Die) \ + { \ + .cu = (fromcu), \ + .addr = ((char *) fromcu->dbg->sectiondata[cu_sec_idx (fromcu)]->d_buf \ + + DIE_OFFSET_FROM_CU_OFFSET ((fromcu)->start, \ + (fromcu)->offset_size, \ + (fromcu)->type_offset != 0)) \ + }) \ + + +/* Prototype of a single .debug_macro operator. */ +typedef struct +{ + Dwarf_Word nforms; + unsigned char const *forms; +} Dwarf_Macro_Op_Proto; + +/* Prototype table. */ +typedef struct +{ + /* Offset of .debug_macro section. */ + Dwarf_Off offset; + + /* Offset of associated .debug_line section. */ + Dwarf_Off line_offset; + + /* The source file information. */ + Dwarf_Files *files; + + /* If this macro unit was opened through dwarf_getmacros or + dwarf_getmacros_die, this caches value of DW_AT_comp_dir, if + present. */ + const char *comp_dir; + + /* Header length. */ + Dwarf_Half header_len; + + uint16_t version; + bool is_64bit; + uint8_t sec_index; /* IDX_debug_macro or IDX_debug_macinfo. */ + + /* Shows where in TABLE each opcode is defined. Since opcode 0 is + never used, it stores index of opcode X in X-1'th element. The + value of 0xff means not stored at all. */ + unsigned char opcodes[255]; + + /* Individual opcode prototypes. */ + Dwarf_Macro_Op_Proto table[]; +} Dwarf_Macro_Op_Table; + +struct Dwarf_Macro_s +{ + Dwarf_Macro_Op_Table *table; + Dwarf_Attribute *attributes; + uint8_t opcode; +}; + +static inline Dwarf_Word +libdw_macro_nforms (Dwarf_Macro *macro) +{ + return macro->table->table[macro->table->opcodes[macro->opcode - 1]].nforms; +} + +/* We have to include the file at this point because the inline + functions access internals of the Dwarf structure. */ +#include "memory-access.h" + + +/* Set error value. */ +extern void __libdw_seterrno (int value) internal_function; + + +/* Memory handling, the easy parts. This macro does not do any locking. */ +#define libdw_alloc(dbg, type, tsize, cnt) \ + ({ struct libdw_memblock *_tail = (dbg)->mem_tail; \ + size_t _required = (tsize) * (cnt); \ + type *_result = (type *) (_tail->mem + (_tail->size - _tail->remaining));\ + size_t _padding = ((__alignof (type) \ + - ((uintptr_t) _result & (__alignof (type) - 1))) \ + & (__alignof (type) - 1)); \ + if (unlikely (_tail->remaining < _required + _padding)) \ + _result = (type *) __libdw_allocate (dbg, _required, __alignof (type));\ + else \ + { \ + _required += _padding; \ + _result = (type *) ((char *) _result + _padding); \ + _tail->remaining -= _required; \ + } \ + _result; }) + +#define libdw_typed_alloc(dbg, type) \ + libdw_alloc (dbg, type, sizeof (type), 1) + +/* Callback to allocate more. */ +extern void *__libdw_allocate (Dwarf *dbg, size_t minsize, size_t align) + __attribute__ ((__malloc__)) __nonnull_attribute__ (1); + +/* Default OOM handler. */ +extern void __libdw_oom (void) __attribute ((noreturn, visibility ("hidden"))); + +#if USE_ZLIB +extern void __libdw_free_zdata (Dwarf *dwarf) internal_function; +#else +# define __libdw_free_zdata(dwarf) ((void) (dwarf)) +#endif + +/* Allocate the internal data for a unit not seen before. */ +extern struct Dwarf_CU *__libdw_intern_next_unit (Dwarf *dbg, bool debug_types) + __nonnull_attribute__ (1) internal_function; + +/* Find CU for given offset. */ +extern struct Dwarf_CU *__libdw_findcu (Dwarf *dbg, Dwarf_Off offset, bool tu) + __nonnull_attribute__ (1) internal_function; + +/* Get abbreviation with given code. */ +extern Dwarf_Abbrev *__libdw_findabbrev (struct Dwarf_CU *cu, + unsigned int code) + __nonnull_attribute__ (1) internal_function; + +/* Get abbreviation at given offset. */ +extern Dwarf_Abbrev *__libdw_getabbrev (Dwarf *dbg, struct Dwarf_CU *cu, + Dwarf_Off offset, size_t *lengthp, + Dwarf_Abbrev *result) + __nonnull_attribute__ (1) internal_function; + +/* Get abbreviation of given DIE, and optionally set *READP to the DIE memory + just past the abbreviation code. */ +static inline Dwarf_Abbrev * +__nonnull_attribute__ (1) +__libdw_dieabbrev (Dwarf_Die *die, const unsigned char **readp) +{ + /* Do we need to get the abbreviation, or need to read after the code? */ + if (die->abbrev == NULL || readp != NULL) + { + /* Get the abbreviation code. */ + unsigned int code; + const unsigned char *addr = die->addr; + get_uleb128 (code, addr, die->cu->endp); + if (readp != NULL) + *readp = addr; + + /* Find the abbreviation. */ + if (die->abbrev == NULL) + die->abbrev = __libdw_findabbrev (die->cu, code); + } + return die->abbrev; +} + +/* Helper functions for form handling. */ +extern size_t __libdw_form_val_compute_len (struct Dwarf_CU *cu, + unsigned int form, + const unsigned char *valp) + __nonnull_attribute__ (1, 3) internal_function; + +/* Find the length of a form attribute. */ +static inline size_t +__nonnull_attribute__ (1, 3) +__libdw_form_val_len (struct Dwarf_CU *cu, unsigned int form, + const unsigned char *valp) +{ + /* Small lookup table of forms with fixed lengths. Absent indexes are + initialized 0, so any truly desired 0 is set to 0x80 and masked. */ + static const uint8_t form_lengths[] = + { + [DW_FORM_flag_present] = 0x80, + [DW_FORM_data1] = 1, [DW_FORM_ref1] = 1, [DW_FORM_flag] = 1, + [DW_FORM_data2] = 2, [DW_FORM_ref2] = 2, + [DW_FORM_data4] = 4, [DW_FORM_ref4] = 4, + [DW_FORM_data8] = 8, [DW_FORM_ref8] = 8, [DW_FORM_ref_sig8] = 8, + }; + + /* Return immediately for forms with fixed lengths. */ + if (form < sizeof form_lengths / sizeof form_lengths[0]) + { + uint8_t len = form_lengths[form]; + if (len != 0) + { + const unsigned char *endp = cu->endp; + len &= 0x7f; /* Mask to allow 0x80 -> 0. */ + if (unlikely (len > (size_t) (endp - valp))) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return -1; + } + return len; + } + } + + /* Other forms require some computation. */ + return __libdw_form_val_compute_len (cu, form, valp); +} + +/* Helper function for DW_FORM_ref* handling. */ +extern int __libdw_formref (Dwarf_Attribute *attr, Dwarf_Off *return_offset) + __nonnull_attribute__ (1, 2) internal_function; + + +/* Helper function to locate attribute. */ +extern unsigned char *__libdw_find_attr (Dwarf_Die *die, + unsigned int search_name, + unsigned int *codep, + unsigned int *formp) + __nonnull_attribute__ (1) internal_function; + +/* Helper function to access integer attribute. */ +extern int __libdw_attr_intval (Dwarf_Die *die, int *valp, int attval) + __nonnull_attribute__ (1, 2) internal_function; + +/* Helper function to walk scopes. */ +struct Dwarf_Die_Chain +{ + Dwarf_Die die; + struct Dwarf_Die_Chain *parent; + bool prune; /* The PREVISIT function can set this. */ +}; +extern int __libdw_visit_scopes (unsigned int depth, + struct Dwarf_Die_Chain *root, + int (*previsit) (unsigned int depth, + struct Dwarf_Die_Chain *, + void *arg), + int (*postvisit) (unsigned int depth, + struct Dwarf_Die_Chain *, + void *arg), + void *arg) + __nonnull_attribute__ (2, 3) internal_function; + +/* Parse a DWARF Dwarf_Block into an array of Dwarf_Op's, + and cache the result (via tsearch). */ +extern int __libdw_intern_expression (Dwarf *dbg, + bool other_byte_order, + unsigned int address_size, + unsigned int ref_size, + void **cache, const Dwarf_Block *block, + bool cfap, bool valuep, + Dwarf_Op **llbuf, size_t *listlen, + int sec_index) + __nonnull_attribute__ (5, 6, 9, 10) internal_function; + +extern Dwarf_Die *__libdw_offdie (Dwarf *dbg, Dwarf_Off offset, + Dwarf_Die *result, bool debug_types) + internal_function; + + +/* Return error code of last failing function call. This value is kept + separately for each thread. */ +extern int __dwarf_errno_internal (void); + + +/* Reader hooks. */ + +/* Relocation hooks return -1 on error (in that case the error code + must already have been set), 0 if there is no relocation and 1 if a + relocation was present.*/ + +static inline int +__libdw_relocate_address (Dwarf *dbg __attribute__ ((unused)), + int sec_index __attribute__ ((unused)), + const void *addr __attribute__ ((unused)), + int width __attribute__ ((unused)), + Dwarf_Addr *val __attribute__ ((unused))) +{ + return 0; +} + +static inline int +__libdw_relocate_offset (Dwarf *dbg __attribute__ ((unused)), + int sec_index __attribute__ ((unused)), + const void *addr __attribute__ ((unused)), + int width __attribute__ ((unused)), + Dwarf_Off *val __attribute__ ((unused))) +{ + return 0; +} + +static inline Elf_Data * +__libdw_checked_get_data (Dwarf *dbg, int sec_index) +{ + Elf_Data *data = dbg->sectiondata[sec_index]; + if (unlikely (data == NULL) + || unlikely (data->d_buf == NULL)) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; + } + return data; +} + +static inline int +__libdw_offset_in_section (Dwarf *dbg, int sec_index, + Dwarf_Off offset, size_t size) +{ + Elf_Data *data = __libdw_checked_get_data (dbg, sec_index); + if (data == NULL) + return -1; + if (unlikely (offset > data->d_size) + || unlikely (data->d_size - offset < size)) + { + __libdw_seterrno (DWARF_E_INVALID_OFFSET); + return -1; + } + + return 0; +} + +static inline bool +__libdw_in_section (Dwarf *dbg, int sec_index, + const void *addr, size_t size) +{ + Elf_Data *data = __libdw_checked_get_data (dbg, sec_index); + if (data == NULL) + return false; + if (unlikely (addr < data->d_buf) + || unlikely (data->d_size - (addr - data->d_buf) < size)) + { + __libdw_seterrno (DWARF_E_INVALID_OFFSET); + return false; + } + + return true; +} + +#define READ_AND_RELOCATE(RELOC_HOOK, VAL) \ + ({ \ + if (!__libdw_in_section (dbg, sec_index, addr, width)) \ + return -1; \ + \ + const unsigned char *orig_addr = addr; \ + if (width == 4) \ + VAL = read_4ubyte_unaligned_inc (dbg, addr); \ + else \ + VAL = read_8ubyte_unaligned_inc (dbg, addr); \ + \ + int status = RELOC_HOOK (dbg, sec_index, orig_addr, width, &VAL); \ + if (status < 0) \ + return status; \ + status > 0; \ + }) + +static inline int +__libdw_read_address_inc (Dwarf *dbg, + int sec_index, const unsigned char **addrp, + int width, Dwarf_Addr *ret) +{ + const unsigned char *addr = *addrp; + READ_AND_RELOCATE (__libdw_relocate_address, (*ret)); + *addrp = addr; + return 0; +} + +static inline int +__libdw_read_address (Dwarf *dbg, + int sec_index, const unsigned char *addr, + int width, Dwarf_Addr *ret) +{ + READ_AND_RELOCATE (__libdw_relocate_address, (*ret)); + return 0; +} + +static inline int +__libdw_read_offset_inc (Dwarf *dbg, + int sec_index, const unsigned char **addrp, + int width, Dwarf_Off *ret, int sec_ret, + size_t size) +{ + const unsigned char *addr = *addrp; + READ_AND_RELOCATE (__libdw_relocate_offset, (*ret)); + *addrp = addr; + return __libdw_offset_in_section (dbg, sec_ret, *ret, size); +} + +static inline int +__libdw_read_offset (Dwarf *dbg, Dwarf *dbg_ret, + int sec_index, const unsigned char *addr, + int width, Dwarf_Off *ret, int sec_ret, + size_t size) +{ + READ_AND_RELOCATE (__libdw_relocate_offset, (*ret)); + return __libdw_offset_in_section (dbg_ret, sec_ret, *ret, size); +} + +static inline size_t +cu_sec_idx (struct Dwarf_CU *cu) +{ + return cu->type_offset == 0 ? IDX_debug_info : IDX_debug_types; +} + +/* Read up begin/end pair and increment read pointer. + - If it's normal range record, set up *BEGINP and *ENDP and return 0. + - If it's base address selection record, set up *BASEP and return 1. + - If it's end of rangelist, don't set anything and return 2 + - If an error occurs, don't set anything and return <0. */ +int __libdw_read_begin_end_pair_inc (Dwarf *dbg, int sec_index, + unsigned char **addr, int width, + Dwarf_Addr *beginp, Dwarf_Addr *endp, + Dwarf_Addr *basep) + internal_function; + +unsigned char * __libdw_formptr (Dwarf_Attribute *attr, int sec_index, + int err_nodata, unsigned char **endpp, + Dwarf_Off *offsetp) + internal_function; + +/* Fills in the given attribute to point at an empty location expression. */ +void __libdw_empty_loc_attr (Dwarf_Attribute *attr) + internal_function; + +/* Load .debug_line unit at DEBUG_LINE_OFFSET. COMP_DIR is a value of + DW_AT_comp_dir or NULL if that attribute is not available. Caches + the loaded unit and optionally set *LINESP and/or *FILESP (if not + NULL) with loaded information. Returns 0 for success or a negative + value for failure. */ +int __libdw_getsrclines (Dwarf *dbg, Dwarf_Off debug_line_offset, + const char *comp_dir, unsigned address_size, + Dwarf_Lines **linesp, Dwarf_Files **filesp) + internal_function + __nonnull_attribute__ (1); + +/* Load and return value of DW_AT_comp_dir from CUDIE. */ +const char *__libdw_getcompdir (Dwarf_Die *cudie); + + +/* Aliases to avoid PLTs. */ +INTDECL (dwarf_aggregate_size) +INTDECL (dwarf_attr) +INTDECL (dwarf_attr_integrate) +INTDECL (dwarf_begin) +INTDECL (dwarf_begin_elf) +INTDECL (dwarf_child) +INTDECL (dwarf_dieoffset) +INTDECL (dwarf_diename) +INTDECL (dwarf_end) +INTDECL (dwarf_entrypc) +INTDECL (dwarf_errmsg) +INTDECL (dwarf_formaddr) +INTDECL (dwarf_formblock) +INTDECL (dwarf_formref_die) +INTDECL (dwarf_formsdata) +INTDECL (dwarf_formstring) +INTDECL (dwarf_formudata) +INTDECL (dwarf_getalt) +INTDECL (dwarf_getarange_addr) +INTDECL (dwarf_getarangeinfo) +INTDECL (dwarf_getaranges) +INTDECL (dwarf_getlocation_die) +INTDECL (dwarf_getsrcfiles) +INTDECL (dwarf_getsrclines) +INTDECL (dwarf_hasattr) +INTDECL (dwarf_haschildren) +INTDECL (dwarf_haspc) +INTDECL (dwarf_highpc) +INTDECL (dwarf_lowpc) +INTDECL (dwarf_nextcu) +INTDECL (dwarf_next_unit) +INTDECL (dwarf_offdie) +INTDECL (dwarf_peel_type) +INTDECL (dwarf_ranges) +INTDECL (dwarf_setalt) +INTDECL (dwarf_siblingof) +INTDECL (dwarf_srclang) +INTDECL (dwarf_tag) + +#endif /* libdwP.h */ diff --git a/3rdparty/elfutils/libdw/libdw_alloc.c b/3rdparty/elfutils/libdw/libdw_alloc.c new file mode 100644 index 0000000..a3b7958 --- /dev/null +++ b/3rdparty/elfutils/libdw/libdw_alloc.c @@ -0,0 +1,78 @@ +/* Memory handling for libdw. + Copyright (C) 2003, 2004, 2006 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <error.h> +#include <errno.h> +#include <stdlib.h> +#include <sys/param.h> +#include "libdwP.h" + + +void * +__libdw_allocate (Dwarf *dbg, size_t minsize, size_t align) +{ + size_t size = MAX (dbg->mem_default_size, + (align - 1 + + 2 * minsize + offsetof (struct libdw_memblock, mem))); + struct libdw_memblock *newp = malloc (size); + if (newp == NULL) + dbg->oom_handler (); + + uintptr_t result = ((uintptr_t) newp->mem + align - 1) & ~(align - 1); + + newp->size = size - offsetof (struct libdw_memblock, mem); + newp->remaining = (uintptr_t) newp + size - (result + minsize); + + newp->prev = dbg->mem_tail; + dbg->mem_tail = newp; + + return (void *) result; +} + + +Dwarf_OOM +dwarf_new_oom_handler (Dwarf *dbg, Dwarf_OOM handler) +{ + Dwarf_OOM old = dbg->oom_handler; + dbg->oom_handler = handler; + return old; +} + + +void +__attribute ((noreturn, visibility ("hidden"))) +__libdw_oom (void) +{ + while (1) + error (EXIT_FAILURE, ENOMEM, "libdw"); +} diff --git a/3rdparty/elfutils/libdw/libdw_findcu.c b/3rdparty/elfutils/libdw/libdw_findcu.c new file mode 100644 index 0000000..d8da2e3 --- /dev/null +++ b/3rdparty/elfutils/libdw/libdw_findcu.c @@ -0,0 +1,172 @@ +/* Find CU for given offset. + Copyright (C) 2003-2010, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <search.h> +#include "libdwP.h" + +static int +findcu_cb (const void *arg1, const void *arg2) +{ + struct Dwarf_CU *cu1 = (struct Dwarf_CU *) arg1; + struct Dwarf_CU *cu2 = (struct Dwarf_CU *) arg2; + + /* Find out which of the two arguments is the search value. It has + end offset 0. */ + if (cu1->end == 0) + { + if (cu1->start < cu2->start) + return -1; + if (cu1->start >= cu2->end) + return 1; + } + else + { + if (cu2->start < cu1->start) + return 1; + if (cu2->start >= cu1->end) + return -1; + } + + return 0; +} + +struct Dwarf_CU * +internal_function +__libdw_intern_next_unit (dbg, debug_types) + Dwarf *dbg; + bool debug_types; +{ + Dwarf_Off *const offsetp + = debug_types ? &dbg->next_tu_offset : &dbg->next_cu_offset; + void **tree = debug_types ? &dbg->tu_tree : &dbg->cu_tree; + + Dwarf_Off oldoff = *offsetp; + uint16_t version; + uint8_t address_size; + uint8_t offset_size; + Dwarf_Off abbrev_offset; + uint64_t type_sig8 = 0; + Dwarf_Off type_offset = 0; + + if (INTUSE(dwarf_next_unit) (dbg, oldoff, offsetp, NULL, + &version, &abbrev_offset, + &address_size, &offset_size, + debug_types ? &type_sig8 : NULL, + debug_types ? &type_offset : NULL) != 0) + /* No more entries. */ + return NULL; + + /* We only know how to handle the DWARF version 2 through 4 formats. */ + if (unlikely (version < 2) || unlikely (version > 4)) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; + } + + /* Invalid or truncated debug section data? */ + Elf_Data *data = dbg->sectiondata[debug_types + ? IDX_debug_types : IDX_debug_info]; + if (unlikely (*offsetp > data->d_size)) + *offsetp = data->d_size; + + /* Create an entry for this CU. */ + struct Dwarf_CU *newp = libdw_typed_alloc (dbg, struct Dwarf_CU); + + newp->dbg = dbg; + newp->start = oldoff; + newp->end = *offsetp; + newp->address_size = address_size; + newp->offset_size = offset_size; + newp->version = version; + newp->type_sig8 = type_sig8; + newp->type_offset = type_offset; + Dwarf_Abbrev_Hash_init (&newp->abbrev_hash, 41); + newp->orig_abbrev_offset = newp->last_abbrev_offset = abbrev_offset; + newp->lines = NULL; + newp->locs = NULL; + + if (debug_types) + Dwarf_Sig8_Hash_insert (&dbg->sig8_hash, type_sig8, newp); + + newp->startp = data->d_buf + newp->start; + newp->endp = data->d_buf + newp->end; + + /* Add the new entry to the search tree. */ + if (tsearch (newp, tree, findcu_cb) == NULL) + { + /* Something went wrong. Undo the operation. */ + *offsetp = oldoff; + __libdw_seterrno (DWARF_E_NOMEM); + return NULL; + } + + return newp; +} + +struct Dwarf_CU * +__libdw_findcu (dbg, start, debug_types) + Dwarf *dbg; + Dwarf_Off start; + bool debug_types; +{ + void **tree = debug_types ? &dbg->tu_tree : &dbg->cu_tree; + Dwarf_Off *next_offset + = debug_types ? &dbg->next_tu_offset : &dbg->next_cu_offset; + + /* Maybe we already know that CU. */ + struct Dwarf_CU fake = { .start = start, .end = 0 }; + struct Dwarf_CU **found = tfind (&fake, tree, findcu_cb); + if (found != NULL) + return *found; + + if (start < *next_offset) + { + __libdw_seterrno (DWARF_E_INVALID_DWARF); + return NULL; + } + + /* No. Then read more CUs. */ + while (1) + { + struct Dwarf_CU *newp = __libdw_intern_next_unit (dbg, debug_types); + if (newp == NULL) + return NULL; + + /* Is this the one we are looking for? */ + if (start < *next_offset) + // XXX Match exact offset. + return newp; + } + /* NOTREACHED */ +} diff --git a/3rdparty/elfutils/libdw/libdw_form.c b/3rdparty/elfutils/libdw/libdw_form.c new file mode 100644 index 0000000..72e2390 --- /dev/null +++ b/3rdparty/elfutils/libdw/libdw_form.c @@ -0,0 +1,132 @@ +/* Helper functions for form handling. + Copyright (C) 2003-2009, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> +#include <string.h> + +#include "libdwP.h" + + +size_t +internal_function +__libdw_form_val_compute_len (struct Dwarf_CU *cu, unsigned int form, + const unsigned char *valp) +{ + const unsigned char *startp = valp; + const unsigned char *endp = cu->endp; + Dwarf_Word u128; + size_t result; + + /* NB: This doesn't cover constant form lengths, which are + already handled by the inlined __libdw_form_val_len. */ + switch (form) + { + case DW_FORM_addr: + result = cu->address_size; + break; + + case DW_FORM_ref_addr: + result = cu->version == 2 ? cu->address_size : cu->offset_size; + break; + + case DW_FORM_strp: + case DW_FORM_sec_offset: + case DW_FORM_GNU_ref_alt: + case DW_FORM_GNU_strp_alt: + result = cu->offset_size; + break; + + case DW_FORM_block1: + if (unlikely ((size_t) (endp - startp) < 1)) + goto invalid; + result = *valp + 1; + break; + + case DW_FORM_block2: + if (unlikely ((size_t) (endp - startp) < 2)) + goto invalid; + result = read_2ubyte_unaligned (cu->dbg, valp) + 2; + break; + + case DW_FORM_block4: + if (unlikely ((size_t) (endp - startp) < 4)) + goto invalid; + result = read_4ubyte_unaligned (cu->dbg, valp) + 4; + break; + + case DW_FORM_block: + case DW_FORM_exprloc: + get_uleb128 (u128, valp, endp); + result = u128 + (valp - startp); + break; + + case DW_FORM_string: + { + const unsigned char *endstrp = memchr (valp, '\0', + (size_t) (endp - startp)); + if (unlikely (endstrp == NULL)) + goto invalid; + result = (size_t) (endstrp - startp) + 1; + break; + } + + case DW_FORM_sdata: + case DW_FORM_udata: + case DW_FORM_ref_udata: + get_uleb128 (u128, valp, endp); + result = valp - startp; + break; + + case DW_FORM_indirect: + get_uleb128 (u128, valp, endp); + // XXX Is this really correct? + result = __libdw_form_val_len (cu, u128, valp); + if (result != (size_t) -1) + result += valp - startp; + else + return (size_t) -1; + break; + + default: + goto invalid; + } + + if (unlikely (result > (size_t) (endp - startp))) + { + invalid: + __libdw_seterrno (DWARF_E_INVALID_DWARF); + result = (size_t) -1; + } + + return result; +} diff --git a/3rdparty/elfutils/libdw/libdw_visit_scopes.c b/3rdparty/elfutils/libdw/libdw_visit_scopes.c new file mode 100644 index 0000000..487375d --- /dev/null +++ b/3rdparty/elfutils/libdw/libdw_visit_scopes.c @@ -0,0 +1,147 @@ +/* Helper functions to descend DWARF scope trees. + Copyright (C) 2005,2006,2007 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwP.h" +#include <dwarf.h> + + +static bool +may_have_scopes (Dwarf_Die *die) +{ + switch (INTUSE(dwarf_tag) (die)) + { + /* DIEs with addresses we can try to match. */ + case DW_TAG_compile_unit: + case DW_TAG_module: + case DW_TAG_lexical_block: + case DW_TAG_with_stmt: + case DW_TAG_catch_block: + case DW_TAG_try_block: + case DW_TAG_entry_point: + case DW_TAG_inlined_subroutine: + case DW_TAG_subprogram: + return true; + + /* DIEs without addresses that can own DIEs with addresses. */ + case DW_TAG_namespace: + case DW_TAG_class_type: + case DW_TAG_structure_type: + return true; + + /* Other DIEs we have no reason to descend. */ + default: + break; + } + return false; +} + +int +__libdw_visit_scopes (depth, root, previsit, postvisit, arg) + unsigned int depth; + struct Dwarf_Die_Chain *root; + int (*previsit) (unsigned int depth, struct Dwarf_Die_Chain *, void *); + int (*postvisit) (unsigned int depth, struct Dwarf_Die_Chain *, void *); + void *arg; +{ + struct Dwarf_Die_Chain child; + int ret; + + child.parent = root; + if ((ret = INTUSE(dwarf_child) (&root->die, &child.die)) != 0) + return ret < 0 ? -1 : 0; // Having zero children is legal. + + inline int recurse (void) + { + return __libdw_visit_scopes (depth + 1, &child, + previsit, postvisit, arg); + } + + inline int walk_children () + { + do + { + /* For an imported unit, it is logically as if the children of + that unit are siblings of the other children. So don't do + a full recursion into the imported unit, but just walk the + children in place before moving to the next real child. */ + while (INTUSE(dwarf_tag) (&child.die) == DW_TAG_imported_unit) + { + Dwarf_Die orig_child_die = child.die; + Dwarf_Attribute attr_mem; + Dwarf_Attribute *attr = INTUSE(dwarf_attr) (&child.die, + DW_AT_import, + &attr_mem); + if (INTUSE(dwarf_formref_die) (attr, &child.die) != NULL + && INTUSE(dwarf_child) (&child.die, &child.die) == 0) + { + int result = walk_children (); + if (result != DWARF_CB_OK) + return result; + } + + /* Any "real" children left? */ + if ((ret = INTUSE(dwarf_siblingof) (&orig_child_die, + &child.die)) != 0) + return ret < 0 ? -1 : 0; + }; + + child.prune = false; + + if (previsit != NULL) + { + int result = (*previsit) (depth + 1, &child, arg); + if (result != DWARF_CB_OK) + return result; + } + + if (!child.prune && may_have_scopes (&child.die) + && INTUSE(dwarf_haschildren) (&child.die)) + { + int result = recurse (); + if (result != DWARF_CB_OK) + return result; + } + + if (postvisit != NULL) + { + int result = (*postvisit) (depth + 1, &child, arg); + if (result != DWARF_CB_OK) + return result; + } + } + while ((ret = INTUSE(dwarf_siblingof) (&child.die, &child.die)) == 0); + + return ret < 0 ? -1 : 0; + } + + return walk_children (); +} diff --git a/3rdparty/elfutils/libdw/memory-access.h b/3rdparty/elfutils/libdw/memory-access.h new file mode 100644 index 0000000..a53f791 --- /dev/null +++ b/3rdparty/elfutils/libdw/memory-access.h @@ -0,0 +1,272 @@ +/* Unaligned memory access functionality. + Copyright (C) 2000-2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2001. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifndef _MEMORY_ACCESS_H +#define _MEMORY_ACCESS_H 1 + +#include <byteswap.h> +#include <limits.h> +#include <stdint.h> + + +/* Number decoding macros. See 7.6 Variable Length Data. */ + +#define len_leb128(var) ((8 * sizeof (var) + 6) / 7) + +static inline size_t +__libdw_max_len_leb128 (const unsigned char *addr, const unsigned char *end) +{ + const size_t type_len = len_leb128 (uint64_t); + const size_t pointer_len = likely (addr < end) ? end - addr : 0; + return likely (type_len <= pointer_len) ? type_len : pointer_len; +} + +#define get_uleb128_step(var, addr, nth) \ + do { \ + unsigned char __b = *(addr)++; \ + (var) |= (typeof (var)) (__b & 0x7f) << ((nth) * 7); \ + if (likely ((__b & 0x80) == 0)) \ + return (var); \ + } while (0) + +static inline uint64_t +__libdw_get_uleb128 (const unsigned char **addrp, const unsigned char *end) +{ + uint64_t acc = 0; + + /* Unroll the first step to help the compiler optimize + for the common single-byte case. */ + get_uleb128_step (acc, *addrp, 0); + + const size_t max = __libdw_max_len_leb128 (*addrp - 1, end); + for (size_t i = 1; i < max; ++i) + get_uleb128_step (acc, *addrp, i); + /* Other implementations set VALUE to UINT_MAX in this + case. So we better do this as well. */ + return UINT64_MAX; +} + +/* Note, addr needs to me smaller than end. */ +#define get_uleb128(var, addr, end) ((var) = __libdw_get_uleb128 (&(addr), end)) + +/* The signed case is similar, but we sign-extend the result. */ + +#define get_sleb128_step(var, addr, nth) \ + do { \ + unsigned char __b = *(addr)++; \ + if (likely ((__b & 0x80) == 0)) \ + { \ + struct { signed int i:7; } __s = { .i = __b }; \ + (var) |= (typeof (var)) __s.i * ((typeof (var)) 1 << ((nth) * 7)); \ + return (var); \ + } \ + (var) |= (typeof (var)) (__b & 0x7f) << ((nth) * 7); \ + } while (0) + +static inline int64_t +__libdw_get_sleb128 (const unsigned char **addrp, const unsigned char *end) +{ + int64_t acc = 0; + + /* Unroll the first step to help the compiler optimize + for the common single-byte case. */ + get_sleb128_step (acc, *addrp, 0); + + const size_t max = __libdw_max_len_leb128 (*addrp - 1, end); + for (size_t i = 1; i < max; ++i) + get_sleb128_step (acc, *addrp, i); + /* Other implementations set VALUE to INT_MAX in this + case. So we better do this as well. */ + return INT64_MAX; +} + +#define get_sleb128(var, addr, end) ((var) = __libdw_get_sleb128 (&(addr), end)) + + +/* We use simple memory access functions in case the hardware allows it. + The caller has to make sure we don't have alias problems. */ +#if ALLOW_UNALIGNED + +# define read_2ubyte_unaligned(Dbg, Addr) \ + (unlikely ((Dbg)->other_byte_order) \ + ? bswap_16 (*((const uint16_t *) (Addr))) \ + : *((const uint16_t *) (Addr))) +# define read_2sbyte_unaligned(Dbg, Addr) \ + (unlikely ((Dbg)->other_byte_order) \ + ? (int16_t) bswap_16 (*((const int16_t *) (Addr))) \ + : *((const int16_t *) (Addr))) + +# define read_4ubyte_unaligned_noncvt(Addr) \ + *((const uint32_t *) (Addr)) +# define read_4ubyte_unaligned(Dbg, Addr) \ + (unlikely ((Dbg)->other_byte_order) \ + ? bswap_32 (*((const uint32_t *) (Addr))) \ + : *((const uint32_t *) (Addr))) +# define read_4sbyte_unaligned(Dbg, Addr) \ + (unlikely ((Dbg)->other_byte_order) \ + ? (int32_t) bswap_32 (*((const int32_t *) (Addr))) \ + : *((const int32_t *) (Addr))) + +# define read_8ubyte_unaligned_noncvt(Addr) \ + *((const uint64_t *) (Addr)) +# define read_8ubyte_unaligned(Dbg, Addr) \ + (unlikely ((Dbg)->other_byte_order) \ + ? bswap_64 (*((const uint64_t *) (Addr))) \ + : *((const uint64_t *) (Addr))) +# define read_8sbyte_unaligned(Dbg, Addr) \ + (unlikely ((Dbg)->other_byte_order) \ + ? (int64_t) bswap_64 (*((const int64_t *) (Addr))) \ + : *((const int64_t *) (Addr))) + +#else + +union unaligned + { + void *p; + uint16_t u2; + uint32_t u4; + uint64_t u8; + int16_t s2; + int32_t s4; + int64_t s8; + } __attribute__ ((packed)); + +# define read_2ubyte_unaligned(Dbg, Addr) \ + read_2ubyte_unaligned_1 ((Dbg)->other_byte_order, (Addr)) +# define read_2sbyte_unaligned(Dbg, Addr) \ + read_2sbyte_unaligned_1 ((Dbg)->other_byte_order, (Addr)) +# define read_4ubyte_unaligned(Dbg, Addr) \ + read_4ubyte_unaligned_1 ((Dbg)->other_byte_order, (Addr)) +# define read_4sbyte_unaligned(Dbg, Addr) \ + read_4sbyte_unaligned_1 ((Dbg)->other_byte_order, (Addr)) +# define read_8ubyte_unaligned(Dbg, Addr) \ + read_8ubyte_unaligned_1 ((Dbg)->other_byte_order, (Addr)) +# define read_8sbyte_unaligned(Dbg, Addr) \ + read_8sbyte_unaligned_1 ((Dbg)->other_byte_order, (Addr)) + +static inline uint16_t +read_2ubyte_unaligned_1 (bool other_byte_order, const void *p) +{ + const union unaligned *up = p; + if (unlikely (other_byte_order)) + return bswap_16 (up->u2); + return up->u2; +} +static inline int16_t +read_2sbyte_unaligned_1 (bool other_byte_order, const void *p) +{ + const union unaligned *up = p; + if (unlikely (other_byte_order)) + return (int16_t) bswap_16 (up->u2); + return up->s2; +} + +static inline uint32_t +read_4ubyte_unaligned_noncvt (const void *p) +{ + const union unaligned *up = p; + return up->u4; +} +static inline uint32_t +read_4ubyte_unaligned_1 (bool other_byte_order, const void *p) +{ + const union unaligned *up = p; + if (unlikely (other_byte_order)) + return bswap_32 (up->u4); + return up->u4; +} +static inline int32_t +read_4sbyte_unaligned_1 (bool other_byte_order, const void *p) +{ + const union unaligned *up = p; + if (unlikely (other_byte_order)) + return (int32_t) bswap_32 (up->u4); + return up->s4; +} + +static inline uint64_t +read_8ubyte_unaligned_noncvt (const void *p) +{ + const union unaligned *up = p; + return up->u8; +} +static inline uint64_t +read_8ubyte_unaligned_1 (bool other_byte_order, const void *p) +{ + const union unaligned *up = p; + if (unlikely (other_byte_order)) + return bswap_64 (up->u8); + return up->u8; +} +static inline int64_t +read_8sbyte_unaligned_1 (bool other_byte_order, const void *p) +{ + const union unaligned *up = p; + if (unlikely (other_byte_order)) + return (int64_t) bswap_64 (up->u8); + return up->s8; +} + +#endif /* allow unaligned */ + + +#define read_2ubyte_unaligned_inc(Dbg, Addr) \ + ({ uint16_t t_ = read_2ubyte_unaligned (Dbg, Addr); \ + Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 2); \ + t_; }) +#define read_2sbyte_unaligned_inc(Dbg, Addr) \ + ({ int16_t t_ = read_2sbyte_unaligned (Dbg, Addr); \ + Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 2); \ + t_; }) + +#define read_4ubyte_unaligned_inc(Dbg, Addr) \ + ({ uint32_t t_ = read_4ubyte_unaligned (Dbg, Addr); \ + Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 4); \ + t_; }) +#define read_4sbyte_unaligned_inc(Dbg, Addr) \ + ({ int32_t t_ = read_4sbyte_unaligned (Dbg, Addr); \ + Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 4); \ + t_; }) + +#define read_8ubyte_unaligned_inc(Dbg, Addr) \ + ({ uint64_t t_ = read_8ubyte_unaligned (Dbg, Addr); \ + Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 8); \ + t_; }) +#define read_8sbyte_unaligned_inc(Dbg, Addr) \ + ({ int64_t t_ = read_8sbyte_unaligned (Dbg, Addr); \ + Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 8); \ + t_; }) + + +#define read_addr_unaligned_inc(Nbytes, Dbg, Addr) \ + (assert ((Nbytes) == 4 || (Nbytes) == 8), \ + ((Nbytes) == 4 ? read_4ubyte_unaligned_inc (Dbg, Addr) \ + : read_8ubyte_unaligned_inc (Dbg, Addr))) + +#endif /* memory-access.h */ diff --git a/3rdparty/elfutils/libdwelf/dwelf_dwarf_gnu_debugaltlink.c b/3rdparty/elfutils/libdwelf/dwelf_dwarf_gnu_debugaltlink.c new file mode 100644 index 0000000..b8285d0 --- /dev/null +++ b/3rdparty/elfutils/libdwelf/dwelf_dwarf_gnu_debugaltlink.c @@ -0,0 +1,62 @@ +/* Returns the file name and build ID stored in the .gnu_altdebuglink if found. + Copyright (C) 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwelfP.h" + +ssize_t +dwelf_dwarf_gnu_debugaltlink (Dwarf *dwarf, + const char **name_p, + const void **build_idp) +{ + Elf_Data *data = dwarf->sectiondata[IDX_gnu_debugaltlink]; + if (data == NULL) + { + return 0; + } + + const void *ptr = memchr (data->d_buf, '\0', data->d_size); + if (ptr == NULL) + { + __libdw_seterrno (DWARF_E_INVALID_ELF); + return -1; + } + size_t build_id_len = data->d_size - (ptr - data->d_buf + 1); + if (build_id_len == 0 || (size_t) (ssize_t) build_id_len != build_id_len) + { + __libdw_seterrno (DWARF_E_INVALID_ELF); + return -1; + } + *name_p = data->d_buf; + *build_idp = ptr + 1; + return build_id_len; +} +INTDEF(dwelf_dwarf_gnu_debugaltlink) diff --git a/3rdparty/elfutils/libdwelf/dwelf_elf_gnu_build_id.c b/3rdparty/elfutils/libdwelf/dwelf_elf_gnu_build_id.c new file mode 100644 index 0000000..1ed501d --- /dev/null +++ b/3rdparty/elfutils/libdwelf/dwelf_elf_gnu_build_id.c @@ -0,0 +1,147 @@ +/* Returns the build id if found in a NT_GNU_BUILD_ID note. + Copyright (C) 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwelfP.h" +#include "libdwflP.h" + +#define NO_VADDR ((GElf_Addr) -1l) + +/* Defined here for reuse. The dwelf interface doesn't care about the + address of the note, but libdwfl does. */ +static int +find_elf_build_id (Dwfl_Module *mod, int e_type, Elf *elf, + const void **build_id_bits, GElf_Addr *build_id_elfaddr, + int *build_id_len) +{ + int check_notes (Elf_Data *data, GElf_Addr data_elfaddr) + { + size_t pos = 0; + GElf_Nhdr nhdr; + size_t name_pos; + size_t desc_pos; + while ((pos = gelf_getnote (data, pos, &nhdr, &name_pos, &desc_pos)) > 0) + if (nhdr.n_type == NT_GNU_BUILD_ID + && nhdr.n_namesz == sizeof "GNU" && !memcmp (data->d_buf + name_pos, + "GNU", sizeof "GNU")) + { + *build_id_bits = data->d_buf + desc_pos; + *build_id_elfaddr = (data_elfaddr == NO_VADDR + ? 0 : data_elfaddr + desc_pos); + *build_id_len = nhdr.n_descsz; + return 1; + } + return 0; + } + + size_t shstrndx = SHN_UNDEF; + int result = 0; + + Elf_Scn *scn = elf_nextscn (elf, NULL); + + if (scn == NULL) + { + /* No sections, have to look for phdrs. */ + size_t phnum; + if (unlikely (elf_getphdrnum (elf, &phnum) != 0)) + { + if (mod != NULL) + __libdwfl_seterrno (DWFL_E_LIBELF); + return -1; + } + for (size_t i = 0; result == 0 && i < phnum; ++i) + { + GElf_Phdr phdr_mem; + GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem); + if (likely (phdr != NULL) && phdr->p_type == PT_NOTE) + result = check_notes (elf_getdata_rawchunk (elf, + phdr->p_offset, + phdr->p_filesz, + ELF_T_NHDR), + phdr->p_vaddr); + } + } + else + do + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + if (likely (shdr != NULL) && shdr->sh_type == SHT_NOTE) + { + /* Determine the right sh_addr in this module. */ + GElf_Addr vaddr = 0; + if (!(shdr->sh_flags & SHF_ALLOC)) + vaddr = NO_VADDR; + else if (mod == NULL || e_type != ET_REL) + vaddr = shdr->sh_addr; + else if (__libdwfl_relocate_value (mod, elf, &shstrndx, + elf_ndxscn (scn), &vaddr)) + vaddr = NO_VADDR; + result = check_notes (elf_getdata (scn, NULL), vaddr); + } + } + while (result == 0 && (scn = elf_nextscn (elf, scn)) != NULL); + + return result; +} + +int +internal_function +__libdwfl_find_elf_build_id (Dwfl_Module *mod, Elf *elf, + const void **build_id_bits, + GElf_Addr *build_id_elfaddr, int *build_id_len) +{ + GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem); + if (unlikely (ehdr == NULL)) + { + __libdwfl_seterrno (DWFL_E_LIBELF); + return -1; + } + // MOD->E_TYPE is zero here. + assert (ehdr->e_type != ET_REL || mod != NULL); + + return find_elf_build_id (mod, ehdr->e_type, elf, + build_id_bits, build_id_elfaddr, build_id_len); +} + +ssize_t +dwelf_elf_gnu_build_id (Elf *elf, const void **build_idp) +{ + GElf_Addr build_id_elfaddr; + int build_id_len; + int result = find_elf_build_id (NULL, ET_NONE, elf, build_idp, + &build_id_elfaddr, &build_id_len); + if (result > 0) + return build_id_len; + + return result; +} +INTDEF(dwelf_elf_gnu_build_id) diff --git a/3rdparty/elfutils/libdwelf/dwelf_elf_gnu_debuglink.c b/3rdparty/elfutils/libdwelf/dwelf_elf_gnu_debuglink.c new file mode 100644 index 0000000..6e22cf6 --- /dev/null +++ b/3rdparty/elfutils/libdwelf/dwelf_elf_gnu_debuglink.c @@ -0,0 +1,99 @@ +/* Returns the file name and crc stored in the .gnu_debuglink if found. + Copyright (C) 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwelfP.h" + +const char * +dwelf_elf_gnu_debuglink (Elf *elf, GElf_Word *crc) +{ + size_t shstrndx; + if (elf_getshdrstrndx (elf, &shstrndx) < 0) + return NULL; + + Elf_Scn *scn = NULL; + while ((scn = elf_nextscn (elf, scn)) != NULL) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + if (shdr == NULL) + return NULL; + + const char *name = elf_strptr (elf, shstrndx, shdr->sh_name); + if (name == NULL) + return NULL; + + if (!strcmp (name, ".gnu_debuglink")) + break; + } + + if (scn == NULL) + return NULL; + + /* Found the .gnu_debuglink section. Extract its contents. */ + Elf_Data *rawdata = elf_rawdata (scn, NULL); + if (rawdata == NULL || rawdata->d_buf == NULL) + return NULL; + + /* The CRC comes after the zero-terminated file name, + (aligned up to 4 bytes) at the end of the section data. */ + if (rawdata->d_size <= sizeof *crc + || memchr (rawdata->d_buf, '\0', rawdata->d_size - sizeof *crc) == NULL) + return NULL; + + Elf_Data crcdata = + { + .d_type = ELF_T_WORD, + .d_buf = crc, + .d_size = sizeof *crc, + .d_version = EV_CURRENT, + }; + Elf_Data conv = + { + .d_type = ELF_T_WORD, + .d_buf = rawdata->d_buf + rawdata->d_size - sizeof *crc, + .d_size = sizeof *crc, + .d_version = EV_CURRENT, + }; + + GElf_Ehdr ehdr_mem; + GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem); + if (ehdr == NULL) + return NULL; + + Elf_Data *d = gelf_xlatetom (elf, &crcdata, &conv, ehdr->e_ident[EI_DATA]); + if (d == NULL) + return NULL; + assert (d == &crcdata); + + return rawdata->d_buf; +} +INTDEF(dwelf_elf_gnu_debuglink) diff --git a/3rdparty/elfutils/libdwelf/dwelfheaders.pri b/3rdparty/elfutils/libdwelf/dwelfheaders.pri new file mode 100644 index 0000000..d214fae --- /dev/null +++ b/3rdparty/elfutils/libdwelf/dwelfheaders.pri @@ -0,0 +1,5 @@ +HEADERS += \ + $$PWD/libdwelf.h \ + $$PWD/libdwelfP.h + +INCLUDEPATH += $$PWD diff --git a/3rdparty/elfutils/libdwelf/libdwelf.h b/3rdparty/elfutils/libdwelf/libdwelf.h new file mode 100644 index 0000000..e16dc0f --- /dev/null +++ b/3rdparty/elfutils/libdwelf/libdwelf.h @@ -0,0 +1,72 @@ +/* Interfaces for libdwelf. DWARF ELF Low-level Functions. + Copyright (C) 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifndef _LIBDWELF_H +#define _LIBDWELF_H 1 + +#include "libdw.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* DWARF ELF Low-level Functions (dwelf). + Functions starting with dwelf_elf will take a (libelf) Elf object as + first argument and might set elf_errno on error. Functions starting + with dwelf_dwarf will take a (libdw) Dwarf object as first argument + and might set dwarf_errno on error. */ + +/* Returns the name and the CRC32 of the separate debug file from the + .gnu_debuglink section if found in the ELF. Return NULL if the ELF + file didn't have a .gnu_debuglink section, had malformed data in the + section or some other error occured. */ +extern const char *dwelf_elf_gnu_debuglink (Elf *elf, GElf_Word *crc); + +/* Returns the name and build ID from the .gnu_debugaltlink section if + found in the ELF. On success, pointers to the name and build ID + are written to *NAMEP and *BUILDID_P, and the positive length of + the build ID is returned. Returns 0 if the ELF lacks a + .gnu_debugaltlink section. Returns -1 in case of malformed data or + other errors. */ +extern ssize_t dwelf_dwarf_gnu_debugaltlink (Dwarf *dwarf, + const char **namep, + const void **build_idp); + +/* Returns the build ID as found in a NT_GNU_BUILD_ID note from either + a SHT_NOTE section or from a PT_NOTE segment if the ELF file + doesn't contain any section headers. On success a pointer to the + build ID is written to *BUILDID_P, and the positive length of the + build ID is returned. Returns 0 if the ELF lacks a NT_GNU_BUILD_ID + note. Returns -1 in case of malformed data or other errors. */ +extern ssize_t dwelf_elf_gnu_build_id (Elf *elf, const void **build_idp); + +#ifdef __cplusplus +} +#endif + +#endif /* libdwelf.h */ diff --git a/3rdparty/elfutils/libdwelf/libdwelf.pro b/3rdparty/elfutils/libdwelf/libdwelf.pro new file mode 100644 index 0000000..f3736a0 --- /dev/null +++ b/3rdparty/elfutils/libdwelf/libdwelf.pro @@ -0,0 +1,14 @@ +TEMPLATE = lib +CONFIG += staticlib +TARGET = ../dwelf + +include(../elfutils.pri) +include(dwelfheaders.pri) +include(../libdw/dwheaders.pri) +include(../libdwfl/dwflheaders.pri) +include(../libebl/eblheaders.pri) + +SOURCES += \ + $$PWD/dwelf_dwarf_gnu_debugaltlink.c \ + $$PWD/dwelf_elf_gnu_build_id.c \ + $$PWD/dwelf_elf_gnu_debuglink.c diff --git a/3rdparty/elfutils/libdwelf/libdwelfP.h b/3rdparty/elfutils/libdwelf/libdwelfP.h new file mode 100644 index 0000000..d83c759 --- /dev/null +++ b/3rdparty/elfutils/libdwelf/libdwelfP.h @@ -0,0 +1,42 @@ +/* Internal definitions for libdwelf. DWARF ELF Low-level Functions. + Copyright (C) 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifndef _LIBDWELFP_H +#define _LIBDWELFP_H 1 + +#include <libdwelf.h> +#include "../libdw/libdwP.h" /* We need its INTDECLs. */ +#include <assert.h> +#include <string.h> + +/* Avoid PLT entries. */ +INTDECL (dwelf_elf_gnu_debuglink) +INTDECL (dwelf_dwarf_gnu_debugaltlink) +INTDECL (dwelf_elf_gnu_build_id) + +#endif /* libdwelfP.h */ diff --git a/3rdparty/elfutils/libdwfl/argp-std.c b/3rdparty/elfutils/libdwfl/argp-std.c new file mode 100644 index 0000000..42b7e78 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/argp-std.c @@ -0,0 +1,364 @@ +/* Standard argp argument parsers for tools using libdwfl. + Copyright (C) 2005-2010, 2012 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" +#include <argp.h> +#include <stdlib.h> +#include <assert.h> +#include <libintl.h> +#include <fcntl.h> +#include <unistd.h> + +/* gettext helper macros. */ +#define _(Str) dgettext ("elfutils", Str) + + +#define OPT_DEBUGINFO 0x100 +#define OPT_COREFILE 0x101 + +static const struct argp_option options[] = +{ + { NULL, 0, NULL, 0, N_("Input selection options:"), 0 }, + { "executable", 'e', "FILE", 0, N_("Find addresses in FILE"), 0 }, + { "core", OPT_COREFILE, "COREFILE", 0, + N_("Find addresses from signatures found in COREFILE"), 0 }, + { "pid", 'p', "PID", 0, + N_("Find addresses in files mapped into process PID"), 0 }, + { "linux-process-map", 'M', "FILE", 0, + N_("Find addresses in files mapped as read from FILE" + " in Linux /proc/PID/maps format"), 0 }, + { "kernel", 'k', NULL, 0, N_("Find addresses in the running kernel"), 0 }, + { "offline-kernel", 'K', "RELEASE", OPTION_ARG_OPTIONAL, + N_("Kernel with all modules"), 0 }, + { "debuginfo-path", OPT_DEBUGINFO, "PATH", 0, + N_("Search path for separate debuginfo files"), 0 }, + { NULL, 0, NULL, 0, NULL, 0 } +}; + +static char *debuginfo_path; + +static const Dwfl_Callbacks offline_callbacks = + { + .find_debuginfo = INTUSE(dwfl_standard_find_debuginfo), + .debuginfo_path = &debuginfo_path, + + .section_address = INTUSE(dwfl_offline_section_address), + + /* We use this table for core files too. */ + .find_elf = INTUSE(dwfl_build_id_find_elf), + }; + +static const Dwfl_Callbacks proc_callbacks = + { + .find_debuginfo = INTUSE(dwfl_standard_find_debuginfo), + .debuginfo_path = &debuginfo_path, + + .find_elf = INTUSE(dwfl_linux_proc_find_elf), + }; + +static const Dwfl_Callbacks kernel_callbacks = + { + .find_debuginfo = INTUSE(dwfl_standard_find_debuginfo), + .debuginfo_path = &debuginfo_path, + + .find_elf = INTUSE(dwfl_linux_kernel_find_elf), + .section_address = INTUSE(dwfl_linux_kernel_module_section_address), + }; + +/* Structure held at state->HOOK. */ +struct parse_opt +{ + Dwfl *dwfl; + /* The -e|--executable parameter. */ + const char *e; + /* The --core parameter. */ + const char *core; +}; + +static error_t +parse_opt (int key, char *arg, struct argp_state *state) +{ + inline void failure (Dwfl *dwfl, int errnum, const char *msg) + { + if (dwfl != NULL) + dwfl_end (dwfl); + if (errnum == -1) + argp_failure (state, EXIT_FAILURE, 0, "%s: %s", + msg, INTUSE(dwfl_errmsg) (-1)); + else + argp_failure (state, EXIT_FAILURE, errnum, "%s", msg); + } + inline error_t fail (Dwfl *dwfl, int errnum, const char *msg) + { + failure (dwfl, errnum, msg); + return errnum == -1 ? EIO : errnum; + } + + switch (key) + { + case ARGP_KEY_INIT: + { + assert (state->hook == NULL); + struct parse_opt *opt = calloc (1, sizeof (*opt)); + if (opt == NULL) + failure (NULL, DWFL_E_ERRNO, "calloc"); + state->hook = opt; + } + break; + + case OPT_DEBUGINFO: + debuginfo_path = arg; + break; + + case 'e': + { + struct parse_opt *opt = state->hook; + Dwfl *dwfl = opt->dwfl; + if (dwfl == NULL) + { + dwfl = INTUSE(dwfl_begin) (&offline_callbacks); + if (dwfl == NULL) + return fail (dwfl, -1, arg); + opt->dwfl = dwfl; + + /* Start at zero so if there is just one -e foo.so, + the DSO is shown without address bias. */ + dwfl->offline_next_address = 0; + } + if (dwfl->callbacks != &offline_callbacks) + { + toomany: + argp_error (state, "%s", + _("only one of -e, -p, -k, -K, or --core allowed")); + return EINVAL; + } + opt->e = arg; + } + break; + + case 'p': + { + struct parse_opt *opt = state->hook; + if (opt->dwfl == NULL) + { + Dwfl *dwfl = INTUSE(dwfl_begin) (&proc_callbacks); + int result = INTUSE(dwfl_linux_proc_report) (dwfl, atoi (arg)); + if (result != 0) + return fail (dwfl, result, arg); + + /* Non-fatal to not be able to attach to process, ignore error. */ + INTUSE(dwfl_linux_proc_attach) (dwfl, atoi (arg), false); + + opt->dwfl = dwfl; + } + else + goto toomany; + } + break; + + case 'M': + { + struct parse_opt *opt = state->hook; + if (opt->dwfl == NULL) + { + FILE *f = fopen (arg, "r"); + if (f == NULL) + { + int code = errno; + argp_failure (state, EXIT_FAILURE, code, + "cannot open '%s'", arg); + return code; + } + Dwfl *dwfl = INTUSE(dwfl_begin) (&proc_callbacks); + int result = INTUSE(dwfl_linux_proc_maps_report) (dwfl, f); + fclose (f); + if (result != 0) + return fail (dwfl, result, arg); + opt->dwfl = dwfl; + } + else + goto toomany; + } + break; + + case OPT_COREFILE: + { + struct parse_opt *opt = state->hook; + Dwfl *dwfl = opt->dwfl; + if (dwfl == NULL) + opt->dwfl = dwfl = INTUSE(dwfl_begin) (&offline_callbacks); + /* Permit -e and --core together. */ + else if (dwfl->callbacks != &offline_callbacks) + goto toomany; + opt->core = arg; + } + break; + + case 'k': + { + struct parse_opt *opt = state->hook; + if (opt->dwfl == NULL) + { + Dwfl *dwfl = INTUSE(dwfl_begin) (&kernel_callbacks); + int result = INTUSE(dwfl_linux_kernel_report_kernel) (dwfl); + if (result != 0) + return fail (dwfl, result, _("cannot load kernel symbols")); + result = INTUSE(dwfl_linux_kernel_report_modules) (dwfl); + if (result != 0) + /* Non-fatal to have no modules since we do have the kernel. */ + failure (dwfl, result, _("cannot find kernel modules")); + opt->dwfl = dwfl; + } + else + goto toomany; + } + break; + + case 'K': + { + struct parse_opt *opt = state->hook; + if (opt->dwfl == NULL) + { + Dwfl *dwfl = INTUSE(dwfl_begin) (&offline_callbacks); + int result = INTUSE(dwfl_linux_kernel_report_offline) (dwfl, arg, + NULL); + if (result != 0) + return fail (dwfl, result, _("cannot find kernel or modules")); + opt->dwfl = dwfl; + } + else + goto toomany; + } + break; + + case ARGP_KEY_SUCCESS: + { + struct parse_opt *opt = state->hook; + Dwfl *dwfl = opt->dwfl; + + if (dwfl == NULL) + { + /* Default if no -e, -p, or -k, is "-e a.out". */ + arg = "a.out"; + dwfl = INTUSE(dwfl_begin) (&offline_callbacks); + if (INTUSE(dwfl_report_offline) (dwfl, "", arg, -1) == NULL) + return fail (dwfl, -1, arg); + opt->dwfl = dwfl; + } + + if (opt->core) + { + int fd = open64 (opt->core, O_RDONLY); + if (fd < 0) + { + int code = errno; + argp_failure (state, EXIT_FAILURE, code, + "cannot open '%s'", opt->core); + return code; + } + + Elf *core; + Dwfl_Error error = __libdw_open_file (&fd, &core, true, false); + if (error != DWFL_E_NOERROR) + { + argp_failure (state, EXIT_FAILURE, 0, + _("cannot read ELF core file: %s"), + INTUSE(dwfl_errmsg) (error)); + return error == DWFL_E_ERRNO ? errno : EIO; + } + + int result = INTUSE(dwfl_core_file_report) (dwfl, core, opt->e); + if (result < 0) + { + elf_end (core); + close (fd); + return fail (dwfl, result, opt->core); + } + + /* Non-fatal to not be able to attach to core, ignore error. */ + INTUSE(dwfl_core_file_attach) (dwfl, core); + + /* From now we leak FD and CORE. */ + + if (result == 0) + { + argp_failure (state, EXIT_FAILURE, 0, + _("No modules recognized in core file")); + return ENOENT; + } + } + else if (opt->e) + { + if (INTUSE(dwfl_report_offline) (dwfl, "", opt->e, -1) == NULL) + return fail (dwfl, -1, opt->e); + } + + /* One of the three flavors has done dwfl_begin and some reporting + if we got here. Tie up the Dwfl and return it to the caller of + argp_parse. */ + + int result = INTUSE(dwfl_report_end) (dwfl, NULL, NULL); + assert (result == 0); + + /* Update the input all along, so a parent parser can see it. + As we free OPT the update below will be no longer active. */ + *(Dwfl **) state->input = dwfl; + free (opt); + state->hook = NULL; + } + break; + + case ARGP_KEY_ERROR: + { + struct parse_opt *opt = state->hook; + dwfl_end (opt->dwfl); + free (opt); + state->hook = NULL; + } + break; + + default: + return ARGP_ERR_UNKNOWN; + } + + /* Update the input all along, so a parent parser can see it. */ + struct parse_opt *opt = state->hook; + if (opt) + *(Dwfl **) state->input = opt->dwfl; + + return 0; +} + +static const struct argp libdwfl_argp = + { .options = options, .parser = parse_opt }; + +const struct argp * +dwfl_standard_argp (void) +{ + return &libdwfl_argp; +} diff --git a/3rdparty/elfutils/libdwfl/core-file.c b/3rdparty/elfutils/libdwfl/core-file.c new file mode 100644 index 0000000..50031ae --- /dev/null +++ b/3rdparty/elfutils/libdwfl/core-file.c @@ -0,0 +1,589 @@ +/* Core file handling. + Copyright (C) 2008-2010, 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include <config.h> +#include "../libelf/libelfP.h" /* For NOTE_ALIGN. */ +#undef _ +#include "libdwflP.h" +#include <gelf.h> + +#include <sys/param.h> +#include <unistd.h> +#include <endian.h> +#include <byteswap.h> +#include "system.h" + + +/* This is a prototype of what a new libelf interface might be. + This implementation is pessimal for non-mmap cases and should + be replaced by more diddling inside libelf internals. */ +static Elf * +elf_begin_rand (Elf *parent, loff_t offset, loff_t size, loff_t *next) +{ + if (parent == NULL) + return NULL; + + /* On failure return, we update *NEXT to point back at OFFSET. */ + inline Elf *fail (int error) + { + if (next != NULL) + *next = offset; + //__libelf_seterrno (error); + __libdwfl_seterrno (DWFL_E (LIBELF, error)); + return NULL; + } + + loff_t min = (parent->kind == ELF_K_ELF ? + (parent->class == ELFCLASS32 + ? sizeof (Elf32_Ehdr) : sizeof (Elf64_Ehdr)) + : parent->kind == ELF_K_AR ? SARMAG + : 0); + + if (unlikely (offset < min) + || unlikely (offset >= (loff_t) parent->maximum_size)) + return fail (ELF_E_RANGE); + + /* For an archive, fetch just the size field + from the archive header to override SIZE. */ + if (parent->kind == ELF_K_AR) + { + struct ar_hdr h = { .ar_size = "" }; + + if (unlikely (parent->maximum_size - offset < sizeof h)) + return fail (ELF_E_RANGE); + + if (parent->map_address != NULL) + memcpy (h.ar_size, parent->map_address + parent->start_offset + offset, + sizeof h.ar_size); + else if (unlikely (pread_retry (parent->fildes, + h.ar_size, sizeof (h.ar_size), + parent->start_offset + offset + + offsetof (struct ar_hdr, ar_size)) + != sizeof (h.ar_size))) + return fail (ELF_E_READ_ERROR); + + offset += sizeof h; + + char *endp; + size = strtoll (h.ar_size, &endp, 10); + if (unlikely (endp == h.ar_size) + || unlikely ((loff_t) parent->maximum_size - offset < size)) + return fail (ELF_E_INVALID_ARCHIVE); + } + + if (unlikely ((loff_t) parent->maximum_size - offset < size)) + return fail (ELF_E_RANGE); + + /* Even if we fail at this point, update *NEXT to point past the file. */ + if (next != NULL) + *next = offset + size; + + if (unlikely (offset == 0) + && unlikely (size == (loff_t) parent->maximum_size)) + return elf_clone (parent, parent->cmd); + + /* Note the image is guaranteed live only as long as PARENT + lives. Using elf_memory is quite suboptimal if the whole + file is not mmap'd. We really should have something like + a generalization of the archive support. */ + Elf_Data *data = elf_getdata_rawchunk (parent, offset, size, ELF_T_BYTE); + if (data == NULL) + return NULL; + assert ((loff_t) data->d_size == size); + return elf_memory (data->d_buf, size); +} + + +int +dwfl_report_core_segments (Dwfl *dwfl, Elf *elf, size_t phnum, GElf_Phdr *notes) +{ + if (unlikely (dwfl == NULL)) + return -1; + + int result = 0; + + if (notes != NULL) + notes->p_type = PT_NULL; + + for (size_t ndx = 0; result >= 0 && ndx < phnum; ++ndx) + { + GElf_Phdr phdr_mem; + GElf_Phdr *phdr = gelf_getphdr (elf, ndx, &phdr_mem); + if (unlikely (phdr == NULL)) + { + __libdwfl_seterrno (DWFL_E_LIBELF); + return -1; + } + switch (phdr->p_type) + { + case PT_LOAD: + result = dwfl_report_segment (dwfl, ndx, phdr, 0, NULL); + break; + + case PT_NOTE: + if (notes != NULL) + { + *notes = *phdr; + notes = NULL; + } + break; + } + } + + return result; +} + +/* Never read more than this much without mmap. */ +#define MAX_EAGER_COST 8192 + +static bool +core_file_read_eagerly (Dwfl_Module *mod, + void **userdata __attribute__ ((unused)), + const char *name __attribute__ ((unused)), + Dwarf_Addr start __attribute__ ((unused)), + void **buffer, size_t *buffer_available, + GElf_Off cost, GElf_Off worthwhile, + GElf_Off whole, + GElf_Off contiguous __attribute__ ((unused)), + void *arg, Elf **elfp) +{ + Elf *core = arg; + + if (whole <= *buffer_available) + { + /* All there ever was, we already have on hand. */ + + if (core->map_address == NULL) + { + /* We already malloc'd the buffer. */ + *elfp = elf_memory (*buffer, whole); + if (unlikely (*elfp == NULL)) + return false; + + (*elfp)->flags |= ELF_F_MALLOCED; + *buffer = NULL; + *buffer_available = 0; + return true; + } + + /* We can use the image inside the core file directly. */ + *elfp = elf_begin_rand (core, *buffer - core->map_address, whole, NULL); + *buffer = NULL; + *buffer_available = 0; + return *elfp != NULL; + } + + /* We don't have the whole file. + Figure out if this is better than nothing. */ + + if (worthwhile == 0) + /* Caller doesn't think so. */ + return false; + + /* + XXX would like to fall back to partial file via memory + when build id find_elf fails + also, link_map name may give file name from disk better than partial here + requires find_elf hook re-doing the magic to fall back if no file found + */ + + if (mod->build_id_len > 0) + /* There is a build ID that could help us find the whole file, + which might be more useful than what we have. + We'll just rely on that. */ + return false; + + if (core->map_address != NULL) + /* It's cheap to get, so get it. */ + return true; + + /* Only use it if there isn't too much to be read. */ + return cost <= MAX_EAGER_COST; +} + +bool +dwfl_elf_phdr_memory_callback (Dwfl *dwfl, int ndx, + void **buffer, size_t *buffer_available, + GElf_Addr vaddr, + size_t minread, + void *arg) +{ + Elf *elf = arg; + + if (ndx == -1) + { + /* Called for cleanup. */ + if (elf->map_address == NULL) + free (*buffer); + *buffer = NULL; + *buffer_available = 0; + return false; + } + + const GElf_Off align = dwfl->segment_align ?: 1; + GElf_Phdr phdr; + + do + if (unlikely (gelf_getphdr (elf, ndx++, &phdr) == NULL)) + return false; + while (phdr.p_type != PT_LOAD + || ((phdr.p_vaddr + phdr.p_memsz + align - 1) & -align) <= vaddr); + + GElf_Off start = vaddr - phdr.p_vaddr + phdr.p_offset; + GElf_Off end; + GElf_Addr end_vaddr; + + inline void update_end () + { + end = (phdr.p_offset + phdr.p_filesz + align - 1) & -align; + end_vaddr = (phdr.p_vaddr + phdr.p_memsz + align - 1) & -align; + } + + update_end (); + + /* Use following contiguous segments to get towards SIZE. */ + inline bool more (size_t size) + { + while (end <= start || end - start < size) + { + if (phdr.p_filesz < phdr.p_memsz) + /* This segment is truncated, so no following one helps us. */ + return false; + + if (unlikely (gelf_getphdr (elf, ndx++, &phdr) == NULL)) + return false; + + if (phdr.p_type == PT_LOAD) + { + if (phdr.p_offset > end + || phdr.p_vaddr > end_vaddr) + /* It's discontiguous! */ + return false; + + update_end (); + } + } + return true; + } + + /* We need at least this much. */ + if (! more (minread)) + return false; + + /* See how much more we can get of what the caller wants. */ + (void) more (*buffer_available); + + /* If it's already on hand anyway, use as much as there is. */ + if (elf->map_address != NULL) + (void) more (elf->maximum_size - start); + + /* Make sure we don't look past the end of the actual file, + even if the headers tell us to. */ + if (unlikely (end > elf->maximum_size)) + end = elf->maximum_size; + + /* If the file is too small, there is nothing at all to get. */ + if (unlikely (start >= end)) + return false; + + if (elf->map_address != NULL) + { + void *contents = elf->map_address + elf->start_offset + start; + size_t size = end - start; + + if (minread == 0) /* String mode. */ + { + const void *eos = memchr (contents, '\0', size); + if (unlikely (eos == NULL) || unlikely (eos == contents)) + return false; + size = eos + 1 - contents; + } + + if (*buffer == NULL) + { + *buffer = contents; + *buffer_available = size; + } + else + { + *buffer_available = MIN (size, *buffer_available); + memcpy (*buffer, contents, *buffer_available); + } + } + else + { + void *into = *buffer; + if (*buffer == NULL) + { + *buffer_available = MIN (minread ?: 512, + MAX (4096, MIN (end - start, + *buffer_available))); + into = malloc (*buffer_available); + if (unlikely (into == NULL)) + { + __libdwfl_seterrno (DWFL_E_NOMEM); + return false; + } + } + + ssize_t nread = pread_retry (elf->fildes, into, *buffer_available, start); + if (nread < (ssize_t) minread) + { + if (into != *buffer) + free (into); + if (nread < 0) + __libdwfl_seterrno (DWFL_E_ERRNO); + return false; + } + + if (minread == 0) /* String mode. */ + { + const void *eos = memchr (into, '\0', nread); + if (unlikely (eos == NULL) || unlikely (eos == into)) + { + if (*buffer == NULL) + free (into); + return false; + } + nread = eos + 1 - into; + } + + if (*buffer == NULL) + *buffer = into; + *buffer_available = nread; + } + + return true; +} + +/* Free the contents of R_DEBUG_INFO without the R_DEBUG_INFO memory itself. */ + +static void +clear_r_debug_info (struct r_debug_info *r_debug_info) +{ + while (r_debug_info->module != NULL) + { + struct r_debug_info_module *module = r_debug_info->module; + r_debug_info->module = module->next; + elf_end (module->elf); + if (module->fd != -1) + close (module->fd); + free (module); + } +} + +bool +internal_function +__libdwfl_dynamic_vaddr_get (Elf *elf, GElf_Addr *vaddrp) +{ + size_t phnum; + if (unlikely (elf_getphdrnum (elf, &phnum) != 0)) + return false; + for (size_t i = 0; i < phnum; ++i) + { + GElf_Phdr phdr_mem; + GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem); + if (unlikely (phdr == NULL)) + return false; + if (phdr->p_type == PT_DYNAMIC) + { + *vaddrp = phdr->p_vaddr; + return true; + } + } + return false; +} + +int +dwfl_core_file_report (Dwfl *dwfl, Elf *elf, const char *executable) +{ + size_t phnum; + if (unlikely (elf_getphdrnum (elf, &phnum) != 0)) + { + __libdwfl_seterrno (DWFL_E_LIBELF); + return -1; + } + + free (dwfl->executable_for_core); + if (executable == NULL) + dwfl->executable_for_core = NULL; + else + { + dwfl->executable_for_core = strdup (executable); + if (dwfl->executable_for_core == NULL) + { + __libdwfl_seterrno (DWFL_E_NOMEM); + return -1; + } + } + + /* First report each PT_LOAD segment. */ + GElf_Phdr notes_phdr; + int ndx = dwfl_report_core_segments (dwfl, elf, phnum, ¬es_phdr); + if (unlikely (ndx <= 0)) + return ndx; + + /* Next, we should follow the chain from DT_DEBUG. */ + + const void *auxv = NULL; + const void *note_file = NULL; + size_t auxv_size = 0; + size_t note_file_size = 0; + if (likely (notes_phdr.p_type == PT_NOTE)) + { + /* PT_NOTE -> NT_AUXV -> AT_PHDR -> PT_DYNAMIC -> DT_DEBUG */ + + Elf_Data *notes = elf_getdata_rawchunk (elf, + notes_phdr.p_offset, + notes_phdr.p_filesz, + ELF_T_NHDR); + if (likely (notes != NULL)) + { + size_t pos = 0; + GElf_Nhdr nhdr; + size_t name_pos; + size_t desc_pos; + while ((pos = gelf_getnote (notes, pos, &nhdr, + &name_pos, &desc_pos)) > 0) + if (nhdr.n_namesz == sizeof "CORE" + && !memcmp (notes->d_buf + name_pos, "CORE", sizeof "CORE")) + { + if (nhdr.n_type == NT_AUXV) + { + auxv = notes->d_buf + desc_pos; + auxv_size = nhdr.n_descsz; + } + if (nhdr.n_type == NT_FILE) + { + note_file = notes->d_buf + desc_pos; + note_file_size = nhdr.n_descsz; + } + } + } + } + + /* Now we have NT_AUXV contents. From here on this processing could be + used for a live process with auxv read from /proc. */ + + struct r_debug_info r_debug_info; + memset (&r_debug_info, 0, sizeof r_debug_info); + int retval = dwfl_link_map_report (dwfl, auxv, auxv_size, + dwfl_elf_phdr_memory_callback, elf, + &r_debug_info); + int listed = retval > 0 ? retval : 0; + + /* Now sniff segment contents for modules hinted by information gathered + from DT_DEBUG. */ + + ndx = 0; + do + { + int seg = dwfl_segment_report_module (dwfl, ndx, NULL, + &dwfl_elf_phdr_memory_callback, elf, + core_file_read_eagerly, elf, + note_file, note_file_size, + &r_debug_info); + if (unlikely (seg < 0)) + { + clear_r_debug_info (&r_debug_info); + return seg; + } + if (seg > ndx) + { + ndx = seg; + ++listed; + } + else + ++ndx; + } + while (ndx < (int) phnum); + + /* Now report the modules from dwfl_link_map_report which were not filtered + out by dwfl_segment_report_module. */ + + Dwfl_Module **lastmodp = &dwfl->modulelist; + while (*lastmodp != NULL) + lastmodp = &(*lastmodp)->next; + for (struct r_debug_info_module *module = r_debug_info.module; + module != NULL; module = module->next) + { + if (module->elf == NULL) + continue; + GElf_Addr file_dynamic_vaddr; + if (! __libdwfl_dynamic_vaddr_get (module->elf, &file_dynamic_vaddr)) + continue; + Dwfl_Module *mod; + mod = __libdwfl_report_elf (dwfl, basename (module->name), module->name, + module->fd, module->elf, + module->l_ld - file_dynamic_vaddr, + true, true); + if (mod == NULL) + continue; + ++listed; + module->elf = NULL; + module->fd = -1; + /* Move this module to the end of the list, so that we end + up with a list in the same order as the link_map chain. */ + if (mod->next != NULL) + { + if (*lastmodp != mod) + { + lastmodp = &dwfl->modulelist; + while (*lastmodp != mod) + lastmodp = &(*lastmodp)->next; + } + *lastmodp = mod->next; + mod->next = NULL; + while (*lastmodp != NULL) + lastmodp = &(*lastmodp)->next; + *lastmodp = mod; + } + lastmodp = &mod->next; + } + + clear_r_debug_info (&r_debug_info); + + /* We return the number of modules we found if we found any. + If we found none, we return -1 instead of 0 if there was an + error rather than just nothing found. */ + return listed > 0 ? listed : retval; +} +INTDEF (dwfl_core_file_report) +NEW_VERSION (dwfl_core_file_report, ELFUTILS_0.158) + +#ifdef SHARED +int _compat_without_executable_dwfl_core_file_report (Dwfl *dwfl, Elf *elf); +COMPAT_VERSION_NEWPROTO (dwfl_core_file_report, ELFUTILS_0.146, + without_executable) + +int +_compat_without_executable_dwfl_core_file_report (Dwfl *dwfl, Elf *elf) +{ + return dwfl_core_file_report (dwfl, elf, NULL); +} +#endif diff --git a/3rdparty/elfutils/libdwfl/cu.c b/3rdparty/elfutils/libdwfl/cu.c new file mode 100644 index 0000000..5ce531b --- /dev/null +++ b/3rdparty/elfutils/libdwfl/cu.c @@ -0,0 +1,312 @@ +/* Keeping track of DWARF compilation units in libdwfl. + Copyright (C) 2005-2010 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" +#include "../libdw/libdwP.h" +#include "../libdw/memory-access.h" +#include <search.h> + + +static inline Dwarf_Arange * +dwar (Dwfl_Module *mod, unsigned int idx) +{ + return &mod->dw->aranges->info[mod->aranges[idx].arange]; +} + + +static Dwfl_Error +addrarange (Dwfl_Module *mod, Dwarf_Addr addr, struct dwfl_arange **arange) +{ + if (mod->aranges == NULL) + { + struct dwfl_arange *aranges = NULL; + Dwarf_Aranges *dwaranges = NULL; + size_t naranges; + if (INTUSE(dwarf_getaranges) (mod->dw, &dwaranges, &naranges) != 0) + return DWFL_E_LIBDW; + + /* If the module has no aranges (when no code is included) we + allocate nothing. */ + if (naranges != 0) + { + aranges = malloc (naranges * sizeof *aranges); + if (unlikely (aranges == NULL)) + return DWFL_E_NOMEM; + + /* libdw has sorted its list by address, which is how we want it. + But the sorted list is full of not-quite-contiguous runs pointing + to the same CU. We don't care about the little gaps inside the + module, we'll consider them part of the surrounding CU anyway. + Collect our own array with just one record for each run of ranges + pointing to one CU. */ + + naranges = 0; + Dwarf_Off lastcu = 0; + for (size_t i = 0; i < dwaranges->naranges; ++i) + if (i == 0 || dwaranges->info[i].offset != lastcu) + { + aranges[naranges].arange = i; + aranges[naranges].cu = NULL; + ++naranges; + lastcu = dwaranges->info[i].offset; + } + } + + /* Store the final array, which is probably much smaller than before. */ + mod->naranges = naranges; + mod->aranges = (realloc (aranges, naranges * sizeof aranges[0]) + ?: aranges); + mod->lazycu += naranges; + } + + /* The address must be inside the module to begin with. */ + addr = dwfl_deadjust_dwarf_addr (mod, addr); + + /* The ranges are sorted by address, so we can use binary search. */ + size_t l = 0, u = mod->naranges; + while (l < u) + { + size_t idx = (l + u) / 2; + Dwarf_Addr start = dwar (mod, idx)->addr; + if (addr < start) + { + u = idx; + continue; + } + else if (addr > start) + { + if (idx + 1 < mod->naranges) + { + if (addr >= dwar (mod, idx + 1)->addr) + { + l = idx + 1; + continue; + } + } + else + { + /* It might be in the last range. */ + const Dwarf_Arange *last + = &mod->dw->aranges->info[mod->dw->aranges->naranges - 1]; + if (addr > last->addr + last->length) + break; + } + } + + *arange = &mod->aranges[idx]; + return DWFL_E_NOERROR; + } + + return DWFL_E_ADDR_OUTOFRANGE; +} + + +static void +nofree (void *arg) +{ + struct dwfl_cu *cu = arg; + if (cu == (void *) -1l) + return; + + assert (cu->mod->lazycu == 0); +} + +/* One reason fewer to keep the lazy lookup table for CUs. */ +static inline void +less_lazy (Dwfl_Module *mod) +{ + if (--mod->lazycu > 0) + return; + + /* We know about all the CUs now, we don't need this table. */ + tdestroy (mod->lazy_cu_root, nofree); + mod->lazy_cu_root = NULL; +} + +static inline Dwarf_Off +cudie_offset (const struct dwfl_cu *cu) +{ + /* These are real CUs, so there never is a type_sig8. Note + initialization of dwkey.start and offset_size in intern_cu () + to see why this calculates the same value for both key and + die.cu search items. */ + return DIE_OFFSET_FROM_CU_OFFSET (cu->die.cu->start, cu->die.cu->offset_size, + 0); +} + +static int +compare_cukey (const void *a, const void *b) +{ + Dwarf_Off a_off = cudie_offset (a); + Dwarf_Off b_off = cudie_offset (b); + return (a_off < b_off) ? -1 : ((a_off > b_off) ? 1 : 0); +} + +/* Intern the CU if necessary. */ +static Dwfl_Error +intern_cu (Dwfl_Module *mod, Dwarf_Off cuoff, struct dwfl_cu **result) +{ + struct Dwarf_CU dwkey; + struct dwfl_cu key; + key.die.cu = &dwkey; + dwkey.offset_size = 0; + dwkey.start = cuoff - (3 * 0 - 4 + 3); + struct dwfl_cu **found = tsearch (&key, &mod->lazy_cu_root, &compare_cukey); + if (unlikely (found == NULL)) + return DWFL_E_NOMEM; + + if (*found == &key || *found == NULL) + { + if (unlikely (cuoff + 4 >= mod->dw->sectiondata[IDX_debug_info]->d_size)) + { + /* This is the EOF marker. Now we have interned all the CUs. + One increment in MOD->lazycu counts not having hit EOF yet. */ + *found = (void *) -1l; + less_lazy (mod); + } + else + { + /* This is a new entry, meaning we haven't looked at this CU. */ + + *found = NULL; + + struct dwfl_cu *cu = malloc (sizeof *cu); + if (unlikely (cu == NULL)) + return DWFL_E_NOMEM; + + cu->mod = mod; + cu->next = NULL; + cu->lines = NULL; + + /* XXX use non-searching lookup */ + Dwarf_Die *die = INTUSE(dwarf_offdie) (mod->dw, cuoff, &cu->die); + if (die == NULL) + { + free (cu); + return DWFL_E_LIBDW; + } + assert (die == &cu->die); + + struct dwfl_cu **newvec = realloc (mod->cu, ((mod->ncu + 1) + * sizeof (mod->cu[0]))); + if (newvec == NULL) + { + free (cu); + return DWFL_E_NOMEM; + } + mod->cu = newvec; + + mod->cu[mod->ncu++] = cu; + if (cu->die.cu->start == 0) + mod->first_cu = cu; + + *found = cu; + } + } + + *result = *found; + return DWFL_E_NOERROR; +} + + +/* Traverse all the CUs in the module. */ + +Dwfl_Error +internal_function +__libdwfl_nextcu (Dwfl_Module *mod, struct dwfl_cu *lastcu, + struct dwfl_cu **cu) +{ + Dwarf_Off cuoff; + struct dwfl_cu **nextp; + + if (lastcu == NULL) + { + /* Start the traversal. */ + cuoff = 0; + nextp = &mod->first_cu; + } + else + { + /* Continue following LASTCU. */ + cuoff = lastcu->die.cu->end; + nextp = &lastcu->next; + } + + if (*nextp == NULL) + { + size_t cuhdrsz; + Dwarf_Off nextoff; + int end = INTUSE(dwarf_nextcu) (mod->dw, cuoff, &nextoff, &cuhdrsz, + NULL, NULL, NULL); + if (end < 0) + return DWFL_E_LIBDW; + if (end > 0) + { + *cu = NULL; + return DWFL_E_NOERROR; + } + + Dwfl_Error result = intern_cu (mod, cuoff + cuhdrsz, nextp); + if (result != DWFL_E_NOERROR) + return result; + + if ((*nextp)->next == NULL && nextoff == (Dwarf_Off) -1l) + (*nextp)->next = (void *) -1l; + } + + *cu = *nextp == (void *) -1l ? NULL : *nextp; + return DWFL_E_NOERROR; +} + + +/* Intern the CU arange points to, if necessary. */ + +static Dwfl_Error +arangecu (Dwfl_Module *mod, struct dwfl_arange *arange, struct dwfl_cu **cu) +{ + if (arange->cu == NULL) + { + const Dwarf_Arange *dwarange = &mod->dw->aranges->info[arange->arange]; + Dwfl_Error result = intern_cu (mod, dwarange->offset, &arange->cu); + if (result != DWFL_E_NOERROR) + return result; + assert (arange->cu != NULL && arange->cu != (void *) -1l); + less_lazy (mod); /* Each arange with null ->cu counts once. */ + } + + *cu = arange->cu; + return DWFL_E_NOERROR; +} + +Dwfl_Error +internal_function +__libdwfl_addrcu (Dwfl_Module *mod, Dwarf_Addr addr, struct dwfl_cu **cu) +{ + struct dwfl_arange *arange; + return addrarange (mod, addr, &arange) ?: arangecu (mod, arange, cu); +} diff --git a/3rdparty/elfutils/libdwfl/derelocate.c b/3rdparty/elfutils/libdwfl/derelocate.c new file mode 100644 index 0000000..da67908 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/derelocate.c @@ -0,0 +1,401 @@ +/* Recover relocatibility for addresses computed from debug information. + Copyright (C) 2005-2010, 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" + +struct dwfl_relocation +{ + size_t count; + struct + { + Elf_Scn *scn; + Elf_Scn *relocs; + const char *name; + GElf_Addr start, end; + } refs[0]; +}; + + +struct secref +{ + struct secref *next; + Elf_Scn *scn; + Elf_Scn *relocs; + const char *name; + GElf_Addr start, end; +}; + +static int +compare_secrefs (const void *a, const void *b) +{ + struct secref *const *p1 = a; + struct secref *const *p2 = b; + + /* No signed difference calculation is correct here, since the + terms are unsigned and could be more than INT64_MAX apart. */ + if ((*p1)->start < (*p2)->start) + return -1; + if ((*p1)->start > (*p2)->start) + return 1; + + return 0; +} + +static int +cache_sections (Dwfl_Module *mod) +{ + if (likely (mod->reloc_info != NULL)) + return mod->reloc_info->count; + + struct secref *refs = NULL; + size_t nrefs = 0; + + size_t shstrndx; + if (unlikely (elf_getshdrstrndx (mod->main.elf, &shstrndx) < 0)) + { + elf_error: + __libdwfl_seterrno (DWFL_E_LIBELF); + return -1; + } + + bool check_reloc_sections = false; + Elf_Scn *scn = NULL; + while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + if (shdr == NULL) + goto elf_error; + + if ((shdr->sh_flags & SHF_ALLOC) && shdr->sh_addr == 0 + && mod->e_type == ET_REL) + { + /* This section might not yet have been looked at. */ + if (__libdwfl_relocate_value (mod, mod->main.elf, &shstrndx, + elf_ndxscn (scn), + &shdr->sh_addr) != DWFL_E_NOERROR) + continue; + shdr = gelf_getshdr (scn, &shdr_mem); + if (unlikely (shdr == NULL)) + goto elf_error; + } + + if (shdr->sh_flags & SHF_ALLOC) + { + const char *name = elf_strptr (mod->main.elf, shstrndx, + shdr->sh_name); + if (unlikely (name == NULL)) + goto elf_error; + + struct secref *newref = alloca (sizeof *newref); + newref->scn = scn; + newref->relocs = NULL; + newref->name = name; + newref->start = dwfl_adjusted_address (mod, shdr->sh_addr); + newref->end = newref->start + shdr->sh_size; + newref->next = refs; + refs = newref; + ++nrefs; + } + + if (mod->e_type == ET_REL + && shdr->sh_size != 0 + && (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA) + && mod->dwfl->callbacks->section_address != NULL) + { + if (shdr->sh_info < elf_ndxscn (scn)) + { + /* We've already looked at the section these relocs apply to. */ + Elf_Scn *tscn = elf_getscn (mod->main.elf, shdr->sh_info); + if (likely (tscn != NULL)) + for (struct secref *sec = refs; sec != NULL; sec = sec->next) + if (sec->scn == tscn) + { + sec->relocs = scn; + break; + } + } + else + /* We'll have to do a second pass. */ + check_reloc_sections = true; + } + } + + mod->reloc_info = malloc (offsetof (struct dwfl_relocation, refs[nrefs])); + if (mod->reloc_info == NULL) + { + __libdwfl_seterrno (DWFL_E_NOMEM); + return -1; + } + + struct secref **sortrefs = alloca (nrefs * sizeof sortrefs[0]); + for (size_t i = nrefs; i-- > 0; refs = refs->next) + sortrefs[i] = refs; + assert (refs == NULL); + + qsort (sortrefs, nrefs, sizeof sortrefs[0], &compare_secrefs); + + mod->reloc_info->count = nrefs; + for (size_t i = 0; i < nrefs; ++i) + { + mod->reloc_info->refs[i].name = sortrefs[i]->name; + mod->reloc_info->refs[i].scn = sortrefs[i]->scn; + mod->reloc_info->refs[i].relocs = sortrefs[i]->relocs; + mod->reloc_info->refs[i].start = sortrefs[i]->start; + mod->reloc_info->refs[i].end = sortrefs[i]->end; + } + + if (unlikely (check_reloc_sections)) + { + /* There was a reloc section that preceded its target section. + So we have to scan again now that we have cached all the + possible target sections we care about. */ + + scn = NULL; + while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + if (shdr == NULL) + goto elf_error; + + if (shdr->sh_size != 0 + && (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)) + { + Elf_Scn *tscn = elf_getscn (mod->main.elf, shdr->sh_info); + if (likely (tscn != NULL)) + for (size_t i = 0; i < nrefs; ++i) + if (mod->reloc_info->refs[i].scn == tscn) + { + mod->reloc_info->refs[i].relocs = scn; + break; + } + } + } + } + + return nrefs; +} + + +int +dwfl_module_relocations (Dwfl_Module *mod) +{ + if (mod == NULL) + return -1; + + switch (mod->e_type) + { + case ET_REL: + return cache_sections (mod); + + case ET_DYN: + return 1; + + case ET_EXEC: + assert (mod->main.vaddr == mod->low_addr); + break; + } + + return 0; +} + +const char * +dwfl_module_relocation_info (Dwfl_Module *mod, unsigned int idx, + Elf32_Word *shndxp) +{ + if (mod == NULL) + return NULL; + + switch (mod->e_type) + { + case ET_REL: + break; + + case ET_DYN: + if (idx != 0) + return NULL; + if (shndxp) + *shndxp = SHN_ABS; + return ""; + + default: + return NULL; + } + + if (cache_sections (mod) < 0) + return NULL; + + struct dwfl_relocation *sections = mod->reloc_info; + + if (idx >= sections->count) + return NULL; + + if (shndxp) + *shndxp = elf_ndxscn (sections->refs[idx].scn); + + return sections->refs[idx].name; +} + +/* Check that MOD is valid and make sure its relocation has been done. */ +static bool +check_module (Dwfl_Module *mod) +{ + if (INTUSE(dwfl_module_getsymtab) (mod) < 0) + { + Dwfl_Error error = dwfl_errno (); + if (error != DWFL_E_NO_SYMTAB) + { + __libdwfl_seterrno (error); + return true; + } + } + + if (mod->dw == NULL) + { + Dwarf_Addr bias; + if (INTUSE(dwfl_module_getdwarf) (mod, &bias) == NULL) + { + Dwfl_Error error = dwfl_errno (); + if (error != DWFL_E_NO_DWARF) + { + __libdwfl_seterrno (error); + return true; + } + } + } + + return false; +} + +/* Find the index in MOD->reloc_info.refs containing *ADDR. */ +static int +find_section (Dwfl_Module *mod, Dwarf_Addr *addr) +{ + if (cache_sections (mod) < 0) + return -1; + + struct dwfl_relocation *sections = mod->reloc_info; + + /* The sections are sorted by address, so we can use binary search. */ + size_t l = 0, u = sections->count; + while (l < u) + { + size_t idx = (l + u) / 2; + if (*addr < sections->refs[idx].start) + u = idx; + else if (*addr > sections->refs[idx].end) + l = idx + 1; + else + { + /* Consider the limit of a section to be inside it, unless it's + inside the next one. A section limit address can appear in + line records. */ + if (*addr == sections->refs[idx].end + && idx + 1 < sections->count + && *addr == sections->refs[idx + 1].start) + ++idx; + + *addr -= sections->refs[idx].start; + return idx; + } + } + + __libdwfl_seterrno (DWFL_E (LIBDW, DWARF_E_NO_MATCH)); + return -1; +} + +size_t +internal_function +__libdwfl_find_section_ndx (Dwfl_Module *mod, Dwarf_Addr *addr) +{ + int idx = find_section (mod, addr); + if (unlikely (idx == -1)) + return SHN_UNDEF; + + return elf_ndxscn (mod->reloc_info->refs[idx].scn); +} + +int +dwfl_module_relocate_address (Dwfl_Module *mod, Dwarf_Addr *addr) +{ + if (unlikely (check_module (mod))) + return -1; + + switch (mod->e_type) + { + case ET_REL: + return find_section (mod, addr); + + case ET_DYN: + /* All relative to first and only relocation base: module start. */ + *addr -= mod->low_addr; + break; + + default: + /* Already absolute, dwfl_module_relocations returned zero. We + shouldn't really have been called, but it's a harmless no-op. */ + break; + } + + return 0; +} +INTDEF (dwfl_module_relocate_address) + +Elf_Scn * +dwfl_module_address_section (Dwfl_Module *mod, Dwarf_Addr *address, + Dwarf_Addr *bias) +{ + if (check_module (mod)) + return NULL; + + int idx = find_section (mod, address); + if (idx < 0) + return NULL; + + if (mod->reloc_info->refs[idx].relocs != NULL) + { + assert (mod->e_type == ET_REL); + + Elf_Scn *tscn = mod->reloc_info->refs[idx].scn; + Elf_Scn *relocscn = mod->reloc_info->refs[idx].relocs; + Dwfl_Error result = __libdwfl_relocate_section (mod, mod->main.elf, + relocscn, tscn, true); + if (likely (result == DWFL_E_NOERROR)) + mod->reloc_info->refs[idx].relocs = NULL; + else + { + __libdwfl_seterrno (result); + return NULL; + } + } + + *bias = dwfl_adjusted_address (mod, 0); + return mod->reloc_info->refs[idx].scn; +} +INTDEF (dwfl_module_address_section) diff --git a/3rdparty/elfutils/libdwfl/dwfl_addrdie.c b/3rdparty/elfutils/libdwfl/dwfl_addrdie.c new file mode 100644 index 0000000..1e9b3ab --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_addrdie.c @@ -0,0 +1,36 @@ +/* Fetch CU DIE from address. + Copyright (C) 2005 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" + +Dwarf_Die * +dwfl_addrdie (Dwfl *dwfl, Dwarf_Addr addr, Dwarf_Addr *bias) +{ + return INTUSE(dwfl_module_addrdie) (INTUSE(dwfl_addrmodule) (dwfl, addr), + addr, bias); +} diff --git a/3rdparty/elfutils/libdwfl/dwfl_addrdwarf.c b/3rdparty/elfutils/libdwfl/dwfl_addrdwarf.c new file mode 100644 index 0000000..ba412ec --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_addrdwarf.c @@ -0,0 +1,37 @@ +/* Fetch libdw handle from address. + Copyright (C) 2005 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" + +Dwarf * +dwfl_addrdwarf (Dwfl *dwfl, Dwarf_Addr address, Dwarf_Addr *bias) +{ + return INTUSE(dwfl_module_getdwarf) (INTUSE(dwfl_addrmodule) (dwfl, address), + bias); +} +INTDEF (dwfl_addrdwarf) diff --git a/3rdparty/elfutils/libdwfl/dwfl_addrmodule.c b/3rdparty/elfutils/libdwfl/dwfl_addrmodule.c new file mode 100644 index 0000000..9234eb7 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_addrmodule.c @@ -0,0 +1,38 @@ +/* Find module containing address. + Copyright (C) 2005, 2006, 2007, 2008 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" + +Dwfl_Module * +dwfl_addrmodule (Dwfl *dwfl, Dwarf_Addr address) +{ + Dwfl_Module *mod; + (void) INTUSE(dwfl_addrsegment) (dwfl, address, &mod); + return mod; +} +INTDEF (dwfl_addrmodule) diff --git a/3rdparty/elfutils/libdwfl/dwfl_begin.c b/3rdparty/elfutils/libdwfl/dwfl_begin.c new file mode 100644 index 0000000..44c16a9 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_begin.c @@ -0,0 +1,51 @@ +/* Set up a session using libdwfl. + Copyright (C) 2005 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" + +Dwfl * +dwfl_begin (const Dwfl_Callbacks *callbacks) +{ + if (elf_version (EV_CURRENT) == EV_NONE) + { + __libdwfl_seterrno (DWFL_E_LIBELF); + return NULL; + } + + Dwfl *dwfl = calloc (1, sizeof *dwfl); + if (dwfl == NULL) + __libdwfl_seterrno (DWFL_E_NOMEM); + else + { + dwfl->callbacks = callbacks; + dwfl->offline_next_address = OFFLINE_REDZONE; + } + + return dwfl; +} +INTDEF (dwfl_begin) diff --git a/3rdparty/elfutils/libdwfl/dwfl_build_id_find_debuginfo.c b/3rdparty/elfutils/libdwfl/dwfl_build_id_find_debuginfo.c new file mode 100644 index 0000000..f1c64bc --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_build_id_find_debuginfo.c @@ -0,0 +1,128 @@ +/* Find the debuginfo file for a module from its build ID. + Copyright (C) 2007, 2009, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" +#include <unistd.h> + + +int +dwfl_build_id_find_debuginfo (Dwfl_Module *mod, + void **userdata __attribute__ ((unused)), + const char *modname __attribute__ ((unused)), + Dwarf_Addr base __attribute__ ((unused)), + const char *file __attribute__ ((unused)), + const char *debuglink __attribute__ ((unused)), + GElf_Word crc __attribute__ ((unused)), + char **debuginfo_file_name) +{ + int fd = -1; + + /* Are we looking for a separate debug file for the main file or for + an alternate (dwz multi) debug file? Alternatively we could check + whether the dwbias == -1. */ + if (mod->dw != NULL) + { + const void *build_id; + const char *altname; + ssize_t build_id_len = INTUSE(dwelf_dwarf_gnu_debugaltlink) (mod->dw, + &altname, + &build_id); + if (build_id_len > 0) + fd = __libdwfl_open_by_build_id (mod, true, debuginfo_file_name, + build_id_len, build_id); + + if (fd >= 0) + { + /* We need to open an Elf handle on the file so we can check its + build ID note for validation. Backdoor the handle into the + module data structure since we had to open it early anyway. */ + Dwfl_Error error = __libdw_open_file (&fd, &mod->alt_elf, + true, false); + if (error != DWFL_E_NOERROR) + __libdwfl_seterrno (error); + else + { + const void *alt_build_id; + ssize_t alt_len = INTUSE(dwelf_elf_gnu_build_id) (mod->alt_elf, + &alt_build_id); + if (alt_len > 0 && alt_len == build_id_len + && memcmp (build_id, alt_build_id, alt_len) == 0) + return fd; + else + { + /* A mismatch! */ + elf_end (mod->alt_elf); + mod->alt_elf = NULL; + close (fd); + fd = -1; + } + free (*debuginfo_file_name); + *debuginfo_file_name = NULL; + errno = 0; + } + } + return fd; + } + + /* We don't even have the Dwarf yet and it isn't in the main file. + Try to find separate debug file now using the module build id. */ + const unsigned char *bits; + GElf_Addr vaddr; + + if (INTUSE(dwfl_module_build_id) (mod, &bits, &vaddr) > 0) + fd = __libdwfl_open_mod_by_build_id (mod, true, debuginfo_file_name); + if (fd >= 0) + { + /* We need to open an Elf handle on the file so we can check its + build ID note for validation. Backdoor the handle into the + module data structure since we had to open it early anyway. */ + Dwfl_Error error = __libdw_open_file (&fd, &mod->debug.elf, true, false); + if (error != DWFL_E_NOERROR) + __libdwfl_seterrno (error); + else if (likely (__libdwfl_find_build_id (mod, false, + mod->debug.elf) == 2)) + { + /* Also backdoor the gratuitous flag. */ + mod->debug.valid = true; + return fd; + } + else + { + /* A mismatch! */ + elf_end (mod->debug.elf); + mod->debug.elf = NULL; + close (fd); + fd = -1; + } + free (*debuginfo_file_name); + *debuginfo_file_name = NULL; + errno = 0; + } + return fd; +} +INTDEF (dwfl_build_id_find_debuginfo) diff --git a/3rdparty/elfutils/libdwfl/dwfl_build_id_find_elf.c b/3rdparty/elfutils/libdwfl/dwfl_build_id_find_elf.c new file mode 100644 index 0000000..062aad1 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_build_id_find_elf.c @@ -0,0 +1,174 @@ +/* Find an ELF file for a module from its build ID. + Copyright (C) 2007-2010, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" +#include <inttypes.h> +#include <fcntl.h> +#include <unistd.h> + + +int +internal_function +__libdwfl_open_by_build_id (Dwfl_Module *mod, bool debug, char **file_name, + const size_t id_len, const uint8_t *id) +{ + /* Search debuginfo_path directories' .build-id/ subdirectories. */ + + char id_name[sizeof "/.build-id/" + 1 + id_len * 2 + sizeof ".debug" - 1]; + strcpy (id_name, "/.build-id/"); + int n = snprintf (&id_name[sizeof "/.build-id/" - 1], + 4, "%02" PRIx8 "/", (uint8_t) id[0]); + assert (n == 3); + for (size_t i = 1; i < id_len; ++i) + { + n = snprintf (&id_name[sizeof "/.build-id/" - 1 + 3 + (i - 1) * 2], + 3, "%02" PRIx8, (uint8_t) id[i]); + assert (n == 2); + } + if (debug) + strcpy (&id_name[sizeof "/.build-id/" - 1 + 3 + (id_len - 1) * 2], + ".debug"); + + const Dwfl_Callbacks *const cb = mod->dwfl->callbacks; + char *path = strdupa ((cb->debuginfo_path ? *cb->debuginfo_path : NULL) + ?: DEFAULT_DEBUGINFO_PATH); + + int fd = -1; + char *dir; + while (fd < 0 && (dir = strsep (&path, ":")) != NULL) + { + if (dir[0] == '+' || dir[0] == '-') + ++dir; + + /* Only absolute directory names are useful to us. */ + if (dir[0] != '/') + continue; + + size_t dirlen = strlen (dir); + char *name = malloc (dirlen + sizeof id_name); + if (unlikely (name == NULL)) + break; + memcpy (mempcpy (name, dir, dirlen), id_name, sizeof id_name); + + fd = TEMP_FAILURE_RETRY (open64 (name, O_RDONLY)); + if (fd >= 0) + { + if (*file_name != NULL) + free (*file_name); + *file_name = canonicalize_file_name (name); + if (*file_name == NULL) + { + *file_name = name; + name = NULL; + } + } + free (name); + } + + /* If we simply found nothing, clear errno. If we had some other error + with the file, report that. Possibly this should treat other errors + like ENOENT too. But ignoring all errors could mask some that should + be reported. */ + if (fd < 0 && errno == ENOENT) + errno = 0; + + return fd; +} + +int +internal_function +__libdwfl_open_mod_by_build_id (Dwfl_Module *mod, bool debug, char **file_name) +{ + /* If *FILE_NAME was primed into the module, leave it there + as the fallback when we have nothing to offer. */ + errno = 0; + if (mod->build_id_len <= 0) + return -1; + + const size_t id_len = mod->build_id_len; + const uint8_t *id = mod->build_id_bits; + + return __libdwfl_open_by_build_id (mod, debug, file_name, id_len, id); +} + +int +dwfl_build_id_find_elf (Dwfl_Module *mod, + void **userdata __attribute__ ((unused)), + const char *modname __attribute__ ((unused)), + Dwarf_Addr base __attribute__ ((unused)), + char **file_name, Elf **elfp) +{ + *elfp = NULL; + if (mod->is_executable && mod->dwfl->executable_for_core != NULL) + { + /* When dwfl_core_file_report was called with a non-NULL executable file + name this callback will replace the Dwfl_Module main.name with the + recorded executable file when MOD was identified as main executable + (which then triggers opening and reporting of the executable). */ + int fd = open64 (mod->dwfl->executable_for_core, O_RDONLY); + if (fd >= 0) + { + *file_name = strdup (mod->dwfl->executable_for_core); + if (*file_name != NULL) + return fd; + else + close (fd); + } + } + int fd = __libdwfl_open_mod_by_build_id (mod, false, file_name); + if (fd >= 0) + { + Dwfl_Error error = __libdw_open_file (&fd, elfp, true, false); + if (error != DWFL_E_NOERROR) + __libdwfl_seterrno (error); + else if (__libdwfl_find_build_id (mod, false, *elfp) == 2) + { + /* This is a backdoor signal to short-circuit the ID refresh. */ + mod->main.valid = true; + return fd; + } + else + { + /* This file does not contain the ID it should! */ + elf_end (*elfp); + *elfp = NULL; + close (fd); + fd = -1; + } + free (*file_name); + *file_name = NULL; + } + else if (errno == 0 && mod->build_id_len > 0) + /* Setting this with no file yet loaded is a marker that + the build ID is authoritative even if we also know a + putative *FILE_NAME. */ + mod->main.valid = true; + + return fd; +} +INTDEF (dwfl_build_id_find_elf) diff --git a/3rdparty/elfutils/libdwfl/dwfl_cumodule.c b/3rdparty/elfutils/libdwfl/dwfl_cumodule.c new file mode 100644 index 0000000..c5cf004 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_cumodule.c @@ -0,0 +1,36 @@ +/* Find the module for a CU DIE previously returned by libdwfl. + Copyright (C) 2005 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" + +Dwfl_Module * +dwfl_cumodule (Dwarf_Die *cudie) +{ + struct dwfl_cu *cu = (struct dwfl_cu *) cudie; + return cu->mod; +} diff --git a/3rdparty/elfutils/libdwfl/dwfl_dwarf_line.c b/3rdparty/elfutils/libdwfl/dwfl_dwarf_line.c new file mode 100644 index 0000000..e96f859 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_dwarf_line.c @@ -0,0 +1,43 @@ +/* Get information from a source line record returned by libdwfl. + Copyright (C) 2010 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" +#include "../libdw/libdwP.h" + +Dwarf_Line * +dwfl_dwarf_line (Dwfl_Line *line, Dwarf_Addr *bias) +{ + if (line == NULL) + return NULL; + + struct dwfl_cu *cu = dwfl_linecu (line); + const Dwarf_Line *info = &cu->die.cu->lines->info[line->idx]; + + *bias = dwfl_adjusted_dwarf_addr (cu->mod, 0); + return (Dwarf_Line *) info; +} diff --git a/3rdparty/elfutils/libdwfl/dwfl_end.c b/3rdparty/elfutils/libdwfl/dwfl_end.c new file mode 100644 index 0000000..33cae48 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_end.c @@ -0,0 +1,54 @@ +/* Finish a session using libdwfl. + Copyright (C) 2005, 2008, 2012-2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" + +void +dwfl_end (Dwfl *dwfl) +{ + if (dwfl == NULL) + return; + + if (dwfl->process) + __libdwfl_process_free (dwfl->process); + + free (dwfl->lookup_addr); + free (dwfl->lookup_module); + free (dwfl->lookup_segndx); + + Dwfl_Module *next = dwfl->modulelist; + while (next != NULL) + { + Dwfl_Module *dead = next; + next = dead->next; + __libdwfl_module_free (dead); + } + + free (dwfl->executable_for_core); + free (dwfl); +} diff --git a/3rdparty/elfutils/libdwfl/dwfl_error.c b/3rdparty/elfutils/libdwfl/dwfl_error.c new file mode 100644 index 0000000..d9ca9e7 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_error.c @@ -0,0 +1,159 @@ +/* Error handling in libdwfl. + Copyright (C) 2005-2010 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <libintl.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdlib.h> +#include <errno.h> + +#include "libdwflP.h" + + +/* The error number. */ +static __thread int global_error; + + +int +dwfl_errno (void) +{ + int result = global_error; + global_error = DWFL_E_NOERROR; + return result; +} +INTDEF (dwfl_errno) + + +static const struct msgtable +{ +#define DWFL_ERROR(name, text) char msg_##name[sizeof text]; + DWFL_ERRORS +#undef DWFL_ERROR +} msgtable = + { +#define DWFL_ERROR(name, text) text, + DWFL_ERRORS +#undef DWFL_ERROR + }; +#define msgstr (&msgtable.msg_NOERROR[0]) + +static const uint_fast16_t msgidx[] = +{ +#define DWFL_ERROR(name, text) \ + [DWFL_E_##name] = offsetof (struct msgtable, msg_##name), + DWFL_ERRORS +#undef DWFL_ERROR +}; +#define nmsgidx (sizeof msgidx / sizeof msgidx[0]) + + +static inline int +canonicalize (Dwfl_Error error) +{ + unsigned int value; + + switch (error) + { + default: + value = error; + if ((value &~ 0xffff) != 0) + break; + assert (value < nmsgidx); + break; + case DWFL_E_ERRNO: + value = DWFL_E (ERRNO, errno); + break; + case DWFL_E_LIBELF: + value = DWFL_E (LIBELF, elf_errno ()); + break; + case DWFL_E_LIBDW: + value = DWFL_E (LIBDW, INTUSE(dwarf_errno) ()); + break; +#if 0 + DWFL_E_LIBEBL: + value = DWFL_E (LIBEBL, ebl_errno ()); + break; +#endif + } + + return value; +} + +int +internal_function +__libdwfl_canon_error (Dwfl_Error error) +{ + return canonicalize (error); +} + +void +internal_function +__libdwfl_seterrno (Dwfl_Error error) +{ + global_error = canonicalize (error); +} + + +const char * +dwfl_errmsg (error) + int error; +{ + if (error == 0 || error == -1) + { + int last_error = global_error; + + if (error == 0 && last_error == 0) + return NULL; + + error = last_error; + global_error = DWFL_E_NOERROR; + } + + switch (error &~ 0xffff) + { + case OTHER_ERROR (ERRNO): + return strerror_r (error & 0xffff, "bad", 0); + case OTHER_ERROR (LIBELF): + return elf_errmsg (error & 0xffff); + case OTHER_ERROR (LIBDW): + return INTUSE(dwarf_errmsg) (error & 0xffff); +#if 0 + case OTHER_ERROR (LIBEBL): + return ebl_errmsg (error & 0xffff); +#endif + } + + return _(&msgstr[msgidx[(unsigned int) error < nmsgidx + ? error : DWFL_E_UNKNOWN_ERROR]]); +} +INTDEF (dwfl_errmsg) diff --git a/3rdparty/elfutils/libdwfl/dwfl_frame.c b/3rdparty/elfutils/libdwfl/dwfl_frame.c new file mode 100644 index 0000000..f6f86c0 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_frame.c @@ -0,0 +1,474 @@ +/* Get Dwarf Frame state for target PID or core file. + Copyright (C) 2013, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" +#include <sys/ptrace.h> +#include <unistd.h> + +/* Set STATE->pc_set from STATE->regs according to the backend. Return true on + success, false on error. */ +static bool +state_fetch_pc (Dwfl_Frame *state) +{ + switch (state->pc_state) + { + case DWFL_FRAME_STATE_PC_SET: + return true; + case DWFL_FRAME_STATE_PC_UNDEFINED: + abort (); + case DWFL_FRAME_STATE_ERROR: + { + Ebl *ebl = state->thread->process->ebl; + Dwarf_CIE abi_info; + if (ebl_abi_cfi (ebl, &abi_info) != 0) + { + __libdwfl_seterrno (DWFL_E_LIBEBL); + return false; + } + unsigned ra = abi_info.return_address_register; + /* dwarf_frame_state_reg_is_set is not applied here. */ + if (ra >= ebl_frame_nregs (ebl)) + { + __libdwfl_seterrno (DWFL_E_LIBEBL_BAD); + return false; + } + state->pc = state->regs[ra]; + state->pc_state = DWFL_FRAME_STATE_PC_SET; + } + return true; + } + abort (); +} + +/* Do not call it on your own, to be used by thread_* functions only. */ + +static void +state_free (Dwfl_Frame *state) +{ + Dwfl_Thread *thread = state->thread; + assert (thread->unwound == state); + thread->unwound = state->unwound; + free (state); +} + +static void +thread_free_all_states (Dwfl_Thread *thread) +{ + while (thread->unwound) + state_free (thread->unwound); +} + +static Dwfl_Frame * +state_alloc (Dwfl_Thread *thread) +{ + assert (thread->unwound == NULL); + Ebl *ebl = thread->process->ebl; + size_t nregs = ebl_frame_nregs (ebl); + if (nregs == 0) + return NULL; + assert (nregs < sizeof (((Dwfl_Frame *) NULL)->regs_set) * 8); + Dwfl_Frame *state = malloc (sizeof (*state) + sizeof (*state->regs) * nregs); + if (state == NULL) + return NULL; + state->thread = thread; + state->signal_frame = false; + state->initial_frame = true; + state->pc_state = DWFL_FRAME_STATE_ERROR; + memset (state->regs_set, 0, sizeof (state->regs_set)); + thread->unwound = state; + state->unwound = NULL; + return state; +} + +void +internal_function +__libdwfl_process_free (Dwfl_Process *process) +{ + Dwfl *dwfl = process->dwfl; + if (process->callbacks->detach != NULL) + process->callbacks->detach (dwfl, process->callbacks_arg); + assert (dwfl->process == process); + dwfl->process = NULL; + if (process->ebl_close) + ebl_closebackend (process->ebl); + free (process); + dwfl->attacherr = DWFL_E_NOERROR; +} + +/* Allocate new Dwfl_Process for DWFL. */ +static void +process_alloc (Dwfl *dwfl) +{ + Dwfl_Process *process = malloc (sizeof (*process)); + if (process == NULL) + return; + process->dwfl = dwfl; + dwfl->process = process; +} + +bool +dwfl_attach_state (Dwfl *dwfl, Elf *elf, pid_t pid, + const Dwfl_Thread_Callbacks *thread_callbacks, void *arg) +{ + if (dwfl->process != NULL) + { + __libdwfl_seterrno (DWFL_E_ATTACH_STATE_CONFLICT); + return false; + } + + /* Reset any previous error, we are just going to try again. */ + dwfl->attacherr = DWFL_E_NOERROR; + if (thread_callbacks == NULL || thread_callbacks->next_thread == NULL + || thread_callbacks->set_initial_registers == NULL) + { + dwfl->attacherr = DWFL_E_INVALID_ARGUMENT; + fail: + dwfl->attacherr = __libdwfl_canon_error (dwfl->attacherr); + __libdwfl_seterrno (dwfl->attacherr); + return false; + } + + Ebl *ebl; + bool ebl_close; + if (elf != NULL) + { + ebl = ebl_openbackend (elf); + ebl_close = true; + } + else + { + ebl = NULL; + for (Dwfl_Module *mod = dwfl->modulelist; mod != NULL; mod = mod->next) + { + /* Reading of the vDSO or (deleted) modules may fail as + /proc/PID/mem is unreadable without PTRACE_ATTACH and + we may not be PTRACE_ATTACH-ed now. MOD would not be + re-read later to unwind it when we are already + PTRACE_ATTACH-ed to PID. This happens when this function + is called from dwfl_linux_proc_attach with elf == NULL. + __libdwfl_module_getebl will call __libdwfl_getelf which + will call the find_elf callback. */ + if (strncmp (mod->name, "[vdso: ", 7) == 0 + || strcmp (strrchr (mod->name, ' ') ?: "", + " (deleted)") == 0) + continue; + Dwfl_Error error = __libdwfl_module_getebl (mod); + if (error != DWFL_E_NOERROR) + continue; + ebl = mod->ebl; + break; + } + ebl_close = false; + } + if (ebl == NULL) + { + /* Not identified EBL from any of the modules. */ + dwfl->attacherr = DWFL_E_PROCESS_NO_ARCH; + goto fail; + } + process_alloc (dwfl); + Dwfl_Process *process = dwfl->process; + if (process == NULL) + { + if (ebl_close) + ebl_closebackend (ebl); + dwfl->attacherr = DWFL_E_NOMEM; + goto fail; + } + process->ebl = ebl; + process->ebl_close = ebl_close; + process->pid = pid; + process->callbacks = thread_callbacks; + process->callbacks_arg = arg; + return true; +} +INTDEF(dwfl_attach_state) + +pid_t +dwfl_pid (Dwfl *dwfl) +{ + if (dwfl->attacherr != DWFL_E_NOERROR) + { + __libdwfl_seterrno (dwfl->attacherr); + return -1; + } + + if (dwfl->process == NULL) + { + __libdwfl_seterrno (DWFL_E_NO_ATTACH_STATE); + return -1; + } + return dwfl->process->pid; +} +INTDEF(dwfl_pid) + +Dwfl * +dwfl_thread_dwfl (Dwfl_Thread *thread) +{ + return thread->process->dwfl; +} +INTDEF(dwfl_thread_dwfl) + +pid_t +dwfl_thread_tid (Dwfl_Thread *thread) +{ + return thread->tid; +} +INTDEF(dwfl_thread_tid) + +Dwfl_Thread * +dwfl_frame_thread (Dwfl_Frame *state) +{ + return state->thread; +} +INTDEF(dwfl_frame_thread) + +int +dwfl_getthreads (Dwfl *dwfl, int (*callback) (Dwfl_Thread *thread, void *arg), + void *arg) +{ + if (dwfl->attacherr != DWFL_E_NOERROR) + { + __libdwfl_seterrno (dwfl->attacherr); + return -1; + } + + Dwfl_Process *process = dwfl->process; + if (process == NULL) + { + __libdwfl_seterrno (DWFL_E_NO_ATTACH_STATE); + return -1; + } + + Dwfl_Thread thread; + thread.process = process; + thread.unwound = NULL; + thread.callbacks_arg = NULL; + for (;;) + { + thread.tid = process->callbacks->next_thread (dwfl, + process->callbacks_arg, + &thread.callbacks_arg); + if (thread.tid < 0) + { + Dwfl_Error saved_errno = dwfl_errno (); + thread_free_all_states (&thread); + __libdwfl_seterrno (saved_errno); + return -1; + } + if (thread.tid == 0) + { + thread_free_all_states (&thread); + __libdwfl_seterrno (DWFL_E_NOERROR); + return 0; + } + int err = callback (&thread, arg); + if (err != DWARF_CB_OK) + { + thread_free_all_states (&thread); + return err; + } + assert (thread.unwound == NULL); + } + /* NOTREACHED */ +} +INTDEF(dwfl_getthreads) + +struct one_arg +{ + pid_t tid; + bool seen; + int (*callback) (Dwfl_Thread *thread, void *arg); + void *arg; + int ret; +}; + +static int +get_one_thread_cb (Dwfl_Thread *thread, void *arg) +{ + struct one_arg *oa = (struct one_arg *) arg; + if (! oa->seen && INTUSE(dwfl_thread_tid) (thread) == oa->tid) + { + oa->seen = true; + oa->ret = oa->callback (thread, oa->arg); + return DWARF_CB_ABORT; + } + + return DWARF_CB_OK; +} + +/* Note not currently exported, will be when there are more Dwfl_Thread + properties to query. Use dwfl_getthread_frames for now directly. */ +static int +getthread (Dwfl *dwfl, pid_t tid, + int (*callback) (Dwfl_Thread *thread, void *arg), + void *arg) +{ + if (dwfl->attacherr != DWFL_E_NOERROR) + { + __libdwfl_seterrno (dwfl->attacherr); + return -1; + } + + Dwfl_Process *process = dwfl->process; + if (process == NULL) + { + __libdwfl_seterrno (DWFL_E_NO_ATTACH_STATE); + return -1; + } + + if (process->callbacks->get_thread != NULL) + { + Dwfl_Thread thread; + thread.process = process; + thread.unwound = NULL; + thread.callbacks_arg = NULL; + + if (process->callbacks->get_thread (dwfl, tid, process->callbacks_arg, + &thread.callbacks_arg)) + { + int err; + thread.tid = tid; + err = callback (&thread, arg); + thread_free_all_states (&thread); + return err; + } + + return -1; + } + + struct one_arg oa = { .tid = tid, .callback = callback, + .arg = arg, .seen = false }; + int err = INTUSE(dwfl_getthreads) (dwfl, get_one_thread_cb, &oa); + + if (err == DWARF_CB_ABORT && oa.seen) + return oa.ret; + + if (err == DWARF_CB_OK && ! oa.seen) + { + errno = ESRCH; + __libdwfl_seterrno (DWFL_E_ERRNO); + return -1; + } + + return err; +} + +struct one_thread +{ + int (*callback) (Dwfl_Frame *frame, void *arg); + void *arg; +}; + +static int +get_one_thread_frames_cb (Dwfl_Thread *thread, void *arg) +{ + struct one_thread *ot = (struct one_thread *) arg; + return INTUSE(dwfl_thread_getframes) (thread, ot->callback, ot->arg); +} + +int +dwfl_getthread_frames (Dwfl *dwfl, pid_t tid, + int (*callback) (Dwfl_Frame *frame, void *arg), + void *arg) +{ + struct one_thread ot = { .callback = callback, .arg = arg }; + return getthread (dwfl, tid, get_one_thread_frames_cb, &ot); +} +INTDEF(dwfl_getthread_frames) + +int +dwfl_thread_getframes (Dwfl_Thread *thread, + int (*callback) (Dwfl_Frame *state, void *arg), + void *arg) +{ + if (thread->unwound != NULL) + { + /* We had to be called from inside CALLBACK. */ + __libdwfl_seterrno (DWFL_E_ATTACH_STATE_CONFLICT); + return -1; + } + Ebl *ebl = thread->process->ebl; + if (ebl_frame_nregs (ebl) == 0) + { + __libdwfl_seterrno (DWFL_E_NO_UNWIND); + return -1; + } + if (state_alloc (thread) == NULL) + { + __libdwfl_seterrno (DWFL_E_NOMEM); + return -1; + } + Dwfl_Process *process = thread->process; + if (! process->callbacks->set_initial_registers (thread, + thread->callbacks_arg)) + { + thread_free_all_states (thread); + return -1; + } + if (! state_fetch_pc (thread->unwound)) + { + if (process->callbacks->thread_detach) + process->callbacks->thread_detach (thread, thread->callbacks_arg); + thread_free_all_states (thread); + return -1; + } + + Dwfl_Frame *state; + do + { + state = thread->unwound; + int err = callback (state, arg); + if (err != DWARF_CB_OK) + { + if (process->callbacks->thread_detach) + process->callbacks->thread_detach (thread, thread->callbacks_arg); + thread_free_all_states (thread); + return err; + } + __libdwfl_frame_unwind (state); + /* The old frame is no longer needed. */ + state_free (thread->unwound); + state = thread->unwound; + } + while (state && state->pc_state == DWFL_FRAME_STATE_PC_SET); + + Dwfl_Error err = dwfl_errno (); + if (process->callbacks->thread_detach) + process->callbacks->thread_detach (thread, thread->callbacks_arg); + if (state == NULL || state->pc_state == DWFL_FRAME_STATE_ERROR) + { + thread_free_all_states (thread); + __libdwfl_seterrno (err); + return -1; + } + assert (state->pc_state == DWFL_FRAME_STATE_PC_UNDEFINED); + thread_free_all_states (thread); + return 0; +} +INTDEF(dwfl_thread_getframes) diff --git a/3rdparty/elfutils/libdwfl/dwfl_frame_pc.c b/3rdparty/elfutils/libdwfl/dwfl_frame_pc.c new file mode 100644 index 0000000..296c815 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_frame_pc.c @@ -0,0 +1,64 @@ +/* Get return address register value for frame. + Copyright (C) 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwflP.h" + +bool +dwfl_frame_pc (Dwfl_Frame *state, Dwarf_Addr *pc, bool *isactivation) +{ + assert (state->pc_state == DWFL_FRAME_STATE_PC_SET); + *pc = state->pc; + ebl_normalize_pc (state->thread->process->ebl, pc); + if (isactivation) + { + /* Bottom frame? */ + if (state->initial_frame) + *isactivation = true; + /* *ISACTIVATION is logical union of whether current or previous frame + state is SIGNAL_FRAME. */ + else if (state->signal_frame) + *isactivation = true; + else + { + /* If the previous frame has unwound unsuccessfully just silently do + not consider it could be a SIGNAL_FRAME. */ + __libdwfl_frame_unwind (state); + if (state->unwound == NULL + || state->unwound->pc_state != DWFL_FRAME_STATE_PC_SET) + *isactivation = false; + else + *isactivation = state->unwound->signal_frame; + } + } + return true; +} +INTDEF (dwfl_frame_pc) diff --git a/3rdparty/elfutils/libdwfl/dwfl_frame_regs.c b/3rdparty/elfutils/libdwfl/dwfl_frame_regs.c new file mode 100644 index 0000000..10803fe --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_frame_regs.c @@ -0,0 +1,57 @@ +/* Get Dwarf Frame state from modules present in DWFL. + Copyright (C) 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" + +bool +dwfl_thread_state_registers (Dwfl_Thread *thread, int firstreg, + unsigned nregs, const Dwarf_Word *regs) +{ + Dwfl_Frame *state = thread->unwound; + assert (state && state->unwound == NULL); + assert (state->initial_frame); + for (unsigned regno = firstreg; regno < firstreg + nregs; regno++) + if (! __libdwfl_frame_reg_set (state, regno, regs[regno - firstreg])) + { + __libdwfl_seterrno (DWFL_E_INVALID_REGISTER); + return false; + } + return true; +} +INTDEF(dwfl_thread_state_registers) + +void +dwfl_thread_state_register_pc (Dwfl_Thread *thread, Dwarf_Word pc) +{ + Dwfl_Frame *state = thread->unwound; + assert (state && state->unwound == NULL); + assert (state->initial_frame); + state->pc = pc; + state->pc_state = DWFL_FRAME_STATE_PC_SET; +} +INTDEF(dwfl_thread_state_register_pc) diff --git a/3rdparty/elfutils/libdwfl/dwfl_getdwarf.c b/3rdparty/elfutils/libdwfl/dwfl_getdwarf.c new file mode 100644 index 0000000..8d1d9ba --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_getdwarf.c @@ -0,0 +1,59 @@ +/* Iterate through modules to fetch Dwarf information. + Copyright (C) 2005, 2008 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" + +struct module_callback_info +{ + int (*callback) (Dwfl_Module *, void **, + const char *, Dwarf_Addr, + Dwarf *, Dwarf_Addr, void *); + void *arg; +}; + +static int +module_callback (Dwfl_Module *mod, void **userdata, + const char *name, Dwarf_Addr start, void *arg) +{ + const struct module_callback_info *info = arg; + Dwarf_Addr bias = 0; + Dwarf *dw = INTUSE(dwfl_module_getdwarf) (mod, &bias); + return (*info->callback) (mod, userdata, name, start, dw, bias, info->arg); +} + +ptrdiff_t +dwfl_getdwarf (Dwfl *dwfl, + int (*callback) (Dwfl_Module *, void **, + const char *, Dwarf_Addr, + Dwarf *, Dwarf_Addr, void *), + void *arg, + ptrdiff_t offset) +{ + struct module_callback_info info = { callback, arg }; + return INTUSE(dwfl_getmodules) (dwfl, &module_callback, &info, offset); +} diff --git a/3rdparty/elfutils/libdwfl/dwfl_getmodules.c b/3rdparty/elfutils/libdwfl/dwfl_getmodules.c new file mode 100644 index 0000000..eed9b4f --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_getmodules.c @@ -0,0 +1,92 @@ +/* Iterate through modules. + Copyright (C) 2005, 2008 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" + +ptrdiff_t +dwfl_getmodules (Dwfl *dwfl, + int (*callback) (Dwfl_Module *, void **, + const char *, Dwarf_Addr, void *), + void *arg, + ptrdiff_t offset) +{ + if (dwfl == NULL) + return -1; + + /* We iterate through the linked list when it's all we have. + But continuing from an offset is slow that way. So when + DWFL->lookup_module is populated, we can instead keep our + place by jumping directly into the array. Since the actions + of a callback could cause it to get populated, we must + choose the style of place-holder when we return an offset, + and we encode the choice in the low bits of that value. */ + + Dwfl_Module *m = dwfl->modulelist; + + if ((offset & 3) == 1) + { + offset >>= 2; + for (ptrdiff_t pos = 0; pos < offset; ++pos) + if (m == NULL) + return -1; + else + m = m->next; + } + else if (((offset & 3) == 2) && likely (dwfl->lookup_module != NULL)) + { + offset >>= 2; + + if ((size_t) offset - 1 == dwfl->lookup_elts) + return 0; + + if (unlikely ((size_t) offset - 1 > dwfl->lookup_elts)) + return -1; + + m = dwfl->lookup_module[offset - 1]; + if (unlikely (m == NULL)) + return -1; + } + else if (offset != 0) + { + __libdwfl_seterrno (DWFL_E_BADSTROFF); + return -1; + } + + while (m != NULL) + { + int ok = (*callback) (MODCB_ARGS (m), arg); + ++offset; + m = m->next; + if (ok != DWARF_CB_OK) + return ((dwfl->lookup_module == NULL) ? ((offset << 2) | 1) + : (((m == NULL ? (ptrdiff_t) dwfl->lookup_elts + 1 + : m->segment + 1) << 2) | 2)); + } + return 0; +} +INTDEF (dwfl_getmodules) diff --git a/3rdparty/elfutils/libdwfl/dwfl_getsrc.c b/3rdparty/elfutils/libdwfl/dwfl_getsrc.c new file mode 100644 index 0000000..8d4ae02 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_getsrc.c @@ -0,0 +1,36 @@ +/* Find source location for PC address. + Copyright (C) 2005 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" + +Dwfl_Line * +dwfl_getsrc (Dwfl *dwfl, Dwarf_Addr addr) +{ + return INTUSE(dwfl_module_getsrc) (INTUSE(dwfl_addrmodule) (dwfl, addr), + addr); +} diff --git a/3rdparty/elfutils/libdwfl/dwfl_getsrclines.c b/3rdparty/elfutils/libdwfl/dwfl_getsrclines.c new file mode 100644 index 0000000..bdfcf5c --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_getsrclines.c @@ -0,0 +1,48 @@ +/* Fetch source line information for CU. + Copyright (C) 2005, 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" + +int +dwfl_getsrclines (Dwarf_Die *cudie, size_t *nlines) +{ + struct dwfl_cu *cu = (struct dwfl_cu *) cudie; + + if (cu->lines == NULL) + { + Dwfl_Error error = __libdwfl_cu_getsrclines (cu); + if (error != DWFL_E_NOERROR) + { + __libdwfl_seterrno (error); + return -1; + } + } + + *nlines = cu->die.cu->lines->nlines; + return 0; +} diff --git a/3rdparty/elfutils/libdwfl/dwfl_line_comp_dir.c b/3rdparty/elfutils/libdwfl/dwfl_line_comp_dir.c new file mode 100644 index 0000000..bda09c4 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_line_comp_dir.c @@ -0,0 +1,43 @@ +/* Get information from a source line record returned by libdwfl. + Copyright (C) 2005, 2006 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" +#include <dwarf.h> + +const char * +dwfl_line_comp_dir (Dwfl_Line *line) +{ + if (line == NULL) + return NULL; + + struct dwfl_cu *cu = dwfl_linecu (line); + Dwarf_Attribute attr_mem; + return INTUSE(dwarf_formstring) (INTUSE(dwarf_attr) (&cu->die, + DW_AT_comp_dir, + &attr_mem)); +} diff --git a/3rdparty/elfutils/libdwfl/dwfl_linecu.c b/3rdparty/elfutils/libdwfl/dwfl_linecu.c new file mode 100644 index 0000000..ce78d29 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_linecu.c @@ -0,0 +1,41 @@ +/* Fetch the module containing a source line record returned by libdwfl. + Copyright (C) 2006 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" + +#undef dwfl_linecu + +Dwarf_Die * +dwfl_linecu (Dwfl_Line *line) +{ + if (line == NULL) + return NULL; + + struct dwfl_cu *cu = dwfl_linecu_inline (line); + return &cu->die; +} diff --git a/3rdparty/elfutils/libdwfl/dwfl_lineinfo.c b/3rdparty/elfutils/libdwfl/dwfl_lineinfo.c new file mode 100644 index 0000000..dfb27d8 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_lineinfo.c @@ -0,0 +1,55 @@ +/* Get information from a source line record returned by libdwfl. + Copyright (C) 2005-2010 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" +#include "../libdw/libdwP.h" + +const char * +dwfl_lineinfo (Dwfl_Line *line, Dwarf_Addr *addr, int *linep, int *colp, + Dwarf_Word *mtime, Dwarf_Word *length) +{ + if (line == NULL) + return NULL; + + struct dwfl_cu *cu = dwfl_linecu (line); + const Dwarf_Line *info = &cu->die.cu->lines->info[line->idx]; + + if (addr != NULL) + *addr = dwfl_adjusted_dwarf_addr (cu->mod, info->addr); + if (linep != NULL) + *linep = info->line; + if (colp != NULL) + *colp = info->column; + + struct Dwarf_Fileinfo_s *file = &info->files->info[info->file]; + if (mtime != NULL) + *mtime = file->mtime; + if (length != NULL) + *length = file->length; + return file->name; +} diff --git a/3rdparty/elfutils/libdwfl/dwfl_linemodule.c b/3rdparty/elfutils/libdwfl/dwfl_linemodule.c new file mode 100644 index 0000000..e4a35e0 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_linemodule.c @@ -0,0 +1,38 @@ +/* Fetch the module containing a source line record returned by libdwfl. + Copyright (C) 2005 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" + +Dwfl_Module * +dwfl_linemodule (Dwfl_Line *line) +{ + if (line == NULL) + return NULL; + + return dwfl_linecu (line)->mod; +} diff --git a/3rdparty/elfutils/libdwfl/dwfl_module.c b/3rdparty/elfutils/libdwfl/dwfl_module.c new file mode 100644 index 0000000..8efcfaa --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_module.c @@ -0,0 +1,222 @@ +/* Maintenance of module list in libdwfl. + Copyright (C) 2005, 2006, 2007, 2008, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" +#include <search.h> +#include <unistd.h> + +static void +free_cu (struct dwfl_cu *cu) +{ + if (cu->lines != NULL) + free (cu->lines); + free (cu); +} + +static void +nofree (void *arg __attribute__ ((unused))) +{ +} + +static void +free_file (struct dwfl_file *file) +{ + free (file->name); + + /* Close the fd only on the last reference. */ + if (file->elf != NULL && elf_end (file->elf) == 0 && file->fd != -1) + close (file->fd); +} + +void +internal_function +__libdwfl_module_free (Dwfl_Module *mod) +{ + if (mod->lazy_cu_root != NULL) + tdestroy (mod->lazy_cu_root, nofree); + + if (mod->aranges != NULL) + free (mod->aranges); + + if (mod->cu != NULL) + { + for (size_t i = 0; i < mod->ncu; ++i) + free_cu (mod->cu[i]); + free (mod->cu); + } + + if (mod->dw != NULL) + { + INTUSE(dwarf_end) (mod->dw); + if (mod->alt != NULL) + { + INTUSE(dwarf_end) (mod->alt); + if (mod->alt_elf != NULL) + elf_end (mod->alt_elf); + if (mod->alt_fd != -1) + close (mod->alt_fd); + } + } + + if (mod->ebl != NULL) + ebl_closebackend (mod->ebl); + + if (mod->debug.elf != mod->main.elf) + free_file (&mod->debug); + free_file (&mod->main); + free_file (&mod->aux_sym); + + if (mod->build_id_bits != NULL) + free (mod->build_id_bits); + + if (mod->reloc_info != NULL) + free (mod->reloc_info); + + if (mod->eh_cfi != NULL) + dwarf_cfi_end (mod->eh_cfi); + + free (mod->name); + free (mod); +} + +void +dwfl_report_begin_add (Dwfl *dwfl __attribute__ ((unused))) +{ + /* The lookup table will be cleared on demand, there is nothing we need + to do here. */ +} +INTDEF (dwfl_report_begin_add) + +void +dwfl_report_begin (Dwfl *dwfl) +{ + /* Clear the segment lookup table. */ + dwfl->lookup_elts = 0; + + for (Dwfl_Module *m = dwfl->modulelist; m != NULL; m = m->next) + m->gc = true; + + dwfl->offline_next_address = OFFLINE_REDZONE; +} +INTDEF (dwfl_report_begin) + +/* Report that a module called NAME spans addresses [START, END). + Returns the module handle, either existing or newly allocated, + or returns a null pointer for an allocation error. */ +Dwfl_Module * +dwfl_report_module (Dwfl *dwfl, const char *name, + GElf_Addr start, GElf_Addr end) +{ + Dwfl_Module **tailp = &dwfl->modulelist, **prevp = tailp; + + inline Dwfl_Module *use (Dwfl_Module *mod) + { + mod->next = *tailp; + *tailp = mod; + + if (unlikely (dwfl->lookup_module != NULL)) + { + free (dwfl->lookup_module); + dwfl->lookup_module = NULL; + } + + return mod; + } + + for (Dwfl_Module *m = *prevp; m != NULL; m = *(prevp = &m->next)) + { + if (m->low_addr == start && m->high_addr == end + && !strcmp (m->name, name)) + { + /* This module is still here. Move it to the place in the list + after the last module already reported. */ + *prevp = m->next; + m->gc = false; + return use (m); + } + + if (! m->gc) + tailp = &m->next; + } + + Dwfl_Module *mod = calloc (1, sizeof *mod); + if (mod == NULL) + goto nomem; + + mod->name = strdup (name); + if (mod->name == NULL) + { + free (mod); + nomem: + __libdwfl_seterrno (DWFL_E_NOMEM); + return NULL; + } + + mod->low_addr = start; + mod->high_addr = end; + mod->dwfl = dwfl; + + return use (mod); +} +INTDEF (dwfl_report_module) + + +/* Finish reporting the current set of modules to the library. + If REMOVED is not null, it's called for each module that + existed before but was not included in the current report. + Returns a nonzero return value from the callback. + DWFL cannot be used until this function has returned zero. */ +int +dwfl_report_end (Dwfl *dwfl, + int (*removed) (Dwfl_Module *, void *, + const char *, Dwarf_Addr, + void *arg), + void *arg) +{ + Dwfl_Module **tailp = &dwfl->modulelist; + while (*tailp != NULL) + { + Dwfl_Module *m = *tailp; + if (m->gc && removed != NULL) + { + int result = (*removed) (MODCB_ARGS (m), arg); + if (result != 0) + return result; + } + if (m->gc) + { + *tailp = m->next; + __libdwfl_module_free (m); + } + else + tailp = &m->next; + } + + return 0; +} +INTDEF (dwfl_report_end) diff --git a/3rdparty/elfutils/libdwfl/dwfl_module_addrdie.c b/3rdparty/elfutils/libdwfl/dwfl_module_addrdie.c new file mode 100644 index 0000000..20d2842 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_module_addrdie.c @@ -0,0 +1,45 @@ +/* Fetch the CU DIE for a PC address in a given module. + Copyright (C) 2005 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" + +Dwarf_Die * +dwfl_module_addrdie (Dwfl_Module *mod, Dwarf_Addr addr, Dwarf_Addr *bias) +{ + if (INTUSE(dwfl_module_getdwarf) (mod, bias) == NULL) + return NULL; + + struct dwfl_cu *cu; + Dwfl_Error error = __libdwfl_addrcu (mod, addr, &cu); + if (likely (error == DWFL_E_NOERROR)) + return &cu->die; + + __libdwfl_seterrno (error); + return NULL; +} +INTDEF (dwfl_module_addrdie) diff --git a/3rdparty/elfutils/libdwfl/dwfl_module_addrname.c b/3rdparty/elfutils/libdwfl/dwfl_module_addrname.c new file mode 100644 index 0000000..88a8139 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_module_addrname.c @@ -0,0 +1,38 @@ +/* Find debugging and symbol information for a module in libdwfl. + Copyright (C) 2005, 2006, 2007, 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" + +const char * +dwfl_module_addrname (Dwfl_Module *mod, GElf_Addr addr) +{ + GElf_Off off; + GElf_Sym sym; + return INTUSE(dwfl_module_addrinfo) (mod, addr, &off, &sym, + NULL, NULL, NULL); +} diff --git a/3rdparty/elfutils/libdwfl/dwfl_module_addrsym.c b/3rdparty/elfutils/libdwfl/dwfl_module_addrsym.c new file mode 100644 index 0000000..d205832 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_module_addrsym.c @@ -0,0 +1,289 @@ +/* Find debugging and symbol information for a module in libdwfl. + Copyright (C) 2005-2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" + +/* Returns the name of the symbol "closest" to ADDR. + Never returns symbols at addresses above ADDR. */ + +const char * +internal_function +__libdwfl_addrsym (Dwfl_Module *mod, GElf_Addr addr, GElf_Off *off, + GElf_Sym *closest_sym, GElf_Word *shndxp, + Elf **elfp, Dwarf_Addr *biasp, bool adjust_st_value) +{ + int syments = INTUSE(dwfl_module_getsymtab) (mod); + if (syments < 0) + return NULL; + + /* Return true iff we consider ADDR to lie in the same section as SYM. */ + GElf_Word addr_shndx = SHN_UNDEF; + Elf *addr_symelf = NULL; + inline bool same_section (GElf_Addr value, Elf *symelf, GElf_Word shndx) + { + /* For absolute symbols and the like, only match exactly. */ + if (shndx >= SHN_LORESERVE) + return value == addr; + + /* If value might not be st_value, the shndx of the symbol might + not match the section of the value. Explicitly look both up. */ + if (! adjust_st_value) + { + Dwarf_Addr v; + if (addr_shndx == SHN_UNDEF) + { + v = addr; + addr_shndx = __libdwfl_find_section_ndx (mod, &v); + } + + v = value; + return addr_shndx == __libdwfl_find_section_ndx (mod, &v); + } + + /* Figure out what section ADDR lies in. */ + if (addr_shndx == SHN_UNDEF || addr_symelf != symelf) + { + GElf_Addr mod_addr = dwfl_deadjust_st_value (mod, symelf, addr); + Elf_Scn *scn = NULL; + addr_shndx = SHN_ABS; + addr_symelf = symelf; + while ((scn = elf_nextscn (symelf, scn)) != NULL) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + if (likely (shdr != NULL) + && mod_addr >= shdr->sh_addr + && mod_addr < shdr->sh_addr + shdr->sh_size) + { + addr_shndx = elf_ndxscn (scn); + break; + } + } + } + + return shndx == addr_shndx && addr_symelf == symelf; + } + + /* Keep track of the closest symbol we have seen so far. + Here we store only symbols with nonzero st_size. */ + const char *closest_name = NULL; + GElf_Addr closest_value = 0; + GElf_Word closest_shndx = SHN_UNDEF; + Elf *closest_elf = NULL; + + /* Keep track of an eligible symbol with st_size == 0 as a fallback. */ + const char *sizeless_name = NULL; + GElf_Sym sizeless_sym = { 0, 0, 0, 0, 0, SHN_UNDEF }; + GElf_Addr sizeless_value = 0; + GElf_Word sizeless_shndx = SHN_UNDEF; + Elf *sizeless_elf = NULL; + + /* Keep track of the lowest address a relevant sizeless symbol could have. */ + GElf_Addr min_label = 0; + + /* Try one symbol and associated value from the search table. */ + inline void try_sym_value (GElf_Addr value, GElf_Sym *sym, + const char *name, GElf_Word shndx, + Elf *elf, bool resolved) + { + /* Even if we don't choose this symbol, its existence excludes + any sizeless symbol (assembly label) that is below its upper + bound. */ + if (value + sym->st_size > min_label) + min_label = value + sym->st_size; + + if (sym->st_size == 0 || addr - value < sym->st_size) + { + /* Return GELF_ST_BIND as higher-is-better integer. */ + inline int binding_value (const GElf_Sym *symp) + { + switch (GELF_ST_BIND (symp->st_info)) + { + case STB_GLOBAL: + return 3; + case STB_WEAK: + return 2; + case STB_LOCAL: + return 1; + default: + return 0; + } + } + + /* This symbol is a better candidate than the current one + if it's closer to ADDR or is global when it was local. */ + if (closest_name == NULL + || closest_value < value + || binding_value (closest_sym) < binding_value (sym)) + { + if (sym->st_size != 0) + { + *closest_sym = *sym; + closest_value = value; + closest_shndx = shndx; + closest_elf = elf; + closest_name = name; + } + else if (closest_name == NULL + && value >= min_label + && same_section (value, + resolved ? mod->main.elf : elf, shndx)) + { + /* Handwritten assembly symbols sometimes have no + st_size. If no symbol with proper size includes + the address, we'll use the closest one that is in + the same section as ADDR. */ + sizeless_sym = *sym; + sizeless_value = value; + sizeless_shndx = shndx; + sizeless_elf = elf; + sizeless_name = name; + } + } + /* When the beginning of its range is no closer, + the end of its range might be. Otherwise follow + GELF_ST_BIND preference. If all are equal prefer + the first symbol found. */ + else if (sym->st_size != 0 + && closest_value == value + && ((closest_sym->st_size > sym->st_size + && (binding_value (closest_sym) + <= binding_value (sym))) + || (closest_sym->st_size >= sym->st_size + && (binding_value (closest_sym) + < binding_value (sym))))) + { + *closest_sym = *sym; + closest_value = value; + closest_shndx = shndx; + closest_elf = elf; + closest_name = name; + } + } + } + + /* Look through the symbol table for a matching symbol. */ + inline void search_table (int start, int end) + { + for (int i = start; i < end; ++i) + { + GElf_Sym sym; + GElf_Addr value; + GElf_Word shndx; + Elf *elf; + bool resolved; + const char *name = __libdwfl_getsym (mod, i, &sym, &value, + &shndx, &elf, NULL, + &resolved, adjust_st_value); + if (name != NULL && name[0] != '\0' + && sym.st_shndx != SHN_UNDEF + && value <= addr + && GELF_ST_TYPE (sym.st_info) != STT_SECTION + && GELF_ST_TYPE (sym.st_info) != STT_FILE + && GELF_ST_TYPE (sym.st_info) != STT_TLS) + { + try_sym_value (value, &sym, name, shndx, elf, resolved); + + /* If this is an addrinfo variant and the value could be + resolved then also try matching the (adjusted) st_value. */ + if (resolved && mod->e_type != ET_REL) + { + GElf_Addr adjusted_st_value; + adjusted_st_value = dwfl_adjusted_st_value (mod, elf, + sym.st_value); + if (value != adjusted_st_value && adjusted_st_value <= addr) + try_sym_value (adjusted_st_value, &sym, name, shndx, + elf, false); + } + } + } + } + + /* First go through global symbols. mod->first_global and + mod->aux_first_global are setup by dwfl_module_getsymtab to the + index of the first global symbol in those symbol tables. Both + are non-zero when the table exist, except when there is only a + dynsym table loaded through phdrs, then first_global is zero and + there will be no auxiliary table. All symbols with local binding + come first in the symbol table, then all globals. The zeroth, + null entry, in the auxiliary table is skipped if there is a main + table. */ + int first_global = INTUSE (dwfl_module_getsymtab_first_global) (mod); + if (first_global < 0) + return NULL; + search_table (first_global == 0 ? 1 : first_global, syments); + + /* If we found nothing searching the global symbols, then try the locals. + Unless we have a global sizeless symbol that matches exactly. */ + if (closest_name == NULL && first_global > 1 + && (sizeless_name == NULL || sizeless_value != addr)) + search_table (1, first_global); + + /* If we found no proper sized symbol to use, fall back to the best + candidate sizeless symbol we found, if any. */ + if (closest_name == NULL + && sizeless_name != NULL && sizeless_value >= min_label) + { + *closest_sym = sizeless_sym; + closest_value = sizeless_value; + closest_shndx = sizeless_shndx; + closest_elf = sizeless_elf; + closest_name = sizeless_name; + } + + *off = addr - closest_value; + + if (shndxp != NULL) + *shndxp = closest_shndx; + if (elfp != NULL) + *elfp = closest_elf; + if (biasp != NULL) + *biasp = dwfl_adjusted_st_value (mod, closest_elf, 0); + return closest_name; +} + + +const char * +dwfl_module_addrsym (Dwfl_Module *mod, GElf_Addr addr, + GElf_Sym *closest_sym, GElf_Word *shndxp) +{ + GElf_Off off; + return __libdwfl_addrsym (mod, addr, &off, closest_sym, shndxp, + NULL, NULL, true); +} +INTDEF (dwfl_module_addrsym) + +const char +*dwfl_module_addrinfo (Dwfl_Module *mod, GElf_Addr address, + GElf_Off *offset, GElf_Sym *sym, + GElf_Word *shndxp, Elf **elfp, Dwarf_Addr *bias) +{ + return __libdwfl_addrsym (mod, address, offset, sym, shndxp, elfp, bias, + false); +} +INTDEF (dwfl_module_addrinfo) diff --git a/3rdparty/elfutils/libdwfl/dwfl_module_build_id.c b/3rdparty/elfutils/libdwfl/dwfl_module_build_id.c new file mode 100644 index 0000000..350bbf8 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_module_build_id.c @@ -0,0 +1,117 @@ +/* Return build ID information for a module. + Copyright (C) 2007-2010, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" + +static int +found_build_id (Dwfl_Module *mod, bool set, + const void *bits, int len, GElf_Addr vaddr) +{ + if (!set) + /* When checking bits, we do not compare VADDR because the + address found in a debuginfo file may not match the main + file as modified by prelink. */ + return 1 + (mod->build_id_len == len + && !memcmp (bits, mod->build_id_bits, len)); + + void *copy = malloc (len); + if (unlikely (copy == NULL)) + { + __libdwfl_seterrno (DWFL_E_NOMEM); + return -1; + } + + mod->build_id_bits = memcpy (copy, bits, len); + mod->build_id_vaddr = vaddr; + mod->build_id_len = len; + return len; +} + +int +internal_function +__libdwfl_find_build_id (Dwfl_Module *mod, bool set, Elf *elf) +{ + const void *build_id_bits; + GElf_Addr build_id_elfaddr; + int build_id_len; + + /* For mod == NULL use dwelf_elf_gnu_build_id directly. */ + assert (mod != NULL); + + int result = __libdwfl_find_elf_build_id (mod, elf, &build_id_bits, + &build_id_elfaddr, &build_id_len); + if (result <= 0) + return result; + + GElf_Addr build_id_vaddr = build_id_elfaddr + (build_id_elfaddr != 0 + ? mod->main_bias : 0); + return found_build_id (mod, set, build_id_bits, build_id_len, build_id_vaddr); +} + +int +dwfl_module_build_id (Dwfl_Module *mod, + const unsigned char **bits, GElf_Addr *vaddr) +{ + if (mod == NULL) + return -1; + + if (mod->build_id_len == 0 && mod->main.elf != NULL) + { + /* We have the file, but have not examined it yet. */ + int result = __libdwfl_find_build_id (mod, true, mod->main.elf); + if (result <= 0) + { + mod->build_id_len = -1; /* Cache negative result. */ + return result; + } + } + + if (mod->build_id_len <= 0) + return 0; + + *bits = mod->build_id_bits; + *vaddr = mod->build_id_vaddr; + return mod->build_id_len; +} +INTDEF (dwfl_module_build_id) +NEW_VERSION (dwfl_module_build_id, ELFUTILS_0.138) + +#ifdef SHARED +COMPAT_VERSION (dwfl_module_build_id, ELFUTILS_0.130, vaddr_at_end) + +int +_compat_vaddr_at_end_dwfl_module_build_id (Dwfl_Module *mod, + const unsigned char **bits, + GElf_Addr *vaddr) +{ + int result = INTUSE(dwfl_module_build_id) (mod, bits, vaddr); + if (result > 0) + *vaddr += (result + 3) & -4; + return result; +} +#endif diff --git a/3rdparty/elfutils/libdwfl/dwfl_module_dwarf_cfi.c b/3rdparty/elfutils/libdwfl/dwfl_module_dwarf_cfi.c new file mode 100644 index 0000000..5182d6a --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_module_dwarf_cfi.c @@ -0,0 +1,71 @@ +/* Find DWARF CFI for a module in libdwfl. + Copyright (C) 2009-2010 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" +#include "../libdw/cfi.h" + +Dwarf_CFI * +internal_function +__libdwfl_set_cfi (Dwfl_Module *mod, Dwarf_CFI **slot, Dwarf_CFI *cfi) +{ + if (cfi != NULL && cfi->ebl == NULL) + { + Dwfl_Error error = __libdwfl_module_getebl (mod); + if (error == DWFL_E_NOERROR) + cfi->ebl = mod->ebl; + else + { + if (slot == &mod->eh_cfi) + INTUSE(dwarf_cfi_end) (cfi); + __libdwfl_seterrno (error); + return NULL; + } + } + + return *slot = cfi; +} + +Dwarf_CFI * +dwfl_module_dwarf_cfi (mod, bias) + Dwfl_Module *mod; + Dwarf_Addr *bias; +{ + if (mod == NULL) + return NULL; + + if (mod->dwarf_cfi != NULL) + { + *bias = dwfl_adjusted_dwarf_addr (mod, 0); + return mod->dwarf_cfi; + } + + return __libdwfl_set_cfi (mod, &mod->dwarf_cfi, + INTUSE(dwarf_getcfi) + (INTUSE(dwfl_module_getdwarf) (mod, bias))); +} +INTDEF (dwfl_module_dwarf_cfi) diff --git a/3rdparty/elfutils/libdwfl/dwfl_module_eh_cfi.c b/3rdparty/elfutils/libdwfl/dwfl_module_eh_cfi.c new file mode 100644 index 0000000..da10d9f --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_module_eh_cfi.c @@ -0,0 +1,57 @@ +/* Find EH CFI for a module in libdwfl. + Copyright (C) 2009-2010 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" +#include "../libdw/cfi.h" + +Dwarf_CFI * +dwfl_module_eh_cfi (mod, bias) + Dwfl_Module *mod; + Dwarf_Addr *bias; +{ + if (mod == NULL) + return NULL; + + if (mod->eh_cfi != NULL) + { + *bias = dwfl_adjusted_address (mod, 0); + return mod->eh_cfi; + } + + __libdwfl_getelf (mod); + if (mod->elferr != DWFL_E_NOERROR) + { + __libdwfl_seterrno (mod->elferr); + return NULL; + } + + *bias = dwfl_adjusted_address (mod, 0); + return __libdwfl_set_cfi (mod, &mod->eh_cfi, + INTUSE(dwarf_getcfi_elf) (mod->main.elf)); +} +INTDEF (dwfl_module_eh_cfi) diff --git a/3rdparty/elfutils/libdwfl/dwfl_module_getdwarf.c b/3rdparty/elfutils/libdwfl/dwfl_module_getdwarf.c new file mode 100644 index 0000000..494407d --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_module_getdwarf.c @@ -0,0 +1,1358 @@ +/* Find debugging and symbol information for a module in libdwfl. + Copyright (C) 2005-2012, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" +#include <inttypes.h> +#include <fcntl.h> +#include <string.h> +#include <unistd.h> +#include "../libdw/libdwP.h" /* DWARF_E_* values are here. */ +#include "../libelf/libelfP.h" + +static inline Dwfl_Error +open_elf_file (Elf **elf, int *fd, char **name) +{ + if (*elf == NULL) + { + /* CBFAIL uses errno if it's set, so clear it first in case we don't + set it with an open failure below. */ + errno = 0; + + /* If there was a pre-primed file name left that the callback left + behind, try to open that file name. */ + if (*fd < 0 && *name != NULL) + *fd = TEMP_FAILURE_RETRY (open64 (*name, O_RDONLY)); + + if (*fd < 0) + return CBFAIL; + + return __libdw_open_file (fd, elf, true, false); + } + else if (unlikely (elf_kind (*elf) != ELF_K_ELF)) + { + elf_end (*elf); + *elf = NULL; + close (*fd); + *fd = -1; + return DWFL_E_BADELF; + } + + /* Elf file already open and looks fine. */ + return DWFL_E_NOERROR; +} + +/* Open libelf FILE->fd and compute the load base of ELF as loaded in MOD. + When we return success, FILE->elf and FILE->vaddr are set up. */ +static inline Dwfl_Error +open_elf (Dwfl_Module *mod, struct dwfl_file *file) +{ + Dwfl_Error error = open_elf_file (&file->elf, &file->fd, &file->name); + if (error != DWFL_E_NOERROR) + return error; + + GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (file->elf, &ehdr_mem); + if (ehdr == NULL) + { + elf_error: + elf_end (file->elf); + file->elf = NULL; + close (file->fd); + file->fd = -1; + return DWFL_E (LIBELF, elf_errno ()); + } + + if (ehdr->e_type != ET_REL) + { + /* In any non-ET_REL file, we compute the "synchronization address". + + We start with the address at the end of the first PT_LOAD + segment. When prelink converts REL to RELA in an ET_DYN + file, it expands the space between the beginning of the + segment and the actual code/data addresses. Since that + change wasn't made in the debug file, the distance from + p_vaddr to an address of interest (in an st_value or DWARF + data) now differs between the main and debug files. The + distance from address_sync to an address of interest remains + consistent. + + If there are no section headers at all (full stripping), then + the end of the first segment is a valid synchronization address. + This cannot happen in a prelinked file, since prelink itself + relies on section headers for prelinking and for undoing it. + (If you do full stripping on a prelinked file, then you get what + you deserve--you can neither undo the prelinking, nor expect to + line it up with a debug file separated before prelinking.) + + However, when prelink processes an ET_EXEC file, it can do + something different. There it juggles the "special" sections + (SHT_DYNSYM et al) to make space for the additional prelink + special sections. Sometimes it will do this by moving a special + section like .dynstr after the real program sections in the first + PT_LOAD segment--i.e. to the end. That changes the end address of + the segment, so it no longer lines up correctly and is not a valid + synchronization address to use. Because of this, we need to apply + a different prelink-savvy means to discover the synchronization + address when there is a separate debug file and a prelinked main + file. That is done in find_debuginfo, below. */ + + size_t phnum; + if (unlikely (elf_getphdrnum (file->elf, &phnum) != 0)) + goto elf_error; + + file->vaddr = file->address_sync = 0; + for (size_t i = 0; i < phnum; ++i) + { + GElf_Phdr ph_mem; + GElf_Phdr *ph = gelf_getphdr (file->elf, i, &ph_mem); + if (unlikely (ph == NULL)) + goto elf_error; + if (ph->p_type == PT_LOAD) + { + file->vaddr = ph->p_vaddr & -ph->p_align; + file->address_sync = ph->p_vaddr + ph->p_memsz; + break; + } + } + } + + /* We only want to set the module e_type explictly once, derived from + the main ELF file. (It might be changed for the kernel, because + that is special - see below.) open_elf is always called first for + the main ELF file, because both find_dw and find_symtab call + __libdwfl_getelf first to open the main file. So don't let debug + or aux files override the module e_type. The kernel heuristic + below could otherwise trigger for non-kernel/non-main files, since + their phdrs might not match the actual load addresses. */ + if (file == &mod->main) + { + mod->e_type = ehdr->e_type; + + /* Relocatable Linux kernels are ET_EXEC but act like ET_DYN. */ + if (mod->e_type == ET_EXEC && file->vaddr != mod->low_addr) + mod->e_type = ET_DYN; + } + else + assert (mod->main.elf != NULL); + + return DWFL_E_NOERROR; +} + +/* We have an authoritative build ID for this module MOD, so don't use + a file by name that doesn't match that ID. */ +static void +mod_verify_build_id (Dwfl_Module *mod) +{ + assert (mod->build_id_len > 0); + + switch (__builtin_expect (__libdwfl_find_build_id (mod, false, + mod->main.elf), 2)) + { + case 2: + /* Build ID matches as it should. */ + return; + + case -1: /* ELF error. */ + mod->elferr = INTUSE(dwfl_errno) (); + break; + + case 0: /* File has no build ID note. */ + case 1: /* FIle has a build ID that does not match. */ + mod->elferr = DWFL_E_WRONG_ID_ELF; + break; + + default: + abort (); + } + + /* We get here when it was the right ELF file. Clear it out. */ + elf_end (mod->main.elf); + mod->main.elf = NULL; + if (mod->main.fd >= 0) + { + close (mod->main.fd); + mod->main.fd = -1; + } +} + +/* Find the main ELF file for this module and open libelf on it. + When we return success, MOD->main.elf and MOD->main.bias are set up. */ +void +internal_function +__libdwfl_getelf (Dwfl_Module *mod) +{ + if (mod->main.elf != NULL /* Already done. */ + || mod->elferr != DWFL_E_NOERROR) /* Cached failure. */ + return; + + mod->main.fd = (*mod->dwfl->callbacks->find_elf) (MODCB_ARGS (mod), + &mod->main.name, + &mod->main.elf); + const bool fallback = mod->main.elf == NULL && mod->main.fd < 0; + mod->elferr = open_elf (mod, &mod->main); + if (mod->elferr != DWFL_E_NOERROR) + return; + + if (!mod->main.valid) + { + /* Clear any explicitly reported build ID, just in case it was wrong. + We'll fetch it from the file when asked. */ + free (mod->build_id_bits); + mod->build_id_bits = NULL; + mod->build_id_len = 0; + } + else if (fallback) + mod_verify_build_id (mod); + + mod->main_bias = mod->e_type == ET_REL ? 0 : mod->low_addr - mod->main.vaddr; +} + +/* If the main file might have been prelinked, then we need to + discover the correct synchronization address between the main and + debug files. Because of prelink's section juggling, we cannot rely + on the address_sync computed from PT_LOAD segments (see open_elf). + + We will attempt to discover a synchronization address based on the + section headers instead. But finding a section address that is + safe to use requires identifying which sections are SHT_PROGBITS. + We can do that in the main file, but in the debug file all the + allocated sections have been transformed into SHT_NOBITS so we have + lost the means to match them up correctly. + + The only method left to us is to decode the .gnu.prelink_undo + section in the prelinked main file. This shows what the sections + looked like before prelink juggled them--when they still had a + direct correspondence to the debug file. */ +static Dwfl_Error +find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file) +{ + /* The magic section is only identified by name. */ + size_t shstrndx; + if (elf_getshdrstrndx (mod->main.elf, &shstrndx) < 0) + return DWFL_E_LIBELF; + + Elf_Scn *scn = NULL; + while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + if (unlikely (shdr == NULL)) + return DWFL_E_LIBELF; + if (shdr->sh_type == SHT_PROGBITS + && !(shdr->sh_flags & SHF_ALLOC) + && shdr->sh_name != 0) + { + const char *secname = elf_strptr (mod->main.elf, shstrndx, + shdr->sh_name); + if (unlikely (secname == NULL)) + return DWFL_E_LIBELF; + if (!strcmp (secname, ".gnu.prelink_undo")) + break; + } + } + + if (scn == NULL) + /* There was no .gnu.prelink_undo section. */ + return DWFL_E_NOERROR; + + Elf_Data *undodata = elf_rawdata (scn, NULL); + if (unlikely (undodata == NULL)) + return DWFL_E_LIBELF; + + /* Decode the section. It consists of the original ehdr, phdrs, + and shdrs (but omits section 0). */ + + union + { + Elf32_Ehdr e32; + Elf64_Ehdr e64; + } ehdr; + Elf_Data dst = + { + .d_buf = &ehdr, + .d_size = sizeof ehdr, + .d_type = ELF_T_EHDR, + .d_version = EV_CURRENT + }; + Elf_Data src = *undodata; + src.d_size = gelf_fsize (mod->main.elf, ELF_T_EHDR, 1, EV_CURRENT); + src.d_type = ELF_T_EHDR; + if (unlikely (gelf_xlatetom (mod->main.elf, &dst, &src, + elf_getident (mod->main.elf, NULL)[EI_DATA]) + == NULL)) + return DWFL_E_LIBELF; + + size_t shentsize = gelf_fsize (mod->main.elf, ELF_T_SHDR, 1, EV_CURRENT); + size_t phentsize = gelf_fsize (mod->main.elf, ELF_T_PHDR, 1, EV_CURRENT); + + uint_fast16_t phnum; + uint_fast16_t shnum; + if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32) + { + if (ehdr.e32.e_shentsize != shentsize + || ehdr.e32.e_phentsize != phentsize) + return DWFL_E_BAD_PRELINK; + phnum = ehdr.e32.e_phnum; + shnum = ehdr.e32.e_shnum; + } + else + { + if (ehdr.e64.e_shentsize != shentsize + || ehdr.e64.e_phentsize != phentsize) + return DWFL_E_BAD_PRELINK; + phnum = ehdr.e64.e_phnum; + shnum = ehdr.e64.e_shnum; + } + + /* Since prelink does not store the zeroth section header in the undo + section, it cannot support SHN_XINDEX encoding. */ + if (unlikely (shnum >= SHN_LORESERVE) + || unlikely (undodata->d_size != (src.d_size + + phnum * phentsize + + (shnum - 1) * shentsize))) + return DWFL_E_BAD_PRELINK; + + /* We look at the allocated SHT_PROGBITS (or SHT_NOBITS) sections. (Most + every file will have some SHT_PROGBITS sections, but it's possible to + have one with nothing but .bss, i.e. SHT_NOBITS.) The special sections + that can be moved around have different sh_type values--except for + .interp, the section that became the PT_INTERP segment. So we exclude + the SHT_PROGBITS section whose address matches the PT_INTERP p_vaddr. + For this reason, we must examine the phdrs first to find PT_INTERP. */ + + GElf_Addr main_interp = 0; + { + size_t main_phnum; + if (unlikely (elf_getphdrnum (mod->main.elf, &main_phnum))) + return DWFL_E_LIBELF; + for (size_t i = 0; i < main_phnum; ++i) + { + GElf_Phdr phdr; + if (unlikely (gelf_getphdr (mod->main.elf, i, &phdr) == NULL)) + return DWFL_E_LIBELF; + if (phdr.p_type == PT_INTERP) + { + main_interp = phdr.p_vaddr; + break; + } + } + } + + src.d_buf += src.d_size; + src.d_type = ELF_T_PHDR; + src.d_size = phnum * phentsize; + + GElf_Addr undo_interp = 0; + { + union + { + Elf32_Phdr p32[phnum]; + Elf64_Phdr p64[phnum]; + } phdr; + dst.d_buf = &phdr; + dst.d_size = sizeof phdr; + if (unlikely (gelf_xlatetom (mod->main.elf, &dst, &src, + ehdr.e32.e_ident[EI_DATA]) == NULL)) + return DWFL_E_LIBELF; + if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32) + { + for (uint_fast16_t i = 0; i < phnum; ++i) + if (phdr.p32[i].p_type == PT_INTERP) + { + undo_interp = phdr.p32[i].p_vaddr; + break; + } + } + else + { + for (uint_fast16_t i = 0; i < phnum; ++i) + if (phdr.p64[i].p_type == PT_INTERP) + { + undo_interp = phdr.p64[i].p_vaddr; + break; + } + } + } + + if (unlikely ((main_interp == 0) != (undo_interp == 0))) + return DWFL_E_BAD_PRELINK; + + src.d_buf += src.d_size; + src.d_type = ELF_T_SHDR; + src.d_size = gelf_fsize (mod->main.elf, ELF_T_SHDR, shnum - 1, EV_CURRENT); + + union + { + Elf32_Shdr s32[shnum - 1]; + Elf64_Shdr s64[shnum - 1]; + } shdr; + dst.d_buf = &shdr; + dst.d_size = sizeof shdr; + if (unlikely (gelf_xlatetom (mod->main.elf, &dst, &src, + ehdr.e32.e_ident[EI_DATA]) == NULL)) + return DWFL_E_LIBELF; + + /* Now we can look at the original section headers of the main file + before it was prelinked. First we'll apply our method to the main + file sections as they are after prelinking, to calculate the + synchronization address of the main file. Then we'll apply that + same method to the saved section headers, to calculate the matching + synchronization address of the debug file. + + The method is to consider SHF_ALLOC sections that are either + SHT_PROGBITS or SHT_NOBITS, excluding the section whose sh_addr + matches the PT_INTERP p_vaddr. The special sections that can be + moved by prelink have other types, except for .interp (which + becomes PT_INTERP). The "real" sections cannot move as such, but + .bss can be split into .dynbss and .bss, with the total memory + image remaining the same but being spread across the two sections. + So we consider the highest section end, which still matches up. */ + + GElf_Addr highest; + + inline void consider_shdr (GElf_Addr interp, + GElf_Word sh_type, + GElf_Xword sh_flags, + GElf_Addr sh_addr, + GElf_Xword sh_size) + { + if ((sh_flags & SHF_ALLOC) + && ((sh_type == SHT_PROGBITS && sh_addr != interp) + || sh_type == SHT_NOBITS)) + { + const GElf_Addr sh_end = sh_addr + sh_size; + if (sh_end > highest) + highest = sh_end; + } + } + + highest = 0; + scn = NULL; + while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL) + { + GElf_Shdr sh_mem; + GElf_Shdr *sh = gelf_getshdr (scn, &sh_mem); + if (unlikely (sh == NULL)) + return DWFL_E_LIBELF; + consider_shdr (main_interp, sh->sh_type, sh->sh_flags, + sh->sh_addr, sh->sh_size); + } + if (highest > mod->main.vaddr) + { + mod->main.address_sync = highest; + + highest = 0; + if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32) + for (size_t i = 0; i < shnum - 1; ++i) + consider_shdr (undo_interp, shdr.s32[i].sh_type, shdr.s32[i].sh_flags, + shdr.s32[i].sh_addr, shdr.s32[i].sh_size); + else + for (size_t i = 0; i < shnum - 1; ++i) + consider_shdr (undo_interp, shdr.s64[i].sh_type, shdr.s64[i].sh_flags, + shdr.s64[i].sh_addr, shdr.s64[i].sh_size); + + if (highest > file->vaddr) + file->address_sync = highest; + else + return DWFL_E_BAD_PRELINK; + } + + return DWFL_E_NOERROR; +} + +/* Find the separate debuginfo file for this module and open libelf on it. + When we return success, MOD->debug is set up. */ +static Dwfl_Error +find_debuginfo (Dwfl_Module *mod) +{ + if (mod->debug.elf != NULL) + return DWFL_E_NOERROR; + + GElf_Word debuglink_crc = 0; + const char *debuglink_file; + debuglink_file = INTUSE(dwelf_elf_gnu_debuglink) (mod->main.elf, + &debuglink_crc); + + mod->debug.fd = (*mod->dwfl->callbacks->find_debuginfo) (MODCB_ARGS (mod), + mod->main.name, + debuglink_file, + debuglink_crc, + &mod->debug.name); + Dwfl_Error result = open_elf (mod, &mod->debug); + if (result == DWFL_E_NOERROR && mod->debug.address_sync != 0) + result = find_prelink_address_sync (mod, &mod->debug); + return result; +} + +/* Try to find the alternative debug link for the given DWARF and set + it if found. Only called when mod->dw is already setup but still + might need an alternative (dwz multi) debug file. filename is either + the main or debug name from which the Dwarf was created. */ +static void +find_debug_altlink (Dwfl_Module *mod, const char *filename) +{ + assert (mod->dw != NULL); + + const char *altname; + const void *build_id; + ssize_t build_id_len = INTUSE(dwelf_dwarf_gnu_debugaltlink) (mod->dw, + &altname, + &build_id); + + if (build_id_len > 0) + { + /* We could store altfile in the module, but don't really need it. */ + char *altfile = NULL; + mod->alt_fd = (*mod->dwfl->callbacks->find_debuginfo) (MODCB_ARGS (mod), + filename, + altname, + 0, + &altfile); + + /* The (internal) callbacks might just set mod->alt_elf directly + because they open the Elf anyway for sanity checking. + Otherwise open either the given file name or use the fd + returned. */ + Dwfl_Error error = open_elf_file (&mod->alt_elf, &mod->alt_fd, + &altfile); + if (error == DWFL_E_NOERROR) + { + mod->alt = INTUSE(dwarf_begin_elf) (mod->alt_elf, + DWARF_C_READ, NULL); + if (mod->alt == NULL) + { + elf_end (mod->alt_elf); + mod->alt_elf = NULL; + close (mod->alt_fd); + mod->alt_fd = -1; + } + else + dwarf_setalt (mod->dw, mod->alt); + } + + free (altfile); /* See above, we don't really need it. */ + } +} + +/* Try to find a symbol table in FILE. + Returns DWFL_E_NOERROR if a proper one is found. + Returns DWFL_E_NO_SYMTAB if not, but still sets results for SHT_DYNSYM. */ +static Dwfl_Error +load_symtab (struct dwfl_file *file, struct dwfl_file **symfile, + Elf_Scn **symscn, Elf_Scn **xndxscn, + size_t *syments, int *first_global, GElf_Word *strshndx) +{ + bool symtab = false; + Elf_Scn *scn = NULL; + while ((scn = elf_nextscn (file->elf, scn)) != NULL) + { + GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem); + if (shdr != NULL) + switch (shdr->sh_type) + { + case SHT_SYMTAB: + if (shdr->sh_entsize == 0) + break; + symtab = true; + *symscn = scn; + *symfile = file; + *strshndx = shdr->sh_link; + *syments = shdr->sh_size / shdr->sh_entsize; + *first_global = shdr->sh_info; + if (*xndxscn != NULL) + return DWFL_E_NOERROR; + break; + + case SHT_DYNSYM: + if (symtab) + break; + /* Use this if need be, but keep looking for SHT_SYMTAB. */ + if (shdr->sh_entsize == 0) + break; + *symscn = scn; + *symfile = file; + *strshndx = shdr->sh_link; + *syments = shdr->sh_size / shdr->sh_entsize; + *first_global = shdr->sh_info; + break; + + case SHT_SYMTAB_SHNDX: + *xndxscn = scn; + if (symtab) + return DWFL_E_NOERROR; + break; + + default: + break; + } + } + + if (symtab) + /* We found one, though no SHT_SYMTAB_SHNDX to go with it. */ + return DWFL_E_NOERROR; + + /* We found no SHT_SYMTAB, so any SHT_SYMTAB_SHNDX was bogus. + We might have found an SHT_DYNSYM and set *SYMSCN et al though. */ + *xndxscn = NULL; + return DWFL_E_NO_SYMTAB; +} + + +/* Translate addresses into file offsets. + OFFS[*] start out zero and remain zero if unresolved. */ +static void +find_offsets (Elf *elf, GElf_Addr main_bias, size_t phnum, size_t n, + GElf_Addr addrs[n], GElf_Off offs[n]) +{ + size_t unsolved = n; + for (size_t i = 0; i < phnum; ++i) + { + GElf_Phdr phdr_mem; + GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem); + if (phdr != NULL && phdr->p_type == PT_LOAD && phdr->p_memsz > 0) + for (size_t j = 0; j < n; ++j) + if (offs[j] == 0 + && addrs[j] >= phdr->p_vaddr + main_bias + && addrs[j] - (phdr->p_vaddr + main_bias) < phdr->p_filesz) + { + offs[j] = addrs[j] - (phdr->p_vaddr + main_bias) + phdr->p_offset; + if (--unsolved == 0) + break; + } + } +} + +/* Try to find a dynamic symbol table via phdrs. */ +static void +find_dynsym (Dwfl_Module *mod) +{ + GElf_Ehdr ehdr_mem; + GElf_Ehdr *ehdr = gelf_getehdr (mod->main.elf, &ehdr_mem); + + size_t phnum; + if (unlikely (elf_getphdrnum (mod->main.elf, &phnum) != 0)) + return; + + for (size_t i = 0; i < phnum; ++i) + { + GElf_Phdr phdr_mem; + GElf_Phdr *phdr = gelf_getphdr (mod->main.elf, i, &phdr_mem); + if (phdr == NULL) + break; + + if (phdr->p_type == PT_DYNAMIC) + { + /* Examine the dynamic section for the pointers we need. */ + + Elf_Data *data = elf_getdata_rawchunk (mod->main.elf, + phdr->p_offset, phdr->p_filesz, + ELF_T_DYN); + if (data == NULL) + continue; + + enum + { + i_symtab, + i_strtab, + i_hash, + i_gnu_hash, + i_max + }; + GElf_Addr addrs[i_max] = { 0, }; + GElf_Xword strsz = 0; + size_t n = data->d_size / gelf_fsize (mod->main.elf, + ELF_T_DYN, 1, EV_CURRENT); + for (size_t j = 0; j < n; ++j) + { + GElf_Dyn dyn_mem; + GElf_Dyn *dyn = gelf_getdyn (data, j, &dyn_mem); + if (dyn != NULL) + switch (dyn->d_tag) + { + case DT_SYMTAB: + addrs[i_symtab] = dyn->d_un.d_ptr; + continue; + + case DT_HASH: + addrs[i_hash] = dyn->d_un.d_ptr; + continue; + + case DT_GNU_HASH: + addrs[i_gnu_hash] = dyn->d_un.d_ptr; + continue; + + case DT_STRTAB: + addrs[i_strtab] = dyn->d_un.d_ptr; + continue; + + case DT_STRSZ: + strsz = dyn->d_un.d_val; + continue; + + default: + continue; + + case DT_NULL: + break; + } + break; + } + + /* Translate pointers into file offsets. ADJUST is either zero + in case the dynamic segment wasn't adjusted or mod->main_bias. */ + void translate_offs (GElf_Addr adjust) + { + GElf_Off offs[i_max] = { 0, }; + find_offsets (mod->main.elf, adjust, phnum, i_max, addrs, offs); + + /* Figure out the size of the symbol table. */ + if (offs[i_hash] != 0) + { + /* In the original format, .hash says the size of .dynsym. */ + + size_t entsz = SH_ENTSIZE_HASH (ehdr); + data = elf_getdata_rawchunk (mod->main.elf, + offs[i_hash] + entsz, entsz, + entsz == 4 ? ELF_T_WORD + : ELF_T_XWORD); + if (data != NULL) + mod->syments = (entsz == 4 + ? *(const GElf_Word *) data->d_buf + : *(const GElf_Xword *) data->d_buf); + } + if (offs[i_gnu_hash] != 0 && mod->syments == 0) + { + /* In the new format, we can derive it with some work. */ + + const struct + { + Elf32_Word nbuckets; + Elf32_Word symndx; + Elf32_Word maskwords; + Elf32_Word shift2; + } *header; + + data = elf_getdata_rawchunk (mod->main.elf, offs[i_gnu_hash], + sizeof *header, ELF_T_WORD); + if (data != NULL) + { + header = data->d_buf; + Elf32_Word nbuckets = header->nbuckets; + Elf32_Word symndx = header->symndx; + GElf_Off buckets_at = (offs[i_gnu_hash] + sizeof *header + + (gelf_getclass (mod->main.elf) + * sizeof (Elf32_Word) + * header->maskwords)); + + // elf_getdata_rawchunk takes a size_t, make sure it + // doesn't overflow. +#if SIZE_MAX <= UINT32_MAX + if (nbuckets > SIZE_MAX / sizeof (Elf32_Word)) + data = NULL; + else +#endif + data + = elf_getdata_rawchunk (mod->main.elf, buckets_at, + nbuckets * sizeof (Elf32_Word), + ELF_T_WORD); + if (data != NULL && symndx < nbuckets) + { + const Elf32_Word *const buckets = data->d_buf; + Elf32_Word maxndx = symndx; + for (Elf32_Word bucket = 0; bucket < nbuckets; ++bucket) + if (buckets[bucket] > maxndx) + maxndx = buckets[bucket]; + + GElf_Off hasharr_at = (buckets_at + + nbuckets * sizeof (Elf32_Word)); + hasharr_at += (maxndx - symndx) * sizeof (Elf32_Word); + do + { + data = elf_getdata_rawchunk (mod->main.elf, + hasharr_at, + sizeof (Elf32_Word), + ELF_T_WORD); + if (data != NULL + && (*(const Elf32_Word *) data->d_buf & 1u)) + { + mod->syments = maxndx + 1; + break; + } + ++maxndx; + hasharr_at += sizeof (Elf32_Word); + } while (data != NULL); + } + } + } + if (offs[i_strtab] > offs[i_symtab] && mod->syments == 0) + mod->syments = ((offs[i_strtab] - offs[i_symtab]) + / gelf_fsize (mod->main.elf, + ELF_T_SYM, 1, EV_CURRENT)); + + if (mod->syments > 0) + { + mod->symdata = elf_getdata_rawchunk (mod->main.elf, + offs[i_symtab], + gelf_fsize (mod->main.elf, + ELF_T_SYM, + mod->syments, + EV_CURRENT), + ELF_T_SYM); + if (mod->symdata != NULL) + { + mod->symstrdata = elf_getdata_rawchunk (mod->main.elf, + offs[i_strtab], + strsz, + ELF_T_BYTE); + if (mod->symstrdata == NULL) + mod->symdata = NULL; + } + if (mod->symdata == NULL) + mod->symerr = DWFL_E (LIBELF, elf_errno ()); + else + { + mod->symfile = &mod->main; + mod->symerr = DWFL_E_NOERROR; + } + } + } + + /* First try unadjusted, like ELF files from disk, vdso. + Then try for already adjusted dynamic section, like ELF + from remote memory. */ + translate_offs (0); + if (mod->symfile == NULL) + translate_offs (mod->main_bias); + + return; + } + } +} + + +#if USE_LZMA +/* Try to find the offset between the main file and .gnu_debugdata. */ +static bool +find_aux_address_sync (Dwfl_Module *mod) +{ + /* Don't trust the phdrs in the minisymtab elf file to be setup correctly. + The address_sync is equal to the main file it is embedded in at first. */ + mod->aux_sym.address_sync = mod->main.address_sync; + + /* Adjust address_sync for the difference in entry addresses, attempting to + account for ELF relocation changes after aux was split. */ + GElf_Ehdr ehdr_main, ehdr_aux; + if (unlikely (gelf_getehdr (mod->main.elf, &ehdr_main) == NULL) + || unlikely (gelf_getehdr (mod->aux_sym.elf, &ehdr_aux) == NULL)) + return false; + mod->aux_sym.address_sync += ehdr_aux.e_entry - ehdr_main.e_entry; + + /* The shdrs are setup OK to make find_prelink_address_sync () do the right + thing, which is possibly more reliable, but it needs .gnu.prelink_undo. */ + if (mod->aux_sym.address_sync != 0) + return find_prelink_address_sync (mod, &mod->aux_sym) == DWFL_E_NOERROR; + + return true; +} +#endif + +/* Try to find the auxiliary symbol table embedded in the main elf file + section .gnu_debugdata. Only matters if the symbol information comes + from the main file dynsym. No harm done if not found. */ +static void +find_aux_sym (Dwfl_Module *mod __attribute__ ((unused)), + Elf_Scn **aux_symscn __attribute__ ((unused)), + Elf_Scn **aux_xndxscn __attribute__ ((unused)), + GElf_Word *aux_strshndx __attribute__ ((unused))) +{ + /* Since a .gnu_debugdata section is compressed using lzma don't do + anything unless we have support for that. */ +#if USE_LZMA + Elf *elf = mod->main.elf; + + size_t shstrndx; + if (elf_getshdrstrndx (elf, &shstrndx) < 0) + return; + + Elf_Scn *scn = NULL; + while ((scn = elf_nextscn (elf, scn)) != NULL) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + if (shdr == NULL) + return; + + const char *name = elf_strptr (elf, shstrndx, shdr->sh_name); + if (name == NULL) + return; + + if (!strcmp (name, ".gnu_debugdata")) + break; + } + + if (scn == NULL) + return; + + /* Found the .gnu_debugdata section. Uncompress the lzma image and + turn it into an ELF image. */ + Elf_Data *rawdata = elf_rawdata (scn, NULL); + if (rawdata == NULL) + return; + + Dwfl_Error error; + void *buffer = NULL; + size_t size = 0; + error = __libdw_unlzma (-1, 0, rawdata->d_buf, rawdata->d_size, + &buffer, &size); + if (error == DWFL_E_NOERROR) + { + if (unlikely (size == 0)) + free (buffer); + else + { + mod->aux_sym.elf = elf_memory (buffer, size); + if (mod->aux_sym.elf == NULL) + free (buffer); + else + { + mod->aux_sym.fd = -1; + mod->aux_sym.elf->flags |= ELF_F_MALLOCED; + if (open_elf (mod, &mod->aux_sym) != DWFL_E_NOERROR) + return; + if (! find_aux_address_sync (mod)) + { + elf_end (mod->aux_sym.elf); + mod->aux_sym.elf = NULL; + return; + } + + /* So far, so good. Get minisymtab table data and cache it. */ + bool minisymtab = false; + scn = NULL; + while ((scn = elf_nextscn (mod->aux_sym.elf, scn)) != NULL) + { + GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem); + if (shdr != NULL) + switch (shdr->sh_type) + { + case SHT_SYMTAB: + minisymtab = true; + *aux_symscn = scn; + *aux_strshndx = shdr->sh_link; + mod->aux_syments = shdr->sh_size / shdr->sh_entsize; + mod->aux_first_global = shdr->sh_info; + if (*aux_xndxscn != NULL) + return; + break; + + case SHT_SYMTAB_SHNDX: + *aux_xndxscn = scn; + if (minisymtab) + return; + break; + + default: + break; + } + } + + if (minisymtab) + /* We found one, though no SHT_SYMTAB_SHNDX to go with it. */ + return; + + /* We found no SHT_SYMTAB, so everything else is bogus. */ + *aux_xndxscn = NULL; + *aux_strshndx = 0; + mod->aux_syments = 0; + elf_end (mod->aux_sym.elf); + mod->aux_sym.elf = NULL; + return; + } + } + } + else + free (buffer); +#endif +} + +/* Try to find a symbol table in either MOD->main.elf or MOD->debug.elf. */ +static void +find_symtab (Dwfl_Module *mod) +{ + if (mod->symdata != NULL || mod->aux_symdata != NULL /* Already done. */ + || mod->symerr != DWFL_E_NOERROR) /* Cached previous failure. */ + return; + + __libdwfl_getelf (mod); + mod->symerr = mod->elferr; + if (mod->symerr != DWFL_E_NOERROR) + return; + + /* First see if the main ELF file has the debugging information. */ + Elf_Scn *symscn = NULL, *xndxscn = NULL; + Elf_Scn *aux_symscn = NULL, *aux_xndxscn = NULL; + GElf_Word strshndx, aux_strshndx = 0; + mod->symerr = load_symtab (&mod->main, &mod->symfile, &symscn, + &xndxscn, &mod->syments, &mod->first_global, + &strshndx); + switch (mod->symerr) + { + default: + return; + + case DWFL_E_NOERROR: + break; + + case DWFL_E_NO_SYMTAB: + /* Now we have to look for a separate debuginfo file. */ + mod->symerr = find_debuginfo (mod); + switch (mod->symerr) + { + default: + return; + + case DWFL_E_NOERROR: + mod->symerr = load_symtab (&mod->debug, &mod->symfile, &symscn, + &xndxscn, &mod->syments, + &mod->first_global, &strshndx); + break; + + case DWFL_E_CB: /* The find_debuginfo hook failed. */ + mod->symerr = DWFL_E_NO_SYMTAB; + break; + } + + switch (mod->symerr) + { + default: + return; + + case DWFL_E_NOERROR: + break; + + case DWFL_E_NO_SYMTAB: + /* There might be an auxiliary table. */ + find_aux_sym (mod, &aux_symscn, &aux_xndxscn, &aux_strshndx); + + if (symscn != NULL) + { + /* We still have the dynamic symbol table. */ + mod->symerr = DWFL_E_NOERROR; + break; + } + + if (aux_symscn != NULL) + { + /* We still have the auxiliary symbol table. */ + mod->symerr = DWFL_E_NOERROR; + goto aux_cache; + } + + /* Last ditch, look for dynamic symbols without section headers. */ + find_dynsym (mod); + return; + } + break; + } + + /* This does some sanity checks on the string table section. */ + if (elf_strptr (mod->symfile->elf, strshndx, 0) == NULL) + { + elferr: + mod->symerr = DWFL_E (LIBELF, elf_errno ()); + goto aux_cleanup; /* This cleans up some more and tries find_dynsym. */ + } + + /* Cache the data; MOD->syments and MOD->first_global were set above. */ + + mod->symstrdata = elf_getdata (elf_getscn (mod->symfile->elf, strshndx), + NULL); + if (mod->symstrdata == NULL || mod->symstrdata->d_buf == NULL) + goto elferr; + + if (xndxscn == NULL) + mod->symxndxdata = NULL; + else + { + mod->symxndxdata = elf_getdata (xndxscn, NULL); + if (mod->symxndxdata == NULL || mod->symxndxdata->d_buf == NULL) + goto elferr; + } + + mod->symdata = elf_getdata (symscn, NULL); + if (mod->symdata == NULL || mod->symdata->d_buf == NULL) + goto elferr; + + // Sanity check number of symbols. + GElf_Shdr shdr_mem, *shdr = gelf_getshdr (symscn, &shdr_mem); + if (mod->syments > mod->symdata->d_size / shdr->sh_entsize + || (size_t) mod->first_global > mod->syments) + goto elferr; + + /* Cache any auxiliary symbol info, when it fails, just ignore aux_sym. */ + if (aux_symscn != NULL) + { + aux_cache: + /* This does some sanity checks on the string table section. */ + if (elf_strptr (mod->aux_sym.elf, aux_strshndx, 0) == NULL) + { + aux_cleanup: + mod->aux_syments = 0; + elf_end (mod->aux_sym.elf); + mod->aux_sym.elf = NULL; + /* We thought we had something through shdrs, but it failed... + Last ditch, look for dynamic symbols without section headers. */ + find_dynsym (mod); + return; + } + + mod->aux_symstrdata = elf_getdata (elf_getscn (mod->aux_sym.elf, + aux_strshndx), + NULL); + if (mod->aux_symstrdata == NULL || mod->aux_symstrdata->d_buf == NULL) + goto aux_cleanup; + + if (aux_xndxscn == NULL) + mod->aux_symxndxdata = NULL; + else + { + mod->aux_symxndxdata = elf_getdata (aux_xndxscn, NULL); + if (mod->aux_symxndxdata == NULL + || mod->aux_symxndxdata->d_buf == NULL) + goto aux_cleanup; + } + + mod->aux_symdata = elf_getdata (aux_symscn, NULL); + if (mod->aux_symdata == NULL || mod->aux_symdata->d_buf == NULL) + goto aux_cleanup; + + // Sanity check number of aux symbols. + shdr = gelf_getshdr (aux_symscn, &shdr_mem); + if (mod->aux_syments > mod->aux_symdata->d_size / shdr->sh_entsize + || (size_t) mod->aux_first_global > mod->aux_syments) + goto aux_cleanup; + } +} + + +/* Try to open a libebl backend for MOD. */ +Dwfl_Error +internal_function +__libdwfl_module_getebl (Dwfl_Module *mod) +{ + if (mod->ebl == NULL) + { + __libdwfl_getelf (mod); + if (mod->elferr != DWFL_E_NOERROR) + return mod->elferr; + + mod->ebl = ebl_openbackend (mod->main.elf); + if (mod->ebl == NULL) + return DWFL_E_LIBEBL; + } + return DWFL_E_NOERROR; +} + +/* Try to start up libdw on DEBUGFILE. */ +static Dwfl_Error +load_dw (Dwfl_Module *mod, struct dwfl_file *debugfile) +{ + if (mod->e_type == ET_REL && !debugfile->relocated) + { + const Dwfl_Callbacks *const cb = mod->dwfl->callbacks; + + /* The debugging sections have to be relocated. */ + if (cb->section_address == NULL) + return DWFL_E_NOREL; + + Dwfl_Error error = __libdwfl_module_getebl (mod); + if (error != DWFL_E_NOERROR) + return error; + + find_symtab (mod); + Dwfl_Error result = mod->symerr; + if (result == DWFL_E_NOERROR) + result = __libdwfl_relocate (mod, debugfile->elf, true); + if (result != DWFL_E_NOERROR) + return result; + + /* Don't keep the file descriptors around. */ + if (mod->main.fd != -1 && elf_cntl (mod->main.elf, ELF_C_FDREAD) == 0) + { + close (mod->main.fd); + mod->main.fd = -1; + } + if (debugfile->fd != -1 && elf_cntl (debugfile->elf, ELF_C_FDREAD) == 0) + { + close (debugfile->fd); + debugfile->fd = -1; + } + } + + mod->dw = INTUSE(dwarf_begin_elf) (debugfile->elf, DWARF_C_READ, NULL); + if (mod->dw == NULL) + { + int err = INTUSE(dwarf_errno) (); + return err == DWARF_E_NO_DWARF ? DWFL_E_NO_DWARF : DWFL_E (LIBDW, err); + } + + /* Until we have iterated through all CU's, we might do lazy lookups. */ + mod->lazycu = 1; + + return DWFL_E_NOERROR; +} + +/* Try to start up libdw on either the main file or the debuginfo file. */ +static void +find_dw (Dwfl_Module *mod) +{ + if (mod->dw != NULL /* Already done. */ + || mod->dwerr != DWFL_E_NOERROR) /* Cached previous failure. */ + return; + + __libdwfl_getelf (mod); + mod->dwerr = mod->elferr; + if (mod->dwerr != DWFL_E_NOERROR) + return; + + /* First see if the main ELF file has the debugging information. */ + mod->dwerr = load_dw (mod, &mod->main); + switch (mod->dwerr) + { + case DWFL_E_NOERROR: + mod->debug.elf = mod->main.elf; + mod->debug.address_sync = mod->main.address_sync; + + /* The Dwarf might need an alt debug file, find that now after + everything about the debug file has been setup (the + find_debuginfo callback might need it). */ + find_debug_altlink (mod, mod->main.name); + return; + + case DWFL_E_NO_DWARF: + break; + + default: + goto canonicalize; + } + + /* Now we have to look for a separate debuginfo file. */ + mod->dwerr = find_debuginfo (mod); + switch (mod->dwerr) + { + case DWFL_E_NOERROR: + mod->dwerr = load_dw (mod, &mod->debug); + if (mod->dwerr == DWFL_E_NOERROR) + { + /* The Dwarf might need an alt debug file, find that now after + everything about the debug file has been setup (the + find_debuginfo callback might need it). */ + find_debug_altlink (mod, mod->debug.name); + return; + } + + break; + + case DWFL_E_CB: /* The find_debuginfo hook failed. */ + mod->dwerr = DWFL_E_NO_DWARF; + return; + + default: + break; + } + + canonicalize: + mod->dwerr = __libdwfl_canon_error (mod->dwerr); +} + +Dwarf * +dwfl_module_getdwarf (Dwfl_Module *mod, Dwarf_Addr *bias) +{ + if (mod == NULL) + return NULL; + + find_dw (mod); + if (mod->dwerr == DWFL_E_NOERROR) + { + /* If dwfl_module_getelf was used previously, then partial apply + relocation to miscellaneous sections in the debug file too. */ + if (mod->e_type == ET_REL + && mod->main.relocated && ! mod->debug.relocated) + { + mod->debug.relocated = true; + if (mod->debug.elf != mod->main.elf) + (void) __libdwfl_relocate (mod, mod->debug.elf, false); + } + + *bias = dwfl_adjusted_dwarf_addr (mod, 0); + return mod->dw; + } + + __libdwfl_seterrno (mod->dwerr); + return NULL; +} +INTDEF (dwfl_module_getdwarf) + +int +dwfl_module_getsymtab (Dwfl_Module *mod) +{ + if (mod == NULL) + return -1; + + find_symtab (mod); + if (mod->symerr == DWFL_E_NOERROR) + /* We will skip the auxiliary zero entry if there is another one. */ + return (mod->syments + mod->aux_syments + - (mod->syments > 0 && mod->aux_syments > 0 ? 1 : 0)); + + __libdwfl_seterrno (mod->symerr); + return -1; +} +INTDEF (dwfl_module_getsymtab) + +int +dwfl_module_getsymtab_first_global (Dwfl_Module *mod) +{ + if (mod == NULL) + return -1; + + find_symtab (mod); + if (mod->symerr == DWFL_E_NOERROR) + { + /* All local symbols should come before all global symbols. If + we have an auxiliary table make sure all the main locals come + first, then all aux locals, then all main globals and finally all + aux globals. And skip the auxiliary table zero undefined + entry. */ + int skip_aux_zero = (mod->syments > 0 && mod->aux_syments > 0) ? 1 : 0; + return mod->first_global + mod->aux_first_global - skip_aux_zero; + } + + __libdwfl_seterrno (mod->symerr); + return -1; +} +INTDEF (dwfl_module_getsymtab_first_global) diff --git a/3rdparty/elfutils/libdwfl/dwfl_module_getelf.c b/3rdparty/elfutils/libdwfl/dwfl_module_getelf.c new file mode 100644 index 0000000..f20fb04 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_module_getelf.c @@ -0,0 +1,67 @@ +/* Find debugging and symbol information for a module in libdwfl. + Copyright (C) 2009-2010 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" + +Elf * +dwfl_module_getelf (Dwfl_Module *mod, GElf_Addr *loadbase) +{ + if (mod == NULL) + return NULL; + + __libdwfl_getelf (mod); + if (mod->elferr == DWFL_E_NOERROR) + { + if (mod->e_type == ET_REL && ! mod->main.relocated) + { + /* Before letting them get at the Elf handle, + apply all the relocations we know how to. */ + + mod->main.relocated = true; + if (likely (__libdwfl_module_getebl (mod) == DWFL_E_NOERROR)) + { + (void) __libdwfl_relocate (mod, mod->main.elf, false); + + if (mod->debug.elf == mod->main.elf) + mod->debug.relocated = true; + else if (mod->debug.elf != NULL && ! mod->debug.relocated) + { + mod->debug.relocated = true; + (void) __libdwfl_relocate (mod, mod->debug.elf, false); + } + } + } + + *loadbase = dwfl_adjusted_address (mod, 0); + return mod->main.elf; + } + + __libdwfl_seterrno (mod->elferr); + return NULL; +} +INTDEF (dwfl_module_getelf) diff --git a/3rdparty/elfutils/libdwfl/dwfl_module_getsrc.c b/3rdparty/elfutils/libdwfl/dwfl_module_getsrc.c new file mode 100644 index 0000000..f6d8839 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_module_getsrc.c @@ -0,0 +1,81 @@ +/* Find source location for PC address in module. + Copyright (C) 2005, 2008, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" +#include "../libdw/libdwP.h" + +Dwfl_Line * +dwfl_module_getsrc (Dwfl_Module *mod, Dwarf_Addr addr) +{ + Dwarf_Addr bias; + if (INTUSE(dwfl_module_getdwarf) (mod, &bias) == NULL) + return NULL; + + struct dwfl_cu *cu; + Dwfl_Error error = __libdwfl_addrcu (mod, addr, &cu); + if (likely (error == DWFL_E_NOERROR)) + error = __libdwfl_cu_getsrclines (cu); + if (likely (error == DWFL_E_NOERROR)) + { + Dwarf_Lines *lines = cu->die.cu->lines; + size_t nlines = lines->nlines; + if (nlines > 0) + { + /* This is guaranteed for us by libdw read_srclines. */ + assert(lines->info[nlines - 1].end_sequence); + + /* Now we look at the module-relative address. */ + addr -= bias; + + /* The lines are sorted by address, so we can use binary search. */ + size_t l = 0, u = nlines - 1; + while (l < u) + { + size_t idx = u - (u - l) / 2; + Dwarf_Line *line = &lines->info[idx]; + if (addr < line->addr) + u = idx - 1; + else + l = idx; + } + + /* The last line which is less than or equal to addr is what we want, + except with an end_sequence which can only be strictly equal. */ + Dwarf_Line *line = &lines->info[l]; + if (line->addr == addr + || (! line->end_sequence && line->addr < addr)) + return &cu->lines->idx[l]; + } + + error = DWFL_E_ADDR_OUTOFRANGE; + } + + __libdwfl_seterrno (error); + return NULL; +} +INTDEF (dwfl_module_getsrc) diff --git a/3rdparty/elfutils/libdwfl/dwfl_module_getsrc_file.c b/3rdparty/elfutils/libdwfl/dwfl_module_getsrc_file.c new file mode 100644 index 0000000..20aa8a5 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_module_getsrc_file.c @@ -0,0 +1,167 @@ +/* Find matching source locations in a module. + Copyright (C) 2005 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" +#include "../libdw/libdwP.h" + + +int +dwfl_module_getsrc_file (Dwfl_Module *mod, + const char *fname, int lineno, int column, + Dwfl_Line ***srcsp, size_t *nsrcs) +{ + if (mod == NULL) + return -1; + + if (mod->dw == NULL) + { + Dwarf_Addr bias; + if (INTUSE(dwfl_module_getdwarf) (mod, &bias) == NULL) + return -1; + } + + bool is_basename = strchr (fname, '/') == NULL; + + size_t max_match = *nsrcs ?: ~0u; + size_t act_match = *nsrcs; + size_t cur_match = 0; + Dwfl_Line **match = *nsrcs == 0 ? NULL : *srcsp; + + struct dwfl_cu *cu = NULL; + Dwfl_Error error; + while ((error = __libdwfl_nextcu (mod, cu, &cu)) == DWFL_E_NOERROR + && cu != NULL + && (error = __libdwfl_cu_getsrclines (cu)) == DWFL_E_NOERROR) + { + inline const char *INTUSE(dwarf_line_file) (const Dwarf_Line *line) + { + return line->files->info[line->file].name; + } + inline Dwarf_Line *dwfl_line (const Dwfl_Line *line) + { + return &dwfl_linecu (line)->die.cu->lines->info[line->idx]; + } + inline const char *dwfl_line_file (const Dwfl_Line *line) + { + return INTUSE(dwarf_line_file) (dwfl_line (line)); + } + + /* Search through all the line number records for a matching + file and line/column number. If any of the numbers is zero, + no match is performed. */ + const char *lastfile = NULL; + bool lastmatch = false; + for (size_t cnt = 0; cnt < cu->die.cu->lines->nlines; ++cnt) + { + Dwarf_Line *line = &cu->die.cu->lines->info[cnt]; + + if (unlikely (line->file >= line->files->nfiles)) + { + __libdwfl_seterrno (DWFL_E (LIBDW, DWARF_E_INVALID_DWARF)); + return -1; + } + else + { + const char *file = INTUSE(dwarf_line_file) (line); + if (file != lastfile) + { + /* Match the name with the name the user provided. */ + lastfile = file; + lastmatch = !strcmp (is_basename ? basename (file) : file, + fname); + } + } + if (!lastmatch) + continue; + + /* See whether line and possibly column match. */ + if (lineno != 0 + && (lineno > line->line + || (column != 0 && column > line->column))) + /* Cannot match. */ + continue; + + /* Determine whether this is the best match so far. */ + size_t inner; + for (inner = 0; inner < cur_match; ++inner) + if (dwfl_line_file (match[inner]) + == INTUSE(dwarf_line_file) (line)) + break; + if (inner < cur_match + && (dwfl_line (match[inner])->line != line->line + || dwfl_line (match[inner])->line != lineno + || (column != 0 + && (dwfl_line (match[inner])->column != line->column + || dwfl_line (match[inner])->column != column)))) + { + /* We know about this file already. If this is a better + match for the line number, use it. */ + if (dwfl_line (match[inner])->line >= line->line + && (dwfl_line (match[inner])->line != line->line + || dwfl_line (match[inner])->column >= line->column)) + /* Use the new line. Otherwise the old one. */ + match[inner] = &cu->lines->idx[cnt]; + continue; + } + + if (cur_match < max_match) + { + if (cur_match == act_match) + { + /* Enlarge the array for the results. */ + act_match += 10; + Dwfl_Line **newp = realloc (match, + act_match + * sizeof (Dwfl_Line *)); + if (newp == NULL) + { + free (match); + __libdwfl_seterrno (DWFL_E_NOMEM); + return -1; + } + match = newp; + } + + match[cur_match++] = &cu->lines->idx[cnt]; + } + } + } + + if (cur_match > 0) + { + assert (*nsrcs == 0 || *srcsp == match); + + *nsrcs = cur_match; + *srcsp = match; + + return 0; + } + + __libdwfl_seterrno (DWFL_E_NO_MATCH); + return -1; +} diff --git a/3rdparty/elfutils/libdwfl/dwfl_module_getsym.c b/3rdparty/elfutils/libdwfl/dwfl_module_getsym.c new file mode 100644 index 0000000..42d2b67 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_module_getsym.c @@ -0,0 +1,216 @@ +/* Find debugging and symbol information for a module in libdwfl. + Copyright (C) 2006-2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" + +const char * +internal_function +__libdwfl_getsym (Dwfl_Module *mod, int ndx, GElf_Sym *sym, GElf_Addr *addr, + GElf_Word *shndxp, Elf **elfp, Dwarf_Addr *biasp, + bool *resolved, bool adjust_st_value) +{ + if (unlikely (mod == NULL)) + return NULL; + + if (unlikely (mod->symdata == NULL)) + { + int result = INTUSE(dwfl_module_getsymtab) (mod); + if (result < 0) + return NULL; + } + + /* All local symbols should come before all global symbols. If we + have an auxiliary table make sure all the main locals come first, + then all aux locals, then all main globals and finally all aux globals. + And skip the auxiliary table zero undefined entry. */ + GElf_Word shndx; + int tndx = ndx; + int skip_aux_zero = (mod->syments > 0 && mod->aux_syments > 0) ? 1 : 0; + Elf *elf; + Elf_Data *symdata; + Elf_Data *symxndxdata; + Elf_Data *symstrdata; + if (mod->aux_symdata == NULL + || ndx < mod->first_global) + { + /* main symbol table (locals). */ + tndx = ndx; + elf = mod->symfile->elf; + symdata = mod->symdata; + symxndxdata = mod->symxndxdata; + symstrdata = mod->symstrdata; + } + else if (ndx < mod->first_global + mod->aux_first_global - skip_aux_zero) + { + /* aux symbol table (locals). */ + tndx = ndx - mod->first_global + skip_aux_zero; + elf = mod->aux_sym.elf; + symdata = mod->aux_symdata; + symxndxdata = mod->aux_symxndxdata; + symstrdata = mod->aux_symstrdata; + } + else if ((size_t) ndx < mod->syments + mod->aux_first_global - skip_aux_zero) + { + /* main symbol table (globals). */ + tndx = ndx - mod->aux_first_global + skip_aux_zero; + elf = mod->symfile->elf; + symdata = mod->symdata; + symxndxdata = mod->symxndxdata; + symstrdata = mod->symstrdata; + } + else + { + /* aux symbol table (globals). */ + tndx = ndx - mod->syments + skip_aux_zero; + elf = mod->aux_sym.elf; + symdata = mod->aux_symdata; + symxndxdata = mod->aux_symxndxdata; + symstrdata = mod->aux_symstrdata; + } + sym = gelf_getsymshndx (symdata, symxndxdata, tndx, sym, &shndx); + + if (unlikely (sym == NULL)) + { + __libdwfl_seterrno (DWFL_E_LIBELF); + return NULL; + } + + if (sym->st_shndx != SHN_XINDEX) + shndx = sym->st_shndx; + + /* Figure out whether this symbol points into an SHF_ALLOC section. */ + bool alloc = true; + if ((shndxp != NULL || mod->e_type != ET_REL) + && (sym->st_shndx == SHN_XINDEX + || (sym->st_shndx < SHN_LORESERVE && sym->st_shndx != SHN_UNDEF))) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (elf_getscn (elf, shndx), &shdr_mem); + alloc = unlikely (shdr == NULL) || (shdr->sh_flags & SHF_ALLOC); + } + + /* In case of an value in an allocated section the main Elf Ebl + might know where the real value is (e.g. for function + descriptors). */ + + char *ident; + GElf_Addr st_value = sym->st_value & ebl_func_addr_mask (mod->ebl); + *resolved = false; + if (! adjust_st_value && mod->e_type != ET_REL && alloc + && (GELF_ST_TYPE (sym->st_info) == STT_FUNC + || (GELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC + && (ident = elf_getident (elf, NULL)) != NULL + && ident[EI_OSABI] == ELFOSABI_LINUX))) + { + if (likely (__libdwfl_module_getebl (mod) == DWFL_E_NOERROR)) + { + if (elf != mod->main.elf) + { + st_value = dwfl_adjusted_st_value (mod, elf, st_value); + st_value = dwfl_deadjust_st_value (mod, mod->main.elf, st_value); + } + + *resolved = ebl_resolve_sym_value (mod->ebl, &st_value); + if (! *resolved) + st_value = sym->st_value; + } + } + + if (shndxp != NULL) + /* Yield -1 in case of a non-SHF_ALLOC section. */ + *shndxp = alloc ? shndx : (GElf_Word) -1; + + switch (sym->st_shndx) + { + case SHN_ABS: /* XXX sometimes should use bias?? */ + case SHN_UNDEF: + case SHN_COMMON: + break; + + default: + if (mod->e_type == ET_REL) + { + /* In an ET_REL file, the symbol table values are relative + to the section, not to the module's load base. */ + size_t symshstrndx = SHN_UNDEF; + Dwfl_Error result = __libdwfl_relocate_value (mod, elf, + &symshstrndx, + shndx, &st_value); + if (unlikely (result != DWFL_E_NOERROR)) + { + __libdwfl_seterrno (result); + return NULL; + } + } + else if (alloc) + /* Apply the bias to the symbol value. */ + st_value = dwfl_adjusted_st_value (mod, + *resolved ? mod->main.elf : elf, + st_value); + break; + } + + if (adjust_st_value) + sym->st_value = st_value; + + if (addr != NULL) + *addr = st_value; + + if (unlikely (sym->st_name >= symstrdata->d_size)) + { + __libdwfl_seterrno (DWFL_E_BADSTROFF); + return NULL; + } + if (elfp) + *elfp = elf; + if (biasp) + *biasp = dwfl_adjusted_st_value (mod, elf, 0); + return (const char *) symstrdata->d_buf + sym->st_name; +} + +const char * +dwfl_module_getsym_info (Dwfl_Module *mod, int ndx, + GElf_Sym *sym, GElf_Addr *addr, + GElf_Word *shndxp, + Elf **elfp, Dwarf_Addr *bias) +{ + bool resolved; + return __libdwfl_getsym (mod, ndx, sym, addr, shndxp, elfp, bias, + &resolved, false); +} +INTDEF (dwfl_module_getsym_info) + +const char * +dwfl_module_getsym (Dwfl_Module *mod, int ndx, + GElf_Sym *sym, GElf_Word *shndxp) +{ + bool resolved; + return __libdwfl_getsym (mod, ndx, sym, NULL, shndxp, NULL, NULL, + &resolved, true); +} +INTDEF (dwfl_module_getsym) diff --git a/3rdparty/elfutils/libdwfl/dwfl_module_info.c b/3rdparty/elfutils/libdwfl/dwfl_module_info.c new file mode 100644 index 0000000..df16be4 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_module_info.c @@ -0,0 +1,61 @@ +/* Return information about a module. + Copyright (C) 2005-2010 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" + +const char * +dwfl_module_info (Dwfl_Module *mod, void ***userdata, + Dwarf_Addr *start, Dwarf_Addr *end, + Dwarf_Addr *dwbias, Dwarf_Addr *symbias, + const char **mainfile, const char **debugfile) +{ + if (mod == NULL) + return NULL; + + if (userdata) + *userdata = &mod->userdata; + if (start) + *start = mod->low_addr; + if (end) + *end = mod->high_addr; + + if (dwbias) + *dwbias = (mod->debug.elf == NULL ? (Dwarf_Addr) -1 + : dwfl_adjusted_dwarf_addr (mod, 0)); + if (symbias) + *symbias = (mod->symfile == NULL ? (Dwarf_Addr) -1 + : dwfl_adjusted_st_value (mod, mod->symfile->elf, 0)); + + if (mainfile) + *mainfile = mod->main.name; + + if (debugfile) + *debugfile = mod->debug.name; + + return mod->name; +} diff --git a/3rdparty/elfutils/libdwfl/dwfl_module_nextcu.c b/3rdparty/elfutils/libdwfl/dwfl_module_nextcu.c new file mode 100644 index 0000000..6f81f4c --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_module_nextcu.c @@ -0,0 +1,44 @@ +/* Iterate through DWARF compilation units in a module. + Copyright (C) 2005 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" + +Dwarf_Die * +dwfl_module_nextcu (Dwfl_Module *mod, Dwarf_Die *lastcu, Dwarf_Addr *bias) +{ + if (INTUSE(dwfl_module_getdwarf) (mod, bias) == NULL) + return NULL; + + struct dwfl_cu *cu; + Dwfl_Error error = __libdwfl_nextcu (mod, (struct dwfl_cu *) lastcu, &cu); + if (likely (error == DWFL_E_NOERROR)) + return &cu->die; /* Same as a cast, so ok for null too. */ + + __libdwfl_seterrno (error); + return NULL; +} diff --git a/3rdparty/elfutils/libdwfl/dwfl_module_register_names.c b/3rdparty/elfutils/libdwfl/dwfl_module_register_names.c new file mode 100644 index 0000000..2da4b53 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_module_register_names.c @@ -0,0 +1,79 @@ +/* Enumerate DWARF register numbers and their names. + Copyright (C) 2005, 2006 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" + + +int +dwfl_module_register_names (mod, func, arg) + Dwfl_Module *mod; + int (*func) (void *, int regno, const char *setname, + const char *prefix, const char *regname, + int bits, int type); + void *arg; +{ + if (unlikely (mod == NULL)) + return -1; + + if (unlikely (mod->ebl == NULL)) + { + Dwfl_Error error = __libdwfl_module_getebl (mod); + if (error != DWFL_E_NOERROR) + { + __libdwfl_seterrno (error); + return -1; + } + } + + int nregs = ebl_register_info (mod->ebl, -1, NULL, 0, + NULL, NULL, NULL, NULL); + int result = 0; + for (int regno = 0; regno < nregs && likely (result == 0); ++regno) + { + char name[32]; + const char *setname = NULL; + const char *prefix = NULL; + int bits = -1; + int type = -1; + ssize_t len = ebl_register_info (mod->ebl, regno, name, sizeof name, + &prefix, &setname, &bits, &type); + if (unlikely (len < 0)) + { + __libdwfl_seterrno (DWFL_E_LIBEBL); + result = -1; + break; + } + if (likely (len > 0)) + { + assert (len > 1); /* Backend should never yield "". */ + result = (*func) (arg, regno, setname, prefix, name, bits, type); + } + } + + return result; +} diff --git a/3rdparty/elfutils/libdwfl/dwfl_module_report_build_id.c b/3rdparty/elfutils/libdwfl/dwfl_module_report_build_id.c new file mode 100644 index 0000000..b41512b --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_module_report_build_id.c @@ -0,0 +1,80 @@ +/* Report build ID information for a module. + Copyright (C) 2007, 2008 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" + +// XXX vs report changed module: punting old file +int +dwfl_module_report_build_id (Dwfl_Module *mod, + const unsigned char *bits, size_t len, + GElf_Addr vaddr) +{ + if (mod == NULL) + return -1; + + if (mod->main.elf != NULL) + { + /* Once we know about a file, we won't take any lies about + its contents. The only permissible call is a no-op. */ + + if ((size_t) mod->build_id_len == len + && (mod->build_id_vaddr == vaddr || vaddr == 0) + && !memcmp (bits, mod->build_id_bits, len)) + return 0; + + __libdwfl_seterrno (DWFL_E_ALREADY_ELF); + return -1; + } + + if (vaddr != 0 && (vaddr < mod->low_addr || vaddr + len > mod->high_addr)) + { + __libdwfl_seterrno (DWFL_E_ADDR_OUTOFRANGE); + return -1; + } + + void *copy = NULL; + if (len > 0) + { + copy = malloc (len); + if (unlikely (copy == NULL)) + { + __libdwfl_seterrno (DWFL_E_NOMEM); + return -1; + } + memcpy (copy, bits, len); + } + + free (mod->build_id_bits); + + mod->build_id_bits = copy; + mod->build_id_len = len; + mod->build_id_vaddr = vaddr; + + return 0; +} +INTDEF (dwfl_module_report_build_id) diff --git a/3rdparty/elfutils/libdwfl/dwfl_module_return_value_location.c b/3rdparty/elfutils/libdwfl/dwfl_module_return_value_location.c new file mode 100644 index 0000000..ad83cbf --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_module_return_value_location.c @@ -0,0 +1,64 @@ +/* Return location expression to find return value given a function type DIE. + Copyright (C) 2005, 2006 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" + + +int +dwfl_module_return_value_location (mod, functypedie, locops) + Dwfl_Module *mod; + Dwarf_Die *functypedie; + const Dwarf_Op **locops; +{ + if (mod == NULL) + return -1; + + if (mod->ebl == NULL) + { + Dwfl_Error error = __libdwfl_module_getebl (mod); + if (error != DWFL_E_NOERROR) + { + __libdwfl_seterrno (error); + return -1; + } + } + + int nops = ebl_return_value_location (mod->ebl, functypedie, locops); + if (unlikely (nops < 0)) + { + if (nops == -1) + __libdwfl_seterrno (DWFL_E_LIBDW); + else if (nops == -2) + __libdwfl_seterrno (DWFL_E_WEIRD_TYPE); + else + __libdwfl_seterrno (DWFL_E_LIBEBL); + nops = -1; + } + + return nops; +} diff --git a/3rdparty/elfutils/libdwfl/dwfl_nextcu.c b/3rdparty/elfutils/libdwfl/dwfl_nextcu.c new file mode 100644 index 0000000..9ea8388 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_nextcu.c @@ -0,0 +1,82 @@ +/* Iterate through DWARF compilation units across all modules. + Copyright (C) 2005-2010 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" + +Dwarf_Die * +dwfl_nextcu (Dwfl *dwfl, Dwarf_Die *lastcu, Dwarf_Addr *bias) +{ + if (dwfl == NULL) + return NULL; + + struct dwfl_cu *cu = (struct dwfl_cu *) lastcu; + Dwfl_Module *mod; + + if (cu == NULL) + { + mod = dwfl->modulelist; + goto nextmod; + } + else + mod = cu->mod; + + Dwfl_Error error; + do + { + error = __libdwfl_nextcu (mod, cu, &cu); + if (error != DWFL_E_NOERROR) + break; + + if (cu != NULL) + { + *bias = dwfl_adjusted_dwarf_addr (mod, 0); + return &cu->die; + } + + do + { + mod = mod->next; + + nextmod: + if (mod == NULL) + return NULL; + + if (mod->dwerr == DWFL_E_NOERROR + && (mod->dw != NULL + || INTUSE(dwfl_module_getdwarf) (mod, bias) != NULL)) + break; + } + while (mod->dwerr == DWFL_E_NO_DWARF); + error = mod->dwerr; + } + while (error == DWFL_E_NOERROR); + + __libdwfl_seterrno (error); + return NULL; +} +INTDEF (dwfl_nextcu) diff --git a/3rdparty/elfutils/libdwfl/dwfl_onesrcline.c b/3rdparty/elfutils/libdwfl/dwfl_onesrcline.c new file mode 100644 index 0000000..4c20d65 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_onesrcline.c @@ -0,0 +1,56 @@ +/* Return one of the sources lines of a CU. + Copyright (C) 2005 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" + +Dwfl_Line * +dwfl_onesrcline (Dwarf_Die *cudie, size_t idx) +{ + struct dwfl_cu *cu = (struct dwfl_cu *) cudie; + + if (cudie == NULL) + return NULL; + + if (cu->lines == NULL) + { + Dwfl_Error error = __libdwfl_cu_getsrclines (cu); + if (error != DWFL_E_NOERROR) + { + __libdwfl_seterrno (error); + return NULL; + } + } + + if (idx >= cu->die.cu->lines->nlines) + { + __libdwfl_seterrno (DWFL_E (LIBDW, DWARF_E_INVALID_LINE_IDX)); + return NULL; + } + + return &cu->lines->idx[idx]; +} diff --git a/3rdparty/elfutils/libdwfl/dwfl_report_elf.c b/3rdparty/elfutils/libdwfl/dwfl_report_elf.c new file mode 100644 index 0000000..3a4ae2e --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_report_elf.c @@ -0,0 +1,338 @@ +/* Report a module to libdwfl based on ELF program headers. + Copyright (C) 2005-2010 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" +#include <fcntl.h> +#include <unistd.h> + + +/* We start every ET_REL module at a moderately aligned boundary. + This keeps the low addresses easy to read compared to a layout + starting at 0 (as when using -e). It also makes it unlikely + that a middle section will have a larger alignment and require + rejiggering (see below). */ +#define REL_MIN_ALIGN ((GElf_Xword) 0x100) + +bool +internal_function +__libdwfl_elf_address_range (Elf *elf, GElf_Addr base, bool add_p_vaddr, + bool sanity, GElf_Addr *vaddrp, + GElf_Addr *address_syncp, GElf_Addr *startp, + GElf_Addr *endp, GElf_Addr *biasp, + GElf_Half *e_typep) +{ + GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem); + if (ehdr == NULL) + { + elf_error: + __libdwfl_seterrno (DWFL_E_LIBELF); + return false; + } + + GElf_Addr vaddr = 0; + GElf_Addr address_sync = 0; + GElf_Addr start = 0, end = 0, bias = 0; + switch (ehdr->e_type) + { + case ET_REL: + /* For a relocatable object, we do an arbitrary section layout. + By updating the section header in place, we leave the layout + information to be found by relocation. */ + + start = end = base = (base + REL_MIN_ALIGN - 1) & -REL_MIN_ALIGN; + + bool first = true; + Elf_Scn *scn = NULL; + while ((scn = elf_nextscn (elf, scn)) != NULL) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + if (unlikely (shdr == NULL)) + goto elf_error; + + if (shdr->sh_flags & SHF_ALLOC) + { + const GElf_Xword align = shdr->sh_addralign ?: 1; + const GElf_Addr next = (end + align - 1) & -align; + if (shdr->sh_addr == 0 + /* Once we've started doing layout we have to do it all, + unless we just layed out the first section at 0 when + it already was at 0. */ + || (bias == 0 && end > start && end != next)) + { + shdr->sh_addr = next; + if (end == base) + /* This is the first section assigned a location. + Use its aligned address as the module's base. */ + start = base = shdr->sh_addr; + else if (unlikely (base & (align - 1))) + { + /* If BASE has less than the maximum alignment of + any section, we eat more than the optimal amount + of padding and so make the module's apparent + size come out larger than it would when placed + at zero. So reset the layout with a better base. */ + + start = end = base = (base + align - 1) & -align; + Elf_Scn *prev_scn = NULL; + do + { + prev_scn = elf_nextscn (elf, prev_scn); + GElf_Shdr prev_shdr_mem; + GElf_Shdr *prev_shdr = gelf_getshdr (prev_scn, + &prev_shdr_mem); + if (unlikely (prev_shdr == NULL)) + goto elf_error; + if (prev_shdr->sh_flags & SHF_ALLOC) + { + const GElf_Xword prev_align + = prev_shdr->sh_addralign ?: 1; + + prev_shdr->sh_addr + = (end + prev_align - 1) & -prev_align; + end = prev_shdr->sh_addr + prev_shdr->sh_size; + + if (unlikely (! gelf_update_shdr (prev_scn, + prev_shdr))) + goto elf_error; + } + } + while (prev_scn != scn); + continue; + } + + end = shdr->sh_addr + shdr->sh_size; + if (likely (shdr->sh_addr != 0) + && unlikely (! gelf_update_shdr (scn, shdr))) + goto elf_error; + } + else + { + /* The address is already assigned. Just track it. */ + if (first || end < shdr->sh_addr + shdr->sh_size) + end = shdr->sh_addr + shdr->sh_size; + if (first || bias > shdr->sh_addr) + /* This is the lowest address in the module. */ + bias = shdr->sh_addr; + + if ((shdr->sh_addr - bias + base) & (align - 1)) + /* This section winds up misaligned using BASE. + Adjust BASE upwards to make it congruent to + the lowest section address in the file modulo ALIGN. */ + base = (((base + align - 1) & -align) + + (bias & (align - 1))); + } + + first = false; + } + } + + if (bias != 0) + { + /* The section headers had nonzero sh_addr values. The layout + was already done. We've just collected the total span. + Now just compute the bias from the requested base. */ + start = base; + end = end - bias + start; + bias = start - bias; + } + break; + + /* Everything else has to have program headers. */ + + case ET_EXEC: + case ET_CORE: + /* An assigned base address is meaningless for these. */ + base = 0; + add_p_vaddr = true; + + case ET_DYN: + default:; + size_t phnum; + if (unlikely (elf_getphdrnum (elf, &phnum) != 0)) + goto elf_error; + for (size_t i = 0; i < phnum; ++i) + { + GElf_Phdr phdr_mem, *ph = gelf_getphdr (elf, i, &phdr_mem); + if (unlikely (ph == NULL)) + goto elf_error; + if (ph->p_type == PT_LOAD) + { + vaddr = ph->p_vaddr & -ph->p_align; + address_sync = ph->p_vaddr + ph->p_memsz; + break; + } + } + if (add_p_vaddr) + { + start = base + vaddr; + bias = base; + } + else + { + start = base; + bias = base - vaddr; + } + + for (size_t i = phnum; i-- > 0;) + { + GElf_Phdr phdr_mem, *ph = gelf_getphdr (elf, i, &phdr_mem); + if (unlikely (ph == NULL)) + goto elf_error; + if (ph->p_type == PT_LOAD + && ph->p_vaddr + ph->p_memsz > 0) + { + end = bias + (ph->p_vaddr + ph->p_memsz); + break; + } + } + + if (end == 0 && sanity) + { + __libdwfl_seterrno (DWFL_E_NO_PHDR); + return false; + } + break; + } + if (vaddrp) + *vaddrp = vaddr; + if (address_syncp) + *address_syncp = address_sync; + if (startp) + *startp = start; + if (endp) + *endp = end; + if (biasp) + *biasp = bias; + if (e_typep) + *e_typep = ehdr->e_type; + return true; +} + +Dwfl_Module * +internal_function +__libdwfl_report_elf (Dwfl *dwfl, const char *name, const char *file_name, + int fd, Elf *elf, GElf_Addr base, bool add_p_vaddr, + bool sanity) +{ + GElf_Addr vaddr, address_sync, start, end, bias; + GElf_Half e_type; + if (! __libdwfl_elf_address_range (elf, base, add_p_vaddr, sanity, &vaddr, + &address_sync, &start, &end, &bias, + &e_type)) + return NULL; + Dwfl_Module *m = INTUSE(dwfl_report_module) (dwfl, name, start, end); + if (m != NULL) + { + if (m->main.name == NULL) + { + m->main.name = strdup (file_name); + m->main.fd = fd; + } + else if ((fd >= 0 && m->main.fd != fd) + || strcmp (m->main.name, file_name)) + { + overlap: + m->gc = true; + __libdwfl_seterrno (DWFL_E_OVERLAP); + return NULL; + } + + /* Preinstall the open ELF handle for the module. */ + if (m->main.elf == NULL) + { + m->main.elf = elf; + m->main.vaddr = vaddr; + m->main.address_sync = address_sync; + m->main_bias = bias; + m->e_type = e_type; + } + else + { + elf_end (elf); + if (m->main_bias != bias + || m->main.vaddr != vaddr || m->main.address_sync != address_sync) + goto overlap; + } + } + return m; +} + +Dwfl_Module * +dwfl_report_elf (Dwfl *dwfl, const char *name, const char *file_name, int fd, + GElf_Addr base, bool add_p_vaddr) +{ + bool closefd = false; + if (fd < 0) + { + closefd = true; + fd = open64 (file_name, O_RDONLY); + if (fd < 0) + { + __libdwfl_seterrno (DWFL_E_ERRNO); + return NULL; + } + } + + Elf *elf; + Dwfl_Error error = __libdw_open_file (&fd, &elf, closefd, false); + if (error != DWFL_E_NOERROR) + { + __libdwfl_seterrno (error); + return NULL; + } + + Dwfl_Module *mod = __libdwfl_report_elf (dwfl, name, file_name, + fd, elf, base, add_p_vaddr, true); + if (mod == NULL) + { + elf_end (elf); + if (closefd) + close (fd); + } + + return mod; +} +INTDEF (dwfl_report_elf) +NEW_VERSION (dwfl_report_elf, ELFUTILS_0.156) + +#ifdef SHARED +Dwfl_Module * + _compat_without_add_p_vaddr_dwfl_report_elf (Dwfl *dwfl, const char *name, + const char *file_name, int fd, + GElf_Addr base); +COMPAT_VERSION_NEWPROTO (dwfl_report_elf, ELFUTILS_0.122, without_add_p_vaddr) + +Dwfl_Module * +_compat_without_add_p_vaddr_dwfl_report_elf (Dwfl *dwfl, const char *name, + const char *file_name, int fd, + GElf_Addr base) +{ + return dwfl_report_elf (dwfl, name, file_name, fd, base, true); +} +#endif diff --git a/3rdparty/elfutils/libdwfl/dwfl_segment_report_module.c b/3rdparty/elfutils/libdwfl/dwfl_segment_report_module.c new file mode 100644 index 0000000..898457f --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_segment_report_module.c @@ -0,0 +1,922 @@ +/* Sniff out modules from ELF headers visible in memory segments. + Copyright (C) 2008-2012, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include <config.h> +#include "../libelf/libelfP.h" /* For NOTE_ALIGN. */ +#undef _ +#include "libdwflP.h" +#include "common.h" + +#include <elf.h> +#include <gelf.h> +#include <inttypes.h> +#include <sys/param.h> +#include <alloca.h> +#include <endian.h> +#include <unistd.h> +#include <fcntl.h> + + +/* A good size for the initial read from memory, if it's not too costly. + This more than covers the phdrs and note segment in the average 64-bit + binary. */ + +#define INITIAL_READ 1024 + +#if __BYTE_ORDER == __LITTLE_ENDIAN +# define MY_ELFDATA ELFDATA2LSB +#else +# define MY_ELFDATA ELFDATA2MSB +#endif + + +/* Return user segment index closest to ADDR but not above it. + If NEXT, return the closest to ADDR but not below it. */ +static int +addr_segndx (Dwfl *dwfl, size_t segment, GElf_Addr addr, bool next) +{ + int ndx = -1; + do + { + if (dwfl->lookup_segndx[segment] >= 0) + ndx = dwfl->lookup_segndx[segment]; + if (++segment >= dwfl->lookup_elts - 1) + return next ? ndx + 1 : ndx; + } + while (dwfl->lookup_addr[segment] < addr); + + if (next) + { + while (dwfl->lookup_segndx[segment] < 0) + if (++segment >= dwfl->lookup_elts - 1) + return ndx + 1; + ndx = dwfl->lookup_segndx[segment]; + } + + return ndx; +} + +/* Return whether there is SZ bytes available at PTR till END. */ + +static bool +buf_has_data (const void *ptr, const void *end, size_t sz) +{ + return ptr < end && (size_t) (end - ptr) >= sz; +} + +/* Read SZ bytes into *RETP from *PTRP (limited by END) in format EI_DATA. + Function comes from src/readelf.c . */ + +static bool +buf_read_ulong (unsigned char ei_data, size_t sz, + const void **ptrp, const void *end, uint64_t *retp) +{ + if (! buf_has_data (*ptrp, end, sz)) + return false; + + union + { + uint64_t u64; + uint32_t u32; + } u; + + memcpy (&u, *ptrp, sz); + (*ptrp) += sz; + + if (retp == NULL) + return true; + + if (MY_ELFDATA != ei_data) + { + if (sz == 4) + CONVERT (u.u32); + else + CONVERT (u.u64); + } + if (sz == 4) + *retp = u.u32; + else + *retp = u.u64; + return true; +} + +/* Try to find matching entry for module from address MODULE_START to + MODULE_END in NT_FILE note located at NOTE_FILE of NOTE_FILE_SIZE + bytes in format EI_CLASS and EI_DATA. */ + +static const char * +handle_file_note (GElf_Addr module_start, GElf_Addr module_end, + unsigned char ei_class, unsigned char ei_data, + const void *note_file, size_t note_file_size) +{ + if (note_file == NULL) + return NULL; + + size_t sz; + switch (ei_class) + { + case ELFCLASS32: + sz = 4; + break; + case ELFCLASS64: + sz = 8; + break; + default: + return NULL; + } + + const void *ptr = note_file; + const void *end = note_file + note_file_size; + uint64_t count; + if (! buf_read_ulong (ei_data, sz, &ptr, end, &count)) + return NULL; + if (! buf_read_ulong (ei_data, sz, &ptr, end, NULL)) // page_size + return NULL; + + uint64_t maxcount = (size_t) (end - ptr) / (3 * sz); + if (count > maxcount) + return NULL; + + /* Where file names are stored. */ + const char *fptr = ptr + 3 * count * sz; + + ssize_t firstix = -1; + ssize_t lastix = -1; + for (size_t mix = 0; mix < count; mix++) + { + uint64_t mstart, mend, moffset; + if (! buf_read_ulong (ei_data, sz, &ptr, fptr, &mstart) + || ! buf_read_ulong (ei_data, sz, &ptr, fptr, &mend) + || ! buf_read_ulong (ei_data, sz, &ptr, fptr, &moffset)) + return NULL; + if (mstart == module_start && moffset == 0) + firstix = lastix = mix; + if (firstix != -1 && mstart < module_end) + lastix = mix; + if (mend >= module_end) + break; + } + if (firstix == -1) + return NULL; + + const char *retval = NULL; + for (ssize_t mix = 0; mix <= lastix; mix++) + { + const char *fnext = memchr (fptr, 0, (const char *) end - fptr); + if (fnext == NULL) + return NULL; + if (mix == firstix) + retval = fptr; + if (firstix < mix && mix <= lastix && strcmp (fptr, retval) != 0) + return NULL; + fptr = fnext + 1; + } + return retval; +} + +/* Return true iff we are certain ELF cannot match BUILD_ID of + BUILD_ID_LEN bytes. Pass DISK_FILE_HAS_BUILD_ID as false if it is + certain ELF does not contain build-id (it is only a performance hit + to pass it always as true). */ + +static bool +invalid_elf (Elf *elf, bool disk_file_has_build_id, + const void *build_id, size_t build_id_len) +{ + if (! disk_file_has_build_id && build_id_len > 0) + { + /* Module found in segments with build-id is more reliable + than a module found via DT_DEBUG on disk without any + build-id. */ + return true; + } + if (disk_file_has_build_id && build_id_len > 0) + { + const void *elf_build_id; + ssize_t elf_build_id_len; + + /* If there is a build id in the elf file, check it. */ + elf_build_id_len = INTUSE(dwelf_elf_gnu_build_id) (elf, &elf_build_id); + if (elf_build_id_len > 0) + { + if (build_id_len != (size_t) elf_build_id_len + || memcmp (build_id, elf_build_id, build_id_len) != 0) + return true; + } + } + return false; +} + +int +dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, + Dwfl_Memory_Callback *memory_callback, + void *memory_callback_arg, + Dwfl_Module_Callback *read_eagerly, + void *read_eagerly_arg, + const void *note_file, size_t note_file_size, + const struct r_debug_info *r_debug_info) +{ + size_t segment = ndx; + + if (segment >= dwfl->lookup_elts) + segment = dwfl->lookup_elts - 1; + + while (segment > 0 + && (dwfl->lookup_segndx[segment] > ndx + || dwfl->lookup_segndx[segment] == -1)) + --segment; + + while (dwfl->lookup_segndx[segment] < ndx) + if (++segment == dwfl->lookup_elts) + return 0; + + GElf_Addr start = dwfl->lookup_addr[segment]; + + inline bool segment_read (int segndx, + void **buffer, size_t *buffer_available, + GElf_Addr addr, size_t minread) + { + return ! (*memory_callback) (dwfl, segndx, buffer, buffer_available, + addr, minread, memory_callback_arg); + } + + inline void release_buffer (void **buffer, size_t *buffer_available) + { + if (*buffer != NULL) + (void) segment_read (-1, buffer, buffer_available, 0, 0); + } + + /* First read in the file header and check its sanity. */ + + void *buffer = NULL; + size_t buffer_available = INITIAL_READ; + Elf *elf = NULL; + int fd = -1; + + inline int finish (void) + { + release_buffer (&buffer, &buffer_available); + if (elf != NULL) + elf_end (elf); + if (fd != -1) + close (fd); + return ndx; + } + + if (segment_read (ndx, &buffer, &buffer_available, + start, sizeof (Elf64_Ehdr)) + || memcmp (buffer, ELFMAG, SELFMAG) != 0) + return finish (); + + inline bool read_portion (void **data, size_t *data_size, + GElf_Addr vaddr, size_t filesz) + { + if (vaddr - start + filesz > buffer_available + /* If we're in string mode, then don't consider the buffer we have + sufficient unless it contains the terminator of the string. */ + || (filesz == 0 && memchr (vaddr - start + buffer, '\0', + buffer_available - (vaddr - start)) == NULL)) + { + *data = NULL; + *data_size = filesz; + return segment_read (addr_segndx (dwfl, segment, vaddr, false), + data, data_size, vaddr, filesz); + } + + /* We already have this whole note segment from our initial read. */ + *data = vaddr - start + buffer; + *data_size = 0; + return false; + } + + inline void finish_portion (void **data, size_t *data_size) + { + if (*data_size != 0) + release_buffer (data, data_size); + } + + /* Extract the information we need from the file header. */ + const unsigned char *e_ident; + unsigned char ei_class; + unsigned char ei_data; + uint16_t e_type; + union + { + Elf32_Ehdr e32; + Elf64_Ehdr e64; + } ehdr; + GElf_Off phoff; + uint_fast16_t phnum; + uint_fast16_t phentsize; + GElf_Off shdrs_end; + Elf_Data xlatefrom = + { + .d_type = ELF_T_EHDR, + .d_buf = (void *) buffer, + .d_version = EV_CURRENT, + }; + Elf_Data xlateto = + { + .d_type = ELF_T_EHDR, + .d_buf = &ehdr, + .d_size = sizeof ehdr, + .d_version = EV_CURRENT, + }; + e_ident = ((const unsigned char *) buffer); + ei_class = e_ident[EI_CLASS]; + ei_data = e_ident[EI_DATA]; + switch (ei_class) + { + case ELFCLASS32: + xlatefrom.d_size = sizeof (Elf32_Ehdr); + if (elf32_xlatetom (&xlateto, &xlatefrom, ei_data) == NULL) + return finish (); + e_type = ehdr.e32.e_type; + phoff = ehdr.e32.e_phoff; + phnum = ehdr.e32.e_phnum; + phentsize = ehdr.e32.e_phentsize; + if (phentsize != sizeof (Elf32_Phdr)) + return finish (); + shdrs_end = ehdr.e32.e_shoff + ehdr.e32.e_shnum * ehdr.e32.e_shentsize; + break; + + case ELFCLASS64: + xlatefrom.d_size = sizeof (Elf64_Ehdr); + if (elf64_xlatetom (&xlateto, &xlatefrom, ei_data) == NULL) + return finish (); + e_type = ehdr.e64.e_type; + phoff = ehdr.e64.e_phoff; + phnum = ehdr.e64.e_phnum; + phentsize = ehdr.e64.e_phentsize; + if (phentsize != sizeof (Elf64_Phdr)) + return finish (); + shdrs_end = ehdr.e64.e_shoff + ehdr.e64.e_shnum * ehdr.e64.e_shentsize; + break; + + default: + return finish (); + } + + /* The file header tells where to find the program headers. + These are what we need to find the boundaries of the module. + Without them, we don't have a module to report. */ + + if (phnum == 0) + return finish (); + + xlatefrom.d_type = xlateto.d_type = ELF_T_PHDR; + xlatefrom.d_size = phnum * phentsize; + + void *ph_buffer = NULL; + size_t ph_buffer_size = 0; + if (read_portion (&ph_buffer, &ph_buffer_size, + start + phoff, xlatefrom.d_size)) + return finish (); + + xlatefrom.d_buf = ph_buffer; + + union + { + Elf32_Phdr p32[phnum]; + Elf64_Phdr p64[phnum]; + } phdrs; + + xlateto.d_buf = &phdrs; + xlateto.d_size = sizeof phdrs; + + /* Track the bounds of the file visible in memory. */ + GElf_Off file_trimmed_end = 0; /* Proper p_vaddr + p_filesz end. */ + GElf_Off file_end = 0; /* Rounded up to effective page size. */ + GElf_Off contiguous = 0; /* Visible as contiguous file from START. */ + GElf_Off total_filesz = 0; /* Total size of data to read. */ + + /* Collect the bias between START and the containing PT_LOAD's p_vaddr. */ + GElf_Addr bias = 0; + bool found_bias = false; + + /* Collect the unbiased bounds of the module here. */ + GElf_Addr module_start = -1l; + GElf_Addr module_end = 0; + GElf_Addr module_address_sync = 0; + + /* If we see PT_DYNAMIC, record it here. */ + GElf_Addr dyn_vaddr = 0; + GElf_Xword dyn_filesz = 0; + + /* Collect the build ID bits here. */ + void *build_id = NULL; + size_t build_id_len = 0; + GElf_Addr build_id_vaddr = 0; + + /* Consider a PT_NOTE we've found in the image. */ + inline void consider_notes (GElf_Addr vaddr, GElf_Xword filesz) + { + /* If we have already seen a build ID, we don't care any more. */ + if (build_id != NULL || filesz == 0) + return; + + void *data; + size_t data_size; + if (read_portion (&data, &data_size, vaddr, filesz)) + return; + + assert (sizeof (Elf32_Nhdr) == sizeof (Elf64_Nhdr)); + + void *notes; + if (ei_data == MY_ELFDATA) + notes = data; + else + { + notes = malloc (filesz); + if (unlikely (notes == NULL)) + return; + xlatefrom.d_type = xlateto.d_type = ELF_T_NHDR; + xlatefrom.d_buf = (void *) data; + xlatefrom.d_size = filesz; + xlateto.d_buf = notes; + xlateto.d_size = filesz; + if (elf32_xlatetom (&xlateto, &xlatefrom, + ehdr.e32.e_ident[EI_DATA]) == NULL) + goto done; + } + + const GElf_Nhdr *nh = notes; + while ((const void *) nh < (const void *) notes + filesz) + { + const void *note_name = nh + 1; + const void *note_desc = note_name + NOTE_ALIGN (nh->n_namesz); + if (unlikely ((size_t) ((const void *) notes + filesz + - note_desc) < nh->n_descsz)) + break; + + if (nh->n_type == NT_GNU_BUILD_ID + && nh->n_descsz > 0 + && nh->n_namesz == sizeof "GNU" + && !memcmp (note_name, "GNU", sizeof "GNU")) + { + build_id_vaddr = note_desc - (const void *) notes + vaddr; + build_id_len = nh->n_descsz; + build_id = malloc (nh->n_descsz); + if (likely (build_id != NULL)) + memcpy (build_id, note_desc, build_id_len); + break; + } + + nh = note_desc + NOTE_ALIGN (nh->n_descsz); + } + + done: + if (notes != data) + free (notes); + finish_portion (&data, &data_size); + } + + /* Consider each of the program headers we've read from the image. */ + inline void consider_phdr (GElf_Word type, + GElf_Addr vaddr, GElf_Xword memsz, + GElf_Off offset, GElf_Xword filesz, + GElf_Xword align) + { + switch (type) + { + case PT_DYNAMIC: + dyn_vaddr = vaddr; + dyn_filesz = filesz; + break; + + case PT_NOTE: + /* We calculate from the p_offset of the note segment, + because we don't yet know the bias for its p_vaddr. */ + consider_notes (start + offset, filesz); + break; + + case PT_LOAD: + align = dwfl->segment_align > 1 ? dwfl->segment_align : align ?: 1; + + GElf_Addr vaddr_end = (vaddr + memsz + align - 1) & -align; + GElf_Addr filesz_vaddr = filesz < memsz ? vaddr + filesz : vaddr_end; + GElf_Off filesz_offset = filesz_vaddr - vaddr + offset; + + if (file_trimmed_end < offset + filesz) + { + file_trimmed_end = offset + filesz; + + /* Trim the last segment so we don't bother with zeros + in the last page that are off the end of the file. + However, if the extra bit in that page includes the + section headers, keep them. */ + if (shdrs_end <= filesz_offset && shdrs_end > file_trimmed_end) + { + filesz += shdrs_end - file_trimmed_end; + file_trimmed_end = shdrs_end; + } + } + + total_filesz += filesz; + + if (file_end < filesz_offset) + { + file_end = filesz_offset; + if (filesz_vaddr - start == filesz_offset) + contiguous = file_end; + } + + if (!found_bias && (offset & -align) == 0 + && likely (filesz_offset >= phoff + phnum * phentsize)) + { + bias = start - vaddr; + found_bias = true; + } + + if ((vaddr & -align) < module_start) + { + module_start = vaddr & -align; + module_address_sync = vaddr + memsz; + } + + if (module_end < vaddr_end) + module_end = vaddr_end; + break; + } + } + if (ei_class == ELFCLASS32) + { + if (elf32_xlatetom (&xlateto, &xlatefrom, ei_data) == NULL) + found_bias = false; /* Trigger error check. */ + else + for (uint_fast16_t i = 0; i < phnum; ++i) + consider_phdr (phdrs.p32[i].p_type, + phdrs.p32[i].p_vaddr, phdrs.p32[i].p_memsz, + phdrs.p32[i].p_offset, phdrs.p32[i].p_filesz, + phdrs.p32[i].p_align); + } + else + { + if (elf64_xlatetom (&xlateto, &xlatefrom, ei_data) == NULL) + found_bias = false; /* Trigger error check. */ + else + for (uint_fast16_t i = 0; i < phnum; ++i) + consider_phdr (phdrs.p64[i].p_type, + phdrs.p64[i].p_vaddr, phdrs.p64[i].p_memsz, + phdrs.p64[i].p_offset, phdrs.p64[i].p_filesz, + phdrs.p64[i].p_align); + } + + finish_portion (&ph_buffer, &ph_buffer_size); + + /* We must have seen the segment covering offset 0, or else the ELF + header we read at START was not produced by these program headers. */ + if (unlikely (!found_bias)) + { + free (build_id); + return finish (); + } + + /* Now we know enough to report a module for sure: its bounds. */ + module_start += bias; + module_end += bias; + + dyn_vaddr += bias; + + /* NAME found from link map has precedence over DT_SONAME possibly read + below. */ + bool name_is_final = false; + + /* Try to match up DYN_VADDR against L_LD as found in link map. + Segments sniffing may guess invalid address as the first read-only memory + mapping may not be dumped to the core file (if ELF headers are not dumped) + and the ELF header is dumped first with the read/write mapping of the same + file at higher addresses. */ + if (r_debug_info != NULL) + for (const struct r_debug_info_module *module = r_debug_info->module; + module != NULL; module = module->next) + if (module_start <= module->l_ld && module->l_ld < module_end) + { + /* L_LD read from link map must be right while DYN_VADDR is unsafe. + Therefore subtract DYN_VADDR and add L_LD to get a possibly + corrective displacement for all addresses computed so far. */ + GElf_Addr fixup = module->l_ld - dyn_vaddr; + if ((fixup & (dwfl->segment_align - 1)) == 0 + && module_start + fixup <= module->l_ld + && module->l_ld < module_end + fixup) + { + module_start += fixup; + module_end += fixup; + dyn_vaddr += fixup; + bias += fixup; + if (module->name[0] != '\0') + { + name = basename (module->name); + name_is_final = true; + } + break; + } + } + + if (r_debug_info != NULL) + { + bool skip_this_module = false; + for (struct r_debug_info_module *module = r_debug_info->module; + module != NULL; module = module->next) + if ((module_end > module->start && module_start < module->end) + || dyn_vaddr == module->l_ld) + { + if (module->elf != NULL + && invalid_elf (module->elf, module->disk_file_has_build_id, + build_id, build_id_len)) + { + elf_end (module->elf); + close (module->fd); + module->elf = NULL; + module->fd = -1; + } + if (module->elf != NULL) + { + /* Ignore this found module if it would conflict in address + space with any already existing module of DWFL. */ + skip_this_module = true; + } + } + if (skip_this_module) + { + free (build_id); + return finish (); + } + } + + const char *file_note_name = handle_file_note (module_start, module_end, + ei_class, ei_data, + note_file, note_file_size); + if (file_note_name) + { + name = file_note_name; + name_is_final = true; + bool invalid = false; + fd = open64 (name, O_RDONLY); + if (fd >= 0) + { + Dwfl_Error error = __libdw_open_file (&fd, &elf, true, false); + if (error == DWFL_E_NOERROR) + invalid = invalid_elf (elf, true /* disk_file_has_build_id */, + build_id, build_id_len); + } + if (invalid) + { + free (build_id); + return finish (); + } + } + + /* Our return value now says to skip the segments contained + within the module. */ + ndx = addr_segndx (dwfl, segment, module_end, true); + + /* Examine its .dynamic section to get more interesting details. + If it has DT_SONAME, we'll use that as the module name. + If it has a DT_DEBUG, then it's actually a PIE rather than a DSO. + We need its DT_STRTAB and DT_STRSZ to decipher DT_SONAME, + and they also tell us the essential portion of the file + for fetching symbols. */ + GElf_Addr soname_stroff = 0; + GElf_Addr dynstr_vaddr = 0; + GElf_Xword dynstrsz = 0; + bool execlike = false; + inline bool consider_dyn (GElf_Sxword tag, GElf_Xword val) + { + switch (tag) + { + default: + return false; + + case DT_DEBUG: + execlike = true; + break; + + case DT_SONAME: + soname_stroff = val; + break; + + case DT_STRTAB: + dynstr_vaddr = val; + break; + + case DT_STRSZ: + dynstrsz = val; + break; + } + + return soname_stroff != 0 && dynstr_vaddr != 0 && dynstrsz != 0; + } + + const size_t dyn_entsize = (ei_class == ELFCLASS32 + ? sizeof (Elf32_Dyn) : sizeof (Elf64_Dyn)); + void *dyn_data = NULL; + size_t dyn_data_size = 0; + if (dyn_filesz != 0 && dyn_filesz % dyn_entsize == 0 + && ! read_portion (&dyn_data, &dyn_data_size, dyn_vaddr, dyn_filesz)) + { + union + { + Elf32_Dyn d32[dyn_filesz / sizeof (Elf32_Dyn)]; + Elf64_Dyn d64[dyn_filesz / sizeof (Elf64_Dyn)]; + } dyn; + + xlatefrom.d_type = xlateto.d_type = ELF_T_DYN; + xlatefrom.d_buf = (void *) dyn_data; + xlatefrom.d_size = dyn_filesz; + xlateto.d_buf = &dyn; + xlateto.d_size = sizeof dyn; + + if (ei_class == ELFCLASS32) + { + if (elf32_xlatetom (&xlateto, &xlatefrom, ei_data) != NULL) + for (size_t i = 0; i < dyn_filesz / sizeof dyn.d32[0]; ++i) + if (consider_dyn (dyn.d32[i].d_tag, dyn.d32[i].d_un.d_val)) + break; + } + else + { + if (elf64_xlatetom (&xlateto, &xlatefrom, ei_data) != NULL) + for (size_t i = 0; i < dyn_filesz / sizeof dyn.d64[0]; ++i) + if (consider_dyn (dyn.d64[i].d_tag, dyn.d64[i].d_un.d_val)) + break; + } + } + finish_portion (&dyn_data, &dyn_data_size); + + /* We'll use the name passed in or a stupid default if not DT_SONAME. */ + if (name == NULL) + name = e_type == ET_EXEC ? "[exe]" : execlike ? "[pie]" : "[dso]"; + + void *soname = NULL; + size_t soname_size = 0; + if (! name_is_final && dynstrsz != 0 && dynstr_vaddr != 0) + { + /* We know the bounds of the .dynstr section. + + The DYNSTR_VADDR pointer comes from the .dynamic section + (DT_STRTAB, detected above). Ordinarily the dynamic linker + will have adjusted this pointer in place so it's now an + absolute address. But sometimes .dynamic is read-only (in + vDSOs and odd architectures), and sometimes the adjustment + just hasn't happened yet in the memory image we looked at. + So treat DYNSTR_VADDR as an absolute address if it falls + within the module bounds, or try applying the phdr bias + when that adjusts it to fall within the module bounds. */ + + if ((dynstr_vaddr < module_start || dynstr_vaddr >= module_end) + && dynstr_vaddr + bias >= module_start + && dynstr_vaddr + bias < module_end) + dynstr_vaddr += bias; + + if (unlikely (dynstr_vaddr + dynstrsz > module_end)) + dynstrsz = 0; + + /* Try to get the DT_SONAME string. */ + if (soname_stroff != 0 && soname_stroff + 1 < dynstrsz + && ! read_portion (&soname, &soname_size, + dynstr_vaddr + soname_stroff, 0)) + name = soname; + } + + /* Now that we have chosen the module's name and bounds, report it. + If we found a build ID, report that too. */ + + Dwfl_Module *mod = INTUSE(dwfl_report_module) (dwfl, name, + module_start, module_end); + + // !execlike && ET_EXEC is PIE. + // execlike && !ET_EXEC is a static executable. + if (mod != NULL && (execlike || ehdr.e32.e_type == ET_EXEC)) + mod->is_executable = true; + + if (likely (mod != NULL) && build_id != NULL + && unlikely (INTUSE(dwfl_module_report_build_id) (mod, + build_id, + build_id_len, + build_id_vaddr))) + { + mod->gc = true; + mod = NULL; + } + + /* At this point we do not need BUILD_ID or NAME any more. + They have been copied. */ + free (build_id); + finish_portion (&soname, &soname_size); + + if (unlikely (mod == NULL)) + { + ndx = -1; + return finish (); + } + + /* We have reported the module. Now let the caller decide whether we + should read the whole thing in right now. */ + + const GElf_Off cost = (contiguous < file_trimmed_end ? total_filesz + : buffer_available >= contiguous ? 0 + : contiguous - buffer_available); + const GElf_Off worthwhile = ((dynstr_vaddr == 0 || dynstrsz == 0) ? 0 + : dynstr_vaddr + dynstrsz - start); + const GElf_Off whole = MAX (file_trimmed_end, shdrs_end); + + if (elf == NULL + && (*read_eagerly) (MODCB_ARGS (mod), &buffer, &buffer_available, + cost, worthwhile, whole, contiguous, + read_eagerly_arg, &elf) + && elf == NULL) + { + /* The caller wants to read the whole file in right now, but hasn't + done it for us. Fill in a local image of the virtual file. */ + + void *contents = calloc (1, file_trimmed_end); + if (unlikely (contents == NULL)) + return finish (); + + inline void final_read (size_t offset, GElf_Addr vaddr, size_t size) + { + void *into = contents + offset; + size_t read_size = size; + (void) segment_read (addr_segndx (dwfl, segment, vaddr, false), + &into, &read_size, vaddr, size); + } + + if (contiguous < file_trimmed_end) + { + /* We can't use the memory image verbatim as the file image. + So we'll be reading into a local image of the virtual file. */ + + inline void read_phdr (GElf_Word type, GElf_Addr vaddr, + GElf_Off offset, GElf_Xword filesz) + { + if (type == PT_LOAD) + final_read (offset, vaddr + bias, filesz); + } + + if (ei_class == ELFCLASS32) + for (uint_fast16_t i = 0; i < phnum; ++i) + read_phdr (phdrs.p32[i].p_type, phdrs.p32[i].p_vaddr, + phdrs.p32[i].p_offset, phdrs.p32[i].p_filesz); + else + for (uint_fast16_t i = 0; i < phnum; ++i) + read_phdr (phdrs.p64[i].p_type, phdrs.p64[i].p_vaddr, + phdrs.p64[i].p_offset, phdrs.p64[i].p_filesz); + } + else + { + /* The whole file sits contiguous in memory, + but the caller didn't want to just do it. */ + + const size_t have = MIN (buffer_available, file_trimmed_end); + memcpy (contents, buffer, have); + + if (have < file_trimmed_end) + final_read (have, start + have, file_trimmed_end - have); + } + + elf = elf_memory (contents, file_trimmed_end); + if (unlikely (elf == NULL)) + free (contents); + else + elf->flags |= ELF_F_MALLOCED; + } + + if (elf != NULL) + { + /* Install the file in the module. */ + mod->main.elf = elf; + elf = NULL; + fd = -1; + mod->main.vaddr = module_start - bias; + mod->main.address_sync = module_address_sync; + mod->main_bias = bias; + } + + return finish (); +} diff --git a/3rdparty/elfutils/libdwfl/dwfl_validate_address.c b/3rdparty/elfutils/libdwfl/dwfl_validate_address.c new file mode 100644 index 0000000..7334c3e --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_validate_address.c @@ -0,0 +1,61 @@ +/* Validate an address and the relocatability of an offset from it. + Copyright (C) 2005 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" + +int +dwfl_validate_address (Dwfl *dwfl, Dwarf_Addr address, Dwarf_Sword offset) +{ + Dwfl_Module *mod = INTUSE(dwfl_addrmodule) (dwfl, address); + if (mod == NULL) + return -1; + + Dwarf_Addr relative = address; + int idx = INTUSE(dwfl_module_relocate_address) (mod, &relative); + if (idx < 0) + return -1; + + if (offset != 0) + { + int offset_idx = -1; + relative = address + offset; + if (relative >= mod->low_addr && relative <= mod->high_addr) + { + offset_idx = INTUSE(dwfl_module_relocate_address) (mod, &relative); + if (offset_idx < 0) + return -1; + } + if (offset_idx != idx) + { + __libdwfl_seterrno (DWFL_E_ADDR_OUTOFRANGE); + return -1; + } + } + + return 0; +} diff --git a/3rdparty/elfutils/libdwfl/dwfl_version.c b/3rdparty/elfutils/libdwfl/dwfl_version.c new file mode 100644 index 0000000..9673a53 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwfl_version.c @@ -0,0 +1,36 @@ +/* Return implementation's version string suitable for printing. + Copyright (C) 2006, 2007 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" + +const char * +dwfl_version (dwfl) + Dwfl *dwfl __attribute__ ((unused)); +{ + return PACKAGE_VERSION; +} diff --git a/3rdparty/elfutils/libdwfl/dwflheaders.pri b/3rdparty/elfutils/libdwfl/dwflheaders.pri new file mode 100644 index 0000000..7acb427 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/dwflheaders.pri @@ -0,0 +1,5 @@ +HEADERS += \ + $$PWD/libdwfl.h \ + $$PWD/libdwflP.h + +INCLUDEPATH += $$PWD diff --git a/3rdparty/elfutils/libdwfl/elf-from-memory.c b/3rdparty/elfutils/libdwfl/elf-from-memory.c new file mode 100644 index 0000000..b35fac7 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/elf-from-memory.c @@ -0,0 +1,370 @@ +/* Reconstruct an ELF file by reading the segments out of remote memory. + Copyright (C) 2005-2011, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include <config.h> +#include "../libelf/libelfP.h" +#undef _ + +#include "libdwflP.h" + +#include <gelf.h> +#include <sys/types.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> + +/* Reconstruct an ELF file by reading the segments out of remote memory + based on the ELF file header at EHDR_VMA and the ELF program headers it + points to. If not null, *LOADBASEP is filled in with the difference + between the addresses from which the segments were read, and the + addresses the file headers put them at. + + The function READ_MEMORY is called to copy at least MINREAD and at most + MAXREAD bytes from the remote memory at target address ADDRESS into the + local buffer at DATA; it should return -1 for errors (with code in + `errno'), 0 if it failed to read at least MINREAD bytes due to EOF, or + the number of bytes read if >= MINREAD. ARG is passed through. + + PAGESIZE is the minimum page size and alignment used for the PT_LOAD + segments. */ + +Elf * +elf_from_remote_memory (GElf_Addr ehdr_vma, + GElf_Xword pagesize, + GElf_Addr *loadbasep, + ssize_t (*read_memory) (void *arg, void *data, + GElf_Addr address, + size_t minread, + size_t maxread), + void *arg) +{ + /* First read in the file header and check its sanity. */ + + const size_t initial_bufsize = 256; + unsigned char *buffer = malloc (initial_bufsize); + if (buffer == NULL) + { + no_memory: + __libdwfl_seterrno (DWFL_E_NOMEM); + return NULL; + } + + ssize_t nread = (*read_memory) (arg, buffer, ehdr_vma, + sizeof (Elf32_Ehdr), initial_bufsize); + if (nread <= 0) + { + read_error: + free (buffer); + __libdwfl_seterrno (nread < 0 ? DWFL_E_ERRNO : DWFL_E_TRUNCATED); + return NULL; + } + + if (memcmp (buffer, ELFMAG, SELFMAG) != 0) + { + bad_elf: + free (buffer); + __libdwfl_seterrno (DWFL_E_BADELF); + return NULL; + } + + /* Extract the information we need from the file header. */ + + union + { + Elf32_Ehdr e32; + Elf64_Ehdr e64; + } ehdr; + Elf_Data xlatefrom = + { + .d_type = ELF_T_EHDR, + .d_buf = buffer, + .d_version = EV_CURRENT, + }; + Elf_Data xlateto = + { + .d_type = ELF_T_EHDR, + .d_buf = &ehdr, + .d_size = sizeof ehdr, + .d_version = EV_CURRENT, + }; + + GElf_Off phoff; + uint_fast16_t phnum; + uint_fast16_t phentsize; + GElf_Off shdrs_end; + + switch (buffer[EI_CLASS]) + { + case ELFCLASS32: + xlatefrom.d_size = sizeof (Elf32_Ehdr); + if (elf32_xlatetom (&xlateto, &xlatefrom, buffer[EI_DATA]) == NULL) + { + libelf_error: + __libdwfl_seterrno (DWFL_E_LIBELF); + return NULL; + } + phoff = ehdr.e32.e_phoff; + phnum = ehdr.e32.e_phnum; + phentsize = ehdr.e32.e_phentsize; + if (phentsize != sizeof (Elf32_Phdr) || phnum == 0) + goto bad_elf; + shdrs_end = ehdr.e32.e_shoff + ehdr.e32.e_shnum * ehdr.e32.e_shentsize; + break; + + case ELFCLASS64: + xlatefrom.d_size = sizeof (Elf64_Ehdr); + if (elf64_xlatetom (&xlateto, &xlatefrom, buffer[EI_DATA]) == NULL) + goto libelf_error; + phoff = ehdr.e64.e_phoff; + phnum = ehdr.e64.e_phnum; + phentsize = ehdr.e64.e_phentsize; + if (phentsize != sizeof (Elf64_Phdr) || phnum == 0) + goto bad_elf; + shdrs_end = ehdr.e64.e_shoff + ehdr.e64.e_shnum * ehdr.e64.e_shentsize; + break; + + default: + goto bad_elf; + } + + + /* The file header tells where to find the program headers. + These are what we use to actually choose what to read. */ + + xlatefrom.d_type = xlateto.d_type = ELF_T_PHDR; + xlatefrom.d_size = phnum * phentsize; + + if ((size_t) nread >= phoff + phnum * phentsize) + /* We already have all the phdrs from the initial read. */ + xlatefrom.d_buf = buffer + phoff; + else + { + /* Read in the program headers. */ + + if (initial_bufsize < phnum * phentsize) + { + unsigned char *newbuf = realloc (buffer, phnum * phentsize); + if (newbuf == NULL) + { + free (buffer); + goto no_memory; + } + buffer = newbuf; + } + nread = (*read_memory) (arg, buffer, ehdr_vma + phoff, + phnum * phentsize, phnum * phentsize); + if (nread <= 0) + goto read_error; + + xlatefrom.d_buf = buffer; + } + + union + { + Elf32_Phdr p32[phnum]; + Elf64_Phdr p64[phnum]; + } phdrs; + + xlateto.d_buf = &phdrs; + xlateto.d_size = sizeof phdrs; + + /* Scan for PT_LOAD segments to find the total size of the file image. */ + size_t contents_size = 0; + GElf_Off segments_end = 0; + GElf_Off segments_end_mem = 0; + GElf_Addr loadbase = ehdr_vma; + bool found_base = false; + switch (ehdr.e32.e_ident[EI_CLASS]) + { + /* Sanity checks segments and calculates segment_end, + segments_end, segments_end_mem and loadbase (if not + found_base yet). Returns true if sanity checking failed, + false otherwise. */ + inline bool handle_segment (GElf_Addr vaddr, GElf_Off offset, + GElf_Xword filesz, GElf_Xword memsz) + { + /* Sanity check the segment load aligns with the pagesize. */ + if (((vaddr - offset) & (pagesize - 1)) != 0) + return true; + + GElf_Off segment_end = ((offset + filesz + pagesize - 1) + & -pagesize); + + if (segment_end > (GElf_Off) contents_size) + contents_size = segment_end; + + if (!found_base && (offset & -pagesize) == 0) + { + loadbase = ehdr_vma - (vaddr & -pagesize); + found_base = true; + } + + segments_end = offset + filesz; + segments_end_mem = offset + memsz; + return false; + } + + case ELFCLASS32: + if (elf32_xlatetom (&xlateto, &xlatefrom, + ehdr.e32.e_ident[EI_DATA]) == NULL) + goto libelf_error; + for (uint_fast16_t i = 0; i < phnum; ++i) + if (phdrs.p32[i].p_type == PT_LOAD) + if (handle_segment (phdrs.p32[i].p_vaddr, phdrs.p32[i].p_offset, + phdrs.p32[i].p_filesz, phdrs.p32[i].p_memsz)) + goto bad_elf; + break; + + case ELFCLASS64: + if (elf64_xlatetom (&xlateto, &xlatefrom, + ehdr.e64.e_ident[EI_DATA]) == NULL) + goto libelf_error; + for (uint_fast16_t i = 0; i < phnum; ++i) + if (phdrs.p64[i].p_type == PT_LOAD) + if (handle_segment (phdrs.p64[i].p_vaddr, phdrs.p64[i].p_offset, + phdrs.p64[i].p_filesz, phdrs.p64[i].p_memsz)) + goto bad_elf; + break; + + default: + abort (); + break; + } + + /* Trim the last segment so we don't bother with zeros in the last page + that are off the end of the file. However, if the extra bit in that + page includes the section headers and the memory isn't extended (which + might indicate it will have been reused otherwise), keep them. */ + if ((GElf_Off) contents_size > segments_end + && (GElf_Off) contents_size >= shdrs_end + && segments_end == segments_end_mem) + { + contents_size = segments_end; + if ((GElf_Off) contents_size < shdrs_end) + contents_size = shdrs_end; + } + else + contents_size = segments_end; + + free (buffer); + + /* Now we know the size of the whole image we want read in. */ + buffer = calloc (1, contents_size); + if (buffer == NULL) + goto no_memory; + + switch (ehdr.e32.e_ident[EI_CLASS]) + { + /* Reads the given segment. Returns true if reading fails, + false otherwise. */ + inline bool handle_segment (GElf_Addr vaddr, GElf_Off offset, + GElf_Xword filesz) + { + GElf_Off start = offset & -pagesize; + GElf_Off end = (offset + filesz + pagesize - 1) & -pagesize; + if (end > (GElf_Off) contents_size) + end = contents_size; + nread = (*read_memory) (arg, buffer + start, + (loadbase + vaddr) & -pagesize, + end - start, end - start); + return nread <= 0; + } + + case ELFCLASS32: + for (uint_fast16_t i = 0; i < phnum; ++i) + if (phdrs.p32[i].p_type == PT_LOAD) + if (handle_segment (phdrs.p32[i].p_vaddr, phdrs.p32[i].p_offset, + phdrs.p32[i].p_filesz)) + goto read_error; + + /* If the segments visible in memory didn't include the section + headers, then clear them from the file header. */ + if (contents_size < shdrs_end) + { + ehdr.e32.e_shoff = 0; + ehdr.e32.e_shnum = 0; + ehdr.e32.e_shstrndx = 0; + } + + /* This will normally have been in the first PT_LOAD segment. But it + conceivably could be missing, and we might have just changed it. */ + xlatefrom.d_type = xlateto.d_type = ELF_T_EHDR; + xlatefrom.d_size = xlateto.d_size = sizeof ehdr.e32; + xlatefrom.d_buf = &ehdr.e32; + xlateto.d_buf = buffer; + if (elf32_xlatetof (&xlateto, &xlatefrom, + ehdr.e32.e_ident[EI_DATA]) == NULL) + goto libelf_error; + break; + + case ELFCLASS64: + for (uint_fast16_t i = 0; i < phnum; ++i) + if (phdrs.p64[i].p_type == PT_LOAD) + if (handle_segment (phdrs.p64[i].p_vaddr, phdrs.p64[i].p_offset, + phdrs.p64[i].p_filesz)) + goto read_error; + + /* If the segments visible in memory didn't include the section + headers, then clear them from the file header. */ + if (contents_size < shdrs_end) + { + ehdr.e64.e_shoff = 0; + ehdr.e64.e_shnum = 0; + ehdr.e64.e_shstrndx = 0; + } + + /* This will normally have been in the first PT_LOAD segment. But it + conceivably could be missing, and we might have just changed it. */ + xlatefrom.d_type = xlateto.d_type = ELF_T_EHDR; + xlatefrom.d_size = xlateto.d_size = sizeof ehdr.e64; + xlatefrom.d_buf = &ehdr.e64; + xlateto.d_buf = buffer; + if (elf64_xlatetof (&xlateto, &xlatefrom, + ehdr.e64.e_ident[EI_DATA]) == NULL) + goto libelf_error; + break; + + default: + abort (); + break; + } + + /* Now we have the image. Open libelf on it. */ + + Elf *elf = elf_memory ((char *) buffer, contents_size); + if (elf == NULL) + { + free (buffer); + goto libelf_error; + } + + elf->flags |= ELF_F_MALLOCED; + if (loadbasep != NULL) + *loadbasep = loadbase; + return elf; +} diff --git a/3rdparty/elfutils/libdwfl/find-debuginfo.c b/3rdparty/elfutils/libdwfl/find-debuginfo.c new file mode 100644 index 0000000..3f5314a --- /dev/null +++ b/3rdparty/elfutils/libdwfl/find-debuginfo.c @@ -0,0 +1,351 @@ +/* Standard find_debuginfo callback for libdwfl. + Copyright (C) 2005-2010, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/stat.h> +#include "system.h" + + +/* Try to open64 [DIR/][SUBDIR/]DEBUGLINK, return file descriptor or -1. + On success, *DEBUGINFO_FILE_NAME has the malloc'd name of the open file. */ +static int +try_open (const struct stat64 *main_stat, + const char *dir, const char *subdir, const char *debuglink, + char **debuginfo_file_name) +{ + char *fname; + if (dir == NULL && subdir == NULL) + { + fname = strdup (debuglink); + if (fname == NULL) + return -1; + } + else if ((subdir == NULL ? asprintf (&fname, "%s/%s", dir, debuglink) + : dir == NULL ? asprintf (&fname, "%s/%s", subdir, debuglink) + : asprintf (&fname, "%s/%s/%s", dir, subdir, debuglink)) < 0) + return -1; + + struct stat64 st; + int fd = TEMP_FAILURE_RETRY (open64 (fname, O_RDONLY)); + if (fd < 0) + free (fname); + else if (fstat64 (fd, &st) == 0 + && st.st_ino == main_stat->st_ino + && st.st_dev == main_stat->st_dev) + { + /* This is the main file by another name. Don't look at it again. */ + close (fd); + errno = ENOENT; + fd = -1; + } + else + *debuginfo_file_name = fname; + + return fd; +} + +/* Return true iff the FD's contents CRC matches DEBUGLINK_CRC. */ +static inline bool +check_crc (int fd, GElf_Word debuglink_crc) +{ + uint32_t file_crc; + return (__libdwfl_crc32_file (fd, &file_crc) == 0 + && file_crc == debuglink_crc); +} + +static bool +validate (Dwfl_Module *mod, int fd, bool check, GElf_Word debuglink_crc) +{ + /* For alt debug files always check the build-id from the Dwarf and alt. */ + if (mod->dw != NULL) + { + bool valid = false; + const void *build_id; + const char *altname; + ssize_t build_id_len = INTUSE(dwelf_dwarf_gnu_debugaltlink) (mod->dw, + &altname, + &build_id); + if (build_id_len > 0) + { + /* We need to open an Elf handle on the file so we can check its + build ID note for validation. Backdoor the handle into the + module data structure since we had to open it early anyway. */ + Dwfl_Error error = __libdw_open_file (&fd, &mod->alt_elf, + false, false); + if (error != DWFL_E_NOERROR) + __libdwfl_seterrno (error); + else + { + const void *alt_build_id; + ssize_t alt_len = INTUSE(dwelf_elf_gnu_build_id) (mod->alt_elf, + &alt_build_id); + if (alt_len > 0 && alt_len == build_id_len + && memcmp (build_id, alt_build_id, alt_len) == 0) + valid = true; + else + { + /* A mismatch! */ + elf_end (mod->alt_elf); + mod->alt_elf = NULL; + close (fd); + fd = -1; + } + } + } + return valid; + } + + /* If we have a build ID, check only that. */ + if (mod->build_id_len > 0) + { + /* We need to open an Elf handle on the file so we can check its + build ID note for validation. Backdoor the handle into the + module data structure since we had to open it early anyway. */ + + mod->debug.valid = false; + Dwfl_Error error = __libdw_open_file (&fd, &mod->debug.elf, false, false); + if (error != DWFL_E_NOERROR) + __libdwfl_seterrno (error); + else if (likely (__libdwfl_find_build_id (mod, false, + mod->debug.elf) == 2)) + /* Also backdoor the gratuitous flag. */ + mod->debug.valid = true; + else + { + /* A mismatch! */ + elf_end (mod->debug.elf); + mod->debug.elf = NULL; + close (fd); + fd = -1; + } + + return mod->debug.valid; + } + + return !check || check_crc (fd, debuglink_crc); +} + +static int +find_debuginfo_in_path (Dwfl_Module *mod, const char *file_name, + const char *debuglink_file, GElf_Word debuglink_crc, + char **debuginfo_file_name) +{ + bool cancheck = debuglink_crc != (GElf_Word) 0; + + const char *file_basename = file_name == NULL ? NULL : basename (file_name); + if (debuglink_file == NULL) + { + /* For a alt debug multi file we need a name, for a separate debug + name we may be able to fall back on file_basename.debug. */ + if (file_basename == NULL || mod->dw != NULL) + { + errno = 0; + return -1; + } + + size_t len = strlen (file_basename); + char *localname = alloca (len + sizeof ".debug"); + memcpy (localname, file_basename, len); + memcpy (&localname[len], ".debug", sizeof ".debug"); + debuglink_file = localname; + cancheck = false; + } + + /* Look for a file named DEBUGLINK_FILE in the directories + indicated by the debug directory path setting. */ + + const Dwfl_Callbacks *const cb = mod->dwfl->callbacks; + char *path = strdupa ((cb->debuginfo_path ? *cb->debuginfo_path : NULL) + ?: DEFAULT_DEBUGINFO_PATH); + + /* A leading - or + in the whole path sets whether to check file CRCs. */ + bool defcheck = true; + if (path[0] == '-' || path[0] == '+') + { + defcheck = path[0] == '+'; + ++path; + } + + /* XXX dev/ino should be cached in struct dwfl_file. */ + struct stat64 main_stat; + if (unlikely ((mod->main.fd != -1 ? fstat64 (mod->main.fd, &main_stat) + : file_name != NULL ? stat64 (file_name, &main_stat) + : -1) < 0)) + { + main_stat.st_dev = 0; + main_stat.st_ino = 0; + } + + char *file_dirname = (file_basename == file_name ? NULL + : strndupa (file_name, file_basename - 1 - file_name)); + char *p; + while ((p = strsep (&path, ":")) != NULL) + { + /* A leading - or + says whether to check file CRCs for this element. */ + bool check = defcheck; + if (*p == '+' || *p == '-') + check = *p++ == '+'; + check = check && cancheck; + + const char *dir, *subdir, *file; + switch (p[0]) + { + case '\0': + /* An empty entry says to try the main file's directory. */ + dir = file_dirname; + subdir = NULL; + file = debuglink_file; + break; + case '/': + /* An absolute path says to look there for a subdirectory + named by the main file's absolute directory. This cannot + be applied to a relative file name. For alt debug files + it means to look for the basename file in that dir or the + .dwz subdir (see below). */ + if (mod->dw == NULL + && (file_dirname == NULL || file_dirname[0] != '/')) + continue; + dir = p; + if (mod->dw == NULL) + { + subdir = file_dirname + 1; + file = debuglink_file; + } + else + { + subdir = NULL; + file = basename (debuglink_file); + } + break; + default: + /* A relative path says to try a subdirectory of that name + in the main file's directory. */ + dir = file_dirname; + subdir = p; + file = debuglink_file; + break; + } + + char *fname = NULL; + int fd = try_open (&main_stat, dir, subdir, file, &fname); + if (fd < 0) + switch (errno) + { + case ENOENT: + case ENOTDIR: + /* If we are looking for the alt file also try the .dwz subdir. + But only if this is the empty or absolute path. */ + if (mod->dw != NULL && (p[0] == '\0' || p[0] == '/')) + { + fd = try_open (&main_stat, dir, ".dwz", + basename (file), &fname); + if (fd < 0) + { + if (errno != ENOENT && errno != ENOTDIR) + return -1; + else + continue; + } + break; + } + continue; + default: + return -1; + } + if (validate (mod, fd, check, debuglink_crc)) + { + *debuginfo_file_name = fname; + return fd; + } + free (fname); + close (fd); + } + + /* No dice. */ + errno = 0; + return -1; +} + +int +dwfl_standard_find_debuginfo (Dwfl_Module *mod, + void **userdata __attribute__ ((unused)), + const char *modname __attribute__ ((unused)), + GElf_Addr base __attribute__ ((unused)), + const char *file_name, + const char *debuglink_file, + GElf_Word debuglink_crc, + char **debuginfo_file_name) +{ + /* First try by build ID if we have one. If that succeeds or fails + other than just by finding nothing, that's all we do. */ + const unsigned char *bits; + GElf_Addr vaddr; + if (INTUSE(dwfl_module_build_id) (mod, &bits, &vaddr) > 0) + { + /* Dropping most arguments means we cannot rely on them in + dwfl_build_id_find_debuginfo. But leave it that way since + some user code out there also does this, so we'll have to + handle it anyway. */ + int fd = INTUSE(dwfl_build_id_find_debuginfo) (mod, + NULL, NULL, 0, + NULL, NULL, 0, + debuginfo_file_name); + + /* Did the build_id callback find something or report an error? + Then we are done. Otherwise fallback on path based search. */ + if (fd >= 0 + || (mod->dw == NULL && mod->debug.elf != NULL) + || (mod->dw != NULL && mod->alt_elf != NULL) + || errno != 0) + return fd; + } + + /* Failing that, search the path by name. */ + int fd = find_debuginfo_in_path (mod, file_name, + debuglink_file, debuglink_crc, + debuginfo_file_name); + + if (fd < 0 && errno == 0) + { + /* If FILE_NAME is a symlink, the debug file might be associated + with the symlink target name instead. */ + + char *canon = canonicalize_file_name (file_name); + if (canon != NULL && strcmp (file_name, canon)) + fd = find_debuginfo_in_path (mod, canon, + debuglink_file, debuglink_crc, + debuginfo_file_name); + free (canon); + } + + return fd; +} +INTDEF (dwfl_standard_find_debuginfo) diff --git a/3rdparty/elfutils/libdwfl/frame_unwind.c b/3rdparty/elfutils/libdwfl/frame_unwind.c new file mode 100644 index 0000000..16cebd0 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/frame_unwind.c @@ -0,0 +1,725 @@ +/* Get previous frame state for an existing frame state. + Copyright (C) 2013, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "cfi.h" +#include <stdlib.h> +#include "libdwflP.h" +#include "../libdw/dwarf.h" +#include <sys/ptrace.h> + +/* Maximum number of DWARF expression stack slots before returning an error. */ +#define DWARF_EXPR_STACK_MAX 0x100 + +/* Maximum number of DWARF expression executed operations before returning an + error. */ +#define DWARF_EXPR_STEPS_MAX 0x1000 + +#ifndef MAX +# define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif + +bool +internal_function +__libdwfl_frame_reg_get (Dwfl_Frame *state, unsigned regno, Dwarf_Addr *val) +{ + Ebl *ebl = state->thread->process->ebl; + if (! ebl_dwarf_to_regno (ebl, ®no)) + return false; + if (regno >= ebl_frame_nregs (ebl)) + return false; + if ((state->regs_set[regno / sizeof (*state->regs_set) / 8] + & ((uint64_t) 1U << (regno % (sizeof (*state->regs_set) * 8)))) == 0) + return false; + if (val) + *val = state->regs[regno]; + return true; +} + +bool +internal_function +__libdwfl_frame_reg_set (Dwfl_Frame *state, unsigned regno, Dwarf_Addr val) +{ + Ebl *ebl = state->thread->process->ebl; + if (! ebl_dwarf_to_regno (ebl, ®no)) + return false; + if (regno >= ebl_frame_nregs (ebl)) + return false; + /* For example i386 user_regs_struct has signed fields. */ + if (ebl_get_elfclass (ebl) == ELFCLASS32) + val &= 0xffffffff; + state->regs_set[regno / sizeof (*state->regs_set) / 8] |= + ((uint64_t) 1U << (regno % (sizeof (*state->regs_set) * 8))); + state->regs[regno] = val; + return true; +} + +static bool +state_get_reg (Dwfl_Frame *state, unsigned regno, Dwarf_Addr *val) +{ + if (! __libdwfl_frame_reg_get (state, regno, val)) + { + __libdwfl_seterrno (DWFL_E_INVALID_REGISTER); + return false; + } + return true; +} + +static int +bra_compar (const void *key_voidp, const void *elem_voidp) +{ + Dwarf_Word offset = (uintptr_t) key_voidp; + const Dwarf_Op *op = elem_voidp; + return (offset > op->offset) - (offset < op->offset); +} + +/* If FRAME is NULL is are computing CFI frame base. In such case another + DW_OP_call_frame_cfa is no longer permitted. */ + +static bool +expr_eval (Dwfl_Frame *state, Dwarf_Frame *frame, const Dwarf_Op *ops, + size_t nops, Dwarf_Addr *result, Dwarf_Addr bias) +{ + Dwfl_Process *process = state->thread->process; + if (nops == 0) + { + __libdwfl_seterrno (DWFL_E_INVALID_DWARF); + return false; + } + Dwarf_Addr *stack = NULL; + size_t stack_used = 0, stack_allocated = 0; + + bool + push (Dwarf_Addr val) + { + if (stack_used >= DWARF_EXPR_STACK_MAX) + { + __libdwfl_seterrno (DWFL_E_INVALID_DWARF); + return false; + } + if (stack_used == stack_allocated) + { + stack_allocated = MAX (stack_allocated * 2, 32); + Dwarf_Addr *stack_new = realloc (stack, stack_allocated * sizeof (*stack)); + if (stack_new == NULL) + { + __libdwfl_seterrno (DWFL_E_NOMEM); + return false; + } + stack = stack_new; + } + stack[stack_used++] = val; + return true; + } + + bool + pop (Dwarf_Addr *val) + { + if (stack_used == 0) + { + __libdwfl_seterrno (DWFL_E_INVALID_DWARF); + return false; + } + *val = stack[--stack_used]; + return true; + } + + Dwarf_Addr val1, val2; + bool is_location = false; + size_t steps_count = 0; + for (const Dwarf_Op *op = ops; op < ops + nops; op++) + { + if (++steps_count > DWARF_EXPR_STEPS_MAX) + { + __libdwfl_seterrno (DWFL_E_INVALID_DWARF); + return false; + } + switch (op->atom) + { + /* DW_OP_* order matches libgcc/unwind-dw2.c execute_stack_op: */ + case DW_OP_lit0 ... DW_OP_lit31: + if (! push (op->atom - DW_OP_lit0)) + { + free (stack); + return false; + } + break; + case DW_OP_addr: + if (! push (op->number + bias)) + { + free (stack); + return false; + } + break; + case DW_OP_GNU_encoded_addr: + /* Missing support in the rest of elfutils. */ + __libdwfl_seterrno (DWFL_E_UNSUPPORTED_DWARF); + return false; + case DW_OP_const1u: + case DW_OP_const1s: + case DW_OP_const2u: + case DW_OP_const2s: + case DW_OP_const4u: + case DW_OP_const4s: + case DW_OP_const8u: + case DW_OP_const8s: + case DW_OP_constu: + case DW_OP_consts: + if (! push (op->number)) + { + free (stack); + return false; + } + break; + case DW_OP_reg0 ... DW_OP_reg31: + if (! state_get_reg (state, op->atom - DW_OP_reg0, &val1) + || ! push (val1)) + { + free (stack); + return false; + } + break; + case DW_OP_regx: + if (! state_get_reg (state, op->number, &val1) || ! push (val1)) + { + free (stack); + return false; + } + break; + case DW_OP_breg0 ... DW_OP_breg31: + if (! state_get_reg (state, op->atom - DW_OP_breg0, &val1)) + { + free (stack); + return false; + } + val1 += op->number; + if (! push (val1)) + { + free (stack); + return false; + } + break; + case DW_OP_bregx: + if (! state_get_reg (state, op->number, &val1)) + { + free (stack); + return false; + } + val1 += op->number2; + if (! push (val1)) + { + free (stack); + return false; + } + break; + case DW_OP_dup: + if (! pop (&val1) || ! push (val1) || ! push (val1)) + { + free (stack); + return false; + } + break; + case DW_OP_drop: + if (! pop (&val1)) + { + free (stack); + return false; + } + break; + case DW_OP_pick: + if (stack_used <= op->number) + { + free (stack); + __libdwfl_seterrno (DWFL_E_INVALID_DWARF); + return false; + } + if (! push (stack[stack_used - 1 - op->number])) + { + free (stack); + return false; + } + break; + case DW_OP_over: + if (! pop (&val1) || ! pop (&val2) + || ! push (val2) || ! push (val1) || ! push (val2)) + { + free (stack); + return false; + } + break; + case DW_OP_swap: + if (! pop (&val1) || ! pop (&val2) || ! push (val1) || ! push (val2)) + { + free (stack); + return false; + } + break; + case DW_OP_rot: + { + Dwarf_Addr val3; + if (! pop (&val1) || ! pop (&val2) || ! pop (&val3) + || ! push (val1) || ! push (val3) || ! push (val2)) + { + free (stack); + return false; + } + } + break; + case DW_OP_deref: + case DW_OP_deref_size: + if (process->callbacks->memory_read == NULL) + { + free (stack); + __libdwfl_seterrno (DWFL_E_INVALID_ARGUMENT); + return false; + } + if (! pop (&val1) + || ! process->callbacks->memory_read (process->dwfl, val1, &val1, + process->callbacks_arg)) + { + free (stack); + return false; + } + if (op->atom == DW_OP_deref_size) + { + const int elfclass = frame->cache->e_ident[EI_CLASS]; + const unsigned addr_bytes = elfclass == ELFCLASS32 ? 4 : 8; + if (op->number > addr_bytes) + { + free (stack); + __libdwfl_seterrno (DWFL_E_INVALID_DWARF); + return false; + } +#if BYTE_ORDER == BIG_ENDIAN + if (op->number == 0) + val1 = 0; + else + val1 >>= (addr_bytes - op->number) * 8; +#else + if (op->number < 8) + val1 &= (1 << (op->number * 8)) - 1; +#endif + } + if (! push (val1)) + { + free (stack); + return false; + } + break; +#define UNOP(atom, expr) \ + case atom: \ + if (! pop (&val1) || ! push (expr)) \ + { \ + free (stack); \ + return false; \ + } \ + break; + UNOP (DW_OP_abs, abs ((int64_t) val1)) + UNOP (DW_OP_neg, -(int64_t) val1) + UNOP (DW_OP_not, ~val1) +#undef UNOP + case DW_OP_plus_uconst: + if (! pop (&val1) || ! push (val1 + op->number)) + { + free (stack); + return false; + } + break; +#define BINOP(atom, op) \ + case atom: \ + if (! pop (&val2) || ! pop (&val1) || ! push (val1 op val2)) \ + { \ + free (stack); \ + return false; \ + } \ + break; +#define BINOP_SIGNED(atom, op) \ + case atom: \ + if (! pop (&val2) || ! pop (&val1) \ + || ! push ((int64_t) val1 op (int64_t) val2)) \ + { \ + free (stack); \ + return false; \ + } \ + break; + BINOP (DW_OP_and, &) + case DW_OP_div: + if (! pop (&val2) || ! pop (&val1)) + { + free (stack); + return false; + } + if (val2 == 0) + { + free (stack); + __libdwfl_seterrno (DWFL_E_INVALID_DWARF); + return false; + } + if (! push ((int64_t) val1 / (int64_t) val2)) + { + free (stack); + return false; + } + break; + BINOP (DW_OP_minus, -) + case DW_OP_mod: + if (! pop (&val2) || ! pop (&val1)) + { + free (stack); + return false; + } + if (val2 == 0) + { + free (stack); + __libdwfl_seterrno (DWFL_E_INVALID_DWARF); + return false; + } + if (! push (val1 % val2)) + { + free (stack); + return false; + } + break; + BINOP (DW_OP_mul, *) + BINOP (DW_OP_or, |) + BINOP (DW_OP_plus, +) + BINOP (DW_OP_shl, <<) + BINOP (DW_OP_shr, >>) + BINOP_SIGNED (DW_OP_shra, >>) + BINOP (DW_OP_xor, ^) + BINOP_SIGNED (DW_OP_le, <=) + BINOP_SIGNED (DW_OP_ge, >=) + BINOP_SIGNED (DW_OP_eq, ==) + BINOP_SIGNED (DW_OP_lt, <) + BINOP_SIGNED (DW_OP_gt, >) + BINOP_SIGNED (DW_OP_ne, !=) +#undef BINOP +#undef BINOP_SIGNED + case DW_OP_bra: + if (! pop (&val1)) + { + free (stack); + return false; + } + if (val1 == 0) + break; + /* FALLTHRU */ + case DW_OP_skip:; + Dwarf_Word offset = op->offset + 1 + 2 + (int16_t) op->number; + const Dwarf_Op *found = bsearch ((void *) (uintptr_t) offset, ops, nops, + sizeof (*ops), bra_compar); + if (found == NULL) + { + free (stack); + /* PPC32 vDSO has such invalid operations. */ + __libdwfl_seterrno (DWFL_E_INVALID_DWARF); + return false; + } + /* Undo the 'for' statement increment. */ + op = found - 1; + break; + case DW_OP_nop: + break; + /* DW_OP_* not listed in libgcc/unwind-dw2.c execute_stack_op: */ + case DW_OP_call_frame_cfa:; + // Not used by CFI itself but it is synthetized by elfutils internation. + Dwarf_Op *cfa_ops; + size_t cfa_nops; + Dwarf_Addr cfa; + if (frame == NULL + || dwarf_frame_cfa (frame, &cfa_ops, &cfa_nops) != 0 + || ! expr_eval (state, NULL, cfa_ops, cfa_nops, &cfa, bias) + || ! push (cfa)) + { + __libdwfl_seterrno (DWFL_E_LIBDW); + free (stack); + return false; + } + is_location = true; + break; + case DW_OP_stack_value: + // Not used by CFI itself but it is synthetized by elfutils internation. + is_location = false; + break; + default: + __libdwfl_seterrno (DWFL_E_INVALID_DWARF); + return false; + } + } + if (! pop (result)) + { + free (stack); + return false; + } + free (stack); + if (is_location) + { + if (process->callbacks->memory_read == NULL) + { + __libdwfl_seterrno (DWFL_E_INVALID_ARGUMENT); + return false; + } + if (! process->callbacks->memory_read (process->dwfl, *result, result, + process->callbacks_arg)) + return false; + } + return true; +} + +static void +new_unwound (Dwfl_Frame *state) +{ + assert (state->unwound == NULL); + Dwfl_Thread *thread = state->thread; + Dwfl_Process *process = thread->process; + Ebl *ebl = process->ebl; + size_t nregs = ebl_frame_nregs (ebl); + assert (nregs > 0); + Dwfl_Frame *unwound; + unwound = malloc (sizeof (*unwound) + sizeof (*unwound->regs) * nregs); + state->unwound = unwound; + unwound->thread = thread; + unwound->unwound = NULL; + unwound->signal_frame = false; + unwound->initial_frame = false; + unwound->pc_state = DWFL_FRAME_STATE_ERROR; + memset (unwound->regs_set, 0, sizeof (unwound->regs_set)); +} + +/* The logic is to call __libdwfl_seterrno for any CFI bytecode interpretation + error so one can easily catch the problem with a debugger. Still there are + archs with invalid CFI for some registers where the registers are never used + later. Therefore we continue unwinding leaving the registers undefined. */ + +static void +handle_cfi (Dwfl_Frame *state, Dwarf_Addr pc, Dwarf_CFI *cfi, Dwarf_Addr bias) +{ + Dwarf_Frame *frame; + if (INTUSE(dwarf_cfi_addrframe) (cfi, pc, &frame) != 0) + { + __libdwfl_seterrno (DWFL_E_LIBDW); + return; + } + new_unwound (state); + Dwfl_Frame *unwound = state->unwound; + unwound->signal_frame = frame->fde->cie->signal_frame; + Dwfl_Thread *thread = state->thread; + Dwfl_Process *process = thread->process; + Ebl *ebl = process->ebl; + size_t nregs = ebl_frame_nregs (ebl); + assert (nregs > 0); + + /* The return register is special for setting the unwound->pc_state. */ + unsigned ra = frame->fde->cie->return_address_register; + bool ra_set = false; + ebl_dwarf_to_regno (ebl, &ra); + + for (unsigned regno = 0; regno < nregs; regno++) + { + Dwarf_Op reg_ops_mem[3], *reg_ops; + size_t reg_nops; + if (dwarf_frame_register (frame, regno, reg_ops_mem, ®_ops, + ®_nops) != 0) + { + __libdwfl_seterrno (DWFL_E_LIBDW); + continue; + } + Dwarf_Addr regval; + if (reg_nops == 0) + { + if (reg_ops == reg_ops_mem) + { + /* REGNO is undefined. */ + if (regno == ra) + unwound->pc_state = DWFL_FRAME_STATE_PC_UNDEFINED; + continue; + } + else if (reg_ops == NULL) + { + /* REGNO is same-value. */ + if (! state_get_reg (state, regno, ®val)) + continue; + } + else + { + __libdwfl_seterrno (DWFL_E_INVALID_DWARF); + continue; + } + } + else if (! expr_eval (state, frame, reg_ops, reg_nops, ®val, bias)) + { + /* PPC32 vDSO has various invalid operations, ignore them. The + register will look as unset causing an error later, if used. + But PPC32 does not use such registers. */ + continue; + } + + /* Some architectures encode some extra info in the return address. */ + if (regno == frame->fde->cie->return_address_register) + regval &= ebl_func_addr_mask (ebl); + + /* This is another strange PPC[64] case. There are two + registers numbers that can represent the same DWARF return + register number. We only want one to actually set the return + register value. But we always want to override the value if + the register is the actual CIE return address register. */ + if (ra_set && regno != frame->fde->cie->return_address_register) + { + unsigned r = regno; + if (ebl_dwarf_to_regno (ebl, &r) && r == ra) + continue; + } + + if (! __libdwfl_frame_reg_set (unwound, regno, regval)) + { + __libdwfl_seterrno (DWFL_E_INVALID_REGISTER); + continue; + } + else if (! ra_set) + { + unsigned r = regno; + if (ebl_dwarf_to_regno (ebl, &r) && r == ra) + ra_set = true; + } + } + if (unwound->pc_state == DWFL_FRAME_STATE_ERROR + && __libdwfl_frame_reg_get (unwound, + frame->fde->cie->return_address_register, + &unwound->pc)) + { + /* PPC32 __libc_start_main properly CFI-unwinds PC as zero. Currently + none of the archs supported for unwinding have zero as a valid PC. */ + if (unwound->pc == 0) + unwound->pc_state = DWFL_FRAME_STATE_PC_UNDEFINED; + else + unwound->pc_state = DWFL_FRAME_STATE_PC_SET; + } + free (frame); +} + +static bool +setfunc (int firstreg, unsigned nregs, const Dwarf_Word *regs, void *arg) +{ + Dwfl_Frame *state = arg; + Dwfl_Frame *unwound = state->unwound; + if (firstreg < 0) + { + assert (firstreg == -1); + assert (nregs == 1); + assert (unwound->pc_state == DWFL_FRAME_STATE_PC_UNDEFINED); + unwound->pc = *regs; + unwound->pc_state = DWFL_FRAME_STATE_PC_SET; + return true; + } + while (nregs--) + if (! __libdwfl_frame_reg_set (unwound, firstreg++, *regs++)) + return false; + return true; +} + +static bool +getfunc (int firstreg, unsigned nregs, Dwarf_Word *regs, void *arg) +{ + Dwfl_Frame *state = arg; + assert (firstreg >= 0); + while (nregs--) + if (! __libdwfl_frame_reg_get (state, firstreg++, regs++)) + return false; + return true; +} + +static bool +readfunc (Dwarf_Addr addr, Dwarf_Word *datap, void *arg) +{ + Dwfl_Frame *state = arg; + Dwfl_Thread *thread = state->thread; + Dwfl_Process *process = thread->process; + return process->callbacks->memory_read (process->dwfl, addr, datap, + process->callbacks_arg); +} + +void +internal_function +__libdwfl_frame_unwind (Dwfl_Frame *state) +{ + if (state->unwound) + return; + /* Do not ask dwfl_frame_pc for ISACTIVATION, it would try to unwind STATE + which would deadlock us. */ + Dwarf_Addr pc; + bool ok = INTUSE(dwfl_frame_pc) (state, &pc, NULL); + assert (ok); + /* Check whether this is the initial frame or a signal frame. + Then we need to unwind from the original, unadjusted PC. */ + if (! state->initial_frame && ! state->signal_frame) + pc--; + Dwfl_Module *mod = INTUSE(dwfl_addrmodule) (state->thread->process->dwfl, pc); + if (mod == NULL) + __libdwfl_seterrno (DWFL_E_NO_DWARF); + else + { + Dwarf_Addr bias; + Dwarf_CFI *cfi_eh = INTUSE(dwfl_module_eh_cfi) (mod, &bias); + if (cfi_eh) + { + handle_cfi (state, pc - bias, cfi_eh, bias); + if (state->unwound) + return; + } + Dwarf_CFI *cfi_dwarf = INTUSE(dwfl_module_dwarf_cfi) (mod, &bias); + if (cfi_dwarf) + { + handle_cfi (state, pc - bias, cfi_dwarf, bias); + if (state->unwound) + return; + } + } + assert (state->unwound == NULL); + Dwfl_Thread *thread = state->thread; + Dwfl_Process *process = thread->process; + Ebl *ebl = process->ebl; + new_unwound (state); + state->unwound->pc_state = DWFL_FRAME_STATE_PC_UNDEFINED; + // &Dwfl_Frame.signal_frame cannot be passed as it is a bitfield. + bool signal_frame = false; + if (! ebl_unwind (ebl, pc, setfunc, getfunc, readfunc, state, &signal_frame)) + { + // Discard the unwind attempt. During next __libdwfl_frame_unwind call + // we may have for example the appropriate Dwfl_Module already mapped. + assert (state->unwound->unwound == NULL); + free (state->unwound); + state->unwound = NULL; + // __libdwfl_seterrno has been called above. + return; + } + assert (state->unwound->pc_state == DWFL_FRAME_STATE_PC_SET); + state->unwound->signal_frame = signal_frame; +} diff --git a/3rdparty/elfutils/libdwfl/gzip.c b/3rdparty/elfutils/libdwfl/gzip.c new file mode 100644 index 0000000..b7dde5d --- /dev/null +++ b/3rdparty/elfutils/libdwfl/gzip.c @@ -0,0 +1,295 @@ +/* Decompression support for libdwfl: zlib (gzip) and/or bzlib (bzip2). + Copyright (C) 2009 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" +#include "system.h" + +#include <unistd.h> + +#ifdef LZMA +# define USE_INFLATE 1 +# include <lzma.h> +# define unzip __libdw_unlzma +# define DWFL_E_ZLIB DWFL_E_LZMA +# define MAGIC "\xFD" "7zXZ\0" /* XZ file format. */ +# define MAGIC2 "\x5d\0" /* Raw LZMA format. */ +# define Z(what) LZMA_##what +# define LZMA_ERRNO LZMA_PROG_ERROR +# define z_stream lzma_stream +# define inflateInit(z) lzma_auto_decoder (z, 1 << 30, 0) +# define do_inflate(z) lzma_code (z, LZMA_RUN) +# define inflateEnd(z) lzma_end (z) +#elif defined BZLIB +# define USE_INFLATE 1 +# include <bzlib.h> +# define unzip __libdw_bunzip2 +# define DWFL_E_ZLIB DWFL_E_BZLIB +# define MAGIC "BZh" +# define Z(what) BZ_##what +# define BZ_ERRNO BZ_IO_ERROR +# define z_stream bz_stream +# define inflateInit(z) BZ2_bzDecompressInit (z, 0, 0) +# define do_inflate(z) BZ2_bzDecompress (z) +# define inflateEnd(z) BZ2_bzDecompressEnd (z) +#else +# define USE_INFLATE 0 +# define crc32 loser_crc32 +# include <zlib.h> +# define unzip __libdw_gunzip +# define MAGIC "\037\213" +# define Z(what) Z_##what +#endif + +#define READ_SIZE (1 << 20) + +/* If this is not a compressed image, return DWFL_E_BADELF. + If we uncompressed it into *WHOLE, *WHOLE_SIZE, return DWFL_E_NOERROR. + Otherwise return an error for bad compressed data or I/O failure. + If we return an error after reading the first part of the file, + leave that portion malloc'd in *WHOLE, *WHOLE_SIZE. If *WHOLE + is not null on entry, we'll use it in lieu of repeating a read. */ + +Dwfl_Error internal_function +unzip (int fd, off64_t start_offset, + void *mapped, size_t mapped_size, + void **whole, size_t *whole_size) +{ + void *buffer = NULL; + size_t size = 0; + inline bool bigger_buffer (size_t start) + { + size_t more = size ? size * 2 : start; + char *b = realloc (buffer, more); + while (unlikely (b == NULL) && more >= size + 1024) + b = realloc (buffer, more -= 1024); + if (unlikely (b == NULL)) + return false; + buffer = b; + size = more; + return true; + } + inline void smaller_buffer (size_t end) + { + buffer = realloc (buffer, end) ?: end == 0 ? NULL : buffer; + size = end; + } + + void *input_buffer = NULL; + off_t input_pos = 0; + + inline Dwfl_Error fail (Dwfl_Error failure) + { + if (input_pos == (off_t) mapped_size) + *whole = input_buffer; + else + { + free (input_buffer); + *whole = NULL; + } + free (buffer); + return failure; + } + + inline Dwfl_Error zlib_fail (int result) + { + switch (result) + { + case Z (MEM_ERROR): + return fail (DWFL_E_NOMEM); + case Z (ERRNO): + return fail (DWFL_E_ERRNO); + default: + return fail (DWFL_E_ZLIB); + } + } + + if (mapped == NULL) + { + if (*whole == NULL) + { + input_buffer = malloc (READ_SIZE); + if (unlikely (input_buffer == NULL)) + return DWFL_E_NOMEM; + + ssize_t n = pread_retry (fd, input_buffer, READ_SIZE, start_offset); + if (unlikely (n < 0)) + return zlib_fail (Z (ERRNO)); + + input_pos = n; + mapped = input_buffer; + mapped_size = n; + } + else + { + input_buffer = *whole; + input_pos = mapped_size = *whole_size; + } + } + +#define NOMAGIC(magic) \ + (mapped_size <= sizeof magic || memcmp (mapped, magic, sizeof magic - 1)) + + /* First, look at the header. */ + if (NOMAGIC (MAGIC) +#ifdef MAGIC2 + && NOMAGIC (MAGIC2) +#endif + ) + /* Not a compressed file. */ + return DWFL_E_BADELF; + +#if USE_INFLATE + + /* This style actually only works with bzlib and liblzma. + The stupid zlib interface has nothing to grok the + gzip file headers except the slow gzFile interface. */ + + z_stream z = { .next_in = mapped, .avail_in = mapped_size }; + int result = inflateInit (&z); + if (result != Z (OK)) + { + inflateEnd (&z); + return zlib_fail (result); + } + + do + { + if (z.avail_in == 0 && input_buffer != NULL) + { + ssize_t n = pread_retry (fd, input_buffer, READ_SIZE, + start_offset + input_pos); + if (unlikely (n < 0)) + { + inflateEnd (&z); + return zlib_fail (Z (ERRNO)); + } + z.next_in = input_buffer; + z.avail_in = n; + input_pos += n; + } + if (z.avail_out == 0) + { + ptrdiff_t pos = (void *) z.next_out - buffer; + if (!bigger_buffer (z.avail_in)) + { + result = Z (MEM_ERROR); + break; + } + z.next_out = buffer + pos; + z.avail_out = size - pos; + } + } + while ((result = do_inflate (&z)) == Z (OK)); + +#ifdef BZLIB + uint64_t total_out = (((uint64_t) z.total_out_hi32 << 32) + | z.total_out_lo32); + smaller_buffer (total_out); +#else + smaller_buffer (z.total_out); +#endif + + inflateEnd (&z); + + if (result != Z (STREAM_END)) + return zlib_fail (result); + +#else /* gzip only. */ + + /* Let the decompression library read the file directly. */ + + gzFile zf; + Dwfl_Error open_stream (void) + { + int d = dup (fd); + if (unlikely (d < 0)) + return DWFL_E_BADELF; + if (start_offset != 0) + { + off64_t off = lseek (d, start_offset, SEEK_SET); + if (off != start_offset) + { + close (d); + return DWFL_E_BADELF; + } + } + zf = gzdopen (d, "r"); + if (unlikely (zf == NULL)) + { + close (d); + return zlib_fail (Z (MEM_ERROR)); + } + + /* From here on, zlib will close D. */ + + return DWFL_E_NOERROR; + } + + Dwfl_Error result = open_stream (); + + if (result == DWFL_E_NOERROR && gzdirect (zf)) + { + gzclose (zf); + return fail (DWFL_E_BADELF); + } + + if (result != DWFL_E_NOERROR) + return fail (result); + + ptrdiff_t pos = 0; + while (1) + { + if (!bigger_buffer (1024)) + { + gzclose (zf); + return zlib_fail (Z (MEM_ERROR)); + } + int n = gzread (zf, buffer + pos, size - pos); + if (n < 0) + { + int code; + gzerror (zf, &code); + gzclose (zf); + return zlib_fail (code); + } + if (n == 0) + break; + pos += n; + } + + gzclose (zf); + smaller_buffer (pos); +#endif + + free (input_buffer); + + *whole = buffer; + *whole_size = size; + + return DWFL_E_NOERROR; +} diff --git a/3rdparty/elfutils/libdwfl/image-header.c b/3rdparty/elfutils/libdwfl/image-header.c new file mode 100644 index 0000000..a4f6799 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/image-header.c @@ -0,0 +1,101 @@ +/* Linux kernel image support for libdwfl. + Copyright (C) 2009-2011 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" +#include "system.h" + +#include <unistd.h> +#include <endian.h> + +#if BYTE_ORDER == LITTLE_ENDIAN +# define LE16(x) (x) +#else +# define LE16(x) bswap_16 (x) +#endif + +/* See Documentation/x86/boot.txt in Linux kernel sources + for an explanation of these format details. */ + +#define MAGIC1 0xaa55 +#define MAGIC2 0x53726448 /* "HdrS" little-endian */ +#define MIN_VERSION 0x0208 + +#define H_START (H_SETUP_SECTS & -4) +#define H_SETUP_SECTS 0x1f1 +#define H_MAGIC1 0x1fe +#define H_MAGIC2 0x202 +#define H_VERSION 0x206 +#define H_PAYLOAD_OFFSET 0x248 +#define H_PAYLOAD_LENGTH 0x24c +#define H_END 0x250 +#define H_READ_SIZE (H_END - H_START) + +Dwfl_Error +internal_function +__libdw_image_header (int fd, off64_t *start_offset, + void *mapped, size_t mapped_size) +{ + if (likely (mapped_size > H_END)) + { + const void *header = mapped; + char header_buffer[H_READ_SIZE]; + if (header == NULL) + { + ssize_t n = pread_retry (fd, header_buffer, H_READ_SIZE, + *start_offset + H_START); + if (n < 0) + return DWFL_E_ERRNO; + if (n < H_READ_SIZE) + return DWFL_E_BADELF; + + header = header_buffer - H_START; + } + + if (*(uint16_t *) (header + H_MAGIC1) == LE16 (MAGIC1) + && *(uint32_t *) (header + H_MAGIC2) == LE32 (MAGIC2) + && LE16 (*(uint16_t *) (header + H_VERSION)) >= MIN_VERSION) + { + /* The magic numbers match and the version field is sufficient. + Extract the payload bounds. */ + + uint32_t offset = LE32 (*(uint32_t *) (header + H_PAYLOAD_OFFSET)); + uint32_t length = LE32 (*(uint32_t *) (header + H_PAYLOAD_LENGTH)); + + offset += ((*(uint8_t *) (header + H_SETUP_SECTS) ?: 4) + 1) * 512; + + if (offset > H_END && offset < mapped_size + && mapped_size - offset >= length) + { + /* It looks kosher. Use it! */ + *start_offset += offset; + return DWFL_E_NOERROR; + } + } + } + return DWFL_E_BADELF; +} diff --git a/3rdparty/elfutils/libdwfl/libdwfl.h b/3rdparty/elfutils/libdwfl/libdwfl.h new file mode 100644 index 0000000..2bb4f45 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/libdwfl.h @@ -0,0 +1,812 @@ +/* Interfaces for libdwfl. + Copyright (C) 2005-2010, 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifndef _LIBDWFL_H +#define _LIBDWFL_H 1 + +#include "libdw.h" +#include <stdio.h> + +/* Handle for a session using the library. */ +typedef struct Dwfl Dwfl; + +/* Handle for a module. */ +typedef struct Dwfl_Module Dwfl_Module; + +/* Handle describing a line record. */ +typedef struct Dwfl_Line Dwfl_Line; + +/* This holds information common for all the frames of one backtrace for + a partical thread/task/TID. Several threads belong to one Dwfl. */ +typedef struct Dwfl_Thread Dwfl_Thread; + +/* This holds everything we know about the state of the frame at a particular + PC location described by an FDE belonging to Dwfl_Thread. */ +typedef struct Dwfl_Frame Dwfl_Frame; + +/* Callbacks. */ +typedef struct +{ + int (*find_elf) (Dwfl_Module *mod, void **userdata, + const char *modname, Dwarf_Addr base, + char **file_name, Elf **elfp); + + int (*find_debuginfo) (Dwfl_Module *mod, void **userdata, + const char *modname, Dwarf_Addr base, + const char *file_name, + const char *debuglink_file, GElf_Word debuglink_crc, + char **debuginfo_file_name); + + /* Fill *ADDR with the loaded address of the section called SECNAME in + the given module. Use (Dwarf_Addr) -1 if this section is omitted from + accessible memory. This is called exactly once for each SHF_ALLOC + section that relocations affecting DWARF data refer to, so it can + easily be used to collect state about the sections referenced. */ + int (*section_address) (Dwfl_Module *mod, void **userdata, + const char *modname, Dwarf_Addr base, + const char *secname, + GElf_Word shndx, const GElf_Shdr *shdr, + Dwarf_Addr *addr); + + char **debuginfo_path; /* See dwfl_standard_find_debuginfo. */ +} Dwfl_Callbacks; + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Start a new session with the library. */ +extern Dwfl *dwfl_begin (const Dwfl_Callbacks *callbacks) + __nonnull_attribute__ (1); + + +/* End a session. */ +extern void dwfl_end (Dwfl *); + +/* Return implementation's version string suitable for printing. */ +extern const char *dwfl_version (Dwfl *); + +/* Return error code of last failing function call. This value is kept + separately for each thread. */ +extern int dwfl_errno (void); + +/* Return error string for ERROR. If ERROR is zero, return error string + for most recent error or NULL if none occurred. If ERROR is -1 the + behaviour is similar to the last case except that not NULL but a legal + string is returned. */ +extern const char *dwfl_errmsg (int err); + + +/* Start reporting the current set of segments and modules to the library. + All existing segments are wiped. Existing modules are marked to be + deleted, and will not be found via dwfl_addrmodule et al if they are not + re-reported before dwfl_report_end is called. */ +extern void dwfl_report_begin (Dwfl *dwfl); + +/* Report that segment NDX begins at PHDR->p_vaddr + BIAS. + If NDX is < 0, the value succeeding the last call's NDX + is used instead (zero on the first call). + + If nonzero, the smallest PHDR->p_align value seen sets the + effective page size for the address space DWFL describes. + This is the granularity at which reported module boundary + addresses will be considered to fall in or out of a segment. + + Returns -1 for errors, or NDX (or its assigned replacement) on success. + + When NDX is the value succeeding the last call's NDX (or is implicitly + so as above), IDENT is nonnull and matches the value in the last call, + and the PHDR and BIAS values reflect a segment that would be contiguous, + in both memory and file, with the last segment reported, then this + segment may be coalesced internally with preceding segments. When given + an address inside this segment, dwfl_addrsegment may return the NDX of a + preceding contiguous segment. To prevent coalesced segments, always + pass a null pointer for IDENT. + + The values passed are not stored (except to track coalescence). + The only information that can be extracted from DWFL later is the + mapping of an address to a segment index that starts at or below + it. Reporting segments at all is optional. Its only benefit to + the caller is to offer this quick lookup via dwfl_addrsegment, + or use other segment-based calls. */ +extern int dwfl_report_segment (Dwfl *dwfl, int ndx, + const GElf_Phdr *phdr, GElf_Addr bias, + const void *ident); + +/* Report that a module called NAME spans addresses [START, END). + Returns the module handle, either existing or newly allocated, + or returns a null pointer for an allocation error. */ +extern Dwfl_Module *dwfl_report_module (Dwfl *dwfl, const char *name, + Dwarf_Addr start, Dwarf_Addr end); + +/* Report a module to address BASE with start and end addresses computed + from the ELF program headers in the given file - see the table below. + FD may be -1 to open FILE_NAME. On success, FD is consumed by the + library, and the `find_elf' callback will not be used for this module. + ADD_P_VADDR BASE + ET_EXEC ignored ignored + ET_DYN false absolute address where to place the file + true start address relative to ELF's phdr p_vaddr + ET_REL ignored absolute address where to place the file + ET_CORE ignored ignored + ET_DYN ELF phdr p_vaddr address can be non-zero if the shared library + has been prelinked by tool prelink(8). */ +extern Dwfl_Module *dwfl_report_elf (Dwfl *dwfl, const char *name, + const char *file_name, int fd, + GElf_Addr base, bool add_p_vaddr); + +/* Similar, but report the module for offline use. All ET_EXEC files + being reported must be reported before any relocatable objects. + If this is used, dwfl_report_module and dwfl_report_elf may not be + used in the same reporting session. */ +extern Dwfl_Module *dwfl_report_offline (Dwfl *dwfl, const char *name, + const char *file_name, int fd); + + +/* Finish reporting the current set of modules to the library. + If REMOVED is not null, it's called for each module that + existed before but was not included in the current report. + Returns a nonzero return value from the callback. + The callback may call dwfl_report_module; doing so with the + details of the module being removed prevents its removal. + DWFL cannot be used until this function has returned zero. */ +extern int dwfl_report_end (Dwfl *dwfl, + int (*removed) (Dwfl_Module *, void *, + const char *, Dwarf_Addr, + void *arg), + void *arg); + +/* Start reporting additional modules to the library. No calls but + dwfl_report_* can be made on DWFL until dwfl_report_end is called. + This is like dwfl_report_begin, but all the old modules are kept on. + More dwfl_report_* calls can follow to add more modules. + When dwfl_report_end is called, no old modules will be removed. */ +extern void dwfl_report_begin_add (Dwfl *dwfl); + + +/* Return the name of the module, and for each non-null argument store + interesting details: *USERDATA is a location for storing your own + pointer, **USERDATA is initially null; *START and *END give the address + range covered by the module; *DWBIAS is the address bias for debugging + information, and *SYMBIAS for symbol table entries (either is -1 if not + yet accessed); *MAINFILE is the name of the ELF file, and *DEBUGFILE the + name of the debuginfo file (might be equal to *MAINFILE; either is null + if not yet accessed). */ +extern const char *dwfl_module_info (Dwfl_Module *mod, void ***userdata, + Dwarf_Addr *start, Dwarf_Addr *end, + Dwarf_Addr *dwbias, Dwarf_Addr *symbias, + const char **mainfile, + const char **debugfile); + +/* Iterate through the modules, starting the walk with OFFSET == 0. + Calls *CALLBACK for each module as long as it returns DWARF_CB_OK. + When *CALLBACK returns another value, the walk stops and the + return value can be passed as OFFSET to resume it. Returns 0 when + there are no more modules, or -1 for errors. */ +extern ptrdiff_t dwfl_getmodules (Dwfl *dwfl, + int (*callback) (Dwfl_Module *, void **, + const char *, Dwarf_Addr, + void *arg), + void *arg, + ptrdiff_t offset); + +/* Find the module containing the given address. */ +extern Dwfl_Module *dwfl_addrmodule (Dwfl *dwfl, Dwarf_Addr address); + +/* Find the segment, if any, and module, if any, containing ADDRESS. + Returns a segment index returned by dwfl_report_segment, or -1 + if no segment matches the address. Regardless of the return value, + *MOD is always set to the module containing ADDRESS, or to null. */ +extern int dwfl_addrsegment (Dwfl *dwfl, Dwarf_Addr address, Dwfl_Module **mod); + + + +/* Report the known build ID bits associated with a module. + If VADDR is nonzero, it gives the absolute address where those + bits are found within the module. This can be called at any + time, but is usually used immediately after dwfl_report_module. + Once the module's main ELF file is opened, the ID note found + there takes precedence and cannot be changed. */ +extern int dwfl_module_report_build_id (Dwfl_Module *mod, + const unsigned char *bits, size_t len, + GElf_Addr vaddr) + __nonnull_attribute__ (2); + +/* Extract the build ID bits associated with a module. + Returns -1 for errors, 0 if no ID is known, or the number of ID bytes. + When an ID is found, *BITS points to it; *VADDR is the absolute address + at which the ID bits are found within the module, or 0 if unknown. + + This returns 0 when the module's main ELF file has not yet been loaded + and its build ID bits were not reported. To ensure the ID is always + returned when determinable, call dwfl_module_getelf first. */ +extern int dwfl_module_build_id (Dwfl_Module *mod, + const unsigned char **bits, GElf_Addr *vaddr) + __nonnull_attribute__ (2, 3); + + +/*** Standard callbacks ***/ + +/* These standard find_elf and find_debuginfo callbacks are + controlled by a string specifying directories to look in. + If `debuginfo_path' is set in the Dwfl_Callbacks structure + and the char * it points to is not null, that supplies the + string. Otherwise a default path is used. + + If the first character of the string is + or - that enables or + disables CRC32 checksum validation when it's necessary. The + remainder of the string is composed of elements separated by + colons. Each element can start with + or - to override the + global checksum behavior. This flag is never relevant when + working with build IDs, but it's always parsed in the path + string. The remainder of the element indicates a directory. + + Searches by build ID consult only the elements naming absolute + directory paths. They look under those directories for a link + named ".build-id/xx/yy" or ".build-id/xx/yy.debug", where "xxyy" + is the lower-case hexadecimal representation of the ID bytes. + + In searches for debuginfo by name, if the remainder of the + element is empty, the directory containing the main file is + tried; if it's an absolute path name, the absolute directory path + containing the main file is taken as a subdirectory of this path; + a relative path name is taken as a subdirectory of the directory + containing the main file. Hence for /bin/ls, the default string + ":.debug:/usr/lib/debug" says to look in /bin, then /bin/.debug, + then /usr/lib/debug/bin, for the file name in the .gnu_debuglink + section (or "ls.debug" if none was found). */ + +/* Standard find_elf callback function working solely on build ID. + This can be tried first by any find_elf callback, to use the + bits passed to dwfl_module_report_build_id, if any. */ +extern int dwfl_build_id_find_elf (Dwfl_Module *, void **, + const char *, Dwarf_Addr, + char **, Elf **); + +/* Standard find_debuginfo callback function working solely on build ID. + This can be tried first by any find_debuginfo callback, + to use the build ID bits from the main file when present. */ +extern int dwfl_build_id_find_debuginfo (Dwfl_Module *, void **, + const char *, Dwarf_Addr, + const char *, const char *, + GElf_Word, char **); + +/* Standard find_debuginfo callback function. + If a build ID is available, this tries first to use that. + If there is no build ID or no valid debuginfo found by ID, + it searches the debuginfo path by name, as described above. + Any file found in the path is validated by build ID if possible, + or else by CRC32 checksum if enabled, and skipped if it does not match. */ +extern int dwfl_standard_find_debuginfo (Dwfl_Module *, void **, + const char *, Dwarf_Addr, + const char *, const char *, + GElf_Word, char **); + + +/* This callback must be used when using dwfl_offline_* to report modules, + if ET_REL is to be supported. */ +extern int dwfl_offline_section_address (Dwfl_Module *, void **, + const char *, Dwarf_Addr, + const char *, GElf_Word, + const GElf_Shdr *, + Dwarf_Addr *addr); + + +/* Callbacks for working with kernel modules in the running Linux kernel. */ +extern int dwfl_linux_kernel_find_elf (Dwfl_Module *, void **, + const char *, Dwarf_Addr, + char **, Elf **); +extern int dwfl_linux_kernel_module_section_address (Dwfl_Module *, void **, + const char *, Dwarf_Addr, + const char *, GElf_Word, + const GElf_Shdr *, + Dwarf_Addr *addr); + +/* Call dwfl_report_elf for the running Linux kernel. + Returns zero on success, -1 if dwfl_report_module failed, + or an errno code if opening the kernel binary failed. */ +extern int dwfl_linux_kernel_report_kernel (Dwfl *dwfl); + +/* Call dwfl_report_module for each kernel module in the running Linux kernel. + Returns zero on success, -1 if dwfl_report_module failed, + or an errno code if reading the list of modules failed. */ +extern int dwfl_linux_kernel_report_modules (Dwfl *dwfl); + +/* Report a kernel and its modules found on disk, for offline use. + If RELEASE starts with '/', it names a directory to look in; + if not, it names a directory to find under /lib/modules/; + if null, /lib/modules/`uname -r` is used. + Returns zero on success, -1 if dwfl_report_module failed, + or an errno code if finding the files on disk failed. + + If PREDICATE is not null, it is called with each module to be reported; + its arguments are the module name, and the ELF file name or null if unknown, + and its return value should be zero to skip the module, one to report it, + or -1 to cause the call to fail and return errno. */ +extern int dwfl_linux_kernel_report_offline (Dwfl *dwfl, const char *release, + int (*predicate) (const char *, + const char *)); + +/* Examine an ET_CORE file and report modules based on its contents. + This can follow a dwfl_report_offline call to bootstrap the + DT_DEBUG method of following the dynamic linker link_map chain, in + case the core file does not contain enough of the executable's text + segment to locate its PT_DYNAMIC in the dump. In such case you need to + supply non-NULL EXECUTABLE, otherwise dynamic libraries will not be loaded + into the DWFL map. This might call dwfl_report_elf on file names found in + the dump if reading some link_map files is the only way to ascertain those + modules' addresses. Returns the number of modules reported, or -1 for + errors. */ +extern int dwfl_core_file_report (Dwfl *dwfl, Elf *elf, const char *executable); + +/* Call dwfl_report_module for each file mapped into the address space of PID. + Returns zero on success, -1 if dwfl_report_module failed, + or an errno code if opening the proc files failed. */ +extern int dwfl_linux_proc_report (Dwfl *dwfl, pid_t pid); + +/* Similar, but reads an input stream in the format of Linux /proc/PID/maps + files giving module layout, not the file for a live process. */ +extern int dwfl_linux_proc_maps_report (Dwfl *dwfl, FILE *); + +/* Trivial find_elf callback for use with dwfl_linux_proc_report. + This uses the module name as a file name directly and tries to open it + if it begin with a slash, or handles the magic string "[vdso]". */ +extern int dwfl_linux_proc_find_elf (Dwfl_Module *mod, void **userdata, + const char *module_name, Dwarf_Addr base, + char **file_name, Elf **); + +/* Standard argument parsing for using a standard callback set. */ +struct argp; +extern const struct argp *dwfl_standard_argp (void) __attribute__ ((const)); + + +/*** Relocation of addresses from Dwfl ***/ + +/* Return the number of relocatable bases associated with the module, + which is zero for ET_EXEC and one for ET_DYN. Returns -1 for errors. */ +extern int dwfl_module_relocations (Dwfl_Module *mod); + +/* Return the relocation base index associated with the *ADDRESS location, + and adjust *ADDRESS to be an offset relative to that base. + Returns -1 for errors. */ +extern int dwfl_module_relocate_address (Dwfl_Module *mod, + Dwarf_Addr *address); + +/* Return the ELF section name for the given relocation base index; + if SHNDXP is not null, set *SHNDXP to the ELF section index. + For ET_DYN, returns "" and sets *SHNDXP to SHN_ABS; the relocation + base is the runtime start address reported for the module. + Returns null for errors. */ +extern const char *dwfl_module_relocation_info (Dwfl_Module *mod, + unsigned int idx, + GElf_Word *shndxp); + +/* Validate that ADDRESS and ADDRESS+OFFSET lie in a known module + and both within the same contiguous region for relocation purposes. + Returns zero for success and -1 for errors. */ +extern int dwfl_validate_address (Dwfl *dwfl, + Dwarf_Addr address, Dwarf_Sword offset); + + +/*** ELF access functions ***/ + +/* Fetch the module main ELF file (where the allocated sections + are found) for use with libelf. If successful, fills in *BIAS + with the difference between addresses within the loaded module + and those in symbol tables or Dwarf information referring to it. */ +extern Elf *dwfl_module_getelf (Dwfl_Module *, GElf_Addr *bias) + __nonnull_attribute__ (1, 2); + +/* Return the number of symbols in the module's symbol table, + or -1 for errors. */ +extern int dwfl_module_getsymtab (Dwfl_Module *mod); + +/* Return the index of the first global symbol in the module's symbol + table, or -1 for errors. In each symbol table, all symbols with + STB_LOCAL binding precede the weak and global symbols. This + function returns the symbol table index one greater than the last + local symbol. */ +extern int dwfl_module_getsymtab_first_global (Dwfl_Module *mod); + +/* Fetch one entry from the module's symbol table. On errors, returns + NULL. If successful, fills in *SYM and returns the string for st_name. + This works like gelf_getsym except that st_value is always adjusted to + an absolute value based on the module's location, when the symbol is in + an SHF_ALLOC section. If SHNDXP is non-null, it's set with the section + index (whether from st_shndx or extended index table); in case of a + symbol in a non-allocated section, *SHNDXP is instead set to -1. + Note that since symbols can come from either the main, debug or auxiliary + ELF symbol file (either dynsym or symtab) the section index can only + be reliably used to compare against special section constants like + SHN_UNDEF or SHN_ABS. It is recommended to use dwfl_module_getsym_info + which doesn't have these deficiencies. */ +extern const char *dwfl_module_getsym (Dwfl_Module *mod, int ndx, + GElf_Sym *sym, GElf_Word *shndxp) + __nonnull_attribute__ (3); + +/* Fetch one entry from the module's symbol table and the associated + address value. On errors, returns NULL. If successful, fills in + *SYM, *ADDR and returns the string for st_name. This works like + gelf_getsym. *ADDR is set to the st_value adjusted to an absolute + value based on the module's location, when the symbol is in an + SHF_ALLOC section. For non-ET_REL files, if the arch uses function + descriptors, and the st_value points to one, *ADDR will be resolved + to the actual function entry address. The SYM->ST_VALUE itself + isn't adjusted in any way. Fills in ELFP, if not NULL, with the + ELF file the symbol originally came from. Note that symbols can + come from either the main, debug or auxiliary ELF symbol file + (either dynsym or symtab). If SHNDXP is non-null, it's set with + the section index (whether from st_shndx or extended index table); + in case of a symbol in a non-allocated section, *SHNDXP is instead + set to -1. Fills in BIAS, if not NULL, with the difference between + addresses within the loaded module and those in symbol table of the + ELF file. Note that the address associated with the symbol might + be in a different section than the returned symbol. The section in + the main elf file in which returned ADDR falls can be found with + dwfl_module_address_section. */ +extern const char *dwfl_module_getsym_info (Dwfl_Module *mod, int ndx, + GElf_Sym *sym, GElf_Addr *addr, + GElf_Word *shndxp, + Elf **elfp, Dwarf_Addr *bias) + __nonnull_attribute__ (3, 4); + +/* Find the symbol that ADDRESS lies inside, and return its name. */ +extern const char *dwfl_module_addrname (Dwfl_Module *mod, GElf_Addr address); + +/* Find the symbol associated with ADDRESS. Return its name or NULL + when nothing was found. If the architecture uses function + descriptors, and symbol st_value points to one, ADDRESS wil be + matched against either the adjusted st_value or the associated + function entry value as described in dwfl_module_getsym_info. If + OFFSET is not NULL it will be filled in with the difference from + the start of the symbol (or function entry). If SYM is not NULL it + is filled in with the symbol associated with the matched ADDRESS. + The SYM->ST_VALUE itself isn't adjusted in any way. Fills in ELFP, + if not NULL, with the ELF file the symbol originally came from. + Note that symbols can come from either the main, debug or auxiliary + ELF symbol file (either dynsym or symtab). If SHNDXP is non-null, + it's set with the section index (whether from st_shndx or extended + index table). Fills in BIAS, if not NULL, with the difference + between addresses within the loaded module and those in symbol + table of the ELF file. Note that the address matched against the + symbol might be in a different section than the returned symbol. + The section in the main elf file in ADDRESS falls can be found with + dwfl_module_address_section. */ +extern const char *dwfl_module_addrinfo (Dwfl_Module *mod, GElf_Addr address, + GElf_Off *offset, GElf_Sym *sym, + GElf_Word *shndxp, Elf **elfp, + Dwarf_Addr *bias) + __nonnull_attribute__ (3); + +/* Find the symbol that ADDRESS lies inside, and return detailed + information as for dwfl_module_getsym (above). Note that like + dwfl_module_getsym this function also adjusts SYM->ST_VALUE to an + absolute value based on the module's location. ADDRESS is only + matched against this adjusted SYM->ST_VALUE. This means that + depending on architecture this might only match symbols that + represent function descriptor addresses (and not function entry + addresses). For these reasons it is recommended to use + dwfl_module_addrinfo instead. */ +extern const char *dwfl_module_addrsym (Dwfl_Module *mod, GElf_Addr address, + GElf_Sym *sym, GElf_Word *shndxp) + __nonnull_attribute__ (3); + +/* Find the ELF section that *ADDRESS lies inside and return it. + On success, adjusts *ADDRESS to be relative to the section, + and sets *BIAS to the difference between addresses used in + the returned section's headers and run-time addresses. */ +extern Elf_Scn *dwfl_module_address_section (Dwfl_Module *mod, + Dwarf_Addr *address, + Dwarf_Addr *bias) + __nonnull_attribute__ (2, 3); + + +/*** Dwarf access functions ***/ + +/* Fetch the module's debug information for use with libdw. + If successful, fills in *BIAS with the difference between + addresses within the loaded module and those to use with libdw. */ +extern Dwarf *dwfl_module_getdwarf (Dwfl_Module *, Dwarf_Addr *bias) + __nonnull_attribute__ (2); + +/* Get the libdw handle for each module. */ +extern ptrdiff_t dwfl_getdwarf (Dwfl *, + int (*callback) (Dwfl_Module *, void **, + const char *, Dwarf_Addr, + Dwarf *, Dwarf_Addr, void *), + void *arg, ptrdiff_t offset); + +/* Look up the module containing ADDR and return its debugging information, + loading it if necessary. */ +extern Dwarf *dwfl_addrdwarf (Dwfl *dwfl, Dwarf_Addr addr, Dwarf_Addr *bias) + __nonnull_attribute__ (3); + + +/* Find the CU containing ADDR and return its DIE. */ +extern Dwarf_Die *dwfl_addrdie (Dwfl *dwfl, Dwarf_Addr addr, Dwarf_Addr *bias) + __nonnull_attribute__ (3); +extern Dwarf_Die *dwfl_module_addrdie (Dwfl_Module *mod, + Dwarf_Addr addr, Dwarf_Addr *bias) + __nonnull_attribute__ (3); + +/* Iterate through the CUs, start with null for LASTCU. */ +extern Dwarf_Die *dwfl_nextcu (Dwfl *dwfl, Dwarf_Die *lastcu, Dwarf_Addr *bias) + __nonnull_attribute__ (3); +extern Dwarf_Die *dwfl_module_nextcu (Dwfl_Module *mod, + Dwarf_Die *lastcu, Dwarf_Addr *bias) + __nonnull_attribute__ (3); + +/* Return the module containing the CU DIE. */ +extern Dwfl_Module *dwfl_cumodule (Dwarf_Die *cudie); + + +/* Cache the source line information fo the CU and return the + number of Dwfl_Line entries it has. */ +extern int dwfl_getsrclines (Dwarf_Die *cudie, size_t *nlines); + +/* Access one line number entry within the CU. */ +extern Dwfl_Line *dwfl_onesrcline (Dwarf_Die *cudie, size_t idx); + +/* Get source for address. */ +extern Dwfl_Line *dwfl_module_getsrc (Dwfl_Module *mod, Dwarf_Addr addr); +extern Dwfl_Line *dwfl_getsrc (Dwfl *dwfl, Dwarf_Addr addr); + +/* Get address for source. */ +extern int dwfl_module_getsrc_file (Dwfl_Module *mod, + const char *fname, int lineno, int column, + Dwfl_Line ***srcsp, size_t *nsrcs); + +/* Return the module containing this line record. */ +extern Dwfl_Module *dwfl_linemodule (Dwfl_Line *line); + +/* Return the CU containing this line record. */ +extern Dwarf_Die *dwfl_linecu (Dwfl_Line *line); + +/* Return the source file name and fill in other information. + Arguments may be null for unneeded fields. */ +extern const char *dwfl_lineinfo (Dwfl_Line *line, Dwarf_Addr *addr, + int *linep, int *colp, + Dwarf_Word *mtime, Dwarf_Word *length); + + /* Return the equivalent Dwarf_Line and the bias to apply to its address. */ +extern Dwarf_Line *dwfl_dwarf_line (Dwfl_Line *line, Dwarf_Addr *bias); + +/* Return the compilation directory (AT_comp_dir) from this line's CU. */ +extern const char *dwfl_line_comp_dir (Dwfl_Line *line); + + +/*** Machine backend access functions ***/ + +/* Return location expression to find return value given a + DW_TAG_subprogram, DW_TAG_subroutine_type, or similar DIE describing + function itself (whose DW_AT_type attribute describes its return type). + The given DIE must come from the given module. Returns -1 for errors. + Returns zero if the function has no return value (e.g. "void" in C). + Otherwise, *LOCOPS gets a location expression to find the return value, + and returns the number of operations in the expression. The pointer is + permanently allocated at least as long as the module is live. */ +extern int dwfl_module_return_value_location (Dwfl_Module *mod, + Dwarf_Die *functypedie, + const Dwarf_Op **locops); + +/* Enumerate the DWARF register numbers and their names. + For each register, CALLBACK gets its DWARF number, a string describing + the register set (such as "integer" or "FPU"), a prefix used in + assembler syntax (such as "%" or "$", may be ""), and the name for the + register (contains identifier characters only, possibly all digits). + The REGNAME string is valid only during the callback. */ +extern int dwfl_module_register_names (Dwfl_Module *mod, + int (*callback) (void *arg, + int regno, + const char *setname, + const char *prefix, + const char *regname, + int bits, int type), + void *arg); + + +/* Find the CFI for this module. Returns NULL if there is no CFI. + On success, fills in *BIAS with the difference between addresses + within the loaded module and those in the CFI referring to it. + The pointer returned can be used until the module is cleaned up. + Calling these more than once returns the same pointers. + + dwfl_module_dwarf_cfi gets the '.debug_frame' information found with the + rest of the DWARF information. dwfl_module_eh_cfi gets the '.eh_frame' + information found linked into the text. A module might have either or + both. */ +extern Dwarf_CFI *dwfl_module_dwarf_cfi (Dwfl_Module *mod, Dwarf_Addr *bias); +extern Dwarf_CFI *dwfl_module_eh_cfi (Dwfl_Module *mod, Dwarf_Addr *bias); + + +typedef struct +{ + /* Called to iterate through threads. Returns next TID (thread ID) on + success, a negative number on failure and zero if there are no more + threads. dwfl_errno () should be set if negative number has been + returned. *THREAD_ARGP is NULL on first call, and may be optionally + set by the implementation. The value set by the implementation will + be passed in on the next call to NEXT_THREAD. THREAD_ARGP is never + NULL. *THREAD_ARGP will be passed to set_initial_registers or + thread_detach callbacks together with Dwfl_Thread *thread. This + method must not be NULL. */ + pid_t (*next_thread) (Dwfl *dwfl, void *dwfl_arg, void **thread_argp) + __nonnull_attribute__ (1); + + /* Called to get a specific thread. Returns true if there is a + thread with the given thread id number, returns false if no such + thread exists and will set dwfl_errno in that case. THREAD_ARGP + is never NULL. *THREAD_ARGP will be passed to + set_initial_registers or thread_detach callbacks together with + Dwfl_Thread *thread. This method may be NULL and will then be + emulated using the next_thread callback. */ + bool (*get_thread) (Dwfl *dwfl, pid_t tid, void *dwfl_arg, + void **thread_argp) + __nonnull_attribute__ (1); + + /* Called during unwinding to access memory (stack) state. Returns true for + successfully read *RESULT or false and sets dwfl_errno () on failure. + This method may be NULL - in such case dwfl_thread_getframes will return + only the initial frame. */ + bool (*memory_read) (Dwfl *dwfl, Dwarf_Addr addr, Dwarf_Word *result, + void *dwfl_arg) + __nonnull_attribute__ (1, 3); + + /* Called on initial unwind to get the initial register state of the first + frame. Should call dwfl_thread_state_registers, possibly multiple times + for different ranges and possibly also dwfl_thread_state_register_pc, to + fill in initial (DWARF) register values. After this call, till at least + thread_detach is called, the thread is assumed to be frozen, so that it is + safe to unwind. Returns true on success or false and sets dwfl_errno () + on failure. In the case of a failure thread_detach will not be called. + This method must not be NULL. */ + bool (*set_initial_registers) (Dwfl_Thread *thread, void *thread_arg) + __nonnull_attribute__ (1); + + /* Called by dwfl_end. All thread_detach method calls have been already + done. This method may be NULL. */ + void (*detach) (Dwfl *dwfl, void *dwfl_arg) + __nonnull_attribute__ (1); + + /* Called when unwinding is done. No callback will be called after + this method has been called. Iff set_initial_registers was called for + a TID and it returned success thread_detach will be called before the + detach method above. This method may be NULL. */ + void (*thread_detach) (Dwfl_Thread *thread, void *thread_arg) + __nonnull_attribute__ (1); +} Dwfl_Thread_Callbacks; + +/* PID is the process id associated with the DWFL state. Architecture of DWFL + modules is specified by ELF, ELF must remain valid during DWFL lifetime. + Use NULL ELF to detect architecture from DWFL, the function will then detect + it from arbitrary Dwfl_Module of DWFL. DWFL_ARG is the callback backend + state. DWFL_ARG will be provided to the callbacks. *THREAD_CALLBACKS + function pointers must remain valid during lifetime of DWFL. Function + returns true on success, false otherwise. */ +bool dwfl_attach_state (Dwfl *dwfl, Elf *elf, pid_t pid, + const Dwfl_Thread_Callbacks *thread_callbacks, + void *dwfl_arg) + __nonnull_attribute__ (1, 4); + +/* Calls dwfl_attach_state with Dwfl_Thread_Callbacks setup for extracting + thread state from the ELF core file. Returns the pid number extracted + from the core file, or -1 for errors. */ +extern int dwfl_core_file_attach (Dwfl *dwfl, Elf *elf); + +/* Calls dwfl_attach_state with Dwfl_Thread_Callbacks setup for extracting + thread state from the proc file system. Uses ptrace to attach and stop + the thread under inspection and detaches when thread_detach is called + and unwinding for the thread is done, unless ASSUME_PTRACE_STOPPED is + true. If ASSUME_PTRACE_STOPPED is true the caller should make sure that + the thread is ptrace attached and stopped before unwinding by calling + either dwfl_thread_getframes or dwfl_getthread_frames. Returns zero on + success, -1 if dwfl_attach_state failed, or an errno code if opening the + proc files failed. */ +extern int dwfl_linux_proc_attach (Dwfl *dwfl, pid_t pid, + bool assume_ptrace_stopped); + +/* Return PID for the process associated with DWFL. Function returns -1 if + dwfl_attach_state was not called for DWFL. */ +pid_t dwfl_pid (Dwfl *dwfl) + __nonnull_attribute__ (1); + +/* Return DWFL from which THREAD was created using dwfl_getthreads. */ +Dwfl *dwfl_thread_dwfl (Dwfl_Thread *thread) + __nonnull_attribute__ (1); + +/* Return positive TID (thread ID) for THREAD. This function never fails. */ +pid_t dwfl_thread_tid (Dwfl_Thread *thread) + __nonnull_attribute__ (1); + +/* Return thread for frame STATE. This function never fails. */ +Dwfl_Thread *dwfl_frame_thread (Dwfl_Frame *state) + __nonnull_attribute__ (1); + +/* Called by Dwfl_Thread_Callbacks.set_initial_registers implementation. + For every known continuous block of registers <FIRSTREG..FIRSTREG+NREGS) + (inclusive..exclusive) set their content to REGS (array of NREGS items). + Function returns false if any of the registers has invalid number. */ +bool dwfl_thread_state_registers (Dwfl_Thread *thread, int firstreg, + unsigned nregs, const Dwarf_Word *regs) + __nonnull_attribute__ (1, 4); + +/* Called by Dwfl_Thread_Callbacks.set_initial_registers implementation. + If PC is not contained among DWARF registers passed by + dwfl_thread_state_registers on the target architecture pass the PC value + here. */ +void dwfl_thread_state_register_pc (Dwfl_Thread *thread, Dwarf_Word pc) + __nonnull_attribute__ (1); + +/* Iterate through the threads for a process. Returns zero if all threads have + been processed by the callback, returns -1 on error, or the value of the + callback when not DWARF_CB_OK. -1 returned on error will set dwfl_errno (). + Keeps calling the callback with the next thread while the callback returns + DWARF_CB_OK, till there are no more threads. */ +int dwfl_getthreads (Dwfl *dwfl, + int (*callback) (Dwfl_Thread *thread, void *arg), + void *arg) + __nonnull_attribute__ (1, 2); + +/* Iterate through the frames for a thread. Returns zero if all frames + have been processed by the callback, returns -1 on error, or the value of + the callback when not DWARF_CB_OK. -1 returned on error will + set dwfl_errno (). Some systems return error instead of zero on end of the + backtrace, for cross-platform compatibility callers should consider error as + a zero. Keeps calling the callback with the next frame while the callback + returns DWARF_CB_OK, till there are no more frames. On start will call the + set_initial_registers callback and on return will call the detach_thread + callback of the Dwfl_Thread. */ +int dwfl_thread_getframes (Dwfl_Thread *thread, + int (*callback) (Dwfl_Frame *state, void *arg), + void *arg) + __nonnull_attribute__ (1, 2); + +/* Like dwfl_thread_getframes, but specifying the thread by its unique + identifier number. Returns zero if all frames have been processed + by the callback, returns -1 on error (and when no thread with + the given thread id number exists), or the value of the callback + when not DWARF_CB_OK. -1 returned on error will set dwfl_errno (). */ +int dwfl_getthread_frames (Dwfl *dwfl, pid_t tid, + int (*callback) (Dwfl_Frame *thread, void *arg), + void *arg) + __nonnull_attribute__ (1, 3); + +/* Return *PC (program counter) for thread-specific frame STATE. + Set *ISACTIVATION according to DWARF frame "activation" definition. + Typically you need to substract 1 from *PC if *ACTIVATION is false to safely + find function of the caller. ACTIVATION may be NULL. PC must not be NULL. + Function returns false if it failed to find *PC. */ +bool dwfl_frame_pc (Dwfl_Frame *state, Dwarf_Addr *pc, bool *isactivation) + __nonnull_attribute__ (1, 2); + +#ifdef __cplusplus +} +#endif + +#endif /* libdwfl.h */ diff --git a/3rdparty/elfutils/libdwfl/libdwfl.pro b/3rdparty/elfutils/libdwfl/libdwfl.pro new file mode 100644 index 0000000..d3af0eb --- /dev/null +++ b/3rdparty/elfutils/libdwfl/libdwfl.pro @@ -0,0 +1,76 @@ +TEMPLATE = lib +CONFIG += staticlib +TARGET = ../dwfl + +include(../elfutils.pri) +include(dwflheaders.pri) +include(../libdw/dwheaders.pri) +include(../libebl/eblheaders.pri) +include(../libdwelf/dwelfheaders.pri) + +SOURCES += \ + $$PWD/argp-std.c \ + $$PWD/core-file.c \ + $$PWD/cu.c \ + $$PWD/derelocate.c \ + $$PWD/dwfl_addrdie.c \ + $$PWD/dwfl_addrdwarf.c \ + $$PWD/dwfl_addrmodule.c \ + $$PWD/dwfl_begin.c \ + $$PWD/dwfl_build_id_find_debuginfo.c \ + $$PWD/dwfl_build_id_find_elf.c \ + $$PWD/dwfl_cumodule.c \ + $$PWD/dwfl_dwarf_line.c \ + $$PWD/dwfl_end.c \ + $$PWD/dwfl_error.c \ + $$PWD/dwfl_frame_pc.c \ + $$PWD/dwfl_frame_regs.c \ + $$PWD/dwfl_frame.c \ + $$PWD/dwfl_getdwarf.c \ + $$PWD/dwfl_getmodules.c \ + $$PWD/dwfl_getsrc.c \ + $$PWD/dwfl_getsrclines.c \ + $$PWD/dwfl_line_comp_dir.c \ + $$PWD/dwfl_linecu.c \ + $$PWD/dwfl_lineinfo.c \ + $$PWD/dwfl_linemodule.c \ + $$PWD/dwfl_module_addrdie.c \ + $$PWD/dwfl_module_addrname.c \ + $$PWD/dwfl_module_addrsym.c \ + $$PWD/dwfl_module_build_id.c \ + $$PWD/dwfl_module_dwarf_cfi.c \ + $$PWD/dwfl_module_eh_cfi.c \ + $$PWD/dwfl_module_getdwarf.c \ + $$PWD/dwfl_module_getelf.c \ + $$PWD/dwfl_module_getsrc_file.c \ + $$PWD/dwfl_module_getsrc.c \ + $$PWD/dwfl_module_getsym.c \ + $$PWD/dwfl_module_info.c \ + $$PWD/dwfl_module_nextcu.c \ + $$PWD/dwfl_module_register_names.c \ + $$PWD/dwfl_module_report_build_id.c \ + $$PWD/dwfl_module_return_value_location.c \ + $$PWD/dwfl_module.c \ + $$PWD/dwfl_nextcu.c \ + $$PWD/dwfl_onesrcline.c \ + $$PWD/dwfl_report_elf.c \ + $$PWD/dwfl_segment_report_module.c \ + $$PWD/dwfl_validate_address.c \ + $$PWD/dwfl_version.c \ + $$PWD/elf-from-memory.c \ + $$PWD/find-debuginfo.c \ + $$PWD/frame_unwind.c \ + $$PWD/gzip.c \ + $$PWD/image-header.c \ + $$PWD/libdwfl_crc32_file.c \ + $$PWD/libdwfl_crc32.c \ + $$PWD/lines.c \ + $$PWD/link_map.c \ + $$PWD/linux-core-attach.c \ + $$PWD/linux-kernel-modules.c \ + $$PWD/linux-pid-attach.c \ + $$PWD/linux-proc-maps.c \ + $$PWD/offline.c \ + $$PWD/open.c \ + $$PWD/relocate.c \ + $$PWD/segment.c diff --git a/3rdparty/elfutils/libdwfl/libdwflP.h b/3rdparty/elfutils/libdwfl/libdwflP.h new file mode 100644 index 0000000..12ee116 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/libdwflP.h @@ -0,0 +1,760 @@ +/* Internal definitions for libdwfl. + Copyright (C) 2005-2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifndef _LIBDWFLP_H +#define _LIBDWFLP_H 1 + +#ifndef PACKAGE_NAME +# include <config.h> +#endif +#include <libdwfl.h> +#include <libebl.h> +#include <assert.h> +#include <dirent.h> +#include <errno.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> + +#include "../libdw/libdwP.h" /* We need its INTDECLs. */ +#include "../libdwelf/libdwelfP.h" + +typedef struct Dwfl_Process Dwfl_Process; + +/* gettext helper macros. */ +#define _(Str) dgettext ("elfutils", Str) + +#define DWFL_ERRORS \ + DWFL_ERROR (NOERROR, N_("no error")) \ + DWFL_ERROR (UNKNOWN_ERROR, N_("unknown error")) \ + DWFL_ERROR (NOMEM, N_("out of memory")) \ + DWFL_ERROR (ERRNO, N_("See errno")) \ + DWFL_ERROR (LIBELF, N_("See elf_errno")) \ + DWFL_ERROR (LIBDW, N_("See dwarf_errno")) \ + DWFL_ERROR (LIBEBL, N_("See ebl_errno (XXX missing)")) \ + DWFL_ERROR (ZLIB, N_("gzip decompression failed")) \ + DWFL_ERROR (BZLIB, N_("bzip2 decompression failed")) \ + DWFL_ERROR (LZMA, N_("LZMA decompression failed")) \ + DWFL_ERROR (UNKNOWN_MACHINE, N_("no support library found for machine")) \ + DWFL_ERROR (NOREL, N_("Callbacks missing for ET_REL file")) \ + DWFL_ERROR (BADRELTYPE, N_("Unsupported relocation type")) \ + DWFL_ERROR (BADRELOFF, N_("r_offset is bogus")) \ + DWFL_ERROR (BADSTROFF, N_("offset out of range")) \ + DWFL_ERROR (RELUNDEF, N_("relocation refers to undefined symbol")) \ + DWFL_ERROR (CB, N_("Callback returned failure")) \ + DWFL_ERROR (NO_DWARF, N_("No DWARF information found")) \ + DWFL_ERROR (NO_SYMTAB, N_("No symbol table found")) \ + DWFL_ERROR (NO_PHDR, N_("No ELF program headers")) \ + DWFL_ERROR (OVERLAP, N_("address range overlaps an existing module")) \ + DWFL_ERROR (ADDR_OUTOFRANGE, N_("address out of range")) \ + DWFL_ERROR (NO_MATCH, N_("no matching address range")) \ + DWFL_ERROR (TRUNCATED, N_("image truncated")) \ + DWFL_ERROR (ALREADY_ELF, N_("ELF file opened")) \ + DWFL_ERROR (BADELF, N_("not a valid ELF file")) \ + DWFL_ERROR (WEIRD_TYPE, N_("cannot handle DWARF type description")) \ + DWFL_ERROR (WRONG_ID_ELF, N_("ELF file does not match build ID")) \ + DWFL_ERROR (BAD_PRELINK, N_("corrupt .gnu.prelink_undo section data")) \ + DWFL_ERROR (LIBEBL_BAD, N_("Internal error due to ebl")) \ + DWFL_ERROR (CORE_MISSING, N_("Missing data in core file")) \ + DWFL_ERROR (INVALID_REGISTER, N_("Invalid register")) \ + DWFL_ERROR (PROCESS_MEMORY_READ, N_("Error reading process memory")) \ + DWFL_ERROR (PROCESS_NO_ARCH, N_("Couldn't find architecture of any ELF")) \ + DWFL_ERROR (PARSE_PROC, N_("Error parsing /proc filesystem")) \ + DWFL_ERROR (INVALID_DWARF, N_("Invalid DWARF")) \ + DWFL_ERROR (UNSUPPORTED_DWARF, N_("Unsupported DWARF")) \ + DWFL_ERROR (NEXT_THREAD_FAIL, N_("Unable to find more threads")) \ + DWFL_ERROR (ATTACH_STATE_CONFLICT, N_("Dwfl already has attached state")) \ + DWFL_ERROR (NO_ATTACH_STATE, N_("Dwfl has no attached state")) \ + DWFL_ERROR (NO_UNWIND, N_("Unwinding not supported for this architecture")) \ + DWFL_ERROR (INVALID_ARGUMENT, N_("Invalid argument")) \ + DWFL_ERROR (NO_CORE_FILE, N_("Not an ET_CORE ELF file")) + +#define DWFL_ERROR(name, text) DWFL_E_##name, +typedef enum { DWFL_ERRORS DWFL_E_NUM } Dwfl_Error; +#undef DWFL_ERROR + +#define OTHER_ERROR(name) ((unsigned int) DWFL_E_##name << 16) +#define DWFL_E(name, errno) (OTHER_ERROR (name) | (errno)) + +extern int __libdwfl_canon_error (Dwfl_Error) internal_function; +extern void __libdwfl_seterrno (Dwfl_Error) internal_function; + +struct Dwfl +{ + const Dwfl_Callbacks *callbacks; + + Dwfl_Module *modulelist; /* List in order used by full traversals. */ + + Dwfl_Process *process; + Dwfl_Error attacherr; /* Previous error attaching process. */ + + GElf_Addr offline_next_address; + + GElf_Addr segment_align; /* Smallest granularity of segments. */ + + /* Binary search table in three parallel malloc'd arrays. */ + size_t lookup_elts; /* Elements in use. */ + size_t lookup_alloc; /* Elements allococated. */ + GElf_Addr *lookup_addr; /* Start address of segment. */ + Dwfl_Module **lookup_module; /* Module associated with segment, or null. */ + int *lookup_segndx; /* User segment index, or -1. */ + + /* Cache from last dwfl_report_segment call. */ + const void *lookup_tail_ident; + GElf_Off lookup_tail_vaddr; + GElf_Off lookup_tail_offset; + int lookup_tail_ndx; + + char *executable_for_core; /* --executable if --core was specified. */ +}; + +#define OFFLINE_REDZONE 0x10000 + +struct dwfl_file +{ + char *name; + int fd; + bool valid; /* The build ID note has been matched. */ + bool relocated; /* Partial relocation of all sections done. */ + + Elf *elf; + + /* This is the lowest p_vaddr in this ELF file, aligned to p_align. + For a file without phdrs, this is zero. */ + GElf_Addr vaddr; + + /* This is an address chosen for synchronization between the main file + and the debug file. See dwfl_module_getdwarf.c for how it's chosen. */ + GElf_Addr address_sync; +}; + +struct Dwfl_Module +{ + Dwfl *dwfl; + struct Dwfl_Module *next; /* Link on Dwfl.modulelist. */ + + void *userdata; + + char *name; /* Iterator name for this module. */ + GElf_Addr low_addr, high_addr; + + struct dwfl_file main, debug, aux_sym; + GElf_Addr main_bias; + Ebl *ebl; + GElf_Half e_type; /* GElf_Ehdr.e_type cache. */ + Dwfl_Error elferr; /* Previous failure to open main file. */ + + struct dwfl_relocation *reloc_info; /* Relocatable sections. */ + + struct dwfl_file *symfile; /* Either main or debug. */ + Elf_Data *symdata; /* Data in the ELF symbol table section. */ + Elf_Data *aux_symdata; /* Data in the auxiliary ELF symbol table. */ + size_t syments; /* sh_size / sh_entsize of that section. */ + size_t aux_syments; /* sh_size / sh_entsize of aux_sym section. */ + int first_global; /* Index of first global symbol of table. */ + int aux_first_global; /* Index of first global of aux_sym table. */ + Elf_Data *symstrdata; /* Data for its string table. */ + Elf_Data *aux_symstrdata; /* Data for aux_sym string table. */ + Elf_Data *symxndxdata; /* Data in the extended section index table. */ + Elf_Data *aux_symxndxdata; /* Data in the extended auxiliary table. */ + + Dwarf *dw; /* libdw handle for its debugging info. */ + Dwarf *alt; /* Dwarf used for dwarf_setalt, or NULL. */ + int alt_fd; /* descriptor, only valid when alt != NULL. */ + Elf *alt_elf; /* Elf for alt Dwarf. */ + + Dwfl_Error symerr; /* Previous failure to load symbols. */ + Dwfl_Error dwerr; /* Previous failure to load DWARF. */ + + /* Known CU's in this module. */ + struct dwfl_cu *first_cu, **cu; + + void *lazy_cu_root; /* Table indexed by Dwarf_Off of CU. */ + + struct dwfl_arange *aranges; /* Mapping of addresses in module to CUs. */ + + void *build_id_bits; /* malloc'd copy of build ID bits. */ + GElf_Addr build_id_vaddr; /* Address where they reside, 0 if unknown. */ + int build_id_len; /* -1 for prior failure, 0 if unset. */ + + unsigned int ncu; + unsigned int lazycu; /* Possible users, deleted when none left. */ + unsigned int naranges; + + Dwarf_CFI *dwarf_cfi; /* Cached DWARF CFI for this module. */ + Dwarf_CFI *eh_cfi; /* Cached EH CFI for this module. */ + + int segment; /* Index of first segment table entry. */ + bool gc; /* Mark/sweep flag. */ + bool is_executable; /* Use Dwfl::executable_for_core? */ +}; + +/* This holds information common for all the threads/tasks/TIDs of one process + for backtraces. */ + +struct Dwfl_Process +{ + struct Dwfl *dwfl; + pid_t pid; + const Dwfl_Thread_Callbacks *callbacks; + void *callbacks_arg; + struct ebl *ebl; + bool ebl_close:1; +}; + +/* See its typedef in libdwfl.h. */ + +struct Dwfl_Thread +{ + Dwfl_Process *process; + pid_t tid; + /* The current frame being unwound. Initially it is the bottom frame. + Later the processed frames get freed and this pointer is updated. */ + Dwfl_Frame *unwound; + void *callbacks_arg; +}; + +/* See its typedef in libdwfl.h. */ + +struct Dwfl_Frame +{ + Dwfl_Thread *thread; + /* Previous (outer) frame. */ + Dwfl_Frame *unwound; + bool signal_frame : 1; + bool initial_frame : 1; + enum + { + /* This structure is still being initialized or there was an error + initializing it. */ + DWFL_FRAME_STATE_ERROR, + /* PC field is valid. */ + DWFL_FRAME_STATE_PC_SET, + /* PC field is undefined, this means the next (inner) frame was the + outermost frame. */ + DWFL_FRAME_STATE_PC_UNDEFINED + } pc_state; + /* Either initialized from appropriate REGS element or on some archs + initialized separately as the return address has no DWARF register. */ + Dwarf_Addr pc; + /* (1 << X) bitmask where 0 <= X < ebl_frame_nregs. */ + uint64_t regs_set[3]; + /* REGS array size is ebl_frame_nregs. + REGS_SET tells which of the REGS are valid. */ + Dwarf_Addr regs[]; +}; + +/* Fetch value from Dwfl_Frame->regs indexed by DWARF REGNO. + No error code is set if the function returns FALSE. */ +bool __libdwfl_frame_reg_get (Dwfl_Frame *state, unsigned regno, + Dwarf_Addr *val) + internal_function; + +/* Store value to Dwfl_Frame->regs indexed by DWARF REGNO. + No error code is set if the function returns FALSE. */ +bool __libdwfl_frame_reg_set (Dwfl_Frame *state, unsigned regno, + Dwarf_Addr val) + internal_function; + +/* Information cached about each CU in Dwfl_Module.dw. */ +struct dwfl_cu +{ + /* This caches libdw information about the CU. It's also the + address passed back to users, so we take advantage of the + fact that it's placed first to cast back. */ + Dwarf_Die die; + + Dwfl_Module *mod; /* Pointer back to containing module. */ + + struct dwfl_cu *next; /* CU immediately following in the file. */ + + struct Dwfl_Lines *lines; +}; + +struct Dwfl_Lines +{ + struct dwfl_cu *cu; + + /* This is what the opaque Dwfl_Line * pointers we pass to users are. + We need to recover pointers to our struct dwfl_cu and a record in + libdw's Dwarf_Line table. To minimize the memory used in addition + to libdw's Dwarf_Lines buffer, we just point to our own index in + this table, and have one pointer back to the CU. The indices here + match those in libdw's Dwarf_CU.lines->info table. */ + struct Dwfl_Line + { + unsigned int idx; /* My index in the dwfl_cu.lines table. */ + } idx[0]; +}; + +static inline struct dwfl_cu * +dwfl_linecu_inline (const Dwfl_Line *line) +{ + const struct Dwfl_Lines *lines = ((const void *) line + - offsetof (struct Dwfl_Lines, + idx[line->idx])); + return lines->cu; +} +#define dwfl_linecu dwfl_linecu_inline + +static inline GElf_Addr +dwfl_adjusted_address (Dwfl_Module *mod, GElf_Addr addr) +{ + return addr + mod->main_bias; +} + +static inline GElf_Addr +dwfl_deadjust_address (Dwfl_Module *mod, GElf_Addr addr) +{ + return addr - mod->main_bias; +} + +static inline Dwarf_Addr +dwfl_adjusted_dwarf_addr (Dwfl_Module *mod, Dwarf_Addr addr) +{ + return dwfl_adjusted_address (mod, (addr + - mod->debug.address_sync + + mod->main.address_sync)); +} + +static inline Dwarf_Addr +dwfl_deadjust_dwarf_addr (Dwfl_Module *mod, Dwarf_Addr addr) +{ + return (dwfl_deadjust_address (mod, addr) + - mod->main.address_sync + + mod->debug.address_sync); +} + +static inline Dwarf_Addr +dwfl_adjusted_aux_sym_addr (Dwfl_Module *mod, Dwarf_Addr addr) +{ + return dwfl_adjusted_address (mod, (addr + - mod->aux_sym.address_sync + + mod->main.address_sync)); +} + +static inline Dwarf_Addr +dwfl_deadjust_aux_sym_addr (Dwfl_Module *mod, Dwarf_Addr addr) +{ + return (dwfl_deadjust_address (mod, addr) + - mod->main.address_sync + + mod->aux_sym.address_sync); +} + +static inline GElf_Addr +dwfl_adjusted_st_value (Dwfl_Module *mod, Elf *symelf, GElf_Addr addr) +{ + if (symelf == mod->main.elf) + return dwfl_adjusted_address (mod, addr); + if (symelf == mod->debug.elf) + return dwfl_adjusted_dwarf_addr (mod, addr); + return dwfl_adjusted_aux_sym_addr (mod, addr); +} + +static inline GElf_Addr +dwfl_deadjust_st_value (Dwfl_Module *mod, Elf *symelf, GElf_Addr addr) +{ + if (symelf == mod->main.elf) + return dwfl_deadjust_address (mod, addr); + if (symelf == mod->debug.elf) + return dwfl_deadjust_dwarf_addr (mod, addr); + return dwfl_deadjust_aux_sym_addr (mod, addr); +} + +/* This describes a contiguous address range that lies in a single CU. + We condense runs of Dwarf_Arange entries for the same CU into this. */ +struct dwfl_arange +{ + struct dwfl_cu *cu; + size_t arange; /* Index in Dwarf_Aranges. */ +}; + + +/* Structure used for keeping track of ptrace attaching a thread. + Shared by linux-pid-attach and linux-proc-maps. If it has been setup + then get the instance through __libdwfl_get_pid_arg. */ +struct __libdwfl_pid_arg +{ + DIR *dir; + /* It is 0 if not used. */ + pid_t tid_attached; + /* Valid only if TID_ATTACHED is not zero. */ + bool tid_was_stopped; + /* True if threads are ptrace stopped by caller. */ + bool assume_ptrace_stopped; +}; + +/* If DWfl is not NULL and a Dwfl_Process has been setup that has + Dwfl_Thread_Callbacks set to pid_thread_callbacks, then return the + callbacks_arg, which will be a struct __libdwfl_pid_arg. Otherwise + returns NULL. */ +extern struct __libdwfl_pid_arg *__libdwfl_get_pid_arg (Dwfl *dwfl) + internal_function; + +/* Makes sure the given tid is attached. On success returns true and + sets tid_was_stopped. */ +extern bool __libdwfl_ptrace_attach (pid_t tid, bool *tid_was_stoppedp) + internal_function; + +/* Detaches a tid that was attached through + __libdwfl_ptrace_attach. Must be given the tid_was_stopped as set + by __libdwfl_ptrace_attach. */ +extern void __libdwfl_ptrace_detach (pid_t tid, bool tid_was_stopped) + internal_function; + + +/* Internal wrapper for old dwfl_module_getsym and new dwfl_module_getsym_info. + adjust_st_value set to true returns adjusted SYM st_value, set to false + it will not adjust SYM at all, but does match against resolved *ADDR. */ +extern const char *__libdwfl_getsym (Dwfl_Module *mod, int ndx, GElf_Sym *sym, + GElf_Addr *addr, GElf_Word *shndxp, + Elf **elfp, Dwarf_Addr *biasp, + bool *resolved, bool adjust_st_value) + internal_function; + +/* Internal wrapper for old dwfl_module_addrsym and new dwfl_module_addrinfo. + adjust_st_value set to true returns adjusted SYM st_value, set to false + it will not adjust SYM at all, but does match against resolved values. */ +extern const char *__libdwfl_addrsym (Dwfl_Module *mod, GElf_Addr addr, + GElf_Off *off, GElf_Sym *sym, + GElf_Word *shndxp, Elf **elfp, + Dwarf_Addr *bias, + bool adjust_st_value) internal_function; + +extern void __libdwfl_module_free (Dwfl_Module *mod) internal_function; + +/* Find the main ELF file, update MOD->elferr and/or MOD->main.elf. */ +extern void __libdwfl_getelf (Dwfl_Module *mod) internal_function; + +/* Process relocations in debugging sections in an ET_REL file. + FILE must be opened with ELF_C_READ_MMAP_PRIVATE or ELF_C_READ, + to make it possible to relocate the data in place (or ELF_C_RDWR or + ELF_C_RDWR_MMAP if you intend to modify the Elf file on disk). After + this, dwarf_begin_elf on FILE will read the relocated data. + + When DEBUG is false, apply partial relocation to all sections. */ +extern Dwfl_Error __libdwfl_relocate (Dwfl_Module *mod, Elf *file, bool debug) + internal_function; + +/* Find the section index in mod->main.elf that contains the given + *ADDR. Adjusts *ADDR to be section relative on success, returns + SHN_UNDEF on failure. */ +extern size_t __libdwfl_find_section_ndx (Dwfl_Module *mod, Dwarf_Addr *addr) + internal_function; + +/* Process (simple) relocations in arbitrary section TSCN of an ET_REL file. + RELOCSCN is SHT_REL or SHT_RELA and TSCN is its sh_info target section. */ +extern Dwfl_Error __libdwfl_relocate_section (Dwfl_Module *mod, Elf *relocated, + Elf_Scn *relocscn, Elf_Scn *tscn, + bool partial) + internal_function; + +/* Adjust *VALUE from section-relative to absolute. + MOD->dwfl->callbacks->section_address is called to determine the actual + address of a loaded section. */ +extern Dwfl_Error __libdwfl_relocate_value (Dwfl_Module *mod, Elf *elf, + size_t *shstrndx_cache, + Elf32_Word shndx, + GElf_Addr *value) + internal_function; + +/* Ensure that MOD->ebl is set up. */ +extern Dwfl_Error __libdwfl_module_getebl (Dwfl_Module *mod) internal_function; + +/* Install a new Dwarf_CFI in *SLOT (MOD->eh_cfi or MOD->dwarf_cfi). */ +extern Dwarf_CFI *__libdwfl_set_cfi (Dwfl_Module *mod, Dwarf_CFI **slot, + Dwarf_CFI *cfi) + internal_function; + +/* Iterate through all the CU's in the module. Start by passing a null + LASTCU, and then pass the last *CU returned. Success return with null + *CU no more CUs. */ +extern Dwfl_Error __libdwfl_nextcu (Dwfl_Module *mod, struct dwfl_cu *lastcu, + struct dwfl_cu **cu) internal_function; + +/* Find the CU by address. */ +extern Dwfl_Error __libdwfl_addrcu (Dwfl_Module *mod, Dwarf_Addr addr, + struct dwfl_cu **cu) internal_function; + +/* Ensure that CU->lines (and CU->cu->lines) is set up. */ +extern Dwfl_Error __libdwfl_cu_getsrclines (struct dwfl_cu *cu) + internal_function; + +/* Look in ELF for an NT_GNU_BUILD_ID note. Store it to BUILD_ID_BITS, + its vaddr in ELF to BUILD_ID_VADDR (it is unrelocated, even if MOD is not + NULL) and store length to BUILD_ID_LEN. Returns -1 for errors, 1 if it was + stored and 0 if no note is found. MOD may be NULL, MOD must be non-NULL + only if ELF is ET_REL. */ +extern int __libdwfl_find_elf_build_id (Dwfl_Module *mod, Elf *elf, + const void **build_id_bits, + GElf_Addr *build_id_elfaddr, + int *build_id_len) + internal_function; + +/* Look in ELF for an NT_GNU_BUILD_ID note. If SET is true, store it + in MOD and return its length. If SET is false, instead compare it + to that stored in MOD and return 2 if they match, 1 if they do not. + Returns -1 for errors, 0 if no note is found. */ +extern int __libdwfl_find_build_id (Dwfl_Module *mod, bool set, Elf *elf) + internal_function; + +/* Open a main or debuginfo file by its build ID, returns the fd. */ +extern int __libdwfl_open_mod_by_build_id (Dwfl_Module *mod, bool debug, + char **file_name) internal_function; + +/* Same, but takes an explicit build_id, can also be used for alt debug. */ +extern int __libdwfl_open_by_build_id (Dwfl_Module *mod, bool debug, + char **file_name, const size_t id_len, + const uint8_t *id) internal_function; + +extern uint32_t __libdwfl_crc32 (uint32_t crc, unsigned char *buf, size_t len) + attribute_hidden; +extern int __libdwfl_crc32_file (int fd, uint32_t *resp) attribute_hidden; + + +/* Given ELF and some parameters return TRUE if the *P return value parameters + have been successfully filled in. Any of the *P parameters can be NULL. */ +extern bool __libdwfl_elf_address_range (Elf *elf, GElf_Addr base, + bool add_p_vaddr, bool sanity, + GElf_Addr *vaddrp, + GElf_Addr *address_syncp, + GElf_Addr *startp, GElf_Addr *endp, + GElf_Addr *biasp, GElf_Half *e_typep) + internal_function; + +/* Meat of dwfl_report_elf, given elf_begin just called. + Consumes ELF on success, not on failure. */ +extern Dwfl_Module *__libdwfl_report_elf (Dwfl *dwfl, const char *name, + const char *file_name, int fd, + Elf *elf, GElf_Addr base, + bool add_p_vaddr, bool sanity) + internal_function; + +/* Meat of dwfl_report_offline. */ +extern Dwfl_Module *__libdwfl_report_offline (Dwfl *dwfl, const char *name, + const char *file_name, + int fd, bool closefd, + int (*predicate) (const char *, + const char *)) + internal_function; + +/* Free PROCESS. Unlink and free also any structures it references. */ +extern void __libdwfl_process_free (Dwfl_Process *process) + internal_function; + +/* Update STATE->unwound for the unwound frame. + On error STATE->unwound == NULL + or STATE->unwound->pc_state == DWFL_FRAME_STATE_ERROR; + in such case dwfl_errno () is set. + If STATE->unwound->pc_state == DWFL_FRAME_STATE_PC_UNDEFINED + then STATE was the last valid frame. */ +extern void __libdwfl_frame_unwind (Dwfl_Frame *state) + internal_function; + +/* Align segment START downwards or END upwards addresses according to DWFL. */ +extern GElf_Addr __libdwfl_segment_start (Dwfl *dwfl, GElf_Addr start) + internal_function; +extern GElf_Addr __libdwfl_segment_end (Dwfl *dwfl, GElf_Addr end) + internal_function; + +/* Decompression wrappers: decompress whole file into memory. */ +extern Dwfl_Error __libdw_gunzip (int fd, off64_t start_offset, + void *mapped, size_t mapped_size, + void **whole, size_t *whole_size) + internal_function; +extern Dwfl_Error __libdw_bunzip2 (int fd, off64_t start_offset, + void *mapped, size_t mapped_size, + void **whole, size_t *whole_size) + internal_function; +extern Dwfl_Error __libdw_unlzma (int fd, off64_t start_offset, + void *mapped, size_t mapped_size, + void **whole, size_t *whole_size) + internal_function; + +/* Skip the image header before a file image: updates *START_OFFSET. */ +extern Dwfl_Error __libdw_image_header (int fd, off64_t *start_offset, + void *mapped, size_t mapped_size) + internal_function; + +/* Open Elf handle on *FDP. This handles decompression and checks + elf_kind. Succeed only for ELF_K_ELF, or also ELF_K_AR if ARCHIVE_OK. + Returns DWFL_E_NOERROR and sets *ELFP on success, resets *FDP to -1 if + it's no longer used. Resets *FDP on failure too iff CLOSE_ON_FAIL. */ +extern Dwfl_Error __libdw_open_file (int *fdp, Elf **elfp, + bool close_on_fail, bool archive_ok) + internal_function; + +/* Fetch PT_DYNAMIC P_VADDR from ELF and store it to *VADDRP. Return success. + *VADDRP is not modified if the function fails. */ +extern bool __libdwfl_dynamic_vaddr_get (Elf *elf, GElf_Addr *vaddrp) + internal_function; + +/* These are working nicely for --core, but are not ready to be + exported interfaces quite yet. */ + +/* Type of callback function ... + */ +typedef bool Dwfl_Memory_Callback (Dwfl *dwfl, int segndx, + void **buffer, size_t *buffer_available, + GElf_Addr vaddr, size_t minread, void *arg); + +/* Type of callback function ... + */ +typedef bool Dwfl_Module_Callback (Dwfl_Module *mod, void **userdata, + const char *name, Dwarf_Addr base, + void **buffer, size_t *buffer_available, + GElf_Off cost, GElf_Off worthwhile, + GElf_Off whole, GElf_Off contiguous, + void *arg, Elf **elfp); + +/* One shared library (or executable) info from DT_DEBUG link map. */ +struct r_debug_info_module +{ + struct r_debug_info_module *next; + /* FD is -1 iff ELF is NULL. */ + int fd; + Elf *elf; + GElf_Addr l_ld; + /* START and END are both zero if not valid. */ + GElf_Addr start, end; + bool disk_file_has_build_id; + char name[0]; +}; + +/* Information gathered from DT_DEBUG by dwfl_link_map_report hinted to + dwfl_segment_report_module. */ +struct r_debug_info +{ + struct r_debug_info_module *module; +}; + +/* ... + */ +extern int dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, + Dwfl_Memory_Callback *memory_callback, + void *memory_callback_arg, + Dwfl_Module_Callback *read_eagerly, + void *read_eagerly_arg, + const void *note_file, + size_t note_file_size, + const struct r_debug_info *r_debug_info); + +/* Report a module for entry in the dynamic linker's struct link_map list. + For each link_map entry, if an existing module resides at its address, + this just modifies that module's name and suggested file name. If + no such module exists, this calls dwfl_report_elf on the l_name string. + + If AUXV is not null, it points to AUXV_SIZE bytes of auxiliary vector + data as contained in an NT_AUXV note or read from a /proc/pid/auxv + file. When this is available, it guides the search. If AUXV is null + or the memory it points to is not accessible, then this search can + only find where to begin if the correct executable file was + previously reported and preloaded as with dwfl_report_elf. + + Fill in R_DEBUG_INFO if it is not NULL. It should be cleared by the + caller, this function does not touch fields it does not need to modify. + If R_DEBUG_INFO is not NULL then no modules get added to DWFL, caller + has to add them from filled in R_DEBUG_INFO. + + Returns the number of modules found, or -1 for errors. */ +extern int dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size, + Dwfl_Memory_Callback *memory_callback, + void *memory_callback_arg, + struct r_debug_info *r_debug_info); + + +/* Avoid PLT entries. */ +INTDECL (dwfl_begin) +INTDECL (dwfl_errmsg) +INTDECL (dwfl_errno) +INTDECL (dwfl_addrmodule) +INTDECL (dwfl_addrsegment) +INTDECL (dwfl_addrdwarf) +INTDECL (dwfl_addrdie) +INTDECL (dwfl_core_file_attach) +INTDECL (dwfl_core_file_report) +INTDECL (dwfl_getmodules) +INTDECL (dwfl_module_addrdie) +INTDECL (dwfl_module_address_section) +INTDECL (dwfl_module_addrinfo) +INTDECL (dwfl_module_addrsym) +INTDECL (dwfl_module_build_id) +INTDECL (dwfl_module_getdwarf) +INTDECL (dwfl_module_getelf) +INTDECL (dwfl_module_getsym) +INTDECL (dwfl_module_getsym_info) +INTDECL (dwfl_module_getsymtab) +INTDECL (dwfl_module_getsymtab_first_global) +INTDECL (dwfl_module_getsrc) +INTDECL (dwfl_module_report_build_id) +INTDECL (dwfl_report_elf) +INTDECL (dwfl_report_begin) +INTDECL (dwfl_report_begin_add) +INTDECL (dwfl_report_module) +INTDECL (dwfl_report_segment) +INTDECL (dwfl_report_offline) +INTDECL (dwfl_report_end) +INTDECL (dwfl_build_id_find_elf) +INTDECL (dwfl_build_id_find_debuginfo) +INTDECL (dwfl_standard_find_debuginfo) +INTDECL (dwfl_link_map_report) +INTDECL (dwfl_linux_kernel_find_elf) +INTDECL (dwfl_linux_kernel_module_section_address) +INTDECL (dwfl_linux_proc_attach) +INTDECL (dwfl_linux_proc_report) +INTDECL (dwfl_linux_proc_maps_report) +INTDECL (dwfl_linux_proc_find_elf) +INTDECL (dwfl_linux_kernel_report_kernel) +INTDECL (dwfl_linux_kernel_report_modules) +INTDECL (dwfl_linux_kernel_report_offline) +INTDECL (dwfl_offline_section_address) +INTDECL (dwfl_module_relocate_address) +INTDECL (dwfl_module_dwarf_cfi) +INTDECL (dwfl_module_eh_cfi) +INTDECL (dwfl_attach_state) +INTDECL (dwfl_pid) +INTDECL (dwfl_thread_dwfl) +INTDECL (dwfl_thread_tid) +INTDECL (dwfl_frame_thread) +INTDECL (dwfl_thread_state_registers) +INTDECL (dwfl_thread_state_register_pc) +INTDECL (dwfl_getthread_frames) +INTDECL (dwfl_getthreads) +INTDECL (dwfl_thread_getframes) +INTDECL (dwfl_frame_pc) + +/* Leading arguments standard to callbacks passed a Dwfl_Module. */ +#define MODCB_ARGS(mod) (mod), &(mod)->userdata, (mod)->name, (mod)->low_addr +#define CBFAIL (errno ? DWFL_E (ERRNO, errno) : DWFL_E_CB); + + +/* The default used by dwfl_standard_find_debuginfo. */ +#define DEFAULT_DEBUGINFO_PATH ":.debug:/usr/lib/debug" + + +#endif /* libdwflP.h */ diff --git a/3rdparty/elfutils/libdwfl/libdwfl_crc32.c b/3rdparty/elfutils/libdwfl/libdwfl_crc32.c new file mode 100644 index 0000000..b89d0d3 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/libdwfl_crc32.c @@ -0,0 +1,35 @@ +/* Copyright (C) 2002, 2005 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define crc32 attribute_hidden __libdwfl_crc32 +#define LIB_SYSTEM_H 1 +#include <libdwflP.h> +#include "../lib/crc32.c" diff --git a/3rdparty/elfutils/libdwfl/libdwfl_crc32_file.c b/3rdparty/elfutils/libdwfl/libdwfl_crc32_file.c new file mode 100644 index 0000000..6b6b7d3 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/libdwfl_crc32_file.c @@ -0,0 +1,36 @@ +/* Copyright (C) 2002, 2005 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define crc32_file attribute_hidden __libdwfl_crc32_file +#define crc32 __libdwfl_crc32 +#define LIB_SYSTEM_H 1 +#include <libdwflP.h> +#include "../lib/crc32_file.c" diff --git a/3rdparty/elfutils/libdwfl/lines.c b/3rdparty/elfutils/libdwfl/lines.c new file mode 100644 index 0000000..721e29c --- /dev/null +++ b/3rdparty/elfutils/libdwfl/lines.c @@ -0,0 +1,52 @@ +/* Fetch source line info for CU. + Copyright (C) 2005, 2006 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" +#include "../libdw/libdwP.h" + +Dwfl_Error +internal_function +__libdwfl_cu_getsrclines (struct dwfl_cu *cu) +{ + if (cu->lines == NULL) + { + Dwarf_Lines *lines; + size_t nlines; + if (INTUSE(dwarf_getsrclines) (&cu->die, &lines, &nlines) != 0) + return DWFL_E_LIBDW; + + cu->lines = malloc (offsetof (struct Dwfl_Lines, idx[nlines])); + if (cu->lines == NULL) + return DWFL_E_NOMEM; + cu->lines->cu = cu; + for (unsigned int i = 0; i < nlines; ++i) + cu->lines->idx[i].idx = i; + } + + return DWFL_E_NOERROR; +} diff --git a/3rdparty/elfutils/libdwfl/link_map.c b/3rdparty/elfutils/libdwfl/link_map.c new file mode 100644 index 0000000..eaf43b5 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/link_map.c @@ -0,0 +1,1021 @@ +/* Report modules by examining dynamic linker data structures. + Copyright (C) 2008-2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include <config.h> +#include "libdwflP.h" +#include "../libdw/memory-access.h" +#include "system.h" + +#include <byteswap.h> +#include <endian.h> +#include <fcntl.h> + +/* This element is always provided and always has a constant value. + This makes it an easy thing to scan for to discern the format. */ +#define PROBE_TYPE AT_PHENT +#define PROBE_VAL32 sizeof (Elf32_Phdr) +#define PROBE_VAL64 sizeof (Elf64_Phdr) + + +/* Examine an auxv data block and determine its format. + Return true iff we figured it out. */ +static bool +auxv_format_probe (const void *auxv, size_t size, + uint_fast8_t *elfclass, uint_fast8_t *elfdata) +{ + const union + { + char buf[size]; + Elf32_auxv_t a32[size / sizeof (Elf32_auxv_t)]; + Elf64_auxv_t a64[size / sizeof (Elf64_auxv_t)]; + } *u = auxv; + + inline bool check64 (size_t i) + { + /* The AUXV pointer might not even be naturally aligned for 64-bit + data, because note payloads in a core file are not aligned. + But we assume the data is 32-bit aligned. */ + + uint64_t type = read_8ubyte_unaligned_noncvt (&u->a64[i].a_type); + uint64_t val = read_8ubyte_unaligned_noncvt (&u->a64[i].a_un.a_val); + + if (type == BE64 (PROBE_TYPE) + && val == BE64 (PROBE_VAL64)) + { + *elfdata = ELFDATA2MSB; + return true; + } + + if (type == LE64 (PROBE_TYPE) + && val == LE64 (PROBE_VAL64)) + { + *elfdata = ELFDATA2LSB; + return true; + } + + return false; + } + + inline bool check32 (size_t i) + { + if (u->a32[i].a_type == BE32 (PROBE_TYPE) + && u->a32[i].a_un.a_val == BE32 (PROBE_VAL32)) + { + *elfdata = ELFDATA2MSB; + return true; + } + + if (u->a32[i].a_type == LE32 (PROBE_TYPE) + && u->a32[i].a_un.a_val == LE32 (PROBE_VAL32)) + { + *elfdata = ELFDATA2LSB; + return true; + } + + return false; + } + + for (size_t i = 0; i < size / sizeof (Elf64_auxv_t); ++i) + { + if (check64 (i)) + { + *elfclass = ELFCLASS64; + return true; + } + + if (check32 (i * 2) || check32 (i * 2 + 1)) + { + *elfclass = ELFCLASS32; + return true; + } + } + + return false; +} + +/* This is a Dwfl_Memory_Callback that wraps another memory callback. + If the underlying callback cannot fill the data, then this will + fall back to fetching data from module files. */ + +struct integrated_memory_callback +{ + Dwfl_Memory_Callback *memory_callback; + void *memory_callback_arg; + void *buffer; +}; + +static bool +integrated_memory_callback (Dwfl *dwfl, int ndx, + void **buffer, size_t *buffer_available, + GElf_Addr vaddr, + size_t minread, + void *arg) +{ + struct integrated_memory_callback *info = arg; + + if (ndx == -1) + { + /* Called for cleanup. */ + if (info->buffer != NULL) + { + /* The last probe buffer came from the underlying callback. + Let it do its cleanup. */ + assert (*buffer == info->buffer); /* XXX */ + *buffer = info->buffer; + info->buffer = NULL; + return (*info->memory_callback) (dwfl, ndx, buffer, buffer_available, + vaddr, minread, + info->memory_callback_arg); + } + *buffer = NULL; + *buffer_available = 0; + return false; + } + + if (*buffer != NULL) + /* For a final-read request, we only use the underlying callback. */ + return (*info->memory_callback) (dwfl, ndx, buffer, buffer_available, + vaddr, minread, info->memory_callback_arg); + + /* Let the underlying callback try to fill this request. */ + if ((*info->memory_callback) (dwfl, ndx, &info->buffer, buffer_available, + vaddr, minread, info->memory_callback_arg)) + { + *buffer = info->buffer; + return true; + } + + /* Now look for module text covering this address. */ + + Dwfl_Module *mod; + (void) INTUSE(dwfl_addrsegment) (dwfl, vaddr, &mod); + if (mod == NULL) + return false; + + Dwarf_Addr bias; + Elf_Scn *scn = INTUSE(dwfl_module_address_section) (mod, &vaddr, &bias); + if (unlikely (scn == NULL)) + { +#if 0 // XXX would have to handle ndx=-1 cleanup calls passed down. + /* If we have no sections we can try to fill it from the module file + based on its phdr mappings. */ + if (likely (mod->e_type != ET_REL) && mod->main.elf != NULL) + return INTUSE(dwfl_elf_phdr_memory_callback) + (dwfl, 0, buffer, buffer_available, + vaddr - mod->main.bias, minread, mod->main.elf); +#endif + return false; + } + + Elf_Data *data = elf_rawdata (scn, NULL); + if (unlikely (data == NULL)) + // XXX throw error? + return false; + + if (unlikely (data->d_size < vaddr)) + return false; + + /* Provide as much data as we have. */ + void *contents = data->d_buf + vaddr; + size_t avail = data->d_size - vaddr; + if (unlikely (avail < minread)) + return false; + + /* If probing for a string, make sure it's terminated. */ + if (minread == 0 && unlikely (memchr (contents, '\0', avail) == NULL)) + return false; + + /* We have it! */ + *buffer = contents; + *buffer_available = avail; + return true; +} + +static size_t +addrsize (uint_fast8_t elfclass) +{ + return elfclass * 4; +} + +/* Report a module for each struct link_map in the linked list at r_map + in the struct r_debug at R_DEBUG_VADDR. For r_debug_info description + see dwfl_link_map_report in libdwflP.h. If R_DEBUG_INFO is not NULL then no + modules get added to DWFL, caller has to add them from filled in + R_DEBUG_INFO. + + For each link_map entry, if an existing module resides at its address, + this just modifies that module's name and suggested file name. If + no such module exists, this calls dwfl_report_elf on the l_name string. + + Returns the number of modules found, or -1 for errors. */ + +static int +report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata, + Dwfl *dwfl, GElf_Addr r_debug_vaddr, + Dwfl_Memory_Callback *memory_callback, + void *memory_callback_arg, + struct r_debug_info *r_debug_info) +{ + /* Skip r_version, to aligned r_map field. */ + GElf_Addr read_vaddr = r_debug_vaddr + addrsize (elfclass); + + void *buffer = NULL; + size_t buffer_available = 0; + inline int release_buffer (int result) + { + if (buffer != NULL) + (void) (*memory_callback) (dwfl, -1, &buffer, &buffer_available, 0, 0, + memory_callback_arg); + return result; + } + + GElf_Addr addrs[4]; + inline bool read_addrs (GElf_Addr vaddr, size_t n) + { + size_t nb = n * addrsize (elfclass); /* Address words -> bytes to read. */ + + /* Read a new buffer if the old one doesn't cover these words. */ + if (buffer == NULL + || vaddr < read_vaddr + || vaddr - read_vaddr + nb > buffer_available) + { + release_buffer (0); + + read_vaddr = vaddr; + int segndx = INTUSE(dwfl_addrsegment) (dwfl, vaddr, NULL); + if (unlikely (segndx < 0) + || unlikely (! (*memory_callback) (dwfl, segndx, + &buffer, &buffer_available, + vaddr, nb, memory_callback_arg))) + return true; + } + + const union + { + Elf32_Addr a32[n]; + Elf64_Addr a64[n]; + } *in = vaddr - read_vaddr + buffer; + + if (elfclass == ELFCLASS32) + { + if (elfdata == ELFDATA2MSB) + for (size_t i = 0; i < n; ++i) + addrs[i] = BE32 (in->a32[i]); + else + for (size_t i = 0; i < n; ++i) + addrs[i] = LE32 (in->a32[i]); + } + else + { + if (elfdata == ELFDATA2MSB) + for (size_t i = 0; i < n; ++i) + addrs[i] = BE64 (in->a64[i]); + else + for (size_t i = 0; i < n; ++i) + addrs[i] = LE64 (in->a64[i]); + } + + return false; + } + + if (unlikely (read_addrs (read_vaddr, 1))) + return release_buffer (-1); + + GElf_Addr next = addrs[0]; + + Dwfl_Module **lastmodp = &dwfl->modulelist; + int result = 0; + + /* There can't be more elements in the link_map list than there are + segments. DWFL->lookup_elts is probably twice that number, so it + is certainly above the upper bound. If we iterate too many times, + there must be a loop in the pointers due to link_map clobberation. */ + size_t iterations = 0; + while (next != 0 && ++iterations < dwfl->lookup_elts) + { + if (read_addrs (next, 4)) + return release_buffer (-1); + + /* Unused: l_addr is the difference between the address in memory + and the ELF file when the core was created. We need to + recalculate the difference below because the ELF file we use + might be differently pre-linked. */ + // GElf_Addr l_addr = addrs[0]; + GElf_Addr l_name = addrs[1]; + GElf_Addr l_ld = addrs[2]; + next = addrs[3]; + + /* If a clobbered or truncated memory image has no useful pointer, + just skip this element. */ + if (l_ld == 0) + continue; + + /* Fetch the string at the l_name address. */ + const char *name = NULL; + if (buffer != NULL + && read_vaddr <= l_name + && l_name + 1 - read_vaddr < buffer_available + && memchr (l_name - read_vaddr + buffer, '\0', + buffer_available - (l_name - read_vaddr)) != NULL) + name = l_name - read_vaddr + buffer; + else + { + release_buffer (0); + read_vaddr = l_name; + int segndx = INTUSE(dwfl_addrsegment) (dwfl, l_name, NULL); + if (likely (segndx >= 0) + && (*memory_callback) (dwfl, segndx, + &buffer, &buffer_available, + l_name, 0, memory_callback_arg)) + name = buffer; + } + + if (name != NULL && name[0] == '\0') + name = NULL; + + if (iterations == 1 && dwfl->executable_for_core != NULL) + name = dwfl->executable_for_core; + + struct r_debug_info_module *r_debug_info_module = NULL; + if (r_debug_info != NULL) + { + /* Save link map information about valid shared library (or + executable) which has not been found on disk. */ + const char *name1 = name == NULL ? "" : name; + r_debug_info_module = malloc (sizeof (*r_debug_info_module) + + strlen (name1) + 1); + if (r_debug_info_module == NULL) + return release_buffer (result); + r_debug_info_module->fd = -1; + r_debug_info_module->elf = NULL; + r_debug_info_module->l_ld = l_ld; + r_debug_info_module->start = 0; + r_debug_info_module->end = 0; + r_debug_info_module->disk_file_has_build_id = false; + strcpy (r_debug_info_module->name, name1); + r_debug_info_module->next = r_debug_info->module; + r_debug_info->module = r_debug_info_module; + } + + Dwfl_Module *mod = NULL; + if (name != NULL) + { + /* This code is mostly inlined dwfl_report_elf. */ + // XXX hook for sysroot + int fd = open64 (name, O_RDONLY); + if (fd >= 0) + { + Elf *elf; + Dwfl_Error error = __libdw_open_file (&fd, &elf, true, false); + GElf_Addr elf_dynamic_vaddr; + if (error == DWFL_E_NOERROR + && __libdwfl_dynamic_vaddr_get (elf, &elf_dynamic_vaddr)) + { + const void *build_id_bits; + GElf_Addr build_id_elfaddr; + int build_id_len; + bool valid = true; + + if (__libdwfl_find_elf_build_id (NULL, elf, &build_id_bits, + &build_id_elfaddr, + &build_id_len) > 0 + && build_id_elfaddr != 0) + { + if (r_debug_info_module != NULL) + r_debug_info_module->disk_file_has_build_id = true; + GElf_Addr build_id_vaddr = (build_id_elfaddr + - elf_dynamic_vaddr + l_ld); + + release_buffer (0); + int segndx = INTUSE(dwfl_addrsegment) (dwfl, + build_id_vaddr, + NULL); + if (! (*memory_callback) (dwfl, segndx, + &buffer, &buffer_available, + build_id_vaddr, build_id_len, + memory_callback_arg)) + { + /* File has valid build-id which cannot be read from + memory. This happens for core files without bit 4 + (0x10) set in Linux /proc/PID/coredump_filter. */ + } + else + { + if (memcmp (build_id_bits, buffer, build_id_len) != 0) + /* File has valid build-id which does not match + the one in memory. */ + valid = false; + release_buffer (0); + } + } + + if (valid) + { + // It is like l_addr but it handles differently prelinked + // files at core dumping vs. core loading time. + GElf_Addr base = l_ld - elf_dynamic_vaddr; + if (r_debug_info_module == NULL) + { + // XXX hook for sysroot + mod = __libdwfl_report_elf (dwfl, basename (name), + name, fd, elf, base, + true, true); + if (mod != NULL) + { + elf = NULL; + fd = -1; + } + } + else if (__libdwfl_elf_address_range (elf, base, true, + true, NULL, NULL, + &r_debug_info_module->start, + &r_debug_info_module->end, + NULL, NULL)) + { + r_debug_info_module->elf = elf; + r_debug_info_module->fd = fd; + elf = NULL; + fd = -1; + } + } + if (elf != NULL) + elf_end (elf); + if (fd != -1) + close (fd); + } + } + } + + if (mod != NULL) + { + ++result; + + /* Move this module to the end of the list, so that we end + up with a list in the same order as the link_map chain. */ + if (mod->next != NULL) + { + if (*lastmodp != mod) + { + lastmodp = &dwfl->modulelist; + while (*lastmodp != mod) + lastmodp = &(*lastmodp)->next; + } + *lastmodp = mod->next; + mod->next = NULL; + while (*lastmodp != NULL) + lastmodp = &(*lastmodp)->next; + *lastmodp = mod; + } + + lastmodp = &mod->next; + } + } + + return release_buffer (result); +} + +static GElf_Addr +consider_executable (Dwfl_Module *mod, GElf_Addr at_phdr, GElf_Addr at_entry, + uint_fast8_t *elfclass, uint_fast8_t *elfdata, + Dwfl_Memory_Callback *memory_callback, + void *memory_callback_arg) +{ + GElf_Ehdr ehdr; + if (unlikely (gelf_getehdr (mod->main.elf, &ehdr) == NULL)) + return 0; + + if (at_entry != 0) + { + /* If we have an AT_ENTRY value, reject this executable if + its entry point address could not have supplied that. */ + + if (ehdr.e_entry == 0) + return 0; + + if (mod->e_type == ET_EXEC) + { + if (ehdr.e_entry != at_entry) + return 0; + } + else + { + /* It could be a PIE. */ + } + } + + // XXX this could be saved in the file cache: phdr vaddr, DT_DEBUG d_val vaddr + /* Find the vaddr of the DT_DEBUG's d_ptr. This is the memory + address where &r_debug was written at runtime. */ + GElf_Xword align = mod->dwfl->segment_align; + GElf_Addr d_val_vaddr = 0; + size_t phnum; + if (elf_getphdrnum (mod->main.elf, &phnum) != 0) + return 0; + + for (size_t i = 0; i < phnum; ++i) + { + GElf_Phdr phdr_mem; + GElf_Phdr *phdr = gelf_getphdr (mod->main.elf, i, &phdr_mem); + if (phdr == NULL) + break; + + if (phdr->p_align > 1 && (align == 0 || phdr->p_align < align)) + align = phdr->p_align; + + if (at_phdr != 0 + && phdr->p_type == PT_LOAD + && (phdr->p_offset & -align) == (ehdr.e_phoff & -align)) + { + /* This is the segment that would map the phdrs. + If we have an AT_PHDR value, reject this executable + if its phdr mapping could not have supplied that. */ + if (mod->e_type == ET_EXEC) + { + if (ehdr.e_phoff - phdr->p_offset + phdr->p_vaddr != at_phdr) + return 0; + } + else + { + /* It could be a PIE. If the AT_PHDR value and our + phdr address don't match modulo ALIGN, then this + could not have been the right PIE. */ + if (((ehdr.e_phoff - phdr->p_offset + phdr->p_vaddr) & -align) + != (at_phdr & -align)) + return 0; + + /* Calculate the bias applied to the PIE's p_vaddr values. */ + GElf_Addr bias = (at_phdr - (ehdr.e_phoff - phdr->p_offset + + phdr->p_vaddr)); + + /* Final sanity check: if we have an AT_ENTRY value, + reject this PIE unless its biased e_entry matches. */ + if (at_entry != 0 && at_entry != ehdr.e_entry + bias) + return 0; + + /* If we're changing the module's address range, + we've just invalidated the module lookup table. */ + GElf_Addr mod_bias = dwfl_adjusted_address (mod, 0); + if (bias != mod_bias) + { + mod->low_addr -= mod_bias; + mod->high_addr -= mod_bias; + mod->low_addr += bias; + mod->high_addr += bias; + + free (mod->dwfl->lookup_module); + mod->dwfl->lookup_module = NULL; + } + } + } + + if (phdr->p_type == PT_DYNAMIC) + { + Elf_Data *data = elf_getdata_rawchunk (mod->main.elf, phdr->p_offset, + phdr->p_filesz, ELF_T_DYN); + if (data == NULL) + continue; + const size_t entsize = gelf_fsize (mod->main.elf, + ELF_T_DYN, 1, EV_CURRENT); + const size_t n = data->d_size / entsize; + for (size_t j = 0; j < n; ++j) + { + GElf_Dyn dyn_mem; + GElf_Dyn *dyn = gelf_getdyn (data, j, &dyn_mem); + if (dyn != NULL && dyn->d_tag == DT_DEBUG) + { + d_val_vaddr = phdr->p_vaddr + entsize * j + entsize / 2; + break; + } + } + } + } + + if (d_val_vaddr != 0) + { + /* Now we have the final address from which to read &r_debug. */ + d_val_vaddr = dwfl_adjusted_address (mod, d_val_vaddr); + + void *buffer = NULL; + size_t buffer_available = addrsize (ehdr.e_ident[EI_CLASS]); + + int segndx = INTUSE(dwfl_addrsegment) (mod->dwfl, d_val_vaddr, NULL); + + if ((*memory_callback) (mod->dwfl, segndx, + &buffer, &buffer_available, + d_val_vaddr, buffer_available, + memory_callback_arg)) + { + const union + { + Elf32_Addr a32; + Elf64_Addr a64; + } *u = buffer; + + GElf_Addr vaddr; + if (ehdr.e_ident[EI_CLASS] == ELFCLASS32) + vaddr = (ehdr.e_ident[EI_DATA] == ELFDATA2MSB + ? BE32 (u->a32) : LE32 (u->a32)); + else + vaddr = (ehdr.e_ident[EI_DATA] == ELFDATA2MSB + ? BE64 (u->a64) : LE64 (u->a64)); + + (*memory_callback) (mod->dwfl, -1, &buffer, &buffer_available, 0, 0, + memory_callback_arg); + + if (*elfclass == ELFCLASSNONE) + *elfclass = ehdr.e_ident[EI_CLASS]; + else if (*elfclass != ehdr.e_ident[EI_CLASS]) + return 0; + + if (*elfdata == ELFDATANONE) + *elfdata = ehdr.e_ident[EI_DATA]; + else if (*elfdata != ehdr.e_ident[EI_DATA]) + return 0; + + return vaddr; + } + } + + return 0; +} + +/* Try to find an existing executable module with a DT_DEBUG. */ +static GElf_Addr +find_executable (Dwfl *dwfl, GElf_Addr at_phdr, GElf_Addr at_entry, + uint_fast8_t *elfclass, uint_fast8_t *elfdata, + Dwfl_Memory_Callback *memory_callback, + void *memory_callback_arg) +{ + for (Dwfl_Module *mod = dwfl->modulelist; mod != NULL; mod = mod->next) + if (mod->main.elf != NULL) + { + GElf_Addr r_debug_vaddr = consider_executable (mod, at_phdr, at_entry, + elfclass, elfdata, + memory_callback, + memory_callback_arg); + if (r_debug_vaddr != 0) + return r_debug_vaddr; + } + + return 0; +} + + +int +dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size, + Dwfl_Memory_Callback *memory_callback, + void *memory_callback_arg, + struct r_debug_info *r_debug_info) +{ + GElf_Addr r_debug_vaddr = 0; + + uint_fast8_t elfclass = ELFCLASSNONE; + uint_fast8_t elfdata = ELFDATANONE; + if (likely (auxv != NULL) + && likely (auxv_format_probe (auxv, auxv_size, &elfclass, &elfdata))) + { + GElf_Addr entry = 0; + GElf_Addr phdr = 0; + GElf_Xword phent = 0; + GElf_Xword phnum = 0; + +#define READ_AUXV32(ptr) read_4ubyte_unaligned_noncvt (ptr) +#define READ_AUXV64(ptr) read_8ubyte_unaligned_noncvt (ptr) +#define AUXV_SCAN(NN, BL) do \ + { \ + const Elf##NN##_auxv_t *av = auxv; \ + for (size_t i = 0; i < auxv_size / sizeof av[0]; ++i) \ + { \ + uint##NN##_t type = READ_AUXV##NN (&av[i].a_type); \ + uint##NN##_t val = BL##NN (READ_AUXV##NN (&av[i].a_un.a_val)); \ + if (type == BL##NN (AT_ENTRY)) \ + entry = val; \ + else if (type == BL##NN (AT_PHDR)) \ + phdr = val; \ + else if (type == BL##NN (AT_PHNUM)) \ + phnum = val; \ + else if (type == BL##NN (AT_PHENT)) \ + phent = val; \ + else if (type == BL##NN (AT_PAGESZ)) \ + { \ + if (val > 1 \ + && (dwfl->segment_align == 0 \ + || val < dwfl->segment_align)) \ + dwfl->segment_align = val; \ + } \ + } \ + } \ + while (0) + + if (elfclass == ELFCLASS32) + { + if (elfdata == ELFDATA2MSB) + AUXV_SCAN (32, BE); + else + AUXV_SCAN (32, LE); + } + else + { + if (elfdata == ELFDATA2MSB) + AUXV_SCAN (64, BE); + else + AUXV_SCAN (64, LE); + } + + /* If we found the phdr dimensions, search phdrs for PT_DYNAMIC. */ + GElf_Addr dyn_vaddr = 0; + GElf_Xword dyn_filesz = 0; + GElf_Addr dyn_bias = (GElf_Addr) -1; + + inline bool consider_phdr (GElf_Word type, + GElf_Addr vaddr, GElf_Xword filesz) + { + switch (type) + { + case PT_PHDR: + if (dyn_bias == (GElf_Addr) -1 + /* Do a sanity check on the putative address. */ + && ((vaddr & (dwfl->segment_align - 1)) + == (phdr & (dwfl->segment_align - 1)))) + { + dyn_bias = phdr - vaddr; + return dyn_vaddr != 0; + } + break; + + case PT_DYNAMIC: + dyn_vaddr = vaddr; + dyn_filesz = filesz; + return dyn_bias != (GElf_Addr) -1; + } + + return false; + } + + if (phdr != 0 && phnum != 0) + { + Dwfl_Module *phdr_mod; + int phdr_segndx = INTUSE(dwfl_addrsegment) (dwfl, phdr, &phdr_mod); + Elf_Data in = + { + .d_type = ELF_T_PHDR, + .d_version = EV_CURRENT, + .d_size = phnum * phent, + .d_buf = NULL + }; + bool in_ok = (*memory_callback) (dwfl, phdr_segndx, &in.d_buf, + &in.d_size, phdr, phnum * phent, + memory_callback_arg); + if (! in_ok && dwfl->executable_for_core != NULL) + { + /* AUXV -> PHDR -> DYNAMIC + Both AUXV and DYNAMIC should be always present in a core file. + PHDR may be missing in core file, try to read it from + EXECUTABLE_FOR_CORE to find where DYNAMIC is located in the + core file. */ + + int fd = open (dwfl->executable_for_core, O_RDONLY); + Elf *elf; + Dwfl_Error error = DWFL_E_ERRNO; + if (fd != -1) + error = __libdw_open_file (&fd, &elf, true, false); + if (error != DWFL_E_NOERROR) + { + __libdwfl_seterrno (error); + return false; + } + GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem); + if (ehdr == NULL) + { + elf_end (elf); + close (fd); + __libdwfl_seterrno (DWFL_E_LIBELF); + return false; + } + size_t e_phnum; + if (elf_getphdrnum (elf, &e_phnum) != 0) + { + elf_end (elf); + close (fd); + __libdwfl_seterrno (DWFL_E_LIBELF); + return false; + } + if (e_phnum != phnum || ehdr->e_phentsize != phent) + { + elf_end (elf); + close (fd); + __libdwfl_seterrno (DWFL_E_BADELF); + return false; + } + off_t off = ehdr->e_phoff; + assert (in.d_buf == NULL); + assert (in.d_size == phnum * phent); + in.d_buf = malloc (in.d_size); + if (unlikely (in.d_buf == NULL)) + { + elf_end (elf); + close (fd); + __libdwfl_seterrno (DWFL_E_NOMEM); + return false; + } + ssize_t nread = pread_retry (fd, in.d_buf, in.d_size, off); + elf_end (elf); + close (fd); + if (nread != (ssize_t) in.d_size) + { + free (in.d_buf); + __libdwfl_seterrno (DWFL_E_ERRNO); + return false; + } + in_ok = true; + } + if (in_ok) + { + union + { + Elf32_Phdr p32; + Elf64_Phdr p64; + char data[phnum * phent]; + } buf; + Elf_Data out = + { + .d_type = ELF_T_PHDR, + .d_version = EV_CURRENT, + .d_size = phnum * phent, + .d_buf = &buf + }; + in.d_size = out.d_size; + if (likely ((elfclass == ELFCLASS32 + ? elf32_xlatetom : elf64_xlatetom) + (&out, &in, elfdata) != NULL)) + { + /* We are looking for PT_DYNAMIC. */ + const union + { + Elf32_Phdr p32[phnum]; + Elf64_Phdr p64[phnum]; + } *u = (void *) &buf; + if (elfclass == ELFCLASS32) + { + for (size_t i = 0; i < phnum; ++i) + if (consider_phdr (u->p32[i].p_type, + u->p32[i].p_vaddr, + u->p32[i].p_filesz)) + break; + } + else + { + for (size_t i = 0; i < phnum; ++i) + if (consider_phdr (u->p64[i].p_type, + u->p64[i].p_vaddr, + u->p64[i].p_filesz)) + break; + } + } + + (*memory_callback) (dwfl, -1, &in.d_buf, &in.d_size, 0, 0, + memory_callback_arg); + } + else + /* We could not read the executable's phdrs from the + memory image. If we have a presupplied executable, + we can still use the AT_PHDR and AT_ENTRY values to + verify it, and to adjust its bias if it's a PIE. + + If there was an ET_EXEC module presupplied that contains + the AT_PHDR address, then we only consider that one. + We'll either accept it if its phdr location and e_entry + make sense or reject it if they don't. If there is no + presupplied ET_EXEC, then look for a presupplied module, + which might be a PIE (ET_DYN) that needs its bias adjusted. */ + r_debug_vaddr = ((phdr_mod == NULL + || phdr_mod->main.elf == NULL + || phdr_mod->e_type != ET_EXEC) + ? find_executable (dwfl, phdr, entry, + &elfclass, &elfdata, + memory_callback, + memory_callback_arg) + : consider_executable (phdr_mod, phdr, entry, + &elfclass, &elfdata, + memory_callback, + memory_callback_arg)); + } + + /* If we found PT_DYNAMIC, search it for DT_DEBUG. */ + if (dyn_filesz != 0) + { + if (dyn_bias != (GElf_Addr) -1) + dyn_vaddr += dyn_bias; + + Elf_Data in = + { + .d_type = ELF_T_DYN, + .d_version = EV_CURRENT, + .d_size = dyn_filesz, + .d_buf = NULL + }; + int dyn_segndx = dwfl_addrsegment (dwfl, dyn_vaddr, NULL); + if ((*memory_callback) (dwfl, dyn_segndx, &in.d_buf, &in.d_size, + dyn_vaddr, dyn_filesz, memory_callback_arg)) + { + union + { + Elf32_Dyn d32; + Elf64_Dyn d64; + char data[dyn_filesz]; + } buf; + Elf_Data out = + { + .d_type = ELF_T_DYN, + .d_version = EV_CURRENT, + .d_size = dyn_filesz, + .d_buf = &buf + }; + in.d_size = out.d_size; + if (likely ((elfclass == ELFCLASS32 + ? elf32_xlatetom : elf64_xlatetom) + (&out, &in, elfdata) != NULL)) + { + /* We are looking for DT_DEBUG. */ + const union + { + Elf32_Dyn d32[dyn_filesz / sizeof (Elf32_Dyn)]; + Elf64_Dyn d64[dyn_filesz / sizeof (Elf64_Dyn)]; + } *u = (void *) &buf; + if (elfclass == ELFCLASS32) + { + size_t n = dyn_filesz / sizeof (Elf32_Dyn); + for (size_t i = 0; i < n; ++i) + if (u->d32[i].d_tag == DT_DEBUG) + { + r_debug_vaddr = u->d32[i].d_un.d_val; + break; + } + } + else + { + size_t n = dyn_filesz / sizeof (Elf64_Dyn); + for (size_t i = 0; i < n; ++i) + if (u->d64[i].d_tag == DT_DEBUG) + { + r_debug_vaddr = u->d64[i].d_un.d_val; + break; + } + } + } + + (*memory_callback) (dwfl, -1, &in.d_buf, &in.d_size, 0, 0, + memory_callback_arg); + } + } + } + else + /* We have to look for a presupplied executable file to determine + the vaddr of its dynamic section and DT_DEBUG therein. */ + r_debug_vaddr = find_executable (dwfl, 0, 0, &elfclass, &elfdata, + memory_callback, memory_callback_arg); + + if (r_debug_vaddr == 0) + return 0; + + /* For following pointers from struct link_map, we will use an + integrated memory access callback that can consult module text + elided from the core file. This is necessary when the l_name + pointer for the dynamic linker's own entry is a pointer into the + executable's .interp section. */ + struct integrated_memory_callback mcb = + { + .memory_callback = memory_callback, + .memory_callback_arg = memory_callback_arg + }; + + /* Now we can follow the dynamic linker's library list. */ + return report_r_debug (elfclass, elfdata, dwfl, r_debug_vaddr, + &integrated_memory_callback, &mcb, r_debug_info); +} +INTDEF (dwfl_link_map_report) diff --git a/3rdparty/elfutils/libdwfl/linux-core-attach.c b/3rdparty/elfutils/libdwfl/linux-core-attach.c new file mode 100644 index 0000000..5a7b3b3 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/linux-core-attach.c @@ -0,0 +1,427 @@ +/* Get Dwarf Frame state for target core file. + Copyright (C) 2013, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" +#include <fcntl.h> +#include "system.h" + +#include "../libdw/memory-access.h" + +#ifndef MIN +# define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif + +struct core_arg +{ + Elf *core; + Elf_Data *note_data; + size_t thread_note_offset; + Ebl *ebl; +}; + +struct thread_arg +{ + struct core_arg *core_arg; + size_t note_offset; +}; + +static bool +core_memory_read (Dwfl *dwfl, Dwarf_Addr addr, Dwarf_Word *result, + void *dwfl_arg) +{ + Dwfl_Process *process = dwfl->process; + struct core_arg *core_arg = dwfl_arg; + Elf *core = core_arg->core; + assert (core != NULL); + static size_t phnum; + if (elf_getphdrnum (core, &phnum) < 0) + { + __libdwfl_seterrno (DWFL_E_LIBELF); + return false; + } + for (size_t cnt = 0; cnt < phnum; ++cnt) + { + GElf_Phdr phdr_mem, *phdr = gelf_getphdr (core, cnt, &phdr_mem); + if (phdr == NULL || phdr->p_type != PT_LOAD) + continue; + /* Bias is zero here, a core file itself has no bias. */ + GElf_Addr start = __libdwfl_segment_start (dwfl, phdr->p_vaddr); + GElf_Addr end = __libdwfl_segment_end (dwfl, + phdr->p_vaddr + phdr->p_memsz); + unsigned bytes = ebl_get_elfclass (process->ebl) == ELFCLASS64 ? 8 : 4; + if (addr < start || addr + bytes > end) + continue; + Elf_Data *data; + data = elf_getdata_rawchunk (core, phdr->p_offset + addr - start, + bytes, ELF_T_ADDR); + if (data == NULL) + { + __libdwfl_seterrno (DWFL_E_LIBELF); + return false; + } + assert (data->d_size == bytes); + if (bytes == 8) + *result = read_8ubyte_unaligned_noncvt (data->d_buf); + else + *result = read_4ubyte_unaligned_noncvt (data->d_buf); + return true; + } + __libdwfl_seterrno (DWFL_E_ADDR_OUTOFRANGE); + return false; +} + +static pid_t +core_next_thread (Dwfl *dwfl __attribute__ ((unused)), void *dwfl_arg, + void **thread_argp) +{ + struct core_arg *core_arg = dwfl_arg; + Elf *core = core_arg->core; + GElf_Nhdr nhdr; + size_t name_offset; + size_t desc_offset; + Elf_Data *note_data = core_arg->note_data; + size_t offset; + + struct thread_arg *thread_arg; + if (*thread_argp == NULL) + { + core_arg->thread_note_offset = 0; + thread_arg = malloc (sizeof (*thread_arg)); + if (thread_arg == NULL) + { + __libdwfl_seterrno (DWFL_E_NOMEM); + return -1; + } + thread_arg->core_arg = core_arg; + *thread_argp = thread_arg; + } + else + thread_arg = (struct thread_arg *) *thread_argp; + + while (offset = core_arg->thread_note_offset, offset < note_data->d_size + && (core_arg->thread_note_offset = gelf_getnote (note_data, offset, + &nhdr, &name_offset, + &desc_offset)) > 0) + { + /* Do not check NAME for now, help broken Linux kernels. */ + const char *name = note_data->d_buf + name_offset; + const char *desc = note_data->d_buf + desc_offset; + GElf_Word regs_offset; + size_t nregloc; + const Ebl_Register_Location *reglocs; + size_t nitems; + const Ebl_Core_Item *items; + if (! ebl_core_note (core_arg->ebl, &nhdr, name, + ®s_offset, &nregloc, ®locs, &nitems, &items)) + { + /* This note may be just not recognized, skip it. */ + continue; + } + if (nhdr.n_type != NT_PRSTATUS) + continue; + const Ebl_Core_Item *item; + for (item = items; item < items + nitems; item++) + if (strcmp (item->name, "pid") == 0) + break; + if (item == items + nitems) + continue; + uint32_t val32 = read_4ubyte_unaligned_noncvt (desc + item->offset); + val32 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB + ? be32toh (val32) : le32toh (val32)); + pid_t tid = (int32_t) val32; + eu_static_assert (sizeof val32 <= sizeof tid); + thread_arg->note_offset = offset; + return tid; + } + + free (thread_arg); + return 0; +} + +static bool +core_set_initial_registers (Dwfl_Thread *thread, void *thread_arg_voidp) +{ + struct thread_arg *thread_arg = thread_arg_voidp; + struct core_arg *core_arg = thread_arg->core_arg; + Elf *core = core_arg->core; + size_t offset = thread_arg->note_offset; + GElf_Nhdr nhdr; + size_t name_offset; + size_t desc_offset; + Elf_Data *note_data = core_arg->note_data; + size_t nregs = ebl_frame_nregs (core_arg->ebl); + assert (nregs > 0); + assert (offset < note_data->d_size); + size_t getnote_err = gelf_getnote (note_data, offset, &nhdr, &name_offset, + &desc_offset); + /* __libdwfl_attach_state_for_core already verified the note is there. */ + assert (getnote_err != 0); + /* Do not check NAME for now, help broken Linux kernels. */ + const char *name = note_data->d_buf + name_offset; + const char *desc = note_data->d_buf + desc_offset; + GElf_Word regs_offset; + size_t nregloc; + const Ebl_Register_Location *reglocs; + size_t nitems; + const Ebl_Core_Item *items; + int core_note_err = ebl_core_note (core_arg->ebl, &nhdr, name, ®s_offset, + &nregloc, ®locs, &nitems, &items); + /* __libdwfl_attach_state_for_core already verified the note is there. */ + assert (core_note_err != 0); + assert (nhdr.n_type == NT_PRSTATUS); + const Ebl_Core_Item *item; + for (item = items; item < items + nitems; item++) + if (strcmp (item->name, "pid") == 0) + break; + assert (item < items + nitems); + pid_t tid; + { + uint32_t val32 = read_4ubyte_unaligned_noncvt (desc + item->offset); + val32 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB + ? be32toh (val32) : le32toh (val32)); + tid = (int32_t) val32; + eu_static_assert (sizeof val32 <= sizeof tid); + } + /* core_next_thread already found this TID there. */ + assert (tid == INTUSE(dwfl_thread_tid) (thread)); + for (item = items; item < items + nitems; item++) + if (item->pc_register) + break; + if (item < items + nitems) + { + Dwarf_Word pc; + switch (gelf_getclass (core) == ELFCLASS32 ? 32 : 64) + { + case 32:; + uint32_t val32 = read_4ubyte_unaligned_noncvt (desc + item->offset); + val32 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB + ? be32toh (val32) : le32toh (val32)); + /* Do a host width conversion. */ + pc = val32; + break; + case 64:; + uint64_t val64 = read_8ubyte_unaligned_noncvt (desc + item->offset); + val64 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB + ? be64toh (val64) : le64toh (val64)); + pc = val64; + break; + default: + abort (); + } + INTUSE(dwfl_thread_state_register_pc) (thread, pc); + } + desc += regs_offset; + for (size_t regloci = 0; regloci < nregloc; regloci++) + { + const Ebl_Register_Location *regloc = reglocs + regloci; + // Iterate even regs out of NREGS range so that we can find pc_register. + if (regloc->bits != 32 && regloc->bits != 64) + continue; + const char *reg_desc = desc + regloc->offset; + for (unsigned regno = regloc->regno; + regno < regloc->regno + (regloc->count ?: 1U); + regno++) + { + /* PPC provides DWARF register 65 irrelevant for + CFI which clashes with register 108 (LR) we need. + LR (108) is provided earlier (in NT_PRSTATUS) than the # 65. + FIXME: It depends now on their order in core notes. + FIXME: It uses private function. */ + if (regno < nregs + && __libdwfl_frame_reg_get (thread->unwound, regno, NULL)) + continue; + Dwarf_Word val; + switch (regloc->bits) + { + case 32:; + uint32_t val32 = read_4ubyte_unaligned_noncvt (reg_desc); + reg_desc += sizeof val32; + val32 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB + ? be32toh (val32) : le32toh (val32)); + /* Do a host width conversion. */ + val = val32; + break; + case 64:; + uint64_t val64 = read_8ubyte_unaligned_noncvt (reg_desc); + reg_desc += sizeof val64; + val64 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB + ? be64toh (val64) : le64toh (val64)); + assert (sizeof (*thread->unwound->regs) == sizeof val64); + val = val64; + break; + default: + abort (); + } + /* Registers not valid for CFI are just ignored. */ + if (regno < nregs) + INTUSE(dwfl_thread_state_registers) (thread, regno, 1, &val); + if (regloc->pc_register) + INTUSE(dwfl_thread_state_register_pc) (thread, val); + reg_desc += regloc->pad; + } + } + return true; +} + +static void +core_detach (Dwfl *dwfl __attribute__ ((unused)), void *dwfl_arg) +{ + struct core_arg *core_arg = dwfl_arg; + ebl_closebackend (core_arg->ebl); + free (core_arg); +} + +static const Dwfl_Thread_Callbacks core_thread_callbacks = +{ + core_next_thread, + NULL, /* get_thread */ + core_memory_read, + core_set_initial_registers, + core_detach, + NULL, /* core_thread_detach */ +}; + +int +dwfl_core_file_attach (Dwfl *dwfl, Elf *core) +{ + Dwfl_Error err = DWFL_E_NOERROR; + Ebl *ebl = ebl_openbackend (core); + if (ebl == NULL) + { + err = DWFL_E_LIBEBL; + fail_err: + if (dwfl->process == NULL && dwfl->attacherr == DWFL_E_NOERROR) + dwfl->attacherr = __libdwfl_canon_error (err); + __libdwfl_seterrno (err); + return -1; + } + size_t nregs = ebl_frame_nregs (ebl); + if (nregs == 0) + { + err = DWFL_E_NO_UNWIND; + fail: + ebl_closebackend (ebl); + goto fail_err; + } + GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (core, &ehdr_mem); + if (ehdr == NULL) + { + err = DWFL_E_LIBELF; + goto fail; + } + if (ehdr->e_type != ET_CORE) + { + err = DWFL_E_NO_CORE_FILE; + goto fail; + } + size_t phnum; + if (elf_getphdrnum (core, &phnum) < 0) + { + err = DWFL_E_LIBELF; + goto fail; + } + pid_t pid = -1; + Elf_Data *note_data = NULL; + for (size_t cnt = 0; cnt < phnum; ++cnt) + { + GElf_Phdr phdr_mem, *phdr = gelf_getphdr (core, cnt, &phdr_mem); + if (phdr != NULL && phdr->p_type == PT_NOTE) + { + note_data = elf_getdata_rawchunk (core, phdr->p_offset, + phdr->p_filesz, ELF_T_NHDR); + break; + } + } + if (note_data == NULL) + { + err = DWFL_E_LIBELF; + goto fail; + } + size_t offset = 0; + GElf_Nhdr nhdr; + size_t name_offset; + size_t desc_offset; + while (offset < note_data->d_size + && (offset = gelf_getnote (note_data, offset, + &nhdr, &name_offset, &desc_offset)) > 0) + { + /* Do not check NAME for now, help broken Linux kernels. */ + const char *name = note_data->d_buf + name_offset; + const char *desc = note_data->d_buf + desc_offset; + GElf_Word regs_offset; + size_t nregloc; + const Ebl_Register_Location *reglocs; + size_t nitems; + const Ebl_Core_Item *items; + if (! ebl_core_note (ebl, &nhdr, name, + ®s_offset, &nregloc, ®locs, &nitems, &items)) + { + /* This note may be just not recognized, skip it. */ + continue; + } + if (nhdr.n_type != NT_PRPSINFO) + continue; + const Ebl_Core_Item *item; + for (item = items; item < items + nitems; item++) + if (strcmp (item->name, "pid") == 0) + break; + if (item == items + nitems) + continue; + uint32_t val32 = read_4ubyte_unaligned_noncvt (desc + item->offset); + val32 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB + ? be32toh (val32) : le32toh (val32)); + pid = (int32_t) val32; + eu_static_assert (sizeof val32 <= sizeof pid); + break; + } + if (pid == -1) + { + /* No valid NT_PRPSINFO recognized in this CORE. */ + err = DWFL_E_BADELF; + goto fail; + } + struct core_arg *core_arg = malloc (sizeof *core_arg); + if (core_arg == NULL) + { + err = DWFL_E_NOMEM; + goto fail; + } + core_arg->core = core; + core_arg->note_data = note_data; + core_arg->thread_note_offset = 0; + core_arg->ebl = ebl; + if (! INTUSE(dwfl_attach_state) (dwfl, core, pid, &core_thread_callbacks, + core_arg)) + { + free (core_arg); + ebl_closebackend (ebl); + return -1; + } + return pid; +} +INTDEF (dwfl_core_file_attach) diff --git a/3rdparty/elfutils/libdwfl/linux-kernel-modules.c b/3rdparty/elfutils/libdwfl/linux-kernel-modules.c new file mode 100644 index 0000000..e4065d8 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/linux-kernel-modules.c @@ -0,0 +1,928 @@ +/* Standard libdwfl callbacks for debugging the running Linux kernel. + Copyright (C) 2005-2011, 2013, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +/* We include this before config.h because it can't handle _FILE_OFFSET_BITS. + Everything we need here is fine if its declarations just come first. */ + +#include <fts.h> + +#include <config.h> + +#include "libdwflP.h" +#include <inttypes.h> +#include <errno.h> +#include <stdio.h> +#include <stdio_ext.h> +#include <string.h> +#include <stdlib.h> +#include <sys/utsname.h> +#include <fcntl.h> +#include <unistd.h> + + +#define KERNEL_MODNAME "kernel" + +#define MODULEDIRFMT "/lib/modules/%s" + +#define KNOTESFILE "/sys/kernel/notes" +#define MODNOTESFMT "/sys/module/%s/notes" +#define KSYMSFILE "/proc/kallsyms" +#define MODULELIST "/proc/modules" +#define SECADDRDIRFMT "/sys/module/%s/sections/" +#define MODULE_SECT_NAME_LEN 32 /* Minimum any linux/module.h has had. */ + + +#if defined (USE_ZLIB) || defined (USE_BZLIB) || defined (USE_LZMA) +static const char *vmlinux_suffixes[] = + { +#ifdef USE_ZLIB + ".gz", +#endif +#ifdef USE_BZLIB + ".bz2", +#endif +#ifdef USE_LZMA + ".xz", +#endif + }; +#endif + +/* Try to open the given file as it is or under the debuginfo directory. */ +static int +try_kernel_name (Dwfl *dwfl, char **fname, bool try_debug) +{ + if (*fname == NULL) + return -1; + + /* Don't bother trying *FNAME itself here if the path will cause it to be + tried because we give its own basename as DEBUGLINK_FILE. */ + int fd = ((((dwfl->callbacks->debuginfo_path + ? *dwfl->callbacks->debuginfo_path : NULL) + ?: DEFAULT_DEBUGINFO_PATH)[0] == ':') ? -1 + : TEMP_FAILURE_RETRY (open64 (*fname, O_RDONLY))); + + if (fd < 0) + { + Dwfl_Module fakemod = { .dwfl = dwfl }; + /* First try the file's unadorned basename as DEBUGLINK_FILE, + to look for "vmlinux" files. */ + fd = INTUSE(dwfl_standard_find_debuginfo) (&fakemod, NULL, NULL, 0, + *fname, basename (*fname), 0, + &fakemod.debug.name); + if (fd < 0 && try_debug) + /* Next, let the call use the default of basename + ".debug", + to look for "vmlinux.debug" files. */ + fd = INTUSE(dwfl_standard_find_debuginfo) (&fakemod, NULL, NULL, 0, + *fname, NULL, 0, + &fakemod.debug.name); + if (fakemod.debug.name != NULL) + { + free (*fname); + *fname = fakemod.debug.name; + } + } + +#if defined (USE_ZLIB) || defined (USE_BZLIB) || defined (USE_LZMA) + if (fd < 0) + for (size_t i = 0; + i < sizeof vmlinux_suffixes / sizeof vmlinux_suffixes[0]; + ++i) + { + char *zname; + if (asprintf (&zname, "%s%s", *fname, vmlinux_suffixes[i]) > 0) + { + fd = TEMP_FAILURE_RETRY (open64 (zname, O_RDONLY)); + if (fd < 0) + free (zname); + else + { + free (*fname); + *fname = zname; + } + } + } +#endif + + if (fd < 0) + { + free (*fname); + *fname = NULL; + } + + return fd; +} + +static inline const char * +kernel_release (void) +{ + /* Cache the `uname -r` string we'll use. */ + static struct utsname utsname; + if (utsname.release[0] == '\0' && uname (&utsname) != 0) + return NULL; + return utsname.release; +} + +static int +find_kernel_elf (Dwfl *dwfl, const char *release, char **fname) +{ + if ((release[0] == '/' + ? asprintf (fname, "%s/vmlinux", release) + : asprintf (fname, "/boot/vmlinux-%s", release)) < 0) + return -1; + + int fd = try_kernel_name (dwfl, fname, true); + if (fd < 0 && release[0] != '/') + { + free (*fname); + if (asprintf (fname, MODULEDIRFMT "/vmlinux", release) < 0) + return -1; + fd = try_kernel_name (dwfl, fname, true); + } + + return fd; +} + +static int +get_release (Dwfl *dwfl, const char **release) +{ + if (dwfl == NULL) + return -1; + + const char *release_string = release == NULL ? NULL : *release; + if (release_string == NULL) + { + release_string = kernel_release (); + if (release_string == NULL) + return errno; + if (release != NULL) + *release = release_string; + } + + return 0; +} + +static int +report_kernel (Dwfl *dwfl, const char **release, + int (*predicate) (const char *module, const char *file)) +{ + int result = get_release (dwfl, release); + if (unlikely (result != 0)) + return result; + + char *fname; + int fd = find_kernel_elf (dwfl, *release, &fname); + + if (fd < 0) + result = ((predicate != NULL && !(*predicate) (KERNEL_MODNAME, NULL)) + ? 0 : errno ?: ENOENT); + else + { + bool report = true; + + if (predicate != NULL) + { + /* Let the predicate decide whether to use this one. */ + int want = (*predicate) (KERNEL_MODNAME, fname); + if (want < 0) + result = errno; + report = want > 0; + } + + if (report) + { + /* Note that on some architectures (e.g. x86_64) the vmlinux + is ET_EXEC, while on others (e.g. ppc64) it is ET_DYN. + In both cases the phdr p_vaddr load address will be non-zero. + We want the image to be placed as if it was ET_DYN, so + pass true for add_p_vaddr which will do the right thing + (in combination with a zero base) in either case. */ + Dwfl_Module *mod = INTUSE(dwfl_report_elf) (dwfl, KERNEL_MODNAME, + fname, fd, 0, true); + if (mod == NULL) + result = -1; + else + /* The kernel is ET_EXEC, but always treat it as relocatable. */ + mod->e_type = ET_DYN; + } + + free (fname); + + if (!report || result < 0) + close (fd); + } + + return result; +} + +/* Look for a kernel debug archive. If we find one, report all its modules. + If not, return ENOENT. */ +static int +report_kernel_archive (Dwfl *dwfl, const char **release, + int (*predicate) (const char *module, const char *file)) +{ + int result = get_release (dwfl, release); + if (unlikely (result != 0)) + return result; + + char *archive; + int res = (((*release)[0] == '/') + ? asprintf (&archive, "%s/debug.a", *release) + : asprintf (&archive, MODULEDIRFMT "/debug.a", *release)); + if (unlikely (res < 0)) + return ENOMEM; + + int fd = try_kernel_name (dwfl, &archive, false); + if (fd < 0) + result = errno ?: ENOENT; + else + { + /* We have the archive file open! */ + Dwfl_Module *last = __libdwfl_report_offline (dwfl, NULL, archive, fd, + true, predicate); + if (unlikely (last == NULL)) + result = -1; + else + { + /* Find the kernel and move it to the head of the list. */ + Dwfl_Module **tailp = &dwfl->modulelist, **prevp = tailp; + for (Dwfl_Module *m = *prevp; m != NULL; m = *(prevp = &m->next)) + if (!m->gc && m->e_type != ET_REL && !strcmp (m->name, "kernel")) + { + *prevp = m->next; + m->next = *tailp; + *tailp = m; + break; + } + } + } + + free (archive); + return result; +} + +static size_t +check_suffix (const FTSENT *f, size_t namelen) +{ +#define TRY(sfx) \ + if ((namelen ? f->fts_namelen == namelen + sizeof sfx - 1 \ + : f->fts_namelen >= sizeof sfx) \ + && !memcmp (f->fts_name + f->fts_namelen - (sizeof sfx - 1), \ + sfx, sizeof sfx)) \ + return sizeof sfx - 1 + + TRY (".ko"); +#if USE_ZLIB + TRY (".ko.gz"); +#endif +#if USE_BZLIB + TRY (".ko.bz2"); +#endif +#if USE_LZMA + TRY (".ko.xz"); +#endif + + return 0; + +#undef TRY +} + +/* Report a kernel and all its modules found on disk, for offline use. + If RELEASE starts with '/', it names a directory to look in; + if not, it names a directory to find under /lib/modules/; + if null, /lib/modules/`uname -r` is used. + Returns zero on success, -1 if dwfl_report_module failed, + or an errno code if finding the files on disk failed. */ +int +dwfl_linux_kernel_report_offline (Dwfl *dwfl, const char *release, + int (*predicate) (const char *module, + const char *file)) +{ + int result = report_kernel_archive (dwfl, &release, predicate); + if (result != ENOENT) + return result; + + /* First report the kernel. */ + result = report_kernel (dwfl, &release, predicate); + if (result == 0) + { + /* Do "find /lib/modules/RELEASE -name *.ko". */ + + char *modulesdir[] = { NULL, NULL }; + if (release[0] == '/') + modulesdir[0] = (char *) release; + else + { + if (asprintf (&modulesdir[0], MODULEDIRFMT, release) < 0) + return errno; + } + + FTS *fts = fts_open (modulesdir, FTS_NOSTAT | FTS_LOGICAL, NULL); + if (modulesdir[0] == (char *) release) + modulesdir[0] = NULL; + if (fts == NULL) + { + free (modulesdir[0]); + return errno; + } + + FTSENT *f; + while ((f = fts_read (fts)) != NULL) + { + /* Skip a "source" subtree, which tends to be large. + This insane hard-coding of names is what depmod does too. */ + if (f->fts_namelen == sizeof "source" - 1 + && !strcmp (f->fts_name, "source")) + { + fts_set (fts, f, FTS_SKIP); + continue; + } + + switch (f->fts_info) + { + case FTS_F: + case FTS_SL: + case FTS_NSOK:; + /* See if this file name matches "*.ko". */ + const size_t suffix = check_suffix (f, 0); + if (suffix) + { + /* We have a .ko file to report. Following the algorithm + by which the kernel makefiles set KBUILD_MODNAME, we + replace all ',' or '-' with '_' in the file name and + call that the module name. Modules could well be + built using different embedded names than their file + names. To handle that, we would have to look at the + __this_module.name contents in the module's text. */ + + char name[f->fts_namelen - suffix + 1]; + for (size_t i = 0; i < f->fts_namelen - 3U; ++i) + if (f->fts_name[i] == '-' || f->fts_name[i] == ',') + name[i] = '_'; + else + name[i] = f->fts_name[i]; + name[f->fts_namelen - suffix] = '\0'; + + if (predicate != NULL) + { + /* Let the predicate decide whether to use this one. */ + int want = (*predicate) (name, f->fts_path); + if (want < 0) + { + result = -1; + break; + } + if (!want) + continue; + } + + if (dwfl_report_offline (dwfl, name, f->fts_path, -1) == NULL) + { + result = -1; + break; + } + } + continue; + + case FTS_ERR: + case FTS_DNR: + case FTS_NS: + result = f->fts_errno; + break; + + case FTS_SLNONE: + default: + continue; + } + + /* We only get here in error cases. */ + break; + } + fts_close (fts); + free (modulesdir[0]); + } + + return result; +} +INTDEF (dwfl_linux_kernel_report_offline) + + +/* Grovel around to guess the bounds of the runtime kernel image. */ +static int +intuit_kernel_bounds (Dwarf_Addr *start, Dwarf_Addr *end, Dwarf_Addr *notes) +{ + FILE *f = fopen (KSYMSFILE, "r"); + if (f == NULL) + return errno; + + (void) __fsetlocking (f, FSETLOCKING_BYCALLER); + + *notes = 0; + + char *line = NULL; + size_t linesz = 0; + size_t n; + char *p = NULL; + const char *type; + + inline bool read_address (Dwarf_Addr *addr) + { + if ((n = getline (&line, &linesz, f)) < 1 || line[n - 2] == ']') + return false; + *addr = strtoull (line, &p, 16); + p += strspn (p, " \t"); + type = strsep (&p, " \t\n"); + if (type == NULL) + return false; + return p != NULL && p != line; + } + + int result; + do + result = read_address (start) ? 0 : -1; + while (result == 0 && strchr ("TtRr", *type) == NULL); + + if (result == 0) + { + *end = *start; + while (read_address (end)) + if (*notes == 0 && !strcmp (p, "__start_notes\n")) + *notes = *end; + + Dwarf_Addr round_kernel = sysconf (_SC_PAGE_SIZE); + *start &= -(Dwarf_Addr) round_kernel; + *end += round_kernel - 1; + *end &= -(Dwarf_Addr) round_kernel; + if (*start >= *end || *end - *start < round_kernel) + result = -1; + } + free (line); + + if (result == -1) + result = ferror_unlocked (f) ? errno : ENOEXEC; + + fclose (f); + + return result; +} + + +/* Look for a build ID note in NOTESFILE and associate the ID with MOD. */ +static int +check_notes (Dwfl_Module *mod, const char *notesfile, + Dwarf_Addr vaddr, const char *secname) +{ + int fd = open64 (notesfile, O_RDONLY); + if (fd < 0) + return 1; + + assert (sizeof (Elf32_Nhdr) == sizeof (GElf_Nhdr)); + assert (sizeof (Elf64_Nhdr) == sizeof (GElf_Nhdr)); + union + { + GElf_Nhdr nhdr; + unsigned char data[8192]; + } buf; + + ssize_t n = read (fd, buf.data, sizeof buf); + close (fd); + + if (n <= 0) + return 1; + + unsigned char *p = buf.data; + while (p < &buf.data[n]) + { + /* No translation required since we are reading the native kernel. */ + GElf_Nhdr *nhdr = (void *) p; + p += sizeof *nhdr; + unsigned char *name = p; + p += (nhdr->n_namesz + 3) & -4U; + unsigned char *bits = p; + p += (nhdr->n_descsz + 3) & -4U; + + if (p <= &buf.data[n] + && nhdr->n_type == NT_GNU_BUILD_ID + && nhdr->n_namesz == sizeof "GNU" + && !memcmp (name, "GNU", sizeof "GNU")) + { + /* Found it. For a module we must figure out its VADDR now. */ + + if (secname != NULL + && (INTUSE(dwfl_linux_kernel_module_section_address) + (mod, NULL, mod->name, 0, secname, 0, NULL, &vaddr) != 0 + || vaddr == (GElf_Addr) -1l)) + vaddr = 0; + + if (vaddr != 0) + vaddr += bits - buf.data; + return INTUSE(dwfl_module_report_build_id) (mod, bits, + nhdr->n_descsz, vaddr); + } + } + + return 0; +} + +/* Look for a build ID for the kernel. */ +static int +check_kernel_notes (Dwfl_Module *kernelmod, GElf_Addr vaddr) +{ + return check_notes (kernelmod, KNOTESFILE, vaddr, NULL) < 0 ? -1 : 0; +} + +/* Look for a build ID for a loaded kernel module. */ +static int +check_module_notes (Dwfl_Module *mod) +{ + char *dirs[2] = { NULL, NULL }; + if (asprintf (&dirs[0], MODNOTESFMT, mod->name) < 0) + return ENOMEM; + + FTS *fts = fts_open (dirs, FTS_NOSTAT | FTS_LOGICAL, NULL); + if (fts == NULL) + { + free (dirs[0]); + return 0; + } + + int result = 0; + FTSENT *f; + while ((f = fts_read (fts)) != NULL) + { + switch (f->fts_info) + { + case FTS_F: + case FTS_SL: + case FTS_NSOK: + result = check_notes (mod, f->fts_accpath, 0, f->fts_name); + if (result > 0) /* Nothing found. */ + { + result = 0; + continue; + } + break; + + case FTS_ERR: + case FTS_DNR: + result = f->fts_errno; + break; + + case FTS_NS: + case FTS_SLNONE: + default: + continue; + } + + /* We only get here when finished or in error cases. */ + break; + } + fts_close (fts); + free (dirs[0]); + + return result; +} + +int +dwfl_linux_kernel_report_kernel (Dwfl *dwfl) +{ + Dwarf_Addr start; + Dwarf_Addr end; + inline Dwfl_Module *report (void) + { + return INTUSE(dwfl_report_module) (dwfl, KERNEL_MODNAME, start, end); + } + + /* This is a bit of a kludge. If we already reported the kernel, + don't bother figuring it out again--it never changes. */ + for (Dwfl_Module *m = dwfl->modulelist; m != NULL; m = m->next) + if (!strcmp (m->name, KERNEL_MODNAME)) + { + start = m->low_addr; + end = m->high_addr; + return report () == NULL ? -1 : 0; + } + + /* Try to figure out the bounds of the kernel image without + looking for any vmlinux file. */ + Dwarf_Addr notes; + /* The compiler cannot deduce that if intuit_kernel_bounds returns + zero NOTES will be initialized. Fake the initialization. */ + asm ("" : "=m" (notes)); + int result = intuit_kernel_bounds (&start, &end, ¬es); + if (result == 0) + { + Dwfl_Module *mod = report (); + return unlikely (mod == NULL) ? -1 : check_kernel_notes (mod, notes); + } + if (result != ENOENT) + return result; + + /* Find the ELF file for the running kernel and dwfl_report_elf it. */ + return report_kernel (dwfl, NULL, NULL); +} +INTDEF (dwfl_linux_kernel_report_kernel) + + +/* Dwfl_Callbacks.find_elf for the running Linux kernel and its modules. */ + +int +dwfl_linux_kernel_find_elf (Dwfl_Module *mod, + void **userdata __attribute__ ((unused)), + const char *module_name, + Dwarf_Addr base __attribute__ ((unused)), + char **file_name, Elf **elfp) +{ + if (mod->build_id_len > 0) + { + int fd = INTUSE(dwfl_build_id_find_elf) (mod, NULL, NULL, 0, + file_name, elfp); + if (fd >= 0 || mod->main.elf != NULL || errno != 0) + return fd; + } + + const char *release = kernel_release (); + if (release == NULL) + return errno; + + if (!strcmp (module_name, KERNEL_MODNAME)) + return find_kernel_elf (mod->dwfl, release, file_name); + + /* Do "find /lib/modules/`uname -r` -name MODULE_NAME.ko". */ + + char *modulesdir[] = { NULL, NULL }; + if (asprintf (&modulesdir[0], MODULEDIRFMT, release) < 0) + return -1; + + FTS *fts = fts_open (modulesdir, FTS_NOSTAT | FTS_LOGICAL, NULL); + if (fts == NULL) + { + free (modulesdir[0]); + return -1; + } + + size_t namelen = strlen (module_name); + + /* This is a kludge. There is no actual necessary relationship between + the name of the .ko file installed and the module name the kernel + knows it by when it's loaded. The kernel's only idea of the module + name comes from the name embedded in the object's magic + .gnu.linkonce.this_module section. + + In practice, these module names match the .ko file names except for + some using '_' and some using '-'. So our cheap kludge is to look for + two files when either a '_' or '-' appears in a module name, one using + only '_' and one only using '-'. */ + + char alternate_name[namelen + 1]; + inline bool subst_name (char from, char to) + { + const char *n = memchr (module_name, from, namelen); + if (n == NULL) + return false; + char *a = mempcpy (alternate_name, module_name, n - module_name); + *a++ = to; + ++n; + const char *p; + while ((p = memchr (n, from, namelen - (n - module_name))) != NULL) + { + a = mempcpy (a, n, p - n); + *a++ = to; + n = p + 1; + } + memcpy (a, n, namelen - (n - module_name) + 1); + return true; + } + if (!subst_name ('-', '_') && !subst_name ('_', '-')) + alternate_name[0] = '\0'; + + FTSENT *f; + int error = ENOENT; + while ((f = fts_read (fts)) != NULL) + { + /* Skip a "source" subtree, which tends to be large. + This insane hard-coding of names is what depmod does too. */ + if (f->fts_namelen == sizeof "source" - 1 + && !strcmp (f->fts_name, "source")) + { + fts_set (fts, f, FTS_SKIP); + continue; + } + + error = ENOENT; + switch (f->fts_info) + { + case FTS_F: + case FTS_SL: + case FTS_NSOK: + /* See if this file name is "MODULE_NAME.ko". */ + if (check_suffix (f, namelen) + && (!memcmp (f->fts_name, module_name, namelen) + || !memcmp (f->fts_name, alternate_name, namelen))) + { + int fd = open64 (f->fts_accpath, O_RDONLY); + *file_name = strdup (f->fts_path); + fts_close (fts); + free (modulesdir[0]); + if (fd < 0) + free (*file_name); + else if (*file_name == NULL) + { + close (fd); + fd = -1; + } + return fd; + } + break; + + case FTS_ERR: + case FTS_DNR: + case FTS_NS: + error = f->fts_errno; + break; + + case FTS_SLNONE: + default: + break; + } + } + + fts_close (fts); + free (modulesdir[0]); + errno = error; + return -1; +} +INTDEF (dwfl_linux_kernel_find_elf) + + +/* Dwfl_Callbacks.section_address for kernel modules in the running Linux. + We read the information from /sys/module directly. */ + +int +dwfl_linux_kernel_module_section_address +(Dwfl_Module *mod __attribute__ ((unused)), + void **userdata __attribute__ ((unused)), + const char *modname, Dwarf_Addr base __attribute__ ((unused)), + const char *secname, Elf32_Word shndx __attribute__ ((unused)), + const GElf_Shdr *shdr __attribute__ ((unused)), + Dwarf_Addr *addr) +{ + char *sysfile; + if (asprintf (&sysfile, SECADDRDIRFMT "%s", modname, secname) < 0) + return DWARF_CB_ABORT; + + FILE *f = fopen (sysfile, "r"); + free (sysfile); + + if (f == NULL) + { + if (errno == ENOENT) + { + /* The .modinfo and .data.percpu sections are never kept + loaded in the kernel. If the kernel was compiled without + CONFIG_MODULE_UNLOAD, the .exit.* sections are not + actually loaded at all. + + Setting *ADDR to -1 tells the caller this section is + actually absent from memory. */ + + if (!strcmp (secname, ".modinfo") + || !strcmp (secname, ".data.percpu") + || !strncmp (secname, ".exit", 5)) + { + *addr = (Dwarf_Addr) -1l; + return DWARF_CB_OK; + } + + /* The goofy PPC64 module_frob_arch_sections function tweaks + the section names as a way to control other kernel code's + behavior, and this cruft leaks out into the /sys information. + The file name for ".init*" may actually look like "_init*". */ + + const bool is_init = !strncmp (secname, ".init", 5); + if (is_init) + { + if (asprintf (&sysfile, SECADDRDIRFMT "_%s", + modname, &secname[1]) < 0) + return ENOMEM; + f = fopen (sysfile, "r"); + free (sysfile); + if (f != NULL) + goto ok; + } + + /* The kernel truncates section names to MODULE_SECT_NAME_LEN - 1. + In case that size increases in the future, look for longer + truncated names first. */ + size_t namelen = strlen (secname); + if (namelen >= MODULE_SECT_NAME_LEN) + { + int len = asprintf (&sysfile, SECADDRDIRFMT "%s", + modname, secname); + if (len < 0) + return DWARF_CB_ABORT; + char *end = sysfile + len; + do + { + *--end = '\0'; + f = fopen (sysfile, "r"); + if (is_init && f == NULL && errno == ENOENT) + { + sysfile[len - namelen] = '_'; + f = fopen (sysfile, "r"); + sysfile[len - namelen] = '.'; + } + } + while (f == NULL && errno == ENOENT + && end - &sysfile[len - namelen] >= MODULE_SECT_NAME_LEN); + free (sysfile); + + if (f != NULL) + goto ok; + } + } + + return DWARF_CB_ABORT; + } + + ok: + (void) __fsetlocking (f, FSETLOCKING_BYCALLER); + + int result = (fscanf (f, "%" PRIx64 "\n", addr) == 1 ? 0 + : ferror_unlocked (f) ? errno : ENOEXEC); + fclose (f); + + if (result == 0) + return DWARF_CB_OK; + + errno = result; + return DWARF_CB_ABORT; +} +INTDEF (dwfl_linux_kernel_module_section_address) + +int +dwfl_linux_kernel_report_modules (Dwfl *dwfl) +{ + FILE *f = fopen (MODULELIST, "r"); + if (f == NULL) + return errno; + + (void) __fsetlocking (f, FSETLOCKING_BYCALLER); + + int result = 0; + Dwarf_Addr modaddr; + unsigned long int modsz; + char modname[128]; + char *line = NULL; + size_t linesz = 0; + /* We can't just use fscanf here because it's not easy to distinguish \n + from other whitespace so as to take the optional word following the + address but always stop at the end of the line. */ + while (getline (&line, &linesz, f) > 0 + && sscanf (line, "%128s %lu %*s %*s %*s %" PRIx64 " %*s\n", + modname, &modsz, &modaddr) == 3) + { + Dwfl_Module *mod = INTUSE(dwfl_report_module) (dwfl, modname, + modaddr, modaddr + modsz); + if (mod == NULL) + { + result = -1; + break; + } + + result = check_module_notes (mod); + } + free (line); + + if (result == 0) + result = ferror_unlocked (f) ? errno : feof_unlocked (f) ? 0 : ENOEXEC; + + fclose (f); + + return result; +} +INTDEF (dwfl_linux_kernel_report_modules) diff --git a/3rdparty/elfutils/libdwfl/linux-pid-attach.c b/3rdparty/elfutils/libdwfl/linux-pid-attach.c new file mode 100644 index 0000000..ae71702 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/linux-pid-attach.c @@ -0,0 +1,475 @@ +/* Get Dwarf Frame state for target live PID process. + Copyright (C) 2013, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" +#include <sys/ptrace.h> +#include <sys/wait.h> +#include <dirent.h> +#include <sys/syscall.h> +#include <unistd.h> + +#ifndef MAX +# define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif + +#ifdef __linux__ + +static bool +linux_proc_pid_is_stopped (pid_t pid) +{ + char buffer[64]; + FILE *procfile; + bool retval, have_state; + + snprintf (buffer, sizeof (buffer), "/proc/%ld/status", (long) pid); + procfile = fopen (buffer, "r"); + if (procfile == NULL) + return false; + + have_state = false; + while (fgets (buffer, sizeof (buffer), procfile) != NULL) + if (strncmp (buffer, "State:", 6) == 0) + { + have_state = true; + break; + } + retval = (have_state && strstr (buffer, "T (stopped)") != NULL); + fclose (procfile); + return retval; +} + +bool +internal_function +__libdwfl_ptrace_attach (pid_t tid, bool *tid_was_stoppedp) +{ + if (ptrace (PTRACE_ATTACH, tid, NULL, NULL) != 0) + { + __libdwfl_seterrno (DWFL_E_ERRNO); + return false; + } + *tid_was_stoppedp = linux_proc_pid_is_stopped (tid); + if (*tid_was_stoppedp) + { + /* Make sure there is a SIGSTOP signal pending even when the process is + already State: T (stopped). Older kernels might fail to generate + a SIGSTOP notification in that case in response to our PTRACE_ATTACH + above. Which would make the waitpid below wait forever. So emulate + it. Since there can only be one SIGSTOP notification pending this is + safe. See also gdb/linux-nat.c linux_nat_post_attach_wait. */ + syscall (__NR_tkill, tid, SIGSTOP); + ptrace (PTRACE_CONT, tid, NULL, NULL); + } + for (;;) + { + int status; + if (waitpid (tid, &status, __WALL) != tid || !WIFSTOPPED (status)) + { + int saved_errno = errno; + ptrace (PTRACE_DETACH, tid, NULL, NULL); + errno = saved_errno; + __libdwfl_seterrno (DWFL_E_ERRNO); + return false; + } + if (WSTOPSIG (status) == SIGSTOP) + break; + if (ptrace (PTRACE_CONT, tid, NULL, + (void *) (uintptr_t) WSTOPSIG (status)) != 0) + { + int saved_errno = errno; + ptrace (PTRACE_DETACH, tid, NULL, NULL); + errno = saved_errno; + __libdwfl_seterrno (DWFL_E_ERRNO); + return false; + } + } + return true; +} + +static bool +pid_memory_read (Dwfl *dwfl, Dwarf_Addr addr, Dwarf_Word *result, void *arg) +{ + struct __libdwfl_pid_arg *pid_arg = arg; + pid_t tid = pid_arg->tid_attached; + assert (tid > 0); + Dwfl_Process *process = dwfl->process; + if (ebl_get_elfclass (process->ebl) == ELFCLASS64) + { +#if SIZEOF_LONG == 8 + errno = 0; + *result = ptrace (PTRACE_PEEKDATA, tid, (void *) (uintptr_t) addr, NULL); + return errno == 0; +#else /* SIZEOF_LONG != 8 */ + /* This should not happen. */ + return false; +#endif /* SIZEOF_LONG != 8 */ + } +#if SIZEOF_LONG == 8 + /* We do not care about reads unaliged to 4 bytes boundary. + But 0x...ffc read of 8 bytes could overrun a page. */ + bool lowered = (addr & 4) != 0; + if (lowered) + addr -= 4; +#endif /* SIZEOF_LONG == 8 */ + errno = 0; + *result = ptrace (PTRACE_PEEKDATA, tid, (void *) (uintptr_t) addr, NULL); + if (errno != 0) + return false; +#if SIZEOF_LONG == 8 +# if BYTE_ORDER == BIG_ENDIAN + if (! lowered) + *result >>= 32; +# else + if (lowered) + *result >>= 32; +# endif +#endif /* SIZEOF_LONG == 8 */ + *result &= 0xffffffff; + return true; +} + +static pid_t +pid_next_thread (Dwfl *dwfl __attribute__ ((unused)), void *dwfl_arg, + void **thread_argp) +{ + struct __libdwfl_pid_arg *pid_arg = dwfl_arg; + struct dirent *dirent; + /* Start fresh on first traversal. */ + if (*thread_argp == NULL) + rewinddir (pid_arg->dir); + do + { + errno = 0; + dirent = readdir (pid_arg->dir); + if (dirent == NULL) + { + if (errno != 0) + { + __libdwfl_seterrno (DWFL_E_ERRNO); + return -1; + } + return 0; + } + } + while (strcmp (dirent->d_name, ".") == 0 + || strcmp (dirent->d_name, "..") == 0); + char *end; + errno = 0; + long tidl = strtol (dirent->d_name, &end, 10); + if (errno != 0) + { + __libdwfl_seterrno (DWFL_E_ERRNO); + return -1; + } + pid_t tid = tidl; + if (tidl <= 0 || (end && *end) || tid != tidl) + { + __libdwfl_seterrno (DWFL_E_PARSE_PROC); + return -1; + } + *thread_argp = dwfl_arg; + return tid; +} + +/* Just checks that the thread id exists. */ +static bool +pid_getthread (Dwfl *dwfl __attribute__ ((unused)), pid_t tid, + void *dwfl_arg, void **thread_argp) +{ + *thread_argp = dwfl_arg; + if (kill (tid, 0) < 0) + { + __libdwfl_seterrno (DWFL_E_ERRNO); + return false; + } + return true; +} + +/* Implement the ebl_set_initial_registers_tid setfunc callback. */ + +static bool +pid_thread_state_registers_cb (int firstreg, unsigned nregs, + const Dwarf_Word *regs, void *arg) +{ + Dwfl_Thread *thread = (Dwfl_Thread *) arg; + if (firstreg < 0) + { + assert (firstreg == -1); + assert (nregs == 1); + INTUSE(dwfl_thread_state_register_pc) (thread, *regs); + return true; + } + assert (nregs > 0); + return INTUSE(dwfl_thread_state_registers) (thread, firstreg, nregs, regs); +} + +static bool +pid_set_initial_registers (Dwfl_Thread *thread, void *thread_arg) +{ + struct __libdwfl_pid_arg *pid_arg = thread_arg; + assert (pid_arg->tid_attached == 0); + pid_t tid = INTUSE(dwfl_thread_tid) (thread); + if (! pid_arg->assume_ptrace_stopped + && ! __libdwfl_ptrace_attach (tid, &pid_arg->tid_was_stopped)) + return false; + pid_arg->tid_attached = tid; + Dwfl_Process *process = thread->process; + Ebl *ebl = process->ebl; + return ebl_set_initial_registers_tid (ebl, tid, + pid_thread_state_registers_cb, thread); +} + +static void +pid_detach (Dwfl *dwfl __attribute__ ((unused)), void *dwfl_arg) +{ + struct __libdwfl_pid_arg *pid_arg = dwfl_arg; + closedir (pid_arg->dir); + free (pid_arg); +} + +void +internal_function +__libdwfl_ptrace_detach (pid_t tid, bool tid_was_stopped) +{ + /* This handling is needed only on older Linux kernels such as + 2.6.32-358.23.2.el6.ppc64. Later kernels such as + 3.11.7-200.fc19.x86_64 remember the T (stopped) state + themselves and no longer need to pass SIGSTOP during + PTRACE_DETACH. */ + ptrace (PTRACE_DETACH, tid, NULL, + (void *) (intptr_t) (tid_was_stopped ? SIGSTOP : 0)); +} + +static void +pid_thread_detach (Dwfl_Thread *thread, void *thread_arg) +{ + struct __libdwfl_pid_arg *pid_arg = thread_arg; + pid_t tid = INTUSE(dwfl_thread_tid) (thread); + assert (pid_arg->tid_attached == tid); + pid_arg->tid_attached = 0; + if (! pid_arg->assume_ptrace_stopped) + __libdwfl_ptrace_detach (tid, pid_arg->tid_was_stopped); +} + +static const Dwfl_Thread_Callbacks pid_thread_callbacks = +{ + pid_next_thread, + pid_getthread, + pid_memory_read, + pid_set_initial_registers, + pid_detach, + pid_thread_detach, +}; + +int +dwfl_linux_proc_attach (Dwfl *dwfl, pid_t pid, bool assume_ptrace_stopped) +{ + char buffer[36]; + FILE *procfile; + int err = 0; /* The errno to return and set for dwfl->attcherr. */ + + /* Make sure to report the actual PID (thread group leader) to + dwfl_attach_state. */ + snprintf (buffer, sizeof (buffer), "/proc/%ld/status", (long) pid); + procfile = fopen (buffer, "r"); + if (procfile == NULL) + { + err = errno; + fail: + if (dwfl->process == NULL && dwfl->attacherr == DWFL_E_NOERROR) + { + errno = err; + dwfl->attacherr = __libdwfl_canon_error (DWFL_E_ERRNO); + } + return err; + } + + char *line = NULL; + size_t linelen = 0; + while (getline (&line, &linelen, procfile) >= 0) + if (strncmp (line, "Tgid:", 5) == 0) + { + errno = 0; + char *endptr; + long val = strtol (&line[5], &endptr, 10); + if ((errno == ERANGE && val == LONG_MAX) + || *endptr != '\n' || val < 0 || val != (pid_t) val) + pid = 0; + else + pid = (pid_t) val; + break; + } + free (line); + fclose (procfile); + + if (pid == 0) + { + err = ESRCH; + goto fail; + } + + char dirname[64]; + int i = snprintf (dirname, sizeof (dirname), "/proc/%ld/task", (long) pid); + assert (i > 0 && i < (ssize_t) sizeof (dirname) - 1); + DIR *dir = opendir (dirname); + if (dir == NULL) + { + err = errno; + goto fail; + } + struct __libdwfl_pid_arg *pid_arg = malloc (sizeof *pid_arg); + if (pid_arg == NULL) + { + closedir (dir); + err = ENOMEM; + goto fail; + } + pid_arg->dir = dir; + pid_arg->tid_attached = 0; + pid_arg->assume_ptrace_stopped = assume_ptrace_stopped; + if (! INTUSE(dwfl_attach_state) (dwfl, NULL, pid, &pid_thread_callbacks, + pid_arg)) + { + closedir (dir); + free (pid_arg); + return -1; + } + return 0; +} +INTDEF (dwfl_linux_proc_attach) + +struct __libdwfl_pid_arg * +internal_function +__libdwfl_get_pid_arg (Dwfl *dwfl) +{ + if (dwfl != NULL && dwfl->process != NULL + && dwfl->process->callbacks == &pid_thread_callbacks) + return (struct __libdwfl_pid_arg *) dwfl->process->callbacks_arg; + + return NULL; +} + +#else /* __linux__ */ + +static pid_t +pid_next_thread (Dwfl *dwfl __attribute__ ((unused)), + void *dwfl_arg __attribute__ ((unused)), + void **thread_argp __attribute__ ((unused))) +{ + errno = ENOSYS; + __libdwfl_seterrno (DWFL_E_ERRNO); + return -1; +} + +static bool +pid_getthread (Dwfl *dwfl __attribute__ ((unused)), + pid_t tid __attribute__ ((unused)), + void *dwfl_arg __attribute__ ((unused)), + void **thread_argp __attribute__ ((unused))) +{ + errno = ENOSYS; + __libdwfl_seterrno (DWFL_E_ERRNO); + return false; +} + +bool +internal_function +__libdwfl_ptrace_attach (pid_t tid __attribute__ ((unused)), + bool *tid_was_stoppedp __attribute__ ((unused))) +{ + errno = ENOSYS; + __libdwfl_seterrno (DWFL_E_ERRNO); + return false; +} + +static bool +pid_memory_read (Dwfl *dwfl __attribute__ ((unused)), + Dwarf_Addr addr __attribute__ ((unused)), + Dwarf_Word *result __attribute__ ((unused)), + void *arg __attribute__ ((unused))) +{ + errno = ENOSYS; + __libdwfl_seterrno (DWFL_E_ERRNO); + return false; +} + +static bool +pid_set_initial_registers (Dwfl_Thread *thread __attribute__ ((unused)), + void *thread_arg __attribute__ ((unused))) +{ + errno = ENOSYS; + __libdwfl_seterrno (DWFL_E_ERRNO); + return false; +} + +static void +pid_detach (Dwfl *dwfl __attribute__ ((unused)), + void *dwfl_arg __attribute__ ((unused))) +{ +} + +void +internal_function +__libdwfl_ptrace_detach (pid_t tid __attribute__ ((unused)), + bool tid_was_stopped __attribute__ ((unused))) +{ +} + +static void +pid_thread_detach (Dwfl_Thread *thread __attribute__ ((unused)), + void *thread_arg __attribute__ ((unused))) +{ +} + +static const Dwfl_Thread_Callbacks pid_thread_callbacks = +{ + pid_next_thread, + pid_getthread, + pid_memory_read, + pid_set_initial_registers, + pid_detach, + pid_thread_detach, +}; + +int +dwfl_linux_proc_attach (Dwfl *dwfl __attribute__ ((unused)), + pid_t pid __attribute__ ((unused)), + bool assume_ptrace_stopped __attribute__ ((unused))) +{ + return ENOSYS; +} +INTDEF (dwfl_linux_proc_attach) + +struct __libdwfl_pid_arg * +internal_function +__libdwfl_get_pid_arg (Dwfl *dwfl __attribute__ ((unused))) +{ + return NULL; +} + +#endif /* ! __linux __ */ + diff --git a/3rdparty/elfutils/libdwfl/linux-proc-maps.c b/3rdparty/elfutils/libdwfl/linux-proc-maps.c new file mode 100644 index 0000000..d085834 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/linux-proc-maps.c @@ -0,0 +1,422 @@ +/* Standard libdwfl callbacks for debugging a live Linux process. + Copyright (C) 2005-2010, 2013, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" +#include <inttypes.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <stdio.h> +#include <stdio_ext.h> +#include <stdbool.h> +#include <string.h> +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> +#include <assert.h> +#include <endian.h> +#include "system.h" + + +#define PROCMAPSFMT "/proc/%d/maps" +#define PROCMEMFMT "/proc/%d/mem" +#define PROCAUXVFMT "/proc/%d/auxv" +#define PROCEXEFMT "/proc/%d/exe" + + +/* Return ELFCLASS64 or ELFCLASS32 for the main ELF executable. Return + ELFCLASSNONE for an error. */ + +static unsigned char +get_pid_class (pid_t pid) +{ + char *fname; + if (asprintf (&fname, PROCEXEFMT, pid) < 0) + return ELFCLASSNONE; + + int fd = open64 (fname, O_RDONLY); + free (fname); + if (fd < 0) + return ELFCLASSNONE; + + unsigned char buf[EI_CLASS + 1]; + ssize_t nread = pread_retry (fd, &buf, sizeof buf, 0); + close (fd); + if (nread != sizeof buf || buf[EI_MAG0] != ELFMAG0 + || buf[EI_MAG1] != ELFMAG1 || buf[EI_MAG2] != ELFMAG2 + || buf[EI_MAG3] != ELFMAG3 + || (buf[EI_CLASS] != ELFCLASS64 && buf[EI_CLASS] != ELFCLASS32)) + return ELFCLASSNONE; + + return buf[EI_CLASS]; +} + +/* Search /proc/PID/auxv for the AT_SYSINFO_EHDR tag. + + It would be easiest to call get_pid_class and parse everything according to + the 32-bit or 64-bit class. But this would bring the overhead of syscalls + to open and read the "/proc/%d/exe" file. + + Therefore this function tries to parse the "/proc/%d/auxv" content both + ways, as if it were the 32-bit format and also if it were the 64-bit format. + Only if it gives some valid data in both cases get_pid_class gets called. + In most cases only one of the format bit sizes gives valid data and the + get_pid_class call overhead can be saved. */ + +static int +grovel_auxv (pid_t pid, Dwfl *dwfl, GElf_Addr *sysinfo_ehdr) +{ + char *fname; + if (asprintf (&fname, PROCAUXVFMT, pid) < 0) + return ENOMEM; + + int fd = open64 (fname, O_RDONLY); + free (fname); + if (fd < 0) + return errno == ENOENT ? 0 : errno; + + GElf_Addr sysinfo_ehdr64 = 0; + GElf_Addr sysinfo_ehdr32 = 0; + GElf_Addr segment_align64 = dwfl->segment_align; + GElf_Addr segment_align32 = dwfl->segment_align; + off_t offset = 0; + ssize_t nread; + union + { + Elf64_auxv_t a64[64]; + Elf32_auxv_t a32[128]; + } d; + do + { + eu_static_assert (sizeof d.a64 == sizeof d.a32); + nread = pread_retry (fd, d.a64, sizeof d.a64, offset); + if (nread < 0) + { + int ret = errno; + close (fd); + return ret; + } + for (size_t a32i = 0; a32i < nread / sizeof d.a32[0]; a32i++) + { + const Elf32_auxv_t *a32 = d.a32 + a32i; + switch (a32->a_type) + { + case AT_SYSINFO_EHDR: + sysinfo_ehdr32 = a32->a_un.a_val; + break; + case AT_PAGESZ: + segment_align32 = a32->a_un.a_val; + break; + } + } + for (size_t a64i = 0; a64i < nread / sizeof d.a64[0]; a64i++) + { + const Elf64_auxv_t *a64 = d.a64 + a64i; + switch (a64->a_type) + { + case AT_SYSINFO_EHDR: + sysinfo_ehdr64 = a64->a_un.a_val; + break; + case AT_PAGESZ: + segment_align64 = a64->a_un.a_val; + break; + } + } + offset += nread; + } + while (nread == sizeof d.a64); + + close (fd); + + bool valid64 = sysinfo_ehdr64 != 0 || segment_align64 != dwfl->segment_align; + bool valid32 = sysinfo_ehdr32 != 0 || segment_align32 != dwfl->segment_align; + + unsigned char pid_class = ELFCLASSNONE; + if (valid64 && valid32) + pid_class = get_pid_class (pid); + + if (pid_class == ELFCLASS64 || (valid64 && ! valid32)) + { + *sysinfo_ehdr = sysinfo_ehdr64; + dwfl->segment_align = segment_align64; + return 0; + } + if (pid_class == ELFCLASS32 || (! valid64 && valid32)) + { + *sysinfo_ehdr = sysinfo_ehdr32; + dwfl->segment_align = segment_align32; + return 0; + } + return ENOEXEC; +} + +static int +proc_maps_report (Dwfl *dwfl, FILE *f, GElf_Addr sysinfo_ehdr, pid_t pid) +{ + unsigned int last_dmajor = -1, last_dminor = -1; + uint64_t last_ino = -1; + char *last_file = NULL; + Dwarf_Addr low = 0, high = 0; + + inline bool report (void) + { + if (last_file != NULL) + { + Dwfl_Module *mod = INTUSE(dwfl_report_module) (dwfl, last_file, + low, high); + free (last_file); + last_file = NULL; + if (unlikely (mod == NULL)) + return true; + } + return false; + } + + char *line = NULL; + size_t linesz; + ssize_t len; + while ((len = getline (&line, &linesz, f)) > 0) + { + if (line[len - 1] == '\n') + line[len - 1] = '\0'; + + Dwarf_Addr start, end, offset; + unsigned int dmajor, dminor; + uint64_t ino; + int nread = -1; + if (sscanf (line, "%" PRIx64 "-%" PRIx64 " %*s %" PRIx64 + " %x:%x %" PRIi64 " %n", + &start, &end, &offset, &dmajor, &dminor, &ino, &nread) < 6 + || nread <= 0) + { + free (line); + return ENOEXEC; + } + + /* If this is the special mapping AT_SYSINFO_EHDR pointed us at, + report the last one and then this special one. */ + if (start == sysinfo_ehdr && start != 0) + { + if (report ()) + { + bad_report: + free (line); + return -1; + } + + low = start; + high = end; + if (asprintf (&last_file, "[vdso: %d]", (int) pid) < 0 + || report ()) + goto bad_report; + } + + char *file = line + nread + strspn (line + nread, " \t"); + if (file[0] != '/' || (ino == 0 && dmajor == 0 && dminor == 0)) + /* This line doesn't indicate a file mapping. */ + continue; + + if (last_file != NULL + && ino == last_ino && dmajor == last_dmajor && dminor == last_dminor) + { + /* This is another portion of the same file's mapping. */ + if (strcmp (last_file, file) != 0) + goto bad_report; + high = end; + } + else + { + /* This is a different file mapping. Report the last one. */ + if (report ()) + goto bad_report; + low = start; + high = end; + last_file = strdup (file); + last_ino = ino; + last_dmajor = dmajor; + last_dminor = dminor; + } + } + free (line); + + int result = ferror_unlocked (f) ? errno : feof_unlocked (f) ? 0 : ENOEXEC; + + /* Report the final one. */ + bool lose = report (); + + return result != 0 ? result : lose ? -1 : 0; +} + +int +dwfl_linux_proc_maps_report (Dwfl *dwfl, FILE *f) +{ + return proc_maps_report (dwfl, f, 0, 0); +} +INTDEF (dwfl_linux_proc_maps_report) + +int +dwfl_linux_proc_report (Dwfl *dwfl, pid_t pid) +{ + if (dwfl == NULL) + return -1; + + /* We'll notice the AT_SYSINFO_EHDR address specially when we hit it. */ + GElf_Addr sysinfo_ehdr = 0; + int result = grovel_auxv (pid, dwfl, &sysinfo_ehdr); + if (result != 0) + return result; + + char *fname; + if (asprintf (&fname, PROCMAPSFMT, pid) < 0) + return ENOMEM; + + FILE *f = fopen (fname, "r"); + free (fname); + if (f == NULL) + return errno; + + (void) __fsetlocking (f, FSETLOCKING_BYCALLER); + + result = proc_maps_report (dwfl, f, sysinfo_ehdr, pid); + + fclose (f); + + return result; +} +INTDEF (dwfl_linux_proc_report) + +static ssize_t +read_proc_memory (void *arg, void *data, GElf_Addr address, + size_t minread, size_t maxread) +{ + const int fd = *(const int *) arg; + ssize_t nread = pread64 (fd, data, maxread, (off64_t) address); + /* Some kernels don't actually let us do this read, ignore those errors. */ + if (nread < 0 && (errno == EINVAL || errno == EPERM)) + return 0; + if (nread > 0 && (size_t) nread < minread) + nread = 0; + return nread; +} + +extern Elf *elf_from_remote_memory (GElf_Addr ehdr_vma, + GElf_Xword pagesize, + GElf_Addr *loadbasep, + ssize_t (*read_memory) (void *arg, + void *data, + GElf_Addr address, + size_t minread, + size_t maxread), + void *arg); + + +/* Dwfl_Callbacks.find_elf */ + +int +dwfl_linux_proc_find_elf (Dwfl_Module *mod __attribute__ ((unused)), + void **userdata __attribute__ ((unused)), + const char *module_name, Dwarf_Addr base, + char **file_name, Elf **elfp) +{ + int pid = -1; + if (module_name[0] == '/') + { + /* When this callback is used together with dwfl_linux_proc_report + then we might see mappings of special character devices. Make + sure we only open and return regular files. Special devices + might hang on open or read. (deleted) files are super special. + The image might come from memory if we are attached. */ + struct stat sb; + if (stat (module_name, &sb) == -1 || (sb.st_mode & S_IFMT) != S_IFREG) + { + if (strcmp (strrchr (module_name, ' ') ?: "", " (deleted)") == 0) + pid = INTUSE(dwfl_pid) (mod->dwfl); + else + return -1; + } + + if (pid == -1) + { + int fd = open64 (module_name, O_RDONLY); + if (fd >= 0) + { + *file_name = strdup (module_name); + if (*file_name == NULL) + { + close (fd); + return ENOMEM; + } + } + return fd; + } + } + + if (pid != -1 || sscanf (module_name, "[vdso: %d]", &pid) == 1) + { + /* Special case for in-memory ELF image. */ + + bool detach = false; + bool tid_was_stopped = false; + struct __libdwfl_pid_arg *pid_arg = __libdwfl_get_pid_arg (mod->dwfl); + if (pid_arg != NULL && ! pid_arg->assume_ptrace_stopped) + { + /* If any thread is already attached we are fine. Read + through that thread. It doesn't have to be the main + thread pid. */ + pid_t tid = pid_arg->tid_attached; + if (tid != 0) + pid = tid; + else + detach = __libdwfl_ptrace_attach (pid, &tid_was_stopped); + } + + char *fname; + if (asprintf (&fname, PROCMEMFMT, pid) < 0) + goto detach; + + int fd = open64 (fname, O_RDONLY); + free (fname); + if (fd < 0) + goto detach; + + *elfp = elf_from_remote_memory (base, getpagesize (), NULL, + &read_proc_memory, &fd); + + close (fd); + + *file_name = NULL; + + detach: + if (detach) + __libdwfl_ptrace_detach (pid, tid_was_stopped); + return -1; + } + + return -1; +} +INTDEF (dwfl_linux_proc_find_elf) diff --git a/3rdparty/elfutils/libdwfl/offline.c b/3rdparty/elfutils/libdwfl/offline.c new file mode 100644 index 0000000..982ceab --- /dev/null +++ b/3rdparty/elfutils/libdwfl/offline.c @@ -0,0 +1,311 @@ +/* Recover relocatibility for addresses computed from debug information. + Copyright (C) 2005-2009, 2012 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" +#include <fcntl.h> +#include <unistd.h> + +/* Since dwfl_report_elf lays out the sections already, this will only be + called when the section headers of the debuginfo file are being + consulted instead, or for the section placed at 0. With binutils + strip-to-debug, the symbol table is in the debuginfo file and relocation + looks there. */ +int +dwfl_offline_section_address (Dwfl_Module *mod, + void **userdata __attribute__ ((unused)), + const char *modname __attribute__ ((unused)), + Dwarf_Addr base __attribute__ ((unused)), + const char *secname __attribute__ ((unused)), + Elf32_Word shndx, + const GElf_Shdr *shdr __attribute__ ((unused)), + Dwarf_Addr *addr) +{ + assert (mod->e_type == ET_REL); + assert (shdr->sh_addr == 0); + assert (shdr->sh_flags & SHF_ALLOC); + assert (shndx != 0); + + if (mod->debug.elf == NULL) + /* We are only here because sh_addr is zero even though layout is complete. + The first section in the first file under -e is placed at 0. */ + return 0; + + /* The section numbers might not match between the two files. + The best we can rely on is the order of SHF_ALLOC sections. */ + + Elf_Scn *ourscn = elf_getscn (mod->debug.elf, shndx); + Elf_Scn *scn = NULL; + uint_fast32_t skip_alloc = 0; + while ((scn = elf_nextscn (mod->debug.elf, scn)) != ourscn) + { + assert (scn != NULL); + GElf_Shdr shdr_mem; + GElf_Shdr *sh = gelf_getshdr (scn, &shdr_mem); + if (unlikely (sh == NULL)) + return -1; + if (sh->sh_flags & SHF_ALLOC) + ++skip_alloc; + } + + scn = NULL; + while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL) + { + GElf_Shdr shdr_mem; + GElf_Shdr *main_shdr = gelf_getshdr (scn, &shdr_mem); + if (unlikely (main_shdr == NULL)) + return -1; + if ((main_shdr->sh_flags & SHF_ALLOC) && skip_alloc-- == 0) + { + assert (main_shdr->sh_flags == shdr->sh_flags); + *addr = main_shdr->sh_addr; + return 0; + } + } + + /* This should never happen. */ + return -1; +} +INTDEF (dwfl_offline_section_address) + +/* Forward declarations. */ +static Dwfl_Module *process_elf (Dwfl *dwfl, const char *name, + const char *file_name, int fd, Elf *elf); +static Dwfl_Module *process_archive (Dwfl *dwfl, const char *name, + const char *file_name, int fd, Elf *elf, + int (*predicate) (const char *module, + const char *file)); + +/* Report one module for an ELF file, or many for an archive. + Always consumes ELF and FD. */ +static Dwfl_Module * +process_file (Dwfl *dwfl, const char *name, const char *file_name, int fd, + Elf *elf, int (*predicate) (const char *module, + const char *file)) +{ + switch (elf_kind (elf)) + { + default: + case ELF_K_NONE: + __libdwfl_seterrno (elf == NULL ? DWFL_E_LIBELF : DWFL_E_BADELF); + return NULL; + + case ELF_K_ELF: + return process_elf (dwfl, name, file_name, fd, elf); + + case ELF_K_AR: + return process_archive (dwfl, name, file_name, fd, elf, predicate); + } +} + +/* Report the open ELF file as a module. Always consumes ELF and FD. */ +static Dwfl_Module * +process_elf (Dwfl *dwfl, const char *name, const char *file_name, int fd, + Elf *elf) +{ + Dwfl_Module *mod = __libdwfl_report_elf (dwfl, name, file_name, fd, elf, + dwfl->offline_next_address, true, + false); + if (mod != NULL) + { + /* If this is an ET_EXEC file with fixed addresses, the address range + it consumed may or may not intersect with the arbitrary range we + will use for relocatable modules. Make sure we always use a free + range for the offline allocations. If this module did use + offline_next_address, it may have rounded it up for the module's + alignment requirements. */ + if ((dwfl->offline_next_address >= mod->low_addr + || mod->low_addr - dwfl->offline_next_address < OFFLINE_REDZONE) + && dwfl->offline_next_address < mod->high_addr + OFFLINE_REDZONE) + dwfl->offline_next_address = mod->high_addr + OFFLINE_REDZONE; + + /* Don't keep the file descriptor around. */ + if (mod->main.fd != -1 && elf_cntl (mod->main.elf, ELF_C_FDREAD) == 0) + { + close (mod->main.fd); + mod->main.fd = -1; + } + } + + return mod; +} + +/* Always consumes MEMBER. Returns elf_next result on success. + For errors returns ELF_C_NULL with *MOD set to null. */ +static Elf_Cmd +process_archive_member (Dwfl *dwfl, const char *name, const char *file_name, + int (*predicate) (const char *module, const char *file), + int fd, Elf *member, Dwfl_Module **mod) +{ + const Elf_Arhdr *h = elf_getarhdr (member); + if (unlikely (h == NULL)) + { + __libdwfl_seterrno (DWFL_E_LIBELF); + fail: + elf_end (member); + *mod = NULL; + return ELF_C_NULL; + } + + if (!strcmp (h->ar_name, "/") || !strcmp (h->ar_name, "//") + || !strcmp (h->ar_name, "/SYM64/")) + { + skip:; + /* Skip this and go to the next. */ + Elf_Cmd result = elf_next (member); + elf_end (member); + return result; + } + + char *member_name; + if (unlikely (asprintf (&member_name, "%s(%s)", file_name, h->ar_name) < 0)) + { + nomem: + __libdwfl_seterrno (DWFL_E_NOMEM); + elf_end (member); + *mod = NULL; + return ELF_C_NULL; + } + + char *module_name = NULL; + if (name == NULL || name[0] == '\0') + name = h->ar_name; + else if (unlikely (asprintf (&module_name, "%s:%s", name, h->ar_name) < 0)) + { + free (member_name); + goto nomem; + } + else + name = module_name; + + if (predicate != NULL) + { + /* Let the predicate decide whether to use this one. */ + int want = (*predicate) (name, member_name); + if (want <= 0) + { + free (member_name); + free (module_name); + if (unlikely (want < 0)) + { + __libdwfl_seterrno (DWFL_E_CB); + goto fail; + } + goto skip; + } + } + + /* We let __libdwfl_report_elf cache the fd in mod->main.fd, + though it's the same fd for all the members. + On module teardown we will close it only on the last Elf reference. */ + *mod = process_file (dwfl, name, member_name, fd, member, predicate); + free (member_name); + free (module_name); + + if (*mod == NULL) /* process_file called elf_end. */ + return ELF_C_NULL; + + /* Advance the archive-reading offset for the next iteration. */ + return elf_next (member); +} + +/* Report each member of the archive as its own module. */ +static Dwfl_Module * +process_archive (Dwfl *dwfl, const char *name, const char *file_name, int fd, + Elf *archive, + int (*predicate) (const char *module, const char *file)) + +{ + Dwfl_Module *mod = NULL; + Elf *member = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, archive); + if (unlikely (member == NULL)) /* Empty archive. */ + { + __libdwfl_seterrno (DWFL_E_BADELF); + return NULL; + } + + while (process_archive_member (dwfl, name, file_name, predicate, + fd, member, &mod) != ELF_C_NULL) + member = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, archive); + + /* We can drop the archive Elf handle even if we're still using members + in live modules. When the last module's elf_end on a member returns + zero, that module will close FD. If no modules survived the predicate, + we are all done with the file right here. */ + if (mod != NULL /* If no modules, caller will clean up. */ + && elf_end (archive) == 0) + close (fd); + + return mod; +} + +Dwfl_Module * +internal_function +__libdwfl_report_offline (Dwfl *dwfl, const char *name, + const char *file_name, int fd, bool closefd, + int (*predicate) (const char *module, + const char *file)) +{ + Elf *elf; + Dwfl_Error error = __libdw_open_file (&fd, &elf, closefd, true); + if (error != DWFL_E_NOERROR) + { + __libdwfl_seterrno (error); + return NULL; + } + Dwfl_Module *mod = process_file (dwfl, name, file_name, fd, elf, predicate); + if (mod == NULL) + { + elf_end (elf); + if (closefd) + close (fd); + } + return mod; +} + +Dwfl_Module * +dwfl_report_offline (Dwfl *dwfl, const char *name, + const char *file_name, int fd) +{ + if (dwfl == NULL) + return NULL; + + bool closefd = false; + if (fd < 0) + { + closefd = true; + fd = open64 (file_name, O_RDONLY); + if (fd < 0) + { + __libdwfl_seterrno (DWFL_E_ERRNO); + return NULL; + } + } + + return __libdwfl_report_offline (dwfl, name, file_name, fd, closefd, NULL); +} +INTDEF (dwfl_report_offline) diff --git a/3rdparty/elfutils/libdwfl/open.c b/3rdparty/elfutils/libdwfl/open.c new file mode 100644 index 0000000..40aac38 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/open.c @@ -0,0 +1,182 @@ +/* Decompression support for libdwfl: zlib (gzip) and/or bzlib (bzip2). + Copyright (C) 2009 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "../libelf/libelfP.h" +#undef _ +#include "libdwflP.h" + +#include <unistd.h> + +#if !USE_ZLIB +# define __libdw_gunzip(...) DWFL_E_BADELF +#endif + +#if !USE_BZLIB +# define __libdw_bunzip2(...) DWFL_E_BADELF +#endif + +#if !USE_LZMA +# define __libdw_unlzma(...) DWFL_E_BADELF +#endif + +/* Consumes and replaces *ELF only on success. */ +static Dwfl_Error +decompress (int fd __attribute__ ((unused)), Elf **elf) +{ + Dwfl_Error error = DWFL_E_BADELF; + void *buffer = NULL; + size_t size = 0; + +#if USE_ZLIB || USE_BZLIB || USE_LZMA + const off64_t offset = (*elf)->start_offset; + void *const mapped = ((*elf)->map_address == NULL ? NULL + : (*elf)->map_address + offset); + const size_t mapped_size = (*elf)->maximum_size; + if (mapped_size == 0) + return error; + + error = __libdw_gunzip (fd, offset, mapped, mapped_size, &buffer, &size); + if (error == DWFL_E_BADELF) + error = __libdw_bunzip2 (fd, offset, mapped, mapped_size, &buffer, &size); + if (error == DWFL_E_BADELF) + error = __libdw_unlzma (fd, offset, mapped, mapped_size, &buffer, &size); +#endif + + if (error == DWFL_E_NOERROR) + { + if (unlikely (size == 0)) + { + error = DWFL_E_BADELF; + free (buffer); + } + else + { + Elf *memelf = elf_memory (buffer, size); + if (memelf == NULL) + { + error = DWFL_E_LIBELF; + free (buffer); + } + else + { + memelf->flags |= ELF_F_MALLOCED; + elf_end (*elf); + *elf = memelf; + } + } + } + else + free (buffer); + + return error; +} + +static Dwfl_Error +what_kind (int fd, Elf **elfp, Elf_Kind *kind, bool *close_fd) +{ + Dwfl_Error error = DWFL_E_NOERROR; + *kind = elf_kind (*elfp); + if (unlikely (*kind == ELF_K_NONE)) + { + if (unlikely (*elfp == NULL)) + error = DWFL_E_LIBELF; + else + { + error = decompress (fd, elfp); + if (error == DWFL_E_NOERROR) + { + *close_fd = true; + *kind = elf_kind (*elfp); + } + } + } + return error; +} + +Dwfl_Error internal_function +__libdw_open_file (int *fdp, Elf **elfp, bool close_on_fail, bool archive_ok) +{ + bool close_fd = false; + + Elf *elf = elf_begin (*fdp, ELF_C_READ_MMAP_PRIVATE, NULL); + + Elf_Kind kind; + Dwfl_Error error = what_kind (*fdp, &elf, &kind, &close_fd); + if (error == DWFL_E_BADELF) + { + /* It's not an ELF file or a compressed file. + See if it's an image with a header preceding the real file. */ + + off64_t offset = elf->start_offset; + error = __libdw_image_header (*fdp, &offset, + (elf->map_address == NULL ? NULL + : elf->map_address + offset), + elf->maximum_size); + if (error == DWFL_E_NOERROR) + { + /* Pure evil. libelf needs some better interfaces. */ + elf->kind = ELF_K_AR; + elf->state.ar.elf_ar_hdr.ar_name = "libdwfl is faking you out"; + elf->state.ar.elf_ar_hdr.ar_size = elf->maximum_size - offset; + elf->state.ar.offset = offset - sizeof (struct ar_hdr); + Elf *subelf = elf_begin (-1, ELF_C_READ_MMAP_PRIVATE, elf); + elf->kind = ELF_K_NONE; + if (unlikely (subelf == NULL)) + error = DWFL_E_LIBELF; + else + { + subelf->parent = NULL; + subelf->flags |= elf->flags & (ELF_F_MMAPPED | ELF_F_MALLOCED); + elf->flags &= ~(ELF_F_MMAPPED | ELF_F_MALLOCED); + elf_end (elf); + elf = subelf; + error = what_kind (*fdp, &elf, &kind, &close_fd); + } + } + } + + if (error == DWFL_E_NOERROR + && kind != ELF_K_ELF + && !(archive_ok && kind == ELF_K_AR)) + error = DWFL_E_BADELF; + + if (error != DWFL_E_NOERROR) + { + elf_end (elf); + elf = NULL; + } + + if (error == DWFL_E_NOERROR ? close_fd : close_on_fail) + { + close (*fdp); + *fdp = -1; + } + + *elfp = elf; + return error; +} diff --git a/3rdparty/elfutils/libdwfl/relocate.c b/3rdparty/elfutils/libdwfl/relocate.c new file mode 100644 index 0000000..e102e1e --- /dev/null +++ b/3rdparty/elfutils/libdwfl/relocate.c @@ -0,0 +1,683 @@ +/* Relocate debug information. + Copyright (C) 2005-2011, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" + +typedef uint8_t GElf_Byte; + +/* Adjust *VALUE to add the load address of the SHNDX section. + We update the section header in place to cache the result. */ + +Dwfl_Error +internal_function +__libdwfl_relocate_value (Dwfl_Module *mod, Elf *elf, size_t *shstrndx, + Elf32_Word shndx, GElf_Addr *value) +{ + /* No adjustment needed for section zero, it is never loaded. + Handle it first, just in case the ELF file has strange section + zero flags set. */ + if (shndx == 0) + return DWFL_E_NOERROR; + + Elf_Scn *refscn = elf_getscn (elf, shndx); + GElf_Shdr refshdr_mem, *refshdr = gelf_getshdr (refscn, &refshdr_mem); + if (refshdr == NULL) + return DWFL_E_LIBELF; + + if (refshdr->sh_addr == 0 && (refshdr->sh_flags & SHF_ALLOC)) + { + /* This is a loaded section. Find its actual + address and update the section header. */ + + if (*shstrndx == SHN_UNDEF + && unlikely (elf_getshdrstrndx (elf, shstrndx) < 0)) + return DWFL_E_LIBELF; + + const char *name = elf_strptr (elf, *shstrndx, refshdr->sh_name); + if (unlikely (name == NULL)) + return DWFL_E_LIBELF; + + if ((*mod->dwfl->callbacks->section_address) (MODCB_ARGS (mod), + name, shndx, refshdr, + &refshdr->sh_addr)) + return CBFAIL; + + if (refshdr->sh_addr == (Dwarf_Addr) -1l) + /* The callback indicated this section wasn't really loaded but we + don't really care. */ + refshdr->sh_addr = 0; /* Make no adjustment below. */ + + /* Update the in-core file's section header to show the final + load address (or unloadedness). This serves as a cache, + so we won't get here again for the same section. */ + if (likely (refshdr->sh_addr != 0) + && unlikely (! gelf_update_shdr (refscn, refshdr))) + return DWFL_E_LIBELF; + } + + if (refshdr->sh_flags & SHF_ALLOC) + /* Apply the adjustment. */ + *value += dwfl_adjusted_address (mod, refshdr->sh_addr); + + return DWFL_E_NOERROR; +} + + +/* Cache used by relocate_getsym. */ +struct reloc_symtab_cache +{ + Elf *symelf; + Elf_Data *symdata; + Elf_Data *symxndxdata; + Elf_Data *symstrdata; + size_t symshstrndx; + size_t strtabndx; +}; +#define RELOC_SYMTAB_CACHE(cache) \ + struct reloc_symtab_cache cache = \ + { NULL, NULL, NULL, NULL, SHN_UNDEF, SHN_UNDEF } + +/* This is just doing dwfl_module_getsym, except that we must always use + the symbol table in RELOCATED itself when it has one, not MOD->symfile. */ +static Dwfl_Error +relocate_getsym (Dwfl_Module *mod, + Elf *relocated, struct reloc_symtab_cache *cache, + int symndx, GElf_Sym *sym, GElf_Word *shndx) +{ + if (cache->symdata == NULL) + { + if (mod->symfile == NULL || mod->symfile->elf != relocated) + { + /* We have to look up the symbol table in the file we are + relocating, if it has its own. These reloc sections refer to + the symbol table in this file, and a symbol table in the main + file might not match. However, some tools did produce ET_REL + .debug files with relocs but no symtab of their own. */ + Elf_Scn *scn = NULL; + while ((scn = elf_nextscn (relocated, scn)) != NULL) + { + GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem); + if (shdr != NULL) + switch (shdr->sh_type) + { + default: + continue; + case SHT_SYMTAB: + cache->symelf = relocated; + cache->symdata = elf_getdata (scn, NULL); + cache->strtabndx = shdr->sh_link; + if (unlikely (cache->symdata == NULL)) + return DWFL_E_LIBELF; + break; + case SHT_SYMTAB_SHNDX: + cache->symxndxdata = elf_getdata (scn, NULL); + if (unlikely (cache->symxndxdata == NULL)) + return DWFL_E_LIBELF; + break; + } + if (cache->symdata != NULL && cache->symxndxdata != NULL) + break; + } + } + if (cache->symdata == NULL) + { + /* We might not have looked for a symbol table file yet, + when coming from __libdwfl_relocate_section. */ + if (unlikely (mod->symfile == NULL) + && unlikely (INTUSE(dwfl_module_getsymtab) (mod) < 0)) + return dwfl_errno (); + + /* The symbol table we have already cached is the one from + the file being relocated, so it's what we need. Or else + this is an ET_REL .debug file with no .symtab of its own; + the symbols refer to the section indices in the main file. */ + cache->symelf = mod->symfile->elf; + cache->symdata = mod->symdata; + cache->symxndxdata = mod->symxndxdata; + cache->symstrdata = mod->symstrdata; + } + } + + if (unlikely (gelf_getsymshndx (cache->symdata, cache->symxndxdata, + symndx, sym, shndx) == NULL)) + return DWFL_E_LIBELF; + + if (sym->st_shndx != SHN_XINDEX) + *shndx = sym->st_shndx; + + switch (sym->st_shndx) + { + case SHN_ABS: + case SHN_UNDEF: + return DWFL_E_NOERROR; + + case SHN_COMMON: + sym->st_value = 0; /* Value is size, not helpful. */ + return DWFL_E_NOERROR; + } + + return __libdwfl_relocate_value (mod, cache->symelf, &cache->symshstrndx, + *shndx, &sym->st_value); +} + +/* Handle an undefined symbol. We really only support ET_REL for Linux + kernel modules, and offline archives. The behavior of the Linux module + loader is very simple and easy to mimic. It only matches magically + exported symbols, and we match any defined symbols. But we get the same + answer except when the module's symbols are undefined and would prevent + it from being loaded. */ +static Dwfl_Error +resolve_symbol (Dwfl_Module *referer, struct reloc_symtab_cache *symtab, + GElf_Sym *sym, GElf_Word shndx) +{ + /* First we need its name. */ + if (sym->st_name != 0) + { + if (symtab->symstrdata == NULL) + { + /* Cache the strtab for this symtab. */ + assert (referer->symfile == NULL + || referer->symfile->elf != symtab->symelf); + symtab->symstrdata = elf_getdata (elf_getscn (symtab->symelf, + symtab->strtabndx), + NULL); + if (unlikely (symtab->symstrdata == NULL + || symtab->symstrdata->d_buf == NULL)) + return DWFL_E_LIBELF; + } + if (unlikely (sym->st_name >= symtab->symstrdata->d_size)) + return DWFL_E_BADSTROFF; + + const char *name = symtab->symstrdata->d_buf; + name += sym->st_name; + + for (Dwfl_Module *m = referer->dwfl->modulelist; m != NULL; m = m->next) + if (m != referer) + { + /* Get this module's symtab. + If we got a fresh error reading the table, report it. + If we just have no symbols in this module, no harm done. */ + if (m->symdata == NULL + && m->symerr == DWFL_E_NOERROR + && INTUSE(dwfl_module_getsymtab) (m) < 0 + && m->symerr != DWFL_E_NO_SYMTAB) + return m->symerr; + + for (size_t ndx = 1; ndx < m->syments; ++ndx) + { + sym = gelf_getsymshndx (m->symdata, m->symxndxdata, + ndx, sym, &shndx); + if (unlikely (sym == NULL)) + return DWFL_E_LIBELF; + if (sym->st_shndx != SHN_XINDEX) + shndx = sym->st_shndx; + + /* We are looking for a defined global symbol with a name. */ + if (shndx == SHN_UNDEF || shndx == SHN_COMMON + || GELF_ST_BIND (sym->st_info) == STB_LOCAL + || sym->st_name == 0) + continue; + + /* Get this candidate symbol's name. */ + if (unlikely (sym->st_name >= m->symstrdata->d_size)) + return DWFL_E_BADSTROFF; + const char *n = m->symstrdata->d_buf; + n += sym->st_name; + + /* Does the name match? */ + if (strcmp (name, n)) + continue; + + /* We found it! */ + if (shndx == SHN_ABS) /* XXX maybe should apply bias? */ + return DWFL_E_NOERROR; + + if (m->e_type != ET_REL) + { + sym->st_value = dwfl_adjusted_st_value (m, m->symfile->elf, + sym->st_value); + return DWFL_E_NOERROR; + } + + /* In an ET_REL file, the symbol table values are relative + to the section, not to the module's load base. */ + size_t symshstrndx = SHN_UNDEF; + return __libdwfl_relocate_value (m, m->symfile->elf, + &symshstrndx, + shndx, &sym->st_value); + } + } + } + + return DWFL_E_RELUNDEF; +} + +static Dwfl_Error +relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr, + size_t shstrndx, struct reloc_symtab_cache *reloc_symtab, + Elf_Scn *scn, GElf_Shdr *shdr, + Elf_Scn *tscn, bool debugscn, bool partial) +{ + /* First, fetch the name of the section these relocations apply to. */ + GElf_Shdr tshdr_mem; + GElf_Shdr *tshdr = gelf_getshdr (tscn, &tshdr_mem); + const char *tname = elf_strptr (relocated, shstrndx, tshdr->sh_name); + if (tname == NULL) + return DWFL_E_LIBELF; + + if (unlikely (tshdr->sh_type == SHT_NOBITS) || unlikely (tshdr->sh_size == 0)) + /* No contents to relocate. */ + return DWFL_E_NOERROR; + + if (debugscn && ! ebl_debugscn_p (mod->ebl, tname)) + /* This relocation section is not for a debugging section. + Nothing to do here. */ + return DWFL_E_NOERROR; + + /* Fetch the section data that needs the relocations applied. */ + Elf_Data *tdata = elf_rawdata (tscn, NULL); + if (tdata == NULL) + return DWFL_E_LIBELF; + + /* If either the section that needs the relocation applied, or the + section that the relocations come from overlap one of the ehdrs, + shdrs or phdrs data then we refuse to do the relocations. It + isn't illegal for ELF section data to overlap the header data, + but updating the (relocation) data might corrupt the in-memory + libelf headers causing strange corruptions or errors. */ + size_t ehsize = gelf_fsize (relocated, ELF_T_EHDR, 1, EV_CURRENT); + if (unlikely (shdr->sh_offset < ehsize + || tshdr->sh_offset < ehsize)) + return DWFL_E_BADELF; + + GElf_Off shdrs_start = ehdr->e_shoff; + size_t shnums; + if (elf_getshdrnum (relocated, &shnums) < 0) + return DWFL_E_LIBELF; + /* Overflows will have been checked by elf_getshdrnum/get|rawdata. */ + size_t shentsize = gelf_fsize (relocated, ELF_T_SHDR, 1, EV_CURRENT); + GElf_Off shdrs_end = shdrs_start + shnums * shentsize; + if (unlikely ((shdrs_start < shdr->sh_offset + shdr->sh_size + && shdr->sh_offset < shdrs_end) + || (shdrs_start < tshdr->sh_offset + tshdr->sh_size + && tshdr->sh_offset < shdrs_end))) + return DWFL_E_BADELF; + + GElf_Off phdrs_start = ehdr->e_phoff; + size_t phnums; + if (elf_getphdrnum (relocated, &phnums) < 0) + return DWFL_E_LIBELF; + if (phdrs_start != 0 && phnums != 0) + { + /* Overflows will have been checked by elf_getphdrnum/get|rawdata. */ + size_t phentsize = gelf_fsize (relocated, ELF_T_PHDR, 1, EV_CURRENT); + GElf_Off phdrs_end = phdrs_start + phnums * phentsize; + if (unlikely ((phdrs_start < shdr->sh_offset + shdr->sh_size + && shdr->sh_offset < phdrs_end) + || (phdrs_start < tshdr->sh_offset + tshdr->sh_size + && tshdr->sh_offset < phdrs_end))) + return DWFL_E_BADELF; + } + + /* Apply one relocation. Returns true for any invalid data. */ + Dwfl_Error relocate (GElf_Addr offset, const GElf_Sxword *addend, + int rtype, int symndx) + { + /* First see if this is a reloc we can handle. + If we are skipping it, don't bother resolving the symbol. */ + + if (unlikely (rtype == 0)) + /* In some odd situations, the linker can leave R_*_NONE relocs + behind. This is probably bogus ld -r behavior, but the only + cases it's known to appear in are harmless: DWARF data + referring to addresses in a section that has been discarded. + So we just pretend it's OK without further relocation. */ + return DWFL_E_NOERROR; + + Elf_Type type = ebl_reloc_simple_type (mod->ebl, rtype); + if (unlikely (type == ELF_T_NUM)) + return DWFL_E_BADRELTYPE; + + /* First, resolve the symbol to an absolute value. */ + GElf_Addr value; + + if (symndx == STN_UNDEF) + /* When strip removes a section symbol referring to a + section moved into the debuginfo file, it replaces + that symbol index in relocs with STN_UNDEF. We + don't actually need the symbol, because those relocs + are always references relative to the nonallocated + debugging sections, which start at zero. */ + value = 0; + else + { + GElf_Sym sym; + GElf_Word shndx; + Dwfl_Error error = relocate_getsym (mod, relocated, reloc_symtab, + symndx, &sym, &shndx); + if (unlikely (error != DWFL_E_NOERROR)) + return error; + + if (shndx == SHN_UNDEF || shndx == SHN_COMMON) + { + /* Maybe we can figure it out anyway. */ + error = resolve_symbol (mod, reloc_symtab, &sym, shndx); + if (error != DWFL_E_NOERROR + && !(error == DWFL_E_RELUNDEF && shndx == SHN_COMMON)) + return error; + } + + value = sym.st_value; + } + + /* These are the types we can relocate. */ +#define TYPES DO_TYPE (BYTE, Byte); DO_TYPE (HALF, Half); \ + DO_TYPE (WORD, Word); DO_TYPE (SWORD, Sword); \ + DO_TYPE (XWORD, Xword); DO_TYPE (SXWORD, Sxword) + size_t size; + switch (type) + { +#define DO_TYPE(NAME, Name) \ + case ELF_T_##NAME: \ + size = sizeof (GElf_##Name); \ + break + TYPES; +#undef DO_TYPE + default: + return DWFL_E_BADRELTYPE; + } + + if (offset > tdata->d_size || tdata->d_size - offset < size) + return DWFL_E_BADRELOFF; + +#define DO_TYPE(NAME, Name) GElf_##Name Name; + union { TYPES; } tmpbuf; +#undef DO_TYPE + Elf_Data tmpdata = + { + .d_type = type, + .d_buf = &tmpbuf, + .d_size = size, + .d_version = EV_CURRENT, + }; + Elf_Data rdata = + { + .d_type = type, + .d_buf = tdata->d_buf + offset, + .d_size = size, + .d_version = EV_CURRENT, + }; + + /* XXX check for overflow? */ + if (addend) + { + /* For the addend form, we have the value already. */ + value += *addend; + switch (type) + { +#define DO_TYPE(NAME, Name) \ + case ELF_T_##NAME: \ + tmpbuf.Name = value; \ + break + TYPES; +#undef DO_TYPE + default: + abort (); + } + } + else + { + /* Extract the original value and apply the reloc. */ + Elf_Data *d = gelf_xlatetom (relocated, &tmpdata, &rdata, + ehdr->e_ident[EI_DATA]); + if (d == NULL) + return DWFL_E_LIBELF; + assert (d == &tmpdata); + switch (type) + { +#define DO_TYPE(NAME, Name) \ + case ELF_T_##NAME: \ + tmpbuf.Name += (GElf_##Name) value; \ + break + TYPES; +#undef DO_TYPE + default: + abort (); + } + } + + /* Now convert the relocated datum back to the target + format. This will write into rdata.d_buf, which + points into the raw section data being relocated. */ + Elf_Data *s = gelf_xlatetof (relocated, &rdata, &tmpdata, + ehdr->e_ident[EI_DATA]); + if (s == NULL) + return DWFL_E_LIBELF; + assert (s == &rdata); + + /* We have applied this relocation! */ + return DWFL_E_NOERROR; + } + + /* Fetch the relocation section and apply each reloc in it. */ + Elf_Data *reldata = elf_getdata (scn, NULL); + if (reldata == NULL) + return DWFL_E_LIBELF; + + Dwfl_Error result = DWFL_E_NOERROR; + bool first_badreltype = true; + inline void check_badreltype (void) + { + if (first_badreltype) + { + first_badreltype = false; + if (ebl_get_elfmachine (mod->ebl) == EM_NONE) + /* This might be because ebl_openbackend failed to find + any libebl_CPU.so library. Diagnose that clearly. */ + result = DWFL_E_UNKNOWN_MACHINE; + } + } + + size_t sh_entsize + = gelf_fsize (relocated, shdr->sh_type == SHT_REL ? ELF_T_REL : ELF_T_RELA, + 1, EV_CURRENT); + size_t nrels = shdr->sh_size / sh_entsize; + size_t complete = 0; + if (shdr->sh_type == SHT_REL) + for (size_t relidx = 0; !result && relidx < nrels; ++relidx) + { + GElf_Rel rel_mem, *r = gelf_getrel (reldata, relidx, &rel_mem); + if (r == NULL) + return DWFL_E_LIBELF; + result = relocate (r->r_offset, NULL, + GELF_R_TYPE (r->r_info), + GELF_R_SYM (r->r_info)); + check_badreltype (); + if (partial) + switch (result) + { + case DWFL_E_NOERROR: + /* We applied the relocation. Elide it. */ + memset (&rel_mem, 0, sizeof rel_mem); + gelf_update_rel (reldata, relidx, &rel_mem); + ++complete; + break; + case DWFL_E_BADRELTYPE: + case DWFL_E_RELUNDEF: + /* We couldn't handle this relocation. Skip it. */ + result = DWFL_E_NOERROR; + break; + default: + break; + } + } + else + for (size_t relidx = 0; !result && relidx < nrels; ++relidx) + { + GElf_Rela rela_mem, *r = gelf_getrela (reldata, relidx, + &rela_mem); + if (r == NULL) + return DWFL_E_LIBELF; + result = relocate (r->r_offset, &r->r_addend, + GELF_R_TYPE (r->r_info), + GELF_R_SYM (r->r_info)); + check_badreltype (); + if (partial) + switch (result) + { + case DWFL_E_NOERROR: + /* We applied the relocation. Elide it. */ + memset (&rela_mem, 0, sizeof rela_mem); + gelf_update_rela (reldata, relidx, &rela_mem); + ++complete; + break; + case DWFL_E_BADRELTYPE: + case DWFL_E_RELUNDEF: + /* We couldn't handle this relocation. Skip it. */ + result = DWFL_E_NOERROR; + break; + default: + break; + } + } + + if (likely (result == DWFL_E_NOERROR)) + { + if (!partial || complete == nrels) + /* Mark this relocation section as being empty now that we have + done its work. This affects unstrip -R, so e.g. it emits an + empty .rela.debug_info along with a .debug_info that has + already been fully relocated. */ + nrels = 0; + else if (complete != 0) + { + /* We handled some of the relocations but not all. + We've zeroed out the ones we processed. + Now remove them from the section. */ + + size_t next = 0; + if (shdr->sh_type == SHT_REL) + for (size_t relidx = 0; relidx < nrels; ++relidx) + { + GElf_Rel rel_mem; + GElf_Rel *r = gelf_getrel (reldata, relidx, &rel_mem); + if (r->r_info != 0 || r->r_offset != 0) + { + if (next != relidx) + gelf_update_rel (reldata, next, r); + ++next; + } + } + else + for (size_t relidx = 0; relidx < nrels; ++relidx) + { + GElf_Rela rela_mem; + GElf_Rela *r = gelf_getrela (reldata, relidx, &rela_mem); + if (r->r_info != 0 || r->r_offset != 0 || r->r_addend != 0) + { + if (next != relidx) + gelf_update_rela (reldata, next, r); + ++next; + } + } + nrels = next; + } + + shdr->sh_size = reldata->d_size = nrels * sh_entsize; + gelf_update_shdr (scn, shdr); + } + + return result; +} + +Dwfl_Error +internal_function +__libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile, bool debug) +{ + assert (mod->e_type == ET_REL); + + GElf_Ehdr ehdr_mem; + const GElf_Ehdr *ehdr = gelf_getehdr (debugfile, &ehdr_mem); + if (ehdr == NULL) + return DWFL_E_LIBELF; + + size_t d_shstrndx; + if (elf_getshdrstrndx (debugfile, &d_shstrndx) < 0) + return DWFL_E_LIBELF; + + RELOC_SYMTAB_CACHE (reloc_symtab); + + /* Look at each section in the debuginfo file, and process the + relocation sections for debugging sections. */ + Dwfl_Error result = DWFL_E_NOERROR; + Elf_Scn *scn = NULL; + while (result == DWFL_E_NOERROR + && (scn = elf_nextscn (debugfile, scn)) != NULL) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + + if ((shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA) + && shdr->sh_size != 0) + { + /* It's a relocation section. */ + + Elf_Scn *tscn = elf_getscn (debugfile, shdr->sh_info); + if (unlikely (tscn == NULL)) + result = DWFL_E_LIBELF; + else + result = relocate_section (mod, debugfile, ehdr, d_shstrndx, + &reloc_symtab, scn, shdr, tscn, + debug, !debug); + } + } + + return result; +} + +Dwfl_Error +internal_function +__libdwfl_relocate_section (Dwfl_Module *mod, Elf *relocated, + Elf_Scn *relocscn, Elf_Scn *tscn, bool partial) +{ + GElf_Ehdr ehdr_mem; + GElf_Shdr shdr_mem; + + RELOC_SYMTAB_CACHE (reloc_symtab); + + size_t shstrndx; + if (elf_getshdrstrndx (relocated, &shstrndx) < 0) + return DWFL_E_LIBELF; + + return (__libdwfl_module_getebl (mod) + ?: relocate_section (mod, relocated, + gelf_getehdr (relocated, &ehdr_mem), shstrndx, + &reloc_symtab, + relocscn, gelf_getshdr (relocscn, &shdr_mem), + tscn, false, partial)); +} diff --git a/3rdparty/elfutils/libdwfl/segment.c b/3rdparty/elfutils/libdwfl/segment.c new file mode 100644 index 0000000..9276917 --- /dev/null +++ b/3rdparty/elfutils/libdwfl/segment.c @@ -0,0 +1,332 @@ +/* Manage address space lookup table for libdwfl. + Copyright (C) 2008, 2009, 2010, 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libdwflP.h" + +GElf_Addr +internal_function +__libdwfl_segment_start (Dwfl *dwfl, GElf_Addr start) +{ + if (dwfl->segment_align > 1) + start &= -dwfl->segment_align; + return start; +} + +GElf_Addr +internal_function +__libdwfl_segment_end (Dwfl *dwfl, GElf_Addr end) +{ + if (dwfl->segment_align > 1) + end = (end + dwfl->segment_align - 1) & -dwfl->segment_align; + return end; +} + +static bool +insert (Dwfl *dwfl, size_t i, GElf_Addr start, GElf_Addr end, int segndx) +{ + bool need_start = (i == 0 || dwfl->lookup_addr[i - 1] != start); + bool need_end = (i >= dwfl->lookup_elts || dwfl->lookup_addr[i + 1] != end); + size_t need = need_start + need_end; + if (need == 0) + return false; + + if (dwfl->lookup_alloc - dwfl->lookup_elts < need) + { + size_t n = dwfl->lookup_alloc == 0 ? 16 : dwfl->lookup_alloc * 2; + GElf_Addr *naddr = realloc (dwfl->lookup_addr, sizeof naddr[0] * n); + if (unlikely (naddr == NULL)) + return true; + int *nsegndx = realloc (dwfl->lookup_segndx, sizeof nsegndx[0] * n); + if (unlikely (nsegndx == NULL)) + { + if (naddr != dwfl->lookup_addr) + free (naddr); + return true; + } + dwfl->lookup_alloc = n; + dwfl->lookup_addr = naddr; + dwfl->lookup_segndx = nsegndx; + + if (dwfl->lookup_module != NULL) + { + /* Make sure this array is big enough too. */ + Dwfl_Module **old = dwfl->lookup_module; + dwfl->lookup_module = realloc (dwfl->lookup_module, + sizeof dwfl->lookup_module[0] * n); + if (unlikely (dwfl->lookup_module == NULL)) + { + free (old); + return true; + } + } + } + + if (unlikely (i < dwfl->lookup_elts)) + { + const size_t move = dwfl->lookup_elts - i; + memmove (&dwfl->lookup_addr[i + need], &dwfl->lookup_addr[i], + move * sizeof dwfl->lookup_addr[0]); + memmove (&dwfl->lookup_segndx[i + need], &dwfl->lookup_segndx[i], + move * sizeof dwfl->lookup_segndx[0]); + if (dwfl->lookup_module != NULL) + memmove (&dwfl->lookup_module[i + need], &dwfl->lookup_module[i], + move * sizeof dwfl->lookup_module[0]); + } + + if (need_start) + { + dwfl->lookup_addr[i] = start; + dwfl->lookup_segndx[i] = segndx; + if (dwfl->lookup_module != NULL) + dwfl->lookup_module[i] = NULL; + ++i; + } + else + dwfl->lookup_segndx[i - 1] = segndx; + + if (need_end) + { + dwfl->lookup_addr[i] = end; + dwfl->lookup_segndx[i] = -1; + if (dwfl->lookup_module != NULL) + dwfl->lookup_module[i] = NULL; + } + + dwfl->lookup_elts += need; + + return false; +} + +static int +lookup (Dwfl *dwfl, GElf_Addr address, int hint) +{ + if (hint >= 0 + && address >= dwfl->lookup_addr[hint] + && ((size_t) hint + 1 == dwfl->lookup_elts + || address < dwfl->lookup_addr[hint + 1])) + return hint; + + /* Do binary search on the array indexed by module load address. */ + size_t l = 0, u = dwfl->lookup_elts; + while (l < u) + { + size_t idx = (l + u) / 2; + if (address < dwfl->lookup_addr[idx]) + u = idx; + else + { + l = idx + 1; + if (l == dwfl->lookup_elts || address < dwfl->lookup_addr[l]) + return idx; + } + } + + return -1; +} + +static bool +reify_segments (Dwfl *dwfl) +{ + int hint = -1; + int highest = -1; + bool fixup = false; + for (Dwfl_Module *mod = dwfl->modulelist; mod != NULL; mod = mod->next) + if (! mod->gc) + { + const GElf_Addr start = __libdwfl_segment_start (dwfl, mod->low_addr); + const GElf_Addr end = __libdwfl_segment_end (dwfl, mod->high_addr); + bool resized = false; + + int idx = lookup (dwfl, start, hint); + if (unlikely (idx < 0)) + { + /* Module starts below any segment. Insert a low one. */ + if (unlikely (insert (dwfl, 0, start, end, -1))) + return true; + idx = 0; + resized = true; + } + else if (dwfl->lookup_addr[idx] > start) + { + /* The module starts in the middle of this segment. Split it. */ + if (unlikely (insert (dwfl, idx + 1, start, end, + dwfl->lookup_segndx[idx]))) + return true; + ++idx; + resized = true; + } + else if (dwfl->lookup_addr[idx] < start) + { + /* The module starts past the end of this segment. + Add a new one. */ + if (unlikely (insert (dwfl, idx + 1, start, end, -1))) + return true; + ++idx; + resized = true; + } + + if ((size_t) idx + 1 < dwfl->lookup_elts + && end < dwfl->lookup_addr[idx + 1]) + { + /* The module ends in the middle of this segment. Split it. */ + if (unlikely (insert (dwfl, idx + 1, + end, dwfl->lookup_addr[idx + 1], -1))) + return true; + resized = true; + } + + if (dwfl->lookup_module == NULL) + { + dwfl->lookup_module = calloc (dwfl->lookup_alloc, + sizeof dwfl->lookup_module[0]); + if (unlikely (dwfl->lookup_module == NULL)) + return true; + } + + /* Cache a backpointer in the module. */ + mod->segment = idx; + + /* Put MOD in the table for each segment that's inside it. */ + do + dwfl->lookup_module[idx++] = mod; + while ((size_t) idx < dwfl->lookup_elts + && dwfl->lookup_addr[idx] < end); + assert (dwfl->lookup_module[mod->segment] == mod); + + if (resized && idx - 1 >= highest) + /* Expanding the lookup tables invalidated backpointers + we've already stored. Reset those ones. */ + fixup = true; + + highest = idx - 1; + hint = (size_t) idx < dwfl->lookup_elts ? idx : -1; + } + + if (fixup) + /* Reset backpointer indices invalidated by table insertions. */ + for (size_t idx = 0; idx < dwfl->lookup_elts; ++idx) + if (dwfl->lookup_module[idx] != NULL) + dwfl->lookup_module[idx]->segment = idx; + + return false; +} + +int +dwfl_addrsegment (Dwfl *dwfl, Dwarf_Addr address, Dwfl_Module **mod) +{ + if (unlikely (dwfl == NULL)) + return -1; + + if (unlikely (dwfl->lookup_module == NULL) + && mod != NULL + && unlikely (reify_segments (dwfl))) + { + __libdwfl_seterrno (DWFL_E_NOMEM); + return -1; + } + + int idx = lookup (dwfl, address, -1); + if (likely (mod != NULL)) + { + if (unlikely (idx < 0) || unlikely (dwfl->lookup_module == NULL)) + *mod = NULL; + else + { + *mod = dwfl->lookup_module[idx]; + + /* If this segment does not have a module, but the address is + the upper boundary of the previous segment's module, use that. */ + if (*mod == NULL && idx > 0 && dwfl->lookup_addr[idx] == address) + { + *mod = dwfl->lookup_module[idx - 1]; + if (*mod != NULL && (*mod)->high_addr != address) + *mod = NULL; + } + } + } + + if (likely (idx >= 0)) + /* Translate internal segment table index to user segment index. */ + idx = dwfl->lookup_segndx[idx]; + + return idx; +} +INTDEF (dwfl_addrsegment) + +int +dwfl_report_segment (Dwfl *dwfl, int ndx, const GElf_Phdr *phdr, GElf_Addr bias, + const void *ident) +{ + if (dwfl == NULL) + return -1; + + if (ndx < 0) + ndx = dwfl->lookup_tail_ndx; + + if (phdr->p_align > 1 && (dwfl->segment_align <= 1 || + phdr->p_align < dwfl->segment_align)) + dwfl->segment_align = phdr->p_align; + + if (unlikely (dwfl->lookup_module != NULL)) + { + free (dwfl->lookup_module); + dwfl->lookup_module = NULL; + } + + GElf_Addr start = __libdwfl_segment_start (dwfl, bias + phdr->p_vaddr); + GElf_Addr end = __libdwfl_segment_end (dwfl, + bias + phdr->p_vaddr + phdr->p_memsz); + + /* Coalesce into the last one if contiguous and matching. */ + if (ndx != dwfl->lookup_tail_ndx + || ident == NULL + || ident != dwfl->lookup_tail_ident + || start != dwfl->lookup_tail_vaddr + || phdr->p_offset != dwfl->lookup_tail_offset) + { + /* Normally just appending keeps us sorted. */ + + size_t i = dwfl->lookup_elts; + while (i > 0 && unlikely (start < dwfl->lookup_addr[i - 1])) + --i; + + if (unlikely (insert (dwfl, i, start, end, ndx))) + { + __libdwfl_seterrno (DWFL_E_NOMEM); + return -1; + } + } + + dwfl->lookup_tail_ident = ident; + dwfl->lookup_tail_vaddr = end; + dwfl->lookup_tail_offset = end - bias - phdr->p_vaddr + phdr->p_offset; + dwfl->lookup_tail_ndx = ndx + 1; + + return ndx; +} +INTDEF (dwfl_report_segment) diff --git a/3rdparty/elfutils/libebl/ebl-hooks.h b/3rdparty/elfutils/libebl/ebl-hooks.h new file mode 100644 index 0000000..2e31446 --- /dev/null +++ b/3rdparty/elfutils/libebl/ebl-hooks.h @@ -0,0 +1,195 @@ +/* Backend hook signatures internal interface for libebl. + Copyright (C) 2000-2011, 2013, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +/* Return symbol representaton of object file type. */ +const char *EBLHOOK(object_type_name) (int, char *, size_t); + +/* Return symbolic representation of relocation type. */ +const char *EBLHOOK(reloc_type_name) (int, char *, size_t); + +/* Check relocation type. */ +bool EBLHOOK(reloc_type_check) (int); + +/* Check if relocation type is for simple absolute relocations. */ +Elf_Type EBLHOOK(reloc_simple_type) (Ebl *, int); + +/* Check relocation type use. */ +bool EBLHOOK(reloc_valid_use) (Elf *, int); + +/* Return true if the symbol type is that referencing the GOT. */ +bool EBLHOOK(gotpc_reloc_check) (Elf *, int); + +/* Return symbolic representation of segment type. */ +const char *EBLHOOK(segment_type_name) (int, char *, size_t); + +/* Return symbolic representation of section type. */ +const char *EBLHOOK(section_type_name) (int, char *, size_t); + +/* Return section name. */ +const char *EBLHOOK(section_name) (int, int, char *, size_t); + +/* Return next machine flag name. */ +const char *EBLHOOK(machine_flag_name) (GElf_Word *); + +/* Check whether machine flags are valid. */ +bool EBLHOOK(machine_flag_check) (GElf_Word); + +/* Check whether SHF_MASKPROC flag bits are valid. */ +bool EBLHOOK(machine_section_flag_check) (GElf_Xword); + +/* Check whether the section with the given index, header, and name + is a special machine section that is valid despite a combination + of flags or other details that are not generically valid. */ +bool EBLHOOK(check_special_section) (Ebl *, int, + const GElf_Shdr *, const char *); + +/* Return symbolic representation of symbol type. */ +const char *EBLHOOK(symbol_type_name) (int, char *, size_t); + +/* Return symbolic representation of symbol binding. */ +const char *EBLHOOK(symbol_binding_name) (int, char *, size_t); + +/* Return symbolic representation of dynamic tag. */ +const char *EBLHOOK(dynamic_tag_name) (int64_t, char *, size_t); + +/* Check dynamic tag. */ +bool EBLHOOK(dynamic_tag_check) (int64_t); + +/* Combine section header flags values. */ +GElf_Word EBLHOOK(sh_flags_combine) (GElf_Word, GElf_Word); + +/* Return symbolic representation of OS ABI. */ +const char *EBLHOOK(osabi_name) (int, char *, size_t); + +/* Name of a note entry type for core files. */ +const char *EBLHOOK(core_note_type_name) (uint32_t, char *, size_t); + +/* Name of a note entry type for object files. */ +const char *EBLHOOK(object_note_type_name) (const char *, uint32_t, + char *, size_t); + +/* Describe core note format. */ +int EBLHOOK(core_note) (const GElf_Nhdr *, const char *, + GElf_Word *, size_t *, const Ebl_Register_Location **, + size_t *, const Ebl_Core_Item **); + +/* Handle object file note. */ +bool EBLHOOK(object_note) (const char *, uint32_t, uint32_t, const char *); + +/* Check object attribute. */ +bool EBLHOOK(check_object_attribute) (Ebl *, const char *, int, uint64_t, + const char **, const char **); + +/* Check reloc target section type. */ +bool EBLHOOK(check_reloc_target_type) (Ebl *, Elf64_Word); + +/* Describe auxv element type. */ +int EBLHOOK(auxv_info) (GElf_Xword, const char **, const char **); + +/* Check section name for being that of a debug informatino section. */ +bool EBLHOOK(debugscn_p) (const char *); + +/* Check whether given relocation is a copy relocation. */ +bool EBLHOOK(copy_reloc_p) (int); + +/* Check whether given relocation is a no-op relocation. */ +bool EBLHOOK(none_reloc_p) (int); + +/* Check whether given relocation is a relative relocation. */ +bool EBLHOOK(relative_reloc_p) (int); + +/* Check whether given symbol's value is ok despite normal checks. */ +bool EBLHOOK(check_special_symbol) (Elf *, GElf_Ehdr *, const GElf_Sym *, + const char *, const GElf_Shdr *); + +/* Check whether only valid bits are set on the st_other symbol flag. + Standard ST_VISIBILITY have already been masked off. */ +bool EBLHOOK(check_st_other_bits) (unsigned char st_other); + +/* Check if backend uses a bss PLT in this file. */ +bool EBLHOOK(bss_plt_p) (Elf *); + +/* Return location expression to find return value given the + DW_AT_type DIE of a DW_TAG_subprogram DIE. */ +int EBLHOOK(return_value_location) (Dwarf_Die *functypedie, + const Dwarf_Op **locp); + +/* Return register name information. */ +ssize_t EBLHOOK(register_info) (Ebl *ebl, + int regno, char *name, size_t namelen, + const char **prefix, const char **setname, + int *bits, int *type); + +/* Return system call ABI registers. */ +int EBLHOOK(syscall_abi) (Ebl *ebl, int *sp, int *pc, + int *callno, int args[6]); + +/* Disassembler function. */ +int EBLHOOK(disasm) (const uint8_t **startp, const uint8_t *end, + GElf_Addr addr, const char *fmt, DisasmOutputCB_t outcb, + DisasmGetSymCB_t symcb, void *outcbarg, void *symcbarg); + +/* Supply the machine-specific state of CFI before CIE initial programs. + Function returns 0 on success and -1 on error. */ +int EBLHOOK(abi_cfi) (Ebl *ebl, Dwarf_CIE *abi_info); + +/* Fetch process data from live TID and call SETFUNC one or more times. + Method should be present only when EBL_FRAME_NREGS > 0, otherwise the + backend doesn't support unwinding. */ +bool EBLHOOK(set_initial_registers_tid) (pid_t tid, + ebl_tid_registers_t *setfunc, + void *arg); + +/* Convert *REGNO as is in DWARF to a lower range suitable for + Dwarf_Frame->REGS indexing. */ +bool EBLHOOK(dwarf_to_regno) (Ebl *ebl, unsigned *regno); + +/* Optionally modify *PC as fetched from inferior data into valid PC + instruction pointer. */ +void EBLHOOK(normalize_pc) (Ebl *ebl, Dwarf_Addr *pc); + +/* Get previous frame state for an existing frame state. Method is called only + if unwinder could not find CFI for current PC. PC is for the + existing frame. SETFUNC sets register in the previous frame. GETFUNC gets + register from the existing frame. Note that GETFUNC vs. SETFUNC act on + a disjunct set of registers. READFUNC reads memory. ARG has to be passed + for SETFUNC, GETFUNC and READFUNC. *SIGNAL_FRAMEP is initialized to false, + it can be set to true if existing frame is a signal frame. SIGNAL_FRAMEP is + never NULL. */ +bool EBLHOOK(unwind) (Ebl *ebl, Dwarf_Addr pc, ebl_tid_registers_t *setfunc, + ebl_tid_registers_get_t *getfunc, + ebl_pid_memory_read_t *readfunc, void *arg, + bool *signal_framep); + +/* Returns true if the value can be resolved to an address in an + allocated section, which will be returned in *ADDR. + (e.g. function descriptor resolving) */ +bool EBLHOOK(resolve_sym_value) (Ebl *ebl, GElf_Addr *addr); + +/* Destructor for ELF backend handle. */ +void EBLHOOK(destr) (struct ebl *); diff --git a/3rdparty/elfutils/libebl/ebl_check_special_section.c b/3rdparty/elfutils/libebl/ebl_check_special_section.c new file mode 100644 index 0000000..aabe44e --- /dev/null +++ b/3rdparty/elfutils/libebl/ebl_check_special_section.c @@ -0,0 +1,44 @@ +/* Check for a special section allowed to violate generic constraints. + Copyright (C) 2008 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libeblP.h> + + +bool +ebl_check_special_section (ebl, ndx, shdr, sname) + Ebl *ebl; + int ndx; + const GElf_Shdr *shdr; + const char *sname; +{ + return ebl != NULL && ebl->check_special_section (ebl, ndx, shdr, sname); +} diff --git a/3rdparty/elfutils/libebl/ebl_check_special_symbol.c b/3rdparty/elfutils/libebl/ebl_check_special_symbol.c new file mode 100644 index 0000000..8e702ba --- /dev/null +++ b/3rdparty/elfutils/libebl/ebl_check_special_symbol.c @@ -0,0 +1,49 @@ +/* Check special symbol's st_value. + Copyright (C) 2005 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <inttypes.h> +#include <libeblP.h> + + +bool +ebl_check_special_symbol (ebl, ehdr, sym, name, destshdr) + Ebl *ebl; + GElf_Ehdr *ehdr; + const GElf_Sym *sym; + const char *name; + const GElf_Shdr *destshdr; +{ + if (ebl == NULL) + return false; + + return ebl->check_special_symbol (ebl->elf, ehdr, sym, name, destshdr); +} diff --git a/3rdparty/elfutils/libebl/ebl_syscall_abi.c b/3rdparty/elfutils/libebl/ebl_syscall_abi.c new file mode 100644 index 0000000..de73703 --- /dev/null +++ b/3rdparty/elfutils/libebl/ebl_syscall_abi.c @@ -0,0 +1,45 @@ +/* Return system call ABI mapped to DWARF register numbers. + Copyright (C) 2008 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libeblP.h> + + +int +ebl_syscall_abi (ebl, sp, pc, callno, args) + Ebl *ebl; + int *sp; + int *pc; + int *callno; + int args[6]; +{ + return ebl != NULL ? ebl->syscall_abi (ebl, sp, pc, callno, args) : -1; +} diff --git a/3rdparty/elfutils/libebl/eblabicfi.c b/3rdparty/elfutils/libebl/eblabicfi.c new file mode 100644 index 0000000..20a29ea --- /dev/null +++ b/3rdparty/elfutils/libebl/eblabicfi.c @@ -0,0 +1,42 @@ +/* Return ABI-specific DWARF CFI details. + Copyright (C) 2009 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libeblP.h> + + +int +ebl_abi_cfi (ebl, abi_info) + Ebl *ebl; + Dwarf_CIE *abi_info; +{ + return ebl == NULL ? -1 : ebl->abi_cfi (ebl, abi_info); +} diff --git a/3rdparty/elfutils/libebl/eblauxvinfo.c b/3rdparty/elfutils/libebl/eblauxvinfo.c new file mode 100644 index 0000000..5c310b2 --- /dev/null +++ b/3rdparty/elfutils/libebl/eblauxvinfo.c @@ -0,0 +1,103 @@ +/* Describe known auxv types. + Copyright (C) 2007, 2008, 2009 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <byteswap.h> +#include <endian.h> +#include <inttypes.h> +#include <stdio.h> +#include <stddef.h> +#include <libeblP.h> + +#define AUXV_TYPES \ + TYPE (NULL, "") \ + TYPE (IGNORE, "") \ + TYPE (EXECFD, "d") \ + TYPE (EXECFN, "s") \ + TYPE (PHDR, "p") \ + TYPE (PHENT, "u") \ + TYPE (PHNUM, "u") \ + TYPE (PAGESZ, "u") \ + TYPE (BASE, "p") \ + TYPE (FLAGS, "x") \ + TYPE (ENTRY, "p") \ + TYPE (NOTELF, "") \ + TYPE (UID, "u") \ + TYPE (EUID, "u") \ + TYPE (GID, "u") \ + TYPE (EGID, "u") \ + TYPE (CLKTCK, "u") \ + TYPE (PLATFORM, "s") \ + TYPE (BASE_PLATFORM, "s") \ + TYPE (HWCAP, "x") \ + TYPE (FPUCW, "x") \ + TYPE (DCACHEBSIZE, "d") \ + TYPE (ICACHEBSIZE, "d") \ + TYPE (UCACHEBSIZE, "d") \ + TYPE (IGNOREPPC, "") \ + TYPE (SECURE, "u") \ + TYPE (SYSINFO, "p") \ + TYPE (SYSINFO_EHDR, "p") \ + TYPE (L1I_CACHESHAPE, "d") \ + TYPE (L1D_CACHESHAPE, "d") \ + TYPE (L2_CACHESHAPE, "d") \ + TYPE (L3_CACHESHAPE, "d") \ + TYPE (RANDOM, "p") + +static const struct +{ + const char *name, *format; +} auxv_types[] = + { +#define TYPE(name, fmt) [AT_##name] = { #name, fmt }, + AUXV_TYPES +#undef TYPE + }; +#define nauxv_types (sizeof auxv_types / sizeof auxv_types[0]) + +int +ebl_auxv_info (ebl, a_type, name, format) + Ebl *ebl; + GElf_Xword a_type; + const char **name; + const char **format; +{ + int result = ebl->auxv_info (a_type, name, format); + if (result == 0 && a_type < nauxv_types && auxv_types[a_type].name != NULL) + { + /* The machine specific function did not know this type. */ + *name = auxv_types[a_type].name; + *format = auxv_types[a_type].format; + result = 1; + } + return result; +} diff --git a/3rdparty/elfutils/libebl/eblbackendname.c b/3rdparty/elfutils/libebl/eblbackendname.c new file mode 100644 index 0000000..92e576e --- /dev/null +++ b/3rdparty/elfutils/libebl/eblbackendname.c @@ -0,0 +1,43 @@ +/* Return backend name. + Copyright (C) 2001, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2001. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> +#include <libeblP.h> + + +const char * +ebl_backend_name (ebl) + Ebl *ebl; +{ + return ebl != NULL ? ebl->emulation : gettext ("No backend"); +} diff --git a/3rdparty/elfutils/libebl/eblbsspltp.c b/3rdparty/elfutils/libebl/eblbsspltp.c new file mode 100644 index 0000000..95a5d8a --- /dev/null +++ b/3rdparty/elfutils/libebl/eblbsspltp.c @@ -0,0 +1,42 @@ +/* Check if backend uses a bss PLT. + Copyright (C) 2005, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <inttypes.h> +#include <libeblP.h> + + +bool +ebl_bss_plt_p (ebl) + Ebl *ebl; +{ + return ebl == NULL ? false : ebl->bss_plt_p (ebl->elf); +} diff --git a/3rdparty/elfutils/libebl/eblcheckobjattr.c b/3rdparty/elfutils/libebl/eblcheckobjattr.c new file mode 100644 index 0000000..b0481d2 --- /dev/null +++ b/3rdparty/elfutils/libebl/eblcheckobjattr.c @@ -0,0 +1,60 @@ +/* Check object attributes. + Copyright (C) 2008 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> +#include <libeblP.h> + + +bool +ebl_check_object_attribute (ebl, vendor, tag, value, tag_name, value_name) + Ebl *ebl; + const char *vendor; + int tag; + uint64_t value; + const char **tag_name; + const char **value_name; +{ + if (ebl->check_object_attribute (ebl, vendor, tag, value, + tag_name, value_name)) + return true; + + if (strcmp (vendor, "gnu")) + return false; + + if (tag == 32) + { + *tag_name = "compatibility"; + return true; + } + + return false; +} diff --git a/3rdparty/elfutils/libebl/eblcheckreloctargettype.c b/3rdparty/elfutils/libebl/eblcheckreloctargettype.c new file mode 100644 index 0000000..e135f8a --- /dev/null +++ b/3rdparty/elfutils/libebl/eblcheckreloctargettype.c @@ -0,0 +1,46 @@ +/* Check whether a section type is a valid target for relocation. + Copyright (C) 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libeblP.h> + + +bool +ebl_check_reloc_target_type (Ebl *ebl, Elf64_Word sh_type) +{ + if (ebl->check_reloc_target_type (ebl, sh_type)) + return true; + + if (sh_type == SHT_PROGBITS || sh_type == SHT_NOBITS) + return true; + + return false; +} diff --git a/3rdparty/elfutils/libebl/eblclosebackend.c b/3rdparty/elfutils/libebl/eblclosebackend.c new file mode 100644 index 0000000..67fbdfe --- /dev/null +++ b/3rdparty/elfutils/libebl/eblclosebackend.c @@ -0,0 +1,54 @@ +/* Free ELF backend handle. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dlfcn.h> +#include <stdlib.h> + +#include <libeblP.h> + + +void +ebl_closebackend (Ebl *ebl) +{ + if (ebl != NULL) + { + /* Run the destructor. */ + ebl->destr (ebl); + + /* Close the dynamically loaded object. */ + if (ebl->dlhandle != NULL) + (void) dlclose (ebl->dlhandle); + + /* Free the resources. */ + free (ebl); + } +} diff --git a/3rdparty/elfutils/libebl/eblcopyrelocp.c b/3rdparty/elfutils/libebl/eblcopyrelocp.c new file mode 100644 index 0000000..702f8c7 --- /dev/null +++ b/3rdparty/elfutils/libebl/eblcopyrelocp.c @@ -0,0 +1,43 @@ +/* Check whether given relocation is a copy relocation. + Copyright (C) 2005 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2005. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libeblP.h> + + +bool +ebl_copy_reloc_p (ebl, reloc) + Ebl *ebl; + int reloc; +{ + return ebl->copy_reloc_p (reloc); +} diff --git a/3rdparty/elfutils/libebl/eblcorenote.c b/3rdparty/elfutils/libebl/eblcorenote.c new file mode 100644 index 0000000..2a79278 --- /dev/null +++ b/3rdparty/elfutils/libebl/eblcorenote.c @@ -0,0 +1,86 @@ +/* Describe known core note formats. + Copyright (C) 2007, 2010 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <byteswap.h> +#include <endian.h> +#include <inttypes.h> +#include <stdio.h> +#include <stddef.h> +#include <libeblP.h> + + +int +ebl_core_note (ebl, nhdr, name, + regs_offset, nregloc, reglocs, nitems, items) + Ebl *ebl; + const GElf_Nhdr *nhdr; + const char *name; + GElf_Word *regs_offset; + size_t *nregloc; + const Ebl_Register_Location **reglocs; + size_t *nitems; + const Ebl_Core_Item **items; +{ + int result = ebl->core_note (nhdr, name, + regs_offset, nregloc, reglocs, nitems, items); + if (result == 0) + { + /* The machine specific function did not know this type. */ + + *regs_offset = 0; + *nregloc = 0; + *reglocs = NULL; + switch (nhdr->n_type) + { +#define ITEMS(type, table) \ + case type: \ + *items = table; \ + *nitems = sizeof table / sizeof table[0]; \ + result = 1; \ + break + + static const Ebl_Core_Item platform[] = + { + { + .name = "Platform", + .type = ELF_T_BYTE, .count = 0, .format = 's' + } + }; + ITEMS (NT_PLATFORM, platform); + +#undef ITEMS + } + } + + return result; +} diff --git a/3rdparty/elfutils/libebl/eblcorenotetypename.c b/3rdparty/elfutils/libebl/eblcorenotetypename.c new file mode 100644 index 0000000..b6db6cd --- /dev/null +++ b/3rdparty/elfutils/libebl/eblcorenotetypename.c @@ -0,0 +1,109 @@ +/* Return note type name. + Copyright (C) 2002, 2007, 2008, 2012, 2013 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <inttypes.h> +#include <stdio.h> +#include <libeblP.h> + +const char * +ebl_core_note_type_name (ebl, type, buf, len) + Ebl *ebl; + uint32_t type; + char *buf; + size_t len; +{ + const char *res = ebl->core_note_type_name (type, buf, len); + + if (res == NULL) + { + static const char *knowntypes[] = + { +#define KNOWNSTYPE(name) [NT_##name] = #name + KNOWNSTYPE (PRSTATUS), + KNOWNSTYPE (FPREGSET), + KNOWNSTYPE (PRPSINFO), + KNOWNSTYPE (TASKSTRUCT), + KNOWNSTYPE (PLATFORM), + KNOWNSTYPE (AUXV), + KNOWNSTYPE (GWINDOWS), + KNOWNSTYPE (ASRS), + KNOWNSTYPE (PSTATUS), + KNOWNSTYPE (PSINFO), + KNOWNSTYPE (PRCRED), + KNOWNSTYPE (UTSNAME), + KNOWNSTYPE (LWPSTATUS), + KNOWNSTYPE (LWPSINFO), + KNOWNSTYPE (PRFPXREG) +#undef KNOWNSTYPE + }; + + /* Handle standard names. */ + if (type < sizeof (knowntypes) / sizeof (knowntypes[0]) + && knowntypes[type] != NULL) + res = knowntypes[type]; + else + switch (type) + { +#define KNOWNSTYPE(name) case NT_##name: res = #name; break + KNOWNSTYPE (PRXFPREG); + KNOWNSTYPE (PPC_VMX); + KNOWNSTYPE (PPC_SPE); + KNOWNSTYPE (PPC_VSX); + KNOWNSTYPE (386_TLS); + KNOWNSTYPE (386_IOPERM); + KNOWNSTYPE (X86_XSTATE); + KNOWNSTYPE (S390_HIGH_GPRS); + KNOWNSTYPE (S390_TIMER); + KNOWNSTYPE (S390_TODCMP); + KNOWNSTYPE (S390_TODPREG); + KNOWNSTYPE (S390_CTRS); + KNOWNSTYPE (S390_PREFIX); + KNOWNSTYPE (S390_LAST_BREAK); + KNOWNSTYPE (S390_SYSTEM_CALL); + KNOWNSTYPE (ARM_VFP); + KNOWNSTYPE (ARM_TLS); + KNOWNSTYPE (ARM_HW_BREAK); + KNOWNSTYPE (ARM_HW_WATCH); + KNOWNSTYPE (SIGINFO); + KNOWNSTYPE (FILE); +#undef KNOWNSTYPE + + default: + snprintf (buf, len, "%s: %" PRIu32, gettext ("<unknown>"), type); + + res = buf; + } + } + + return res; +} diff --git a/3rdparty/elfutils/libebl/ebldebugscnp.c b/3rdparty/elfutils/libebl/ebldebugscnp.c new file mode 100644 index 0000000..01a5675 --- /dev/null +++ b/3rdparty/elfutils/libebl/ebldebugscnp.c @@ -0,0 +1,44 @@ +/* Check section name for being that of a debug informatino section. + Copyright (C) 2002, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdint.h> +#include <libeblP.h> + + +bool +ebl_debugscn_p (ebl, name) + Ebl *ebl; + const char *name; +{ + return name != NULL && ebl->debugscn_p (name); +} diff --git a/3rdparty/elfutils/libebl/ebldwarftoregno.c b/3rdparty/elfutils/libebl/ebldwarftoregno.c new file mode 100644 index 0000000..8fb8540 --- /dev/null +++ b/3rdparty/elfutils/libebl/ebldwarftoregno.c @@ -0,0 +1,41 @@ +/* Convert *REGNO as is in DWARF to a lower range. + Copyright (C) 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libeblP.h> + +bool +ebl_dwarf_to_regno (Ebl *ebl, unsigned *regno) +{ + if (ebl == NULL) + return false; + return ebl->dwarf_to_regno == NULL ? true : ebl->dwarf_to_regno (ebl, regno); +} diff --git a/3rdparty/elfutils/libebl/ebldynamictagcheck.c b/3rdparty/elfutils/libebl/ebldynamictagcheck.c new file mode 100644 index 0000000..17acee0 --- /dev/null +++ b/3rdparty/elfutils/libebl/ebldynamictagcheck.c @@ -0,0 +1,56 @@ +/* Check dynamic tag. + Copyright (C) 2001, 2002, 2006 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2001. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <inttypes.h> +#include <libeblP.h> + + +bool +ebl_dynamic_tag_check (ebl, tag) + Ebl *ebl; + int64_t tag; +{ + bool res = ebl != NULL ? ebl->dynamic_tag_check (tag) : false; + + if (!res + && ((tag >= 0 && tag < DT_NUM) + || (tag >= DT_GNU_PRELINKED && tag <= DT_SYMINENT) + || (tag >= DT_GNU_HASH && tag <= DT_SYMINFO) + || tag == DT_VERSYM + || (tag >= DT_RELACOUNT && tag <= DT_VERNEEDNUM) + || tag == DT_AUXILIARY + || tag == DT_FILTER)) + res = true; + + return res; +} diff --git a/3rdparty/elfutils/libebl/ebldynamictagname.c b/3rdparty/elfutils/libebl/ebldynamictagname.c new file mode 100644 index 0000000..6b09ee6 --- /dev/null +++ b/3rdparty/elfutils/libebl/ebldynamictagname.c @@ -0,0 +1,113 @@ +/* Return dynamic tag name. + Copyright (C) 2001, 2002, 2006, 2008 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2001. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <inttypes.h> +#include <stdio.h> +#include <libeblP.h> + + +const char * +ebl_dynamic_tag_name (ebl, tag, buf, len) + Ebl *ebl; + int64_t tag; + char *buf; + size_t len; +{ + const char *res = ebl != NULL ? ebl->dynamic_tag_name (tag, buf, len) : NULL; + + if (res == NULL) + { + if (tag >= 0 && tag < DT_NUM) + { + static const char *stdtags[] = + { + "NULL", "NEEDED", "PLTRELSZ", "PLTGOT", "HASH", "STRTAB", + "SYMTAB", "RELA", "RELASZ", "RELAENT", "STRSZ", "SYMENT", + "INIT", "FINI", "SONAME", "RPATH", "SYMBOLIC", "REL", "RELSZ", + "RELENT", "PLTREL", "DEBUG", "TEXTREL", "JMPREL", "BIND_NOW", + "INIT_ARRAY", "FINI_ARRAY", "INIT_ARRAYSZ", "FINI_ARRAYSZ", + "RUNPATH", "FLAGS", "ENCODING", "PREINIT_ARRAY", + "PREINIT_ARRAYSZ" + }; + + res = stdtags[tag]; + } + else if (tag == DT_VERSYM) + res = "VERSYM"; + else if (tag >= DT_GNU_PRELINKED && tag <= DT_SYMINENT) + { + static const char *valrntags[] = + { + "GNU_PRELINKED", "GNU_CONFLICTSZ", "GNU_LIBLISTSZ", + "CHECKSUM", "PLTPADSZ", "MOVEENT", "MOVESZ", "FEATURE_1", + "POSFLAG_1", "SYMINSZ", "SYMINENT" + }; + + res = valrntags[tag - DT_GNU_PRELINKED]; + } + else if (tag >= DT_GNU_HASH && tag <= DT_SYMINFO) + { + static const char *addrrntags[] = + { + "GNU_HASH", "TLSDESC_PLT", "TLSDESC_GOT", + "GNU_CONFLICT", "GNU_LIBLIST", "CONFIG", "DEPAUDIT", "AUDIT", + "PLTPAD", "MOVETAB", "SYMINFO" + }; + + res = addrrntags[tag - DT_GNU_HASH]; + } + else if (tag >= DT_RELACOUNT && tag <= DT_VERNEEDNUM) + { + static const char *suntags[] = + { + "RELACOUNT", "RELCOUNT", "FLAGS_1", "VERDEF", "VERDEFNUM", + "VERNEED", "VERNEEDNUM" + }; + + res = suntags[tag - DT_RELACOUNT]; + } + else if (tag == DT_AUXILIARY) + res = "AUXILIARY"; + else if (tag == DT_FILTER) + res = "FILTER"; + else + { + snprintf (buf, len, gettext ("<unknown>: %#" PRIx64), tag); + + res = buf; + + } + } + + return res; +} diff --git a/3rdparty/elfutils/libebl/eblelfclass.c b/3rdparty/elfutils/libebl/eblelfclass.c new file mode 100644 index 0000000..62d1283 --- /dev/null +++ b/3rdparty/elfutils/libebl/eblelfclass.c @@ -0,0 +1,42 @@ +/* Return ELF class. + Copyright (C) 2005 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2005. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libeblP.h> + + +int +ebl_get_elfclass (ebl) + Ebl *ebl; +{ + return ebl->class; +} diff --git a/3rdparty/elfutils/libebl/eblelfdata.c b/3rdparty/elfutils/libebl/eblelfdata.c new file mode 100644 index 0000000..b09dbb5 --- /dev/null +++ b/3rdparty/elfutils/libebl/eblelfdata.c @@ -0,0 +1,42 @@ +/* Return ELF data encoding. + Copyright (C) 2005 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2005. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libeblP.h> + + +int +ebl_get_elfdata (ebl) + Ebl *ebl; +{ + return ebl->data; +} diff --git a/3rdparty/elfutils/libebl/eblelfmachine.c b/3rdparty/elfutils/libebl/eblelfmachine.c new file mode 100644 index 0000000..cd961e7 --- /dev/null +++ b/3rdparty/elfutils/libebl/eblelfmachine.c @@ -0,0 +1,42 @@ +/* Return ELF machine. + Copyright (C) 2005 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2005. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libeblP.h> + + +int +ebl_get_elfmachine (ebl) + Ebl *ebl; +{ + return ebl->machine; +} diff --git a/3rdparty/elfutils/libebl/eblgotpcreloccheck.c b/3rdparty/elfutils/libebl/eblgotpcreloccheck.c new file mode 100644 index 0000000..55625de --- /dev/null +++ b/3rdparty/elfutils/libebl/eblgotpcreloccheck.c @@ -0,0 +1,44 @@ +/* Return true if the symbol type is that referencing the GOT. E.g., + R_386_GOTPC. + Copyright (C) 2003 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libeblP.h> + + +bool +ebl_gotpc_reloc_check (ebl, reloc) + Ebl *ebl; + int reloc; +{ + return ebl != NULL ? ebl->gotpc_reloc_check (ebl->elf, reloc) : false; +} diff --git a/3rdparty/elfutils/libebl/eblgstrtab.c b/3rdparty/elfutils/libebl/eblgstrtab.c new file mode 100644 index 0000000..0d92c00 --- /dev/null +++ b/3rdparty/elfutils/libebl/eblgstrtab.c @@ -0,0 +1,365 @@ +/* Generic string table handling. + Copyright (C) 2000, 2001, 2002, 2005 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <inttypes.h> +#include <libelf.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/param.h> + +#include "libebl.h" + +#ifndef MIN +# define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif + + +struct Ebl_GStrent +{ + const char *string; + size_t len; + struct Ebl_GStrent *next; + struct Ebl_GStrent *left; + struct Ebl_GStrent *right; + size_t offset; + unsigned int width; + char reverse[0]; +}; + + +struct memoryblock +{ + struct memoryblock *next; + char memory[0]; +}; + + +struct Ebl_GStrtab +{ + struct Ebl_GStrent *root; + struct memoryblock *memory; + char *backp; + size_t left; + size_t total; + unsigned int width; + bool nullstr; + + struct Ebl_GStrent null; +}; + + +/* Cache for the pagesize. We correct this value a bit so that `malloc' + is not allocating more than a page. */ +static size_t ps; + + +struct Ebl_GStrtab * +ebl_gstrtabinit (unsigned int width, bool nullstr) +{ + struct Ebl_GStrtab *ret; + + if (ps == 0) + { + ps = sysconf (_SC_PAGESIZE) - 2 * sizeof (void *); + assert (sizeof (struct memoryblock) < ps); + } + + ret = (struct Ebl_GStrtab *) calloc (1, sizeof (struct Ebl_GStrtab)); + if (ret != NULL) + { + ret->width = width; + ret->nullstr = nullstr; + + if (nullstr) + { + ret->null.len = 1; + ret->null.string = (char *) calloc (1, width); + } + } + + return ret; +} + + +static void +morememory (struct Ebl_GStrtab *st, size_t len) +{ + struct memoryblock *newmem; + + if (len < ps) + len = ps; + newmem = (struct memoryblock *) malloc (len); + if (newmem == NULL) + abort (); + + newmem->next = st->memory; + st->memory = newmem; + st->backp = newmem->memory; + st->left = len - offsetof (struct memoryblock, memory); +} + + +void +ebl_gstrtabfree (struct Ebl_GStrtab *st) +{ + struct memoryblock *mb = st->memory; + + while (mb != NULL) + { + void *old = mb; + mb = mb->next; + free (old); + } + + if (st->null.string != NULL) + free ((char *) st->null.string); + + free (st); +} + + +static struct Ebl_GStrent * +newstring (struct Ebl_GStrtab *st, const char *str, size_t len) +{ + /* Compute the amount of padding needed to make the structure aligned. */ + size_t align = ((__alignof__ (struct Ebl_GStrent) + - (((uintptr_t) st->backp) + & (__alignof__ (struct Ebl_GStrent) - 1))) + & (__alignof__ (struct Ebl_GStrent) - 1)); + + /* Make sure there is enough room in the memory block. */ + if (st->left < align + sizeof (struct Ebl_GStrent) + len * st->width) + { + morememory (st, sizeof (struct Ebl_GStrent) + len * st->width); + align = 0; + } + + /* Create the reserved string. */ + struct Ebl_GStrent *newstr = (struct Ebl_GStrent *) (st->backp + align); + newstr->string = str; + newstr->len = len; + newstr->width = st->width; + newstr->next = NULL; + newstr->left = NULL; + newstr->right = NULL; + newstr->offset = 0; + for (int i = len - 2; i >= 0; --i) + for (int j = st->width - 1; j >= 0; --j) + newstr->reverse[i * st->width + j] = str[(len - 2 - i) * st->width + j]; + for (size_t j = 0; j < st->width; ++j) + newstr->reverse[(len - 1) * st->width + j] = '\0'; + st->backp += align + sizeof (struct Ebl_GStrent) + len * st->width; + st->left -= align + sizeof (struct Ebl_GStrent) + len * st->width; + + return newstr; +} + + +/* XXX This function should definitely be rewritten to use a balancing + tree algorith (AVL, red-black trees). For now a simple, correct + implementation is enough. */ +static struct Ebl_GStrent ** +searchstring (struct Ebl_GStrent **sep, struct Ebl_GStrent *newstr) +{ + int cmpres; + + /* More strings? */ + if (*sep == NULL) + { + *sep = newstr; + return sep; + } + + /* Compare the strings. */ + cmpres = memcmp ((*sep)->reverse, newstr->reverse, + (MIN ((*sep)->len, newstr->len) - 1) * (*sep)->width); + if (cmpres == 0) + /* We found a matching string. */ + return sep; + else if (cmpres > 0) + return searchstring (&(*sep)->left, newstr); + else + return searchstring (&(*sep)->right, newstr); +} + + +/* Add new string. The actual string is assumed to be permanent. */ +struct Ebl_GStrent * +ebl_gstrtabadd (struct Ebl_GStrtab *st, const char *str, size_t len) +{ + struct Ebl_GStrent *newstr; + struct Ebl_GStrent **sep; + + /* Compute the string length if the caller doesn't know it. */ + if (len == 0) + { + size_t j; + + do + for (j = 0; j < st->width; ++j) + if (str[len * st->width + j] != '\0') + break; + while (j == st->width && ++len); + } + + /* Make sure all "" strings get offset 0 but only if the table was + created with a special null entry in mind. */ + if (len == 1 && st->null.string != NULL) + return &st->null; + + /* Allocate memory for the new string and its associated information. */ + newstr = newstring (st, str, len); + + /* Search in the array for the place to insert the string. If there + is no string with matching prefix and no string with matching + leading substring, create a new entry. */ + sep = searchstring (&st->root, newstr); + if (*sep != newstr) + { + /* This is not the same entry. This means we have a prefix match. */ + if ((*sep)->len > newstr->len) + { + struct Ebl_GStrent *subs; + + /* Check whether we already know this string. */ + for (subs = (*sep)->next; subs != NULL; subs = subs->next) + if (subs->len == newstr->len) + { + /* We have an exact match with a substring. Free the memory + we allocated. */ + st->left += (st->backp - (char *) newstr) * st->width; + st->backp = (char *) newstr; + + return subs; + } + + /* We have a new substring. This means we don't need the reverse + string of this entry anymore. */ + st->backp -= newstr->len; + st->left += newstr->len; + + newstr->next = (*sep)->next; + (*sep)->next = newstr; + } + else if ((*sep)->len != newstr->len) + { + /* When we get here it means that the string we are about to + add has a common prefix with a string we already have but + it is longer. In this case we have to put it first. */ + st->total += newstr->len - (*sep)->len; + newstr->next = *sep; + newstr->left = (*sep)->left; + newstr->right = (*sep)->right; + *sep = newstr; + } + else + { + /* We have an exact match. Free the memory we allocated. */ + st->left += (st->backp - (char *) newstr) * st->width; + st->backp = (char *) newstr; + + newstr = *sep; + } + } + else + st->total += newstr->len; + + return newstr; +} + + +static void +copystrings (struct Ebl_GStrent *nodep, char **freep, size_t *offsetp) +{ + struct Ebl_GStrent *subs; + + if (nodep->left != NULL) + copystrings (nodep->left, freep, offsetp); + + /* Process the current node. */ + nodep->offset = *offsetp; + *freep = (char *) mempcpy (*freep, nodep->string, nodep->len * nodep->width); + *offsetp += nodep->len * nodep->width; + + for (subs = nodep->next; subs != NULL; subs = subs->next) + { + assert (subs->len < nodep->len); + subs->offset = nodep->offset + (nodep->len - subs->len) * nodep->width; + assert (subs->offset != 0 || subs->string[0] == '\0'); + } + + if (nodep->right != NULL) + copystrings (nodep->right, freep, offsetp); +} + + +void +ebl_gstrtabfinalize (struct Ebl_GStrtab *st, Elf_Data *data) +{ + size_t copylen; + char *endp; + size_t nulllen = st->nullstr ? st->width : 0; + + /* Fill in the information. */ + data->d_buf = malloc (st->total + nulllen); + if (data->d_buf == NULL) + abort (); + + /* The first byte must always be zero if we created the table with a + null string. */ + if (st->nullstr) + memset (data->d_buf, '\0', st->width); + + data->d_type = ELF_T_BYTE; + data->d_size = st->total + nulllen; + data->d_off = 0; + data->d_align = 1; + data->d_version = EV_CURRENT; + + /* Now run through the tree and add all the string while also updating + the offset members of the elfstrent records. */ + endp = (char *) data->d_buf + nulllen; + copylen = nulllen; + copystrings (st->root, &endp, ©len); + assert (copylen == st->total * st->width + nulllen); +} + + +size_t +ebl_gstrtaboffset (struct Ebl_GStrent *se) +{ + return se->offset; +} diff --git a/3rdparty/elfutils/libebl/eblheaders.pri b/3rdparty/elfutils/libebl/eblheaders.pri new file mode 100644 index 0000000..71168fd --- /dev/null +++ b/3rdparty/elfutils/libebl/eblheaders.pri @@ -0,0 +1,10 @@ +include(../libasm/asmheaders.pri) +include(../libdw/dwheaders.pri) +include(../libelf/elfheaders.pri) + +HEADERS += \ + $$PWD/ebl-hooks.h \ + $$PWD/libebl.h \ + $$PWD/libeblP.h + +INCLUDEPATH += $$PWD diff --git a/3rdparty/elfutils/libebl/eblinitreg.c b/3rdparty/elfutils/libebl/eblinitreg.c new file mode 100644 index 0000000..5729b3c --- /dev/null +++ b/3rdparty/elfutils/libebl/eblinitreg.c @@ -0,0 +1,58 @@ +/* Fetch live process Dwfl_Frame from PID. + Copyright (C) 2013, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libeblP.h> +#include <assert.h> + +bool +ebl_set_initial_registers_tid (Ebl *ebl, pid_t tid, + ebl_tid_registers_t *setfunc, + void *arg) +{ + /* Otherwise caller could not allocate THREAD frame of proper size. + If set_initial_registers_tid is unsupported then FRAME_NREGS is zero. */ + assert (ebl->set_initial_registers_tid != NULL); + return ebl->set_initial_registers_tid (tid, setfunc, arg); +} + +size_t +ebl_frame_nregs (Ebl *ebl) +{ + return ebl == NULL ? 0 : ebl->frame_nregs; +} + +GElf_Addr +ebl_func_addr_mask (Ebl *ebl) +{ + return ((ebl == NULL || ebl->func_addr_mask == 0) + ? ~(GElf_Addr)0 : ebl->func_addr_mask); +} diff --git a/3rdparty/elfutils/libebl/eblmachineflagcheck.c b/3rdparty/elfutils/libebl/eblmachineflagcheck.c new file mode 100644 index 0000000..d6d7931 --- /dev/null +++ b/3rdparty/elfutils/libebl/eblmachineflagcheck.c @@ -0,0 +1,43 @@ +/* Check machine flag. + Copyright (C) 2001, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2001. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libeblP.h> + + +bool +ebl_machine_flag_check (ebl, flags) + Ebl *ebl; + Elf64_Word flags; +{ + return ebl != NULL ? ebl->machine_flag_check (flags) : (flags == 0); +} diff --git a/3rdparty/elfutils/libebl/eblmachineflagname.c b/3rdparty/elfutils/libebl/eblmachineflagname.c new file mode 100644 index 0000000..e392f5a --- /dev/null +++ b/3rdparty/elfutils/libebl/eblmachineflagname.c @@ -0,0 +1,91 @@ +/* Return machine flag names. + Copyright (C) 2001, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2001. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> +#include <string.h> +#include <libeblP.h> + + +const char * +ebl_machine_flag_name (ebl, flags, buf, len) + Ebl *ebl; + Elf64_Word flags; + char *buf; + size_t len; +{ + const char *res; + + if (flags == 0) + res = ""; + else + { + char *cp = buf; + int first = 1; + const char *machstr; + size_t machstrlen; + + do + { + if (! first) + { + if (cp + 1 >= buf + len) + break; + *cp++ = ','; + } + + machstr = ebl != NULL ? ebl->machine_flag_name (&flags) : NULL; + if (machstr == NULL) + { + /* No more known flag. */ + snprintf (cp, buf + len - cp, "%#x", flags); + break; + } + + machstrlen = strlen (machstr) + 1; + if ((size_t) (buf + len - cp) < machstrlen) + { + *((char *) mempcpy (cp, machstr, buf + len - cp - 1)) = '\0'; + break; + } + + cp = mempcpy (cp, machstr, machstrlen); + + first = 0; + } + while (flags != 0); + + res = buf; + } + + return res; +} diff --git a/3rdparty/elfutils/libebl/eblmachinesectionflagcheck.c b/3rdparty/elfutils/libebl/eblmachinesectionflagcheck.c new file mode 100644 index 0000000..671eb8c --- /dev/null +++ b/3rdparty/elfutils/libebl/eblmachinesectionflagcheck.c @@ -0,0 +1,42 @@ +/* Check SHF_MASKPROC flags. + Copyright (C) 2007 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libeblP.h> + + +bool +ebl_machine_section_flag_check (ebl, flags) + Ebl *ebl; + GElf_Xword flags; +{ + return ebl != NULL ? ebl->machine_section_flag_check (flags) : (flags == 0); +} diff --git a/3rdparty/elfutils/libebl/eblnonerelocp.c b/3rdparty/elfutils/libebl/eblnonerelocp.c new file mode 100644 index 0000000..07c6b0e --- /dev/null +++ b/3rdparty/elfutils/libebl/eblnonerelocp.c @@ -0,0 +1,43 @@ +/* Check whether given relocation is a no-op relocation. + Copyright (C) 2006 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2006. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libeblP.h> + + +bool +ebl_none_reloc_p (ebl, reloc) + Ebl *ebl; + int reloc; +{ + return ebl->none_reloc_p (reloc); +} diff --git a/3rdparty/elfutils/libebl/eblnormalizepc.c b/3rdparty/elfutils/libebl/eblnormalizepc.c new file mode 100644 index 0000000..a5fea77 --- /dev/null +++ b/3rdparty/elfutils/libebl/eblnormalizepc.c @@ -0,0 +1,40 @@ +/* Modify PC as fetched from inferior data into valid PC. + Copyright (C) 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libeblP.h> + +void +ebl_normalize_pc (Ebl *ebl, Dwarf_Addr *pc) +{ + if (ebl != NULL && ebl->normalize_pc != NULL) + ebl->normalize_pc (ebl, pc); +} diff --git a/3rdparty/elfutils/libebl/eblobjecttypename.c b/3rdparty/elfutils/libebl/eblobjecttypename.c new file mode 100644 index 0000000..1a2c8e8 --- /dev/null +++ b/3rdparty/elfutils/libebl/eblobjecttypename.c @@ -0,0 +1,63 @@ +/* Return object file type name. + Copyright (C) 2001, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2001. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> +#include <libeblP.h> + + +const char * +ebl_object_type_name (ebl, object, buf, len) + Ebl *ebl; + int object; + char *buf; + size_t len; +{ + const char *res; + + res = ebl != NULL ? ebl->object_type_name (object, buf, len) : NULL; + if (res == NULL) + { + /* Handle OS-specific section names. */ + if (object >= ET_LOOS && object <= ET_HIOS) + snprintf (buf, len, "LOOS+%x", object - ET_LOOS); + /* Handle processor-specific section names. */ + else if (object >= ET_LOPROC && object <= ET_HIPROC) + snprintf (buf, len, "LOPROC+%x", object - ET_LOPROC); + else + snprintf (buf, len, "%s: %d", gettext ("<unknown>"), object); + + res = buf; + } + + return res; +} diff --git a/3rdparty/elfutils/libebl/eblobjnote.c b/3rdparty/elfutils/libebl/eblobjnote.c new file mode 100644 index 0000000..d1fe821 --- /dev/null +++ b/3rdparty/elfutils/libebl/eblobjnote.c @@ -0,0 +1,220 @@ +/* Print contents of object file note. + Copyright (C) 2002, 2007, 2009, 2011 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <inttypes.h> +#include <stdio.h> +#include <string.h> +#include <libeblP.h> + + +void +ebl_object_note (ebl, name, type, descsz, desc) + Ebl *ebl; + const char *name; + uint32_t type; + uint32_t descsz; + const char *desc; +{ + if (! ebl->object_note (name, type, descsz, desc)) + /* The machine specific function did not know this type. */ + + if (strcmp ("stapsdt", name) == 0) + { + if (type != 3) + { + printf (gettext ("unknown SDT version %u\n"), type); + return; + } + + /* Descriptor starts with three addresses, pc, base ref and + semaphore. Then three zero terminated strings provider, + name and arguments. */ + + union + { + Elf64_Addr a64[3]; + Elf32_Addr a32[3]; + } addrs; + + size_t addrs_size = gelf_fsize (ebl->elf, ELF_T_ADDR, 3, EV_CURRENT); + if (descsz < addrs_size + 3) + { + invalid_sdt: + printf (gettext ("invalid SDT probe descriptor\n")); + return; + } + + Elf_Data src = + { + .d_type = ELF_T_ADDR, .d_version = EV_CURRENT, + .d_buf = (void *) desc, .d_size = addrs_size + }; + + Elf_Data dst = + { + .d_type = ELF_T_ADDR, .d_version = EV_CURRENT, + .d_buf = &addrs, .d_size = addrs_size + }; + + if (gelf_xlatetom (ebl->elf, &dst, &src, + elf_getident (ebl->elf, NULL)[EI_DATA]) == NULL) + { + printf ("%s\n", elf_errmsg (-1)); + return; + } + + const char *provider = desc + addrs_size; + const char *pname = memchr (provider, '\0', desc + descsz - provider); + if (pname == NULL) + goto invalid_sdt; + + ++pname; + const char *args = memchr (pname, '\0', desc + descsz - pname); + if (args == NULL || + memchr (++args, '\0', desc + descsz - pname) != desc + descsz - 1) + goto invalid_sdt; + + GElf_Addr pc; + GElf_Addr base; + GElf_Addr sem; + if (gelf_getclass (ebl->elf) == ELFCLASS32) + { + pc = addrs.a32[0]; + base = addrs.a32[1]; + sem = addrs.a32[2]; + } + else + { + pc = addrs.a64[0]; + base = addrs.a64[1]; + sem = addrs.a64[2]; + } + + printf (gettext (" PC: ")); + printf ("%#" PRIx64 ",", pc); + printf (gettext (" Base: ")); + printf ("%#" PRIx64 ",", base); + printf (gettext (" Semaphore: ")); + printf ("%#" PRIx64 "\n", sem); + printf (gettext (" Provider: ")); + printf ("%s,", provider); + printf (gettext (" Name: ")); + printf ("%s,", pname); + printf (gettext (" Args: ")); + printf ("'%s'\n", args); + return; + } + + switch (type) + { + case NT_GNU_BUILD_ID: + if (strcmp (name, "GNU") == 0 && descsz > 0) + { + printf (gettext (" Build ID: ")); + uint_fast32_t i; + for (i = 0; i < descsz - 1; ++i) + printf ("%02" PRIx8, (uint8_t) desc[i]); + printf ("%02" PRIx8 "\n", (uint8_t) desc[i]); + } + break; + + case NT_GNU_GOLD_VERSION: + if (strcmp (name, "GNU") == 0 && descsz > 0) + /* A non-null terminated version string. */ + printf (gettext (" Linker version: %.*s\n"), + (int) descsz, desc); + break; + + case NT_GNU_ABI_TAG: + if (strcmp (name, "GNU") == 0 && descsz >= 8 && descsz % 4 == 0) + { + Elf_Data in = + { + .d_version = EV_CURRENT, + .d_type = ELF_T_WORD, + .d_size = descsz, + .d_buf = (void *) desc + }; + uint32_t buf[descsz / 4]; + Elf_Data out = + { + .d_version = EV_CURRENT, + .d_type = ELF_T_WORD, + .d_size = descsz, + .d_buf = buf + }; + + if (elf32_xlatetom (&out, &in, ebl->data) != NULL) + { + const char *os; + switch (buf[0]) + { + case ELF_NOTE_OS_LINUX: + os = "Linux"; + break; + + case ELF_NOTE_OS_GNU: + os = "GNU"; + break; + + case ELF_NOTE_OS_SOLARIS2: + os = "Solaris"; + break; + + case ELF_NOTE_OS_FREEBSD: + os = "FreeBSD"; + break; + + default: + os = "???"; + break; + } + + printf (gettext (" OS: %s, ABI: "), os); + for (size_t cnt = 1; cnt < descsz / 4; ++cnt) + { + if (cnt > 1) + putchar_unlocked ('.'); + printf ("%" PRIu32, buf[cnt]); + } + putchar_unlocked ('\n'); + } + break; + } + /* FALLTHROUGH */ + + default: + /* Unknown type. */ + break; + } +} diff --git a/3rdparty/elfutils/libebl/eblobjnotetypename.c b/3rdparty/elfutils/libebl/eblobjnotetypename.c new file mode 100644 index 0000000..8a70e61 --- /dev/null +++ b/3rdparty/elfutils/libebl/eblobjnotetypename.c @@ -0,0 +1,80 @@ +/* Return note type name. + Copyright (C) 2002, 2007, 2009, 2011 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <inttypes.h> +#include <stdio.h> +#include <string.h> +#include <libeblP.h> + + +const char * +ebl_object_note_type_name (ebl, name, type, buf, len) + Ebl *ebl; + const char *name; + uint32_t type; + char *buf; + size_t len; +{ + const char *res = ebl->object_note_type_name (name, type, buf, len); + + if (res == NULL) + { + if (strcmp (name, "stapsdt") == 0) + { + snprintf (buf, len, "Version: %" PRIu32, type); + return buf; + } + + static const char *knowntypes[] = + { +#define KNOWNSTYPE(name) [NT_##name] = #name + KNOWNSTYPE (VERSION), + KNOWNSTYPE (GNU_HWCAP), + KNOWNSTYPE (GNU_BUILD_ID), + KNOWNSTYPE (GNU_GOLD_VERSION), + }; + + /* Handle standard names. */ + if (type < sizeof (knowntypes) / sizeof (knowntypes[0]) + && knowntypes[type] != NULL) + res = knowntypes[type]; + else + { + snprintf (buf, len, "%s: %" PRIu32, gettext ("<unknown>"), type); + + res = buf; + } + } + + return res; +} diff --git a/3rdparty/elfutils/libebl/eblopenbackend.c b/3rdparty/elfutils/libebl/eblopenbackend.c new file mode 100644 index 0000000..3a22f53 --- /dev/null +++ b/3rdparty/elfutils/libebl/eblopenbackend.c @@ -0,0 +1,763 @@ +/* Generate ELF backend handle. + Copyright (C) 2000-2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dlfcn.h> +#include <error.h> +#include <libelfP.h> +#include <dwarf.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#include <libeblP.h> + + +/* This table should contain the complete list of architectures as far + as the ELF specification is concerned. */ +/* XXX When things are stable replace the string pointers with char + arrays to avoid relocations. */ +static const struct +{ + const char *dsoname; + const char *emulation; + const char *prefix; + int prefix_len; + int em; + int class; + int data; +} machines[] = +{ + { "i386", "elf_i386", "i386", 4, EM_386, ELFCLASS32, ELFDATA2LSB }, + { "ia64", "elf_ia64", "ia64", 4, EM_IA_64, ELFCLASS64, ELFDATA2LSB }, + { "alpha", "elf_alpha", "alpha", 5, EM_ALPHA, ELFCLASS64, ELFDATA2LSB }, + { "x86_64", "elf_x86_64", "x86_64", 6, EM_X86_64, ELFCLASS64, ELFDATA2LSB }, + { "ppc", "elf_ppc", "ppc", 3, EM_PPC, ELFCLASS32, ELFDATA2MSB }, + { "ppc64", "elf_ppc64", "ppc64", 5, EM_PPC64, ELFCLASS64, ELFDATA2MSB }, + { "tilegx", "elf_tilegx", "tilegx", 6, EM_TILEGX, ELFCLASS64, ELFDATA2LSB }, + // XXX class and machine fields need to be filled in for all archs. + { "sh", "elf_sh", "sh", 2, EM_SH, 0, 0 }, + { "arm", "ebl_arm", "arm", 3, EM_ARM, 0, 0 }, + { "sparc", "elf_sparcv9", "sparc", 5, EM_SPARCV9, 0, 0 }, + { "sparc", "elf_sparc", "sparc", 5, EM_SPARC, 0, 0 }, + { "sparc", "elf_sparcv8plus", "sparc", 5, EM_SPARC32PLUS, 0, 0 }, + { "s390", "ebl_s390", "s390", 4, EM_S390, 0, 0 }, + + { "m32", "elf_m32", "m32", 3, EM_M32, 0, 0 }, + { "m68k", "elf_m68k", "m68k", 4, EM_68K, 0, 0 }, + { "m88k", "elf_m88k", "m88k", 4, EM_88K, 0, 0 }, + { "i860", "elf_i860", "i860", 4, EM_860, 0, 0 }, + { "s370", "ebl_s370", "s370", 4, EM_S370, 0, 0 }, + { "parisc", "elf_parisc", "parisc", 6, EM_PARISC, 0, 0 }, + { "vpp500", "elf_vpp500", "vpp500", 5, EM_VPP500, 0, 0 }, + { "sparc", "elf_v8plus", "v8plus", 6, EM_SPARC32PLUS, 0, 0 }, + { "i960", "elf_i960", "i960", 4, EM_960, 0, 0 }, + { "v800", "ebl_v800", "v800", 4, EM_V800, 0, 0 }, + { "fr20", "ebl_fr20", "fr20", 4, EM_FR20, 0, 0 }, + { "rh32", "ebl_rh32", "rh32", 4, EM_RH32, 0, 0 }, + { "rce", "ebl_rce", "rce", 3, EM_RCE, 0, 0 }, + { "tricore", "elf_tricore", "tricore", 7, EM_TRICORE, 0, 0 }, + { "arc", "elf_arc", "arc", 3, EM_ARC, 0, 0 }, + { "h8", "elf_h8_300", "h8_300", 6, EM_H8_300, 0, 0 }, + { "h8", "elf_h8_300h", "h8_300h", 6, EM_H8_300H, 0, 0 }, + { "h8", "elf_h8s", "h8s", 6, EM_H8S, 0, 0 }, + { "h8", "elf_h8_500", "h8_500", 6, EM_H8_500, 0, 0 }, + { "coldfire", "elf_coldfire", "coldfire", 8, EM_COLDFIRE, 0, 0 }, + { "m68k", "elf_68hc12", "68hc12", 6, EM_68HC12, 0, 0 }, + { "mma", "elf_mma", "mma", 3, EM_MMA, 0, 0 }, + { "pcp", "elf_pcp", "pcp", 3, EM_PCP, 0, 0 }, + { "ncpu", "elf_ncpu", "ncpu", 4, EM_NCPU, 0, 0 }, + { "ndr1", "elf_ndr1", "ndr1", 4, EM_NDR1, 0, 0 }, + { "starcore", "elf_starcore", "starcore", 8, EM_STARCORE, 0, 0 }, + { "me16", "elf_me16", "em16", 4, EM_ME16, 0, 0 }, + { "st100", "elf_st100", "st100", 5, EM_ST100, 0, 0 }, + { "tinyj", "elf_tinyj", "tinyj", 5, EM_TINYJ, 0, 0 }, + { "pdsp", "elf_pdsp", "pdsp", 4, EM_PDSP, 0, 0 }, + { "fx66", "elf_fx66", "fx66", 4, EM_FX66, 0, 0 }, + { "st9plus", "elf_st9plus", "st9plus", 7, EM_ST9PLUS, 0, 0 }, + { "st7", "elf_st7", "st7", 3, EM_ST7, 0, 0 }, + { "m68k", "elf_68hc16", "68hc16", 6, EM_68HC16, 0, 0 }, + { "m68k", "elf_68hc11", "68hc11", 6, EM_68HC11, 0, 0 }, + { "m68k", "elf_68hc08", "68hc08", 6, EM_68HC08, 0, 0 }, + { "m68k", "elf_68hc05", "68hc05", 6, EM_68HC05, 0, 0 }, + { "svx", "elf_svx", "svx", 3, EM_SVX, 0, 0 }, + { "st19", "elf_st19", "st19", 4, EM_ST19, 0, 0 }, + { "vax", "elf_vax", "vax", 3, EM_VAX, 0, 0 }, + { "cris", "elf_cris", "cris", 4, EM_CRIS, 0, 0 }, + { "javelin", "elf_javelin", "javelin", 7, EM_JAVELIN, 0, 0 }, + { "firepath", "elf_firepath", "firepath", 8, EM_FIREPATH, 0, 0 }, + { "zsp", "elf_zsp", "zsp", 3, EM_ZSP, 0, 0 }, + { "mmix", "elf_mmix", "mmix", 4, EM_MMIX, 0, 0 }, + { "hunay", "elf_huany", "huany", 5, EM_HUANY, 0, 0 }, + { "prism", "elf_prism", "prism", 5, EM_PRISM, 0, 0 }, + { "avr", "elf_avr", "avr", 3, EM_AVR, 0, 0 }, + { "fr30", "elf_fr30", "fr30", 4, EM_FR30, 0, 0 }, + { "dv10", "elf_dv10", "dv10", 4, EM_D10V, 0, 0 }, + { "dv30", "elf_dv30", "dv30", 4, EM_D30V, 0, 0 }, + { "v850", "elf_v850", "v850", 4, EM_V850, 0, 0 }, + { "m32r", "elf_m32r", "m32r", 4, EM_M32R, 0, 0 }, + { "mn10300", "elf_mn10300", "mn10300", 7, EM_MN10300, 0, 0 }, + { "mn10200", "elf_mn10200", "mn10200", 7, EM_MN10200, 0, 0 }, + { "pj", "elf_pj", "pj", 2, EM_PJ, 0, 0 }, + { "openrisc", "elf_openrisc", "openrisc", 8, EM_OPENRISC, 0, 0 }, + { "arc", "elf_arc_a5", "arc_a5", 6, EM_ARC_A5, 0, 0 }, + { "xtensa", "elf_xtensa", "xtensa", 6, EM_XTENSA, 0, 0 }, + { "aarch64", "elf_aarch64", "aarch64", 7, EM_AARCH64, ELFCLASS64, 0 }, +}; +#define nmachines (sizeof (machines) / sizeof (machines[0])) + + +/* Default callbacks. Mostly they just return the error value. */ +static const char *default_object_type_name (int ignore, char *buf, + size_t len); +static const char *default_reloc_type_name (int ignore, char *buf, size_t len); +static bool default_reloc_type_check (int ignore); +static bool default_reloc_valid_use (Elf *elf, int ignore); +static Elf_Type default_reloc_simple_type (Ebl *ebl, int ignore); +static bool default_gotpc_reloc_check (Elf *elf, int ignore); +static const char *default_segment_type_name (int ignore, char *buf, + size_t len); +static const char *default_section_type_name (int ignore, char *buf, + size_t len); +static const char *default_section_name (int ignore, int ignore2, char *buf, + size_t len); +static const char *default_machine_flag_name (Elf64_Word *ignore); +static bool default_machine_flag_check (Elf64_Word flags); +static bool default_machine_section_flag_check (GElf_Xword flags); +static const char *default_symbol_type_name (int ignore, char *buf, + size_t len); +static const char *default_symbol_binding_name (int ignore, char *buf, + size_t len); +static const char *default_dynamic_tag_name (int64_t ignore, char *buf, + size_t len); +static bool default_dynamic_tag_check (int64_t ignore); +static GElf_Word default_sh_flags_combine (GElf_Word flags1, GElf_Word flags2); +static const char *default_osabi_name (int ignore, char *buf, size_t len); +static void default_destr (struct ebl *ignore); +static const char *default_core_note_type_name (uint32_t, char *buf, + size_t len); +static const char *default_object_note_type_name (const char *name, uint32_t, + char *buf, size_t len); +static int default_core_note (const GElf_Nhdr *nhdr, const char *name, + GElf_Word *regs_offset, size_t *nregloc, + const Ebl_Register_Location **reglocs, + size_t *nitems, const Ebl_Core_Item **); +static int default_auxv_info (GElf_Xword a_type, + const char **name, const char **format); +static bool default_object_note (const char *name, uint32_t type, + uint32_t descsz, const char *desc); +static bool default_debugscn_p (const char *name); +static bool default_copy_reloc_p (int reloc); +static bool default_none_reloc_p (int reloc); +static bool default_relative_reloc_p (int reloc); +static bool default_check_special_symbol (Elf *elf, GElf_Ehdr *ehdr, + const GElf_Sym *sym, + const char *name, + const GElf_Shdr *destshdr); +static bool default_check_st_other_bits (unsigned char st_other); +static bool default_check_special_section (Ebl *, int, + const GElf_Shdr *, const char *); +static bool default_bss_plt_p (Elf *elf); +static int default_return_value_location (Dwarf_Die *functypedie, + const Dwarf_Op **locops); +static ssize_t default_register_info (Ebl *ebl, + int regno, char *name, size_t namelen, + const char **prefix, + const char **setname, + int *bits, int *type); +static int default_syscall_abi (Ebl *ebl, int *sp, int *pc, + int *callno, int args[6]); +static bool default_check_object_attribute (Ebl *ebl, const char *vendor, + int tag, uint64_t value, + const char **tag_name, + const char **value_name); +static bool default_check_reloc_target_type (Ebl *ebl, Elf64_Word sh_type); +static int default_abi_cfi (Ebl *ebl, Dwarf_CIE *abi_info); + + +static void +fill_defaults (Ebl *result) +{ + result->object_type_name = default_object_type_name; + result->reloc_type_name = default_reloc_type_name; + result->reloc_type_check = default_reloc_type_check; + result->reloc_valid_use = default_reloc_valid_use; + result->reloc_simple_type = default_reloc_simple_type; + result->gotpc_reloc_check = default_gotpc_reloc_check; + result->segment_type_name = default_segment_type_name; + result->section_type_name = default_section_type_name; + result->section_name = default_section_name; + result->machine_flag_name = default_machine_flag_name; + result->machine_flag_check = default_machine_flag_check; + result->machine_section_flag_check = default_machine_section_flag_check; + result->check_special_section = default_check_special_section; + result->symbol_type_name = default_symbol_type_name; + result->symbol_binding_name = default_symbol_binding_name; + result->dynamic_tag_name = default_dynamic_tag_name; + result->dynamic_tag_check = default_dynamic_tag_check; + result->sh_flags_combine = default_sh_flags_combine; + result->osabi_name = default_osabi_name; + result->core_note_type_name = default_core_note_type_name; + result->object_note_type_name = default_object_note_type_name; + result->core_note = default_core_note; + result->auxv_info = default_auxv_info; + result->object_note = default_object_note; + result->debugscn_p = default_debugscn_p; + result->copy_reloc_p = default_copy_reloc_p; + result->none_reloc_p = default_none_reloc_p; + result->relative_reloc_p = default_relative_reloc_p; + result->check_special_symbol = default_check_special_symbol; + result->check_st_other_bits = default_check_st_other_bits; + result->bss_plt_p = default_bss_plt_p; + result->return_value_location = default_return_value_location; + result->register_info = default_register_info; + result->syscall_abi = default_syscall_abi; + result->check_object_attribute = default_check_object_attribute; + result->check_reloc_target_type = default_check_reloc_target_type; + result->disasm = NULL; + result->abi_cfi = default_abi_cfi; + result->destr = default_destr; + result->sysvhash_entrysize = sizeof (Elf32_Word); +} + + +/* Find an appropriate backend for the file associated with ELF. */ +static Ebl * +openbackend (elf, emulation, machine) + Elf *elf; + const char *emulation; + GElf_Half machine; +{ + Ebl *result; + size_t cnt; + + /* First allocate the data structure for the result. We do this + here since this assures that the structure is always large + enough. */ + result = (Ebl *) calloc (1, sizeof (Ebl)); + if (result == NULL) + { + // XXX uncomment + // __libebl_seterror (ELF_E_NOMEM); + return NULL; + } + + /* Fill in the default callbacks. The initializer for the machine + specific module can overwrite the values. */ + fill_defaults (result); + + /* XXX Currently all we do is to look at 'e_machine' value in the + ELF header. With an internal mapping table from EM_* value to + DSO name we try to load the appropriate module to handle this + binary type. + + Multiple modules for the same machine type are possible and they + will be tried in sequence. The lookup process will only stop + when a module which can handle the machine type is found or all + available matching modules are tried. */ + for (cnt = 0; cnt < nmachines; ++cnt) + if ((emulation != NULL && strcmp (emulation, machines[cnt].emulation) == 0) + || (emulation == NULL && machines[cnt].em == machine)) + { + /* Well, we know the emulation name now. */ + result->emulation = machines[cnt].emulation; + + /* We access some data structures directly. Make sure the 32 and + 64 bit variants are laid out the same. */ + assert (offsetof (Elf32_Ehdr, e_machine) + == offsetof (Elf64_Ehdr, e_machine)); + assert (sizeof (((Elf32_Ehdr *) 0)->e_machine) + == sizeof (((Elf64_Ehdr *) 0)->e_machine)); + assert (offsetof (Elf, state.elf32.ehdr) + == offsetof (Elf, state.elf64.ehdr)); + + /* Prefer taking the information from the ELF file. */ + if (elf == NULL) + { + result->machine = machines[cnt].em; + result->class = machines[cnt].class; + result->data = machines[cnt].data; + } + else + { + result->machine = elf->state.elf32.ehdr->e_machine; + result->class = elf->state.elf32.ehdr->e_ident[EI_CLASS]; + result->data = elf->state.elf32.ehdr->e_ident[EI_DATA]; + } + +#ifndef LIBEBL_SUBDIR +# define LIBEBL_SUBDIR PACKAGE +#endif +#define ORIGINDIR "$ORIGIN/../$LIB/" LIBEBL_SUBDIR "/" + + /* Give it a try. At least the machine type matches. First + try to load the module. */ + char dsoname[100]; + strcpy (stpcpy (stpcpy (dsoname, ORIGINDIR "libebl_"), + machines[cnt].dsoname), + ".so"); + + void *h = dlopen (dsoname, RTLD_LAZY); + if (h == NULL) + { + strcpy (stpcpy (stpcpy (dsoname, "libebl_"), + machines[cnt].dsoname), + ".so"); + h = dlopen (dsoname, RTLD_LAZY); + } + + /* Try without an explicit path. */ + if (h != NULL) + { + /* We managed to load the object. Now see whether the + initialization function likes our file. */ + static const char version[] = MODVERSION; + const char *modversion; + ebl_bhinit_t initp; + char symname[machines[cnt].prefix_len + sizeof "_init"]; + + strcpy (mempcpy (symname, machines[cnt].prefix, + machines[cnt].prefix_len), "_init"); + + initp = (ebl_bhinit_t) dlsym (h, symname); + if (initp != NULL + && (modversion = initp (elf, machine, result, sizeof (Ebl))) + && strcmp (version, modversion) == 0) + { + /* We found a module to handle our file. */ + result->dlhandle = h; + result->elf = elf; + + /* A few entries are mandatory. */ + assert (result->name != NULL); + assert (result->destr != NULL); + + return result; + } + + /* Not the module we need. */ + (void) dlclose (h); + } + + /* We cannot find a DSO but the emulation/machine ID matches. + Return that information. */ + result->dlhandle = NULL; + result->elf = elf; + result->name = machines[cnt].prefix; + fill_defaults (result); + + return result; + } + + /* Nothing matched. We use only the default callbacks. */ + result->dlhandle = NULL; + result->elf = elf; + result->emulation = "<unknown>"; + result->name = "<unknown>"; + fill_defaults (result); + + return result; +} + + +/* Find an appropriate backend for the file associated with ELF. */ +Ebl * +ebl_openbackend (elf) + Elf *elf; +{ + GElf_Ehdr ehdr_mem; + GElf_Ehdr *ehdr; + + /* Get the ELF header of the object. */ + ehdr = gelf_getehdr (elf, &ehdr_mem); + if (ehdr == NULL) + { + // XXX uncomment + // __libebl_seterror (elf_errno ()); + return NULL; + } + + return openbackend (elf, NULL, ehdr->e_machine); +} + + +/* Find backend without underlying ELF file. */ +Ebl * +ebl_openbackend_machine (machine) + GElf_Half machine; +{ + return openbackend (NULL, NULL, machine); +} + + +/* Find backend with given emulation name. */ +Ebl * +ebl_openbackend_emulation (const char *emulation) +{ + return openbackend (NULL, emulation, EM_NONE); +} + + +/* Default callbacks. Mostly they just return the error value. */ +static const char * +default_object_type_name (int ignore __attribute__ ((unused)), + char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + return NULL; +} + +static const char * +default_reloc_type_name (int ignore __attribute__ ((unused)), + char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + return NULL; +} + +static bool +default_reloc_type_check (int ignore __attribute__ ((unused))) +{ + return false; +} + +static bool +default_reloc_valid_use (Elf *elf __attribute__ ((unused)), + int ignore __attribute__ ((unused))) +{ + return false; +} + +static Elf_Type +default_reloc_simple_type (Ebl *eh __attribute__ ((unused)), + int ignore __attribute__ ((unused))) +{ + return ELF_T_NUM; +} + +static bool +default_gotpc_reloc_check (Elf *elf __attribute__ ((unused)), + int ignore __attribute__ ((unused))) +{ + return false; +} + +static const char * +default_segment_type_name (int ignore __attribute__ ((unused)), + char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + return NULL; +} + +static const char * +default_section_type_name (int ignore __attribute__ ((unused)), + char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + return NULL; +} + +static const char * +default_section_name (int ignore __attribute__ ((unused)), + int ignore2 __attribute__ ((unused)), + char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + return NULL; +} + +static const char * +default_machine_flag_name (Elf64_Word *ignore __attribute__ ((unused))) +{ + return NULL; +} + +static bool +default_machine_flag_check (Elf64_Word flags __attribute__ ((unused))) +{ + return flags == 0; +} + +static bool +default_machine_section_flag_check (GElf_Xword flags) +{ + return flags == 0; +} + +static bool +default_check_special_section (Ebl *ebl __attribute__ ((unused)), + int ndx __attribute__ ((unused)), + const GElf_Shdr *shdr __attribute__ ((unused)), + const char *sname __attribute__ ((unused))) +{ + return false; +} + +static const char * +default_symbol_type_name (int ignore __attribute__ ((unused)), + char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + return NULL; +} + +static const char * +default_symbol_binding_name (int ignore __attribute__ ((unused)), + char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + return NULL; +} + +static const char * +default_dynamic_tag_name (int64_t ignore __attribute__ ((unused)), + char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + return NULL; +} + +static bool +default_dynamic_tag_check (int64_t ignore __attribute__ ((unused))) +{ + return false; +} + +static GElf_Word +default_sh_flags_combine (GElf_Word flags1, GElf_Word flags2) +{ + return SH_FLAGS_COMBINE (flags1, flags2); +} + +static void +default_destr (struct ebl *ignore __attribute__ ((unused))) +{ +} + +static const char * +default_osabi_name (int ignore __attribute__ ((unused)), + char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + return NULL; +} + +static const char * +default_core_note_type_name (uint32_t ignore __attribute__ ((unused)), + char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + return NULL; +} + +static int +default_auxv_info (GElf_Xword a_type __attribute__ ((unused)), + const char **name __attribute__ ((unused)), + const char **format __attribute__ ((unused))) +{ + return 0; +} + +static int +default_core_note (const GElf_Nhdr *nhdr __attribute__ ((unused)), + const char *name __attribute__ ((unused)), + GElf_Word *ro __attribute__ ((unused)), + size_t *nregloc __attribute__ ((unused)), + const Ebl_Register_Location **reglocs + __attribute__ ((unused)), + size_t *nitems __attribute__ ((unused)), + const Ebl_Core_Item **items __attribute__ ((unused))) +{ + return 0; +} + +static const char * +default_object_note_type_name (const char *name __attribute__ ((unused)), + uint32_t ignore __attribute__ ((unused)), + char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + return NULL; +} + +static bool +default_object_note (const char *name __attribute__ ((unused)), + uint32_t type __attribute__ ((unused)), + uint32_t descsz __attribute__ ((unused)), + const char *desc __attribute__ ((unused))) +{ + return NULL; +} + +static bool +default_debugscn_p (const char *name) +{ + /* We know by default only about the DWARF debug sections which have + fixed names. */ + static const char *dwarf_scn_names[] = + { + /* DWARF 1 */ + ".debug", + ".line", + /* GNU DWARF 1 extensions */ + ".debug_srcinfo", + ".debug_sfnames", + /* DWARF 1.1 and DWARF 2 */ + ".debug_aranges", + ".debug_pubnames", + /* DWARF 2 */ + ".debug_info", + ".debug_abbrev", + ".debug_line", + ".debug_frame", + ".debug_str", + ".debug_loc", + ".debug_macinfo", + /* DWARF 3 */ + ".debug_ranges", + ".debug_pubtypes", + /* DWARF 4 */ + ".debug_types", + /* GDB DWARF 4 extension */ + ".gdb_index", + /* GNU/DWARF 5 extension/proposal */ + ".debug_macro", + /* SGI/MIPS DWARF 2 extensions */ + ".debug_weaknames", + ".debug_funcnames", + ".debug_typenames", + ".debug_varnames" + }; + const size_t ndwarf_scn_names = (sizeof (dwarf_scn_names) + / sizeof (dwarf_scn_names[0])); + for (size_t cnt = 0; cnt < ndwarf_scn_names; ++cnt) + if (strcmp (name, dwarf_scn_names[cnt]) == 0) + return true; + + return false; +} + +static bool +default_copy_reloc_p (int reloc __attribute__ ((unused))) +{ + return false; +} +strong_alias (default_copy_reloc_p, default_none_reloc_p) +strong_alias (default_copy_reloc_p, default_relative_reloc_p) + +static bool +default_check_special_symbol (Elf *elf __attribute__ ((unused)), + GElf_Ehdr *ehdr __attribute__ ((unused)), + const GElf_Sym *sym __attribute__ ((unused)), + const char *name __attribute__ ((unused)), + const GElf_Shdr *destshdr __attribute__ ((unused))) +{ + return false; +} + +static bool +default_check_st_other_bits (unsigned char st_other __attribute__ ((unused))) +{ + return false; +} + + +static bool +default_bss_plt_p (Elf *elf __attribute__ ((unused))) +{ + return false; +} + +static int +default_return_value_location (Dwarf_Die *functypedie __attribute__ ((unused)), + const Dwarf_Op **locops __attribute__ ((unused))) +{ + return -2; +} + +static ssize_t +default_register_info (Ebl *ebl __attribute__ ((unused)), + int regno, char *name, size_t namelen, + const char **prefix, + const char **setname, + int *bits, int *type) +{ + if (name == NULL) + return 0; + + *setname = "???"; + *prefix = ""; + *bits = -1; + *type = DW_ATE_void; + return snprintf (name, namelen, "reg%d", regno); +} + +static int +default_syscall_abi (Ebl *ebl __attribute__ ((unused)), + int *sp, int *pc, int *callno, int args[6]) +{ + *sp = *pc = *callno = -1; + args[0] = -1; + args[1] = -1; + args[2] = -1; + args[3] = -1; + args[4] = -1; + args[5] = -1; + return -1; +} + +static bool +default_check_object_attribute (Ebl *ebl __attribute__ ((unused)), + const char *vendor __attribute__ ((unused)), + int tag __attribute__ ((unused)), + uint64_t value __attribute__ ((unused)), + const char **tag_name, const char **value_name) +{ + *tag_name = NULL; + *value_name = NULL; + return false; +} + +static bool +default_check_reloc_target_type (Ebl *ebl __attribute__ ((unused)), + Elf64_Word sh_type __attribute__ ((unused))) +{ + return false; +} + +static int +default_abi_cfi (Ebl *ebl __attribute__ ((unused)), + Dwarf_CIE *abi_info __attribute__ ((unused))) +{ + return -1; +} diff --git a/3rdparty/elfutils/libebl/eblosabiname.c b/3rdparty/elfutils/libebl/eblosabiname.c new file mode 100644 index 0000000..3ea6f56 --- /dev/null +++ b/3rdparty/elfutils/libebl/eblosabiname.c @@ -0,0 +1,84 @@ +/* Return OS ABI name + Copyright (C) 2001, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2001. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> +#include <libeblP.h> + + +const char * +ebl_osabi_name (ebl, osabi, buf, len) + Ebl *ebl; + int osabi; + char *buf; + size_t len; +{ + const char *res = ebl != NULL ? ebl->osabi_name (osabi, buf, len) : NULL; + + if (res == NULL) + { + if (osabi == ELFOSABI_NONE) + res = "UNIX - System V"; + else if (osabi == ELFOSABI_HPUX) + res = "HP/UX"; + else if (osabi == ELFOSABI_NETBSD) + res = "NetBSD"; + else if (osabi == ELFOSABI_LINUX) + res = "Linux"; + else if (osabi == ELFOSABI_SOLARIS) + res = "Solaris"; + else if (osabi == ELFOSABI_AIX) + res = "AIX"; + else if (osabi == ELFOSABI_IRIX) + res = "Irix"; + else if (osabi == ELFOSABI_FREEBSD) + res = "FreeBSD"; + else if (osabi == ELFOSABI_TRU64) + res = "TRU64"; + else if (osabi == ELFOSABI_MODESTO) + res = "Modesto"; + else if (osabi == ELFOSABI_OPENBSD) + res = "OpenBSD"; + else if (osabi == ELFOSABI_ARM) + res = "Arm"; + else if (osabi == ELFOSABI_STANDALONE) + res = gettext ("Stand alone"); + else + { + snprintf (buf, len, "%s: %d", gettext ("<unknown>"), osabi); + + res = buf; + } + } + + return res; +} diff --git a/3rdparty/elfutils/libebl/eblreginfo.c b/3rdparty/elfutils/libebl/eblreginfo.c new file mode 100644 index 0000000..f213b4a --- /dev/null +++ b/3rdparty/elfutils/libebl/eblreginfo.c @@ -0,0 +1,50 @@ +/* Return register name information. + Copyright (C) 2005, 2006 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <inttypes.h> +#include <libeblP.h> + + +ssize_t +ebl_register_info (ebl, regno, name, namelen, prefix, setname, bits, type) + Ebl *ebl; + int regno; + char *name; + size_t namelen; + const char **prefix; + const char **setname; + int *bits; + int *type; +{ + return ebl == NULL ? -1 : ebl->register_info (ebl, regno, name, namelen, + prefix, setname, bits, type); +} diff --git a/3rdparty/elfutils/libebl/eblrelativerelocp.c b/3rdparty/elfutils/libebl/eblrelativerelocp.c new file mode 100644 index 0000000..297caec --- /dev/null +++ b/3rdparty/elfutils/libebl/eblrelativerelocp.c @@ -0,0 +1,43 @@ +/* Check whether given relocation is a relative relocation. + Copyright (C) 2006 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2006. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libeblP.h> + + +bool +ebl_relative_reloc_p (ebl, reloc) + Ebl *ebl; + int reloc; +{ + return ebl->relative_reloc_p (reloc); +} diff --git a/3rdparty/elfutils/libebl/eblrelocsimpletype.c b/3rdparty/elfutils/libebl/eblrelocsimpletype.c new file mode 100644 index 0000000..085fc93 --- /dev/null +++ b/3rdparty/elfutils/libebl/eblrelocsimpletype.c @@ -0,0 +1,42 @@ +/* Check relocation type for simple types. + Copyright (C) 2005 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libeblP.h> + + +Elf_Type +ebl_reloc_simple_type (ebl, reloc) + Ebl *ebl; + int reloc; +{ + return ebl != NULL ? ebl->reloc_simple_type (ebl, reloc) : ELF_T_NUM; +} diff --git a/3rdparty/elfutils/libebl/eblreloctypecheck.c b/3rdparty/elfutils/libebl/eblreloctypecheck.c new file mode 100644 index 0000000..e322ace --- /dev/null +++ b/3rdparty/elfutils/libebl/eblreloctypecheck.c @@ -0,0 +1,43 @@ +/* Check relocation type. + Copyright (C) 2001, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2001. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libeblP.h> + + +bool +ebl_reloc_type_check (ebl, reloc) + Ebl *ebl; + int reloc; +{ + return ebl != NULL ? ebl->reloc_type_check (reloc) : false; +} diff --git a/3rdparty/elfutils/libebl/eblreloctypename.c b/3rdparty/elfutils/libebl/eblreloctypename.c new file mode 100644 index 0000000..fb39101 --- /dev/null +++ b/3rdparty/elfutils/libebl/eblreloctypename.c @@ -0,0 +1,53 @@ +/* Return relocation type name. + Copyright (C) 2001, 2002, 2009 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2001. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> +#include <libeblP.h> + + +const char * +ebl_reloc_type_name (ebl, reloc, buf, len) + Ebl *ebl; + int reloc; + char *buf; + size_t len; +{ + const char *res; + + res = ebl != NULL ? ebl->reloc_type_name (reloc, buf, len) : NULL; + if (res == NULL) + /* There are no generic relocation type names. */ + res = "<INVALID RELOC>"; + + return res; +} diff --git a/3rdparty/elfutils/libebl/eblrelocvaliduse.c b/3rdparty/elfutils/libebl/eblrelocvaliduse.c new file mode 100644 index 0000000..62c4ae7 --- /dev/null +++ b/3rdparty/elfutils/libebl/eblrelocvaliduse.c @@ -0,0 +1,43 @@ +/* Check relocation type use. + Copyright (C) 2003 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libeblP.h> + + +bool +ebl_reloc_valid_use (ebl, reloc) + Ebl *ebl; + int reloc; +{ + return ebl != NULL ? ebl->reloc_valid_use (ebl->elf, reloc) : false; +} diff --git a/3rdparty/elfutils/libebl/eblresolvesym.c b/3rdparty/elfutils/libebl/eblresolvesym.c new file mode 100644 index 0000000..470f6f0 --- /dev/null +++ b/3rdparty/elfutils/libebl/eblresolvesym.c @@ -0,0 +1,43 @@ +/* Resolve a symbol value to an allocated section of the Elf file. + Copyright (C) 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libeblP.h> +#include <assert.h> + +bool +ebl_resolve_sym_value (Ebl *ebl, GElf_Addr *addr) +{ + if (ebl == NULL || ebl->resolve_sym_value == NULL) + return false; + + return ebl->resolve_sym_value (ebl, addr); +} diff --git a/3rdparty/elfutils/libebl/eblretval.c b/3rdparty/elfutils/libebl/eblretval.c new file mode 100644 index 0000000..056a549 --- /dev/null +++ b/3rdparty/elfutils/libebl/eblretval.c @@ -0,0 +1,44 @@ +/* Return location expression to find return value given a function type DIE. + Copyright (C) 2005 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <inttypes.h> +#include <libeblP.h> + + +int +ebl_return_value_location (ebl, functypedie, locops) + Ebl *ebl; + Dwarf_Die *functypedie; + const Dwarf_Op **locops; +{ + return ebl == NULL ? -1 : ebl->return_value_location (functypedie, locops); +} diff --git a/3rdparty/elfutils/libebl/eblsectionname.c b/3rdparty/elfutils/libebl/eblsectionname.c new file mode 100644 index 0000000..81c7add --- /dev/null +++ b/3rdparty/elfutils/libebl/eblsectionname.c @@ -0,0 +1,96 @@ +/* Return section name. + Copyright (C) 2001, 2002, 2004 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2001. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> +#include <libeblP.h> + + +const char * +ebl_section_name (ebl, section, xsection, buf, len, scnnames, shnum) + Ebl *ebl; + int section; + int xsection; + char *buf; + size_t len; + const char *scnnames[]; + size_t shnum; +{ + const char *res = ebl != NULL ? ebl->section_name (section, xsection, + buf, len) : NULL; + + if (res == NULL) + { + if (section == SHN_UNDEF) + res = "UNDEF"; + else if (section == SHN_ABS) + res = "ABS"; + else if (section == SHN_COMMON) + res = "COMMON"; + else if (section == SHN_BEFORE) + res = "BEFORE"; + else if (section == SHN_AFTER) + res = "AFTER"; + else if ((section < SHN_LORESERVE || section == SHN_XINDEX) + && (size_t) section < shnum) + { + int idx = section != SHN_XINDEX ? section : xsection; + + if (scnnames != NULL) + res = scnnames[idx]; + else + { + snprintf (buf, len, "%d", idx); + res = buf; + } + } + else + { + /* Handle OS-specific section names. */ + if (section == SHN_XINDEX) + snprintf (buf, len, "%s: %d", "XINDEX", xsection); + else if (section >= SHN_LOOS && section <= SHN_HIOS) + snprintf (buf, len, "LOOS+%x", section - SHN_LOOS); + /* Handle processor-specific section names. */ + else if (section >= SHN_LOPROC && section <= SHN_HIPROC) + snprintf (buf, len, "LOPROC+%x", section - SHN_LOPROC); + else if (section >= SHN_LORESERVE && section <= SHN_HIRESERVE) + snprintf (buf, len, "LORESERVE+%x", section - SHN_LORESERVE); + else + snprintf (buf, len, "%s: %d", gettext ("<unknown>"), section); + + res = buf; + } + } + + return res; +} diff --git a/3rdparty/elfutils/libebl/eblsectionstripp.c b/3rdparty/elfutils/libebl/eblsectionstripp.c new file mode 100644 index 0000000..c6cda63 --- /dev/null +++ b/3rdparty/elfutils/libebl/eblsectionstripp.c @@ -0,0 +1,67 @@ +/* Check whether section can be stripped. + Copyright (C) 2005, 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> +#include "libeblP.h" + + +bool +ebl_section_strip_p (Ebl *ebl, const GElf_Ehdr *ehdr, const GElf_Shdr *shdr, + const char *name, bool remove_comment, + bool only_remove_debug) +{ + /* If only debug information should be removed check the name. There + is unfortunately no other way. */ + if (unlikely (only_remove_debug)) + { + if (ebl_debugscn_p (ebl, name)) + return true; + + if (shdr->sh_type == SHT_RELA || shdr->sh_type == SHT_REL) + { + Elf_Scn *scn_l = elf_getscn (ebl->elf, (shdr)->sh_info); + GElf_Shdr shdr_mem_l; + GElf_Shdr *shdr_l = gelf_getshdr (scn_l, &shdr_mem_l); + if (shdr_l != NULL) + { + const char *s_l = elf_strptr (ebl->elf, ehdr->e_shstrndx, + shdr_l->sh_name); + if (s_l != NULL && ebl_debugscn_p (ebl, s_l)) + return true; + } + } + + return false; + } + + return SECTION_STRIP_P (shdr, name, remove_comment); +} diff --git a/3rdparty/elfutils/libebl/eblsectiontypename.c b/3rdparty/elfutils/libebl/eblsectiontypename.c new file mode 100644 index 0000000..3a30cd6 --- /dev/null +++ b/3rdparty/elfutils/libebl/eblsectiontypename.c @@ -0,0 +1,127 @@ +/* Return section type name. + Copyright (C) 2001, 2002, 2006, 2008 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2001. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> +#include <libeblP.h> + + +const char * +ebl_section_type_name (ebl, section, buf, len) + Ebl *ebl; + int section; + char *buf; + size_t len; +{ + const char *res = ebl->section_type_name (section, buf, len); + + if (res == NULL) + { + static const char *knowntypes[] = + { +#define KNOWNSTYPE(name) [SHT_##name] = #name + KNOWNSTYPE (NULL), + KNOWNSTYPE (PROGBITS), + KNOWNSTYPE (SYMTAB), + KNOWNSTYPE (STRTAB), + KNOWNSTYPE (RELA), + KNOWNSTYPE (HASH), + KNOWNSTYPE (DYNAMIC), + KNOWNSTYPE (NOTE), + KNOWNSTYPE (NOBITS), + KNOWNSTYPE (REL), + KNOWNSTYPE (SHLIB), + KNOWNSTYPE (DYNSYM), + KNOWNSTYPE (INIT_ARRAY), + KNOWNSTYPE (FINI_ARRAY), + KNOWNSTYPE (PREINIT_ARRAY), + KNOWNSTYPE (GROUP), + KNOWNSTYPE (SYMTAB_SHNDX) + }; + + /* Handle standard names. */ + if ((size_t) section < sizeof (knowntypes) / sizeof (knowntypes[0]) + && knowntypes[section] != NULL) + res = knowntypes[section]; + /* The symbol versioning/Sun extensions. */ + else if (section >= SHT_LOSUNW && section <= SHT_HISUNW) + { + static const char *sunwtypes[] = + { +#undef KNOWNSTYPE +#define KNOWNSTYPE(name) [SHT_##name - SHT_LOSUNW] = #name + KNOWNSTYPE (SUNW_move), + KNOWNSTYPE (SUNW_COMDAT), + KNOWNSTYPE (SUNW_syminfo), + KNOWNSTYPE (GNU_verdef), + KNOWNSTYPE (GNU_verneed), + KNOWNSTYPE (GNU_versym) + }; + res = sunwtypes[section - SHT_LOSUNW]; + } + else + /* A few GNU additions. */ + switch (section) + { + case SHT_CHECKSUM: + res = "CHECKSUM"; + break; + case SHT_GNU_LIBLIST: + res = "GNU_LIBLIST"; + break; + case SHT_GNU_HASH: + res = "GNU_HASH"; + break; + case SHT_GNU_ATTRIBUTES: + res = "GNU_ATTRIBUTES"; + break; + + default: + /* Handle OS-specific section names. */ + if (section >= SHT_LOOS && section <= SHT_HIOS) + snprintf (buf, len, "SHT_LOOS+%x", section - SHT_LOOS); + /* Handle processor-specific section names. */ + else if (section >= SHT_LOPROC && section <= SHT_HIPROC) + snprintf (buf, len, "SHT_LOPROC+%x", section - SHT_LOPROC); + else if ((unsigned int) section >= SHT_LOUSER + && (unsigned int) section <= SHT_HIUSER) + snprintf (buf, len, "SHT_LOUSER+%x", section - SHT_LOUSER); + else + snprintf (buf, len, "%s: %d", gettext ("<unknown>"), section); + + res = buf; + break; + } + } + + return res; +} diff --git a/3rdparty/elfutils/libebl/eblsegmenttypename.c b/3rdparty/elfutils/libebl/eblsegmenttypename.c new file mode 100644 index 0000000..3cad66e --- /dev/null +++ b/3rdparty/elfutils/libebl/eblsegmenttypename.c @@ -0,0 +1,90 @@ +/* Return segment type name. + Copyright (C) 2001, 2002, 2004 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2001. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> +#include <libeblP.h> + + +const char * +ebl_segment_type_name (ebl, segment, buf, len) + Ebl *ebl; + int segment; + char *buf; + size_t len; +{ + const char *res; + + res = ebl != NULL ? ebl->segment_type_name (segment, buf, len) : NULL; + if (res == NULL) + { + static const char *ptypes[PT_NUM] = + { +#define PTYPE(name) [PT_##name] = #name + PTYPE (NULL), + PTYPE (LOAD), + PTYPE (DYNAMIC), + PTYPE (INTERP), + PTYPE (NOTE), + PTYPE (SHLIB), + PTYPE (PHDR), + PTYPE (TLS) + }; + + /* Is it one of the standard segment types? */ + if (segment >= PT_NULL && segment < PT_NUM) + res = ptypes[segment]; + else if (segment == PT_GNU_EH_FRAME) + res = "GNU_EH_FRAME"; + else if (segment == PT_GNU_STACK) + res = "GNU_STACK"; + else if (segment == PT_GNU_RELRO) + res = "GNU_RELRO"; + else if (segment == PT_SUNWBSS) + res = "SUNWBSS"; + else if (segment == PT_SUNWSTACK) + res = "SUNWSTACK"; + else + { + if (segment >= PT_LOOS && segment <= PT_HIOS) + snprintf (buf, len, "LOOS+%d", segment - PT_LOOS); + else if (segment >= PT_LOPROC && segment <= PT_HIPROC) + snprintf (buf, len, "LOPROC+%d", segment - PT_LOPROC); + else + snprintf (buf, len, "%s: %d", gettext ("<unknown>"), segment); + + res = buf; + } + } + + return res; +} diff --git a/3rdparty/elfutils/libebl/eblshflagscombine.c b/3rdparty/elfutils/libebl/eblshflagscombine.c new file mode 100644 index 0000000..87625f8 --- /dev/null +++ b/3rdparty/elfutils/libebl/eblshflagscombine.c @@ -0,0 +1,44 @@ +/* Return combines section header flags value. + Copyright (C) 2001, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2001. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libeblP.h> + + +GElf_Word +ebl_sh_flags_combine (ebl, flags1, flags2) + Ebl *ebl; + GElf_Word flags1; + GElf_Word flags2; +{ + return ebl->sh_flags_combine (flags1, flags2); +} diff --git a/3rdparty/elfutils/libebl/eblstother.c b/3rdparty/elfutils/libebl/eblstother.c new file mode 100644 index 0000000..ccbf138 --- /dev/null +++ b/3rdparty/elfutils/libebl/eblstother.c @@ -0,0 +1,43 @@ +/* Check st_other flag. + Copyright (C) 2011 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libeblP.h> + + +bool +ebl_check_st_other_bits (ebl, st_other) + Ebl *ebl; + unsigned char st_other; +{ + return ((st_other ^ GELF_ST_VISIBILITY (st_other)) == 0 + || ebl->check_st_other_bits (st_other ^ GELF_ST_VISIBILITY (st_other))); +} diff --git a/3rdparty/elfutils/libebl/eblstrtab.c b/3rdparty/elfutils/libebl/eblstrtab.c new file mode 100644 index 0000000..798c34c --- /dev/null +++ b/3rdparty/elfutils/libebl/eblstrtab.c @@ -0,0 +1,358 @@ +/* ELF string table handling. + Copyright (C) 2000, 2001, 2002, 2005 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <inttypes.h> +#include <libelf.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/param.h> + +#include "libebl.h" +#include <system.h> + +#ifndef MIN +# define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif + + +struct Ebl_Strent +{ + const char *string; + size_t len; + struct Ebl_Strent *next; + struct Ebl_Strent *left; + struct Ebl_Strent *right; + size_t offset; + char reverse[0]; +}; + + +struct memoryblock +{ + struct memoryblock *next; + char memory[0]; +}; + + +struct Ebl_Strtab +{ + struct Ebl_Strent *root; + struct memoryblock *memory; + char *backp; + size_t left; + size_t total; + bool nullstr; + + struct Ebl_Strent null; +}; + + +/* Cache for the pagesize. */ +static size_t ps; +/* We correct this value a bit so that `malloc' is not allocating more + than a page. */ +#define MALLOC_OVERHEAD (2 * sizeof (void *)) + + +struct Ebl_Strtab * +ebl_strtabinit (bool nullstr) +{ + if (ps == 0) + { + ps = sysconf (_SC_PAGESIZE); + assert (sizeof (struct memoryblock) < ps - MALLOC_OVERHEAD); + } + + struct Ebl_Strtab *ret + = (struct Ebl_Strtab *) calloc (1, sizeof (struct Ebl_Strtab)); + if (ret != NULL) + { + ret->nullstr = nullstr; + + if (nullstr) + { + ret->null.len = 1; + ret->null.string = ""; + } + } + + return ret; +} + + +static int +morememory (struct Ebl_Strtab *st, size_t len) +{ + size_t overhead = offsetof (struct memoryblock, memory); + len += overhead + MALLOC_OVERHEAD; + + /* Allocate nearest multiple of pagesize >= len. */ + len = ((len / ps) + (len % ps != 0)) * ps - MALLOC_OVERHEAD; + + struct memoryblock *newmem = (struct memoryblock *) malloc (len); + if (newmem == NULL) + return 1; + + newmem->next = st->memory; + st->memory = newmem; + st->backp = newmem->memory; + st->left = len - overhead; + + return 0; +} + + +void +ebl_strtabfree (struct Ebl_Strtab *st) +{ + struct memoryblock *mb = st->memory; + + while (mb != NULL) + { + void *old = mb; + mb = mb->next; + free (old); + } + + free (st); +} + + +static struct Ebl_Strent * +newstring (struct Ebl_Strtab *st, const char *str, size_t len) +{ + /* Compute the amount of padding needed to make the structure aligned. */ + size_t align = ((__alignof__ (struct Ebl_Strent) + - (((uintptr_t) st->backp) + & (__alignof__ (struct Ebl_Strent) - 1))) + & (__alignof__ (struct Ebl_Strent) - 1)); + + /* Make sure there is enough room in the memory block. */ + if (st->left < align + sizeof (struct Ebl_Strent) + len) + { + if (morememory (st, sizeof (struct Ebl_Strent) + len)) + return NULL; + + align = 0; + } + + /* Create the reserved string. */ + struct Ebl_Strent *newstr = (struct Ebl_Strent *) (st->backp + align); + newstr->string = str; + newstr->len = len; + newstr->next = NULL; + newstr->left = NULL; + newstr->right = NULL; + newstr->offset = 0; + for (int i = len - 2; i >= 0; --i) + newstr->reverse[i] = str[len - 2 - i]; + newstr->reverse[len - 1] = '\0'; + st->backp += align + sizeof (struct Ebl_Strent) + len; + st->left -= align + sizeof (struct Ebl_Strent) + len; + + return newstr; +} + + +/* XXX This function should definitely be rewritten to use a balancing + tree algorith (AVL, red-black trees). For now a simple, correct + implementation is enough. */ +static struct Ebl_Strent ** +searchstring (struct Ebl_Strent **sep, struct Ebl_Strent *newstr) +{ + /* More strings? */ + if (*sep == NULL) + { + *sep = newstr; + return sep; + } + + /* Compare the strings. */ + int cmpres = memcmp ((*sep)->reverse, newstr->reverse, + MIN ((*sep)->len, newstr->len) - 1); + if (cmpres == 0) + /* We found a matching string. */ + return sep; + else if (cmpres > 0) + return searchstring (&(*sep)->left, newstr); + else + return searchstring (&(*sep)->right, newstr); +} + + +/* Add new string. The actual string is assumed to be permanent. */ +struct Ebl_Strent * +ebl_strtabadd (struct Ebl_Strtab *st, const char *str, size_t len) +{ + /* Compute the string length if the caller doesn't know it. */ + if (len == 0) + len = strlen (str) + 1; + + /* Make sure all "" strings get offset 0 but only if the table was + created with a special null entry in mind. */ + if (len == 1 && st->null.string != NULL) + return &st->null; + + /* Allocate memory for the new string and its associated information. */ + struct Ebl_Strent *newstr = newstring (st, str, len); + if (newstr == NULL) + return NULL; + + /* Search in the array for the place to insert the string. If there + is no string with matching prefix and no string with matching + leading substring, create a new entry. */ + struct Ebl_Strent **sep = searchstring (&st->root, newstr); + if (*sep != newstr) + { + /* This is not the same entry. This means we have a prefix match. */ + if ((*sep)->len > newstr->len) + { + /* Check whether we already know this string. */ + for (struct Ebl_Strent *subs = (*sep)->next; subs != NULL; + subs = subs->next) + if (subs->len == newstr->len) + { + /* We have an exact match with a substring. Free the memory + we allocated. */ + st->left += st->backp - (char *) newstr; + st->backp = (char *) newstr; + + return subs; + } + + /* We have a new substring. This means we don't need the reverse + string of this entry anymore. */ + st->backp -= newstr->len; + st->left += newstr->len; + + newstr->next = (*sep)->next; + (*sep)->next = newstr; + } + else if ((*sep)->len != newstr->len) + { + /* When we get here it means that the string we are about to + add has a common prefix with a string we already have but + it is longer. In this case we have to put it first. */ + st->total += newstr->len - (*sep)->len; + newstr->next = *sep; + newstr->left = (*sep)->left; + newstr->right = (*sep)->right; + *sep = newstr; + } + else + { + /* We have an exact match. Free the memory we allocated. */ + st->left += st->backp - (char *) newstr; + st->backp = (char *) newstr; + + newstr = *sep; + } + } + else + st->total += newstr->len; + + return newstr; +} + + +static void +copystrings (struct Ebl_Strent *nodep, char **freep, size_t *offsetp) +{ + if (nodep->left != NULL) + copystrings (nodep->left, freep, offsetp); + + /* Process the current node. */ + nodep->offset = *offsetp; + *freep = (char *) mempcpy (*freep, nodep->string, nodep->len); + *offsetp += nodep->len; + + for (struct Ebl_Strent *subs = nodep->next; subs != NULL; subs = subs->next) + { + assert (subs->len < nodep->len); + subs->offset = nodep->offset + nodep->len - subs->len; + assert (subs->offset != 0 || subs->string[0] == '\0'); + } + + if (nodep->right != NULL) + copystrings (nodep->right, freep, offsetp); +} + + +void +ebl_strtabfinalize (struct Ebl_Strtab *st, Elf_Data *data) +{ + size_t nulllen = st->nullstr ? 1 : 0; + + /* Fill in the information. */ + data->d_buf = malloc (st->total + nulllen); + if (data->d_buf == NULL) + abort (); + + /* The first byte must always be zero if we created the table with a + null string. */ + if (st->nullstr) + *((char *) data->d_buf) = '\0'; + + data->d_type = ELF_T_BYTE; + data->d_size = st->total + nulllen; + data->d_off = 0; + data->d_align = 1; + data->d_version = EV_CURRENT; + + /* Now run through the tree and add all the string while also updating + the offset members of the elfstrent records. */ + char *endp = (char *) data->d_buf + nulllen; + size_t copylen = nulllen; + if (st->root) + copystrings (st->root, &endp, ©len); + assert (copylen == st->total + nulllen); +} + + +size_t +ebl_strtaboffset (struct Ebl_Strent *se) +{ + return se->offset; +} + + +const char * +ebl_string (struct Ebl_Strent *se) +{ + assert (se->string != NULL); + + return se->string; +} diff --git a/3rdparty/elfutils/libebl/eblsymbolbindingname.c b/3rdparty/elfutils/libebl/eblsymbolbindingname.c new file mode 100644 index 0000000..fd5bfda --- /dev/null +++ b/3rdparty/elfutils/libebl/eblsymbolbindingname.c @@ -0,0 +1,78 @@ +/* Return symbol binding name. + Copyright (C) 2001, 2002, 2009 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2001. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> +#include <libeblP.h> + + +const char * +ebl_symbol_binding_name (ebl, binding, buf, len) + Ebl *ebl; + int binding; + char *buf; + size_t len; +{ + const char *res; + + res = ebl != NULL ? ebl->symbol_type_name (binding, buf, len) : NULL; + if (res == NULL) + { + static const char *stb_names[STB_NUM] = + { + "LOCAL", "GLOBAL", "WEAK" + }; + + /* Standard binding? */ + if (binding < STB_NUM) + res = stb_names[binding]; + else + { + char *ident; + + if (binding >= STB_LOPROC && binding <= STB_HIPROC) + snprintf (buf, len, "LOPROC+%d", binding - STB_LOPROC); + else if (binding == STB_GNU_UNIQUE + && (ident = elf_getident (ebl->elf, NULL)) != NULL + && ident[EI_OSABI] == ELFOSABI_LINUX) + return "GNU_UNIQUE"; + else if (binding >= STB_LOOS && binding <= STB_HIOS) + snprintf (buf, len, "LOOS+%d", binding - STB_LOOS); + else + snprintf (buf, len, gettext ("<unknown>: %d"), binding); + + res = buf; + } + } + + return res; +} diff --git a/3rdparty/elfutils/libebl/eblsymboltypename.c b/3rdparty/elfutils/libebl/eblsymboltypename.c new file mode 100644 index 0000000..4e653d2 --- /dev/null +++ b/3rdparty/elfutils/libebl/eblsymboltypename.c @@ -0,0 +1,84 @@ +/* Return symbol type name. + Copyright (C) 2001, 2002, 2009 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2001. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> +#include <libeblP.h> + + +const char * +ebl_symbol_type_name (ebl, symbol, buf, len) + Ebl *ebl; + int symbol; + char *buf; + size_t len; +{ + const char *res; + + res = ebl != NULL ? ebl->symbol_type_name (symbol, buf, len) : NULL; + if (res == NULL) + { + static const char *stt_names[STT_NUM] = + { + [STT_NOTYPE] = "NOTYPE", + [STT_OBJECT] = "OBJECT", + [STT_FUNC] = "FUNC", + [STT_SECTION] = "SECTION", + [STT_FILE] = "FILE", + [STT_COMMON] = "COMMON", + [STT_TLS] = "TLS" + }; + + /* Standard type? */ + if (symbol < STT_NUM) + res = stt_names[symbol]; + else + { + char *ident; + + if (symbol >= STT_LOPROC && symbol <= STT_HIPROC) + snprintf (buf, len, "LOPROC+%d", symbol - STT_LOPROC); + else if (symbol == STT_GNU_IFUNC + && (ident = elf_getident (ebl->elf, NULL)) != NULL + && ident[EI_OSABI] == ELFOSABI_LINUX) + return "GNU_IFUNC"; + else if (symbol >= STT_LOOS && symbol <= STT_HIOS) + snprintf (buf, len, "LOOS+%d", symbol - STT_LOOS); + else + snprintf (buf, len, gettext ("<unknown>: %d"), symbol); + + res = buf; + } + } + + return res; +} diff --git a/3rdparty/elfutils/libebl/eblsysvhashentrysize.c b/3rdparty/elfutils/libebl/eblsysvhashentrysize.c new file mode 100644 index 0000000..f966646 --- /dev/null +++ b/3rdparty/elfutils/libebl/eblsysvhashentrysize.c @@ -0,0 +1,42 @@ +/* Return OS ABI name + Copyright (C) 2006 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2006. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libeblP.h> + + +int +ebl_sysvhash_entrysize (ebl) + Ebl *ebl; +{ + return ebl->sysvhash_entrysize; +} diff --git a/3rdparty/elfutils/libebl/eblunwind.c b/3rdparty/elfutils/libebl/eblunwind.c new file mode 100644 index 0000000..1251c1b --- /dev/null +++ b/3rdparty/elfutils/libebl/eblunwind.c @@ -0,0 +1,43 @@ +/* Get previous frame state for an existing frame state. + Copyright (C) 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libeblP.h> + +bool +ebl_unwind (Ebl *ebl, Dwarf_Addr pc, ebl_tid_registers_t *setfunc, + ebl_tid_registers_get_t *getfunc, ebl_pid_memory_read_t *readfunc, + void *arg, bool *signal_framep) +{ + if (ebl == NULL || ebl->unwind == NULL) + return false; + return ebl->unwind (ebl, pc, setfunc, getfunc, readfunc, arg, signal_framep); +} diff --git a/3rdparty/elfutils/libebl/eblwstrtab.c b/3rdparty/elfutils/libebl/eblwstrtab.c new file mode 100644 index 0000000..08e0ba7 --- /dev/null +++ b/3rdparty/elfutils/libebl/eblwstrtab.c @@ -0,0 +1,359 @@ +/* ELF string table handling. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <inttypes.h> +#include <libelf.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <wchar.h> +#include <sys/param.h> + +#include "libebl.h" +#include <system.h> + +#ifndef MIN +# define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif + + +struct Ebl_WStrent +{ + const wchar_t *string; + size_t len; + struct Ebl_WStrent *next; + struct Ebl_WStrent *left; + struct Ebl_WStrent *right; + size_t offset; + wchar_t reverse[0]; +}; + + +struct memoryblock +{ + struct memoryblock *next; + char memory[0]; +}; + + +struct Ebl_WStrtab +{ + struct Ebl_WStrent *root; + struct memoryblock *memory; + char *backp; + size_t left; + size_t total; + bool nullstr; + + struct Ebl_WStrent null; +}; + + +/* Cache for the pagesize. We correct this value a bit so that `malloc' + is not allocating more than a page. */ +static size_t ps; + + +struct Ebl_WStrtab * +ebl_wstrtabinit (bool nullstr) +{ + struct Ebl_WStrtab *ret; + + if (ps == 0) + { + ps = sysconf (_SC_PAGESIZE) - 2 * sizeof (void *); + assert (sizeof (struct memoryblock) < ps); + } + + ret = (struct Ebl_WStrtab *) calloc (1, sizeof (struct Ebl_WStrtab)); + if (ret != NULL) + { + ret->nullstr = nullstr; + if (nullstr) + { + ret->null.len = 1; + ret->null.string = L""; + } + } + return ret; +} + + +static int +morememory (struct Ebl_WStrtab *st, size_t len) +{ + struct memoryblock *newmem; + + if (len < ps) + len = ps; + newmem = (struct memoryblock *) malloc (len); + if (newmem == NULL) + return 1; + + newmem->next = st->memory; + st->memory = newmem; + st->backp = newmem->memory; + st->left = len - offsetof (struct memoryblock, memory); + + return 0; +} + + +void +ebl_wstrtabfree (struct Ebl_WStrtab *st) +{ + struct memoryblock *mb = st->memory; + + while (mb != NULL) + { + void *old = mb; + mb = mb->next; + free (old); + } + + free (st); +} + + +static struct Ebl_WStrent * +newstring (struct Ebl_WStrtab *st, const wchar_t *str, size_t len) +{ + struct Ebl_WStrent *newstr; + size_t align; + int i; + + /* Compute the amount of padding needed to make the structure aligned. */ + align = ((__alignof__ (struct Ebl_WStrent) + - (((uintptr_t) st->backp) + & (__alignof__ (struct Ebl_WStrent) - 1))) + & (__alignof__ (struct Ebl_WStrent) - 1)); + + /* Make sure there is enough room in the memory block. */ + if (st->left < align + sizeof (struct Ebl_WStrent) + len * sizeof (wchar_t)) + { + if (morememory (st, + sizeof (struct Ebl_WStrent) + len * sizeof (wchar_t))) + return NULL; + + align = 0; + } + + /* Create the reserved string. */ + newstr = (struct Ebl_WStrent *) (st->backp + align); + newstr->string = str; + newstr->len = len; + newstr->next = NULL; + newstr->left = NULL; + newstr->right = NULL; + newstr->offset = 0; + for (i = len - 2; i >= 0; --i) + newstr->reverse[i] = str[len - 2 - i]; + newstr->reverse[len - 1] = L'\0'; + st->backp += align + sizeof (struct Ebl_WStrent) + len * sizeof (wchar_t); + st->left -= align + sizeof (struct Ebl_WStrent) + len * sizeof (wchar_t); + + return newstr; +} + + +/* XXX This function should definitely be rewritten to use a balancing + tree algorith (AVL, red-black trees). For now a simple, correct + implementation is enough. */ +static struct Ebl_WStrent ** +searchstring (struct Ebl_WStrent **sep, struct Ebl_WStrent *newstr) +{ + int cmpres; + + /* More strings? */ + if (*sep == NULL) + { + *sep = newstr; + return sep; + } + + /* Compare the strings. */ + cmpres = wmemcmp ((*sep)->reverse, newstr->reverse, + MIN ((*sep)->len, newstr->len) - 1); + if (cmpres == 0) + /* We found a matching string. */ + return sep; + else if (cmpres > 0) + return searchstring (&(*sep)->left, newstr); + else + return searchstring (&(*sep)->right, newstr); +} + + +/* Add new string. The actual string is assumed to be permanent. */ +struct Ebl_WStrent * +ebl_wstrtabadd (struct Ebl_WStrtab *st, const wchar_t *str, size_t len) +{ + struct Ebl_WStrent *newstr; + struct Ebl_WStrent **sep; + + /* Compute the string length if the caller doesn't know it. */ + if (len == 0) + len = wcslen (str) + 1; + + /* Make sure all "" strings get offset 0 but only if the table was + created with a special null entry in mind. */ + if (len == 1 && st->null.string != NULL) + return &st->null; + + /* Allocate memory for the new string and its associated information. */ + newstr = newstring (st, str, len); + if (newstr == NULL) + return NULL; + + /* Search in the array for the place to insert the string. If there + is no string with matching prefix and no string with matching + leading substring, create a new entry. */ + sep = searchstring (&st->root, newstr); + if (*sep != newstr) + { + /* This is not the same entry. This means we have a prefix match. */ + if ((*sep)->len > newstr->len) + { + struct Ebl_WStrent *subs; + + /* Check whether we already know this string. */ + for (subs = (*sep)->next; subs != NULL; subs = subs->next) + if (subs->len == newstr->len) + { + /* We have an exact match with a substring. Free the memory + we allocated. */ + st->left += st->backp - (char *) newstr; + st->backp = (char *) newstr; + + return subs; + } + + /* We have a new substring. This means we don't need the reverse + string of this entry anymore. */ + st->backp -= newstr->len; + st->left += newstr->len; + + newstr->next = (*sep)->next; + (*sep)->next = newstr; + } + else if ((*sep)->len != newstr->len) + { + /* When we get here it means that the string we are about to + add has a common prefix with a string we already have but + it is longer. In this case we have to put it first. */ + st->total += newstr->len - (*sep)->len; + newstr->next = *sep; + newstr->left = (*sep)->left; + newstr->right = (*sep)->right; + *sep = newstr; + } + else + { + /* We have an exact match. Free the memory we allocated. */ + st->left += st->backp - (char *) newstr; + st->backp = (char *) newstr; + + newstr = *sep; + } + } + else + st->total += newstr->len; + + return newstr; +} + + +static void +copystrings (struct Ebl_WStrent *nodep, wchar_t **freep, size_t *offsetp) +{ + struct Ebl_WStrent *subs; + + if (nodep->left != NULL) + copystrings (nodep->left, freep, offsetp); + + /* Process the current node. */ + nodep->offset = *offsetp; + *freep = wmempcpy (*freep, nodep->string, nodep->len); + *offsetp += nodep->len * sizeof (wchar_t); + + for (subs = nodep->next; subs != NULL; subs = subs->next) + { + assert (subs->len < nodep->len); + subs->offset = nodep->offset + nodep->len - subs->len; + assert (subs->offset != 0 || subs->string[0] == '\0'); + } + + if (nodep->right != NULL) + copystrings (nodep->right, freep, offsetp); +} + + +void +ebl_wstrtabfinalize (struct Ebl_WStrtab *st, Elf_Data *data) +{ + size_t copylen; + wchar_t *endp; + size_t nulllen = st->nullstr ? 1 : 0; + + /* Fill in the information. */ + data->d_buf = malloc ((st->total + nulllen) * sizeof (wchar_t)); + if (data->d_buf == NULL) + abort (); + + /* The first byte must always be zero if we created the table with a + null string. */ + if (st->nullstr) + *((wchar_t *) data->d_buf) = L'\0'; + + data->d_type = ELF_T_BYTE; + data->d_size = st->total + nulllen; + data->d_off = 0; + data->d_align = 1; + data->d_version = EV_CURRENT; + + /* Now run through the tree and add all the string while also updating + the offset members of the elfstrent records. */ + endp = (wchar_t *) data->d_buf + nulllen; + copylen = sizeof (wchar_t) * nulllen; + copystrings (st->root, &endp, ©len); + assert (copylen == (st->total + nulllen) * sizeof (wchar_t)); +} + + +size_t +ebl_wstrtaboffset (struct Ebl_WStrent *se) +{ + return se->offset; +} diff --git a/3rdparty/elfutils/libebl/libebl.h b/3rdparty/elfutils/libebl/libebl.h new file mode 100644 index 0000000..7c3c764 --- /dev/null +++ b/3rdparty/elfutils/libebl/libebl.h @@ -0,0 +1,466 @@ +/* Interface for libebl. + Copyright (C) 2000-2010, 2013, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifndef _LIBEBL_H +#define _LIBEBL_H 1 + +#include <gelf.h> +#include "libdw.h" +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> + +#include "elf-knowledge.h" + + +/* Opaque type for the handle. */ +typedef struct ebl Ebl; + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Get backend handle for object associated with ELF handle. */ +extern Ebl *ebl_openbackend (Elf *elf); +/* Similar but without underlying ELF file. */ +extern Ebl *ebl_openbackend_machine (GElf_Half machine); +/* Similar but with emulation name given. */ +extern Ebl *ebl_openbackend_emulation (const char *emulation); + +/* Free resources allocated for backend handle. */ +extern void ebl_closebackend (Ebl *bh); + + +/* Information about the descriptor. */ + +/* Get ELF machine. */ +extern int ebl_get_elfmachine (Ebl *ebl) __attribute__ ((__pure__)); + +/* Get ELF class. */ +extern int ebl_get_elfclass (Ebl *ebl) __attribute__ ((__pure__)); + +/* Get ELF data encoding. */ +extern int ebl_get_elfdata (Ebl *ebl) __attribute__ ((__pure__)); + + +/* Function to call the callback functions including default ELF + handling. */ + +/* Return backend name. */ +extern const char *ebl_backend_name (Ebl *ebl); + +/* Return relocation type name. */ +extern const char *ebl_object_type_name (Ebl *ebl, int object, + char *buf, size_t len); + +/* Return relocation type name. */ +extern const char *ebl_reloc_type_name (Ebl *ebl, int reloc, + char *buf, size_t len); + +/* Check relocation type. */ +extern bool ebl_reloc_type_check (Ebl *ebl, int reloc); + +/* Check relocation type use. */ +extern bool ebl_reloc_valid_use (Ebl *ebl, int reloc); + +/* Check if relocation type is for simple absolute relocations. + Return ELF_T_{BYTE,HALF,SWORD,SXWORD} for a simple type, else ELF_T_NUM. */ +extern Elf_Type ebl_reloc_simple_type (Ebl *ebl, int reloc); + +/* Return true if the symbol type is that referencing the GOT. E.g., + R_386_GOTPC. */ +extern bool ebl_gotpc_reloc_check (Ebl *ebl, int reloc); + +/* Return segment type name. */ +extern const char *ebl_segment_type_name (Ebl *ebl, int segment, + char *buf, size_t len); + +/* Return section type name. */ +extern const char *ebl_section_type_name (Ebl *ebl, int section, + char *buf, size_t len); + +/* Return section name. */ +extern const char *ebl_section_name (Ebl *ebl, int section, int xsection, + char *buf, size_t len, + const char *scnnames[], size_t shnum); + +/* Return machine flag names. */ +extern const char *ebl_machine_flag_name (Ebl *ebl, GElf_Word flags, + char *buf, size_t len); + +/* Check whether machine flag is valid. */ +extern bool ebl_machine_flag_check (Ebl *ebl, GElf_Word flags); + +/* Check whether SHF_MASKPROC flags are valid. */ +extern bool ebl_machine_section_flag_check (Ebl *ebl, GElf_Xword flags); + +/* Check whether the section with the given index, header, and name + is a special machine section that is valid despite a combination + of flags or other details that are not generically valid. */ +extern bool ebl_check_special_section (Ebl *ebl, int ndx, + const GElf_Shdr *shdr, const char *name); + +/* Return symbol type name. */ +extern const char *ebl_symbol_type_name (Ebl *ebl, int symbol, + char *buf, size_t len); + +/* Return symbol binding name. */ +extern const char *ebl_symbol_binding_name (Ebl *ebl, int binding, + char *buf, size_t len); + +/* Return dynamic tag name. */ +extern const char *ebl_dynamic_tag_name (Ebl *ebl, int64_t tag, + char *buf, size_t len); + +/* Check dynamic tag. */ +extern bool ebl_dynamic_tag_check (Ebl *ebl, int64_t tag); + +/* Check whether given symbol's st_value and st_size are OK despite failing + normal checks. */ +extern bool ebl_check_special_symbol (Ebl *ebl, GElf_Ehdr *ehdr, + const GElf_Sym *sym, const char *name, + const GElf_Shdr *destshdr); + +/* Check whether only valid bits are set on the st_other symbol flag. */ +extern bool ebl_check_st_other_bits (Ebl *ebl, unsigned char st_other); + +/* Return combined section header flags value. */ +extern GElf_Word ebl_sh_flags_combine (Ebl *ebl, GElf_Word flags1, + GElf_Word flags2); + +/* Return symbolic representation of OS ABI. */ +extern const char *ebl_osabi_name (Ebl *ebl, int osabi, char *buf, size_t len); + + +/* Return name of the note section type for a core file. */ +extern const char *ebl_core_note_type_name (Ebl *ebl, uint32_t type, char *buf, + size_t len); + +/* Return name of the note section type for an object file. */ +extern const char *ebl_object_note_type_name (Ebl *ebl, const char *name, + uint32_t type, char *buf, + size_t len); + +/* Print information about object note if available. */ +extern void ebl_object_note (Ebl *ebl, const char *name, uint32_t type, + uint32_t descsz, const char *desc); + +/* Check whether an attribute in a .gnu_attributes section is recognized. + Fills in *TAG_NAME with the name for this tag. + If VALUE is a known value for that tag, also fills in *VALUE_NAME. */ +extern bool ebl_check_object_attribute (Ebl *ebl, const char *vendor, + int tag, uint64_t value, + const char **tag_name, + const char **value_name); + +/* Check whether a section type is a valid reloc target. */ +extern bool ebl_check_reloc_target_type (Ebl *ebl, Elf64_Word sh_type); + + +/* Check section name for being that of a debug informatino section. */ +extern bool ebl_debugscn_p (Ebl *ebl, const char *name); + +/* Check whether given relocation is a copy relocation. */ +extern bool ebl_copy_reloc_p (Ebl *ebl, int reloc); + +/* Check whether given relocation is a no-op relocation. */ +extern bool ebl_none_reloc_p (Ebl *ebl, int reloc); + +/* Check whether given relocation is a relative relocation. */ +extern bool ebl_relative_reloc_p (Ebl *ebl, int reloc); + +/* Check whether section should be stripped. */ +extern bool ebl_section_strip_p (Ebl *ebl, const GElf_Ehdr *ehdr, + const GElf_Shdr *shdr, const char *name, + bool remove_comment, bool only_remove_debug); + +/* Check if backend uses a bss PLT in this file. */ +extern bool ebl_bss_plt_p (Ebl *ebl); + +/* Return size of entry in SysV-style hash table. */ +extern int ebl_sysvhash_entrysize (Ebl *ebl); + +/* Return location expression to find return value given a + DW_TAG_subprogram, DW_TAG_subroutine_type, or similar DIE describing + function itself (whose DW_AT_type attribute describes its return type). + Returns -1 for a libdw error (see dwarf_errno). + Returns -2 for an unrecognized type formation. + Returns zero if the function has no return value (e.g. "void" in C). + Otherwise, *LOCOPS gets a location expression to find the return value, + and returns the number of operations in the expression. The pointer is + permanently allocated at least as long as the Ebl handle is open. */ +extern int ebl_return_value_location (Ebl *ebl, + Dwarf_Die *functypedie, + const Dwarf_Op **locops); + +/* Fill in register information given DWARF register numbers. + If NAME is null, return the maximum REGNO + 1 that has a name. + Otherwise, store in NAME the name for DWARF register number REGNO + and return the number of bytes written (including '\0' terminator). + Return -1 if NAMELEN is too short or REGNO is negative or too large. + Return 0 if REGNO is unused (a gap in the DWARF number assignment). + On success, set *SETNAME to a description like "integer" or "FPU" + fit for "%s registers" title display, and *PREFIX to the string + that precedes NAME in canonical assembler syntax (e.g. "%" or "$"). + The NAME string contains identifier characters only (maybe just digits). */ +extern ssize_t ebl_register_info (Ebl *ebl, + int regno, char *name, size_t namelen, + const char **prefix, const char **setname, + int *bits, int *type); + +/* Fill in the DWARF register numbers for the registers used in system calls. + The SP and PC are what kernel reports call the user stack pointer and PC. + The CALLNO and ARGS are the system call number and incoming arguments. + Each of these is filled with the DWARF register number corresponding, + or -1 if there is none. Returns zero when the information is available. */ +extern int ebl_syscall_abi (Ebl *ebl, int *sp, int *pc, + int *callno, int args[6]); + +/* Supply the ABI-specified state of DWARF CFI before CIE initial programs. + + The DWARF 3.0 spec says that the default initial states of all registers + are "undefined", unless otherwise specified by the machine/compiler ABI. + + This default is wrong for every machine with the CFI generated by GCC. + The EH unwinder does not really distinguish "same_value" and "undefined", + since it doesn't matter for unwinding (in either case there is no change + to make for that register). GCC generates CFI that says nothing at all + about registers it hasn't spilled somewhere. For our unwinder to give + the true story, the backend must supply an initial state that uses + "same_value" rules for all the callee-saves registers. + + This can fill in the initial_instructions, initial_instructions_end + members of *ABI_INFO to point at a CFI instruction stream to process + before each CIE's initial instructions. It should set the + data_alignment_factor member if it affects the initial instructions. + + The callback should not use the register rules DW_CFA_expression or + DW_CFA_val_expression. Defining the CFA using DW_CFA_def_cfa_expression + is allowed. This is an implementation detail since register rules + store expressions as offsets from the .eh_frame or .debug_frame data. + + As a shorthand for some common cases, for this instruction stream + we overload some CFI instructions that cannot be used in a CIE: + + DW_CFA_restore -- Change default rule for all unmentioned + registers from undefined to same_value. + + This function can also fill in ABI_INFO->return_address_register with the + DWARF register number that identifies the actual PC in machine state. + If there is no canonical DWARF register number with that meaning, it's + left unchanged (callers usually initialize with (Dwarf_Word) -1). + This value is not used by CFI per se. + + Function returns 0 on success and -1 for error or unsupported by the + backend. */ +extern int ebl_abi_cfi (Ebl *ebl, Dwarf_CIE *abi_info) + __nonnull_attribute__ (2); + +/* ELF string table handling. */ +struct Ebl_Strtab; +struct Ebl_Strent; + +/* Create new ELF string table object in memory. */ +extern struct Ebl_Strtab *ebl_strtabinit (bool nullstr); + +/* Free resources allocated for ELF string table ST. */ +extern void ebl_strtabfree (struct Ebl_Strtab *st); + +/* Add string STR (length LEN is != 0) to ELF string table ST. */ +extern struct Ebl_Strent *ebl_strtabadd (struct Ebl_Strtab *st, + const char *str, size_t len); + +/* Finalize string table ST and store size and memory location information + in DATA. */ +extern void ebl_strtabfinalize (struct Ebl_Strtab *st, Elf_Data *data); + +/* Get offset in string table for string associated with SE. */ +extern size_t ebl_strtaboffset (struct Ebl_Strent *se); + +/* Return the string associated with SE. */ +extern const char *ebl_string (struct Ebl_Strent *se); + + +/* ELF wide char string table handling. */ +struct Ebl_WStrtab; +struct Ebl_WStrent; + +/* Create new ELF wide char string table object in memory. */ +extern struct Ebl_WStrtab *ebl_wstrtabinit (bool nullstr); + +/* Free resources allocated for ELF wide char string table ST. */ +extern void ebl_wstrtabfree (struct Ebl_WStrtab *st); + +/* Add string STR (length LEN is != 0) to ELF string table ST. */ +extern struct Ebl_WStrent *ebl_wstrtabadd (struct Ebl_WStrtab *st, + const wchar_t *str, size_t len); + +/* Finalize string table ST and store size and memory location information + in DATA. */ +extern void ebl_wstrtabfinalize (struct Ebl_WStrtab *st, Elf_Data *data); + +/* Get offset in wide char string table for string associated with SE. */ +extern size_t ebl_wstrtaboffset (struct Ebl_WStrent *se); + + +/* Generic string table handling. */ +struct Ebl_GStrtab; +struct Ebl_GStrent; + +/* Create new string table object in memory. */ +extern struct Ebl_GStrtab *ebl_gstrtabinit (unsigned int width, bool nullstr); + +/* Free resources allocated for string table ST. */ +extern void ebl_gstrtabfree (struct Ebl_GStrtab *st); + +/* Add string STR (length LEN is != 0) to string table ST. */ +extern struct Ebl_GStrent *ebl_gstrtabadd (struct Ebl_GStrtab *st, + const char *str, size_t len); + +/* Finalize string table ST and store size and memory location information + in DATA. */ +extern void ebl_gstrtabfinalize (struct Ebl_GStrtab *st, Elf_Data *data); + +/* Get offset in wide char string table for string associated with SE. */ +extern size_t ebl_gstrtaboffset (struct Ebl_GStrent *se); + + +/* Register map info. */ +typedef struct +{ + Dwarf_Half offset; /* Byte offset in register data block. */ + Dwarf_Half regno; /* DWARF register number. */ + uint8_t bits; /* Bits of data for one register. */ + uint8_t pad; /* Bytes of padding after register's data. */ + Dwarf_Half count; /* Consecutive register numbers here. */ + bool pc_register; +} Ebl_Register_Location; + +/* Non-register data items in core notes. */ +typedef struct +{ + const char *name; /* Printable identifier. */ + const char *group; /* Identifier for category of related items. */ + Dwarf_Half offset; /* Byte offset in note data. */ + Dwarf_Half count; + Elf_Type type; + char format; + bool thread_identifier; + bool pc_register; +} Ebl_Core_Item; + +/* Describe the format of a core file note with the given header and NAME. + NAME is not guaranteed terminated, it's NHDR->n_namesz raw bytes. */ +extern int ebl_core_note (Ebl *ebl, const GElf_Nhdr *nhdr, const char *name, + GElf_Word *regs_offset, size_t *nregloc, + const Ebl_Register_Location **reglocs, + size_t *nitems, const Ebl_Core_Item **items) + __nonnull_attribute__ (1, 2, 3, 4, 5, 6, 7, 8); + +/* Describe the auxv type number. */ +extern int ebl_auxv_info (Ebl *ebl, GElf_Xword a_type, + const char **name, const char **format) + __nonnull_attribute__ (1, 3, 4); + +/* Callback type for ebl_set_initial_registers_tid. + Register -1 is mapped to PC (if arch PC has no DWARF number). + If FIRSTREG is -1 then NREGS has to be 1. */ +typedef bool (ebl_tid_registers_t) (int firstreg, unsigned nregs, + const Dwarf_Word *regs, void *arg) + __nonnull_attribute__ (3); + +/* Callback to fetch process data from live TID. + EBL architecture has to have EBL_FRAME_NREGS > 0, otherwise the + backend doesn't support unwinding and this function call may crash. */ +extern bool ebl_set_initial_registers_tid (Ebl *ebl, + pid_t tid, + ebl_tid_registers_t *setfunc, + void *arg) + __nonnull_attribute__ (1, 3); + +/* Number of registers to allocate for ebl_set_initial_registers_tid. + EBL architecture can unwind iff EBL_FRAME_NREGS > 0. */ +extern size_t ebl_frame_nregs (Ebl *ebl) + __nonnull_attribute__ (1); + +/* Mask to use for function symbol or unwind return addresses in case + the architecture adds some extra non-address bits to it. This is + different from ebl_resolve_sym_value which only works for actual + symbol addresses (in non-ET_REL files) that might resolve to an + address in a different section. ebl_func_addr_mask is called to + turn a given function value into the a real address or offset (the + original value might not be a real address). This works for all + cases where an actual function address (or offset in ET_REL symbol + tables) is needed. */ +extern GElf_Addr ebl_func_addr_mask (Ebl *ebl); + +/* Convert *REGNO as is in DWARF to a lower range suitable for + Dwarf_Frame->REGS indexing. */ +extern bool ebl_dwarf_to_regno (Ebl *ebl, unsigned *regno) + __nonnull_attribute__ (1, 2); + +/* Modify PC as fetched from inferior data into valid PC. */ +extern void ebl_normalize_pc (Ebl *ebl, Dwarf_Addr *pc) + __nonnull_attribute__ (1, 2); + +/* Callback type for ebl_unwind's parameter getfunc. */ +typedef bool (ebl_tid_registers_get_t) (int firstreg, unsigned nregs, + Dwarf_Word *regs, void *arg) + __nonnull_attribute__ (3); + +/* Callback type for ebl_unwind's parameter readfunc. */ +typedef bool (ebl_pid_memory_read_t) (Dwarf_Addr addr, Dwarf_Word *data, + void *arg) + __nonnull_attribute__ (3); + +/* Get previous frame state for an existing frame state. Method is called only + if unwinder could not find CFI for current PC. PC is for the + existing frame. SETFUNC sets register in the previous frame. GETFUNC gets + register from the existing frame. Note that GETFUNC vs. SETFUNC act on + a disjunct set of registers. READFUNC reads memory. ARG has to be passed + for SETFUNC, GETFUNC and READFUNC. *SIGNAL_FRAMEP is initialized to false, + it can be set to true if existing frame is a signal frame. SIGNAL_FRAMEP is + never NULL. */ +extern bool ebl_unwind (Ebl *ebl, Dwarf_Addr pc, ebl_tid_registers_t *setfunc, + ebl_tid_registers_get_t *getfunc, + ebl_pid_memory_read_t *readfunc, void *arg, + bool *signal_framep) + __nonnull_attribute__ (1, 3, 4, 5, 7); + +/* Returns true if the value can be resolved to an address in an + allocated section, which will be returned in *ADDR + (e.g. function descriptor resolving) */ +extern bool ebl_resolve_sym_value (Ebl *ebl, GElf_Addr *addr) + __nonnull_attribute__ (2); + +#ifdef __cplusplus +} +#endif + +#endif /* libebl.h */ diff --git a/3rdparty/elfutils/libebl/libebl.pro b/3rdparty/elfutils/libebl/libebl.pro new file mode 100644 index 0000000..5e855c5 --- /dev/null +++ b/3rdparty/elfutils/libebl/libebl.pro @@ -0,0 +1,61 @@ +TEMPLATE = lib +CONFIG += staticlib +TARGET = ../ebl + +include(../elfutils.pri) +include(eblheaders.pri) + +SOURCES += \ + $$PWD/ebl_check_special_section.c \ + $$PWD/ebl_check_special_symbol.c \ + $$PWD/ebl_syscall_abi.c \ + $$PWD/eblabicfi.c \ + $$PWD/eblauxvinfo.c \ + $$PWD/eblbackendname.c \ + $$PWD/eblbsspltp.c \ + $$PWD/eblcheckobjattr.c \ + $$PWD/eblcheckreloctargettype.c \ + $$PWD/eblclosebackend.c \ + $$PWD/eblcopyrelocp.c \ + $$PWD/eblcorenote.c \ + $$PWD/eblcorenotetypename.c \ + $$PWD/ebldebugscnp.c \ + $$PWD/ebldwarftoregno.c \ + $$PWD/ebldynamictagcheck.c \ + $$PWD/ebldynamictagname.c \ + $$PWD/eblelfclass.c \ + $$PWD/eblelfdata.c \ + $$PWD/eblelfmachine.c \ + $$PWD/eblgotpcreloccheck.c \ + $$PWD/eblgstrtab.c \ + $$PWD/eblinitreg.c \ + $$PWD/eblmachineflagcheck.c \ + $$PWD/eblmachineflagname.c \ + $$PWD/eblmachinesectionflagcheck.c \ + $$PWD/eblnonerelocp.c \ + $$PWD/eblnormalizepc.c \ + $$PWD/eblobjecttypename.c \ + $$PWD/eblobjnote.c \ + $$PWD/eblobjnotetypename.c \ + $$PWD/eblopenbackend.c \ + $$PWD/eblosabiname.c \ + $$PWD/eblreginfo.c \ + $$PWD/eblrelativerelocp.c \ + $$PWD/eblrelocsimpletype.c \ + $$PWD/eblreloctypecheck.c \ + $$PWD/eblreloctypename.c \ + $$PWD/eblrelocvaliduse.c \ + $$PWD/eblresolvesym.c \ + $$PWD/eblretval.c \ + $$PWD/eblsectionname.c \ + $$PWD/eblsectionstripp.c \ + $$PWD/eblsectiontypename.c \ + $$PWD/eblsegmenttypename.c \ + $$PWD/eblshflagscombine.c \ + $$PWD/eblstother.c \ + $$PWD/eblstrtab.c \ + $$PWD/eblsymbolbindingname.c \ + $$PWD/eblsymboltypename.c \ + $$PWD/eblsysvhashentrysize.c \ + $$PWD/eblunwind.c \ + $$PWD/eblwstrtab.c diff --git a/3rdparty/elfutils/libebl/libeblP.h b/3rdparty/elfutils/libebl/libeblP.h new file mode 100644 index 0000000..dbd67f3 --- /dev/null +++ b/3rdparty/elfutils/libebl/libeblP.h @@ -0,0 +1,97 @@ +/* Internal definitions for interface for libebl. + Copyright (C) 2000-2009, 2013, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifndef _LIBEBLP_H +#define _LIBEBLP_H 1 + +#include <gelf.h> +#include <libasm.h> +#include <libebl.h> +#include <libintl.h> + + +/* Backend handle. */ +struct ebl +{ + /* Machine name. */ + const char *name; + + /* Emulation name. */ + const char *emulation; + + /* ELF machine, class, and data encoding. */ + uint_fast16_t machine; + uint_fast8_t class; + uint_fast8_t data; + + /* The libelf handle (if known). */ + Elf *elf; + + /* See ebl-hooks.h for the declarations of the hook functions. */ +# define EBLHOOK(name) (*name) +# include "ebl-hooks.h" +# undef EBLHOOK + + /* Size of entry in Sysv-style hash table. */ + int sysvhash_entrysize; + + /* Number of registers to allocate for ebl_set_initial_registers_tid. + Ebl architecture can unwind iff FRAME_NREGS > 0. */ + size_t frame_nregs; + + /* Mask to use to turn a function value into a real function address + in case the architecture adds some extra non-address bits to it. + If not initialized (0) then ebl_func_addr_mask will return ~0, + otherwise it should be the actual mask to use. */ + GElf_Addr func_addr_mask; + + /* Function descriptor load address and table as used by + ebl_resolve_sym_value if available for this arch. */ + GElf_Addr fd_addr; + Elf_Data *fd_data; + + /* Internal data. */ + void *dlhandle; +}; + + +/* Type of the initialization functions in the backend modules. */ +typedef const char *(*ebl_bhinit_t) (Elf *, GElf_Half, Ebl *, size_t); + + +/* gettext helper macros. */ +#undef _ +#define _(Str) dgettext ("elfutils", Str) + + +/* LEB128 constant helper macros. */ +#define ULEB128_7(x) (BUILD_BUG_ON_ZERO ((x) >= (1U << 7)) + (x)) + +#define BUILD_BUG_ON_ZERO(x) (sizeof (char [(x) ? -1 : 1]) - 1) + +#endif /* libeblP.h */ diff --git a/3rdparty/elfutils/libelf/abstract.h b/3rdparty/elfutils/libelf/abstract.h new file mode 100644 index 0000000..53713ee --- /dev/null +++ b/3rdparty/elfutils/libelf/abstract.h @@ -0,0 +1,312 @@ +/* Abstract description of component ELF types. + Copyright (C) 1998, 1999, 2000, 2002, 2004, 2007 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +/* ELF header. */ +#define Ehdr(Bits, Ext) \ +START (Bits, Ehdr, Ext##Ehdr) \ + TYPE_EXTRA (unsigned char e_ident[EI_NIDENT];) \ + TYPE_XLATE (memmove (tdest->e_ident, tsrc->e_ident, EI_NIDENT);) \ + TYPE_NAME (ElfW2(Bits, Ext##Half), e_type) \ + TYPE_NAME (ElfW2(Bits, Ext##Half), e_machine) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), e_version) \ + TYPE_NAME (ElfW2(Bits, Ext##Addr), e_entry) \ + TYPE_NAME (ElfW2(Bits, Ext##Off), e_phoff) \ + TYPE_NAME (ElfW2(Bits, Ext##Off), e_shoff) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), e_flags) \ + TYPE_NAME (ElfW2(Bits, Ext##Half), e_ehsize) \ + TYPE_NAME (ElfW2(Bits, Ext##Half), e_phentsize) \ + TYPE_NAME (ElfW2(Bits, Ext##Half), e_phnum) \ + TYPE_NAME (ElfW2(Bits, Ext##Half), e_shentsize) \ + TYPE_NAME (ElfW2(Bits, Ext##Half), e_shnum) \ + TYPE_NAME (ElfW2(Bits, Ext##Half), e_shstrndx) \ +END (Bits, Ext##Ehdr) + +#define Ehdr32(Ext) \ + Ehdr(32, Ext) +#define Ehdr64(Ext) \ + Ehdr(64, Ext) + + +/* Program header. */ +#define Phdr32(Ext) \ +START (32, Phdr, Ext##Phdr) \ + TYPE_NAME (ElfW2(32, Ext##Word), p_type) \ + TYPE_NAME (ElfW2(32, Ext##Off), p_offset) \ + TYPE_NAME (ElfW2(32, Ext##Addr), p_vaddr) \ + TYPE_NAME (ElfW2(32, Ext##Addr), p_paddr) \ + TYPE_NAME (ElfW2(32, Ext##Word), p_filesz) \ + TYPE_NAME (ElfW2(32, Ext##Word), p_memsz) \ + TYPE_NAME (ElfW2(32, Ext##Word), p_flags) \ + TYPE_NAME (ElfW2(32, Ext##Word), p_align) \ +END (32, Ext##Phdr) +#define Phdr64(Ext) \ +START (64, Phdr, Ext##Phdr) \ + TYPE_NAME (ElfW2(64, Ext##Word), p_type) \ + TYPE_NAME (ElfW2(64, Ext##Word), p_flags) \ + TYPE_NAME (ElfW2(64, Ext##Off), p_offset) \ + TYPE_NAME (ElfW2(64, Ext##Addr), p_vaddr) \ + TYPE_NAME (ElfW2(64, Ext##Addr), p_paddr) \ + TYPE_NAME (ElfW2(64, Ext##Xword), p_filesz) \ + TYPE_NAME (ElfW2(64, Ext##Xword), p_memsz) \ + TYPE_NAME (ElfW2(64, Ext##Xword), p_align) \ +END (64, Ext##Phdr) + + +/* Section header. */ +#define Shdr32(Ext) \ +START (32, Shdr, Ext##Shdr) \ + TYPE_NAME (ElfW2(32, Ext##Word), sh_name) \ + TYPE_NAME (ElfW2(32, Ext##Word), sh_type) \ + TYPE_NAME (ElfW2(32, Ext##Word), sh_flags) \ + TYPE_NAME (ElfW2(32, Ext##Addr), sh_addr) \ + TYPE_NAME (ElfW2(32, Ext##Off), sh_offset) \ + TYPE_NAME (ElfW2(32, Ext##Word), sh_size) \ + TYPE_NAME (ElfW2(32, Ext##Word), sh_link) \ + TYPE_NAME (ElfW2(32, Ext##Word), sh_info) \ + TYPE_NAME (ElfW2(32, Ext##Word), sh_addralign) \ + TYPE_NAME (ElfW2(32, Ext##Word), sh_entsize) \ +END (32, Ext##Shdr) +#define Shdr64(Ext) \ +START (64, Shdr, Ext##Shdr) \ + TYPE_NAME (ElfW2(64, Ext##Word), sh_name) \ + TYPE_NAME (ElfW2(64, Ext##Word), sh_type) \ + TYPE_NAME (ElfW2(64, Ext##Xword), sh_flags) \ + TYPE_NAME (ElfW2(64, Ext##Addr), sh_addr) \ + TYPE_NAME (ElfW2(64, Ext##Off), sh_offset) \ + TYPE_NAME (ElfW2(64, Ext##Xword), sh_size) \ + TYPE_NAME (ElfW2(64, Ext##Word), sh_link) \ + TYPE_NAME (ElfW2(64, Ext##Word), sh_info) \ + TYPE_NAME (ElfW2(64, Ext##Xword), sh_addralign) \ + TYPE_NAME (ElfW2(64, Ext##Xword), sh_entsize) \ +END (64, Ext##Shdr) + + +/* Symbol table. */ +#define Sym32(Ext) \ +START (32, Sym, Ext##Sym) \ + TYPE_NAME (ElfW2(32, Ext##Word), st_name) \ + TYPE_NAME (ElfW2(32, Ext##Addr), st_value) \ + TYPE_NAME (ElfW2(32, Ext##Word), st_size) \ + TYPE_EXTRA (unsigned char st_info;) \ + TYPE_XLATE (tdest->st_info = tsrc->st_info;) \ + TYPE_EXTRA (unsigned char st_other;) \ + TYPE_XLATE (tdest->st_other = tsrc->st_other;) \ + TYPE_NAME (ElfW2(32, Ext##Half), st_shndx) \ +END (32, Ext##Sym) +#define Sym64(Ext) \ +START (64, Sym, Ext##Sym) \ + TYPE_NAME (ElfW2(64, Ext##Word), st_name) \ + TYPE_EXTRA (unsigned char st_info;) \ + TYPE_XLATE (tdest->st_info = tsrc->st_info;) \ + TYPE_EXTRA (unsigned char st_other;) \ + TYPE_XLATE (tdest->st_other = tsrc->st_other;) \ + TYPE_NAME (ElfW2(64, Ext##Half), st_shndx) \ + TYPE_NAME (ElfW2(64, Ext##Addr), st_value) \ + TYPE_NAME (ElfW2(64, Ext##Xword), st_size) \ +END (64, Ext##Sym) + + +/* Relocation. */ +#define Rel32(Ext) \ +START (32, Rel, Ext##Rel) \ + TYPE_NAME (ElfW2(32, Ext##Addr), r_offset) \ + TYPE_NAME (ElfW2(32, Ext##Word), r_info) \ +END (32, Ext##Rel) +#define Rel64(Ext) \ +START (64, Rel, Ext##Rel) \ + TYPE_NAME (ElfW2(64, Ext##Addr), r_offset) \ + TYPE_NAME (ElfW2(64, Ext##Xword), r_info) \ +END (64, Ext##Rel) + +#define Rela32(Ext) \ +START (32, Rela, Ext##Rela) \ + TYPE_NAME (ElfW2(32, Ext##Addr), r_offset) \ + TYPE_NAME (ElfW2(32, Ext##Word), r_info) \ + TYPE_NAME (ElfW2(32, Ext##Sword), r_addend) \ +END (32, Ext##Rela) +#define Rela64(Ext) \ +START (64, Rela, Ext##Rela) \ + TYPE_NAME (ElfW2(64, Ext##Addr), r_offset) \ + TYPE_NAME (ElfW2(64, Ext##Xword), r_info) \ + TYPE_NAME (ElfW2(64, Ext##Sxword), r_addend) \ +END (64, Ext##Rela) + + +/* Note entry header. */ +#define Note(Bits, Ext) \ +START (Bits, Nhdr, Ext##Nhdr) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), n_namesz) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), n_descsz) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), n_type) \ +END (Bits, Ext##Nhdr) + +#define Note32(Ext) \ + Note (32, Ext) +#define Note64(Ext) \ + Note (64, Ext) + + +/* Dynamic section data. */ +#define Dyn32(Ext) \ +START (32, Dyn, Ext##Dyn) \ + TYPE_NAME (ElfW2(32, Ext##Sword), d_tag) \ + TYPE_EXTRA (union {) \ + TYPE_EXTRA (ElfW2(32, Ext##Word) d_val;) \ + TYPE_EXTRA (ElfW2(32, Ext##Addr) d_ptr;) \ + TYPE_XLATE (Elf32_cvt_Addr1 (&tdest->d_un.d_val, &tsrc->d_un.d_val);) \ + TYPE_EXTRA (ElfW2(32, Ext##Off) d_off;) \ + TYPE_EXTRA (} d_un;) \ +END (32, Ext##Dyn) +#define Dyn64(Ext) \ +START (64, Dyn, Ext##Dyn) \ + TYPE_NAME (ElfW2(64, Ext##Xword), d_tag) \ + TYPE_EXTRA (union {) \ + TYPE_EXTRA (ElfW2(64, Ext##Xword) d_val;) \ + TYPE_EXTRA (ElfW2(64, Ext##Addr) d_ptr;) \ + TYPE_XLATE (Elf64_cvt_Addr1 (&tdest->d_un.d_val, &tsrc->d_un.d_val);) \ + TYPE_EXTRA (} d_un;) \ +END (64, Ext##Dyn) + + +#ifndef GENERATE_CONVERSION +/* Version definitions. */ +# define Verdef(Bits, Ext) \ +START (Bits, Verdef, Ext##Verdef) \ + TYPE_NAME (ElfW2(Bits, Ext##Half), vd_version) \ + TYPE_NAME (ElfW2(Bits, Ext##Half), vd_flags) \ + TYPE_NAME (ElfW2(Bits, Ext##Half), vd_ndx) \ + TYPE_NAME (ElfW2(Bits, Ext##Half), vd_cnt) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), vd_hash) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), vd_aux) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), vd_next) \ +END (Bits, Ext##Verdef) + +# define Verdef32(Ext) \ + Verdef (32, Ext) +# define Verdef64(Ext) \ + Verdef (64, Ext) + +# define Verdaux(Bits, Ext) \ +START (Bits, Verdaux, Ext##Verdaux) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), vda_name) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), vda_next) \ +END (Bits, Ext##Verdaux) + +# define Verdaux32(Ext) \ + Verdaux (32, Ext) +# define Verdaux64(Ext) \ + Verdaux (64, Ext) + +/* Required versions. */ +# define Verneed(Bits, Ext) \ +START (Bits, Verneed, Ext##Verneed) \ + TYPE_NAME (ElfW2(Bits, Ext##Half), vn_version) \ + TYPE_NAME (ElfW2(Bits, Ext##Half), vn_cnt) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), vn_file) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), vn_aux) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), vn_next) \ +END (Bits, Ext##Verneed) + +# define Verneed32(Ext) \ + Verneed (32, Ext) +# define Verneed64(Ext) \ + Verneed (64, Ext) + +# define Vernaux(Bits, Ext) \ +START (Bits, Vernaux, Ext##Vernaux) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), vna_hash) \ + TYPE_NAME (ElfW2(Bits, Ext##Half), vna_flags) \ + TYPE_NAME (ElfW2(Bits, Ext##Half), vna_other) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), vna_name) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), vna_next) \ +END (Bits, Ext##Vernaux) + +# define Vernaux32(Ext) \ + Vernaux (32, Ext) +# define Vernaux64(Ext) \ + Vernaux (64, Ext) +#endif + +/* Symbol information. */ +#define Syminfo(Bits, Ext) \ +START (Bits, Syminfo, Ext##Syminfo) \ + TYPE_NAME (ElfW2(Bits, Ext##Half), si_boundto) \ + TYPE_NAME (ElfW2(Bits, Ext##Half), si_flags) \ +END (Bits, Ext##Syminfo) + +#define Syminfo32(Ext) \ + Syminfo (32, Ext) +#define Syminfo64(Ext) \ + Syminfo (64, Ext) + +/* Move information. */ +#define Move(Bits, Ext) \ +START (Bits, Move, Ext##Move) \ + TYPE_NAME (ElfW2(Bits, Ext##Xword), m_value) \ + TYPE_NAME (ElfW2(Bits, Ext##Xword), m_info) \ + TYPE_NAME (ElfW2(Bits, Ext##Xword), m_poffset) \ + TYPE_NAME (ElfW2(Bits, Ext##Half), m_repeat) \ + TYPE_NAME (ElfW2(Bits, Ext##Half), m_stride) \ +END (Bits, Ext##Move) + +#define Move32(Ext) \ + Move (32, Ext) +#define Move64(Ext) \ + Move (64, Ext) + +#define Lib(Bits, Ext) \ +START (Bits, Lib, Ext##Lib) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), l_name) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), l_time_stamp) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), l_checksum) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), l_version) \ + TYPE_NAME (ElfW2(Bits, Ext##Word), l_flags) \ +END (Bits, Ext##Lib) + +#define Lib32(Ext) \ + Lib (32, Ext) +#define Lib64(Ext) \ + Lib (64, Ext) + +#define auxv_t32(Ext) \ +START (32, auxv_t, Ext##auxv_t) \ + TYPE_NAME (ElfW2(32, Ext##Word), a_type) \ + TYPE_EXTRA (union {) \ + TYPE_EXTRA (ElfW2(32, Ext##Word) a_val;) \ + TYPE_XLATE (Elf32_cvt_Addr1 (&tdest->a_un.a_val, &tsrc->a_un.a_val);) \ + TYPE_EXTRA (} a_un;) \ +END (32, Ext##auxv_t) +#define auxv_t64(Ext) \ +START (64, auxv_t, Ext##auxv_t) \ + TYPE_NAME (ElfW2(64, Ext##Xword), a_type) \ + TYPE_EXTRA (union {) \ + TYPE_EXTRA (ElfW2(64, Ext##Xword) a_val;) \ + TYPE_XLATE (Elf64_cvt_Addr1 (&tdest->a_un.a_val, &tsrc->a_un.a_val);) \ + TYPE_EXTRA (} a_un;) \ +END (64, Ext##auxv_t) diff --git a/3rdparty/elfutils/libelf/common.h b/3rdparty/elfutils/libelf/common.h new file mode 100644 index 0000000..744f1bb --- /dev/null +++ b/3rdparty/elfutils/libelf/common.h @@ -0,0 +1,163 @@ +/* Common definitions for handling files in memory or only on disk. + Copyright (C) 1998, 1999, 2000, 2002, 2005, 2008 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifndef _COMMON_H +#define _COMMON_H 1 + +#include <ar.h> +#include <byteswap.h> +#include <endian.h> +#include <stdlib.h> +#include <string.h> + +#include "libelfP.h" + +static inline Elf_Kind +__attribute__ ((unused)) +determine_kind (void *buf, size_t len) +{ + /* First test for an archive. */ + if (len >= SARMAG && memcmp (buf, ARMAG, SARMAG) == 0) + return ELF_K_AR; + + /* Next try ELF files. */ + if (len >= EI_NIDENT && memcmp (buf, ELFMAG, SELFMAG) == 0) + { + /* Could be an ELF file. */ + int eclass = (int) ((unsigned char *) buf)[EI_CLASS]; + int data = (int) ((unsigned char *) buf)[EI_DATA]; + int version = (int) ((unsigned char *) buf)[EI_VERSION]; + + if (eclass > ELFCLASSNONE && eclass < ELFCLASSNUM + && data > ELFDATANONE && data < ELFDATANUM + && version > EV_NONE && version < EV_NUM) + return ELF_K_ELF; + } + + /* We do not know this file type. */ + return ELF_K_NONE; +} + + +/* Allocate an Elf descriptor and fill in the generic information. */ +static inline Elf * +__attribute__ ((unused)) +allocate_elf (int fildes, void *map_address, off_t offset, size_t maxsize, + Elf_Cmd cmd, Elf *parent, Elf_Kind kind, size_t extra) +{ + Elf *result = (Elf *) calloc (1, sizeof (Elf) + extra); + if (result == NULL) + __libelf_seterrno (ELF_E_NOMEM); + else + { + result->kind = kind; + result->ref_count = 1; + result->cmd = cmd; + result->fildes = fildes; + result->start_offset = offset; + result->maximum_size = maxsize; + result->map_address = map_address; + result->parent = parent; + + rwlock_init (result->lock); + } + + return result; +} + + +/* Acquire lock for the descriptor and all children. */ +static void +__attribute__ ((unused)) +libelf_acquire_all (Elf *elf) +{ + rwlock_wrlock (elf->lock); + + if (elf->kind == ELF_K_AR) + { + Elf *child = elf->state.ar.children; + + while (child != NULL) + { + if (child->ref_count != 0) + libelf_acquire_all (child); + child = child->next; + } + } +} + +/* Release own lock and those of the children. */ +static void +__attribute__ ((unused)) +libelf_release_all (Elf *elf) +{ + if (elf->kind == ELF_K_AR) + { + Elf *child = elf->state.ar.children; + + while (child != NULL) + { + if (child->ref_count != 0) + libelf_release_all (child); + child = child->next; + } + } + + rwlock_unlock (elf->lock); +} + + +/* Macro to convert endianess in place. It determines the function it + has to use itself. */ +#define CONVERT(Var) \ + (Var) = (sizeof (Var) == 1 \ + ? (unsigned char) (Var) \ + : (sizeof (Var) == 2 \ + ? bswap_16 (Var) \ + : (sizeof (Var) == 4 \ + ? bswap_32 (Var) \ + : bswap_64 (Var)))) + +#define CONVERT_TO(Dst, Var) \ + (Dst) = (sizeof (Var) == 1 \ + ? (unsigned char) (Var) \ + : (sizeof (Var) == 2 \ + ? bswap_16 (Var) \ + : (sizeof (Var) == 4 \ + ? bswap_32 (Var) \ + : bswap_64 (Var)))) + + +#if __BYTE_ORDER == __LITTLE_ENDIAN +# define MY_ELFDATA ELFDATA2LSB +#else +# define MY_ELFDATA ELFDATA2MSB +#endif + +#endif /* common.h */ diff --git a/3rdparty/elfutils/libelf/dl-hash.h b/3rdparty/elfutils/libelf/dl-hash.h new file mode 100644 index 0000000..e286d2e --- /dev/null +++ b/3rdparty/elfutils/libelf/dl-hash.h @@ -0,0 +1,82 @@ +/* Compute hash value for given string according to ELF standard. + Copyright (C) 2006 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1995. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifndef _DL_HASH_H +#define _DL_HASH_H 1 + + +/* This is the hashing function specified by the ELF ABI. In the + first five operations no overflow is possible so we optimized it a + bit. */ +static inline unsigned int +__attribute__ ((__pure__)) +_dl_elf_hash (const char *name) +{ + const unsigned char *iname = (const unsigned char *) name; + unsigned int hash = (unsigned int) *iname++; + if (*iname != '\0') + { + hash = (hash << 4) + (unsigned int) *iname++; + if (*iname != '\0') + { + hash = (hash << 4) + (unsigned int) *iname++; + if (*iname != '\0') + { + hash = (hash << 4) + (unsigned int) *iname++; + if (*iname != '\0') + { + hash = (hash << 4) + (unsigned int) *iname++; + while (*iname != '\0') + { + unsigned int hi; + hash = (hash << 4) + (unsigned int) *iname++; + hi = hash & 0xf0000000; + + /* The algorithm specified in the ELF ABI is as + follows: + + if (hi != 0) + hash ^= hi >> 24; + + hash &= ~hi; + + But the following is equivalent and a lot + faster, especially on modern processors. */ + + hash ^= hi; + hash ^= hi >> 24; + } + } + } + } + } + return hash; +} + +#endif /* dl-hash.h */ diff --git a/3rdparty/elfutils/libelf/elf-knowledge.h b/3rdparty/elfutils/libelf/elf-knowledge.h new file mode 100644 index 0000000..24534b3 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf-knowledge.h @@ -0,0 +1,104 @@ +/* Accumulation of various pieces of knowledge about ELF. + Copyright (C) 2000-2012, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifndef _ELF_KNOWLEDGE_H +#define _ELF_KNOWLEDGE_H 1 + +#include <stdbool.h> + + +/* Test whether a section can be stripped or not. */ +#define SECTION_STRIP_P(shdr, name, remove_comment) \ + /* Sections which are allocated are not removed. */ \ + (((shdr)->sh_flags & SHF_ALLOC) == 0 \ + /* We never remove .note sections. */ \ + && (shdr)->sh_type != SHT_NOTE \ + && (((shdr)->sh_type) != SHT_PROGBITS \ + /* Never remove .gnu.warning.* sections. */ \ + || (name != NULL \ + && strncmp (name, ".gnu.warning.", sizeof ".gnu.warning." - 1) != 0\ + /* We remove .comment sections only if explicitly told to do so. */\ + && (remove_comment \ + || strcmp (name, ".comment") != 0)))) + + +/* Test whether `sh_info' field in section header contains a section + index. There are two kinds of sections doing this: + + - the sections containing relocation information reference in this + field the section to which the relocations apply; + + - section with the SHF_INFO_LINK flag set to signal that `sh_info' + references a section. This allows correct handling of unknown + sections. */ +#define SH_INFO_LINK_P(Shdr) \ + ((Shdr)->sh_type == SHT_REL || (Shdr)->sh_type == SHT_RELA \ + || ((Shdr)->sh_flags & SHF_INFO_LINK) != 0) + + +/* When combining ELF section flags we must distinguish two kinds: + + - flags which cause problem if not added to the result even if not + present in all input sections + + - flags which cause problem if added to the result if not present + in all input sections + + The following definition is for the general case. There might be + machine specific extensions. */ +#define SH_FLAGS_COMBINE(Flags1, Flags2) \ + (((Flags1 | Flags2) \ + & (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR | SHF_LINK_ORDER \ + | SHF_OS_NONCONFORMING | SHF_GROUP)) \ + | (Flags1 & Flags2 & (SHF_MERGE | SHF_STRINGS | SHF_INFO_LINK))) + +/* Similar macro: return the bits of the flags which necessarily must + match if two sections are automatically combined. Sections still + can be forcefully combined in which case SH_FLAGS_COMBINE can be + used to determine the combined flags. */ +#define SH_FLAGS_IMPORTANT(Flags) \ + ((Flags) & ~((GElf_Xword) 0 | SHF_LINK_ORDER | SHF_OS_NONCONFORMING)) + + +/* Size of an entry in the hash table. The ELF specification says all + entries are regardless of platform 32-bits in size. Early 64-bit + ports (namely Alpha for Linux) got this wrong. The wording was not + clear. + + Several years later the ABI for the 64-bit S390s was developed. + Many things were copied from the IA-64 ABI (which uses the correct + 32-bit entry size) but what do these people do? They use 64-bit + entries. It is really shocking to see what kind of morons are out + there. And even worse: they are allowed to design ABIs. */ +#define SH_ENTSIZE_HASH(Ehdr) \ + ((Ehdr)->e_machine == EM_ALPHA \ + || ((Ehdr)->e_machine == EM_S390 \ + && (Ehdr)->e_ident[EI_CLASS] == ELFCLASS64) ? 8 : 4) + +#endif /* elf-knowledge.h */ diff --git a/3rdparty/elfutils/libelf/elf.h b/3rdparty/elfutils/libelf/elf.h new file mode 100644 index 0000000..40e87b2 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf.h @@ -0,0 +1,3363 @@ +/* This file defines standard ELF types, structures, and macros. + Copyright (C) 1995-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _ELF_H +#define _ELF_H 1 + +#include <features.h> + +__BEGIN_DECLS + +/* Standard ELF types. */ + +#include <stdint.h> + +/* Type for a 16-bit quantity. */ +typedef uint16_t Elf32_Half; +typedef uint16_t Elf64_Half; + +/* Types for signed and unsigned 32-bit quantities. */ +typedef uint32_t Elf32_Word; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf64_Word; +typedef int32_t Elf64_Sword; + +/* Types for signed and unsigned 64-bit quantities. */ +typedef uint64_t Elf32_Xword; +typedef int64_t Elf32_Sxword; +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; + +/* Type of addresses. */ +typedef uint32_t Elf32_Addr; +typedef uint64_t Elf64_Addr; + +/* Type of file offsets. */ +typedef uint32_t Elf32_Off; +typedef uint64_t Elf64_Off; + +/* Type for section indices, which are 16-bit quantities. */ +typedef uint16_t Elf32_Section; +typedef uint16_t Elf64_Section; + +/* Type for version symbol information. */ +typedef Elf32_Half Elf32_Versym; +typedef Elf64_Half Elf64_Versym; + + +/* The ELF file header. This appears at the start of every ELF file. */ + +#define EI_NIDENT (16) + +typedef struct +{ + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ + Elf32_Half e_type; /* Object file type */ + Elf32_Half e_machine; /* Architecture */ + Elf32_Word e_version; /* Object file version */ + Elf32_Addr e_entry; /* Entry point virtual address */ + Elf32_Off e_phoff; /* Program header table file offset */ + Elf32_Off e_shoff; /* Section header table file offset */ + Elf32_Word e_flags; /* Processor-specific flags */ + Elf32_Half e_ehsize; /* ELF header size in bytes */ + Elf32_Half e_phentsize; /* Program header table entry size */ + Elf32_Half e_phnum; /* Program header table entry count */ + Elf32_Half e_shentsize; /* Section header table entry size */ + Elf32_Half e_shnum; /* Section header table entry count */ + Elf32_Half e_shstrndx; /* Section header string table index */ +} Elf32_Ehdr; + +typedef struct +{ + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ + Elf64_Half e_type; /* Object file type */ + Elf64_Half e_machine; /* Architecture */ + Elf64_Word e_version; /* Object file version */ + Elf64_Addr e_entry; /* Entry point virtual address */ + Elf64_Off e_phoff; /* Program header table file offset */ + Elf64_Off e_shoff; /* Section header table file offset */ + Elf64_Word e_flags; /* Processor-specific flags */ + Elf64_Half e_ehsize; /* ELF header size in bytes */ + Elf64_Half e_phentsize; /* Program header table entry size */ + Elf64_Half e_phnum; /* Program header table entry count */ + Elf64_Half e_shentsize; /* Section header table entry size */ + Elf64_Half e_shnum; /* Section header table entry count */ + Elf64_Half e_shstrndx; /* Section header string table index */ +} Elf64_Ehdr; + +/* Fields in the e_ident array. The EI_* macros are indices into the + array. The macros under each EI_* macro are the values the byte + may have. */ + +#define EI_MAG0 0 /* File identification byte 0 index */ +#define ELFMAG0 0x7f /* Magic number byte 0 */ + +#define EI_MAG1 1 /* File identification byte 1 index */ +#define ELFMAG1 'E' /* Magic number byte 1 */ + +#define EI_MAG2 2 /* File identification byte 2 index */ +#define ELFMAG2 'L' /* Magic number byte 2 */ + +#define EI_MAG3 3 /* File identification byte 3 index */ +#define ELFMAG3 'F' /* Magic number byte 3 */ + +/* Conglomeration of the identification bytes, for easy testing as a word. */ +#define ELFMAG "\177ELF" +#define SELFMAG 4 + +#define EI_CLASS 4 /* File class byte index */ +#define ELFCLASSNONE 0 /* Invalid class */ +#define ELFCLASS32 1 /* 32-bit objects */ +#define ELFCLASS64 2 /* 64-bit objects */ +#define ELFCLASSNUM 3 + +#define EI_DATA 5 /* Data encoding byte index */ +#define ELFDATANONE 0 /* Invalid data encoding */ +#define ELFDATA2LSB 1 /* 2's complement, little endian */ +#define ELFDATA2MSB 2 /* 2's complement, big endian */ +#define ELFDATANUM 3 + +#define EI_VERSION 6 /* File version byte index */ + /* Value must be EV_CURRENT */ + +#define EI_OSABI 7 /* OS ABI identification */ +#define ELFOSABI_NONE 0 /* UNIX System V ABI */ +#define ELFOSABI_SYSV 0 /* Alias. */ +#define ELFOSABI_HPUX 1 /* HP-UX */ +#define ELFOSABI_NETBSD 2 /* NetBSD. */ +#define ELFOSABI_GNU 3 /* Object uses GNU ELF extensions. */ +#define ELFOSABI_LINUX ELFOSABI_GNU /* Compatibility alias. */ +#define ELFOSABI_SOLARIS 6 /* Sun Solaris. */ +#define ELFOSABI_AIX 7 /* IBM AIX. */ +#define ELFOSABI_IRIX 8 /* SGI Irix. */ +#define ELFOSABI_FREEBSD 9 /* FreeBSD. */ +#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */ +#define ELFOSABI_MODESTO 11 /* Novell Modesto. */ +#define ELFOSABI_OPENBSD 12 /* OpenBSD. */ +#define ELFOSABI_ARM_AEABI 64 /* ARM EABI */ +#define ELFOSABI_ARM 97 /* ARM */ +#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ + +#define EI_ABIVERSION 8 /* ABI version */ + +#define EI_PAD 9 /* Byte index of padding bytes */ + +/* Legal values for e_type (object file type). */ + +#define ET_NONE 0 /* No file type */ +#define ET_REL 1 /* Relocatable file */ +#define ET_EXEC 2 /* Executable file */ +#define ET_DYN 3 /* Shared object file */ +#define ET_CORE 4 /* Core file */ +#define ET_NUM 5 /* Number of defined types */ +#define ET_LOOS 0xfe00 /* OS-specific range start */ +#define ET_HIOS 0xfeff /* OS-specific range end */ +#define ET_LOPROC 0xff00 /* Processor-specific range start */ +#define ET_HIPROC 0xffff /* Processor-specific range end */ + +/* Legal values for e_machine (architecture). */ + +#define EM_NONE 0 /* No machine */ +#define EM_M32 1 /* AT&T WE 32100 */ +#define EM_SPARC 2 /* SUN SPARC */ +#define EM_386 3 /* Intel 80386 */ +#define EM_68K 4 /* Motorola m68k family */ +#define EM_88K 5 /* Motorola m88k family */ +#define EM_860 7 /* Intel 80860 */ +#define EM_MIPS 8 /* MIPS R3000 big-endian */ +#define EM_S370 9 /* IBM System/370 */ +#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */ + +#define EM_PARISC 15 /* HPPA */ +#define EM_VPP500 17 /* Fujitsu VPP500 */ +#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ +#define EM_960 19 /* Intel 80960 */ +#define EM_PPC 20 /* PowerPC */ +#define EM_PPC64 21 /* PowerPC 64-bit */ +#define EM_S390 22 /* IBM S390 */ + +#define EM_V800 36 /* NEC V800 series */ +#define EM_FR20 37 /* Fujitsu FR20 */ +#define EM_RH32 38 /* TRW RH-32 */ +#define EM_RCE 39 /* Motorola RCE */ +#define EM_ARM 40 /* ARM */ +#define EM_FAKE_ALPHA 41 /* Digital Alpha */ +#define EM_SH 42 /* Hitachi SH */ +#define EM_SPARCV9 43 /* SPARC v9 64-bit */ +#define EM_TRICORE 44 /* Siemens Tricore */ +#define EM_ARC 45 /* Argonaut RISC Core */ +#define EM_H8_300 46 /* Hitachi H8/300 */ +#define EM_H8_300H 47 /* Hitachi H8/300H */ +#define EM_H8S 48 /* Hitachi H8S */ +#define EM_H8_500 49 /* Hitachi H8/500 */ +#define EM_IA_64 50 /* Intel Merced */ +#define EM_MIPS_X 51 /* Stanford MIPS-X */ +#define EM_COLDFIRE 52 /* Motorola Coldfire */ +#define EM_68HC12 53 /* Motorola M68HC12 */ +#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator*/ +#define EM_PCP 55 /* Siemens PCP */ +#define EM_NCPU 56 /* Sony nCPU embeeded RISC */ +#define EM_NDR1 57 /* Denso NDR1 microprocessor */ +#define EM_STARCORE 58 /* Motorola Start*Core processor */ +#define EM_ME16 59 /* Toyota ME16 processor */ +#define EM_ST100 60 /* STMicroelectronic ST100 processor */ +#define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam*/ +#define EM_X86_64 62 /* AMD x86-64 architecture */ +#define EM_PDSP 63 /* Sony DSP Processor */ + +#define EM_FX66 66 /* Siemens FX66 microcontroller */ +#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */ +#define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */ +#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */ +#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */ +#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */ +#define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */ +#define EM_SVX 73 /* Silicon Graphics SVx */ +#define EM_ST19 74 /* STMicroelectronics ST19 8 bit mc */ +#define EM_VAX 75 /* Digital VAX */ +#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */ +#define EM_JAVELIN 77 /* Infineon Technologies 32-bit embedded processor */ +#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */ +#define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */ +#define EM_MMIX 80 /* Donald Knuth's educational 64-bit processor */ +#define EM_HUANY 81 /* Harvard University machine-independent object files */ +#define EM_PRISM 82 /* SiTera Prism */ +#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */ +#define EM_FR30 84 /* Fujitsu FR30 */ +#define EM_D10V 85 /* Mitsubishi D10V */ +#define EM_D30V 86 /* Mitsubishi D30V */ +#define EM_V850 87 /* NEC v850 */ +#define EM_M32R 88 /* Mitsubishi M32R */ +#define EM_MN10300 89 /* Matsushita MN10300 */ +#define EM_MN10200 90 /* Matsushita MN10200 */ +#define EM_PJ 91 /* picoJava */ +#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */ +#define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */ +#define EM_XTENSA 94 /* Tensilica Xtensa Architecture */ +#define EM_AARCH64 183 /* ARM AARCH64 */ +#define EM_TILEPRO 188 /* Tilera TILEPro */ +#define EM_MICROBLAZE 189 /* Xilinx MicroBlaze */ +#define EM_TILEGX 191 /* Tilera TILE-Gx */ +#define EM_NUM 192 + +/* If it is necessary to assign new unofficial EM_* values, please + pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the + chances of collision with official or non-GNU unofficial values. */ + +#define EM_ALPHA 0x9026 + +/* Legal values for e_version (version). */ + +#define EV_NONE 0 /* Invalid ELF version */ +#define EV_CURRENT 1 /* Current version */ +#define EV_NUM 2 + +/* Section header. */ + +typedef struct +{ + Elf32_Word sh_name; /* Section name (string tbl index) */ + Elf32_Word sh_type; /* Section type */ + Elf32_Word sh_flags; /* Section flags */ + Elf32_Addr sh_addr; /* Section virtual addr at execution */ + Elf32_Off sh_offset; /* Section file offset */ + Elf32_Word sh_size; /* Section size in bytes */ + Elf32_Word sh_link; /* Link to another section */ + Elf32_Word sh_info; /* Additional section information */ + Elf32_Word sh_addralign; /* Section alignment */ + Elf32_Word sh_entsize; /* Entry size if section holds table */ +} Elf32_Shdr; + +typedef struct +{ + Elf64_Word sh_name; /* Section name (string tbl index) */ + Elf64_Word sh_type; /* Section type */ + Elf64_Xword sh_flags; /* Section flags */ + Elf64_Addr sh_addr; /* Section virtual addr at execution */ + Elf64_Off sh_offset; /* Section file offset */ + Elf64_Xword sh_size; /* Section size in bytes */ + Elf64_Word sh_link; /* Link to another section */ + Elf64_Word sh_info; /* Additional section information */ + Elf64_Xword sh_addralign; /* Section alignment */ + Elf64_Xword sh_entsize; /* Entry size if section holds table */ +} Elf64_Shdr; + +/* Special section indices. */ + +#define SHN_UNDEF 0 /* Undefined section */ +#define SHN_LORESERVE 0xff00 /* Start of reserved indices */ +#define SHN_LOPROC 0xff00 /* Start of processor-specific */ +#define SHN_BEFORE 0xff00 /* Order section before all others + (Solaris). */ +#define SHN_AFTER 0xff01 /* Order section after all others + (Solaris). */ +#define SHN_HIPROC 0xff1f /* End of processor-specific */ +#define SHN_LOOS 0xff20 /* Start of OS-specific */ +#define SHN_HIOS 0xff3f /* End of OS-specific */ +#define SHN_ABS 0xfff1 /* Associated symbol is absolute */ +#define SHN_COMMON 0xfff2 /* Associated symbol is common */ +#define SHN_XINDEX 0xffff /* Index is in extra table. */ +#define SHN_HIRESERVE 0xffff /* End of reserved indices */ + +/* Legal values for sh_type (section type). */ + +#define SHT_NULL 0 /* Section header table entry unused */ +#define SHT_PROGBITS 1 /* Program data */ +#define SHT_SYMTAB 2 /* Symbol table */ +#define SHT_STRTAB 3 /* String table */ +#define SHT_RELA 4 /* Relocation entries with addends */ +#define SHT_HASH 5 /* Symbol hash table */ +#define SHT_DYNAMIC 6 /* Dynamic linking information */ +#define SHT_NOTE 7 /* Notes */ +#define SHT_NOBITS 8 /* Program space with no data (bss) */ +#define SHT_REL 9 /* Relocation entries, no addends */ +#define SHT_SHLIB 10 /* Reserved */ +#define SHT_DYNSYM 11 /* Dynamic linker symbol table */ +#define SHT_INIT_ARRAY 14 /* Array of constructors */ +#define SHT_FINI_ARRAY 15 /* Array of destructors */ +#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */ +#define SHT_GROUP 17 /* Section group */ +#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */ +#define SHT_NUM 19 /* Number of defined types. */ +#define SHT_LOOS 0x60000000 /* Start OS-specific. */ +#define SHT_GNU_ATTRIBUTES 0x6ffffff5 /* Object attributes. */ +#define SHT_GNU_HASH 0x6ffffff6 /* GNU-style hash table. */ +#define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */ +#define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */ +#define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */ +#define SHT_SUNW_move 0x6ffffffa +#define SHT_SUNW_COMDAT 0x6ffffffb +#define SHT_SUNW_syminfo 0x6ffffffc +#define SHT_GNU_verdef 0x6ffffffd /* Version definition section. */ +#define SHT_GNU_verneed 0x6ffffffe /* Version needs section. */ +#define SHT_GNU_versym 0x6fffffff /* Version symbol table. */ +#define SHT_HISUNW 0x6fffffff /* Sun-specific high bound. */ +#define SHT_HIOS 0x6fffffff /* End OS-specific type */ +#define SHT_LOPROC 0x70000000 /* Start of processor-specific */ +#define SHT_HIPROC 0x7fffffff /* End of processor-specific */ +#define SHT_LOUSER 0x80000000 /* Start of application-specific */ +#define SHT_HIUSER 0x8fffffff /* End of application-specific */ + +/* Legal values for sh_flags (section flags). */ + +#define SHF_WRITE (1 << 0) /* Writable */ +#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */ +#define SHF_EXECINSTR (1 << 2) /* Executable */ +#define SHF_MERGE (1 << 4) /* Might be merged */ +#define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */ +#define SHF_INFO_LINK (1 << 6) /* `sh_info' contains SHT index */ +#define SHF_LINK_ORDER (1 << 7) /* Preserve order after combining */ +#define SHF_OS_NONCONFORMING (1 << 8) /* Non-standard OS specific handling + required */ +#define SHF_GROUP (1 << 9) /* Section is member of a group. */ +#define SHF_TLS (1 << 10) /* Section hold thread-local data. */ +#define SHF_MASKOS 0x0ff00000 /* OS-specific. */ +#define SHF_MASKPROC 0xf0000000 /* Processor-specific */ +#define SHF_ORDERED (1 << 30) /* Special ordering requirement + (Solaris). */ +#define SHF_EXCLUDE (1 << 31) /* Section is excluded unless + referenced or allocated (Solaris).*/ + +/* Section group handling. */ +#define GRP_COMDAT 0x1 /* Mark group as COMDAT. */ + +/* Symbol table entry. */ + +typedef struct +{ + Elf32_Word st_name; /* Symbol name (string tbl index) */ + Elf32_Addr st_value; /* Symbol value */ + Elf32_Word st_size; /* Symbol size */ + unsigned char st_info; /* Symbol type and binding */ + unsigned char st_other; /* Symbol visibility */ + Elf32_Section st_shndx; /* Section index */ +} Elf32_Sym; + +typedef struct +{ + Elf64_Word st_name; /* Symbol name (string tbl index) */ + unsigned char st_info; /* Symbol type and binding */ + unsigned char st_other; /* Symbol visibility */ + Elf64_Section st_shndx; /* Section index */ + Elf64_Addr st_value; /* Symbol value */ + Elf64_Xword st_size; /* Symbol size */ +} Elf64_Sym; + +/* The syminfo section if available contains additional information about + every dynamic symbol. */ + +typedef struct +{ + Elf32_Half si_boundto; /* Direct bindings, symbol bound to */ + Elf32_Half si_flags; /* Per symbol flags */ +} Elf32_Syminfo; + +typedef struct +{ + Elf64_Half si_boundto; /* Direct bindings, symbol bound to */ + Elf64_Half si_flags; /* Per symbol flags */ +} Elf64_Syminfo; + +/* Possible values for si_boundto. */ +#define SYMINFO_BT_SELF 0xffff /* Symbol bound to self */ +#define SYMINFO_BT_PARENT 0xfffe /* Symbol bound to parent */ +#define SYMINFO_BT_LOWRESERVE 0xff00 /* Beginning of reserved entries */ + +/* Possible bitmasks for si_flags. */ +#define SYMINFO_FLG_DIRECT 0x0001 /* Direct bound symbol */ +#define SYMINFO_FLG_PASSTHRU 0x0002 /* Pass-thru symbol for translator */ +#define SYMINFO_FLG_COPY 0x0004 /* Symbol is a copy-reloc */ +#define SYMINFO_FLG_LAZYLOAD 0x0008 /* Symbol bound to object to be lazy + loaded */ +/* Syminfo version values. */ +#define SYMINFO_NONE 0 +#define SYMINFO_CURRENT 1 +#define SYMINFO_NUM 2 + + +/* How to extract and insert information held in the st_info field. */ + +#define ELF32_ST_BIND(val) (((unsigned char) (val)) >> 4) +#define ELF32_ST_TYPE(val) ((val) & 0xf) +#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) + +/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field. */ +#define ELF64_ST_BIND(val) ELF32_ST_BIND (val) +#define ELF64_ST_TYPE(val) ELF32_ST_TYPE (val) +#define ELF64_ST_INFO(bind, type) ELF32_ST_INFO ((bind), (type)) + +/* Legal values for ST_BIND subfield of st_info (symbol binding). */ + +#define STB_LOCAL 0 /* Local symbol */ +#define STB_GLOBAL 1 /* Global symbol */ +#define STB_WEAK 2 /* Weak symbol */ +#define STB_NUM 3 /* Number of defined types. */ +#define STB_LOOS 10 /* Start of OS-specific */ +#define STB_GNU_UNIQUE 10 /* Unique symbol. */ +#define STB_HIOS 12 /* End of OS-specific */ +#define STB_LOPROC 13 /* Start of processor-specific */ +#define STB_HIPROC 15 /* End of processor-specific */ + +/* Legal values for ST_TYPE subfield of st_info (symbol type). */ + +#define STT_NOTYPE 0 /* Symbol type is unspecified */ +#define STT_OBJECT 1 /* Symbol is a data object */ +#define STT_FUNC 2 /* Symbol is a code object */ +#define STT_SECTION 3 /* Symbol associated with a section */ +#define STT_FILE 4 /* Symbol's name is file name */ +#define STT_COMMON 5 /* Symbol is a common data object */ +#define STT_TLS 6 /* Symbol is thread-local data object*/ +#define STT_NUM 7 /* Number of defined types. */ +#define STT_LOOS 10 /* Start of OS-specific */ +#define STT_GNU_IFUNC 10 /* Symbol is indirect code object */ +#define STT_HIOS 12 /* End of OS-specific */ +#define STT_LOPROC 13 /* Start of processor-specific */ +#define STT_HIPROC 15 /* End of processor-specific */ + + +/* Symbol table indices are found in the hash buckets and chain table + of a symbol hash table section. This special index value indicates + the end of a chain, meaning no further symbols are found in that bucket. */ + +#define STN_UNDEF 0 /* End of a chain. */ + + +/* How to extract and insert information held in the st_other field. */ + +#define ELF32_ST_VISIBILITY(o) ((o) & 0x03) + +/* For ELF64 the definitions are the same. */ +#define ELF64_ST_VISIBILITY(o) ELF32_ST_VISIBILITY (o) + +/* Symbol visibility specification encoded in the st_other field. */ +#define STV_DEFAULT 0 /* Default symbol visibility rules */ +#define STV_INTERNAL 1 /* Processor specific hidden class */ +#define STV_HIDDEN 2 /* Sym unavailable in other modules */ +#define STV_PROTECTED 3 /* Not preemptible, not exported */ + + +/* Relocation table entry without addend (in section of type SHT_REL). */ + +typedef struct +{ + Elf32_Addr r_offset; /* Address */ + Elf32_Word r_info; /* Relocation type and symbol index */ +} Elf32_Rel; + +/* I have seen two different definitions of the Elf64_Rel and + Elf64_Rela structures, so we'll leave them out until Novell (or + whoever) gets their act together. */ +/* The following, at least, is used on Sparc v9, MIPS, and Alpha. */ + +typedef struct +{ + Elf64_Addr r_offset; /* Address */ + Elf64_Xword r_info; /* Relocation type and symbol index */ +} Elf64_Rel; + +/* Relocation table entry with addend (in section of type SHT_RELA). */ + +typedef struct +{ + Elf32_Addr r_offset; /* Address */ + Elf32_Word r_info; /* Relocation type and symbol index */ + Elf32_Sword r_addend; /* Addend */ +} Elf32_Rela; + +typedef struct +{ + Elf64_Addr r_offset; /* Address */ + Elf64_Xword r_info; /* Relocation type and symbol index */ + Elf64_Sxword r_addend; /* Addend */ +} Elf64_Rela; + +/* How to extract and insert information held in the r_info field. */ + +#define ELF32_R_SYM(val) ((val) >> 8) +#define ELF32_R_TYPE(val) ((val) & 0xff) +#define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff)) + +#define ELF64_R_SYM(i) ((i) >> 32) +#define ELF64_R_TYPE(i) ((i) & 0xffffffff) +#define ELF64_R_INFO(sym,type) ((((Elf64_Xword) (sym)) << 32) + (type)) + +/* Program segment header. */ + +typedef struct +{ + Elf32_Word p_type; /* Segment type */ + Elf32_Off p_offset; /* Segment file offset */ + Elf32_Addr p_vaddr; /* Segment virtual address */ + Elf32_Addr p_paddr; /* Segment physical address */ + Elf32_Word p_filesz; /* Segment size in file */ + Elf32_Word p_memsz; /* Segment size in memory */ + Elf32_Word p_flags; /* Segment flags */ + Elf32_Word p_align; /* Segment alignment */ +} Elf32_Phdr; + +typedef struct +{ + Elf64_Word p_type; /* Segment type */ + Elf64_Word p_flags; /* Segment flags */ + Elf64_Off p_offset; /* Segment file offset */ + Elf64_Addr p_vaddr; /* Segment virtual address */ + Elf64_Addr p_paddr; /* Segment physical address */ + Elf64_Xword p_filesz; /* Segment size in file */ + Elf64_Xword p_memsz; /* Segment size in memory */ + Elf64_Xword p_align; /* Segment alignment */ +} Elf64_Phdr; + +/* Special value for e_phnum. This indicates that the real number of + program headers is too large to fit into e_phnum. Instead the real + value is in the field sh_info of section 0. */ + +#define PN_XNUM 0xffff + +/* Legal values for p_type (segment type). */ + +#define PT_NULL 0 /* Program header table entry unused */ +#define PT_LOAD 1 /* Loadable program segment */ +#define PT_DYNAMIC 2 /* Dynamic linking information */ +#define PT_INTERP 3 /* Program interpreter */ +#define PT_NOTE 4 /* Auxiliary information */ +#define PT_SHLIB 5 /* Reserved */ +#define PT_PHDR 6 /* Entry for header table itself */ +#define PT_TLS 7 /* Thread-local storage segment */ +#define PT_NUM 8 /* Number of defined types */ +#define PT_LOOS 0x60000000 /* Start of OS-specific */ +#define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */ +#define PT_GNU_STACK 0x6474e551 /* Indicates stack executability */ +#define PT_GNU_RELRO 0x6474e552 /* Read-only after relocation */ +#define PT_LOSUNW 0x6ffffffa +#define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */ +#define PT_SUNWSTACK 0x6ffffffb /* Stack segment */ +#define PT_HISUNW 0x6fffffff +#define PT_HIOS 0x6fffffff /* End of OS-specific */ +#define PT_LOPROC 0x70000000 /* Start of processor-specific */ +#define PT_HIPROC 0x7fffffff /* End of processor-specific */ + +/* Legal values for p_flags (segment flags). */ + +#define PF_X (1 << 0) /* Segment is executable */ +#define PF_W (1 << 1) /* Segment is writable */ +#define PF_R (1 << 2) /* Segment is readable */ +#define PF_MASKOS 0x0ff00000 /* OS-specific */ +#define PF_MASKPROC 0xf0000000 /* Processor-specific */ + +/* Legal values for note segment descriptor types for core files. */ + +#define NT_PRSTATUS 1 /* Contains copy of prstatus struct */ +#define NT_FPREGSET 2 /* Contains copy of fpregset struct */ +#define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */ +#define NT_PRXREG 4 /* Contains copy of prxregset struct */ +#define NT_TASKSTRUCT 4 /* Contains copy of task structure */ +#define NT_PLATFORM 5 /* String from sysinfo(SI_PLATFORM) */ +#define NT_AUXV 6 /* Contains copy of auxv array */ +#define NT_GWINDOWS 7 /* Contains copy of gwindows struct */ +#define NT_ASRS 8 /* Contains copy of asrset struct */ +#define NT_PSTATUS 10 /* Contains copy of pstatus struct */ +#define NT_PSINFO 13 /* Contains copy of psinfo struct */ +#define NT_PRCRED 14 /* Contains copy of prcred struct */ +#define NT_UTSNAME 15 /* Contains copy of utsname struct */ +#define NT_LWPSTATUS 16 /* Contains copy of lwpstatus struct */ +#define NT_LWPSINFO 17 /* Contains copy of lwpinfo struct */ +#define NT_PRFPXREG 20 /* Contains copy of fprxregset struct */ +#define NT_SIGINFO 0x53494749 /* Contains copy of siginfo_t, + size might increase */ +#define NT_FILE 0x46494c45 /* Contains information about mapped + files */ +#define NT_PRXFPREG 0x46e62b7f /* Contains copy of user_fxsr_struct */ +#define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */ +#define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */ +#define NT_PPC_VSX 0x102 /* PowerPC VSX registers */ +#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */ +#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */ +#define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */ +#define NT_S390_HIGH_GPRS 0x300 /* s390 upper register halves */ +#define NT_S390_TIMER 0x301 /* s390 timer register */ +#define NT_S390_TODCMP 0x302 /* s390 TOD clock comparator register */ +#define NT_S390_TODPREG 0x303 /* s390 TOD programmable register */ +#define NT_S390_CTRS 0x304 /* s390 control registers */ +#define NT_S390_PREFIX 0x305 /* s390 prefix register */ +#define NT_S390_LAST_BREAK 0x306 /* s390 breaking event address */ +#define NT_S390_SYSTEM_CALL 0x307 /* s390 system call restart data */ +#define NT_S390_TDB 0x308 /* s390 transaction diagnostic block */ +#define NT_ARM_VFP 0x400 /* ARM VFP/NEON registers */ +#define NT_ARM_TLS 0x401 /* ARM TLS register */ +#define NT_ARM_HW_BREAK 0x402 /* ARM hardware breakpoint registers */ +#define NT_ARM_HW_WATCH 0x403 /* ARM hardware watchpoint registers */ + +/* Legal values for the note segment descriptor types for object files. */ + +#define NT_VERSION 1 /* Contains a version string. */ + + +/* Dynamic section entry. */ + +typedef struct +{ + Elf32_Sword d_tag; /* Dynamic entry type */ + union + { + Elf32_Word d_val; /* Integer value */ + Elf32_Addr d_ptr; /* Address value */ + } d_un; +} Elf32_Dyn; + +typedef struct +{ + Elf64_Sxword d_tag; /* Dynamic entry type */ + union + { + Elf64_Xword d_val; /* Integer value */ + Elf64_Addr d_ptr; /* Address value */ + } d_un; +} Elf64_Dyn; + +/* Legal values for d_tag (dynamic entry type). */ + +#define DT_NULL 0 /* Marks end of dynamic section */ +#define DT_NEEDED 1 /* Name of needed library */ +#define DT_PLTRELSZ 2 /* Size in bytes of PLT relocs */ +#define DT_PLTGOT 3 /* Processor defined value */ +#define DT_HASH 4 /* Address of symbol hash table */ +#define DT_STRTAB 5 /* Address of string table */ +#define DT_SYMTAB 6 /* Address of symbol table */ +#define DT_RELA 7 /* Address of Rela relocs */ +#define DT_RELASZ 8 /* Total size of Rela relocs */ +#define DT_RELAENT 9 /* Size of one Rela reloc */ +#define DT_STRSZ 10 /* Size of string table */ +#define DT_SYMENT 11 /* Size of one symbol table entry */ +#define DT_INIT 12 /* Address of init function */ +#define DT_FINI 13 /* Address of termination function */ +#define DT_SONAME 14 /* Name of shared object */ +#define DT_RPATH 15 /* Library search path (deprecated) */ +#define DT_SYMBOLIC 16 /* Start symbol search here */ +#define DT_REL 17 /* Address of Rel relocs */ +#define DT_RELSZ 18 /* Total size of Rel relocs */ +#define DT_RELENT 19 /* Size of one Rel reloc */ +#define DT_PLTREL 20 /* Type of reloc in PLT */ +#define DT_DEBUG 21 /* For debugging; unspecified */ +#define DT_TEXTREL 22 /* Reloc might modify .text */ +#define DT_JMPREL 23 /* Address of PLT relocs */ +#define DT_BIND_NOW 24 /* Process relocations of object */ +#define DT_INIT_ARRAY 25 /* Array with addresses of init fct */ +#define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */ +#define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */ +#define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */ +#define DT_RUNPATH 29 /* Library search path */ +#define DT_FLAGS 30 /* Flags for the object being loaded */ +#define DT_ENCODING 32 /* Start of encoded range */ +#define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/ +#define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */ +#define DT_NUM 34 /* Number used */ +#define DT_LOOS 0x6000000d /* Start of OS-specific */ +#define DT_HIOS 0x6ffff000 /* End of OS-specific */ +#define DT_LOPROC 0x70000000 /* Start of processor-specific */ +#define DT_HIPROC 0x7fffffff /* End of processor-specific */ +#define DT_PROCNUM DT_MIPS_NUM /* Most used by any processor */ + +/* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the + Dyn.d_un.d_val field of the Elf*_Dyn structure. This follows Sun's + approach. */ +#define DT_VALRNGLO 0x6ffffd00 +#define DT_GNU_PRELINKED 0x6ffffdf5 /* Prelinking timestamp */ +#define DT_GNU_CONFLICTSZ 0x6ffffdf6 /* Size of conflict section */ +#define DT_GNU_LIBLISTSZ 0x6ffffdf7 /* Size of library list */ +#define DT_CHECKSUM 0x6ffffdf8 +#define DT_PLTPADSZ 0x6ffffdf9 +#define DT_MOVEENT 0x6ffffdfa +#define DT_MOVESZ 0x6ffffdfb +#define DT_FEATURE_1 0x6ffffdfc /* Feature selection (DTF_*). */ +#define DT_POSFLAG_1 0x6ffffdfd /* Flags for DT_* entries, effecting + the following DT_* entry. */ +#define DT_SYMINSZ 0x6ffffdfe /* Size of syminfo table (in bytes) */ +#define DT_SYMINENT 0x6ffffdff /* Entry size of syminfo */ +#define DT_VALRNGHI 0x6ffffdff +#define DT_VALTAGIDX(tag) (DT_VALRNGHI - (tag)) /* Reverse order! */ +#define DT_VALNUM 12 + +/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the + Dyn.d_un.d_ptr field of the Elf*_Dyn structure. + + If any adjustment is made to the ELF object after it has been + built these entries will need to be adjusted. */ +#define DT_ADDRRNGLO 0x6ffffe00 +#define DT_GNU_HASH 0x6ffffef5 /* GNU-style hash table. */ +#define DT_TLSDESC_PLT 0x6ffffef6 +#define DT_TLSDESC_GOT 0x6ffffef7 +#define DT_GNU_CONFLICT 0x6ffffef8 /* Start of conflict section */ +#define DT_GNU_LIBLIST 0x6ffffef9 /* Library list */ +#define DT_CONFIG 0x6ffffefa /* Configuration information. */ +#define DT_DEPAUDIT 0x6ffffefb /* Dependency auditing. */ +#define DT_AUDIT 0x6ffffefc /* Object auditing. */ +#define DT_PLTPAD 0x6ffffefd /* PLT padding. */ +#define DT_MOVETAB 0x6ffffefe /* Move table. */ +#define DT_SYMINFO 0x6ffffeff /* Syminfo table. */ +#define DT_ADDRRNGHI 0x6ffffeff +#define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */ +#define DT_ADDRNUM 11 + +/* The versioning entry types. The next are defined as part of the + GNU extension. */ +#define DT_VERSYM 0x6ffffff0 + +#define DT_RELACOUNT 0x6ffffff9 +#define DT_RELCOUNT 0x6ffffffa + +/* These were chosen by Sun. */ +#define DT_FLAGS_1 0x6ffffffb /* State flags, see DF_1_* below. */ +#define DT_VERDEF 0x6ffffffc /* Address of version definition + table */ +#define DT_VERDEFNUM 0x6ffffffd /* Number of version definitions */ +#define DT_VERNEED 0x6ffffffe /* Address of table with needed + versions */ +#define DT_VERNEEDNUM 0x6fffffff /* Number of needed versions */ +#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */ +#define DT_VERSIONTAGNUM 16 + +/* Sun added these machine-independent extensions in the "processor-specific" + range. Be compatible. */ +#define DT_AUXILIARY 0x7ffffffd /* Shared object to load before self */ +#define DT_FILTER 0x7fffffff /* Shared object to get values from */ +#define DT_EXTRATAGIDX(tag) ((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1) +#define DT_EXTRANUM 3 + +/* Values of `d_un.d_val' in the DT_FLAGS entry. */ +#define DF_ORIGIN 0x00000001 /* Object may use DF_ORIGIN */ +#define DF_SYMBOLIC 0x00000002 /* Symbol resolutions starts here */ +#define DF_TEXTREL 0x00000004 /* Object contains text relocations */ +#define DF_BIND_NOW 0x00000008 /* No lazy binding for this object */ +#define DF_STATIC_TLS 0x00000010 /* Module uses the static TLS model */ + +/* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1 + entry in the dynamic section. */ +#define DF_1_NOW 0x00000001 /* Set RTLD_NOW for this object. */ +#define DF_1_GLOBAL 0x00000002 /* Set RTLD_GLOBAL for this object. */ +#define DF_1_GROUP 0x00000004 /* Set RTLD_GROUP for this object. */ +#define DF_1_NODELETE 0x00000008 /* Set RTLD_NODELETE for this object.*/ +#define DF_1_LOADFLTR 0x00000010 /* Trigger filtee loading at runtime.*/ +#define DF_1_INITFIRST 0x00000020 /* Set RTLD_INITFIRST for this object*/ +#define DF_1_NOOPEN 0x00000040 /* Set RTLD_NOOPEN for this object. */ +#define DF_1_ORIGIN 0x00000080 /* $ORIGIN must be handled. */ +#define DF_1_DIRECT 0x00000100 /* Direct binding enabled. */ +#define DF_1_TRANS 0x00000200 +#define DF_1_INTERPOSE 0x00000400 /* Object is used to interpose. */ +#define DF_1_NODEFLIB 0x00000800 /* Ignore default lib search path. */ +#define DF_1_NODUMP 0x00001000 /* Object can't be dldump'ed. */ +#define DF_1_CONFALT 0x00002000 /* Configuration alternative created.*/ +#define DF_1_ENDFILTEE 0x00004000 /* Filtee terminates filters search. */ +#define DF_1_DISPRELDNE 0x00008000 /* Disp reloc applied at build time. */ +#define DF_1_DISPRELPND 0x00010000 /* Disp reloc applied at run-time. */ +#define DF_1_NODIRECT 0x00020000 /* Object has no-direct binding. */ +#define DF_1_IGNMULDEF 0x00040000 +#define DF_1_NOKSYMS 0x00080000 +#define DF_1_NOHDR 0x00100000 +#define DF_1_EDITED 0x00200000 /* Object is modified after built. */ +#define DF_1_NORELOC 0x00400000 +#define DF_1_SYMINTPOSE 0x00800000 /* Object has individual interposers. */ +#define DF_1_GLOBAUDIT 0x01000000 /* Global auditing required. */ +#define DF_1_SINGLETON 0x02000000 /* Singleton symbols are used. */ + +/* Flags for the feature selection in DT_FEATURE_1. */ +#define DTF_1_PARINIT 0x00000001 +#define DTF_1_CONFEXP 0x00000002 + +/* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry. */ +#define DF_P1_LAZYLOAD 0x00000001 /* Lazyload following object. */ +#define DF_P1_GROUPPERM 0x00000002 /* Symbols from next object are not + generally available. */ + +/* Version definition sections. */ + +typedef struct +{ + Elf32_Half vd_version; /* Version revision */ + Elf32_Half vd_flags; /* Version information */ + Elf32_Half vd_ndx; /* Version Index */ + Elf32_Half vd_cnt; /* Number of associated aux entries */ + Elf32_Word vd_hash; /* Version name hash value */ + Elf32_Word vd_aux; /* Offset in bytes to verdaux array */ + Elf32_Word vd_next; /* Offset in bytes to next verdef + entry */ +} Elf32_Verdef; + +typedef struct +{ + Elf64_Half vd_version; /* Version revision */ + Elf64_Half vd_flags; /* Version information */ + Elf64_Half vd_ndx; /* Version Index */ + Elf64_Half vd_cnt; /* Number of associated aux entries */ + Elf64_Word vd_hash; /* Version name hash value */ + Elf64_Word vd_aux; /* Offset in bytes to verdaux array */ + Elf64_Word vd_next; /* Offset in bytes to next verdef + entry */ +} Elf64_Verdef; + + +/* Legal values for vd_version (version revision). */ +#define VER_DEF_NONE 0 /* No version */ +#define VER_DEF_CURRENT 1 /* Current version */ +#define VER_DEF_NUM 2 /* Given version number */ + +/* Legal values for vd_flags (version information flags). */ +#define VER_FLG_BASE 0x1 /* Version definition of file itself */ +#define VER_FLG_WEAK 0x2 /* Weak version identifier */ + +/* Versym symbol index values. */ +#define VER_NDX_LOCAL 0 /* Symbol is local. */ +#define VER_NDX_GLOBAL 1 /* Symbol is global. */ +#define VER_NDX_LORESERVE 0xff00 /* Beginning of reserved entries. */ +#define VER_NDX_ELIMINATE 0xff01 /* Symbol is to be eliminated. */ + +/* Auxialiary version information. */ + +typedef struct +{ + Elf32_Word vda_name; /* Version or dependency names */ + Elf32_Word vda_next; /* Offset in bytes to next verdaux + entry */ +} Elf32_Verdaux; + +typedef struct +{ + Elf64_Word vda_name; /* Version or dependency names */ + Elf64_Word vda_next; /* Offset in bytes to next verdaux + entry */ +} Elf64_Verdaux; + + +/* Version dependency section. */ + +typedef struct +{ + Elf32_Half vn_version; /* Version of structure */ + Elf32_Half vn_cnt; /* Number of associated aux entries */ + Elf32_Word vn_file; /* Offset of filename for this + dependency */ + Elf32_Word vn_aux; /* Offset in bytes to vernaux array */ + Elf32_Word vn_next; /* Offset in bytes to next verneed + entry */ +} Elf32_Verneed; + +typedef struct +{ + Elf64_Half vn_version; /* Version of structure */ + Elf64_Half vn_cnt; /* Number of associated aux entries */ + Elf64_Word vn_file; /* Offset of filename for this + dependency */ + Elf64_Word vn_aux; /* Offset in bytes to vernaux array */ + Elf64_Word vn_next; /* Offset in bytes to next verneed + entry */ +} Elf64_Verneed; + + +/* Legal values for vn_version (version revision). */ +#define VER_NEED_NONE 0 /* No version */ +#define VER_NEED_CURRENT 1 /* Current version */ +#define VER_NEED_NUM 2 /* Given version number */ + +/* Auxiliary needed version information. */ + +typedef struct +{ + Elf32_Word vna_hash; /* Hash value of dependency name */ + Elf32_Half vna_flags; /* Dependency specific information */ + Elf32_Half vna_other; /* Unused */ + Elf32_Word vna_name; /* Dependency name string offset */ + Elf32_Word vna_next; /* Offset in bytes to next vernaux + entry */ +} Elf32_Vernaux; + +typedef struct +{ + Elf64_Word vna_hash; /* Hash value of dependency name */ + Elf64_Half vna_flags; /* Dependency specific information */ + Elf64_Half vna_other; /* Unused */ + Elf64_Word vna_name; /* Dependency name string offset */ + Elf64_Word vna_next; /* Offset in bytes to next vernaux + entry */ +} Elf64_Vernaux; + + +/* Legal values for vna_flags. */ +#define VER_FLG_WEAK 0x2 /* Weak version identifier */ + + +/* Auxiliary vector. */ + +/* This vector is normally only used by the program interpreter. The + usual definition in an ABI supplement uses the name auxv_t. The + vector is not usually defined in a standard <elf.h> file, but it + can't hurt. We rename it to avoid conflicts. The sizes of these + types are an arrangement between the exec server and the program + interpreter, so we don't fully specify them here. */ + +typedef struct +{ + uint32_t a_type; /* Entry type */ + union + { + uint32_t a_val; /* Integer value */ + /* We use to have pointer elements added here. We cannot do that, + though, since it does not work when using 32-bit definitions + on 64-bit platforms and vice versa. */ + } a_un; +} Elf32_auxv_t; + +typedef struct +{ + uint64_t a_type; /* Entry type */ + union + { + uint64_t a_val; /* Integer value */ + /* We use to have pointer elements added here. We cannot do that, + though, since it does not work when using 32-bit definitions + on 64-bit platforms and vice versa. */ + } a_un; +} Elf64_auxv_t; + +/* Legal values for a_type (entry type). */ + +#define AT_NULL 0 /* End of vector */ +#define AT_IGNORE 1 /* Entry should be ignored */ +#define AT_EXECFD 2 /* File descriptor of program */ +#define AT_PHDR 3 /* Program headers for program */ +#define AT_PHENT 4 /* Size of program header entry */ +#define AT_PHNUM 5 /* Number of program headers */ +#define AT_PAGESZ 6 /* System page size */ +#define AT_BASE 7 /* Base address of interpreter */ +#define AT_FLAGS 8 /* Flags */ +#define AT_ENTRY 9 /* Entry point of program */ +#define AT_NOTELF 10 /* Program is not ELF */ +#define AT_UID 11 /* Real uid */ +#define AT_EUID 12 /* Effective uid */ +#define AT_GID 13 /* Real gid */ +#define AT_EGID 14 /* Effective gid */ +#define AT_CLKTCK 17 /* Frequency of times() */ + +/* Some more special a_type values describing the hardware. */ +#define AT_PLATFORM 15 /* String identifying platform. */ +#define AT_HWCAP 16 /* Machine-dependent hints about + processor capabilities. */ + +/* This entry gives some information about the FPU initialization + performed by the kernel. */ +#define AT_FPUCW 18 /* Used FPU control word. */ + +/* Cache block sizes. */ +#define AT_DCACHEBSIZE 19 /* Data cache block size. */ +#define AT_ICACHEBSIZE 20 /* Instruction cache block size. */ +#define AT_UCACHEBSIZE 21 /* Unified cache block size. */ + +/* A special ignored value for PPC, used by the kernel to control the + interpretation of the AUXV. Must be > 16. */ +#define AT_IGNOREPPC 22 /* Entry should be ignored. */ + +#define AT_SECURE 23 /* Boolean, was exec setuid-like? */ + +#define AT_BASE_PLATFORM 24 /* String identifying real platforms.*/ + +#define AT_RANDOM 25 /* Address of 16 random bytes. */ + +#define AT_HWCAP2 26 /* More machine-dependent hints about + processor capabilities. */ + +#define AT_EXECFN 31 /* Filename of executable. */ + +/* Pointer to the global system page used for system calls and other + nice things. */ +#define AT_SYSINFO 32 +#define AT_SYSINFO_EHDR 33 + +/* Shapes of the caches. Bits 0-3 contains associativity; bits 4-7 contains + log2 of line size; mask those to get cache size. */ +#define AT_L1I_CACHESHAPE 34 +#define AT_L1D_CACHESHAPE 35 +#define AT_L2_CACHESHAPE 36 +#define AT_L3_CACHESHAPE 37 + +/* Note section contents. Each entry in the note section begins with + a header of a fixed form. */ + +typedef struct +{ + Elf32_Word n_namesz; /* Length of the note's name. */ + Elf32_Word n_descsz; /* Length of the note's descriptor. */ + Elf32_Word n_type; /* Type of the note. */ +} Elf32_Nhdr; + +typedef struct +{ + Elf64_Word n_namesz; /* Length of the note's name. */ + Elf64_Word n_descsz; /* Length of the note's descriptor. */ + Elf64_Word n_type; /* Type of the note. */ +} Elf64_Nhdr; + +/* Known names of notes. */ + +/* Solaris entries in the note section have this name. */ +#define ELF_NOTE_SOLARIS "SUNW Solaris" + +/* Note entries for GNU systems have this name. */ +#define ELF_NOTE_GNU "GNU" + + +/* Defined types of notes for Solaris. */ + +/* Value of descriptor (one word) is desired pagesize for the binary. */ +#define ELF_NOTE_PAGESIZE_HINT 1 + + +/* Defined note types for GNU systems. */ + +/* ABI information. The descriptor consists of words: + word 0: OS descriptor + word 1: major version of the ABI + word 2: minor version of the ABI + word 3: subminor version of the ABI +*/ +#define NT_GNU_ABI_TAG 1 +#define ELF_NOTE_ABI NT_GNU_ABI_TAG /* Old name. */ + +/* Known OSes. These values can appear in word 0 of an + NT_GNU_ABI_TAG note section entry. */ +#define ELF_NOTE_OS_LINUX 0 +#define ELF_NOTE_OS_GNU 1 +#define ELF_NOTE_OS_SOLARIS2 2 +#define ELF_NOTE_OS_FREEBSD 3 + +/* Synthetic hwcap information. The descriptor begins with two words: + word 0: number of entries + word 1: bitmask of enabled entries + Then follow variable-length entries, one byte followed by a + '\0'-terminated hwcap name string. The byte gives the bit + number to test if enabled, (1U << bit) & bitmask. */ +#define NT_GNU_HWCAP 2 + +/* Build ID bits as generated by ld --build-id. + The descriptor consists of any nonzero number of bytes. */ +#define NT_GNU_BUILD_ID 3 + +/* Version note generated by GNU gold containing a version string. */ +#define NT_GNU_GOLD_VERSION 4 + + +/* Move records. */ +typedef struct +{ + Elf32_Xword m_value; /* Symbol value. */ + Elf32_Word m_info; /* Size and index. */ + Elf32_Word m_poffset; /* Symbol offset. */ + Elf32_Half m_repeat; /* Repeat count. */ + Elf32_Half m_stride; /* Stride info. */ +} Elf32_Move; + +typedef struct +{ + Elf64_Xword m_value; /* Symbol value. */ + Elf64_Xword m_info; /* Size and index. */ + Elf64_Xword m_poffset; /* Symbol offset. */ + Elf64_Half m_repeat; /* Repeat count. */ + Elf64_Half m_stride; /* Stride info. */ +} Elf64_Move; + +/* Macro to construct move records. */ +#define ELF32_M_SYM(info) ((info) >> 8) +#define ELF32_M_SIZE(info) ((unsigned char) (info)) +#define ELF32_M_INFO(sym, size) (((sym) << 8) + (unsigned char) (size)) + +#define ELF64_M_SYM(info) ELF32_M_SYM (info) +#define ELF64_M_SIZE(info) ELF32_M_SIZE (info) +#define ELF64_M_INFO(sym, size) ELF32_M_INFO (sym, size) + + +/* Motorola 68k specific definitions. */ + +/* Values for Elf32_Ehdr.e_flags. */ +#define EF_CPU32 0x00810000 + +/* m68k relocs. */ + +#define R_68K_NONE 0 /* No reloc */ +#define R_68K_32 1 /* Direct 32 bit */ +#define R_68K_16 2 /* Direct 16 bit */ +#define R_68K_8 3 /* Direct 8 bit */ +#define R_68K_PC32 4 /* PC relative 32 bit */ +#define R_68K_PC16 5 /* PC relative 16 bit */ +#define R_68K_PC8 6 /* PC relative 8 bit */ +#define R_68K_GOT32 7 /* 32 bit PC relative GOT entry */ +#define R_68K_GOT16 8 /* 16 bit PC relative GOT entry */ +#define R_68K_GOT8 9 /* 8 bit PC relative GOT entry */ +#define R_68K_GOT32O 10 /* 32 bit GOT offset */ +#define R_68K_GOT16O 11 /* 16 bit GOT offset */ +#define R_68K_GOT8O 12 /* 8 bit GOT offset */ +#define R_68K_PLT32 13 /* 32 bit PC relative PLT address */ +#define R_68K_PLT16 14 /* 16 bit PC relative PLT address */ +#define R_68K_PLT8 15 /* 8 bit PC relative PLT address */ +#define R_68K_PLT32O 16 /* 32 bit PLT offset */ +#define R_68K_PLT16O 17 /* 16 bit PLT offset */ +#define R_68K_PLT8O 18 /* 8 bit PLT offset */ +#define R_68K_COPY 19 /* Copy symbol at runtime */ +#define R_68K_GLOB_DAT 20 /* Create GOT entry */ +#define R_68K_JMP_SLOT 21 /* Create PLT entry */ +#define R_68K_RELATIVE 22 /* Adjust by program base */ +#define R_68K_TLS_GD32 25 /* 32 bit GOT offset for GD */ +#define R_68K_TLS_GD16 26 /* 16 bit GOT offset for GD */ +#define R_68K_TLS_GD8 27 /* 8 bit GOT offset for GD */ +#define R_68K_TLS_LDM32 28 /* 32 bit GOT offset for LDM */ +#define R_68K_TLS_LDM16 29 /* 16 bit GOT offset for LDM */ +#define R_68K_TLS_LDM8 30 /* 8 bit GOT offset for LDM */ +#define R_68K_TLS_LDO32 31 /* 32 bit module-relative offset */ +#define R_68K_TLS_LDO16 32 /* 16 bit module-relative offset */ +#define R_68K_TLS_LDO8 33 /* 8 bit module-relative offset */ +#define R_68K_TLS_IE32 34 /* 32 bit GOT offset for IE */ +#define R_68K_TLS_IE16 35 /* 16 bit GOT offset for IE */ +#define R_68K_TLS_IE8 36 /* 8 bit GOT offset for IE */ +#define R_68K_TLS_LE32 37 /* 32 bit offset relative to + static TLS block */ +#define R_68K_TLS_LE16 38 /* 16 bit offset relative to + static TLS block */ +#define R_68K_TLS_LE8 39 /* 8 bit offset relative to + static TLS block */ +#define R_68K_TLS_DTPMOD32 40 /* 32 bit module number */ +#define R_68K_TLS_DTPREL32 41 /* 32 bit module-relative offset */ +#define R_68K_TLS_TPREL32 42 /* 32 bit TP-relative offset */ +/* Keep this the last entry. */ +#define R_68K_NUM 43 + +/* Intel 80386 specific definitions. */ + +/* i386 relocs. */ + +#define R_386_NONE 0 /* No reloc */ +#define R_386_32 1 /* Direct 32 bit */ +#define R_386_PC32 2 /* PC relative 32 bit */ +#define R_386_GOT32 3 /* 32 bit GOT entry */ +#define R_386_PLT32 4 /* 32 bit PLT address */ +#define R_386_COPY 5 /* Copy symbol at runtime */ +#define R_386_GLOB_DAT 6 /* Create GOT entry */ +#define R_386_JMP_SLOT 7 /* Create PLT entry */ +#define R_386_RELATIVE 8 /* Adjust by program base */ +#define R_386_GOTOFF 9 /* 32 bit offset to GOT */ +#define R_386_GOTPC 10 /* 32 bit PC relative offset to GOT */ +#define R_386_32PLT 11 +#define R_386_TLS_TPOFF 14 /* Offset in static TLS block */ +#define R_386_TLS_IE 15 /* Address of GOT entry for static TLS + block offset */ +#define R_386_TLS_GOTIE 16 /* GOT entry for static TLS block + offset */ +#define R_386_TLS_LE 17 /* Offset relative to static TLS + block */ +#define R_386_TLS_GD 18 /* Direct 32 bit for GNU version of + general dynamic thread local data */ +#define R_386_TLS_LDM 19 /* Direct 32 bit for GNU version of + local dynamic thread local data + in LE code */ +#define R_386_16 20 +#define R_386_PC16 21 +#define R_386_8 22 +#define R_386_PC8 23 +#define R_386_TLS_GD_32 24 /* Direct 32 bit for general dynamic + thread local data */ +#define R_386_TLS_GD_PUSH 25 /* Tag for pushl in GD TLS code */ +#define R_386_TLS_GD_CALL 26 /* Relocation for call to + __tls_get_addr() */ +#define R_386_TLS_GD_POP 27 /* Tag for popl in GD TLS code */ +#define R_386_TLS_LDM_32 28 /* Direct 32 bit for local dynamic + thread local data in LE code */ +#define R_386_TLS_LDM_PUSH 29 /* Tag for pushl in LDM TLS code */ +#define R_386_TLS_LDM_CALL 30 /* Relocation for call to + __tls_get_addr() in LDM code */ +#define R_386_TLS_LDM_POP 31 /* Tag for popl in LDM TLS code */ +#define R_386_TLS_LDO_32 32 /* Offset relative to TLS block */ +#define R_386_TLS_IE_32 33 /* GOT entry for negated static TLS + block offset */ +#define R_386_TLS_LE_32 34 /* Negated offset relative to static + TLS block */ +#define R_386_TLS_DTPMOD32 35 /* ID of module containing symbol */ +#define R_386_TLS_DTPOFF32 36 /* Offset in TLS block */ +#define R_386_TLS_TPOFF32 37 /* Negated offset in static TLS block */ +#define R_386_SIZE32 38 /* 32-bit symbol size */ +#define R_386_TLS_GOTDESC 39 /* GOT offset for TLS descriptor. */ +#define R_386_TLS_DESC_CALL 40 /* Marker of call through TLS + descriptor for + relaxation. */ +#define R_386_TLS_DESC 41 /* TLS descriptor containing + pointer to code and to + argument, returning the TLS + offset for the symbol. */ +#define R_386_IRELATIVE 42 /* Adjust indirectly by program base */ +/* Keep this the last entry. */ +#define R_386_NUM 43 + +/* SUN SPARC specific definitions. */ + +/* Legal values for ST_TYPE subfield of st_info (symbol type). */ + +#define STT_SPARC_REGISTER 13 /* Global register reserved to app. */ + +/* Values for Elf64_Ehdr.e_flags. */ + +#define EF_SPARCV9_MM 3 +#define EF_SPARCV9_TSO 0 +#define EF_SPARCV9_PSO 1 +#define EF_SPARCV9_RMO 2 +#define EF_SPARC_LEDATA 0x800000 /* little endian data */ +#define EF_SPARC_EXT_MASK 0xFFFF00 +#define EF_SPARC_32PLUS 0x000100 /* generic V8+ features */ +#define EF_SPARC_SUN_US1 0x000200 /* Sun UltraSPARC1 extensions */ +#define EF_SPARC_HAL_R1 0x000400 /* HAL R1 extensions */ +#define EF_SPARC_SUN_US3 0x000800 /* Sun UltraSPARCIII extensions */ + +/* SPARC relocs. */ + +#define R_SPARC_NONE 0 /* No reloc */ +#define R_SPARC_8 1 /* Direct 8 bit */ +#define R_SPARC_16 2 /* Direct 16 bit */ +#define R_SPARC_32 3 /* Direct 32 bit */ +#define R_SPARC_DISP8 4 /* PC relative 8 bit */ +#define R_SPARC_DISP16 5 /* PC relative 16 bit */ +#define R_SPARC_DISP32 6 /* PC relative 32 bit */ +#define R_SPARC_WDISP30 7 /* PC relative 30 bit shifted */ +#define R_SPARC_WDISP22 8 /* PC relative 22 bit shifted */ +#define R_SPARC_HI22 9 /* High 22 bit */ +#define R_SPARC_22 10 /* Direct 22 bit */ +#define R_SPARC_13 11 /* Direct 13 bit */ +#define R_SPARC_LO10 12 /* Truncated 10 bit */ +#define R_SPARC_GOT10 13 /* Truncated 10 bit GOT entry */ +#define R_SPARC_GOT13 14 /* 13 bit GOT entry */ +#define R_SPARC_GOT22 15 /* 22 bit GOT entry shifted */ +#define R_SPARC_PC10 16 /* PC relative 10 bit truncated */ +#define R_SPARC_PC22 17 /* PC relative 22 bit shifted */ +#define R_SPARC_WPLT30 18 /* 30 bit PC relative PLT address */ +#define R_SPARC_COPY 19 /* Copy symbol at runtime */ +#define R_SPARC_GLOB_DAT 20 /* Create GOT entry */ +#define R_SPARC_JMP_SLOT 21 /* Create PLT entry */ +#define R_SPARC_RELATIVE 22 /* Adjust by program base */ +#define R_SPARC_UA32 23 /* Direct 32 bit unaligned */ + +/* Additional Sparc64 relocs. */ + +#define R_SPARC_PLT32 24 /* Direct 32 bit ref to PLT entry */ +#define R_SPARC_HIPLT22 25 /* High 22 bit PLT entry */ +#define R_SPARC_LOPLT10 26 /* Truncated 10 bit PLT entry */ +#define R_SPARC_PCPLT32 27 /* PC rel 32 bit ref to PLT entry */ +#define R_SPARC_PCPLT22 28 /* PC rel high 22 bit PLT entry */ +#define R_SPARC_PCPLT10 29 /* PC rel trunc 10 bit PLT entry */ +#define R_SPARC_10 30 /* Direct 10 bit */ +#define R_SPARC_11 31 /* Direct 11 bit */ +#define R_SPARC_64 32 /* Direct 64 bit */ +#define R_SPARC_OLO10 33 /* 10bit with secondary 13bit addend */ +#define R_SPARC_HH22 34 /* Top 22 bits of direct 64 bit */ +#define R_SPARC_HM10 35 /* High middle 10 bits of ... */ +#define R_SPARC_LM22 36 /* Low middle 22 bits of ... */ +#define R_SPARC_PC_HH22 37 /* Top 22 bits of pc rel 64 bit */ +#define R_SPARC_PC_HM10 38 /* High middle 10 bit of ... */ +#define R_SPARC_PC_LM22 39 /* Low miggle 22 bits of ... */ +#define R_SPARC_WDISP16 40 /* PC relative 16 bit shifted */ +#define R_SPARC_WDISP19 41 /* PC relative 19 bit shifted */ +#define R_SPARC_GLOB_JMP 42 /* was part of v9 ABI but was removed */ +#define R_SPARC_7 43 /* Direct 7 bit */ +#define R_SPARC_5 44 /* Direct 5 bit */ +#define R_SPARC_6 45 /* Direct 6 bit */ +#define R_SPARC_DISP64 46 /* PC relative 64 bit */ +#define R_SPARC_PLT64 47 /* Direct 64 bit ref to PLT entry */ +#define R_SPARC_HIX22 48 /* High 22 bit complemented */ +#define R_SPARC_LOX10 49 /* Truncated 11 bit complemented */ +#define R_SPARC_H44 50 /* Direct high 12 of 44 bit */ +#define R_SPARC_M44 51 /* Direct mid 22 of 44 bit */ +#define R_SPARC_L44 52 /* Direct low 10 of 44 bit */ +#define R_SPARC_REGISTER 53 /* Global register usage */ +#define R_SPARC_UA64 54 /* Direct 64 bit unaligned */ +#define R_SPARC_UA16 55 /* Direct 16 bit unaligned */ +#define R_SPARC_TLS_GD_HI22 56 +#define R_SPARC_TLS_GD_LO10 57 +#define R_SPARC_TLS_GD_ADD 58 +#define R_SPARC_TLS_GD_CALL 59 +#define R_SPARC_TLS_LDM_HI22 60 +#define R_SPARC_TLS_LDM_LO10 61 +#define R_SPARC_TLS_LDM_ADD 62 +#define R_SPARC_TLS_LDM_CALL 63 +#define R_SPARC_TLS_LDO_HIX22 64 +#define R_SPARC_TLS_LDO_LOX10 65 +#define R_SPARC_TLS_LDO_ADD 66 +#define R_SPARC_TLS_IE_HI22 67 +#define R_SPARC_TLS_IE_LO10 68 +#define R_SPARC_TLS_IE_LD 69 +#define R_SPARC_TLS_IE_LDX 70 +#define R_SPARC_TLS_IE_ADD 71 +#define R_SPARC_TLS_LE_HIX22 72 +#define R_SPARC_TLS_LE_LOX10 73 +#define R_SPARC_TLS_DTPMOD32 74 +#define R_SPARC_TLS_DTPMOD64 75 +#define R_SPARC_TLS_DTPOFF32 76 +#define R_SPARC_TLS_DTPOFF64 77 +#define R_SPARC_TLS_TPOFF32 78 +#define R_SPARC_TLS_TPOFF64 79 +#define R_SPARC_GOTDATA_HIX22 80 +#define R_SPARC_GOTDATA_LOX10 81 +#define R_SPARC_GOTDATA_OP_HIX22 82 +#define R_SPARC_GOTDATA_OP_LOX10 83 +#define R_SPARC_GOTDATA_OP 84 +#define R_SPARC_H34 85 +#define R_SPARC_SIZE32 86 +#define R_SPARC_SIZE64 87 +#define R_SPARC_WDISP10 88 +#define R_SPARC_JMP_IREL 248 +#define R_SPARC_IRELATIVE 249 +#define R_SPARC_GNU_VTINHERIT 250 +#define R_SPARC_GNU_VTENTRY 251 +#define R_SPARC_REV32 252 +/* Keep this the last entry. */ +#define R_SPARC_NUM 253 + +/* For Sparc64, legal values for d_tag of Elf64_Dyn. */ + +#define DT_SPARC_REGISTER 0x70000001 +#define DT_SPARC_NUM 2 + +/* MIPS R3000 specific definitions. */ + +/* Legal values for e_flags field of Elf32_Ehdr. */ + +#define EF_MIPS_NOREORDER 1 /* A .noreorder directive was used. */ +#define EF_MIPS_PIC 2 /* Contains PIC code. */ +#define EF_MIPS_CPIC 4 /* Uses PIC calling sequence. */ +#define EF_MIPS_XGOT 8 +#define EF_MIPS_64BIT_WHIRL 16 +#define EF_MIPS_ABI2 32 +#define EF_MIPS_ABI_ON32 64 +#define EF_MIPS_NAN2008 1024 /* Uses IEEE 754-2008 NaN encoding. */ +#define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level. */ + +/* Legal values for MIPS architecture level. */ + +#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ +#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ +#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ +#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ +#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ +#define EF_MIPS_ARCH_32 0x50000000 /* MIPS32 code. */ +#define EF_MIPS_ARCH_64 0x60000000 /* MIPS64 code. */ +#define EF_MIPS_ARCH_32R2 0x70000000 /* MIPS32r2 code. */ +#define EF_MIPS_ARCH_64R2 0x80000000 /* MIPS64r2 code. */ + +/* The following are unofficial names and should not be used. */ + +#define E_MIPS_ARCH_1 EF_MIPS_ARCH_1 +#define E_MIPS_ARCH_2 EF_MIPS_ARCH_2 +#define E_MIPS_ARCH_3 EF_MIPS_ARCH_3 +#define E_MIPS_ARCH_4 EF_MIPS_ARCH_4 +#define E_MIPS_ARCH_5 EF_MIPS_ARCH_5 +#define E_MIPS_ARCH_32 EF_MIPS_ARCH_32 +#define E_MIPS_ARCH_64 EF_MIPS_ARCH_64 + +/* Special section indices. */ + +#define SHN_MIPS_ACOMMON 0xff00 /* Allocated common symbols. */ +#define SHN_MIPS_TEXT 0xff01 /* Allocated test symbols. */ +#define SHN_MIPS_DATA 0xff02 /* Allocated data symbols. */ +#define SHN_MIPS_SCOMMON 0xff03 /* Small common symbols. */ +#define SHN_MIPS_SUNDEFINED 0xff04 /* Small undefined symbols. */ + +/* Legal values for sh_type field of Elf32_Shdr. */ + +#define SHT_MIPS_LIBLIST 0x70000000 /* Shared objects used in link. */ +#define SHT_MIPS_MSYM 0x70000001 +#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicting symbols. */ +#define SHT_MIPS_GPTAB 0x70000003 /* Global data area sizes. */ +#define SHT_MIPS_UCODE 0x70000004 /* Reserved for SGI/MIPS compilers */ +#define SHT_MIPS_DEBUG 0x70000005 /* MIPS ECOFF debugging info. */ +#define SHT_MIPS_REGINFO 0x70000006 /* Register usage information. */ +#define SHT_MIPS_PACKAGE 0x70000007 +#define SHT_MIPS_PACKSYM 0x70000008 +#define SHT_MIPS_RELD 0x70000009 +#define SHT_MIPS_IFACE 0x7000000b +#define SHT_MIPS_CONTENT 0x7000000c +#define SHT_MIPS_OPTIONS 0x7000000d /* Miscellaneous options. */ +#define SHT_MIPS_SHDR 0x70000010 +#define SHT_MIPS_FDESC 0x70000011 +#define SHT_MIPS_EXTSYM 0x70000012 +#define SHT_MIPS_DENSE 0x70000013 +#define SHT_MIPS_PDESC 0x70000014 +#define SHT_MIPS_LOCSYM 0x70000015 +#define SHT_MIPS_AUXSYM 0x70000016 +#define SHT_MIPS_OPTSYM 0x70000017 +#define SHT_MIPS_LOCSTR 0x70000018 +#define SHT_MIPS_LINE 0x70000019 +#define SHT_MIPS_RFDESC 0x7000001a +#define SHT_MIPS_DELTASYM 0x7000001b +#define SHT_MIPS_DELTAINST 0x7000001c +#define SHT_MIPS_DELTACLASS 0x7000001d +#define SHT_MIPS_DWARF 0x7000001e /* DWARF debugging information. */ +#define SHT_MIPS_DELTADECL 0x7000001f +#define SHT_MIPS_SYMBOL_LIB 0x70000020 +#define SHT_MIPS_EVENTS 0x70000021 /* Event section. */ +#define SHT_MIPS_TRANSLATE 0x70000022 +#define SHT_MIPS_PIXIE 0x70000023 +#define SHT_MIPS_XLATE 0x70000024 +#define SHT_MIPS_XLATE_DEBUG 0x70000025 +#define SHT_MIPS_WHIRL 0x70000026 +#define SHT_MIPS_EH_REGION 0x70000027 +#define SHT_MIPS_XLATE_OLD 0x70000028 +#define SHT_MIPS_PDR_EXCEPTION 0x70000029 + +/* Legal values for sh_flags field of Elf32_Shdr. */ + +#define SHF_MIPS_GPREL 0x10000000 /* Must be in global data area. */ +#define SHF_MIPS_MERGE 0x20000000 +#define SHF_MIPS_ADDR 0x40000000 +#define SHF_MIPS_STRINGS 0x80000000 +#define SHF_MIPS_NOSTRIP 0x08000000 +#define SHF_MIPS_LOCAL 0x04000000 +#define SHF_MIPS_NAMES 0x02000000 +#define SHF_MIPS_NODUPE 0x01000000 + + +/* Symbol tables. */ + +/* MIPS specific values for `st_other'. */ +#define STO_MIPS_DEFAULT 0x0 +#define STO_MIPS_INTERNAL 0x1 +#define STO_MIPS_HIDDEN 0x2 +#define STO_MIPS_PROTECTED 0x3 +#define STO_MIPS_PLT 0x8 +#define STO_MIPS_SC_ALIGN_UNUSED 0xff + +/* MIPS specific values for `st_info'. */ +#define STB_MIPS_SPLIT_COMMON 13 + +/* Entries found in sections of type SHT_MIPS_GPTAB. */ + +typedef union +{ + struct + { + Elf32_Word gt_current_g_value; /* -G value used for compilation. */ + Elf32_Word gt_unused; /* Not used. */ + } gt_header; /* First entry in section. */ + struct + { + Elf32_Word gt_g_value; /* If this value were used for -G. */ + Elf32_Word gt_bytes; /* This many bytes would be used. */ + } gt_entry; /* Subsequent entries in section. */ +} Elf32_gptab; + +/* Entry found in sections of type SHT_MIPS_REGINFO. */ + +typedef struct +{ + Elf32_Word ri_gprmask; /* General registers used. */ + Elf32_Word ri_cprmask[4]; /* Coprocessor registers used. */ + Elf32_Sword ri_gp_value; /* $gp register value. */ +} Elf32_RegInfo; + +/* Entries found in sections of type SHT_MIPS_OPTIONS. */ + +typedef struct +{ + unsigned char kind; /* Determines interpretation of the + variable part of descriptor. */ + unsigned char size; /* Size of descriptor, including header. */ + Elf32_Section section; /* Section header index of section affected, + 0 for global options. */ + Elf32_Word info; /* Kind-specific information. */ +} Elf_Options; + +/* Values for `kind' field in Elf_Options. */ + +#define ODK_NULL 0 /* Undefined. */ +#define ODK_REGINFO 1 /* Register usage information. */ +#define ODK_EXCEPTIONS 2 /* Exception processing options. */ +#define ODK_PAD 3 /* Section padding options. */ +#define ODK_HWPATCH 4 /* Hardware workarounds performed */ +#define ODK_FILL 5 /* record the fill value used by the linker. */ +#define ODK_TAGS 6 /* reserve space for desktop tools to write. */ +#define ODK_HWAND 7 /* HW workarounds. 'AND' bits when merging. */ +#define ODK_HWOR 8 /* HW workarounds. 'OR' bits when merging. */ + +/* Values for `info' in Elf_Options for ODK_EXCEPTIONS entries. */ + +#define OEX_FPU_MIN 0x1f /* FPE's which MUST be enabled. */ +#define OEX_FPU_MAX 0x1f00 /* FPE's which MAY be enabled. */ +#define OEX_PAGE0 0x10000 /* page zero must be mapped. */ +#define OEX_SMM 0x20000 /* Force sequential memory mode? */ +#define OEX_FPDBUG 0x40000 /* Force floating point debug mode? */ +#define OEX_PRECISEFP OEX_FPDBUG +#define OEX_DISMISS 0x80000 /* Dismiss invalid address faults? */ + +#define OEX_FPU_INVAL 0x10 +#define OEX_FPU_DIV0 0x08 +#define OEX_FPU_OFLO 0x04 +#define OEX_FPU_UFLO 0x02 +#define OEX_FPU_INEX 0x01 + +/* Masks for `info' in Elf_Options for an ODK_HWPATCH entry. */ + +#define OHW_R4KEOP 0x1 /* R4000 end-of-page patch. */ +#define OHW_R8KPFETCH 0x2 /* may need R8000 prefetch patch. */ +#define OHW_R5KEOP 0x4 /* R5000 end-of-page patch. */ +#define OHW_R5KCVTL 0x8 /* R5000 cvt.[ds].l bug. clean=1. */ + +#define OPAD_PREFIX 0x1 +#define OPAD_POSTFIX 0x2 +#define OPAD_SYMBOL 0x4 + +/* Entry found in `.options' section. */ + +typedef struct +{ + Elf32_Word hwp_flags1; /* Extra flags. */ + Elf32_Word hwp_flags2; /* Extra flags. */ +} Elf_Options_Hw; + +/* Masks for `info' in ElfOptions for ODK_HWAND and ODK_HWOR entries. */ + +#define OHWA0_R4KEOP_CHECKED 0x00000001 +#define OHWA1_R4KEOP_CLEAN 0x00000002 + +/* MIPS relocs. */ + +#define R_MIPS_NONE 0 /* No reloc */ +#define R_MIPS_16 1 /* Direct 16 bit */ +#define R_MIPS_32 2 /* Direct 32 bit */ +#define R_MIPS_REL32 3 /* PC relative 32 bit */ +#define R_MIPS_26 4 /* Direct 26 bit shifted */ +#define R_MIPS_HI16 5 /* High 16 bit */ +#define R_MIPS_LO16 6 /* Low 16 bit */ +#define R_MIPS_GPREL16 7 /* GP relative 16 bit */ +#define R_MIPS_LITERAL 8 /* 16 bit literal entry */ +#define R_MIPS_GOT16 9 /* 16 bit GOT entry */ +#define R_MIPS_PC16 10 /* PC relative 16 bit */ +#define R_MIPS_CALL16 11 /* 16 bit GOT entry for function */ +#define R_MIPS_GPREL32 12 /* GP relative 32 bit */ + +#define R_MIPS_SHIFT5 16 +#define R_MIPS_SHIFT6 17 +#define R_MIPS_64 18 +#define R_MIPS_GOT_DISP 19 +#define R_MIPS_GOT_PAGE 20 +#define R_MIPS_GOT_OFST 21 +#define R_MIPS_GOT_HI16 22 +#define R_MIPS_GOT_LO16 23 +#define R_MIPS_SUB 24 +#define R_MIPS_INSERT_A 25 +#define R_MIPS_INSERT_B 26 +#define R_MIPS_DELETE 27 +#define R_MIPS_HIGHER 28 +#define R_MIPS_HIGHEST 29 +#define R_MIPS_CALL_HI16 30 +#define R_MIPS_CALL_LO16 31 +#define R_MIPS_SCN_DISP 32 +#define R_MIPS_REL16 33 +#define R_MIPS_ADD_IMMEDIATE 34 +#define R_MIPS_PJUMP 35 +#define R_MIPS_RELGOT 36 +#define R_MIPS_JALR 37 +#define R_MIPS_TLS_DTPMOD32 38 /* Module number 32 bit */ +#define R_MIPS_TLS_DTPREL32 39 /* Module-relative offset 32 bit */ +#define R_MIPS_TLS_DTPMOD64 40 /* Module number 64 bit */ +#define R_MIPS_TLS_DTPREL64 41 /* Module-relative offset 64 bit */ +#define R_MIPS_TLS_GD 42 /* 16 bit GOT offset for GD */ +#define R_MIPS_TLS_LDM 43 /* 16 bit GOT offset for LDM */ +#define R_MIPS_TLS_DTPREL_HI16 44 /* Module-relative offset, high 16 bits */ +#define R_MIPS_TLS_DTPREL_LO16 45 /* Module-relative offset, low 16 bits */ +#define R_MIPS_TLS_GOTTPREL 46 /* 16 bit GOT offset for IE */ +#define R_MIPS_TLS_TPREL32 47 /* TP-relative offset, 32 bit */ +#define R_MIPS_TLS_TPREL64 48 /* TP-relative offset, 64 bit */ +#define R_MIPS_TLS_TPREL_HI16 49 /* TP-relative offset, high 16 bits */ +#define R_MIPS_TLS_TPREL_LO16 50 /* TP-relative offset, low 16 bits */ +#define R_MIPS_GLOB_DAT 51 +#define R_MIPS_COPY 126 +#define R_MIPS_JUMP_SLOT 127 +/* Keep this the last entry. */ +#define R_MIPS_NUM 128 + +/* Legal values for p_type field of Elf32_Phdr. */ + +#define PT_MIPS_REGINFO 0x70000000 /* Register usage information */ +#define PT_MIPS_RTPROC 0x70000001 /* Runtime procedure table. */ +#define PT_MIPS_OPTIONS 0x70000002 + +/* Special program header types. */ + +#define PF_MIPS_LOCAL 0x10000000 + +/* Legal values for d_tag field of Elf32_Dyn. */ + +#define DT_MIPS_RLD_VERSION 0x70000001 /* Runtime linker interface version */ +#define DT_MIPS_TIME_STAMP 0x70000002 /* Timestamp */ +#define DT_MIPS_ICHECKSUM 0x70000003 /* Checksum */ +#define DT_MIPS_IVERSION 0x70000004 /* Version string (string tbl index) */ +#define DT_MIPS_FLAGS 0x70000005 /* Flags */ +#define DT_MIPS_BASE_ADDRESS 0x70000006 /* Base address */ +#define DT_MIPS_MSYM 0x70000007 +#define DT_MIPS_CONFLICT 0x70000008 /* Address of CONFLICT section */ +#define DT_MIPS_LIBLIST 0x70000009 /* Address of LIBLIST section */ +#define DT_MIPS_LOCAL_GOTNO 0x7000000a /* Number of local GOT entries */ +#define DT_MIPS_CONFLICTNO 0x7000000b /* Number of CONFLICT entries */ +#define DT_MIPS_LIBLISTNO 0x70000010 /* Number of LIBLIST entries */ +#define DT_MIPS_SYMTABNO 0x70000011 /* Number of DYNSYM entries */ +#define DT_MIPS_UNREFEXTNO 0x70000012 /* First external DYNSYM */ +#define DT_MIPS_GOTSYM 0x70000013 /* First GOT entry in DYNSYM */ +#define DT_MIPS_HIPAGENO 0x70000014 /* Number of GOT page table entries */ +#define DT_MIPS_RLD_MAP 0x70000016 /* Address of run time loader map. */ +#define DT_MIPS_DELTA_CLASS 0x70000017 /* Delta C++ class definition. */ +#define DT_MIPS_DELTA_CLASS_NO 0x70000018 /* Number of entries in + DT_MIPS_DELTA_CLASS. */ +#define DT_MIPS_DELTA_INSTANCE 0x70000019 /* Delta C++ class instances. */ +#define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a /* Number of entries in + DT_MIPS_DELTA_INSTANCE. */ +#define DT_MIPS_DELTA_RELOC 0x7000001b /* Delta relocations. */ +#define DT_MIPS_DELTA_RELOC_NO 0x7000001c /* Number of entries in + DT_MIPS_DELTA_RELOC. */ +#define DT_MIPS_DELTA_SYM 0x7000001d /* Delta symbols that Delta + relocations refer to. */ +#define DT_MIPS_DELTA_SYM_NO 0x7000001e /* Number of entries in + DT_MIPS_DELTA_SYM. */ +#define DT_MIPS_DELTA_CLASSSYM 0x70000020 /* Delta symbols that hold the + class declaration. */ +#define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 /* Number of entries in + DT_MIPS_DELTA_CLASSSYM. */ +#define DT_MIPS_CXX_FLAGS 0x70000022 /* Flags indicating for C++ flavor. */ +#define DT_MIPS_PIXIE_INIT 0x70000023 +#define DT_MIPS_SYMBOL_LIB 0x70000024 +#define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025 +#define DT_MIPS_LOCAL_GOTIDX 0x70000026 +#define DT_MIPS_HIDDEN_GOTIDX 0x70000027 +#define DT_MIPS_PROTECTED_GOTIDX 0x70000028 +#define DT_MIPS_OPTIONS 0x70000029 /* Address of .options. */ +#define DT_MIPS_INTERFACE 0x7000002a /* Address of .interface. */ +#define DT_MIPS_DYNSTR_ALIGN 0x7000002b +#define DT_MIPS_INTERFACE_SIZE 0x7000002c /* Size of the .interface section. */ +#define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002d /* Address of rld_text_rsolve + function stored in GOT. */ +#define DT_MIPS_PERF_SUFFIX 0x7000002e /* Default suffix of dso to be added + by rld on dlopen() calls. */ +#define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */ +#define DT_MIPS_GP_VALUE 0x70000030 /* GP value for aux GOTs. */ +#define DT_MIPS_AUX_DYNAMIC 0x70000031 /* Address of aux .dynamic. */ +/* The address of .got.plt in an executable using the new non-PIC ABI. */ +#define DT_MIPS_PLTGOT 0x70000032 +/* The base of the PLT in an executable using the new non-PIC ABI if that + PLT is writable. For a non-writable PLT, this is omitted or has a zero + value. */ +#define DT_MIPS_RWPLT 0x70000034 +#define DT_MIPS_NUM 0x35 + +/* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry. */ + +#define RHF_NONE 0 /* No flags */ +#define RHF_QUICKSTART (1 << 0) /* Use quickstart */ +#define RHF_NOTPOT (1 << 1) /* Hash size not power of 2 */ +#define RHF_NO_LIBRARY_REPLACEMENT (1 << 2) /* Ignore LD_LIBRARY_PATH */ +#define RHF_NO_MOVE (1 << 3) +#define RHF_SGI_ONLY (1 << 4) +#define RHF_GUARANTEE_INIT (1 << 5) +#define RHF_DELTA_C_PLUS_PLUS (1 << 6) +#define RHF_GUARANTEE_START_INIT (1 << 7) +#define RHF_PIXIE (1 << 8) +#define RHF_DEFAULT_DELAY_LOAD (1 << 9) +#define RHF_REQUICKSTART (1 << 10) +#define RHF_REQUICKSTARTED (1 << 11) +#define RHF_CORD (1 << 12) +#define RHF_NO_UNRES_UNDEF (1 << 13) +#define RHF_RLD_ORDER_SAFE (1 << 14) + +/* Entries found in sections of type SHT_MIPS_LIBLIST. */ + +typedef struct +{ + Elf32_Word l_name; /* Name (string table index) */ + Elf32_Word l_time_stamp; /* Timestamp */ + Elf32_Word l_checksum; /* Checksum */ + Elf32_Word l_version; /* Interface version */ + Elf32_Word l_flags; /* Flags */ +} Elf32_Lib; + +typedef struct +{ + Elf64_Word l_name; /* Name (string table index) */ + Elf64_Word l_time_stamp; /* Timestamp */ + Elf64_Word l_checksum; /* Checksum */ + Elf64_Word l_version; /* Interface version */ + Elf64_Word l_flags; /* Flags */ +} Elf64_Lib; + + +/* Legal values for l_flags. */ + +#define LL_NONE 0 +#define LL_EXACT_MATCH (1 << 0) /* Require exact match */ +#define LL_IGNORE_INT_VER (1 << 1) /* Ignore interface version */ +#define LL_REQUIRE_MINOR (1 << 2) +#define LL_EXPORTS (1 << 3) +#define LL_DELAY_LOAD (1 << 4) +#define LL_DELTA (1 << 5) + +/* Entries found in sections of type SHT_MIPS_CONFLICT. */ + +typedef Elf32_Addr Elf32_Conflict; + + +/* HPPA specific definitions. */ + +/* Legal values for e_flags field of Elf32_Ehdr. */ + +#define EF_PARISC_TRAPNIL 0x00010000 /* Trap nil pointer dereference. */ +#define EF_PARISC_EXT 0x00020000 /* Program uses arch. extensions. */ +#define EF_PARISC_LSB 0x00040000 /* Program expects little endian. */ +#define EF_PARISC_WIDE 0x00080000 /* Program expects wide mode. */ +#define EF_PARISC_NO_KABP 0x00100000 /* No kernel assisted branch + prediction. */ +#define EF_PARISC_LAZYSWAP 0x00400000 /* Allow lazy swapping. */ +#define EF_PARISC_ARCH 0x0000ffff /* Architecture version. */ + +/* Defined values for `e_flags & EF_PARISC_ARCH' are: */ + +#define EFA_PARISC_1_0 0x020b /* PA-RISC 1.0 big-endian. */ +#define EFA_PARISC_1_1 0x0210 /* PA-RISC 1.1 big-endian. */ +#define EFA_PARISC_2_0 0x0214 /* PA-RISC 2.0 big-endian. */ + +/* Additional section indeces. */ + +#define SHN_PARISC_ANSI_COMMON 0xff00 /* Section for tenatively declared + symbols in ANSI C. */ +#define SHN_PARISC_HUGE_COMMON 0xff01 /* Common blocks in huge model. */ + +/* Legal values for sh_type field of Elf32_Shdr. */ + +#define SHT_PARISC_EXT 0x70000000 /* Contains product specific ext. */ +#define SHT_PARISC_UNWIND 0x70000001 /* Unwind information. */ +#define SHT_PARISC_DOC 0x70000002 /* Debug info for optimized code. */ + +/* Legal values for sh_flags field of Elf32_Shdr. */ + +#define SHF_PARISC_SHORT 0x20000000 /* Section with short addressing. */ +#define SHF_PARISC_HUGE 0x40000000 /* Section far from gp. */ +#define SHF_PARISC_SBP 0x80000000 /* Static branch prediction code. */ + +/* Legal values for ST_TYPE subfield of st_info (symbol type). */ + +#define STT_PARISC_MILLICODE 13 /* Millicode function entry point. */ + +#define STT_HP_OPAQUE (STT_LOOS + 0x1) +#define STT_HP_STUB (STT_LOOS + 0x2) + +/* HPPA relocs. */ + +#define R_PARISC_NONE 0 /* No reloc. */ +#define R_PARISC_DIR32 1 /* Direct 32-bit reference. */ +#define R_PARISC_DIR21L 2 /* Left 21 bits of eff. address. */ +#define R_PARISC_DIR17R 3 /* Right 17 bits of eff. address. */ +#define R_PARISC_DIR17F 4 /* 17 bits of eff. address. */ +#define R_PARISC_DIR14R 6 /* Right 14 bits of eff. address. */ +#define R_PARISC_PCREL32 9 /* 32-bit rel. address. */ +#define R_PARISC_PCREL21L 10 /* Left 21 bits of rel. address. */ +#define R_PARISC_PCREL17R 11 /* Right 17 bits of rel. address. */ +#define R_PARISC_PCREL17F 12 /* 17 bits of rel. address. */ +#define R_PARISC_PCREL14R 14 /* Right 14 bits of rel. address. */ +#define R_PARISC_DPREL21L 18 /* Left 21 bits of rel. address. */ +#define R_PARISC_DPREL14R 22 /* Right 14 bits of rel. address. */ +#define R_PARISC_GPREL21L 26 /* GP-relative, left 21 bits. */ +#define R_PARISC_GPREL14R 30 /* GP-relative, right 14 bits. */ +#define R_PARISC_LTOFF21L 34 /* LT-relative, left 21 bits. */ +#define R_PARISC_LTOFF14R 38 /* LT-relative, right 14 bits. */ +#define R_PARISC_SECREL32 41 /* 32 bits section rel. address. */ +#define R_PARISC_SEGBASE 48 /* No relocation, set segment base. */ +#define R_PARISC_SEGREL32 49 /* 32 bits segment rel. address. */ +#define R_PARISC_PLTOFF21L 50 /* PLT rel. address, left 21 bits. */ +#define R_PARISC_PLTOFF14R 54 /* PLT rel. address, right 14 bits. */ +#define R_PARISC_LTOFF_FPTR32 57 /* 32 bits LT-rel. function pointer. */ +#define R_PARISC_LTOFF_FPTR21L 58 /* LT-rel. fct ptr, left 21 bits. */ +#define R_PARISC_LTOFF_FPTR14R 62 /* LT-rel. fct ptr, right 14 bits. */ +#define R_PARISC_FPTR64 64 /* 64 bits function address. */ +#define R_PARISC_PLABEL32 65 /* 32 bits function address. */ +#define R_PARISC_PLABEL21L 66 /* Left 21 bits of fdesc address. */ +#define R_PARISC_PLABEL14R 70 /* Right 14 bits of fdesc address. */ +#define R_PARISC_PCREL64 72 /* 64 bits PC-rel. address. */ +#define R_PARISC_PCREL22F 74 /* 22 bits PC-rel. address. */ +#define R_PARISC_PCREL14WR 75 /* PC-rel. address, right 14 bits. */ +#define R_PARISC_PCREL14DR 76 /* PC rel. address, right 14 bits. */ +#define R_PARISC_PCREL16F 77 /* 16 bits PC-rel. address. */ +#define R_PARISC_PCREL16WF 78 /* 16 bits PC-rel. address. */ +#define R_PARISC_PCREL16DF 79 /* 16 bits PC-rel. address. */ +#define R_PARISC_DIR64 80 /* 64 bits of eff. address. */ +#define R_PARISC_DIR14WR 83 /* 14 bits of eff. address. */ +#define R_PARISC_DIR14DR 84 /* 14 bits of eff. address. */ +#define R_PARISC_DIR16F 85 /* 16 bits of eff. address. */ +#define R_PARISC_DIR16WF 86 /* 16 bits of eff. address. */ +#define R_PARISC_DIR16DF 87 /* 16 bits of eff. address. */ +#define R_PARISC_GPREL64 88 /* 64 bits of GP-rel. address. */ +#define R_PARISC_GPREL14WR 91 /* GP-rel. address, right 14 bits. */ +#define R_PARISC_GPREL14DR 92 /* GP-rel. address, right 14 bits. */ +#define R_PARISC_GPREL16F 93 /* 16 bits GP-rel. address. */ +#define R_PARISC_GPREL16WF 94 /* 16 bits GP-rel. address. */ +#define R_PARISC_GPREL16DF 95 /* 16 bits GP-rel. address. */ +#define R_PARISC_LTOFF64 96 /* 64 bits LT-rel. address. */ +#define R_PARISC_LTOFF14WR 99 /* LT-rel. address, right 14 bits. */ +#define R_PARISC_LTOFF14DR 100 /* LT-rel. address, right 14 bits. */ +#define R_PARISC_LTOFF16F 101 /* 16 bits LT-rel. address. */ +#define R_PARISC_LTOFF16WF 102 /* 16 bits LT-rel. address. */ +#define R_PARISC_LTOFF16DF 103 /* 16 bits LT-rel. address. */ +#define R_PARISC_SECREL64 104 /* 64 bits section rel. address. */ +#define R_PARISC_SEGREL64 112 /* 64 bits segment rel. address. */ +#define R_PARISC_PLTOFF14WR 115 /* PLT-rel. address, right 14 bits. */ +#define R_PARISC_PLTOFF14DR 116 /* PLT-rel. address, right 14 bits. */ +#define R_PARISC_PLTOFF16F 117 /* 16 bits LT-rel. address. */ +#define R_PARISC_PLTOFF16WF 118 /* 16 bits PLT-rel. address. */ +#define R_PARISC_PLTOFF16DF 119 /* 16 bits PLT-rel. address. */ +#define R_PARISC_LTOFF_FPTR64 120 /* 64 bits LT-rel. function ptr. */ +#define R_PARISC_LTOFF_FPTR14WR 123 /* LT-rel. fct. ptr., right 14 bits. */ +#define R_PARISC_LTOFF_FPTR14DR 124 /* LT-rel. fct. ptr., right 14 bits. */ +#define R_PARISC_LTOFF_FPTR16F 125 /* 16 bits LT-rel. function ptr. */ +#define R_PARISC_LTOFF_FPTR16WF 126 /* 16 bits LT-rel. function ptr. */ +#define R_PARISC_LTOFF_FPTR16DF 127 /* 16 bits LT-rel. function ptr. */ +#define R_PARISC_LORESERVE 128 +#define R_PARISC_COPY 128 /* Copy relocation. */ +#define R_PARISC_IPLT 129 /* Dynamic reloc, imported PLT */ +#define R_PARISC_EPLT 130 /* Dynamic reloc, exported PLT */ +#define R_PARISC_TPREL32 153 /* 32 bits TP-rel. address. */ +#define R_PARISC_TPREL21L 154 /* TP-rel. address, left 21 bits. */ +#define R_PARISC_TPREL14R 158 /* TP-rel. address, right 14 bits. */ +#define R_PARISC_LTOFF_TP21L 162 /* LT-TP-rel. address, left 21 bits. */ +#define R_PARISC_LTOFF_TP14R 166 /* LT-TP-rel. address, right 14 bits.*/ +#define R_PARISC_LTOFF_TP14F 167 /* 14 bits LT-TP-rel. address. */ +#define R_PARISC_TPREL64 216 /* 64 bits TP-rel. address. */ +#define R_PARISC_TPREL14WR 219 /* TP-rel. address, right 14 bits. */ +#define R_PARISC_TPREL14DR 220 /* TP-rel. address, right 14 bits. */ +#define R_PARISC_TPREL16F 221 /* 16 bits TP-rel. address. */ +#define R_PARISC_TPREL16WF 222 /* 16 bits TP-rel. address. */ +#define R_PARISC_TPREL16DF 223 /* 16 bits TP-rel. address. */ +#define R_PARISC_LTOFF_TP64 224 /* 64 bits LT-TP-rel. address. */ +#define R_PARISC_LTOFF_TP14WR 227 /* LT-TP-rel. address, right 14 bits.*/ +#define R_PARISC_LTOFF_TP14DR 228 /* LT-TP-rel. address, right 14 bits.*/ +#define R_PARISC_LTOFF_TP16F 229 /* 16 bits LT-TP-rel. address. */ +#define R_PARISC_LTOFF_TP16WF 230 /* 16 bits LT-TP-rel. address. */ +#define R_PARISC_LTOFF_TP16DF 231 /* 16 bits LT-TP-rel. address. */ +#define R_PARISC_GNU_VTENTRY 232 +#define R_PARISC_GNU_VTINHERIT 233 +#define R_PARISC_TLS_GD21L 234 /* GD 21-bit left. */ +#define R_PARISC_TLS_GD14R 235 /* GD 14-bit right. */ +#define R_PARISC_TLS_GDCALL 236 /* GD call to __t_g_a. */ +#define R_PARISC_TLS_LDM21L 237 /* LD module 21-bit left. */ +#define R_PARISC_TLS_LDM14R 238 /* LD module 14-bit right. */ +#define R_PARISC_TLS_LDMCALL 239 /* LD module call to __t_g_a. */ +#define R_PARISC_TLS_LDO21L 240 /* LD offset 21-bit left. */ +#define R_PARISC_TLS_LDO14R 241 /* LD offset 14-bit right. */ +#define R_PARISC_TLS_DTPMOD32 242 /* DTP module 32-bit. */ +#define R_PARISC_TLS_DTPMOD64 243 /* DTP module 64-bit. */ +#define R_PARISC_TLS_DTPOFF32 244 /* DTP offset 32-bit. */ +#define R_PARISC_TLS_DTPOFF64 245 /* DTP offset 32-bit. */ +#define R_PARISC_TLS_LE21L R_PARISC_TPREL21L +#define R_PARISC_TLS_LE14R R_PARISC_TPREL14R +#define R_PARISC_TLS_IE21L R_PARISC_LTOFF_TP21L +#define R_PARISC_TLS_IE14R R_PARISC_LTOFF_TP14R +#define R_PARISC_TLS_TPREL32 R_PARISC_TPREL32 +#define R_PARISC_TLS_TPREL64 R_PARISC_TPREL64 +#define R_PARISC_HIRESERVE 255 + +/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr. */ + +#define PT_HP_TLS (PT_LOOS + 0x0) +#define PT_HP_CORE_NONE (PT_LOOS + 0x1) +#define PT_HP_CORE_VERSION (PT_LOOS + 0x2) +#define PT_HP_CORE_KERNEL (PT_LOOS + 0x3) +#define PT_HP_CORE_COMM (PT_LOOS + 0x4) +#define PT_HP_CORE_PROC (PT_LOOS + 0x5) +#define PT_HP_CORE_LOADABLE (PT_LOOS + 0x6) +#define PT_HP_CORE_STACK (PT_LOOS + 0x7) +#define PT_HP_CORE_SHM (PT_LOOS + 0x8) +#define PT_HP_CORE_MMF (PT_LOOS + 0x9) +#define PT_HP_PARALLEL (PT_LOOS + 0x10) +#define PT_HP_FASTBIND (PT_LOOS + 0x11) +#define PT_HP_OPT_ANNOT (PT_LOOS + 0x12) +#define PT_HP_HSL_ANNOT (PT_LOOS + 0x13) +#define PT_HP_STACK (PT_LOOS + 0x14) + +#define PT_PARISC_ARCHEXT 0x70000000 +#define PT_PARISC_UNWIND 0x70000001 + +/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr. */ + +#define PF_PARISC_SBP 0x08000000 + +#define PF_HP_PAGE_SIZE 0x00100000 +#define PF_HP_FAR_SHARED 0x00200000 +#define PF_HP_NEAR_SHARED 0x00400000 +#define PF_HP_CODE 0x01000000 +#define PF_HP_MODIFY 0x02000000 +#define PF_HP_LAZYSWAP 0x04000000 +#define PF_HP_SBP 0x08000000 + + +/* Alpha specific definitions. */ + +/* Legal values for e_flags field of Elf64_Ehdr. */ + +#define EF_ALPHA_32BIT 1 /* All addresses must be < 2GB. */ +#define EF_ALPHA_CANRELAX 2 /* Relocations for relaxing exist. */ + +/* Legal values for sh_type field of Elf64_Shdr. */ + +/* These two are primerily concerned with ECOFF debugging info. */ +#define SHT_ALPHA_DEBUG 0x70000001 +#define SHT_ALPHA_REGINFO 0x70000002 + +/* Legal values for sh_flags field of Elf64_Shdr. */ + +#define SHF_ALPHA_GPREL 0x10000000 + +/* Legal values for st_other field of Elf64_Sym. */ +#define STO_ALPHA_NOPV 0x80 /* No PV required. */ +#define STO_ALPHA_STD_GPLOAD 0x88 /* PV only used for initial ldgp. */ + +/* Alpha relocs. */ + +#define R_ALPHA_NONE 0 /* No reloc */ +#define R_ALPHA_REFLONG 1 /* Direct 32 bit */ +#define R_ALPHA_REFQUAD 2 /* Direct 64 bit */ +#define R_ALPHA_GPREL32 3 /* GP relative 32 bit */ +#define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */ +#define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */ +#define R_ALPHA_GPDISP 6 /* Add displacement to GP */ +#define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */ +#define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */ +#define R_ALPHA_SREL16 9 /* PC relative 16 bit */ +#define R_ALPHA_SREL32 10 /* PC relative 32 bit */ +#define R_ALPHA_SREL64 11 /* PC relative 64 bit */ +#define R_ALPHA_GPRELHIGH 17 /* GP relative 32 bit, high 16 bits */ +#define R_ALPHA_GPRELLOW 18 /* GP relative 32 bit, low 16 bits */ +#define R_ALPHA_GPREL16 19 /* GP relative 16 bit */ +#define R_ALPHA_COPY 24 /* Copy symbol at runtime */ +#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */ +#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */ +#define R_ALPHA_RELATIVE 27 /* Adjust by program base */ +#define R_ALPHA_TLS_GD_HI 28 +#define R_ALPHA_TLSGD 29 +#define R_ALPHA_TLS_LDM 30 +#define R_ALPHA_DTPMOD64 31 +#define R_ALPHA_GOTDTPREL 32 +#define R_ALPHA_DTPREL64 33 +#define R_ALPHA_DTPRELHI 34 +#define R_ALPHA_DTPRELLO 35 +#define R_ALPHA_DTPREL16 36 +#define R_ALPHA_GOTTPREL 37 +#define R_ALPHA_TPREL64 38 +#define R_ALPHA_TPRELHI 39 +#define R_ALPHA_TPRELLO 40 +#define R_ALPHA_TPREL16 41 +/* Keep this the last entry. */ +#define R_ALPHA_NUM 46 + +/* Magic values of the LITUSE relocation addend. */ +#define LITUSE_ALPHA_ADDR 0 +#define LITUSE_ALPHA_BASE 1 +#define LITUSE_ALPHA_BYTOFF 2 +#define LITUSE_ALPHA_JSR 3 +#define LITUSE_ALPHA_TLS_GD 4 +#define LITUSE_ALPHA_TLS_LDM 5 + +/* Legal values for d_tag of Elf64_Dyn. */ +#define DT_ALPHA_PLTRO (DT_LOPROC + 0) +#define DT_ALPHA_NUM 1 + +/* PowerPC specific declarations */ + +/* Values for Elf32/64_Ehdr.e_flags. */ +#define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag */ + +/* Cygnus local bits below */ +#define EF_PPC_RELOCATABLE 0x00010000 /* PowerPC -mrelocatable flag*/ +#define EF_PPC_RELOCATABLE_LIB 0x00008000 /* PowerPC -mrelocatable-lib + flag */ + +/* PowerPC relocations defined by the ABIs */ +#define R_PPC_NONE 0 +#define R_PPC_ADDR32 1 /* 32bit absolute address */ +#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */ +#define R_PPC_ADDR16 3 /* 16bit absolute address */ +#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */ +#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */ +#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */ +#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */ +#define R_PPC_ADDR14_BRTAKEN 8 +#define R_PPC_ADDR14_BRNTAKEN 9 +#define R_PPC_REL24 10 /* PC relative 26 bit */ +#define R_PPC_REL14 11 /* PC relative 16 bit */ +#define R_PPC_REL14_BRTAKEN 12 +#define R_PPC_REL14_BRNTAKEN 13 +#define R_PPC_GOT16 14 +#define R_PPC_GOT16_LO 15 +#define R_PPC_GOT16_HI 16 +#define R_PPC_GOT16_HA 17 +#define R_PPC_PLTREL24 18 +#define R_PPC_COPY 19 +#define R_PPC_GLOB_DAT 20 +#define R_PPC_JMP_SLOT 21 +#define R_PPC_RELATIVE 22 +#define R_PPC_LOCAL24PC 23 +#define R_PPC_UADDR32 24 +#define R_PPC_UADDR16 25 +#define R_PPC_REL32 26 +#define R_PPC_PLT32 27 +#define R_PPC_PLTREL32 28 +#define R_PPC_PLT16_LO 29 +#define R_PPC_PLT16_HI 30 +#define R_PPC_PLT16_HA 31 +#define R_PPC_SDAREL16 32 +#define R_PPC_SECTOFF 33 +#define R_PPC_SECTOFF_LO 34 +#define R_PPC_SECTOFF_HI 35 +#define R_PPC_SECTOFF_HA 36 + +/* PowerPC relocations defined for the TLS access ABI. */ +#define R_PPC_TLS 67 /* none (sym+add)@tls */ +#define R_PPC_DTPMOD32 68 /* word32 (sym+add)@dtpmod */ +#define R_PPC_TPREL16 69 /* half16* (sym+add)@tprel */ +#define R_PPC_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ +#define R_PPC_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ +#define R_PPC_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ +#define R_PPC_TPREL32 73 /* word32 (sym+add)@tprel */ +#define R_PPC_DTPREL16 74 /* half16* (sym+add)@dtprel */ +#define R_PPC_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ +#define R_PPC_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ +#define R_PPC_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ +#define R_PPC_DTPREL32 78 /* word32 (sym+add)@dtprel */ +#define R_PPC_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ +#define R_PPC_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ +#define R_PPC_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ +#define R_PPC_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ +#define R_PPC_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ +#define R_PPC_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ +#define R_PPC_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ +#define R_PPC_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ +#define R_PPC_GOT_TPREL16 87 /* half16* (sym+add)@got@tprel */ +#define R_PPC_GOT_TPREL16_LO 88 /* half16 (sym+add)@got@tprel@l */ +#define R_PPC_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ +#define R_PPC_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ +#define R_PPC_GOT_DTPREL16 91 /* half16* (sym+add)@got@dtprel */ +#define R_PPC_GOT_DTPREL16_LO 92 /* half16* (sym+add)@got@dtprel@l */ +#define R_PPC_GOT_DTPREL16_HI 93 /* half16* (sym+add)@got@dtprel@h */ +#define R_PPC_GOT_DTPREL16_HA 94 /* half16* (sym+add)@got@dtprel@ha */ + +/* The remaining relocs are from the Embedded ELF ABI, and are not + in the SVR4 ELF ABI. */ +#define R_PPC_EMB_NADDR32 101 +#define R_PPC_EMB_NADDR16 102 +#define R_PPC_EMB_NADDR16_LO 103 +#define R_PPC_EMB_NADDR16_HI 104 +#define R_PPC_EMB_NADDR16_HA 105 +#define R_PPC_EMB_SDAI16 106 +#define R_PPC_EMB_SDA2I16 107 +#define R_PPC_EMB_SDA2REL 108 +#define R_PPC_EMB_SDA21 109 /* 16 bit offset in SDA */ +#define R_PPC_EMB_MRKREF 110 +#define R_PPC_EMB_RELSEC16 111 +#define R_PPC_EMB_RELST_LO 112 +#define R_PPC_EMB_RELST_HI 113 +#define R_PPC_EMB_RELST_HA 114 +#define R_PPC_EMB_BIT_FLD 115 +#define R_PPC_EMB_RELSDA 116 /* 16 bit relative offset in SDA */ + +/* Diab tool relocations. */ +#define R_PPC_DIAB_SDA21_LO 180 /* like EMB_SDA21, but lower 16 bit */ +#define R_PPC_DIAB_SDA21_HI 181 /* like EMB_SDA21, but high 16 bit */ +#define R_PPC_DIAB_SDA21_HA 182 /* like EMB_SDA21, adjusted high 16 */ +#define R_PPC_DIAB_RELSDA_LO 183 /* like EMB_RELSDA, but lower 16 bit */ +#define R_PPC_DIAB_RELSDA_HI 184 /* like EMB_RELSDA, but high 16 bit */ +#define R_PPC_DIAB_RELSDA_HA 185 /* like EMB_RELSDA, adjusted high 16 */ + +/* GNU extension to support local ifunc. */ +#define R_PPC_IRELATIVE 248 + +/* GNU relocs used in PIC code sequences. */ +#define R_PPC_REL16 249 /* half16 (sym+add-.) */ +#define R_PPC_REL16_LO 250 /* half16 (sym+add-.)@l */ +#define R_PPC_REL16_HI 251 /* half16 (sym+add-.)@h */ +#define R_PPC_REL16_HA 252 /* half16 (sym+add-.)@ha */ + +/* This is a phony reloc to handle any old fashioned TOC16 references + that may still be in object files. */ +#define R_PPC_TOC16 255 + +/* PowerPC specific values for the Dyn d_tag field. */ +#define DT_PPC_GOT (DT_LOPROC + 0) +#define DT_PPC_NUM 1 + +/* PowerPC64 relocations defined by the ABIs */ +#define R_PPC64_NONE R_PPC_NONE +#define R_PPC64_ADDR32 R_PPC_ADDR32 /* 32bit absolute address */ +#define R_PPC64_ADDR24 R_PPC_ADDR24 /* 26bit address, word aligned */ +#define R_PPC64_ADDR16 R_PPC_ADDR16 /* 16bit absolute address */ +#define R_PPC64_ADDR16_LO R_PPC_ADDR16_LO /* lower 16bits of address */ +#define R_PPC64_ADDR16_HI R_PPC_ADDR16_HI /* high 16bits of address. */ +#define R_PPC64_ADDR16_HA R_PPC_ADDR16_HA /* adjusted high 16bits. */ +#define R_PPC64_ADDR14 R_PPC_ADDR14 /* 16bit address, word aligned */ +#define R_PPC64_ADDR14_BRTAKEN R_PPC_ADDR14_BRTAKEN +#define R_PPC64_ADDR14_BRNTAKEN R_PPC_ADDR14_BRNTAKEN +#define R_PPC64_REL24 R_PPC_REL24 /* PC-rel. 26 bit, word aligned */ +#define R_PPC64_REL14 R_PPC_REL14 /* PC relative 16 bit */ +#define R_PPC64_REL14_BRTAKEN R_PPC_REL14_BRTAKEN +#define R_PPC64_REL14_BRNTAKEN R_PPC_REL14_BRNTAKEN +#define R_PPC64_GOT16 R_PPC_GOT16 +#define R_PPC64_GOT16_LO R_PPC_GOT16_LO +#define R_PPC64_GOT16_HI R_PPC_GOT16_HI +#define R_PPC64_GOT16_HA R_PPC_GOT16_HA + +#define R_PPC64_COPY R_PPC_COPY +#define R_PPC64_GLOB_DAT R_PPC_GLOB_DAT +#define R_PPC64_JMP_SLOT R_PPC_JMP_SLOT +#define R_PPC64_RELATIVE R_PPC_RELATIVE + +#define R_PPC64_UADDR32 R_PPC_UADDR32 +#define R_PPC64_UADDR16 R_PPC_UADDR16 +#define R_PPC64_REL32 R_PPC_REL32 +#define R_PPC64_PLT32 R_PPC_PLT32 +#define R_PPC64_PLTREL32 R_PPC_PLTREL32 +#define R_PPC64_PLT16_LO R_PPC_PLT16_LO +#define R_PPC64_PLT16_HI R_PPC_PLT16_HI +#define R_PPC64_PLT16_HA R_PPC_PLT16_HA + +#define R_PPC64_SECTOFF R_PPC_SECTOFF +#define R_PPC64_SECTOFF_LO R_PPC_SECTOFF_LO +#define R_PPC64_SECTOFF_HI R_PPC_SECTOFF_HI +#define R_PPC64_SECTOFF_HA R_PPC_SECTOFF_HA +#define R_PPC64_ADDR30 37 /* word30 (S + A - P) >> 2 */ +#define R_PPC64_ADDR64 38 /* doubleword64 S + A */ +#define R_PPC64_ADDR16_HIGHER 39 /* half16 #higher(S + A) */ +#define R_PPC64_ADDR16_HIGHERA 40 /* half16 #highera(S + A) */ +#define R_PPC64_ADDR16_HIGHEST 41 /* half16 #highest(S + A) */ +#define R_PPC64_ADDR16_HIGHESTA 42 /* half16 #highesta(S + A) */ +#define R_PPC64_UADDR64 43 /* doubleword64 S + A */ +#define R_PPC64_REL64 44 /* doubleword64 S + A - P */ +#define R_PPC64_PLT64 45 /* doubleword64 L + A */ +#define R_PPC64_PLTREL64 46 /* doubleword64 L + A - P */ +#define R_PPC64_TOC16 47 /* half16* S + A - .TOC */ +#define R_PPC64_TOC16_LO 48 /* half16 #lo(S + A - .TOC.) */ +#define R_PPC64_TOC16_HI 49 /* half16 #hi(S + A - .TOC.) */ +#define R_PPC64_TOC16_HA 50 /* half16 #ha(S + A - .TOC.) */ +#define R_PPC64_TOC 51 /* doubleword64 .TOC */ +#define R_PPC64_PLTGOT16 52 /* half16* M + A */ +#define R_PPC64_PLTGOT16_LO 53 /* half16 #lo(M + A) */ +#define R_PPC64_PLTGOT16_HI 54 /* half16 #hi(M + A) */ +#define R_PPC64_PLTGOT16_HA 55 /* half16 #ha(M + A) */ + +#define R_PPC64_ADDR16_DS 56 /* half16ds* (S + A) >> 2 */ +#define R_PPC64_ADDR16_LO_DS 57 /* half16ds #lo(S + A) >> 2 */ +#define R_PPC64_GOT16_DS 58 /* half16ds* (G + A) >> 2 */ +#define R_PPC64_GOT16_LO_DS 59 /* half16ds #lo(G + A) >> 2 */ +#define R_PPC64_PLT16_LO_DS 60 /* half16ds #lo(L + A) >> 2 */ +#define R_PPC64_SECTOFF_DS 61 /* half16ds* (R + A) >> 2 */ +#define R_PPC64_SECTOFF_LO_DS 62 /* half16ds #lo(R + A) >> 2 */ +#define R_PPC64_TOC16_DS 63 /* half16ds* (S + A - .TOC.) >> 2 */ +#define R_PPC64_TOC16_LO_DS 64 /* half16ds #lo(S + A - .TOC.) >> 2 */ +#define R_PPC64_PLTGOT16_DS 65 /* half16ds* (M + A) >> 2 */ +#define R_PPC64_PLTGOT16_LO_DS 66 /* half16ds #lo(M + A) >> 2 */ + +/* PowerPC64 relocations defined for the TLS access ABI. */ +#define R_PPC64_TLS 67 /* none (sym+add)@tls */ +#define R_PPC64_DTPMOD64 68 /* doubleword64 (sym+add)@dtpmod */ +#define R_PPC64_TPREL16 69 /* half16* (sym+add)@tprel */ +#define R_PPC64_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ +#define R_PPC64_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ +#define R_PPC64_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ +#define R_PPC64_TPREL64 73 /* doubleword64 (sym+add)@tprel */ +#define R_PPC64_DTPREL16 74 /* half16* (sym+add)@dtprel */ +#define R_PPC64_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ +#define R_PPC64_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ +#define R_PPC64_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ +#define R_PPC64_DTPREL64 78 /* doubleword64 (sym+add)@dtprel */ +#define R_PPC64_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ +#define R_PPC64_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ +#define R_PPC64_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ +#define R_PPC64_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ +#define R_PPC64_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ +#define R_PPC64_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ +#define R_PPC64_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ +#define R_PPC64_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ +#define R_PPC64_GOT_TPREL16_DS 87 /* half16ds* (sym+add)@got@tprel */ +#define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@got@tprel@l */ +#define R_PPC64_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ +#define R_PPC64_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ +#define R_PPC64_GOT_DTPREL16_DS 91 /* half16ds* (sym+add)@got@dtprel */ +#define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@got@dtprel@l */ +#define R_PPC64_GOT_DTPREL16_HI 93 /* half16 (sym+add)@got@dtprel@h */ +#define R_PPC64_GOT_DTPREL16_HA 94 /* half16 (sym+add)@got@dtprel@ha */ +#define R_PPC64_TPREL16_DS 95 /* half16ds* (sym+add)@tprel */ +#define R_PPC64_TPREL16_LO_DS 96 /* half16ds (sym+add)@tprel@l */ +#define R_PPC64_TPREL16_HIGHER 97 /* half16 (sym+add)@tprel@higher */ +#define R_PPC64_TPREL16_HIGHERA 98 /* half16 (sym+add)@tprel@highera */ +#define R_PPC64_TPREL16_HIGHEST 99 /* half16 (sym+add)@tprel@highest */ +#define R_PPC64_TPREL16_HIGHESTA 100 /* half16 (sym+add)@tprel@highesta */ +#define R_PPC64_DTPREL16_DS 101 /* half16ds* (sym+add)@dtprel */ +#define R_PPC64_DTPREL16_LO_DS 102 /* half16ds (sym+add)@dtprel@l */ +#define R_PPC64_DTPREL16_HIGHER 103 /* half16 (sym+add)@dtprel@higher */ +#define R_PPC64_DTPREL16_HIGHERA 104 /* half16 (sym+add)@dtprel@highera */ +#define R_PPC64_DTPREL16_HIGHEST 105 /* half16 (sym+add)@dtprel@highest */ +#define R_PPC64_DTPREL16_HIGHESTA 106 /* half16 (sym+add)@dtprel@highesta */ +#define R_PPC64_TLSGD 107 /* none (sym+add)@tlsgd */ +#define R_PPC64_TLSLD 108 /* none (sym+add)@tlsld */ +#define R_PPC64_TOCSAVE 109 /* none */ + +/* Added when HA and HI relocs were changed to report overflows. */ +#define R_PPC64_ADDR16_HIGH 110 +#define R_PPC64_ADDR16_HIGHA 111 +#define R_PPC64_TPREL16_HIGH 112 +#define R_PPC64_TPREL16_HIGHA 113 +#define R_PPC64_DTPREL16_HIGH 114 +#define R_PPC64_DTPREL16_HIGHA 115 + +/* GNU extension to support local ifunc. */ +#define R_PPC64_JMP_IREL 247 +#define R_PPC64_IRELATIVE 248 +#define R_PPC64_REL16 249 /* half16 (sym+add-.) */ +#define R_PPC64_REL16_LO 250 /* half16 (sym+add-.)@l */ +#define R_PPC64_REL16_HI 251 /* half16 (sym+add-.)@h */ +#define R_PPC64_REL16_HA 252 /* half16 (sym+add-.)@ha */ + +/* e_flags bits specifying ABI. + 1 for original function descriptor using ABI, + 2 for revised ABI without function descriptors, + 0 for unspecified or not using any features affected by the differences. */ +#define EF_PPC64_ABI 3 + +/* PowerPC64 specific values for the Dyn d_tag field. */ +#define DT_PPC64_GLINK (DT_LOPROC + 0) +#define DT_PPC64_OPD (DT_LOPROC + 1) +#define DT_PPC64_OPDSZ (DT_LOPROC + 2) +#define DT_PPC64_OPT (DT_LOPROC + 3) +#define DT_PPC64_NUM 3 + +/* PowerPC64 specific values for the DT_PPC64_OPT Dyn entry. */ +#define PPC64_OPT_TLS 1 +#define PPC64_OPT_MULTI_TOC 2 + +/* PowerPC64 specific values for the Elf64_Sym st_other field. */ +#define STO_PPC64_LOCAL_BIT 5 +#define STO_PPC64_LOCAL_MASK (7 << STO_PPC64_LOCAL_BIT) +#define PPC64_LOCAL_ENTRY_OFFSET(other) \ + (((1 << (((other) & STO_PPC64_LOCAL_MASK) >> STO_PPC64_LOCAL_BIT)) >> 2) << 2) + + +/* ARM specific declarations */ + +/* Processor specific flags for the ELF header e_flags field. */ +#define EF_ARM_RELEXEC 0x01 +#define EF_ARM_HASENTRY 0x02 +#define EF_ARM_INTERWORK 0x04 +#define EF_ARM_APCS_26 0x08 +#define EF_ARM_APCS_FLOAT 0x10 +#define EF_ARM_PIC 0x20 +#define EF_ARM_ALIGN8 0x40 /* 8-bit structure alignment is in use */ +#define EF_ARM_NEW_ABI 0x80 +#define EF_ARM_OLD_ABI 0x100 +#define EF_ARM_SOFT_FLOAT 0x200 +#define EF_ARM_VFP_FLOAT 0x400 +#define EF_ARM_MAVERICK_FLOAT 0x800 + +#define EF_ARM_ABI_FLOAT_SOFT 0x200 /* NB conflicts with EF_ARM_SOFT_FLOAT */ +#define EF_ARM_ABI_FLOAT_HARD 0x400 /* NB conflicts with EF_ARM_VFP_FLOAT */ + + +/* Other constants defined in the ARM ELF spec. version B-01. */ +/* NB. These conflict with values defined above. */ +#define EF_ARM_SYMSARESORTED 0x04 +#define EF_ARM_DYNSYMSUSESEGIDX 0x08 +#define EF_ARM_MAPSYMSFIRST 0x10 +#define EF_ARM_EABIMASK 0XFF000000 + +/* Constants defined in AAELF. */ +#define EF_ARM_BE8 0x00800000 +#define EF_ARM_LE8 0x00400000 + +#define EF_ARM_EABI_VERSION(flags) ((flags) & EF_ARM_EABIMASK) +#define EF_ARM_EABI_UNKNOWN 0x00000000 +#define EF_ARM_EABI_VER1 0x01000000 +#define EF_ARM_EABI_VER2 0x02000000 +#define EF_ARM_EABI_VER3 0x03000000 +#define EF_ARM_EABI_VER4 0x04000000 +#define EF_ARM_EABI_VER5 0x05000000 + +/* Additional symbol types for Thumb. */ +#define STT_ARM_TFUNC STT_LOPROC /* A Thumb function. */ +#define STT_ARM_16BIT STT_HIPROC /* A Thumb label. */ + +/* ARM-specific values for sh_flags */ +#define SHF_ARM_ENTRYSECT 0x10000000 /* Section contains an entry point */ +#define SHF_ARM_COMDEF 0x80000000 /* Section may be multiply defined + in the input to a link step. */ + +/* ARM-specific program header flags */ +#define PF_ARM_SB 0x10000000 /* Segment contains the location + addressed by the static base. */ +#define PF_ARM_PI 0x20000000 /* Position-independent segment. */ +#define PF_ARM_ABS 0x40000000 /* Absolute segment. */ + +/* Processor specific values for the Phdr p_type field. */ +#define PT_ARM_EXIDX (PT_LOPROC + 1) /* ARM unwind segment. */ + +/* Processor specific values for the Shdr sh_type field. */ +#define SHT_ARM_EXIDX (SHT_LOPROC + 1) /* ARM unwind section. */ +#define SHT_ARM_PREEMPTMAP (SHT_LOPROC + 2) /* Preemption details. */ +#define SHT_ARM_ATTRIBUTES (SHT_LOPROC + 3) /* ARM attributes section. */ + + +/* AArch64 relocs. */ + +#define R_AARCH64_NONE 0 /* No relocation. */ +#define R_AARCH64_ABS64 257 /* Direct 64 bit. */ +#define R_AARCH64_ABS32 258 /* Direct 32 bit. */ +#define R_AARCH64_ABS16 259 /* Direct 16-bit. */ +#define R_AARCH64_PREL64 260 /* PC-relative 64-bit. */ +#define R_AARCH64_PREL32 261 /* PC-relative 32-bit. */ +#define R_AARCH64_PREL16 262 /* PC-relative 16-bit. */ +#define R_AARCH64_MOVW_UABS_G0 263 /* Dir. MOVZ imm. from bits 15:0. */ +#define R_AARCH64_MOVW_UABS_G0_NC 264 /* Likewise for MOVK; no check. */ +#define R_AARCH64_MOVW_UABS_G1 265 /* Dir. MOVZ imm. from bits 31:16. */ +#define R_AARCH64_MOVW_UABS_G1_NC 266 /* Likewise for MOVK; no check. */ +#define R_AARCH64_MOVW_UABS_G2 267 /* Dir. MOVZ imm. from bits 47:32. */ +#define R_AARCH64_MOVW_UABS_G2_NC 268 /* Likewise for MOVK; no check. */ +#define R_AARCH64_MOVW_UABS_G3 269 /* Dir. MOV{K,Z} imm. from 63:48. */ +#define R_AARCH64_MOVW_SABS_G0 270 /* Dir. MOV{N,Z} imm. from 15:0. */ +#define R_AARCH64_MOVW_SABS_G1 271 /* Dir. MOV{N,Z} imm. from 31:16. */ +#define R_AARCH64_MOVW_SABS_G2 272 /* Dir. MOV{N,Z} imm. from 47:32. */ +#define R_AARCH64_LD_PREL_LO19 273 /* PC-rel. LD imm. from bits 20:2. */ +#define R_AARCH64_ADR_PREL_LO21 274 /* PC-rel. ADR imm. from bits 20:0. */ +#define R_AARCH64_ADR_PREL_PG_HI21 275 /* Page-rel. ADRP imm. from 32:12. */ +#define R_AARCH64_ADR_PREL_PG_HI21_NC 276 /* Likewise; no overflow check. */ +#define R_AARCH64_ADD_ABS_LO12_NC 277 /* Dir. ADD imm. from bits 11:0. */ +#define R_AARCH64_LDST8_ABS_LO12_NC 278 /* Likewise for LD/ST; no check. */ +#define R_AARCH64_TSTBR14 279 /* PC-rel. TBZ/TBNZ imm. from 15:2. */ +#define R_AARCH64_CONDBR19 280 /* PC-rel. cond. br. imm. from 20:2. */ +#define R_AARCH64_JUMP26 282 /* PC-rel. B imm. from bits 27:2. */ +#define R_AARCH64_CALL26 283 /* Likewise for CALL. */ +#define R_AARCH64_LDST16_ABS_LO12_NC 284 /* Dir. ADD imm. from bits 11:1. */ +#define R_AARCH64_LDST32_ABS_LO12_NC 285 /* Likewise for bits 11:2. */ +#define R_AARCH64_LDST64_ABS_LO12_NC 286 /* Likewise for bits 11:3. */ +#define R_AARCH64_MOVW_PREL_G0 287 /* PC-rel. MOV{N,Z} imm. from 15:0. */ +#define R_AARCH64_MOVW_PREL_G0_NC 288 /* Likewise for MOVK; no check. */ +#define R_AARCH64_MOVW_PREL_G1 289 /* PC-rel. MOV{N,Z} imm. from 31:16. */ +#define R_AARCH64_MOVW_PREL_G1_NC 290 /* Likewise for MOVK; no check. */ +#define R_AARCH64_MOVW_PREL_G2 291 /* PC-rel. MOV{N,Z} imm. from 47:32. */ +#define R_AARCH64_MOVW_PREL_G2_NC 292 /* Likewise for MOVK; no check. */ +#define R_AARCH64_MOVW_PREL_G3 293 /* PC-rel. MOV{N,Z} imm. from 63:48. */ +#define R_AARCH64_LDST128_ABS_LO12_NC 299 /* Dir. ADD imm. from bits 11:4. */ +#define R_AARCH64_MOVW_GOTOFF_G0 300 /* GOT-rel. off. MOV{N,Z} imm. 15:0. */ +#define R_AARCH64_MOVW_GOTOFF_G0_NC 301 /* Likewise for MOVK; no check. */ +#define R_AARCH64_MOVW_GOTOFF_G1 302 /* GOT-rel. o. MOV{N,Z} imm. 31:16. */ +#define R_AARCH64_MOVW_GOTOFF_G1_NC 303 /* Likewise for MOVK; no check. */ +#define R_AARCH64_MOVW_GOTOFF_G2 304 /* GOT-rel. o. MOV{N,Z} imm. 47:32. */ +#define R_AARCH64_MOVW_GOTOFF_G2_NC 305 /* Likewise for MOVK; no check. */ +#define R_AARCH64_MOVW_GOTOFF_G3 306 /* GOT-rel. o. MOV{N,Z} imm. 63:48. */ +#define R_AARCH64_GOTREL64 307 /* GOT-relative 64-bit. */ +#define R_AARCH64_GOTREL32 308 /* GOT-relative 32-bit. */ +#define R_AARCH64_GOT_LD_PREL19 309 /* PC-rel. GOT off. load imm. 20:2. */ +#define R_AARCH64_LD64_GOTOFF_LO15 310 /* GOT-rel. off. LD/ST imm. 14:3. */ +#define R_AARCH64_ADR_GOT_PAGE 311 /* P-page-rel. GOT off. ADRP 32:12. */ +#define R_AARCH64_LD64_GOT_LO12_NC 312 /* Dir. GOT off. LD/ST imm. 11:3. */ +#define R_AARCH64_LD64_GOTPAGE_LO15 313 /* GOT-page-rel. GOT off. LD/ST 14:3 */ +#define R_AARCH64_TLSGD_ADR_PREL21 512 /* PC-relative ADR imm. 20:0. */ +#define R_AARCH64_TLSGD_ADR_PAGE21 513 /* page-rel. ADRP imm. 32:12. */ +#define R_AARCH64_TLSGD_ADD_LO12_NC 514 /* direct ADD imm. from 11:0. */ +#define R_AARCH64_TLSGD_MOVW_G1 515 /* GOT-rel. MOV{N,Z} 31:16. */ +#define R_AARCH64_TLSGD_MOVW_G0_NC 516 /* GOT-rel. MOVK imm. 15:0. */ +#define R_AARCH64_TLSLD_ADR_PREL21 517 /* Like 512; local dynamic model. */ +#define R_AARCH64_TLSLD_ADR_PAGE21 518 /* Like 513; local dynamic model. */ +#define R_AARCH64_TLSLD_ADD_LO12_NC 519 /* Like 514; local dynamic model. */ +#define R_AARCH64_TLSLD_MOVW_G1 520 /* Like 515; local dynamic model. */ +#define R_AARCH64_TLSLD_MOVW_G0_NC 521 /* Like 516; local dynamic model. */ +#define R_AARCH64_TLSLD_LD_PREL19 522 /* TLS PC-rel. load imm. 20:2. */ +#define R_AARCH64_TLSLD_MOVW_DTPREL_G2 523 /* TLS DTP-rel. MOV{N,Z} 47:32. */ +#define R_AARCH64_TLSLD_MOVW_DTPREL_G1 524 /* TLS DTP-rel. MOV{N,Z} 31:16. */ +#define R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC 525 /* Likewise; MOVK; no check. */ +#define R_AARCH64_TLSLD_MOVW_DTPREL_G0 526 /* TLS DTP-rel. MOV{N,Z} 15:0. */ +#define R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC 527 /* Likewise; MOVK; no check. */ +#define R_AARCH64_TLSLD_ADD_DTPREL_HI12 528 /* DTP-rel. ADD imm. from 23:12. */ +#define R_AARCH64_TLSLD_ADD_DTPREL_LO12 529 /* DTP-rel. ADD imm. from 11:0. */ +#define R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC 530 /* Likewise; no ovfl. check. */ +#define R_AARCH64_TLSLD_LDST8_DTPREL_LO12 531 /* DTP-rel. LD/ST imm. 11:0. */ +#define R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC 532 /* Likewise; no check. */ +#define R_AARCH64_TLSLD_LDST16_DTPREL_LO12 533 /* DTP-rel. LD/ST imm. 11:1. */ +#define R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC 534 /* Likewise; no check. */ +#define R_AARCH64_TLSLD_LDST32_DTPREL_LO12 535 /* DTP-rel. LD/ST imm. 11:2. */ +#define R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC 536 /* Likewise; no check. */ +#define R_AARCH64_TLSLD_LDST64_DTPREL_LO12 537 /* DTP-rel. LD/ST imm. 11:3. */ +#define R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC 538 /* Likewise; no check. */ +#define R_AARCH64_TLSIE_MOVW_GOTTPREL_G1 539 /* GOT-rel. MOV{N,Z} 31:16. */ +#define R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC 540 /* GOT-rel. MOVK 15:0. */ +#define R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 541 /* Page-rel. ADRP 32:12. */ +#define R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC 542 /* Direct LD off. 11:3. */ +#define R_AARCH64_TLSIE_LD_GOTTPREL_PREL19 543 /* PC-rel. load imm. 20:2. */ +#define R_AARCH64_TLSLE_MOVW_TPREL_G2 544 /* TLS TP-rel. MOV{N,Z} 47:32. */ +#define R_AARCH64_TLSLE_MOVW_TPREL_G1 545 /* TLS TP-rel. MOV{N,Z} 31:16. */ +#define R_AARCH64_TLSLE_MOVW_TPREL_G1_NC 546 /* Likewise; MOVK; no check. */ +#define R_AARCH64_TLSLE_MOVW_TPREL_G0 547 /* TLS TP-rel. MOV{N,Z} 15:0. */ +#define R_AARCH64_TLSLE_MOVW_TPREL_G0_NC 548 /* Likewise; MOVK; no check. */ +#define R_AARCH64_TLSLE_ADD_TPREL_HI12 549 /* TP-rel. ADD imm. 23:12. */ +#define R_AARCH64_TLSLE_ADD_TPREL_LO12 550 /* TP-rel. ADD imm. 11:0. */ +#define R_AARCH64_TLSLE_ADD_TPREL_LO12_NC 551 /* Likewise; no ovfl. check. */ +#define R_AARCH64_TLSLE_LDST8_TPREL_LO12 552 /* TP-rel. LD/ST off. 11:0. */ +#define R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC 553 /* Likewise; no ovfl. check. */ +#define R_AARCH64_TLSLE_LDST16_TPREL_LO12 554 /* TP-rel. LD/ST off. 11:1. */ +#define R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC 555 /* Likewise; no check. */ +#define R_AARCH64_TLSLE_LDST32_TPREL_LO12 556 /* TP-rel. LD/ST off. 11:2. */ +#define R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC 557 /* Likewise; no check. */ +#define R_AARCH64_TLSLE_LDST64_TPREL_LO12 558 /* TP-rel. LD/ST off. 11:3. */ +#define R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC 559 /* Likewise; no check. */ +#define R_AARCH64_TLSDESC_LD_PREL19 560 /* PC-rel. load immediate 20:2. */ +#define R_AARCH64_TLSDESC_ADR_PREL21 561 /* PC-rel. ADR immediate 20:0. */ +#define R_AARCH64_TLSDESC_ADR_PAGE21 562 /* Page-rel. ADRP imm. 32:12. */ +#define R_AARCH64_TLSDESC_LD64_LO12 563 /* Direct LD off. from 11:3. */ +#define R_AARCH64_TLSDESC_ADD_LO12 564 /* Direct ADD imm. from 11:0. */ +#define R_AARCH64_TLSDESC_OFF_G1 565 /* GOT-rel. MOV{N,Z} imm. 31:16. */ +#define R_AARCH64_TLSDESC_OFF_G0_NC 566 /* GOT-rel. MOVK imm. 15:0; no ck. */ +#define R_AARCH64_TLSDESC_LDR 567 /* Relax LDR. */ +#define R_AARCH64_TLSDESC_ADD 568 /* Relax ADD. */ +#define R_AARCH64_TLSDESC_CALL 569 /* Relax BLR. */ +#define R_AARCH64_TLSLE_LDST128_TPREL_LO12 570 /* TP-rel. LD/ST off. 11:4. */ +#define R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC 571 /* Likewise; no check. */ +#define R_AARCH64_TLSLD_LDST128_DTPREL_LO12 572 /* DTP-rel. LD/ST imm. 11:4. */ +#define R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC 573 /* Likewise; no check. */ +#define R_AARCH64_COPY 1024 /* Copy symbol at runtime. */ +#define R_AARCH64_GLOB_DAT 1025 /* Create GOT entry. */ +#define R_AARCH64_JUMP_SLOT 1026 /* Create PLT entry. */ +#define R_AARCH64_RELATIVE 1027 /* Adjust by program base. */ +#define R_AARCH64_TLS_DTPMOD64 1028 /* Module number, 64 bit. */ +#define R_AARCH64_TLS_DTPREL64 1029 /* Module-relative offset, 64 bit. */ +#define R_AARCH64_TLS_TPREL64 1030 /* TP-relative offset, 64 bit. */ +#define R_AARCH64_TLSDESC 1031 /* TLS Descriptor. */ +#define R_AARCH64_IRELATIVE 1032 /* STT_GNU_IFUNC relocation. */ + +/* ARM relocs. */ + +#define R_ARM_NONE 0 /* No reloc */ +#define R_ARM_PC24 1 /* Deprecated PC relative 26 + bit branch. */ +#define R_ARM_ABS32 2 /* Direct 32 bit */ +#define R_ARM_REL32 3 /* PC relative 32 bit */ +#define R_ARM_PC13 4 +#define R_ARM_ABS16 5 /* Direct 16 bit */ +#define R_ARM_ABS12 6 /* Direct 12 bit */ +#define R_ARM_THM_ABS5 7 /* Direct & 0x7C (LDR, STR). */ +#define R_ARM_ABS8 8 /* Direct 8 bit */ +#define R_ARM_SBREL32 9 +#define R_ARM_THM_PC22 10 /* PC relative 24 bit (Thumb32 BL). */ +#define R_ARM_THM_PC8 11 /* PC relative & 0x3FC + (Thumb16 LDR, ADD, ADR). */ +#define R_ARM_AMP_VCALL9 12 +#define R_ARM_SWI24 13 /* Obsolete static relocation. */ +#define R_ARM_TLS_DESC 13 /* Dynamic relocation. */ +#define R_ARM_THM_SWI8 14 /* Reserved. */ +#define R_ARM_XPC25 15 /* Reserved. */ +#define R_ARM_THM_XPC22 16 /* Reserved. */ +#define R_ARM_TLS_DTPMOD32 17 /* ID of module containing symbol */ +#define R_ARM_TLS_DTPOFF32 18 /* Offset in TLS block */ +#define R_ARM_TLS_TPOFF32 19 /* Offset in static TLS block */ +#define R_ARM_COPY 20 /* Copy symbol at runtime */ +#define R_ARM_GLOB_DAT 21 /* Create GOT entry */ +#define R_ARM_JUMP_SLOT 22 /* Create PLT entry */ +#define R_ARM_RELATIVE 23 /* Adjust by program base */ +#define R_ARM_GOTOFF 24 /* 32 bit offset to GOT */ +#define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */ +#define R_ARM_GOT32 26 /* 32 bit GOT entry */ +#define R_ARM_PLT32 27 /* Deprecated, 32 bit PLT address. */ +#define R_ARM_CALL 28 /* PC relative 24 bit (BL, BLX). */ +#define R_ARM_JUMP24 29 /* PC relative 24 bit + (B, BL<cond>). */ +#define R_ARM_THM_JUMP24 30 /* PC relative 24 bit (Thumb32 B.W). */ +#define R_ARM_BASE_ABS 31 /* Adjust by program base. */ +#define R_ARM_ALU_PCREL_7_0 32 /* Obsolete. */ +#define R_ARM_ALU_PCREL_15_8 33 /* Obsolete. */ +#define R_ARM_ALU_PCREL_23_15 34 /* Obsolete. */ +#define R_ARM_LDR_SBREL_11_0 35 /* Deprecated, prog. base relative. */ +#define R_ARM_ALU_SBREL_19_12 36 /* Deprecated, prog. base relative. */ +#define R_ARM_ALU_SBREL_27_20 37 /* Deprecated, prog. base relative. */ +#define R_ARM_TARGET1 38 +#define R_ARM_SBREL31 39 /* Program base relative. */ +#define R_ARM_V4BX 40 +#define R_ARM_TARGET2 41 +#define R_ARM_PREL31 42 /* 32 bit PC relative. */ +#define R_ARM_MOVW_ABS_NC 43 /* Direct 16-bit (MOVW). */ +#define R_ARM_MOVT_ABS 44 /* Direct high 16-bit (MOVT). */ +#define R_ARM_MOVW_PREL_NC 45 /* PC relative 16-bit (MOVW). */ +#define R_ARM_MOVT_PREL 46 /* PC relative (MOVT). */ +#define R_ARM_THM_MOVW_ABS_NC 47 /* Direct 16 bit (Thumb32 MOVW). */ +#define R_ARM_THM_MOVT_ABS 48 /* Direct high 16 bit + (Thumb32 MOVT). */ +#define R_ARM_THM_MOVW_PREL_NC 49 /* PC relative 16 bit + (Thumb32 MOVW). */ +#define R_ARM_THM_MOVT_PREL 50 /* PC relative high 16 bit + (Thumb32 MOVT). */ +#define R_ARM_THM_JUMP19 51 /* PC relative 20 bit + (Thumb32 B<cond>.W). */ +#define R_ARM_THM_JUMP6 52 /* PC relative X & 0x7E + (Thumb16 CBZ, CBNZ). */ +#define R_ARM_THM_ALU_PREL_11_0 53 /* PC relative 12 bit + (Thumb32 ADR.W). */ +#define R_ARM_THM_PC12 54 /* PC relative 12 bit + (Thumb32 LDR{D,SB,H,SH}). */ +#define R_ARM_ABS32_NOI 55 /* Direct 32-bit. */ +#define R_ARM_REL32_NOI 56 /* PC relative 32-bit. */ +#define R_ARM_ALU_PC_G0_NC 57 /* PC relative (ADD, SUB). */ +#define R_ARM_ALU_PC_G0 58 /* PC relative (ADD, SUB). */ +#define R_ARM_ALU_PC_G1_NC 59 /* PC relative (ADD, SUB). */ +#define R_ARM_ALU_PC_G1 60 /* PC relative (ADD, SUB). */ +#define R_ARM_ALU_PC_G2 61 /* PC relative (ADD, SUB). */ +#define R_ARM_LDR_PC_G1 62 /* PC relative (LDR,STR,LDRB,STRB). */ +#define R_ARM_LDR_PC_G2 63 /* PC relative (LDR,STR,LDRB,STRB). */ +#define R_ARM_LDRS_PC_G0 64 /* PC relative (STR{D,H}, + LDR{D,SB,H,SH}). */ +#define R_ARM_LDRS_PC_G1 65 /* PC relative (STR{D,H}, + LDR{D,SB,H,SH}). */ +#define R_ARM_LDRS_PC_G2 66 /* PC relative (STR{D,H}, + LDR{D,SB,H,SH}). */ +#define R_ARM_LDC_PC_G0 67 /* PC relative (LDC, STC). */ +#define R_ARM_LDC_PC_G1 68 /* PC relative (LDC, STC). */ +#define R_ARM_LDC_PC_G2 69 /* PC relative (LDC, STC). */ +#define R_ARM_ALU_SB_G0_NC 70 /* Program base relative (ADD,SUB). */ +#define R_ARM_ALU_SB_G0 71 /* Program base relative (ADD,SUB). */ +#define R_ARM_ALU_SB_G1_NC 72 /* Program base relative (ADD,SUB). */ +#define R_ARM_ALU_SB_G1 73 /* Program base relative (ADD,SUB). */ +#define R_ARM_ALU_SB_G2 74 /* Program base relative (ADD,SUB). */ +#define R_ARM_LDR_SB_G0 75 /* Program base relative (LDR, + STR, LDRB, STRB). */ +#define R_ARM_LDR_SB_G1 76 /* Program base relative + (LDR, STR, LDRB, STRB). */ +#define R_ARM_LDR_SB_G2 77 /* Program base relative + (LDR, STR, LDRB, STRB). */ +#define R_ARM_LDRS_SB_G0 78 /* Program base relative + (LDR, STR, LDRB, STRB). */ +#define R_ARM_LDRS_SB_G1 79 /* Program base relative + (LDR, STR, LDRB, STRB). */ +#define R_ARM_LDRS_SB_G2 80 /* Program base relative + (LDR, STR, LDRB, STRB). */ +#define R_ARM_LDC_SB_G0 81 /* Program base relative (LDC,STC). */ +#define R_ARM_LDC_SB_G1 82 /* Program base relative (LDC,STC). */ +#define R_ARM_LDC_SB_G2 83 /* Program base relative (LDC,STC). */ +#define R_ARM_MOVW_BREL_NC 84 /* Program base relative 16 + bit (MOVW). */ +#define R_ARM_MOVT_BREL 85 /* Program base relative high + 16 bit (MOVT). */ +#define R_ARM_MOVW_BREL 86 /* Program base relative 16 + bit (MOVW). */ +#define R_ARM_THM_MOVW_BREL_NC 87 /* Program base relative 16 + bit (Thumb32 MOVW). */ +#define R_ARM_THM_MOVT_BREL 88 /* Program base relative high + 16 bit (Thumb32 MOVT). */ +#define R_ARM_THM_MOVW_BREL 89 /* Program base relative 16 + bit (Thumb32 MOVW). */ +#define R_ARM_TLS_GOTDESC 90 +#define R_ARM_TLS_CALL 91 +#define R_ARM_TLS_DESCSEQ 92 /* TLS relaxation. */ +#define R_ARM_THM_TLS_CALL 93 +#define R_ARM_PLT32_ABS 94 +#define R_ARM_GOT_ABS 95 /* GOT entry. */ +#define R_ARM_GOT_PREL 96 /* PC relative GOT entry. */ +#define R_ARM_GOT_BREL12 97 /* GOT entry relative to GOT + origin (LDR). */ +#define R_ARM_GOTOFF12 98 /* 12 bit, GOT entry relative + to GOT origin (LDR, STR). */ +#define R_ARM_GOTRELAX 99 +#define R_ARM_GNU_VTENTRY 100 +#define R_ARM_GNU_VTINHERIT 101 +#define R_ARM_THM_PC11 102 /* PC relative & 0xFFE (Thumb16 B). */ +#define R_ARM_THM_PC9 103 /* PC relative & 0x1FE + (Thumb16 B/B<cond>). */ +#define R_ARM_TLS_GD32 104 /* PC-rel 32 bit for global dynamic + thread local data */ +#define R_ARM_TLS_LDM32 105 /* PC-rel 32 bit for local dynamic + thread local data */ +#define R_ARM_TLS_LDO32 106 /* 32 bit offset relative to TLS + block */ +#define R_ARM_TLS_IE32 107 /* PC-rel 32 bit for GOT entry of + static TLS block offset */ +#define R_ARM_TLS_LE32 108 /* 32 bit offset relative to static + TLS block */ +#define R_ARM_TLS_LDO12 109 /* 12 bit relative to TLS + block (LDR, STR). */ +#define R_ARM_TLS_LE12 110 /* 12 bit relative to static + TLS block (LDR, STR). */ +#define R_ARM_TLS_IE12GP 111 /* 12 bit GOT entry relative + to GOT origin (LDR). */ +#define R_ARM_ME_TOO 128 /* Obsolete. */ +#define R_ARM_THM_TLS_DESCSEQ 129 +#define R_ARM_THM_TLS_DESCSEQ16 129 +#define R_ARM_THM_TLS_DESCSEQ32 130 +#define R_ARM_THM_GOT_BREL12 131 /* GOT entry relative to GOT + origin, 12 bit (Thumb32 LDR). */ +#define R_ARM_IRELATIVE 160 +#define R_ARM_RXPC25 249 +#define R_ARM_RSBREL32 250 +#define R_ARM_THM_RPC22 251 +#define R_ARM_RREL32 252 +#define R_ARM_RABS22 253 +#define R_ARM_RPC24 254 +#define R_ARM_RBASE 255 +/* Keep this the last entry. */ +#define R_ARM_NUM 256 + +/* IA-64 specific declarations. */ + +/* Processor specific flags for the Ehdr e_flags field. */ +#define EF_IA_64_MASKOS 0x0000000f /* os-specific flags */ +#define EF_IA_64_ABI64 0x00000010 /* 64-bit ABI */ +#define EF_IA_64_ARCH 0xff000000 /* arch. version mask */ + +/* Processor specific values for the Phdr p_type field. */ +#define PT_IA_64_ARCHEXT (PT_LOPROC + 0) /* arch extension bits */ +#define PT_IA_64_UNWIND (PT_LOPROC + 1) /* ia64 unwind bits */ +#define PT_IA_64_HP_OPT_ANOT (PT_LOOS + 0x12) +#define PT_IA_64_HP_HSL_ANOT (PT_LOOS + 0x13) +#define PT_IA_64_HP_STACK (PT_LOOS + 0x14) + +/* Processor specific flags for the Phdr p_flags field. */ +#define PF_IA_64_NORECOV 0x80000000 /* spec insns w/o recovery */ + +/* Processor specific values for the Shdr sh_type field. */ +#define SHT_IA_64_EXT (SHT_LOPROC + 0) /* extension bits */ +#define SHT_IA_64_UNWIND (SHT_LOPROC + 1) /* unwind bits */ + +/* Processor specific flags for the Shdr sh_flags field. */ +#define SHF_IA_64_SHORT 0x10000000 /* section near gp */ +#define SHF_IA_64_NORECOV 0x20000000 /* spec insns w/o recovery */ + +/* Processor specific values for the Dyn d_tag field. */ +#define DT_IA_64_PLT_RESERVE (DT_LOPROC + 0) +#define DT_IA_64_NUM 1 + +/* IA-64 relocations. */ +#define R_IA64_NONE 0x00 /* none */ +#define R_IA64_IMM14 0x21 /* symbol + addend, add imm14 */ +#define R_IA64_IMM22 0x22 /* symbol + addend, add imm22 */ +#define R_IA64_IMM64 0x23 /* symbol + addend, mov imm64 */ +#define R_IA64_DIR32MSB 0x24 /* symbol + addend, data4 MSB */ +#define R_IA64_DIR32LSB 0x25 /* symbol + addend, data4 LSB */ +#define R_IA64_DIR64MSB 0x26 /* symbol + addend, data8 MSB */ +#define R_IA64_DIR64LSB 0x27 /* symbol + addend, data8 LSB */ +#define R_IA64_GPREL22 0x2a /* @gprel(sym + add), add imm22 */ +#define R_IA64_GPREL64I 0x2b /* @gprel(sym + add), mov imm64 */ +#define R_IA64_GPREL32MSB 0x2c /* @gprel(sym + add), data4 MSB */ +#define R_IA64_GPREL32LSB 0x2d /* @gprel(sym + add), data4 LSB */ +#define R_IA64_GPREL64MSB 0x2e /* @gprel(sym + add), data8 MSB */ +#define R_IA64_GPREL64LSB 0x2f /* @gprel(sym + add), data8 LSB */ +#define R_IA64_LTOFF22 0x32 /* @ltoff(sym + add), add imm22 */ +#define R_IA64_LTOFF64I 0x33 /* @ltoff(sym + add), mov imm64 */ +#define R_IA64_PLTOFF22 0x3a /* @pltoff(sym + add), add imm22 */ +#define R_IA64_PLTOFF64I 0x3b /* @pltoff(sym + add), mov imm64 */ +#define R_IA64_PLTOFF64MSB 0x3e /* @pltoff(sym + add), data8 MSB */ +#define R_IA64_PLTOFF64LSB 0x3f /* @pltoff(sym + add), data8 LSB */ +#define R_IA64_FPTR64I 0x43 /* @fptr(sym + add), mov imm64 */ +#define R_IA64_FPTR32MSB 0x44 /* @fptr(sym + add), data4 MSB */ +#define R_IA64_FPTR32LSB 0x45 /* @fptr(sym + add), data4 LSB */ +#define R_IA64_FPTR64MSB 0x46 /* @fptr(sym + add), data8 MSB */ +#define R_IA64_FPTR64LSB 0x47 /* @fptr(sym + add), data8 LSB */ +#define R_IA64_PCREL60B 0x48 /* @pcrel(sym + add), brl */ +#define R_IA64_PCREL21B 0x49 /* @pcrel(sym + add), ptb, call */ +#define R_IA64_PCREL21M 0x4a /* @pcrel(sym + add), chk.s */ +#define R_IA64_PCREL21F 0x4b /* @pcrel(sym + add), fchkf */ +#define R_IA64_PCREL32MSB 0x4c /* @pcrel(sym + add), data4 MSB */ +#define R_IA64_PCREL32LSB 0x4d /* @pcrel(sym + add), data4 LSB */ +#define R_IA64_PCREL64MSB 0x4e /* @pcrel(sym + add), data8 MSB */ +#define R_IA64_PCREL64LSB 0x4f /* @pcrel(sym + add), data8 LSB */ +#define R_IA64_LTOFF_FPTR22 0x52 /* @ltoff(@fptr(s+a)), imm22 */ +#define R_IA64_LTOFF_FPTR64I 0x53 /* @ltoff(@fptr(s+a)), imm64 */ +#define R_IA64_LTOFF_FPTR32MSB 0x54 /* @ltoff(@fptr(s+a)), data4 MSB */ +#define R_IA64_LTOFF_FPTR32LSB 0x55 /* @ltoff(@fptr(s+a)), data4 LSB */ +#define R_IA64_LTOFF_FPTR64MSB 0x56 /* @ltoff(@fptr(s+a)), data8 MSB */ +#define R_IA64_LTOFF_FPTR64LSB 0x57 /* @ltoff(@fptr(s+a)), data8 LSB */ +#define R_IA64_SEGREL32MSB 0x5c /* @segrel(sym + add), data4 MSB */ +#define R_IA64_SEGREL32LSB 0x5d /* @segrel(sym + add), data4 LSB */ +#define R_IA64_SEGREL64MSB 0x5e /* @segrel(sym + add), data8 MSB */ +#define R_IA64_SEGREL64LSB 0x5f /* @segrel(sym + add), data8 LSB */ +#define R_IA64_SECREL32MSB 0x64 /* @secrel(sym + add), data4 MSB */ +#define R_IA64_SECREL32LSB 0x65 /* @secrel(sym + add), data4 LSB */ +#define R_IA64_SECREL64MSB 0x66 /* @secrel(sym + add), data8 MSB */ +#define R_IA64_SECREL64LSB 0x67 /* @secrel(sym + add), data8 LSB */ +#define R_IA64_REL32MSB 0x6c /* data 4 + REL */ +#define R_IA64_REL32LSB 0x6d /* data 4 + REL */ +#define R_IA64_REL64MSB 0x6e /* data 8 + REL */ +#define R_IA64_REL64LSB 0x6f /* data 8 + REL */ +#define R_IA64_LTV32MSB 0x74 /* symbol + addend, data4 MSB */ +#define R_IA64_LTV32LSB 0x75 /* symbol + addend, data4 LSB */ +#define R_IA64_LTV64MSB 0x76 /* symbol + addend, data8 MSB */ +#define R_IA64_LTV64LSB 0x77 /* symbol + addend, data8 LSB */ +#define R_IA64_PCREL21BI 0x79 /* @pcrel(sym + add), 21bit inst */ +#define R_IA64_PCREL22 0x7a /* @pcrel(sym + add), 22bit inst */ +#define R_IA64_PCREL64I 0x7b /* @pcrel(sym + add), 64bit inst */ +#define R_IA64_IPLTMSB 0x80 /* dynamic reloc, imported PLT, MSB */ +#define R_IA64_IPLTLSB 0x81 /* dynamic reloc, imported PLT, LSB */ +#define R_IA64_COPY 0x84 /* copy relocation */ +#define R_IA64_SUB 0x85 /* Addend and symbol difference */ +#define R_IA64_LTOFF22X 0x86 /* LTOFF22, relaxable. */ +#define R_IA64_LDXMOV 0x87 /* Use of LTOFF22X. */ +#define R_IA64_TPREL14 0x91 /* @tprel(sym + add), imm14 */ +#define R_IA64_TPREL22 0x92 /* @tprel(sym + add), imm22 */ +#define R_IA64_TPREL64I 0x93 /* @tprel(sym + add), imm64 */ +#define R_IA64_TPREL64MSB 0x96 /* @tprel(sym + add), data8 MSB */ +#define R_IA64_TPREL64LSB 0x97 /* @tprel(sym + add), data8 LSB */ +#define R_IA64_LTOFF_TPREL22 0x9a /* @ltoff(@tprel(s+a)), imm2 */ +#define R_IA64_DTPMOD64MSB 0xa6 /* @dtpmod(sym + add), data8 MSB */ +#define R_IA64_DTPMOD64LSB 0xa7 /* @dtpmod(sym + add), data8 LSB */ +#define R_IA64_LTOFF_DTPMOD22 0xaa /* @ltoff(@dtpmod(sym + add)), imm22 */ +#define R_IA64_DTPREL14 0xb1 /* @dtprel(sym + add), imm14 */ +#define R_IA64_DTPREL22 0xb2 /* @dtprel(sym + add), imm22 */ +#define R_IA64_DTPREL64I 0xb3 /* @dtprel(sym + add), imm64 */ +#define R_IA64_DTPREL32MSB 0xb4 /* @dtprel(sym + add), data4 MSB */ +#define R_IA64_DTPREL32LSB 0xb5 /* @dtprel(sym + add), data4 LSB */ +#define R_IA64_DTPREL64MSB 0xb6 /* @dtprel(sym + add), data8 MSB */ +#define R_IA64_DTPREL64LSB 0xb7 /* @dtprel(sym + add), data8 LSB */ +#define R_IA64_LTOFF_DTPREL22 0xba /* @ltoff(@dtprel(s+a)), imm22 */ + +/* SH specific declarations */ + +/* Processor specific flags for the ELF header e_flags field. */ +#define EF_SH_MACH_MASK 0x1f +#define EF_SH_UNKNOWN 0x0 +#define EF_SH1 0x1 +#define EF_SH2 0x2 +#define EF_SH3 0x3 +#define EF_SH_DSP 0x4 +#define EF_SH3_DSP 0x5 +#define EF_SH4AL_DSP 0x6 +#define EF_SH3E 0x8 +#define EF_SH4 0x9 +#define EF_SH2E 0xb +#define EF_SH4A 0xc +#define EF_SH2A 0xd +#define EF_SH4_NOFPU 0x10 +#define EF_SH4A_NOFPU 0x11 +#define EF_SH4_NOMMU_NOFPU 0x12 +#define EF_SH2A_NOFPU 0x13 +#define EF_SH3_NOMMU 0x14 +#define EF_SH2A_SH4_NOFPU 0x15 +#define EF_SH2A_SH3_NOFPU 0x16 +#define EF_SH2A_SH4 0x17 +#define EF_SH2A_SH3E 0x18 + +/* SH relocs. */ +#define R_SH_NONE 0 +#define R_SH_DIR32 1 +#define R_SH_REL32 2 +#define R_SH_DIR8WPN 3 +#define R_SH_IND12W 4 +#define R_SH_DIR8WPL 5 +#define R_SH_DIR8WPZ 6 +#define R_SH_DIR8BP 7 +#define R_SH_DIR8W 8 +#define R_SH_DIR8L 9 +#define R_SH_SWITCH16 25 +#define R_SH_SWITCH32 26 +#define R_SH_USES 27 +#define R_SH_COUNT 28 +#define R_SH_ALIGN 29 +#define R_SH_CODE 30 +#define R_SH_DATA 31 +#define R_SH_LABEL 32 +#define R_SH_SWITCH8 33 +#define R_SH_GNU_VTINHERIT 34 +#define R_SH_GNU_VTENTRY 35 +#define R_SH_TLS_GD_32 144 +#define R_SH_TLS_LD_32 145 +#define R_SH_TLS_LDO_32 146 +#define R_SH_TLS_IE_32 147 +#define R_SH_TLS_LE_32 148 +#define R_SH_TLS_DTPMOD32 149 +#define R_SH_TLS_DTPOFF32 150 +#define R_SH_TLS_TPOFF32 151 +#define R_SH_GOT32 160 +#define R_SH_PLT32 161 +#define R_SH_COPY 162 +#define R_SH_GLOB_DAT 163 +#define R_SH_JMP_SLOT 164 +#define R_SH_RELATIVE 165 +#define R_SH_GOTOFF 166 +#define R_SH_GOTPC 167 +/* Keep this the last entry. */ +#define R_SH_NUM 256 + +/* S/390 specific definitions. */ + +/* Valid values for the e_flags field. */ + +#define EF_S390_HIGH_GPRS 0x00000001 /* High GPRs kernel facility needed. */ + +/* Additional s390 relocs */ + +#define R_390_NONE 0 /* No reloc. */ +#define R_390_8 1 /* Direct 8 bit. */ +#define R_390_12 2 /* Direct 12 bit. */ +#define R_390_16 3 /* Direct 16 bit. */ +#define R_390_32 4 /* Direct 32 bit. */ +#define R_390_PC32 5 /* PC relative 32 bit. */ +#define R_390_GOT12 6 /* 12 bit GOT offset. */ +#define R_390_GOT32 7 /* 32 bit GOT offset. */ +#define R_390_PLT32 8 /* 32 bit PC relative PLT address. */ +#define R_390_COPY 9 /* Copy symbol at runtime. */ +#define R_390_GLOB_DAT 10 /* Create GOT entry. */ +#define R_390_JMP_SLOT 11 /* Create PLT entry. */ +#define R_390_RELATIVE 12 /* Adjust by program base. */ +#define R_390_GOTOFF32 13 /* 32 bit offset to GOT. */ +#define R_390_GOTPC 14 /* 32 bit PC relative offset to GOT. */ +#define R_390_GOT16 15 /* 16 bit GOT offset. */ +#define R_390_PC16 16 /* PC relative 16 bit. */ +#define R_390_PC16DBL 17 /* PC relative 16 bit shifted by 1. */ +#define R_390_PLT16DBL 18 /* 16 bit PC rel. PLT shifted by 1. */ +#define R_390_PC32DBL 19 /* PC relative 32 bit shifted by 1. */ +#define R_390_PLT32DBL 20 /* 32 bit PC rel. PLT shifted by 1. */ +#define R_390_GOTPCDBL 21 /* 32 bit PC rel. GOT shifted by 1. */ +#define R_390_64 22 /* Direct 64 bit. */ +#define R_390_PC64 23 /* PC relative 64 bit. */ +#define R_390_GOT64 24 /* 64 bit GOT offset. */ +#define R_390_PLT64 25 /* 64 bit PC relative PLT address. */ +#define R_390_GOTENT 26 /* 32 bit PC rel. to GOT entry >> 1. */ +#define R_390_GOTOFF16 27 /* 16 bit offset to GOT. */ +#define R_390_GOTOFF64 28 /* 64 bit offset to GOT. */ +#define R_390_GOTPLT12 29 /* 12 bit offset to jump slot. */ +#define R_390_GOTPLT16 30 /* 16 bit offset to jump slot. */ +#define R_390_GOTPLT32 31 /* 32 bit offset to jump slot. */ +#define R_390_GOTPLT64 32 /* 64 bit offset to jump slot. */ +#define R_390_GOTPLTENT 33 /* 32 bit rel. offset to jump slot. */ +#define R_390_PLTOFF16 34 /* 16 bit offset from GOT to PLT. */ +#define R_390_PLTOFF32 35 /* 32 bit offset from GOT to PLT. */ +#define R_390_PLTOFF64 36 /* 16 bit offset from GOT to PLT. */ +#define R_390_TLS_LOAD 37 /* Tag for load insn in TLS code. */ +#define R_390_TLS_GDCALL 38 /* Tag for function call in general + dynamic TLS code. */ +#define R_390_TLS_LDCALL 39 /* Tag for function call in local + dynamic TLS code. */ +#define R_390_TLS_GD32 40 /* Direct 32 bit for general dynamic + thread local data. */ +#define R_390_TLS_GD64 41 /* Direct 64 bit for general dynamic + thread local data. */ +#define R_390_TLS_GOTIE12 42 /* 12 bit GOT offset for static TLS + block offset. */ +#define R_390_TLS_GOTIE32 43 /* 32 bit GOT offset for static TLS + block offset. */ +#define R_390_TLS_GOTIE64 44 /* 64 bit GOT offset for static TLS + block offset. */ +#define R_390_TLS_LDM32 45 /* Direct 32 bit for local dynamic + thread local data in LE code. */ +#define R_390_TLS_LDM64 46 /* Direct 64 bit for local dynamic + thread local data in LE code. */ +#define R_390_TLS_IE32 47 /* 32 bit address of GOT entry for + negated static TLS block offset. */ +#define R_390_TLS_IE64 48 /* 64 bit address of GOT entry for + negated static TLS block offset. */ +#define R_390_TLS_IEENT 49 /* 32 bit rel. offset to GOT entry for + negated static TLS block offset. */ +#define R_390_TLS_LE32 50 /* 32 bit negated offset relative to + static TLS block. */ +#define R_390_TLS_LE64 51 /* 64 bit negated offset relative to + static TLS block. */ +#define R_390_TLS_LDO32 52 /* 32 bit offset relative to TLS + block. */ +#define R_390_TLS_LDO64 53 /* 64 bit offset relative to TLS + block. */ +#define R_390_TLS_DTPMOD 54 /* ID of module containing symbol. */ +#define R_390_TLS_DTPOFF 55 /* Offset in TLS block. */ +#define R_390_TLS_TPOFF 56 /* Negated offset in static TLS + block. */ +#define R_390_20 57 /* Direct 20 bit. */ +#define R_390_GOT20 58 /* 20 bit GOT offset. */ +#define R_390_GOTPLT20 59 /* 20 bit offset to jump slot. */ +#define R_390_TLS_GOTIE20 60 /* 20 bit GOT offset for static TLS + block offset. */ +#define R_390_IRELATIVE 61 /* STT_GNU_IFUNC relocation. */ +/* Keep this the last entry. */ +#define R_390_NUM 62 + + +/* CRIS relocations. */ +#define R_CRIS_NONE 0 +#define R_CRIS_8 1 +#define R_CRIS_16 2 +#define R_CRIS_32 3 +#define R_CRIS_8_PCREL 4 +#define R_CRIS_16_PCREL 5 +#define R_CRIS_32_PCREL 6 +#define R_CRIS_GNU_VTINHERIT 7 +#define R_CRIS_GNU_VTENTRY 8 +#define R_CRIS_COPY 9 +#define R_CRIS_GLOB_DAT 10 +#define R_CRIS_JUMP_SLOT 11 +#define R_CRIS_RELATIVE 12 +#define R_CRIS_16_GOT 13 +#define R_CRIS_32_GOT 14 +#define R_CRIS_16_GOTPLT 15 +#define R_CRIS_32_GOTPLT 16 +#define R_CRIS_32_GOTREL 17 +#define R_CRIS_32_PLT_GOTREL 18 +#define R_CRIS_32_PLT_PCREL 19 + +#define R_CRIS_NUM 20 + + +/* AMD x86-64 relocations. */ +#define R_X86_64_NONE 0 /* No reloc */ +#define R_X86_64_64 1 /* Direct 64 bit */ +#define R_X86_64_PC32 2 /* PC relative 32 bit signed */ +#define R_X86_64_GOT32 3 /* 32 bit GOT entry */ +#define R_X86_64_PLT32 4 /* 32 bit PLT address */ +#define R_X86_64_COPY 5 /* Copy symbol at runtime */ +#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */ +#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */ +#define R_X86_64_RELATIVE 8 /* Adjust by program base */ +#define R_X86_64_GOTPCREL 9 /* 32 bit signed PC relative + offset to GOT */ +#define R_X86_64_32 10 /* Direct 32 bit zero extended */ +#define R_X86_64_32S 11 /* Direct 32 bit sign extended */ +#define R_X86_64_16 12 /* Direct 16 bit zero extended */ +#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */ +#define R_X86_64_8 14 /* Direct 8 bit sign extended */ +#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */ +#define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */ +#define R_X86_64_DTPOFF64 17 /* Offset in module's TLS block */ +#define R_X86_64_TPOFF64 18 /* Offset in initial TLS block */ +#define R_X86_64_TLSGD 19 /* 32 bit signed PC relative offset + to two GOT entries for GD symbol */ +#define R_X86_64_TLSLD 20 /* 32 bit signed PC relative offset + to two GOT entries for LD symbol */ +#define R_X86_64_DTPOFF32 21 /* Offset in TLS block */ +#define R_X86_64_GOTTPOFF 22 /* 32 bit signed PC relative offset + to GOT entry for IE symbol */ +#define R_X86_64_TPOFF32 23 /* Offset in initial TLS block */ +#define R_X86_64_PC64 24 /* PC relative 64 bit */ +#define R_X86_64_GOTOFF64 25 /* 64 bit offset to GOT */ +#define R_X86_64_GOTPC32 26 /* 32 bit signed pc relative + offset to GOT */ +#define R_X86_64_GOT64 27 /* 64-bit GOT entry offset */ +#define R_X86_64_GOTPCREL64 28 /* 64-bit PC relative offset + to GOT entry */ +#define R_X86_64_GOTPC64 29 /* 64-bit PC relative offset to GOT */ +#define R_X86_64_GOTPLT64 30 /* like GOT64, says PLT entry needed */ +#define R_X86_64_PLTOFF64 31 /* 64-bit GOT relative offset + to PLT entry */ +#define R_X86_64_SIZE32 32 /* Size of symbol plus 32-bit addend */ +#define R_X86_64_SIZE64 33 /* Size of symbol plus 64-bit addend */ +#define R_X86_64_GOTPC32_TLSDESC 34 /* GOT offset for TLS descriptor. */ +#define R_X86_64_TLSDESC_CALL 35 /* Marker for call through TLS + descriptor. */ +#define R_X86_64_TLSDESC 36 /* TLS descriptor. */ +#define R_X86_64_IRELATIVE 37 /* Adjust indirectly by program base */ +#define R_X86_64_RELATIVE64 38 /* 64-bit adjust by program base */ + +#define R_X86_64_NUM 39 + + +/* AM33 relocations. */ +#define R_MN10300_NONE 0 /* No reloc. */ +#define R_MN10300_32 1 /* Direct 32 bit. */ +#define R_MN10300_16 2 /* Direct 16 bit. */ +#define R_MN10300_8 3 /* Direct 8 bit. */ +#define R_MN10300_PCREL32 4 /* PC-relative 32-bit. */ +#define R_MN10300_PCREL16 5 /* PC-relative 16-bit signed. */ +#define R_MN10300_PCREL8 6 /* PC-relative 8-bit signed. */ +#define R_MN10300_GNU_VTINHERIT 7 /* Ancient C++ vtable garbage... */ +#define R_MN10300_GNU_VTENTRY 8 /* ... collection annotation. */ +#define R_MN10300_24 9 /* Direct 24 bit. */ +#define R_MN10300_GOTPC32 10 /* 32-bit PCrel offset to GOT. */ +#define R_MN10300_GOTPC16 11 /* 16-bit PCrel offset to GOT. */ +#define R_MN10300_GOTOFF32 12 /* 32-bit offset from GOT. */ +#define R_MN10300_GOTOFF24 13 /* 24-bit offset from GOT. */ +#define R_MN10300_GOTOFF16 14 /* 16-bit offset from GOT. */ +#define R_MN10300_PLT32 15 /* 32-bit PCrel to PLT entry. */ +#define R_MN10300_PLT16 16 /* 16-bit PCrel to PLT entry. */ +#define R_MN10300_GOT32 17 /* 32-bit offset to GOT entry. */ +#define R_MN10300_GOT24 18 /* 24-bit offset to GOT entry. */ +#define R_MN10300_GOT16 19 /* 16-bit offset to GOT entry. */ +#define R_MN10300_COPY 20 /* Copy symbol at runtime. */ +#define R_MN10300_GLOB_DAT 21 /* Create GOT entry. */ +#define R_MN10300_JMP_SLOT 22 /* Create PLT entry. */ +#define R_MN10300_RELATIVE 23 /* Adjust by program base. */ +#define R_MN10300_TLS_GD 24 /* 32-bit offset for global dynamic. */ +#define R_MN10300_TLS_LD 25 /* 32-bit offset for local dynamic. */ +#define R_MN10300_TLS_LDO 26 /* Module-relative offset. */ +#define R_MN10300_TLS_GOTIE 27 /* GOT offset for static TLS block + offset. */ +#define R_MN10300_TLS_IE 28 /* GOT address for static TLS block + offset. */ +#define R_MN10300_TLS_LE 29 /* Offset relative to static TLS + block. */ +#define R_MN10300_TLS_DTPMOD 30 /* ID of module containing symbol. */ +#define R_MN10300_TLS_DTPOFF 31 /* Offset in module TLS block. */ +#define R_MN10300_TLS_TPOFF 32 /* Offset in static TLS block. */ +#define R_MN10300_SYM_DIFF 33 /* Adjustment for next reloc as needed + by linker relaxation. */ +#define R_MN10300_ALIGN 34 /* Alignment requirement for linker + relaxation. */ +#define R_MN10300_NUM 35 + + +/* M32R relocs. */ +#define R_M32R_NONE 0 /* No reloc. */ +#define R_M32R_16 1 /* Direct 16 bit. */ +#define R_M32R_32 2 /* Direct 32 bit. */ +#define R_M32R_24 3 /* Direct 24 bit. */ +#define R_M32R_10_PCREL 4 /* PC relative 10 bit shifted. */ +#define R_M32R_18_PCREL 5 /* PC relative 18 bit shifted. */ +#define R_M32R_26_PCREL 6 /* PC relative 26 bit shifted. */ +#define R_M32R_HI16_ULO 7 /* High 16 bit with unsigned low. */ +#define R_M32R_HI16_SLO 8 /* High 16 bit with signed low. */ +#define R_M32R_LO16 9 /* Low 16 bit. */ +#define R_M32R_SDA16 10 /* 16 bit offset in SDA. */ +#define R_M32R_GNU_VTINHERIT 11 +#define R_M32R_GNU_VTENTRY 12 +/* M32R relocs use SHT_RELA. */ +#define R_M32R_16_RELA 33 /* Direct 16 bit. */ +#define R_M32R_32_RELA 34 /* Direct 32 bit. */ +#define R_M32R_24_RELA 35 /* Direct 24 bit. */ +#define R_M32R_10_PCREL_RELA 36 /* PC relative 10 bit shifted. */ +#define R_M32R_18_PCREL_RELA 37 /* PC relative 18 bit shifted. */ +#define R_M32R_26_PCREL_RELA 38 /* PC relative 26 bit shifted. */ +#define R_M32R_HI16_ULO_RELA 39 /* High 16 bit with unsigned low */ +#define R_M32R_HI16_SLO_RELA 40 /* High 16 bit with signed low */ +#define R_M32R_LO16_RELA 41 /* Low 16 bit */ +#define R_M32R_SDA16_RELA 42 /* 16 bit offset in SDA */ +#define R_M32R_RELA_GNU_VTINHERIT 43 +#define R_M32R_RELA_GNU_VTENTRY 44 +#define R_M32R_REL32 45 /* PC relative 32 bit. */ + +#define R_M32R_GOT24 48 /* 24 bit GOT entry */ +#define R_M32R_26_PLTREL 49 /* 26 bit PC relative to PLT shifted */ +#define R_M32R_COPY 50 /* Copy symbol at runtime */ +#define R_M32R_GLOB_DAT 51 /* Create GOT entry */ +#define R_M32R_JMP_SLOT 52 /* Create PLT entry */ +#define R_M32R_RELATIVE 53 /* Adjust by program base */ +#define R_M32R_GOTOFF 54 /* 24 bit offset to GOT */ +#define R_M32R_GOTPC24 55 /* 24 bit PC relative offset to GOT */ +#define R_M32R_GOT16_HI_ULO 56 /* High 16 bit GOT entry with unsigned + low */ +#define R_M32R_GOT16_HI_SLO 57 /* High 16 bit GOT entry with signed + low */ +#define R_M32R_GOT16_LO 58 /* Low 16 bit GOT entry */ +#define R_M32R_GOTPC_HI_ULO 59 /* High 16 bit PC relative offset to + GOT with unsigned low */ +#define R_M32R_GOTPC_HI_SLO 60 /* High 16 bit PC relative offset to + GOT with signed low */ +#define R_M32R_GOTPC_LO 61 /* Low 16 bit PC relative offset to + GOT */ +#define R_M32R_GOTOFF_HI_ULO 62 /* High 16 bit offset to GOT + with unsigned low */ +#define R_M32R_GOTOFF_HI_SLO 63 /* High 16 bit offset to GOT + with signed low */ +#define R_M32R_GOTOFF_LO 64 /* Low 16 bit offset to GOT */ +#define R_M32R_NUM 256 /* Keep this the last entry. */ + +/* MicroBlaze relocations */ +#define R_MICROBLAZE_NONE 0 /* No reloc. */ +#define R_MICROBLAZE_32 1 /* Direct 32 bit. */ +#define R_MICROBLAZE_32_PCREL 2 /* PC relative 32 bit. */ +#define R_MICROBLAZE_64_PCREL 3 /* PC relative 64 bit. */ +#define R_MICROBLAZE_32_PCREL_LO 4 /* Low 16 bits of PCREL32. */ +#define R_MICROBLAZE_64 5 /* Direct 64 bit. */ +#define R_MICROBLAZE_32_LO 6 /* Low 16 bit. */ +#define R_MICROBLAZE_SRO32 7 /* Read-only small data area. */ +#define R_MICROBLAZE_SRW32 8 /* Read-write small data area. */ +#define R_MICROBLAZE_64_NONE 9 /* No reloc. */ +#define R_MICROBLAZE_32_SYM_OP_SYM 10 /* Symbol Op Symbol relocation. */ +#define R_MICROBLAZE_GNU_VTINHERIT 11 /* GNU C++ vtable hierarchy. */ +#define R_MICROBLAZE_GNU_VTENTRY 12 /* GNU C++ vtable member usage. */ +#define R_MICROBLAZE_GOTPC_64 13 /* PC-relative GOT offset. */ +#define R_MICROBLAZE_GOT_64 14 /* GOT entry offset. */ +#define R_MICROBLAZE_PLT_64 15 /* PLT offset (PC-relative). */ +#define R_MICROBLAZE_REL 16 /* Adjust by program base. */ +#define R_MICROBLAZE_JUMP_SLOT 17 /* Create PLT entry. */ +#define R_MICROBLAZE_GLOB_DAT 18 /* Create GOT entry. */ +#define R_MICROBLAZE_GOTOFF_64 19 /* 64 bit offset to GOT. */ +#define R_MICROBLAZE_GOTOFF_32 20 /* 32 bit offset to GOT. */ +#define R_MICROBLAZE_COPY 21 /* Runtime copy. */ +#define R_MICROBLAZE_TLS 22 /* TLS Reloc. */ +#define R_MICROBLAZE_TLSGD 23 /* TLS General Dynamic. */ +#define R_MICROBLAZE_TLSLD 24 /* TLS Local Dynamic. */ +#define R_MICROBLAZE_TLSDTPMOD32 25 /* TLS Module ID. */ +#define R_MICROBLAZE_TLSDTPREL32 26 /* TLS Offset Within TLS Block. */ +#define R_MICROBLAZE_TLSDTPREL64 27 /* TLS Offset Within TLS Block. */ +#define R_MICROBLAZE_TLSGOTTPREL32 28 /* TLS Offset From Thread Pointer. */ +#define R_MICROBLAZE_TLSTPREL32 29 /* TLS Offset From Thread Pointer. */ + +/* TILEPro relocations. */ +#define R_TILEPRO_NONE 0 /* No reloc */ +#define R_TILEPRO_32 1 /* Direct 32 bit */ +#define R_TILEPRO_16 2 /* Direct 16 bit */ +#define R_TILEPRO_8 3 /* Direct 8 bit */ +#define R_TILEPRO_32_PCREL 4 /* PC relative 32 bit */ +#define R_TILEPRO_16_PCREL 5 /* PC relative 16 bit */ +#define R_TILEPRO_8_PCREL 6 /* PC relative 8 bit */ +#define R_TILEPRO_LO16 7 /* Low 16 bit */ +#define R_TILEPRO_HI16 8 /* High 16 bit */ +#define R_TILEPRO_HA16 9 /* High 16 bit, adjusted */ +#define R_TILEPRO_COPY 10 /* Copy relocation */ +#define R_TILEPRO_GLOB_DAT 11 /* Create GOT entry */ +#define R_TILEPRO_JMP_SLOT 12 /* Create PLT entry */ +#define R_TILEPRO_RELATIVE 13 /* Adjust by program base */ +#define R_TILEPRO_BROFF_X1 14 /* X1 pipe branch offset */ +#define R_TILEPRO_JOFFLONG_X1 15 /* X1 pipe jump offset */ +#define R_TILEPRO_JOFFLONG_X1_PLT 16 /* X1 pipe jump offset to PLT */ +#define R_TILEPRO_IMM8_X0 17 /* X0 pipe 8-bit */ +#define R_TILEPRO_IMM8_Y0 18 /* Y0 pipe 8-bit */ +#define R_TILEPRO_IMM8_X1 19 /* X1 pipe 8-bit */ +#define R_TILEPRO_IMM8_Y1 20 /* Y1 pipe 8-bit */ +#define R_TILEPRO_MT_IMM15_X1 21 /* X1 pipe mtspr */ +#define R_TILEPRO_MF_IMM15_X1 22 /* X1 pipe mfspr */ +#define R_TILEPRO_IMM16_X0 23 /* X0 pipe 16-bit */ +#define R_TILEPRO_IMM16_X1 24 /* X1 pipe 16-bit */ +#define R_TILEPRO_IMM16_X0_LO 25 /* X0 pipe low 16-bit */ +#define R_TILEPRO_IMM16_X1_LO 26 /* X1 pipe low 16-bit */ +#define R_TILEPRO_IMM16_X0_HI 27 /* X0 pipe high 16-bit */ +#define R_TILEPRO_IMM16_X1_HI 28 /* X1 pipe high 16-bit */ +#define R_TILEPRO_IMM16_X0_HA 29 /* X0 pipe high 16-bit, adjusted */ +#define R_TILEPRO_IMM16_X1_HA 30 /* X1 pipe high 16-bit, adjusted */ +#define R_TILEPRO_IMM16_X0_PCREL 31 /* X0 pipe PC relative 16 bit */ +#define R_TILEPRO_IMM16_X1_PCREL 32 /* X1 pipe PC relative 16 bit */ +#define R_TILEPRO_IMM16_X0_LO_PCREL 33 /* X0 pipe PC relative low 16 bit */ +#define R_TILEPRO_IMM16_X1_LO_PCREL 34 /* X1 pipe PC relative low 16 bit */ +#define R_TILEPRO_IMM16_X0_HI_PCREL 35 /* X0 pipe PC relative high 16 bit */ +#define R_TILEPRO_IMM16_X1_HI_PCREL 36 /* X1 pipe PC relative high 16 bit */ +#define R_TILEPRO_IMM16_X0_HA_PCREL 37 /* X0 pipe PC relative ha() 16 bit */ +#define R_TILEPRO_IMM16_X1_HA_PCREL 38 /* X1 pipe PC relative ha() 16 bit */ +#define R_TILEPRO_IMM16_X0_GOT 39 /* X0 pipe 16-bit GOT offset */ +#define R_TILEPRO_IMM16_X1_GOT 40 /* X1 pipe 16-bit GOT offset */ +#define R_TILEPRO_IMM16_X0_GOT_LO 41 /* X0 pipe low 16-bit GOT offset */ +#define R_TILEPRO_IMM16_X1_GOT_LO 42 /* X1 pipe low 16-bit GOT offset */ +#define R_TILEPRO_IMM16_X0_GOT_HI 43 /* X0 pipe high 16-bit GOT offset */ +#define R_TILEPRO_IMM16_X1_GOT_HI 44 /* X1 pipe high 16-bit GOT offset */ +#define R_TILEPRO_IMM16_X0_GOT_HA 45 /* X0 pipe ha() 16-bit GOT offset */ +#define R_TILEPRO_IMM16_X1_GOT_HA 46 /* X1 pipe ha() 16-bit GOT offset */ +#define R_TILEPRO_MMSTART_X0 47 /* X0 pipe mm "start" */ +#define R_TILEPRO_MMEND_X0 48 /* X0 pipe mm "end" */ +#define R_TILEPRO_MMSTART_X1 49 /* X1 pipe mm "start" */ +#define R_TILEPRO_MMEND_X1 50 /* X1 pipe mm "end" */ +#define R_TILEPRO_SHAMT_X0 51 /* X0 pipe shift amount */ +#define R_TILEPRO_SHAMT_X1 52 /* X1 pipe shift amount */ +#define R_TILEPRO_SHAMT_Y0 53 /* Y0 pipe shift amount */ +#define R_TILEPRO_SHAMT_Y1 54 /* Y1 pipe shift amount */ +#define R_TILEPRO_DEST_IMM8_X1 55 /* X1 pipe destination 8-bit */ +/* Relocs 56-59 are currently not defined. */ +#define R_TILEPRO_TLS_GD_CALL 60 /* "jal" for TLS GD */ +#define R_TILEPRO_IMM8_X0_TLS_GD_ADD 61 /* X0 pipe "addi" for TLS GD */ +#define R_TILEPRO_IMM8_X1_TLS_GD_ADD 62 /* X1 pipe "addi" for TLS GD */ +#define R_TILEPRO_IMM8_Y0_TLS_GD_ADD 63 /* Y0 pipe "addi" for TLS GD */ +#define R_TILEPRO_IMM8_Y1_TLS_GD_ADD 64 /* Y1 pipe "addi" for TLS GD */ +#define R_TILEPRO_TLS_IE_LOAD 65 /* "lw_tls" for TLS IE */ +#define R_TILEPRO_IMM16_X0_TLS_GD 66 /* X0 pipe 16-bit TLS GD offset */ +#define R_TILEPRO_IMM16_X1_TLS_GD 67 /* X1 pipe 16-bit TLS GD offset */ +#define R_TILEPRO_IMM16_X0_TLS_GD_LO 68 /* X0 pipe low 16-bit TLS GD offset */ +#define R_TILEPRO_IMM16_X1_TLS_GD_LO 69 /* X1 pipe low 16-bit TLS GD offset */ +#define R_TILEPRO_IMM16_X0_TLS_GD_HI 70 /* X0 pipe high 16-bit TLS GD offset */ +#define R_TILEPRO_IMM16_X1_TLS_GD_HI 71 /* X1 pipe high 16-bit TLS GD offset */ +#define R_TILEPRO_IMM16_X0_TLS_GD_HA 72 /* X0 pipe ha() 16-bit TLS GD offset */ +#define R_TILEPRO_IMM16_X1_TLS_GD_HA 73 /* X1 pipe ha() 16-bit TLS GD offset */ +#define R_TILEPRO_IMM16_X0_TLS_IE 74 /* X0 pipe 16-bit TLS IE offset */ +#define R_TILEPRO_IMM16_X1_TLS_IE 75 /* X1 pipe 16-bit TLS IE offset */ +#define R_TILEPRO_IMM16_X0_TLS_IE_LO 76 /* X0 pipe low 16-bit TLS IE offset */ +#define R_TILEPRO_IMM16_X1_TLS_IE_LO 77 /* X1 pipe low 16-bit TLS IE offset */ +#define R_TILEPRO_IMM16_X0_TLS_IE_HI 78 /* X0 pipe high 16-bit TLS IE offset */ +#define R_TILEPRO_IMM16_X1_TLS_IE_HI 79 /* X1 pipe high 16-bit TLS IE offset */ +#define R_TILEPRO_IMM16_X0_TLS_IE_HA 80 /* X0 pipe ha() 16-bit TLS IE offset */ +#define R_TILEPRO_IMM16_X1_TLS_IE_HA 81 /* X1 pipe ha() 16-bit TLS IE offset */ +#define R_TILEPRO_TLS_DTPMOD32 82 /* ID of module containing symbol */ +#define R_TILEPRO_TLS_DTPOFF32 83 /* Offset in TLS block */ +#define R_TILEPRO_TLS_TPOFF32 84 /* Offset in static TLS block */ +#define R_TILEPRO_IMM16_X0_TLS_LE 85 /* X0 pipe 16-bit TLS LE offset */ +#define R_TILEPRO_IMM16_X1_TLS_LE 86 /* X1 pipe 16-bit TLS LE offset */ +#define R_TILEPRO_IMM16_X0_TLS_LE_LO 87 /* X0 pipe low 16-bit TLS LE offset */ +#define R_TILEPRO_IMM16_X1_TLS_LE_LO 88 /* X1 pipe low 16-bit TLS LE offset */ +#define R_TILEPRO_IMM16_X0_TLS_LE_HI 89 /* X0 pipe high 16-bit TLS LE offset */ +#define R_TILEPRO_IMM16_X1_TLS_LE_HI 90 /* X1 pipe high 16-bit TLS LE offset */ +#define R_TILEPRO_IMM16_X0_TLS_LE_HA 91 /* X0 pipe ha() 16-bit TLS LE offset */ +#define R_TILEPRO_IMM16_X1_TLS_LE_HA 92 /* X1 pipe ha() 16-bit TLS LE offset */ + +#define R_TILEPRO_GNU_VTINHERIT 128 /* GNU C++ vtable hierarchy */ +#define R_TILEPRO_GNU_VTENTRY 129 /* GNU C++ vtable member usage */ + +#define R_TILEPRO_NUM 130 + + +/* TILE-Gx relocations. */ +#define R_TILEGX_NONE 0 /* No reloc */ +#define R_TILEGX_64 1 /* Direct 64 bit */ +#define R_TILEGX_32 2 /* Direct 32 bit */ +#define R_TILEGX_16 3 /* Direct 16 bit */ +#define R_TILEGX_8 4 /* Direct 8 bit */ +#define R_TILEGX_64_PCREL 5 /* PC relative 64 bit */ +#define R_TILEGX_32_PCREL 6 /* PC relative 32 bit */ +#define R_TILEGX_16_PCREL 7 /* PC relative 16 bit */ +#define R_TILEGX_8_PCREL 8 /* PC relative 8 bit */ +#define R_TILEGX_HW0 9 /* hword 0 16-bit */ +#define R_TILEGX_HW1 10 /* hword 1 16-bit */ +#define R_TILEGX_HW2 11 /* hword 2 16-bit */ +#define R_TILEGX_HW3 12 /* hword 3 16-bit */ +#define R_TILEGX_HW0_LAST 13 /* last hword 0 16-bit */ +#define R_TILEGX_HW1_LAST 14 /* last hword 1 16-bit */ +#define R_TILEGX_HW2_LAST 15 /* last hword 2 16-bit */ +#define R_TILEGX_COPY 16 /* Copy relocation */ +#define R_TILEGX_GLOB_DAT 17 /* Create GOT entry */ +#define R_TILEGX_JMP_SLOT 18 /* Create PLT entry */ +#define R_TILEGX_RELATIVE 19 /* Adjust by program base */ +#define R_TILEGX_BROFF_X1 20 /* X1 pipe branch offset */ +#define R_TILEGX_JUMPOFF_X1 21 /* X1 pipe jump offset */ +#define R_TILEGX_JUMPOFF_X1_PLT 22 /* X1 pipe jump offset to PLT */ +#define R_TILEGX_IMM8_X0 23 /* X0 pipe 8-bit */ +#define R_TILEGX_IMM8_Y0 24 /* Y0 pipe 8-bit */ +#define R_TILEGX_IMM8_X1 25 /* X1 pipe 8-bit */ +#define R_TILEGX_IMM8_Y1 26 /* Y1 pipe 8-bit */ +#define R_TILEGX_DEST_IMM8_X1 27 /* X1 pipe destination 8-bit */ +#define R_TILEGX_MT_IMM14_X1 28 /* X1 pipe mtspr */ +#define R_TILEGX_MF_IMM14_X1 29 /* X1 pipe mfspr */ +#define R_TILEGX_MMSTART_X0 30 /* X0 pipe mm "start" */ +#define R_TILEGX_MMEND_X0 31 /* X0 pipe mm "end" */ +#define R_TILEGX_SHAMT_X0 32 /* X0 pipe shift amount */ +#define R_TILEGX_SHAMT_X1 33 /* X1 pipe shift amount */ +#define R_TILEGX_SHAMT_Y0 34 /* Y0 pipe shift amount */ +#define R_TILEGX_SHAMT_Y1 35 /* Y1 pipe shift amount */ +#define R_TILEGX_IMM16_X0_HW0 36 /* X0 pipe hword 0 */ +#define R_TILEGX_IMM16_X1_HW0 37 /* X1 pipe hword 0 */ +#define R_TILEGX_IMM16_X0_HW1 38 /* X0 pipe hword 1 */ +#define R_TILEGX_IMM16_X1_HW1 39 /* X1 pipe hword 1 */ +#define R_TILEGX_IMM16_X0_HW2 40 /* X0 pipe hword 2 */ +#define R_TILEGX_IMM16_X1_HW2 41 /* X1 pipe hword 2 */ +#define R_TILEGX_IMM16_X0_HW3 42 /* X0 pipe hword 3 */ +#define R_TILEGX_IMM16_X1_HW3 43 /* X1 pipe hword 3 */ +#define R_TILEGX_IMM16_X0_HW0_LAST 44 /* X0 pipe last hword 0 */ +#define R_TILEGX_IMM16_X1_HW0_LAST 45 /* X1 pipe last hword 0 */ +#define R_TILEGX_IMM16_X0_HW1_LAST 46 /* X0 pipe last hword 1 */ +#define R_TILEGX_IMM16_X1_HW1_LAST 47 /* X1 pipe last hword 1 */ +#define R_TILEGX_IMM16_X0_HW2_LAST 48 /* X0 pipe last hword 2 */ +#define R_TILEGX_IMM16_X1_HW2_LAST 49 /* X1 pipe last hword 2 */ +#define R_TILEGX_IMM16_X0_HW0_PCREL 50 /* X0 pipe PC relative hword 0 */ +#define R_TILEGX_IMM16_X1_HW0_PCREL 51 /* X1 pipe PC relative hword 0 */ +#define R_TILEGX_IMM16_X0_HW1_PCREL 52 /* X0 pipe PC relative hword 1 */ +#define R_TILEGX_IMM16_X1_HW1_PCREL 53 /* X1 pipe PC relative hword 1 */ +#define R_TILEGX_IMM16_X0_HW2_PCREL 54 /* X0 pipe PC relative hword 2 */ +#define R_TILEGX_IMM16_X1_HW2_PCREL 55 /* X1 pipe PC relative hword 2 */ +#define R_TILEGX_IMM16_X0_HW3_PCREL 56 /* X0 pipe PC relative hword 3 */ +#define R_TILEGX_IMM16_X1_HW3_PCREL 57 /* X1 pipe PC relative hword 3 */ +#define R_TILEGX_IMM16_X0_HW0_LAST_PCREL 58 /* X0 pipe PC-rel last hword 0 */ +#define R_TILEGX_IMM16_X1_HW0_LAST_PCREL 59 /* X1 pipe PC-rel last hword 0 */ +#define R_TILEGX_IMM16_X0_HW1_LAST_PCREL 60 /* X0 pipe PC-rel last hword 1 */ +#define R_TILEGX_IMM16_X1_HW1_LAST_PCREL 61 /* X1 pipe PC-rel last hword 1 */ +#define R_TILEGX_IMM16_X0_HW2_LAST_PCREL 62 /* X0 pipe PC-rel last hword 2 */ +#define R_TILEGX_IMM16_X1_HW2_LAST_PCREL 63 /* X1 pipe PC-rel last hword 2 */ +#define R_TILEGX_IMM16_X0_HW0_GOT 64 /* X0 pipe hword 0 GOT offset */ +#define R_TILEGX_IMM16_X1_HW0_GOT 65 /* X1 pipe hword 0 GOT offset */ +#define R_TILEGX_IMM16_X0_HW0_PLT_PCREL 66 /* X0 pipe PC-rel PLT hword 0 */ +#define R_TILEGX_IMM16_X1_HW0_PLT_PCREL 67 /* X1 pipe PC-rel PLT hword 0 */ +#define R_TILEGX_IMM16_X0_HW1_PLT_PCREL 68 /* X0 pipe PC-rel PLT hword 1 */ +#define R_TILEGX_IMM16_X1_HW1_PLT_PCREL 69 /* X1 pipe PC-rel PLT hword 1 */ +#define R_TILEGX_IMM16_X0_HW2_PLT_PCREL 70 /* X0 pipe PC-rel PLT hword 2 */ +#define R_TILEGX_IMM16_X1_HW2_PLT_PCREL 71 /* X1 pipe PC-rel PLT hword 2 */ +#define R_TILEGX_IMM16_X0_HW0_LAST_GOT 72 /* X0 pipe last hword 0 GOT offset */ +#define R_TILEGX_IMM16_X1_HW0_LAST_GOT 73 /* X1 pipe last hword 0 GOT offset */ +#define R_TILEGX_IMM16_X0_HW1_LAST_GOT 74 /* X0 pipe last hword 1 GOT offset */ +#define R_TILEGX_IMM16_X1_HW1_LAST_GOT 75 /* X1 pipe last hword 1 GOT offset */ +#define R_TILEGX_IMM16_X0_HW3_PLT_PCREL 76 /* X0 pipe PC-rel PLT hword 3 */ +#define R_TILEGX_IMM16_X1_HW3_PLT_PCREL 77 /* X1 pipe PC-rel PLT hword 3 */ +#define R_TILEGX_IMM16_X0_HW0_TLS_GD 78 /* X0 pipe hword 0 TLS GD offset */ +#define R_TILEGX_IMM16_X1_HW0_TLS_GD 79 /* X1 pipe hword 0 TLS GD offset */ +#define R_TILEGX_IMM16_X0_HW0_TLS_LE 80 /* X0 pipe hword 0 TLS LE offset */ +#define R_TILEGX_IMM16_X1_HW0_TLS_LE 81 /* X1 pipe hword 0 TLS LE offset */ +#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE 82 /* X0 pipe last hword 0 LE off */ +#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE 83 /* X1 pipe last hword 0 LE off */ +#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE 84 /* X0 pipe last hword 1 LE off */ +#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE 85 /* X1 pipe last hword 1 LE off */ +#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD 86 /* X0 pipe last hword 0 GD off */ +#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD 87 /* X1 pipe last hword 0 GD off */ +#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD 88 /* X0 pipe last hword 1 GD off */ +#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD 89 /* X1 pipe last hword 1 GD off */ +/* Relocs 90-91 are currently not defined. */ +#define R_TILEGX_IMM16_X0_HW0_TLS_IE 92 /* X0 pipe hword 0 TLS IE offset */ +#define R_TILEGX_IMM16_X1_HW0_TLS_IE 93 /* X1 pipe hword 0 TLS IE offset */ +#define R_TILEGX_IMM16_X0_HW0_LAST_PLT_PCREL 94 /* X0 pipe PC-rel PLT last hword 0 */ +#define R_TILEGX_IMM16_X1_HW0_LAST_PLT_PCREL 95 /* X1 pipe PC-rel PLT last hword 0 */ +#define R_TILEGX_IMM16_X0_HW1_LAST_PLT_PCREL 96 /* X0 pipe PC-rel PLT last hword 1 */ +#define R_TILEGX_IMM16_X1_HW1_LAST_PLT_PCREL 97 /* X1 pipe PC-rel PLT last hword 1 */ +#define R_TILEGX_IMM16_X0_HW2_LAST_PLT_PCREL 98 /* X0 pipe PC-rel PLT last hword 2 */ +#define R_TILEGX_IMM16_X1_HW2_LAST_PLT_PCREL 99 /* X1 pipe PC-rel PLT last hword 2 */ +#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE 100 /* X0 pipe last hword 0 IE off */ +#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE 101 /* X1 pipe last hword 0 IE off */ +#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE 102 /* X0 pipe last hword 1 IE off */ +#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE 103 /* X1 pipe last hword 1 IE off */ +/* Relocs 104-105 are currently not defined. */ +#define R_TILEGX_TLS_DTPMOD64 106 /* 64-bit ID of symbol's module */ +#define R_TILEGX_TLS_DTPOFF64 107 /* 64-bit offset in TLS block */ +#define R_TILEGX_TLS_TPOFF64 108 /* 64-bit offset in static TLS block */ +#define R_TILEGX_TLS_DTPMOD32 109 /* 32-bit ID of symbol's module */ +#define R_TILEGX_TLS_DTPOFF32 110 /* 32-bit offset in TLS block */ +#define R_TILEGX_TLS_TPOFF32 111 /* 32-bit offset in static TLS block */ +#define R_TILEGX_TLS_GD_CALL 112 /* "jal" for TLS GD */ +#define R_TILEGX_IMM8_X0_TLS_GD_ADD 113 /* X0 pipe "addi" for TLS GD */ +#define R_TILEGX_IMM8_X1_TLS_GD_ADD 114 /* X1 pipe "addi" for TLS GD */ +#define R_TILEGX_IMM8_Y0_TLS_GD_ADD 115 /* Y0 pipe "addi" for TLS GD */ +#define R_TILEGX_IMM8_Y1_TLS_GD_ADD 116 /* Y1 pipe "addi" for TLS GD */ +#define R_TILEGX_TLS_IE_LOAD 117 /* "ld_tls" for TLS IE */ +#define R_TILEGX_IMM8_X0_TLS_ADD 118 /* X0 pipe "addi" for TLS GD/IE */ +#define R_TILEGX_IMM8_X1_TLS_ADD 119 /* X1 pipe "addi" for TLS GD/IE */ +#define R_TILEGX_IMM8_Y0_TLS_ADD 120 /* Y0 pipe "addi" for TLS GD/IE */ +#define R_TILEGX_IMM8_Y1_TLS_ADD 121 /* Y1 pipe "addi" for TLS GD/IE */ + +#define R_TILEGX_GNU_VTINHERIT 128 /* GNU C++ vtable hierarchy */ +#define R_TILEGX_GNU_VTENTRY 129 /* GNU C++ vtable member usage */ + +#define R_TILEGX_NUM 130 + + +__END_DECLS + +#endif /* elf.h */ diff --git a/3rdparty/elfutils/libelf/elf32/elf32.pro b/3rdparty/elfutils/libelf/elf32/elf32.pro new file mode 100644 index 0000000..3dcf8c0 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf32/elf32.pro @@ -0,0 +1,21 @@ +TEMPLATE = lib +CONFIG += staticlib +TARGET = ../../elf32 + +include(../../elfutils.pri) +include(../elfheaders.pri) + +SOURCES += \ + $$PWD/../elf32_checksum.c \ + $$PWD/../elf32_fsize.c \ + $$PWD/../elf32_getehdr.c \ + $$PWD/../elf32_getphdr.c \ + $$PWD/../elf32_getshdr.c \ + $$PWD/../elf32_newehdr.c \ + $$PWD/../elf32_newphdr.c \ + $$PWD/../elf32_offscn.c \ + $$PWD/../elf32_updatefile.c \ + $$PWD/../elf32_updatenull.c \ + $$PWD/../elf32_xlatetof.c \ + $$PWD/../elf32_xlatetom.c \ + diff --git a/3rdparty/elfutils/libelf/elf32_checksum.c b/3rdparty/elfutils/libelf/elf32_checksum.c new file mode 100644 index 0000000..4c59856 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf32_checksum.c @@ -0,0 +1,169 @@ +/* Compute simple checksum from permanent parts of the ELF file. + Copyright (C) 2002, 2003, 2004, 2005, 2009 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <endian.h> +#include <stdbool.h> +#include <stddef.h> +#include <string.h> + +#include "gelf.h" +#include "libelfP.h" +#include "elf-knowledge.h" + +#ifndef LIBELFBITS +# define LIBELFBITS 32 +#endif + + +#define process_block(crc, data) \ + __libelf_crc32 (crc, data->d_buf, data->d_size) + + +long int +elfw2(LIBELFBITS,checksum) (elf) + Elf *elf; +{ + size_t shstrndx; + Elf_Scn *scn; + long int result = 0; + unsigned char *ident; + bool same_byte_order; + + if (elf == NULL) + return -1l; + + /* Find the section header string table. */ + if (INTUSE(elf_getshdrstrndx) (elf, &shstrndx) < 0) + { + /* This can only happen if the ELF handle is not for real. */ + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return -1l; + } + + /* Determine whether the byte order of the file and that of the host + is the same. */ + ident = elf->state.ELFW(elf,LIBELFBITS).ehdr->e_ident; + same_byte_order = ((ident[EI_DATA] == ELFDATA2LSB + && __BYTE_ORDER == __LITTLE_ENDIAN) + || (ident[EI_DATA] == ELFDATA2MSB + && __BYTE_ORDER == __BIG_ENDIAN)); + + /* If we don't have native byte order, we will likely need to + convert the data with xlate functions. We do it upfront instead + of relocking mid-iteration. */ + if (!likely (same_byte_order)) + rwlock_wrlock (elf->lock); + else + rwlock_rdlock (elf->lock); + + /* Iterate over all sections to find those which are not strippable. */ + scn = NULL; + while ((scn = INTUSE(elf_nextscn) (elf, scn)) != NULL) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr; + Elf_Data *data; + + /* Get the section header. */ + shdr = INTUSE(gelf_getshdr) (scn, &shdr_mem); + if (shdr == NULL) + { + __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER); + result = -1l; + goto out; + } + + if (SECTION_STRIP_P (shdr, + INTUSE(elf_strptr) (elf, shstrndx, shdr->sh_name), + true)) + /* The section can be stripped. Don't use it. */ + continue; + + /* Do not look at NOBITS sections. */ + if (shdr->sh_type == SHT_NOBITS) + continue; + + /* To compute the checksum we need to get to the data. For + repeatable results we must use the external format. The data + we get with 'elf'getdata' might be changed for endianess + reasons. Therefore we use 'elf_rawdata' if possible. But + this function can fail if the data was constructed by the + program. In this case we have to use 'elf_getdata' and + eventually convert the data to the external format. */ + data = INTUSE(elf_rawdata) (scn, NULL); + if (data != NULL) + { + /* The raw data is available. */ + result = process_block (result, data); + + /* Maybe the user added more data. These blocks cannot be + read using 'elf_rawdata'. Simply proceed with looking + for more data block with 'elf_getdata'. */ + } + + /* Iterate through the list of data blocks. */ + while ((data = INTUSE(elf_getdata) (scn, data)) != NULL) + /* If the file byte order is the same as the host byte order + process the buffer directly. If the data is just a stream + of bytes which the library will not convert we can use it + as well. */ + if (likely (same_byte_order) || data->d_type == ELF_T_BYTE) + result = process_block (result, data); + else + { + /* Convert the data to file byte order. */ + if (INTUSE(elfw2(LIBELFBITS,xlatetof)) (data, data, ident[EI_DATA]) + == NULL) + { + result = -1l; + goto out; + } + + result = process_block (result, data); + + /* And convert it back. */ + if (INTUSE(elfw2(LIBELFBITS,xlatetom)) (data, data, ident[EI_DATA]) + == NULL) + { + result = -1l; + goto out; + } + } + } + + out: + rwlock_unlock (elf->lock); + return result; +} +INTDEF(elfw2(LIBELFBITS,checksum)) diff --git a/3rdparty/elfutils/libelf/elf32_fsize.c b/3rdparty/elfutils/libelf/elf32_fsize.c new file mode 100644 index 0000000..d7496fa --- /dev/null +++ b/3rdparty/elfutils/libelf/elf32_fsize.c @@ -0,0 +1,71 @@ +/* Return the size of an object file type. + Copyright (C) 1998, 1999, 2000, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libelf.h> +#include "libelfP.h" + +#ifndef LIBELFBITS +# define LIBELFBITS 32 +#endif + + +size_t +elfw2(LIBELFBITS, fsize) (type, count, version) + Elf_Type type; + size_t count; + unsigned int version; +{ + /* We do not have differences between file and memory sizes. Better + not since otherwise `mmap' would not work. */ + if (unlikely (version == EV_NONE) || unlikely (version >= EV_NUM)) + { + __libelf_seterrno (ELF_E_UNKNOWN_VERSION); + return 0; + } + + if (unlikely (type >= ELF_T_NUM)) + { + __libelf_seterrno (ELF_E_UNKNOWN_TYPE); + return 0; + } + +#if EV_NUM != 2 + return (count + * __libelf_type_sizes[version - 1][ELFW(ELFCLASS,LIBELFBITS) - 1][type]); +#else + return (count + * __libelf_type_sizes[0][ELFW(ELFCLASS,LIBELFBITS) - 1][type]); +#endif +} +#define local_strong_alias(n1, n2) strong_alias (n1, n2) +local_strong_alias (elfw2(LIBELFBITS, fsize), __elfw2(LIBELFBITS, msize)) diff --git a/3rdparty/elfutils/libelf/elf32_getehdr.c b/3rdparty/elfutils/libelf/elf32_getehdr.c new file mode 100644 index 0000000..ee0a2e0 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf32_getehdr.c @@ -0,0 +1,99 @@ +/* Get ELF header. + Copyright (C) 1998, 1999, 2000, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libelf.h> +#include <stddef.h> + +#include "libelfP.h" + +#ifndef LIBELFBITS +# define LIBELFBITS 32 +#endif + + +static ElfW2(LIBELFBITS,Ehdr) * +getehdr_impl (elf, wrlock) + Elf *elf; + int wrlock; +{ + if (elf == NULL) + return NULL; + + if (unlikely (elf->kind != ELF_K_ELF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + again: + if (elf->class == 0) + { + if (!wrlock) + { + rwlock_unlock (elf->lock); + rwlock_wrlock (elf->lock); + wrlock = 1; + goto again; + } + elf->class = ELFW(ELFCLASS,LIBELFBITS); + } + else if (unlikely (elf->class != ELFW(ELFCLASS,LIBELFBITS))) + { + __libelf_seterrno (ELF_E_INVALID_CLASS); + return NULL; + } + + return elf->state.ELFW(elf,LIBELFBITS).ehdr; +} + +ElfW2(LIBELFBITS,Ehdr) * +__elfw2(LIBELFBITS,getehdr_wrlock) (elf) + Elf *elf; +{ + return getehdr_impl (elf, 1); +} + +ElfW2(LIBELFBITS,Ehdr) * +elfw2(LIBELFBITS,getehdr) (elf) + Elf *elf; +{ + ElfW2(LIBELFBITS,Ehdr) *result; + if (elf == NULL) + return NULL; + + rwlock_rdlock (elf->lock); + result = getehdr_impl (elf, 0); + rwlock_unlock (elf->lock); + + return result; +} diff --git a/3rdparty/elfutils/libelf/elf32_getphdr.c b/3rdparty/elfutils/libelf/elf32_getphdr.c new file mode 100644 index 0000000..1b82a48 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf32_getphdr.c @@ -0,0 +1,257 @@ +/* Get ELF program header table. + Copyright (C) 1998-2010, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <errno.h> +#include <stdbool.h> +#include <stdlib.h> +#include <unistd.h> +#include <assert.h> + +#include <system.h> +#include "libelfP.h" +#include "common.h" + +#ifndef LIBELFBITS +# define LIBELFBITS 32 +#endif + +ElfW2(LIBELFBITS,Phdr) * +__elfw2(LIBELFBITS,getphdr_wrlock) (elf) + Elf *elf; +{ + ElfW2(LIBELFBITS,Phdr) *result; + + /* If the program header entry has already been filled in the code + below must already have been run. So the class is set, too. No + need to waste any more time here. */ + result = elf->state.ELFW(elf,LIBELFBITS).phdr; + if (likely (result != NULL)) + return result; + + if (elf->class == 0) + elf->class = ELFW(ELFCLASS,LIBELFBITS); + else if (elf->class != ELFW(ELFCLASS,LIBELFBITS)) + { + __libelf_seterrno (ELF_E_INVALID_CLASS); + result = NULL; + goto out; + } + + if (likely (result == NULL)) + { + /* Read the section header table. */ + ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr; + + /* If no program header exists return NULL. */ + size_t phnum; + if (__elf_getphdrnum_rdlock (elf, &phnum) != 0) + goto out; + if (phnum == 0 || ehdr->e_phoff == 0) + { + __libelf_seterrno (ELF_E_NO_PHDR); + goto out; + } + + /* Check this doesn't overflow. */ + size_t size = phnum * sizeof (ElfW2(LIBELFBITS,Phdr)); + + if (phnum > SIZE_MAX / sizeof (ElfW2(LIBELFBITS,Phdr)) + || ehdr->e_phoff > elf->maximum_size + || elf->maximum_size - ehdr->e_phoff < size) + { + __libelf_seterrno (ELF_E_INVALID_DATA); + goto out; + } + + if (elf->map_address != NULL) + { + /* First see whether the information in the ELF header is + valid and it does not ask for too much. */ + if (unlikely (ehdr->e_phoff >= elf->maximum_size) + || unlikely (elf->maximum_size - ehdr->e_phoff < size)) + { + /* Something is wrong. */ + __libelf_seterrno (ELF_E_INVALID_PHDR); + goto out; + } + + /* All the data is already mapped. Use it. */ + void *file_phdr = ((char *) elf->map_address + + elf->start_offset + ehdr->e_phoff); + if (ehdr->e_ident[EI_DATA] == MY_ELFDATA + && (ALLOW_UNALIGNED + || ((uintptr_t) file_phdr + & (__alignof__ (ElfW2(LIBELFBITS,Phdr)) - 1)) == 0)) + /* Simply use the mapped data. */ + elf->state.ELFW(elf,LIBELFBITS).phdr = file_phdr; + else + { + ElfW2(LIBELFBITS,Phdr) *notcvt; + ElfW2(LIBELFBITS,Phdr) *phdr; + + /* Allocate memory for the program headers. We know the number + of entries from the ELF header. */ + phdr = elf->state.ELFW(elf,LIBELFBITS).phdr = + (ElfW2(LIBELFBITS,Phdr) *) malloc (size); + if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL) + { + __libelf_seterrno (ELF_E_NOMEM); + goto out; + } + elf->state.ELFW(elf,LIBELFBITS).phdr_flags |= + ELF_F_MALLOCED | ELF_F_DIRTY; + + /* Now copy the data and at the same time convert the + byte order. */ + + if (ehdr->e_ident[EI_DATA] == MY_ELFDATA) + { + assert (! ALLOW_UNALIGNED); + memcpy (phdr, file_phdr, size); + } + else + { + if (ALLOW_UNALIGNED + || ((uintptr_t) file_phdr + & (__alignof__ (ElfW2(LIBELFBITS,Phdr)) - 1)) == 0) + notcvt = file_phdr; + else + { + notcvt = (ElfW2(LIBELFBITS,Phdr) *) alloca (size); + memcpy (notcvt, file_phdr, size); + } + + for (size_t cnt = 0; cnt < phnum; ++cnt) + { + CONVERT_TO (phdr[cnt].p_type, notcvt[cnt].p_type); + CONVERT_TO (phdr[cnt].p_offset, notcvt[cnt].p_offset); + CONVERT_TO (phdr[cnt].p_vaddr, notcvt[cnt].p_vaddr); + CONVERT_TO (phdr[cnt].p_paddr, notcvt[cnt].p_paddr); + CONVERT_TO (phdr[cnt].p_filesz, notcvt[cnt].p_filesz); + CONVERT_TO (phdr[cnt].p_memsz, notcvt[cnt].p_memsz); + CONVERT_TO (phdr[cnt].p_flags, notcvt[cnt].p_flags); + CONVERT_TO (phdr[cnt].p_align, notcvt[cnt].p_align); + } + } + } + } + else if (likely (elf->fildes != -1)) + { + /* Allocate memory for the program headers. We know the number + of entries from the ELF header. */ + elf->state.ELFW(elf,LIBELFBITS).phdr = + (ElfW2(LIBELFBITS,Phdr) *) malloc (size); + if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL) + { + __libelf_seterrno (ELF_E_NOMEM); + goto out; + } + elf->state.ELFW(elf,LIBELFBITS).phdr_flags |= ELF_F_MALLOCED; + + /* Read the header. */ + ssize_t n = pread_retry (elf->fildes, + elf->state.ELFW(elf,LIBELFBITS).phdr, size, + elf->start_offset + ehdr->e_phoff); + if (unlikely ((size_t) n != size)) + { + /* Severe problems. We cannot read the data. */ + __libelf_seterrno (ELF_E_READ_ERROR); + free (elf->state.ELFW(elf,LIBELFBITS).phdr); + elf->state.ELFW(elf,LIBELFBITS).phdr = NULL; + goto out; + } + + /* If the byte order of the file is not the same as the one + of the host convert the data now. */ + if (ehdr->e_ident[EI_DATA] != MY_ELFDATA) + { + ElfW2(LIBELFBITS,Phdr) *phdr + = elf->state.ELFW(elf,LIBELFBITS).phdr; + + for (size_t cnt = 0; cnt < phnum; ++cnt) + { + CONVERT (phdr[cnt].p_type); + CONVERT (phdr[cnt].p_offset); + CONVERT (phdr[cnt].p_vaddr); + CONVERT (phdr[cnt].p_paddr); + CONVERT (phdr[cnt].p_filesz); + CONVERT (phdr[cnt].p_memsz); + CONVERT (phdr[cnt].p_flags); + CONVERT (phdr[cnt].p_align); + } + } + } + else + { + /* The file descriptor was already enabled and not all data was + read. */ + __libelf_seterrno (ELF_E_FD_DISABLED); + goto out; + } + + result = elf->state.ELFW(elf,LIBELFBITS).phdr; + } + + out: + return result; +} + +ElfW2(LIBELFBITS,Phdr) * +elfw2(LIBELFBITS,getphdr) (elf) + Elf *elf; +{ + ElfW2(LIBELFBITS,Phdr) *result; + + if (elf == NULL) + return NULL; + + if (unlikely (elf->kind != ELF_K_ELF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + /* If the program header entry has already been filled in the code + * in getphdr_wrlock must already have been run. So the class is + * set, too. No need to waste any more time here. */ + result = elf->state.ELFW(elf,LIBELFBITS).phdr; + if (likely (result != NULL)) + return result; + + rwlock_wrlock (elf->lock); + result = __elfw2(LIBELFBITS,getphdr_wrlock) (elf); + rwlock_unlock (elf->lock); + + return result; +} +INTDEF(elfw2(LIBELFBITS,getphdr)) diff --git a/3rdparty/elfutils/libelf/elf32_getshdr.c b/3rdparty/elfutils/libelf/elf32_getshdr.c new file mode 100644 index 0000000..7417047 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf32_getshdr.c @@ -0,0 +1,287 @@ +/* Return section header. + Copyright (C) 1998-2002, 2005, 2007, 2009, 2012, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <errno.h> +#include <stdbool.h> +#include <unistd.h> + +#include <system.h> +#include "libelfP.h" +#include "common.h" + +#ifndef LIBELFBITS +# define LIBELFBITS 32 +#endif + + +static ElfW2(LIBELFBITS,Shdr) * +load_shdr_wrlock (Elf_Scn *scn) +{ + ElfW2(LIBELFBITS,Shdr) *result; + + /* Read the section header table. */ + Elf *elf = scn->elf; + ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr; + + /* Try again, maybe the data is there now. */ + result = scn->shdr.ELFW(e,LIBELFBITS); + if (result != NULL) + goto out; + + size_t shnum; + if (__elf_getshdrnum_rdlock (elf, &shnum) != 0 + || shnum > SIZE_MAX / sizeof (ElfW2(LIBELFBITS,Shdr))) + goto out; + size_t size = shnum * sizeof (ElfW2(LIBELFBITS,Shdr)); + + /* Allocate memory for the section headers. We know the number + of entries from the ELF header. */ + ElfW2(LIBELFBITS,Shdr) *shdr = elf->state.ELFW(elf,LIBELFBITS).shdr = + (ElfW2(LIBELFBITS,Shdr) *) malloc (size); + if (elf->state.ELFW(elf,LIBELFBITS).shdr == NULL) + { + __libelf_seterrno (ELF_E_NOMEM); + goto out; + } + elf->state.ELFW(elf,LIBELFBITS).shdr_malloced = 1; + + if (elf->map_address != NULL) + { + /* First see whether the information in the ELF header is + valid and it does not ask for too much. */ + if (unlikely (ehdr->e_shoff >= elf->maximum_size) + || unlikely (elf->maximum_size - ehdr->e_shoff < size)) + { + /* Something is wrong. */ + __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER); + goto free_and_out; + } + + ElfW2(LIBELFBITS,Shdr) *notcvt; + + /* All the data is already mapped. If we could use it + directly this would already have happened. Unless + we allocated the memory ourselves and the ELF_F_MALLOCED + flag is set. */ + void *file_shdr = ((char *) elf->map_address + + elf->start_offset + ehdr->e_shoff); + + assert ((elf->flags & ELF_F_MALLOCED) + || ehdr->e_ident[EI_DATA] != MY_ELFDATA + || (! ALLOW_UNALIGNED + && ((uintptr_t) file_shdr + & (__alignof__ (ElfW2(LIBELFBITS,Shdr)) - 1)) != 0)); + + /* Now copy the data and at the same time convert the byte order. */ + if (ehdr->e_ident[EI_DATA] == MY_ELFDATA) + { + assert ((elf->flags & ELF_F_MALLOCED) || ! ALLOW_UNALIGNED); + memcpy (shdr, file_shdr, size); + } + else + { + if (ALLOW_UNALIGNED + || ((uintptr_t) file_shdr + & (__alignof__ (ElfW2(LIBELFBITS,Shdr)) - 1)) == 0) + notcvt = (ElfW2(LIBELFBITS,Shdr) *) + ((char *) elf->map_address + + elf->start_offset + ehdr->e_shoff); + else + { + notcvt = (ElfW2(LIBELFBITS,Shdr) *) alloca (size); + memcpy (notcvt, ((char *) elf->map_address + + elf->start_offset + ehdr->e_shoff), + size); + } + + for (size_t cnt = 0; cnt < shnum; ++cnt) + { + CONVERT_TO (shdr[cnt].sh_name, notcvt[cnt].sh_name); + CONVERT_TO (shdr[cnt].sh_type, notcvt[cnt].sh_type); + CONVERT_TO (shdr[cnt].sh_flags, notcvt[cnt].sh_flags); + CONVERT_TO (shdr[cnt].sh_addr, notcvt[cnt].sh_addr); + CONVERT_TO (shdr[cnt].sh_offset, notcvt[cnt].sh_offset); + CONVERT_TO (shdr[cnt].sh_size, notcvt[cnt].sh_size); + CONVERT_TO (shdr[cnt].sh_link, notcvt[cnt].sh_link); + CONVERT_TO (shdr[cnt].sh_info, notcvt[cnt].sh_info); + CONVERT_TO (shdr[cnt].sh_addralign, + notcvt[cnt].sh_addralign); + CONVERT_TO (shdr[cnt].sh_entsize, notcvt[cnt].sh_entsize); + + /* If this is a section with an extended index add a + reference in the section which uses the extended + index. */ + if (shdr[cnt].sh_type == SHT_SYMTAB_SHNDX + && shdr[cnt].sh_link < shnum) + elf->state.ELFW(elf,LIBELFBITS).scns.data[shdr[cnt].sh_link].shndx_index + = cnt; + + /* Set the own shndx_index field in case it has not yet + been set. */ + if (elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shndx_index == 0) + elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shndx_index + = -1; + } + } + } + else if (likely (elf->fildes != -1)) + { + /* Read the header. */ + ssize_t n = pread_retry (elf->fildes, + elf->state.ELFW(elf,LIBELFBITS).shdr, size, + elf->start_offset + ehdr->e_shoff); + if (unlikely ((size_t) n != size)) + { + /* Severe problems. We cannot read the data. */ + __libelf_seterrno (ELF_E_READ_ERROR); + goto free_and_out; + } + + /* If the byte order of the file is not the same as the one + of the host convert the data now. */ + if (ehdr->e_ident[EI_DATA] != MY_ELFDATA) + for (size_t cnt = 0; cnt < shnum; ++cnt) + { + CONVERT (shdr[cnt].sh_name); + CONVERT (shdr[cnt].sh_type); + CONVERT (shdr[cnt].sh_flags); + CONVERT (shdr[cnt].sh_addr); + CONVERT (shdr[cnt].sh_offset); + CONVERT (shdr[cnt].sh_size); + CONVERT (shdr[cnt].sh_link); + CONVERT (shdr[cnt].sh_info); + CONVERT (shdr[cnt].sh_addralign); + CONVERT (shdr[cnt].sh_entsize); + } + } + else + { + /* The file descriptor was already enabled and not all data was + read. Undo the allocation. */ + __libelf_seterrno (ELF_E_FD_DISABLED); + + free_and_out: + free (shdr); + elf->state.ELFW(elf,LIBELFBITS).shdr = NULL; + elf->state.ELFW(elf,LIBELFBITS).shdr_malloced = 0; + + goto out; + } + + /* Set the pointers in the `scn's. */ + for (size_t cnt = 0; cnt < shnum; ++cnt) + elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shdr.ELFW(e,LIBELFBITS) + = &elf->state.ELFW(elf,LIBELFBITS).shdr[cnt]; + + result = scn->shdr.ELFW(e,LIBELFBITS); + assert (result != NULL); + +out: + return result; +} + +static bool +scn_valid (Elf_Scn *scn) +{ + if (scn == NULL) + return false; + + if (unlikely (scn->elf->state.elf.ehdr == NULL)) + { + __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR); + return false; + } + + if (unlikely (scn->elf->class != ELFW(ELFCLASS,LIBELFBITS))) + { + __libelf_seterrno (ELF_E_INVALID_CLASS); + return false; + } + + return true; +} + +ElfW2(LIBELFBITS,Shdr) * +__elfw2(LIBELFBITS,getshdr_rdlock) (scn) + Elf_Scn *scn; +{ + ElfW2(LIBELFBITS,Shdr) *result; + + if (!scn_valid (scn)) + return NULL; + + result = scn->shdr.ELFW(e,LIBELFBITS); + if (result == NULL) + { + rwlock_unlock (scn->elf->lock); + rwlock_wrlock (scn->elf->lock); + result = scn->shdr.ELFW(e,LIBELFBITS); + if (result == NULL) + result = load_shdr_wrlock (scn); + } + + return result; +} + +ElfW2(LIBELFBITS,Shdr) * +__elfw2(LIBELFBITS,getshdr_wrlock) (scn) + Elf_Scn *scn; +{ + ElfW2(LIBELFBITS,Shdr) *result; + + if (!scn_valid (scn)) + return NULL; + + result = scn->shdr.ELFW(e,LIBELFBITS); + if (result == NULL) + result = load_shdr_wrlock (scn); + + return result; +} + +ElfW2(LIBELFBITS,Shdr) * +elfw2(LIBELFBITS,getshdr) (scn) + Elf_Scn *scn; +{ + ElfW2(LIBELFBITS,Shdr) *result; + + if (!scn_valid (scn)) + return NULL; + + rwlock_rdlock (scn->elf->lock); + result = __elfw2(LIBELFBITS,getshdr_rdlock) (scn); + rwlock_unlock (scn->elf->lock); + + return result; +} diff --git a/3rdparty/elfutils/libelf/elf32_newehdr.c b/3rdparty/elfutils/libelf/elf32_newehdr.c new file mode 100644 index 0000000..4b547bc --- /dev/null +++ b/3rdparty/elfutils/libelf/elf32_newehdr.c @@ -0,0 +1,92 @@ +/* Create new ELF header. + Copyright (C) 1998, 1999, 2000, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> +#include <string.h> + +#include "libelfP.h" + +#ifndef LIBELFBITS +# define LIBELFBITS 32 +#endif + + +ElfW2(LIBELFBITS,Ehdr) * +elfw2(LIBELFBITS,newehdr) (elf) + Elf *elf; +{ + ElfW2(LIBELFBITS,Ehdr) *result; + + if (elf == NULL) + return NULL; + + if (unlikely (elf->kind != ELF_K_ELF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + rwlock_wrlock (elf->lock); + + if (elf->class == 0) + elf->class = ELFW(ELFCLASS,LIBELFBITS); + else if (unlikely (elf->class != ELFW(ELFCLASS,LIBELFBITS))) + { + __libelf_seterrno (ELF_E_INVALID_CLASS); + result = NULL; + goto out; + } + + /* Don't create an ELF header if one already exists. */ + if (elf->state.ELFW(elf,LIBELFBITS).ehdr == NULL) + { + /* We use the memory in the ELF descriptor. */ + elf->state.ELFW(elf,LIBELFBITS).ehdr = + &elf->state.ELFW(elf,LIBELFBITS).ehdr_mem; + + /* We clear this memory. */ + memset (elf->state.ELFW(elf,LIBELFBITS).ehdr, '\0', + sizeof (ElfW2(LIBELFBITS,Ehdr))); + + /* Mark the ELF header has modified. */ + elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY; + } + + result = elf->state.ELFW(elf,LIBELFBITS).ehdr; + + out: + rwlock_unlock (elf->lock); + + return result; +} +INTDEF(elfw2(LIBELFBITS,newehdr)) diff --git a/3rdparty/elfutils/libelf/elf32_newphdr.c b/3rdparty/elfutils/libelf/elf32_newphdr.c new file mode 100644 index 0000000..01038e7 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf32_newphdr.c @@ -0,0 +1,182 @@ +/* Create new ELF program header table. + Copyright (C) 1999-2010, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +#include "libelfP.h" + +#ifndef LIBELFBITS +# define LIBELFBITS 32 +#endif + + +ElfW2(LIBELFBITS,Phdr) * +elfw2(LIBELFBITS,newphdr) (elf, count) + Elf *elf; + size_t count; +{ + ElfW2(LIBELFBITS,Phdr) *result; + + if (elf == NULL) + return NULL; + + if (unlikely (elf->kind != ELF_K_ELF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + if (unlikely ((ElfW2(LIBELFBITS,Word)) count != count)) + { + __libelf_seterrno (ELF_E_INVALID_OPERAND); + return NULL; + } + + rwlock_wrlock (elf->lock); + + if (elf->class == 0) + elf->class = ELFW(ELFCLASS,LIBELFBITS); + else if (unlikely (elf->class != ELFW(ELFCLASS,LIBELFBITS))) + { + __libelf_seterrno (ELF_E_INVALID_CLASS); + result = NULL; + goto out; + } + + if (unlikely (elf->state.ELFW(elf,LIBELFBITS).ehdr == NULL)) + { + __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR); + result = NULL; + goto out; + } + + /* A COUNT of zero means remove existing table. */ + if (count == 0) + { + /* Free the old program header. */ + if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL) + { + if (elf->state.ELFW(elf,LIBELFBITS).phdr_flags & ELF_F_MALLOCED) + free (elf->state.ELFW(elf,LIBELFBITS).phdr); + + /* Set the pointer to NULL. */ + elf->state.ELFW(elf,LIBELFBITS).phdr = NULL; + /* Set the `e_phnum' member to the new value. */ + elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phnum = 0; + /* Also clear any old PN_XNUM extended value. */ + if (elf->state.ELFW(elf,LIBELFBITS).scns.cnt > 0) + elf->state.ELFW(elf,LIBELFBITS).scns.data[0] + .shdr.ELFW(e,LIBELFBITS)->sh_info = 0; + /* Also set the size. */ + elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phentsize = + sizeof (ElfW2(LIBELFBITS,Phdr)); + + elf->state.ELFW(elf,LIBELFBITS).phdr_flags |= ELF_F_DIRTY; + elf->flags |= ELF_F_DIRTY; + __libelf_seterrno (ELF_E_NOERROR); + } + + result = NULL; + } + else if (elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phnum != count + || count == PN_XNUM + || elf->state.ELFW(elf,LIBELFBITS).phdr == NULL) + { + if (unlikely (count > SIZE_MAX / sizeof (ElfW2(LIBELFBITS,Phdr)))) + { + result = NULL; + goto out; + } + + /* Allocate a new program header with the appropriate number of + elements. */ + result = (ElfW2(LIBELFBITS,Phdr) *) + realloc (elf->state.ELFW(elf,LIBELFBITS).phdr, + count * sizeof (ElfW2(LIBELFBITS,Phdr))); + if (result == NULL) + __libelf_seterrno (ELF_E_NOMEM); + else + { + /* Now set the result. */ + elf->state.ELFW(elf,LIBELFBITS).phdr = result; + if (count >= PN_XNUM) + { + /* We have to write COUNT into the zeroth section's sh_info. */ + Elf_Scn *scn0 = &elf->state.ELFW(elf,LIBELFBITS).scns.data[0]; + if (elf->state.ELFW(elf,LIBELFBITS).scns.cnt == 0) + { + assert (elf->state.ELFW(elf,LIBELFBITS).scns.max > 0); + elf->state.ELFW(elf,LIBELFBITS).scns.cnt = 1; + } + scn0->shdr.ELFW(e,LIBELFBITS)->sh_info = count; + scn0->shdr_flags |= ELF_F_DIRTY; + elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phnum = PN_XNUM; + } + else + /* Set the `e_phnum' member to the new value. */ + elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phnum = count; + /* Clear the whole memory. */ + memset (result, '\0', count * sizeof (ElfW2(LIBELFBITS,Phdr))); + /* Also set the size. */ + elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phentsize = + elf_typesize (LIBELFBITS, ELF_T_PHDR, 1); + /* Remember we allocated the array and mark the structure is + modified. */ + elf->state.ELFW(elf,LIBELFBITS).phdr_flags |= + ELF_F_DIRTY | ELF_F_MALLOCED; + /* We have to rewrite the entire file if the size of the + program header is changed. */ + elf->flags |= ELF_F_DIRTY; + } + } + else + { + /* We have the same number of entries. Just clear the array. */ + assert (elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phentsize + == elf_typesize (LIBELFBITS, ELF_T_PHDR, 1)); + + /* Mark the structure as modified. */ + elf->state.ELFW(elf,LIBELFBITS).phdr_flags |= ELF_F_DIRTY; + + result = elf->state.ELFW(elf,LIBELFBITS).phdr; + memset (result, '\0', count * sizeof (ElfW2(LIBELFBITS,Phdr))); + } + + out: + rwlock_unlock (elf->lock); + + return result; +} +INTDEF(elfw2(LIBELFBITS,newphdr)) diff --git a/3rdparty/elfutils/libelf/elf32_offscn.c b/3rdparty/elfutils/libelf/elf32_offscn.c new file mode 100644 index 0000000..a1ff6d4 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf32_offscn.c @@ -0,0 +1,101 @@ +/* Get section at specific index. + Copyright (C) 2005, 2008 Red Hat, Inc. + This file is part of elfutils. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2005. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <stddef.h> +#include <stdlib.h> + +#include "libelfP.h" + +#ifndef LIBELFBITS +# define LIBELFBITS 32 +#endif + + +Elf_Scn * +elfw2(LIBELFBITS,offscn) (elf, offset) + Elf *elf; + ElfW2(LIBELFBITS,Off) offset; +{ + if (elf == NULL) + return NULL; + + if (unlikely (elf->kind != ELF_K_ELF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + Elf_ScnList *runp = &elf->state.ELFW(elf,LIBELFBITS).scns; + + /* If we have not looked at section headers before, + we might need to read them in first. */ + if (runp->cnt > 0 + && unlikely (runp->data[0].shdr.ELFW(e,LIBELFBITS) == NULL) + && unlikely (elfw2(LIBELFBITS,getshdr) (&runp->data[0]) == NULL)) + return NULL; + + rwlock_rdlock (elf->lock); + + Elf_Scn *result = NULL; + + /* Find the section in the list. */ + while (1) + { + for (unsigned int i = 0; i < runp->cnt; ++i) + if (runp->data[i].shdr.ELFW(e,LIBELFBITS)->sh_offset == offset) + { + result = &runp->data[i]; + + /* If this section is empty, the following one has the same + sh_offset. We presume the caller is looking for a nonempty + section, so keep looking if this one is empty. */ + if (runp->data[i].shdr.ELFW(e,LIBELFBITS)->sh_size != 0 + && runp->data[i].shdr.ELFW(e,LIBELFBITS)->sh_type != SHT_NOBITS) + goto out; + } + + runp = runp->next; + if (runp == NULL) + { + __libelf_seterrno (ELF_E_INVALID_OFFSET); + break; + } + } + + out: + rwlock_unlock (elf->lock); + + return result; +} +INTDEF(elfw2(LIBELFBITS,offscn)) diff --git a/3rdparty/elfutils/libelf/elf32_updatefile.c b/3rdparty/elfutils/libelf/elf32_updatefile.c new file mode 100644 index 0000000..153e377 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf32_updatefile.c @@ -0,0 +1,808 @@ +/* Write changed data structures. + Copyright (C) 2000-2010, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <errno.h> +#include <libelf.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/param.h> + +#include <system.h> +#include "libelfP.h" + + +#ifndef LIBELFBITS +# define LIBELFBITS 32 +#endif + + +static int +compare_sections (const void *a, const void *b) +{ + const Elf_Scn **scna = (const Elf_Scn **) a; + const Elf_Scn **scnb = (const Elf_Scn **) b; + + if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_offset + < (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_offset) + return -1; + + if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_offset + > (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_offset) + return 1; + + if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_size + < (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_size) + return -1; + + if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_size + > (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_size) + return 1; + + if ((*scna)->index < (*scnb)->index) + return -1; + + if ((*scna)->index > (*scnb)->index) + return 1; + + return 0; +} + + +/* Insert the sections in the list into the provided array and sort + them according to their start offsets. For sections with equal + start offsets, the size is used; for sections with equal start + offsets and sizes, the section index is used. Sorting by size + ensures that zero-length sections are processed first, which + is what we want since they do not advance our file writing position. */ +static void +sort_sections (Elf_Scn **scns, Elf_ScnList *list) +{ + Elf_Scn **scnp = scns; + do + for (size_t cnt = 0; cnt < list->cnt; ++cnt) + *scnp++ = &list->data[cnt]; + while ((list = list->next) != NULL); + + qsort (scns, scnp - scns, sizeof (*scns), compare_sections); +} + + +int +internal_function +__elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum) +{ + bool previous_scn_changed = false; + + /* We need the ELF header several times. */ + ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr; + + /* Write out the ELF header. */ + if ((elf->state.ELFW(elf,LIBELFBITS).ehdr_flags | elf->flags) & ELF_F_DIRTY) + { + /* If the type sizes should be different at some time we have to + rewrite this code. */ + assert (sizeof (ElfW2(LIBELFBITS,Ehdr)) + == elf_typesize (LIBELFBITS, ELF_T_EHDR, 1)); + + if (unlikely (change_bo)) + { + /* Today there is only one version of the ELF header. */ +#if EV_NUM != 2 + xfct_t fctp; + fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR]; +#else +# undef fctp +# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR] +#endif + + /* Do the real work. */ + (*fctp) ((char *) elf->map_address + elf->start_offset, ehdr, + sizeof (ElfW2(LIBELFBITS,Ehdr)), 1); + } + else if (elf->map_address + elf->start_offset != ehdr) + memcpy (elf->map_address + elf->start_offset, ehdr, + sizeof (ElfW2(LIBELFBITS,Ehdr))); + + elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY; + + /* We start writing sections after the ELF header only if there is + no program header. */ + previous_scn_changed = elf->state.ELFW(elf,LIBELFBITS).phdr == NULL; + } + + size_t phnum; + if (unlikely (__elf_getphdrnum_rdlock (elf, &phnum) != 0)) + return -1; + + /* Write out the program header table. */ + if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL + && ((elf->state.ELFW(elf,LIBELFBITS).phdr_flags | elf->flags) + & ELF_F_DIRTY)) + { + /* If the type sizes should be different at some time we have to + rewrite this code. */ + assert (sizeof (ElfW2(LIBELFBITS,Phdr)) + == elf_typesize (LIBELFBITS, ELF_T_PHDR, 1)); + + /* Maybe the user wants a gap between the ELF header and the program + header. */ + if (ehdr->e_phoff > ehdr->e_ehsize) + memset (elf->map_address + elf->start_offset + ehdr->e_ehsize, + __libelf_fill_byte, ehdr->e_phoff - ehdr->e_ehsize); + + if (unlikely (change_bo)) + { + /* Today there is only one version of the ELF header. */ +#if EV_NUM != 2 + xfct_t fctp; + fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR]; +#else +# undef fctp +# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR] +#endif + + /* Do the real work. */ + (*fctp) (elf->map_address + elf->start_offset + ehdr->e_phoff, + elf->state.ELFW(elf,LIBELFBITS).phdr, + sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum, 1); + } + else + memcpy (elf->map_address + elf->start_offset + ehdr->e_phoff, + elf->state.ELFW(elf,LIBELFBITS).phdr, + sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum); + + elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY; + + /* We modified the program header. Maybe this created a gap so + we have to write fill bytes, if necessary. */ + previous_scn_changed = true; + } + + /* From now on we have to keep track of the last position to eventually + fill the gaps with the prescribed fill byte. */ + char *last_position = ((char *) elf->map_address + elf->start_offset + + MAX (elf_typesize (LIBELFBITS, ELF_T_EHDR, 1), + ehdr->e_phoff) + + elf_typesize (LIBELFBITS, ELF_T_PHDR, phnum)); + + /* Write all the sections. Well, only those which are modified. */ + if (shnum > 0) + { + if (unlikely (shnum > SIZE_MAX / sizeof (Elf_Scn *))) + return 1; + + Elf_ScnList *list = &elf->state.ELFW(elf,LIBELFBITS).scns; + Elf_Scn **scns = (Elf_Scn **) alloca (shnum * sizeof (Elf_Scn *)); + char *const shdr_start = ((char *) elf->map_address + elf->start_offset + + ehdr->e_shoff); + char *const shdr_end = shdr_start + ehdr->e_shnum * ehdr->e_shentsize; + +#if EV_NUM != 2 + xfct_t shdr_fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]; +#else +# undef shdr_fctp +# define shdr_fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR] +#endif +#define shdr_dest ((ElfW2(LIBELFBITS,Shdr) *) shdr_start) + + /* Get all sections into the array and sort them. */ + sort_sections (scns, list); + + /* We possibly have to copy the section header data because moving + the sections might overwrite the data. */ + for (size_t cnt = 0; cnt < shnum; ++cnt) + { + Elf_Scn *scn = scns[cnt]; + + if (!elf->state.ELFW(elf,LIBELFBITS).shdr_malloced + && (scn->shdr_flags & ELF_F_MALLOCED) == 0 + && scn->shdr.ELFW(e,LIBELFBITS) != &shdr_dest[scn->index]) + { + assert ((char *) elf->map_address + elf->start_offset + < (char *) scn->shdr.ELFW(e,LIBELFBITS)); + assert ((char *) scn->shdr.ELFW(e,LIBELFBITS) + < ((char *) elf->map_address + elf->start_offset + + elf->maximum_size)); + + void *p = alloca (sizeof (ElfW2(LIBELFBITS,Shdr))); + scn->shdr.ELFW(e,LIBELFBITS) + = memcpy (p, scn->shdr.ELFW(e,LIBELFBITS), + sizeof (ElfW2(LIBELFBITS,Shdr))); + } + + /* If the file is mmaped and the original position of the + section in the file is lower than the new position we + need to save the section content since otherwise it is + overwritten before it can be copied. If there are + multiple data segments in the list only the first can be + from the file. */ + if (((char *) elf->map_address + elf->start_offset + <= (char *) scn->data_list.data.d.d_buf) + && ((char *) scn->data_list.data.d.d_buf + < ((char *) elf->map_address + elf->start_offset + + elf->maximum_size)) + && (((char *) elf->map_address + elf->start_offset + + scn->shdr.ELFW(e,LIBELFBITS)->sh_offset) + > (char *) scn->data_list.data.d.d_buf)) + { + void *p = malloc (scn->data_list.data.d.d_size); + if (p == NULL) + { + __libelf_seterrno (ELF_E_NOMEM); + return -1; + } + scn->data_list.data.d.d_buf = scn->data_base + = memcpy (p, scn->data_list.data.d.d_buf, + scn->data_list.data.d.d_size); + } + } + + /* Iterate over all the section in the order in which they + appear in the output file. */ + for (size_t cnt = 0; cnt < shnum; ++cnt) + { + Elf_Scn *scn = scns[cnt]; + if (scn->index == 0) + { + /* The dummy section header entry. It should not be + possible to mark this "section" as dirty. */ + assert ((scn->flags & ELF_F_DIRTY) == 0); + continue; + } + + ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS); + if (shdr->sh_type == SHT_NOBITS) + goto next; + + char *scn_start = ((char *) elf->map_address + + elf->start_offset + shdr->sh_offset); + Elf_Data_List *dl = &scn->data_list; + bool scn_changed = false; + + void fill_mmap (size_t offset) + { + size_t written = 0; + + if (last_position < shdr_start) + { + written = MIN (scn_start + offset - last_position, + shdr_start - last_position); + + memset (last_position, __libelf_fill_byte, written); + } + + if (last_position + written != scn_start + offset + && shdr_end < scn_start + offset) + { + char *fill_start = MAX (shdr_end, scn_start); + memset (fill_start, __libelf_fill_byte, + scn_start + offset - fill_start); + } + } + + if (scn->data_list_rear != NULL) + do + { + assert (dl->data.d.d_off >= 0); + assert ((GElf_Off) dl->data.d.d_off <= shdr->sh_size); + assert (dl->data.d.d_size <= (shdr->sh_size + - (GElf_Off) dl->data.d.d_off)); + + /* If there is a gap, fill it. */ + if (scn_start + dl->data.d.d_off > last_position + && (dl->data.d.d_off == 0 + || ((scn->flags | dl->flags | elf->flags) + & ELF_F_DIRTY) != 0)) + { + fill_mmap (dl->data.d.d_off); + last_position = scn_start + dl->data.d.d_off; + } + + if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY) + { + /* Let it go backward if the sections use a bogus + layout with overlaps. We'll overwrite the stupid + user's section data with the latest one, rather than + crashing. */ + + last_position = scn_start + dl->data.d.d_off; + + if (unlikely (change_bo)) + { +#if EV_NUM != 2 + xfct_t fctp; + fctp = __elf_xfctstom[__libelf_version - 1][dl->data.d.d_version - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]; +#else +# undef fctp +# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type] +#endif + + /* Do the real work. */ + (*fctp) (last_position, dl->data.d.d_buf, + dl->data.d.d_size, 1); + + last_position += dl->data.d.d_size; + } + else + last_position = mempcpy (last_position, + dl->data.d.d_buf, + dl->data.d.d_size); + + scn_changed = true; + } + else + last_position += dl->data.d.d_size; + + assert (scn_start + dl->data.d.d_off + dl->data.d.d_size + == last_position); + + dl->flags &= ~ELF_F_DIRTY; + + dl = dl->next; + } + while (dl != NULL); + else + { + /* If the previous section (or the ELF/program + header) changed we might have to fill the gap. */ + if (scn_start > last_position && previous_scn_changed) + fill_mmap (0); + + /* We have to trust the existing section header information. */ + last_position = scn_start + shdr->sh_size; + } + + + previous_scn_changed = scn_changed; + next: + scn->flags &= ~ELF_F_DIRTY; + } + + /* Fill the gap between last section and section header table if + necessary. */ + if ((elf->flags & ELF_F_DIRTY) + && last_position < ((char *) elf->map_address + elf->start_offset + + ehdr->e_shoff)) + memset (last_position, __libelf_fill_byte, + (char *) elf->map_address + elf->start_offset + ehdr->e_shoff + - last_position); + + /* Write the section header table entry if necessary. */ + for (size_t cnt = 0; cnt < shnum; ++cnt) + { + Elf_Scn *scn = scns[cnt]; + + if ((scn->shdr_flags | elf->flags) & ELF_F_DIRTY) + { + if (unlikely (change_bo)) + (*shdr_fctp) (&shdr_dest[scn->index], + scn->shdr.ELFW(e,LIBELFBITS), + sizeof (ElfW2(LIBELFBITS,Shdr)), 1); + else + memcpy (&shdr_dest[scn->index], + scn->shdr.ELFW(e,LIBELFBITS), + sizeof (ElfW2(LIBELFBITS,Shdr))); + + /* If we previously made a copy of the section header + entry we now have to adjust the pointer again so + point to new place in the mapping. */ + if (!elf->state.ELFW(elf,LIBELFBITS).shdr_malloced + && (scn->shdr_flags & ELF_F_MALLOCED) == 0) + scn->shdr.ELFW(e,LIBELFBITS) = &shdr_dest[scn->index]; + + scn->shdr_flags &= ~ELF_F_DIRTY; + } + } + } + + /* That was the last part. Clear the overall flag. */ + elf->flags &= ~ELF_F_DIRTY; + + /* Make sure the content hits the disk. */ + char *msync_start = ((char *) elf->map_address + + (elf->start_offset & ~(sysconf (_SC_PAGESIZE) - 1))); + char *msync_end = ((char *) elf->map_address + + elf->start_offset + ehdr->e_shoff + + ehdr->e_shentsize * shnum); + (void) msync (msync_start, msync_end - msync_start, MS_SYNC); + + return 0; +} + + +/* Size of the buffer we use to generate the blocks of fill bytes. */ +#define FILLBUFSIZE 4096 + +/* If we have to convert the section buffer contents we have to use + temporary buffer. Only buffers up to MAX_TMPBUF bytes are allocated + on the stack. */ +#define MAX_TMPBUF 32768 + + +/* Helper function to write out fill bytes. */ +static int +fill (int fd, off_t pos, size_t len, char *fillbuf, size_t *filledp) +{ + size_t filled = *filledp; + size_t fill_len = MIN (len, FILLBUFSIZE); + + if (unlikely (fill_len > filled) && filled < FILLBUFSIZE) + { + /* Initialize a few more bytes. */ + memset (fillbuf + filled, __libelf_fill_byte, fill_len - filled); + *filledp = filled = fill_len; + } + + do + { + /* This many bytes we want to write in this round. */ + size_t n = MIN (filled, len); + + if (unlikely ((size_t) pwrite_retry (fd, fillbuf, n, pos) != n)) + { + __libelf_seterrno (ELF_E_WRITE_ERROR); + return 1; + } + + pos += n; + len -= n; + } + while (len > 0); + + return 0; +} + + +int +internal_function +__elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum) +{ + char fillbuf[FILLBUFSIZE]; + size_t filled = 0; + bool previous_scn_changed = false; + + /* We need the ELF header several times. */ + ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr; + + /* Write out the ELF header. */ + if ((elf->state.ELFW(elf,LIBELFBITS).ehdr_flags | elf->flags) & ELF_F_DIRTY) + { + ElfW2(LIBELFBITS,Ehdr) tmp_ehdr; + ElfW2(LIBELFBITS,Ehdr) *out_ehdr = ehdr; + + /* If the type sizes should be different at some time we have to + rewrite this code. */ + assert (sizeof (ElfW2(LIBELFBITS,Ehdr)) + == elf_typesize (LIBELFBITS, ELF_T_EHDR, 1)); + + if (unlikely (change_bo)) + { + /* Today there is only one version of the ELF header. */ +#if EV_NUM != 2 + xfct_t fctp; + fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR]; +#else +# undef fctp +# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR] +#endif + + /* Write the converted ELF header in a temporary buffer. */ + (*fctp) (&tmp_ehdr, ehdr, sizeof (ElfW2(LIBELFBITS,Ehdr)), 1); + + /* This is the buffer we want to write. */ + out_ehdr = &tmp_ehdr; + } + + /* Write out the ELF header. */ + if (unlikely (pwrite_retry (elf->fildes, out_ehdr, + sizeof (ElfW2(LIBELFBITS,Ehdr)), 0) + != sizeof (ElfW2(LIBELFBITS,Ehdr)))) + { + __libelf_seterrno (ELF_E_WRITE_ERROR); + return 1; + } + + elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY; + + /* We start writing sections after the ELF header only if there is + no program header. */ + previous_scn_changed = elf->state.ELFW(elf,LIBELFBITS).phdr == NULL; + } + + /* If the type sizes should be different at some time we have to + rewrite this code. */ + assert (sizeof (ElfW2(LIBELFBITS,Phdr)) + == elf_typesize (LIBELFBITS, ELF_T_PHDR, 1)); + + size_t phnum; + if (unlikely (__elf_getphdrnum_rdlock (elf, &phnum) != 0)) + return -1; + + /* Write out the program header table. */ + if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL + && ((elf->state.ELFW(elf,LIBELFBITS).phdr_flags | elf->flags) + & ELF_F_DIRTY)) + { + ElfW2(LIBELFBITS,Phdr) *tmp_phdr = NULL; + ElfW2(LIBELFBITS,Phdr) *out_phdr = elf->state.ELFW(elf,LIBELFBITS).phdr; + + /* Maybe the user wants a gap between the ELF header and the program + header. */ + if (ehdr->e_phoff > ehdr->e_ehsize + && unlikely (fill (elf->fildes, ehdr->e_ehsize, + ehdr->e_phoff - ehdr->e_ehsize, fillbuf, &filled) + != 0)) + return 1; + + if (unlikely (change_bo)) + { + /* Today there is only one version of the ELF header. */ +#if EV_NUM != 2 + xfct_t fctp; + fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR]; +#else +# undef fctp +# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR] +#endif + + /* Allocate sufficient memory. */ + tmp_phdr = (ElfW2(LIBELFBITS,Phdr) *) + malloc (sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum); + if (tmp_phdr == NULL) + { + __libelf_seterrno (ELF_E_NOMEM); + return 1; + } + + /* Write the converted ELF header in a temporary buffer. */ + (*fctp) (tmp_phdr, elf->state.ELFW(elf,LIBELFBITS).phdr, + sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum, 1); + + /* This is the buffer we want to write. */ + out_phdr = tmp_phdr; + } + + /* Write out the ELF header. */ + size_t phdr_size = sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum; + if (unlikely ((size_t) pwrite_retry (elf->fildes, out_phdr, + phdr_size, ehdr->e_phoff) + != phdr_size)) + { + __libelf_seterrno (ELF_E_WRITE_ERROR); + return 1; + } + + /* This is a no-op we we have not allocated any memory. */ + free (tmp_phdr); + + elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY; + + /* We modified the program header. Maybe this created a gap so + we have to write fill bytes, if necessary. */ + previous_scn_changed = true; + } + + /* From now on we have to keep track of the last position to eventually + fill the gaps with the prescribed fill byte. */ + off_t last_offset; + if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL) + last_offset = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1); + else + last_offset = (ehdr->e_phoff + sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum); + + /* Write all the sections. Well, only those which are modified. */ + if (shnum > 0) + { + if (unlikely (shnum > SIZE_MAX / (sizeof (Elf_Scn *) + + sizeof (ElfW2(LIBELFBITS,Shdr))))) + return 1; + + off_t shdr_offset = elf->start_offset + ehdr->e_shoff; +#if EV_NUM != 2 + xfct_t shdr_fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]; +#else +# undef shdr_fctp +# define shdr_fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR] +#endif + + ElfW2(LIBELFBITS,Shdr) *shdr_data; + if (change_bo || elf->state.ELFW(elf,LIBELFBITS).shdr == NULL + || (elf->flags & ELF_F_DIRTY)) + shdr_data = (ElfW2(LIBELFBITS,Shdr) *) + alloca (shnum * sizeof (ElfW2(LIBELFBITS,Shdr))); + else + shdr_data = elf->state.ELFW(elf,LIBELFBITS).shdr; + int shdr_flags = elf->flags; + + /* Get all sections into the array and sort them. */ + Elf_ScnList *list = &elf->state.ELFW(elf,LIBELFBITS).scns; + Elf_Scn **scns = (Elf_Scn **) alloca (shnum * sizeof (Elf_Scn *)); + sort_sections (scns, list); + + for (size_t cnt = 0; cnt < shnum; ++cnt) + { + Elf_Scn *scn = scns[cnt]; + if (scn->index == 0) + { + /* The dummy section header entry. It should not be + possible to mark this "section" as dirty. */ + assert ((scn->flags & ELF_F_DIRTY) == 0); + goto next; + } + + ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS); + if (shdr->sh_type == SHT_NOBITS) + goto next; + + off_t scn_start = elf->start_offset + shdr->sh_offset; + Elf_Data_List *dl = &scn->data_list; + bool scn_changed = false; + + if (scn->data_list_rear != NULL) + do + { + /* If there is a gap, fill it. */ + if (scn_start + dl->data.d.d_off > last_offset + && ((previous_scn_changed && dl->data.d.d_off == 0) + || ((scn->flags | dl->flags | elf->flags) + & ELF_F_DIRTY) != 0)) + { + if (unlikely (fill (elf->fildes, last_offset, + (scn_start + dl->data.d.d_off) + - last_offset, fillbuf, + &filled) != 0)) + return 1; + } + + if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY) + { + char tmpbuf[MAX_TMPBUF]; + void *buf = dl->data.d.d_buf; + + /* Let it go backward if the sections use a bogus + layout with overlaps. We'll overwrite the stupid + user's section data with the latest one, rather than + crashing. */ + + last_offset = scn_start + dl->data.d.d_off; + + if (unlikely (change_bo)) + { +#if EV_NUM != 2 + xfct_t fctp; + fctp = __elf_xfctstom[__libelf_version - 1][dl->data.d.d_version - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]; +#else +# undef fctp +# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type] +#endif + + buf = tmpbuf; + if (dl->data.d.d_size > MAX_TMPBUF) + { + buf = malloc (dl->data.d.d_size); + if (buf == NULL) + { + __libelf_seterrno (ELF_E_NOMEM); + return 1; + } + } + + /* Do the real work. */ + (*fctp) (buf, dl->data.d.d_buf, dl->data.d.d_size, 1); + } + + ssize_t n = pwrite_retry (elf->fildes, buf, + dl->data.d.d_size, + last_offset); + if (unlikely ((size_t) n != dl->data.d.d_size)) + { + if (buf != dl->data.d.d_buf && buf != tmpbuf) + free (buf); + + __libelf_seterrno (ELF_E_WRITE_ERROR); + return 1; + } + + if (buf != dl->data.d.d_buf && buf != tmpbuf) + free (buf); + + scn_changed = true; + } + + last_offset += dl->data.d.d_size; + + dl->flags &= ~ELF_F_DIRTY; + + dl = dl->next; + } + while (dl != NULL); + else + { + /* If the previous section (or the ELF/program + header) changed we might have to fill the gap. */ + if (scn_start > last_offset && previous_scn_changed) + { + if (unlikely (fill (elf->fildes, last_offset, + scn_start - last_offset, fillbuf, + &filled) != 0)) + return 1; + } + + last_offset = scn_start + shdr->sh_size; + } + + previous_scn_changed = scn_changed; + next: + /* Collect the section header table information. */ + if (unlikely (change_bo)) + (*shdr_fctp) (&shdr_data[scn->index], + scn->shdr.ELFW(e,LIBELFBITS), + sizeof (ElfW2(LIBELFBITS,Shdr)), 1); + else if (elf->state.ELFW(elf,LIBELFBITS).shdr == NULL + || (elf->flags & ELF_F_DIRTY)) + memcpy (&shdr_data[scn->index], scn->shdr.ELFW(e,LIBELFBITS), + sizeof (ElfW2(LIBELFBITS,Shdr))); + + shdr_flags |= scn->shdr_flags; + scn->shdr_flags &= ~ELF_F_DIRTY; + } + + /* Fill the gap between last section and section header table if + necessary. */ + if ((elf->flags & ELF_F_DIRTY) && last_offset < shdr_offset + && unlikely (fill (elf->fildes, last_offset, + shdr_offset - last_offset, + fillbuf, &filled) != 0)) + return 1; + + /* Write out the section header table. */ + if (shdr_flags & ELF_F_DIRTY + && unlikely ((size_t) pwrite_retry (elf->fildes, shdr_data, + sizeof (ElfW2(LIBELFBITS,Shdr)) + * shnum, shdr_offset) + != sizeof (ElfW2(LIBELFBITS,Shdr)) * shnum)) + { + __libelf_seterrno (ELF_E_WRITE_ERROR); + return 1; + } + } + + /* That was the last part. Clear the overall flag. */ + elf->flags &= ~ELF_F_DIRTY; + + return 0; +} diff --git a/3rdparty/elfutils/libelf/elf32_updatenull.c b/3rdparty/elfutils/libelf/elf32_updatenull.c new file mode 100644 index 0000000..be4cea0 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf32_updatenull.c @@ -0,0 +1,417 @@ +/* Update data structures for changes. + Copyright (C) 2000-2010 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <endian.h> +#include <libelf.h> +#include <stdbool.h> +#include <string.h> +#include <sys/param.h> + +#include "libelfP.h" +#include "elf-knowledge.h" + +#ifndef LIBELFBITS +# define LIBELFBITS 32 +#endif + + + +static int +ELFW(default_ehdr,LIBELFBITS) (Elf *elf, ElfW2(LIBELFBITS,Ehdr) *ehdr, + size_t shnum, int *change_bop) +{ + /* Always write the magic bytes. */ + if (memcmp (&ehdr->e_ident[EI_MAG0], ELFMAG, SELFMAG) != 0) + { + memcpy (&ehdr->e_ident[EI_MAG0], ELFMAG, SELFMAG); + elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY; + } + + /* Always set the file class. */ + update_if_changed (ehdr->e_ident[EI_CLASS], ELFW(ELFCLASS,LIBELFBITS), + elf->state.ELFW(elf,LIBELFBITS).ehdr_flags); + + /* Set the data encoding if necessary. */ + if (unlikely (ehdr->e_ident[EI_DATA] == ELFDATANONE)) + { + ehdr->e_ident[EI_DATA] = + BYTE_ORDER == BIG_ENDIAN ? ELFDATA2MSB : ELFDATA2LSB; + elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY; + } + else if (unlikely (ehdr->e_ident[EI_DATA] >= ELFDATANUM)) + { + __libelf_seterrno (ELF_E_DATA_ENCODING); + return 1; + } + else + *change_bop = ((BYTE_ORDER == LITTLE_ENDIAN + && ehdr->e_ident[EI_DATA] != ELFDATA2LSB) + || (BYTE_ORDER == BIG_ENDIAN + && ehdr->e_ident[EI_DATA] != ELFDATA2MSB)); + + /* Unconditionally overwrite the ELF version. */ + update_if_changed (ehdr->e_ident[EI_VERSION], EV_CURRENT, + elf->state.ELFW(elf,LIBELFBITS).ehdr_flags); + + if (unlikely (ehdr->e_version == EV_NONE) + || unlikely (ehdr->e_version >= EV_NUM)) + { + __libelf_seterrno (ELF_E_UNKNOWN_VERSION); + return 1; + } + + if (unlikely (shnum >= SHN_LORESERVE)) + { + update_if_changed (ehdr->e_shnum, 0, + elf->state.ELFW(elf,LIBELFBITS).ehdr_flags); + } + else + update_if_changed (ehdr->e_shnum, shnum, + elf->state.ELFW(elf,LIBELFBITS).ehdr_flags); + + if (unlikely (ehdr->e_ehsize != elf_typesize (LIBELFBITS, ELF_T_EHDR, 1))) + { + ehdr->e_ehsize = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1); + elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY; + } + + return 0; +} + + +off_t +internal_function +__elfw2(LIBELFBITS,updatenull_wrlock) (Elf *elf, int *change_bop, size_t shnum) +{ + ElfW2(LIBELFBITS,Ehdr) *ehdr; + int changed = 0; + int ehdr_flags = 0; + + ehdr = __elfw2(LIBELFBITS,getehdr_wrlock) (elf); + + /* Set the default values. */ + if (ELFW(default_ehdr,LIBELFBITS) (elf, ehdr, shnum, change_bop) != 0) + return -1; + + /* At least the ELF header is there. */ + off_t size = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1); + + /* Set the program header position. */ + if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL + && (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN + || ehdr->e_type == ET_CORE)) + (void) __elfw2(LIBELFBITS,getphdr_wrlock) (elf); + if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL) + { + /* Only executables, shared objects, and core files have a program + header. */ + if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN + && unlikely (ehdr->e_type != ET_CORE)) + { + __libelf_seterrno (ELF_E_INVALID_PHDR); + return -1; + } + + size_t phnum; + if (unlikely (__elf_getphdrnum_rdlock (elf, &phnum) != 0)) + return -1; + + if (elf->flags & ELF_F_LAYOUT) + { + /* The user is supposed to fill out e_phoff. Use it and + e_phnum to determine the maximum extend. */ + size = MAX ((size_t) size, + ehdr->e_phoff + + elf_typesize (LIBELFBITS, ELF_T_PHDR, phnum)); + } + else + { + update_if_changed (ehdr->e_phoff, + elf_typesize (LIBELFBITS, ELF_T_EHDR, 1), + ehdr_flags); + + /* We need no alignment here. */ + size += elf_typesize (LIBELFBITS, ELF_T_PHDR, phnum); + } + } + + if (shnum > 0) + { + Elf_ScnList *list; + bool first = true; + + assert (elf->state.ELFW(elf,LIBELFBITS).scns.cnt > 0); + + if (shnum >= SHN_LORESERVE) + { + /* We have to fill in the number of sections in the header + of the zeroth section. */ + Elf_Scn *scn0 = &elf->state.ELFW(elf,LIBELFBITS).scns.data[0]; + + update_if_changed (scn0->shdr.ELFW(e,LIBELFBITS)->sh_size, + shnum, scn0->shdr_flags); + } + + /* Go over all sections and find out how large they are. */ + list = &elf->state.ELFW(elf,LIBELFBITS).scns; + + /* Load the section headers if necessary. This loads the + headers for all sections. */ + if (list->data[1].shdr.ELFW(e,LIBELFBITS) == NULL) + (void) __elfw2(LIBELFBITS,getshdr_wrlock) (&list->data[1]); + + do + { + for (size_t cnt = first == true; cnt < list->cnt; ++cnt) + { + Elf_Scn *scn = &list->data[cnt]; + ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS); + off_t offset = 0; + + assert (shdr != NULL); + ElfW2(LIBELFBITS,Word) sh_entsize = shdr->sh_entsize; + ElfW2(LIBELFBITS,Word) sh_align = shdr->sh_addralign ?: 1; + + /* Set the sh_entsize value if we can reliably detect it. */ + switch (shdr->sh_type) + { + case SHT_SYMTAB: + sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYM, 1); + break; + case SHT_RELA: + sh_entsize = elf_typesize (LIBELFBITS, ELF_T_RELA, 1); + break; + case SHT_GROUP: + /* Only relocatable files can contain section groups. */ + if (ehdr->e_type != ET_REL) + { + __libelf_seterrno (ELF_E_GROUP_NOT_REL); + return -1; + } + /* FALLTHROUGH */ + case SHT_SYMTAB_SHNDX: + sh_entsize = elf_typesize (32, ELF_T_WORD, 1); + break; + case SHT_HASH: + sh_entsize = SH_ENTSIZE_HASH (ehdr); + break; + case SHT_DYNAMIC: + sh_entsize = elf_typesize (LIBELFBITS, ELF_T_DYN, 1); + break; + case SHT_REL: + sh_entsize = elf_typesize (LIBELFBITS, ELF_T_REL, 1); + break; + case SHT_DYNSYM: + sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYM, 1); + break; + case SHT_SUNW_move: + sh_entsize = elf_typesize (LIBELFBITS, ELF_T_MOVE, 1); + break; + case SHT_SUNW_syminfo: + sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYMINFO, 1); + break; + default: + break; + } + + /* If the section header contained the wrong entry size + correct it and mark the header as modified. */ + update_if_changed (shdr->sh_entsize, sh_entsize, + scn->shdr_flags); + + if (scn->data_read == 0 + && __libelf_set_rawdata_wrlock (scn) != 0) + /* Something went wrong. The error value is already set. */ + return -1; + + /* Iterate over all data blocks. */ + if (list->data[cnt].data_list_rear != NULL) + { + Elf_Data_List *dl = &scn->data_list; + + while (dl != NULL) + { + Elf_Data *data = &dl->data.d; + if (dl == &scn->data_list && data->d_buf == NULL + && scn->rawdata.d.d_buf != NULL) + data = &scn->rawdata.d; + + if (unlikely (data->d_version == EV_NONE) + || unlikely (data->d_version >= EV_NUM)) + { + __libelf_seterrno (ELF_E_UNKNOWN_VERSION); + return -1; + } + + if (unlikely (! powerof2 (data->d_align))) + { + __libelf_seterrno (ELF_E_INVALID_ALIGN); + return -1; + } + + sh_align = MAX (sh_align, data->d_align); + + if (elf->flags & ELF_F_LAYOUT) + { + /* The user specified the offset and the size. + All we have to do is check whether this block + fits in the size specified for the section. */ + if (unlikely ((GElf_Word) (data->d_off + + data->d_size) + > shdr->sh_size)) + { + __libelf_seterrno (ELF_E_SECTION_TOO_SMALL); + return -1; + } + } + else + { + /* Determine the padding. */ + offset = ((offset + data->d_align - 1) + & ~(data->d_align - 1)); + + update_if_changed (data->d_off, offset, changed); + + offset += data->d_size; + } + + /* Next data block. */ + dl = dl->next; + } + } + else + /* Get the size of the section from the raw data. If + none is available the value is zero. */ + offset += scn->rawdata.d.d_size; + + if (elf->flags & ELF_F_LAYOUT) + { + size = MAX ((GElf_Word) size, + shdr->sh_offset + + (shdr->sh_type != SHT_NOBITS + ? shdr->sh_size : 0)); + + /* The alignment must be a power of two. This is a + requirement from the ELF specification. Additionally + we test for the alignment of the section being large + enough for the largest alignment required by a data + block. */ + if (unlikely (! powerof2 (shdr->sh_addralign)) + || unlikely (shdr->sh_addralign < sh_align)) + { + __libelf_seterrno (ELF_E_INVALID_ALIGN); + return -1; + } + } + else + { + /* How much alignment do we need for this section. */ + update_if_changed (shdr->sh_addralign, sh_align, + scn->shdr_flags); + + size = (size + sh_align - 1) & ~(sh_align - 1); + int offset_changed = 0; + update_if_changed (shdr->sh_offset, (GElf_Word) size, + offset_changed); + changed |= offset_changed; + + if (offset_changed && scn->data_list_rear == NULL) + { + /* The position of the section in the file + changed. Create the section data list. */ + if (__elf_getdata_rdlock (scn, NULL) == NULL) + return -1; + } + + /* See whether the section size is correct. */ + update_if_changed (shdr->sh_size, (GElf_Word) offset, + changed); + + if (shdr->sh_type != SHT_NOBITS) + size += offset; + + scn->flags |= changed; + } + + /* Check that the section size is actually a multiple of + the entry size. */ + if (shdr->sh_entsize != 0 + && unlikely (shdr->sh_size % shdr->sh_entsize != 0) + && (elf->flags & ELF_F_PERMISSIVE) == 0) + { + __libelf_seterrno (ELF_E_INVALID_SHENTSIZE); + return -1; + } + } + + assert (list->next == NULL || list->cnt == list->max); + + first = false; + } + while ((list = list->next) != NULL); + + /* Store section information. */ + if (elf->flags & ELF_F_LAYOUT) + { + /* The user is supposed to fill out e_shoff. Use it and + e_shnum (or sh_size of the dummy, first section header) + to determine the maximum extend. */ + size = MAX ((GElf_Word) size, + (ehdr->e_shoff + + (elf_typesize (LIBELFBITS, ELF_T_SHDR, shnum)))); + } + else + { + /* Align for section header table. + + Yes, we use `sizeof' and not `__alignof__' since we do not + want to be surprised by architectures with less strict + alignment rules. */ +#define SHDR_ALIGN sizeof (ElfW2(LIBELFBITS,Off)) + size = (size + SHDR_ALIGN - 1) & ~(SHDR_ALIGN - 1); + + update_if_changed (ehdr->e_shoff, (GElf_Word) size, elf->flags); + update_if_changed (ehdr->e_shentsize, + elf_typesize (LIBELFBITS, ELF_T_SHDR, 1), + ehdr_flags); + + /* Account for the section header size. */ + size += elf_typesize (LIBELFBITS, ELF_T_SHDR, shnum); + } + } + + elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ehdr_flags; + + return size; +} diff --git a/3rdparty/elfutils/libelf/elf32_xlatetof.c b/3rdparty/elfutils/libelf/elf32_xlatetof.c new file mode 100644 index 0000000..27a973e --- /dev/null +++ b/3rdparty/elfutils/libelf/elf32_xlatetof.c @@ -0,0 +1,123 @@ +/* Convert from memory to file representation. + Copyright (C) 1998, 1999, 2000, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <endian.h> +#include <string.h> + +#include "libelfP.h" + +#ifndef LIBELFBITS +# define LIBELFBITS 32 +#endif + + +Elf_Data * +elfw2(LIBELFBITS, xlatetof) (dest, src, encode) + Elf_Data *dest; + const Elf_Data *src; + unsigned int encode; +{ + /* First test whether the input data is really suitable for this + type. This means, whether there is an integer number of records. + Note that for this implementation the memory and file size of the + data types are identical. */ +#if EV_NUM != 2 + size_t recsize = __libelf_type_sizes[src->d_version - 1][ELFW(ELFCLASS,LIBELFBITS) - 1][src->d_type]; +#else + size_t recsize = __libelf_type_sizes[0][ELFW(ELFCLASS,LIBELFBITS) - 1][src->d_type]; +#endif + + if (src->d_size % recsize != 0) + { + __libelf_seterrno (ELF_E_INVALID_DATA); + return NULL; + } + + /* Next see whether the converted data fits in the output buffer. */ + if (src->d_size > dest->d_size) + { + __libelf_seterrno (ELF_E_DEST_SIZE); + return NULL; + } + + /* Test the encode parameter. */ + if (encode != ELFDATA2LSB && encode != ELFDATA2MSB) + { + __libelf_seterrno (ELF_E_INVALID_ENCODING); + return NULL; + } + + /* Determine the translation function to use. + + At this point we make an assumption which is valid for all + existing implementations so far: the memory and file sizes are + the same. This has very important consequences: + a) The requirement that the source and destination buffer can + overlap can easily be fulfilled. + b) We need only one function to convert from and memory to file + and vice versa since the function only has to copy and/or + change the byte order. + */ + if ((__BYTE_ORDER == __LITTLE_ENDIAN && encode == ELFDATA2LSB) + || (__BYTE_ORDER == __BIG_ENDIAN && encode == ELFDATA2MSB)) + { + /* We simply have to copy since the byte order is the same. */ + if (src->d_buf != dest->d_buf) + memmove (dest->d_buf, src->d_buf, src->d_size); + } + else + { + xfct_t fctp; + + /* Get a pointer to the transformation functions. The `#ifdef' is + a small optimization since we don't anticipate another ELF + version and so would waste "precious" code. */ +#if EV_NUM != 2 + fctp = __elf_xfctstom[dest->d_version - 1][src->d_version - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][src->d_type]; +#else + fctp = __elf_xfctstom[0][0][ELFW(ELFCLASS, LIBELFBITS) - 1][src->d_type]; +#endif + + /* Do the real work. */ + (*fctp) (dest->d_buf, src->d_buf, src->d_size, 1); + } + + /* Now set the real destination type and length since the operation was + successful. */ + dest->d_type = src->d_type; + dest->d_size = src->d_size; + + return dest; +} +INTDEF(elfw2(LIBELFBITS, xlatetof)) diff --git a/3rdparty/elfutils/libelf/elf32_xlatetom.c b/3rdparty/elfutils/libelf/elf32_xlatetom.c new file mode 100644 index 0000000..368df07 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf32_xlatetom.c @@ -0,0 +1,128 @@ +/* Convert from file to memory representation. + Copyright (C) 1998, 1999, 2000, 2002, 2012 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <endian.h> +#include <string.h> + +#include "libelfP.h" + +#ifndef LIBELFBITS +# define LIBELFBITS 32 +#endif + + +Elf_Data * +elfw2(LIBELFBITS, xlatetom) (dest, src, encode) + Elf_Data *dest; + const Elf_Data *src; + unsigned int encode; +{ + /* First test whether the input data is really suitable for this + type. This means, whether there is an integer number of records. + Note that for this implementation the memory and file size of the + data types are identical. */ +#if EV_NUM != 2 + size_t recsize = __libelf_type_sizes[src->d_version - 1][ELFW(ELFCLASS,LIBELFBITS) - 1][src->d_type]; +#else + size_t recsize = __libelf_type_sizes[0][ELFW(ELFCLASS,LIBELFBITS) - 1][src->d_type]; +#endif + + + /* We shouldn't require integer number of records when processing + notes. Payload bytes follow the header immediately, it's not an + array of records as is the case otherwise. */ + if (src->d_type != ELF_T_NHDR + && src->d_size % recsize != 0) + { + __libelf_seterrno (ELF_E_INVALID_DATA); + return NULL; + } + + /* Next see whether the converted data fits in the output buffer. */ + if (src->d_size > dest->d_size) + { + __libelf_seterrno (ELF_E_DEST_SIZE); + return NULL; + } + + /* Test the encode parameter. */ + if (encode != ELFDATA2LSB && encode != ELFDATA2MSB) + { + __libelf_seterrno (ELF_E_INVALID_ENCODING); + return NULL; + } + + /* Determine the translation function to use. + + At this point we make an assumption which is valid for all + existing implementations so far: the memory and file sizes are + the same. This has very important consequences: + a) The requirement that the source and destination buffer can + overlap can easily be fulfilled. + b) We need only one function to convert from and memory to file + and vice versa since the function only has to copy and/or + change the byte order. + */ + if ((BYTE_ORDER == LITTLE_ENDIAN && encode == ELFDATA2LSB) + || (BYTE_ORDER == BIG_ENDIAN && encode == ELFDATA2MSB)) + { + /* We simply have to copy since the byte order is the same. */ + if (src->d_buf != dest->d_buf) + memmove (dest->d_buf, src->d_buf, src->d_size); + } + else + { + xfct_t fctp; + + /* Get a pointer to the transformation functions. The `#ifdef' is + a small optimization since we don't anticipate another ELF + version and so would waste "precious" code. */ +#if EV_NUM != 2 + fctp = __elf_xfctstom[src->d_version - 1][dest->d_version - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][src->d_type]; +#else + fctp = __elf_xfctstom[0][0][ELFW(ELFCLASS, LIBELFBITS) - 1][src->d_type]; +#endif + + /* Do the real work. */ + (*fctp) (dest->d_buf, src->d_buf, src->d_size, 0); + } + + /* Now set the real destination type and length since the operation was + successful. */ + dest->d_type = src->d_type; + dest->d_size = src->d_size; + + return dest; +} +INTDEF(elfw2(LIBELFBITS, xlatetom)) diff --git a/3rdparty/elfutils/libelf/elf64/elf64.pro b/3rdparty/elfutils/libelf/elf64/elf64.pro new file mode 100644 index 0000000..021b53e --- /dev/null +++ b/3rdparty/elfutils/libelf/elf64/elf64.pro @@ -0,0 +1,20 @@ +TEMPLATE = lib +CONFIG += staticlib +TARGET = ../../elf64 + +include(../../elfutils.pri) +include(../elfheaders.pri) + +SOURCES += \ + $$PWD/../elf64_checksum.c \ + $$PWD/../elf64_fsize.c \ + $$PWD/../elf64_getehdr.c \ + $$PWD/../elf64_getphdr.c \ + $$PWD/../elf64_getshdr.c \ + $$PWD/../elf64_newehdr.c \ + $$PWD/../elf64_newphdr.c \ + $$PWD/../elf64_offscn.c \ + $$PWD/../elf64_updatefile.c \ + $$PWD/../elf64_updatenull.c \ + $$PWD/../elf64_xlatetof.c \ + $$PWD/../elf64_xlatetom.c \ diff --git a/3rdparty/elfutils/libelf/elf64_checksum.c b/3rdparty/elfutils/libelf/elf64_checksum.c new file mode 100644 index 0000000..1802240 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf64_checksum.c @@ -0,0 +1,31 @@ +/* Compute simple checksum from permanent parts of the ELF file. + Copyright (C) 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#define LIBELFBITS 64 +#include "elf32_checksum.c" diff --git a/3rdparty/elfutils/libelf/elf64_fsize.c b/3rdparty/elfutils/libelf/elf64_fsize.c new file mode 100644 index 0000000..1ee1067 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf64_fsize.c @@ -0,0 +1,31 @@ +/* Return the size of an object file type. + Copyright (C) 1998, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#define LIBELFBITS 64 +#include "elf32_fsize.c" diff --git a/3rdparty/elfutils/libelf/elf64_getehdr.c b/3rdparty/elfutils/libelf/elf64_getehdr.c new file mode 100644 index 0000000..b35e7f6 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf64_getehdr.c @@ -0,0 +1,31 @@ +/* Return program header table. + Copyright (C) 1998, 1999, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#define LIBELFBITS 64 +#include "elf32_getehdr.c" diff --git a/3rdparty/elfutils/libelf/elf64_getphdr.c b/3rdparty/elfutils/libelf/elf64_getphdr.c new file mode 100644 index 0000000..c1ee60f --- /dev/null +++ b/3rdparty/elfutils/libelf/elf64_getphdr.c @@ -0,0 +1,31 @@ +/* Return program header table. + Copyright (C) 1998, 1999, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#define LIBELFBITS 64 +#include "elf32_getphdr.c" diff --git a/3rdparty/elfutils/libelf/elf64_getshdr.c b/3rdparty/elfutils/libelf/elf64_getshdr.c new file mode 100644 index 0000000..c50cc71 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf64_getshdr.c @@ -0,0 +1,31 @@ +/* Return section header. + Copyright (C) 1998, 1999, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#define LIBELFBITS 64 +#include "elf32_getshdr.c" diff --git a/3rdparty/elfutils/libelf/elf64_newehdr.c b/3rdparty/elfutils/libelf/elf64_newehdr.c new file mode 100644 index 0000000..65dd0f7 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf64_newehdr.c @@ -0,0 +1,31 @@ +/* Create new program header table. + Copyright (C) 1999, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1999. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#define LIBELFBITS 64 +#include "elf32_newehdr.c" diff --git a/3rdparty/elfutils/libelf/elf64_newphdr.c b/3rdparty/elfutils/libelf/elf64_newphdr.c new file mode 100644 index 0000000..58bfc73 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf64_newphdr.c @@ -0,0 +1,31 @@ +/* Create new program header table. + Copyright (C) 1999, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1999. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#define LIBELFBITS 64 +#include "elf32_newphdr.c" diff --git a/3rdparty/elfutils/libelf/elf64_offscn.c b/3rdparty/elfutils/libelf/elf64_offscn.c new file mode 100644 index 0000000..1b37b36 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf64_offscn.c @@ -0,0 +1,31 @@ +/* Return program header table. + Copyright (C) 2005 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2005. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#define LIBELFBITS 64 +#include "elf32_offscn.c" diff --git a/3rdparty/elfutils/libelf/elf64_updatefile.c b/3rdparty/elfutils/libelf/elf64_updatefile.c new file mode 100644 index 0000000..6941fe9 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf64_updatefile.c @@ -0,0 +1,30 @@ +/* Copyright (C) 2000, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#define LIBELFBITS 64 +#include "elf32_updatefile.c" diff --git a/3rdparty/elfutils/libelf/elf64_updatenull.c b/3rdparty/elfutils/libelf/elf64_updatenull.c new file mode 100644 index 0000000..8333b5b --- /dev/null +++ b/3rdparty/elfutils/libelf/elf64_updatenull.c @@ -0,0 +1,30 @@ +/* Copyright (C) 2000, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#define LIBELFBITS 64 +#include "elf32_updatenull.c" diff --git a/3rdparty/elfutils/libelf/elf64_xlatetof.c b/3rdparty/elfutils/libelf/elf64_xlatetof.c new file mode 100644 index 0000000..aacf5b0 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf64_xlatetof.c @@ -0,0 +1,31 @@ +/* Convert from memory to file representation. + Copyright (C) 1998, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#define LIBELFBITS 64 +#include "elf32_xlatetof.c" diff --git a/3rdparty/elfutils/libelf/elf64_xlatetom.c b/3rdparty/elfutils/libelf/elf64_xlatetom.c new file mode 100644 index 0000000..034262c --- /dev/null +++ b/3rdparty/elfutils/libelf/elf64_xlatetom.c @@ -0,0 +1,31 @@ +/* Convert from file to memory representation. + Copyright (C) 1998, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#define LIBELFBITS 64 +#include "elf32_xlatetom.c" diff --git a/3rdparty/elfutils/libelf/elf_begin.c b/3rdparty/elfutils/libelf/elf_begin.c new file mode 100644 index 0000000..30abe0b --- /dev/null +++ b/3rdparty/elfutils/libelf/elf_begin.c @@ -0,0 +1,1135 @@ +/* Create descriptor for processing file. + Copyright (C) 1998-2010, 2012, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <stdbool.h> +#include <stddef.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/param.h> +#include <sys/stat.h> + +#include <system.h> +#include "libelfP.h" +#include "common.h" + + +/* Create descriptor for archive in memory. */ +static inline Elf * +file_read_ar (int fildes, void *map_address, off_t offset, size_t maxsize, + Elf_Cmd cmd, Elf *parent) +{ + Elf *elf; + + /* Create a descriptor. */ + elf = allocate_elf (fildes, map_address, offset, maxsize, cmd, parent, + ELF_K_AR, 0); + if (elf != NULL) + { + /* We don't read all the symbol tables in advance. All this will + happen on demand. */ + elf->state.ar.offset = offset + SARMAG; + + elf->state.ar.elf_ar_hdr.ar_rawname = elf->state.ar.raw_name; + } + + return elf; +} + + +static size_t +get_shnum (void *map_address, unsigned char *e_ident, int fildes, off_t offset, + size_t maxsize) +{ + size_t result; + union + { + Elf32_Ehdr *e32; + Elf64_Ehdr *e64; + void *p; + } ehdr; + union + { + Elf32_Ehdr e32; + Elf64_Ehdr e64; + } ehdr_mem; + bool is32 = e_ident[EI_CLASS] == ELFCLASS32; + + /* Make the ELF header available. */ + if (e_ident[EI_DATA] == MY_ELFDATA + && (ALLOW_UNALIGNED + || (((size_t) e_ident + & ((is32 ? __alignof__ (Elf32_Ehdr) : __alignof__ (Elf64_Ehdr)) + - 1)) == 0))) + ehdr.p = e_ident; + else + { + /* We already read the ELF header. We have to copy the header + since we possibly modify the data here and the caller + expects the memory it passes in to be preserved. */ + ehdr.p = &ehdr_mem; + + if (is32) + { + if (ALLOW_UNALIGNED) + { + ehdr_mem.e32.e_shnum = ((Elf32_Ehdr *) e_ident)->e_shnum; + ehdr_mem.e32.e_shoff = ((Elf32_Ehdr *) e_ident)->e_shoff; + } + else + memcpy (&ehdr_mem, e_ident, sizeof (Elf32_Ehdr)); + + if (e_ident[EI_DATA] != MY_ELFDATA) + { + CONVERT (ehdr_mem.e32.e_shnum); + CONVERT (ehdr_mem.e32.e_shoff); + } + } + else + { + if (ALLOW_UNALIGNED) + { + ehdr_mem.e64.e_shnum = ((Elf64_Ehdr *) e_ident)->e_shnum; + ehdr_mem.e64.e_shoff = ((Elf64_Ehdr *) e_ident)->e_shoff; + } + else + memcpy (&ehdr_mem, e_ident, sizeof (Elf64_Ehdr)); + + if (e_ident[EI_DATA] != MY_ELFDATA) + { + CONVERT (ehdr_mem.e64.e_shnum); + CONVERT (ehdr_mem.e64.e_shoff); + } + } + } + + if (is32) + { + /* Get the number of sections from the ELF header. */ + result = ehdr.e32->e_shnum; + + if (unlikely (result == 0) && ehdr.e32->e_shoff != 0) + { + if (unlikely (ehdr.e32->e_shoff >= maxsize) + || unlikely (maxsize - ehdr.e32->e_shoff < sizeof (Elf32_Shdr))) + /* Cannot read the first section header. */ + return 0; + + if (likely (map_address != NULL) && e_ident[EI_DATA] == MY_ELFDATA + && (ALLOW_UNALIGNED + || (((size_t) ((char *) map_address + offset)) + & (__alignof__ (Elf32_Ehdr) - 1)) == 0)) + /* We can directly access the memory. */ + result = ((Elf32_Shdr *) ((char *) map_address + ehdr.e32->e_shoff + + offset))->sh_size; + else + { + Elf32_Word size; + + if (likely (map_address != NULL)) + /* gcc will optimize the memcpy to a simple memory + access while taking care of alignment issues. */ + memcpy (&size, &((Elf32_Shdr *) ((char *) map_address + + ehdr.e32->e_shoff + + offset))->sh_size, + sizeof (Elf32_Word)); + else + if (unlikely (pread_retry (fildes, &size, sizeof (Elf32_Word), + offset + ehdr.e32->e_shoff + + offsetof (Elf32_Shdr, sh_size)) + != sizeof (Elf32_Word))) + return (size_t) -1l; + + if (e_ident[EI_DATA] != MY_ELFDATA) + CONVERT (size); + + result = size; + } + } + + /* If the section headers were truncated, pretend none were there. */ + if (ehdr.e32->e_shoff > maxsize + || maxsize - ehdr.e32->e_shoff < sizeof (Elf32_Shdr) * result) + result = 0; + } + else + { + /* Get the number of sections from the ELF header. */ + result = ehdr.e64->e_shnum; + + if (unlikely (result == 0) && ehdr.e64->e_shoff != 0) + { + if (unlikely (ehdr.e64->e_shoff >= maxsize) + || unlikely (ehdr.e64->e_shoff + sizeof (Elf64_Shdr) > maxsize)) + /* Cannot read the first section header. */ + return 0; + + Elf64_Xword size; + if (likely (map_address != NULL) && e_ident[EI_DATA] == MY_ELFDATA + && (ALLOW_UNALIGNED + || (((size_t) ((char *) map_address + offset)) + & (__alignof__ (Elf64_Ehdr) - 1)) == 0)) + /* We can directly access the memory. */ + size = ((Elf64_Shdr *) ((char *) map_address + ehdr.e64->e_shoff + + offset))->sh_size; + else + { + if (likely (map_address != NULL)) + /* gcc will optimize the memcpy to a simple memory + access while taking care of alignment issues. */ + memcpy (&size, &((Elf64_Shdr *) ((char *) map_address + + ehdr.e64->e_shoff + + offset))->sh_size, + sizeof (Elf64_Xword)); + else + if (unlikely (pread_retry (fildes, &size, sizeof (Elf64_Word), + offset + ehdr.e64->e_shoff + + offsetof (Elf64_Shdr, sh_size)) + != sizeof (Elf64_Xword))) + return (size_t) -1l; + + if (e_ident[EI_DATA] != MY_ELFDATA) + CONVERT (size); + } + + if (size > ~((GElf_Word) 0)) + /* Invalid value, it is too large. */ + return (size_t) -1l; + + result = size; + } + + /* If the section headers were truncated, pretend none were there. */ + if (ehdr.e64->e_shoff > maxsize + || maxsize - ehdr.e64->e_shoff < sizeof (Elf64_Shdr) * result) + result = 0; + } + + return result; +} + + +/* Create descriptor for ELF file in memory. */ +static Elf * +file_read_elf (int fildes, void *map_address, unsigned char *e_ident, + off_t offset, size_t maxsize, Elf_Cmd cmd, Elf *parent) +{ + /* Verify the binary is of the class we can handle. */ + if (unlikely ((e_ident[EI_CLASS] != ELFCLASS32 + && e_ident[EI_CLASS] != ELFCLASS64) + /* We also can only handle two encodings. */ + || (e_ident[EI_DATA] != ELFDATA2LSB + && e_ident[EI_DATA] != ELFDATA2MSB))) + { + /* Cannot handle this. */ + __libelf_seterrno (ELF_E_INVALID_FILE); + return NULL; + } + + /* Determine the number of sections. */ + size_t scncnt = get_shnum (map_address, e_ident, fildes, offset, maxsize); + if (scncnt == (size_t) -1l) + /* Could not determine the number of sections. */ + return NULL; + + /* Check for too many sections. */ + if (e_ident[EI_CLASS] == ELFCLASS32) + { + if (scncnt > SIZE_MAX / (sizeof (Elf_Scn) + sizeof (Elf32_Shdr))) + return NULL; + } + else if (scncnt > SIZE_MAX / (sizeof (Elf_Scn) + sizeof (Elf64_Shdr))) + return NULL; + + /* We can now allocate the memory. Even if there are no section headers, + we allocate space for a zeroth section in case we need it later. */ + const size_t scnmax = (scncnt ?: (cmd == ELF_C_RDWR || cmd == ELF_C_RDWR_MMAP) + ? 1 : 0); + Elf *elf = allocate_elf (fildes, map_address, offset, maxsize, cmd, parent, + ELF_K_ELF, scnmax * sizeof (Elf_Scn)); + if (elf == NULL) + /* Not enough memory. */ + return NULL; + + assert ((unsigned int) scncnt == scncnt); + assert (offsetof (struct Elf, state.elf32.scns) + == offsetof (struct Elf, state.elf64.scns)); + elf->state.elf32.scns.cnt = scncnt; + elf->state.elf32.scns.max = scnmax; + + /* Some more or less arbitrary value. */ + elf->state.elf.scnincr = 10; + + /* Make the class easily available. */ + elf->class = e_ident[EI_CLASS]; + + if (e_ident[EI_CLASS] == ELFCLASS32) + { + /* This pointer might not be directly usable if the alignment is + not sufficient for the architecture. */ + Elf32_Ehdr *ehdr = (Elf32_Ehdr *) ((char *) map_address + offset); + + /* This is a 32-bit binary. */ + if (map_address != NULL && e_ident[EI_DATA] == MY_ELFDATA + && (ALLOW_UNALIGNED + || ((((uintptr_t) ehdr) & (__alignof__ (Elf32_Ehdr) - 1)) == 0 + && ((uintptr_t) ((char *) ehdr + ehdr->e_shoff) + & (__alignof__ (Elf32_Shdr) - 1)) == 0 + && ((uintptr_t) ((char *) ehdr + ehdr->e_phoff) + & (__alignof__ (Elf32_Phdr) - 1)) == 0))) + { + /* We can use the mmapped memory. */ + elf->state.elf32.ehdr = ehdr; + + if (unlikely (ehdr->e_shoff >= maxsize) + || unlikely (maxsize - ehdr->e_shoff + < scncnt * sizeof (Elf32_Shdr))) + { + free_and_out: + free (elf); + __libelf_seterrno (ELF_E_INVALID_FILE); + return NULL; + } + elf->state.elf32.shdr + = (Elf32_Shdr *) ((char *) ehdr + ehdr->e_shoff); + + /* Don't precache the phdr pointer here. + elf32_getphdr will validate it against the size when asked. */ + + for (size_t cnt = 0; cnt < scncnt; ++cnt) + { + elf->state.elf32.scns.data[cnt].index = cnt; + elf->state.elf32.scns.data[cnt].elf = elf; + elf->state.elf32.scns.data[cnt].shdr.e32 = + &elf->state.elf32.shdr[cnt]; + if (likely (elf->state.elf32.shdr[cnt].sh_offset < maxsize) + && likely (elf->state.elf32.shdr[cnt].sh_size + <= maxsize - elf->state.elf32.shdr[cnt].sh_offset)) + elf->state.elf32.scns.data[cnt].rawdata_base = + elf->state.elf32.scns.data[cnt].data_base = + ((char *) map_address + offset + + elf->state.elf32.shdr[cnt].sh_offset); + elf->state.elf32.scns.data[cnt].list = &elf->state.elf32.scns; + + /* If this is a section with an extended index add a + reference in the section which uses the extended + index. */ + if (elf->state.elf32.shdr[cnt].sh_type == SHT_SYMTAB_SHNDX + && elf->state.elf32.shdr[cnt].sh_link < scncnt) + elf->state.elf32.scns.data[elf->state.elf32.shdr[cnt].sh_link].shndx_index + = cnt; + + /* Set the own shndx_index field in case it has not yet + been set. */ + if (elf->state.elf32.scns.data[cnt].shndx_index == 0) + elf->state.elf32.scns.data[cnt].shndx_index = -1; + } + } + else + { + /* Copy the ELF header. */ + elf->state.elf32.ehdr = memcpy (&elf->state.elf32.ehdr_mem, e_ident, + sizeof (Elf32_Ehdr)); + + if (e_ident[EI_DATA] != MY_ELFDATA) + { + CONVERT (elf->state.elf32.ehdr_mem.e_type); + CONVERT (elf->state.elf32.ehdr_mem.e_machine); + CONVERT (elf->state.elf32.ehdr_mem.e_version); + CONVERT (elf->state.elf32.ehdr_mem.e_entry); + CONVERT (elf->state.elf32.ehdr_mem.e_phoff); + CONVERT (elf->state.elf32.ehdr_mem.e_shoff); + CONVERT (elf->state.elf32.ehdr_mem.e_flags); + CONVERT (elf->state.elf32.ehdr_mem.e_ehsize); + CONVERT (elf->state.elf32.ehdr_mem.e_phentsize); + CONVERT (elf->state.elf32.ehdr_mem.e_phnum); + CONVERT (elf->state.elf32.ehdr_mem.e_shentsize); + CONVERT (elf->state.elf32.ehdr_mem.e_shnum); + CONVERT (elf->state.elf32.ehdr_mem.e_shstrndx); + } + + for (size_t cnt = 0; cnt < scncnt; ++cnt) + { + elf->state.elf32.scns.data[cnt].index = cnt; + elf->state.elf32.scns.data[cnt].elf = elf; + elf->state.elf32.scns.data[cnt].list = &elf->state.elf32.scns; + } + } + + /* So far only one block with sections. */ + elf->state.elf32.scns_last = &elf->state.elf32.scns; + } + else + { + /* This pointer might not be directly usable if the alignment is + not sufficient for the architecture. */ + Elf64_Ehdr *ehdr = (Elf64_Ehdr *) ((char *) map_address + offset); + + /* This is a 64-bit binary. */ + if (map_address != NULL && e_ident[EI_DATA] == MY_ELFDATA + && (ALLOW_UNALIGNED + || ((((uintptr_t) ehdr) & (__alignof__ (Elf64_Ehdr) - 1)) == 0 + && ((uintptr_t) ((char *) ehdr + ehdr->e_shoff) + & (__alignof__ (Elf64_Shdr) - 1)) == 0 + && ((uintptr_t) ((char *) ehdr + ehdr->e_phoff) + & (__alignof__ (Elf64_Phdr) - 1)) == 0))) + { + /* We can use the mmapped memory. */ + elf->state.elf64.ehdr = ehdr; + + if (unlikely (ehdr->e_shoff >= maxsize) + || unlikely (maxsize - ehdr->e_shoff + < scncnt * sizeof (Elf64_Shdr))) + goto free_and_out; + elf->state.elf64.shdr + = (Elf64_Shdr *) ((char *) ehdr + ehdr->e_shoff); + + /* Don't precache the phdr pointer here. + elf64_getphdr will validate it against the size when asked. */ + + for (size_t cnt = 0; cnt < scncnt; ++cnt) + { + elf->state.elf64.scns.data[cnt].index = cnt; + elf->state.elf64.scns.data[cnt].elf = elf; + elf->state.elf64.scns.data[cnt].shdr.e64 = + &elf->state.elf64.shdr[cnt]; + if (likely (elf->state.elf64.shdr[cnt].sh_offset < maxsize) + && likely (elf->state.elf64.shdr[cnt].sh_size + <= maxsize - elf->state.elf64.shdr[cnt].sh_offset)) + elf->state.elf64.scns.data[cnt].rawdata_base = + elf->state.elf64.scns.data[cnt].data_base = + ((char *) map_address + offset + + elf->state.elf64.shdr[cnt].sh_offset); + elf->state.elf64.scns.data[cnt].list = &elf->state.elf64.scns; + + /* If this is a section with an extended index add a + reference in the section which uses the extended + index. */ + if (elf->state.elf64.shdr[cnt].sh_type == SHT_SYMTAB_SHNDX + && elf->state.elf64.shdr[cnt].sh_link < scncnt) + elf->state.elf64.scns.data[elf->state.elf64.shdr[cnt].sh_link].shndx_index + = cnt; + + /* Set the own shndx_index field in case it has not yet + been set. */ + if (elf->state.elf64.scns.data[cnt].shndx_index == 0) + elf->state.elf64.scns.data[cnt].shndx_index = -1; + } + } + else + { + /* Copy the ELF header. */ + elf->state.elf64.ehdr = memcpy (&elf->state.elf64.ehdr_mem, e_ident, + sizeof (Elf64_Ehdr)); + + if (e_ident[EI_DATA] != MY_ELFDATA) + { + CONVERT (elf->state.elf64.ehdr_mem.e_type); + CONVERT (elf->state.elf64.ehdr_mem.e_machine); + CONVERT (elf->state.elf64.ehdr_mem.e_version); + CONVERT (elf->state.elf64.ehdr_mem.e_entry); + CONVERT (elf->state.elf64.ehdr_mem.e_phoff); + CONVERT (elf->state.elf64.ehdr_mem.e_shoff); + CONVERT (elf->state.elf64.ehdr_mem.e_flags); + CONVERT (elf->state.elf64.ehdr_mem.e_ehsize); + CONVERT (elf->state.elf64.ehdr_mem.e_phentsize); + CONVERT (elf->state.elf64.ehdr_mem.e_phnum); + CONVERT (elf->state.elf64.ehdr_mem.e_shentsize); + CONVERT (elf->state.elf64.ehdr_mem.e_shnum); + CONVERT (elf->state.elf64.ehdr_mem.e_shstrndx); + } + + for (size_t cnt = 0; cnt < scncnt; ++cnt) + { + elf->state.elf64.scns.data[cnt].index = cnt; + elf->state.elf64.scns.data[cnt].elf = elf; + elf->state.elf64.scns.data[cnt].list = &elf->state.elf64.scns; + } + } + + /* So far only one block with sections. */ + elf->state.elf64.scns_last = &elf->state.elf64.scns; + } + + return elf; +} + + +Elf * +internal_function +__libelf_read_mmaped_file (int fildes, void *map_address, off_t offset, + size_t maxsize, Elf_Cmd cmd, Elf *parent) +{ + /* We have to find out what kind of file this is. We handle ELF + files and archives. To find out what we have we must look at the + header. The header for an ELF file is EI_NIDENT bytes in size, + the header for an archive file SARMAG bytes long. */ + unsigned char *e_ident = (unsigned char *) map_address + offset; + + /* See what kind of object we have here. */ + Elf_Kind kind = determine_kind (e_ident, maxsize); + + switch (kind) + { + case ELF_K_ELF: + return file_read_elf (fildes, map_address, e_ident, offset, maxsize, + cmd, parent); + + case ELF_K_AR: + return file_read_ar (fildes, map_address, offset, maxsize, cmd, parent); + + default: + break; + } + + /* This case is easy. Since we cannot do anything with this file + create a dummy descriptor. */ + return allocate_elf (fildes, map_address, offset, maxsize, cmd, parent, + ELF_K_NONE, 0); +} + + +static Elf * +read_unmmaped_file (int fildes, off_t offset, size_t maxsize, Elf_Cmd cmd, + Elf *parent) +{ + /* We have to find out what kind of file this is. We handle ELF + files and archives. To find out what we have we must read the + header. The identification header for an ELF file is EI_NIDENT + bytes in size, but we read the whole ELF header since we will + need it anyway later. For archives the header in SARMAG bytes + long. Read the maximum of these numbers. + + XXX We have to change this for the extended `ar' format some day. + + Use a union to ensure alignment. We might later access the + memory as a ElfXX_Ehdr. */ + union + { + Elf64_Ehdr ehdr; + unsigned char header[MAX (sizeof (Elf64_Ehdr), SARMAG)]; + } mem; + + /* Read the head of the file. */ + ssize_t nread = pread_retry (fildes, mem.header, + MIN (MAX (sizeof (Elf64_Ehdr), SARMAG), + maxsize), + offset); + if (unlikely (nread == -1)) + { + /* We cannot even read the head of the file. Maybe FILDES is associated + with an unseekable device. This is nothing we can handle. */ + __libelf_seterrno (ELF_E_INVALID_FILE); + return NULL; + } + + /* See what kind of object we have here. */ + Elf_Kind kind = determine_kind (mem.header, nread); + + switch (kind) + { + case ELF_K_AR: + return file_read_ar (fildes, NULL, offset, maxsize, cmd, parent); + + case ELF_K_ELF: + /* Make sure at least the ELF header is contained in the file. */ + if ((size_t) nread >= (mem.header[EI_CLASS] == ELFCLASS32 + ? sizeof (Elf32_Ehdr) : sizeof (Elf64_Ehdr))) + return file_read_elf (fildes, NULL, mem.header, offset, maxsize, cmd, + parent); + /* FALLTHROUGH */ + + default: + break; + } + + /* This case is easy. Since we cannot do anything with this file + create a dummy descriptor. */ + return allocate_elf (fildes, NULL, offset, maxsize, cmd, parent, + ELF_K_NONE, 0); +} + + +/* Open a file for reading. If possible we will try to mmap() the file. */ +static struct Elf * +read_file (int fildes, off_t offset, size_t maxsize, + Elf_Cmd cmd, Elf *parent) +{ + void *map_address = NULL; + int use_mmap = (cmd == ELF_C_READ_MMAP || cmd == ELF_C_RDWR_MMAP + || cmd == ELF_C_WRITE_MMAP + || cmd == ELF_C_READ_MMAP_PRIVATE); + + if (use_mmap) + { + if (parent == NULL) + { + if (maxsize == ~((size_t) 0)) + { + /* We don't know in the moment how large the file is. + Determine it now. */ + struct stat st; + + if (fstat (fildes, &st) == 0 + && (sizeof (size_t) >= sizeof (st.st_size) + || st.st_size <= ~((size_t) 0))) + maxsize = (size_t) st.st_size; + } + + /* We try to map the file ourself. */ + map_address = mmap (NULL, maxsize, (cmd == ELF_C_READ_MMAP + ? PROT_READ + : PROT_READ|PROT_WRITE), + cmd == ELF_C_READ_MMAP_PRIVATE + || cmd == ELF_C_READ_MMAP + ? MAP_PRIVATE : MAP_SHARED, + fildes, offset); + + if (map_address == MAP_FAILED) + map_address = NULL; + } + else + { + /* The parent is already loaded. Use it. */ + assert (maxsize != ~((size_t) 0)); + + map_address = parent->map_address; + } + } + + /* If we have the file in memory optimize the access. */ + if (map_address != NULL) + { + assert (map_address != MAP_FAILED); + + struct Elf *result = __libelf_read_mmaped_file (fildes, map_address, + offset, maxsize, cmd, + parent); + + /* If something went wrong during the initialization unmap the + memory if we mmaped here. */ + if (result == NULL + && (parent == NULL + || parent->map_address != map_address)) + munmap (map_address, maxsize); + else if (parent == NULL) + /* Remember that we mmap()ed the memory. */ + result->flags |= ELF_F_MMAPPED; + + return result; + } + + /* Otherwise we have to do it the hard way. We read as much as necessary + from the file whenever we need information which is not available. */ + return read_unmmaped_file (fildes, offset, maxsize, cmd, parent); +} + + +/* Find the entry with the long names for the content of this archive. */ +static const char * +read_long_names (Elf *elf) +{ + off_t offset = SARMAG; /* This is the first entry. */ + struct ar_hdr hdrm; + struct ar_hdr *hdr; + char *newp; + size_t len; + + while (1) + { + if (elf->map_address != NULL) + { + if ((size_t) offset > elf->maximum_size + || elf->maximum_size - offset < sizeof (struct ar_hdr)) + return NULL; + + /* The data is mapped. */ + hdr = (struct ar_hdr *) (elf->map_address + offset); + } + else + { + /* Read the header from the file. */ + if (unlikely (pread_retry (elf->fildes, &hdrm, sizeof (hdrm), + elf->start_offset + offset) + != sizeof (hdrm))) + return NULL; + + hdr = &hdrm; + } + + len = atol (hdr->ar_size); + + if (memcmp (hdr->ar_name, "// ", 16) == 0) + break; + + offset += sizeof (struct ar_hdr) + ((len + 1) & ~1l); + } + + /* Due to the stupid format of the long name table entry (which are not + NUL terminted) we have to provide an appropriate representation anyhow. + Therefore we always make a copy which has the appropriate form. */ + newp = (char *) malloc (len); + if (newp != NULL) + { + char *runp; + + if (elf->map_address != NULL) + { + if (len > elf->maximum_size - offset - sizeof (struct ar_hdr)) + goto too_much; + /* Simply copy it over. */ + elf->state.ar.long_names = (char *) memcpy (newp, + elf->map_address + offset + + sizeof (struct ar_hdr), + len); + } + else + { + if (unlikely ((size_t) pread_retry (elf->fildes, newp, len, + elf->start_offset + offset + + sizeof (struct ar_hdr)) + != len)) + { + too_much: + /* We were not able to read all data. */ + free (newp); + elf->state.ar.long_names = NULL; + return NULL; + } + elf->state.ar.long_names = newp; + } + + elf->state.ar.long_names_len = len; + + /* Now NUL-terminate the strings. */ + runp = newp; + while (1) + { + char *startp = runp; + runp = (char *) memchr (runp, '/', newp + len - runp); + if (runp == NULL) + { + /* This was the last entry. Clear any left overs. */ + memset (startp, '\0', newp + len - startp); + break; + } + + /* NUL-terminate the string. */ + *runp = '\0'; + + /* Skip the NUL byte and the \012. */ + runp += 2; + + /* A sanity check. Somebody might have generated invalid + archive. */ + if (runp >= newp + len) + break; + } + } + + return newp; +} + + +/* Read the next archive header. */ +int +internal_function +__libelf_next_arhdr_wrlock (elf) + Elf *elf; +{ + struct ar_hdr *ar_hdr; + Elf_Arhdr *elf_ar_hdr; + + if (elf->map_address != NULL) + { + /* See whether this entry is in the file. */ + if (unlikely ((size_t) elf->state.ar.offset + > elf->start_offset + elf->maximum_size + || (elf->start_offset + elf->maximum_size + - elf->state.ar.offset) < sizeof (struct ar_hdr))) + { + /* This record is not anymore in the file. */ + __libelf_seterrno (ELF_E_RANGE); + return -1; + } + ar_hdr = (struct ar_hdr *) (elf->map_address + elf->state.ar.offset); + } + else + { + ar_hdr = &elf->state.ar.ar_hdr; + + if (unlikely (pread_retry (elf->fildes, ar_hdr, sizeof (struct ar_hdr), + elf->state.ar.offset) + != sizeof (struct ar_hdr))) + { + /* Something went wrong while reading the file. */ + __libelf_seterrno (ELF_E_RANGE); + return -1; + } + } + + /* One little consistency check. */ + if (unlikely (memcmp (ar_hdr->ar_fmag, ARFMAG, 2) != 0)) + { + /* This is no valid archive. */ + __libelf_seterrno (ELF_E_ARCHIVE_FMAG); + return -1; + } + + /* Copy the raw name over to a NUL terminated buffer. */ + *((char *) mempcpy (elf->state.ar.raw_name, ar_hdr->ar_name, 16)) = '\0'; + + elf_ar_hdr = &elf->state.ar.elf_ar_hdr; + + /* Now convert the `struct ar_hdr' into `Elf_Arhdr'. + Determine whether this is a special entry. */ + if (ar_hdr->ar_name[0] == '/') + { + if (ar_hdr->ar_name[1] == ' ' + && memcmp (ar_hdr->ar_name, "/ ", 16) == 0) + /* This is the index. */ + elf_ar_hdr->ar_name = memcpy (elf->state.ar.ar_name, "/", 2); + else if (ar_hdr->ar_name[1] == 'S' + && memcmp (ar_hdr->ar_name, "/SYM64/ ", 16) == 0) + /* 64-bit index. */ + elf_ar_hdr->ar_name = memcpy (elf->state.ar.ar_name, "/SYM64/", 8); + else if (ar_hdr->ar_name[1] == '/' + && memcmp (ar_hdr->ar_name, "// ", 16) == 0) + /* This is the array with the long names. */ + elf_ar_hdr->ar_name = memcpy (elf->state.ar.ar_name, "//", 3); + else if (likely (isdigit (ar_hdr->ar_name[1]))) + { + size_t offset; + + /* This is a long name. First we have to read the long name + table, if this hasn't happened already. */ + if (unlikely (elf->state.ar.long_names == NULL + && read_long_names (elf) == NULL)) + { + /* No long name table although it is reference. The archive is + broken. */ + __libelf_seterrno (ELF_E_INVALID_ARCHIVE); + return -1; + } + + offset = atol (ar_hdr->ar_name + 1); + if (unlikely (offset >= elf->state.ar.long_names_len)) + { + /* The index in the long name table is larger than the table. */ + __libelf_seterrno (ELF_E_INVALID_ARCHIVE); + return -1; + } + elf_ar_hdr->ar_name = elf->state.ar.long_names + offset; + } + else + { + /* This is none of the known special entries. */ + __libelf_seterrno (ELF_E_INVALID_ARCHIVE); + return -1; + } + } + else + { + char *endp; + + /* It is a normal entry. Copy over the name. */ + endp = (char *) memccpy (elf->state.ar.ar_name, ar_hdr->ar_name, + '/', 16); + if (endp != NULL) + endp[-1] = '\0'; + else + { + /* In the old BSD style of archive, there is no / terminator. + Instead, there is space padding at the end of the name. */ + size_t i = 15; + do + elf->state.ar.ar_name[i] = '\0'; + while (i > 0 && elf->state.ar.ar_name[--i] == ' '); + } + + elf_ar_hdr->ar_name = elf->state.ar.ar_name; + } + + if (unlikely (ar_hdr->ar_size[0] == ' ')) + /* Something is really wrong. We cannot live without a size for + the member since it will not be possible to find the next + archive member. */ + { + __libelf_seterrno (ELF_E_INVALID_ARCHIVE); + return -1; + } + + /* Since there are no specialized functions to convert ASCII to + time_t, uid_t, gid_t, mode_t, and off_t we use either atol or + atoll depending on the size of the types. We are also prepared + for the case where the whole field in the `struct ar_hdr' is + filled in which case we cannot simply use atol/l but instead have + to create a temporary copy. */ + +#define INT_FIELD(FIELD) \ + do \ + { \ + char buf[sizeof (ar_hdr->FIELD) + 1]; \ + const char *string = ar_hdr->FIELD; \ + if (ar_hdr->FIELD[sizeof (ar_hdr->FIELD) - 1] != ' ') \ + { \ + *((char *) mempcpy (buf, ar_hdr->FIELD, sizeof (ar_hdr->FIELD))) \ + = '\0'; \ + string = buf; \ + } \ + if (sizeof (elf_ar_hdr->FIELD) <= sizeof (long int)) \ + elf_ar_hdr->FIELD = (__typeof (elf_ar_hdr->FIELD)) atol (string); \ + else \ + elf_ar_hdr->FIELD = (__typeof (elf_ar_hdr->FIELD)) atoll (string); \ + } \ + while (0) + + INT_FIELD (ar_date); + INT_FIELD (ar_uid); + INT_FIELD (ar_gid); + INT_FIELD (ar_mode); + INT_FIELD (ar_size); + + /* Truncated file? */ + size_t maxsize; + maxsize = elf->maximum_size - elf->state.ar.offset - sizeof (struct ar_hdr); + if ((size_t) elf_ar_hdr->ar_size > maxsize) + elf_ar_hdr->ar_size = maxsize; + + return 0; +} + + +/* We were asked to return a clone of an existing descriptor. This + function must be called with the lock on the parent descriptor + being held. */ +static Elf * +dup_elf (int fildes, Elf_Cmd cmd, Elf *ref) +{ + struct Elf *result; + + if (fildes == -1) + /* Allow the user to pass -1 as the file descriptor for the new file. */ + fildes = ref->fildes; + /* The file descriptor better should be the same. If it was disconnected + already (using `elf_cntl') we do not test it. */ + else if (unlikely (ref->fildes != -1 && fildes != ref->fildes)) + { + __libelf_seterrno (ELF_E_FD_MISMATCH); + return NULL; + } + + /* The mode must allow reading. I.e., a descriptor creating with a + command different then ELF_C_READ, ELF_C_WRITE and ELF_C_RDWR is + not allowed. */ + if (unlikely (ref->cmd != ELF_C_READ && ref->cmd != ELF_C_READ_MMAP + && ref->cmd != ELF_C_WRITE && ref->cmd != ELF_C_WRITE_MMAP + && ref->cmd != ELF_C_RDWR && ref->cmd != ELF_C_RDWR_MMAP + && ref->cmd != ELF_C_READ_MMAP_PRIVATE)) + { + __libelf_seterrno (ELF_E_INVALID_OP); + return NULL; + } + + /* Now it is time to distinguish between reading normal files and + archives. Normal files can easily be handled be incrementing the + reference counter and return the same descriptor. */ + if (ref->kind != ELF_K_AR) + { + ++ref->ref_count; + return ref; + } + + /* This is an archive. We must create a descriptor for the archive + member the internal pointer of the archive file desriptor is + pointing to. First read the header of the next member if this + has not happened already. */ + if (ref->state.ar.elf_ar_hdr.ar_name == NULL + && __libelf_next_arhdr_wrlock (ref) != 0) + /* Something went wrong. Maybe there is no member left. */ + return NULL; + + /* We have all the information we need about the next archive member. + Now create a descriptor for it. */ + result = read_file (fildes, ref->state.ar.offset + sizeof (struct ar_hdr), + ref->state.ar.elf_ar_hdr.ar_size, cmd, ref); + + /* Enlist this new descriptor in the list of children. */ + if (result != NULL) + { + result->next = ref->state.ar.children; + ref->state.ar.children = result; + } + + return result; +} + + +/* Return desriptor for empty file ready for writing. */ +static struct Elf * +write_file (int fd, Elf_Cmd cmd) +{ + /* We simply create an empty `Elf' structure. */ +#define NSCNSALLOC 10 + Elf *result = allocate_elf (fd, NULL, 0, 0, cmd, NULL, ELF_K_ELF, + NSCNSALLOC * sizeof (Elf_Scn)); + + if (result != NULL) + { + /* We have to write to the file in any case. */ + result->flags = ELF_F_DIRTY; + + /* Some more or less arbitrary value. */ + result->state.elf.scnincr = NSCNSALLOC; + + /* We have allocated room for some sections. */ + assert (offsetof (struct Elf, state.elf32.scns) + == offsetof (struct Elf, state.elf64.scns)); + result->state.elf.scns_last = &result->state.elf32.scns; + result->state.elf32.scns.max = NSCNSALLOC; + } + + return result; +} + + +/* Return a descriptor for the file belonging to FILDES. */ +Elf * +elf_begin (fildes, cmd, ref) + int fildes; + Elf_Cmd cmd; + Elf *ref; +{ + Elf *retval; + + if (unlikely (! __libelf_version_initialized)) + { + /* Version wasn't set so far. */ + __libelf_seterrno (ELF_E_NO_VERSION); + return NULL; + } + + if (ref != NULL) + /* Make sure the descriptor is not suddenly going away. */ + rwlock_rdlock (ref->lock); + else if (unlikely (fcntl (fildes, F_GETFL) == -1 && errno == EBADF)) + { + /* We cannot do anything productive without a file descriptor. */ + __libelf_seterrno (ELF_E_INVALID_FILE); + return NULL; + } + + Elf *lock_dup_elf () + { + /* We need wrlock to dup an archive. */ + if (ref->kind == ELF_K_AR) + { + rwlock_unlock (ref->lock); + rwlock_wrlock (ref->lock); + } + + /* Duplicate the descriptor. */ + return dup_elf (fildes, cmd, ref); + } + + switch (cmd) + { + case ELF_C_NULL: + /* We simply return a NULL pointer. */ + retval = NULL; + break; + + case ELF_C_READ_MMAP_PRIVATE: + /* If we have a reference it must also be opened this way. */ + if (unlikely (ref != NULL && ref->cmd != ELF_C_READ_MMAP_PRIVATE)) + { + __libelf_seterrno (ELF_E_INVALID_CMD); + retval = NULL; + break; + } + /* FALLTHROUGH */ + + case ELF_C_READ: + case ELF_C_READ_MMAP: + if (ref != NULL) + retval = lock_dup_elf (); + else + /* Create descriptor for existing file. */ + retval = read_file (fildes, 0, ~((size_t) 0), cmd, NULL); + break; + + case ELF_C_RDWR: + case ELF_C_RDWR_MMAP: + /* If we have a REF object it must also be opened using this + command. */ + if (ref != NULL) + { + if (unlikely (ref->cmd != ELF_C_RDWR && ref->cmd != ELF_C_RDWR_MMAP + && ref->cmd != ELF_C_WRITE + && ref->cmd != ELF_C_WRITE_MMAP)) + { + /* This is not ok. REF must also be opened for writing. */ + __libelf_seterrno (ELF_E_INVALID_CMD); + retval = NULL; + } + else + retval = lock_dup_elf (); + } + else + /* Create descriptor for existing file. */ + retval = read_file (fildes, 0, ~((size_t) 0), cmd, NULL); + break; + + case ELF_C_WRITE: + case ELF_C_WRITE_MMAP: + /* We ignore REF and prepare a descriptor to write a new file. */ + retval = write_file (fildes, cmd); + break; + + default: + __libelf_seterrno (ELF_E_INVALID_CMD); + retval = NULL; + break; + } + + /* Release the lock. */ + if (ref != NULL) + rwlock_unlock (ref->lock); + + return retval; +} +INTDEF(elf_begin) diff --git a/3rdparty/elfutils/libelf/elf_clone.c b/3rdparty/elfutils/libelf/elf_clone.c new file mode 100644 index 0000000..e6fe472 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf_clone.c @@ -0,0 +1,81 @@ +/* Create clone of a given descriptor. + Copyright (C) 2003, 2004 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2003. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <stddef.h> +#include "libelfP.h" +#include "common.h" + + +Elf * +elf_clone (Elf *elf, Elf_Cmd cmd) +{ + Elf *retval = NULL; + + if (elf == NULL) + /* Some earlier mistake. */ + return NULL; + + /* Make sure the descriptor is not suddenly going away. */ + rwlock_rdlock (elf->lock); + + if (cmd != ELF_C_EMPTY) + // XXX TODO handle ELF_C_READ/WRITE etc + goto out; + + retval = allocate_elf (elf->fildes, elf->map_address, elf->start_offset, + elf->maximum_size, elf->cmd, elf->parent, elf->kind, + elf->state.elf32.scns.max * sizeof (Elf_Scn)); + if (retval != NULL) + { + /* We have to write to the file in any case. */ + retval->flags = ELF_F_DIRTY; + + /* Some more or less arbitrary value. */ + retval->state.elf.scnincr = 10; + + /* We have allocated room for some sections. */ + assert (offsetof (struct Elf, state.elf32.scns) + == offsetof (struct Elf, state.elf64.scns)); + retval->state.elf.scns_last = &retval->state.elf32.scns; + retval->state.elf32.scns.max = elf->state.elf32.scns.max; + + retval->class = elf->class; + } + + /* Release the lock. */ + out: + rwlock_unlock (elf->lock); + + return retval; +} diff --git a/3rdparty/elfutils/libelf/elf_cntl.c b/3rdparty/elfutils/libelf/elf_cntl.c new file mode 100644 index 0000000..a3c5805 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf_cntl.c @@ -0,0 +1,83 @@ +/* Control an ELF file desrciptor. + Copyright (C) 1998, 1999, 2000, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <unistd.h> + +#include "libelfP.h" + + +int +elf_cntl (elf, cmd) + Elf *elf; + Elf_Cmd cmd; +{ + int result = 0; + + if (elf == NULL) + return -1; + + if (elf->fildes == -1) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return -1; + } + + rwlock_wrlock (elf->lock); + + switch (cmd) + { + case ELF_C_FDREAD: + /* If not all of the file is in the memory read it now. */ + if (elf->map_address == NULL && __libelf_readall (elf) == NULL) + { + /* We were not able to read everything. */ + result = -1; + break; + } + /* FALLTHROUGH */ + + case ELF_C_FDDONE: + /* Mark the file descriptor as not usable. */ + elf->fildes = -1; + break; + + default: + __libelf_seterrno (ELF_E_INVALID_CMD); + result = -1; + break; + } + + rwlock_unlock (elf->lock); + + return result; +} diff --git a/3rdparty/elfutils/libelf/elf_end.c b/3rdparty/elfutils/libelf/elf_end.c new file mode 100644 index 0000000..d4ae051 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf_end.c @@ -0,0 +1,232 @@ +/* Free resources associated with Elf descriptor. + Copyright (C) 1998,1999,2000,2001,2002,2004,2005,2007 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <stddef.h> +#include <stdlib.h> +#include <sys/mman.h> + +#include "libelfP.h" + + +int +elf_end (elf) + Elf *elf; +{ + Elf *parent; + + if (elf == NULL) + /* This is allowed and is a no-op. */ + return 0; + + /* Make sure we are alone. */ + rwlock_wrlock (elf->lock); + + if (elf->ref_count != 0 && --elf->ref_count != 0) + { + /* Not yet the last activation. */ + int result = elf->ref_count; + rwlock_unlock (elf->lock); + return result; + } + + if (elf->kind == ELF_K_AR) + { + /* We cannot remove the descriptor now since we still have some + descriptors which depend on it. But we can free the archive + symbol table since this is only available via the archive ELF + descriptor. The long name table cannot be freed yet since + the archive headers for the ELF files in the archive point + into this array. */ + if (elf->state.ar.ar_sym != (Elf_Arsym *) -1l) + free (elf->state.ar.ar_sym); + elf->state.ar.ar_sym = NULL; + + if (elf->state.ar.children != NULL) + return 0; + } + + /* Remove this structure from the children list. */ + parent = elf->parent; + if (parent != NULL) + { + /* This is tricky. Lock must be acquire from the father to + the child but here we already have the child lock. We + solve this problem by giving free the child lock. The + state of REF_COUNT==0 is handled all over the library, so + this should be ok. */ + rwlock_unlock (elf->lock); + rwlock_rdlock (parent->lock); + rwlock_wrlock (elf->lock); + + if (parent->state.ar.children == elf) + parent->state.ar.children = elf->next; + else + { + struct Elf *child = parent->state.ar.children; + + while (child->next != elf) + child = child->next; + + child->next = elf->next; + } + + rwlock_unlock (parent->lock); + } + + /* This was the last activation. Free all resources. */ + switch (elf->kind) + { + case ELF_K_AR: + if (elf->state.ar.long_names != NULL) + free (elf->state.ar.long_names); + break; + + case ELF_K_ELF: + { + Elf_Data_Chunk *rawchunks + = (elf->class == ELFCLASS32 + || (offsetof (struct Elf, state.elf32.rawchunks) + == offsetof (struct Elf, state.elf64.rawchunks)) + ? elf->state.elf32.rawchunks + : elf->state.elf64.rawchunks); + while (rawchunks != NULL) + { + Elf_Data_Chunk *next = rawchunks->next; + if (rawchunks->dummy_scn.flags & ELF_F_MALLOCED) + free (rawchunks->data.d.d_buf); + free (rawchunks); + rawchunks = next; + } + + Elf_ScnList *list = (elf->class == ELFCLASS32 + || (offsetof (struct Elf, state.elf32.scns) + == offsetof (struct Elf, state.elf64.scns)) + ? &elf->state.elf32.scns + : &elf->state.elf64.scns); + + do + { + /* Free all separately allocated section headers. */ + size_t cnt = list->max; + + while (cnt-- > 0) + { + /* These pointers can be NULL; it's safe to use + 'free' since it will check for this. */ + Elf_Scn *scn = &list->data[cnt]; + Elf_Data_List *runp; + + if ((scn->shdr_flags & ELF_F_MALLOCED) != 0) + /* It doesn't matter which pointer. */ + free (scn->shdr.e32); + + /* If the file has the same byte order and the + architecture doesn't require overly stringent + alignment the raw data buffer is the same as the + one used for presenting to the caller. */ + if (scn->data_base != scn->rawdata_base) + free (scn->data_base); + + /* The section data is allocated if we couldn't mmap + the file. */ + if (elf->map_address == NULL) + free (scn->rawdata_base); + + /* Free the list of data buffers for the section. + We don't free the buffers themselves since this + is the users job. */ + runp = scn->data_list.next; + while (runp != NULL) + { + Elf_Data_List *oldp = runp; + runp = runp->next; + if ((oldp->flags & ELF_F_MALLOCED) != 0) + free (oldp); + } + } + + /* Free the memory for the array. */ + Elf_ScnList *oldp = list; + list = list->next; + assert (list == NULL || oldp->cnt == oldp->max); + if (oldp != (elf->class == ELFCLASS32 + || (offsetof (struct Elf, state.elf32.scns) + == offsetof (struct Elf, state.elf64.scns)) + ? &elf->state.elf32.scns + : &elf->state.elf64.scns)) + free (oldp); + } + while (list != NULL); + } + + /* Free the section header. */ + if (elf->state.elf.shdr_malloced != 0) + free (elf->class == ELFCLASS32 + || (offsetof (struct Elf, state.elf32.shdr) + == offsetof (struct Elf, state.elf64.shdr)) + ? (void *) elf->state.elf32.shdr + : (void *) elf->state.elf64.shdr); + + /* Free the program header. */ + if ((elf->state.elf.phdr_flags & ELF_F_MALLOCED) != 0) + free (elf->class == ELFCLASS32 + || (offsetof (struct Elf, state.elf32.phdr) + == offsetof (struct Elf, state.elf64.phdr)) + ? (void *) elf->state.elf32.phdr + : (void *) elf->state.elf64.phdr); + break; + + default: + break; + } + + if (elf->map_address != NULL && parent == NULL) + { + /* The file was read or mapped for this descriptor. */ + if ((elf->flags & ELF_F_MALLOCED) != 0) + free (elf->map_address); + else if ((elf->flags & ELF_F_MMAPPED) != 0) + munmap (elf->map_address, elf->maximum_size); + } + + rwlock_unlock (elf->lock); + rwlock_fini (elf->lock); + + /* Finally the descriptor itself. */ + free (elf); + + return (parent != NULL && parent->ref_count == 0 + ? INTUSE(elf_end) (parent) : 0); +} +INTDEF(elf_end) diff --git a/3rdparty/elfutils/libelf/elf_error.c b/3rdparty/elfutils/libelf/elf_error.c new file mode 100644 index 0000000..aa7f917 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf_error.c @@ -0,0 +1,309 @@ +/* Error handling in libelf. + Copyright (C) 1998-2010 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <libintl.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdlib.h> + +#include "libelfP.h" + + +/* The error number. */ +static __thread int global_error; + + +int +elf_errno (void) +{ + int result = global_error; + global_error = ELF_E_NOERROR; + return result; +} + + +/* Return the appropriate message for the error. */ +static const char msgstr[] = +{ +#define ELF_E_NOERROR_IDX 0 + N_("no error") + "\0" +#define ELF_E_UNKNOWN_ERROR_IDX (ELF_E_NOERROR_IDX + sizeof "no error") + N_("unknown error") + "\0" +#define ELF_E_UNKNOWN_VERSION_IDX \ + (ELF_E_UNKNOWN_ERROR_IDX + sizeof "unknown error") + N_("unknown version") + "\0" +#define ELF_E_UNKNOWN_TYPE_IDX \ + (ELF_E_UNKNOWN_VERSION_IDX + sizeof "unknown version") + N_("unknown type") + "\0" +#define ELF_E_INVALID_HANDLE_IDX \ + (ELF_E_UNKNOWN_TYPE_IDX + sizeof "unknown type") + N_("invalid `Elf' handle") + "\0" +#define ELF_E_SOURCE_SIZE_IDX \ + (ELF_E_INVALID_HANDLE_IDX + sizeof "invalid `Elf' handle") + N_("invalid size of source operand") + "\0" +#define ELF_E_DEST_SIZE_IDX \ + (ELF_E_SOURCE_SIZE_IDX + sizeof "invalid size of source operand") + N_("invalid size of destination operand") + "\0" +#define ELF_E_INVALID_ENCODING_IDX \ + (ELF_E_DEST_SIZE_IDX + sizeof "invalid size of destination operand") + N_("invalid encoding") + "\0" +#define ELF_E_NOMEM_IDX \ + (ELF_E_INVALID_ENCODING_IDX + sizeof "invalid encoding") + N_("out of memory") + "\0" +#define ELF_E_INVALID_FILE_IDX \ + (ELF_E_NOMEM_IDX + sizeof "out of memory") + N_("invalid file descriptor") + "\0" +#define ELF_E_INVALID_OP_IDX \ + (ELF_E_INVALID_FILE_IDX + sizeof "invalid file descriptor") + N_("invalid operation") + "\0" +#define ELF_E_NO_VERSION_IDX \ + (ELF_E_INVALID_OP_IDX + sizeof "invalid operation") + N_("ELF version not set") + "\0" +#define ELF_E_INVALID_CMD_IDX \ + (ELF_E_NO_VERSION_IDX + sizeof "ELF version not set") + N_("invalid command") + "\0" +#define ELF_E_RANGE_IDX \ + (ELF_E_INVALID_CMD_IDX + sizeof "invalid command") + N_("offset out of range") + "\0" +#define ELF_E_ARCHIVE_FMAG_IDX \ + (ELF_E_RANGE_IDX + sizeof "offset out of range") + N_("invalid fmag field in archive header") + "\0" +#define ELF_E_INVALID_ARCHIVE_IDX \ + (ELF_E_ARCHIVE_FMAG_IDX + sizeof "invalid fmag field in archive header") + N_("invalid archive file") + "\0" +#define ELF_E_NO_ARCHIVE_IDX \ + (ELF_E_INVALID_ARCHIVE_IDX + sizeof "invalid archive file") + N_("descriptor is not for an archive") + "\0" +#define ELF_E_NO_INDEX_IDX \ + (ELF_E_NO_ARCHIVE_IDX + sizeof "descriptor is not for an archive") + N_("no index available") + "\0" +#define ELF_E_READ_ERROR_IDX \ + (ELF_E_NO_INDEX_IDX + sizeof "no index available") + N_("cannot read data from file") + "\0" +#define ELF_E_WRITE_ERROR_IDX \ + (ELF_E_READ_ERROR_IDX + sizeof "cannot read data from file") + N_("cannot write data to file") + "\0" +#define ELF_E_INVALID_CLASS_IDX \ + (ELF_E_WRITE_ERROR_IDX + sizeof "cannot write data to file") + N_("invalid binary class") + "\0" +#define ELF_E_INVALID_INDEX_IDX \ + (ELF_E_INVALID_CLASS_IDX + sizeof "invalid binary class") + N_("invalid section index") + "\0" +#define ELF_E_INVALID_OPERAND_IDX \ + (ELF_E_INVALID_INDEX_IDX + sizeof "invalid section index") + N_("invalid operand") + "\0" +#define ELF_E_INVALID_SECTION_IDX \ + (ELF_E_INVALID_OPERAND_IDX + sizeof "invalid operand") + N_("invalid section") + "\0" +#define ELF_E_INVALID_COMMAND_IDX \ + (ELF_E_INVALID_SECTION_IDX + sizeof "invalid section") + N_("invalid command") + "\0" +#define ELF_E_WRONG_ORDER_EHDR_IDX \ + (ELF_E_INVALID_COMMAND_IDX + sizeof "invalid command") + N_("executable header not created first") + "\0" +#define ELF_E_FD_DISABLED_IDX \ + (ELF_E_WRONG_ORDER_EHDR_IDX + sizeof "executable header not created first") + N_("file descriptor disabled") + "\0" +#define ELF_E_FD_MISMATCH_IDX \ + (ELF_E_FD_DISABLED_IDX + sizeof "file descriptor disabled") + N_("archive/member file descriptor mismatch") + "\0" +#define ELF_E_OFFSET_RANGE_IDX \ + (ELF_E_FD_MISMATCH_IDX + sizeof "archive/member file descriptor mismatch") + N_("offset out of range") + "\0" +#define ELF_E_NOT_NUL_SECTION_IDX \ + (ELF_E_OFFSET_RANGE_IDX + sizeof "offset out of range") + N_("cannot manipulate null section") + "\0" +#define ELF_E_DATA_MISMATCH_IDX \ + (ELF_E_NOT_NUL_SECTION_IDX + sizeof "cannot manipulate null section") + N_("data/scn mismatch") + "\0" +#define ELF_E_INVALID_SECTION_HEADER_IDX \ + (ELF_E_DATA_MISMATCH_IDX + sizeof "data/scn mismatch") + N_("invalid section header") + "\0" +#define ELF_E_INVALID_DATA_IDX \ + (ELF_E_INVALID_SECTION_HEADER_IDX + sizeof "invalid section header") + N_("invalid data") + "\0" +#define ELF_E_DATA_ENCODING_IDX \ + (ELF_E_INVALID_DATA_IDX + sizeof "invalid data") + N_("unknown data encoding") + "\0" +#define ELF_E_SECTION_TOO_SMALL_IDX \ + (ELF_E_DATA_ENCODING_IDX + sizeof "unknown data encoding") + N_("section `sh_size' too small for data") + "\0" +#define ELF_E_INVALID_ALIGN_IDX \ + (ELF_E_SECTION_TOO_SMALL_IDX + sizeof "section `sh_size' too small for data") + N_("invalid section alignment") + "\0" +#define ELF_E_INVALID_SHENTSIZE_IDX \ + (ELF_E_INVALID_ALIGN_IDX + sizeof "invalid section alignment") + N_("invalid section entry size") + "\0" +#define ELF_E_UPDATE_RO_IDX \ + (ELF_E_INVALID_SHENTSIZE_IDX + sizeof "invalid section entry size") + N_("update() for write on read-only file") + "\0" +#define ELF_E_NOFILE_IDX \ + (ELF_E_UPDATE_RO_IDX + sizeof "update() for write on read-only file") + N_("no such file") + "\0" +#define ELF_E_GROUP_NOT_REL_IDX \ + (ELF_E_NOFILE_IDX + sizeof "no such file") + N_("only relocatable files can contain section groups") + "\0" +#define ELF_E_INVALID_PHDR_IDX \ + (ELF_E_GROUP_NOT_REL_IDX \ + + sizeof "only relocatable files can contain section groups") + N_("program header only allowed in executables, shared objects, and \ +core files") + "\0" +#define ELF_E_NO_PHDR_IDX \ + (ELF_E_INVALID_PHDR_IDX \ + + sizeof "program header only allowed in executables, shared objects, and \ +core files") + N_("file has no program header") + "\0" +#define ELF_E_INVALID_OFFSET_IDX \ + (ELF_E_NO_PHDR_IDX \ + + sizeof "file has no program header") + N_("invalid offset") +}; + + +static const uint_fast16_t msgidx[ELF_E_NUM] = +{ + [ELF_E_NOERROR] = ELF_E_NOERROR_IDX, + [ELF_E_UNKNOWN_ERROR] = ELF_E_UNKNOWN_ERROR_IDX, + [ELF_E_UNKNOWN_VERSION] = ELF_E_UNKNOWN_VERSION_IDX, + [ELF_E_UNKNOWN_TYPE] = ELF_E_UNKNOWN_TYPE_IDX, + [ELF_E_INVALID_HANDLE] = ELF_E_INVALID_HANDLE_IDX, + [ELF_E_SOURCE_SIZE] = ELF_E_SOURCE_SIZE_IDX, + [ELF_E_DEST_SIZE] = ELF_E_DEST_SIZE_IDX, + [ELF_E_INVALID_ENCODING] = ELF_E_INVALID_ENCODING_IDX, + [ELF_E_NOMEM] = ELF_E_NOMEM_IDX, + [ELF_E_INVALID_FILE] = ELF_E_INVALID_FILE_IDX, + [ELF_E_INVALID_OP] = ELF_E_INVALID_OP_IDX, + [ELF_E_NO_VERSION] = ELF_E_NO_VERSION_IDX, + [ELF_E_INVALID_CMD] = ELF_E_INVALID_CMD_IDX, + [ELF_E_RANGE] = ELF_E_RANGE_IDX, + [ELF_E_ARCHIVE_FMAG] = ELF_E_ARCHIVE_FMAG_IDX, + [ELF_E_INVALID_ARCHIVE] = ELF_E_INVALID_ARCHIVE_IDX, + [ELF_E_NO_ARCHIVE] = ELF_E_NO_ARCHIVE_IDX, + [ELF_E_NO_INDEX] = ELF_E_NO_INDEX_IDX, + [ELF_E_READ_ERROR] = ELF_E_READ_ERROR_IDX, + [ELF_E_WRITE_ERROR] = ELF_E_WRITE_ERROR_IDX, + [ELF_E_INVALID_CLASS] = ELF_E_INVALID_CLASS_IDX, + [ELF_E_INVALID_INDEX] = ELF_E_INVALID_INDEX_IDX, + [ELF_E_INVALID_OPERAND] = ELF_E_INVALID_OPERAND_IDX, + [ELF_E_INVALID_SECTION] = ELF_E_INVALID_SECTION_IDX, + [ELF_E_INVALID_COMMAND] = ELF_E_INVALID_COMMAND_IDX, + [ELF_E_WRONG_ORDER_EHDR] = ELF_E_WRONG_ORDER_EHDR_IDX, + [ELF_E_FD_DISABLED] = ELF_E_FD_DISABLED_IDX, + [ELF_E_FD_MISMATCH] = ELF_E_FD_MISMATCH_IDX, + [ELF_E_OFFSET_RANGE] = ELF_E_OFFSET_RANGE_IDX, + [ELF_E_NOT_NUL_SECTION] = ELF_E_NOT_NUL_SECTION_IDX, + [ELF_E_DATA_MISMATCH] = ELF_E_DATA_MISMATCH_IDX, + [ELF_E_INVALID_SECTION_HEADER] = ELF_E_INVALID_SECTION_HEADER_IDX, + [ELF_E_INVALID_DATA] = ELF_E_INVALID_DATA_IDX, + [ELF_E_DATA_ENCODING] = ELF_E_DATA_ENCODING_IDX, + [ELF_E_SECTION_TOO_SMALL] = ELF_E_SECTION_TOO_SMALL_IDX, + [ELF_E_INVALID_ALIGN] = ELF_E_INVALID_ALIGN_IDX, + [ELF_E_INVALID_SHENTSIZE] = ELF_E_INVALID_SHENTSIZE_IDX, + [ELF_E_UPDATE_RO] = ELF_E_UPDATE_RO_IDX, + [ELF_E_NOFILE] = ELF_E_NOFILE_IDX, + [ELF_E_GROUP_NOT_REL] = ELF_E_GROUP_NOT_REL_IDX, + [ELF_E_INVALID_PHDR] = ELF_E_INVALID_PHDR_IDX, + [ELF_E_NO_PHDR] = ELF_E_NO_PHDR_IDX, + [ELF_E_INVALID_OFFSET] = ELF_E_INVALID_OFFSET_IDX +}; +#define nmsgidx ((int) (sizeof (msgidx) / sizeof (msgidx[0]))) + + +void +__libelf_seterrno (value) + int value; +{ + global_error = value >= 0 && value < nmsgidx ? value : ELF_E_UNKNOWN_ERROR; +} + + +const char * +elf_errmsg (error) + int error; +{ + int last_error = global_error; + + if (error == 0) + { + assert (msgidx[last_error] < sizeof (msgstr)); + return last_error != 0 ? _(msgstr + msgidx[last_error]) : NULL; + } + else if (error < -1 || error >= nmsgidx) + return _(msgstr + ELF_E_UNKNOWN_ERROR_IDX); + + assert (msgidx[error == -1 ? last_error : error] < sizeof (msgstr)); + return _(msgstr + msgidx[error == -1 ? last_error : error]); +} diff --git a/3rdparty/elfutils/libelf/elf_fill.c b/3rdparty/elfutils/libelf/elf_fill.c new file mode 100644 index 0000000..174ab45 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf_fill.c @@ -0,0 +1,47 @@ +/* Set fill byte used when constructing ELF objects. + Copyright (C) 1998, 2000, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libelf.h> + +#include "libelfP.h" + + +int __libelf_fill_byte; + + +void +elf_fill (fill) + int fill; +{ + __libelf_fill_byte = fill; +} diff --git a/3rdparty/elfutils/libelf/elf_flagdata.c b/3rdparty/elfutils/libelf/elf_flagdata.c new file mode 100644 index 0000000..ace8cc5 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf_flagdata.c @@ -0,0 +1,71 @@ +/* Manipulate ELF data flag. + Copyright (C) 2000, 2001, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libelf.h> +#include <stddef.h> + +#include "libelfP.h" + + +unsigned int +elf_flagdata (data, cmd, flags) + Elf_Data *data; + Elf_Cmd cmd; + unsigned int flags; +{ + Elf_Data_Scn *data_scn; + unsigned int result; + + if (data == NULL) + return 0; + + data_scn = (Elf_Data_Scn *) data; + + if (data_scn == NULL || unlikely (data_scn->s->elf->kind != ELF_K_ELF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return 0; + } + + if (likely (cmd == ELF_C_SET)) + result = (data_scn->s->flags |= (flags & ELF_F_DIRTY)); + else if (likely (cmd == ELF_C_CLR)) + result = (data_scn->s->flags &= ~(flags & ELF_F_DIRTY)); + else + { + __libelf_seterrno (ELF_E_INVALID_COMMAND); + return 0; + } + + return result; +} diff --git a/3rdparty/elfutils/libelf/elf_flagehdr.c b/3rdparty/elfutils/libelf/elf_flagehdr.c new file mode 100644 index 0000000..d3a320b --- /dev/null +++ b/3rdparty/elfutils/libelf/elf_flagehdr.c @@ -0,0 +1,68 @@ +/* Manipulate ELF header flags. + Copyright (C) 1999, 2000, 2001, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1999. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libelf.h> +#include <stddef.h> + +#include "libelfP.h" + + +unsigned int +elf_flagehdr (elf, cmd, flags) + Elf *elf; + Elf_Cmd cmd; + unsigned int flags; +{ + unsigned int result; + + if (elf == NULL) + return 0; + + if (unlikely (elf->kind != ELF_K_ELF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return 0; + } + + if (likely (cmd == ELF_C_SET)) + result = (elf->state.elf.ehdr_flags |= (flags & ELF_F_DIRTY)); + else if (cmd == ELF_C_CLR) + result = (elf->state.elf.ehdr_flags &= ~(flags & ELF_F_DIRTY)); + else + { + __libelf_seterrno (ELF_E_INVALID_COMMAND); + return 0; + } + + return result; +} diff --git a/3rdparty/elfutils/libelf/elf_flagelf.c b/3rdparty/elfutils/libelf/elf_flagelf.c new file mode 100644 index 0000000..b34bd4f --- /dev/null +++ b/3rdparty/elfutils/libelf/elf_flagelf.c @@ -0,0 +1,70 @@ +/* Manipulate ELF file flags. + Copyright (C) 1999, 2000, 2001, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1999. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libelf.h> +#include <stddef.h> + +#include "libelfP.h" + + +unsigned int +elf_flagelf (elf, cmd, flags) + Elf *elf; + Elf_Cmd cmd; + unsigned int flags; +{ + unsigned int result; + + if (elf == NULL) + return 0; + + if (unlikely (elf->kind != ELF_K_ELF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return 0; + } + + if (likely (cmd == ELF_C_SET)) + result = (elf->flags + |= (flags & (ELF_F_DIRTY | ELF_F_LAYOUT | ELF_F_PERMISSIVE))); + else if (likely (cmd == ELF_C_CLR)) + result = (elf->flags + &= ~(flags & (ELF_F_DIRTY | ELF_F_LAYOUT | ELF_F_PERMISSIVE))); + else + { + __libelf_seterrno (ELF_E_INVALID_COMMAND); + return 0; + } + + return result; +} diff --git a/3rdparty/elfutils/libelf/elf_flagphdr.c b/3rdparty/elfutils/libelf/elf_flagphdr.c new file mode 100644 index 0000000..2a589cc --- /dev/null +++ b/3rdparty/elfutils/libelf/elf_flagphdr.c @@ -0,0 +1,68 @@ +/* Manipulate ELF program header flags. + Copyright (C) 1999, 2000, 2001, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1999. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libelf.h> +#include <stddef.h> + +#include "libelfP.h" + + +unsigned int +elf_flagphdr (elf, cmd, flags) + Elf *elf; + Elf_Cmd cmd; + unsigned int flags; +{ + unsigned int result; + + if (elf == NULL) + return 0; + + if (unlikely (elf->kind != ELF_K_ELF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return 0; + } + + if (likely (cmd == ELF_C_SET)) + result = (elf->state.elf.phdr_flags |= (flags & ELF_F_DIRTY)); + else if (likely (cmd == ELF_C_CLR)) + result = (elf->state.elf.phdr_flags &= ~(flags & ELF_F_DIRTY)); + else + { + __libelf_seterrno (ELF_E_INVALID_COMMAND); + return 0; + } + + return result; +} diff --git a/3rdparty/elfutils/libelf/elf_flagscn.c b/3rdparty/elfutils/libelf/elf_flagscn.c new file mode 100644 index 0000000..3ff826c --- /dev/null +++ b/3rdparty/elfutils/libelf/elf_flagscn.c @@ -0,0 +1,68 @@ +/* Manipulate ELF section flags. + Copyright (C) 1999, 2000, 2001, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1999. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libelf.h> +#include <stddef.h> + +#include "libelfP.h" + + +unsigned int +elf_flagscn (scn, cmd, flags) + Elf_Scn *scn; + Elf_Cmd cmd; + unsigned int flags; +{ + unsigned int result; + + if (scn == NULL) + return 0; + + if (unlikely (scn->elf->kind != ELF_K_ELF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return 0; + } + + if (likely (cmd == ELF_C_SET)) + result = (scn->flags |= (flags & ELF_F_DIRTY)); + else if (likely (cmd == ELF_C_CLR)) + result = (scn->flags &= ~(flags & ELF_F_DIRTY)); + else + { + __libelf_seterrno (ELF_E_INVALID_COMMAND); + return 0; + } + + return result; +} diff --git a/3rdparty/elfutils/libelf/elf_flagshdr.c b/3rdparty/elfutils/libelf/elf_flagshdr.c new file mode 100644 index 0000000..8d797af --- /dev/null +++ b/3rdparty/elfutils/libelf/elf_flagshdr.c @@ -0,0 +1,68 @@ +/* Manipulate ELF section header flags. + Copyright (C) 1999, 2000, 2001, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1999. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libelf.h> +#include <stddef.h> + +#include "libelfP.h" + + +unsigned int +elf_flagshdr (scn, cmd, flags) + Elf_Scn *scn; + Elf_Cmd cmd; + unsigned int flags; +{ + unsigned int result; + + if (scn == NULL) + return 0; + + if (unlikely (scn->elf->kind != ELF_K_ELF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return 0; + } + + if (likely (cmd == ELF_C_SET)) + result = (scn->shdr_flags |= (flags & ELF_F_DIRTY)); + else if (likely (cmd == ELF_C_CLR)) + result = (scn->shdr_flags &= ~(flags & ELF_F_DIRTY)); + else + { + __libelf_seterrno (ELF_E_INVALID_COMMAND); + return 0; + } + + return result; +} diff --git a/3rdparty/elfutils/libelf/elf_getarhdr.c b/3rdparty/elfutils/libelf/elf_getarhdr.c new file mode 100644 index 0000000..f8b36b8 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf_getarhdr.c @@ -0,0 +1,74 @@ +/* Read header of next archive member. + Copyright (C) 1998, 1999, 2000, 2002, 2008 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <libelf.h> +#include <stddef.h> + +#include "libelfP.h" + + +Elf_Arhdr * +elf_getarhdr (elf) + Elf *elf; +{ + if (elf == NULL) + return NULL; + + Elf *parent = elf->parent; + + /* Calling this function is not ok for any file type but archives. */ + if (parent == NULL) + { + __libelf_seterrno (ELF_E_INVALID_OP); + return NULL; + } + + /* Make sure we have read the archive header. */ + if (parent->state.ar.elf_ar_hdr.ar_name == NULL + && __libelf_next_arhdr_wrlock (parent) != 0) + { + rwlock_wrlock (parent->lock); + int st = __libelf_next_arhdr_wrlock (parent); + rwlock_unlock (parent->lock); + + if (st != 0) + /* Something went wrong. Maybe there is no member left. */ + return NULL; + } + + /* We can be sure the parent is an archive. */ + assert (parent->kind == ELF_K_AR); + + return &parent->state.ar.elf_ar_hdr; +} diff --git a/3rdparty/elfutils/libelf/elf_getaroff.c b/3rdparty/elfutils/libelf/elf_getaroff.c new file mode 100644 index 0000000..62da34d --- /dev/null +++ b/3rdparty/elfutils/libelf/elf_getaroff.c @@ -0,0 +1,54 @@ +/* Return offset in archive for current file ELF. + Copyright (C) 2005, 2008 Red Hat, Inc. + This file is part of elfutils. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2005. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <libelf.h> +#include <stddef.h> + +#include "libelfP.h" + + +off_t +elf_getaroff (elf) + Elf *elf; +{ + /* Be gratious, the specs demand it. */ + if (elf == NULL || elf->parent == NULL) + return ELF_C_NULL; + + /* We can be sure the parent is an archive. */ + Elf *parent = elf->parent; + assert (parent->kind == ELF_K_AR); + + return elf->start_offset - sizeof (struct ar_hdr) - parent->start_offset; +} diff --git a/3rdparty/elfutils/libelf/elf_getarsym.c b/3rdparty/elfutils/libelf/elf_getarsym.c new file mode 100644 index 0000000..40633aa --- /dev/null +++ b/3rdparty/elfutils/libelf/elf_getarsym.c @@ -0,0 +1,309 @@ +/* Return symbol table of archive. + Copyright (C) 1998-2000, 2002, 2005, 2009, 2012, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <byteswap.h> +#include <endian.h> +#include <errno.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <system.h> +#include <dl-hash.h> +#include "libelfP.h" + + +static int +read_number_entries (uint64_t *nump, Elf *elf, size_t *offp, bool index64_p) +{ + union u + { + uint64_t ret64; + uint32_t ret32; + } u; + + size_t w = index64_p ? 8 : 4; + if (elf->map_address != NULL) + /* Use memcpy instead of pointer dereference so as not to assume the + field is naturally aligned within the file. */ + memcpy (&u, elf->map_address + *offp, sizeof u); + else if ((size_t) pread_retry (elf->fildes, &u, w, *offp) != w) + return -1; + + *offp += w; + + if (__BYTE_ORDER == __LITTLE_ENDIAN) + *nump = index64_p ? bswap_64 (u.ret64) : bswap_32 (u.ret32); + else + *nump = index64_p ? u.ret64 : u.ret32; + + return 0; +} + +Elf_Arsym * +elf_getarsym (elf, ptr) + Elf *elf; + size_t *ptr; +{ + if (elf->kind != ELF_K_AR) + { + /* This is no archive. */ + __libelf_seterrno (ELF_E_NO_ARCHIVE); + return NULL; + } + + if (ptr != NULL) + /* In case of an error or when we know the value store the expected + value now. Doing this allows us easier exits in an error case. */ + *ptr = elf->state.ar.ar_sym_num; + + if (elf->state.ar.ar_sym == (Elf_Arsym *) -1l) + { + /* There is no index. */ + __libelf_seterrno (ELF_E_NO_INDEX); + return NULL; + } + + Elf_Arsym *result = elf->state.ar.ar_sym; + if (result == NULL) + { + /* We have not yet read the index. */ + rwlock_wrlock (elf->lock); + + /* In case we find no index remember this for the next call. */ + elf->state.ar.ar_sym = (Elf_Arsym *) -1l; + + struct ar_hdr *index_hdr; + if (elf->map_address == NULL) + { + /* We must read index from the file. */ + assert (elf->fildes != -1); + if (pread_retry (elf->fildes, &elf->state.ar.ar_hdr, + sizeof (struct ar_hdr), elf->start_offset + SARMAG) + != sizeof (struct ar_hdr)) + { + /* It is not possible to read the index. Maybe it does not + exist. */ + __libelf_seterrno (ELF_E_READ_ERROR); + goto out; + } + + index_hdr = &elf->state.ar.ar_hdr; + } + else + { + if (SARMAG + sizeof (struct ar_hdr) > elf->maximum_size) + { + /* There is no room for the full archive. */ + __libelf_seterrno (ELF_E_NO_INDEX); + goto out; + } + + index_hdr = (struct ar_hdr *) (elf->map_address + + elf->start_offset + SARMAG); + } + + /* Now test whether this really is an archive. */ + if (memcmp (index_hdr->ar_fmag, ARFMAG, 2) != 0) + { + /* Invalid magic bytes. */ + __libelf_seterrno (ELF_E_ARCHIVE_FMAG); + goto out; + } + + bool index64_p; + /* Now test whether this is the index. If the name is "/", this + is 32-bit index, if it's "/SYM64/", it's 64-bit index. + + XXX This is not entirely true. There are some more forms. + Which of them shall we handle? */ + if (memcmp (index_hdr->ar_name, "/ ", 16) == 0) + index64_p = false; + else if (memcmp (index_hdr->ar_name, "/SYM64/ ", 16) == 0) + index64_p = true; + else + { + /* If the index is not the first entry, there is no index. + + XXX Is this true? */ + __libelf_seterrno (ELF_E_NO_INDEX); + goto out; + } + int w = index64_p ? 8 : 4; + + /* We have an archive. The first word in there is the number of + entries in the table. */ + uint64_t n; + size_t off = elf->start_offset + SARMAG + sizeof (struct ar_hdr); + if (read_number_entries (&n, elf, &off, index64_p) < 0) + { + /* Cannot read the number of entries. */ + __libelf_seterrno (ELF_E_NO_INDEX); + goto out; + } + + /* Now we can perform some first tests on whether all the data + needed for the index is available. */ + char tmpbuf[17]; + memcpy (tmpbuf, index_hdr->ar_size, 10); + tmpbuf[10] = '\0'; + size_t index_size = atol (tmpbuf); + + if (index_size > elf->maximum_size + || elf->maximum_size - index_size < SARMAG + sizeof (struct ar_hdr) +#if SIZE_MAX <= 4294967295U + || n >= SIZE_MAX / sizeof (Elf_Arsym) +#endif + || n > index_size / w) + { + /* This index table cannot be right since it does not fit into + the file. */ + __libelf_seterrno (ELF_E_NO_INDEX); + goto out; + } + + /* Now we can allocate the arrays needed to store the index. */ + size_t ar_sym_len = (n + 1) * sizeof (Elf_Arsym); + elf->state.ar.ar_sym = (Elf_Arsym *) malloc (ar_sym_len); + if (elf->state.ar.ar_sym != NULL) + { + union + { + uint32_t u32[n]; + uint64_t u64[n]; + } *file_data; + char *str_data; + size_t sz = n * w; + + if (elf->map_address == NULL) + { + file_data = alloca (sz); + + ar_sym_len += index_size - n * w; + Elf_Arsym *newp = (Elf_Arsym *) realloc (elf->state.ar.ar_sym, + ar_sym_len); + if (newp == NULL) + { + free (elf->state.ar.ar_sym); + elf->state.ar.ar_sym = NULL; + __libelf_seterrno (ELF_E_NOMEM); + goto out; + } + elf->state.ar.ar_sym = newp; + + char *new_str = (char *) (elf->state.ar.ar_sym + n + 1); + + /* Now read the data from the file. */ + if ((size_t) pread_retry (elf->fildes, file_data, sz, off) != sz + || ((size_t) pread_retry (elf->fildes, new_str, + index_size - sz, off + sz) + != index_size - sz)) + { + /* We were not able to read the data. */ + free (elf->state.ar.ar_sym); + elf->state.ar.ar_sym = NULL; + __libelf_seterrno (ELF_E_NO_INDEX); + goto out; + } + + str_data = (char *) new_str; + } + else + { + file_data = (void *) (elf->map_address + off); + if (!ALLOW_UNALIGNED + && ((uintptr_t) file_data & -(uintptr_t) n) != 0) + file_data = memcpy (alloca (sz), elf->map_address + off, sz); + str_data = (char *) (elf->map_address + off + sz); + } + + /* Now we can build the data structure. */ + Elf_Arsym *arsym = elf->state.ar.ar_sym; + for (size_t cnt = 0; cnt < n; ++cnt) + { + arsym[cnt].as_name = str_data; + if (index64_p) + { + uint64_t tmp = file_data->u64[cnt]; + if (__BYTE_ORDER == __LITTLE_ENDIAN) + tmp = bswap_64 (tmp); + + arsym[cnt].as_off = tmp; + + /* Check whether 64-bit offset fits into 32-bit + size_t. */ + if (sizeof (arsym[cnt].as_off) < 8 + && arsym[cnt].as_off != tmp) + { + if (elf->map_address == NULL) + { + free (elf->state.ar.ar_sym); + elf->state.ar.ar_sym = NULL; + } + + __libelf_seterrno (ELF_E_RANGE); + goto out; + } + } + else if (__BYTE_ORDER == __LITTLE_ENDIAN) + arsym[cnt].as_off = bswap_32 (file_data->u32[cnt]); + else + arsym[cnt].as_off = file_data->u32[cnt]; + + arsym[cnt].as_hash = _dl_elf_hash (str_data); + str_data = rawmemchr (str_data, '\0') + 1; + } + + /* At the end a special entry. */ + arsym[n].as_name = NULL; + arsym[n].as_off = 0; + arsym[n].as_hash = ~0UL; + + /* Tell the caller how many entries we have. */ + elf->state.ar.ar_sym_num = n + 1; + } + + result = elf->state.ar.ar_sym; + + out: + rwlock_unlock (elf->lock); + } + + if (ptr != NULL) + *ptr = elf->state.ar.ar_sym_num; + + return result; +} diff --git a/3rdparty/elfutils/libelf/elf_getbase.c b/3rdparty/elfutils/libelf/elf_getbase.c new file mode 100644 index 0000000..ff0feb4 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf_getbase.c @@ -0,0 +1,45 @@ +/* Return offset of first byte for the object. + Copyright (C) 1998, 2000, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libelf.h> +#include <stddef.h> + +#include "libelfP.h" + + +off_t +elf_getbase (elf) + Elf *elf; +{ + return elf == NULL ? (off_t) -1 : elf->start_offset; +} diff --git a/3rdparty/elfutils/libelf/elf_getdata.c b/3rdparty/elfutils/libelf/elf_getdata.c new file mode 100644 index 0000000..0aeb997 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf_getdata.c @@ -0,0 +1,487 @@ +/* Return the next data element from the section after possibly converting it. + Copyright (C) 1998-2005, 2006, 2007 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <errno.h> +#include <stddef.h> +#include <string.h> +#include <unistd.h> + +#include "libelfP.h" +#include <system.h> +#include "common.h" +#include "elf-knowledge.h" + + +#define TYPEIDX(Sh_Type) \ + (Sh_Type >= SHT_NULL && Sh_Type < SHT_NUM \ + ? Sh_Type \ + : (Sh_Type >= SHT_GNU_HASH && Sh_Type <= SHT_HISUNW \ + ? SHT_NUM + Sh_Type - SHT_GNU_HASH \ + : 0)) + +/* Associate section types with libelf types. */ +static const Elf_Type shtype_map[EV_NUM - 1][TYPEIDX (SHT_HISUNW) + 1] = + { + [EV_CURRENT - 1] = + { + [SHT_SYMTAB] = ELF_T_SYM, + [SHT_RELA] = ELF_T_RELA, + [SHT_HASH] = ELF_T_WORD, + [SHT_DYNAMIC] = ELF_T_DYN, + [SHT_REL] = ELF_T_REL, + [SHT_DYNSYM] = ELF_T_SYM, + [SHT_INIT_ARRAY] = ELF_T_ADDR, + [SHT_FINI_ARRAY] = ELF_T_ADDR, + [SHT_PREINIT_ARRAY] = ELF_T_ADDR, + [SHT_GROUP] = ELF_T_WORD, + [SHT_SYMTAB_SHNDX] = ELF_T_WORD, + [SHT_NOTE] = ELF_T_NHDR, + [TYPEIDX (SHT_GNU_verdef)] = ELF_T_VDEF, + [TYPEIDX (SHT_GNU_verneed)] = ELF_T_VNEED, + [TYPEIDX (SHT_GNU_versym)] = ELF_T_HALF, + [TYPEIDX (SHT_SUNW_syminfo)] = ELF_T_SYMINFO, + [TYPEIDX (SHT_SUNW_move)] = ELF_T_MOVE, + [TYPEIDX (SHT_GNU_LIBLIST)] = ELF_T_LIB, + [TYPEIDX (SHT_GNU_HASH)] = ELF_T_GNUHASH, + } + }; + +#if !ALLOW_UNALIGNED +/* Associate libelf types with their internal alignment requirements. */ +const uint_fast8_t __libelf_type_aligns[EV_NUM - 1][ELFCLASSNUM - 1][ELF_T_NUM] = + { +# define TYPE_ALIGNS(Bits) \ + { \ + [ELF_T_ADDR] = __alignof__ (ElfW2(Bits,Addr)), \ + [ELF_T_HALF] = __alignof__ (ElfW2(Bits,Half)), \ + [ELF_T_WORD] = __alignof__ (ElfW2(Bits,Word)), \ + [ELF_T_SYM] = __alignof__ (ElfW2(Bits,Sym)), \ + [ELF_T_SYMINFO] = __alignof__ (ElfW2(Bits,Syminfo)), \ + [ELF_T_REL] = __alignof__ (ElfW2(Bits,Rel)), \ + [ELF_T_RELA] = __alignof__ (ElfW2(Bits,Rela)), \ + [ELF_T_DYN] = __alignof__ (ElfW2(Bits,Dyn)), \ + [ELF_T_VDEF] = __alignof__ (ElfW2(Bits,Verdef)), \ + [ELF_T_VDAUX] = __alignof__ (ElfW2(Bits,Verdaux)), \ + [ELF_T_VNEED] = __alignof__ (ElfW2(Bits,Verneed)), \ + [ELF_T_VNAUX] = __alignof__ (ElfW2(Bits,Vernaux)), \ + [ELF_T_MOVE] = __alignof__ (ElfW2(Bits,Move)), \ + [ELF_T_LIB] = __alignof__ (ElfW2(Bits,Lib)), \ + [ELF_T_NHDR] = __alignof__ (ElfW2(Bits,Nhdr)), \ + } + [EV_CURRENT - 1] = + { + [ELFCLASS32 - 1] = TYPE_ALIGNS (32), + [ELFCLASS64 - 1] = TYPE_ALIGNS (64), + } +# undef TYPE_ALIGNS + }; +#endif + + +/* Convert the data in the current section. */ +static void +convert_data (Elf_Scn *scn, int version __attribute__ ((unused)), int eclass, + int data, size_t size, Elf_Type type) +{ + const size_t align = __libelf_type_align (eclass, type); + + if (data == MY_ELFDATA) + { + if (((((size_t) (char *) scn->rawdata_base)) & (align - 1)) == 0) + /* No need to copy, we can use the raw data. */ + scn->data_base = scn->rawdata_base; + else + { + scn->data_base = (char *) malloc (size); + if (scn->data_base == NULL) + { + __libelf_seterrno (ELF_E_NOMEM); + return; + } + + /* The copy will be appropriately aligned for direct access. */ + memcpy (scn->data_base, scn->rawdata_base, size); + } + } + else + { + xfct_t fp; + + scn->data_base = (char *) malloc (size); + if (scn->data_base == NULL) + { + __libelf_seterrno (ELF_E_NOMEM); + return; + } + + /* Get the conversion function. */ +#if EV_NUM != 2 + fp = __elf_xfctstom[version - 1][__libelf_version - 1][eclass - 1][type]; +#else + fp = __elf_xfctstom[0][0][eclass - 1][type]; +#endif + + fp (scn->data_base, scn->rawdata_base, size, 0); + } + + scn->data_list.data.d.d_buf = scn->data_base; + scn->data_list.data.d.d_size = size; + scn->data_list.data.d.d_type = type; + scn->data_list.data.d.d_off = scn->rawdata.d.d_off; + scn->data_list.data.d.d_align = scn->rawdata.d.d_align; + scn->data_list.data.d.d_version = scn->rawdata.d.d_version; + + scn->data_list.data.s = scn; +} + + +/* Store the information for the raw data in the `rawdata' element. */ +int +internal_function +__libelf_set_rawdata_wrlock (Elf_Scn *scn) +{ + Elf64_Off offset; + Elf64_Xword size; + Elf64_Xword align; + int type; + Elf *elf = scn->elf; + + if (elf->class == ELFCLASS32) + { + Elf32_Shdr *shdr + = scn->shdr.e32 ?: __elf32_getshdr_wrlock (scn); + + if (shdr == NULL) + /* Something went terribly wrong. */ + return 1; + + offset = shdr->sh_offset; + size = shdr->sh_size; + type = shdr->sh_type; + align = shdr->sh_addralign; + } + else + { + Elf64_Shdr *shdr + = scn->shdr.e64 ?: __elf64_getshdr_wrlock (scn); + + if (shdr == NULL) + /* Something went terribly wrong. */ + return 1; + + offset = shdr->sh_offset; + size = shdr->sh_size; + type = shdr->sh_type; + align = shdr->sh_addralign; + } + + /* If the section has no data (for whatever reason), leave the `d_buf' + pointer NULL. */ + if (size != 0 && type != SHT_NOBITS) + { + /* First a test whether the section is valid at all. */ + size_t entsize; + + if (type == SHT_HASH) + { + GElf_Ehdr ehdr_mem; + GElf_Ehdr *ehdr = __gelf_getehdr_rdlock (elf, &ehdr_mem); + entsize = SH_ENTSIZE_HASH (ehdr); + } + else + { + Elf_Type t = shtype_map[LIBELF_EV_IDX][TYPEIDX (type)]; + if (t == ELF_T_VDEF || t == ELF_T_NHDR + || (t == ELF_T_GNUHASH && elf->class == ELFCLASS64)) + entsize = 1; + else + entsize = __libelf_type_sizes[LIBELF_EV_IDX][elf->class - 1][t]; + } + + /* We assume it is an array of bytes if it is none of the structured + sections we know of. */ + if (entsize == 0) + entsize = 1; + + if (unlikely (size % entsize != 0)) + { + __libelf_seterrno (ELF_E_INVALID_DATA); + return 1; + } + + /* We can use the mapped or loaded data if available. */ + if (elf->map_address != NULL) + { + /* First see whether the information in the section header is + valid and it does not ask for too much. Check for unsigned + overflow. */ + if (unlikely (offset > elf->maximum_size + || elf->maximum_size - offset < size)) + { + /* Something is wrong. */ + __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER); + return 1; + } + + scn->rawdata_base = scn->rawdata.d.d_buf + = (char *) elf->map_address + elf->start_offset + offset; + } + else if (likely (elf->fildes != -1)) + { + /* We have to read the data from the file. Allocate the needed + memory. */ + scn->rawdata_base = scn->rawdata.d.d_buf + = (char *) malloc (size); + if (scn->rawdata.d.d_buf == NULL) + { + __libelf_seterrno (ELF_E_NOMEM); + return 1; + } + + ssize_t n = pread_retry (elf->fildes, scn->rawdata.d.d_buf, size, + elf->start_offset + offset); + if (unlikely ((size_t) n != size)) + { + /* Cannot read the data. */ + free (scn->rawdata.d.d_buf); + scn->rawdata_base = scn->rawdata.d.d_buf = NULL; + __libelf_seterrno (ELF_E_READ_ERROR); + return 1; + } + } + else + { + /* The file descriptor is already closed, we cannot get the data + anymore. */ + __libelf_seterrno (ELF_E_FD_DISABLED); + return 1; + } + } + + scn->rawdata.d.d_size = size; + /* Some broken ELF ABI for 64-bit machines use the wrong hash table + entry size. See elf-knowledge.h for more information. */ + if (type == SHT_HASH && elf->class == ELFCLASS64) + { + GElf_Ehdr ehdr_mem; + GElf_Ehdr *ehdr = __gelf_getehdr_rdlock (elf, &ehdr_mem); + scn->rawdata.d.d_type + = (SH_ENTSIZE_HASH (ehdr) == 4 ? ELF_T_WORD : ELF_T_XWORD); + } + else + scn->rawdata.d.d_type = shtype_map[LIBELF_EV_IDX][TYPEIDX (type)]; + scn->rawdata.d.d_off = 0; + scn->rawdata.d.d_align = align; + if (elf->class == ELFCLASS32 + || (offsetof (struct Elf, state.elf32.ehdr) + == offsetof (struct Elf, state.elf64.ehdr))) + scn->rawdata.d.d_version = + elf->state.elf32.ehdr->e_ident[EI_VERSION]; + else + scn->rawdata.d.d_version = + elf->state.elf64.ehdr->e_ident[EI_VERSION]; + + scn->rawdata.s = scn; + + scn->data_read = 1; + + /* We actually read data from the file. At least we tried. */ + scn->flags |= ELF_F_FILEDATA; + + return 0; +} + +int +internal_function +__libelf_set_rawdata (Elf_Scn *scn) +{ + int result; + + if (scn == NULL) + return 1; + + rwlock_wrlock (scn->elf->lock); + result = __libelf_set_rawdata_wrlock (scn); + rwlock_unlock (scn->elf->lock); + + return result; +} + +Elf_Data * +internal_function +__elf_getdata_rdlock (scn, data) + Elf_Scn *scn; + Elf_Data *data; +{ + Elf_Data *result = NULL; + Elf *elf; + int locked = 0; + + if (scn == NULL) + return NULL; + + if (unlikely (scn->elf->kind != ELF_K_ELF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + /* We will need this multiple times later on. */ + elf = scn->elf; + + /* If `data' is not NULL this means we are not addressing the initial + data in the file. But this also means this data is already read + (since otherwise it is not possible to have a valid `data' pointer) + and all the data structures are initialized as well. In this case + we can simply walk the list of data records. */ + if (data != NULL) + { + Elf_Data_List *runp; + + /* It is not possible that if DATA is not NULL the first entry is + returned. But this also means that there must be a first data + entry. */ + if (scn->data_list_rear == NULL + /* The section the reference data is for must match the section + parameter. */ + || unlikely (((Elf_Data_Scn *) data)->s != scn)) + { + __libelf_seterrno (ELF_E_DATA_MISMATCH); + goto out; + } + + /* We start searching with the first entry. */ + runp = &scn->data_list; + + while (1) + { + /* If `data' does not match any known record punt. */ + if (runp == NULL) + { + __libelf_seterrno (ELF_E_DATA_MISMATCH); + goto out; + } + + if (&runp->data.d == data) + /* Found the entry. */ + break; + + runp = runp->next; + } + + /* Return the data for the next data record. */ + result = runp->next ? &runp->next->data.d : NULL; + goto out; + } + + /* If the data for this section was not yet initialized do it now. */ + if (scn->data_read == 0) + { + /* We cannot acquire a write lock while we are holding a read + lock. Therefore give up the read lock and then get the write + lock. But this means that the data could meanwhile be + modified, therefore start the tests again. */ + rwlock_unlock (elf->lock); + rwlock_wrlock (elf->lock); + locked = 1; + + /* Read the data from the file. There is always a file (or + memory region) associated with this descriptor since + otherwise the `data_read' flag would be set. */ + if (scn->data_read == 0 && __libelf_set_rawdata_wrlock (scn) != 0) + /* Something went wrong. The error value is already set. */ + goto out; + } + + /* At this point we know the raw data is available. But it might be + empty in case the section has size zero (for whatever reason). + Now create the converted data in case this is necessary. */ + if (scn->data_list_rear == NULL) + { + if (scn->rawdata.d.d_buf != NULL && scn->rawdata.d.d_size > 0) + { + if (!locked) + { + rwlock_unlock (elf->lock); + rwlock_wrlock (elf->lock); + if (scn->data_list_rear != NULL) + goto pass; + } + + /* Convert according to the version and the type. */ + convert_data (scn, __libelf_version, elf->class, + (elf->class == ELFCLASS32 + || (offsetof (struct Elf, state.elf32.ehdr) + == offsetof (struct Elf, state.elf64.ehdr)) + ? elf->state.elf32.ehdr->e_ident[EI_DATA] + : elf->state.elf64.ehdr->e_ident[EI_DATA]), + scn->rawdata.d.d_size, scn->rawdata.d.d_type); + } + else + { + /* This is an empty or NOBITS section. There is no buffer but + the size information etc is important. */ + scn->data_list.data.d = scn->rawdata.d; + scn->data_list.data.s = scn; + } + + scn->data_list_rear = &scn->data_list; + } + + /* If no data is present we cannot return any. */ + if (scn->data_list_rear != NULL) + pass: + /* Return the first data element in the list. */ + result = &scn->data_list.data.d; + + out: + return result; +} + +Elf_Data * +elf_getdata (scn, data) + Elf_Scn *scn; + Elf_Data *data; +{ + Elf_Data *result; + + if (scn == NULL) + return NULL; + + rwlock_rdlock (scn->elf->lock); + result = __elf_getdata_rdlock (scn, data); + rwlock_unlock (scn->elf->lock); + + return result; +} +INTDEF(elf_getdata) diff --git a/3rdparty/elfutils/libelf/elf_getdata_rawchunk.c b/3rdparty/elfutils/libelf/elf_getdata_rawchunk.c new file mode 100644 index 0000000..63a9914 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf_getdata_rawchunk.c @@ -0,0 +1,177 @@ +/* Return converted data from raw chunk of ELF file. + Copyright (C) 2007, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <system.h> +#include "libelfP.h" +#include "common.h" + +Elf_Data * +elf_getdata_rawchunk (elf, offset, size, type) + Elf *elf; + off64_t offset; + size_t size; + Elf_Type type; +{ + if (unlikely (elf == NULL)) + return NULL; + + if (unlikely (elf->kind != ELF_K_ELF)) + { + /* No valid descriptor. */ + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + if (unlikely (offset < 0 || (uint64_t) offset > elf->maximum_size + || elf->maximum_size - (uint64_t) offset < size)) + + { + /* Invalid request. */ + __libelf_seterrno (ELF_E_INVALID_OP); + return NULL; + } + + if (type >= ELF_T_NUM) + { + __libelf_seterrno (ELF_E_UNKNOWN_TYPE); + return NULL; + } + + /* Get the raw bytes from the file. */ + void *rawchunk; + int flags = 0; + Elf_Data *result = NULL; + + rwlock_rdlock (elf->lock); + + /* If the file is mmap'ed we can use it directly. */ + if (elf->map_address != NULL) + rawchunk = elf->map_address + elf->start_offset + offset; + else + { + /* We allocate the memory and read the data from the file. */ + rawchunk = malloc (size); + if (rawchunk == NULL) + { + nomem: + __libelf_seterrno (ELF_E_NOMEM); + goto out; + } + + /* Read the file content. */ + if (unlikely ((size_t) pread_retry (elf->fildes, rawchunk, size, + elf->start_offset + offset) + != size)) + { + /* Something went wrong. */ + free (rawchunk); + __libelf_seterrno (ELF_E_READ_ERROR); + goto out; + } + + flags = ELF_F_MALLOCED; + } + + /* Copy and/or convert the data as needed for aligned native-order access. */ + size_t align = __libelf_type_align (elf->class, type); + void *buffer; + if (elf->state.elf32.ehdr->e_ident[EI_DATA] == MY_ELFDATA) + { + if (((uintptr_t) rawchunk & (align - 1)) == 0) + /* No need to copy, we can use the raw data. */ + buffer = rawchunk; + else + { + /* A malloc'd block is always sufficiently aligned. */ + assert (flags == 0); + + buffer = malloc (size); + if (unlikely (buffer == NULL)) + goto nomem; + flags = ELF_F_MALLOCED; + + /* The copy will be appropriately aligned for direct access. */ + memcpy (buffer, rawchunk, size); + } + } + else + { + if (flags) + buffer = rawchunk; + else + { + buffer = malloc (size); + if (unlikely (buffer == NULL)) + goto nomem; + flags = ELF_F_MALLOCED; + } + + /* Call the conversion function. */ + (*__elf_xfctstom[LIBELF_EV_IDX][LIBELF_EV_IDX][elf->class - 1][type]) + (buffer, rawchunk, size, 0); + } + + /* Allocate the dummy container to point at this buffer. */ + Elf_Data_Chunk *chunk = calloc (1, sizeof *chunk); + if (chunk == NULL) + { + if (flags) + free (buffer); + goto nomem; + } + + chunk->dummy_scn.elf = elf; + chunk->dummy_scn.flags = flags; + chunk->data.s = &chunk->dummy_scn; + chunk->data.d.d_buf = buffer; + chunk->data.d.d_size = size; + chunk->data.d.d_type = type; + chunk->data.d.d_align = align; + chunk->data.d.d_version = __libelf_version; + + rwlock_unlock (elf->lock); + rwlock_wrlock (elf->lock); + + chunk->next = elf->state.elf.rawchunks; + elf->state.elf.rawchunks = chunk; + result = &chunk->data.d; + + out: + rwlock_unlock (elf->lock); + return result; +} diff --git a/3rdparty/elfutils/libelf/elf_getident.c b/3rdparty/elfutils/libelf/elf_getident.c new file mode 100644 index 0000000..10beeaf --- /dev/null +++ b/3rdparty/elfutils/libelf/elf_getident.c @@ -0,0 +1,63 @@ +/* Retrieve file identification data. + Copyright (C) 1998, 1999, 2000, 2002, 2004 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stddef.h> + +#include "libelfP.h" + + +char * +elf_getident (elf, ptr) + Elf *elf; + size_t *ptr; +{ + /* In case this is no ELF file, the handle is invalid and we return + NULL. */ + if (elf == NULL || elf->kind != ELF_K_ELF) + { + if (ptr != NULL) + *ptr = 0; + return NULL; + } + + /* We already read the ELF header. Return a pointer to it and store + the length in *PTR. */ + if (ptr != NULL) + *ptr = EI_NIDENT; + + return (char *) (elf->class == ELFCLASS32 + || (offsetof (struct Elf, state.elf32.ehdr) + == offsetof (struct Elf, state.elf64.ehdr)) + ? elf->state.elf32.ehdr->e_ident + : elf->state.elf64.ehdr->e_ident); +} diff --git a/3rdparty/elfutils/libelf/elf_getphdrnum.c b/3rdparty/elfutils/libelf/elf_getphdrnum.c new file mode 100644 index 0000000..63c27fb --- /dev/null +++ b/3rdparty/elfutils/libelf/elf_getphdrnum.c @@ -0,0 +1,136 @@ +/* Return number of program headers in the ELF file. + Copyright (C) 2010, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <gelf.h> +#include <stddef.h> + +#include "libelfP.h" + + +int +__elf_getphdrnum_rdlock (elf, dst) + Elf *elf; + size_t *dst; +{ + if (unlikely (elf->state.elf64.ehdr == NULL)) + { + /* Maybe no ELF header was created yet. */ + __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR); + return -1; + } + + *dst = (elf->class == ELFCLASS32 + ? elf->state.elf32.ehdr->e_phnum + : elf->state.elf64.ehdr->e_phnum); + + if (*dst == PN_XNUM) + { + const Elf_ScnList *const scns = (elf->class == ELFCLASS32 + ? &elf->state.elf32.scns + : &elf->state.elf64.scns); + + /* If there are no section headers, perhaps this is really just 65536 + written without PN_XNUM support. Either that or it's bad data. */ + + if (elf->class == ELFCLASS32) + { + if (likely (scns->cnt > 0 + && elf->state.elf32.scns.data[0].shdr.e32 != NULL)) + *dst = scns->data[0].shdr.e32->sh_info; + } + else + { + if (likely (scns->cnt > 0 + && elf->state.elf64.scns.data[0].shdr.e64 != NULL)) + *dst = scns->data[0].shdr.e64->sh_info; + } + } + + return 0; +} + +int +elf_getphdrnum (elf, dst) + Elf *elf; + size_t *dst; +{ + int result; + + if (elf == NULL) + return -1; + + if (unlikely (elf->kind != ELF_K_ELF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return -1; + } + + rwlock_rdlock (elf->lock); + result = __elf_getphdrnum_rdlock (elf, dst); + + /* Do some sanity checking to make sure phnum and phoff are consistent. */ + Elf64_Off off = (elf->class == ELFCLASS32 + ? elf->state.elf32.ehdr->e_phoff + : elf->state.elf64.ehdr->e_phoff); + if (unlikely (off == 0)) + { + *dst = 0; + goto out; + } + + if (unlikely (off >= elf->maximum_size)) + { + __libelf_seterrno (ELF_E_INVALID_DATA); + result = -1; + goto out; + } + + /* Check for too many sections. */ + size_t phdr_size = (elf->class == ELFCLASS32 + ? sizeof (Elf32_Phdr) : sizeof (Elf64_Phdr)); + if (unlikely (*dst > SIZE_MAX / phdr_size)) + { + __libelf_seterrno (ELF_E_INVALID_DATA); + result = -1; + goto out; + } + + /* Truncated file? Don't return more than can be indexed. */ + if (unlikely (elf->maximum_size - off < *dst * phdr_size)) + *dst = (elf->maximum_size - off) / phdr_size; + +out: + rwlock_unlock (elf->lock); + + return result; +} diff --git a/3rdparty/elfutils/libelf/elf_getscn.c b/3rdparty/elfutils/libelf/elf_getscn.c new file mode 100644 index 0000000..7c6b7de --- /dev/null +++ b/3rdparty/elfutils/libelf/elf_getscn.c @@ -0,0 +1,89 @@ +/* Get section at specific index. + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004 Red Hat, Inc. + This file is part of elfutils. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <stddef.h> +#include <stdlib.h> + +#include "libelfP.h" + + +Elf_Scn * +elf_getscn (elf, idx) + Elf *elf; + size_t idx; +{ + if (elf == NULL) + return NULL; + + if (unlikely (elf->kind != ELF_K_ELF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + rwlock_rdlock (elf->lock); + + Elf_Scn *result = NULL; + + /* Find the section in the list. */ + Elf_ScnList *runp = (elf->class == ELFCLASS32 + || (offsetof (struct Elf, state.elf32.scns) + == offsetof (struct Elf, state.elf64.scns)) + ? &elf->state.elf32.scns : &elf->state.elf64.scns); + while (1) + { + if (idx < runp->max) + { + if (idx < runp->cnt) + result = &runp->data[idx]; + else + __libelf_seterrno (ELF_E_INVALID_INDEX); + break; + } + + idx -= runp->max; + + runp = runp->next; + if (runp == NULL) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + break; + } + } + + rwlock_unlock (elf->lock); + + return result; +} +INTDEF(elf_getscn) diff --git a/3rdparty/elfutils/libelf/elf_getshdrnum.c b/3rdparty/elfutils/libelf/elf_getshdrnum.c new file mode 100644 index 0000000..73a3300 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf_getshdrnum.c @@ -0,0 +1,90 @@ +/* Return number of sections in the ELF file. + Copyright (C) 2002, 2009 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <gelf.h> +#include <stddef.h> + +#include "libelfP.h" + + +int +__elf_getshdrnum_rdlock (elf, dst) + Elf *elf; + size_t *dst; +{ + int result = 0; + int idx; + + if (elf == NULL) + return -1; + + if (unlikely (elf->kind != ELF_K_ELF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return -1; + } + + idx = elf->state.elf.scns_last->cnt; + if (idx != 0 + || (elf->state.elf.scns_last + != (elf->class == ELFCLASS32 + || (offsetof (Elf, state.elf32.scns) + == offsetof (Elf, state.elf64.scns)) + ? &elf->state.elf32.scns : &elf->state.elf64.scns))) + /* There is at least one section. */ + *dst = 1 + elf->state.elf.scns_last->data[idx - 1].index; + else + *dst = 0; + + return result; +} + +int +elf_getshdrnum (elf, dst) + Elf *elf; + size_t *dst; +{ + int result; + + if (elf == NULL) + return -1; + + rwlock_rdlock (elf->lock); + result = __elf_getshdrnum_rdlock (elf, dst); + rwlock_unlock (elf->lock); + + return result; +} +/* Alias for the deprecated name. */ +strong_alias (elf_getshdrnum, elf_getshnum) diff --git a/3rdparty/elfutils/libelf/elf_getshdrstrndx.c b/3rdparty/elfutils/libelf/elf_getshdrstrndx.c new file mode 100644 index 0000000..6f8d66e --- /dev/null +++ b/3rdparty/elfutils/libelf/elf_getshdrstrndx.c @@ -0,0 +1,229 @@ +/* Return section index of section header string table. + Copyright (C) 2002, 2005, 2009, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <errno.h> +#include <gelf.h> +#include <stddef.h> +#include <unistd.h> + +#include <system.h> +#include "libelfP.h" +#include "common.h" + + +int +elf_getshdrstrndx (elf, dst) + Elf *elf; + size_t *dst; +{ + int result = 0; + + if (elf == NULL) + return -1; + + if (unlikely (elf->kind != ELF_K_ELF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return -1; + } + + rwlock_rdlock (elf->lock); + + /* We rely here on the fact that the `elf' element is a common prefix + of `elf32' and `elf64'. */ + assert (offsetof (struct Elf, state.elf.ehdr) + == offsetof (struct Elf, state.elf32.ehdr)); + assert (sizeof (elf->state.elf.ehdr) + == sizeof (elf->state.elf32.ehdr)); + assert (offsetof (struct Elf, state.elf.ehdr) + == offsetof (struct Elf, state.elf64.ehdr)); + assert (sizeof (elf->state.elf.ehdr) + == sizeof (elf->state.elf64.ehdr)); + + if (unlikely (elf->state.elf.ehdr == NULL)) + { + __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR); + result = -1; + } + else + { + Elf32_Word num; + + num = (elf->class == ELFCLASS32 + ? elf->state.elf32.ehdr->e_shstrndx + : elf->state.elf64.ehdr->e_shstrndx); + + /* Determine whether the index is too big to fit in the ELF + header. */ + if (unlikely (num == SHN_XINDEX)) + { + /* Yes. Search the zeroth section header. */ + if (elf->class == ELFCLASS32) + { + size_t offset; + if (unlikely (elf->state.elf32.scns.cnt == 0)) + { + /* Cannot use SHN_XINDEX without section headers. */ + __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER); + result = -1; + goto out; + } + + if (elf->state.elf32.scns.data[0].shdr.e32 != NULL) + { + num = elf->state.elf32.scns.data[0].shdr.e32->sh_link; + goto success; + } + + offset = elf->state.elf32.ehdr->e_shoff; + + if (elf->map_address != NULL + && elf->state.elf32.ehdr->e_ident[EI_DATA] == MY_ELFDATA + && (ALLOW_UNALIGNED + || (((size_t) ((char *) elf->map_address + + elf->start_offset + offset)) + & (__alignof__ (Elf32_Shdr) - 1)) == 0)) + { + /* First see whether the information in the ELF header is + valid and it does not ask for too much. */ + if (unlikely (elf->maximum_size - offset + < sizeof (Elf32_Shdr))) + { + /* Something is wrong. */ + __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER); + result = -1; + goto out; + } + + /* We can directly access the memory. */ + num = ((Elf32_Shdr *) (elf->map_address + elf->start_offset + + offset))->sh_link; + } + else + { + /* We avoid reading in all the section headers. Just read + the first one. */ + Elf32_Shdr shdr_mem; + + if (unlikely (pread_retry (elf->fildes, &shdr_mem, + sizeof (Elf32_Shdr), offset) + != sizeof (Elf32_Shdr))) + { + /* We must be able to read this ELF section header. */ + __libelf_seterrno (ELF_E_INVALID_FILE); + result = -1; + goto out; + } + + if (elf->state.elf32.ehdr->e_ident[EI_DATA] != MY_ELFDATA) + CONVERT (shdr_mem.sh_link); + num = shdr_mem.sh_link; + } + } + else + { + if (unlikely (elf->state.elf64.scns.cnt == 0)) + { + /* Cannot use SHN_XINDEX without section headers. */ + __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER); + result = -1; + goto out; + } + + if (elf->state.elf64.scns.data[0].shdr.e64 != NULL) + { + num = elf->state.elf64.scns.data[0].shdr.e64->sh_link; + goto success; + } + + size_t offset = elf->state.elf64.ehdr->e_shoff; + + if (elf->map_address != NULL + && elf->state.elf64.ehdr->e_ident[EI_DATA] == MY_ELFDATA + && (ALLOW_UNALIGNED + || (((size_t) ((char *) elf->map_address + + elf->start_offset + offset)) + & (__alignof__ (Elf64_Shdr) - 1)) == 0)) + { + /* First see whether the information in the ELF header is + valid and it does not ask for too much. */ + if (unlikely (elf->maximum_size - offset + < sizeof (Elf64_Shdr))) + { + /* Something is wrong. */ + __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER); + result = -1; + goto out; + } + + /* We can directly access the memory. */ + num = ((Elf64_Shdr *) (elf->map_address + elf->start_offset + + offset))->sh_link; + } + else + { + /* We avoid reading in all the section headers. Just read + the first one. */ + Elf64_Shdr shdr_mem; + + if (unlikely (pread_retry (elf->fildes, &shdr_mem, + sizeof (Elf64_Shdr), offset) + != sizeof (Elf64_Shdr))) + { + /* We must be able to read this ELF section header. */ + __libelf_seterrno (ELF_E_INVALID_FILE); + result = -1; + goto out; + } + + if (elf->state.elf64.ehdr->e_ident[EI_DATA] != MY_ELFDATA) + CONVERT (shdr_mem.sh_link); + num = shdr_mem.sh_link; + } + } + } + + /* Store the result. */ + success: + *dst = num; + } + + out: + rwlock_unlock (elf->lock); + + return result; +} +INTDEF(elf_getshdrstrndx) +/* Alias for the deprecated name. */ +strong_alias (elf_getshdrstrndx, elf_getshstrndx) diff --git a/3rdparty/elfutils/libelf/elf_gnu_hash.c b/3rdparty/elfutils/libelf/elf_gnu_hash.c new file mode 100644 index 0000000..4c21857 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf_gnu_hash.c @@ -0,0 +1,47 @@ +/* GNU-style Hash function used in ELF implementations. + Copyright (C) 2006 Red Hat, Inc. + This file is part of elfutils. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2006. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libelfP.h> + +/* Get the implementation. */ +#include <dl-hash.h> + +unsigned long int +elf_gnu_hash (string) + const char *string; +{ + uint_fast32_t h = 5381; + for (unsigned char c = *string; c != '\0'; c = *++string) + h = h * 33 + c; + return h & 0xffffffff; +} diff --git a/3rdparty/elfutils/libelf/elf_hash.c b/3rdparty/elfutils/libelf/elf_hash.c new file mode 100644 index 0000000..306ebc2 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf_hash.c @@ -0,0 +1,45 @@ +/* Hash function used in ELF implementations. + Copyright (C) 1998, 1999, 2000, 2002 Red Hat, Inc. + This file is part of elfutils. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libelfP.h> + +/* Get the implementation. */ +#include <dl-hash.h> + +unsigned long int +elf_hash (string) + const char *string; +{ + return _dl_elf_hash (string); +} +INTDEF(elf_hash) diff --git a/3rdparty/elfutils/libelf/elf_kind.c b/3rdparty/elfutils/libelf/elf_kind.c new file mode 100644 index 0000000..d8ab2fd --- /dev/null +++ b/3rdparty/elfutils/libelf/elf_kind.c @@ -0,0 +1,45 @@ +/* Return the kind of file associated with the descriptor. + Copyright (C) 1998, 1999, 2000, 2002 Red Hat, Inc. + This file is part of elfutils. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libelf.h> +#include <stddef.h> + +#include "libelfP.h" + + +Elf_Kind +elf_kind (elf) + Elf *elf; +{ + return elf == NULL ? ELF_K_NONE : elf->kind; +} diff --git a/3rdparty/elfutils/libelf/elf_memory.c b/3rdparty/elfutils/libelf/elf_memory.c new file mode 100644 index 0000000..08f85a1 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf_memory.c @@ -0,0 +1,52 @@ +/* Create descriptor for memory region. + Copyright (C) 1999, 2000, 2002 Red Hat, Inc. + This file is part of elfutils. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libelf.h> +#include <stddef.h> + +#include "libelfP.h" + + +Elf * +elf_memory (image, size) + char *image; + size_t size; +{ + if (image == NULL) + { + __libelf_seterrno (ELF_E_INVALID_OPERAND); + return NULL; + } + + return __libelf_read_mmaped_file (-1, image, 0, size, ELF_C_READ, NULL); +} diff --git a/3rdparty/elfutils/libelf/elf_ndxscn.c b/3rdparty/elfutils/libelf/elf_ndxscn.c new file mode 100644 index 0000000..bd4bfbf --- /dev/null +++ b/3rdparty/elfutils/libelf/elf_ndxscn.c @@ -0,0 +1,48 @@ +/* Get index of section. + Copyright (C) 1998, 1999, 2000, 2002 Red Hat, Inc. + This file is part of elfutils. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libelf.h> +#include <stddef.h> + +#include "libelfP.h" + + +size_t +elf_ndxscn (scn) + Elf_Scn *scn; +{ + if (scn == NULL) + return SHN_UNDEF; + + return scn->index; +} diff --git a/3rdparty/elfutils/libelf/elf_newdata.c b/3rdparty/elfutils/libelf/elf_newdata.c new file mode 100644 index 0000000..90d1813 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf_newdata.c @@ -0,0 +1,109 @@ +/* Create new, empty section data. + Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. + This file is part of elfutils. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stddef.h> +#include <stdlib.h> + +#include "libelfP.h" + + +Elf_Data * +elf_newdata (Elf_Scn *scn) +{ + Elf_Data_List *result = NULL; + + if (scn == NULL) + return NULL; + + if (unlikely (scn->index == 0)) + { + /* It is not allowed to add something to the 0th section. */ + __libelf_seterrno (ELF_E_NOT_NUL_SECTION); + return NULL; + } + + if (scn->elf->class == ELFCLASS32 + || (offsetof (struct Elf, state.elf32.ehdr) + == offsetof (struct Elf, state.elf64.ehdr)) + ? scn->elf->state.elf32.ehdr == NULL + : scn->elf->state.elf64.ehdr == NULL) + { + __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR); + return NULL; + } + + rwlock_wrlock (scn->elf->lock); + + if (scn->data_read && scn->data_list_rear == NULL) + { + /* This means the section was created by the user and this is the + first data. */ + result = &scn->data_list; + result->flags = ELF_F_DIRTY; + } + else + { + /* Create a new, empty data descriptor. */ + result = (Elf_Data_List *) calloc (1, sizeof (Elf_Data_List)); + if (result == NULL) + { + __libelf_seterrno (ELF_E_NOMEM); + goto out; + } + + result->flags = ELF_F_DIRTY | ELF_F_MALLOCED; + + if (scn->data_list_rear == NULL) + /* We create new data without reading/converting the data from the + file. That is fine but we have to remember this. */ + scn->data_list_rear = &scn->data_list; + } + + /* Set the predefined values. */ + result->data.d.d_version = __libelf_version; + + result->data.s = scn; + + /* Add to the end of the list. */ + if (scn->data_list_rear != NULL) + scn->data_list_rear->next = result; + + scn->data_list_rear = result; + + out: + rwlock_unlock (scn->elf->lock); + + /* Please note that the following is thread safe and is also defined + for RESULT == NULL since it still return NULL. */ + return &result->data.d; +} diff --git a/3rdparty/elfutils/libelf/elf_newscn.c b/3rdparty/elfutils/libelf/elf_newscn.c new file mode 100644 index 0000000..6e0029e --- /dev/null +++ b/3rdparty/elfutils/libelf/elf_newscn.c @@ -0,0 +1,163 @@ +/* Append new section. + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2005, 2009, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + +#include "libelfP.h" + + +Elf_Scn * +elf_newscn (elf) + Elf *elf; +{ + Elf_Scn *result = NULL; + bool first = false; + + if (elf == NULL) + return NULL; + + /* We rely on the prefix of the `elf', `elf32', and `elf64' element + being the same. */ + assert (offsetof (Elf, state.elf.scns_last) + == offsetof (Elf, state.elf32.scns_last)); + assert (offsetof (Elf, state.elf.scns_last) + == offsetof (Elf, state.elf64.scns_last)); + assert (offsetof (Elf, state.elf32.scns) + == offsetof (Elf, state.elf64.scns)); + + rwlock_wrlock (elf->lock); + + again: + if (elf->state.elf.scns_last->cnt < elf->state.elf.scns_last->max) + { + result = &elf->state.elf.scns_last->data[elf->state.elf.scns_last->cnt]; + + if (++elf->state.elf.scns_last->cnt == 1 + && (elf->state.elf.scns_last + == (elf->class == ELFCLASS32 + || (offsetof (Elf, state.elf32.scns) + == offsetof (Elf, state.elf64.scns)) + ? &elf->state.elf32.scns : &elf->state.elf64.scns))) + /* This is zeroth section. */ + first = true; + else + { + assert (elf->state.elf.scns_last->cnt > 1); + result->index = result[-1].index + 1; + } + } + else + { + /* We must allocate a new element. */ + Elf_ScnList *newp = NULL; + + assert (elf->state.elf.scnincr > 0); + + if ( +#if SIZE_MAX <= 4294967295U + likely (elf->state.elf.scnincr + < SIZE_MAX / 2 / sizeof (Elf_Scn) - sizeof (Elf_ScnList)) +#else + 1 +#endif + ) + newp = (Elf_ScnList *) calloc (sizeof (Elf_ScnList) + + ((elf->state.elf.scnincr *= 2) + * sizeof (Elf_Scn)), 1); + if (newp == NULL) + { + __libelf_seterrno (ELF_E_NOMEM); + goto out; + } + + result = &newp->data[0]; + + /* One section used. */ + ++newp->cnt; + + /* This is the number of sections we allocated. */ + newp->max = elf->state.elf.scnincr; + + /* Remember the index for the first section in this block. */ + newp->data[0].index + = 1 + elf->state.elf.scns_last->data[elf->state.elf.scns_last->max - 1].index; + + /* Enqueue the new list element. */ + elf->state.elf.scns_last = elf->state.elf.scns_last->next = newp; + } + + /* Create a section header for this section. */ + if (elf->class == ELFCLASS32) + { + result->shdr.e32 = (Elf32_Shdr *) calloc (1, sizeof (Elf32_Shdr)); + if (result->shdr.e32 == NULL) + { + __libelf_seterrno (ELF_E_NOMEM); + goto out; + } + } + else + { + result->shdr.e64 = (Elf64_Shdr *) calloc (1, sizeof (Elf64_Shdr)); + if (result->shdr.e64 == NULL) + { + __libelf_seterrno (ELF_E_NOMEM); + goto out; + } + } + + result->elf = elf; + result->shdr_flags = ELF_F_DIRTY | ELF_F_MALLOCED; + result->list = elf->state.elf.scns_last; + + /* Initialize the data part. */ + result->data_read = 1; + if (unlikely (first)) + { + /* For the first section we mark the data as already available. */ + //result->data_list_rear = &result->data_list; + first = false; + goto again; + } + + result->flags |= ELF_F_DIRTY; + + out: + rwlock_unlock (elf->lock); + + return result; +} diff --git a/3rdparty/elfutils/libelf/elf_next.c b/3rdparty/elfutils/libelf/elf_next.c new file mode 100644 index 0000000..1f5c03c --- /dev/null +++ b/3rdparty/elfutils/libelf/elf_next.c @@ -0,0 +1,73 @@ +/* Advance in archive to next element. + Copyright (C) 1998-2009 Red Hat, Inc. + This file is part of elfutils. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <libelf.h> +#include <stddef.h> + +#include "libelfP.h" + + +Elf_Cmd +elf_next (elf) + Elf *elf; +{ + Elf *parent; + Elf_Cmd ret; + + /* Be gratious, the specs demand it. */ + if (elf == NULL || elf->parent == NULL) + return ELF_C_NULL; + + /* We can be sure the parent is an archive. */ + parent = elf->parent; + assert (parent->kind == ELF_K_AR); + + rwlock_wrlock (parent->lock); + + /* Now advance the offset. */ + parent->state.ar.offset += (sizeof (struct ar_hdr) + + ((parent->state.ar.elf_ar_hdr.ar_size + 1) + & ~1l)); + + /* Get the next archive header. */ + ret = __libelf_next_arhdr_wrlock (parent) != 0 ? ELF_C_NULL : elf->cmd; + + /* If necessary, mark the archive header as unusable. */ + if (ret == ELF_C_NULL) + parent->state.ar.elf_ar_hdr.ar_name = NULL; + + rwlock_unlock (parent->lock); + + return ret; +} diff --git a/3rdparty/elfutils/libelf/elf_nextscn.c b/3rdparty/elfutils/libelf/elf_nextscn.c new file mode 100644 index 0000000..0d2bd66 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf_nextscn.c @@ -0,0 +1,89 @@ +/* Get next section. + Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. + This file is part of elfutils. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <libelf.h> +#include <stddef.h> + +#include "libelfP.h" + + +Elf_Scn * +elf_nextscn (elf, scn) + Elf *elf; + Elf_Scn *scn; +{ + Elf_Scn *result = NULL; + + if (elf == NULL) + return NULL; + + rwlock_rdlock (elf->lock); + + if (scn == NULL) + { + /* If no section handle is given return the first (not 0th) section. */ + if (elf->class == ELFCLASS32 + || (offsetof (Elf, state.elf32.scns) + == offsetof (Elf, state.elf64.scns))) + { + if (elf->state.elf32.scns.cnt > 1) + result = &elf->state.elf32.scns.data[1]; + } + else + { + if (elf->state.elf64.scns.cnt > 1) + result = &elf->state.elf64.scns.data[1]; + } + } + else + { + Elf_ScnList *list = scn->list; + + if (scn + 1 < &list->data[list->cnt]) + result = scn + 1; + else if (scn + 1 == &list->data[list->max] + && (list = list->next) != NULL) + { + /* If there is another element in the section list it must + have at least one entry. */ + assert (list->cnt > 0); + result = &list->data[0]; + } + } + + rwlock_unlock (elf->lock); + + return result; +} +INTDEF(elf_nextscn) diff --git a/3rdparty/elfutils/libelf/elf_rand.c b/3rdparty/elfutils/libelf/elf_rand.c new file mode 100644 index 0000000..cef4e44 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf_rand.c @@ -0,0 +1,65 @@ +/* Select specific element in archive. + Copyright (C) 1998, 1999, 2000, 2002 Red Hat, Inc. + This file is part of elfutils. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libelf.h> +#include <stddef.h> + +#include "libelfP.h" + + +size_t +elf_rand (elf, offset) + Elf *elf; + size_t offset; +{ + /* Be gratious, the specs demand it. */ + if (elf == NULL || elf->kind != ELF_K_AR) + return 0; + + rwlock_wrlock (elf->lock); + + /* Save the old offset and set the offset. */ + elf->state.ar.offset = elf->start_offset + offset; + + /* Get the next archive header. */ + if (__libelf_next_arhdr_wrlock (elf) != 0) + { + /* Mark the archive header as unusable. */ + elf->state.ar.elf_ar_hdr.ar_name = NULL; + return 0; + } + + rwlock_unlock (elf->lock); + + return offset; +} diff --git a/3rdparty/elfutils/libelf/elf_rawdata.c b/3rdparty/elfutils/libelf/elf_rawdata.c new file mode 100644 index 0000000..9672652 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf_rawdata.c @@ -0,0 +1,78 @@ +/* Return raw section content. + Copyright (C) 1998, 1999, 2000, 2002 Red Hat, Inc. + This file is part of elfutils. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> + +#include "libelfP.h" + + +Elf_Data * +elf_rawdata (scn, data) + Elf_Scn *scn; + Elf_Data *data; +{ + if (scn == NULL || scn->elf->kind != ELF_K_ELF) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + /* If `data' is not NULL this means we are not addressing the initial + data in the file. But this also means this data is already read + (since otherwise it is not possible to have a valid `data' pointer) + and all the data structures are initialized as well. In this case + we can simply walk the list of data records. */ + if (data != NULL + || (scn->data_read != 0 && (scn->flags & ELF_F_FILEDATA) == 0)) + { + /* We don't allow accessing any but the data read from the file + as raw. */ + __libelf_seterrno (ELF_E_DATA_MISMATCH); + return NULL; + } + + /* If the data for this section was not yet initialized do it now. */ + if (scn->data_read == 0) + { + /* First thing we do is to read the data from the file. There is + always a file (or memory region) associated with this descriptor + since otherwise the `data_read' flag would be set. */ + if (__libelf_set_rawdata (scn) != 0) + /* Something went wrong. The error value is already set. */ + return NULL; + } + + /* Return the first data element in the list. */ + return &scn->rawdata.d; +} +INTDEF(elf_rawdata) diff --git a/3rdparty/elfutils/libelf/elf_rawfile.c b/3rdparty/elfutils/libelf/elf_rawfile.c new file mode 100644 index 0000000..dd71b88 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf_rawfile.c @@ -0,0 +1,69 @@ +/* Retrieve uninterpreted file contents. + Copyright (C) 1998, 1999, 2000, 2002 Red Hat, Inc. + This file is part of elfutils. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libelf.h> +#include <stddef.h> + +#include "libelfP.h" + + +char * +elf_rawfile (elf, ptr) + Elf *elf; + size_t *ptr; +{ + char *result; + + if (elf == NULL) + { + /* No valid descriptor. */ + __libelf_seterrno (ELF_E_INVALID_HANDLE); + error_out: + if (ptr != NULL) + *ptr = 0; + return NULL; + } + + /* If the file is not mmap'ed and not previously loaded, do it now. */ + if (elf->map_address == NULL && __libelf_readall (elf) == NULL) + goto error_out; + + rwlock_rdlock (elf->lock); + if (ptr != NULL) + *ptr = elf->maximum_size; + + result = (char *) elf->map_address + elf->start_offset; + rwlock_unlock (elf->lock); + + return result; +} diff --git a/3rdparty/elfutils/libelf/elf_readall.c b/3rdparty/elfutils/libelf/elf_readall.c new file mode 100644 index 0000000..0101618 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf_readall.c @@ -0,0 +1,152 @@ +/* Read all of the file associated with the descriptor. + Copyright (C) 1998-2009 Red Hat, Inc. + This file is part of elfutils. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <errno.h> +#include <unistd.h> +#include <sys/stat.h> + +#include <system.h> +#include "libelfP.h" +#include "common.h" + + +static void +set_address (Elf *elf, size_t offset) +{ + if (elf->kind == ELF_K_AR) + { + Elf *child = elf->state.ar.children; + + while (child != NULL) + { + if (child->map_address == NULL) + { + child->map_address = elf->map_address; + child->start_offset -= offset; + if (child->kind == ELF_K_AR) + child->state.ar.offset -= offset; + + set_address (child, offset); + } + + child = child->next; + } + } +} + + +char * +__libelf_readall (elf) + Elf *elf; +{ + /* Get the file. */ + rwlock_wrlock (elf->lock); + + if (elf->map_address == NULL && unlikely (elf->fildes == -1)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + rwlock_unlock (elf->lock); + return NULL; + } + + /* If the file is not mmap'ed and not previously loaded, do it now. */ + if (elf->map_address == NULL) + { + char *mem = NULL; + + /* If this is an archive and we have derived descriptors get the + locks for all of them. */ + libelf_acquire_all (elf); + + if (elf->maximum_size == ~((size_t) 0)) + { + /* We don't yet know how large the file is. Determine that now. */ + struct stat st; + + if (fstat (elf->fildes, &st) < 0) + goto read_error; + + if (sizeof (size_t) >= sizeof (st.st_size) + || st.st_size <= ~((size_t) 0)) + elf->maximum_size = (size_t) st.st_size; + else + { + errno = EOVERFLOW; + goto read_error; + } + } + + /* Allocate all the memory we need. */ + mem = (char *) malloc (elf->maximum_size); + if (mem != NULL) + { + /* Read the file content. */ + if (unlikely ((size_t) pread_retry (elf->fildes, mem, + elf->maximum_size, + elf->start_offset) + != elf->maximum_size)) + { + /* Something went wrong. */ + read_error: + __libelf_seterrno (ELF_E_READ_ERROR); + free (mem); + } + else + { + /* Remember the address. */ + elf->map_address = mem; + + /* Also remember that we allocated the memory. */ + elf->flags |= ELF_F_MALLOCED; + + /* Propagate the information down to all children and + their children. */ + set_address (elf, elf->start_offset); + + /* Correct the own offsets. */ + if (elf->kind == ELF_K_AR) + elf->state.ar.offset -= elf->start_offset; + elf->start_offset = 0; + } + } + else + __libelf_seterrno (ELF_E_NOMEM); + + /* Free the locks on the children. */ + libelf_release_all (elf); + } + + rwlock_unlock (elf->lock); + + return (char *) elf->map_address; +} diff --git a/3rdparty/elfutils/libelf/elf_scnshndx.c b/3rdparty/elfutils/libelf/elf_scnshndx.c new file mode 100644 index 0000000..5b783fa --- /dev/null +++ b/3rdparty/elfutils/libelf/elf_scnshndx.c @@ -0,0 +1,50 @@ +/* Get the section index of the extended section index table. + Copyright (C) 2007 Red Hat, Inc. + This file is part of elfutils. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2007. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libelfP.h" + + +int +elf_scnshndx (Elf_Scn *scn) +{ + if (unlikely (scn->shndx_index == 0)) + { + /* We do not have the value yet. We get it as a side effect of + getting a section header. */ + GElf_Shdr shdr_mem; + (void) INTUSE(gelf_getshdr) (scn, &shdr_mem); + } + + return scn->shndx_index; +} +INTDEF(elf_scnshndx) diff --git a/3rdparty/elfutils/libelf/elf_strptr.c b/3rdparty/elfutils/libelf/elf_strptr.c new file mode 100644 index 0000000..1f40429 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf_strptr.c @@ -0,0 +1,161 @@ +/* Return string pointer from string section. + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2008, 2009 Red Hat, Inc. + This file is part of elfutils. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libelf.h> +#include <stddef.h> + +#include "libelfP.h" + + +char * +elf_strptr (elf, idx, offset) + Elf *elf; + size_t idx; + size_t offset; +{ + if (elf == NULL) + return NULL; + + if (elf->kind != ELF_K_ELF) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + rwlock_rdlock (elf->lock); + + char *result = NULL; + Elf_Scn *strscn; + + /* Find the section in the list. */ + Elf_ScnList *runp = (elf->class == ELFCLASS32 + || (offsetof (struct Elf, state.elf32.scns) + == offsetof (struct Elf, state.elf64.scns)) + ? &elf->state.elf32.scns : &elf->state.elf64.scns); + while (1) + { + if (idx < runp->max) + { + if (idx < runp->cnt) + strscn = &runp->data[idx]; + else + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + break; + } + + idx -= runp->max; + + runp = runp->next; + if (runp == NULL) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + } + + if (elf->class == ELFCLASS32) + { + if (unlikely (strscn->shdr.e32->sh_type != SHT_STRTAB)) + { + /* This is no string section. */ + __libelf_seterrno (ELF_E_INVALID_SECTION); + goto out; + } + + if (unlikely (offset >= strscn->shdr.e32->sh_size)) + { + /* The given offset is too big, it is beyond this section. */ + __libelf_seterrno (ELF_E_OFFSET_RANGE); + goto out; + } + } + else + { + if (unlikely (strscn->shdr.e64->sh_type != SHT_STRTAB)) + { + /* This is no string section. */ + __libelf_seterrno (ELF_E_INVALID_SECTION); + goto out; + } + + if (unlikely (offset >= strscn->shdr.e64->sh_size)) + { + /* The given offset is too big, it is beyond this section. */ + __libelf_seterrno (ELF_E_OFFSET_RANGE); + goto out; + } + } + + if (strscn->rawdata_base == NULL && ! strscn->data_read) + { + rwlock_unlock (elf->lock); + rwlock_wrlock (elf->lock); + if (strscn->rawdata_base == NULL && ! strscn->data_read + /* Read the section data. */ + && __libelf_set_rawdata_wrlock (strscn) != 0) + goto out; + } + + if (likely (strscn->rawdata_base != NULL)) + // XXX Is this correct if a file is read and then new data is added + // XXX to the string section? Likely needs to check offset against + // XXX size of rawdata_base buffer and then iterate over rest of the + // XXX list. + result = &strscn->rawdata_base[offset]; + else + { + /* This is a file which is currently created. Use the list of + data blocks. */ + struct Elf_Data_List *dl = &strscn->data_list; + while (dl != NULL) + { + if (offset >= (size_t) dl->data.d.d_off + && offset < dl->data.d.d_off + dl->data.d.d_size) + { + result = (char *) dl->data.d.d_buf + (offset - dl->data.d.d_off); + break; + } + + dl = dl->next; + } + } + + out: + rwlock_unlock (elf->lock); + + return result; +} +INTDEF(elf_strptr) diff --git a/3rdparty/elfutils/libelf/elf_update.c b/3rdparty/elfutils/libelf/elf_update.c new file mode 100644 index 0000000..54c20f5 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf_update.c @@ -0,0 +1,199 @@ +/* Update data structures for changes and write them out. + Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006 Red Hat, Inc. + This file is part of elfutils. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libelf.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/stat.h> + +#include "libelfP.h" + + +static off_t +write_file (Elf *elf, off_t size, int change_bo, size_t shnum) +{ + int class = elf->class; + + /* Check the mode bits now, before modification might change them. */ + struct stat st; + if (unlikely (fstat (elf->fildes, &st) != 0)) + { + __libelf_seterrno (ELF_E_WRITE_ERROR); + return -1; + } + + /* Adjust the size in any case. We do this even if we use `write'. + We cannot do this if this file is in an archive. We also don't + do it *now* if we are shortening the file since this would + prevent programs to use the data of the file in generating the + new file. We truncate the file later in this case. */ + if (elf->parent == NULL + && (elf->maximum_size == ~((size_t) 0) + || (size_t) size > elf->maximum_size) + && unlikely (ftruncate (elf->fildes, size) != 0)) + { + __libelf_seterrno (ELF_E_WRITE_ERROR); + return -1; + } + + /* Try to map the file if this isn't done yet. */ + if (elf->map_address == NULL && elf->cmd == ELF_C_WRITE_MMAP) + { + elf->map_address = mmap (NULL, size, PROT_READ | PROT_WRITE, + MAP_SHARED, elf->fildes, 0); + if (unlikely (elf->map_address == MAP_FAILED)) + elf->map_address = NULL; + } + + if (elf->map_address != NULL) + { + /* The file is mmaped. */ + if ((class == ELFCLASS32 + ? __elf32_updatemmap (elf, change_bo, shnum) + : __elf64_updatemmap (elf, change_bo, shnum)) != 0) + /* Some problem while writing. */ + size = -1; + } + else + { + /* The file is not mmaped. */ + if ((class == ELFCLASS32 + ? __elf32_updatefile (elf, change_bo, shnum) + : __elf64_updatefile (elf, change_bo, shnum)) != 0) + /* Some problem while writing. */ + size = -1; + } + + if (size != -1 + && elf->parent == NULL + && elf->maximum_size != ~((size_t) 0) + && (size_t) size < elf->maximum_size + && unlikely (ftruncate (elf->fildes, size) != 0)) + { + __libelf_seterrno (ELF_E_WRITE_ERROR); + size = -1; + } + + /* POSIX says that ftruncate and write may clear the S_ISUID and S_ISGID + mode bits. So make sure we restore them afterwards if they were set. + This is not atomic if someone else chmod's the file while we operate. */ + if (size != -1 + && unlikely (st.st_mode & (S_ISUID | S_ISGID)) + /* fchmod ignores the bits we cannot change. */ + && unlikely (fchmod (elf->fildes, st.st_mode) != 0)) + { + __libelf_seterrno (ELF_E_WRITE_ERROR); + size = -1; + } + + if (size != -1 && elf->parent == NULL) + elf->maximum_size = size; + + return size; +} + + +off_t +elf_update (elf, cmd) + Elf *elf; + Elf_Cmd cmd; +{ + size_t shnum; + off_t size; + int change_bo = 0; + + if (cmd != ELF_C_NULL + && cmd != ELF_C_WRITE + && unlikely (cmd != ELF_C_WRITE_MMAP)) + { + __libelf_seterrno (ELF_E_INVALID_CMD); + return -1; + } + + if (elf == NULL) + return -1; + + if (elf->kind != ELF_K_ELF) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return -1; + } + + rwlock_wrlock (elf->lock); + + /* Make sure we have an ELF header. */ + if (elf->state.elf.ehdr == NULL) + { + __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR); + size = -1; + goto out; + } + + /* Determine the number of sections. */ + shnum = (elf->state.elf.scns_last->cnt == 0 + ? 0 + : 1 + elf->state.elf.scns_last->data[elf->state.elf.scns_last->cnt - 1].index); + + /* Update the ELF descriptor. First, place the program header. It + will come right after the ELF header. The count the size of all + sections and finally place the section table. */ + size = (elf->class == ELFCLASS32 + ? __elf32_updatenull_wrlock (elf, &change_bo, shnum) + : __elf64_updatenull_wrlock (elf, &change_bo, shnum)); + if (likely (size != -1) + /* See whether we actually have to write out the data. */ + && (cmd == ELF_C_WRITE || cmd == ELF_C_WRITE_MMAP)) + { + if (elf->cmd != ELF_C_RDWR + && elf->cmd != ELF_C_RDWR_MMAP + && elf->cmd != ELF_C_WRITE + && unlikely (elf->cmd != ELF_C_WRITE_MMAP)) + { + __libelf_seterrno (ELF_E_UPDATE_RO); + size = -1; + } + else if (unlikely (elf->fildes == -1)) + { + /* We closed the file already. */ + __libelf_seterrno (ELF_E_FD_DISABLED); + size = -1; + } + else + size = write_file (elf, size, change_bo, shnum); + } + + out: + rwlock_unlock (elf->lock); + + return size; +} diff --git a/3rdparty/elfutils/libelf/elf_version.c b/3rdparty/elfutils/libelf/elf_version.c new file mode 100644 index 0000000..dcb6758 --- /dev/null +++ b/3rdparty/elfutils/libelf/elf_version.c @@ -0,0 +1,70 @@ +/* Coordinate ELF library and application versions. + Copyright (C) 1998, 1999, 2000, 2002 Red Hat, Inc. + This file is part of elfutils. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libelfP.h> + + +/* Is the version initialized? */ +int __libelf_version_initialized; + +/* Currently selected version. */ +unsigned int __libelf_version = EV_CURRENT; + + +unsigned int +elf_version (version) + unsigned int version; +{ + if (version == EV_NONE) + return __libelf_version; + + if (likely (version < EV_NUM)) + { + /* Phew, we know this version. */ + unsigned int last_version = __libelf_version; + + /* Store the new version. */ + __libelf_version = version; + + /* Signal that the version is now initialized. */ + __libelf_version_initialized = 1; + + /* And return the last version. */ + return last_version; + } + + /* We cannot handle this version. */ + __libelf_seterrno (ELF_E_UNKNOWN_VERSION); + return EV_NONE; +} +INTDEF(elf_version) diff --git a/3rdparty/elfutils/libelf/elfheaders.pri b/3rdparty/elfutils/libelf/elfheaders.pri new file mode 100644 index 0000000..2597ec8 --- /dev/null +++ b/3rdparty/elfutils/libelf/elfheaders.pri @@ -0,0 +1,17 @@ +HEADERS += \ + $$PWD/abstract.h \ + $$PWD/common.h \ + $$PWD/dl-hash.h \ + $$PWD/elf-knowledge.h \ + $$PWD/elf.h \ + $$PWD/exttypes.h \ + $$PWD/gelf_xlate.h \ + $$PWD/gelf.h \ + $$PWD/gnuhash_xlate.h \ + $$PWD/libelf.h \ + $$PWD/libelfP.h \ + $$PWD/nlist.h \ + $$PWD/note_xlate.h \ + $$PWD/version_xlate.h + +INCLUDEPATH += $$PWD diff --git a/3rdparty/elfutils/libelf/exttypes.h b/3rdparty/elfutils/libelf/exttypes.h new file mode 100644 index 0000000..8cb2aae --- /dev/null +++ b/3rdparty/elfutils/libelf/exttypes.h @@ -0,0 +1,102 @@ +/* External ELF types. + Copyright (C) 1998-2010 Red Hat, Inc. + This file is part of elfutils. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifndef _EXTTYPES_H +#define _EXTTYPES_H 1 + +/* Integral types. */ +typedef char Elf32_Ext_Addr[ELF32_FSZ_ADDR]; +typedef char Elf32_Ext_Off[ELF32_FSZ_OFF]; +typedef char Elf32_Ext_Half[ELF32_FSZ_HALF]; +typedef char Elf32_Ext_Sword[ELF32_FSZ_SWORD]; +typedef char Elf32_Ext_Word[ELF32_FSZ_WORD]; +typedef char Elf32_Ext_Sxword[ELF32_FSZ_SXWORD]; +typedef char Elf32_Ext_Xword[ELF32_FSZ_XWORD]; + +typedef char Elf64_Ext_Addr[ELF64_FSZ_ADDR]; +typedef char Elf64_Ext_Off[ELF64_FSZ_OFF]; +typedef char Elf64_Ext_Half[ELF64_FSZ_HALF]; +typedef char Elf64_Ext_Sword[ELF64_FSZ_SWORD]; +typedef char Elf64_Ext_Word[ELF64_FSZ_WORD]; +typedef char Elf64_Ext_Sxword[ELF64_FSZ_SXWORD]; +typedef char Elf64_Ext_Xword[ELF64_FSZ_XWORD]; + + +/* Define the composed types. */ +#define START(Bits, Name, EName) typedef struct { +#define END(Bits, Name) } ElfW2(Bits, Name) +#define TYPE_NAME(Type, Name) Type Name; +#define TYPE_EXTRA(Text) Text +#define TYPE_XLATE(Text) + +/* Get the abstract definitions. */ +#include "abstract.h" + +/* And define the types. */ +Ehdr32 (Ext_); +Phdr32 (Ext_); +Shdr32 (Ext_); +Sym32 (Ext_); +Rel32 (Ext_); +Rela32 (Ext_); +Note32 (Ext_); +Dyn32 (Ext_); +Verdef32 (Ext_); +Verdaux32 (Ext_); +Verneed32 (Ext_); +Vernaux32 (Ext_); +Syminfo32 (Ext_); +Move32 (Ext_); +Lib32 (Ext_); +auxv_t32 (Ext_); + +Ehdr64 (Ext_); +Phdr64 (Ext_); +Shdr64 (Ext_); +Sym64 (Ext_); +Rel64 (Ext_); +Rela64 (Ext_); +Note64 (Ext_); +Dyn64 (Ext_); +Verdef64 (Ext_); +Verdaux64 (Ext_); +Verneed64 (Ext_); +Vernaux64 (Ext_); +Syminfo64 (Ext_); +Move64 (Ext_); +Lib64 (Ext_); +auxv_t64 (Ext_); + +#undef START +#undef END +#undef TYPE_NAME +#undef TYPE_EXTRA +#undef TYPE_XLATE + +#endif /* exttypes.h */ diff --git a/3rdparty/elfutils/libelf/gelf.h b/3rdparty/elfutils/libelf/gelf.h new file mode 100644 index 0000000..e3f0740 --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf.h @@ -0,0 +1,332 @@ +/* This file defines generic ELF types, structures, and macros. + Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2007 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifndef _GELF_H +#define _GELF_H 1 + +#include <libelf.h> + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Class independent type definitions. Correctly speaking this is not + true. We assume that 64-bit binaries are the largest class and + therefore all other classes can be represented without loss. */ + +/* Type for a 16-bit quantity. */ +typedef Elf64_Half GElf_Half; + +/* Types for signed and unsigned 32-bit quantities. */ +typedef Elf64_Word GElf_Word; +typedef Elf64_Sword GElf_Sword; + +/* Types for signed and unsigned 64-bit quantities. */ +typedef Elf64_Xword GElf_Xword; +typedef Elf64_Sxword GElf_Sxword; + +/* Type of addresses. */ +typedef Elf64_Addr GElf_Addr; + +/* Type of file offsets. */ +typedef Elf64_Off GElf_Off; + + +/* The ELF file header. This appears at the start of every ELF file. */ +typedef Elf64_Ehdr GElf_Ehdr; + +/* Section header. */ +typedef Elf64_Shdr GElf_Shdr; + +/* Section index. */ +/* XXX This should probably be a larger type in preparation of times when + regular section indices can be larger. */ +typedef Elf64_Section GElf_Section; + +/* Symbol table entry. */ +typedef Elf64_Sym GElf_Sym; + +/* The syminfo section if available contains additional information about + every dynamic symbol. */ +typedef Elf64_Syminfo GElf_Syminfo; + +/* Relocation table entry without addend (in section of type SHT_REL). */ +typedef Elf64_Rel GElf_Rel; + +/* Relocation table entry with addend (in section of type SHT_RELA). */ +typedef Elf64_Rela GElf_Rela; + +/* Program segment header. */ +typedef Elf64_Phdr GElf_Phdr; + +/* Dynamic section entry. */ +typedef Elf64_Dyn GElf_Dyn; + + +/* Version definition sections. */ +typedef Elf64_Verdef GElf_Verdef; + +/* Auxialiary version information. */ +typedef Elf64_Verdaux GElf_Verdaux; + +/* Version dependency section. */ +typedef Elf64_Verneed GElf_Verneed; + +/* Auxiliary needed version information. */ +typedef Elf64_Vernaux GElf_Vernaux; + + +/* Type for version symbol information. */ +typedef Elf64_Versym GElf_Versym; + + +/* Auxiliary vector. */ +typedef Elf64_auxv_t GElf_auxv_t; + + +/* Note section contents. */ +typedef Elf64_Nhdr GElf_Nhdr; + + +/* Move structure. */ +typedef Elf64_Move GElf_Move; + + +/* Library list structure. */ +typedef Elf64_Lib GElf_Lib; + + +/* How to extract and insert information held in the st_info field. */ + +#define GELF_ST_BIND(val) ELF64_ST_BIND (val) +#define GELF_ST_TYPE(val) ELF64_ST_TYPE (val) +#define GELF_ST_INFO(bind, type) ELF64_ST_INFO (bind, type) + +/* How to extract information held in the st_other field. */ + +#define GELF_ST_VISIBILITY(val) ELF64_ST_VISIBILITY (val) + + +/* How to extract and insert information held in the r_info field. */ + +#define GELF_R_SYM(info) ELF64_R_SYM (info) +#define GELF_R_TYPE(info) ELF64_R_TYPE (info) +#define GELF_R_INFO(sym, type) ELF64_R_INFO (sym, type) + + +/* How to extract and insert information held in the m_info field. */ +#define GELF_M_SYM(info) ELF64_M_SYM (info) +#define GELF_M_SIZE(info) ELF64_M_SIZE (info) +#define GELF_M_INFO(sym, size) ELF64_M_INFO (sym, size) + + +/* Get class of the file associated with ELF. */ +extern int gelf_getclass (Elf *__elf); + + +/* Return size of array of COUNT elements of the type denoted by TYPE + in the external representation. The binary class is taken from ELF. + The result is based on version VERSION of the ELF standard. */ +extern size_t gelf_fsize (Elf *__elf, Elf_Type __type, size_t __count, + unsigned int __version); + +/* Retrieve object file header. */ +extern GElf_Ehdr *gelf_getehdr (Elf *__elf, GElf_Ehdr *__dest); + +/* Update the ELF header. */ +extern int gelf_update_ehdr (Elf *__elf, GElf_Ehdr *__src); + +/* Create new ELF header if none exists. */ +extern unsigned long int gelf_newehdr (Elf *__elf, int __class); + +/* Get section at OFFSET. */ +extern Elf_Scn *gelf_offscn (Elf *__elf, GElf_Off __offset); + +/* Retrieve section header. */ +extern GElf_Shdr *gelf_getshdr (Elf_Scn *__scn, GElf_Shdr *__dst); + +/* Update section header. */ +extern int gelf_update_shdr (Elf_Scn *__scn, GElf_Shdr *__src); + +/* Retrieve program header table entry. */ +extern GElf_Phdr *gelf_getphdr (Elf *__elf, int __ndx, GElf_Phdr *__dst); + +/* Update the program header. */ +extern int gelf_update_phdr (Elf *__elf, int __ndx, GElf_Phdr *__src); + +/* Create new program header with PHNUM entries. */ +extern unsigned long int gelf_newphdr (Elf *__elf, size_t __phnum); + + +/* Convert data structure from the representation in the file represented + by ELF to their memory representation. */ +extern Elf_Data *gelf_xlatetom (Elf *__elf, Elf_Data *__dest, + const Elf_Data *__src, unsigned int __encode); + +/* Convert data structure from to the representation in memory + represented by ELF file representation. */ +extern Elf_Data *gelf_xlatetof (Elf *__elf, Elf_Data *__dest, + const Elf_Data *__src, unsigned int __encode); + + +/* Retrieve REL relocation info at the given index. */ +extern GElf_Rel *gelf_getrel (Elf_Data *__data, int __ndx, GElf_Rel *__dst); + +/* Retrieve RELA relocation info at the given index. */ +extern GElf_Rela *gelf_getrela (Elf_Data *__data, int __ndx, GElf_Rela *__dst); + +/* Update REL relocation information at given index. */ +extern int gelf_update_rel (Elf_Data *__dst, int __ndx, GElf_Rel *__src); + +/* Update RELA relocation information at given index. */ +extern int gelf_update_rela (Elf_Data *__dst, int __ndx, GElf_Rela *__src); + + +/* Retrieve symbol information from the symbol table at the given index. */ +extern GElf_Sym *gelf_getsym (Elf_Data *__data, int __ndx, GElf_Sym *__dst); + +/* Update symbol information in the symbol table at the given index. */ +extern int gelf_update_sym (Elf_Data *__data, int __ndx, GElf_Sym *__src); + + +/* Retrieve symbol information and separate section index from the + symbol table at the given index. */ +extern GElf_Sym *gelf_getsymshndx (Elf_Data *__symdata, Elf_Data *__shndxdata, + int __ndx, GElf_Sym *__sym, + Elf32_Word *__xshndx); + +/* Update symbol information and separate section index in the symbol + table at the given index. */ +extern int gelf_update_symshndx (Elf_Data *__symdata, Elf_Data *__shndxdata, + int __ndx, GElf_Sym *__sym, + Elf32_Word __xshndx); + + +/* Retrieve additional symbol information from the symbol table at the + given index. */ +extern GElf_Syminfo *gelf_getsyminfo (Elf_Data *__data, int __ndx, + GElf_Syminfo *__dst); + +/* Update additional symbol information in the symbol table at the + given index. */ +extern int gelf_update_syminfo (Elf_Data *__data, int __ndx, + GElf_Syminfo *__src); + + +/* Get information from dynamic table at the given index. */ +extern GElf_Dyn *gelf_getdyn (Elf_Data *__data, int __ndx, GElf_Dyn *__dst); + +/* Update information in dynamic table at the given index. */ +extern int gelf_update_dyn (Elf_Data *__dst, int __ndx, GElf_Dyn *__src); + + +/* Get move structure at the given index. */ +extern GElf_Move *gelf_getmove (Elf_Data *__data, int __ndx, GElf_Move *__dst); + +/* Update move structure at the given index. */ +extern int gelf_update_move (Elf_Data *__data, int __ndx, + GElf_Move *__src); + + +/* Get library from table at the given index. */ +extern GElf_Lib *gelf_getlib (Elf_Data *__data, int __ndx, GElf_Lib *__dst); + +/* Update library in table at the given index. */ +extern int gelf_update_lib (Elf_Data *__data, int __ndx, GElf_Lib *__src); + + + +/* Retrieve symbol version information at given index. */ +extern GElf_Versym *gelf_getversym (Elf_Data *__data, int __ndx, + GElf_Versym *__dst); + +/* Update symbol version information. */ +extern int gelf_update_versym (Elf_Data *__data, int __ndx, + GElf_Versym *__src); + + +/* Retrieve required symbol version information at given offset. */ +extern GElf_Verneed *gelf_getverneed (Elf_Data *__data, int __offset, + GElf_Verneed *__dst); + +/* Update required symbol version information. */ +extern int gelf_update_verneed (Elf_Data *__data, int __offset, + GElf_Verneed *__src); + +/* Retrieve additional required symbol version information at given offset. */ +extern GElf_Vernaux *gelf_getvernaux (Elf_Data *__data, int __offset, + GElf_Vernaux *__dst); + +/* Update additional required symbol version information. */ +extern int gelf_update_vernaux (Elf_Data *__data, int __offset, + GElf_Vernaux *__src); + + +/* Retrieve symbol version definition information at given offset. */ +extern GElf_Verdef *gelf_getverdef (Elf_Data *__data, int __offset, + GElf_Verdef *__dst); + +/* Update symbol version definition information. */ +extern int gelf_update_verdef (Elf_Data *__data, int __offset, + GElf_Verdef *__src); + +/* Retrieve additional symbol version definition information at given + offset. */ +extern GElf_Verdaux *gelf_getverdaux (Elf_Data *__data, int __offset, + GElf_Verdaux *__dst); + +/* Update additional symbol version definition information. */ +extern int gelf_update_verdaux (Elf_Data *__data, int __offset, + GElf_Verdaux *__src); + + +/* Get auxv entry at the given index. */ +extern GElf_auxv_t *gelf_getauxv (Elf_Data *__data, int __ndx, + GElf_auxv_t *__dst); + +/* Update auxv entry at the given index. */ +extern int gelf_update_auxv (Elf_Data *__data, int __ndx, GElf_auxv_t *__src); + + +/* Get note header at the given offset into the data, and the offsets of + the note's name and descriptor data. Returns the offset of the next + note header, or 0 for an invalid offset or corrupt note header. */ +extern size_t gelf_getnote (Elf_Data *__data, size_t __offset, + GElf_Nhdr *__result, + size_t *__name_offset, size_t *__desc_offset); + + +/* Compute simple checksum from permanent parts of the ELF file. */ +extern long int gelf_checksum (Elf *__elf); + +#ifdef __cplusplus +} +#endif + +#endif /* gelf.h */ diff --git a/3rdparty/elfutils/libelf/gelf_checksum.c b/3rdparty/elfutils/libelf/gelf_checksum.c new file mode 100644 index 0000000..4906782 --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_checksum.c @@ -0,0 +1,49 @@ +/* Convert from file to memory representation. Generic ELF version. + Copyright (C) 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gelf.h> +#include <stddef.h> + +#include "libelfP.h" + + +long int +gelf_checksum (elf) + Elf *elf; +{ + if (elf == NULL) + return -1l; + + return (elf->class == ELFCLASS32 + ? INTUSE(elf32_checksum) (elf) : INTUSE(elf64_checksum) (elf)); +} diff --git a/3rdparty/elfutils/libelf/gelf_fsize.c b/3rdparty/elfutils/libelf/gelf_fsize.c new file mode 100644 index 0000000..a9d2288 --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_fsize.c @@ -0,0 +1,111 @@ +/* Return the size of an object file type. + Copyright (C) 1998-2010 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gelf.h> +#include <stddef.h> + +#include "libelfP.h" + + +/* These are the sizes for all the known types. */ +const size_t __libelf_type_sizes[EV_NUM - 1][ELFCLASSNUM - 1][ELF_T_NUM] = +{ + /* We have no entry for EV_NONE since we have to set an error. */ + [EV_CURRENT - 1] = { + [ELFCLASS32 - 1] = { +#define TYPE_SIZES(LIBELFBITS) \ + [ELF_T_ADDR] = ELFW2(LIBELFBITS, FSZ_ADDR), \ + [ELF_T_OFF] = ELFW2(LIBELFBITS, FSZ_OFF), \ + [ELF_T_BYTE] = 1, \ + [ELF_T_HALF] = ELFW2(LIBELFBITS, FSZ_HALF), \ + [ELF_T_WORD] = ELFW2(LIBELFBITS, FSZ_WORD), \ + [ELF_T_SWORD] = ELFW2(LIBELFBITS, FSZ_SWORD), \ + [ELF_T_XWORD] = ELFW2(LIBELFBITS, FSZ_XWORD), \ + [ELF_T_SXWORD] = ELFW2(LIBELFBITS, FSZ_SXWORD), \ + [ELF_T_EHDR] = sizeof (ElfW2(LIBELFBITS, Ext_Ehdr)), \ + [ELF_T_SHDR] = sizeof (ElfW2(LIBELFBITS, Ext_Shdr)), \ + [ELF_T_SYM] = sizeof (ElfW2(LIBELFBITS, Ext_Sym)), \ + [ELF_T_REL] = sizeof (ElfW2(LIBELFBITS, Ext_Rel)), \ + [ELF_T_RELA] = sizeof (ElfW2(LIBELFBITS, Ext_Rela)), \ + [ELF_T_PHDR] = sizeof (ElfW2(LIBELFBITS, Ext_Phdr)), \ + [ELF_T_DYN] = sizeof (ElfW2(LIBELFBITS, Ext_Dyn)), \ + [ELF_T_VDEF] = sizeof (ElfW2(LIBELFBITS, Ext_Verdef)), \ + [ELF_T_VDAUX] = sizeof (ElfW2(LIBELFBITS, Ext_Verdaux)), \ + [ELF_T_VNEED] = sizeof (ElfW2(LIBELFBITS, Ext_Verneed)), \ + [ELF_T_VNAUX] = sizeof (ElfW2(LIBELFBITS, Ext_Vernaux)), \ + [ELF_T_NHDR] = sizeof (ElfW2(LIBELFBITS, Ext_Nhdr)), \ + [ELF_T_SYMINFO] = sizeof (ElfW2(LIBELFBITS, Ext_Syminfo)), \ + [ELF_T_MOVE] = sizeof (ElfW2(LIBELFBITS, Ext_Move)), \ + [ELF_T_LIB] = sizeof (ElfW2(LIBELFBITS, Ext_Lib)), \ + [ELF_T_AUXV] = sizeof (ElfW2(LIBELFBITS, Ext_auxv_t)), \ + [ELF_T_GNUHASH] = ELFW2(LIBELFBITS, FSZ_WORD) + TYPE_SIZES (32) + }, + [ELFCLASS64 - 1] = { + TYPE_SIZES (64) + } + } +}; + + +size_t +gelf_fsize (elf, type, count, version) + Elf *elf; + Elf_Type type; + size_t count; + unsigned int version; +{ + /* We do not have differences between file and memory sizes. Better + not since otherwise `mmap' would not work. */ + if (elf == NULL) + return 0; + + if (version == EV_NONE || version >= EV_NUM) + { + __libelf_seterrno (ELF_E_UNKNOWN_VERSION); + return 0; + } + + if (type >= ELF_T_NUM) + { + __libelf_seterrno (ELF_E_UNKNOWN_TYPE); + return 0; + } + +#if EV_NUM != 2 + return count * __libelf_type_sizes[version - 1][elf->class - 1][type]; +#else + return count * __libelf_type_sizes[0][elf->class - 1][type]; +#endif +} +INTDEF(gelf_fsize) diff --git a/3rdparty/elfutils/libelf/gelf_getauxv.c b/3rdparty/elfutils/libelf/gelf_getauxv.c new file mode 100644 index 0000000..a2f04e7 --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_getauxv.c @@ -0,0 +1,110 @@ +/* Get information from auxiliary vector at the given index. + Copyright (C) 2007 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <gelf.h> +#include <string.h> + +#include "libelfP.h" + + +GElf_auxv_t * +gelf_getauxv (data, ndx, dst) + Elf_Data *data; + int ndx; + GElf_auxv_t *dst; +{ + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) data; + GElf_auxv_t *result = NULL; + Elf *elf; + + if (data_scn == NULL) + return NULL; + + if (unlikely (data_scn->d.d_type != ELF_T_AUXV)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + elf = data_scn->s->elf; + + rwlock_rdlock (elf->lock); + + /* This is the one place where we have to take advantage of the fact + that an `Elf_Data' pointer is also a pointer to `Elf_Data_Scn'. + The interface is broken so that it requires this hack. */ + if (elf->class == ELFCLASS32) + { + Elf32_auxv_t *src; + + /* Here it gets a bit more complicated. The format of the vector + entries has to be converted. The user better have provided a + buffer where we can store the information. While copying the data + we convert the format. */ + if (unlikely ((ndx + 1) * sizeof (Elf32_auxv_t) > data_scn->d.d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + src = &((Elf32_auxv_t *) data_scn->d.d_buf)[ndx]; + + /* This might look like a simple copy operation but it's + not. There are zero- and sign-extensions going on. */ + dst->a_type = src->a_type; + dst->a_un.a_val = src->a_un.a_val; + } + else + { + /* If this is a 64 bit object it's easy. */ + assert (sizeof (GElf_auxv_t) == sizeof (Elf64_auxv_t)); + + /* The data is already in the correct form. Just make sure the + index is OK. */ + if (unlikely ((ndx + 1) * sizeof (GElf_auxv_t) > data_scn->d.d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + memcpy (dst, data_scn->d.d_buf + ndx * sizeof (GElf_auxv_t), + sizeof (GElf_auxv_t)); + } + + result = dst; + + out: + rwlock_unlock (elf->lock); + + return result; +} diff --git a/3rdparty/elfutils/libelf/gelf_getclass.c b/3rdparty/elfutils/libelf/gelf_getclass.c new file mode 100644 index 0000000..53759dc --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_getclass.c @@ -0,0 +1,45 @@ +/* Return the class of file associated with the descriptor. + Copyright (C) 1999, 2000, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1999. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gelf.h> +#include <stddef.h> + +#include "libelfP.h" + + +int +gelf_getclass (elf) + Elf *elf; +{ + return elf == NULL || elf->kind != ELF_K_ELF ? ELFCLASSNONE : elf->class; +} diff --git a/3rdparty/elfutils/libelf/gelf_getdyn.c b/3rdparty/elfutils/libelf/gelf_getdyn.c new file mode 100644 index 0000000..c366fd5 --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_getdyn.c @@ -0,0 +1,111 @@ +/* Get information from dynamic table at the given index. + Copyright (C) 2000, 2001, 2002, 2005, 2009, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <gelf.h> +#include <string.h> + +#include "libelfP.h" + + +GElf_Dyn * +gelf_getdyn (data, ndx, dst) + Elf_Data *data; + int ndx; + GElf_Dyn *dst; +{ + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) data; + GElf_Dyn *result = NULL; + Elf *elf; + + if (data_scn == NULL) + return NULL; + + if (unlikely (data_scn->d.d_type != ELF_T_DYN)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + elf = data_scn->s->elf; + + rwlock_rdlock (elf->lock); + + /* This is the one place where we have to take advantage of the fact + that an `Elf_Data' pointer is also a pointer to `Elf_Data_Scn'. + The interface is broken so that it requires this hack. */ + if (elf->class == ELFCLASS32) + { + Elf32_Dyn *src; + + /* Here it gets a bit more complicated. The format of the symbol + table entries has to be adopted. The user better has provided + a buffer where we can store the information. While copying the + data we are converting the format. */ + if (INVALID_NDX (ndx, Elf32_Dyn, &data_scn->d)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + src = &((Elf32_Dyn *) data_scn->d.d_buf)[ndx]; + + /* This might look like a simple copy operation but it's + not. There are zero- and sign-extensions going on. */ + dst->d_tag = src->d_tag; + /* It OK to copy `d_val' since `d_ptr' has the same size. */ + dst->d_un.d_val = src->d_un.d_val; + } + else + { + /* If this is a 64 bit object it's easy. */ + assert (sizeof (GElf_Dyn) == sizeof (Elf64_Dyn)); + + /* The data is already in the correct form. Just make sure the + index is OK. */ + if (INVALID_NDX (ndx, GElf_Dyn, &data_scn->d)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + *dst = ((GElf_Dyn *) data_scn->d.d_buf)[ndx]; + } + + result = dst; + + out: + rwlock_unlock (elf->lock); + + return result; +} diff --git a/3rdparty/elfutils/libelf/gelf_getehdr.c b/3rdparty/elfutils/libelf/gelf_getehdr.c new file mode 100644 index 0000000..ea83fc0 --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_getehdr.c @@ -0,0 +1,111 @@ +/* Get ELF header. + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2005 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gelf.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + +#include "libelfP.h" + + +GElf_Ehdr * +__gelf_getehdr_rdlock (elf, dest) + Elf *elf; + GElf_Ehdr *dest; +{ + GElf_Ehdr *result = NULL; + + if (elf == NULL) + return NULL; + + if (unlikely (elf->kind != ELF_K_ELF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + /* The following is an optimization: the ehdr element is at the same + position in both the elf32 and elf64 structure. */ + if (offsetof (struct Elf, state.elf32.ehdr) + != offsetof (struct Elf, state.elf64.ehdr)) + abort (); + /* Just pick one of the values. */ + if (unlikely (elf->state.elf64.ehdr == NULL)) + /* Maybe no ELF header was created yet. */ + __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR); + else if (elf->class == ELFCLASS32) + { + Elf32_Ehdr *ehdr = elf->state.elf32.ehdr; + + /* Convert the 32-bit struct to an 64-bit one. */ + memcpy (dest->e_ident, ehdr->e_ident, EI_NIDENT); +#define COPY(name) \ + dest->name = ehdr->name + COPY (e_type); + COPY (e_machine); + COPY (e_version); + COPY (e_entry); + COPY (e_phoff); + COPY (e_shoff); + COPY (e_flags); + COPY (e_ehsize); + COPY (e_phentsize); + COPY (e_phnum); + COPY (e_shentsize); + COPY (e_shnum); + COPY (e_shstrndx); + + result = dest; + } + else + result = memcpy (dest, elf->state.elf64.ehdr, sizeof (*dest)); + + return result; +} + +GElf_Ehdr * +gelf_getehdr (elf, dest) + Elf *elf; + GElf_Ehdr *dest; +{ + GElf_Ehdr *result; + if (elf == NULL) + return NULL; + + rwlock_rdlock (elf->lock); + result = __gelf_getehdr_rdlock (elf, dest); + rwlock_unlock (elf->lock); + + return result; +} diff --git a/3rdparty/elfutils/libelf/gelf_getlib.c b/3rdparty/elfutils/libelf/gelf_getlib.c new file mode 100644 index 0000000..880817e --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_getlib.c @@ -0,0 +1,80 @@ +/* Get library from table at the given index. + Copyright (C) 2004, 2005, 2009, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <gelf.h> +#include <string.h> + +#include "libelfP.h" + + +GElf_Lib * +gelf_getlib (data, ndx, dst) + Elf_Data *data; + int ndx; + GElf_Lib *dst; +{ + if (data == NULL) + return NULL; + + if (unlikely (data->d_type != ELF_T_LIB)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) data; + + rwlock_rdlock (data_scn->s->elf->lock); + + /* The on disk format of Elf32_Lib and Elf64_Lib is identical. So + we can simplify things significantly. */ + assert (sizeof (GElf_Lib) == sizeof (Elf32_Lib)); + assert (sizeof (GElf_Lib) == sizeof (Elf64_Lib)); + + /* The data is already in the correct form. Just make sure the + index is OK. */ + GElf_Lib *result = NULL; + if (INVALID_NDX (ndx, GElf_Lib, data)) + __libelf_seterrno (ELF_E_INVALID_INDEX); + else + { + *dst = ((GElf_Lib *) data->d_buf)[ndx]; + + result = dst; + } + + rwlock_unlock (data_scn->s->elf->lock); + + return result; +} diff --git a/3rdparty/elfutils/libelf/gelf_getmove.c b/3rdparty/elfutils/libelf/gelf_getmove.c new file mode 100644 index 0000000..b81d61f --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_getmove.c @@ -0,0 +1,82 @@ +/* Get move structure at the given index. + Copyright (C) 2000, 2001, 2002, 2005, 2009, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <gelf.h> +#include <stddef.h> + +#include "libelfP.h" + + +GElf_Move * +gelf_getmove (data, ndx, dst) + Elf_Data *data; + int ndx; + GElf_Move *dst; +{ + GElf_Move *result = NULL; + Elf *elf; + + if (data == NULL) + return NULL; + + if (unlikely (data->d_type != ELF_T_MOVE)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + /* The types for 32 and 64 bit are the same. Lucky us. */ + assert (sizeof (GElf_Move) == sizeof (Elf32_Move)); + assert (sizeof (GElf_Move) == sizeof (Elf64_Move)); + + /* The data is already in the correct form. Just make sure the + index is OK. */ + if (INVALID_NDX (ndx, GElf_Move, data)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + elf = ((Elf_Data_Scn *) data)->s->elf; + rwlock_rdlock (elf->lock); + + *dst = ((GElf_Move *) data->d_buf)[ndx]; + + rwlock_unlock (elf->lock); + + result = dst; + + out: + return result; +} diff --git a/3rdparty/elfutils/libelf/gelf_getnote.c b/3rdparty/elfutils/libelf/gelf_getnote.c new file mode 100644 index 0000000..7dc8215 --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_getnote.c @@ -0,0 +1,104 @@ +/* Get note information at the supplied offset. + Copyright (C) 2007, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <gelf.h> +#include <string.h> + +#include "libelfP.h" + +size_t +gelf_getnote (data, offset, result, name_offset, desc_offset) + Elf_Data *data; + size_t offset; + GElf_Nhdr *result; + size_t *name_offset; + size_t *desc_offset; +{ + if (data == NULL) + return 0; + + if (unlikely (data->d_type != ELF_T_NHDR)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return 0; + } + + /* It's easy to handle this type. It has the same size for 32 and + 64 bit objects. */ + assert (sizeof (GElf_Nhdr) == sizeof (Elf32_Nhdr)); + assert (sizeof (GElf_Nhdr) == sizeof (Elf64_Nhdr)); + + rwlock_rdlock (((Elf_Data_Scn *) data)->s->elf->lock); + + /* The data is already in the correct form. Just make sure the + offset is OK. */ + if (unlikely (offset > data->d_size + || data->d_size - offset < sizeof (GElf_Nhdr))) + { + __libelf_seterrno (ELF_E_OFFSET_RANGE); + offset = 0; + } + else + { + const GElf_Nhdr *n = data->d_buf + offset; + offset += sizeof *n; + + /* Include padding. Check below for overflow. */ + GElf_Word namesz = NOTE_ALIGN (n->n_namesz); + GElf_Word descsz = NOTE_ALIGN (n->n_descsz); + + if (unlikely (offset > data->d_size + || data->d_size - offset < namesz + || (namesz == 0 && n->n_namesz != 0))) + offset = 0; + else + { + *name_offset = offset; + offset += namesz; + if (unlikely (offset > data->d_size + || data->d_size - offset < descsz + || (descsz == 0 && n->n_descsz != 0))) + offset = 0; + else + { + *desc_offset = offset; + offset += descsz; + *result = *n; + } + } + } + + rwlock_unlock (((Elf_Data_Scn *) data)->s->elf->lock); + + return offset; +} diff --git a/3rdparty/elfutils/libelf/gelf_getphdr.c b/3rdparty/elfutils/libelf/gelf_getphdr.c new file mode 100644 index 0000000..3bf7123 --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_getphdr.c @@ -0,0 +1,142 @@ +/* Return program header table entry. + Copyright (C) 1998-2010 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gelf.h> +#include <string.h> +#include <stdbool.h> + +#include "libelfP.h" + + +GElf_Phdr * +gelf_getphdr (elf, ndx, dst) + Elf *elf; + int ndx; + GElf_Phdr *dst; +{ + GElf_Phdr *result = NULL; + + if (elf == NULL) + return NULL; + + if (unlikely (elf->kind != ELF_K_ELF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + if (dst == NULL) + { + __libelf_seterrno (ELF_E_INVALID_OPERAND); + return NULL; + } + + rwlock_rdlock (elf->lock); + + if (elf->class == ELFCLASS32) + { + /* Copy the elements one-by-one. */ + Elf32_Phdr *phdr = elf->state.elf32.phdr; + + if (phdr == NULL) + { + rwlock_unlock (elf->lock); + phdr = INTUSE(elf32_getphdr) (elf); + if (phdr == NULL) + /* The error number is already set. */ + return NULL; + rwlock_rdlock (elf->lock); + } + + /* Test whether the index is ok. */ + size_t phnum; + if (ndx >= elf->state.elf32.ehdr->e_phnum + && (elf->state.elf32.ehdr->e_phnum != PN_XNUM + || __elf_getphdrnum_rdlock (elf, &phnum) != 0 + || (size_t) ndx >= phnum)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + /* We know the result now. */ + result = dst; + + /* Now correct the pointer to point to the correct element. */ + phdr += ndx; + +#define COPY(Name) result->Name = phdr->Name + COPY (p_type); + COPY (p_offset); + COPY (p_vaddr); + COPY (p_paddr); + COPY (p_filesz); + COPY (p_memsz); + COPY (p_flags); + COPY (p_align); + } + else + { + /* Copy the elements one-by-one. */ + Elf64_Phdr *phdr = elf->state.elf64.phdr; + + if (phdr == NULL) + { + rwlock_unlock (elf->lock); + phdr = INTUSE(elf64_getphdr) (elf); + if (phdr == NULL) + /* The error number is already set. */ + return NULL; + rwlock_rdlock (elf->lock); + } + + /* Test whether the index is ok. */ + size_t phnum; + if (ndx >= elf->state.elf64.ehdr->e_phnum + && (elf->state.elf64.ehdr->e_phnum != PN_XNUM + || __elf_getphdrnum_rdlock (elf, &phnum) != 0 + || (size_t) ndx >= phnum)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + /* We only have to copy the data. */ + result = memcpy (dst, phdr + ndx, sizeof (GElf_Phdr)); + } + + out: + rwlock_unlock (elf->lock); + + return result; +} diff --git a/3rdparty/elfutils/libelf/gelf_getrel.c b/3rdparty/elfutils/libelf/gelf_getrel.c new file mode 100644 index 0000000..1f786ff --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_getrel.c @@ -0,0 +1,102 @@ +/* Get REL relocation information at given index. + Copyright (C) 2000, 2001, 2002, 2005, 2009, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gelf.h> +#include <string.h> + +#include "libelfP.h" + + +GElf_Rel * +gelf_getrel (data, ndx, dst) + Elf_Data *data; + int ndx; + GElf_Rel *dst; +{ + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) data; + Elf_Scn *scn; + GElf_Rel *result; + + if (data_scn == NULL) + return NULL; + + if (unlikely (data_scn->d.d_type != ELF_T_REL)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + /* This is the one place where we have to take advantage of the fact + that an `Elf_Data' pointer is also a pointer to `Elf_Data_Scn'. + The interface is broken so that it requires this hack. */ + scn = data_scn->s; + + rwlock_rdlock (scn->elf->lock); + + if (scn->elf->class == ELFCLASS32) + { + /* We have to convert the data. */ + if (INVALID_NDX (ndx, Elf32_Rel, &data_scn->d)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + result = NULL; + } + else + { + Elf32_Rel *src = &((Elf32_Rel *) data_scn->d.d_buf)[ndx]; + + dst->r_offset = src->r_offset; + dst->r_info = GELF_R_INFO (ELF32_R_SYM (src->r_info), + ELF32_R_TYPE (src->r_info)); + + result = dst; + } + } + else + { + /* Simply copy the data after we made sure we are actually getting + correct data. */ + if (INVALID_NDX (ndx, Elf64_Rel, &data_scn->d)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + result = NULL; + } + else + result = memcpy (dst, &((Elf64_Rel *) data_scn->d.d_buf)[ndx], + sizeof (Elf64_Rel)); + } + + rwlock_unlock (scn->elf->lock); + + return result; +} diff --git a/3rdparty/elfutils/libelf/gelf_getrela.c b/3rdparty/elfutils/libelf/gelf_getrela.c new file mode 100644 index 0000000..cead7ee --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_getrela.c @@ -0,0 +1,103 @@ +/* Get RELA relocation information at given index. + Copyright (C) 2000, 2001, 2002, 2005, 2009, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gelf.h> +#include <string.h> + +#include "libelfP.h" + + +GElf_Rela * +gelf_getrela (data, ndx, dst) + Elf_Data *data; + int ndx; + GElf_Rela *dst; +{ + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) data; + Elf_Scn *scn; + GElf_Rela *result; + + if (data_scn == NULL) + return NULL; + + if (unlikely (data_scn->d.d_type != ELF_T_RELA)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + /* This is the one place where we have to take advantage of the fact + that an `Elf_Data' pointer is also a pointer to `Elf_Data_Scn'. + The interface is broken so that it requires this hack. */ + scn = data_scn->s; + + rwlock_rdlock (scn->elf->lock); + + if (scn->elf->class == ELFCLASS32) + { + /* We have to convert the data. */ + if (INVALID_NDX (ndx, Elf32_Rela, &data_scn->d)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + result = NULL; + } + else + { + Elf32_Rela *src = &((Elf32_Rela *) data_scn->d.d_buf)[ndx]; + + dst->r_offset = src->r_offset; + dst->r_info = GELF_R_INFO (ELF32_R_SYM (src->r_info), + ELF32_R_TYPE (src->r_info)); + dst->r_addend = src->r_addend; + + result = dst; + } + } + else + { + /* Simply copy the data after we made sure we are actually getting + correct data. */ + if (INVALID_NDX (ndx, Elf64_Rela, &data_scn->d)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + result = NULL; + } + else + result = memcpy (dst, &((Elf64_Rela *) data_scn->d.d_buf)[ndx], + sizeof (Elf64_Rela)); + } + + rwlock_unlock (scn->elf->lock); + + return result; +} diff --git a/3rdparty/elfutils/libelf/gelf_getshdr.c b/3rdparty/elfutils/libelf/gelf_getshdr.c new file mode 100644 index 0000000..4a48cb6 --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_getshdr.c @@ -0,0 +1,105 @@ +/* Return section header. + Copyright (C) 1998, 1999, 2000, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gelf.h> +#include <string.h> + +#include "libelfP.h" + + +GElf_Shdr * +gelf_getshdr (scn, dst) + Elf_Scn *scn; + GElf_Shdr *dst; +{ + GElf_Shdr *result = NULL; + + if (scn == NULL) + return NULL; + + if (dst == NULL) + { + __libelf_seterrno (ELF_E_INVALID_OPERAND); + return NULL; + } + + rwlock_rdlock (scn->elf->lock); + + if (scn->elf->class == ELFCLASS32) + { + /* Copy the elements one-by-one. */ + Elf32_Shdr *shdr + = scn->shdr.e32 ?: __elf32_getshdr_rdlock (scn); + + if (shdr == NULL) + { + __libelf_seterrno (ELF_E_INVALID_OPERAND); + goto out; + } + +#define COPY(name) \ + dst->name = shdr->name + COPY (sh_name); + COPY (sh_type); + COPY (sh_flags); + COPY (sh_addr); + COPY (sh_offset); + COPY (sh_size); + COPY (sh_link); + COPY (sh_info); + COPY (sh_addralign); + COPY (sh_entsize); + + result = dst; + } + else + { + Elf64_Shdr *shdr + = scn->shdr.e64 ?: __elf64_getshdr_rdlock (scn); + + if (shdr == NULL) + { + __libelf_seterrno (ELF_E_INVALID_OPERAND); + goto out; + } + + /* We only have to copy the data. */ + result = memcpy (dst, shdr, sizeof (GElf_Shdr)); + } + + out: + rwlock_unlock (scn->elf->lock); + + return result; +} +INTDEF(gelf_getshdr) diff --git a/3rdparty/elfutils/libelf/gelf_getsym.c b/3rdparty/elfutils/libelf/gelf_getsym.c new file mode 100644 index 0000000..a141c2d --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_getsym.c @@ -0,0 +1,117 @@ +/* Get symbol information from symbol table at the given index. + Copyright (C) 1999, 2000, 2001, 2002, 2005, 2009, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1999. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <gelf.h> +#include <string.h> + +#include "libelfP.h" + + +GElf_Sym * +gelf_getsym (data, ndx, dst) + Elf_Data *data; + int ndx; + GElf_Sym *dst; +{ + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) data; + GElf_Sym *result = NULL; + + if (data == NULL) + return NULL; + + if (unlikely (data->d_type != ELF_T_SYM)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + rwlock_rdlock (data_scn->s->elf->lock); + + /* This is the one place where we have to take advantage of the fact + that an `Elf_Data' pointer is also a pointer to `Elf_Data_Scn'. + The interface is broken so that it requires this hack. */ + if (data_scn->s->elf->class == ELFCLASS32) + { + Elf32_Sym *src; + + /* Here it gets a bit more complicated. The format of the symbol + table entries has to be adopted. The user better has provided + a buffer where we can store the information. While copying the + data we are converting the format. */ + if (INVALID_NDX (ndx, Elf32_Sym, data)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + src = &((Elf32_Sym *) data->d_buf)[ndx]; + + /* This might look like a simple copy operation but it's + not. There are zero- and sign-extensions going on. */ +#define COPY(name) \ + dst->name = src->name + COPY (st_name); + /* Please note that we can simply copy the `st_info' element since + the definitions of ELFxx_ST_BIND and ELFxx_ST_TYPE are the same + for the 64 bit variant. */ + COPY (st_info); + COPY (st_other); + COPY (st_shndx); + COPY (st_value); + COPY (st_size); + } + else + { + /* If this is a 64 bit object it's easy. */ + assert (sizeof (GElf_Sym) == sizeof (Elf64_Sym)); + + /* The data is already in the correct form. Just make sure the + index is OK. */ + if (INVALID_NDX (ndx, GElf_Sym, data)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + *dst = ((GElf_Sym *) data->d_buf)[ndx]; + } + + result = dst; + + out: + rwlock_unlock (data_scn->s->elf->lock); + + return result; +} +INTDEF(gelf_getsym) diff --git a/3rdparty/elfutils/libelf/gelf_getsyminfo.c b/3rdparty/elfutils/libelf/gelf_getsyminfo.c new file mode 100644 index 0000000..8d7da7f --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_getsyminfo.c @@ -0,0 +1,80 @@ +/* Get additional symbol information from symbol table at the given index. + Copyright (C) 2000, 2001, 2002, 2005, 2009, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <gelf.h> +#include <string.h> + +#include "libelfP.h" + + +GElf_Syminfo * +gelf_getsyminfo (data, ndx, dst) + Elf_Data *data; + int ndx; + GElf_Syminfo *dst; +{ + GElf_Syminfo *result = NULL; + + if (data == NULL) + return NULL; + + if (unlikely (data->d_type != ELF_T_SYMINFO)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + /* The types for 32 and 64 bit are the same. Lucky us. */ + assert (sizeof (GElf_Syminfo) == sizeof (Elf32_Syminfo)); + assert (sizeof (GElf_Syminfo) == sizeof (Elf64_Syminfo)); + + rwlock_rdlock (((Elf_Data_Scn *) data)->s->elf->lock); + + /* The data is already in the correct form. Just make sure the + index is OK. */ + if (INVALID_NDX (ndx, GElf_Syminfo, data)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + *dst = ((GElf_Syminfo *) data->d_buf)[ndx]; + + result = dst; + + out: + rwlock_unlock (((Elf_Data_Scn *) data)->s->elf->lock); + + return result; +} diff --git a/3rdparty/elfutils/libelf/gelf_getsymshndx.c b/3rdparty/elfutils/libelf/gelf_getsymshndx.c new file mode 100644 index 0000000..c19e876 --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_getsymshndx.c @@ -0,0 +1,140 @@ +/* Get symbol information and separate section index from symbol table + at the given index. + Copyright (C) 2000, 2001, 2002, 2005, 2009, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <gelf.h> +#include <string.h> + +#include "libelfP.h" + + +GElf_Sym * +gelf_getsymshndx (symdata, shndxdata, ndx, dst, dstshndx) + Elf_Data *symdata; + Elf_Data *shndxdata; + int ndx; + GElf_Sym *dst; + Elf32_Word *dstshndx; +{ + Elf_Data_Scn *symdata_scn = (Elf_Data_Scn *) symdata; + Elf_Data_Scn *shndxdata_scn = (Elf_Data_Scn *) shndxdata; + GElf_Sym *result = NULL; + Elf32_Word shndx = 0; + + if (symdata == NULL) + return NULL; + + if (unlikely (symdata->d_type != ELF_T_SYM) + || (likely (shndxdata_scn != NULL) + && unlikely (shndxdata->d_type != ELF_T_WORD))) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + rwlock_rdlock (symdata_scn->s->elf->lock); + + /* The user is not required to pass a data descriptor for an extended + section index table. */ + if (likely (shndxdata_scn != NULL)) + { + if (INVALID_NDX (ndx, Elf32_Word, &shndxdata_scn->d)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + shndx = ((Elf32_Word *) shndxdata_scn->d.d_buf)[ndx]; + } + + /* This is the one place where we have to take advantage of the fact + that an `Elf_Data' pointer is also a pointer to `Elf_Data_Scn'. + The interface is broken so that it requires this hack. */ + if (symdata_scn->s->elf->class == ELFCLASS32) + { + Elf32_Sym *src; + + /* Here it gets a bit more complicated. The format of the symbol + table entries has to be adopted. The user better has provided + a buffer where we can store the information. While copying the + data we are converting the format. */ + if (INVALID_NDX (ndx, Elf32_Sym, symdata)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + src = &((Elf32_Sym *) symdata->d_buf)[ndx]; + + /* This might look like a simple copy operation but it's + not. There are zero- and sign-extensions going on. */ +#define COPY(name) \ + dst->name = src->name + COPY (st_name); + /* Please note that we can simply copy the `st_info' element since + the definitions of ELFxx_ST_BIND and ELFxx_ST_TYPE are the same + for the 64 bit variant. */ + COPY (st_info); + COPY (st_other); + COPY (st_shndx); + COPY (st_value); + COPY (st_size); + } + else + { + /* If this is a 64 bit object it's easy. */ + assert (sizeof (GElf_Sym) == sizeof (Elf64_Sym)); + + /* The data is already in the correct form. Just make sure the + index is OK. */ + if (INVALID_NDX (ndx, GElf_Sym, symdata)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + *dst = ((GElf_Sym *) symdata->d_buf)[ndx]; + } + + /* Now we can store the section index. */ + if (dstshndx != NULL) + *dstshndx = shndx; + + result = dst; + + out: + rwlock_unlock (symdata_scn->s->elf->lock); + + return result; +} diff --git a/3rdparty/elfutils/libelf/gelf_getverdaux.c b/3rdparty/elfutils/libelf/gelf_getverdaux.c new file mode 100644 index 0000000..d125d9e --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_getverdaux.c @@ -0,0 +1,82 @@ +/* Get additional symbol version definition information at the given offset. + Copyright (C) 1999, 2000, 2001, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1999. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <gelf.h> +#include <string.h> + +#include "libelfP.h" + + +GElf_Verdaux * +gelf_getverdaux (data, offset, dst) + Elf_Data *data; + int offset; + GElf_Verdaux *dst; +{ + GElf_Verdaux *result; + + if (data == NULL) + return NULL; + + if (unlikely (data->d_type != ELF_T_VDEF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + /* It's easy to handle this type. It has the same size for 32 and + 64 bit objects. */ + assert (sizeof (GElf_Verdaux) == sizeof (Elf32_Verdaux)); + assert (sizeof (GElf_Verdaux) == sizeof (Elf64_Verdaux)); + + rwlock_rdlock (((Elf_Data_Scn *) data)->s->elf->lock); + + /* The data is already in the correct form. Just make sure the + index is OK. */ + if (unlikely (offset < 0) + || unlikely (offset + sizeof (GElf_Verdaux) > data->d_size) + || unlikely (offset % __alignof__ (GElf_Verdaux) != 0)) + { + __libelf_seterrno (ELF_E_OFFSET_RANGE); + result = NULL; + } + else + result = (GElf_Verdaux *) memcpy (dst, (char *) data->d_buf + offset, + sizeof (GElf_Verdaux)); + + + rwlock_unlock (((Elf_Data_Scn *) data)->s->elf->lock); + + return result; +} diff --git a/3rdparty/elfutils/libelf/gelf_getverdef.c b/3rdparty/elfutils/libelf/gelf_getverdef.c new file mode 100644 index 0000000..59a3214 --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_getverdef.c @@ -0,0 +1,81 @@ +/* Get symbol version definition information at the given offset. + Copyright (C) 1999, 2000, 2001, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1999. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <gelf.h> +#include <string.h> + +#include "libelfP.h" + + +GElf_Verdef * +gelf_getverdef (data, offset, dst) + Elf_Data *data; + int offset; + GElf_Verdef *dst; +{ + GElf_Verdef *result; + + if (data == NULL) + return NULL; + + if (unlikely (data->d_type != ELF_T_VDEF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + /* It's easy to handle this type. It has the same size for 32 and + 64 bit objects. */ + assert (sizeof (GElf_Verdef) == sizeof (Elf32_Verdef)); + assert (sizeof (GElf_Verdef) == sizeof (Elf64_Verdef)); + + rwlock_rdlock (((Elf_Data_Scn *) data)->s->elf->lock); + + /* The data is already in the correct form. Just make sure the + index is OK. */ + if (unlikely (offset < 0) + || unlikely (offset + sizeof (GElf_Verdef) > data->d_size) + || unlikely (offset % __alignof__ (GElf_Verdef) != 0)) + { + __libelf_seterrno (ELF_E_OFFSET_RANGE); + result = NULL; + } + else + result = (GElf_Verdef *) memcpy (dst, (char *) data->d_buf + offset, + sizeof (GElf_Verdef)); + + rwlock_unlock (((Elf_Data_Scn *) data)->s->elf->lock); + + return result; +} diff --git a/3rdparty/elfutils/libelf/gelf_getvernaux.c b/3rdparty/elfutils/libelf/gelf_getvernaux.c new file mode 100644 index 0000000..8ebf56a --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_getvernaux.c @@ -0,0 +1,84 @@ +/* Get additional required symbol version information at the given offset. + Copyright (C) 1999, 2000, 2001, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1999. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <gelf.h> +#include <string.h> + +#include "libelfP.h" + + +GElf_Vernaux * +gelf_getvernaux (data, offset, dst) + Elf_Data *data; + int offset; + GElf_Vernaux *dst; +{ + GElf_Vernaux *result; + + if (data == NULL) + return NULL; + + if (unlikely (data->d_type != ELF_T_VNEED)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + /* It's easy to handle this type. It has the same size for 32 and + 64 bit objects. And fortunately the `ElfXXX_Vernaux' records + also have the same size. */ + assert (sizeof (GElf_Vernaux) == sizeof (Elf32_Verneed)); + assert (sizeof (GElf_Vernaux) == sizeof (Elf64_Verneed)); + assert (sizeof (GElf_Vernaux) == sizeof (Elf32_Vernaux)); + assert (sizeof (GElf_Vernaux) == sizeof (Elf64_Vernaux)); + + rwlock_rdlock (((Elf_Data_Scn *) data)->s->elf->lock); + + /* The data is already in the correct form. Just make sure the + index is OK. */ + if (unlikely (offset < 0) + || unlikely (offset + sizeof (GElf_Vernaux) > data->d_size) + || unlikely (offset % sizeof (GElf_Vernaux) != 0)) + { + __libelf_seterrno (ELF_E_OFFSET_RANGE); + result = NULL; + } + else + result = (GElf_Vernaux *) memcpy (dst, (char *) data->d_buf + offset, + sizeof (GElf_Verneed)); + + rwlock_unlock (((Elf_Data_Scn *) data)->s->elf->lock); + + return result; +} diff --git a/3rdparty/elfutils/libelf/gelf_getverneed.c b/3rdparty/elfutils/libelf/gelf_getverneed.c new file mode 100644 index 0000000..95fd11f --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_getverneed.c @@ -0,0 +1,84 @@ +/* Get required symbol version information at the given offset. + Copyright (C) 1999, 2000, 2001, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1999. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <gelf.h> +#include <string.h> + +#include "libelfP.h" + + +GElf_Verneed * +gelf_getverneed (data, offset, dst) + Elf_Data *data; + int offset; + GElf_Verneed *dst; +{ + GElf_Verneed *result; + + if (data == NULL) + return NULL; + + if (unlikely (data->d_type != ELF_T_VNEED)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + /* It's easy to handle this type. It has the same size for 32 and + 64 bit objects. And fortunately the `ElfXXX_Vernaux' records + also have the same size. */ + assert (sizeof (GElf_Verneed) == sizeof (Elf32_Verneed)); + assert (sizeof (GElf_Verneed) == sizeof (Elf64_Verneed)); + assert (sizeof (GElf_Verneed) == sizeof (Elf32_Vernaux)); + assert (sizeof (GElf_Verneed) == sizeof (Elf64_Vernaux)); + + rwlock_rdlock (((Elf_Data_Scn *) data)->s->elf->lock); + + /* The data is already in the correct form. Just make sure the + index is OK. */ + if (unlikely (offset < 0) + || unlikely (offset + sizeof (GElf_Verneed) > data->d_size) + || unlikely (offset % sizeof (GElf_Verneed) != 0)) + { + __libelf_seterrno (ELF_E_OFFSET_RANGE); + result = NULL; + } + else + result = (GElf_Verneed *) memcpy (dst, (char *) data->d_buf + offset, + sizeof (GElf_Verneed)); + + rwlock_unlock (((Elf_Data_Scn *) data)->s->elf->lock); + + return result; +} diff --git a/3rdparty/elfutils/libelf/gelf_getversym.c b/3rdparty/elfutils/libelf/gelf_getversym.c new file mode 100644 index 0000000..fe8dc62 --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_getversym.c @@ -0,0 +1,89 @@ +/* Get symbol version information at the given index. + Copyright (C) 1999, 2000, 2001, 2002, 2005, 2009, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1999. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <gelf.h> +#include <string.h> + +#include "libelfP.h" + + +GElf_Versym * +gelf_getversym (data, ndx, dst) + Elf_Data *data; + int ndx; + GElf_Versym *dst; +{ + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) data; + Elf_Scn *scn; + GElf_Versym *result; + + if (data == NULL) + return NULL; + + if (unlikely (data->d_type != ELF_T_HALF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + /* This is the one place where we have to take advantage of the fact + that an `Elf_Data' pointer is also a pointer to `Elf_Data_Scn'. + The interface is broken so that it requires this hack. */ + scn = data_scn->s; + + /* It's easy to handle this type. It has the same size for 32 and + 64 bit objects. */ + assert (sizeof (GElf_Versym) == sizeof (Elf32_Versym)); + assert (sizeof (GElf_Versym) == sizeof (Elf64_Versym)); + + rwlock_rdlock (scn->elf->lock); + + /* The data is already in the correct form. Just make sure the + index is OK. */ + if (INVALID_NDX (ndx, GElf_Versym, data)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + result = NULL; + } + else + { + *dst = ((GElf_Versym *) data->d_buf)[ndx]; + + result = dst; + } + + rwlock_unlock (scn->elf->lock); + + return result; +} diff --git a/3rdparty/elfutils/libelf/gelf_newehdr.c b/3rdparty/elfutils/libelf/gelf_newehdr.c new file mode 100644 index 0000000..e9f7a58 --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_newehdr.c @@ -0,0 +1,48 @@ +/* Create new ELF header. + Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gelf.h> +#include <stdlib.h> + +#include "libelfP.h" + + +unsigned long int +gelf_newehdr (elf, class) + Elf *elf; + int class; +{ + return (class == ELFCLASS32 + ? (unsigned long int) INTUSE(elf32_newehdr) (elf) + : (unsigned long int) INTUSE(elf64_newehdr) (elf)); +} diff --git a/3rdparty/elfutils/libelf/gelf_newphdr.c b/3rdparty/elfutils/libelf/gelf_newphdr.c new file mode 100644 index 0000000..b634037 --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_newphdr.c @@ -0,0 +1,48 @@ +/* Create new ELF program header. + Copyright (C) 1998, 1999, 2000, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gelf.h> +#include <stdlib.h> + +#include "libelfP.h" + + +unsigned long int +gelf_newphdr (elf, phnum) + Elf *elf; + size_t phnum; +{ + return (elf->class == ELFCLASS32 + ? (unsigned long int) INTUSE(elf32_newphdr) (elf, phnum) + : (unsigned long int) INTUSE(elf64_newphdr) (elf, phnum)); +} diff --git a/3rdparty/elfutils/libelf/gelf_offscn.c b/3rdparty/elfutils/libelf/gelf_offscn.c new file mode 100644 index 0000000..62d12e4 --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_offscn.c @@ -0,0 +1,57 @@ +/* Create new ELF header. + Copyright (C) 2005 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2005. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gelf.h> +#include <stdlib.h> + +#include "libelfP.h" + + +Elf_Scn * +gelf_offscn (elf, offset) + Elf *elf; + GElf_Off offset; +{ + if (elf->class == ELFCLASS32) + { + if ((Elf32_Off) offset != offset) + { + __libelf_seterrno (ELF_E_INVALID_OFFSET); + return NULL; + } + + return INTUSE(elf32_offscn) (elf, (Elf32_Off) offset); + } + + return INTUSE(elf64_offscn) (elf, offset); +} diff --git a/3rdparty/elfutils/libelf/gelf_update_auxv.c b/3rdparty/elfutils/libelf/gelf_update_auxv.c new file mode 100644 index 0000000..dd8f472 --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_update_auxv.c @@ -0,0 +1,114 @@ +/* Update information in dynamic table at the given index. + Copyright (C) 2007 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gelf.h> +#include <string.h> + +#include "libelfP.h" + + +int +gelf_update_auxv (data, ndx, src) + Elf_Data *data; + int ndx; + GElf_auxv_t *src; +{ + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) data; + Elf_Scn *scn; + int result = 0; + + if (data == NULL) + return 0; + + if (unlikely (ndx < 0)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + return 0; + } + + if (unlikely (data_scn->d.d_type != ELF_T_AUXV)) + { + /* The type of the data better should match. */ + __libelf_seterrno (ELF_E_DATA_MISMATCH); + return 0; + } + + scn = data_scn->s; + rwlock_wrlock (scn->elf->lock); + + if (scn->elf->class == ELFCLASS32) + { + Elf32_auxv_t *auxv; + + /* There is the possibility that the values in the input are + too large. */ + if (unlikely (src->a_type > 0xffffffffll) + || unlikely (src->a_un.a_val > 0xffffffffull)) + { + __libelf_seterrno (ELF_E_INVALID_DATA); + goto out; + } + + /* Check whether we have to resize the data buffer. */ + if (unlikely ((ndx + 1) * sizeof (Elf32_auxv_t) > data_scn->d.d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + auxv = &((Elf32_auxv_t *) data_scn->d.d_buf)[ndx]; + + auxv->a_type = src->a_type; + auxv->a_un.a_val = src->a_un.a_val; + } + else + { + /* Check whether we have to resize the data buffer. */ + if (unlikely ((ndx + 1) * sizeof (Elf64_auxv_t) > data_scn->d.d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + ((Elf64_auxv_t *) data_scn->d.d_buf)[ndx] = *src; + } + + result = 1; + + /* Mark the section as modified. */ + scn->flags |= ELF_F_DIRTY; + + out: + rwlock_unlock (scn->elf->lock); + + return result; +} diff --git a/3rdparty/elfutils/libelf/gelf_update_dyn.c b/3rdparty/elfutils/libelf/gelf_update_dyn.c new file mode 100644 index 0000000..2eb526e --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_update_dyn.c @@ -0,0 +1,110 @@ +/* Update information in dynamic table at the given index. + Copyright (C) 2000, 2001, 2002, 2005, 2009, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gelf.h> +#include <string.h> + +#include "libelfP.h" + + +int +gelf_update_dyn (data, ndx, src) + Elf_Data *data; + int ndx; + GElf_Dyn *src; +{ + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) data; + Elf_Scn *scn; + int result = 0; + + if (data == NULL) + return 0; + + if (unlikely (data_scn->d.d_type != ELF_T_DYN)) + { + /* The type of the data better should match. */ + __libelf_seterrno (ELF_E_DATA_MISMATCH); + return 0; + } + + scn = data_scn->s; + rwlock_wrlock (scn->elf->lock); + + if (scn->elf->class == ELFCLASS32) + { + Elf32_Dyn *dyn; + + /* There is the possibility that the values in the input are + too large. */ + if (unlikely (src->d_tag < -0x80000000ll) + || unlikely (src->d_tag > 0x7fffffffll) + || unlikely (src->d_un.d_val > 0xffffffffull)) + { + __libelf_seterrno (ELF_E_INVALID_DATA); + goto out; + } + + /* Check whether we have to resize the data buffer. */ + if (INVALID_NDX (ndx, Elf32_Dyn, &data_scn->d)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + dyn = &((Elf32_Dyn *) data_scn->d.d_buf)[ndx]; + + dyn->d_tag = src->d_tag; + dyn->d_un.d_val = src->d_un.d_val; + } + else + { + /* Check whether we have to resize the data buffer. */ + if (INVALID_NDX (ndx, Elf64_Dyn, &data_scn->d)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + ((Elf64_Dyn *) data_scn->d.d_buf)[ndx] = *src; + } + + result = 1; + + /* Mark the section as modified. */ + scn->flags |= ELF_F_DIRTY; + + out: + rwlock_unlock (scn->elf->lock); + + return result; +} diff --git a/3rdparty/elfutils/libelf/gelf_update_ehdr.c b/3rdparty/elfutils/libelf/gelf_update_ehdr.c new file mode 100644 index 0000000..73d5af7 --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_update_ehdr.c @@ -0,0 +1,118 @@ +/* Update ELF header. + Copyright (C) 2000, 2001, 2002, 2010 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gelf.h> +#include <string.h> + +#include "libelfP.h" + + +int +gelf_update_ehdr (Elf *elf, GElf_Ehdr *src) +{ + int result = 0; + + if (elf == NULL) + return 0; + + if (unlikely (elf->kind != ELF_K_ELF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return 0; + } + + rwlock_wrlock (elf->lock); + + if (elf->class == ELFCLASS32) + { + Elf32_Ehdr *ehdr = elf->state.elf32.ehdr; + + if (ehdr == NULL) + { + __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR); + goto out; + } + + /* We have to convert the data to the 32 bit format. This might + overflow some fields so we have to test for this case before + copying. */ + if (unlikely (src->e_entry > 0xffffffffull) + || unlikely (src->e_phoff > 0xffffffffull) + || unlikely (src->e_shoff > 0xffffffffull)) + { + __libelf_seterrno (ELF_E_INVALID_DATA); + goto out; + } + + /* Copy the data. */ + memcpy (ehdr->e_ident, src->e_ident, EI_NIDENT); +#define COPY(name) \ + ehdr->name = src->name + COPY (e_type); + COPY (e_machine); + COPY (e_version); + COPY (e_entry); + COPY (e_phoff); + COPY (e_shoff); + COPY (e_flags); + COPY (e_ehsize); + COPY (e_phentsize); + COPY (e_phnum); + COPY (e_shentsize); + COPY (e_shnum); + COPY (e_shstrndx); + } + else + { + Elf64_Ehdr *ehdr = elf->state.elf64.ehdr; + + if (ehdr == NULL) + { + __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR); + goto out; + } + + /* Just copy the data. */ + memcpy (ehdr, src, sizeof (Elf64_Ehdr)); + } + + /* Mark the ELF header as modified. */ + elf->state.elf.ehdr_flags |= ELF_F_DIRTY; + + result = 1; + + out: + rwlock_unlock (elf->lock); + + return result; +} diff --git a/3rdparty/elfutils/libelf/gelf_update_lib.c b/3rdparty/elfutils/libelf/gelf_update_lib.c new file mode 100644 index 0000000..1c8c23d --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_update_lib.c @@ -0,0 +1,78 @@ +/* Update library in table at the given index. + Copyright (C) 2004, 2005, 2009, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gelf.h> +#include <stdlib.h> +#include <string.h> + +#include "libelfP.h" + + +int +gelf_update_lib (data, ndx, src) + Elf_Data *data; + int ndx; + GElf_Lib *src; +{ + if (data == NULL) + return 0; + + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) data; + if (unlikely (data_scn->d.d_type != ELF_T_LIB)) + { + /* The type of the data better should match. */ + __libelf_seterrno (ELF_E_DATA_MISMATCH); + return 0; + } + + Elf_Scn *scn = data_scn->s; + rwlock_wrlock (scn->elf->lock); + + /* Check whether we have to resize the data buffer. */ + int result = 0; + if (INVALID_NDX (ndx, Elf64_Lib, &data_scn->d)) + __libelf_seterrno (ELF_E_INVALID_INDEX); + else + { + ((Elf64_Lib *) data_scn->d.d_buf)[ndx] = *src; + + result = 1; + + /* Mark the section as modified. */ + scn->flags |= ELF_F_DIRTY; + } + + rwlock_unlock (scn->elf->lock); + + return result; +} diff --git a/3rdparty/elfutils/libelf/gelf_update_move.c b/3rdparty/elfutils/libelf/gelf_update_move.c new file mode 100644 index 0000000..ad2ca6a --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_update_move.c @@ -0,0 +1,80 @@ +/* Update move structure at the given index. + Copyright (C) 2000, 2001, 2002, 2005, 2009, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <gelf.h> +#include <stdlib.h> + +#include "libelfP.h" + + +int +gelf_update_move (data, ndx, src) + Elf_Data *data; + int ndx; + GElf_Move *src; +{ + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) data; + + if (data == NULL) + return 0; + + /* The types for 32 and 64 bit are the same. Lucky us. */ + assert (sizeof (GElf_Move) == sizeof (Elf32_Move)); + assert (sizeof (GElf_Move) == sizeof (Elf64_Move)); + + /* Check whether we have to resize the data buffer. */ + if (INVALID_NDX (ndx, GElf_Move, &data_scn->d)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + return 0; + } + + if (unlikely (data_scn->d.d_type != ELF_T_MOVE)) + { + /* The type of the data better should match. */ + __libelf_seterrno (ELF_E_DATA_MISMATCH); + return 0; + } + + rwlock_wrlock (data_scn->s->elf->lock); + + ((GElf_Move *) data_scn->d.d_buf)[ndx] = *src; + + /* Mark the section as modified. */ + data_scn->s->flags |= ELF_F_DIRTY; + + rwlock_unlock (data_scn->s->elf->lock); + + return 1; +} diff --git a/3rdparty/elfutils/libelf/gelf_update_phdr.c b/3rdparty/elfutils/libelf/gelf_update_phdr.c new file mode 100644 index 0000000..a848677 --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_update_phdr.c @@ -0,0 +1,143 @@ +/* Update program header program header table entry. + Copyright (C) 2000-2010 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gelf.h> +#include <string.h> + +#include "libelfP.h" + + +int +gelf_update_phdr (Elf *elf, int ndx, GElf_Phdr *src) +{ + int result = 0; + + if (elf == NULL) + return 0; + + if (unlikely (elf->kind != ELF_K_ELF)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return 0; + } + + rwlock_wrlock (elf->lock); + + if (elf->class == ELFCLASS32) + { + Elf32_Phdr *phdr = elf->state.elf32.phdr; + + /* We have to convert the data to the 32 bit format. This might + overflow some fields so we have to test for this case before + copying. */ + if (unlikely (src->p_offset > 0xffffffffull) + || unlikely (src->p_vaddr > 0xffffffffull) + || unlikely (src->p_paddr > 0xffffffffull) + || unlikely (src->p_filesz > 0xffffffffull) + || unlikely (src->p_memsz > 0xffffffffull) + || unlikely (src->p_align > 0xffffffffull)) + { + __libelf_seterrno (ELF_E_INVALID_DATA); + goto out; + } + + if (phdr == NULL) + { + phdr = __elf32_getphdr_wrlock (elf); + if (phdr == NULL) + /* The error number is already set. */ + goto out; + } + + /* Test whether the index is ok. */ + size_t phnum; + if (ndx >= elf->state.elf32.ehdr->e_phnum + && (elf->state.elf32.ehdr->e_phnum != PN_XNUM + || __elf_getphdrnum_rdlock (elf, &phnum) != 0 + || (size_t) ndx >= phnum)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + /* Now correct the pointer to point to the correct element. */ + phdr += ndx; + +#define COPY(name) \ + phdr->name = src->name + COPY (p_type); + COPY (p_offset); + COPY (p_vaddr); + COPY (p_paddr); + COPY (p_filesz); + COPY (p_memsz); + COPY (p_flags); + COPY (p_align); + } + else + { + Elf64_Phdr *phdr = elf->state.elf64.phdr; + + if (phdr == NULL) + { + phdr = __elf64_getphdr_wrlock (elf); + if (phdr == NULL) + /* The error number is already set. */ + goto out; + } + + /* Test whether the index is ok. */ + size_t phnum; + if (ndx >= elf->state.elf64.ehdr->e_phnum + && (elf->state.elf64.ehdr->e_phnum != PN_XNUM + || __elf_getphdrnum_rdlock (elf, &phnum) != 0 + || (size_t) ndx >= phnum)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + /* Just copy the data. */ + memcpy (phdr + ndx, src, sizeof (Elf64_Phdr)); + } + + /* Mark the program header as modified. */ + elf->state.elf.phdr_flags |= ELF_F_DIRTY; + + result = 1; + + out: + rwlock_unlock (elf->lock); + + return result; +} diff --git a/3rdparty/elfutils/libelf/gelf_update_rel.c b/3rdparty/elfutils/libelf/gelf_update_rel.c new file mode 100644 index 0000000..14f62e9 --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_update_rel.c @@ -0,0 +1,108 @@ +/* Update REL relocation information at given index. + Copyright (C) 2000, 2001, 2002, 2005, 2009, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gelf.h> +#include <stdlib.h> + +#include "libelfP.h" + + +int +gelf_update_rel (Elf_Data *dst, int ndx, GElf_Rel *src) +{ + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) dst; + Elf_Scn *scn; + int result = 0; + + if (dst == NULL) + return 0; + + if (unlikely (data_scn->d.d_type != ELF_T_REL)) + { + /* The type of the data better should match. */ + __libelf_seterrno (ELF_E_DATA_MISMATCH); + return 0; + } + + scn = data_scn->s; + rwlock_wrlock (scn->elf->lock); + + if (scn->elf->class == ELFCLASS32) + { + Elf32_Rel *rel; + + /* There is the possibility that the values in the input are + too large. */ + if (unlikely (src->r_offset > 0xffffffffull) + || unlikely (GELF_R_SYM (src->r_info) > 0xffffff) + || unlikely (GELF_R_TYPE (src->r_info) > 0xff)) + { + __libelf_seterrno (ELF_E_INVALID_DATA); + goto out; + } + + /* Check whether we have to resize the data buffer. */ + if (INVALID_NDX (ndx, Elf32_Rel, &data_scn->d)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + rel = &((Elf32_Rel *) data_scn->d.d_buf)[ndx]; + + rel->r_offset = src->r_offset; + rel->r_info = ELF32_R_INFO (GELF_R_SYM (src->r_info), + GELF_R_TYPE (src->r_info)); + } + else + { + /* Check whether we have to resize the data buffer. */ + if (INVALID_NDX (ndx, Elf64_Rel, &data_scn->d)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + ((Elf64_Rel *) data_scn->d.d_buf)[ndx] = *src; + } + + result = 1; + + /* Mark the section as modified. */ + scn->flags |= ELF_F_DIRTY; + + out: + rwlock_unlock (scn->elf->lock); + + return result; +} diff --git a/3rdparty/elfutils/libelf/gelf_update_rela.c b/3rdparty/elfutils/libelf/gelf_update_rela.c new file mode 100644 index 0000000..8825270 --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_update_rela.c @@ -0,0 +1,111 @@ +/* Update RELA relocation information at given index. + Copyright (C) 2000, 2001, 2002, 2005, 2009, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gelf.h> +#include <stdlib.h> + +#include "libelfP.h" + + +int +gelf_update_rela (Elf_Data *dst, int ndx, GElf_Rela *src) +{ + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) dst; + Elf_Scn *scn; + int result = 0; + + if (dst == NULL) + return 0; + + if (unlikely (data_scn->d.d_type != ELF_T_RELA)) + { + /* The type of the data better should match. */ + __libelf_seterrno (ELF_E_DATA_MISMATCH); + return 0; + } + + scn = data_scn->s; + rwlock_wrlock (scn->elf->lock); + + if (scn->elf->class == ELFCLASS32) + { + Elf32_Rela *rel; + + /* There is the possibility that the values in the input are + too large. */ + if (unlikely (src->r_offset > 0xffffffffull) + || unlikely (GELF_R_SYM (src->r_info) > 0xffffff) + || unlikely (GELF_R_TYPE (src->r_info) > 0xff) + || unlikely (src->r_addend < -0x80000000ll) + || unlikely (src->r_addend > 0x7fffffffll)) + { + __libelf_seterrno (ELF_E_INVALID_DATA); + goto out; + } + + /* Check whether we have to resize the data buffer. */ + if (INVALID_NDX (ndx, Elf32_Rela, &data_scn->d)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + rel = &((Elf32_Rela *) data_scn->d.d_buf)[ndx]; + + rel->r_offset = src->r_offset; + rel->r_info = ELF32_R_INFO (GELF_R_SYM (src->r_info), + GELF_R_TYPE (src->r_info)); + rel->r_addend = src->r_addend; + } + else + { + /* Check whether we have to resize the data buffer. */ + if (INVALID_NDX (ndx, Elf64_Rela, &data_scn->d)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + ((Elf64_Rela *) data_scn->d.d_buf)[ndx] = *src; + } + + result = 1; + + /* Mark the section as modified. */ + scn->flags |= ELF_F_DIRTY; + + out: + rwlock_unlock (scn->elf->lock); + + return result; +} diff --git a/3rdparty/elfutils/libelf/gelf_update_shdr.c b/3rdparty/elfutils/libelf/gelf_update_shdr.c new file mode 100644 index 0000000..c93c6ec --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_update_shdr.c @@ -0,0 +1,111 @@ +/* Update section header. + Copyright (C) 2000, 2001, 2002, 2010 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gelf.h> +#include <string.h> + +#include "libelfP.h" + + +int +gelf_update_shdr (Elf_Scn *scn, GElf_Shdr *src) +{ + int result = 0; + Elf *elf; + + if (scn == NULL || src == NULL) + return 0; + + elf = scn->elf; + rwlock_wrlock (elf->lock); + + if (elf->class == ELFCLASS32) + { + Elf32_Shdr *shdr + = scn->shdr.e32 ?: __elf32_getshdr_wrlock (scn); + + if (shdr == NULL) + { + __libelf_seterrno (ELF_E_INVALID_OPERAND); + goto out; + } + + if (unlikely (src->sh_flags > 0xffffffffull) + || unlikely (src->sh_addr > 0xffffffffull) + || unlikely (src->sh_offset > 0xffffffffull) + || unlikely (src->sh_size > 0xffffffffull) + || unlikely (src->sh_addralign > 0xffffffffull) + || unlikely (src->sh_entsize > 0xffffffffull)) + { + __libelf_seterrno (ELF_E_INVALID_DATA); + goto out; + } + +#define COPY(name) \ + shdr->name = src->name + COPY (sh_name); + COPY (sh_type); + COPY (sh_flags); + COPY (sh_addr); + COPY (sh_offset); + COPY (sh_size); + COPY (sh_link); + COPY (sh_info); + COPY (sh_addralign); + COPY (sh_entsize); + } + else + { + Elf64_Shdr *shdr + = scn->shdr.e64 ?: __elf64_getshdr_wrlock (scn); + + if (shdr == NULL) + { + __libelf_seterrno (ELF_E_INVALID_OPERAND); + goto out; + } + + /* We only have to copy the data. */ + (void) memcpy (shdr, src, sizeof (GElf_Shdr)); + } + + /* Mark the section header as modified. */ + scn->shdr_flags |= ELF_F_DIRTY; + + result = 1; + + out: + rwlock_unlock (elf->lock); + + return result; +} diff --git a/3rdparty/elfutils/libelf/gelf_update_sym.c b/3rdparty/elfutils/libelf/gelf_update_sym.c new file mode 100644 index 0000000..278129c --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_update_sym.c @@ -0,0 +1,119 @@ +/* Update symbol information in symbol table at the given index. + Copyright (C) 2000, 2001, 2002, 2005, 2009, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gelf.h> +#include <stdlib.h> +#include <string.h> + +#include "libelfP.h" + + +int +gelf_update_sym (data, ndx, src) + Elf_Data *data; + int ndx; + GElf_Sym *src; +{ + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) data; + Elf_Scn *scn; + int result = 0; + + if (data == NULL) + return 0; + + if (unlikely (data_scn->d.d_type != ELF_T_SYM)) + { + /* The type of the data better should match. */ + __libelf_seterrno (ELF_E_DATA_MISMATCH); + return 0; + } + + scn = data_scn->s; + rwlock_wrlock (scn->elf->lock); + + if (scn->elf->class == ELFCLASS32) + { + Elf32_Sym *sym; + + /* There is the possibility that the values in the input are + too large. */ + if (unlikely (src->st_value > 0xffffffffull) + || unlikely (src->st_size > 0xffffffffull)) + { + __libelf_seterrno (ELF_E_INVALID_DATA); + goto out; + } + + /* Check whether we have to resize the data buffer. */ + if (INVALID_NDX (ndx, Elf32_Sym, &data_scn->d)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + sym = &((Elf32_Sym *) data_scn->d.d_buf)[ndx]; + +#define COPY(name) \ + sym->name = src->name + COPY (st_name); + COPY (st_value); + COPY (st_size); + /* Please note that we can simply copy the `st_info' element since + the definitions of ELFxx_ST_BIND and ELFxx_ST_TYPE are the same + for the 64 bit variant. */ + COPY (st_info); + COPY (st_other); + COPY (st_shndx); + } + else + { + /* Check whether we have to resize the data buffer. */ + if (INVALID_NDX (ndx, Elf64_Sym, &data_scn->d)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + ((Elf64_Sym *) data_scn->d.d_buf)[ndx] = *src; + } + + result = 1; + + /* Mark the section as modified. */ + scn->flags |= ELF_F_DIRTY; + + out: + rwlock_unlock (scn->elf->lock); + + return result; +} diff --git a/3rdparty/elfutils/libelf/gelf_update_syminfo.c b/3rdparty/elfutils/libelf/gelf_update_syminfo.c new file mode 100644 index 0000000..640a1ed --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_update_syminfo.c @@ -0,0 +1,86 @@ +/* Update additional symbol information in symbol table at the given index. + Copyright (C) 2000, 2001, 2002, 2005, 2009, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <gelf.h> +#include <stdlib.h> + +#include "libelfP.h" + + +int +gelf_update_syminfo (data, ndx, src) + Elf_Data *data; + int ndx; + GElf_Syminfo *src; +{ + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) data; + Elf_Scn *scn; + int result = 0; + + if (data == NULL) + return 0; + + if (unlikely (data_scn->d.d_type != ELF_T_SYMINFO)) + { + /* The type of the data better should match. */ + __libelf_seterrno (ELF_E_DATA_MISMATCH); + return 0; + } + + /* The types for 32 and 64 bit are the same. Lucky us. */ + assert (sizeof (GElf_Syminfo) == sizeof (Elf32_Syminfo)); + assert (sizeof (GElf_Syminfo) == sizeof (Elf64_Syminfo)); + + scn = data_scn->s; + rwlock_wrlock (scn->elf->lock); + + /* Check whether we have to resize the data buffer. */ + if (INVALID_NDX (ndx, GElf_Syminfo, &data_scn->d)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + ((GElf_Syminfo *) data_scn->d.d_buf)[ndx] = *src; + + result = 1; + + /* Mark the section as modified. */ + scn->flags |= ELF_F_DIRTY; + + out: + rwlock_unlock (scn->elf->lock); + + return result; +} diff --git a/3rdparty/elfutils/libelf/gelf_update_symshndx.c b/3rdparty/elfutils/libelf/gelf_update_symshndx.c new file mode 100644 index 0000000..5e2c7f7 --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_update_symshndx.c @@ -0,0 +1,149 @@ +/* Update symbol information and section index in symbol table at the + given index. + Copyright (C) 2000, 2001, 2002, 2005, 2009, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gelf.h> +#include <stdlib.h> +#include <string.h> + +#include "libelfP.h" + + +int +gelf_update_symshndx (symdata, shndxdata, ndx, src, srcshndx) + Elf_Data *symdata; + Elf_Data *shndxdata; + int ndx; + GElf_Sym *src; + Elf32_Word srcshndx; +{ + Elf_Data_Scn *symdata_scn = (Elf_Data_Scn *) symdata; + Elf_Data_Scn *shndxdata_scn = (Elf_Data_Scn *) shndxdata; + Elf_Scn *scn; + Elf32_Word *shndx = NULL; + int result = 0; + + if (symdata == NULL) + return 0; + + if (unlikely (symdata_scn->d.d_type != ELF_T_SYM)) + { + /* The type of the data better should match. */ + __libelf_seterrno (ELF_E_DATA_MISMATCH); + return 0; + } + + scn = symdata_scn->s; + /* We simply have to believe the user that the two sections belong to + the same ELF file. */ + rwlock_wrlock (scn->elf->lock); + + /* The user is not required to pass a data descriptor for an extended + section index table. */ + if (shndxdata_scn != NULL) + { + if (unlikely ((ndx + 1) * sizeof (Elf32_Word) > shndxdata_scn->d.d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + shndx = &((Elf32_Word *) shndxdata_scn->d.d_buf)[ndx]; + } + /* But if s/he does not the extended sectio index must be zero. */ + else if (unlikely (srcshndx != 0)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + if (scn->elf->class == ELFCLASS32) + { + Elf32_Sym *sym; + + /* There is the possibility that the values in the input are + too large. */ + if (unlikely (src->st_value > 0xffffffffull) + || unlikely (src->st_size > 0xffffffffull)) + { + __libelf_seterrno (ELF_E_INVALID_DATA); + goto out; + } + + /* Check whether we have to resize the data buffer. */ + if (INVALID_NDX (ndx, Elf32_Sym, &symdata_scn->d)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + sym = &((Elf32_Sym *) symdata_scn->d.d_buf)[ndx]; + +#define COPY(name) \ + sym->name = src->name + COPY (st_name); + COPY (st_value); + COPY (st_size); + /* Please note that we can simply copy the `st_info' element since + the definitions of ELFxx_ST_BIND and ELFxx_ST_TYPE are the same + for the 64 bit variant. */ + COPY (st_info); + COPY (st_other); + COPY (st_shndx); + } + else + { + /* Check whether we have to resize the data buffer. */ + if (INVALID_NDX (ndx, Elf64_Sym, &symdata_scn->d)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + ((Elf64_Sym *) symdata_scn->d.d_buf)[ndx] = *src; + } + + /* Now we can store the section index. */ + if (shndx != NULL) + *shndx = srcshndx; + + result = 1; + + /* Mark the section as modified. */ + scn->flags |= ELF_F_DIRTY; + + out: + rwlock_unlock (scn->elf->lock); + + return result; +} diff --git a/3rdparty/elfutils/libelf/gelf_update_verdaux.c b/3rdparty/elfutils/libelf/gelf_update_verdaux.c new file mode 100644 index 0000000..b377d40 --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_update_verdaux.c @@ -0,0 +1,81 @@ +/* Update additional symbol version definition information. + Copyright (C) 2001, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2001. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <gelf.h> +#include <string.h> + +#include "libelfP.h" + + +int +gelf_update_verdaux (data, offset, src) + Elf_Data *data; + int offset; + GElf_Verdaux *src; +{ + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) data; + + if (data == NULL) + return 0; + + /* The types for 32 and 64 bit are the same. Lucky us. */ + assert (sizeof (GElf_Verdaux) == sizeof (Elf32_Verdaux)); + assert (sizeof (GElf_Verdaux) == sizeof (Elf64_Verdaux)); + + /* Check whether we have to resize the data buffer. */ + if (unlikely (offset < 0) + || unlikely ((offset + sizeof (GElf_Verdaux)) > data_scn->d.d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + return 0; + } + + if (unlikely (data_scn->d.d_type != ELF_T_VDEF)) + { + /* The type of the data better should match. */ + __libelf_seterrno (ELF_E_DATA_MISMATCH); + return 0; + } + + rwlock_wrlock (data_scn->s->elf->lock); + + memcpy ((char *) data_scn->d.d_buf + offset, src, sizeof (GElf_Verdaux)); + + /* Mark the section as modified. */ + data_scn->s->flags |= ELF_F_DIRTY; + + rwlock_unlock (data_scn->s->elf->lock); + + return 1; +} diff --git a/3rdparty/elfutils/libelf/gelf_update_verdef.c b/3rdparty/elfutils/libelf/gelf_update_verdef.c new file mode 100644 index 0000000..d591a4f --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_update_verdef.c @@ -0,0 +1,81 @@ +/* Update symbol version definition information. + Copyright (C) 2001, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2001. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <gelf.h> +#include <string.h> + +#include "libelfP.h" + + +int +gelf_update_verdef (data, offset, src) + Elf_Data *data; + int offset; + GElf_Verdef *src; +{ + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) data; + + if (data == NULL) + return 0; + + /* The types for 32 and 64 bit are the same. Lucky us. */ + assert (sizeof (GElf_Verdef) == sizeof (Elf32_Verdef)); + assert (sizeof (GElf_Verdef) == sizeof (Elf64_Verdef)); + + /* Check whether we have to resize the data buffer. */ + if (unlikely (offset < 0) + || unlikely ((offset + sizeof (GElf_Verdef)) > data_scn->d.d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + return 0; + } + + if (unlikely (data_scn->d.d_type != ELF_T_VDEF)) + { + /* The type of the data better should match. */ + __libelf_seterrno (ELF_E_DATA_MISMATCH); + return 0; + } + + rwlock_wrlock (data_scn->s->elf->lock); + + memcpy ((char *) data_scn->d.d_buf + offset, src, sizeof (GElf_Verdef)); + + /* Mark the section as modified. */ + data_scn->s->flags |= ELF_F_DIRTY; + + rwlock_unlock (data_scn->s->elf->lock); + + return 1; +} diff --git a/3rdparty/elfutils/libelf/gelf_update_vernaux.c b/3rdparty/elfutils/libelf/gelf_update_vernaux.c new file mode 100644 index 0000000..1f691b0 --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_update_vernaux.c @@ -0,0 +1,81 @@ +/* Update additional required symbol version information. + Copyright (C) 2001, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2001. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <gelf.h> +#include <string.h> + +#include "libelfP.h" + + +int +gelf_update_vernaux (data, offset, src) + Elf_Data *data; + int offset; + GElf_Vernaux *src; +{ + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) data; + + if (data == NULL) + return 0; + + /* The types for 32 and 64 bit are the same. Lucky us. */ + assert (sizeof (GElf_Vernaux) == sizeof (Elf32_Vernaux)); + assert (sizeof (GElf_Vernaux) == sizeof (Elf64_Vernaux)); + + /* Check whether we have to resize the data buffer. */ + if (unlikely (offset < 0) + || unlikely ((offset + sizeof (GElf_Vernaux)) > data_scn->d.d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + return 0; + } + + if (unlikely (data_scn->d.d_type != ELF_T_VNEED)) + { + /* The type of the data better should match. */ + __libelf_seterrno (ELF_E_DATA_MISMATCH); + return 0; + } + + rwlock_wrlock (data_scn->s->elf->lock); + + memcpy ((char *) data_scn->d.d_buf + offset, src, sizeof (GElf_Vernaux)); + + /* Mark the section as modified. */ + data_scn->s->flags |= ELF_F_DIRTY; + + rwlock_unlock (data_scn->s->elf->lock); + + return 1; +} diff --git a/3rdparty/elfutils/libelf/gelf_update_verneed.c b/3rdparty/elfutils/libelf/gelf_update_verneed.c new file mode 100644 index 0000000..713c017 --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_update_verneed.c @@ -0,0 +1,81 @@ +/* Update required symbol version information. + Copyright (C) 2001, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2001. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <gelf.h> +#include <string.h> + +#include "libelfP.h" + + +int +gelf_update_verneed (data, offset, src) + Elf_Data *data; + int offset; + GElf_Verneed *src; +{ + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) data; + + if (data == NULL) + return 0; + + /* The types for 32 and 64 bit are the same. Lucky us. */ + assert (sizeof (GElf_Verneed) == sizeof (Elf32_Verneed)); + assert (sizeof (GElf_Verneed) == sizeof (Elf64_Verneed)); + + /* Check whether we have to resize the data buffer. */ + if (unlikely (offset < 0) + || unlikely ((offset + sizeof (GElf_Verneed)) > data_scn->d.d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + return 0; + } + + if (unlikely (data_scn->d.d_type != ELF_T_VNEED)) + { + /* The type of the data better should match. */ + __libelf_seterrno (ELF_E_DATA_MISMATCH); + return 0; + } + + rwlock_wrlock (data_scn->s->elf->lock); + + memcpy ((char *) data_scn->d.d_buf + offset, src, sizeof (GElf_Verneed)); + + /* Mark the section as modified. */ + data_scn->s->flags |= ELF_F_DIRTY; + + rwlock_unlock (data_scn->s->elf->lock); + + return 1; +} diff --git a/3rdparty/elfutils/libelf/gelf_update_versym.c b/3rdparty/elfutils/libelf/gelf_update_versym.c new file mode 100644 index 0000000..03a3c5a --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_update_versym.c @@ -0,0 +1,80 @@ +/* Update symbol version information. + Copyright (C) 2001, 2002, 2005, 2009, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2001. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <gelf.h> +#include <stdlib.h> + +#include "libelfP.h" + + +int +gelf_update_versym (data, ndx, src) + Elf_Data *data; + int ndx; + GElf_Versym *src; +{ + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) data; + + if (data == NULL) + return 0; + + /* The types for 32 and 64 bit are the same. Lucky us. */ + assert (sizeof (GElf_Versym) == sizeof (Elf32_Versym)); + assert (sizeof (GElf_Versym) == sizeof (Elf64_Versym)); + + /* Check whether we have to resize the data buffer. */ + if (INVALID_NDX (ndx, GElf_Versym, &data_scn->d)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + return 0; + } + + if (unlikely (data_scn->d.d_type != ELF_T_HALF)) + { + /* The type of the data better should match. */ + __libelf_seterrno (ELF_E_DATA_MISMATCH); + return 0; + } + + rwlock_wrlock (data_scn->s->elf->lock); + + ((GElf_Versym *) data_scn->d.d_buf)[ndx] = *src; + + /* Mark the section as modified. */ + data_scn->s->flags |= ELF_F_DIRTY; + + rwlock_unlock (data_scn->s->elf->lock); + + return 1; +} diff --git a/3rdparty/elfutils/libelf/gelf_xlate.c b/3rdparty/elfutils/libelf/gelf_xlate.c new file mode 100644 index 0000000..c417051 --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_xlate.c @@ -0,0 +1,214 @@ +/* Transformation functions for ELF data types. + Copyright (C) 1998,1999,2000,2002,2004,2005,2006,2007 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <byteswap.h> +#include <stdint.h> +#include <string.h> +#include <stdlib.h> + +#include "libelfP.h" + +#ifndef LIBELFBITS +# define LIBELFBITS 32 +#endif + + +/* Well, what shall I say. Nothing to do here. */ +#define elf_cvt_Byte(dest, src, n) \ + (__builtin_constant_p (n) && (n) == 1 \ + ? (void) (*((char *) (dest)) = *((char *) (src))) \ + : Elf32_cvt_Byte (dest, src, n)) +static void +(elf_cvt_Byte) (void *dest, const void *src, size_t n, + int encode __attribute__ ((unused))) +{ + memmove (dest, src, n); +} + + +/* We'll optimize the definition of the conversion functions here a + bit. We need only functions for 16, 32, and 64 bits. The + functions referenced in the table will be aliases for one of these + functions. Which one is decided by the ELFxx_FSZ_type. */ + +#if ALLOW_UNALIGNED + +#define FETCH(Bits, ptr) (*(const uint##Bits##_t *) ptr) +#define STORE(Bits, ptr, val) (*(uint##Bits##_t *) ptr = val) + +#else + +union unaligned + { + uint16_t u16; + uint32_t u32; + uint64_t u64; + } __attribute__ ((packed)); + +#define FETCH(Bits, ptr) (((const union unaligned *) ptr)->u##Bits) +#define STORE(Bits, ptr, val) (((union unaligned *) ptr)->u##Bits = val) + +#endif + +/* Now define the conversion functions for the basic types. We use here + the fact that file and memory types are the same and that we have the + ELFxx_FSZ_* macros. + + At the same time we define inline functions which we will use to + convert the complex types. */ +#define FUNDAMENTAL(NAME, Name, Bits) \ + INLINE2 (ELFW2(Bits,FSZ_##NAME), ElfW2(Bits,cvt_##Name), ElfW2(Bits,Name)) +#define INLINE2(Bytes, FName, TName) \ + INLINE3 (Bytes, FName, TName) +#define INLINE3(Bytes, FName, TName) \ + static inline void FName##1 (void *dest, const void *ptr) \ + { \ + switch (Bytes) \ + { \ + case 2: STORE (16, dest, bswap_16 (FETCH (16, ptr))); break; \ + case 4: STORE (32, dest, bswap_32 (FETCH (32, ptr))); break; \ + case 8: STORE (64, dest, bswap_64 (FETCH (64, ptr))); break; \ + default: \ + abort (); \ + } \ + } \ + \ + static void FName (void *dest, const void *ptr, size_t len, \ + int encode __attribute__ ((unused))) \ + { \ + size_t n = len / sizeof (TName); \ + if (dest < ptr) \ + while (n-- > 0) \ + { \ + FName##1 (dest, ptr); \ + dest += Bytes; \ + ptr += Bytes; \ + } \ + else \ + { \ + dest += len; \ + ptr += len; \ + while (n-- > 0) \ + { \ + ptr -= Bytes; \ + dest -= Bytes; \ + FName##1 (dest, ptr); \ + } \ + } \ + } + + +/* Now the tricky part: define the transformation functions for the + complex types. We will use the definitions of the types in + abstract.h. */ +#define START(Bits, Name, EName) \ + static void \ + ElfW2 (Bits, cvt_##Name) (void *dest, const void *src, size_t len, \ + int encode __attribute__ ((unused))) \ + { ElfW2(Bits, Name) *tdest = (ElfW2(Bits, Name) *) dest; \ + ElfW2(Bits, Name) *tsrc = (ElfW2(Bits, Name) *) src; \ + size_t n; \ + for (n = len / sizeof (ElfW2(Bits, Name)); n > 0; ++tdest, ++tsrc, --n) { +#define END(Bits, Name) } } +#define TYPE_EXTRA(Code) +#define TYPE_XLATE(Code) Code +#define TYPE_NAME(Type, Name) TYPE_NAME2 (Type, Name) +#define TYPE_NAME2(Type, Name) Type##1 (&tdest->Name, &tsrc->Name); +#define TYPE(Name, Bits) TYPE2 (Name, Bits) +#define TYPE2(Name, Bits) TYPE3 (Name##Bits) +#define TYPE3(Name) Name (cvt_) + +/* Signal that we are generating conversion functions. */ +#define GENERATE_CONVERSION + +/* First generate the 32-bit conversion functions. */ +#define LIBELFBITS 32 +#include "gelf_xlate.h" + +/* Now generate the 64-bit conversion functions. */ +#define LIBELFBITS 64 +#include "gelf_xlate.h" + + +/* We have a few functions which we must create by hand since the sections + do not contain records of only one type. */ +#include "version_xlate.h" +#include "gnuhash_xlate.h" +#include "note_xlate.h" + + +/* Now the externally visible table with the function pointers. */ +const xfct_t __elf_xfctstom[EV_NUM - 1][EV_NUM - 1][ELFCLASSNUM - 1][ELF_T_NUM] = +{ + [EV_CURRENT - 1] = { + [EV_CURRENT - 1] = { + [ELFCLASS32 - 1] = { +#define define_xfcts(Bits) \ + [ELF_T_BYTE] = elf_cvt_Byte, \ + [ELF_T_ADDR] = ElfW2(Bits, cvt_Addr), \ + [ELF_T_DYN] = ElfW2(Bits, cvt_Dyn), \ + [ELF_T_EHDR] = ElfW2(Bits, cvt_Ehdr), \ + [ELF_T_HALF] = ElfW2(Bits, cvt_Half), \ + [ELF_T_OFF] = ElfW2(Bits, cvt_Off), \ + [ELF_T_PHDR] = ElfW2(Bits, cvt_Phdr), \ + [ELF_T_RELA] = ElfW2(Bits, cvt_Rela), \ + [ELF_T_REL] = ElfW2(Bits, cvt_Rel), \ + [ELF_T_SHDR] = ElfW2(Bits, cvt_Shdr), \ + [ELF_T_SWORD] = ElfW2(Bits, cvt_Sword), \ + [ELF_T_SYM] = ElfW2(Bits, cvt_Sym), \ + [ELF_T_WORD] = ElfW2(Bits, cvt_Word), \ + [ELF_T_XWORD] = ElfW2(Bits, cvt_Xword), \ + [ELF_T_SXWORD] = ElfW2(Bits, cvt_Sxword), \ + [ELF_T_VDEF] = elf_cvt_Verdef, \ + [ELF_T_VDAUX] = elf_cvt_Verdef, \ + [ELF_T_VNEED] = elf_cvt_Verneed, \ + [ELF_T_VNAUX] = elf_cvt_Verneed, \ + [ELF_T_NHDR] = elf_cvt_note, \ + [ELF_T_SYMINFO] = ElfW2(Bits, cvt_Syminfo), \ + [ELF_T_MOVE] = ElfW2(Bits, cvt_Move), \ + [ELF_T_LIB] = ElfW2(Bits, cvt_Lib), \ + [ELF_T_AUXV] = ElfW2(Bits, cvt_auxv_t) + define_xfcts (32), + [ELF_T_GNUHASH] = Elf32_cvt_Word + }, + [ELFCLASS64 - 1] = { + define_xfcts (64), + [ELF_T_GNUHASH] = elf_cvt_gnuhash + } + } + } +}; +/* For now we only handle the case where the memory representation is the + same as the file representation. Should this change we have to define + separate functions. For now reuse them. */ +strong_alias (__elf_xfctstom, __elf_xfctstof) diff --git a/3rdparty/elfutils/libelf/gelf_xlate.h b/3rdparty/elfutils/libelf/gelf_xlate.h new file mode 100644 index 0000000..f11eb90 --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_xlate.h @@ -0,0 +1,56 @@ +/* Helper file for type conversion function generation. + Copyright (C) 1998, 1999, 2000, 2002, 2004, 2007 Red Hat, Inc. + This file is part of elfutils. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + + +/* Simple types. */ +FUNDAMENTAL (ADDR, Addr, LIBELFBITS); +FUNDAMENTAL (OFF, Off, LIBELFBITS); +FUNDAMENTAL (HALF, Half, LIBELFBITS); +FUNDAMENTAL (WORD, Word, LIBELFBITS); +FUNDAMENTAL (SWORD, Sword, LIBELFBITS); +FUNDAMENTAL (XWORD, Xword, LIBELFBITS); +FUNDAMENTAL (SXWORD, Sxword, LIBELFBITS); + +/* The structured types. */ +TYPE (Ehdr, LIBELFBITS) +TYPE (Phdr, LIBELFBITS) +TYPE (Shdr, LIBELFBITS) +TYPE (Sym, LIBELFBITS) +TYPE (Rel, LIBELFBITS) +TYPE (Rela, LIBELFBITS) +TYPE (Note, LIBELFBITS) +TYPE (Dyn, LIBELFBITS) +TYPE (Syminfo, LIBELFBITS) +TYPE (Move, LIBELFBITS) +TYPE (Lib, LIBELFBITS) +TYPE (auxv_t, LIBELFBITS) + + +/* Prepare for the next round. */ +#undef LIBELFBITS diff --git a/3rdparty/elfutils/libelf/gelf_xlatetof.c b/3rdparty/elfutils/libelf/gelf_xlatetof.c new file mode 100644 index 0000000..3366bdc --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_xlatetof.c @@ -0,0 +1,53 @@ +/* Convert from memory to file representation. Generic ELF version. + Copyright (C) 2000, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gelf.h> +#include <stddef.h> + +#include "libelfP.h" + + +Elf_Data * +gelf_xlatetof (elf, dest, src, encode) + Elf *elf; + Elf_Data *dest; + const Elf_Data * src; + unsigned int encode; +{ + if (elf == NULL) + return NULL; + + return (elf->class == ELFCLASS32 + ? INTUSE(elf32_xlatetof) (dest, src, encode) + : INTUSE(elf64_xlatetof) (dest, src, encode)); +} diff --git a/3rdparty/elfutils/libelf/gelf_xlatetom.c b/3rdparty/elfutils/libelf/gelf_xlatetom.c new file mode 100644 index 0000000..c3e812f --- /dev/null +++ b/3rdparty/elfutils/libelf/gelf_xlatetom.c @@ -0,0 +1,53 @@ +/* Convert from file to memory representation. Generic ELF version. + Copyright (C) 2000, 2002 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gelf.h> +#include <stddef.h> + +#include "libelfP.h" + + +Elf_Data * +gelf_xlatetom (elf, dest, src, encode) + Elf *elf; + Elf_Data *dest; + const Elf_Data * src; + unsigned int encode; +{ + if (elf == NULL) + return NULL; + + return (elf->class == ELFCLASS32 + ? INTUSE(elf32_xlatetom) (dest, src, encode) + : INTUSE(elf64_xlatetom) (dest, src, encode)); +} diff --git a/3rdparty/elfutils/libelf/gnuhash_xlate.h b/3rdparty/elfutils/libelf/gnuhash_xlate.h new file mode 100644 index 0000000..6faf113 --- /dev/null +++ b/3rdparty/elfutils/libelf/gnuhash_xlate.h @@ -0,0 +1,74 @@ +/* Conversion functions for versioning information. + Copyright (C) 2006, 2007 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2006. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include <assert.h> +#include <gelf.h> + +#include "libelfP.h" + + +static void +elf_cvt_gnuhash (void *dest, const void *src, size_t len, int encode) +{ + /* The GNU hash table format on 64 bit machines mixes 32 bit and 64 bit + words. We must detangle them here. */ + Elf32_Word *dest32 = dest; + const Elf32_Word *src32 = src; + + /* First four control words, 32 bits. */ + for (unsigned int cnt = 0; cnt < 4; ++cnt) + { + if (len < 4) + return; + dest32[cnt] = bswap_32 (src32[cnt]); + len -= 4; + } + + Elf32_Word bitmask_words = encode ? src32[2] : dest32[2]; + + /* Now the 64 bit words. */ + Elf64_Xword *dest64 = (Elf64_Xword *) &dest32[4]; + const Elf64_Xword *src64 = (const Elf64_Xword *) &src32[4]; + for (unsigned int cnt = 0; cnt < bitmask_words; ++cnt) + { + if (len < 8) + return; + dest64[cnt] = bswap_64 (src64[cnt]); + len -= 8; + } + + /* The rest are 32 bit words again. */ + src32 = (const Elf32_Word *) &src64[bitmask_words]; + dest32 = (Elf32_Word *) &dest64[bitmask_words]; + while (len >= 4) + { + *dest32++ = bswap_32 (*src32++); + len -= 4; + } +} diff --git a/3rdparty/elfutils/libelf/libelf.h b/3rdparty/elfutils/libelf/libelf.h new file mode 100644 index 0000000..5a2b3af --- /dev/null +++ b/3rdparty/elfutils/libelf/libelf.h @@ -0,0 +1,396 @@ +/* Interface for libelf. + Copyright (C) 1998-2010 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifndef _LIBELF_H +#define _LIBELF_H 1 + +#include <sys/types.h> + +/* Get the ELF types. */ +#include <elf.h> + + +/* Known translation types. */ +typedef enum +{ + ELF_T_BYTE, /* unsigned char */ + ELF_T_ADDR, /* Elf32_Addr, Elf64_Addr, ... */ + ELF_T_DYN, /* Dynamic section record. */ + ELF_T_EHDR, /* ELF header. */ + ELF_T_HALF, /* Elf32_Half, Elf64_Half, ... */ + ELF_T_OFF, /* Elf32_Off, Elf64_Off, ... */ + ELF_T_PHDR, /* Program header. */ + ELF_T_RELA, /* Relocation entry with addend. */ + ELF_T_REL, /* Relocation entry. */ + ELF_T_SHDR, /* Section header. */ + ELF_T_SWORD, /* Elf32_Sword, Elf64_Sword, ... */ + ELF_T_SYM, /* Symbol record. */ + ELF_T_WORD, /* Elf32_Word, Elf64_Word, ... */ + ELF_T_XWORD, /* Elf32_Xword, Elf64_Xword, ... */ + ELF_T_SXWORD, /* Elf32_Sxword, Elf64_Sxword, ... */ + ELF_T_VDEF, /* Elf32_Verdef, Elf64_Verdef, ... */ + ELF_T_VDAUX, /* Elf32_Verdaux, Elf64_Verdaux, ... */ + ELF_T_VNEED, /* Elf32_Verneed, Elf64_Verneed, ... */ + ELF_T_VNAUX, /* Elf32_Vernaux, Elf64_Vernaux, ... */ + ELF_T_NHDR, /* Elf32_Nhdr, Elf64_Nhdr, ... */ + ELF_T_SYMINFO, /* Elf32_Syminfo, Elf64_Syminfo, ... */ + ELF_T_MOVE, /* Elf32_Move, Elf64_Move, ... */ + ELF_T_LIB, /* Elf32_Lib, Elf64_Lib, ... */ + ELF_T_GNUHASH, /* GNU-style hash section. */ + ELF_T_AUXV, /* Elf32_auxv_t, Elf64_auxv_t, ... */ + /* Keep this the last entry. */ + ELF_T_NUM +} Elf_Type; + +/* Descriptor for data to be converted to or from memory format. */ +typedef struct +{ + void *d_buf; /* Pointer to the actual data. */ + Elf_Type d_type; /* Type of this piece of data. */ + unsigned int d_version; /* ELF version. */ + size_t d_size; /* Size in bytes. */ + loff_t d_off; /* Offset into section. */ + size_t d_align; /* Alignment in section. */ +} Elf_Data; + + +/* Commands for `...'. */ +typedef enum +{ + ELF_C_NULL, /* Nothing, terminate, or compute only. */ + ELF_C_READ, /* Read .. */ + ELF_C_RDWR, /* Read and write .. */ + ELF_C_WRITE, /* Write .. */ + ELF_C_CLR, /* Clear flag. */ + ELF_C_SET, /* Set flag. */ + ELF_C_FDDONE, /* Signal that file descriptor will not be + used anymore. */ + ELF_C_FDREAD, /* Read rest of data so that file descriptor + is not used anymore. */ + /* The following are extensions. */ + ELF_C_READ_MMAP, /* Read, but mmap the file if possible. */ + ELF_C_RDWR_MMAP, /* Read and write, with mmap. */ + ELF_C_WRITE_MMAP, /* Write, with mmap. */ + ELF_C_READ_MMAP_PRIVATE, /* Read, but memory is writable, results are + not written to the file. */ + ELF_C_EMPTY, /* Copy basic file data but not the content. */ + /* Keep this the last entry. */ + ELF_C_NUM +} Elf_Cmd; + + +/* Flags for the ELF structures. */ +enum +{ + ELF_F_DIRTY = 0x1, +#define ELF_F_DIRTY ELF_F_DIRTY + ELF_F_LAYOUT = 0x4, +#define ELF_F_LAYOUT ELF_F_LAYOUT + ELF_F_PERMISSIVE = 0x8 +#define ELF_F_PERMISSIVE ELF_F_PERMISSIVE +}; + + +/* Identification values for recognized object files. */ +typedef enum +{ + ELF_K_NONE, /* Unknown. */ + ELF_K_AR, /* Archive. */ + ELF_K_COFF, /* Stupid old COFF. */ + ELF_K_ELF, /* ELF file. */ + /* Keep this the last entry. */ + ELF_K_NUM +} Elf_Kind; + + +/* Archive member header. */ +typedef struct +{ + char *ar_name; /* Name of archive member. */ + time_t ar_date; /* File date. */ + uid_t ar_uid; /* User ID. */ + gid_t ar_gid; /* Group ID. */ + mode_t ar_mode; /* File mode. */ + loff_t ar_size; /* File size. */ + char *ar_rawname; /* Original name of archive member. */ +} Elf_Arhdr; + + +/* Archive symbol table entry. */ +typedef struct +{ + char *as_name; /* Symbol name. */ + size_t as_off; /* Offset for this file in the archive. */ + unsigned long int as_hash; /* Hash value of the name. */ +} Elf_Arsym; + + +/* Descriptor for the ELF file. */ +typedef struct Elf Elf; + +/* Descriptor for ELF file section. */ +typedef struct Elf_Scn Elf_Scn; + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Return descriptor for ELF file to work according to CMD. */ +extern Elf *elf_begin (int __fildes, Elf_Cmd __cmd, Elf *__ref); + +/* Create a clone of an existing ELF descriptor. */ + extern Elf *elf_clone (Elf *__elf, Elf_Cmd __cmd); + +/* Create descriptor for memory region. */ +extern Elf *elf_memory (char *__image, size_t __size); + +/* Advance archive descriptor to next element. */ +extern Elf_Cmd elf_next (Elf *__elf); + +/* Free resources allocated for ELF. */ +extern int elf_end (Elf *__elf); + +/* Update ELF descriptor and write file to disk. */ +extern loff_t elf_update (Elf *__elf, Elf_Cmd __cmd); + +/* Determine what kind of file is associated with ELF. */ +extern Elf_Kind elf_kind (Elf *__elf) __attribute__ ((__pure__)); + +/* Get the base offset for an object file. */ +extern loff_t elf_getbase (Elf *__elf); + + +/* Retrieve file identification data. */ +extern char *elf_getident (Elf *__elf, size_t *__nbytes); + +/* Retrieve class-dependent object file header. */ +extern Elf32_Ehdr *elf32_getehdr (Elf *__elf); +/* Similar but this time the binary calls is ELFCLASS64. */ +extern Elf64_Ehdr *elf64_getehdr (Elf *__elf); + +/* Create ELF header if none exists. */ +extern Elf32_Ehdr *elf32_newehdr (Elf *__elf); +/* Similar but this time the binary calls is ELFCLASS64. */ +extern Elf64_Ehdr *elf64_newehdr (Elf *__elf); + +/* Get the number of program headers in the ELF file. If the file uses + more headers than can be represented in the e_phnum field of the ELF + header the information from the sh_info field in the zeroth section + header is used. */ +extern int elf_getphdrnum (Elf *__elf, size_t *__dst); + +/* Retrieve class-dependent program header table. */ +extern Elf32_Phdr *elf32_getphdr (Elf *__elf); +/* Similar but this time the binary calls is ELFCLASS64. */ +extern Elf64_Phdr *elf64_getphdr (Elf *__elf); + +/* Create ELF program header. */ +extern Elf32_Phdr *elf32_newphdr (Elf *__elf, size_t __cnt); +/* Similar but this time the binary calls is ELFCLASS64. */ +extern Elf64_Phdr *elf64_newphdr (Elf *__elf, size_t __cnt); + + +/* Get section at INDEX. */ +extern Elf_Scn *elf_getscn (Elf *__elf, size_t __index); + +/* Get section at OFFSET. */ +extern Elf_Scn *elf32_offscn (Elf *__elf, Elf32_Off __offset); +/* Similar bug this time the binary calls is ELFCLASS64. */ +extern Elf_Scn *elf64_offscn (Elf *__elf, Elf64_Off __offset); + +/* Get index of section. */ +extern size_t elf_ndxscn (Elf_Scn *__scn); + +/* Get section with next section index. */ +extern Elf_Scn *elf_nextscn (Elf *__elf, Elf_Scn *__scn); + +/* Create a new section and append it at the end of the table. */ +extern Elf_Scn *elf_newscn (Elf *__elf); + +/* Get the section index of the extended section index table for the + given symbol table. */ +extern int elf_scnshndx (Elf_Scn *__scn); + +/* Get the number of sections in the ELF file. If the file uses more + sections than can be represented in the e_shnum field of the ELF + header the information from the sh_size field in the zeroth section + header is used. */ +extern int elf_getshdrnum (Elf *__elf, size_t *__dst); +/* Sun messed up the implementation of 'elf_getshnum' in their implementation. + It was agreed to make the same functionality available under a different + name and obsolete the old name. */ +extern int elf_getshnum (Elf *__elf, size_t *__dst) + __attribute__ ((__deprecated__)); + + +/* Get the section index of the section header string table in the ELF + file. If the index cannot be represented in the e_shnum field of + the ELF header the information from the sh_link field in the zeroth + section header is used. */ +extern int elf_getshdrstrndx (Elf *__elf, size_t *__dst); +/* Sun messed up the implementation of 'elf_getshnum' in their implementation. + It was agreed to make the same functionality available under a different + name and obsolete the old name. */ +extern int elf_getshstrndx (Elf *__elf, size_t *__dst) + __attribute__ ((__deprecated__)); + + +/* Retrieve section header of ELFCLASS32 binary. */ +extern Elf32_Shdr *elf32_getshdr (Elf_Scn *__scn); +/* Similar for ELFCLASS64. */ +extern Elf64_Shdr *elf64_getshdr (Elf_Scn *__scn); + + +/* Set or clear flags for ELF file. */ +extern unsigned int elf_flagelf (Elf *__elf, Elf_Cmd __cmd, + unsigned int __flags); +/* Similarly for the ELF header. */ +extern unsigned int elf_flagehdr (Elf *__elf, Elf_Cmd __cmd, + unsigned int __flags); +/* Similarly for the ELF program header. */ +extern unsigned int elf_flagphdr (Elf *__elf, Elf_Cmd __cmd, + unsigned int __flags); +/* Similarly for the given ELF section. */ +extern unsigned int elf_flagscn (Elf_Scn *__scn, Elf_Cmd __cmd, + unsigned int __flags); +/* Similarly for the given ELF data. */ +extern unsigned int elf_flagdata (Elf_Data *__data, Elf_Cmd __cmd, + unsigned int __flags); +/* Similarly for the given ELF section header. */ +extern unsigned int elf_flagshdr (Elf_Scn *__scn, Elf_Cmd __cmd, + unsigned int __flags); + + +/* Get data from section while translating from file representation + to memory representation. */ +extern Elf_Data *elf_getdata (Elf_Scn *__scn, Elf_Data *__data); + +/* Get uninterpreted section content. */ +extern Elf_Data *elf_rawdata (Elf_Scn *__scn, Elf_Data *__data); + +/* Create new data descriptor for section SCN. */ +extern Elf_Data *elf_newdata (Elf_Scn *__scn); + +/* Get data translated from a chunk of the file contents as section data + would be for TYPE. The resulting Elf_Data pointer is valid until + elf_end (ELF) is called. */ +extern Elf_Data *elf_getdata_rawchunk (Elf *__elf, + loff_t __offset, size_t __size, + Elf_Type __type); + + +/* Return pointer to string at OFFSET in section INDEX. */ +extern char *elf_strptr (Elf *__elf, size_t __index, size_t __offset); + + +/* Return header of archive. */ +extern Elf_Arhdr *elf_getarhdr (Elf *__elf); + +/* Return offset in archive for current file ELF. */ +extern loff_t elf_getaroff (Elf *__elf); + +/* Select archive element at OFFSET. */ +extern size_t elf_rand (Elf *__elf, size_t __offset); + +/* Get symbol table of archive. */ +extern Elf_Arsym *elf_getarsym (Elf *__elf, size_t *__narsyms); + + +/* Control ELF descriptor. */ +extern int elf_cntl (Elf *__elf, Elf_Cmd __cmd); + +/* Retrieve uninterpreted file contents. */ +extern char *elf_rawfile (Elf *__elf, size_t *__nbytes); + + +/* Return size of array of COUNT elements of the type denoted by TYPE + in the external representation. The binary class is taken from ELF. + The result is based on version VERSION of the ELF standard. */ +extern size_t elf32_fsize (Elf_Type __type, size_t __count, + unsigned int __version) + __attribute__ ((__const__)); +/* Similar but this time the binary calls is ELFCLASS64. */ +extern size_t elf64_fsize (Elf_Type __type, size_t __count, + unsigned int __version) + __attribute__ ((__const__)); + + +/* Convert data structure from the representation in the file represented + by ELF to their memory representation. */ +extern Elf_Data *elf32_xlatetom (Elf_Data *__dest, const Elf_Data *__src, + unsigned int __encode); +/* Same for 64 bit class. */ +extern Elf_Data *elf64_xlatetom (Elf_Data *__dest, const Elf_Data *__src, + unsigned int __encode); + +/* Convert data structure from to the representation in memory + represented by ELF file representation. */ +extern Elf_Data *elf32_xlatetof (Elf_Data *__dest, const Elf_Data *__src, + unsigned int __encode); +/* Same for 64 bit class. */ +extern Elf_Data *elf64_xlatetof (Elf_Data *__dest, const Elf_Data *__src, + unsigned int __encode); + + +/* Return error code of last failing function call. This value is kept + separately for each thread. */ +extern int elf_errno (void); + +/* Return error string for ERROR. If ERROR is zero, return error string + for most recent error or NULL is none occurred. If ERROR is -1 the + behaviour is similar to the last case except that not NULL but a legal + string is returned. */ +extern const char *elf_errmsg (int __error); + + +/* Coordinate ELF library and application versions. */ +extern unsigned int elf_version (unsigned int __version); + +/* Set fill bytes used to fill holes in data structures. */ +extern void elf_fill (int __fill); + +/* Compute hash value. */ +extern unsigned long int elf_hash (const char *__string) + __attribute__ ((__pure__)); + +/* Compute hash value using the GNU-specific hash function. */ +extern unsigned long int elf_gnu_hash (const char *__string) + __attribute__ ((__pure__)); + + +/* Compute simple checksum from permanent parts of the ELF file. */ +extern long int elf32_checksum (Elf *__elf); +/* Similar but this time the binary calls is ELFCLASS64. */ +extern long int elf64_checksum (Elf *__elf); + +#ifdef __cplusplus +} +#endif + +#endif /* libelf.h */ diff --git a/3rdparty/elfutils/libelf/libelf.pro b/3rdparty/elfutils/libelf/libelf.pro new file mode 100644 index 0000000..fc76549 --- /dev/null +++ b/3rdparty/elfutils/libelf/libelf.pro @@ -0,0 +1,95 @@ +TEMPLATE = lib +CONFIG += staticlib +TARGET = ../elf + +include(../elfutils.pri) +include(elfheaders.pri) + +SOURCES += \ + $$PWD/elf_begin.c \ + $$PWD/elf_clone.c \ + $$PWD/elf_cntl.c \ + $$PWD/elf_end.c \ + $$PWD/elf_error.c \ + $$PWD/elf_fill.c \ + $$PWD/elf_flagdata.c \ + $$PWD/elf_flagehdr.c \ + $$PWD/elf_flagelf.c \ + $$PWD/elf_flagphdr.c \ + $$PWD/elf_flagscn.c \ + $$PWD/elf_flagshdr.c \ + $$PWD/elf_getarhdr.c \ + $$PWD/elf_getaroff.c \ + $$PWD/elf_getarsym.c \ + $$PWD/elf_getbase.c \ + $$PWD/elf_getdata_rawchunk.c \ + $$PWD/elf_getdata.c \ + $$PWD/elf_getident.c \ + $$PWD/elf_getphdrnum.c \ + $$PWD/elf_getscn.c \ + $$PWD/elf_getshdrnum.c \ + $$PWD/elf_getshdrstrndx.c \ + $$PWD/elf_gnu_hash.c \ + $$PWD/elf_hash.c \ + $$PWD/elf_kind.c \ + $$PWD/elf_memory.c \ + $$PWD/elf_ndxscn.c \ + $$PWD/elf_newdata.c \ + $$PWD/elf_newscn.c \ + $$PWD/elf_next.c \ + $$PWD/elf_nextscn.c \ + $$PWD/elf_rand.c \ + $$PWD/elf_rawdata.c \ + $$PWD/elf_rawfile.c \ + $$PWD/elf_readall.c \ + $$PWD/elf_scnshndx.c \ + $$PWD/elf_strptr.c \ + $$PWD/elf_update.c \ + $$PWD/elf_version.c \ + $$PWD/gelf_checksum.c \ + $$PWD/gelf_fsize.c \ + $$PWD/gelf_getauxv.c \ + $$PWD/gelf_getclass.c \ + $$PWD/gelf_getdyn.c \ + $$PWD/gelf_getehdr.c \ + $$PWD/gelf_getlib.c \ + $$PWD/gelf_getmove.c \ + $$PWD/gelf_getnote.c \ + $$PWD/gelf_getphdr.c \ + $$PWD/gelf_getrel.c \ + $$PWD/gelf_getrela.c \ + $$PWD/gelf_getshdr.c \ + $$PWD/gelf_getsym.c \ + $$PWD/gelf_getsyminfo.c \ + $$PWD/gelf_getsymshndx.c \ + $$PWD/gelf_getverdaux.c \ + $$PWD/gelf_getverdef.c \ + $$PWD/gelf_getvernaux.c \ + $$PWD/gelf_getverneed.c \ + $$PWD/gelf_getversym.c \ + $$PWD/gelf_newehdr.c \ + $$PWD/gelf_newphdr.c \ + $$PWD/gelf_offscn.c \ + $$PWD/gelf_update_auxv.c \ + $$PWD/gelf_update_dyn.c \ + $$PWD/gelf_update_ehdr.c \ + $$PWD/gelf_update_lib.c \ + $$PWD/gelf_update_move.c \ + $$PWD/gelf_update_phdr.c \ + $$PWD/gelf_update_rel.c \ + $$PWD/gelf_update_rela.c \ + $$PWD/gelf_update_shdr.c \ + $$PWD/gelf_update_sym.c \ + $$PWD/gelf_update_syminfo.c \ + $$PWD/gelf_update_symshndx.c \ + $$PWD/gelf_update_verdaux.c \ + $$PWD/gelf_update_verdef.c \ + $$PWD/gelf_update_vernaux.c \ + $$PWD/gelf_update_verneed.c \ + $$PWD/gelf_update_versym.c \ + $$PWD/gelf_xlate.c \ + $$PWD/gelf_xlatetof.c \ + $$PWD/gelf_xlatetom.c \ + $$PWD/libelf_crc32.c \ + $$PWD/libelf_next_prime.c \ + $$PWD/nlist.c diff --git a/3rdparty/elfutils/libelf/libelfP.h b/3rdparty/elfutils/libelf/libelfP.h new file mode 100644 index 0000000..52cf745 --- /dev/null +++ b/3rdparty/elfutils/libelf/libelfP.h @@ -0,0 +1,594 @@ +/* Internal interfaces for libelf. + Copyright (C) 1998-2010 Red Hat, Inc. + This file is part of elfutils. + Contributed by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifndef _LIBELFP_H +#define _LIBELFP_H 1 + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <ar.h> +#include <gelf.h> + +#include <errno.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +/* gettext helper macros. */ +#define _(Str) dgettext ("elfutils", Str) + + +/* Helper Macros to write 32 bit and 64 bit functions. */ +#define __elfw2_(Bits, Name) __elf##Bits##_##Name +#define elfw2_(Bits, Name) elf##Bits##_##Name +#define ElfW2_(Bits, Name) Elf##Bits##_##Name +#define ELFW2_(Bits, Name) ELF##Bits##_##Name +#define ELFW_(Name, Bits) Name##Bits +#define __elfw2(Bits, Name) __elfw2_(Bits, Name) +#define elfw2(Bits, Name) elfw2_(Bits, Name) +#define ElfW2(Bits, Name) ElfW2_(Bits, Name) +#define ELFW2(Bits, Name) ELFW2_(Bits, Name) +#define ELFW(Name, Bits) ELFW_(Name, Bits) + + +/* Sizes of the external types, for 32 bits objects. */ +#define ELF32_FSZ_ADDR 4 +#define ELF32_FSZ_OFF 4 +#define ELF32_FSZ_HALF 2 +#define ELF32_FSZ_WORD 4 +#define ELF32_FSZ_SWORD 4 +#define ELF32_FSZ_XWORD 8 +#define ELF32_FSZ_SXWORD 8 + +/* Same for 64 bits objects. */ +#define ELF64_FSZ_ADDR 8 +#define ELF64_FSZ_OFF 8 +#define ELF64_FSZ_HALF 2 +#define ELF64_FSZ_WORD 4 +#define ELF64_FSZ_SWORD 4 +#define ELF64_FSZ_XWORD 8 +#define ELF64_FSZ_SXWORD 8 + + +/* This is an extension of the ELF_F_* enumeration. The values here are + not part of the library interface, they are only used internally. */ +enum +{ + ELF_F_MMAPPED = 0x40, + ELF_F_MALLOCED = 0x80, + ELF_F_FILEDATA = 0x100 +}; + + +/* Get definition of all the external types. */ +#include "exttypes.h" + + +/* Error values. */ +enum +{ + ELF_E_NOERROR = 0, + ELF_E_UNKNOWN_ERROR, + ELF_E_UNKNOWN_VERSION, + ELF_E_UNKNOWN_TYPE, + ELF_E_INVALID_HANDLE, + ELF_E_SOURCE_SIZE, + ELF_E_DEST_SIZE, + ELF_E_INVALID_ENCODING, + ELF_E_NOMEM, + ELF_E_INVALID_FILE, + ELF_E_INVALID_OP, + ELF_E_NO_VERSION, + ELF_E_INVALID_CMD, + ELF_E_RANGE, + ELF_E_ARCHIVE_FMAG, + ELF_E_INVALID_ARCHIVE, + ELF_E_NO_ARCHIVE, + ELF_E_NO_INDEX, + ELF_E_READ_ERROR, + ELF_E_WRITE_ERROR, + ELF_E_INVALID_CLASS, + ELF_E_INVALID_INDEX, + ELF_E_INVALID_OPERAND, + ELF_E_INVALID_SECTION, + ELF_E_INVALID_COMMAND, + ELF_E_WRONG_ORDER_EHDR, + ELF_E_FD_DISABLED, + ELF_E_FD_MISMATCH, + ELF_E_OFFSET_RANGE, + ELF_E_NOT_NUL_SECTION, + ELF_E_DATA_MISMATCH, + ELF_E_INVALID_SECTION_HEADER, + ELF_E_INVALID_DATA, + ELF_E_DATA_ENCODING, + ELF_E_SECTION_TOO_SMALL, + ELF_E_INVALID_ALIGN, + ELF_E_INVALID_SHENTSIZE, + ELF_E_UPDATE_RO, + ELF_E_NOFILE, + ELF_E_GROUP_NOT_REL, + ELF_E_INVALID_PHDR, + ELF_E_NO_PHDR, + ELF_E_INVALID_OFFSET, + /* Keep this as the last entry. */ + ELF_E_NUM +}; + + +/* The visible `Elf_Data' type is not sufficent for some operations due + to a misdesigned interface. Extend it for internal purposes. */ +typedef struct +{ + Elf_Data d; + Elf_Scn *s; +} Elf_Data_Scn; + + +/* List of `Elf_Data' descriptors. This is what makes up the section + contents. */ +typedef struct Elf_Data_List +{ + /* `data' *must* be the first element in the struct. */ + Elf_Data_Scn data; + struct Elf_Data_List *next; + int flags; +} Elf_Data_List; + + +/* Descriptor for ELF section. */ +struct Elf_Scn +{ + /* We have to distinguish several different situations: + + 1. the section is user created. Therefore there is no file or memory + region to read the data from. Here we have two different subcases: + + a) data was not yet added (before the first `elf_newdata' call) + + b) at least one data set is available + + 2. this is a section from a file/memory region. We have to read the + current content in one data block if we have to. But we don't + read the data until it is necessary. So we have the subcases: + + a) the section in the file has size zero (for whatever reason) + + b) the data of the file is not (yet) read + + c) the data is read and available. + + In addition to this we have different data sets, the raw and the converted + data. This distinction only exists for the data read from the file. + All user-added data set (all but the first when read from the file or + all of them for user-create sections) are the same in both formats. + We don't create the converted data before it is necessary. + + The `data_read' element signals whether data is available in the + raw format. + + If there is data from the file/memory region or if read one data + set is added the `rawdata_list_read' pointer in non-NULL and points + to the last filled data set. `raw_datalist_rear' is therefore NULL + only if there is no data set at all. + + This so far allows to distinguish all but two cases (given that the + `rawdata_list' and `data_list' entries are initialized to zero) is + between not yet loaded data from the file/memory region and a section + with zero size and type ELF_T_BYTE. */ + Elf_Data_List data_list; /* List of data buffers. */ + Elf_Data_List *data_list_rear; /* Pointer to the rear of the data list. */ + + Elf_Data_Scn rawdata; /* Uninterpreted data of the section. */ + + int data_read; /* Nonzero if the section was created by the + user or if the data from the file/memory + is read. */ + int shndx_index; /* Index of the extended section index + table for this symbol table (if this + section is a symbol table). */ + + size_t index; /* Index of this section. */ + struct Elf *elf; /* The underlying ELF file. */ + + union + { + Elf32_Shdr *e32; /* Pointer to 32bit section header. */ + Elf64_Shdr *e64; /* Pointer to 64bit section header. */ + } shdr; + + unsigned int shdr_flags; /* Section header modified? */ + unsigned int flags; /* Section changed in size? */ + + char *rawdata_base; /* The unmodified data of the section. */ + char *data_base; /* The converted data of the section. */ + + struct Elf_ScnList *list; /* Pointer to the section list element the + data is in. */ +}; + + +/* List of section. */ +typedef struct Elf_ScnList +{ + unsigned int cnt; /* Number of elements of 'data' used. */ + unsigned int max; /* Number of elements of 'data' allocated. */ + struct Elf_ScnList *next; /* Next block of sections. */ + struct Elf_Scn data[0]; /* Section data. */ +} Elf_ScnList; + + +/* elf_getdata_rawchunk result. */ +typedef struct Elf_Data_Chunk +{ + Elf_Data_Scn data; + union + { + Elf_Scn dummy_scn; + struct Elf_Data_Chunk *next; + }; +} Elf_Data_Chunk; + + +/* The ELF descriptor. */ +struct Elf +{ + /* Address to which the file was mapped. NULL if not mapped. */ + void *map_address; + + /* When created for an archive member this points to the descriptor + for the archive. */ + Elf *parent; + Elf *next; /* Used in list of archive descriptors. */ + + /* What kind of file is underneath (ELF file, archive...). */ + Elf_Kind kind; + + /* Command used to create this descriptor. */ + Elf_Cmd cmd; + + /* The binary class. */ + unsigned int class; + + /* The used file descriptor. -1 if not available anymore. */ + int fildes; + + /* Offset in the archive this file starts or zero. */ + off_t start_offset; + + /* Size of the file in the archive or the entire file size, or ~0 + for an (yet) unknown size. */ + size_t maximum_size; + + /* Describes the way the memory was allocated and if the dirty bit is + signalled it means that the whole file has to be rewritten since + the layout changed. */ + int flags; + + /* Reference counting for the descriptor. */ + int ref_count; + + /* Lock to handle multithreaded programs. */ + rwlock_define (,lock); + + union + { + struct + { + /* The next fields are only useful when testing for ==/!= NULL. */ + void *ehdr; + void *shdr; + void *phdr; + + Elf_ScnList *scns_last; /* Last element in the section list. + If NULL the data has not yet been + read from the file. */ + Elf_Data_Chunk *rawchunks; /* List of elf_getdata_rawchunk results. */ + unsigned int scnincr; /* Number of sections allocate the last + time. */ + int ehdr_flags; /* Flags (dirty) for ELF header. */ + int phdr_flags; /* Flags (dirty|malloc) for program header. */ + int shdr_malloced; /* Nonzero if shdr array was allocated. */ + off64_t sizestr_offset; /* Offset of the size string in the parent + if this is an archive member. */ + } elf; + + struct + { + Elf32_Ehdr *ehdr; /* Pointer to the ELF header. This is + never malloced. */ + Elf32_Shdr *shdr; /* Used when reading from a file. */ + Elf32_Phdr *phdr; /* Pointer to the program header array. */ + Elf_ScnList *scns_last; /* Last element in the section list. + If NULL the data has not yet been + read from the file. */ + Elf_Data_Chunk *rawchunks; /* List of elf_getdata_rawchunk results. */ + unsigned int scnincr; /* Number of sections allocate the last + time. */ + int ehdr_flags; /* Flags (dirty) for ELF header. */ + int phdr_flags; /* Flags (dirty|malloc) for program header. */ + int shdr_malloced; /* Nonzero if shdr array was allocated. */ + off64_t sizestr_offset; /* Offset of the size string in the parent + if this is an archive member. */ + Elf32_Ehdr ehdr_mem; /* Memory used for ELF header when not + mmaped. */ + char __e32scnspad[sizeof (Elf64_Ehdr) - sizeof (Elf32_Ehdr)]; + + /* The section array. */ + Elf_ScnList scns; + } elf32; + + struct + { + Elf64_Ehdr *ehdr; /* Pointer to the ELF header. This is + never malloced. */ + Elf64_Shdr *shdr; /* Used when reading from a file. */ + Elf64_Phdr *phdr; /* Pointer to the program header array. */ + Elf_ScnList *scns_last; /* Last element in the section list. + If NULL the data has not yet been + read from the file. */ + Elf_Data_Chunk *rawchunks; /* List of elf_getdata_rawchunk results. */ + unsigned int scnincr; /* Number of sections allocate the last + time. */ + int ehdr_flags; /* Flags (dirty) for ELF header. */ + int phdr_flags; /* Flags (dirty|malloc) for program header. */ + int shdr_malloced; /* Nonzero if shdr array was allocated. */ + off64_t sizestr_offset; /* Offset of the size string in the parent + if this is an archive member. */ + Elf64_Ehdr ehdr_mem; /* Memory used for ELF header when not + mmaped. */ + + /* The section array. */ + Elf_ScnList scns; + } elf64; + + struct + { + Elf *children; /* List of all descriptors for this archive. */ + Elf_Arsym *ar_sym; /* Symbol table returned by elf_getarsym. */ + size_t ar_sym_num; /* Number of entries in `ar_sym'. */ + char *long_names; /* If no index is available but long names + are used this elements points to the data.*/ + size_t long_names_len; /* Length of the long name table. */ + off_t offset; /* Offset in file we are currently at. + elf_next() advances this to the next + member of the archive. */ + Elf_Arhdr elf_ar_hdr; /* Structure returned by 'elf_getarhdr'. */ + struct ar_hdr ar_hdr; /* Header read from file. */ + char ar_name[16]; /* NUL terminated ar_name of elf_ar_hdr. */ + char raw_name[17]; /* This is a buffer for the NUL terminated + named raw_name used in the elf_ar_hdr. */ + } ar; + } state; + + /* There absolutely never must be anything following the union. */ +}; + +/* Type of the conversion functions. These functions will convert the + byte order. */ +typedef void (*xfct_t) (void *, const void *, size_t, int); + +/* The table with the function pointers. */ +extern const xfct_t __elf_xfctstom[EV_NUM - 1][EV_NUM - 1][ELFCLASSNUM - 1][ELF_T_NUM] attribute_hidden; +extern const xfct_t __elf_xfctstof[EV_NUM - 1][EV_NUM - 1][ELFCLASSNUM - 1][ELF_T_NUM] attribute_hidden; + + +/* Array with sizes of the external types indexed by ELF version, binary + class, and type. */ +extern const size_t __libelf_type_sizes[EV_NUM - 1][ELFCLASSNUM - 1][ELF_T_NUM] attribute_hidden; +/* We often have to access the size for a type in the current version. */ +#if EV_NUM != 2 +# define elf_typesize(class,type,n) \ + elfw2(class,fsize) (type, n, __libelf_version) +#else +# define elf_typesize(class,type,n) \ + (__libelf_type_sizes[EV_CURRENT - 1][ELFW(ELFCLASS,class) - 1][type] * n) +#endif + +/* Currently selected version of the ELF specification. */ +extern unsigned int __libelf_version attribute_hidden; + +/* The byte value used for filling gaps. */ +extern int __libelf_fill_byte attribute_hidden; + +/* Nonzero if the version was set. */ +extern int __libelf_version_initialized attribute_hidden; + +/* Index for __libelf_type_sizes et al. */ +#if EV_NUM == 2 +# define LIBELF_EV_IDX 0 +#else +# define LIBELF_EV_IDX (__libelf_version - 1) +#endif + +#if !ALLOW_UNALIGNED +/* Array with alignment requirements of the internal types indexed by ELF + version, binary class, and type. */ +extern const uint_fast8_t __libelf_type_aligns[EV_NUM - 1][ELFCLASSNUM - 1][ELF_T_NUM] attribute_hidden; +# define __libelf_type_align(class, type) \ + (__libelf_type_aligns[LIBELF_EV_IDX][class - 1][type] ?: 1) +#else +# define __libelf_type_align(class, type) 1 +#endif + +/* The libelf API does not have such a function but it is still useful. + Get the memory size for the given type. + + These functions cannot be marked internal since they are aliases + of the export elfXX_fsize functions.*/ +extern size_t __elf32_msize (Elf_Type __type, size_t __count, + unsigned int __version); +extern size_t __elf64_msize (Elf_Type __type, size_t __count, + unsigned int __version); + + +/* Create Elf descriptor from memory image. */ +extern Elf *__libelf_read_mmaped_file (int fildes, void *map_address, + off_t offset, size_t maxsize, + Elf_Cmd cmd, Elf *parent) + internal_function; + +/* Set error value. */ +extern void __libelf_seterrno (int value) internal_function; + +/* Get the next archive header. */ +extern int __libelf_next_arhdr_wrlock (Elf *elf) internal_function; + +/* Read all of the file associated with the descriptor. */ +extern char *__libelf_readall (Elf *elf) internal_function; + +/* Read the complete section table and convert the byte order if necessary. */ +extern int __libelf_readsections (Elf *elf) internal_function; + +/* Store the information for the raw data in the `rawdata_list' element. */ +extern int __libelf_set_rawdata (Elf_Scn *scn) internal_function; +extern int __libelf_set_rawdata_wrlock (Elf_Scn *scn) internal_function; + + +/* Helper functions for elf_update. */ +extern off_t __elf32_updatenull_wrlock (Elf *elf, int *change_bop, + size_t shnum) internal_function; +extern off_t __elf64_updatenull_wrlock (Elf *elf, int *change_bop, + size_t shnum) internal_function; + +extern int __elf32_updatemmap (Elf *elf, int change_bo, size_t shnum) + internal_function; +extern int __elf64_updatemmap (Elf *elf, int change_bo, size_t shnum) + internal_function; +extern int __elf32_updatefile (Elf *elf, int change_bo, size_t shnum) + internal_function; +extern int __elf64_updatefile (Elf *elf, int change_bo, size_t shnum) + internal_function; + + +/* Alias for exported functions to avoid PLT entries, and + rdlock/wrlock variants of these functions. */ +extern int __elf_end_internal (Elf *__elf) attribute_hidden; +extern Elf *__elf_begin_internal (int __fildes, Elf_Cmd __cmd, Elf *__ref) + attribute_hidden; +extern Elf32_Ehdr *__elf32_getehdr_wrlock (Elf *__elf) internal_function; +extern Elf64_Ehdr *__elf64_getehdr_wrlock (Elf *__elf) internal_function; +extern Elf32_Ehdr *__elf32_newehdr_internal (Elf *__elf) attribute_hidden; +extern Elf64_Ehdr *__elf64_newehdr_internal (Elf *__elf) attribute_hidden; +extern Elf32_Phdr *__elf32_getphdr_internal (Elf *__elf) attribute_hidden; +extern Elf64_Phdr *__elf64_getphdr_internal (Elf *__elf) attribute_hidden; +extern Elf32_Phdr *__elf32_getphdr_wrlock (Elf *__elf) attribute_hidden; +extern Elf64_Phdr *__elf64_getphdr_wrlock (Elf *__elf) attribute_hidden; +extern Elf32_Phdr *__elf32_newphdr_internal (Elf *__elf, size_t __cnt) + attribute_hidden; +extern Elf64_Phdr *__elf64_newphdr_internal (Elf *__elf, size_t __cnt) + attribute_hidden; +extern Elf_Scn *__elf32_offscn_internal (Elf *__elf, Elf32_Off __offset) + attribute_hidden; +extern Elf_Scn *__elf64_offscn_internal (Elf *__elf, Elf64_Off __offset) + attribute_hidden; +extern int __elf_getphdrnum_rdlock (Elf *__elf, size_t *__dst) + internal_function; +extern int __elf_getshdrnum_rdlock (Elf *__elf, size_t *__dst) + internal_function; +extern int __elf_getshdrstrndx_internal (Elf *__elf, size_t *__dst) + attribute_hidden; +extern Elf32_Shdr *__elf32_getshdr_rdlock (Elf_Scn *__scn) internal_function; +extern Elf64_Shdr *__elf64_getshdr_rdlock (Elf_Scn *__scn) internal_function; +extern Elf32_Shdr *__elf32_getshdr_wrlock (Elf_Scn *__scn) internal_function; +extern Elf64_Shdr *__elf64_getshdr_wrlock (Elf_Scn *__scn) internal_function; +extern Elf_Scn *__elf_getscn_internal (Elf *__elf, size_t __index) + attribute_hidden; +extern Elf_Scn *__elf_nextscn_internal (Elf *__elf, Elf_Scn *__scn) + attribute_hidden; +extern int __elf_scnshndx_internal (Elf_Scn *__scn) attribute_hidden; +extern Elf_Data *__elf_getdata_internal (Elf_Scn *__scn, Elf_Data *__data) + attribute_hidden; +extern Elf_Data *__elf_getdata_rdlock (Elf_Scn *__scn, Elf_Data *__data) + internal_function; +extern Elf_Data *__elf_rawdata_internal (Elf_Scn *__scn, Elf_Data *__data) + attribute_hidden; +extern char *__elf_strptr_internal (Elf *__elf, size_t __index, + size_t __offset) attribute_hidden; +extern Elf_Data *__elf32_xlatetom_internal (Elf_Data *__dest, + const Elf_Data *__src, + unsigned int __encode) + attribute_hidden; +extern Elf_Data *__elf64_xlatetom_internal (Elf_Data *__dest, + const Elf_Data *__src, + unsigned int __encode) + attribute_hidden; +extern Elf_Data *__elf32_xlatetof_internal (Elf_Data *__dest, + const Elf_Data *__src, + unsigned int __encode) + attribute_hidden; +extern Elf_Data *__elf64_xlatetof_internal (Elf_Data *__dest, + const Elf_Data *__src, + unsigned int __encode) + attribute_hidden; +extern unsigned int __elf_version_internal (unsigned int __version) + attribute_hidden; +extern unsigned long int __elf_hash_internal (const char *__string) + __attribute__ ((__pure__, visibility ("hidden"))); +extern long int __elf32_checksum_internal (Elf *__elf) attribute_hidden; +extern long int __elf64_checksum_internal (Elf *__elf) attribute_hidden; + + +extern GElf_Ehdr *__gelf_getehdr_rdlock (Elf *__elf, GElf_Ehdr *__dest) + internal_function; +extern size_t __gelf_fsize_internal (Elf *__elf, Elf_Type __type, + size_t __count, unsigned int __version) + attribute_hidden; +extern GElf_Shdr *__gelf_getshdr_internal (Elf_Scn *__scn, GElf_Shdr *__dst) + attribute_hidden; +extern GElf_Sym *__gelf_getsym_internal (Elf_Data *__data, int __ndx, + GElf_Sym *__dst) attribute_hidden; + + +extern uint32_t __libelf_crc32 (uint32_t crc, unsigned char *buf, size_t len) + attribute_hidden; + + +/* We often have to update a flag iff a value changed. Make this + convenient. */ +#define update_if_changed(var, exp, flag) \ + do { \ + __typeof__ (var) *_var = &(var); \ + __typeof__ (exp) _exp = (exp); \ + if (*_var != _exp) \ + { \ + *_var = _exp; \ + (flag) |= ELF_F_DIRTY; \ + } \ + } while (0) + +/* Align offset to 4 bytes as needed for note name and descriptor data. */ +#define NOTE_ALIGN(n) (((n) + 3) & -4U) + +/* Convenience macro. */ +#define INVALID_NDX(ndx, type, data) \ + unlikely ((data)->d_size / sizeof (type) <= (unsigned int) (ndx)) + +#endif /* libelfP.h */ diff --git a/3rdparty/elfutils/libelf/libelf_crc32.c b/3rdparty/elfutils/libelf/libelf_crc32.c new file mode 100644 index 0000000..1426faf --- /dev/null +++ b/3rdparty/elfutils/libelf/libelf_crc32.c @@ -0,0 +1,35 @@ +/* Copyright (C) 2002 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define crc32 attribute_hidden __libelf_crc32 +#define LIB_SYSTEM_H 1 +#include <libelf.h> +#include "../lib/crc32.c" diff --git a/3rdparty/elfutils/libelf/libelf_next_prime.c b/3rdparty/elfutils/libelf/libelf_next_prime.c new file mode 100644 index 0000000..05229c3 --- /dev/null +++ b/3rdparty/elfutils/libelf/libelf_next_prime.c @@ -0,0 +1,33 @@ +/* Copyright (C) 2002 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define next_prime attribute_hidden __libelf_next_prime +#include "../lib/next_prime.c" diff --git a/3rdparty/elfutils/libelf/nlist.c b/3rdparty/elfutils/libelf/nlist.c new file mode 100644 index 0000000..41e5ff6 --- /dev/null +++ b/3rdparty/elfutils/libelf/nlist.c @@ -0,0 +1,243 @@ +/* Extract symbol list from binary. + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2005, 2007 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <fcntl.h> +#include <gelf.h> +#include <libelf.h> +#include <nlist.h> +#include <unistd.h> + +#include "libelfP.h" + + +struct hashentry +{ + const char *str; + GElf_Sym sym; +}; +#define TYPE struct hashentry +/* XXX Use a better hash function some day. */ +#define HASHFCT(str, len) INTUSE(elf_hash) (str) +#define COMPARE(p1, p2) strcmp ((p1)->str, (p2)->str) +#define CLASS static +#define PREFIX nlist_ +#define xcalloc(n, m) calloc (n, m) +#define next_prime(s) __libelf_next_prime (s) +#include <fixedsizehash.h> + + +int +nlist (const char *filename, struct nlist *nl) +{ + int fd; + Elf *elf; + Elf_Scn *scn = NULL; + Elf_Scn *symscn = NULL; + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = NULL; + Elf_Data *data; + struct nlist_fshash *table; + size_t nsyms; + size_t cnt; + + /* Open the file. */ + fd = open (filename, O_RDONLY); + if (fd == -1) + { + __libelf_seterrno (ELF_E_NOFILE); + goto fail; + } + + /* For compatibility reasons (`nlist' existed before ELF and libelf) + we don't expect the caller to set the ELF version. Do this here + if it hasn't happened yet. */ + if (__libelf_version_initialized == 0) + INTUSE(elf_version) (EV_CURRENT); + + /* Now get an ELF descriptor. */ + elf = INTUSE(elf_begin) (fd, ELF_C_READ_MMAP, NULL); + if (elf == NULL) + goto fail_fd; + + /* Find a symbol table. We prefer the real symbol table but if it + does not exist use the dynamic symbol table. */ + while ((scn = INTUSE(elf_nextscn) (elf, scn)) != NULL) + { + shdr = INTUSE(gelf_getshdr) (scn, &shdr_mem); + if (shdr == NULL) + goto fail_close; + + /* That is what we are looking for. */ + if (shdr->sh_type == SHT_SYMTAB) + { + symscn = scn; + break; + } + + /* Better than nothing. Remember this section. */ + if (shdr->sh_type == SHT_DYNSYM) + symscn = scn; + } + + if (symscn == NULL) + /* We haven't found anything. Fail. */ + goto fail_close; + + /* Re-get the section header in case we found only the dynamic symbol + table. */ + if (scn == NULL) + shdr = INTUSE(gelf_getshdr) (symscn, &shdr_mem); + /* SHDR->SH_LINK now contains the index of the string section. */ + + /* Get the data for the symbol section. */ + data = INTUSE(elf_getdata) (symscn, NULL); + if (data == NULL) + goto fail_close; + + /* How many symbols are there? */ + nsyms = (shdr->sh_size + / INTUSE(gelf_fsize) (elf, ELF_T_SYM, 1, data->d_version)); + + /* Create the hash table. */ + table = nlist_fshash_init (nsyms); + if (table == NULL) + { + __libelf_seterrno (ELF_E_NOMEM); + goto fail_close; + } + + /* Iterate over all the symbols in the section. */ + for (cnt = 0; cnt < nsyms; ++cnt) + { + struct hashentry mem; + GElf_Sym *sym; + + /* Get the symbol. */ + sym = INTUSE(gelf_getsym) (data, cnt, &mem.sym); + if (sym == NULL) + goto fail_dealloc; + + /* Get the name of the symbol. */ + mem.str = INTUSE(elf_strptr) (elf, shdr->sh_link, sym->st_name); + if (mem.str == NULL) + goto fail_dealloc; + + /* Don't allow zero-length strings. */ + if (mem.str[0] == '\0') + continue; + + /* And add it to the hash table. Note that we are using the + overwrite version. This will ensure that + a) global symbols are preferred over local symbols since + they are all located at the end + b) if there are multiple local symbols with the same name + the last one is used. + */ + (void) nlist_fshash_overwrite (table, mem.str, 0, &mem); + } + + /* Now it is time to look for the symbols the user asked for. + XXX What is a `null name/null string'? This is what the + standard says terminates the list. Is it a null pointer + or a zero-length string? We test for both... */ + while (nl->n_name != NULL && nl->n_name[0] != '\0') + { + struct hashentry search; + const struct hashentry *found; + + /* Search for a matching entry in the hash table. */ + search.str = nl->n_name; + found = nlist_fshash_find (table, nl->n_name, 0, &search); + + if (found != NULL) + { + /* Found it. */ + nl->n_value = found->sym.st_value; + nl->n_scnum = found->sym.st_shndx; + nl->n_type = GELF_ST_TYPE (found->sym.st_info); + /* XXX What shall we fill in the next fields? */ + nl->n_sclass = 0; + nl->n_numaux = 0; + } + else + { + /* Not there. */ + nl->n_value = 0; + nl->n_scnum = 0; + nl->n_type = 0; + nl->n_sclass = 0; + nl->n_numaux = 0; + } + + /* Next search request. */ + ++nl; + } + + /* Free the resources. */ + nlist_fshash_fini (table); + + /* We do not need the ELF descriptor anymore. */ + (void) INTUSE(elf_end) (elf); + + /* Neither the file descriptor. */ + (void) close (fd); + + return 0; + + fail_dealloc: + nlist_fshash_fini (table); + + fail_close: + /* We do not need the ELF descriptor anymore. */ + (void) INTUSE(elf_end) (elf); + + fail_fd: + /* Neither the file descriptor. */ + (void) close (fd); + + fail: + /* We have to set all entries to zero. */ + while (nl->n_name != NULL && nl->n_name[0] != '\0') + { + nl->n_value = 0; + nl->n_scnum = 0; + nl->n_type = 0; + nl->n_sclass = 0; + nl->n_numaux = 0; + + /* Next entry. */ + ++nl; + } + + return -1; +} diff --git a/3rdparty/elfutils/libelf/nlist.h b/3rdparty/elfutils/libelf/nlist.h new file mode 100644 index 0000000..5990918 --- /dev/null +++ b/3rdparty/elfutils/libelf/nlist.h @@ -0,0 +1,56 @@ +/* Interface for nlist. + Copyright (C) 1998, 1999, 2000, 2002 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifndef _NLIST_H +#define _NLIST_H 1 + + +/* Symbol list type. */ +struct nlist +{ + char *n_name; /* Symbol name. */ + long int n_value; /* Value of symbol. */ + short int n_scnum; /* Section number found in. */ + unsigned short int n_type; /* Type of symbol. */ + char n_sclass; /* Storage class. */ + char n_numaux; /* Number of auxiliary entries. */ +}; + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Get specified entries from file. */ +extern int nlist (__const char *__filename, struct nlist *__nl); + +#ifdef __cplusplus +} +#endif + +#endif /* nlist.h */ diff --git a/3rdparty/elfutils/libelf/note_xlate.h b/3rdparty/elfutils/libelf/note_xlate.h new file mode 100644 index 0000000..62c6f63 --- /dev/null +++ b/3rdparty/elfutils/libelf/note_xlate.h @@ -0,0 +1,64 @@ +/* Conversion functions for notes. + Copyright (C) 2007, 2009, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +static void +elf_cvt_note (void *dest, const void *src, size_t len, int encode) +{ + assert (sizeof (Elf32_Nhdr) == sizeof (Elf64_Nhdr)); + + while (len >= sizeof (Elf32_Nhdr)) + { + (1 ? Elf32_cvt_Nhdr : Elf64_cvt_Nhdr) (dest, src, sizeof (Elf32_Nhdr), + encode); + const Elf32_Nhdr *n = encode ? src : dest; + Elf32_Word namesz = NOTE_ALIGN (n->n_namesz); + Elf32_Word descsz = NOTE_ALIGN (n->n_descsz); + + len -= sizeof *n; + src += sizeof *n; + dest += sizeof *n; + + if (namesz > len) + break; + len -= namesz; + if (descsz > len) + break; + len -= descsz; + + if (src != dest) + memcpy (dest, src, namesz + descsz); + + src += namesz + descsz; + dest += namesz + descsz; + } + + /* Copy opver any leftover data unconcerted. Probably part of + truncated name/desc data. */ + if (unlikely (len > 0) && src != dest) + memcpy (dest, src, len); +} diff --git a/3rdparty/elfutils/libelf/version_xlate.h b/3rdparty/elfutils/libelf/version_xlate.h new file mode 100644 index 0000000..16eaa19 --- /dev/null +++ b/3rdparty/elfutils/libelf/version_xlate.h @@ -0,0 +1,220 @@ +/* Conversion functions for versioning information. + Copyright (C) 1998, 1999, 2000, 2002, 2003 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 1998. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include <assert.h> +#include <gelf.h> + +#include "libelfP.h" + + +static void +elf_cvt_Verdef (void *dest, const void *src, size_t len, int encode) +{ + /* We have two different record types: ElfXX_Verndef and ElfXX_Verdaux. + To recognize them we have to walk the data structure and convert + them one after the other. The ENCODE parameter specifies whether + we are encoding or decoding. When we are encoding we can immediately + use the data in the buffer; if not, we have to decode the data before + using it. */ + size_t def_offset = 0; + GElf_Verdef *ddest; + GElf_Verdef *dsrc; + + /* We rely on the types being all the same size. */ + assert (sizeof (GElf_Verdef) == sizeof (Elf32_Verdef)); + assert (sizeof (GElf_Verdaux) == sizeof (Elf32_Verdaux)); + assert (sizeof (GElf_Verdef) == sizeof (Elf64_Verdef)); + assert (sizeof (GElf_Verdaux) == sizeof (Elf64_Verdaux)); + + if (len == 0) + return; + + do + { + size_t aux_offset; + GElf_Verdaux *asrc; + + /* Test for correct offset. */ + if (def_offset > len || len - def_offset < sizeof (GElf_Verdef)) + return; + + /* Work the tree from the first record. */ + ddest = (GElf_Verdef *) ((char *) dest + def_offset); + dsrc = (GElf_Verdef *) ((char *) src + def_offset); + + /* Decode first if necessary. */ + if (! encode) + { + ddest->vd_version = bswap_16 (dsrc->vd_version); + ddest->vd_flags = bswap_16 (dsrc->vd_flags); + ddest->vd_ndx = bswap_16 (dsrc->vd_ndx); + ddest->vd_cnt = bswap_16 (dsrc->vd_cnt); + ddest->vd_hash = bswap_32 (dsrc->vd_hash); + ddest->vd_aux = bswap_32 (dsrc->vd_aux); + ddest->vd_next = bswap_32 (dsrc->vd_next); + + aux_offset = def_offset + ddest->vd_aux; + } + else + aux_offset = def_offset + dsrc->vd_aux; + + /* Handle all the auxiliary records belonging to this definition. */ + do + { + GElf_Verdaux *adest; + + /* Test for correct offset. */ + if (aux_offset > len || len - aux_offset < sizeof (GElf_Verdaux)) + return; + + adest = (GElf_Verdaux *) ((char *) dest + aux_offset); + asrc = (GElf_Verdaux *) ((char *) src + aux_offset); + + if (encode) + aux_offset += asrc->vda_next; + + adest->vda_name = bswap_32 (asrc->vda_name); + adest->vda_next = bswap_32 (asrc->vda_next); + + if (! encode) + aux_offset += adest->vda_next; + } + while (asrc->vda_next != 0); + + /* Encode now if necessary. */ + if (encode) + { + def_offset += dsrc->vd_next; + + ddest->vd_version = bswap_16 (dsrc->vd_version); + ddest->vd_flags = bswap_16 (dsrc->vd_flags); + ddest->vd_ndx = bswap_16 (dsrc->vd_ndx); + ddest->vd_cnt = bswap_16 (dsrc->vd_cnt); + ddest->vd_hash = bswap_32 (dsrc->vd_hash); + ddest->vd_aux = bswap_32 (dsrc->vd_aux); + ddest->vd_next = bswap_32 (dsrc->vd_next); + } + else + def_offset += ddest->vd_next; + } + while (dsrc->vd_next != 0); +} + + +static void +elf_cvt_Verneed (void *dest, const void *src, size_t len, int encode) +{ + /* We have two different record types: ElfXX_Verndef and ElfXX_Verdaux. + To recognize them we have to walk the data structure and convert + them one after the other. The ENCODE parameter specifies whether + we are encoding or decoding. When we are encoding we can immediately + use the data in the buffer; if not, we have to decode the data before + using it. */ + size_t need_offset = 0; + GElf_Verneed *ndest; + GElf_Verneed *nsrc; + + /* We rely on the types being all the same size. */ + assert (sizeof (GElf_Verneed) == sizeof (Elf32_Verneed)); + assert (sizeof (GElf_Vernaux) == sizeof (Elf32_Vernaux)); + assert (sizeof (GElf_Verneed) == sizeof (Elf64_Verneed)); + assert (sizeof (GElf_Vernaux) == sizeof (Elf64_Vernaux)); + + if (len == 0) + return; + + do + { + size_t aux_offset; + GElf_Vernaux *asrc; + + /* Test for correct offset. */ + if (need_offset > len || len - need_offset < sizeof (GElf_Verneed)) + return; + + /* Work the tree from the first record. */ + ndest = (GElf_Verneed *) ((char *) dest + need_offset); + nsrc = (GElf_Verneed *) ((char *) src + need_offset); + + /* Decode first if necessary. */ + if (! encode) + { + ndest->vn_version = bswap_16 (nsrc->vn_version); + ndest->vn_cnt = bswap_16 (nsrc->vn_cnt); + ndest->vn_file = bswap_32 (nsrc->vn_file); + ndest->vn_aux = bswap_32 (nsrc->vn_aux); + ndest->vn_next = bswap_32 (nsrc->vn_next); + + aux_offset = need_offset + ndest->vn_aux; + } + else + aux_offset = need_offset + nsrc->vn_aux; + + /* Handle all the auxiliary records belonging to this requirement. */ + do + { + GElf_Vernaux *adest; + + /* Test for correct offset. */ + if (aux_offset > len || len - aux_offset < sizeof (GElf_Vernaux)) + return; + + adest = (GElf_Vernaux *) ((char *) dest + aux_offset); + asrc = (GElf_Vernaux *) ((char *) src + aux_offset); + + if (encode) + aux_offset += asrc->vna_next; + + adest->vna_hash = bswap_32 (asrc->vna_hash); + adest->vna_flags = bswap_16 (asrc->vna_flags); + adest->vna_other = bswap_16 (asrc->vna_other); + adest->vna_name = bswap_32 (asrc->vna_name); + adest->vna_next = bswap_32 (asrc->vna_next); + + if (! encode) + aux_offset += adest->vna_next; + } + while (asrc->vna_next != 0); + + /* Encode now if necessary. */ + if (encode) + { + need_offset += nsrc->vn_next; + + ndest->vn_version = bswap_16 (nsrc->vn_version); + ndest->vn_cnt = bswap_16 (nsrc->vn_cnt); + ndest->vn_file = bswap_32 (nsrc->vn_file); + ndest->vn_aux = bswap_32 (nsrc->vn_aux); + ndest->vn_next = bswap_32 (nsrc->vn_next); + } + else + need_offset += ndest->vn_next; + } + while (nsrc->vn_next != 0); +} diff --git a/3rdparty/elfutils/version.h b/3rdparty/elfutils/version.h new file mode 100644 index 0000000..7139c45 --- /dev/null +++ b/3rdparty/elfutils/version.h @@ -0,0 +1,38 @@ +/* Version information about elfutils development libraries. + Copyright (C) 2008 Red Hat, Inc. + + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifndef _ELFUTILS_VERSION_H +#define _ELFUTILS_VERSION_H 1 + +#define _ELFUTILS_VERSION 161 + +#define _ELFUTILS_PREREQ(major, minor) \ + (_ELFUTILS_VERSION >= ((major) * 1000 + (minor))) + +#endif /* elfutils/version.h */ diff --git a/app/app.pro b/app/app.pro new file mode 100644 index 0000000..36bf0fe --- /dev/null +++ b/app/app.pro @@ -0,0 +1,52 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2014-08-14T10:44:20 +# +#------------------------------------------------- + +QT += core network + +QT -= gui + +QMAKE_LFLAGS += -Wl,-rpath,\'\$\$ORIGIN/elfutils/backends\' +LIBS += -Wl,--start-group \ + ../3rdparty/elfutils/libdw.a \ + ../3rdparty/elfutils/libdwfl.a \ + ../3rdparty/elfutils/libelf.a \ + ../3rdparty/elfutils/libelf32.a \ + ../3rdparty/elfutils/libelf64.a \ + ../3rdparty/elfutils/libebl.a \ + ../3rdparty/elfutils/libdwelf.a \ + -Wl,--end-group \ + -Wl,-Bstatic -lbfd -Wl,-Bdynamic -lz -ldl -liberty + +TARGET = ../perfparser +CONFIG += console c++11 +CONFIG -= app_bundle + +TEMPLATE = app + +SOURCES += main.cpp \ + perfattributes.cpp \ + perfheader.cpp \ + perffilesection.cpp \ + perffeatures.cpp \ + perfdata.cpp \ + perfunwind.cpp \ + perfregisterinfo.cpp \ + perfstdin.cpp + +HEADERS += \ + perfattributes.h \ + perfheader.h \ + perffilesection.h \ + perffeatures.h \ + perfdata.h \ + perfunwind.h \ + perfregisterinfo.h \ + perfstdin.h + +include(../3rdparty/elfutils/elfutils.pri) +include(../3rdparty/elfutils/libdwfl/dwflheaders.pri) +include(../3rdparty/elfutils/libebl/eblheaders.pri) +include(../3rdparty/elfutils/libdwelf/dwelfheaders.pri) diff --git a/perfattributes.cpp b/app/perfattributes.cpp index 94d59fc..94d59fc 100644 --- a/perfattributes.cpp +++ b/app/perfattributes.cpp diff --git a/perfattributes.h b/app/perfattributes.h index f0c244e..f0c244e 100644 --- a/perfattributes.h +++ b/app/perfattributes.h diff --git a/perfdata.cpp b/app/perfdata.cpp index 6a71b3f..6a71b3f 100644 --- a/perfdata.cpp +++ b/app/perfdata.cpp diff --git a/perfdata.h b/app/perfdata.h index 3c85390..3c85390 100644 --- a/perfdata.h +++ b/app/perfdata.h diff --git a/perffeatures.cpp b/app/perffeatures.cpp index f9f26bb..f9f26bb 100644 --- a/perffeatures.cpp +++ b/app/perffeatures.cpp diff --git a/perffeatures.h b/app/perffeatures.h index c63bea2..c63bea2 100644 --- a/perffeatures.h +++ b/app/perffeatures.h diff --git a/perffilesection.cpp b/app/perffilesection.cpp index 4a6d3e4..4a6d3e4 100644 --- a/perffilesection.cpp +++ b/app/perffilesection.cpp diff --git a/perffilesection.h b/app/perffilesection.h index b375cef..b375cef 100644 --- a/perffilesection.h +++ b/app/perffilesection.h diff --git a/perfheader.cpp b/app/perfheader.cpp index e2abef0..e2abef0 100644 --- a/perfheader.cpp +++ b/app/perfheader.cpp diff --git a/perfheader.h b/app/perfheader.h index 986a18b..986a18b 100644 --- a/perfheader.h +++ b/app/perfheader.h diff --git a/perfregisterinfo.cpp b/app/perfregisterinfo.cpp index 0703881..0703881 100644 --- a/perfregisterinfo.cpp +++ b/app/perfregisterinfo.cpp diff --git a/perfregisterinfo.h b/app/perfregisterinfo.h index c834694..c834694 100644 --- a/perfregisterinfo.h +++ b/app/perfregisterinfo.h diff --git a/perfstdin.cpp b/app/perfstdin.cpp index 5a70976..5a70976 100644 --- a/perfstdin.cpp +++ b/app/perfstdin.cpp diff --git a/perfstdin.h b/app/perfstdin.h index 2633c84..2633c84 100644 --- a/perfstdin.h +++ b/app/perfstdin.h diff --git a/perfunwind.cpp b/app/perfunwind.cpp index b526f89..b79a868 100644 --- a/perfunwind.cpp +++ b/app/perfunwind.cpp @@ -21,7 +21,6 @@ #include "perfunwind.h" #include "perfregisterinfo.h" -#include <dwarf.h> #include <bfd.h> #include <QDir> diff --git a/perfunwind.h b/app/perfunwind.h index df981d0..12b627e 100644 --- a/perfunwind.h +++ b/app/perfunwind.h @@ -23,7 +23,7 @@ #include "perfdata.h" #include "perfregisterinfo.h" -#include <elfutils/libdwfl.h> +#include <libdwfl.h> #include <QFileInfo> #include <QMap> #include <QHash> diff --git a/perfparser.pro b/perfparser.pro index 4e98b45..3151a8c 100644 --- a/perfparser.pro +++ b/perfparser.pro @@ -1,38 +1,5 @@ -#------------------------------------------------- -# -# Project created by QtCreator 2014-08-14T10:44:20 -# -#------------------------------------------------- +TEMPLATE = subdirs -QT += core network +SUBDIRS = app 3rdparty/elfutils -QT -= gui - -LIBS += -ldw -lbfd - -TARGET = perfparser -CONFIG += console c++11 -CONFIG -= app_bundle - -TEMPLATE = app - - -SOURCES += main.cpp \ - perfattributes.cpp \ - perfheader.cpp \ - perffilesection.cpp \ - perffeatures.cpp \ - perfdata.cpp \ - perfunwind.cpp \ - perfregisterinfo.cpp \ - perfstdin.cpp - -HEADERS += \ - perfattributes.h \ - perfheader.h \ - perffilesection.h \ - perffeatures.h \ - perfdata.h \ - perfunwind.h \ - perfregisterinfo.h \ - perfstdin.h +app.depends = 3rdparty/elfutils |