pax_global_header00006660000000000000000000000064122701612030014504gustar00rootroot0000000000000052 comment=d59580888a06555261f3d4255d9c2cfcb408a51a abi-compliance-checker-1.99.9/000077500000000000000000000000001227016120300160625ustar00rootroot00000000000000abi-compliance-checker-1.99.9/INSTALL000066400000000000000000000056301227016120300171170ustar00rootroot00000000000000 Copyright (C) 2009-2010 The Linux Foundation Copyright (C) 2009-2011 Institute for System Programming, RAS Copyright (C) 2011-2012 Nokia Corporation and/or its subsidiary(-ies) Copyright (C) 2011-2014 ROSA Laboratory All rights reserved. RELEASE INFORMATION Project: ABI Compliance Checker (ACC) Version: 1.99.9 Date: 2014-01-23 This file explains how to install and setup environment for the tool in your computer. Content: 1. Requirements for Linux and FreeBSD 2. Requirements for Mac OS X 3. Requirements for MS Windows 4. Configuring and Installing 5. Running the Tool 6. Usage with ABI Dumper 1. REQUIREMENTS FOR LINUX AND FREEBSD ===================================== 1. G++ (3.0-4.7, 4.8.3, recommended 4.5 or newer) 2. GNU Binutils (c++filt, readelf, objdump) 3. Perl 5 (5.8 or newer) 4. Ctags (5.8 or newer) 2. REQUIREMENTS FOR MAC OS X ============================ 1. Xcode (g++, c++filt, otool, nm) 2. Ctags (5.8 or newer) 3. REQUIREMENTS FOR MS WINDOWS ============================== 1. MinGW (3.0-4.7, recommended 4.5 or newer) 2. MS Visual C++ (dumpbin, undname, cl) 3. Active Perl 5 (5.8 or newer) 4. Sigcheck v1.71 or newer 5. Info-ZIP 3.0 (zip, unzip) 6. Ctags (5.8 or newer) 3.1 Setup environment 1. Add tool locations to the PATH environment variable 2. Run vsvars32.bat script (C:\Microsoft Visual Studio 9.0\Common7\Tools\) 4. CONFIGURING AND INSTALLING ============================= This command will install an abi-compliance-checker program in the PREFIX/bin system directory and private modules into the PREFIX/share: sudo perl Makefile.pl -install --prefix=PREFIX [/usr, /usr/local, ...] 4.1 Update sudo perl Makefile.pl -update --prefix=PREFIX 4.2 Remove sudo perl Makefile.pl -remove --prefix=PREFIX 5. RUNNING THE TOOL =================== 1. Create XML-descriptors for two versions of a library (OLD.xml and NEW.xml): 1.0 /path1/to/header(s)/ /path2/to/header(s)/ ... /path1/to/library(ies)/ /path2/to/library(ies)/ ... 2. abi-compliance-checker -lib NAME -old OLD.xml -new NEW.xml 3. For advanced usage, see doc/Readme.html or --help option 6. USAGE WITH ABI DUMPER ======================== 1. Library should be compiled with -g option to contain DWARF debug info 2. Create ABI dumps for both library versions using the ABI Dumper tool (https://github.com/lvc/abi-dumper): abi-dumper OLD.so -o ABI-0.dump -lver 0 abi-dumper NEW.so -o ABI-1.dump -lver 1 3. Compare ABI dumps: abi-compliance-checker -l NAME -old ABI-0.dump -new ABI-1.dump Enjoy! abi-compliance-checker-1.99.9/LICENSE000066400000000000000000001252431227016120300170760ustar00rootroot00000000000000This program is free software. You may use, redistribute and/or modify it under the terms of either the GNU General Public License (GPL) or the GNU Lesser General Public License (LGPL). --------------------------------------------------------------------------- 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. Copyright (C) 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. , 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. --------------------------------------------------------------------------- GNU LIBRARY GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 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. [This is the first released version of the library GPL. It is numbered 2 because it goes with version 2 of the ordinary GPL.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Library General Public License, applies to some specially designated Free Software Foundation software, and to any other libraries whose authors decide to use it. You can use it for your libraries, 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 library, or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link a program with the library, you must provide complete object files to the recipients so that they can relink them with the library, after making changes to the library and recompiling it. And you must show them these terms so they know their rights. Our method of protecting your rights has two steps: (1) copyright the library, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the library. Also, for each distributor's protection, we want to make certain that everyone understands that there is no warranty for this free library. If the library is modified by someone else and passed on, we want its recipients to know that what they have is not the original version, 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 companies distributing free software will individually obtain patent licenses, thus in effect transforming the program into proprietary software. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License, which was designed for utility programs. This license, the GNU Library General Public License, applies to certain designated libraries. This license is quite different from the ordinary one; be sure to read it in full, and don't assume that anything in it is the same as in the ordinary license. The reason we have a separate public license for some libraries is that they blur the distinction we usually make between modifying or adding to a program and simply using it. Linking a program with a library, without changing the library, is in some sense simply using the library, and is analogous to running a utility program or application program. However, in a textual and legal sense, the linked executable is a combined work, a derivative of the original library, and the ordinary General Public License treats it as such. Because of this blurred distinction, using the ordinary General Public License for libraries did not effectively promote software sharing, because most developers did not use the libraries. We concluded that weaker conditions might promote sharing better. However, unrestricted linking of non-free programs would deprive the users of those programs of all benefit from the free status of the libraries themselves. This Library General Public License is intended to permit developers of non-free programs to use free libraries, while preserving your freedom as a user of such programs to change the free libraries that are incorporated in them. (We have not seen how to achieve this as regards changes in header files, but we have achieved it as regards changes in the actual functions of the Library.) The hope is that this will lead to faster development of free libraries. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, while the latter only works together with the library. Note that it is possible for a library to be covered by the ordinary General Public License rather than by this special one. GNU LIBRARY GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Library General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, 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 library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete 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 distribute a copy of this License along with the Library. 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 Library or any portion of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, 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 Library, 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 Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you 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. If distribution of 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 satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also compile or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. c) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. d) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. 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. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. 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 not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library 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. 9. 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 Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library 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. 11. 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 Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library 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 Library. 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. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library 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. 13. The Free Software Foundation may publish revised and/or new versions of the Library 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 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 Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, 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 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "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 LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. 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 LIBRARY 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 LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. 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. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free 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. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! abi-compliance-checker-1.99.9/Makefile.pl000077500000000000000000000167721227016120300201540ustar00rootroot00000000000000#!/usr/bin/perl ########################################################################### # Makefile for ABI Compliance Checker # Install/remove the tool for GNU/Linux, FreeBSD and Mac OS X # # Copyright (C) 2009-2010 The Linux Foundation # Copyright (C) 2009-2011 Institute for System Programming, RAS # Copyright (C) 2011-2012 Nokia Corporation and/or its subsidiary(-ies) # Copyright (C) 2011-2014 ROSA Laboratory # # Written by Andrey Ponomarenko # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License or the GNU Lesser # General Public License as published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # and the GNU Lesser General Public License along with this program. # If not, see . ########################################################################### use Getopt::Long; Getopt::Long::Configure ("posix_default", "no_ignore_case"); use File::Path qw(mkpath rmtree); use File::Spec qw(catfile file_name_is_absolute); use File::Copy qw(copy); use File::Basename qw(dirname); use Cwd qw(abs_path); use File::Find; use Config; use strict; my $TOOL_SNAME = "abi-compliance-checker"; my $ARCHIVE_DIR = abs_path(dirname($0)); my $HELP_MSG = " NAME: Makefile for ABI Compliance Checker DESCRIPTION: Install $TOOL_SNAME command and private modules. USAGE: sudo perl $0 -install -prefix /usr sudo perl $0 -update -prefix /usr sudo perl $0 -remove -prefix /usr OPTIONS: -h|-help Print this help. --prefix=PREFIX Install files in PREFIX [/usr/local]. -install Command to install the tool. -update Command to update existing installation. -remove Command to remove the tool. EXTRA OPTIONS: --destdir=DESTDIR This option is for maintainers to build RPM or DEB packages inside the build root. The environment variable DESTDIR is also supported. \n"; if(not @ARGV) { print $HELP_MSG; exit(0); } my ($PREFIX, $DESTDIR, $Help, $Install, $Update, $Remove); GetOptions( "h|help!" => \$Help, "prefix=s" => \$PREFIX, "destdir=s" => \$DESTDIR, "install!" => \$Install, "update!" => \$Update, "remove!" => \$Remove ) or exit(1); sub scenario() { if($Help) { print $HELP_MSG; exit(0); } if(not $Install and not $Update and not $Remove) { print STDERR "ERROR: command is not selected (-install, -update or -remove)\n"; exit(1); } if($PREFIX ne "/") { $PREFIX=~s/[\/]+\Z//g; } if(not $PREFIX) { # default prefix if($Config{"osname"}!~/win/i) { $PREFIX = "/usr/local"; } } if(my $Var = $ENV{"DESTDIR"}) { print "Using DESTDIR environment variable\n"; $DESTDIR = $Var; } if($DESTDIR) { if($DESTDIR ne "/") { $DESTDIR=~s/[\/]+\Z//g; } if(not isAbs($DESTDIR)) { print STDERR "ERROR: destdir is not absolute path\n"; exit(1); } if(not -d $DESTDIR) { print STDERR "ERROR: you should create destdir directory first\n"; exit(1); } $PREFIX = $DESTDIR.$PREFIX; if(not -d $PREFIX) { print STDERR "ERROR: you should create installation directory first (destdir + prefix):\n mkdir -p $PREFIX\n"; exit(1); } } else { if(not isAbs($PREFIX)) { print STDERR "ERROR: prefix is not absolute path\n"; exit(1); } if(not -d $PREFIX) { print STDERR "ERROR: you should create prefix directory first\n"; exit(1); } } print "INSTALL PREFIX: $PREFIX\n"; # paths my $EXE_PATH = catFile($PREFIX, "bin"); my $MODULES_PATH = catFile($PREFIX, "share", $TOOL_SNAME); my $REL_PATH = catFile("..", "share", $TOOL_SNAME); my $TOOL_PATH = catFile($EXE_PATH, $TOOL_SNAME); if(not -w $PREFIX) { print STDERR "ERROR: you should be root\n"; exit(1); } if($Remove or $Update) { if(-e $EXE_PATH."/".$TOOL_SNAME) { # remove executable print "-- Removing $TOOL_PATH\n"; unlink($EXE_PATH."/".$TOOL_SNAME); } if(-d $MODULES_PATH) { # remove modules print "-- Removing $MODULES_PATH\n"; rmtree($MODULES_PATH); } } if($Install or $Update) { if(-e $EXE_PATH."/".$TOOL_SNAME or -e $MODULES_PATH) { # check installed if(not $Remove) { print STDERR "ERROR: you should remove old version first (`perl $0 -remove --prefix=$PREFIX`)\n"; exit(1); } } # configure my $Content = readFile($ARCHIVE_DIR."/".$TOOL_SNAME.".pl"); if($DESTDIR) { # relative path $Content=~s/MODULES_INSTALL_PATH/$REL_PATH/; } else { # absolute path $Content=~s/MODULES_INSTALL_PATH/$MODULES_PATH/; } # copy executable print "-- Installing $TOOL_PATH\n"; mkpath($EXE_PATH); writeFile($EXE_PATH."/".$TOOL_SNAME, $Content); chmod(0775, $EXE_PATH."/".$TOOL_SNAME); if($Config{"osname"}=~/win/i) { writeFile($EXE_PATH."/".$TOOL_SNAME.".cmd", "\@perl \"$TOOL_PATH\" \%*"); } # copy modules if(-d $ARCHIVE_DIR."/modules") { print "-- Installing $MODULES_PATH\n"; mkpath($MODULES_PATH); copyDir($ARCHIVE_DIR."/modules", $MODULES_PATH); } # check PATH my $Warn = "WARNING: your PATH variable doesn't include \'$EXE_PATH\'\n"; if($Config{"osname"}=~/win/i) { if($ENV{"PATH"}!~/(\A|[:;])\Q$EXE_PATH\E[\/\\]?(\Z|[:;])/i) { print $Warn; } } else { if($ENV{"PATH"}!~/(\A|[:;])\Q$EXE_PATH\E[\/\\]?(\Z|[:;])/) { print $Warn; } } } exit(0); } sub catFile(@) { return File::Spec->catfile(@_); } sub isAbs($) { return File::Spec->file_name_is_absolute($_[0]); } sub copyDir($$) { my ($From, $To) = @_; my %Files; find(\&wanted, $From); sub wanted { $Files{$File::Find::dir."/$_"} = 1 if($_ ne "."); } foreach my $Path (sort keys(%Files)) { if($Config{"osname"}!~/win/ and $Path=~/Targets\/(windows|symbian)/) { next; } my $Inst = $Path; $Inst=~s/\A\Q$ARCHIVE_DIR\E/$To/; if(-d $Path) { # directories mkpath($Inst); } else { # files mkpath(dirname($Inst)); copy($Path, $Inst); } } } sub readFile($) { my $Path = $_[0]; return "" if(not $Path or not -f $Path); open(FILE, $Path) || die ("can't open file \'$Path\': $!\n"); local $/ = undef; my $Content = ; close(FILE); return $Content; } sub writeFile($$) { my ($Path, $Content) = @_; return if(not $Path); open(FILE, ">".$Path) || die ("can't open file \'$Path\': $!\n"); print FILE $Content; close(FILE); } scenario();abi-compliance-checker-1.99.9/README000066400000000000000000000020441227016120300167420ustar00rootroot00000000000000NAME: ABI Compliance Checker (ACC) - a tool for checking backward binary and source-level compatibility of a shared C/C++ library API. INSTALL: sudo perl Makefile.pl -install --prefix=/usr USAGE: abi-compliance-checker -lib NAME -old OLD.xml -new NEW.xml OLD.xml and NEW.xml are XML-descriptors: 1.0 /path/to/headers/ /path/to/libraries/ ADV. USAGE: For advanced usage, see doc/Readme.html or output of --help option. COMPATIBILITY: ABI Dumper >= 0.98 (https://github.com/lvc/abi-dumper) USAGE WITH ABI DUMPER: 1. Library should be compiled with -g option to contain DWARF debug info 2. Create ABI dumps for both library versions using the ABI Dumper (https://github.com/lvc/abi-dumper) tool: abi-dumper OLD.so -o ABI-0.dump -lver 0 abi-dumper NEW.so -o ABI-1.dump -lver 1 3. Compare ABI dumps: abi-compliance-checker -l NAME -old ABI-0.dump -new ABI-1.dumpabi-compliance-checker-1.99.9/abi-compliance-checker.pl000077500000000000000000027020231227016120300226750ustar00rootroot00000000000000#!/usr/bin/perl ########################################################################### # ABI Compliance Checker (ACC) 1.99.9 # A tool for checking backward compatibility of a C/C++ library API # # Copyright (C) 2009-2010 The Linux Foundation # Copyright (C) 2009-2011 Institute for System Programming, RAS # Copyright (C) 2011-2012 Nokia Corporation and/or its subsidiary(-ies) # Copyright (C) 2011-2014 ROSA Laboratory # # Written by Andrey Ponomarenko # # PLATFORMS # ========= # Linux, FreeBSD, Mac OS X, Haiku, MS Windows, Symbian # # REQUIREMENTS # ============ # Linux # - G++ (3.0-4.7, 4.8.3, recommended 4.5 or newer) # - GNU Binutils (readelf, c++filt, objdump) # - Perl 5 (5.8 or newer) # - Ctags (5.8 or newer) # # Mac OS X # - Xcode (g++, c++filt, otool, nm) # - Ctags (5.8 or newer) # # MS Windows # - MinGW (3.0-4.7, recommended 4.5 or newer) # - MS Visual C++ (dumpbin, undname, cl) # - Active Perl 5 (5.8 or newer) # - Sigcheck v1.71 or newer # - Info-ZIP 3.0 (zip, unzip) # - Ctags (5.8 or newer) # - Add tool locations to the PATH environment variable # - Run vsvars32.bat (C:\Microsoft Visual Studio 9.0\Common7\Tools\) # # COMPATIBILITY # ============= # ABI Dumper >= 0.98 # # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License or the GNU Lesser # General Public License as published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # and the GNU Lesser General Public License along with this program. # If not, see . ########################################################################### use Getopt::Long; Getopt::Long::Configure ("posix_default", "no_ignore_case"); use File::Path qw(mkpath rmtree); use File::Temp qw(tempdir); use File::Copy qw(copy move); use Cwd qw(abs_path cwd realpath); use Storable qw(dclone); use Data::Dumper; use Config; my $TOOL_VERSION = "1.99.9"; my $ABI_DUMP_VERSION = "3.2"; my $OLDEST_SUPPORTED_VERSION = "1.18"; my $XML_REPORT_VERSION = "1.2"; my $XML_ABI_DUMP_VERSION = "1.2"; my $OSgroup = get_OSgroup(); my $ORIG_DIR = cwd(); my $TMP_DIR = tempdir(CLEANUP=>1); # Internal modules my $MODULES_DIR = get_Modules(); push(@INC, get_dirname($MODULES_DIR)); # Rules DB my %RULES_PATH = ( "Binary" => $MODULES_DIR."/RulesBin.xml", "Source" => $MODULES_DIR."/RulesSrc.xml"); my ($Help, $ShowVersion, %Descriptor, $TargetLibraryName, $GenerateTemplate, $TestTool, $DumpAPI, $SymbolsListPath, $CheckHeadersOnly_Opt, $UseDumps, $CheckObjectsOnly_Opt, $AppPath, $StrictCompat, $DumpVersion, $ParamNamesPath, %RelativeDirectory, $TargetLibraryFName, $TestDump, $CheckImpl, $LoggingPath, %TargetVersion, $InfoMsg, $UseOldDumps, $CrossGcc, %OutputLogPath, $OutputReportPath, $OutputDumpPath, $ShowRetVal, $SystemRoot_Opt, $DumpSystem, $CmpSystems, $TargetLibsPath, $Debug, $CrossPrefix, $UseStaticLibs, $NoStdInc, $TargetComponent_Opt, $TargetSysInfo, $TargetHeader, $ExtendedCheck, $Quiet, $SkipHeadersPath, $CppCompat, $LogMode, $StdOut, $ListAffected, $ReportFormat, $UserLang, $TargetHeadersPath, $BinaryOnly, $SourceOnly, $BinaryReportPath, $SourceReportPath, $UseXML, $Browse, $OpenReport, $SortDump, $DumpFormat, $ExtraInfo, $ExtraDump, $Force, $Tolerance, $Tolerant, $SkipSymbolsListPath, $CheckInfo, $Quick, $AffectLimit, $AllAffected, $CppIncompat, $SkipInternal); my $CmdName = get_filename($0); my %OS_LibExt = ( "dynamic" => { "linux"=>"so", "macos"=>"dylib", "windows"=>"dll", "symbian"=>"dso", "default"=>"so" }, "static" => { "linux"=>"a", "windows"=>"lib", "symbian"=>"lib", "default"=>"a" } ); my %OS_Archive = ( "windows"=>"zip", "default"=>"tar.gz" ); my %ERROR_CODE = ( # Compatible verdict "Compatible"=>0, "Success"=>0, # Incompatible verdict "Incompatible"=>1, # Undifferentiated error code "Error"=>2, # System command is not found "Not_Found"=>3, # Cannot access input files "Access_Error"=>4, # Cannot compile header files "Cannot_Compile"=>5, # Header compiled with errors "Compile_Error"=>6, # Invalid input ABI dump "Invalid_Dump"=>7, # Incompatible version of ABI dump "Dump_Version"=>8, # Cannot find a module "Module_Error"=>9, # Empty intersection between # headers and shared objects "Empty_Intersection"=>10, # Empty set of symbols in headers "Empty_Set"=>11 ); my %HomePage = ( "Wiki"=>"http://ispras.linuxbase.org/index.php/ABI_compliance_checker", "Dev1"=>"https://github.com/lvc/abi-compliance-checker", "Dev2"=>"http://forge.ispras.ru/projects/abi-compliance-checker" ); my $ShortUsage = "ABI Compliance Checker (ACC) $TOOL_VERSION A tool for checking backward compatibility of a C/C++ library API Copyright (C) 2014 ROSA Laboratory License: GNU LGPL or GNU GPL Usage: $CmdName [options] Example: $CmdName -lib NAME -old OLD.xml -new NEW.xml OLD.xml and NEW.xml are XML-descriptors: 1.0 /path/to/headers/ /path/to/libraries/ More info: $CmdName --help\n"; if($#ARGV==-1) { printMsg("INFO", $ShortUsage); exit(0); } foreach (2 .. $#ARGV) { # correct comma separated options if($ARGV[$_-1] eq ",") { $ARGV[$_-2].=",".$ARGV[$_]; splice(@ARGV, $_-1, 2); } elsif($ARGV[$_-1]=~/,\Z/) { $ARGV[$_-1].=$ARGV[$_]; splice(@ARGV, $_, 1); } elsif($ARGV[$_]=~/\A,/ and $ARGV[$_] ne ",") { $ARGV[$_-1].=$ARGV[$_]; splice(@ARGV, $_, 1); } } GetOptions("h|help!" => \$Help, "i|info!" => \$InfoMsg, "v|version!" => \$ShowVersion, "dumpversion!" => \$DumpVersion, # general options "l|lib|library=s" => \$TargetLibraryName, "d1|old|o=s" => \$Descriptor{1}{"Path"}, "d2|new|n=s" => \$Descriptor{2}{"Path"}, "dump|dump-abi|dump_abi=s" => \$DumpAPI, "old-dumps!" => \$UseOldDumps, # extra options "d|descriptor-template!" => \$GenerateTemplate, "app|application=s" => \$AppPath, "static-libs!" => \$UseStaticLibs, "cross-gcc|gcc-path=s" => \$CrossGcc, "cross-prefix|gcc-prefix=s" => \$CrossPrefix, "sysroot=s" => \$SystemRoot_Opt, "v1|version1|vnum=s" => \$TargetVersion{1}, "v2|version2=s" => \$TargetVersion{2}, "s|strict!" => \$StrictCompat, "symbols-list=s" => \$SymbolsListPath, "skip-symbols=s" => \$SkipSymbolsListPath, "headers-list=s" => \$TargetHeadersPath, "skip-headers=s" => \$SkipHeadersPath, "header=s" => \$TargetHeader, "headers-only|headers_only!" => \$CheckHeadersOnly_Opt, "objects-only!" => \$CheckObjectsOnly_Opt, "check-impl|check-implementation!" => \$CheckImpl, "show-retval!" => \$ShowRetVal, "use-dumps!" => \$UseDumps, "nostdinc!" => \$NoStdInc, "dump-system=s" => \$DumpSystem, "sysinfo=s" => \$TargetSysInfo, "cmp-systems!" => \$CmpSystems, "libs-list=s" => \$TargetLibsPath, "ext|extended!" => \$ExtendedCheck, "q|quiet!" => \$Quiet, "stdout!" => \$StdOut, "report-format=s" => \$ReportFormat, "dump-format=s" => \$DumpFormat, "xml!" => \$UseXML, "lang=s" => \$UserLang, "binary|bin|abi!" => \$BinaryOnly, "source|src|api!" => \$SourceOnly, "limit-affected|affected-limit=s" => \$AffectLimit, # other options "test!" => \$TestTool, "test-dump!" => \$TestDump, "debug!" => \$Debug, "cpp-compatible!" => \$CppCompat, "cpp-incompatible!" => \$CppIncompat, "p|params=s" => \$ParamNamesPath, "relpath1|relpath=s" => \$RelativeDirectory{1}, "relpath2=s" => \$RelativeDirectory{2}, "dump-path=s" => \$OutputDumpPath, "sort!" => \$SortDump, "report-path=s" => \$OutputReportPath, "bin-report-path=s" => \$BinaryReportPath, "src-report-path=s" => \$SourceReportPath, "log-path=s" => \$LoggingPath, "log1-path=s" => \$OutputLogPath{1}, "log2-path=s" => \$OutputLogPath{2}, "logging-mode=s" => \$LogMode, "list-affected!" => \$ListAffected, "l-full|lib-full=s" => \$TargetLibraryFName, "component=s" => \$TargetComponent_Opt, "b|browse=s" => \$Browse, "open!" => \$OpenReport, "extra-info=s" => \$ExtraInfo, "extra-dump!" => \$ExtraDump, "force!" => \$Force, "tolerance=s" => \$Tolerance, "tolerant!" => \$Tolerant, "check!" => \$CheckInfo, "quick!" => \$Quick, "all-affected!" => \$AllAffected, "skip-internal=s" => \$SkipInternal ) or ERR_MESSAGE(); sub ERR_MESSAGE() { printMsg("INFO", "\n".$ShortUsage); exit($ERROR_CODE{"Error"}); } my $LIB_TYPE = $UseStaticLibs?"static":"dynamic"; my $SLIB_TYPE = $LIB_TYPE; if($OSgroup!~/macos|windows/ and $SLIB_TYPE eq "dynamic") { # show as "shared" library $SLIB_TYPE = "shared"; } my $LIB_EXT = getLIB_EXT($OSgroup); my $AR_EXT = getAR_EXT($OSgroup); my $BYTE_SIZE = 8; my $COMMON_LOG_PATH = "logs/run.log"; my $HelpMessage=" NAME: ABI Compliance Checker ($CmdName) Check backward compatibility of a C/C++ library API DESCRIPTION: ABI Compliance Checker (ACC) is a tool for checking backward binary and source-level compatibility of a $SLIB_TYPE C/C++ library. The tool checks header files and $SLIB_TYPE libraries (*.$LIB_EXT) of old and new versions and analyzes changes in API and ABI (ABI=API+compiler ABI) that may break binary and/or source-level compatibility: changes in calling stack, v-table changes, removed symbols, renamed fields, etc. Binary incompatibility may result in crashing or incorrect behavior of applications built with an old version of a library if they run on a new one. Source incompatibility may result in recompilation errors with a new library version. The tool is intended for developers of software libraries and maintainers of operating systems who are interested in ensuring backward compatibility, i.e. allow old applications to run or to be recompiled with newer library versions. Also the tool can be used by ISVs for checking applications portability to new library versions. Found issues can be taken into account when adapting the application to a new library version. This tool is free software: you can redistribute it and/or modify it under the terms of the GNU LGPL or GNU GPL. USAGE: $CmdName [options] EXAMPLE: $CmdName -lib NAME -old OLD.xml -new NEW.xml OLD.xml and NEW.xml are XML-descriptors: 1.0 /path1/to/header(s)/ /path2/to/header(s)/ ... /path1/to/library(ies)/ /path2/to/library(ies)/ ... INFORMATION OPTIONS: -h|-help Print this help. -i|-info Print complete info. -v|-version Print version information. -dumpversion Print the tool version ($TOOL_VERSION) and don't do anything else. GENERAL OPTIONS: -l|-lib|-library NAME Library name (without version). -d1|-old|-o PATH Descriptor of 1st (old) library version. It may be one of the following: 1. XML-descriptor (VERSION.xml file): 1.0 /path1/to/header(s)/ /path2/to/header(s)/ ... /path1/to/library(ies)/ /path2/to/library(ies)/ ... ... (XML-descriptor template can be generated by -d option) 2. ABI dump generated by -dump option 3. Directory with headers and/or $SLIB_TYPE libraries 4. Single header file 5. Single $SLIB_TYPE library 6. Comma separated list of headers and/or libraries If you are using an 2-6 descriptor types then you should specify version numbers with -v1 and -v2 options too. For more information, please see: http://ispras.linuxbase.org/index.php/Library_Descriptor -d2|-new|-n PATH Descriptor of 2nd (new) library version. -dump|-dump-abi PATH Create library ABI dump for the input XML descriptor. You can transfer it anywhere and pass instead of the descriptor. Also it can be used for debugging the tool. Supported ABI dump versions: 2.0<=V<=$ABI_DUMP_VERSION -old-dumps Enable support for old-version ABI dumps ($OLDEST_SUPPORTED_VERSION<=V<2.0).\n"; sub HELP_MESSAGE() { printMsg("INFO", $HelpMessage." MORE INFO: $CmdName --info\n"); } sub INFO_MESSAGE() { printMsg("INFO", "$HelpMessage EXTRA OPTIONS: -d|-descriptor-template Create XML-descriptor template ./VERSION.xml -app|-application PATH This option allows one to specify the application that should be checked for portability to the new library version. -static-libs Check static libraries instead of the shared ones. The section of the XML-descriptor should point to static libraries location. -cross-gcc|-gcc-path PATH Path to the cross GCC compiler to use instead of the usual (host) GCC. -cross-prefix|-gcc-prefix PREFIX GCC toolchain prefix. -sysroot DIR Specify the alternative root directory. The tool will search for include paths in the DIR/usr/include and DIR/usr/lib directories. -v1|-version1 NUM Specify 1st library version outside the descriptor. This option is needed if you have preferred an alternative descriptor type (see -d1 option). In general case you should specify it in the XML-descriptor: VERSION -v2|-version2 NUM Specify 2nd library version outside the descriptor. -s|-strict Treat all compatibility warnings as problems. Add a number of \"Low\" severity problems to the return value of the tool. -headers-only Check header files without $SLIB_TYPE libraries. It is easy to run, but may provide a low quality compatibility report with false positives and without detecting of added/removed symbols. Alternatively you can write \"none\" word to the section in the XML-descriptor: none -objects-only Check $SLIB_TYPE libraries without header files. It is easy to run, but may provide a low quality compatibility report with false positives and without analysis of changes in parameters and data types. Alternatively you can write \"none\" word to the section in the XML-descriptor: none -check-impl|-check-implementation Compare canonified disassembled binary code of $SLIB_TYPE libraries to detect changes in the implementation. Add \'Problems with Implementation\' section to the report. -show-retval Show the symbol's return type in the report. -symbols-list PATH This option allows one to specify a file with a list of symbols (mangled names in C++) that should be checked, other symbols will not be checked. -skip-symbols PATH The list of symbols that should NOT be checked. -headers-list PATH The file with a list of headers, that should be checked/dumped. -skip-headers PATH The file with the list of header files, that should not be checked. -header NAME Check/Dump ABI of this header only. -use-dumps Make dumps for two versions of a library and compare dumps. This should increase the performance of the tool and decrease the system memory usage. -nostdinc Do not search in GCC standard system directories for header files. -dump-system NAME -sysroot DIR Find all the shared libraries and header files in DIR directory, create XML descriptors and make ABI dumps for each library. The result set of ABI dumps can be compared (--cmp-systems) with the other one created for other version of operating system in order to check them for compatibility. Do not forget to specify -cross-gcc option if your target system requires some specific version of GCC compiler (different from the host GCC). The system ABI dump will be generated to: sys_dumps/NAME/ARCH -dump-system DESCRIPTOR.xml The same as the previous option but takes an XML descriptor of the target system as input, where you should describe it: /* Primary sections */ /* Name of the system */ /* The list of paths to header files and/or directories with header files, one per line */ /* The list of paths to shared libraries and/or directories with shared libraries, one per line */ /* Optional sections */ /* List of directories to be searched for header files to automatically generate include paths, one per line */ /* List of directories to be searched for shared libraries to resolve dependencies, one per line */ /* List of directories with tools used for analysis (GCC toolchain), one per line */ /* GCC toolchain prefix. Examples: arm-linux-gnueabi arm-none-symbianelf */ /* Additional GCC options, one per line */ -sysinfo DIR This option may be used with -dump-system to dump ABI of operating systems and configure the dumping process. Default: modules/Targets/{unix, symbian, windows} -cmp-systems -d1 sys_dumps/NAME1/ARCH -d2 sys_dumps/NAME2/ARCH Compare two system ABI dumps. Create compatibility reports for each library and the common HTML report including the summary of test results for all checked libraries. Report will be generated to: sys_compat_reports/NAME1_to_NAME2/ARCH -libs-list PATH The file with a list of libraries, that should be dumped by the -dump-system option or should be checked by the -cmp-systems option. -ext|-extended If your library A is supposed to be used by other library B and you want to control the ABI of B, then you should enable this option. The tool will check for changes in all data types, even if they are not used by any function in the library A. Such data types are not part of the A library ABI, but may be a part of the ABI of the B library. The short scheme is: app C (broken) -> lib B (broken ABI) -> lib A (stable ABI) -q|-quiet Print all messages to the file instead of stdout and stderr. Default path (can be changed by -log-path option): $COMMON_LOG_PATH -stdout Print analysis results (compatibility reports and ABI dumps) to stdout instead of creating a file. This would allow piping data to other programs. -report-format FMT Change format of compatibility report. Formats: htm - HTML format (default) xml - XML format -dump-format FMT Change format of ABI dump. Formats: perl - Data::Dumper format (default) xml - XML format -xml Alias for: --report-format=xml or --dump-format=xml -lang LANG Set library language (C or C++). You can use this option if the tool cannot auto-detect a language. This option may be useful for checking C-library headers (--lang=C) in --headers-only or --extended modes. -binary|-bin|-abi Show \"Binary\" compatibility problems only. Generate report to: compat_reports/LIB_NAME/V1_to_V2/abi_compat_report.html -source|-src|-api Show \"Source\" compatibility problems only. Generate report to: compat_reports/LIB_NAME/V1_to_V2/src_compat_report.html -limit-affected LIMIT The maximum number of affected symbols listed under the description of the changed type in the report. OTHER OPTIONS: -test Run internal tests. Create two binary incompatible versions of a sample library and run the tool to check them for compatibility. This option allows one to check if the tool works correctly in the current environment. -test-dump Test ability to create, read and compare ABI dumps. -debug Debugging mode. Print debug info on the screen. Save intermediate analysis stages in the debug directory: debug/LIB_NAME/VERSION/ Also consider using --dump option for debugging the tool. -cpp-compatible If your header files are written in C language and can be compiled by the G++ compiler (i.e. don't use C++ keywords), then you can tell the tool about this and speedup the analysis. -cpp-incompatible Set this option if input C header files use C++ keywords. -p|-params PATH Path to file with the function parameter names. It can be used for improving report view if the library header files have no parameter names. File format: func1;param1;param2;param3 ... func2;param1;param2;param3 ... ... -relpath PATH Replace {RELPATH} macros to PATH in the XML-descriptor used for dumping the library ABI (see -dump option). -relpath1 PATH Replace {RELPATH} macros to PATH in the 1st XML-descriptor (-d1). -relpath2 PATH Replace {RELPATH} macros to PATH in the 2nd XML-descriptor (-d2). -dump-path PATH Specify a *.abi.$AR_EXT or *.abi file path where to generate an ABI dump. Default: abi_dumps/LIB_NAME/LIB_NAME_VERSION.abi.$AR_EXT -sort Enable sorting of data in ABI dumps. -report-path PATH Path to compatibility report. Default: compat_reports/LIB_NAME/V1_to_V2/compat_report.html -bin-report-path PATH Path to \"Binary\" compatibility report. Default: compat_reports/LIB_NAME/V1_to_V2/abi_compat_report.html -src-report-path PATH Path to \"Source\" compatibility report. Default: compat_reports/LIB_NAME/V1_to_V2/src_compat_report.html -log-path PATH Log path for all messages. Default: logs/LIB_NAME/VERSION/log.txt -log1-path PATH Log path for 1st version of a library. Default: logs/LIB_NAME/V1/log.txt -log2-path PATH Log path for 2nd version of a library. Default: logs/LIB_NAME/V2/log.txt -logging-mode MODE Change logging mode. Modes: w - overwrite old logs (default) a - append old logs n - do not write any logs -list-affected Generate file with the list of incompatible symbols beside the HTML compatibility report. Use 'c++filt \@file' command from GNU binutils to unmangle C++ symbols in the generated file. Default names: abi_affected.txt src_affected.txt -component NAME The component name in the title and summary of the HTML report. Default: library -l-full|-lib-full NAME Change library name in the report title to NAME. By default will be displayed a name specified by -l option. -b|-browse PROGRAM Open report(s) in the browser (firefox, opera, etc.). -open Open report(s) in the default browser. -extra-info DIR Dump extra info to DIR. -extra-dump Create extended ABI dump containing all symbols from the translation unit. -force Try to use this option if the tool doesn't work. -tolerance LEVEL Apply a set of heuristics to successfully compile input header files. You can enable several tolerance levels by joining them into one string (e.g. 13, 124, etc.). Levels: 1 - skip non-Linux headers (e.g. win32_*.h, etc.) 2 - skip internal headers (e.g. *_p.h, impl/*.h, etc.) 3 - skip headers that iclude non-Linux headers 4 - skip headers included by others -tolerant Enable highest tolerance level [1234]. -check Check completeness of the ABI dump. -quick Quick analysis. Disable check of some template instances. -skip-internal PATTERN Do not check internal interfaces matched by the pattern. REPORT: Compatibility report will be generated to: compat_reports/LIB_NAME/V1_to_V2/compat_report.html Log will be generated to: logs/LIB_NAME/V1/log.txt logs/LIB_NAME/V2/log.txt EXIT CODES: 0 - Compatible. The tool has run without any errors. non-zero - Incompatible or the tool has run with errors. REPORT BUGS TO: Andrey Ponomarenko MORE INFORMATION: ".$HomePage{"Wiki"}." ".$HomePage{"Dev1"}."\n"); } my $DescriptorTemplate = " /* Primary sections */ /* Version of the library */ /* The list of paths to header files and/or directories with header files, one per line */ /* The list of paths to shared libraries (*.$LIB_EXT) and/or directories with shared libraries, one per line */ /* Optional sections */ /* The list of include paths that will be provided to GCC to compile library headers, one per line. NOTE: If you define this section then the tool will not automatically generate include paths */ /* The list of include paths that will be added to the automatically generated include paths, one per line */ /* The list of include paths that will be removed from the list of automatically generated include paths, one per line */ /* Additional GCC options, one per line */ /* The list of header files that will be included before other headers, one per line */ /* The list of defines that will be added at the headers compiling stage, one per line: #define A B #define C D */ /* The list of namespaces that should be added to the alanysis if the tool cannot find them automatically, one per line */ /* The list of data types, that should not be checked, one per line */ /* The list of functions (mangled/symbol names in C++), that should not be checked, one per line */ /* The list of C++ namespaces, that should not be checked, one per line */ /* The list of constants that should not be checked, one name per line */ /* The list of header files and/or directories with header files that should not be checked, one per line */ /* The list of shared libraries and/or directories with shared libraries that should not be checked, one per line */ /* The list of header files, that cannot be included directly (or non-self compiled ones), one per line */ /* List of directories to be searched for header files to automatically generate include paths, one per line. */ /* List of directories to be searched for shared librariess to resolve dependencies, one per line */ /* List of directories with tools used for analysis (GCC toolchain), one per line */ /* GCC toolchain prefix. Examples: arm-linux-gnueabi arm-none-symbianelf */ "; my %Operator_Indication = ( "not" => "~", "assign" => "=", "andassign" => "&=", "orassign" => "|=", "xorassign" => "^=", "or" => "|", "xor" => "^", "addr" => "&", "and" => "&", "lnot" => "!", "eq" => "==", "ne" => "!=", "lt" => "<", "lshift" => "<<", "lshiftassign" => "<<=", "rshiftassign" => ">>=", "call" => "()", "mod" => "%", "modassign" => "%=", "subs" => "[]", "land" => "&&", "lor" => "||", "rshift" => ">>", "ref" => "->", "le" => "<=", "deref" => "*", "mult" => "*", "preinc" => "++", "delete" => " delete", "vecnew" => " new[]", "vecdelete" => " delete[]", "predec" => "--", "postinc" => "++", "postdec" => "--", "plusassign" => "+=", "plus" => "+", "minus" => "-", "minusassign" => "-=", "gt" => ">", "ge" => ">=", "new" => " new", "multassign" => "*=", "divassign" => "/=", "div" => "/", "neg" => "-", "pos" => "+", "memref" => "->*", "compound" => "," ); my %UnknownOperator; my %NodeType= ( "array_type" => "Array", "binfo" => "Other", "boolean_type" => "Intrinsic", "complex_type" => "Intrinsic", "const_decl" => "Other", "enumeral_type" => "Enum", "field_decl" => "Other", "function_decl" => "Other", "function_type" => "FunctionType", "identifier_node" => "Other", "integer_cst" => "Other", "integer_type" => "Intrinsic", "vector_type" => "Vector", "method_type" => "MethodType", "namespace_decl" => "Other", "parm_decl" => "Other", "pointer_type" => "Pointer", "real_cst" => "Other", "real_type" => "Intrinsic", "record_type" => "Struct", "reference_type" => "Ref", "string_cst" => "Other", "template_decl" => "Other", "template_type_parm" => "TemplateParam", "typename_type" => "TypeName", "sizeof_expr" => "SizeOf", "tree_list" => "Other", "tree_vec" => "Other", "type_decl" => "Other", "union_type" => "Union", "var_decl" => "Other", "void_type" => "Intrinsic", "nop_expr" => "Other", # "addr_expr" => "Other", # "offset_type" => "Other" ); my %CppKeywords_C = map {$_=>1} ( # C++ 2003 keywords "public", "protected", "private", "default", "template", "new", #"asm", "dynamic_cast", "auto", "try", "namespace", "typename", "using", "reinterpret_cast", "friend", "class", "virtual", "const_cast", "mutable", "static_cast", "export", # C++0x keywords "noexcept", "nullptr", "constexpr", "static_assert", "explicit", # cannot be used as a macro name # as it is an operator in C++ "and", #"and_eq", "not", #"not_eq", "or" #"or_eq", #"bitand", #"bitor", #"xor", #"xor_eq", #"compl" ); my %CppKeywords_F = map {$_=>1} ( "delete", "catch", "alignof", "thread_local", "decltype", "typeid" ); my %CppKeywords_O = map {$_=>1} ( "bool", "register", "inline", "operator" ); my %CppKeywords_A = map {$_=>1} ( "this", "throw", "template" ); foreach (keys(%CppKeywords_C), keys(%CppKeywords_F), keys(%CppKeywords_O)) { $CppKeywords_A{$_}=1; } # Header file extensions as described by gcc my $HEADER_EXT = "h|hh|hp|hxx|hpp|h\\+\\+"; my %IntrinsicMangling = ( "void" => "v", "bool" => "b", "wchar_t" => "w", "char" => "c", "signed char" => "a", "unsigned char" => "h", "short" => "s", "unsigned short" => "t", "int" => "i", "unsigned int" => "j", "long" => "l", "unsigned long" => "m", "long long" => "x", "__int64" => "x", "unsigned long long" => "y", "__int128" => "n", "unsigned __int128" => "o", "float" => "f", "double" => "d", "long double" => "e", "__float80" => "e", "__float128" => "g", "..." => "z" ); my %IntrinsicNames = map {$_=>1} keys(%IntrinsicMangling); my %StdcxxMangling = ( "3std"=>"St", "3std9allocator"=>"Sa", "3std12basic_string"=>"Sb", "3std12basic_stringIcE"=>"Ss", "3std13basic_istreamIcE"=>"Si", "3std13basic_ostreamIcE"=>"So", "3std14basic_iostreamIcE"=>"Sd" ); my $DEFAULT_STD_PARMS = "std::(allocator|less|char_traits|regex_traits|istreambuf_iterator|ostreambuf_iterator)"; my %DEFAULT_STD_ARGS = map {$_=>1} ("_Alloc", "_Compare", "_Traits", "_Rx_traits", "_InIter", "_OutIter"); my $ADD_TMPL_INSTANCES = 1; my $EMERGENCY_MODE_48 = 0; my %ConstantSuffix = ( "unsigned int"=>"u", "long"=>"l", "unsigned long"=>"ul", "long long"=>"ll", "unsigned long long"=>"ull" ); my %ConstantSuffixR = reverse(%ConstantSuffix); my %OperatorMangling = ( "~" => "co", "=" => "aS", "|" => "or", "^" => "eo", "&" => "an",#ad (addr) "==" => "eq", "!" => "nt", "!=" => "ne", "<" => "lt", "<=" => "le", "<<" => "ls", "<<=" => "lS", ">" => "gt", ">=" => "ge", ">>" => "rs", ">>=" => "rS", "()" => "cl", "%" => "rm", "[]" => "ix", "&&" => "aa", "||" => "oo", "*" => "ml",#de (deref) "++" => "pp",# "--" => "mm",# "new" => "nw", "delete" => "dl", "new[]" => "na", "delete[]" => "da", "+=" => "pL", "+" => "pl",#ps (pos) "-" => "mi",#ng (neg) "-=" => "mI", "*=" => "mL", "/=" => "dV", "&=" => "aN", "|=" => "oR", "%=" => "rM", "^=" => "eO", "/" => "dv", "->*" => "pm", "->" => "pt",#rf (ref) "," => "cm", "?" => "qu", "." => "dt", "sizeof"=> "sz"#st ); my %Intrinsic_Keywords = map {$_=>1} ( "true", "false", "_Bool", "_Complex", "const", "int", "long", "void", "short", "float", "volatile", "restrict", "unsigned", "signed", "char", "double", "class", "struct", "union", "enum" ); my %GlibcHeader = map {$_=>1} ( "aliases.h", "argp.h", "argz.h", "assert.h", "cpio.h", "ctype.h", "dirent.h", "envz.h", "errno.h", "error.h", "execinfo.h", "fcntl.h", "fstab.h", "ftw.h", "glob.h", "grp.h", "iconv.h", "ifaddrs.h", "inttypes.h", "langinfo.h", "limits.h", "link.h", "locale.h", "malloc.h", "math.h", "mntent.h", "monetary.h", "nl_types.h", "obstack.h", "printf.h", "pwd.h", "regex.h", "sched.h", "search.h", "setjmp.h", "shadow.h", "signal.h", "spawn.h", "stdarg.h", "stdint.h", "stdio.h", "stdlib.h", "string.h", "strings.h", "tar.h", "termios.h", "time.h", "ulimit.h", "unistd.h", "utime.h", "wchar.h", "wctype.h", "wordexp.h" ); my %GlibcDir = map {$_=>1} ( "arpa", "bits", "gnu", "netinet", "net", "nfs", "rpc", "sys", "linux" ); my %WinHeaders = map {$_=>1} ( "dos.h", "process.h", "winsock.h", "config-win.h", "mem.h", "windows.h", "winsock2.h", "crtdbg.h", "ws2tcpip.h" ); my %ObsoleteHeaders = map {$_=>1} ( "iostream.h", "fstream.h" ); my %AlienHeaders = map {$_=>1} ( # Solaris "thread.h", "sys/atomic.h", # HPUX "sys/stream.h", # Symbian "AknDoc.h", # Atari ST "ext.h", "tos.h", # MS-DOS "alloc.h", # Sparc "sys/atomic.h" ); my %ConfHeaders = map {$_=>1} ( "atomic", "conf.h", "config.h", "configure.h", "build.h", "setup.h" ); my %LocalIncludes = map {$_=>1} ( "/usr/local/include", "/usr/local" ); my %OS_AddPath=( # These paths are needed if the tool cannot detect them automatically "macos"=>{ "include"=>[ "/Library", "/Developer/usr/include" ], "lib"=>[ "/Library", "/Developer/usr/lib" ], "bin"=>[ "/Developer/usr/bin" ] }, "beos"=>{ # Haiku has GCC 2.95.3 by default # try to find GCC>=3.0 in /boot/develop/abi "include"=>[ "/boot/common", "/boot/develop" ], "lib"=>[ "/boot/common/lib", "/boot/system/lib", "/boot/apps" ], "bin"=>[ "/boot/common/bin", "/boot/system/bin", "/boot/develop/abi" ] } ); my %Slash_Type=( "default"=>"/", "windows"=>"\\" ); my $SLASH = $Slash_Type{$OSgroup}?$Slash_Type{$OSgroup}:$Slash_Type{"default"}; # Global Variables my %COMMON_LANGUAGE=( 1 => "C", 2 => "C" ); my $MAX_COMMAND_LINE_ARGUMENTS = 4096; my $MAX_CPPFILT_FILE_SIZE = 50000; my $CPPFILT_SUPPORT_FILE; my (%WORD_SIZE, %CPU_ARCH, %GCC_VERSION); my $STDCXX_TESTING = 0; my $GLIBC_TESTING = 0; my $CPP_HEADERS = 0; my $CheckHeadersOnly = $CheckHeadersOnly_Opt; my $CheckObjectsOnly = $CheckObjectsOnly_Opt; my $TargetComponent; my $CheckUndefined = 0; # Set Target Component Name if($TargetComponent_Opt) { $TargetComponent = lc($TargetComponent_Opt); } else { # default: library # other components: header, system, ... $TargetComponent = "library"; } my $TOP_REF = "to the top"; my $SystemRoot; my $MAIN_CPP_DIR; my %RESULT; my %LOG_PATH; my %DEBUG_PATH; my %Cache; my %LibInfo; my $COMPILE_ERRORS = 0; my %CompilerOptions; my %CheckedDyLib; my $TargetLibraryShortName = parse_libname($TargetLibraryName, "shortest", $OSgroup); # Constants (#defines) my %Constants; my %SkipConstants; my %EnumConstants; # Extra Info my %SymbolHeader; my %KnownLibs; # Templates my %TemplateInstance; my %BasicTemplate; my %TemplateArg; my %TemplateDecl; my %TemplateMap; # Types my %TypeInfo; my %SkipTypes = ( "1"=>{}, "2"=>{} ); my %CheckedTypes; my %TName_Tid; my %EnumMembName_Id; my %NestedNameSpaces = ( "1"=>{}, "2"=>{} ); my %VirtualTable; my %VirtualTable_Model; my %ClassVTable; my %ClassVTable_Content; my %VTableClass; my %AllocableClass; my %ClassMethods; my %ClassNames; my %Class_SubClasses; my %OverriddenMethods; my %TypedefToAnon; my $MAX_ID = 0; my %CheckedTypeInfo; # Typedefs my %Typedef_BaseName; my %Typedef_Tr; my %Typedef_Eq; my %StdCxxTypedef; my %MissedTypedef; my %MissedBase; my %MissedBase_R; my %TypeTypedef; # Symbols my %SymbolInfo; my %tr_name; my %mangled_name_gcc; my %mangled_name; my %SkipSymbols = ( "1"=>{}, "2"=>{} ); my %SkipNameSpaces = ( "1"=>{}, "2"=>{} ); my %AddNameSpaces = ( "1"=>{}, "2"=>{} ); my %SymbolsList; my %SkipSymbolsList; my %SymbolsList_App; my %CheckedSymbols; my %Symbol_Library = ( "1"=>{}, "2"=>{} ); my %Library_Symbol = ( "1"=>{}, "2"=>{} ); my %DepSymbol_Library = ( "1"=>{}, "2"=>{} ); my %DepLibrary_Symbol = ( "1"=>{}, "2"=>{} ); my %MangledNames; my %Func_ShortName; my %AddIntParams; my %Interface_Impl; my %GlobalDataObject; my %WeakSymbols; my %Library_Needed= ( "1"=>{}, "2"=>{} ); # Extra Info my %UndefinedSymbols; my %PreprocessedHeaders; # Headers my %Include_Preamble = ( "1"=>[], "2"=>[] ); my %Registered_Headers; my %Registered_Sources; my %HeaderName_Paths; my %Header_Dependency; my %Include_Neighbors; my %Include_Paths = ( "1"=>[], "2"=>[] ); my %INC_PATH_AUTODETECT = ( "1"=>1, "2"=>1 ); my %Add_Include_Paths = ( "1"=>[], "2"=>[] ); my %Skip_Include_Paths; my %RegisteredDirs; my %Header_ErrorRedirect; my %Header_Includes; my %Header_Includes_R; my %Header_ShouldNotBeUsed; my %RecursiveIncludes; my %Header_Include_Prefix; my %SkipHeaders; my %SkipHeadersList=( "1"=>{}, "2"=>{} ); my %SkipLibs; my %Include_Order; my %TUnit_NameSpaces; my %TUnit_Classes; my %TUnit_Funcs; my %TUnit_Vars; my %CppMode = ( "1"=>0, "2"=>0 ); my %AutoPreambleMode = ( "1"=>0, "2"=>0 ); my %MinGWMode = ( "1"=>0, "2"=>0 ); my %Cpp0xMode = ( "1"=>0, "2"=>0 ); # Shared Objects my %RegisteredObjects; my %RegisteredObjects_Short; my %RegisteredSONAMEs; my %RegisteredObject_Dirs; # System Objects my %SystemObjects; my @DefaultLibPaths; my %DyLib_DefaultPath; # System Headers my %SystemHeaders; my @DefaultCppPaths; my @DefaultGccPaths; my @DefaultIncPaths; my %DefaultCppHeader; my %DefaultGccHeader; my @UsersIncPath; # Merging my %CompleteSignature; my $Version; my %AddedInt; my %RemovedInt; my %AddedInt_Virt; my %RemovedInt_Virt; my %VirtualReplacement; my %ChangedTypedef; my %CompatRules; my %IncompleteRules; my %UnknownRules; my %VTableChanged_M; my %ExtendedSymbols; my %ReturnedClass; my %ParamClass; my %SourceAlternative; my %SourceAlternative_B; my %SourceReplacement; my $CurrentSymbol; # for debugging # Calling Conventions my %UseConv_Real = ( 1=>{ "R"=>0, "P"=>0 }, 2=>{ "R"=>0, "P"=>0 } ); # ABI Dump my %UsedDump; # OS Compliance my %TargetLibs; my %TargetHeaders; # OS Specifics my $OStarget = $OSgroup; my %TargetTools; # Compliance Report my %Type_MaxSeverity; # Recursion locks my @RecurLib; my @RecurTypes; my @RecurTypes_Diff; my @RecurInclude; my @RecurConstant; # System my %SystemPaths = ( "include"=>[], "lib"=>[], "bin"=>[] ); my @DefaultBinPaths; my $GCC_PATH; # Symbols versioning my %SymVer = ( "1"=>{}, "2"=>{} ); # Problem descriptions my %CompatProblems; my %CompatProblems_Constants; my %CompatProblems_Impl; my %TotalAffected; # Reports my $ContentID = 1; my $ContentSpanStart = "\n"; my $ContentSpanStart_Affected = "\n"; my $ContentSpanStart_Info = "\n"; my $ContentSpanEnd = "\n"; my $ContentDivStart = "
\n"; my $ContentDivEnd = "
\n"; my $Content_Counter = 0; # Modes my $JoinReport = 1; my $DoubleReport = 0; my %Severity_Val=( "High"=>3, "Medium"=>2, "Low"=>1, "Safe"=>-1 ); sub get_Modules() { my $TOOL_DIR = get_dirname($0); if(not $TOOL_DIR) { # patch for MS Windows $TOOL_DIR = "."; } my @SEARCH_DIRS = ( # tool's directory abs_path($TOOL_DIR), # relative path to modules abs_path($TOOL_DIR)."/../share/abi-compliance-checker", # install path 'MODULES_INSTALL_PATH' ); foreach my $DIR (@SEARCH_DIRS) { if(not is_abs($DIR)) { # relative path $DIR = abs_path($TOOL_DIR)."/".$DIR; } if(-d $DIR."/modules") { return $DIR."/modules"; } } exitStatus("Module_Error", "can't find modules"); } my %LoadedModules = (); sub loadModule($) { my $Name = $_[0]; if(defined $LoadedModules{$Name}) { return; } my $Path = $MODULES_DIR."/Internals/$Name.pm"; if(not -f $Path) { exitStatus("Module_Error", "can't access \'$Path\'"); } require $Path; $LoadedModules{$Name} = 1; } sub readModule($$) { my ($Module, $Name) = @_; my $Path = $MODULES_DIR."/Internals/$Module/".$Name; if(not -f $Path) { exitStatus("Module_Error", "can't access \'$Path\'"); } return readFile($Path); } sub showPos($) { my $Number = $_[0]; if(not $Number) { $Number = 1; } else { $Number = int($Number)+1; } if($Number>3) { return $Number."th"; } elsif($Number==1) { return "1st"; } elsif($Number==2) { return "2nd"; } elsif($Number==3) { return "3rd"; } else { return $Number; } } sub search_Tools($) { my $Name = $_[0]; return "" if(not $Name); if(my @Paths = keys(%TargetTools)) { foreach my $Path (@Paths) { if(-f join_P($Path, $Name)) { return join_P($Path, $Name); } if($CrossPrefix) { # user-defined prefix (arm-none-symbianelf, ...) my $Candidate = join_P($Path, $CrossPrefix."-".$Name); if(-f $Candidate) { return $Candidate; } } } } else { return ""; } } sub synch_Cmd($) { my $Name = $_[0]; if(not $GCC_PATH) { # GCC was not found yet return ""; } my $Candidate = $GCC_PATH; if($Candidate=~s/\bgcc(|\.\w+)\Z/$Name$1/) { return $Candidate; } return ""; } sub get_CmdPath($) { my $Name = $_[0]; return "" if(not $Name); if(defined $Cache{"get_CmdPath"}{$Name}) { return $Cache{"get_CmdPath"}{$Name}; } my %BinUtils = map {$_=>1} ( "c++filt", "objdump", "readelf" ); if($BinUtils{$Name} and $GCC_PATH) { if(my $Dir = get_dirname($GCC_PATH)) { $TargetTools{$Dir}=1; } } my $Path = search_Tools($Name); if(not $Path and $OSgroup eq "windows") { $Path = search_Tools($Name.".exe"); } if(not $Path and $BinUtils{$Name}) { if($CrossPrefix) { # user-defined prefix $Path = search_Cmd($CrossPrefix."-".$Name); } } if(not $Path and $BinUtils{$Name}) { if(my $Candidate = synch_Cmd($Name)) { # synch with GCC if($Candidate=~/[\/\\]/) { # command path if(-f $Candidate) { $Path = $Candidate; } } elsif($Candidate = search_Cmd($Candidate)) { # command name $Path = $Candidate; } } } if(not $Path) { $Path = search_Cmd($Name); } if(not $Path and $OSgroup eq "windows") { # search for *.exe file $Path=search_Cmd($Name.".exe"); } if($Path=~/\s/) { $Path = "\"".$Path."\""; } return ($Cache{"get_CmdPath"}{$Name}=$Path); } sub search_Cmd($) { my $Name = $_[0]; return "" if(not $Name); if(defined $Cache{"search_Cmd"}{$Name}) { return $Cache{"search_Cmd"}{$Name}; } if(my $DefaultPath = get_CmdPath_Default($Name)) { return ($Cache{"search_Cmd"}{$Name} = $DefaultPath); } foreach my $Path (@{$SystemPaths{"bin"}}) { my $CmdPath = join_P($Path,$Name); if(-f $CmdPath) { if($Name=~/gcc/) { next if(not check_gcc($CmdPath, "3")); } return ($Cache{"search_Cmd"}{$Name} = $CmdPath); } } return ($Cache{"search_Cmd"}{$Name} = ""); } sub get_CmdPath_Default($) { # search in PATH return "" if(not $_[0]); if(defined $Cache{"get_CmdPath_Default"}{$_[0]}) { return $Cache{"get_CmdPath_Default"}{$_[0]}; } return ($Cache{"get_CmdPath_Default"}{$_[0]} = get_CmdPath_Default_I($_[0])); } sub get_CmdPath_Default_I($) { # search in PATH my $Name = $_[0]; if($Name=~/find/) { # special case: search for "find" utility if(`find \"$TMP_DIR\" -maxdepth 0 2>\"$TMP_DIR/null\"`) { return "find"; } } elsif($Name=~/gcc/) { return check_gcc($Name, "3"); } if(checkCmd($Name)) { return $Name; } if($OSgroup eq "windows") { if(`$Name /? 2>\"$TMP_DIR/null\"`) { return $Name; } } foreach my $Path (@DefaultBinPaths) { if(-f $Path."/".$Name) { return join_P($Path, $Name); } } return ""; } sub classifyPath($) { my $Path = $_[0]; if($Path=~/[\*\[]/) { # wildcard $Path=~s/\*/.*/g; $Path=~s/\\/\\\\/g; return ($Path, "Pattern"); } elsif($Path=~/[\/\\]/) { # directory or relative path return (path_format($Path, $OSgroup), "Path"); } else { return ($Path, "Name"); } } sub readDescriptor($$) { my ($LibVersion, $Content) = @_; return if(not $LibVersion); my $DName = $DumpAPI?"descriptor":"descriptor \"d$LibVersion\""; if(not $Content) { exitStatus("Error", "$DName is empty"); } if($Content!~/\//g; $Descriptor{$LibVersion}{"Version"} = parseTag(\$Content, "version"); if($TargetVersion{$LibVersion}) { $Descriptor{$LibVersion}{"Version"} = $TargetVersion{$LibVersion}; } if(not $Descriptor{$LibVersion}{"Version"}) { exitStatus("Error", "version in the $DName is not specified ( section)"); } if($Content=~/{RELPATH}/) { if(my $RelDir = $RelativeDirectory{$LibVersion}) { $Content =~ s/{RELPATH}/$RelDir/g; } else { my $NeedRelpath = $DumpAPI?"-relpath":"-relpath$LibVersion"; exitStatus("Error", "you have not specified $NeedRelpath option, but the $DName contains {RELPATH} macro"); } } if(not $CheckObjectsOnly_Opt) { my $DHeaders = parseTag(\$Content, "headers"); if(not $DHeaders) { exitStatus("Error", "header files in the $DName are not specified ( section)"); } elsif(lc($DHeaders) ne "none") { # append the descriptor headers list if($Descriptor{$LibVersion}{"Headers"}) { # multiple descriptors $Descriptor{$LibVersion}{"Headers"} .= "\n".$DHeaders; } else { $Descriptor{$LibVersion}{"Headers"} = $DHeaders; } foreach my $Path (split(/\s*\n\s*/, $DHeaders)) { if(not -e $Path) { exitStatus("Access_Error", "can't access \'$Path\'"); } } } } if(not $CheckHeadersOnly_Opt) { my $DObjects = parseTag(\$Content, "libs"); if(not $DObjects) { exitStatus("Error", "$SLIB_TYPE libraries in the $DName are not specified ( section)"); } elsif(lc($DObjects) ne "none") { # append the descriptor libraries list if($Descriptor{$LibVersion}{"Libs"}) { # multiple descriptors $Descriptor{$LibVersion}{"Libs"} .= "\n".$DObjects; } else { $Descriptor{$LibVersion}{"Libs"} .= $DObjects; } foreach my $Path (split(/\s*\n\s*/, $DObjects)) { if(not -e $Path) { exitStatus("Access_Error", "can't access \'$Path\'"); } } } } foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_headers"))) { if(not -d $Path) { exitStatus("Access_Error", "can't access directory \'$Path\'"); } $Path = get_abs_path($Path); $Path = path_format($Path, $OSgroup); push_U($SystemPaths{"include"}, $Path); } foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_libs"))) { if(not -d $Path) { exitStatus("Access_Error", "can't access directory \'$Path\'"); } $Path = get_abs_path($Path); $Path = path_format($Path, $OSgroup); push_U($SystemPaths{"lib"}, $Path); } foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "tools"))) { if(not -d $Path) { exitStatus("Access_Error", "can't access directory \'$Path\'"); } $Path = get_abs_path($Path); $Path = path_format($Path, $OSgroup); push_U($SystemPaths{"bin"}, $Path); $TargetTools{$Path}=1; } if(my $Prefix = parseTag(\$Content, "cross_prefix")) { $CrossPrefix = $Prefix; } $Descriptor{$LibVersion}{"IncludePaths"} = [] if(not defined $Descriptor{$LibVersion}{"IncludePaths"}); # perl 5.8 doesn't support //= foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "include_paths"))) { if(not -d $Path) { exitStatus("Access_Error", "can't access directory \'$Path\'"); } $Path = get_abs_path($Path); $Path = path_format($Path, $OSgroup); push(@{$Descriptor{$LibVersion}{"IncludePaths"}}, $Path); } $Descriptor{$LibVersion}{"AddIncludePaths"} = [] if(not defined $Descriptor{$LibVersion}{"AddIncludePaths"}); foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "add_include_paths"))) { if(not -d $Path) { exitStatus("Access_Error", "can't access directory \'$Path\'"); } $Path = get_abs_path($Path); $Path = path_format($Path, $OSgroup); push(@{$Descriptor{$LibVersion}{"AddIncludePaths"}}, $Path); } foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_include_paths"))) { # skip some auto-generated include paths if(not is_abs($Path)) { if(my $P = abs_path($Path)) { $Path = $P; } } $Skip_Include_Paths{$LibVersion}{path_format($Path)} = 1; } foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_including"))) { # skip direct including of some headers my ($CPath, $Type) = classifyPath($Path); $SkipHeaders{$LibVersion}{$Type}{$CPath} = 2; } $Descriptor{$LibVersion}{"GccOptions"} = parseTag(\$Content, "gcc_options"); foreach my $Option (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"GccOptions"})) { if($Option!~/\A\-(Wl|l|L)/) { # skip linker options $CompilerOptions{$LibVersion} .= " ".$Option; } } $Descriptor{$LibVersion}{"SkipHeaders"} = parseTag(\$Content, "skip_headers"); foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipHeaders"})) { $SkipHeadersList{$LibVersion}{$Path} = 1; my ($CPath, $Type) = classifyPath($Path); $SkipHeaders{$LibVersion}{$Type}{$CPath} = 1; } $Descriptor{$LibVersion}{"SkipLibs"} = parseTag(\$Content, "skip_libs"); foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipLibs"})) { my ($CPath, $Type) = classifyPath($Path); $SkipLibs{$LibVersion}{$Type}{$CPath} = 1; } if(my $DDefines = parseTag(\$Content, "defines")) { if($Descriptor{$LibVersion}{"Defines"}) { # multiple descriptors $Descriptor{$LibVersion}{"Defines"} .= "\n".$DDefines; } else { $Descriptor{$LibVersion}{"Defines"} = $DDefines; } } foreach my $Order (split(/\s*\n\s*/, parseTag(\$Content, "include_order"))) { if($Order=~/\A(.+):(.+)\Z/) { $Include_Order{$LibVersion}{$1} = $2; } } foreach my $Type_Name (split(/\s*\n\s*/, parseTag(\$Content, "opaque_types")), split(/\s*\n\s*/, parseTag(\$Content, "skip_types"))) { # opaque_types renamed to skip_types (1.23.4) $SkipTypes{$LibVersion}{$Type_Name} = 1; } foreach my $Symbol (split(/\s*\n\s*/, parseTag(\$Content, "skip_interfaces")), split(/\s*\n\s*/, parseTag(\$Content, "skip_symbols"))) { # skip_interfaces renamed to skip_symbols (1.22.1) $SkipSymbols{$LibVersion}{$Symbol} = 1; } foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "skip_namespaces"))) { $SkipNameSpaces{$LibVersion}{$NameSpace} = 1; } foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "add_namespaces"))) { $AddNameSpaces{$LibVersion}{$NameSpace} = 1; } foreach my $Constant (split(/\s*\n\s*/, parseTag(\$Content, "skip_constants"))) { $SkipConstants{$LibVersion}{$Constant} = 1; } if(my $DIncPreamble = parseTag(\$Content, "include_preamble")) { if($Descriptor{$LibVersion}{"IncludePreamble"}) { # multiple descriptors $Descriptor{$LibVersion}{"IncludePreamble"} .= "\n".$DIncPreamble; } else { $Descriptor{$LibVersion}{"IncludePreamble"} = $DIncPreamble; } } } sub parseTag(@) { my $CodeRef = shift(@_); my $Tag = shift(@_); if(not $Tag or not $CodeRef) { return undef; } my $Sp = 0; if(@_) { $Sp = shift(@_); } my $Start = index(${$CodeRef}, "<$Tag>"); if($Start!=-1) { my $End = index(${$CodeRef}, ""); if($End!=-1) { my $TS = length($Tag)+3; my $Content = substr(${$CodeRef}, $Start, $End-$Start+$TS, ""); substr($Content, 0, $TS-1, ""); # cut start tag substr($Content, -$TS, $TS, ""); # cut end tag if(not $Sp) { $Content=~s/\A\s+//g; $Content=~s/\s+\Z//g; } if(substr($Content, 0, 1) ne "<") { $Content = xmlSpecChars_R($Content); } return $Content; } } return undef; } sub getInfo($) { my $DumpPath = $_[0]; return if(not $DumpPath or not -f $DumpPath); readTUDump($DumpPath); # processing info setTemplateParams_All(); if($ExtraDump) { setAnonTypedef_All(); } getTypeInfo_All(); simplifyNames(); simplifyConstants(); getVarInfo_All(); getSymbolInfo_All(); # clean memory %LibInfo = (); %TemplateInstance = (); %BasicTemplate = (); %MangledNames = (); %TemplateDecl = (); %StdCxxTypedef = (); %MissedTypedef = (); %Typedef_Tr = (); %Typedef_Eq = (); %TypedefToAnon = (); # clean cache delete($Cache{"getTypeAttr"}); delete($Cache{"getTypeDeclId"}); if($ExtraDump) { remove_Unused($Version, "Extra"); } else { # remove unused types if($BinaryOnly and not $ExtendedCheck) { # --binary remove_Unused($Version, "All"); } else { remove_Unused($Version, "Extended"); } } if($CheckInfo) { foreach my $Tid (keys(%{$TypeInfo{$Version}})) { check_Completeness($TypeInfo{$Version}{$Tid}, $Version); } foreach my $Sid (keys(%{$SymbolInfo{$Version}})) { check_Completeness($SymbolInfo{$Version}{$Sid}, $Version); } } if($Debug) { # debugMangling($Version); } } sub readTUDump($) { my $DumpPath = $_[0]; open(TU_DUMP, $DumpPath); local $/ = undef; my $Content = ; close(TU_DUMP); unlink($DumpPath); $Content=~s/\n[ ]+/ /g; my @Lines = split(/\n/, $Content); # clean memory undef $Content; $MAX_ID = $#Lines+1; # number of lines == number of nodes foreach (0 .. $#Lines) { if($Lines[$_]=~/\A\@(\d+)[ ]+([a-z_]+)[ ]+(.+)\Z/i) { # get a number and attributes of a node next if(not $NodeType{$2}); $LibInfo{$Version}{"info_type"}{$1}=$2; $LibInfo{$Version}{"info"}{$1}=$3; } # clean memory delete($Lines[$_]); } # clean memory undef @Lines; } sub simplifyConstants() { foreach my $Constant (keys(%{$Constants{$Version}})) { if(defined $Constants{$Version}{$Constant}{"Header"}) { my $Value = $Constants{$Version}{$Constant}{"Value"}; if(defined $EnumConstants{$Version}{$Value}) { $Constants{$Version}{$Constant}{"Value"} = $EnumConstants{$Version}{$Value}{"Value"}; } } } } sub simplifyNames() { foreach my $Base (keys(%{$Typedef_Tr{$Version}})) { if($Typedef_Eq{$Version}{$Base}) { next; } my @Translations = sort keys(%{$Typedef_Tr{$Version}{$Base}}); if($#Translations==0) { if(length($Translations[0])<=length($Base)) { $Typedef_Eq{$Version}{$Base} = $Translations[0]; } } else { # select most appropriate foreach my $Tr (@Translations) { if($Base=~/\A\Q$Tr\E/) { $Typedef_Eq{$Version}{$Base} = $Tr; last; } } } } foreach my $TypeId (keys(%{$TypeInfo{$Version}})) { my $TypeName = $TypeInfo{$Version}{$TypeId}{"Name"}; if(not $TypeName) { next; } next if(index($TypeName,"<")==-1);# template instances only if($TypeName=~/>(::\w+)+\Z/) { # skip unused types next; } foreach my $Base (sort {length($b)<=>length($a)} sort {$b cmp $a} keys(%{$Typedef_Eq{$Version}})) { next if(not $Base); next if(index($TypeName,$Base)==-1); next if(length($TypeName) - length($Base) <= 3); if(my $Typedef = $Typedef_Eq{$Version}{$Base}) { $TypeName=~s/(\<|\,)\Q$Base\E(\W|\Z)/$1$Typedef$2/g; $TypeName=~s/(\<|\,)\Q$Base\E(\w|\Z)/$1$Typedef $2/g; if(defined $TypeInfo{$Version}{$TypeId}{"TParam"}) { foreach my $TPos (keys(%{$TypeInfo{$Version}{$TypeId}{"TParam"}})) { if(my $TPName = $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"}) { $TPName=~s/\A\Q$Base\E(\W|\Z)/$Typedef$1/g; $TPName=~s/\A\Q$Base\E(\w|\Z)/$Typedef $1/g; $TypeInfo{$Version}{$TypeId}{"TParam"}{$TPos}{"name"} = formatName($TPName, "T"); } } } } } $TypeName = formatName($TypeName, "T"); $TypeInfo{$Version}{$TypeId}{"Name"} = $TypeName; $TName_Tid{$Version}{$TypeName} = $TypeId; } } sub setAnonTypedef_All() { foreach my $InfoId (keys(%{$LibInfo{$Version}{"info"}})) { if($LibInfo{$Version}{"info_type"}{$InfoId} eq "type_decl") { if(isAnon(getNameByInfo($InfoId))) { $TypedefToAnon{getTypeId($InfoId)} = 1; } } } } sub setTemplateParams_All() { foreach (keys(%{$LibInfo{$Version}{"info"}})) { if($LibInfo{$Version}{"info_type"}{$_} eq "template_decl") { setTemplateParams($_); } } } sub setTemplateParams($) { my $Tid = getTypeId($_[0]); if(my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/(inst|spcs)[ ]*:[ ]*@(\d+) /) { my $TmplInst_Id = $2; setTemplateInstParams($_[0], $TmplInst_Id); while($TmplInst_Id = getNextElem($TmplInst_Id)) { setTemplateInstParams($_[0], $TmplInst_Id); } } $BasicTemplate{$Version}{$Tid} = $_[0]; if(my $Prms = getTreeAttr_Prms($_[0])) { if(my $Valu = getTreeAttr_Valu($Prms)) { my $Vector = getTreeVec($Valu); foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$Vector})) { if(my $Val = getTreeAttr_Valu($Vector->{$Pos})) { if(my $Name = getNameByInfo($Val)) { $TemplateArg{$Version}{$_[0]}{$Pos} = $Name; if($LibInfo{$Version}{"info_type"}{$Val} eq "parm_decl") { $TemplateInstance{$Version}{"Type"}{$Tid}{$Pos} = $Val; } else { $TemplateInstance{$Version}{"Type"}{$Tid}{$Pos} = getTreeAttr_Type($Val); } } } } } } } if(my $TypeId = getTreeAttr_Type($_[0])) { if(my $IType = $LibInfo{$Version}{"info_type"}{$TypeId}) { if($IType eq "record_type") { $TemplateDecl{$Version}{$TypeId} = 1; } } } } sub setTemplateInstParams($$) { my ($Tmpl, $Inst) = @_; if(my $Info = $LibInfo{$Version}{"info"}{$Inst}) { my ($Params_InfoId, $ElemId) = (); if($Info=~/purp[ ]*:[ ]*@(\d+) /) { $Params_InfoId = $1; } if($Info=~/valu[ ]*:[ ]*@(\d+) /) { $ElemId = $1; } if($Params_InfoId and $ElemId) { my $Params_Info = $LibInfo{$Version}{"info"}{$Params_InfoId}; while($Params_Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /) { my ($PPos, $PTypeId) = ($1, $2); if(my $PType = $LibInfo{$Version}{"info_type"}{$PTypeId}) { if($PType eq "template_type_parm") { $TemplateDecl{$Version}{$ElemId} = 1; } } if($LibInfo{$Version}{"info_type"}{$ElemId} eq "function_decl") { # functions $TemplateInstance{$Version}{"Func"}{$ElemId}{$PPos} = $PTypeId; $BasicTemplate{$Version}{$ElemId} = $Tmpl; } else { # types $TemplateInstance{$Version}{"Type"}{$ElemId}{$PPos} = $PTypeId; $BasicTemplate{$Version}{$ElemId} = $Tmpl; } } } } } sub getTypeDeclId($) { if($_[0]) { if(defined $Cache{"getTypeDeclId"}{$Version}{$_[0]}) { return $Cache{"getTypeDeclId"}{$Version}{$_[0]}; } if(my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/name[ ]*:[ ]*@(\d+)/) { return ($Cache{"getTypeDeclId"}{$Version}{$_[0]} = $1); } } } return ($Cache{"getTypeDeclId"}{$Version}{$_[0]} = 0); } sub getTypeInfo_All() { if(not check_gcc($GCC_PATH, "4.5")) { # support for GCC < 4.5 # missed typedefs: QStyle::State is typedef to QFlags # but QStyleOption.state is of type QFlags in the TU dump # FIXME: check GCC versions addMissedTypes_Pre(); } foreach (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}})) { # forward order only my $IType = $LibInfo{$Version}{"info_type"}{$_}; if($IType=~/_type\Z/ and $IType ne "function_type" and $IType ne "method_type") { getTypeInfo("$_"); } } # add "..." type $TypeInfo{$Version}{"-1"} = { "Name" => "...", "Type" => "Intrinsic", "Tid" => "-1" }; $TName_Tid{$Version}{"..."} = "-1"; if(not check_gcc($GCC_PATH, "4.5")) { # support for GCC < 4.5 addMissedTypes_Post(); } if($ADD_TMPL_INSTANCES) { # templates foreach my $Tid (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$Version}})) { if(defined $TemplateMap{$Version}{$Tid} and not defined $TypeInfo{$Version}{$Tid}{"Template"}) { if(defined $TypeInfo{$Version}{$Tid}{"Memb"}) { foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$Version}{$Tid}{"Memb"}})) { if(my $MembTypeId = $TypeInfo{$Version}{$Tid}{"Memb"}{$Pos}{"type"}) { if(my %MAttr = getTypeAttr($MembTypeId)) { $TypeInfo{$Version}{$Tid}{"Memb"}{$Pos}{"algn"} = $MAttr{"Algn"}; $MembTypeId = $TypeInfo{$Version}{$Tid}{"Memb"}{$Pos}{"type"} = instType($TemplateMap{$Version}{$Tid}, $MembTypeId, $Version); } } } } if(defined $TypeInfo{$Version}{$Tid}{"Base"}) { foreach my $Bid (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$Version}{$Tid}{"Base"}})) { my $NBid = instType($TemplateMap{$Version}{$Tid}, $Bid, $Version); if($NBid ne $Bid) { %{$TypeInfo{$Version}{$Tid}{"Base"}{$NBid}} = %{$TypeInfo{$Version}{$Tid}{"Base"}{$Bid}}; delete($TypeInfo{$Version}{$Tid}{"Base"}{$Bid}); } } } } } } } sub createType($$) { my ($Attr, $LibVersion) = @_; my $NewId = ++$MAX_ID; $Attr->{"Tid"} = $NewId; $TypeInfo{$Version}{$NewId} = $Attr; $TName_Tid{$Version}{formatName($Attr->{"Name"}, "T")} = $NewId; return "$NewId"; } sub instType($$$) { # create template instances my ($Map, $Tid, $LibVersion) = @_; if(not $TypeInfo{$LibVersion}{$Tid}) { return undef; } my $Attr = dclone($TypeInfo{$LibVersion}{$Tid}); foreach my $Key (sort keys(%{$Map})) { if(my $Val = $Map->{$Key}) { $Attr->{"Name"}=~s/\b$Key\b/$Val/g; if(defined $Attr->{"NameSpace"}) { $Attr->{"NameSpace"}=~s/\b$Key\b/$Val/g; } foreach (keys(%{$Attr->{"TParam"}})) { $Attr->{"TParam"}{$_}{"name"}=~s/\b$Key\b/$Val/g; } } else { # remove absent # _Traits, etc. $Attr->{"Name"}=~s/,\s*\b$Key(,|>)/$1/g; if(defined $Attr->{"NameSpace"}) { $Attr->{"NameSpace"}=~s/,\s*\b$Key(,|>)/$1/g; } foreach (keys(%{$Attr->{"TParam"}})) { if($Attr->{"TParam"}{$_}{"name"} eq $Key) { delete($Attr->{"TParam"}{$_}); } else { $Attr->{"TParam"}{$_}{"name"}=~s/,\s*\b$Key(,|>)/$1/g; } } } } my $Tmpl = 0; if(defined $Attr->{"TParam"}) { foreach (sort {int($a)<=>int($b)} keys(%{$Attr->{"TParam"}})) { my $PName = $Attr->{"TParam"}{$_}{"name"}; if(my $PTid = $TName_Tid{$LibVersion}{$PName}) { my %Base = get_BaseType($PTid, $LibVersion); if($Base{"Type"} eq "TemplateParam" or defined $Base{"Template"}) { $Tmpl = 1; last } } } } if(my $Id = getTypeIdByName($Attr->{"Name"}, $LibVersion)) { return "$Id"; } else { if(not $Tmpl) { delete($Attr->{"Template"}); } my $New = createType($Attr, $LibVersion); my %EMap = (); if(defined $TemplateMap{$LibVersion}{$Tid}) { %EMap = %{$TemplateMap{$LibVersion}{$Tid}}; } foreach (keys(%{$Map})) { $EMap{$_} = $Map->{$_}; } if(defined $TypeInfo{$LibVersion}{$New}{"BaseType"}) { $TypeInfo{$LibVersion}{$New}{"BaseType"} = instType(\%EMap, $TypeInfo{$LibVersion}{$New}{"BaseType"}, $LibVersion); } if(defined $TypeInfo{$LibVersion}{$New}{"Base"}) { foreach my $Bid (keys(%{$TypeInfo{$LibVersion}{$New}{"Base"}})) { my $NBid = instType(\%EMap, $Bid, $LibVersion); if($NBid ne $Bid) { %{$TypeInfo{$LibVersion}{$New}{"Base"}{$NBid}} = %{$TypeInfo{$LibVersion}{$New}{"Base"}{$Bid}}; delete($TypeInfo{$LibVersion}{$New}{"Base"}{$Bid}); } } } if(defined $TypeInfo{$LibVersion}{$New}{"Memb"}) { foreach (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}{$New}{"Memb"}})) { if(defined $TypeInfo{$LibVersion}{$New}{"Memb"}{$_}{"type"}) { $TypeInfo{$LibVersion}{$New}{"Memb"}{$_}{"type"} = instType(\%EMap, $TypeInfo{$LibVersion}{$New}{"Memb"}{$_}{"type"}, $LibVersion); } } } if(defined $TypeInfo{$LibVersion}{$New}{"Param"}) { foreach (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}{$New}{"Param"}})) { $TypeInfo{$LibVersion}{$New}{"Param"}{$_}{"type"} = instType(\%EMap, $TypeInfo{$LibVersion}{$New}{"Param"}{$_}{"type"}, $LibVersion); } } if(defined $TypeInfo{$LibVersion}{$New}{"Return"}) { $TypeInfo{$LibVersion}{$New}{"Return"} = instType(\%EMap, $TypeInfo{$LibVersion}{$New}{"Return"}, $LibVersion); } return $New; } } sub addMissedTypes_Pre() { my %MissedTypes = (); foreach my $MissedTDid (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}})) { # detecting missed typedefs if($LibInfo{$Version}{"info_type"}{$MissedTDid} eq "type_decl") { my $TypeId = getTreeAttr_Type($MissedTDid); next if(not $TypeId); my $TypeType = getTypeType($TypeId); if($TypeType eq "Unknown") { # template_type_parm next; } my $TypeDeclId = getTypeDeclId($TypeId); next if($TypeDeclId eq $MissedTDid);#or not $TypeDeclId my $TypedefName = getNameByInfo($MissedTDid); next if(not $TypedefName); next if($TypedefName eq "__float80"); next if(isAnon($TypedefName)); if(not $TypeDeclId or getNameByInfo($TypeDeclId) ne $TypedefName) { $MissedTypes{$Version}{$TypeId}{$MissedTDid} = 1; } } } my %AddTypes = (); foreach my $Tid (keys(%{$MissedTypes{$Version}})) { # add missed typedefs my @Missed = keys(%{$MissedTypes{$Version}{$Tid}}); if(not @Missed or $#Missed>=1) { next; } my $MissedTDid = $Missed[0]; my ($TypedefName, $TypedefNS) = getTrivialName($MissedTDid, $Tid); if(not $TypedefName) { next; } my $NewId = ++$MAX_ID; my %MissedInfo = ( # typedef info "Name" => $TypedefName, "NameSpace" => $TypedefNS, "BaseType" => $Tid, "Type" => "Typedef", "Tid" => "$NewId" ); my ($H, $L) = getLocation($MissedTDid); $MissedInfo{"Header"} = $H; $MissedInfo{"Line"} = $L; if($TypedefName=~/\*|\&|\s/) { # other types next; } if($TypedefName=~/>(::\w+)+\Z/) { # QFlags::enum_type next; } if(getTypeType($Tid)=~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/) { # double-check for the name of typedef my ($TName, $TNS) = getTrivialName(getTypeDeclId($Tid), $Tid); # base type info next if(not $TName); if(length($TypedefName)>=length($TName)) { # too long typedef next; } if($TName=~/\A\Q$TypedefName\Eint($b)} keys(%{$TemplateInstance{$Version}{$Kind}{$TypeId}}); foreach my $Pos (@Positions) { my $Param_TypeId = $TemplateInstance{$Version}{$Kind}{$TypeId}{$Pos}; my $NodeType = $LibInfo{$Version}{"info_type"}{$Param_TypeId}; if(not $NodeType) { # typename_type return (); } if($NodeType eq "tree_vec") { if($Pos!=$#Positions) { # select last vector of parameters ( ns::type ) next; } } my @Params = get_TemplateParam($Pos, $Param_TypeId); foreach my $P (@Params) { if($P eq "") { return (); } elsif($P ne "\@skip\@") { @TmplParams = (@TmplParams, $P); } } } return @TmplParams; } sub getTypeAttr($) { my $TypeId = $_[0]; my %TypeAttr = (); if(defined $TypeInfo{$Version}{$TypeId} and $TypeInfo{$Version}{$TypeId}{"Name"}) { # already created return %{$TypeInfo{$Version}{$TypeId}}; } elsif($Cache{"getTypeAttr"}{$Version}{$TypeId}) { # incomplete type return (); } $Cache{"getTypeAttr"}{$Version}{$TypeId} = 1; my $TypeDeclId = getTypeDeclId($TypeId); $TypeAttr{"Tid"} = $TypeId; if(not $MissedBase{$Version}{$TypeId} and isTypedef($TypeId)) { if(my $Info = $LibInfo{$Version}{"info"}{$TypeId}) { if($Info=~/qual[ ]*:/) { my $NewId = ++$MAX_ID; $MissedBase{$Version}{$TypeId} = "$NewId"; $MissedBase_R{$Version}{$NewId} = $TypeId; $LibInfo{$Version}{"info"}{$NewId} = $LibInfo{$Version}{"info"}{$TypeId}; $LibInfo{$Version}{"info_type"}{$NewId} = $LibInfo{$Version}{"info_type"}{$TypeId}; } } $TypeAttr{"Type"} = "Typedef"; } else { $TypeAttr{"Type"} = getTypeType($TypeId); } if(my $ScopeId = getTreeAttr_Scpe($TypeDeclId)) { if($LibInfo{$Version}{"info_type"}{$ScopeId} eq "function_decl") { # local code return (); } } if($TypeAttr{"Type"} eq "Unknown") { return (); } elsif($TypeAttr{"Type"}=~/(Func|Method|Field)Ptr/) { %TypeAttr = getMemPtrAttr(pointTo($TypeId), $TypeId, $TypeAttr{"Type"}); if(my $TName = $TypeAttr{"Name"}) { %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr; $TName_Tid{$Version}{$TName} = $TypeId; return %TypeAttr; } else { return (); } } elsif($TypeAttr{"Type"} eq "Array") { my ($BTid, $BTSpec) = selectBaseType($TypeId); if(not $BTid) { return (); } if(my $Algn = getAlgn($TypeId)) { $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE; } $TypeAttr{"BaseType"} = $BTid; if(my %BTAttr = getTypeAttr($BTid)) { if(not $BTAttr{"Name"}) { return (); } if(my $NElems = getArraySize($TypeId, $BTAttr{"Name"})) { if(my $Size = getSize($TypeId)) { $TypeAttr{"Size"} = $Size/$BYTE_SIZE; } if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) { $TypeAttr{"Name"} = $1."[$NElems]".$2; } else { $TypeAttr{"Name"} = $BTAttr{"Name"}."[$NElems]"; } } else { $TypeAttr{"Size"} = $WORD_SIZE{$Version}; # pointer if($BTAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) { $TypeAttr{"Name"} = $1."[]".$2; } else { $TypeAttr{"Name"} = $BTAttr{"Name"}."[]"; } } $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T"); if($BTAttr{"Header"}) { $TypeAttr{"Header"} = $BTAttr{"Header"}; } %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr; $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId; return %TypeAttr; } return (); } elsif($TypeAttr{"Type"}=~/\A(Intrinsic|Union|Struct|Enum|Class|Vector)\Z/) { %TypeAttr = getTrivialTypeAttr($TypeId); if($TypeAttr{"Name"}) { %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr; if(not defined $IntrinsicNames{$TypeAttr{"Name"}} or getTypeDeclId($TypeAttr{"Tid"})) { # NOTE: register only one int: with built-in decl if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) { $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId; } } return %TypeAttr; } else { return (); } } elsif($TypeAttr{"Type"}=~/TemplateParam|TypeName/) { %TypeAttr = getTrivialTypeAttr($TypeId); if($TypeAttr{"Name"}) { %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr; if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) { $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId; } return %TypeAttr; } else { return (); } } elsif($TypeAttr{"Type"} eq "SizeOf") { $TypeAttr{"BaseType"} = getTreeAttr_Type($TypeId); my %BTAttr = getTypeAttr($TypeAttr{"BaseType"}); $TypeAttr{"Name"} = "sizeof(".$BTAttr{"Name"}.")"; if($TypeAttr{"Name"}) { %{$TypeInfo{$Version}{$TypeId}} = %TypeAttr; return %TypeAttr; } else { return (); } } else { # derived types my ($BTid, $BTSpec) = selectBaseType($TypeId); if(not $BTid) { return (); } $TypeAttr{"BaseType"} = $BTid; if(defined $MissedTypedef{$Version}{$BTid}) { if(my $MissedTDid = $MissedTypedef{$Version}{$BTid}{"TDid"}) { if($MissedTDid ne $TypeDeclId) { $TypeAttr{"BaseType"} = $MissedTypedef{$Version}{$BTid}{"Tid"}; } } } my %BTAttr = getTypeAttr($TypeAttr{"BaseType"}); if(not $BTAttr{"Name"}) { # templates return (); } if($BTAttr{"Type"} eq "Typedef") { # relinking typedefs my %BaseBase = get_Type($BTAttr{"BaseType"}, $Version); if($BTAttr{"Name"} eq $BaseBase{"Name"}) { $TypeAttr{"BaseType"} = $BaseBase{"Tid"}; } } if($BTSpec) { if($TypeAttr{"Type"} eq "Pointer" and $BTAttr{"Name"}=~/\([\*]+\)/) { $TypeAttr{"Name"} = $BTAttr{"Name"}; $TypeAttr{"Name"}=~s/\(([*]+)\)/($1*)/g; } else { $TypeAttr{"Name"} = $BTAttr{"Name"}." ".$BTSpec; } } else { $TypeAttr{"Name"} = $BTAttr{"Name"}; } if($TypeAttr{"Type"} eq "Typedef") { $TypeAttr{"Name"} = getNameByInfo($TypeDeclId); if(index($TypeAttr{"Name"}, "tmp_add_type")==0) { return (); } if(isAnon($TypeAttr{"Name"})) { # anon typedef to anon type: ._N return (); } if($LibInfo{$Version}{"info"}{$TypeDeclId}=~/ artificial /i) { # artificial typedef of "struct X" to "X" $TypeAttr{"Artificial"} = 1; } if(my $NS = getNameSpace($TypeDeclId)) { my $TypeName = $TypeAttr{"Name"}; if($NS=~/\A(struct |union |class |)((.+)::|)\Q$TypeName\E\Z/) { # "some_type" is the typedef to "struct some_type" in C++ if($3) { $TypeAttr{"Name"} = $3."::".$TypeName; } } else { $TypeAttr{"NameSpace"} = $NS; $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"}; if($TypeAttr{"NameSpace"}=~/\Astd(::|\Z)/ and $TypeAttr{"Name"}!~/>(::\w+)+\Z/) { if($BTAttr{"NameSpace"} and $BTAttr{"NameSpace"}=~/\Astd(::|\Z)/ and $BTAttr{"Name"}=~/" are # not covered by typedefs in the TU dump # so trying to add such typedefs manually $StdCxxTypedef{$Version}{$BTAttr{"Name"}}{$TypeAttr{"Name"}} = 1; if(length($TypeAttr{"Name"})<=length($BTAttr{"Name"})) { if(($BTAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/)) { # skip "other" in "std" and "type" in "boost" $Typedef_Eq{$Version}{$BTAttr{"Name"}} = $TypeAttr{"Name"}; } } } } } } if($TypeAttr{"Name"} ne $BTAttr{"Name"} and not $TypeAttr{"Artificial"} and $TypeAttr{"Name"}!~/>(::\w+)+\Z/ and $BTAttr{"Name"}!~/>(::\w+)+\Z/) { if(not defined $Typedef_BaseName{$Version}{$TypeAttr{"Name"}}) { # typedef int*const TYPEDEF; // first # int foo(TYPEDEF p); // const is optimized out $Typedef_BaseName{$Version}{$TypeAttr{"Name"}} = $BTAttr{"Name"}; if($BTAttr{"Name"}=~/int($b)} keys(%{$Vector})) { foreach my $P2 (get_TemplateParam($Pos, $Vector->{$P1})) { push(@Params, $P2); } } return @Params; } elsif($NodeType eq "parm_decl") { (getNameByInfo($Type_Id)); } else { my %ParamAttr = getTypeAttr($Type_Id); my $PName = $ParamAttr{"Name"}; if(not $PName) { return (); } if($PName=~/\>/) { if(my $Cover = cover_stdcxx_typedef($PName)) { $PName = $Cover; } } if($Pos>=1 and $PName=~/\A$DEFAULT_STD_PARMS\ > # template # template > # template > # template > # template > return ("\@skip\@"); } return ($PName); } } sub cover_stdcxx_typedef($) { my $TypeName = $_[0]; if(my @Covers = sort {length($a)<=>length($b)} sort keys(%{$StdCxxTypedef{$Version}{$TypeName}})) { # take the shortest typedef # FIXME: there may be more than # one typedefs to the same type return $Covers[0]; } my $Covered = $TypeName; while($TypeName=~s/(>)[ ]*(const|volatile|restrict| |\*|\&)\Z/$1/g){}; if(my @Covers = sort {length($a)<=>length($b)} sort keys(%{$StdCxxTypedef{$Version}{$TypeName}})) { if(my $Cover = $Covers[0]) { $Covered=~s/\b\Q$TypeName\E(\W|\Z)/$Cover$1/g; $Covered=~s/\b\Q$TypeName\E(\w|\Z)/$Cover $1/g; } } return formatName($Covered, "T"); } sub getNodeIntCst($) { my $CstId = $_[0]; my $CstTypeId = getTreeAttr_Type($CstId); if($EnumMembName_Id{$Version}{$CstId}) { return $EnumMembName_Id{$Version}{$CstId}; } elsif((my $Value = getTreeValue($CstId)) ne "") { if($Value eq "0") { if($LibInfo{$Version}{"info_type"}{$CstTypeId} eq "boolean_type") { return "false"; } else { return "0"; } } elsif($Value eq "1") { if($LibInfo{$Version}{"info_type"}{$CstTypeId} eq "boolean_type") { return "true"; } else { return "1"; } } else { return $Value; } } return ""; } sub getNodeStrCst($) { if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/strg[ ]*: (.+) lngt:[ ]*(\d+)/) { if($LibInfo{$Version}{"info_type"}{$_[0]} eq "string_cst") { # string length is N-1 because of the null terminator return substr($1, 0, $2-1); } else { # identifier_node return substr($1, 0, $2); } } } return ""; } sub getMemPtrAttr($$$) { # function, method and field pointers my ($PtrId, $TypeId, $Type) = @_; my $MemInfo = $LibInfo{$Version}{"info"}{$PtrId}; if($Type eq "FieldPtr") { $MemInfo = $LibInfo{$Version}{"info"}{$TypeId}; } my $MemInfo_Type = $LibInfo{$Version}{"info_type"}{$PtrId}; my $MemPtrName = ""; my %TypeAttr = ("Size"=>$WORD_SIZE{$Version}, "Type"=>$Type, "Tid"=>$TypeId); if($Type eq "MethodPtr") { # size of "method pointer" may be greater than WORD size if(my $Size = getSize($TypeId)) { $Size/=$BYTE_SIZE; $TypeAttr{"Size"} = "$Size"; } } if(my $Algn = getAlgn($TypeId)) { $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE; } # Return if($Type eq "FieldPtr") { my %ReturnAttr = getTypeAttr($PtrId); if($ReturnAttr{"Name"}) { $MemPtrName .= $ReturnAttr{"Name"}; } $TypeAttr{"Return"} = $PtrId; } else { if($MemInfo=~/retn[ ]*:[ ]*\@(\d+) /) { my $ReturnTypeId = $1; my %ReturnAttr = getTypeAttr($ReturnTypeId); if(not $ReturnAttr{"Name"}) { # templates return (); } $MemPtrName .= $ReturnAttr{"Name"}; $TypeAttr{"Return"} = $ReturnTypeId; } } # Class if($MemInfo=~/(clas|cls)[ ]*:[ ]*@(\d+) /) { $TypeAttr{"Class"} = $2; my %Class = getTypeAttr($TypeAttr{"Class"}); if($Class{"Name"}) { $MemPtrName .= " (".$Class{"Name"}."\:\:*)"; } else { $MemPtrName .= " (*)"; } } else { $MemPtrName .= " (*)"; } # Parameters if($Type eq "FuncPtr" or $Type eq "MethodPtr") { my @ParamTypeName = (); if($MemInfo=~/prms[ ]*:[ ]*@(\d+) /) { my $PTypeInfoId = $1; my ($Pos, $PPos) = (0, 0); while($PTypeInfoId) { my $PTypeInfo = $LibInfo{$Version}{"info"}{$PTypeInfoId}; if($PTypeInfo=~/valu[ ]*:[ ]*@(\d+) /) { my $PTypeId = $1; my %ParamAttr = getTypeAttr($PTypeId); if(not $ParamAttr{"Name"}) { # templates (template_type_parm), etc. return (); } if($ParamAttr{"Name"} eq "void") { last; } if($Pos!=0 or $Type ne "MethodPtr") { $TypeAttr{"Param"}{$PPos++}{"type"} = $PTypeId; push(@ParamTypeName, $ParamAttr{"Name"}); } if($PTypeInfoId = getNextElem($PTypeInfoId)) { $Pos+=1; } else { last; } } else { last; } } } $MemPtrName .= " (".join(", ", @ParamTypeName).")"; } $TypeAttr{"Name"} = formatName($MemPtrName, "T"); return %TypeAttr; } sub getTreeTypeName($) { my $TypeId = $_[0]; if(my $Info = $LibInfo{$Version}{"info"}{$TypeId}) { if($LibInfo{$Version}{"info_type"}{$_[0]} eq "integer_type") { if(my $Name = getNameByInfo($TypeId)) { # bit_size_type return $Name; } elsif($Info=~/unsigned/) { return "unsigned int"; } else { return "int"; } } elsif($Info=~/name[ ]*:[ ]*@(\d+) /) { return getNameByInfo($1); } } return ""; } sub isFuncPtr($) { my $Ptd = pointTo($_[0]); return 0 if(not $Ptd); if(my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/unql[ ]*:/ and $Info!~/qual[ ]*:/) { return 0; } } if(my $InfoT1 = $LibInfo{$Version}{"info_type"}{$_[0]} and my $InfoT2 = $LibInfo{$Version}{"info_type"}{$Ptd}) { if($InfoT1 eq "pointer_type" and $InfoT2 eq "function_type") { return 1; } } return 0; } sub isMethodPtr($) { my $Ptd = pointTo($_[0]); return 0 if(not $Ptd); if(my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($LibInfo{$Version}{"info_type"}{$_[0]} eq "record_type" and $LibInfo{$Version}{"info_type"}{$Ptd} eq "method_type" and $Info=~/ ptrmem /) { return 1; } } return 0; } sub isFieldPtr($) { if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($LibInfo{$Version}{"info_type"}{$_[0]} eq "offset_type" and $Info=~/ ptrmem /) { return 1; } } return 0; } sub pointTo($) { if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/ptd[ ]*:[ ]*@(\d+)/) { return $1; } } return ""; } sub getTypeTypeByTypeId($) { my $TypeId = $_[0]; if(my $TType = $LibInfo{$Version}{"info_type"}{$TypeId}) { my $NType = $NodeType{$TType}; if($NType eq "Intrinsic") { return $NType; } elsif(isFuncPtr($TypeId)) { return "FuncPtr"; } elsif(isMethodPtr($TypeId)) { return "MethodPtr"; } elsif(isFieldPtr($TypeId)) { return "FieldPtr"; } elsif($NType ne "Other") { return $NType; } } return "Unknown"; } my %UnQual = ( "r"=>"restrict", "v"=>"volatile", "c"=>"const", "cv"=>"const volatile" ); sub getQual($) { my $TypeId = $_[0]; if(my $Info = $LibInfo{$Version}{"info"}{$TypeId}) { my ($Qual, $To) = (); if($Info=~/qual[ ]*:[ ]*(r|c|v|cv) /) { $Qual = $UnQual{$1}; } if($Info=~/unql[ ]*:[ ]*\@(\d+)/) { $To = $1; } if($Qual and $To) { return ($Qual, $To); } } return (); } sub getQualType($) { if($_[0] eq "const volatile") { return "ConstVolatile"; } return ucfirst($_[0]); } sub getTypeType($) { my $TypeId = $_[0]; my $TypeDeclId = getTypeDeclId($TypeId); if(defined $MissedTypedef{$Version}{$TypeId}) { # support for old GCC versions if($MissedTypedef{$Version}{$TypeId}{"TDid"} eq $TypeDeclId) { return "Typedef"; } } my $Info = $LibInfo{$Version}{"info"}{$TypeId}; my ($Qual, $To) = getQual($TypeId); if(($Qual or $To) and $TypeDeclId and (getTypeId($TypeDeclId) ne $TypeId)) { # qualified types (special) return getQualType($Qual); } elsif(not $MissedBase_R{$Version}{$TypeId} and isTypedef($TypeId)) { return "Typedef"; } elsif($Qual) { # qualified types return getQualType($Qual); } if($Info=~/unql[ ]*:[ ]*\@(\d+)/) { # typedef struct { ... } name $TypeTypedef{$Version}{$TypeId} = $1; } my $TypeType = getTypeTypeByTypeId($TypeId); if($TypeType eq "Struct") { if($TypeDeclId and $LibInfo{$Version}{"info_type"}{$TypeDeclId} eq "template_decl") { return "Template"; } } return $TypeType; } sub isTypedef($) { if($_[0]) { if($LibInfo{$Version}{"info_type"}{$_[0]} eq "vector_type") { # typedef float La_x86_64_xmm __attribute__ ((__vector_size__ (16))); return 0; } if(my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if(my $TDid = getTypeDeclId($_[0])) { if(getTypeId($TDid) eq $_[0] and getNameByInfo($TDid)) { if($Info=~/unql[ ]*:[ ]*\@(\d+) /) { return $1; } } } } } return 0; } sub selectBaseType($) { my $TypeId = $_[0]; if(defined $MissedTypedef{$Version}{$TypeId}) { # add missed typedefs if($MissedTypedef{$Version}{$TypeId}{"TDid"} eq getTypeDeclId($TypeId)) { return ($TypeId, ""); } } my $Info = $LibInfo{$Version}{"info"}{$TypeId}; my $InfoType = $LibInfo{$Version}{"info_type"}{$TypeId}; my $MB_R = $MissedBase_R{$Version}{$TypeId}; my $MB = $MissedBase{$Version}{$TypeId}; my ($Qual, $To) = getQual($TypeId); if(($Qual or $To) and $Info=~/name[ ]*:[ ]*\@(\d+) / and (getTypeId($1) ne $TypeId) and (not $MB_R or getTypeId($1) ne $MB_R)) { # qualified types (special) return (getTypeId($1), $Qual); } elsif($MB) { # add base return ($MB, ""); } elsif(not $MB_R and my $Bid = isTypedef($TypeId)) { # typedefs return ($Bid, ""); } elsif($Qual or $To) { # qualified types return ($To, $Qual); } elsif($InfoType eq "reference_type") { if($Info=~/refd[ ]*:[ ]*@(\d+) /) { return ($1, "&"); } } elsif($InfoType eq "array_type") { if($Info=~/elts[ ]*:[ ]*@(\d+) /) { return ($1, ""); } } elsif($InfoType eq "pointer_type") { if($Info=~/ptd[ ]*:[ ]*@(\d+) /) { return ($1, "*"); } } return (0, ""); } sub getSymbolInfo_All() { foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}})) { # reverse order if($LibInfo{$Version}{"info_type"}{$_} eq "function_decl") { getSymbolInfo($_); } } if($ADD_TMPL_INSTANCES) { # templates foreach my $Sid (sort {int($a)<=>int($b)} keys(%{$SymbolInfo{$Version}})) { my %Map = (); if(my $ClassId = $SymbolInfo{$Version}{$Sid}{"Class"}) { if(defined $TemplateMap{$Version}{$ClassId}) { foreach (keys(%{$TemplateMap{$Version}{$ClassId}})) { $Map{$_} = $TemplateMap{$Version}{$ClassId}{$_}; } } } if(defined $TemplateMap{$Version}{$Sid}) { foreach (keys(%{$TemplateMap{$Version}{$Sid}})) { $Map{$_} = $TemplateMap{$Version}{$Sid}{$_}; } } if(defined $SymbolInfo{$Version}{$Sid}{"Param"}) { foreach (keys(%{$SymbolInfo{$Version}{$Sid}{"Param"}})) { my $PTid = $SymbolInfo{$Version}{$Sid}{"Param"}{$_}{"type"}; $SymbolInfo{$Version}{$Sid}{"Param"}{$_}{"type"} = instType(\%Map, $PTid, $Version); } } if(my $Return = $SymbolInfo{$Version}{$Sid}{"Return"}) { $SymbolInfo{$Version}{$Sid}{"Return"} = instType(\%Map, $Return, $Version); } } } } sub getVarInfo_All() { foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}})) { # reverse order if($LibInfo{$Version}{"info_type"}{$_} eq "var_decl") { getVarInfo($_); } } } sub isBuiltIn($) { return ($_[0] and $_[0]=~/\|\|\A\./); } sub getVarInfo($) { my $InfoId = $_[0]; if(my $NSid = getTreeAttr_Scpe($InfoId)) { my $NSInfoType = $LibInfo{$Version}{"info_type"}{$NSid}; if($NSInfoType and $NSInfoType eq "function_decl") { return; } } ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId); if(not $SymbolInfo{$Version}{$InfoId}{"Header"} or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"})) { delete($SymbolInfo{$Version}{$InfoId}); return; } my $ShortName = getTreeStr(getTreeAttr_Name($InfoId)); if(not $ShortName) { delete($SymbolInfo{$Version}{$InfoId}); return; } if($ShortName=~/\Atmp_add_class_\d+\Z/) { delete($SymbolInfo{$Version}{$InfoId}); return; } $SymbolInfo{$Version}{$InfoId}{"ShortName"} = $ShortName; if(my $MnglName = getTreeStr(getTreeAttr_Mngl($InfoId))) { if($OSgroup eq "windows") { # cut the offset $MnglName=~s/\@\d+\Z//g; } $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $MnglName; } if($SymbolInfo{$Version}{$InfoId}{"MnglName"} and index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_Z")!=0) { # validate mangled name delete($SymbolInfo{$Version}{$InfoId}); return; } if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"} and index($ShortName, "_Z")==0) { # _ZTS, etc. $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName; } if(isPrivateData($SymbolInfo{$Version}{$InfoId}{"MnglName"})) { # non-public global data delete($SymbolInfo{$Version}{$InfoId}); return; } $SymbolInfo{$Version}{$InfoId}{"Data"} = 1; if(my $Rid = getTypeId($InfoId)) { if(not defined $TypeInfo{$Version}{$Rid} or not $TypeInfo{$Version}{$Rid}{"Name"}) { delete($SymbolInfo{$Version}{$InfoId}); return; } $SymbolInfo{$Version}{$InfoId}{"Return"} = $Rid; my $Val = getDataVal($InfoId, $Rid); if(defined $Val) { $SymbolInfo{$Version}{$InfoId}{"Value"} = $Val; } } set_Class_And_Namespace($InfoId); if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"}) { if(not defined $TypeInfo{$Version}{$ClassId} or not $TypeInfo{$Version}{$ClassId}{"Name"}) { delete($SymbolInfo{$Version}{$InfoId}); return; } } if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i) { # extern "C" $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C"; $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName; } if($UserLang and $UserLang eq "C") { # --lang=C option $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName; } if(not $CheckHeadersOnly) { if(not $SymbolInfo{$Version}{$InfoId}{"Class"}) { if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"} or not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps")) { if(link_symbol($ShortName, $Version, "-Deps")) { # "const" global data is mangled as _ZL... in the TU dump # but not mangled when compiling a C shared library $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName; } } } } if($COMMON_LANGUAGE{$Version} eq "C++") { if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) { # for some symbols (_ZTI) the short name is the mangled name if(index($ShortName, "_Z")==0) { $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName; } } if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) { # try to mangle symbol (link with libraries) $SymbolInfo{$Version}{$InfoId}{"MnglName"} = linkSymbol($InfoId); } if($OStarget eq "windows") { if(my $Mangled = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")}) { # link MS C++ symbols from library with GCC symbols from headers $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled; } } } if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) { $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName; } if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"}) { if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version)) { # non-target symbols delete($SymbolInfo{$Version}{$InfoId}); return; } } if(my $Rid = $SymbolInfo{$Version}{$InfoId}{"Return"}) { if(defined $MissedTypedef{$Version}{$Rid}) { if(my $AddedTid = $MissedTypedef{$Version}{$Rid}{"Tid"}) { $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid; } } } setFuncAccess($InfoId); if(index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_ZTV")==0) { delete($SymbolInfo{$Version}{$InfoId}{"Return"}); } if($ShortName=~/\A(_Z|\?)/) { delete($SymbolInfo{$Version}{$InfoId}{"ShortName"}); } if($ExtraDump) { $SymbolInfo{$Version}{$InfoId}{"Header"} = guessHeader($InfoId); } } sub isConstType($$) { my ($TypeId, $LibVersion) = @_; my %Base = get_Type($TypeId, $LibVersion); while(defined $Base{"Type"} and $Base{"Type"} eq "Typedef") { %Base = get_OneStep_BaseType($Base{"Tid"}, $TypeInfo{$LibVersion}); } return ($Base{"Type"} eq "Const"); } sub getTrivialName($$) { my ($TypeInfoId, $TypeId) = @_; my %TypeAttr = (); $TypeAttr{"Name"} = getNameByInfo($TypeInfoId); if(not $TypeAttr{"Name"}) { $TypeAttr{"Name"} = getTreeTypeName($TypeId); } ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId); $TypeAttr{"Type"} = getTypeType($TypeId); $TypeAttr{"Name"}=~s/<(.+)\Z//g; # GCC 3.4.4 add template params to the name if(isAnon($TypeAttr{"Name"})) { my $NameSpaceId = $TypeId; while(my $NSId = getTreeAttr_Scpe(getTypeDeclId($NameSpaceId))) { # searching for a first not anon scope if($NSId eq $NameSpaceId) { last; } else { $TypeAttr{"NameSpace"} = getNameSpace(getTypeDeclId($TypeId)); if(not $TypeAttr{"NameSpace"} or not isAnon($TypeAttr{"NameSpace"})) { last; } } $NameSpaceId = $NSId; } } else { if(my $NameSpaceId = getTreeAttr_Scpe($TypeInfoId)) { if($NameSpaceId ne $TypeId) { $TypeAttr{"NameSpace"} = getNameSpace($TypeInfoId); } } } if($TypeAttr{"NameSpace"} and not isAnon($TypeAttr{"Name"})) { $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"}; } $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}, "T"); if(isAnon($TypeAttr{"Name"})) { # anon-struct-header.h-line $TypeAttr{"Name"} = "anon-".lc($TypeAttr{"Type"})."-"; $TypeAttr{"Name"} .= $TypeAttr{"Header"}."-".$TypeAttr{"Line"}; if($TypeAttr{"NameSpace"}) { $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"}; } } if(defined $TemplateInstance{$Version}{"Type"}{$TypeId} and getTypeDeclId($TypeId) eq $TypeInfoId) { if(my @TParams = getTParams($TypeId, "Type")) { $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}."< ".join(", ", @TParams)." >", "T"); } else { $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}."<...>", "T"); } } return ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"}); } sub getTrivialTypeAttr($) { my $TypeId = $_[0]; my $TypeInfoId = getTypeDeclId($_[0]); my %TypeAttr = (); if($TemplateDecl{$Version}{$TypeId}) { # template_decl $TypeAttr{"Template"} = 1; } setTypeAccess($TypeId, \%TypeAttr); ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId); if(isBuiltIn($TypeAttr{"Header"})) { delete($TypeAttr{"Header"}); delete($TypeAttr{"Line"}); } $TypeAttr{"Type"} = getTypeType($TypeId); ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"}) = getTrivialName($TypeInfoId, $TypeId); if(not $TypeAttr{"Name"}) { return (); } if(not $TypeAttr{"NameSpace"}) { delete($TypeAttr{"NameSpace"}); } if($TypeAttr{"Type"} eq "Intrinsic") { if(defined $TypeAttr{"Header"}) { if($TypeAttr{"Header"}=~/\Adump[1-2]\.[ih]\Z/) { # support for SUSE 11.2 # integer_type has srcp dump{1-2}.i delete($TypeAttr{"Header"}); } } } my $Tmpl = undef; if(defined $TemplateInstance{$Version}{"Type"}{$TypeId}) { $Tmpl = $BasicTemplate{$Version}{$TypeId}; if(my @TParams = getTParams($TypeId, "Type")) { foreach my $Pos (0 .. $#TParams) { my $Val = $TParams[$Pos]; $TypeAttr{"TParam"}{$Pos}{"name"} = $Val; if(not defined $TypeAttr{"Template"}) { my %Base = get_BaseType($TemplateInstance{$Version}{"Type"}{$TypeId}{$Pos}, $Version); if($Base{"Type"} eq "TemplateParam" or defined $Base{"Template"}) { $TypeAttr{"Template"} = 1; } } if($Tmpl) { if(my $Arg = $TemplateArg{$Version}{$Tmpl}{$Pos}) { $TemplateMap{$Version}{$TypeId}{$Arg} = $Val; if($Val eq $Arg) { $TypeAttr{"Template"} = 1; } } } } if($Tmpl) { foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$TemplateArg{$Version}{$Tmpl}})) { if($Pos>$#TParams) { my $Arg = $TemplateArg{$Version}{$Tmpl}{$Pos}; $TemplateMap{$Version}{$TypeId}{$Arg} = ""; } } } } if($ADD_TMPL_INSTANCES) { if($Tmpl) { if(my $MainInst = getTreeAttr_Type($Tmpl)) { if(not getTreeAttr_Flds($TypeId)) { if(my $Flds = getTreeAttr_Flds($MainInst)) { $LibInfo{$Version}{"info"}{$TypeId} .= " flds: \@$Flds "; } } if(not getTreeAttr_Binf($TypeId)) { if(my $Binf = getTreeAttr_Binf($MainInst)) { $LibInfo{$Version}{"info"}{$TypeId} .= " binf: \@$Binf "; } } } } } } my $StaticFields = setTypeMemb($TypeId, \%TypeAttr); if(my $Size = getSize($TypeId)) { $Size = $Size/$BYTE_SIZE; $TypeAttr{"Size"} = "$Size"; } else { if($ExtraDump) { if(not defined $TypeAttr{"Memb"} and not $Tmpl) { # declaration only $TypeAttr{"Forward"} = 1; } } } if($TypeAttr{"Type"} eq "Struct" and ($StaticFields or detect_lang($TypeId))) { $TypeAttr{"Type"} = "Class"; $TypeAttr{"Copied"} = 1; # default, will be changed in getSymbolInfo() } if($TypeAttr{"Type"} eq "Struct" or $TypeAttr{"Type"} eq "Class") { my $Skip = setBaseClasses($TypeId, \%TypeAttr); if($Skip) { return (); } } if(my $Algn = getAlgn($TypeId)) { $TypeAttr{"Algn"} = $Algn/$BYTE_SIZE; } setSpec($TypeId, \%TypeAttr); if($TypeAttr{"Type"}=~/\A(Struct|Union|Enum)\Z/) { if(not $TypedefToAnon{$TypeId} and not defined $TemplateInstance{$Version}{"Type"}{$TypeId}) { if(not isAnon($TypeAttr{"Name"})) { $TypeAttr{"Name"} = lc($TypeAttr{"Type"})." ".$TypeAttr{"Name"}; } } } $TypeAttr{"Tid"} = $TypeId; if(my $VTable = $ClassVTable_Content{$Version}{$TypeAttr{"Name"}}) { my @Entries = split(/\n/, $VTable); foreach (1 .. $#Entries) { my $Entry = $Entries[$_]; if($Entry=~/\A(\d+)\s+(.+)\Z/) { $TypeAttr{"VTable"}{$1} = simplifyVTable($2); } } } if($TypeAttr{"Type"} eq "Enum") { if(not $TypeAttr{"NameSpace"}) { foreach my $Pos (keys(%{$TypeAttr{"Memb"}})) { my $MName = $TypeAttr{"Memb"}{$Pos}{"name"}; my $MVal = $TypeAttr{"Memb"}{$Pos}{"value"}; $EnumConstants{$Version}{$MName} = { "Value"=>$MVal, "Header"=>$TypeAttr{"Header"} }; if(isAnon($TypeAttr{"Name"})) { if($ExtraDump or is_target_header($TypeAttr{"Header"}, $Version)) { %{$Constants{$Version}{$MName}} = ( "Value" => $MVal, "Header" => $TypeAttr{"Header"} ); } } } } } if($ExtraDump) { if(defined $TypedefToAnon{$TypeId}) { $TypeAttr{"AnonTypedef"} = 1; } } return %TypeAttr; } sub simplifyVTable($) { my $Content = $_[0]; if($Content=~s/ \[with (.+)]//) { # std::basic_streambuf<_CharT, _Traits>::imbue [with _CharT = char, _Traits = std::char_traits] if(my @Elems = separate_Params($1, 0, 0)) { foreach my $Elem (@Elems) { if($Elem=~/\A(.+?)\s*=\s*(.+?)\Z/) { my ($Arg, $Val) = ($1, $2); if(defined $DEFAULT_STD_ARGS{$Arg}) { $Content=~s/,\s*$Arg\b//g; } else { $Content=~s/\b$Arg\b/$Val/g; } } } } } return $Content; } sub detect_lang($) { my $TypeId = $_[0]; my $Info = $LibInfo{$Version}{"info"}{$TypeId}; if(check_gcc($GCC_PATH, "4")) { # GCC 4 fncs-node points to only non-artificial methods return ($Info=~/(fncs)[ ]*:[ ]*@(\d+) /); } else { # GCC 3 my $Fncs = getTreeAttr_Fncs($TypeId); while($Fncs) { if($LibInfo{$Version}{"info"}{$Fncs}!~/artificial/) { return 1; } $Fncs = getTreeAttr_Chan($Fncs); } } return 0; } sub setSpec($$) { my ($TypeId, $TypeAttr) = @_; my $Info = $LibInfo{$Version}{"info"}{$TypeId}; if($Info=~/\s+spec\s+/) { $TypeAttr->{"Spec"} = 1; } } sub setBaseClasses($$) { my ($TypeId, $TypeAttr) = @_; my $Info = $LibInfo{$Version}{"info"}{$TypeId}; if(my $Binf = getTreeAttr_Binf($TypeId)) { my $Info = $LibInfo{$Version}{"info"}{$Binf}; my $Pos = 0; while($Info=~s/(pub|public|prot|protected|priv|private|)[ ]+binf[ ]*:[ ]*@(\d+) //) { my ($Access, $BInfoId) = ($1, $2); my $ClassId = getBinfClassId($BInfoId); if($ClassId==$TypeId) { # class A:public A next; } my $CType = $LibInfo{$Version}{"info_type"}{$ClassId}; if(not $CType or $CType eq "template_type_parm" or $CType eq "typename_type") { # skip # return 1; } my $BaseInfo = $LibInfo{$Version}{"info"}{$BInfoId}; if($Access=~/prot/) { $TypeAttr->{"Base"}{$ClassId}{"access"} = "protected"; } elsif($Access=~/priv/) { $TypeAttr->{"Base"}{$ClassId}{"access"} = "private"; } $TypeAttr->{"Base"}{$ClassId}{"pos"} = "$Pos"; if($BaseInfo=~/virt/) { # virtual base $TypeAttr->{"Base"}{$ClassId}{"virtual"} = 1; } $Class_SubClasses{$Version}{$ClassId}{$TypeId}=1; $Pos += 1; } } return 0; } sub getBinfClassId($) { my $Info = $LibInfo{$Version}{"info"}{$_[0]}; $Info=~/type[ ]*:[ ]*@(\d+) /; return $1; } sub unmangledFormat($$) { my ($Name, $LibVersion) = @_; $Name = uncover_typedefs($Name, $LibVersion); while($Name=~s/([^\w>*])(const|volatile)(,|>|\Z)/$1$3/g){}; $Name=~s/\(\w+\)(\d)/$1/; return $Name; } sub modelUnmangled($$) { my ($InfoId, $Compiler) = @_; if($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId}) { return $Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId}; } my $PureSignature = $SymbolInfo{$Version}{$InfoId}{"ShortName"}; if($SymbolInfo{$Version}{$InfoId}{"Destructor"}) { $PureSignature = "~".$PureSignature; } if(not $SymbolInfo{$Version}{$InfoId}{"Data"}) { my (@Params, @ParamTypes) = (); if(defined $SymbolInfo{$Version}{$InfoId}{"Param"} and not $SymbolInfo{$Version}{$InfoId}{"Destructor"}) { @Params = keys(%{$SymbolInfo{$Version}{$InfoId}{"Param"}}); } foreach my $ParamPos (sort {int($a) <=> int($b)} @Params) { # checking parameters my $PId = $SymbolInfo{$Version}{$InfoId}{"Param"}{$ParamPos}{"type"}; my $PName = $SymbolInfo{$Version}{$InfoId}{"Param"}{$ParamPos}{"name"}; my %PType = get_PureType($PId, $TypeInfo{$Version}); my $PTName = unmangledFormat($PType{"Name"}, $Version); if($PName eq "this" and $SymbolInfo{$Version}{$InfoId}{"Type"} eq "Method") { next; } $PTName=~s/\b(restrict|register)\b//g; if($Compiler eq "MSVC") { $PTName=~s/\blong long\b/__int64/; } @ParamTypes = (@ParamTypes, $PTName); } if(@ParamTypes) { $PureSignature .= "(".join(", ", @ParamTypes).")"; } else { if($Compiler eq "MSVC") { $PureSignature .= "(void)"; } else { # GCC $PureSignature .= "()"; } } $PureSignature = delete_keywords($PureSignature); } if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"}) { my $ClassName = unmangledFormat($TypeInfo{$Version}{$ClassId}{"Name"}, $Version); $PureSignature = $ClassName."::".$PureSignature; } elsif(my $NS = $SymbolInfo{$Version}{$InfoId}{"NameSpace"}) { $PureSignature = $NS."::".$PureSignature; } if($SymbolInfo{$Version}{$InfoId}{"Const"}) { $PureSignature .= " const"; } if($SymbolInfo{$Version}{$InfoId}{"Volatile"}) { $PureSignature .= " volatile"; } my $ShowReturn = 0; if($Compiler eq "MSVC" and $SymbolInfo{$Version}{$InfoId}{"Data"}) { $ShowReturn=1; } elsif(defined $TemplateInstance{$Version}{"Func"}{$InfoId} and keys(%{$TemplateInstance{$Version}{"Func"}{$InfoId}})) { $ShowReturn=1; } if($ShowReturn) { # mangled names for template function specializations include return value if(my $ReturnId = $SymbolInfo{$Version}{$InfoId}{"Return"}) { my %RType = get_PureType($ReturnId, $TypeInfo{$Version}); my $ReturnName = unmangledFormat($RType{"Name"}, $Version); $PureSignature = $ReturnName." ".$PureSignature; } } return ($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId} = formatName($PureSignature, "S")); } sub mangle_symbol($$$) { # mangling for simple methods # see gcc-4.6.0/gcc/cp/mangle.c my ($InfoId, $LibVersion, $Compiler) = @_; if($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler}) { return $Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler}; } my $Mangled = ""; if($Compiler eq "GCC") { $Mangled = mangle_symbol_GCC($InfoId, $LibVersion); } elsif($Compiler eq "MSVC") { $Mangled = mangle_symbol_MSVC($InfoId, $LibVersion); } return ($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler} = $Mangled); } sub mangle_symbol_MSVC($$) { my ($InfoId, $LibVersion) = @_; return ""; } sub mangle_symbol_GCC($$) { # see gcc-4.6.0/gcc/cp/mangle.c my ($InfoId, $LibVersion) = @_; my ($Mangled, $ClassId, $NameSpace) = ("_Z", 0, ""); my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"}; my %Repl = ();# SN_ replacements if($ClassId = $SymbolInfo{$LibVersion}{$InfoId}{"Class"}) { my $MangledClass = mangle_param($ClassId, $LibVersion, \%Repl); if($MangledClass!~/\AN/) { $MangledClass = "N".$MangledClass; } else { $MangledClass=~s/E\Z//; } if($SymbolInfo{$LibVersion}{$InfoId}{"Volatile"}) { $MangledClass=~s/\AN/NV/; } if($SymbolInfo{$LibVersion}{$InfoId}{"Const"}) { $MangledClass=~s/\AN/NK/; } $Mangled .= $MangledClass; } elsif($NameSpace = $SymbolInfo{$LibVersion}{$InfoId}{"NameSpace"}) { # mangled by name due to the absence of structured info my $MangledNS = mangle_ns($NameSpace, $LibVersion, \%Repl); if($MangledNS!~/\AN/) { $MangledNS = "N".$MangledNS; } else { $MangledNS=~s/E\Z//; } $Mangled .= $MangledNS; } my ($ShortName, $TmplParams) = template_Base($SymbolInfo{$LibVersion}{$InfoId}{"ShortName"}); my @TParams = (); if(my @TPos = keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"TParam"}})) { # parsing mode foreach (@TPos) { push(@TParams, $SymbolInfo{$LibVersion}{$InfoId}{"TParam"}{$_}{"name"}); } } elsif($TmplParams) { # remangling mode # support for old ABI dumps @TParams = separate_Params($TmplParams, 0, 0); } if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"}) { $Mangled .= "C1"; } elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) { $Mangled .= "D0"; } elsif($ShortName) { if($SymbolInfo{$LibVersion}{$InfoId}{"Data"}) { if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"} and isConstType($Return, $LibVersion)) { # "const" global data is mangled as _ZL... $Mangled .= "L"; } } if($ShortName=~/\Aoperator(\W.*)\Z/) { my $Op = $1; $Op=~s/\A[ ]+//g; if(my $OpMngl = $OperatorMangling{$Op}) { $Mangled .= $OpMngl; } else { # conversion operator $Mangled .= "cv".mangle_param(getTypeIdByName($Op, $LibVersion), $LibVersion, \%Repl); } } else { $Mangled .= length($ShortName).$ShortName; } if(@TParams) { # templates $Mangled .= "I"; foreach my $TParam (@TParams) { $Mangled .= mangle_template_param($TParam, $LibVersion, \%Repl); } $Mangled .= "E"; } if(not $ClassId and @TParams) { add_substitution($ShortName, \%Repl, 0); } } if($ClassId or $NameSpace) { $Mangled .= "E"; } if(@TParams) { if($Return) { $Mangled .= mangle_param($Return, $LibVersion, \%Repl); } } if(not $SymbolInfo{$LibVersion}{$InfoId}{"Data"}) { my @Params = (); if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"} and not $SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) { @Params = keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}}); } foreach my $ParamPos (sort {int($a) <=> int($b)} @Params) { # checking parameters my $ParamType_Id = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$ParamPos}{"type"}; $Mangled .= mangle_param($ParamType_Id, $LibVersion, \%Repl); } if(not @Params) { $Mangled .= "v"; } } $Mangled = correct_incharge($InfoId, $LibVersion, $Mangled); $Mangled = write_stdcxx_substitution($Mangled); if($Mangled eq "_Z") { return ""; } return $Mangled; } sub correct_incharge($$$) { my ($InfoId, $LibVersion, $Mangled) = @_; if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"}) { if($MangledNames{$LibVersion}{$Mangled}) { $Mangled=~s/C1([EI])/C2$1/; } } elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) { if($MangledNames{$LibVersion}{$Mangled}) { $Mangled=~s/D0([EI])/D1$1/; } if($MangledNames{$LibVersion}{$Mangled}) { $Mangled=~s/D1([EI])/D2$1/; } } return $Mangled; } sub template_Base($) { # NOTE: std::_Vector_base::_Vector_impl # NOTE: operators: >>, << my $Name = $_[0]; if($Name!~/>\Z/ or $Name!~/ $TParams = substr($TParams, $CPos); } if($TParams=~s/\A<(.+)>\Z/$1/) { $Name=~s/<\Q$TParams\E>\Z//; } else { # error $TParams = ""; } return ($Name, $TParams); } sub get_sub_ns($) { my $Name = $_[0]; my @NS = (); while(my $CPos = find_center($Name, ":")) { push(@NS, substr($Name, 0, $CPos)); $Name = substr($Name, $CPos); $Name=~s/\A:://; } return (join("::", @NS), $Name); } sub mangle_ns($$$) { my ($Name, $LibVersion, $Repl) = @_; if(my $Tid = $TName_Tid{$LibVersion}{$Name}) { my $Mangled = mangle_param($Tid, $LibVersion, $Repl); $Mangled=~s/\AN(.+)E\Z/$1/; return $Mangled; } else { my ($MangledNS, $SubNS) = ("", ""); ($SubNS, $Name) = get_sub_ns($Name); if($SubNS) { $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl); } $MangledNS .= length($Name).$Name; add_substitution($MangledNS, $Repl, 0); return $MangledNS; } } sub mangle_param($$$) { my ($PTid, $LibVersion, $Repl) = @_; my ($MPrefix, $Mangled) = ("", ""); my %ReplCopy = %{$Repl}; my %BaseType = get_BaseType($PTid, $LibVersion); my $BaseType_Name = $BaseType{"Name"}; $BaseType_Name=~s/\A(struct|union|enum) //g; if(not $BaseType_Name) { return ""; } my ($ShortName, $TmplParams) = template_Base($BaseType_Name); my $Suffix = get_BaseTypeQual($PTid, $LibVersion); while($Suffix=~s/\s*(const|volatile|restrict)\Z//g){}; while($Suffix=~/(&|\*|const)\Z/) { if($Suffix=~s/[ ]*&\Z//) { $MPrefix .= "R"; } if($Suffix=~s/[ ]*\*\Z//) { $MPrefix .= "P"; } if($Suffix=~s/[ ]*const\Z//) { if($MPrefix=~/R|P/ or $Suffix=~/&|\*/) { $MPrefix .= "K"; } } if($Suffix=~s/[ ]*volatile\Z//) { $MPrefix .= "V"; } #if($Suffix=~s/[ ]*restrict\Z//) { #$MPrefix .= "r"; #} } if(my $Token = $IntrinsicMangling{$BaseType_Name}) { $Mangled .= $Token; } elsif($BaseType{"Type"}=~/(Class|Struct|Union|Enum)/) { my @TParams = (); if(my @TPos = keys(%{$BaseType{"TParam"}})) { # parsing mode foreach (@TPos) { push(@TParams, $BaseType{"TParam"}{$_}{"name"}); } } elsif($TmplParams) { # remangling mode # support for old ABI dumps @TParams = separate_Params($TmplParams, 0, 0); } my $MangledNS = ""; my ($SubNS, $SName) = get_sub_ns($ShortName); if($SubNS) { $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl); } $MangledNS .= length($SName).$SName; if(@TParams) { add_substitution($MangledNS, $Repl, 0); } $Mangled .= "N".$MangledNS; if(@TParams) { # templates $Mangled .= "I"; foreach my $TParam (@TParams) { $Mangled .= mangle_template_param($TParam, $LibVersion, $Repl); } $Mangled .= "E"; } $Mangled .= "E"; } elsif($BaseType{"Type"}=~/(FuncPtr|MethodPtr)/) { if($BaseType{"Type"} eq "MethodPtr") { $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl)."F"; } else { $Mangled .= "PF"; } $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl); my @Params = keys(%{$BaseType{"Param"}}); foreach my $Num (sort {int($a)<=>int($b)} @Params) { $Mangled .= mangle_param($BaseType{"Param"}{$Num}{"type"}, $LibVersion, $Repl); } if(not @Params) { $Mangled .= "v"; } $Mangled .= "E"; } elsif($BaseType{"Type"} eq "FieldPtr") { $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl); $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl); } $Mangled = $MPrefix.$Mangled;# add prefix (RPK) if(my $Optimized = write_substitution($Mangled, \%ReplCopy)) { if($Mangled eq $Optimized) { if($ShortName!~/::/) { # remove "N ... E" if($MPrefix) { $Mangled=~s/\A($MPrefix)N(.+)E\Z/$1$2/g; } else { $Mangled=~s/\AN(.+)E\Z/$1/g; } } } else { $Mangled = $Optimized; } } add_substitution($Mangled, $Repl, 1); return $Mangled; } sub mangle_template_param($$$) { # types + literals my ($TParam, $LibVersion, $Repl) = @_; if(my $TPTid = $TName_Tid{$LibVersion}{$TParam}) { return mangle_param($TPTid, $LibVersion, $Repl); } elsif($TParam=~/\A(\d+)(\w+)\Z/) { # class_name<1u>::method(...) return "L".$IntrinsicMangling{$ConstantSuffixR{$2}}.$1."E"; } elsif($TParam=~/\A\(([\w ]+)\)(\d+)\Z/) { # class_name<(signed char)1>::method(...) return "L".$IntrinsicMangling{$1}.$2."E"; } elsif($TParam eq "true") { # class_name::method(...) return "Lb1E"; } elsif($TParam eq "false") { # class_name::method(...) return "Lb0E"; } else { # internal error return length($TParam).$TParam; } } sub add_substitution($$$) { my ($Value, $Repl, $Rec) = @_; if($Rec) { # subtypes my @Subs = ($Value); while($Value=~s/\A(R|P|K)//) { push(@Subs, $Value); } foreach (reverse(@Subs)) { add_substitution($_, $Repl, 0); } return; } return if($Value=~/\AS(\d*)_\Z/); $Value=~s/\AN(.+)E\Z/$1/g; return if(defined $Repl->{$Value}); return if(length($Value)<=1); return if($StdcxxMangling{$Value}); # check for duplicates my $Base = $Value; foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl})) { my $Num = $Repl->{$Type}; my $Replace = macro_mangle($Num); $Base=~s/\Q$Replace\E/$Type/; } if(my $OldNum = $Repl->{$Base}) { $Repl->{$Value} = $OldNum; return; } my @Repls = sort {$b<=>$a} values(%{$Repl}); if(@Repls) { $Repl->{$Value} = $Repls[0]+1; } else { $Repl->{$Value} = -1; } # register duplicates # upward $Base = $Value; foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl})) { next if($Base eq $Type); my $Num = $Repl->{$Type}; my $Replace = macro_mangle($Num); $Base=~s/\Q$Type\E/$Replace/; $Repl->{$Base} = $Repl->{$Value}; } } sub macro_mangle($) { my $Num = $_[0]; if($Num==-1) { return "S_"; } else { my $Code = ""; if($Num<10) { # S0_, S1_, S2_, ... $Code = $Num; } elsif($Num>=10 and $Num<=35) { # SA_, SB_, SC_, ... $Code = chr(55+$Num); } else { # S10_, S11_, S12_ $Code = $Num-26; # 26 is length of english alphabet } return "S".$Code."_"; } } sub write_stdcxx_substitution($) { my $Mangled = $_[0]; if($StdcxxMangling{$Mangled}) { return $StdcxxMangling{$Mangled}; } else { my @Repls = keys(%StdcxxMangling); @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls; foreach my $MangledType (@Repls) { my $Replace = $StdcxxMangling{$MangledType}; #if($Mangled!~/$Replace/) { $Mangled=~s/N\Q$MangledType\EE/$Replace/g; $Mangled=~s/\Q$MangledType\E/$Replace/g; #} } } return $Mangled; } sub write_substitution($$) { my ($Mangled, $Repl) = @_; if(defined $Repl->{$Mangled} and my $MnglNum = $Repl->{$Mangled}) { $Mangled = macro_mangle($MnglNum); } else { my @Repls = keys(%{$Repl}); #@Repls = sort {$Repl->{$a}<=>$Repl->{$b}} @Repls; # FIXME: how to apply replacements? by num or by pos @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls; foreach my $MangledType (@Repls) { my $Replace = macro_mangle($Repl->{$MangledType}); if($Mangled!~/$Replace/) { $Mangled=~s/N\Q$MangledType\EE/$Replace/g; $Mangled=~s/\Q$MangledType\E/$Replace/g; } } } return $Mangled; } sub delete_keywords($) { my $TypeName = $_[0]; $TypeName=~s/\b(enum|struct|union|class) //g; return $TypeName; } sub uncover_typedefs($$) { my ($TypeName, $LibVersion) = @_; return "" if(not $TypeName); if(defined $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName}) { return $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName}; } my ($TypeName_New, $TypeName_Pre) = (formatName($TypeName, "T"), ""); while($TypeName_New ne $TypeName_Pre) { $TypeName_Pre = $TypeName_New; my $TypeName_Copy = $TypeName_New; my %Words = (); while($TypeName_Copy=~s/\b([a-z_]([\w:]*\w|))\b//io) { if(not $Intrinsic_Keywords{$1}) { $Words{$1} = 1; } } foreach my $Word (keys(%Words)) { my $BaseType_Name = $Typedef_BaseName{$LibVersion}{$Word}; next if(not $BaseType_Name); next if($TypeName_New=~/\b(struct|union|enum)\s\Q$Word\E\b/); if($BaseType_Name=~/\([\*]+\)/) { # FuncPtr if($TypeName_New=~/\Q$Word\E(.*)\Z/) { my $Type_Suffix = $1; $TypeName_New = $BaseType_Name; if($TypeName_New=~s/\(([\*]+)\)/($1 $Type_Suffix)/) { $TypeName_New = formatName($TypeName_New, "T"); } } } else { if($TypeName_New=~s/\b\Q$Word\E\b/$BaseType_Name/g) { $TypeName_New = formatName($TypeName_New, "T"); } } } } return ($Cache{"uncover_typedefs"}{$LibVersion}{$TypeName} = $TypeName_New); } sub isInternal($) { if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/mngl[ ]*:[ ]*@(\d+) /) { if($LibInfo{$Version}{"info"}{$1}=~/\*[ ]*INTERNAL[ ]*\*/) { # _ZN7mysqlpp8DateTimeC1ERKS0_ *INTERNAL* return 1; } } } return 0; } sub getDataVal($$) { my ($InfoId, $TypeId) = @_; if(my $Info = $LibInfo{$Version}{"info"}{$InfoId}) { if($Info=~/init[ ]*:[ ]*@(\d+) /) { if(defined $LibInfo{$Version}{"info_type"}{$1} and $LibInfo{$Version}{"info_type"}{$1} eq "nop_expr") { if(my $Nop = getTreeAttr_Op($1)) { if(defined $LibInfo{$Version}{"info_type"}{$Nop} and $LibInfo{$Version}{"info_type"}{$Nop} eq "addr_expr") { if(my $Addr = getTreeAttr_Op($1)) { return getInitVal($Addr, $TypeId); } } } } else { return getInitVal($1, $TypeId); } } } return undef; } sub getInitVal($$) { my ($InfoId, $TypeId) = @_; if(my $Info = $LibInfo{$Version}{"info"}{$InfoId}) { if(my $InfoType = $LibInfo{$Version}{"info_type"}{$InfoId}) { if($InfoType eq "integer_cst") { my $Val = getNodeIntCst($InfoId); if($TypeId and $TypeInfo{$Version}{$TypeId}{"Name"}=~/\Achar(| const)\Z/) { # characters $Val = chr($Val); } return $Val; } elsif($InfoType eq "string_cst") { return getNodeStrCst($InfoId); } elsif($InfoType eq "var_decl") { if(my $Name = getNodeStrCst(getTreeAttr_Mngl($InfoId))) { return $Name; } } } } return undef; } sub set_Class_And_Namespace($) { my $InfoId = $_[0]; if(my $Info = $LibInfo{$Version}{"info"}{$InfoId}) { if($Info=~/scpe[ ]*:[ ]*@(\d+) /) { my $NSInfoId = $1; if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId}) { if($InfoType eq "namespace_decl") { $SymbolInfo{$Version}{$InfoId}{"NameSpace"} = getNameSpace($InfoId); } elsif($InfoType eq "record_type") { $SymbolInfo{$Version}{$InfoId}{"Class"} = $NSInfoId; } } } } if($SymbolInfo{$Version}{$InfoId}{"Class"} or $SymbolInfo{$Version}{$InfoId}{"NameSpace"}) { if($COMMON_LANGUAGE{$Version} ne "C++") { # skip return 1; } } return 0; } sub debugMangling($) { my $LibVersion = $_[0]; my %Mangled = (); foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}})) { if(my $Mngl = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"}) { if($Mngl=~/\A(_Z|\?)/) { $Mangled{$Mngl}=$InfoId; } } } translateSymbols(keys(%Mangled), $LibVersion); foreach my $Mngl (keys(%Mangled)) { my $U1 = modelUnmangled($Mangled{$Mngl}, "GCC"); my $U2 = $tr_name{$Mngl}; if($U1 ne $U2) { printMsg("INFO", "INCORRECT MANGLING:\n $Mngl\n $U1\n $U2\n"); } } } sub linkSymbol($) { # link symbols from shared libraries # with the symbols from header files my $InfoId = $_[0]; # try to mangle symbol if((not check_gcc($GCC_PATH, "4") and $SymbolInfo{$Version}{$InfoId}{"Class"}) or (check_gcc($GCC_PATH, "4") and not $SymbolInfo{$Version}{$InfoId}{"Class"}) or $EMERGENCY_MODE_48) { # GCC 3.x doesn't mangle class methods names in the TU dump (only functions and global data) # GCC 4.x doesn't mangle C++ functions in the TU dump (only class methods) except extern "C" functions # GCC 4.8 doesn't mangle anything if(not $CheckHeadersOnly) { if(my $Mangled = $mangled_name_gcc{modelUnmangled($InfoId, "GCC")}) { return correct_incharge($InfoId, $Version, $Mangled); } } if($CheckHeadersOnly or not $BinaryOnly or $EMERGENCY_MODE_48) { # 1. --headers-only mode # 2. not mangled src-only symbols if(my $Mangled = mangle_symbol($InfoId, $Version, "GCC")) { return $Mangled; } } } return ""; } sub setLanguage($$) { my ($LibVersion, $Lang) = @_; if(not $UserLang) { $COMMON_LANGUAGE{$LibVersion} = $Lang; } } sub getSymbolInfo($) { my $InfoId = $_[0]; if(isInternal($InfoId)) { return; } ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId); if(not $SymbolInfo{$Version}{$InfoId}{"Header"} or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"})) { delete($SymbolInfo{$Version}{$InfoId}); return; } setFuncAccess($InfoId); setFuncKind($InfoId); if($SymbolInfo{$Version}{$InfoId}{"PseudoTemplate"}) { delete($SymbolInfo{$Version}{$InfoId}); return; } $SymbolInfo{$Version}{$InfoId}{"Type"} = getFuncType($InfoId); if(my $Return = getFuncReturn($InfoId)) { if(not defined $TypeInfo{$Version}{$Return} or not $TypeInfo{$Version}{$Return}{"Name"}) { delete($SymbolInfo{$Version}{$InfoId}); return; } $SymbolInfo{$Version}{$InfoId}{"Return"} = $Return; } if(my $Rid = $SymbolInfo{$Version}{$InfoId}{"Return"}) { if(defined $MissedTypedef{$Version}{$Rid}) { if(my $AddedTid = $MissedTypedef{$Version}{$Rid}{"Tid"}) { $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid; } } } if(not $SymbolInfo{$Version}{$InfoId}{"Return"}) { delete($SymbolInfo{$Version}{$InfoId}{"Return"}); } my $Orig = getFuncOrig($InfoId); $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getFuncShortName($Orig); if(index($SymbolInfo{$Version}{$InfoId}{"ShortName"}, "\._")!=-1) { delete($SymbolInfo{$Version}{$InfoId}); return; } if(index($SymbolInfo{$Version}{$InfoId}{"ShortName"}, "tmp_add_func")==0) { delete($SymbolInfo{$Version}{$InfoId}); return; } if(defined $TemplateInstance{$Version}{"Func"}{$Orig}) { my $Tmpl = $BasicTemplate{$Version}{$InfoId}; my @TParams = getTParams($Orig, "Func"); if(not @TParams) { delete($SymbolInfo{$Version}{$InfoId}); return; } foreach my $Pos (0 .. $#TParams) { my $Val = $TParams[$Pos]; $SymbolInfo{$Version}{$InfoId}{"TParam"}{$Pos}{"name"} = $Val; if($Tmpl) { if(my $Arg = $TemplateArg{$Version}{$Tmpl}{$Pos}) { $TemplateMap{$Version}{$InfoId}{$Arg} = $Val; } } } if($Tmpl) { foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$TemplateArg{$Version}{$Tmpl}})) { if($Pos>$#TParams) { my $Arg = $TemplateArg{$Version}{$Tmpl}{$Pos}; $TemplateMap{$Version}{$InfoId}{$Arg} = ""; } } } if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\Aoperator\W+\Z/) { # operator<< , operator>> $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= " "; } if(@TParams) { $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= "<".join(", ", @TParams).">"; } else { $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= "<...>"; } $SymbolInfo{$Version}{$InfoId}{"ShortName"} = formatName($SymbolInfo{$Version}{$InfoId}{"ShortName"}, "S"); } else { # support for GCC 3.4 $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//; } if(my $MnglName = getTreeStr(getTreeAttr_Mngl($InfoId))) { if($OSgroup eq "windows") { # cut the offset $MnglName=~s/\@\d+\Z//g; } $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $MnglName; # NOTE: mangling of some symbols may change depending on GCC version # GCC 4.6: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2IT_EERKS_IT_E # GCC 4.7: _ZN28QExplicitlySharedDataPointerI11QPixmapDataEC2ERKS1_ } if($SymbolInfo{$Version}{$InfoId}{"MnglName"} and index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_Z")!=0) { delete($SymbolInfo{$Version}{$InfoId}); return; } if(not $SymbolInfo{$Version}{$InfoId}{"Destructor"}) { # destructors have an empty parameter list my $Skip = setFuncParams($InfoId); if($Skip) { delete($SymbolInfo{$Version}{$InfoId}); return; } } if($LibInfo{$Version}{"info"}{$InfoId}=~/ artificial /i) { $SymbolInfo{$Version}{$InfoId}{"Artificial"} = 1; } if(set_Class_And_Namespace($InfoId)) { delete($SymbolInfo{$Version}{$InfoId}); return; } if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"}) { if(not defined $TypeInfo{$Version}{$ClassId} or not $TypeInfo{$Version}{$ClassId}{"Name"}) { delete($SymbolInfo{$Version}{$InfoId}); return; } } if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i) { # extern "C" $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C"; $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"}; } if($UserLang and $UserLang eq "C") { # --lang=C option $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"}; } if($COMMON_LANGUAGE{$Version} eq "C++") { # correct mangled & short names # C++ or --headers-only mode if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\A__(comp|base|deleting)_(c|d)tor\Z/) { # support for old GCC versions: reconstruct real names for constructors and destructors $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getNameByInfo(getTypeDeclId($SymbolInfo{$Version}{$InfoId}{"Class"})); $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//; } if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) { # try to mangle symbol (link with libraries) if(my $Mangled = linkSymbol($InfoId)) { $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled; } } if($OStarget eq "windows") { # link MS C++ symbols from library with GCC symbols from headers if(my $Mangled1 = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")}) { # exported symbols $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled1; } elsif(my $Mangled2 = mangle_symbol($InfoId, $Version, "MSVC")) { # pure virtual symbols $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled2; } } } else { # not mangled in C $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"}; } if(not $CheckHeadersOnly and $SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function" and not $SymbolInfo{$Version}{$InfoId}{"Class"}) { my $Incorrect = 0; if($SymbolInfo{$Version}{$InfoId}{"MnglName"}) { if(index($SymbolInfo{$Version}{$InfoId}{"MnglName"}, "_Z")==0 and not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps")) { # mangled in the TU dump, but not mangled in the library $Incorrect = 1; } } else { if($SymbolInfo{$Version}{$InfoId}{"Lang"} ne "C") { # all C++ functions are not mangled in the TU dump $Incorrect = 1; } } if($Incorrect) { if(link_symbol($SymbolInfo{$Version}{$InfoId}{"ShortName"}, $Version, "-Deps")) { $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"}; } } } if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) { # can't detect symbol name delete($SymbolInfo{$Version}{$InfoId}); return; } if(not $SymbolInfo{$Version}{$InfoId}{"Constructor"} and my $Spec = getVirtSpec($Orig)) { # identify virtual and pure virtual functions # NOTE: constructors cannot be virtual # NOTE: in GCC 4.7 D1 destructors have no virtual spec # in the TU dump, so taking it from the original symbol if(not ($SymbolInfo{$Version}{$InfoId}{"Destructor"} and $SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/D2E/)) { # NOTE: D2 destructors are not present in a v-table $SymbolInfo{$Version}{$InfoId}{$Spec} = 1; } } if(isInline($InfoId)) { $SymbolInfo{$Version}{$InfoId}{"InLine"} = 1; } if(hasThrow($InfoId)) { $SymbolInfo{$Version}{$InfoId}{"Throw"} = 1; } if($SymbolInfo{$Version}{$InfoId}{"Constructor"} and my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"}) { if(not $SymbolInfo{$Version}{$InfoId}{"InLine"} and not $SymbolInfo{$Version}{$InfoId}{"Artificial"}) { # inline or auto-generated constructor delete($TypeInfo{$Version}{$ClassId}{"Copied"}); } } if(my $Symbol = $SymbolInfo{$Version}{$InfoId}{"MnglName"}) { if(not $ExtraDump) { if(not selectSymbol($Symbol, $SymbolInfo{$Version}{$InfoId}, "Dump", $Version)) { # non-target symbols delete($SymbolInfo{$Version}{$InfoId}); return; } } } if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Method" or $SymbolInfo{$Version}{$InfoId}{"Constructor"} or $SymbolInfo{$Version}{$InfoId}{"Destructor"} or $SymbolInfo{$Version}{$InfoId}{"Class"}) { if($SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A(_Z|\?)/) { delete($SymbolInfo{$Version}{$InfoId}); return; } } if($SymbolInfo{$Version}{$InfoId}{"MnglName"}) { if($MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}}) { # one instance for one mangled name only delete($SymbolInfo{$Version}{$InfoId}); return; } else { $MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}} = 1; } } if($SymbolInfo{$Version}{$InfoId}{"Constructor"} or $SymbolInfo{$Version}{$InfoId}{"Destructor"}) { delete($SymbolInfo{$Version}{$InfoId}{"Return"}); } if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/ and $SymbolInfo{$Version}{$InfoId}{"Class"}) { if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function") { # static methods $SymbolInfo{$Version}{$InfoId}{"Static"} = 1; } } if(getFuncLink($InfoId) eq "Static") { $SymbolInfo{$Version}{$InfoId}{"Static"} = 1; } if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/) { if(my $Unmangled = $tr_name{$SymbolInfo{$Version}{$InfoId}{"MnglName"}}) { if($Unmangled=~/\.\_\d/) { delete($SymbolInfo{$Version}{$InfoId}); return; } } } if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(V|)K/) { $SymbolInfo{$Version}{$InfoId}{"Const"} = 1; } if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(K|)V/) { $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1; } if($WeakSymbols{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}}) { $SymbolInfo{$Version}{$InfoId}{"Weak"} = 1; } if($ExtraDump) { $SymbolInfo{$Version}{$InfoId}{"Header"} = guessHeader($InfoId); } } sub guessHeader($) { my $InfoId = $_[0]; my $ShortName = $SymbolInfo{$Version}{$InfoId}{"ShortName"}; my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"}; my $ClassName = $ClassId?get_ShortClass($ClassId, $Version):""; my $Header = $SymbolInfo{$Version}{$InfoId}{"Header"}; if(my $HPath = $SymbolHeader{$Version}{$ClassName}{$ShortName}) { if(get_filename($HPath) eq $Header) { my $HDir = get_filename(get_dirname($HPath)); if($HDir ne "include" and $HDir=~/\A[a-z]+\Z/i) { return join_P($HDir, $Header); } } } return $Header; } sub isInline($) { # "body: undefined" in the tree # -fkeep-inline-functions GCC option should be specified if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/ undefined /i) { return 0; } } return 1; } sub hasThrow($) { if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/type[ ]*:[ ]*@(\d+) /) { return getTreeAttr_Unql($1, "unql"); } } return 1; } sub getTypeId($) { if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/type[ ]*:[ ]*@(\d+) /) { return $1; } } return ""; } sub setTypeMemb($$) { my ($TypeId, $TypeAttr) = @_; my $TypeType = $TypeAttr->{"Type"}; my ($Pos, $UnnamedPos) = (0, 0); my $StaticFields = 0; if($TypeType eq "Enum") { my $MInfoId = getTreeAttr_Csts($TypeId); while($MInfoId) { $TypeAttr->{"Memb"}{$Pos}{"value"} = getEnumMembVal($MInfoId); my $MembName = getTreeStr(getTreeAttr_Purp($MInfoId)); $TypeAttr->{"Memb"}{$Pos}{"name"} = $MembName; $EnumMembName_Id{$Version}{getTreeAttr_Valu($MInfoId)} = ($TypeAttr->{"NameSpace"})?$TypeAttr->{"NameSpace"}."::".$MembName:$MembName; $MInfoId = getNextElem($MInfoId); $Pos += 1; } } elsif($TypeType=~/\A(Struct|Class|Union)\Z/) { my $MInfoId = getTreeAttr_Flds($TypeId); while($MInfoId) { my $IType = $LibInfo{$Version}{"info_type"}{$MInfoId}; my $MInfo = $LibInfo{$Version}{"info"}{$MInfoId}; if(not $IType or $IType ne "field_decl") { # search for fields, skip other stuff in the declaration if($IType eq "var_decl") { # static field $StaticFields = 1; } $MInfoId = getNextElem($MInfoId); next; } my $StructMembName = getTreeStr(getTreeAttr_Name($MInfoId)); if(index($StructMembName, "_vptr.")==0) { # virtual tables $StructMembName = "_vptr"; } if(not $StructMembName) { # unnamed fields if(index($TypeAttr->{"Name"}, "_type_info_pseudo")==-1) { my $UnnamedTid = getTreeAttr_Type($MInfoId); my $UnnamedTName = getNameByInfo(getTypeDeclId($UnnamedTid)); if(isAnon($UnnamedTName)) { # rename unnamed fields to unnamed0, unnamed1, ... $StructMembName = "unnamed".($UnnamedPos++); } } } if(not $StructMembName) { # unnamed fields and base classes $MInfoId = getNextElem($MInfoId); next; } my $MembTypeId = getTreeAttr_Type($MInfoId); if(defined $MissedTypedef{$Version}{$MembTypeId}) { if(my $AddedTid = $MissedTypedef{$Version}{$MembTypeId}{"Tid"}) { $MembTypeId = $AddedTid; } } $TypeAttr->{"Memb"}{$Pos}{"type"} = $MembTypeId; $TypeAttr->{"Memb"}{$Pos}{"name"} = $StructMembName; if((my $Access = getTreeAccess($MInfoId)) ne "public") { # marked only protected and private, public by default $TypeAttr->{"Memb"}{$Pos}{"access"} = $Access; } if($MInfo=~/spec:\s*mutable /) { # mutable fields $TypeAttr->{"Memb"}{$Pos}{"mutable"} = 1; } if(my $Algn = getAlgn($MInfoId)) { $TypeAttr->{"Memb"}{$Pos}{"algn"} = $Algn; } if(my $BFSize = getBitField($MInfoId)) { # in bits $TypeAttr->{"Memb"}{$Pos}{"bitfield"} = $BFSize; } else { # in bytes if($TypeAttr->{"Memb"}{$Pos}{"algn"}==1) { # template delete($TypeAttr->{"Memb"}{$Pos}{"algn"}); } else { $TypeAttr->{"Memb"}{$Pos}{"algn"} /= $BYTE_SIZE; } } $MInfoId = getNextElem($MInfoId); $Pos += 1; } } return $StaticFields; } sub setFuncParams($) { my $InfoId = $_[0]; my $ParamInfoId = getTreeAttr_Args($InfoId); my $FType = getFuncType($InfoId); if($FType eq "Method") { # check type of "this" pointer my $ObjectTypeId = getTreeAttr_Type($ParamInfoId); if(my $ObjectName = $TypeInfo{$Version}{$ObjectTypeId}{"Name"}) { if($ObjectName=~/\bconst(| volatile)\*const\b/) { $SymbolInfo{$Version}{$InfoId}{"Const"} = 1; } if($ObjectName=~/\bvolatile\b/) { $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1; } } else { # skip return 1; } # skip "this"-parameter # $ParamInfoId = getNextElem($ParamInfoId); } my ($Pos, $PPos, $Vtt_Pos) = (0, 0, -1); while($ParamInfoId) { # formal args my $ParamTypeId = getTreeAttr_Type($ParamInfoId); my $ParamName = getTreeStr(getTreeAttr_Name($ParamInfoId)); if(not $ParamName) { # unnamed $ParamName = "p".($PPos+1); } if(defined $MissedTypedef{$Version}{$ParamTypeId}) { if(my $AddedTid = $MissedTypedef{$Version}{$ParamTypeId}{"Tid"}) { $ParamTypeId = $AddedTid; } } my $PType = $TypeInfo{$Version}{$ParamTypeId}{"Type"}; if(not $PType or $PType eq "Unknown") { return 1; } my $PTName = $TypeInfo{$Version}{$ParamTypeId}{"Name"}; if(not $PTName) { return 1; } if($PTName eq "void") { last; } if($ParamName eq "__vtt_parm" and $TypeInfo{$Version}{$ParamTypeId}{"Name"} eq "void const**") { $Vtt_Pos = $Pos; $ParamInfoId = getNextElem($ParamInfoId); next; } $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId; if(my %Base = get_BaseType($ParamTypeId, $Version)) { if(defined $Base{"Template"}) { return 1; } } $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = $ParamName; if(my $Algn = getAlgn($ParamInfoId)) { $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"algn"} = $Algn/$BYTE_SIZE; } if($LibInfo{$Version}{"info"}{$ParamInfoId}=~/spec:\s*register /) { # foo(register type arg) $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"reg"} = 1; } $ParamInfoId = getNextElem($ParamInfoId); $Pos += 1; if($ParamName ne "this" or $FType ne "Method") { $PPos += 1; } } if(setFuncArgs($InfoId, $Vtt_Pos)) { $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = "-1"; } return 0; } sub setFuncArgs($$) { my ($InfoId, $Vtt_Pos) = @_; my $FuncTypeId = getFuncTypeId($InfoId); my $ParamListElemId = getTreeAttr_Prms($FuncTypeId); my $FType = getFuncType($InfoId); if($FType eq "Method") { # skip "this"-parameter # $ParamListElemId = getNextElem($ParamListElemId); } if(not $ParamListElemId) { # foo(...) return 1; } my $HaveVoid = 0; my ($Pos, $PPos) = (0, 0); while($ParamListElemId) { # actual params: may differ from formal args # formal int*const # actual: int* if($Vtt_Pos!=-1 and $Pos==$Vtt_Pos) { $Vtt_Pos=-1; $ParamListElemId = getNextElem($ParamListElemId); next; } my $ParamTypeId = getTreeAttr_Valu($ParamListElemId); if($TypeInfo{$Version}{$ParamTypeId}{"Name"} eq "void") { $HaveVoid = 1; last; } else { if(not defined $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"}) { $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId; if(not $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"}) { # unnamed $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"name"} = "p".($PPos+1); } } elsif(my $OldId = $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"}) { if($Pos>0 or getFuncType($InfoId) ne "Method") { # params if($OldId ne $ParamTypeId) { my %Old_Pure = get_PureType($OldId, $TypeInfo{$Version}); my %New_Pure = get_PureType($ParamTypeId, $TypeInfo{$Version}); if($Old_Pure{"Name"} ne $New_Pure{"Name"}) { $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"type"} = $ParamTypeId; } } } } } if(my $PurpId = getTreeAttr_Purp($ParamListElemId)) { # default arguments if(my $PurpType = $LibInfo{$Version}{"info_type"}{$PurpId}) { if($PurpType eq "nop_expr") { # func ( const char* arg = (const char*)(void*)0 ) $PurpId = getTreeAttr_Op($PurpId); } my $Val = getInitVal($PurpId, $ParamTypeId); if(defined $Val) { $SymbolInfo{$Version}{$InfoId}{"Param"}{$Pos}{"default"} = $Val; } } } $ParamListElemId = getNextElem($ParamListElemId); if($Pos!=0 or $FType ne "Method") { $PPos += 1; } $Pos += 1; } return ($Pos>=1 and not $HaveVoid); } sub getTreeAttr_Chan($) { if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/chan[ ]*:[ ]*@(\d+) /) { return $1; } } return ""; } sub getTreeAttr_Chain($) { if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/chain[ ]*:[ ]*@(\d+) /) { return $1; } } return ""; } sub getTreeAttr_Unql($) { if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/unql[ ]*:[ ]*@(\d+) /) { return $1; } } return ""; } sub getTreeAttr_Scpe($) { if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/scpe[ ]*:[ ]*@(\d+) /) { return $1; } } return ""; } sub getTreeAttr_Type($) { if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/type[ ]*:[ ]*@(\d+) /) { return $1; } } return ""; } sub getTreeAttr_Name($) { if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/name[ ]*:[ ]*@(\d+) /) { return $1; } } return ""; } sub getTreeAttr_Mngl($) { if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/mngl[ ]*:[ ]*@(\d+) /) { return $1; } } return ""; } sub getTreeAttr_Prms($) { if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/prms[ ]*:[ ]*@(\d+) /) { return $1; } } return ""; } sub getTreeAttr_Fncs($) { if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/fncs[ ]*:[ ]*@(\d+) /) { return $1; } } return ""; } sub getTreeAttr_Csts($) { if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/csts[ ]*:[ ]*@(\d+) /) { return $1; } } return ""; } sub getTreeAttr_Purp($) { if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/purp[ ]*:[ ]*@(\d+) /) { return $1; } } return ""; } sub getTreeAttr_Op($) { if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/op 0[ ]*:[ ]*@(\d+) /) { return $1; } } return ""; } sub getTreeAttr_Valu($) { if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/valu[ ]*:[ ]*@(\d+) /) { return $1; } } return ""; } sub getTreeAttr_Flds($) { if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/flds[ ]*:[ ]*@(\d+) /) { return $1; } } return ""; } sub getTreeAttr_Binf($) { if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/binf[ ]*:[ ]*@(\d+) /) { return $1; } } return ""; } sub getTreeAttr_Args($) { if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/args[ ]*:[ ]*@(\d+) /) { return $1; } } return ""; } sub getTreeValue($) { if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/low[ ]*:[ ]*([^ ]+) /) { return $1; } } return ""; } sub getTreeAccess($) { if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/accs[ ]*:[ ]*([a-zA-Z]+) /) { my $Access = $1; if($Access eq "prot") { return "protected"; } elsif($Access eq "priv") { return "private"; } } elsif($Info=~/ protected /) { # support for old GCC versions return "protected"; } elsif($Info=~/ private /) { # support for old GCC versions return "private"; } } return "public"; } sub setFuncAccess($) { my $Access = getTreeAccess($_[0]); if($Access eq "protected") { $SymbolInfo{$Version}{$_[0]}{"Protected"} = 1; } elsif($Access eq "private") { $SymbolInfo{$Version}{$_[0]}{"Private"} = 1; } } sub setTypeAccess($$) { my ($TypeId, $TypeAttr) = @_; my $Access = getTreeAccess($TypeId); if($Access eq "protected") { $TypeAttr->{"Protected"} = 1; } elsif($Access eq "private") { $TypeAttr->{"Private"} = 1; } } sub setFuncKind($) { if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/pseudo tmpl/) { $SymbolInfo{$Version}{$_[0]}{"PseudoTemplate"} = 1; } elsif($Info=~/ constructor /) { $SymbolInfo{$Version}{$_[0]}{"Constructor"} = 1; } elsif($Info=~/ destructor /) { $SymbolInfo{$Version}{$_[0]}{"Destructor"} = 1; } } } sub getVirtSpec($) { if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/spec[ ]*:[ ]*pure /) { return "PureVirt"; } elsif($Info=~/spec[ ]*:[ ]*virt /) { return "Virt"; } elsif($Info=~/ pure\s+virtual /) { # support for old GCC versions return "PureVirt"; } elsif($Info=~/ virtual /) { # support for old GCC versions return "Virt"; } } return ""; } sub getFuncLink($) { if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/link[ ]*:[ ]*static /) { return "Static"; } elsif($Info=~/link[ ]*:[ ]*([a-zA-Z]+) /) { return $1; } } return ""; } sub select_Symbol_NS($$) { my ($Symbol, $LibVersion) = @_; return "" if(not $Symbol or not $LibVersion); my $NS = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"}; if(not $NS) { if(my $Class = $CompleteSignature{$LibVersion}{$Symbol}{"Class"}) { $NS = $TypeInfo{$LibVersion}{$Class}{"NameSpace"}; } } if($NS) { if(defined $NestedNameSpaces{$LibVersion}{$NS}) { return $NS; } else { while($NS=~s/::[^:]+\Z//) { if(defined $NestedNameSpaces{$LibVersion}{$NS}) { return $NS; } } } } return ""; } sub select_Type_NS($$) { my ($TypeName, $LibVersion) = @_; return "" if(not $TypeName or not $LibVersion); if(my $NS = $TypeInfo{$LibVersion}{$TName_Tid{$LibVersion}{$TypeName}}{"NameSpace"}) { if(defined $NestedNameSpaces{$LibVersion}{$NS}) { return $NS; } else { while($NS=~s/::[^:]+\Z//) { if(defined $NestedNameSpaces{$LibVersion}{$NS}) { return $NS; } } } } return ""; } sub getNameSpace($) { my $InfoId = $_[0]; if(my $NSInfoId = getTreeAttr_Scpe($InfoId)) { if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId}) { if($InfoType eq "namespace_decl") { if($LibInfo{$Version}{"info"}{$NSInfoId}=~/name[ ]*:[ ]*@(\d+) /) { my $NameSpace = getTreeStr($1); if($NameSpace eq "::") { # global namespace return ""; } if(my $BaseNameSpace = getNameSpace($NSInfoId)) { $NameSpace = $BaseNameSpace."::".$NameSpace; } $NestedNameSpaces{$Version}{$NameSpace} = 1; return $NameSpace; } else { return ""; } } elsif($InfoType ne "function_decl") { # inside data type my ($Name, $NameNS) = getTrivialName(getTypeDeclId($NSInfoId), $NSInfoId); return $Name; } } } return ""; } sub getEnumMembVal($) { if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/valu[ ]*:[ ]*\@(\d+)/) { if(my $VInfo = $LibInfo{$Version}{"info"}{$1}) { if($VInfo=~/cnst[ ]*:[ ]*\@(\d+)/) { # in newer versions of GCC the value is in the "const_decl->cnst" node return getTreeValue($1); } else { # some old versions of GCC (3.3) have the value in the "integer_cst" node return getTreeValue($1); } } } } return ""; } sub getSize($) { if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/size[ ]*:[ ]*\@(\d+)/) { return getTreeValue($1); } } return 0; } sub getAlgn($) { if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/algn[ ]*:[ ]*(\d+) /) { return $1; } } return ""; } sub getBitField($) { if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/ bitfield /) { return getSize($_[0]); } } return 0; } sub getNextElem($) { if(my $Chan = getTreeAttr_Chan($_[0])) { return $Chan; } elsif(my $Chain = getTreeAttr_Chain($_[0])) { return $Chain; } return ""; } sub registerHeader($$) { # input: absolute path of header, relative path or name my ($Header, $LibVersion) = @_; if(not $Header) { return ""; } if(is_abs($Header) and not -f $Header) { # incorrect absolute path exitStatus("Access_Error", "can't access \'$Header\'"); } if(skipHeader($Header, $LibVersion)) { # skip return ""; } if(my $Header_Path = identifyHeader($Header, $LibVersion)) { detect_header_includes($Header_Path, $LibVersion); if(defined $Tolerance and $Tolerance=~/3/) { # 3 - skip headers that include non-Linux headers if($OSgroup ne "windows") { foreach my $Inc (keys(%{$Header_Includes{$LibVersion}{$Header_Path}})) { if(specificHeader($Inc, "windows")) { return ""; } } } } if(my $RHeader_Path = $Header_ErrorRedirect{$LibVersion}{$Header_Path}) { # redirect if($Registered_Headers{$LibVersion}{$RHeader_Path}{"Identity"} or skipHeader($RHeader_Path, $LibVersion)) { # skip return ""; } $Header_Path = $RHeader_Path; } elsif($Header_ShouldNotBeUsed{$LibVersion}{$Header_Path}) { # skip return ""; } if(my $HName = get_filename($Header_Path)) { # register $Registered_Headers{$LibVersion}{$Header_Path}{"Identity"} = $HName; $HeaderName_Paths{$LibVersion}{$HName}{$Header_Path} = 1; } if(($Header=~/\.(\w+)\Z/ and $1 ne "h") or $Header!~/\.(\w+)\Z/) { # hpp, hh, etc. setLanguage($LibVersion, "C++"); $CPP_HEADERS = 1; } if($CheckHeadersOnly and $Header=~/(\A|\/)c\+\+(\/|\Z)/) { # /usr/include/c++/4.6.1/... $STDCXX_TESTING = 1; } return $Header_Path; } return ""; } sub registerDir($$$) { my ($Dir, $WithDeps, $LibVersion) = @_; $Dir=~s/[\/\\]+\Z//g; return if(not $LibVersion or not $Dir or not -d $Dir); $Dir = get_abs_path($Dir); my $Mode = "All"; if($WithDeps) { if($RegisteredDirs{$LibVersion}{$Dir}{1}) { return; } elsif($RegisteredDirs{$LibVersion}{$Dir}{0}) { $Mode = "DepsOnly"; } } else { if($RegisteredDirs{$LibVersion}{$Dir}{1} or $RegisteredDirs{$LibVersion}{$Dir}{0}) { return; } } $Header_Dependency{$LibVersion}{$Dir} = 1; $RegisteredDirs{$LibVersion}{$Dir}{$WithDeps} = 1; if($Mode eq "DepsOnly") { foreach my $Path (cmd_find($Dir,"d")) { $Header_Dependency{$LibVersion}{$Path} = 1; } return; } foreach my $Path (sort {length($b)<=>length($a)} cmd_find($Dir,"f")) { if($WithDeps) { my $SubDir = $Path; while(($SubDir = get_dirname($SubDir)) ne $Dir) { # register all sub directories $Header_Dependency{$LibVersion}{$SubDir} = 1; } } next if(is_not_header($Path)); next if(ignore_path($Path)); # Neighbors foreach my $Part (get_prefixes($Path)) { $Include_Neighbors{$LibVersion}{$Part} = $Path; } } if(get_filename($Dir) eq "include") { # search for "lib/include/" directory my $LibDir = $Dir; if($LibDir=~s/([\/\\])include\Z/$1lib/g and -d $LibDir) { registerDir($LibDir, $WithDeps, $LibVersion); } } } sub parse_redirect($$$) { my ($Content, $Path, $LibVersion) = @_; my @Errors = (); while($Content=~s/#\s*error\s+([^\n]+?)\s*(\n|\Z)//) { push(@Errors, $1); } my $Redirect = ""; foreach (@Errors) { s/\s{2,}/ /g; if(/(only|must\ include |update\ to\ include |replaced\ with |replaced\ by|renamed\ to |\ is\ in|\ use)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))/ix) { $Redirect = $2; last; } elsif(/(include|use|is\ in)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))\ instead/i) { $Redirect = $2; last; } elsif(/this\ header\ should\ not\ be\ used |programs\ should\ not\ directly\ include |you\ should\ not\ (include|be\ (including|using)\ this\ (file|header)) |is\ not\ supported\ API\ for\ general\ use |do\ not\ use |should\ not\ be\ (used|using) |cannot\ be\ included\ directly/ix and not /\ from\ /i) { $Header_ShouldNotBeUsed{$LibVersion}{$Path} = 1; } } if($Redirect) { $Redirect=~s/\A\Z//g; } return $Redirect; } sub parse_includes($$) { my ($Content, $Path) = @_; my %Includes = (); while($Content=~s/^[ \t]*#[ \t]*(include|include_next|import)[ \t]*([<"].+?[">])[ \t]*//m) { # C/C++: include, Objective C/C++: import directive my $Header = $2; my $Method = substr($Header, 0, 1, ""); substr($Header, length($Header)-1, 1, ""); $Header = path_format($Header, $OSgroup); if($Method eq "\"" or is_abs($Header)) { if(-e join_P(get_dirname($Path), $Header)) { # relative path exists $Includes{$Header} = -1; } else { # include "..." that doesn't exist is equal to include <...> $Includes{$Header} = 2; } } else { $Includes{$Header} = 1; } } if($ExtraInfo) { while($Content=~s/^[ \t]*#[ \t]*(include|include_next|import)[ \t]+(\w+)[ \t]*//m) { # FT_FREETYPE_H $Includes{$2} = 0; } } return \%Includes; } sub ignore_path($) { my $Path = $_[0]; if($Path=~/\~\Z/) {# skipping system backup files return 1; } if($Path=~/(\A|[\/\\]+)(\.(svn|git|bzr|hg)|CVS)([\/\\]+|\Z)/) {# skipping hidden .svn, .git, .bzr, .hg and CVS directories return 1; } return 0; } sub sortByWord($$) { my ($ArrRef, $W) = @_; return if(length($W)<2); @{$ArrRef} = sort {get_filename($b)=~/\Q$W\E/i<=>get_filename($a)=~/\Q$W\E/i} @{$ArrRef}; } sub sortHeaders($$) { my ($H1, $H2) = @_; $H1=~s/\.[a-z]+\Z//ig; $H2=~s/\.[a-z]+\Z//ig; my $Hname1 = get_filename($H1); my $Hname2 = get_filename($H2); my $HDir1 = get_dirname($H1); my $HDir2 = get_dirname($H2); my $Dirname1 = get_filename($HDir1); my $Dirname2 = get_filename($HDir2); $HDir1=~s/\A.*[\/\\]+([^\/\\]+[\/\\]+[^\/\\]+)\Z/$1/; $HDir2=~s/\A.*[\/\\]+([^\/\\]+[\/\\]+[^\/\\]+)\Z/$1/; if($_[0] eq $_[1] or $H1 eq $H2) { return 0; } elsif($H1=~/\A\Q$H2\E/) { return 1; } elsif($H2=~/\A\Q$H1\E/) { return -1; } elsif($HDir1=~/\Q$Hname1\E/i and $HDir2!~/\Q$Hname2\E/i) { # include/glib-2.0/glib.h return -1; } elsif($HDir2=~/\Q$Hname2\E/i and $HDir1!~/\Q$Hname1\E/i) { # include/glib-2.0/glib.h return 1; } elsif($Hname1=~/\Q$Dirname1\E/i and $Hname2!~/\Q$Dirname2\E/i) { # include/hildon-thumbnail/hildon-thumbnail-factory.h return -1; } elsif($Hname2=~/\Q$Dirname2\E/i and $Hname1!~/\Q$Dirname1\E/i) { # include/hildon-thumbnail/hildon-thumbnail-factory.h return 1; } elsif($Hname1=~/(config|lib|util)/i and $Hname2!~/(config|lib|util)/i) { # include/alsa/asoundlib.h return -1; } elsif($Hname2=~/(config|lib|util)/i and $Hname1!~/(config|lib|util)/i) { # include/alsa/asoundlib.h return 1; } else { my $R1 = checkRelevance($H1); my $R2 = checkRelevance($H2); if($R1 and not $R2) { # libebook/e-book.h return -1; } elsif($R2 and not $R1) { # libebook/e-book.h return 1; } else { return (lc($H1) cmp lc($H2)); } } } sub searchForHeaders($) { my $LibVersion = $_[0]; # gcc standard include paths registerGccHeaders(); if($COMMON_LANGUAGE{$LibVersion} eq "C++" and not $STDCXX_TESTING) { # c++ standard include paths registerCppHeaders(); } # processing header paths foreach my $Path (@{$Descriptor{$LibVersion}{"IncludePaths"}}, @{$Descriptor{$LibVersion}{"AddIncludePaths"}}) { my $IPath = $Path; if($SystemRoot) { if(is_abs($Path)) { $Path = $SystemRoot.$Path; } } if(not -e $Path) { exitStatus("Access_Error", "can't access \'$Path\'"); } elsif(-f $Path) { exitStatus("Access_Error", "\'$Path\' - not a directory"); } elsif(-d $Path) { $Path = get_abs_path($Path); registerDir($Path, 0, $LibVersion); if(grep {$IPath eq $_} @{$Descriptor{$LibVersion}{"AddIncludePaths"}}) { push(@{$Add_Include_Paths{$LibVersion}}, $Path); } else { push(@{$Include_Paths{$LibVersion}}, $Path); } } } if(@{$Include_Paths{$LibVersion}}) { $INC_PATH_AUTODETECT{$LibVersion} = 0; } # registering directories foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"})) { next if(not -e $Path); $Path = get_abs_path($Path); $Path = path_format($Path, $OSgroup); if(-d $Path) { registerDir($Path, 1, $LibVersion); } elsif(-f $Path) { my $Dir = get_dirname($Path); if(not grep { $Dir eq $_ } (@{$SystemPaths{"include"}}) and not $LocalIncludes{$Dir}) { registerDir($Dir, 1, $LibVersion); # if(my $OutDir = get_dirname($Dir)) # { # registering the outer directory # if(not grep { $OutDir eq $_ } (@{$SystemPaths{"include"}}) # and not $LocalIncludes{$OutDir}) { # registerDir($OutDir, 0, $LibVersion); # } # } } } } # clean memory %RegisteredDirs = (); # registering headers my $Position = 0; foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"})) { if(is_abs($Dest) and not -e $Dest) { exitStatus("Access_Error", "can't access \'$Dest\'"); } $Dest = path_format($Dest, $OSgroup); if(is_header($Dest, 1, $LibVersion)) { if(my $HPath = registerHeader($Dest, $LibVersion)) { $Registered_Headers{$LibVersion}{$HPath}{"Pos"} = $Position++; } } elsif(-d $Dest) { my @Registered = (); foreach my $Path (cmd_find($Dest,"f")) { next if(ignore_path($Path)); next if(not is_header($Path, 0, $LibVersion)); if(my $HPath = registerHeader($Path, $LibVersion)) { push(@Registered, $HPath); } } @Registered = sort {sortHeaders($a, $b)} @Registered; sortByWord(\@Registered, $TargetLibraryShortName); foreach my $Path (@Registered) { $Registered_Headers{$LibVersion}{$Path}{"Pos"} = $Position++; } } else { exitStatus("Access_Error", "can't identify \'$Dest\' as a header file"); } } if(defined $Tolerance and $Tolerance=~/4/) { # 4 - skip headers included by others foreach my $Path (keys(%{$Registered_Headers{$LibVersion}})) { if(defined $Header_Includes_R{$LibVersion}{$Path}) { delete($Registered_Headers{$LibVersion}{$Path}); } } } if(my $HList = $Descriptor{$LibVersion}{"IncludePreamble"}) { # preparing preamble headers foreach my $Header (split(/\s*\n\s*/, $HList)) { if(is_abs($Header) and not -f $Header) { exitStatus("Access_Error", "can't access file \'$Header\'"); } $Header = path_format($Header, $OSgroup); if(my $Header_Path = is_header($Header, 1, $LibVersion)) { next if(skipHeader($Header_Path, $LibVersion)); push_U($Include_Preamble{$LibVersion}, $Header_Path); } else { exitStatus("Access_Error", "can't identify \'$Header\' as a header file"); } } } foreach my $Header_Name (keys(%{$HeaderName_Paths{$LibVersion}})) { # set relative paths (for duplicates) if(keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})>=2) { # search for duplicates my $FirstPath = (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))[0]; my $Prefix = get_dirname($FirstPath); while($Prefix=~/\A(.+)[\/\\]+[^\/\\]+\Z/) { # detect a shortest distinguishing prefix my $NewPrefix = $1; my %Identity = (); foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})) { if($Path=~/\A\Q$Prefix\E[\/\\]+(.*)\Z/) { $Identity{$Path} = $1; } } if(keys(%Identity)==keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})) { # all names are differend with current prefix foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})) { $Registered_Headers{$LibVersion}{$Path}{"Identity"} = $Identity{$Path}; } last; } $Prefix = $NewPrefix; # increase prefix } } } # clean memory %HeaderName_Paths = (); foreach my $HeaderName (keys(%{$Include_Order{$LibVersion}})) { # ordering headers according to descriptor my $PairName = $Include_Order{$LibVersion}{$HeaderName}; my ($Pos, $PairPos) = (-1, -1); my ($Path, $PairPath) = (); my @Paths = keys(%{$Registered_Headers{$LibVersion}}); @Paths = sort {int($Registered_Headers{$LibVersion}{$a}{"Pos"})<=>int($Registered_Headers{$LibVersion}{$b}{"Pos"})} @Paths; foreach my $Header_Path (@Paths) { if(get_filename($Header_Path) eq $PairName) { $PairPos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"}; $PairPath = $Header_Path; } if(get_filename($Header_Path) eq $HeaderName) { $Pos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"}; $Path = $Header_Path; } } if($PairPos!=-1 and $Pos!=-1 and int($PairPos)) { if(/#\s+\d+\s+"([^"]+)"[\s\d]*\n/) { my $Include = path_format($1, $OSgroup); if($Include=~/\<(built\-in|internal|command(\-|\s)line)\>|\A\./) { next; } if($Include eq $AbsPath) { next; } $RecursiveIncludes{$LibVersion}{$AbsPath}{$Include} = 1; } } close(PREPROC); return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}}); } sub detect_header_includes($$) { my ($Path, $LibVersion) = @_; return if(not $LibVersion or not $Path); if(defined $Cache{"detect_header_includes"}{$LibVersion}{$Path}) { return; } $Cache{"detect_header_includes"}{$LibVersion}{$Path}=1; if(not -e $Path) { return; } my $Content = readFile($Path); if(my $Redirect = parse_redirect($Content, $Path, $LibVersion)) { # detect error directive in headers if(my $RedirectPath = identifyHeader($Redirect, $LibVersion)) { if($RedirectPath=~/\/usr\/include\// and $Path!~/\/usr\/include\//) { $RedirectPath = identifyHeader(get_filename($Redirect), $LibVersion); } if($RedirectPath ne $Path) { $Header_ErrorRedirect{$LibVersion}{$Path} = $RedirectPath; } } else { # can't find $Header_ShouldNotBeUsed{$LibVersion}{$Path} = 1; } } if(my $Inc = parse_includes($Content, $Path)) { foreach my $Include (keys(%{$Inc})) { # detect includes $Header_Includes{$LibVersion}{$Path}{$Include} = $Inc->{$Include}; if(defined $Tolerance and $Tolerance=~/4/) { if(my $HPath = identifyHeader($Include, $LibVersion)) { $Header_Includes_R{$LibVersion}{$HPath}{$Path} = 1; } } } } } sub fromLibc($) { # system GLIBC header my $Path = $_[0]; my ($Dir, $Name) = separate_path($Path); if($OStarget eq "symbian") { if(get_filename($Dir) eq "libc" and $GlibcHeader{$Name}) { # epoc32/include/libc/{stdio, ...}.h return 1; } } else { if($Dir eq "/usr/include" and $GlibcHeader{$Name}) { # /usr/include/{stdio, ...}.h return 1; } } return 0; } sub isLibcDir($) { # system GLIBC directory my $Dir = $_[0]; my ($OutDir, $Name) = separate_path($Dir); if($OStarget eq "symbian") { if(get_filename($OutDir) eq "libc" and ($Name=~/\Aasm(|-.+)\Z/ or $GlibcDir{$Name})) { # epoc32/include/libc/{sys,bits,asm,asm-*}/*.h return 1; } } else { # linux if($OutDir eq "/usr/include" and ($Name=~/\Aasm(|-.+)\Z/ or $GlibcDir{$Name})) { # /usr/include/{sys,bits,asm,asm-*}/*.h return 1; } } return 0; } sub detect_recursive_includes($$) { my ($AbsPath, $LibVersion) = @_; return () if(not $AbsPath); if(isCyclical(\@RecurInclude, $AbsPath)) { return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}}); } my ($AbsDir, $Name) = separate_path($AbsPath); if(isLibcDir($AbsDir)) { # system GLIBC internals return () if(not $ExtraInfo); } if(keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) { return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}}); } return () if($OSgroup ne "windows" and $Name=~/windows|win32|win64/i); if($MAIN_CPP_DIR and $AbsPath=~/\A\Q$MAIN_CPP_DIR\E/ and not $STDCXX_TESTING) { # skip /usr/include/c++/*/ headers return () if(not $ExtraInfo); } push(@RecurInclude, $AbsPath); if(grep { $AbsDir eq $_ } @DefaultGccPaths or (grep { $AbsDir eq $_ } @DefaultIncPaths and fromLibc($AbsPath))) { # check "real" (non-"model") include paths my @Paths = detect_real_includes($AbsPath, $LibVersion); pop(@RecurInclude); return @Paths; } if(not keys(%{$Header_Includes{$LibVersion}{$AbsPath}})) { detect_header_includes($AbsPath, $LibVersion); } foreach my $Include (keys(%{$Header_Includes{$LibVersion}{$AbsPath}})) { my $IncType = $Header_Includes{$LibVersion}{$AbsPath}{$Include}; my $HPath = ""; if($IncType<0) { # for #include "..." my $Candidate = join_P($AbsDir, $Include); if(-f $Candidate) { $HPath = realpath($Candidate); } } elsif($IncType>0 and $Include=~/[\/\\]/) # and not find_in_defaults($Include) { # search for the nearest header # QtCore/qabstractanimation.h includes my $Candidate = join_P(get_dirname($AbsDir), $Include); if(-f $Candidate) { $HPath = $Candidate; } } if(not $HPath) { $HPath = identifyHeader($Include, $LibVersion); } next if(not $HPath); if($HPath eq $AbsPath) { next; } if($Debug) { # boundary headers # if($HPath=~/vtk/ and $AbsPath!~/vtk/) # { # print STDERR "$AbsPath -> $HPath\n"; # } } $RecursiveIncludes{$LibVersion}{$AbsPath}{$HPath} = $IncType; if($IncType>0) { # only include <...>, skip include "..." prefixes $Header_Include_Prefix{$LibVersion}{$AbsPath}{$HPath}{get_dirname($Include)} = 1; } foreach my $IncPath (detect_recursive_includes($HPath, $LibVersion)) { if($IncPath eq $AbsPath) { next; } my $RIncType = $RecursiveIncludes{$LibVersion}{$HPath}{$IncPath}; if($RIncType==-1) { # include "..." $RIncType = $IncType; } elsif($RIncType==2) { if($IncType!=-1) { $RIncType = $IncType; } } $RecursiveIncludes{$LibVersion}{$AbsPath}{$IncPath} = $RIncType; foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$HPath}{$IncPath}})) { $Header_Include_Prefix{$LibVersion}{$AbsPath}{$IncPath}{$Prefix} = 1; } } foreach my $Dep (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}})) { if($GlibcHeader{get_filename($Dep)} and keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}})>=2 and defined $Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""}) { # distinguish math.h from glibc and math.h from the tested library delete($Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""}); last; } } } pop(@RecurInclude); return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}}); } sub find_in_framework($$$) { my ($Header, $Framework, $LibVersion) = @_; return "" if(not $Header or not $Framework or not $LibVersion); if(defined $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header}) { return $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header}; } foreach my $Dependency (sort {get_depth($a)<=>get_depth($b)} keys(%{$Header_Dependency{$LibVersion}})) { if(get_filename($Dependency) eq $Framework and -f get_dirname($Dependency)."/".$Header) { return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = get_dirname($Dependency)); } } return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = ""); } sub find_in_defaults($) { my $Header = $_[0]; return "" if(not $Header); if(defined $Cache{"find_in_defaults"}{$Header}) { return $Cache{"find_in_defaults"}{$Header}; } foreach my $Dir (@DefaultIncPaths, @DefaultGccPaths, @DefaultCppPaths, @UsersIncPath) { next if(not $Dir); if(-f $Dir."/".$Header) { return ($Cache{"find_in_defaults"}{$Header}=$Dir); } } return ($Cache{"find_in_defaults"}{$Header}=""); } sub cmp_paths($$) { my ($Path1, $Path2) = @_; my @Parts1 = split(/[\/\\]/, $Path1); my @Parts2 = split(/[\/\\]/, $Path2); foreach my $Num (0 .. $#Parts1) { my $Part1 = $Parts1[$Num]; my $Part2 = $Parts2[$Num]; if($GlibcDir{$Part1} and not $GlibcDir{$Part2}) { return 1; } elsif($GlibcDir{$Part2} and not $GlibcDir{$Part1}) { return -1; } elsif($Part1=~/glib/ and $Part2!~/glib/) { return 1; } elsif($Part1!~/glib/ and $Part2=~/glib/) { return -1; } elsif(my $CmpRes = ($Part1 cmp $Part2)) { return $CmpRes; } } return 0; } sub checkRelevance($) { my $Path = $_[0]; return 0 if(not $Path); if($SystemRoot) { $Path = cut_path_prefix($Path, $SystemRoot); } my $Name = lc(get_filename($Path)); my $Dir = lc(get_dirname($Path)); $Name=~s/\.\w+\Z//g; # remove extension (.h) foreach my $Token (split(/[_\d\W]+/, $Name)) { my $Len = length($Token); next if($Len<=1); if($Dir=~/(\A|lib|[_\d\W])\Q$Token\E([_\d\W]|lib|\Z)/) { # include/evolution-data-server-1.4/libebook/e-book.h return 1; } if($Len>=4 and index($Dir, $Token)!=-1) { # include/gupnp-1.0/libgupnp/gupnp-context.h return 1; } } return 0; } sub checkFamily(@) { my @Paths = @_; return 1 if($#Paths<=0); my %Prefix = (); foreach my $Path (@Paths) { if($SystemRoot) { $Path = cut_path_prefix($Path, $SystemRoot); } if(my $Dir = get_dirname($Path)) { $Dir=~s/(\/[^\/]+?)[\d\.\-\_]+\Z/$1/g; # remove version suffix $Prefix{$Dir} += 1; $Prefix{get_dirname($Dir)} += 1; } } foreach (sort keys(%Prefix)) { if(get_depth($_)>=3 and $Prefix{$_}==$#Paths+1) { return 1; } } return 0; } sub isAcceptable($$$) { my ($Header, $Candidate, $LibVersion) = @_; my $HName = get_filename($Header); if(get_dirname($Header)) { # with prefix return 1; } if($HName=~/config|setup/i and $Candidate=~/[\/\\]lib\d*[\/\\]/) { # allow to search for glibconfig.h in /usr/lib/glib-2.0/include/ return 1; } if(checkRelevance($Candidate)) { # allow to search for atk.h in /usr/include/atk-1.0/atk/ return 1; } if(checkFamily(getSystemHeaders($HName, $LibVersion))) { # /usr/include/qt4/QtNetwork/qsslconfiguration.h # /usr/include/qt4/Qt/qsslconfiguration.h return 1; } if($OStarget eq "symbian") { if($Candidate=~/[\/\\]stdapis[\/\\]/) { return 1; } } return 0; } sub isRelevant($$$) { # disallow to search for "abstract" headers in too deep directories my ($Header, $Candidate, $LibVersion) = @_; my $HName = get_filename($Header); if($OStarget eq "symbian") { if($Candidate=~/[\/\\](tools|stlportv5)[\/\\]/) { return 0; } } if($OStarget ne "bsd") { if($Candidate=~/[\/\\]include[\/\\]bsd[\/\\]/) { # openssh: skip /usr/lib/bcc/include/bsd/signal.h return 0; } } if($OStarget ne "windows") { if($Candidate=~/[\/\\](wine|msvcrt|windows)[\/\\]/) { # skip /usr/include/wine/msvcrt return 0; } } if(not get_dirname($Header) and $Candidate=~/[\/\\]wx[\/\\]/) { # do NOT search in system /wx/ directory # for headers without a prefix: sstream.h return 0; } if($Candidate=~/c\+\+[\/\\]\d+/ and $MAIN_CPP_DIR and $Candidate!~/\A\Q$MAIN_CPP_DIR\E/) { # skip ../c++/3.3.3/ if using ../c++/4.5/ return 0; } if($Candidate=~/[\/\\]asm-/ and (my $Arch = getArch($LibVersion)) ne "unknown") { # arch-specific header files if($Candidate!~/[\/\\]asm-\Q$Arch\E/) {# skip ../asm-arm/ if using x86 architecture return 0; } } my @Candidates = getSystemHeaders($HName, $LibVersion); if($#Candidates==1) { # unique header return 1; } my @SCandidates = getSystemHeaders($Header, $LibVersion); if($#SCandidates==1) { # unique name return 1; } my $SystemDepth = $SystemRoot?get_depth($SystemRoot):0; if(get_depth($Candidate)-$SystemDepth>=5) { # abstract headers in too deep directories # sstream.h or typeinfo.h in /usr/include/wx-2.9/wx/ if(not isAcceptable($Header, $Candidate, $LibVersion)) { return 0; } } if($Header eq "parser.h" and $Candidate!~/\/libxml2\//) { # select parser.h from xml2 library return 0; } if(not get_dirname($Header) and keys(%{$SystemHeaders{$HName}})>=3) { # many headers with the same name # like thread.h included without a prefix if(not checkFamily(@Candidates)) { return 0; } } return 1; } sub selectSystemHeader($$) { # cache function if(defined $Cache{"selectSystemHeader"}{$_[1]}{$_[0]}) { return $Cache{"selectSystemHeader"}{$_[1]}{$_[0]}; } return ($Cache{"selectSystemHeader"}{$_[1]}{$_[0]} = selectSystemHeader_I(@_)); } sub selectSystemHeader_I($$) { my ($Header, $LibVersion) = @_; if(-f $Header) { return $Header; } if(is_abs($Header) and not -f $Header) { # incorrect absolute path return ""; } if(defined $ConfHeaders{lc($Header)}) { # too abstract configuration headers return ""; } my $HName = get_filename($Header); if($OSgroup ne "windows") { if(defined $WinHeaders{lc($HName)} or $HName=~/windows|win32|win64/i) { # windows headers return ""; } } if($OSgroup ne "macos") { if($HName eq "fp.h") { # pngconf.h includes fp.h in Mac OS return ""; } } if(defined $ObsoleteHeaders{$HName}) { # obsolete headers return ""; } if($OSgroup eq "linux" or $OSgroup eq "bsd") { if(defined $AlienHeaders{$HName} or defined $AlienHeaders{$Header}) { # alien headers from other systems return ""; } } foreach my $Path (@{$SystemPaths{"include"}}) { # search in default paths if(-f $Path."/".$Header) { return join_P($Path,$Header); } } if(not defined $Cache{"checkSystemFiles"}) { # register all headers in system include dirs checkSystemFiles(); } foreach my $Candidate (sort {get_depth($a)<=>get_depth($b)} sort {cmp_paths($b, $a)} getSystemHeaders($Header, $LibVersion)) { if(isRelevant($Header, $Candidate, $LibVersion)) { return $Candidate; } } # error return ""; } sub getSystemHeaders($$) { my ($Header, $LibVersion) = @_; my @Candidates = (); foreach my $Candidate (sort keys(%{$SystemHeaders{$Header}})) { if(skipHeader($Candidate, $LibVersion)) { next; } push(@Candidates, $Candidate); } return @Candidates; } sub cut_path_prefix($$) { my ($Path, $Prefix) = @_; return $Path if(not $Prefix); $Prefix=~s/[\/\\]+\Z//; $Path=~s/\A\Q$Prefix\E([\/\\]+|\Z)//; return $Path; } sub is_default_include_dir($) { my $Dir = $_[0]; $Dir=~s/[\/\\]+\Z//; return grep { $Dir eq $_ } (@DefaultGccPaths, @DefaultCppPaths, @DefaultIncPaths); } sub identifyHeader($$) { # cache function my ($Header, $LibVersion) = @_; if(not $Header) { return ""; } $Header=~s/\A(\.\.[\\\/])+//g; if(defined $Cache{"identifyHeader"}{$LibVersion}{$Header}) { return $Cache{"identifyHeader"}{$LibVersion}{$Header}; } return ($Cache{"identifyHeader"}{$LibVersion}{$Header} = identifyHeader_I($Header, $LibVersion)); } sub identifyHeader_I($$) { # search for header by absolute path, relative path or name my ($Header, $LibVersion) = @_; if(-f $Header) { # it's relative or absolute path return get_abs_path($Header); } elsif($GlibcHeader{$Header} and not $GLIBC_TESTING and my $HeaderDir = find_in_defaults($Header)) { # search for libc headers in the /usr/include # for non-libc target library before searching # in the library paths return join_P($HeaderDir,$Header); } elsif(my $Path = $Include_Neighbors{$LibVersion}{$Header}) { # search in the target library paths return $Path; } elsif(defined $DefaultGccHeader{$Header}) { # search in the internal GCC include paths return $DefaultGccHeader{$Header}; } elsif(my $DefaultDir = find_in_defaults($Header)) { # search in the default GCC include paths return join_P($DefaultDir,$Header); } elsif(defined $DefaultCppHeader{$Header}) { # search in the default G++ include paths return $DefaultCppHeader{$Header}; } elsif(my $AnyPath = selectSystemHeader($Header, $LibVersion)) { # search everywhere in the system return $AnyPath; } elsif($OSgroup eq "macos") { # search in frameworks: "OpenGL/gl.h" is "OpenGL.framework/Headers/gl.h" if(my $Dir = get_dirname($Header)) { my $RelPath = "Headers\/".get_filename($Header); if(my $HeaderDir = find_in_framework($RelPath, $Dir.".framework", $LibVersion)) { return join_P($HeaderDir, $RelPath); } } } # cannot find anything return ""; } sub getLocation($) { if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/srcp[ ]*:[ ]*([\w\-\<\>\.\+\/\\]+):(\d+) /) { return (path_format($1, $OSgroup), $2); } } return (); } sub getNameByInfo($) { if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/name[ ]*:[ ]*@(\d+) /) { if(my $NInfo = $LibInfo{$Version}{"info"}{$1}) { if($NInfo=~/strg[ ]*:[ ]*(.*?)[ ]+lngt/) { # short unsigned int (may include spaces) my $Str = $1; if($CppMode{$Version} and $Str=~/\Ac99_(.+)\Z/) { if($CppKeywords_A{$1}) { $Str=$1; } } return $Str; } } } } return ""; } sub getTreeStr($) { if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/strg[ ]*:[ ]*([^ ]*)/) { my $Str = $1; if($CppMode{$Version} and $Str=~/\Ac99_(.+)\Z/) { if($CppKeywords_A{$1}) { $Str=$1; } } return $Str; } } return ""; } sub getFuncShortName($) { if(my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if(index($Info, " operator ")!=-1) { if(index($Info, " conversion ")!=-1) { if(my $Rid = $SymbolInfo{$Version}{$_[0]}{"Return"}) { if(my $RName = $TypeInfo{$Version}{$Rid}{"Name"}) { return "operator ".$RName; } } } else { if($Info=~/ operator[ ]+([a-zA-Z]+) /) { if(my $Ind = $Operator_Indication{$1}) { return "operator".$Ind; } elsif(not $UnknownOperator{$1}) { printMsg("WARNING", "unknown operator $1"); $UnknownOperator{$1} = 1; } } } } else { if($Info=~/name[ ]*:[ ]*@(\d+) /) { return getTreeStr($1); } } } return ""; } sub getFuncReturn($) { if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/type[ ]*:[ ]*@(\d+) /) { if($LibInfo{$Version}{"info"}{$1}=~/retn[ ]*:[ ]*@(\d+) /) { return $1; } } } return ""; } sub getFuncOrig($) { if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/orig[ ]*:[ ]*@(\d+) /) { return $1; } } return $_[0]; } sub unmangleArray(@) { if($_[0]=~/\A\?/) { # MSVC mangling my $UndNameCmd = get_CmdPath("undname"); if(not $UndNameCmd) { exitStatus("Not_Found", "can't find \"undname\""); } writeFile("$TMP_DIR/unmangle", join("\n", @_)); return split(/\n/, `$UndNameCmd 0x8386 \"$TMP_DIR/unmangle\"`); } else { # GCC mangling my $CppFiltCmd = get_CmdPath("c++filt"); if(not $CppFiltCmd) { exitStatus("Not_Found", "can't find c++filt in PATH"); } if(not defined $CPPFILT_SUPPORT_FILE) { my $Info = `$CppFiltCmd -h 2>&1`; $CPPFILT_SUPPORT_FILE = $Info=~/\@/; } my $NoStrip = ($OSgroup=~/macos|windows/)?"-n":""; if($CPPFILT_SUPPORT_FILE) { # new versions of c++filt can take a file if($#_>$MAX_CPPFILT_FILE_SIZE) { # c++filt <= 2.22 may crash on large files (larger than 8mb) # this is fixed in the oncoming version of Binutils my @Half = splice(@_, 0, ($#_+1)/2); return (unmangleArray(@Half), unmangleArray(@_)) } else { writeFile("$TMP_DIR/unmangle", join("\n", @_)); my $Res = `$CppFiltCmd $NoStrip \@\"$TMP_DIR/unmangle\"`; if($?==139) { # segmentation fault printMsg("ERROR", "internal error - c++filt crashed, try to reduce MAX_CPPFILT_FILE_SIZE constant"); } return split(/\n/, $Res); } } else { # old-style unmangling if($#_>$MAX_COMMAND_LINE_ARGUMENTS) { my @Half = splice(@_, 0, ($#_+1)/2); return (unmangleArray(@Half), unmangleArray(@_)) } else { my $Strings = join(" ", @_); my $Res = `$CppFiltCmd $NoStrip $Strings`; if($?==139) { # segmentation fault printMsg("ERROR", "internal error - c++filt crashed, try to reduce MAX_COMMAND_LINE_ARGUMENTS constant"); } return split(/\n/, $Res); } } } } sub get_SignatureNoInfo($$) { my ($Symbol, $LibVersion) = @_; if($Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol}) { return $Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol}; } my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol); my $Signature = $tr_name{$MnglName}?$tr_name{$MnglName}:$MnglName; if($Symbol=~/\A(_Z|\?)/) { # C++ # some standard typedefs $Signature=~s/\Qstd::basic_string, std::allocator >\E/std::string/g; $Signature=~s/\Qstd::map, std::allocator > >\E/std::map/g; } if(not $CheckObjectsOnly or $OSgroup=~/linux|bsd|beos/i) { # ELF format marks data as OBJECT if($GlobalDataObject{$LibVersion}{$Symbol}) { $Signature .= " [data]"; } elsif($Symbol!~/\A(_Z|\?)/) { $Signature .= " (...)"; } } if(my $ChargeLevel = get_ChargeLevel($Symbol, $LibVersion)) { my $ShortName = substr($Signature, 0, find_center($Signature, "(")); $Signature=~s/\A\Q$ShortName\E/$ShortName $ChargeLevel/g; } if($SymbolVersion) { $Signature .= $VersionSpec.$SymbolVersion; } return ($Cache{"get_SignatureNoInfo"}{$LibVersion}{$Symbol} = $Signature); } sub get_ChargeLevel($$) { my ($Symbol, $LibVersion) = @_; return "" if($Symbol!~/\A(_Z|\?)/); if(defined $CompleteSignature{$LibVersion}{$Symbol} and $CompleteSignature{$LibVersion}{$Symbol}{"Header"}) { if($CompleteSignature{$LibVersion}{$Symbol}{"Constructor"}) { if($Symbol=~/C1[EI]/) { return "[in-charge]"; } elsif($Symbol=~/C2[EI]/) { return "[not-in-charge]"; } } elsif($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"}) { if($Symbol=~/D1[EI]/) { return "[in-charge]"; } elsif($Symbol=~/D2[EI]/) { return "[not-in-charge]"; } elsif($Symbol=~/D0[EI]/) { return "[in-charge-deleting]"; } } } else { if($Symbol=~/C1[EI]/) { return "[in-charge]"; } elsif($Symbol=~/C2[EI]/) { return "[not-in-charge]"; } elsif($Symbol=~/D1[EI]/) { return "[in-charge]"; } elsif($Symbol=~/D2[EI]/) { return "[not-in-charge]"; } elsif($Symbol=~/D0[EI]/) { return "[in-charge-deleting]"; } } return ""; } sub get_Signature_M($$) { my ($Symbol, $LibVersion) = @_; my $Signature_M = $tr_name{$Symbol}; if(my $RTid = $CompleteSignature{$LibVersion}{$Symbol}{"Return"}) { # add return type name $Signature_M = $TypeInfo{$LibVersion}{$RTid}{"Name"}." ".$Signature_M; } return $Signature_M; } sub get_Signature($$) { my ($Symbol, $LibVersion) = @_; if($Cache{"get_Signature"}{$LibVersion}{$Symbol}) { return $Cache{"get_Signature"}{$LibVersion}{$Symbol}; } my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol); if(isPrivateData($MnglName) or not $CompleteSignature{$LibVersion}{$Symbol}{"Header"}) { # non-public global data return get_SignatureNoInfo($Symbol, $LibVersion); } my ($Signature, @Param_Types_FromUnmangledName) = (); my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"}; if($Symbol=~/\A(_Z|\?)/) { if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"}) { $Signature .= $TypeInfo{$LibVersion}{$ClassId}{"Name"}."::"; if($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"}) { $Signature .= "~"; } $Signature .= $ShortName; } elsif(my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"}) { $Signature .= $NameSpace."::".$ShortName; } else { $Signature .= $ShortName; } my ($Short, $Params) = split_Signature($tr_name{$MnglName}); @Param_Types_FromUnmangledName = separate_Params($Params, 0, 1); } else { $Signature .= $MnglName; } my @ParamArray = (); foreach my $Pos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}})) { next if($Pos eq ""); my $ParamTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"}; next if(not $ParamTypeId); my $ParamTypeName = $TypeInfo{$LibVersion}{$ParamTypeId}{"Name"}; if(not $ParamTypeName) { $ParamTypeName = $Param_Types_FromUnmangledName[$Pos]; } foreach my $Typedef (keys(%ChangedTypedef)) { if(my $Base = $Typedef_BaseName{$LibVersion}{$Typedef}) { $ParamTypeName=~s/\b\Q$Typedef\E\b/$Base/g; } } if(my $ParamName = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"name"}) { if($ParamName eq "this" and $Symbol=~/\A(_Z|\?)/) { # do NOT show first hidded "this"-parameter next; } push(@ParamArray, create_member_decl($ParamTypeName, $ParamName)); } else { push(@ParamArray, $ParamTypeName); } } if($CompleteSignature{$LibVersion}{$Symbol}{"Data"} or $GlobalDataObject{$LibVersion}{$Symbol}) { $Signature .= " [data]"; } else { if(my $ChargeLevel = get_ChargeLevel($Symbol, $LibVersion)) { # add [in-charge] $Signature .= " ".$ChargeLevel; } $Signature .= " (".join(", ", @ParamArray).")"; if($CompleteSignature{$LibVersion}{$Symbol}{"Const"} or $Symbol=~/\A_ZN(V|)K/) { $Signature .= " const"; } if($CompleteSignature{$LibVersion}{$Symbol}{"Volatile"} or $Symbol=~/\A_ZN(K|)V/) { $Signature .= " volatile"; } if($CompleteSignature{$LibVersion}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/) { # for static methods $Signature .= " [static]"; } } if(defined $ShowRetVal and my $ReturnTId = $CompleteSignature{$LibVersion}{$Symbol}{"Return"}) { $Signature .= ":".$TypeInfo{$LibVersion}{$ReturnTId}{"Name"}; } if($SymbolVersion) { $Signature .= $VersionSpec.$SymbolVersion; } return ($Cache{"get_Signature"}{$LibVersion}{$Symbol} = $Signature); } sub create_member_decl($$) { my ($TName, $Member) = @_; if($TName=~/\([\*]+\)/) { $TName=~s/\(([\*]+)\)/\($1$Member\)/; return $TName; } else { my @ArraySizes = (); while($TName=~s/(\[[^\[\]]*\])\Z//) { push(@ArraySizes, $1); } return $TName." ".$Member.join("", @ArraySizes); } } sub getFuncType($) { if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/type[ ]*:[ ]*@(\d+) /) { if(my $Type = $LibInfo{$Version}{"info_type"}{$1}) { if($Type eq "method_type") { return "Method"; } elsif($Type eq "function_type") { return "Function"; } else { return "Other"; } } } } return ""; } sub getFuncTypeId($) { if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]}) { if($Info=~/type[ ]*:[ ]*@(\d+)( |\Z)/) { return $1; } } return 0; } sub isAnon($) { # "._N" or "$_N" in older GCC versions return ($_[0] and $_[0]=~/(\.|\$)\_\d+|anon\-/); } sub formatName($$) { # type name correction if(defined $Cache{"formatName"}{$_[1]}{$_[0]}) { return $Cache{"formatName"}{$_[1]}{$_[0]}; } my $N = $_[0]; if($_[1] ne "S") { $N=~s/\A[ ]+//g; $N=~s/[ ]+\Z//g; $N=~s/[ ]{2,}/ /g; } $N=~s/[ ]*(\W)[ ]*/$1/g; # std::basic_string const $N=~s/\bvolatile const\b/const volatile/g; $N=~s/\b(long long|short|long) unsigned\b/unsigned $1/g; $N=~s/\b(short|long) int\b/$1/g; $N=~s/([\)\]])(const|volatile)\b/$1 $2/g; while($N=~s/>>/> >/g) {}; if($_[1] eq "S") { if(index($N, "operator")!=-1) { $N=~s/\b(operator[ ]*)> >/$1>>/; } } return ($Cache{"formatName"}{$_[1]}{$_[0]} = $N); } sub get_HeaderDeps($$) { my ($AbsPath, $LibVersion) = @_; return () if(not $AbsPath or not $LibVersion); if(defined $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}) { return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}}; } my %IncDir = (); detect_recursive_includes($AbsPath, $LibVersion); foreach my $HeaderPath (keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) { next if(not $HeaderPath); next if($MAIN_CPP_DIR and $HeaderPath=~/\A\Q$MAIN_CPP_DIR\E([\/\\]|\Z)/); my $Dir = get_dirname($HeaderPath); foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$HeaderPath}})) { my $Dep = $Dir; if($Prefix) { if($OSgroup eq "windows") { # case insensitive seach on windows if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//ig) { next; } } elsif($OSgroup eq "macos") { # seach in frameworks if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g) { if($HeaderPath=~/(.+\.framework)\/Headers\/([^\/]+)/) {# frameworks my ($HFramework, $HName) = ($1, $2); $Dep = $HFramework; } else {# mismatch next; } } } elsif(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g) { # Linux, FreeBSD next; } } if(not $Dep) { # nothing to include next; } if(is_default_include_dir($Dep)) { # included by the compiler next; } if(get_depth($Dep)==1) { # too short next; } if(isLibcDir($Dep)) { # do NOT include /usr/include/{sys,bits} next; } $IncDir{$Dep} = 1; } } $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath} = sortIncPaths([keys(%IncDir)], $LibVersion); return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}}; } sub sortIncPaths($$) { my ($ArrRef, $LibVersion) = @_; if(not $ArrRef or $#{$ArrRef}<0) { return $ArrRef; } @{$ArrRef} = sort {$b cmp $a} @{$ArrRef}; @{$ArrRef} = sort {get_depth($a)<=>get_depth($b)} @{$ArrRef}; @{$ArrRef} = sort {sortDeps($b, $a, $LibVersion)} @{$ArrRef}; return $ArrRef; } sub sortDeps($$$) { if($Header_Dependency{$_[2]}{$_[0]} and not $Header_Dependency{$_[2]}{$_[1]}) { return 1; } elsif(not $Header_Dependency{$_[2]}{$_[0]} and $Header_Dependency{$_[2]}{$_[1]}) { return -1; } return 0; } sub join_P($$) { my $S = "/"; if($OSgroup eq "windows") { $S = "\\"; } return join($S, @_); } sub get_namespace_additions($) { my $NameSpaces = $_[0]; my ($Additions, $AddNameSpaceId) = ("", 1); foreach my $NS (sort {$a=~/_/ <=> $b=~/_/} sort {lc($a) cmp lc($b)} keys(%{$NameSpaces})) { next if($SkipNameSpaces{$Version}{$NS}); next if(not $NS or $NameSpaces->{$NS}==-1); next if($NS=~/(\A|::)iterator(::|\Z)/i); next if($NS=~/\A__/i); next if(($NS=~/\Astd::/ or $NS=~/\A(std|tr1|rel_ops|fcntl)\Z/) and not $STDCXX_TESTING); $NestedNameSpaces{$Version}{$NS} = 1; # for future use in reports my ($TypeDecl_Prefix, $TypeDecl_Suffix) = (); my @NS_Parts = split(/::/, $NS); next if($#NS_Parts==-1); next if($NS_Parts[0]=~/\A(random|or)\Z/); foreach my $NS_Part (@NS_Parts) { $TypeDecl_Prefix .= "namespace $NS_Part\{"; $TypeDecl_Suffix .= "}"; } my $TypeDecl = $TypeDecl_Prefix."typedef int tmp_add_type_".$AddNameSpaceId.";".$TypeDecl_Suffix; my $FuncDecl = "$NS\:\:tmp_add_type_$AddNameSpaceId tmp_add_func_$AddNameSpaceId(){return 0;};"; $Additions.=" $TypeDecl\n $FuncDecl\n"; $AddNameSpaceId+=1; } return $Additions; } sub path_format($$) { my ($Path, $Fmt) = @_; $Path=~s/[\/\\]+\.?\Z//g; if($Fmt eq "windows") { $Path=~s/\//\\/g; $Path=lc($Path); } else { # forward slash to pass into MinGW GCC $Path=~s/\\/\//g; } return $Path; } sub inc_opt($$) { my ($Path, $Style) = @_; if($Style eq "GCC") { # GCC options if($OSgroup eq "windows") { # to MinGW GCC return "-I\"".path_format($Path, "unix")."\""; } elsif($OSgroup eq "macos" and $Path=~/\.framework\Z/) { # to Apple's GCC return "-F".esc(get_dirname($Path)); } else { return "-I".esc($Path); } } elsif($Style eq "CL") { return "/I \"".$Path."\""; } return ""; } sub platformSpecs($) { my $LibVersion = $_[0]; my $Arch = getArch($LibVersion); if($OStarget eq "symbian") { # options for GCCE compiler my %Symbian_Opts = map {$_=>1} ( "-D__GCCE__", "-DUNICODE", "-fexceptions", "-D__SYMBIAN32__", "-D__MARM_INTERWORK__", "-D_UNICODE", "-D__S60_50__", "-D__S60_3X__", "-D__SERIES60_3X__", "-D__EPOC32__", "-D__MARM__", "-D__EABI__", "-D__MARM_ARMV5__", "-D__SUPPORT_CPP_EXCEPTIONS__", "-march=armv5t", "-mapcs", "-mthumb-interwork", "-DEKA2", "-DSYMBIAN_ENABLE_SPLIT_HEADERS" ); return join(" ", keys(%Symbian_Opts)); } elsif($OSgroup eq "windows" and get_dumpmachine($GCC_PATH)=~/mingw/i) { # add options to MinGW compiler # to simulate the MSVC compiler my %MinGW_Opts = map {$_=>1} ( "-D_WIN32", "-D_STDCALL_SUPPORTED", "-D__int64=\"long long\"", "-D__int32=int", "-D__int16=short", "-D__int8=char", "-D__possibly_notnullterminated=\" \"", "-D__nullterminated=\" \"", "-D__nullnullterminated=\" \"", "-D__w64=\" \"", "-D__ptr32=\" \"", "-D__ptr64=\" \"", "-D__forceinline=inline", "-D__inline=inline", "-D__uuidof(x)=IID()", "-D__try=", "-D__except(x)=", "-D__declspec(x)=__attribute__((x))", "-D__pragma(x)=", "-D_inline=inline", "-D__forceinline=__inline", "-D__stdcall=__attribute__((__stdcall__))", "-D__cdecl=__attribute__((__cdecl__))", "-D__fastcall=__attribute__((__fastcall__))", "-D__thiscall=__attribute__((__thiscall__))", "-D_stdcall=__attribute__((__stdcall__))", "-D_cdecl=__attribute__((__cdecl__))", "-D_fastcall=__attribute__((__fastcall__))", "-D_thiscall=__attribute__((__thiscall__))", "-DSHSTDAPI_(x)=x", "-D_MSC_EXTENSIONS", "-DSECURITY_WIN32", "-D_MSC_VER=1500", "-D_USE_DECLSPECS_FOR_SAL", "-D__noop=\" \"", "-DDECLSPEC_DEPRECATED=\" \"", "-D__builtin_alignof(x)=__alignof__(x)", "-DSORTPP_PASS"); if($Arch eq "x86") { $MinGW_Opts{"-D_M_IX86=300"}=1; } elsif($Arch eq "x86_64") { $MinGW_Opts{"-D_M_AMD64=300"}=1; } elsif($Arch eq "ia64") { $MinGW_Opts{"-D_M_IA64=300"}=1; } return join(" ", keys(%MinGW_Opts)); } return ""; } my %C_Structure = map {$_=>1} ( # FIXME: Can't separate union and struct data types before dumping, # so it sometimes cause compilation errors for unknown reason # when trying to declare TYPE* tmp_add_class_N # This is a list of such structures + list of other C structures "sigval", "sigevent", "sigaction", "sigvec", "sigstack", "timeval", "timezone", "rusage", "rlimit", "wait", "flock", "stat", "_stat", "stat32", "_stat32", "stat64", "_stat64", "_stati64", "if_nameindex", "usb_device", "sigaltstack", "sysinfo", "timeLocale", "tcp_debug", "rpc_createerr", # Other "timespec", "random_data", "drand48_data", "_IO_marker", "_IO_FILE", "lconv", "sched_param", "tm", "itimerspec", "_pthread_cleanup_buffer", "fd_set", "siginfo", "mallinfo", "timex", "sigcontext", "ucontext", # Mac "_timex", "_class_t", "_category_t", "_class_ro_t", "_protocol_t", "_message_ref_t", "_super_message_ref_t", "_ivar_t", "_ivar_list_t" ); sub getCompileCmd($$$) { my ($Path, $Opt, $Inc) = @_; my $GccCall = $GCC_PATH; if($Opt) { $GccCall .= " ".$Opt; } $GccCall .= " -x "; if($OSgroup eq "macos") { $GccCall .= "objective-"; } if($EMERGENCY_MODE_48) { # workaround for GCC 4.8 (C only) $GccCall .= "c++"; } elsif(check_gcc($GCC_PATH, "4")) { # compile as "C++" header # to obtain complete dump using GCC 4.0 $GccCall .= "c++-header"; } else { # compile as "C++" source # GCC 3.3 cannot compile headers $GccCall .= "c++"; } if(my $Opts = platformSpecs($Version)) {# platform-specific options $GccCall .= " ".$Opts; } # allow extra qualifications # and other nonconformant code $GccCall .= " -fpermissive"; $GccCall .= " -w"; if($NoStdInc) { $GccCall .= " -nostdinc"; $GccCall .= " -nostdinc++"; } if($CompilerOptions{$Version}) { # user-defined options $GccCall .= " ".$CompilerOptions{$Version}; } $GccCall .= " \"$Path\""; if($Inc) { # include paths $GccCall .= " ".$Inc; } return $GccCall; } sub detectPreamble($$) { my ($Content, $LibVersion) = @_; my %HeaderElems = ( # Types "stdio.h" => ["FILE", "va_list"], "stddef.h" => ["NULL", "ptrdiff_t"], "stdint.h" => ["uint8_t", "uint16_t", "uint32_t", "uint64_t", "int8_t", "int16_t", "int32_t", "int64_t"], "time.h" => ["time_t"], "sys/types.h" => ["ssize_t", "u_int32_t", "u_short", "u_char", "u_int", "off_t", "u_quad_t", "u_long", "mode_t"], "unistd.h" => ["gid_t", "uid_t", "socklen_t"], "stdbool.h" => ["_Bool"], "rpc/xdr.h" => ["bool_t"], "in_systm.h" => ["n_long", "n_short"], # Fields "arpa/inet.h" => ["fw_src", "ip_src"], # Functions "stdlib.h" => ["free", "malloc", "size_t"], "string.h" => ["memmove", "strcmp"] ); my %AutoPreamble = (); foreach (keys(%HeaderElems)) { foreach my $Elem (@{$HeaderElems{$_}}) { $AutoPreamble{$Elem} = $_; } } my %Types = (); while($Content=~s/error\:\s*(field\s*|)\W+(.+?)\W+//) { # error: 'FILE' has not been declared $Types{$2} = 1; } if(keys(%Types)) { my %AddHeaders = (); foreach my $Type (keys(%Types)) { if(my $Header = $AutoPreamble{$Type}) { if(my $Path = identifyHeader($Header, $LibVersion)) { if(skipHeader($Path, $LibVersion)) { next; } $Path = path_format($Path, $OSgroup); $AddHeaders{$Path}{"Type"} = $Type; $AddHeaders{$Path}{"Header"} = $Header; } } } if(keys(%AddHeaders)) { return \%AddHeaders; } } return undef; } sub checkCTags($) { my $Path = $_[0]; if(not $Path) { return; } my $CTags = undef; if($OSgroup eq "bsd") { # use ectags on BSD $CTags = get_CmdPath("ectags"); if(not $CTags) { printMsg("WARNING", "can't find \'ectags\' program"); } } if(not $CTags) { $CTags = get_CmdPath("ctags"); } if(not $CTags) { printMsg("WARNING", "can't find \'ctags\' program"); return; } if($OSgroup ne "linux") { # macos, freebsd, etc. my $Info = `$CTags --version 2>\"$TMP_DIR/null\"`; if($Info!~/exuberant/i) { printMsg("WARNING", "incompatible version of \'ctags\' program"); return; } } my $Out = $TMP_DIR."/ctags.txt"; system("$CTags --c-kinds=pxn -f \"$Out\" \"$Path\" 2>\"$TMP_DIR/null\""); if($Debug) { copy($Out, $DEBUG_PATH{$Version}."/ctags.txt"); } open(CTAGS, "<", $Out); while(my $Line = ) { chomp($Line); my ($Name, $Header, $Def, $Type, $Scpe) = split(/\t/, $Line); if(defined $Intrinsic_Keywords{$Name}) { # noise next; } if($Type eq "n") { if(index($Scpe, "class:")==0) { next; } if(index($Scpe, "struct:")==0) { next; } if(index($Scpe, "namespace:")==0) { if($Scpe=~s/\Anamespace://) { $Name = $Scpe."::".$Name; } } $TUnit_NameSpaces{$Version}{$Name} = 1; } elsif($Type eq "p") { if(not $Scpe or index($Scpe, "namespace:")==0) { $TUnit_Funcs{$Version}{$Name} = 1; } } elsif($Type eq "x") { if(not $Scpe or index($Scpe, "namespace:")==0) { $TUnit_Vars{$Version}{$Name} = 1; } } } close(CTAGS); } sub preChange($$) { my ($HeaderPath, $IncStr) = @_; my $PreprocessCmd = getCompileCmd($HeaderPath, "-E", $IncStr); my $Content = undef; if($OStarget eq "windows" and get_dumpmachine($GCC_PATH)=~/mingw/i and $MinGWMode{$Version}!=-1) { # modify headers to compile by MinGW if(not $Content) { # preprocessing $Content = `$PreprocessCmd 2>\"$TMP_DIR/null\"`; } if($Content=~s/__asm\s*(\{[^{}]*?\}|[^{};]*)//g) { # __asm { ... } $MinGWMode{$Version}=1; } if($Content=~s/\s+(\/ \/.*?)\n/\n/g) { # comments after preprocessing $MinGWMode{$Version}=1; } if($Content=~s/(\W)(0x[a-f]+|\d+)(i|ui)(8|16|32|64)(\W)/$1$2$5/g) { # 0xffui8 $MinGWMode{$Version}=1; } if($MinGWMode{$Version}) { printMsg("INFO", "Using MinGW compatibility mode"); } } if(($COMMON_LANGUAGE{$Version} eq "C" or $CheckHeadersOnly) and $CppMode{$Version}!=-1 and not $CppCompat and not $CPP_HEADERS) { # rename C++ keywords in C code # disable this code by -cpp-compatible option if(not $Content) { # preprocessing $Content = `$PreprocessCmd 2>\"$TMP_DIR/null\"`; } my $RegExp_C = join("|", keys(%CppKeywords_C)); my $RegExp_F = join("|", keys(%CppKeywords_F)); my $RegExp_O = join("|", keys(%CppKeywords_O)); my $Detected = undef; while($Content=~s/(\A|\n[^\#\/\n][^\n]*?|\n)(\*\s*|\s+|\@|\,|\()($RegExp_C|$RegExp_F)(\s*([\,\)\;\.\[]|\-\>|\:\s*\d))/$1$2c99_$3$4/g) { # MATCH: # int foo(int new, int class, int (*new)(int)); # int foo(char template[], char*); # unsigned private: 8; # DO NOT MATCH: # #pragma GCC visibility push(default) $CppMode{$Version} = 1; $Detected = "$1$2$3$4" if(not defined $Detected); } if($Content=~s/([^\w\s]|\w\s+)(?int($Registered_Headers{$Version}{$b}{"Pos"})} @Headers; my $IncludeString = getIncString(getIncPaths(@{$Include_Preamble{$Version}}, @Headers), "GCC"); my $TmpHeaderPath = $TMP_DIR."/dump".$Version.".h"; my $HeaderPath = $TmpHeaderPath; # write tmp-header open(TMP_HEADER, ">", $TmpHeaderPath) || die ("can't open file \'$TmpHeaderPath\': $!\n"); if(my $AddDefines = $Descriptor{$Version}{"Defines"}) { $AddDefines=~s/\n\s+/\n /g; print TMP_HEADER "\n // add defines\n ".$AddDefines."\n"; } print TMP_HEADER "\n // add includes\n"; foreach my $HPath (@{$Include_Preamble{$Version}}) { print TMP_HEADER " #include \"".path_format($HPath, "unix")."\"\n"; } foreach my $HPath (@Headers) { if(not grep {$HPath eq $_} (@{$Include_Preamble{$Version}})) { print TMP_HEADER " #include \"".path_format($HPath, "unix")."\"\n"; } } close(TMP_HEADER); if($ExtraInfo) { # extra information for other tools if($IncludeString) { writeFile($ExtraInfo."/include-string", $IncludeString); } writeFile($ExtraInfo."/recursive-includes", Dumper($RecursiveIncludes{$Version})); writeFile($ExtraInfo."/direct-includes", Dumper($Header_Includes{$Version})); if(my @Redirects = keys(%{$Header_ErrorRedirect{$Version}})) { my $REDIR = ""; foreach my $P1 (sort @Redirects) { $REDIR .= $P1.";".$Header_ErrorRedirect{$Version}{$P1}."\n"; } writeFile($ExtraInfo."/include-redirect", $REDIR); } } if(not keys(%{$TargetHeaders{$Version}})) { # Target headers addTargetHeaders($Version); } # clean memory %RecursiveIncludes = (); %Header_Include_Prefix = (); %Header_Includes = (); # clean cache delete($Cache{"identifyHeader"}); delete($Cache{"detect_header_includes"}); delete($Cache{"selectSystemHeader"}); # preprocessing stage my $Pre = callPreprocessor($TmpHeaderPath, $IncludeString, $Version); checkPreprocessedUnit($Pre); if($ExtraInfo) { # extra information for other tools writeFile($ExtraInfo."/header-paths", join("\n", sort keys(%{$PreprocessedHeaders{$Version}}))); } # clean memory delete($Include_Neighbors{$Version}); delete($PreprocessedHeaders{$Version}); if($COMMON_LANGUAGE{$Version} eq "C++") { checkCTags($Pre); } if(my $PrePath = preChange($TmpHeaderPath, $IncludeString)) { # try to correct the preprocessor output $HeaderPath = $PrePath; } if($COMMON_LANGUAGE{$Version} eq "C++") { # add classes and namespaces to the dump my $CHdump = "-fdump-class-hierarchy -c"; if($CppMode{$Version}==1 or $MinGWMode{$Version}==1) { $CHdump .= " -fpreprocessed"; } my $ClassHierarchyCmd = getCompileCmd($HeaderPath, $CHdump, $IncludeString); chdir($TMP_DIR); system($ClassHierarchyCmd." >null 2>&1"); chdir($ORIG_DIR); if(my $ClassDump = (cmd_find($TMP_DIR,"f","*.class",1))[0]) { my $Content = readFile($ClassDump); foreach my $ClassInfo (split(/\n\n/, $Content)) { if($ClassInfo=~/\AClass\s+(.+)\s*/i) { my $CName = $1; next if($CName=~/\A(__|_objc_|_opaque_)/); $TUnit_NameSpaces{$Version}{$CName} = -1; if($CName=~/\A[\w:]+\Z/) { # classes $TUnit_Classes{$Version}{$CName} = 1; } if($CName=~/(\w[\w:]*)::/) { # namespaces my $NS = $1; if(not defined $TUnit_NameSpaces{$Version}{$NS}) { $TUnit_NameSpaces{$Version}{$NS} = 1; } } } elsif($ClassInfo=~/\AVtable\s+for\s+(.+)\n((.|\n)+)\Z/i) { # read v-tables (advanced approach) my ($CName, $VTable) = ($1, $2); $ClassVTable_Content{$Version}{$CName} = $VTable; } } foreach my $NS (keys(%{$AddNameSpaces{$Version}})) { # add user-defined namespaces $TUnit_NameSpaces{$Version}{$NS} = 1; } if($Debug) { # debug mode mkpath($DEBUG_PATH{$Version}); copy($ClassDump, $DEBUG_PATH{$Version}."/class-hierarchy-dump.txt"); } unlink($ClassDump); } # add namespaces and classes if(my $NS_Add = get_namespace_additions($TUnit_NameSpaces{$Version})) { # GCC on all supported platforms does not include namespaces to the dump by default appendFile($HeaderPath, "\n // add namespaces\n".$NS_Add); } # some GCC versions don't include class methods to the TU dump by default my ($AddClass, $ClassNum) = ("", 0); my $GCC_44 = check_gcc($GCC_PATH, "4.4"); # support for old GCC versions foreach my $CName (sort keys(%{$TUnit_Classes{$Version}})) { next if($C_Structure{$CName}); next if(not $STDCXX_TESTING and $CName=~/\Astd::/); next if($SkipTypes{$Version}{$CName}); if(not $Force and $GCC_44 and $OSgroup eq "linux") { # optimization for linux with GCC >= 4.4 # disable this code by -force option if(index($CName, "::")!=-1) { # should be added by name space next; } } else { if($CName=~/\A(.+)::[^:]+\Z/ and $TUnit_Classes{$Version}{$1}) { # classes inside other classes next; } } if(defined $TUnit_Funcs{$Version}{$CName}) { # the same name for a function and type next; } if(defined $TUnit_Vars{$Version}{$CName}) { # the same name for a variable and type next; } $AddClass .= " $CName* tmp_add_class_".($ClassNum++).";\n"; } if($AddClass) { appendFile($HeaderPath, "\n // add classes\n".$AddClass); } } writeLog($Version, "Temporary header file \'$TmpHeaderPath\' with the following content will be compiled to create GCC translation unit dump:\n".readFile($TmpHeaderPath)."\n"); # create TU dump my $TUdump = "-fdump-translation-unit -fkeep-inline-functions -c"; if($UserLang eq "C") { $TUdump .= " -U__cplusplus -D_Bool=\"bool\""; } if($CppMode{$Version}==1 or $MinGWMode{$Version}==1) { $TUdump .= " -fpreprocessed"; } my $SyntaxTreeCmd = getCompileCmd($HeaderPath, $TUdump, $IncludeString); writeLog($Version, "The GCC parameters:\n $SyntaxTreeCmd\n\n"); chdir($TMP_DIR); system($SyntaxTreeCmd." >\"$TMP_DIR/tu_errors\" 2>&1"); my $Errors = ""; if($?) { # failed to compile, but the TU dump still can be created if($Errors = readFile($TMP_DIR."/tu_errors")) { # try to recompile # FIXME: handle other errors and try to recompile if($CppMode{$Version}==1 and index($Errors, "c99_")!=-1 and not defined $CppIncompat) { # disable c99 mode and try again $CppMode{$Version}=-1; if($Debug) { # printMsg("INFO", $Errors); } printMsg("INFO", "Disabling C++ compatibility mode"); resetLogging($Version); $TMP_DIR = tempdir(CLEANUP=>1); return getDump(); } elsif($AutoPreambleMode{$Version}!=-1 and my $AddHeaders = detectPreamble($Errors, $Version)) { # add auto preamble headers and try again $AutoPreambleMode{$Version}=-1; my @Headers = sort {$b cmp $a} keys(%{$AddHeaders}); # sys/types.h should be the first foreach my $Num (0 .. $#Headers) { my $Path = $Headers[$Num]; if(not grep {$Path eq $_} (@{$Include_Preamble{$Version}})) { push_U($Include_Preamble{$Version}, $Path); printMsg("INFO", "Add \'".$AddHeaders->{$Path}{"Header"}."\' preamble header for \'".$AddHeaders->{$Path}{"Type"}."\'"); } } resetLogging($Version); $TMP_DIR = tempdir(CLEANUP=>1); return getDump(); } elsif($Cpp0xMode{$Version}!=-1 and ($Errors=~/\Q-std=c++0x\E/ or $Errors=~/is not a class or namespace/)) { # c++0x: enum class if(check_gcc($GCC_PATH, "4.6")) { $Cpp0xMode{$Version}=-1; printMsg("INFO", "Enabling c++0x mode"); resetLogging($Version); $TMP_DIR = tempdir(CLEANUP=>1); $CompilerOptions{$Version} .= " -std=c++0x"; return getDump(); } else { printMsg("WARNING", "Probably c++0x construction detected"); } } elsif($MinGWMode{$Version}==1) { # disable MinGW mode and try again $MinGWMode{$Version}=-1; resetLogging($Version); $TMP_DIR = tempdir(CLEANUP=>1); return getDump(); } writeLog($Version, $Errors); } else { writeLog($Version, "$!: $?\n"); } printMsg("ERROR", "some errors occurred when compiling headers"); printErrorLog($Version); $COMPILE_ERRORS = $ERROR_CODE{"Compile_Error"}; writeLog($Version, "\n"); # new line } chdir($ORIG_DIR); unlink($TmpHeaderPath); unlink($HeaderPath); if(my @TUs = cmd_find($TMP_DIR,"f","*.tu",1)) { return $TUs[0]; } else { my $Msg = "can't compile header(s)"; if($Errors=~/error trying to exec \W+cc1plus\W+/) { $Msg .= "\nDid you install G++?"; } exitStatus("Cannot_Compile", $Msg); } } sub cmd_file($) { my $Path = $_[0]; return "" if(not $Path or not -e $Path); if(my $CmdPath = get_CmdPath("file")) { return `$CmdPath -b \"$Path\"`; } return ""; } sub getIncString($$) { my ($ArrRef, $Style) = @_; return "" if(not $ArrRef or $#{$ArrRef}<0); my $String = ""; foreach (@{$ArrRef}) { $String .= " ".inc_opt($_, $Style); } return $String; } sub getIncPaths(@) { my @HeaderPaths = @_; my @IncPaths = @{$Add_Include_Paths{$Version}}; if($INC_PATH_AUTODETECT{$Version}) { # auto-detecting dependencies my %Includes = (); foreach my $HPath (@HeaderPaths) { foreach my $Dir (get_HeaderDeps($HPath, $Version)) { if($Skip_Include_Paths{$Version}{$Dir}) { next; } if($SystemRoot) { if($Skip_Include_Paths{$Version}{$SystemRoot.$Dir}) { next; } } $Includes{$Dir} = 1; } } foreach my $Dir (@{sortIncPaths([keys(%Includes)], $Version)}) { push_U(\@IncPaths, $Dir); } } else { # user-defined paths @IncPaths = @{$Include_Paths{$Version}}; } return \@IncPaths; } sub push_U($@) { # push unique if(my $Array = shift @_) { if(@_) { my %Exist = map {$_=>1} @{$Array}; foreach my $Elem (@_) { if(not defined $Exist{$Elem}) { push(@{$Array}, $Elem); $Exist{$Elem} = 1; } } } } } sub callPreprocessor($$$) { my ($Path, $Inc, $LibVersion) = @_; return "" if(not $Path or not -f $Path); my $IncludeString=$Inc; if(not $Inc) { $IncludeString = getIncString(getIncPaths($Path), "GCC"); } my $Cmd = getCompileCmd($Path, "-dD -E", $IncludeString); my $Out = $TMP_DIR."/preprocessed.h"; system($Cmd." >\"$Out\" 2>\"$TMP_DIR/null\""); return $Out; } sub cmd_find($;$$$$) { # native "find" is much faster than File::Find (~6x) # also the File::Find doesn't support --maxdepth N option # so using the cross-platform wrapper for the native one my ($Path, $Type, $Name, $MaxDepth, $UseRegex) = @_; return () if(not $Path or not -e $Path); if($OSgroup eq "windows") { my $DirCmd = get_CmdPath("dir"); if(not $DirCmd) { exitStatus("Not_Found", "can't find \"dir\" command"); } $Path = get_abs_path($Path); $Path = path_format($Path, $OSgroup); my $Cmd = $DirCmd." \"$Path\" /B /O"; if($MaxDepth!=1) { $Cmd .= " /S"; } if($Type eq "d") { $Cmd .= " /AD"; } elsif($Type eq "f") { $Cmd .= " /A-D"; } my @Files = split(/\n/, `$Cmd 2>\"$TMP_DIR/null\"`); if($Name) { if(not $UseRegex) { # FIXME: how to search file names in MS shell? # wildcard to regexp $Name=~s/\*/.*/g; $Name='\A'.$Name.'\Z'; } @Files = grep { /$Name/i } @Files; } my @AbsPaths = (); foreach my $File (@Files) { if(not is_abs($File)) { $File = join_P($Path, $File); } if($Type eq "f" and not -f $File) { # skip dirs next; } push(@AbsPaths, path_format($File, $OSgroup)); } if($Type eq "d") { push(@AbsPaths, $Path); } return @AbsPaths; } else { my $FindCmd = get_CmdPath("find"); if(not $FindCmd) { exitStatus("Not_Found", "can't find a \"find\" command"); } $Path = get_abs_path($Path); if(-d $Path and -l $Path and $Path!~/\/\Z/) { # for directories that are symlinks $Path.="/"; } my $Cmd = $FindCmd." \"$Path\""; if($MaxDepth) { $Cmd .= " -maxdepth $MaxDepth"; } if($Type) { $Cmd .= " -type $Type"; } if($Name and not $UseRegex) { # wildcards $Cmd .= " -name \"$Name\""; } my $Res = `$Cmd 2>\"$TMP_DIR/null\"`; if($? and $!) { printMsg("ERROR", "problem with \'find\' utility ($?): $!"); } my @Files = split(/\n/, $Res); if($Name and $UseRegex) { # regex @Files = grep { /$Name/ } @Files; } return @Files; } } sub unpackDump($) { my $Path = $_[0]; return "" if(not $Path or not -e $Path); $Path = get_abs_path($Path); $Path = path_format($Path, $OSgroup); my ($Dir, $FileName) = separate_path($Path); my $UnpackDir = $TMP_DIR."/unpack"; rmtree($UnpackDir); mkpath($UnpackDir); if($FileName=~s/\Q.zip\E\Z//g) { # *.zip my $UnzipCmd = get_CmdPath("unzip"); if(not $UnzipCmd) { exitStatus("Not_Found", "can't find \"unzip\" command"); } chdir($UnpackDir); system("$UnzipCmd \"$Path\" >\"$TMP_DIR/null\""); if($?) { exitStatus("Error", "can't extract \'$Path\' ($?): $!"); } chdir($ORIG_DIR); my @Contents = cmd_find($UnpackDir, "f"); if(not @Contents) { exitStatus("Error", "can't extract \'$Path\'"); } return $Contents[0]; } elsif($FileName=~s/\Q.tar.gz\E(\.\w+|)\Z//g) { # *.tar.gz if($OSgroup eq "windows") { # -xvzf option is not implemented in tar.exe (2003) # use "gzip.exe -k -d -f" + "tar.exe -xvf" instead my $TarCmd = get_CmdPath("tar"); if(not $TarCmd) { exitStatus("Not_Found", "can't find \"tar\" command"); } my $GzipCmd = get_CmdPath("gzip"); if(not $GzipCmd) { exitStatus("Not_Found", "can't find \"gzip\" command"); } chdir($UnpackDir); system("$GzipCmd -k -d -f \"$Path\""); # keep input files (-k) if($?) { exitStatus("Error", "can't extract \'$Path\'"); } system("$TarCmd -xvf \"$Dir\\$FileName.tar\" >\"$TMP_DIR/null\""); if($?) { exitStatus("Error", "can't extract \'$Path\' ($?): $!"); } chdir($ORIG_DIR); unlink($Dir."/".$FileName.".tar"); my @Contents = cmd_find($UnpackDir, "f"); if(not @Contents) { exitStatus("Error", "can't extract \'$Path\'"); } return $Contents[0]; } else { # Unix, Mac my $TarCmd = get_CmdPath("tar"); if(not $TarCmd) { exitStatus("Not_Found", "can't find \"tar\" command"); } chdir($UnpackDir); system("$TarCmd -xvzf \"$Path\" >\"$TMP_DIR/null\""); if($?) { exitStatus("Error", "can't extract \'$Path\' ($?): $!"); } chdir($ORIG_DIR); my @Contents = cmd_find($UnpackDir, "f"); if(not @Contents) { exitStatus("Error", "can't extract \'$Path\'"); } return $Contents[0]; } } } sub createArchive($$) { my ($Path, $To) = @_; if(not $To) { $To = "."; } if(not $Path or not -e $Path or not -d $To) { return ""; } my ($From, $Name) = separate_path($Path); if($OSgroup eq "windows") { # *.zip my $ZipCmd = get_CmdPath("zip"); if(not $ZipCmd) { exitStatus("Not_Found", "can't find \"zip\""); } my $Pkg = $To."/".$Name.".zip"; unlink($Pkg); chdir($To); system("$ZipCmd -j \"$Name.zip\" \"$Path\" >\"$TMP_DIR/null\""); if($?) { # cannot allocate memory (or other problems with "zip") unlink($Path); exitStatus("Error", "can't pack the ABI dump: ".$!); } chdir($ORIG_DIR); unlink($Path); return $Pkg; } else { # *.tar.gz my $TarCmd = get_CmdPath("tar"); if(not $TarCmd) { exitStatus("Not_Found", "can't find \"tar\""); } my $GzipCmd = get_CmdPath("gzip"); if(not $GzipCmd) { exitStatus("Not_Found", "can't find \"gzip\""); } my $Pkg = abs_path($To)."/".$Name.".tar.gz"; unlink($Pkg); chdir($From); system($TarCmd, "-czf", $Pkg, $Name); if($?) { # cannot allocate memory (or other problems with "tar") unlink($Path); exitStatus("Error", "can't pack the ABI dump: ".$!); } chdir($ORIG_DIR); unlink($Path); return $To."/".$Name.".tar.gz"; } } sub is_header_file($) { if($_[0]=~/\.($HEADER_EXT)\Z/i) { return $_[0]; } return 0; } sub is_not_header($) { if($_[0]=~/\.\w+\Z/ and $_[0]!~/\.($HEADER_EXT)\Z/i) { return 1; } return 0; } sub is_header($$$) { my ($Header, $UserDefined, $LibVersion) = @_; return 0 if(-d $Header); if(-f $Header) { $Header = get_abs_path($Header); } else { if(is_abs($Header)) { # incorrect absolute path return 0; } if(my $HPath = identifyHeader($Header, $LibVersion)) { $Header = $HPath; } else { # can't find header return 0; } } if($Header=~/\.\w+\Z/) { # have an extension return is_header_file($Header); } else { if($UserDefined==2) { # specified on the command line if(cmd_file($Header)!~/HTML|XML/i) { return $Header; } } elsif($UserDefined) { # specified in the XML-descriptor # header file without an extension return $Header; } else { if(index($Header, "/include/")!=-1 or cmd_file($Header)=~/C[\+]*\s+program/i) { # !~/HTML|XML|shared|dynamic/i return $Header; } } } return 0; } sub addTargetHeaders($) { my $LibVersion = $_[0]; foreach my $RegHeader (keys(%{$Registered_Headers{$LibVersion}})) { my $RegDir = get_dirname($RegHeader); $TargetHeaders{$LibVersion}{get_filename($RegHeader)} = 1; if(not $INC_PATH_AUTODETECT{$LibVersion}) { detect_recursive_includes($RegHeader, $LibVersion); } foreach my $RecInc (keys(%{$RecursiveIncludes{$LibVersion}{$RegHeader}})) { my $Dir = get_dirname($RecInc); if(familiarDirs($RegDir, $Dir) or $RecursiveIncludes{$LibVersion}{$RegHeader}{$RecInc}!=1) { # in the same directory or included by #include "..." $TargetHeaders{$LibVersion}{get_filename($RecInc)} = 1; } } } } sub familiarDirs($$) { my ($D1, $D2) = @_; if($D1 eq $D2) { return 1; } my $U1 = index($D1, "/usr/"); my $U2 = index($D2, "/usr/"); if($U1==0 and $U2!=0) { return 0; } if($U2==0 and $U1!=0) { return 0; } if(index($D2, $D1."/")==0) { return 1; } # /usr/include/DIR # /home/user/DIR my $DL = get_depth($D1); my @Dirs1 = ($D1); while($DL - get_depth($D1)<=2 and get_depth($D1)>=4 and $D1=~s/[\/\\]+[^\/\\]*?\Z//) { push(@Dirs1, $D1); } my @Dirs2 = ($D2); while(get_depth($D2)>=4 and $D2=~s/[\/\\]+[^\/\\]*?\Z//) { push(@Dirs2, $D2); } foreach my $P1 (@Dirs1) { foreach my $P2 (@Dirs2) { if($P1 eq $P2) { return 1; } } } return 0; } sub readHeaders($) { $Version = $_[0]; printMsg("INFO", "checking header(s) ".$Descriptor{$Version}{"Version"}." ..."); my $DumpPath = getDump(); if($Debug) { # debug mode mkpath($DEBUG_PATH{$Version}); copy($DumpPath, $DEBUG_PATH{$Version}."/translation-unit-dump.txt"); } getInfo($DumpPath); } sub prepareTypes($) { my $LibVersion = $_[0]; if(not checkDump($LibVersion, "2.0")) { # support for old ABI dumps # type names have been corrected in ACC 1.22 (dump 2.0 format) foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}})) { my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"}; if($TName=~/\A(\w+)::(\w+)/) { my ($P1, $P2) = ($1, $2); if($P1 eq $P2) { $TName=~s/\A$P1:\:$P1(\W)/$P1$1/; } else { $TName=~s/\A(\w+:\:)$P2:\:$P2(\W)/$1$P2$2/; } } $TypeInfo{$LibVersion}{$TypeId}{"Name"} = $TName; } } if(not checkDump($LibVersion, "2.5")) { # support for old ABI dumps # V < 2.5: array size == "number of elements" # V >= 2.5: array size in bytes foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) { my %Type = get_PureType($TypeId, $TypeInfo{$LibVersion}); if($Type{"Type"} eq "Array") { if(my $Size = $Type{"Size"}) { # array[N] my %Base = get_OneStep_BaseType($Type{"Tid"}, $TypeInfo{$LibVersion}); $Size *= $Base{"Size"}; $TypeInfo{$LibVersion}{$TypeId}{"Size"} = "$Size"; } else { # array[] is a pointer $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $WORD_SIZE{$LibVersion}; } } } } my $V2 = ($LibVersion==1)?2:1; if(not checkDump($LibVersion, "2.7")) { # support for old ABI dumps # size of "method ptr" corrected in 2.7 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) { my %PureType = get_PureType($TypeId, $TypeInfo{$LibVersion}); if($PureType{"Type"} eq "MethodPtr") { my %Type = get_Type($TypeId, $LibVersion); my $TypeId_2 = getTypeIdByName($PureType{"Name"}, $V2); my %Type2 = get_Type($TypeId_2, $V2); if($Type{"Size"} ne $Type2{"Size"}) { $TypeInfo{$LibVersion}{$TypeId}{"Size"} = $Type2{"Size"}; } } } } } sub prepareSymbols($) { my $LibVersion = $_[0]; if(not keys(%{$SymbolInfo{$LibVersion}})) { # check if input is valid if(not $ExtendedCheck and not $CheckObjectsOnly) { if($CheckHeadersOnly) { exitStatus("Empty_Set", "the set of public symbols is empty (".$Descriptor{$LibVersion}{"Version"}.")"); } else { exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection (".$Descriptor{$LibVersion}{"Version"}.")"); } } } my $Remangle = 0; if(not checkDump(1, "2.10") or not checkDump(2, "2.10")) { # different formats $Remangle = 1; } if($CheckHeadersOnly) { # different languages if($UserLang) { # --lang=LANG for both versions if(($UsedDump{1}{"V"} and $UserLang ne $UsedDump{1}{"L"}) or ($UsedDump{2}{"V"} and $UserLang ne $UsedDump{2}{"L"})) { if($UserLang eq "C++") { # remangle symbols $Remangle = 1; } elsif($UserLang eq "C") { # remove mangling $Remangle = -1; } } } } foreach my $InfoId (sort {int($b)<=>int($a)} keys(%{$SymbolInfo{$LibVersion}})) { # reverse order: D0, D1, D2, D0 (artificial, GCC < 4.5), C1, C2 if(not checkDump($LibVersion, "2.13")) { # support for old ABI dumps if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}) { foreach my $P (keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})) { my $TypeId = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"type"}; my $DVal = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"}; my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"}; if(defined $DVal and $DVal ne "") { if($TName eq "char") { $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"} = chr($DVal); } elsif($TName eq "bool") { $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$P}{"default"} = $DVal?"true":"false"; } } } } } if($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) { if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"} and keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}}) and $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{0}{"name"} ne "this") { # support for old GCC < 4.5: skip artificial ~dtor(int __in_chrg) # + support for old ABI dumps next; } } my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"}; my $ShortName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"}; my $ClassID = $SymbolInfo{$LibVersion}{$InfoId}{"Class"}; my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"}; my $SRemangle = 0; if(not checkDump(1, "2.12") or not checkDump(2, "2.12")) { # support for old ABI dumps if($ShortName eq "operator>>") { if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}) { # corrected mangling of operator>> $SRemangle = 1; } } if($SymbolInfo{$LibVersion}{$InfoId}{"Data"}) { if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"} and isConstType($Return, $LibVersion) and $MnglName!~/L\d+$ShortName/) { # corrected mangling of const global data # some global data is not mangled in the TU dump: qt_sine_table (Qt 4.8) # and incorrectly mangled by old ACC versions $SRemangle = 1; } } } if(not $CheckHeadersOnly) { # support for old ABI dumps if(not checkDump(1, "2.17") or not checkDump(2, "2.17")) { if($SymbolInfo{$LibVersion}{$InfoId}{"Data"}) { if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}) { if(link_symbol($ShortName, $LibVersion, "-Deps")) { $MnglName = $ShortName; $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName; } } } } } if($Remangle==1 or $SRemangle==1) { # support for old ABI dumps: some symbols are not mangled in old dumps # mangle both sets of symbols (old and new) # NOTE: remangling all symbols by the same mangler if($MnglName=~/\A_ZN(V|)K/) { # mangling may be incorrect on old ABI dumps # because of absent "Const" attribute $SymbolInfo{$LibVersion}{$InfoId}{"Const"} = 1; } if($MnglName=~/\A_ZN(K|)V/) { # mangling may be incorrect on old ABI dumps # because of absent "Volatile" attribute $SymbolInfo{$LibVersion}{$InfoId}{"Volatile"} = 1; } if(($ClassID and $MnglName!~/\A(_Z|\?)/) or (not $ClassID and $CheckHeadersOnly) or (not $ClassID and not link_symbol($MnglName, $LibVersion, "-Deps"))) { # support for old ABI dumps, GCC >= 4.0 # remangling all manually mangled symbols if($MnglName = mangle_symbol($InfoId, $LibVersion, "GCC")) { $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName; $MangledNames{$LibVersion}{$MnglName} = 1; } } } elsif($Remangle==-1) { # remove mangling $MnglName = ""; $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = ""; } if(not $MnglName) { next; } if(not $CompleteSignature{$LibVersion}{$MnglName}{"MnglName"}) { # NOTE: global data may enter here twice %{$CompleteSignature{$LibVersion}{$MnglName}} = %{$SymbolInfo{$LibVersion}{$InfoId}}; } if(not checkDump($LibVersion, "2.6")) { # support for old dumps # add "Volatile" attribute if($MnglName=~/_Z(K|)V/) { $CompleteSignature{$LibVersion}{$MnglName}{"Volatile"}=1; } } # symbol and its symlink have same signatures if($SymVer{$LibVersion}{$MnglName}) { %{$CompleteSignature{$LibVersion}{$SymVer{$LibVersion}{$MnglName}}} = %{$SymbolInfo{$LibVersion}{$InfoId}}; } if(my $Alias = $CompleteSignature{$LibVersion}{$MnglName}{"Alias"}) { %{$CompleteSignature{$LibVersion}{$Alias}} = %{$SymbolInfo{$LibVersion}{$InfoId}}; if($SymVer{$LibVersion}{$Alias}) { %{$CompleteSignature{$LibVersion}{$SymVer{$LibVersion}{$Alias}}} = %{$SymbolInfo{$LibVersion}{$InfoId}}; } } # clean memory delete($SymbolInfo{$LibVersion}{$InfoId}); } if($COMMON_LANGUAGE{$LibVersion} eq "C++" or $OSgroup eq "windows") { translateSymbols(keys(%{$CompleteSignature{$LibVersion}}), $LibVersion); } if($ExtendedCheck) { # --ext option addExtension($LibVersion); } # clean memory delete($SymbolInfo{$LibVersion}); foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}})) { # detect allocable classes with public exported constructors # or classes with auto-generated or inline-only constructors # and other temp info if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"}) { my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"}; if($CompleteSignature{$LibVersion}{$Symbol}{"Constructor"} and not $CompleteSignature{$LibVersion}{$Symbol}{"InLine"}) { # Class() { ... } will not be exported if(not $CompleteSignature{$LibVersion}{$Symbol}{"Private"}) { if($CheckHeadersOnly or link_symbol($Symbol, $LibVersion, "-Deps")) { $AllocableClass{$LibVersion}{$ClassName} = 1; } } } if(not $CompleteSignature{$LibVersion}{$Symbol}{"Private"}) { # all imported class methods if(symbolFilter($Symbol, $LibVersion, "Affected", "Binary")) { if($CheckHeadersOnly) { if(not $CompleteSignature{$LibVersion}{$Symbol}{"InLine"} or $CompleteSignature{$LibVersion}{$Symbol}{"Virt"}) { # all symbols except non-virtual inline $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$Symbol} = 1; } } else { $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$Symbol} = 1; } } if(symbolFilter($Symbol, $LibVersion, "Affected", "Source")) { $ClassMethods{"Source"}{$LibVersion}{$ClassName}{$Symbol} = 1; } } $ClassNames{$LibVersion}{$ClassName} = 1; } if(my $RetId = $CompleteSignature{$LibVersion}{$Symbol}{"Return"}) { my %Base = get_BaseType($RetId, $LibVersion); if(defined $Base{"Type"} and $Base{"Type"}=~/Struct|Class/) { my $Name = $TypeInfo{$LibVersion}{$Base{"Tid"}}{"Name"}; if($Name=~/<([^<>\s]+)>/) { if(my $Tid = getTypeIdByName($1, $LibVersion)) { $ReturnedClass{$LibVersion}{$Tid} = 1; } } else { $ReturnedClass{$LibVersion}{$Base{"Tid"}} = 1; } } } foreach my $Num (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}})) { my $PId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Num}{"type"}; if(get_PLevel($PId, $LibVersion)>=1) { if(my %Base = get_BaseType($PId, $LibVersion)) { if($Base{"Type"}=~/Struct|Class/) { $ParamClass{$LibVersion}{$Base{"Tid"}}{$Symbol} = 1; foreach my $SubId (get_sub_classes($Base{"Tid"}, $LibVersion, 1)) { # mark all derived classes $ParamClass{$LibVersion}{$SubId}{$Symbol} = 1; } } } } } # mapping {short name => symbols} $Func_ShortName{$LibVersion}{$CompleteSignature{$LibVersion}{$Symbol}{"ShortName"}}{$Symbol} = 1; } foreach my $MnglName (keys(%VTableClass)) { # reconstruct attributes of v-tables if(index($MnglName, "_ZTV")==0) { if(my $ClassName = $VTableClass{$MnglName}) { if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName}) { $CompleteSignature{$LibVersion}{$MnglName}{"Header"} = $TypeInfo{$LibVersion}{$ClassId}{"Header"}; $CompleteSignature{$LibVersion}{$MnglName}{"Class"} = $ClassId; } } } } # types foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}})) { if(my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"}) { if(defined $TypeInfo{$LibVersion}{$TypeId}{"VTable"}) { $ClassNames{$LibVersion}{$TName} = 1; } if(defined $TypeInfo{$LibVersion}{$TypeId}{"Base"}) { $ClassNames{$LibVersion}{$TName} = 1; foreach my $Bid (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"Base"}})) { if(my $BName = $TypeInfo{$LibVersion}{$Bid}{"Name"}) { $ClassNames{$LibVersion}{$BName} = 1; } } } } } } sub getFirst($$) { my ($Tid, $LibVersion) = @_; if(not $Tid) { return $Tid; } if(my $Name = $TypeInfo{$LibVersion}{$Tid}{"Name"}) { if($TName_Tid{$LibVersion}{$Name}) { return $TName_Tid{$LibVersion}{$Name}; } } return $Tid; } sub register_SymbolUsage($$$) { my ($InfoId, $UsedType, $LibVersion) = @_; my %FuncInfo = %{$SymbolInfo{$LibVersion}{$InfoId}}; if(my $RTid = getFirst($FuncInfo{"Return"}, $LibVersion)) { register_TypeUsage($RTid, $UsedType, $LibVersion); $SymbolInfo{$LibVersion}{$InfoId}{"Return"} = $RTid; } if(my $FCid = getFirst($FuncInfo{"Class"}, $LibVersion)) { register_TypeUsage($FCid, $UsedType, $LibVersion); $SymbolInfo{$LibVersion}{$InfoId}{"Class"} = $FCid; if(my $ThisId = getTypeIdByName($TypeInfo{$LibVersion}{$FCid}{"Name"}."*const", $LibVersion)) { # register "this" pointer register_TypeUsage($ThisId, $UsedType, $LibVersion); } if(my $ThisId_C = getTypeIdByName($TypeInfo{$LibVersion}{$FCid}{"Name"}."const*const", $LibVersion)) { # register "this" pointer (const method) register_TypeUsage($ThisId_C, $UsedType, $LibVersion); } } foreach my $PPos (keys(%{$FuncInfo{"Param"}})) { if(my $PTid = getFirst($FuncInfo{"Param"}{$PPos}{"type"}, $LibVersion)) { register_TypeUsage($PTid, $UsedType, $LibVersion); $FuncInfo{"Param"}{$PPos}{"type"} = $PTid; } } foreach my $TPos (keys(%{$FuncInfo{"TParam"}})) { my $TPName = $FuncInfo{"TParam"}{$TPos}{"name"}; if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) { register_TypeUsage($TTid, $UsedType, $LibVersion); } } } sub register_TypeUsage($$$) { my ($TypeId, $UsedType, $LibVersion) = @_; if(not $TypeId) { return; } if($UsedType->{$TypeId}) { # already registered return; } my %TInfo = get_Type($TypeId, $LibVersion); if($TInfo{"Type"}) { if(my $NS = $TInfo{"NameSpace"}) { if(my $NSTid = $TName_Tid{$LibVersion}{$NS}) { register_TypeUsage($NSTid, $UsedType, $LibVersion); } } if($TInfo{"Type"}=~/\A(Struct|Union|Class|FuncPtr|Func|MethodPtr|FieldPtr|Enum)\Z/) { $UsedType->{$TypeId} = 1; if($TInfo{"Type"}=~/\A(Struct|Class)\Z/) { foreach my $BaseId (keys(%{$TInfo{"Base"}})) { register_TypeUsage($BaseId, $UsedType, $LibVersion); } foreach my $TPos (keys(%{$TInfo{"TParam"}})) { my $TPName = $TInfo{"TParam"}{$TPos}{"name"}; if(my $TTid = $TName_Tid{$LibVersion}{$TPName}) { register_TypeUsage($TTid, $UsedType, $LibVersion); } } } foreach my $Memb_Pos (keys(%{$TInfo{"Memb"}})) { if(my $MTid = getFirst($TInfo{"Memb"}{$Memb_Pos}{"type"}, $LibVersion)) { register_TypeUsage($MTid, $UsedType, $LibVersion); $TInfo{"Memb"}{$Memb_Pos}{"type"} = $MTid; } } if($TInfo{"Type"} eq "FuncPtr" or $TInfo{"Type"} eq "MethodPtr" or $TInfo{"Type"} eq "Func") { if(my $RTid = $TInfo{"Return"}) { register_TypeUsage($RTid, $UsedType, $LibVersion); } foreach my $PPos (keys(%{$TInfo{"Param"}})) { if(my $PTid = $TInfo{"Param"}{$PPos}{"type"}) { register_TypeUsage($PTid, $UsedType, $LibVersion); } } } if($TInfo{"Type"} eq "FieldPtr") { if(my $RTid = $TInfo{"Return"}) { register_TypeUsage($RTid, $UsedType, $LibVersion); } if(my $CTid = $TInfo{"Class"}) { register_TypeUsage($CTid, $UsedType, $LibVersion); } } if($TInfo{"Type"} eq "MethodPtr") { if(my $CTid = $TInfo{"Class"}) { register_TypeUsage($CTid, $UsedType, $LibVersion); } } } elsif($TInfo{"Type"}=~/\A(Const|ConstVolatile|Volatile|Pointer|Ref|Restrict|Array|Typedef)\Z/) { $UsedType->{$TypeId} = 1; if(my $BTid = getFirst($TInfo{"BaseType"}, $LibVersion)) { register_TypeUsage($BTid, $UsedType, $LibVersion); $TypeInfo{$LibVersion}{$TypeId}{"BaseType"} = $BTid; } } else { # Intrinsic, TemplateParam, TypeName, SizeOf, etc. $UsedType->{$TypeId} = 1; } } } sub selectSymbol($$$$) { # select symbol to check or to dump my ($Symbol, $SInfo, $Level, $LibVersion) = @_; if($Level eq "Dump") { if($SInfo->{"Virt"} or $SInfo->{"PureVirt"}) { # TODO: check if this symbol is from # base classes of other target symbols return 1; } } if(not $STDCXX_TESTING and $Symbol=~/\A(_ZS|_ZNS|_ZNKS)/) { # stdc++ interfaces return 0; } my $Target = 0; if(my $Header = $SInfo->{"Header"}) { $Target = (is_target_header($Header, 1) or is_target_header($Header, 2)); } if($ExtendedCheck) { if(index($Symbol, "external_func_")==0) { $Target = 1; } } if($CheckHeadersOnly or $Level eq "Source") { if($Target) { if($Level eq "Dump") { # dumped if($BinaryOnly) { if(not $SInfo->{"InLine"} or $SInfo->{"Data"}) { return 1; } } else { return 1; } } elsif($Level eq "Source") { # checked return 1; } elsif($Level eq "Binary") { # checked if(not $SInfo->{"InLine"} or $SInfo->{"Data"} or $SInfo->{"Virt"} or $SInfo->{"PureVirt"}) { return 1; } } } } else { # library is available if(link_symbol($Symbol, $LibVersion, "-Deps")) { # exported symbols return 1; } if($Level eq "Dump") { # dumped if($BinaryOnly) { if($SInfo->{"Data"}) { if($Target) { return 1; } } } else { # SrcBin if($Target) { return 1; } } } elsif($Level eq "Source") { # checked if($SInfo->{"PureVirt"} or $SInfo->{"Data"} or $SInfo->{"InLine"} or isInLineInst($Symbol, $SInfo, $LibVersion)) { # skip LOCAL symbols if($Target) { return 1; } } } elsif($Level eq "Binary") { # checked if($SInfo->{"PureVirt"} or $SInfo->{"Data"}) { if($Target) { return 1; } } } } return 0; } sub cleanDump($) { # clean data my $LibVersion = $_[0]; foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}})) { if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}})) { delete($SymbolInfo{$LibVersion}{$InfoId}); next; } my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"}; if(not $MnglName) { delete($SymbolInfo{$LibVersion}{$InfoId}); next; } my $ShortName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"}; if(not $ShortName) { delete($SymbolInfo{$LibVersion}{$InfoId}); next; } if($MnglName eq $ShortName) { # remove duplicate data delete($SymbolInfo{$LibVersion}{$InfoId}{"MnglName"}); } if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})) { delete($SymbolInfo{$LibVersion}{$InfoId}{"Param"}); } if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"TParam"}})) { delete($SymbolInfo{$LibVersion}{$InfoId}{"TParam"}); } delete($SymbolInfo{$LibVersion}{$InfoId}{"Type"}); } foreach my $Tid (keys(%{$TypeInfo{$LibVersion}})) { if(not keys(%{$TypeInfo{$LibVersion}{$Tid}})) { delete($TypeInfo{$LibVersion}{$Tid}); next; } delete($TypeInfo{$LibVersion}{$Tid}{"Tid"}); foreach my $Attr ("Header", "Line", "Size", "NameSpace") { if(not $TypeInfo{$LibVersion}{$Tid}{$Attr}) { delete($TypeInfo{$LibVersion}{$Tid}{$Attr}); } } if(not keys(%{$TypeInfo{$LibVersion}{$Tid}{"TParam"}})) { delete($TypeInfo{$LibVersion}{$Tid}{"TParam"}); } } } sub selectType($$) { my ($Tid, $LibVersion) = @_; if(my $Dupl = $TypeTypedef{$LibVersion}{$Tid}) { if(defined $TypeInfo{$LibVersion}{$Dupl}) { if($TypeInfo{$LibVersion}{$Dupl}{"Name"} eq $TypeInfo{$LibVersion}{$Tid}{"Name"}) { # duplicate return 0; } } } if(my $THeader = $TypeInfo{$LibVersion}{$Tid}{"Header"}) { if(not isBuiltIn($THeader)) { if($TypeInfo{$LibVersion}{$Tid}{"Type"}=~/Class|Struct|Union|Enum|Typedef/) { if(not isAnon($TypeInfo{$LibVersion}{$Tid}{"Name"})) { if(is_target_header($THeader, $LibVersion)) { # from target headers if(not selfTypedef($Tid, $LibVersion)) { return 1; } } } } } } return 0; } sub remove_Unused($$) { # remove unused data types from the ABI dump my ($LibVersion, $Kind) = @_; my %UsedType = (); foreach my $InfoId (sort {int($a)<=>int($b)} keys(%{$SymbolInfo{$LibVersion}})) { register_SymbolUsage($InfoId, \%UsedType, $LibVersion); } foreach my $Tid (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) { if($UsedType{$Tid}) { # All & Extended next; } if($Kind eq "Extended") { if(selectType($Tid, $LibVersion)) { my %Tree = (); register_TypeUsage($Tid, \%Tree, $LibVersion); my $Tmpl = 0; foreach (sort {int($a)<=>int($b)} keys(%Tree)) { if(defined $TypeInfo{$LibVersion}{$_}{"Template"} or $TypeInfo{$LibVersion}{$_}{"Type"} eq "TemplateParam") { $Tmpl = 1; last; } } if(not $Tmpl) { foreach (keys(%Tree)) { $UsedType{$_} = 1; } } } } } my %Delete = (); foreach my $Tid (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) { # remove unused types if($UsedType{$Tid}) { # All & Extended next; } if($Kind eq "Extra") { my %Tree = (); register_TypeUsage($Tid, \%Tree, $LibVersion); foreach (sort {int($a)<=>int($b)} keys(%Tree)) { if(defined $TypeInfo{$LibVersion}{$_}{"Template"} or $TypeInfo{$LibVersion}{$_}{"Type"} eq "TemplateParam") { $Delete{$Tid} = 1; last; } } } else { # remove type delete($TypeInfo{$LibVersion}{$Tid}); } } if($Kind eq "Extra") { # remove duplicates foreach my $Tid (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) { if($UsedType{$Tid}) { # All & Extended next; } my $Name = $TypeInfo{$LibVersion}{$Tid}{"Name"}; if($TName_Tid{$LibVersion}{$Name} ne $Tid) { delete($TypeInfo{$LibVersion}{$Tid}); } } } foreach my $Tid (keys(%Delete)) { delete($TypeInfo{$LibVersion}{$Tid}); } } sub check_Completeness($$) { my ($Info, $LibVersion) = @_; # data types if(defined $Info->{"Memb"}) { foreach my $Pos (keys(%{$Info->{"Memb"}})) { if(defined $Info->{"Memb"}{$Pos}{"type"}) { check_TypeInfo($Info->{"Memb"}{$Pos}{"type"}, $LibVersion); } } } if(defined $Info->{"Base"}) { foreach my $Bid (keys(%{$Info->{"Base"}})) { check_TypeInfo($Bid, $LibVersion); } } if(defined $Info->{"BaseType"}) { check_TypeInfo($Info->{"BaseType"}, $LibVersion); } if(defined $Info->{"TParam"}) { foreach my $Pos (keys(%{$Info->{"TParam"}})) { my $TName = $Info->{"TParam"}{$Pos}{"name"}; if($TName=~/\A\(.+\)(true|false|\d.*)\Z/) { next; } if($TName eq "_BoolType") { next; } if($TName=~/\Asizeof\(/) { next; } if(my $Tid = $TName_Tid{$LibVersion}{$TName}) { check_TypeInfo($Tid, $LibVersion); } else { if(defined $Debug) { printMsg("WARNING", "missed type $TName"); } } } } # symbols if(defined $Info->{"Param"}) { foreach my $Pos (keys(%{$Info->{"Param"}})) { if(defined $Info->{"Param"}{$Pos}{"type"}) { check_TypeInfo($Info->{"Param"}{$Pos}{"type"}, $LibVersion); } } } if(defined $Info->{"Return"}) { check_TypeInfo($Info->{"Return"}, $LibVersion); } if(defined $Info->{"Class"}) { check_TypeInfo($Info->{"Class"}, $LibVersion); } } sub check_TypeInfo($$) { my ($Tid, $LibVersion) = @_; if(defined $CheckedTypeInfo{$LibVersion}{$Tid}) { return; } $CheckedTypeInfo{$LibVersion}{$Tid} = 1; if(defined $TypeInfo{$LibVersion}{$Tid}) { if(not $TypeInfo{$LibVersion}{$Tid}{"Name"}) { printMsg("ERROR", "missed type name ($Tid)"); } check_Completeness($TypeInfo{$LibVersion}{$Tid}, $LibVersion); } else { printMsg("ERROR", "missed type id $Tid"); } } sub selfTypedef($$) { my ($TypeId, $LibVersion) = @_; my %Type = get_Type($TypeId, $LibVersion); if($Type{"Type"} eq "Typedef") { my %Base = get_OneStep_BaseType($TypeId, $TypeInfo{$LibVersion}); if($Base{"Type"}=~/Class|Struct/) { if($Type{"Name"} eq $Base{"Name"}) { return 1; } elsif($Type{"Name"}=~/::(\w+)\Z/) { if($Type{"Name"} eq $Base{"Name"}."::".$1) { # QPointer::QPointer return 1; } } } } return 0; } sub addExtension($) { my $LibVersion = $_[0]; foreach my $Tid (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) { if(selectType($Tid, $LibVersion)) { my $TName = $TypeInfo{$LibVersion}{$Tid}{"Name"}; $TName=~s/\A(struct|union|class|enum) //; my $Symbol = "external_func_".$TName; %{$CompleteSignature{$LibVersion}{$Symbol}} = ( "Header" => "extended.h", "ShortName" => $Symbol, "MnglName" => $Symbol, "Param" => { 0 => { "type"=>$Tid, "name"=>"p1" } } ); $ExtendedSymbols{$Symbol} = 1; $CheckedSymbols{"Binary"}{$Symbol} = 1; $CheckedSymbols{"Source"}{$Symbol} = 1; } } $ExtendedSymbols{"external_func_0"} = 1; $CheckedSymbols{"Binary"}{"external_func_0"} = 1; $CheckedSymbols{"Source"}{"external_func_0"} = 1; } sub findMethod($$$) { my ($VirtFunc, $ClassId, $LibVersion) = @_; foreach my $BaseClass_Id (keys(%{$TypeInfo{$LibVersion}{$ClassId}{"Base"}})) { if(my $VirtMethodInClass = findMethod_Class($VirtFunc, $BaseClass_Id, $LibVersion)) { return $VirtMethodInClass; } elsif(my $VirtMethodInBaseClasses = findMethod($VirtFunc, $BaseClass_Id, $LibVersion)) { return $VirtMethodInBaseClasses; } } return ""; } sub findMethod_Class($$$) { my ($VirtFunc, $ClassId, $LibVersion) = @_; my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"}; return "" if(not defined $VirtualTable{$LibVersion}{$ClassName}); my $TargetSuffix = get_symbol_suffix($VirtFunc, 1); my $TargetShortName = $CompleteSignature{$LibVersion}{$VirtFunc}{"ShortName"}; foreach my $Candidate (keys(%{$VirtualTable{$LibVersion}{$ClassName}})) { # search for interface with the same parameters suffix (overridden) if($TargetSuffix eq get_symbol_suffix($Candidate, 1)) { if($CompleteSignature{$LibVersion}{$VirtFunc}{"Destructor"}) { if($CompleteSignature{$LibVersion}{$Candidate}{"Destructor"}) { if(($VirtFunc=~/D0E/ and $Candidate=~/D0E/) or ($VirtFunc=~/D1E/ and $Candidate=~/D1E/) or ($VirtFunc=~/D2E/ and $Candidate=~/D2E/)) { return $Candidate; } } } else { if($TargetShortName eq $CompleteSignature{$LibVersion}{$Candidate}{"ShortName"}) { return $Candidate; } } } } return ""; } sub registerVTable($) { my $LibVersion = $_[0]; foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}})) { if($CompleteSignature{$LibVersion}{$Symbol}{"Virt"} or $CompleteSignature{$LibVersion}{$Symbol}{"PureVirt"}) { my $ClassName = $TypeInfo{$LibVersion}{$CompleteSignature{$LibVersion}{$Symbol}{"Class"}}{"Name"}; next if(not $STDCXX_TESTING and $ClassName=~/\A(std::|__cxxabi)/); if($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"} and $Symbol=~/D2E/) { # pure virtual D2-destructors are marked as "virt" in the dump # virtual D2-destructors are NOT marked as "virt" in the dump # both destructors are not presented in the v-table next; } my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol); $VirtualTable{$LibVersion}{$ClassName}{$MnglName} = 1; } } } sub registerOverriding($) { my $LibVersion = $_[0]; my @Classes = keys(%{$VirtualTable{$LibVersion}}); @Classes = sort {int($TName_Tid{$LibVersion}{$a})<=>int($TName_Tid{$LibVersion}{$b})} @Classes; foreach my $ClassName (@Classes) { foreach my $VirtFunc (keys(%{$VirtualTable{$LibVersion}{$ClassName}})) { if($CompleteSignature{$LibVersion}{$VirtFunc}{"PureVirt"}) { # pure virtuals next; } my $ClassId = $TName_Tid{$LibVersion}{$ClassName}; if(my $Overridden = findMethod($VirtFunc, $ClassId, $LibVersion)) { if($CompleteSignature{$LibVersion}{$Overridden}{"Virt"} or $CompleteSignature{$LibVersion}{$Overridden}{"PureVirt"}) { # both overridden virtual methods # and implemented pure virtual methods $CompleteSignature{$LibVersion}{$VirtFunc}{"Override"} = $Overridden; $OverriddenMethods{$LibVersion}{$Overridden}{$VirtFunc} = 1; delete($VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}); # remove from v-table model } } } if(not keys(%{$VirtualTable{$LibVersion}{$ClassName}})) { delete($VirtualTable{$LibVersion}{$ClassName}); } } } sub setVirtFuncPositions($) { my $LibVersion = $_[0]; foreach my $ClassName (keys(%{$VirtualTable{$LibVersion}})) { my ($Num, $Rel) = (1, 0); if(my @Funcs = sort keys(%{$VirtualTable{$LibVersion}{$ClassName}})) { if($UsedDump{$LibVersion}{"DWARF"}) { @Funcs = sort {int($CompleteSignature{$LibVersion}{$a}{"VirtPos"}) <=> int($CompleteSignature{$LibVersion}{$b}{"VirtPos"})} @Funcs; } else { @Funcs = sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})} @Funcs; } foreach my $VirtFunc (@Funcs) { if($UsedDump{$LibVersion}{"DWARF"}) { $VirtualTable{$LibVersion}{$ClassName}{$VirtFunc} = $CompleteSignature{$LibVersion}{$VirtFunc}{"VirtPos"}; } else { $VirtualTable{$LibVersion}{$ClassName}{$VirtFunc} = $Num++; } # set relative positions if(defined $VirtualTable{1}{$ClassName} and defined $VirtualTable{1}{$ClassName}{$VirtFunc} and defined $VirtualTable{2}{$ClassName} and defined $VirtualTable{2}{$ClassName}{$VirtFunc}) { # relative position excluding added and removed virtual functions if(not $CompleteSignature{1}{$VirtFunc}{"Override"} and not $CompleteSignature{2}{$VirtFunc}{"Override"}) { $CompleteSignature{$LibVersion}{$VirtFunc}{"RelPos"} = $Rel++; } } } } } foreach my $ClassName (keys(%{$ClassNames{$LibVersion}})) { my $AbsNum = 1; foreach my $VirtFunc (getVTable_Model($TName_Tid{$LibVersion}{$ClassName}, $LibVersion)) { $VirtualTable_Model{$LibVersion}{$ClassName}{$VirtFunc} = $AbsNum++; } } } sub get_sub_classes($$$) { my ($ClassId, $LibVersion, $Recursive) = @_; return () if(not defined $Class_SubClasses{$LibVersion}{$ClassId}); my @Subs = (); foreach my $SubId (keys(%{$Class_SubClasses{$LibVersion}{$ClassId}})) { if($Recursive) { foreach my $SubSubId (get_sub_classes($SubId, $LibVersion, $Recursive)) { push(@Subs, $SubSubId); } } push(@Subs, $SubId); } return @Subs; } sub get_base_classes($$$) { my ($ClassId, $LibVersion, $Recursive) = @_; my %ClassType = get_Type($ClassId, $LibVersion); return () if(not defined $ClassType{"Base"}); my @Bases = (); foreach my $BaseId (sort {int($ClassType{"Base"}{$a}{"pos"})<=>int($ClassType{"Base"}{$b}{"pos"})} keys(%{$ClassType{"Base"}})) { if($Recursive) { foreach my $SubBaseId (get_base_classes($BaseId, $LibVersion, $Recursive)) { push(@Bases, $SubBaseId); } } push(@Bases, $BaseId); } return @Bases; } sub getVTable_Model($$) { # return an ordered list of v-table elements my ($ClassId, $LibVersion) = @_; my @Bases = get_base_classes($ClassId, $LibVersion, 1); my @Elements = (); foreach my $BaseId (@Bases, $ClassId) { if(my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"}) { if(defined $VirtualTable{$LibVersion}{$BName}) { my @VFuncs = keys(%{$VirtualTable{$LibVersion}{$BName}}); if($UsedDump{$LibVersion}{"DWARF"}) { @VFuncs = sort {int($CompleteSignature{$LibVersion}{$a}{"VirtPos"}) <=> int($CompleteSignature{$LibVersion}{$b}{"VirtPos"})} @VFuncs; } else { @VFuncs = sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})} @VFuncs; } foreach my $VFunc (@VFuncs) { push(@Elements, $VFunc); } } } } return @Elements; } sub getVShift($$) { my ($ClassId, $LibVersion) = @_; my @Bases = get_base_classes($ClassId, $LibVersion, 1); my $VShift = 0; foreach my $BaseId (@Bases) { if(my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"}) { if(defined $VirtualTable{$LibVersion}{$BName}) { $VShift+=keys(%{$VirtualTable{$LibVersion}{$BName}}); } } } return $VShift; } sub getShift($$) { my ($ClassId, $LibVersion) = @_; my @Bases = get_base_classes($ClassId, $LibVersion, 0); my $Shift = 0; foreach my $BaseId (@Bases) { if(my $Size = $TypeInfo{$LibVersion}{$BaseId}{"Size"}) { if($Size!=1) { # not empty base class $Shift+=$Size; } } } return $Shift; } sub getVTable_Size($$) { # number of v-table elements my ($ClassName, $LibVersion) = @_; my $Size = 0; # three approaches if(not $Size) { # real size if(my %VTable = getVTable_Real($ClassName, $LibVersion)) { $Size = keys(%VTable); } } if(not $Size) { # shared library symbol size if($Size = getSymbolSize($ClassVTable{$ClassName}, $LibVersion)) { $Size /= $WORD_SIZE{$LibVersion}; } } if(not $Size) { # model size if(defined $VirtualTable_Model{$LibVersion}{$ClassName}) { $Size = keys(%{$VirtualTable_Model{$LibVersion}{$ClassName}}) + 2; } } return $Size; } sub isCopyingClass($$) { my ($TypeId, $LibVersion) = @_; return $TypeInfo{$LibVersion}{$TypeId}{"Copied"}; } sub isLeafClass($$) { my ($ClassId, $LibVersion) = @_; return (not keys(%{$Class_SubClasses{$LibVersion}{$ClassId}})); } sub havePubFields($) { # check structured type for public fields return isAccessible($_[0], {}, 0, -1); } sub isAccessible($$$$) { # check interval in structured type for public fields my ($TypePtr, $Skip, $Start, $End) = @_; return 0 if(not $TypePtr); if($End==-1) { $End = keys(%{$TypePtr->{"Memb"}})-1; } foreach my $MemPos (keys(%{$TypePtr->{"Memb"}})) { if($Skip and $Skip->{$MemPos}) { # skip removed/added fields next; } if(int($MemPos)>=$Start and int($MemPos)<=$End) { if(isPublic($TypePtr, $MemPos)) { return ($MemPos+1); } } } return 0; } sub isReserved($) { # reserved fields == private my $MName = $_[0]; if($MName=~/reserved|padding|f_spare/i) { return 1; } if($MName=~/\A[_]*(spare|pad|unused|dummy)[_\d]*\Z/i) { return 1; } if($MName=~/(pad\d+)/i) { return 1; } return 0; } sub isPublic($$) { my ($TypePtr, $FieldPos) = @_; return 0 if(not $TypePtr); return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos}); return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos}{"name"}); if(not $TypePtr->{"Memb"}{$FieldPos}{"access"}) { # by name in C language # FIXME: add other methods to detect private members my $MName = $TypePtr->{"Memb"}{$FieldPos}{"name"}; if($MName=~/priv|abidata|parent_object/i) { # C-styled private data return 0; } if(lc($MName) eq "abi") { # ABI information/reserved field return 0; } if(isReserved($MName)) { # reserved fields return 0; } return 1; } elsif($TypePtr->{"Memb"}{$FieldPos}{"access"} ne "private") { # by access in C++ language return 1; } return 0; } sub getVTable_Real($$) { my ($ClassName, $LibVersion) = @_; if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName}) { my %Type = get_Type($ClassId, $LibVersion); if(defined $Type{"VTable"}) { return %{$Type{"VTable"}}; } } return (); } sub cmpVTables($) { my $ClassName = $_[0]; my $Res = cmpVTables_Real($ClassName, 1); if($Res==-1) { $Res = cmpVTables_Model($ClassName); } return $Res; } sub cmpVTables_Model($) { my $ClassName = $_[0]; foreach my $Symbol (keys(%{$VirtualTable_Model{1}{$ClassName}})) { if(not defined $VirtualTable_Model{2}{$ClassName}{$Symbol}) { return 1; } } return 0; } sub cmpVTables_Real($$) { my ($ClassName, $Strong) = @_; if(defined $Cache{"cmpVTables_Real"}{$Strong}{$ClassName}) { return $Cache{"cmpVTables_Real"}{$Strong}{$ClassName}; } my %VTable_Old = getVTable_Real($ClassName, 1); my %VTable_New = getVTable_Real($ClassName, 2); if(not %VTable_Old or not %VTable_New) { # old ABI dumps return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = -1); } my %Indexes = map {$_=>1} (keys(%VTable_Old), keys(%VTable_New)); foreach my $Offset (sort {int($a)<=>int($b)} keys(%Indexes)) { if(not defined $VTable_Old{$Offset}) { # v-table v.1 < v-table v.2 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = $Strong); } my $Entry1 = $VTable_Old{$Offset}; if(not defined $VTable_New{$Offset}) { # v-table v.1 > v-table v.2 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = ($Strong or $Entry1!~/__cxa_pure_virtual/)); } my $Entry2 = $VTable_New{$Offset}; $Entry1 = simpleVEntry($Entry1); $Entry2 = simpleVEntry($Entry2); if($Entry1 ne $Entry2) { # register as changed if($Entry1=~/::([^:]+)\Z/) { my $M1 = $1; if($Entry2=~/::([^:]+)\Z/) { my $M2 = $1; if($M1 eq $M2) { # overridden next; } } } if(differentDumps("G")) { if($Entry1=~/\A\-(0x|\d+)/ and $Entry2=~/\A\-(0x|\d+)/) { # GCC 4.6.1: -0x00000000000000010 # GCC 4.7.0: -16 next; } } return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 1); } } return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 0); } sub mergeVTables($) { # merging v-tables without diagnostics my $Level = $_[0]; foreach my $ClassName (keys(%{$VirtualTable{1}})) { if($VTableChanged_M{$ClassName}) { # already registered next; } if(cmpVTables_Real($ClassName, 0)==1) { my @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}})); foreach my $Symbol (@Affected) { %{$CompatProblems{$Level}{$Symbol}{"Virtual_Table_Changed_Unknown"}{$ClassName}}=( "Type_Name"=>$ClassName, "Target"=>$ClassName); } } } } sub mergeBases($) { my $Level = $_[0]; foreach my $ClassName (keys(%{$ClassNames{1}})) { # detect added and removed virtual functions my $ClassId = $TName_Tid{1}{$ClassName}; next if(not $ClassId); if(defined $VirtualTable{2}{$ClassName}) { foreach my $Symbol (keys(%{$VirtualTable{2}{$ClassName}})) { if($TName_Tid{1}{$ClassName} and not defined $VirtualTable{1}{$ClassName}{$Symbol}) { # added to v-table if(defined $CompleteSignature{1}{$Symbol} and $CompleteSignature{1}{$Symbol}{"Virt"}) { # override some method in v.1 next; } $AddedInt_Virt{$Level}{$ClassName}{$Symbol} = 1; } } } if(defined $VirtualTable{1}{$ClassName}) { foreach my $Symbol (keys(%{$VirtualTable{1}{$ClassName}})) { if($TName_Tid{2}{$ClassName} and not defined $VirtualTable{2}{$ClassName}{$Symbol}) { # removed from v-table if(defined $CompleteSignature{2}{$Symbol} and $CompleteSignature{2}{$Symbol}{"Virt"}) { # override some method in v.2 next; } $RemovedInt_Virt{$Level}{$ClassName}{$Symbol} = 1; } } } if($Level eq "Binary") { # Binary-level my %Class_Type = get_Type($ClassId, 1); foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$ClassName}})) { # check replacements, including pure virtual methods my $AddedPos = $VirtualTable{2}{$ClassName}{$AddedVFunc}; foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$ClassName}})) { my $RemovedPos = $VirtualTable{1}{$ClassName}{$RemovedVFunc}; if($AddedPos==$RemovedPos) { $VirtualReplacement{$AddedVFunc} = $RemovedVFunc; $VirtualReplacement{$RemovedVFunc} = $AddedVFunc; last; # other methods will be reported as "added" or "removed" } } if(my $RemovedVFunc = $VirtualReplacement{$AddedVFunc}) { if(lc($AddedVFunc) eq lc($RemovedVFunc)) { # skip: DomUi => DomUI parameter (Qt 4.2.3 to 4.3.0) next; } my $ProblemType = "Virtual_Replacement"; my @Affected = ($RemovedVFunc); if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"}) { # pure methods if(not isUsedClass($ClassId, 1, $Level)) { # not a parameter of some exported method next; } $ProblemType = "Pure_Virtual_Replacement"; # affected all methods (both virtual and non-virtual ones) @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}})); push(@Affected, keys(%{$OverriddenMethods{1}{$RemovedVFunc}})); } $VTableChanged_M{$ClassName}=1; foreach my $AffectedInt (@Affected) { if($CompleteSignature{1}{$AffectedInt}{"PureVirt"}) { # affected exported methods only next; } if(not symbolFilter($AffectedInt, 1, "Affected", $Level)) { next; } %{$CompatProblems{$Level}{$AffectedInt}{$ProblemType}{$tr_name{$AddedVFunc}}}=( "Type_Name"=>$Class_Type{"Name"}, "Target"=>get_Signature($AddedVFunc, 2), "Old_Value"=>get_Signature($RemovedVFunc, 1)); } } } } } if(not checkDump(1, "2.0") or not checkDump(2, "2.0")) { # support for old ABI dumps # "Base" attribute introduced in ACC 1.22 (ABI dump 2.0 format) return; } foreach my $ClassName (sort keys(%{$ClassNames{1}})) { my $ClassId_Old = $TName_Tid{1}{$ClassName}; next if(not $ClassId_Old); if(not isCreatable($ClassId_Old, 1)) { # skip classes without public constructors (including auto-generated) # example: class has only a private exported or private inline constructor next; } if($ClassName=~/>/) { # skip affected template instances next; } my %Class_Old = get_Type($ClassId_Old, 1); my $ClassId_New = $TName_Tid{2}{$ClassName}; if(not $ClassId_New) { next; } my %Class_New = get_Type($ClassId_New, 2); if($Class_New{"Type"}!~/Class|Struct/) { # became typedef if($Level eq "Binary") { next; } if($Level eq "Source") { %Class_New = get_PureType($ClassId_New, $TypeInfo{2}); if($Class_New{"Type"}!~/Class|Struct/) { next; } $ClassId_New = $Class_New{"Tid"}; } } my @Bases_Old = sort {$Class_Old{"Base"}{$a}{"pos"}<=>$Class_Old{"Base"}{$b}{"pos"}} keys(%{$Class_Old{"Base"}}); my @Bases_New = sort {$Class_New{"Base"}{$a}{"pos"}<=>$Class_New{"Base"}{$b}{"pos"}} keys(%{$Class_New{"Base"}}); my %Tr_Old = map {$TypeInfo{1}{$_}{"Name"} => uncover_typedefs($TypeInfo{1}{$_}{"Name"}, 1)} @Bases_Old; my %Tr_New = map {$TypeInfo{2}{$_}{"Name"} => uncover_typedefs($TypeInfo{2}{$_}{"Name"}, 2)} @Bases_New; my ($BNum1, $BNum2) = (1, 1); my %BasePos_Old = map {$Tr_Old{$TypeInfo{1}{$_}{"Name"}} => $BNum1++} @Bases_Old; my %BasePos_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $BNum2++} @Bases_New; my %ShortBase_Old = map {get_ShortClass($_, 1) => 1} @Bases_Old; my %ShortBase_New = map {get_ShortClass($_, 2) => 1} @Bases_New; my $Shift_Old = getShift($ClassId_Old, 1); my $Shift_New = getShift($ClassId_New, 2); my %BaseId_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $_} @Bases_New; my ($Added, $Removed) = (0, 0); my @StableBases_Old = (); foreach my $BaseId (@Bases_Old) { my $BaseName = $TypeInfo{1}{$BaseId}{"Name"}; if($BasePos_New{$Tr_Old{$BaseName}}) { push(@StableBases_Old, $BaseId); } elsif(not $ShortBase_New{$Tr_Old{$BaseName}} and not $ShortBase_New{get_ShortClass($BaseId, 1)}) { # removed base # excluding namespace::SomeClass to SomeClass renaming my $ProblemKind = "Removed_Base_Class"; if($Level eq "Binary") { # Binary-level if($Shift_Old ne $Shift_New) { # affected fields if(havePubFields(\%Class_Old)) { $ProblemKind .= "_And_Shift"; } elsif($Class_Old{"Size"} ne $Class_New{"Size"}) { $ProblemKind .= "_And_Size"; } } if(keys(%{$VirtualTable_Model{1}{$BaseName}}) and cmpVTables($ClassName)==1) { # affected v-table $ProblemKind .= "_And_VTable"; $VTableChanged_M{$ClassName}=1; } } my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}}); foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1)) { if(my $SubName = $TypeInfo{1}{$SubId}{"Name"}) { push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}})); if($ProblemKind=~/VTable/) { $VTableChanged_M{$SubName}=1; } } } foreach my $Interface (@Affected) { if(not symbolFilter($Interface, 1, "Affected", $Level)) { next; } %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=( "Type_Name"=>$ClassName, "Target"=>$BaseName, "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE, "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE, "Shift"=>abs($Shift_New-$Shift_Old) ); } $Removed+=1; } } my @StableBases_New = (); foreach my $BaseId (@Bases_New) { my $BaseName = $TypeInfo{2}{$BaseId}{"Name"}; if($BasePos_Old{$Tr_New{$BaseName}}) { push(@StableBases_New, $BaseId); } elsif(not $ShortBase_Old{$Tr_New{$BaseName}} and not $ShortBase_Old{get_ShortClass($BaseId, 2)}) { # added base # excluding namespace::SomeClass to SomeClass renaming my $ProblemKind = "Added_Base_Class"; if($Level eq "Binary") { # Binary-level if($Shift_Old ne $Shift_New) { # affected fields if(havePubFields(\%Class_Old)) { $ProblemKind .= "_And_Shift"; } elsif($Class_Old{"Size"} ne $Class_New{"Size"}) { $ProblemKind .= "_And_Size"; } } if(keys(%{$VirtualTable_Model{2}{$BaseName}}) and cmpVTables($ClassName)==1) { # affected v-table $ProblemKind .= "_And_VTable"; $VTableChanged_M{$ClassName}=1; } } my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}}); foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1)) { if(my $SubName = $TypeInfo{1}{$SubId}{"Name"}) { push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}})); if($ProblemKind=~/VTable/) { $VTableChanged_M{$SubName}=1; } } } foreach my $Interface (@Affected) { if(not symbolFilter($Interface, 1, "Affected", $Level)) { next; } %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=( "Type_Name"=>$ClassName, "Target"=>$BaseName, "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE, "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE, "Shift"=>abs($Shift_New-$Shift_Old) ); } $Added+=1; } } if($Level eq "Binary") { # Binary-level ($BNum1, $BNum2) = (1, 1); my %BaseRelPos_Old = map {$Tr_Old{$TypeInfo{1}{$_}{"Name"}} => $BNum1++} @StableBases_Old; my %BaseRelPos_New = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $BNum2++} @StableBases_New; foreach my $BaseId (@Bases_Old) { my $BaseName = $TypeInfo{1}{$BaseId}{"Name"}; if(my $NewPos = $BaseRelPos_New{$Tr_Old{$BaseName}}) { my $BaseNewId = $BaseId_New{$Tr_Old{$BaseName}}; my $OldPos = $BaseRelPos_Old{$Tr_Old{$BaseName}}; if($NewPos!=$OldPos) { # changed position of the base class foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}})) { if(not symbolFilter($Interface, 1, "Affected", $Level)) { next; } %{$CompatProblems{$Level}{$Interface}{"Base_Class_Position"}{"this"}}=( "Type_Name"=>$ClassName, "Target"=>$BaseName, "Old_Value"=>$OldPos-1, "New_Value"=>$NewPos-1 ); } } if($Class_Old{"Base"}{$BaseId}{"virtual"} and not $Class_New{"Base"}{$BaseNewId}{"virtual"}) { # became non-virtual base foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}})) { if(not symbolFilter($Interface, 1, "Affected", $Level)) { next; } %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Non_Virtually_Inherited"}{"this->".$BaseName}}=( "Type_Name"=>$ClassName, "Target"=>$BaseName ); } } elsif(not $Class_Old{"Base"}{$BaseId}{"virtual"} and $Class_New{"Base"}{$BaseNewId}{"virtual"}) { # became virtual base foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}})) { if(not symbolFilter($Interface, 1, "Affected", $Level)) { next; } %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Virtually_Inherited"}{"this->".$BaseName}}=( "Type_Name"=>$ClassName, "Target"=>$BaseName ); } } } } # detect size changes in base classes if($Shift_Old!=$Shift_New) { # size of allocable class foreach my $BaseId (@StableBases_Old) { # search for changed base my %BaseType = get_Type($BaseId, 1); my $Size_Old = $TypeInfo{1}{$BaseId}{"Size"}; my $Size_New = $TypeInfo{2}{$BaseId_New{$Tr_Old{$BaseType{"Name"}}}}{"Size"}; if($Size_Old ne $Size_New and $Size_Old and $Size_New) { my $ProblemType = undef; if(isCopyingClass($BaseId, 1)) { $ProblemType = "Size_Of_Copying_Class"; } elsif($AllocableClass{1}{$BaseType{"Name"}}) { if($Size_New>$Size_Old) { # increased size $ProblemType = "Size_Of_Allocable_Class_Increased"; } else { # decreased size $ProblemType = "Size_Of_Allocable_Class_Decreased"; if(not havePubFields(\%Class_Old)) { # affected class has no public members next; } } } next if(not $ProblemType); foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}})) { # base class size changes affecting current class if(not symbolFilter($Interface, 1, "Affected", $Level)) { next; } %{$CompatProblems{$Level}{$Interface}{$ProblemType}{"this->".$BaseType{"Name"}}}=( "Type_Name"=>$BaseType{"Name"}, "Target"=>$BaseType{"Name"}, "Old_Size"=>$Size_Old*$BYTE_SIZE, "New_Size"=>$Size_New*$BYTE_SIZE ); } } } } if(defined $VirtualTable_Model{1}{$ClassName} and cmpVTables_Real($ClassName, 1)==1 and my @VFunctions = keys(%{$VirtualTable_Model{1}{$ClassName}})) { # compare virtual tables size in base classes my $VShift_Old = getVShift($ClassId_Old, 1); my $VShift_New = getVShift($ClassId_New, 2); if($VShift_Old ne $VShift_New) { # changes in the base class or changes in the list of base classes my @AllBases_Old = get_base_classes($ClassId_Old, 1, 1); my @AllBases_New = get_base_classes($ClassId_New, 2, 1); ($BNum1, $BNum2) = (1, 1); my %StableBase = map {$Tr_New{$TypeInfo{2}{$_}{"Name"}} => $_} @AllBases_New; foreach my $BaseId (@AllBases_Old) { my %BaseType = get_Type($BaseId, 1); if(not $StableBase{$Tr_Old{$BaseType{"Name"}}}) { # lost base next; } my $VSize_Old = getVTable_Size($BaseType{"Name"}, 1); my $VSize_New = getVTable_Size($BaseType{"Name"}, 2); if($VSize_Old!=$VSize_New) { foreach my $Symbol (@VFunctions) { # TODO: affected non-virtual methods? if(not defined $VirtualTable_Model{2}{$ClassName}{$Symbol}) { # Removed_Virtual_Method, will be registered in mergeVirtualTables() next; } if($VirtualTable_Model{2}{$ClassName}{$Symbol}-$VirtualTable_Model{1}{$ClassName}{$Symbol}==0) { # skip interfaces that have not changed the absolute virtual position next; } if(not symbolFilter($Symbol, 1, "Affected", $Level)) { next; } $VTableChanged_M{$BaseType{"Name"}} = 1; $VTableChanged_M{$ClassName} = 1; foreach my $VirtFunc (keys(%{$AddedInt_Virt{$Level}{$BaseType{"Name"}}})) { # the reason of the layout change: added virtual functions next if($VirtualReplacement{$VirtFunc}); my $ProblemType = "Added_Virtual_Method"; if($CompleteSignature{2}{$VirtFunc}{"PureVirt"}) { $ProblemType = "Added_Pure_Virtual_Method"; } %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 2)}}=( "Type_Name"=>$BaseType{"Name"}, "Target"=>get_Signature($VirtFunc, 2) ); } foreach my $VirtFunc (keys(%{$RemovedInt_Virt{$Level}{$BaseType{"Name"}}})) { # the reason of the layout change: removed virtual functions next if($VirtualReplacement{$VirtFunc}); my $ProblemType = "Removed_Virtual_Method"; if($CompleteSignature{1}{$VirtFunc}{"PureVirt"}) { $ProblemType = "Removed_Pure_Virtual_Method"; } %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{get_Signature($VirtFunc, 1)}}=( "Type_Name"=>$BaseType{"Name"}, "Target"=>get_Signature($VirtFunc, 1) ); } } } } } } } } } sub isCreatable($$) { my ($ClassId, $LibVersion) = @_; if($AllocableClass{$LibVersion}{$TypeInfo{$LibVersion}{$ClassId}{"Name"}} or isCopyingClass($ClassId, $LibVersion)) { return 1; } if(keys(%{$Class_SubClasses{$LibVersion}{$ClassId}})) { # Fix for incomplete data: if this class has # a base class then it should also has a constructor return 1; } if($ReturnedClass{$LibVersion}{$ClassId}) { # returned by some method of this class # or any other class return 1; } return 0; } sub isUsedClass($$$) { my ($ClassId, $LibVersion, $Level) = @_; if(keys(%{$ParamClass{$LibVersion}{$ClassId}})) { # parameter of some exported method return 1; } my $CName = $TypeInfo{$LibVersion}{$ClassId}{"Name"}; if(keys(%{$ClassMethods{$Level}{$LibVersion}{$CName}})) { # method from target class return 1; } return 0; } sub mergeVirtualTables($$) { # check for changes in the virtual table my ($Interface, $Level) = @_; # affected methods: # - virtual # - pure-virtual # - non-virtual if($CompleteSignature{1}{$Interface}{"Data"}) { # global data is not affected return; } my $Class_Id = $CompleteSignature{1}{$Interface}{"Class"}; if(not $Class_Id) { return; } my $CName = $TypeInfo{1}{$Class_Id}{"Name"}; if(cmpVTables_Real($CName, 1)==0) { # no changes return; } $CheckedTypes{$Level}{$CName} = 1; if($Level eq "Binary") { # Binary-level if($CompleteSignature{1}{$Interface}{"PureVirt"} and not isUsedClass($Class_Id, 1, $Level)) { # pure virtuals should not be affected # if there are no exported methods using this class return; } } foreach my $Func (keys(%{$VirtualTable{1}{$CName}})) { if(defined $VirtualTable{2}{$CName}{$Func} and defined $CompleteSignature{2}{$Func}) { if(not $CompleteSignature{1}{$Func}{"PureVirt"} and $CompleteSignature{2}{$Func}{"PureVirt"}) { # became pure virtual %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Pure"}{$tr_name{$Func}}}=( "Type_Name"=>$CName, "Target"=>get_Signature_M($Func, 1) ); $VTableChanged_M{$CName} = 1; } elsif($CompleteSignature{1}{$Func}{"PureVirt"} and not $CompleteSignature{2}{$Func}{"PureVirt"}) { # became non-pure virtual %{$CompatProblems{$Level}{$Interface}{"Virtual_Method_Became_Non_Pure"}{$tr_name{$Func}}}=( "Type_Name"=>$CName, "Target"=>get_Signature_M($Func, 1) ); $VTableChanged_M{$CName} = 1; } } } if($Level eq "Binary") { # Binary-level # check virtual table structure foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}})) { next if($Interface eq $AddedVFunc); next if($VirtualReplacement{$AddedVFunc}); my $VPos_Added = $VirtualTable{2}{$CName}{$AddedVFunc}; if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"}) { # pure virtual methods affect all others (virtual and non-virtual) %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=( "Type_Name"=>$CName, "Target"=>get_Signature($AddedVFunc, 2) ); $VTableChanged_M{$CName} = 1; } elsif(not defined $VirtualTable{1}{$CName} or $VPos_Added>keys(%{$VirtualTable{1}{$CName}})) { # added virtual function at the end of v-table if(not keys(%{$VirtualTable_Model{1}{$CName}})) { # became polymorphous class, added v-table pointer %{$CompatProblems{$Level}{$Interface}{"Added_First_Virtual_Method"}{$tr_name{$AddedVFunc}}}=( "Type_Name"=>$CName, "Target"=>get_Signature($AddedVFunc, 2) ); $VTableChanged_M{$CName} = 1; } else { my $VSize_Old = getVTable_Size($CName, 1); my $VSize_New = getVTable_Size($CName, 2); next if($VSize_Old==$VSize_New); # exception: register as removed and added virtual method if(isCopyingClass($Class_Id, 1)) { # class has no constructors and v-table will be copied by applications, this may affect all methods my $ProblemType = "Added_Virtual_Method"; if(isLeafClass($Class_Id, 1)) { $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Copying_Class"; } %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=( "Type_Name"=>$CName, "Target"=>get_Signature($AddedVFunc, 2) ); $VTableChanged_M{$CName} = 1; } else { my $ProblemType = "Added_Virtual_Method"; if(isLeafClass($Class_Id, 1)) { $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Allocable_Class"; } %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=( "Type_Name"=>$CName, "Target"=>get_Signature($AddedVFunc, 2) ); $VTableChanged_M{$CName} = 1; } } } elsif($CompleteSignature{1}{$Interface}{"Virt"} or $CompleteSignature{1}{$Interface}{"PureVirt"}) { if(defined $VirtualTable{1}{$CName} and defined $VirtualTable{2}{$CName}) { my $VPos_Old = $VirtualTable{1}{$CName}{$Interface}; my $VPos_New = $VirtualTable{2}{$CName}{$Interface}; if($VPos_Added<=$VPos_Old and $VPos_Old!=$VPos_New) { my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}})); foreach my $ASymbol (@Affected) { if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"}) { if(not symbolFilter($ASymbol, 1, "Affected", $Level)) { next; } } $CheckedSymbols{$Level}{$ASymbol} = 1; %{$CompatProblems{$Level}{$ASymbol}{"Added_Virtual_Method"}{$tr_name{$AddedVFunc}}}=( "Type_Name"=>$CName, "Target"=>get_Signature($AddedVFunc, 2) ); $VTableChanged_M{$TypeInfo{1}{$CompleteSignature{1}{$ASymbol}{"Class"}}{"Name"}} = 1; } } } } else { # safe } } foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}})) { next if($VirtualReplacement{$RemovedVFunc}); if($RemovedVFunc eq $Interface and $CompleteSignature{1}{$RemovedVFunc}{"PureVirt"}) { # This case is for removed virtual methods # implemented in both versions of a library next; } if(not keys(%{$VirtualTable_Model{2}{$CName}})) { # became non-polymorphous class, removed v-table pointer %{$CompatProblems{$Level}{$Interface}{"Removed_Last_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=( "Type_Name"=>$CName, "Target"=>get_Signature($RemovedVFunc, 1) ); $VTableChanged_M{$CName} = 1; } elsif($CompleteSignature{1}{$Interface}{"Virt"} or $CompleteSignature{1}{$Interface}{"PureVirt"}) { if(defined $VirtualTable{1}{$CName} and defined $VirtualTable{2}{$CName}) { if(not defined $VirtualTable{1}{$CName}{$Interface}) { next; } my $VPos_New = -1; if(defined $VirtualTable{2}{$CName}{$Interface}) { $VPos_New = $VirtualTable{2}{$CName}{$Interface}; } else { if($Interface ne $RemovedVFunc) { next; } } my $VPos_Removed = $VirtualTable{1}{$CName}{$RemovedVFunc}; my $VPos_Old = $VirtualTable{1}{$CName}{$Interface}; if($VPos_Removed<=$VPos_Old and $VPos_Old!=$VPos_New) { my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}})); foreach my $ASymbol (@Affected) { if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"}) { if(not symbolFilter($ASymbol, 1, "Affected", $Level)) { next; } } my $ProblemType = "Removed_Virtual_Method"; if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"}) { $ProblemType = "Removed_Pure_Virtual_Method"; } $CheckedSymbols{$Level}{$ASymbol} = 1; %{$CompatProblems{$Level}{$ASymbol}{$ProblemType}{$tr_name{$RemovedVFunc}}}=( "Type_Name"=>$CName, "Target"=>get_Signature($RemovedVFunc, 1) ); $VTableChanged_M{$TypeInfo{1}{$CompleteSignature{1}{$ASymbol}{"Class"}}{"Name"}} = 1; } } } } } } else { # Source-level foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}})) { next if($Interface eq $AddedVFunc); if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"}) { %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=( "Type_Name"=>$CName, "Target"=>get_Signature($AddedVFunc, 2) ); } } foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}})) { if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"}) { %{$CompatProblems{$Level}{$Interface}{"Removed_Pure_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=( "Type_Name"=>$CName, "Target"=>get_Signature($RemovedVFunc, 1) ); } } } } sub find_MemberPair_Pos_byName($$) { my ($Member_Name, $Pair_Type) = @_; $Member_Name=~s/\A[_]+|[_]+\Z//g; foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}})) { if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos}) { my $Name = $Pair_Type->{"Memb"}{$MemberPair_Pos}{"name"}; $Name=~s/\A[_]+|[_]+\Z//g; if($Name eq $Member_Name) { return $MemberPair_Pos; } } } return "lost"; } sub find_MemberPair_Pos_byVal($$) { my ($Member_Value, $Pair_Type) = @_; foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}})) { if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos} and $Pair_Type->{"Memb"}{$MemberPair_Pos}{"value"} eq $Member_Value) { return $MemberPair_Pos; } } return "lost"; } sub isRecurType($$$) { foreach (@{$_[2]}) { if( $_->{"T1"} eq $_[0] and $_->{"T2"} eq $_[1] ) { return 1; } } return 0; } sub pushType($$$) { my %IDs = ( "T1" => $_[0], "T2" => $_[1] ); push(@{$_[2]}, \%IDs); } sub isRenamed($$$$$) { my ($MemPos, $Type1, $LVersion1, $Type2, $LVersion2) = @_; my $Member_Name = $Type1->{"Memb"}{$MemPos}{"name"}; my $MemberType_Id = $Type1->{"Memb"}{$MemPos}{"type"}; my %MemberType_Pure = get_PureType($MemberType_Id, $TypeInfo{$LVersion1}); if(not defined $Type2->{"Memb"}{$MemPos}) { return ""; } my $PairType_Id = $Type2->{"Memb"}{$MemPos}{"type"}; my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{$LVersion2}); my $Pair_Name = $Type2->{"Memb"}{$MemPos}{"name"}; my $MemberPair_Pos_Rev = ($Member_Name eq $Pair_Name)?$MemPos:find_MemberPair_Pos_byName($Pair_Name, $Type1); if($MemberPair_Pos_Rev eq "lost") { if($MemberType_Pure{"Name"} eq $PairType_Pure{"Name"}) { # base type match return $Pair_Name; } if($TypeInfo{$LVersion1}{$MemberType_Id}{"Name"} eq $TypeInfo{$LVersion2}{$PairType_Id}{"Name"}) { # exact type match return $Pair_Name; } if($MemberType_Pure{"Size"} eq $PairType_Pure{"Size"}) { # size match return $Pair_Name; } if(isReserved($Pair_Name)) { # reserved fields return $Pair_Name; } } return ""; } sub isLastElem($$) { my ($Pos, $TypeRef) = @_; my $Name = $TypeRef->{"Memb"}{$Pos}{"name"}; if($Name=~/last|count|max|total/i) { # GST_LEVEL_COUNT, GST_RTSP_ELAST return 1; } elsif($Name=~/END|NLIMITS\Z/) { # __RLIMIT_NLIMITS return 1; } elsif($Name=~/\AN[A-Z](.+)[a-z]+s\Z/ and $Pos+1==keys(%{$TypeRef->{"Memb"}})) { # NImageFormats, NColorRoles return 1; } return 0; } sub nonComparable($$) { my ($T1, $T2) = @_; my $N1 = $T1->{"Name"}; my $N2 = $T2->{"Name"}; $N1=~s/\A(struct|union|enum) //; $N2=~s/\A(struct|union|enum) //; if($N1 ne $N2 and not isAnon($N1) and not isAnon($N2)) { # different names if($T1->{"Type"} ne "Pointer" or $T2->{"Type"} ne "Pointer") { # compare base types return 1; } if($N1!~/\Avoid\s*\*/ and $N2=~/\Avoid\s*\*/) { return 1; } } elsif($T1->{"Type"} ne $T2->{"Type"}) { # different types if($T1->{"Type"} eq "Class" and $T2->{"Type"} eq "Struct") { # "class" to "struct" return 0; } elsif($T2->{"Type"} eq "Class" and $T1->{"Type"} eq "Struct") { # "struct" to "class" return 0; } else { # "class" to "enum" # "union" to "class" # ... return 1; } } return 0; } sub isOpaque($) { my $T = $_[0]; if(not defined $T->{"Memb"}) { return 1; } return 0; } sub removeVPtr($) { # support for old ABI dumps my $TPtr = $_[0]; my @Pos = sort {int($a)<=>int($b)} keys(%{$TPtr->{"Memb"}}); if($#Pos>=1) { foreach my $Pos (0 .. $#Pos-1) { %{$TPtr->{"Memb"}{$Pos}} = %{$TPtr->{"Memb"}{$Pos+1}}; } delete($TPtr->{"Memb"}{$#Pos}); } } sub mergeTypes($$$) { my ($Type1_Id, $Type2_Id, $Level) = @_; return {} if(not $Type1_Id or not $Type2_Id); if($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}) { # already merged return $Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id}; } my %Type1 = get_Type($Type1_Id, 1); my %Type2 = get_Type($Type2_Id, 2); if(not $Type1{"Name"} or not $Type2{"Name"}) { return {}; } $CheckedTypes{$Level}{$Type1{"Name"}} = 1; my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1}); my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2}); $CheckedTypes{$Level}{$Type1_Pure{"Name"}} = 1; my %SubProblems = (); if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}) { if($Type1_Pure{"Type"}=~/Struct|Union/ and $Type2_Pure{"Type"}=~/Struct|Union/) { if(isOpaque(\%Type2_Pure) and not isOpaque(\%Type1_Pure)) { %{$SubProblems{"Type_Became_Opaque"}{$Type1_Pure{"Name"}}}=( "Target"=>$Type1_Pure{"Name"}, "Type_Name"=>$Type1_Pure{"Name"} ); return ($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id} = \%SubProblems); } } } if(not $Type1_Pure{"Size"} or not $Type2_Pure{"Size"}) { # including a case when "class Class { ... };" changed to "class Class;" if(not defined $Type1_Pure{"Memb"} or not defined $Type2_Pure{"Memb"} or index($Type1_Pure{"Name"}, "<")==-1 or index($Type2_Pure{"Name"}, "<")==-1) { # NOTE: template instances have no size return {}; } } if(isRecurType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"}, \@RecurTypes)) { # skip recursive declarations return {}; } return {} if(not $Type1_Pure{"Name"} or not $Type2_Pure{"Name"}); return {} if($SkipTypes{1}{$Type1_Pure{"Name"}}); return {} if($SkipTypes{1}{$Type1{"Name"}}); if($Type1_Pure{"Type"}=~/Class|Struct/ and $Type2_Pure{"Type"}=~/Class|Struct/) { # support for old ABI dumps # _vptr field added in 3.0 if(not checkDump(1, "3.0") and checkDump(2, "3.0")) { if(defined $Type2_Pure{"Memb"} and $Type2_Pure{"Memb"}{0}{"name"} eq "_vptr") { if(keys(%{$Type2_Pure{"Memb"}})==1) { delete($Type2_Pure{"Memb"}{0}); } else { removeVPtr(\%Type2_Pure); } } } if(checkDump(1, "3.0") and not checkDump(2, "3.0")) { if(defined $Type1_Pure{"Memb"} and $Type1_Pure{"Memb"}{0}{"name"} eq "_vptr") { if(keys(%{$Type1_Pure{"Memb"}})==1) { delete($Type1_Pure{"Memb"}{0}); } else { removeVPtr(\%Type1_Pure); } } } } my %Typedef_1 = goToFirst($Type1{"Tid"}, 1, "Typedef"); my %Typedef_2 = goToFirst($Type2{"Tid"}, 2, "Typedef"); if(not $UseOldDumps and %Typedef_1 and %Typedef_2 and $Typedef_1{"Type"} eq "Typedef" and $Typedef_2{"Type"} eq "Typedef" and $Typedef_1{"Name"} eq $Typedef_2{"Name"}) { my %Base_1 = get_OneStep_BaseType($Typedef_1{"Tid"}, $TypeInfo{1}); my %Base_2 = get_OneStep_BaseType($Typedef_2{"Tid"}, $TypeInfo{2}); if($Base_1{"Name"} ne $Base_2{"Name"}) { if(differentDumps("G") or differentDumps("V")) { # different GCC versions or different dumps $Base_1{"Name"} = uncover_typedefs($Base_1{"Name"}, 1); $Base_2{"Name"} = uncover_typedefs($Base_2{"Name"}, 2); # std::__va_list and __va_list $Base_1{"Name"}=~s/\A(\w+::)+//; $Base_2{"Name"}=~s/\A(\w+::)+//; $Base_1{"Name"} = formatName($Base_1{"Name"}, "T"); $Base_2{"Name"} = formatName($Base_2{"Name"}, "T"); } } if($Base_1{"Name"}!~/anon\-/ and $Base_2{"Name"}!~/anon\-/ and $Base_1{"Name"} ne $Base_2{"Name"}) { if($Level eq "Binary" and $Type1{"Size"} and $Type2{"Size"} and $Type1{"Size"} ne $Type2{"Size"}) { %{$SubProblems{"DataType_Size"}{$Typedef_1{"Name"}}}=( "Target"=>$Typedef_1{"Name"}, "Type_Name"=>$Typedef_1{"Name"}, "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE, "New_Size"=>$Type2{"Size"}*$BYTE_SIZE ); } my %Base1_Pure = get_PureType($Base_1{"Tid"}, $TypeInfo{1}); my %Base2_Pure = get_PureType($Base_2{"Tid"}, $TypeInfo{2}); if(tNameLock($Base_1{"Tid"}, $Base_2{"Tid"})) { if(diffTypes($Base1_Pure{"Tid"}, $Base2_Pure{"Tid"}, $Level)) { %{$SubProblems{"Typedef_BaseType_Format"}{$Typedef_1{"Name"}}}=( "Target"=>$Typedef_1{"Name"}, "Type_Name"=>$Typedef_1{"Name"}, "Old_Value"=>$Base_1{"Name"}, "New_Value"=>$Base_2{"Name"} ); } else { %{$SubProblems{"Typedef_BaseType"}{$Typedef_1{"Name"}}}=( "Target"=>$Typedef_1{"Name"}, "Type_Name"=>$Typedef_1{"Name"}, "Old_Value"=>$Base_1{"Name"}, "New_Value"=>$Base_2{"Name"} ); } } } } if(nonComparable(\%Type1_Pure, \%Type2_Pure)) { # different types (reported in detectTypeChange(...)) my $TT1 = $Type1_Pure{"Type"}; my $TT2 = $Type2_Pure{"Type"}; if($TT1 ne $TT2 and $TT1!~/Intrinsic|Pointer|Ref|Typedef/) { # different type of the type my $Short1 = $Type1_Pure{"Name"}; my $Short2 = $Type2_Pure{"Name"}; $Short1=~s/\A\Q$TT1\E //ig; $Short2=~s/\A\Q$TT2\E //ig; if($Short1 eq $Short2) { %{$SubProblems{"DataType_Type"}{$Type1_Pure{"Name"}}}=( "Target"=>$Type1_Pure{"Name"}, "Type_Name"=>$Type1_Pure{"Name"}, "Old_Value"=>lc($Type1_Pure{"Type"}), "New_Value"=>lc($Type2_Pure{"Type"}) ); } } return ($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id} = \%SubProblems); } pushType($Type1_Pure{"Tid"}, $Type2_Pure{"Tid"}, \@RecurTypes); if(($Type1_Pure{"Name"} eq $Type2_Pure{"Name"} or (isAnon($Type1_Pure{"Name"}) and isAnon($Type2_Pure{"Name"}))) and $Type1_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/) { # checking size if($Level eq "Binary" and $Type1_Pure{"Size"} and $Type2_Pure{"Size"} and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) { my $ProblemKind = "DataType_Size"; if($Type1_Pure{"Type"} eq "Class" and keys(%{$ClassMethods{$Level}{1}{$Type1_Pure{"Name"}}})) { if(isCopyingClass($Type1_Pure{"Tid"}, 1)) { $ProblemKind = "Size_Of_Copying_Class"; } elsif($AllocableClass{1}{$Type1_Pure{"Name"}}) { if(int($Type2_Pure{"Size"})>int($Type1_Pure{"Size"})) { $ProblemKind = "Size_Of_Allocable_Class_Increased"; } else { # descreased size of allocable class # it has no special effects } } } %{$SubProblems{$ProblemKind}{$Type1_Pure{"Name"}}}=( "Target"=>$Type1_Pure{"Name"}, "Type_Name"=>$Type1_Pure{"Name"}, "Old_Size"=>$Type1_Pure{"Size"}*$BYTE_SIZE, "New_Size"=>$Type2_Pure{"Size"}*$BYTE_SIZE); } } if(defined $Type1_Pure{"BaseType"} and defined $Type2_Pure{"BaseType"}) { # checking base types my $Sub_SubProblems = mergeTypes($Type1_Pure{"BaseType"}, $Type2_Pure{"BaseType"}, $Level); foreach my $Sub_SubProblemType (keys(%{$Sub_SubProblems})) { foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems->{$Sub_SubProblemType}})) { $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation} = $Sub_SubProblems->{$Sub_SubProblemType}{$Sub_SubLocation}; } } } my (%AddedField, %RemovedField, %RenamedField, %RenamedField_Rev, %RelatedField, %RelatedField_Rev) = (); my %NameToPosA = map {$Type1_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type1_Pure{"Memb"}}); my %NameToPosB = map {$Type2_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type2_Pure{"Memb"}}); foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}})) { # detect removed and renamed fields my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"}; next if(not $Member_Name); my $MemberPair_Pos = (defined $Type2_Pure{"Memb"}{$Member_Pos} and $Type2_Pure{"Memb"}{$Member_Pos}{"name"} eq $Member_Name)?$Member_Pos:find_MemberPair_Pos_byName($Member_Name, \%Type2_Pure); if($MemberPair_Pos eq "lost") { if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/) { if(isUnnamed($Member_Name)) { # support for old-version dumps # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format) if(not checkDump(2, "2.1")) { next; } } if(my $RenamedTo = isRenamed($Member_Pos, \%Type1_Pure, 1, \%Type2_Pure, 2)) { # renamed $RenamedField{$Member_Pos} = $RenamedTo; $RenamedField_Rev{$NameToPosB{$RenamedTo}} = $Member_Name; } else { # removed $RemovedField{$Member_Pos} = 1; } } elsif($Type1_Pure{"Type"} eq "Enum") { my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"}; next if($Member_Value1 eq ""); $MemberPair_Pos = find_MemberPair_Pos_byVal($Member_Value1, \%Type2_Pure); if($MemberPair_Pos ne "lost") { # renamed my $RenamedTo = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"name"}; my $MemberPair_Pos_Rev = find_MemberPair_Pos_byName($RenamedTo, \%Type1_Pure); if($MemberPair_Pos_Rev eq "lost") { $RenamedField{$Member_Pos} = $RenamedTo; $RenamedField_Rev{$NameToPosB{$RenamedTo}} = $Member_Name; } else { $RemovedField{$Member_Pos} = 1; } } else { # removed $RemovedField{$Member_Pos} = 1; } } } else { # related $RelatedField{$Member_Pos} = $MemberPair_Pos; $RelatedField_Rev{$MemberPair_Pos} = $Member_Pos; } } foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}})) { # detect added fields my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"}; next if(not $Member_Name); my $MemberPair_Pos = (defined $Type1_Pure{"Memb"}{$Member_Pos} and $Type1_Pure{"Memb"}{$Member_Pos}{"name"} eq $Member_Name)?$Member_Pos:find_MemberPair_Pos_byName($Member_Name, \%Type1_Pure); if($MemberPair_Pos eq "lost") { if(isUnnamed($Member_Name)) { # support for old-version dumps # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format) if(not checkDump(1, "2.1")) { next; } } if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union|Enum)\Z/) { if(not $RenamedField_Rev{$Member_Pos}) { # added $AddedField{$Member_Pos}=1; } } } } if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/) { # detect moved fields my (%RelPos, %RelPosName, %AbsPos) = (); my $Pos = 0; foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}})) { # relative positions in 1st version my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"}; next if(not $Member_Name); if(not $RemovedField{$Member_Pos}) { # old type without removed fields $RelPos{1}{$Member_Name} = $Pos; $RelPosName{1}{$Pos} = $Member_Name; $AbsPos{1}{$Pos++} = $Member_Pos; } } $Pos = 0; foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}})) { # relative positions in 2nd version my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"}; next if(not $Member_Name); if(not $AddedField{$Member_Pos}) { # new type without added fields $RelPos{2}{$Member_Name} = $Pos; $RelPosName{2}{$Pos} = $Member_Name; $AbsPos{2}{$Pos++} = $Member_Pos; } } foreach my $Member_Name (keys(%{$RelPos{1}})) { my $RPos1 = $RelPos{1}{$Member_Name}; my $AbsPos1 = $NameToPosA{$Member_Name}; my $Member_Name2 = $Member_Name; if(my $RenamedTo = $RenamedField{$AbsPos1}) { # renamed $Member_Name2 = $RenamedTo; } my $RPos2 = $RelPos{2}{$Member_Name2}; if($RPos2 ne "" and $RPos1 ne $RPos2) { # different relative positions my $AbsPos2 = $NameToPosB{$Member_Name2}; if($AbsPos1 ne $AbsPos2) { # different absolute positions my $ProblemType = "Moved_Field"; if(not isPublic(\%Type1_Pure, $AbsPos1)) { # may change layout and size of type if($Level eq "Source") { next; } $ProblemType = "Moved_Private_Field"; } if($Level eq "Binary" and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) { # affected size my $MemSize1 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$AbsPos1}{"type"}}{"Size"}; my $MovedAbsPos = $AbsPos{1}{$RPos2}; my $MemSize2 = $TypeInfo{1}{$Type1_Pure{"Memb"}{$MovedAbsPos}{"type"}}{"Size"}; if($MemSize1 ne $MemSize2) { $ProblemType .= "_And_Size"; } } if($ProblemType eq "Moved_Private_Field") { next; } %{$SubProblems{$ProblemType}{$Member_Name}}=( "Target"=>$Member_Name, "Type_Name"=>$Type1_Pure{"Name"}, "Old_Value"=>$RPos1, "New_Value"=>$RPos2 ); } } } } foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}})) { # check older fields, public and private my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"}; next if(not $Member_Name); next if($Member_Name eq "_vptr"); if(my $RenamedTo = $RenamedField{$Member_Pos}) { # renamed if(defined $Constants{2}{$Member_Name}) { if($Constants{2}{$Member_Name}{"Value"} eq $RenamedTo) { # define OLD NEW next; # Safe } } if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/) { if(isPublic(\%Type1_Pure, $Member_Pos)) { %{$SubProblems{"Renamed_Field"}{$Member_Name}}=( "Target"=>$Member_Name, "Type_Name"=>$Type1_Pure{"Name"}, "Old_Value"=>$Member_Name, "New_Value"=>$RenamedTo ); } elsif(isReserved($Member_Name)) { %{$SubProblems{"Used_Reserved_Field"}{$Member_Name}}=( "Target"=>$Member_Name, "Type_Name"=>$Type1_Pure{"Name"}, "Old_Value"=>$Member_Name, "New_Value"=>$RenamedTo ); } } elsif($Type1_Pure{"Type"} eq "Enum") { %{$SubProblems{"Enum_Member_Name"}{$Type1_Pure{"Memb"}{$Member_Pos}{"value"}}}=( "Target"=>$Type1_Pure{"Memb"}{$Member_Pos}{"value"}, "Type_Name"=>$Type1_Pure{"Name"}, "Old_Value"=>$Member_Name, "New_Value"=>$RenamedTo ); } } elsif($RemovedField{$Member_Pos}) { # removed if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/) { my $ProblemType = "Removed_Field"; if(not isPublic(\%Type1_Pure, $Member_Pos) or isUnnamed($Member_Name)) { if($Level eq "Source") { next; } $ProblemType = "Removed_Private_Field"; } if($Level eq "Binary" and not isMemPadded($Member_Pos, -1, \%Type1_Pure, \%RemovedField, $TypeInfo{1}, getArch(1), $WORD_SIZE{1})) { if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1)) { # affected fields if(getOffset($MNum-1, \%Type1_Pure, $TypeInfo{1}, getArch(1), $WORD_SIZE{1})!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, $TypeInfo{2}, getArch(2), $WORD_SIZE{2})) { # changed offset $ProblemType .= "_And_Layout"; } } if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) { # affected size $ProblemType .= "_And_Size"; } } if($ProblemType eq "Removed_Private_Field") { next; } %{$SubProblems{$ProblemType}{$Member_Name}}=( "Target"=>$Member_Name, "Type_Name"=>$Type1_Pure{"Name"} ); } elsif($Type2_Pure{"Type"} eq "Union") { if($Level eq "Binary" and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) { %{$SubProblems{"Removed_Union_Field_And_Size"}{$Member_Name}}=( "Target"=>$Member_Name, "Type_Name"=>$Type1_Pure{"Name"} ); } else { %{$SubProblems{"Removed_Union_Field"}{$Member_Name}}=( "Target"=>$Member_Name, "Type_Name"=>$Type1_Pure{"Name"} ); } } elsif($Type1_Pure{"Type"} eq "Enum") { %{$SubProblems{"Enum_Member_Removed"}{$Member_Name}}=( "Target"=>$Member_Name, "Type_Name"=>$Type1_Pure{"Name"}, "Old_Value"=>$Member_Name ); } } else { # changed my $MemberPair_Pos = $RelatedField{$Member_Pos}; if($Type1_Pure{"Type"} eq "Enum") { my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"}; next if($Member_Value1 eq ""); my $Member_Value2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"value"}; next if($Member_Value2 eq ""); if($Member_Value1 ne $Member_Value2) { my $ProblemType = "Enum_Member_Value"; if(isLastElem($Member_Pos, \%Type1_Pure)) { $ProblemType = "Enum_Last_Member_Value"; } if($SkipConstants{1}{$Member_Name}) { $ProblemType = "Enum_Private_Member_Value"; } %{$SubProblems{$ProblemType}{$Member_Name}}=( "Target"=>$Member_Name, "Type_Name"=>$Type1_Pure{"Name"}, "Old_Value"=>$Member_Value1, "New_Value"=>$Member_Value2 ); } } elsif($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/) { my $Access1 = $Type1_Pure{"Memb"}{$Member_Pos}{"access"}; my $Access2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"access"}; if($Access1 ne "private" and $Access2 eq "private") { %{$SubProblems{"Field_Became_Private"}{$Member_Name}}=( "Target"=>$Member_Name, "Type_Name"=>$Type1_Pure{"Name"}); } elsif($Access1 ne "protected" and $Access1 ne "private" and $Access2 eq "protected") { %{$SubProblems{"Field_Became_Protected"}{$Member_Name}}=( "Target"=>$Member_Name, "Type_Name"=>$Type1_Pure{"Name"}); } my $MemberType1_Id = $Type1_Pure{"Memb"}{$Member_Pos}{"type"}; my $MemberType2_Id = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"type"}; my $SizeV1 = $TypeInfo{1}{$MemberType1_Id}{"Size"}*$BYTE_SIZE; if(my $BSize1 = $Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}) { $SizeV1 = $BSize1; } my $SizeV2 = $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE; if(my $BSize2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}) { $SizeV2 = $BSize2; } my $MemberType1_Name = $TypeInfo{1}{$MemberType1_Id}{"Name"}; my $MemberType2_Name = $TypeInfo{2}{$MemberType2_Id}{"Name"}; if($Level eq "Binary" and $SizeV1 and $SizeV2 and $SizeV1 ne $SizeV2) { if($MemberType1_Name eq $MemberType2_Name or (isAnon($MemberType1_Name) and isAnon($MemberType2_Name)) or ($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"} and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"})) { # field size change (including anon-structures and unions) # - same types # - unnamed types # - bitfields my $ProblemType = "Field_Size"; if(not isPublic(\%Type1_Pure, $Member_Pos) or isUnnamed($Member_Name)) { # should not be accessed by applications, goes to "Low Severity" # example: "abidata" members in GStreamer types $ProblemType = "Private_".$ProblemType; } if(not isMemPadded($Member_Pos, $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE, \%Type1_Pure, \%RemovedField, $TypeInfo{1}, getArch(1), $WORD_SIZE{1})) { # check an effect if($Type2_Pure{"Type"} ne "Union" and my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1)) { # public fields after the current if(getOffset($MNum-1, \%Type1_Pure, $TypeInfo{1}, getArch(1), $WORD_SIZE{1})!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, $TypeInfo{2}, getArch(2), $WORD_SIZE{2})) { # changed offset $ProblemType .= "_And_Layout"; } } if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) { $ProblemType .= "_And_Type_Size"; } } if($ProblemType eq "Private_Field_Size") { # private field size with no effect } if($ProblemType eq "Field_Size") { if($Type1_Pure{"Type"}=~/Union|Struct/ and $SizeV1<$SizeV2) { # Low severity $ProblemType = "Struct_Field_Size_Increased"; } } if($ProblemType) { # register a problem %{$SubProblems{$ProblemType}{$Member_Name}}=( "Target"=>$Member_Name, "Type_Name"=>$Type1_Pure{"Name"}, "Old_Size"=>$SizeV1, "New_Size"=>$SizeV2); } } } if($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"} or $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}) { # do NOT check bitfield type changes next; } if(checkDump(1, "2.13") and checkDump(2, "2.13")) { if(not $Type1_Pure{"Memb"}{$Member_Pos}{"mutable"} and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"mutable"}) { %{$SubProblems{"Field_Became_Mutable"}{$Member_Name}}=( "Target"=>$Member_Name, "Type_Name"=>$Type1_Pure{"Name"}); } elsif($Type1_Pure{"Memb"}{$Member_Pos}{"mutable"} and not $Type2_Pure{"Memb"}{$MemberPair_Pos}{"mutable"}) { %{$SubProblems{"Field_Became_Non_Mutable"}{$Member_Name}}=( "Target"=>$Member_Name, "Type_Name"=>$Type1_Pure{"Name"}); } } my %Sub_SubChanges = detectTypeChange($MemberType1_Id, $MemberType2_Id, "Field", $Level); foreach my $ProblemType (keys(%Sub_SubChanges)) { my $Old_Value = $Sub_SubChanges{$ProblemType}{"Old_Value"}; my $New_Value = $Sub_SubChanges{$ProblemType}{"New_Value"}; # quals if($ProblemType eq "Field_Type" or $ProblemType eq "Field_Type_And_Size" or $ProblemType eq "Field_Type_Format") { if(checkDump(1, "2.6") and checkDump(2, "2.6")) { if(addedQual($Old_Value, $New_Value, "volatile")) { %{$Sub_SubChanges{"Field_Became_Volatile"}} = %{$Sub_SubChanges{$ProblemType}}; } elsif(removedQual($Old_Value, $New_Value, "volatile")) { %{$Sub_SubChanges{"Field_Became_Non_Volatile"}} = %{$Sub_SubChanges{$ProblemType}}; } } if(my $RA = addedQual($Old_Value, $New_Value, "const")) { if($RA==2) { %{$Sub_SubChanges{"Field_Added_Const"}} = %{$Sub_SubChanges{$ProblemType}}; } else { %{$Sub_SubChanges{"Field_Became_Const"}} = %{$Sub_SubChanges{$ProblemType}}; } } elsif(my $RR = removedQual($Old_Value, $New_Value, "const")) { if($RR==2) { %{$Sub_SubChanges{"Field_Removed_Const"}} = %{$Sub_SubChanges{$ProblemType}}; } else { %{$Sub_SubChanges{"Field_Became_Non_Const"}} = %{$Sub_SubChanges{$ProblemType}}; } } } } if($Level eq "Source") { foreach my $ProblemType (keys(%Sub_SubChanges)) { my $Old_Value = $Sub_SubChanges{$ProblemType}{"Old_Value"}; my $New_Value = $Sub_SubChanges{$ProblemType}{"New_Value"}; if($ProblemType eq "Field_Type") { if(cmpBTypes($Old_Value, $New_Value, 1, 2)) { delete($Sub_SubChanges{$ProblemType}); } } } } foreach my $ProblemType (keys(%Sub_SubChanges)) { my $ProblemType_Init = $ProblemType; if($ProblemType eq "Field_Type_And_Size") { # Binary if(not isPublic(\%Type1_Pure, $Member_Pos) or isUnnamed($Member_Name)) { $ProblemType = "Private_".$ProblemType; } if(not isMemPadded($Member_Pos, $TypeInfo{2}{$MemberType2_Id}{"Size"}*$BYTE_SIZE, \%Type1_Pure, \%RemovedField, $TypeInfo{1}, getArch(1), $WORD_SIZE{1})) { # check an effect if($Type2_Pure{"Type"} ne "Union" and my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1)) { # public fields after the current if(getOffset($MNum-1, \%Type1_Pure, $TypeInfo{1}, getArch(1), $WORD_SIZE{1})!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, $TypeInfo{2}, getArch(2), $WORD_SIZE{2})) { # changed offset $ProblemType .= "_And_Layout"; } } if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) { $ProblemType .= "_And_Type_Size"; } } } else { # TODO: Private_Field_Type rule? if(not isPublic(\%Type1_Pure, $Member_Pos) or isUnnamed($Member_Name)) { next; } } if($ProblemType eq "Private_Field_Type_And_Size") { # private field change with no effect } %{$SubProblems{$ProblemType}{$Member_Name}}=( "Target"=>$Member_Name, "Type_Name"=>$Type1_Pure{"Name"}); foreach my $Attr (keys(%{$Sub_SubChanges{$ProblemType_Init}})) { # other properties $SubProblems{$ProblemType}{$Member_Name}{$Attr} = $Sub_SubChanges{$ProblemType_Init}{$Attr}; } } if(not isPublic(\%Type1_Pure, $Member_Pos)) { # do NOT check internal type changes next; } if($MemberType1_Id and $MemberType2_Id) { # checking member type changes my $Sub_SubProblems = mergeTypes($MemberType1_Id, $MemberType2_Id, $Level); my %DupProblems = (); foreach my $Sub_SubProblemType (keys(%{$Sub_SubProblems})) { foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems->{$Sub_SubProblemType}})) { if(not defined $AllAffected) { if(defined $DupProblems{$Sub_SubProblems->{$Sub_SubProblemType}{$Sub_SubLocation}}) { next; } } my $NewLocation = ($Sub_SubLocation)?$Member_Name."->".$Sub_SubLocation:$Member_Name; $SubProblems{$Sub_SubProblemType}{$NewLocation} = $Sub_SubProblems->{$Sub_SubProblemType}{$Sub_SubLocation}; if(not defined $AllAffected) { $DupProblems{$Sub_SubProblems->{$Sub_SubProblemType}{$Sub_SubLocation}} = 1; } } } %DupProblems = (); } } } } foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}})) { # checking added members, public and private my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"}; next if(not $Member_Name); next if($Member_Name eq "_vptr"); if($AddedField{$Member_Pos}) { # added if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/) { my $ProblemType = "Added_Field"; if(not isPublic(\%Type2_Pure, $Member_Pos) or isUnnamed($Member_Name)) { if($Level eq "Source") { next; } $ProblemType = "Added_Private_Field"; } if($Level eq "Binary" and not isMemPadded($Member_Pos, -1, \%Type2_Pure, \%AddedField, $TypeInfo{2}, getArch(2), $WORD_SIZE{2})) { if(my $MNum = isAccessible(\%Type2_Pure, \%AddedField, $Member_Pos, -1)) { # public fields after the current if(getOffset($MNum-1, \%Type2_Pure, $TypeInfo{2}, getArch(2), $WORD_SIZE{2})!=getOffset($RelatedField_Rev{$MNum-1}, \%Type1_Pure, $TypeInfo{1}, getArch(1), $WORD_SIZE{1})) { # changed offset $ProblemType .= "_And_Layout"; } } if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) { $ProblemType .= "_And_Size"; } } if($ProblemType eq "Added_Private_Field") { # skip added private fields next; } %{$SubProblems{$ProblemType}{$Member_Name}}=( "Target"=>$Member_Name, "Type_Name"=>$Type1_Pure{"Name"}); } elsif($Type2_Pure{"Type"} eq "Union") { if($Level eq "Binary" and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) { %{$SubProblems{"Added_Union_Field_And_Size"}{$Member_Name}}=( "Target"=>$Member_Name, "Type_Name"=>$Type1_Pure{"Name"}); } else { %{$SubProblems{"Added_Union_Field"}{$Member_Name}}=( "Target"=>$Member_Name, "Type_Name"=>$Type1_Pure{"Name"}); } } elsif($Type2_Pure{"Type"} eq "Enum") { my $Member_Value = $Type2_Pure{"Memb"}{$Member_Pos}{"value"}; next if($Member_Value eq ""); %{$SubProblems{"Added_Enum_Member"}{$Member_Name}}=( "Target"=>$Member_Name, "Type_Name"=>$Type2_Pure{"Name"}, "New_Value"=>$Member_Value); } } } pop(@RecurTypes); return ($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type2_Id} = \%SubProblems); } sub isUnnamed($) { return $_[0]=~/\Aunnamed\d+\Z/; } sub get_ShortClass($$) { my ($TypeId, $LibVersion) = @_; my $TypeName = $TypeInfo{$LibVersion}{$TypeId}{"Name"}; if($TypeInfo{$LibVersion}{$TypeId}{"Type"}!~/Intrinsic|Class|Struct|Union|Enum/) { $TypeName = uncover_typedefs($TypeName, $LibVersion); } if(my $NameSpace = $TypeInfo{$LibVersion}{$TypeId}{"NameSpace"}) { $TypeName=~s/\A(struct |)\Q$NameSpace\E\:\://g; } return $TypeName; } sub goToFirst($$$) { my ($TypeId, $LibVersion, $Type_Type) = @_; return () if(not $TypeId); if(defined $Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type}) { return %{$Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type}}; } return () if(not $TypeInfo{$LibVersion}{$TypeId}); my %Type = %{$TypeInfo{$LibVersion}{$TypeId}}; return () if(not $Type{"Type"}); if($Type{"Type"} ne $Type_Type) { return () if(not $Type{"BaseType"}); %Type = goToFirst($Type{"BaseType"}, $LibVersion, $Type_Type); } $Cache{"goToFirst"}{$TypeId}{$LibVersion}{$Type_Type} = \%Type; return %Type; } my %TypeSpecAttributes = ( "Const" => 1, "Volatile" => 1, "ConstVolatile" => 1, "Restrict" => 1, "Typedef" => 1 ); sub get_PureType($$) { my ($TypeId, $Info) = @_; if(not $TypeId or not $Info or not $Info->{$TypeId}) { return (); } if(defined $Cache{"get_PureType"}{$TypeId}{$Info}) { return %{$Cache{"get_PureType"}{$TypeId}{$Info}}; } my %Type = %{$Info->{$TypeId}}; return %Type if(not $Type{"BaseType"}); if($TypeSpecAttributes{$Type{"Type"}}) { %Type = get_PureType($Type{"BaseType"}, $Info); } $Cache{"get_PureType"}{$TypeId}{$Info} = \%Type; return %Type; } sub get_PLevel($$) { my ($TypeId, $LibVersion) = @_; return 0 if(not $TypeId); if(defined $Cache{"get_PLevel"}{$TypeId}{$LibVersion}) { return $Cache{"get_PLevel"}{$TypeId}{$LibVersion}; } return 0 if(not $TypeInfo{$LibVersion}{$TypeId}); my %Type = %{$TypeInfo{$LibVersion}{$TypeId}}; return 1 if($Type{"Type"}=~/FuncPtr|FieldPtr/); my $PLevel = 0; if($Type{"Type"} =~/Pointer|Ref|FuncPtr|FieldPtr/) { $PLevel += 1; } return $PLevel if(not $Type{"BaseType"}); $PLevel += get_PLevel($Type{"BaseType"}, $LibVersion); $Cache{"get_PLevel"}{$TypeId}{$LibVersion} = $PLevel; return $PLevel; } sub get_BaseType($$) { my ($TypeId, $LibVersion) = @_; return () if(not $TypeId); if(defined $Cache{"get_BaseType"}{$TypeId}{$LibVersion}) { return %{$Cache{"get_BaseType"}{$TypeId}{$LibVersion}}; } return () if(not $TypeInfo{$LibVersion}{$TypeId}); my %Type = %{$TypeInfo{$LibVersion}{$TypeId}}; return %Type if(not $Type{"BaseType"}); %Type = get_BaseType($Type{"BaseType"}, $LibVersion); $Cache{"get_BaseType"}{$TypeId}{$LibVersion} = \%Type; return %Type; } sub get_BaseTypeQual($$) { my ($TypeId, $LibVersion) = @_; return "" if(not $TypeId); return "" if(not $TypeInfo{$LibVersion}{$TypeId}); my %Type = %{$TypeInfo{$LibVersion}{$TypeId}}; return "" if(not $Type{"BaseType"}); my $Qual = ""; if($Type{"Type"} eq "Pointer") { $Qual .= "*"; } elsif($Type{"Type"} eq "Ref") { $Qual .= "&"; } elsif($Type{"Type"} eq "ConstVolatile") { $Qual .= "const volatile"; } elsif($Type{"Type"} eq "Const" or $Type{"Type"} eq "Volatile" or $Type{"Type"} eq "Restrict") { $Qual .= lc($Type{"Type"}); } my $BQual = get_BaseTypeQual($Type{"BaseType"}, $LibVersion); return $BQual.$Qual; } sub get_OneStep_BaseType($$) { my ($TypeId, $Info) = @_; if(not $TypeId or not $Info or not $Info->{$TypeId}) { return (); } my %Type = %{$Info->{$TypeId}}; return %Type if(not $Type{"BaseType"}); if(my $BTid = $Type{"BaseType"}) { if($Info->{$BTid}) { return %{$Info->{$BTid}}; } else { # something is going wrong return (); } } else { return %Type; } } sub get_Type($$) { my ($TypeId, $LibVersion) = @_; return () if(not $TypeId); return () if(not $TypeInfo{$LibVersion}{$TypeId}); return %{$TypeInfo{$LibVersion}{$TypeId}}; } sub isPrivateData($) { # non-public global data my $Symbol = $_[0]; return ($Symbol=~/\A(_ZGV|_ZTI|_ZTS|_ZTT|_ZTV|_ZTC|_ZThn|_ZTv0_n)/); } sub isInLineInst($$$) { return (isTemplateInstance(@_) and not isTemplateSpec(@_)); } sub isTemplateInstance($$$) { my ($Symbol, $SInfo, $LibVersion) = @_; if($CheckObjectsOnly) { if($Symbol!~/\A(_Z|\?)/) { return 0; } if(my $Signature = $tr_name{$Symbol}) { if(index($Signature,">")==-1) { return 0; } if(my $ShortName = substr($Signature, 0, find_center($Signature, "("))) { if(index($ShortName,"<")!=-1 and index($ShortName,">")!=-1) { return 1; } } } } else { if(my $ClassId = $SInfo->{"Class"}) { if(my $ClassName = $TypeInfo{$LibVersion}{$ClassId}{"Name"}) { if(index($ClassName,"<")!=-1) { return 1; } } } if(my $ShortName = $SInfo->{"ShortName"}) { if(index($ShortName,"<")!=-1 and index($ShortName,">")!=-1) { return 1; } } } return 0; } sub isTemplateSpec($$$) { my ($Symbol, $SInfo, $LibVersion) = @_; if(my $ClassId = $SInfo->{"Class"}) { if($TypeInfo{$LibVersion}{$ClassId}{"Spec"}) { # class specialization return 1; } elsif($SInfo->{"Spec"}) { # method specialization return 1; } } return 0; } sub symbolFilter($$$$) { # some special cases when the symbol cannot be imported my ($Symbol, $LibVersion, $Type, $Level) = @_; if(isPrivateData($Symbol)) { # non-public global data return 0; } if(defined $SkipInternal) { return 0 if($Symbol=~/($SkipInternal)/); } if($CheckObjectsOnly) { return 0 if($Symbol=~/\A(_init|_fini)\Z/); } if($CheckHeadersOnly and not checkDump($LibVersion, "2.7")) { # support for old ABI dumps in --headers-only mode foreach my $Pos (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}})) { if(my $Pid = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"}) { my $PType = $TypeInfo{$LibVersion}{$Pid}{"Type"}; if(not $PType or $PType eq "Unknown") { return 0; } } } } if($Type=~/Affected/) { my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"}; if($SkipSymbols{$LibVersion}{$Symbol}) { # user defined symbols to ignore return 0; } my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"}; if(not $NameSpace and $ClassId) { # class methods have no "NameSpace" attribute $NameSpace = $TypeInfo{$LibVersion}{$ClassId}{"NameSpace"}; } if($NameSpace) { # user defined namespaces to ignore if($SkipNameSpaces{$LibVersion}{$NameSpace}) { return 0; } foreach my $NS (keys(%{$SkipNameSpaces{$LibVersion}})) { # nested namespaces if($NameSpace=~/\A\Q$NS\E(\:\:|\Z)/) { return 0; } } } if(my $Header = $CompleteSignature{$LibVersion}{$Symbol}{"Header"}) { if(my $Skip = skipHeader($Header, $LibVersion)) { # --skip-headers or (not ) if($Skip==1) { return 0; } } } if($SymbolsListPath and not $SymbolsList{$Symbol}) { # user defined symbols return 0; } if($SkipSymbolsListPath and $SkipSymbolsList{$Symbol}) { # user defined symbols return 0; } if($AppPath and not $SymbolsList_App{$Symbol}) { # user defined symbols (in application) return 0; } if(not selectSymbol($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $Level, $LibVersion)) { # non-target symbols return 0; } if($Level eq "Binary") { if($CheckObjectsOnly) { if(isTemplateInstance($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $LibVersion)) { return 0; } } else { if($CompleteSignature{$LibVersion}{$Symbol}{"InLine"} or isInLineInst($Symbol, $CompleteSignature{$LibVersion}{$Symbol}, $LibVersion)) { if($ClassId and $CompleteSignature{$LibVersion}{$Symbol}{"Virt"}) { # inline virtual methods if($Type=~/InlineVirt/) { return 1; } my $Allocable = (not isCopyingClass($ClassId, $LibVersion)); if(not $Allocable) { # check bases foreach my $DCId (get_sub_classes($ClassId, $LibVersion, 1)) { if(not isCopyingClass($DCId, $LibVersion)) { # exists a derived class without default c-tor $Allocable=1; last; } } } if(not $Allocable) { return 0; } } else { # inline non-virtual methods return 0; } } } } } return 1; } sub mergeImpl() { my $DiffCmd = get_CmdPath("diff"); if(not $DiffCmd) { exitStatus("Not_Found", "can't find \"diff\""); } foreach my $Interface (sort keys(%{$Symbol_Library{1}})) { # implementation changes next if($CompleteSignature{1}{$Interface}{"Private"}); next if(not $CompleteSignature{1}{$Interface}{"Header"} and not $CheckObjectsOnly); next if(not $Symbol_Library{2}{$Interface} and not $Symbol_Library{2}{$SymVer{2}{$Interface}}); if(not symbolFilter($Interface, 1, "Affected", "Binary")) { next; } my $Impl1 = canonifyImpl($Interface_Impl{1}{$Interface}); next if(not $Impl1); my $Impl2 = canonifyImpl($Interface_Impl{2}{$Interface}); next if(not $Impl2); if($Impl1 ne $Impl2) { writeFile("$TMP_DIR/impl1", $Impl1); writeFile("$TMP_DIR/impl2", $Impl2); my $Diff = `$DiffCmd -rNau \"$TMP_DIR/impl1\" \"$TMP_DIR/impl2\"`; $Diff=~s/(---|\+\+\+).+\n//g; $Diff=~s/[ ]{3,}/ /g; $Diff=~s/\n\@\@/\n \n\@\@/g; unlink("$TMP_DIR/impl1"); unlink("$TMP_DIR/impl2"); %{$CompatProblems_Impl{$Interface}}=( "Diff" => get_CodeView($Diff) ); } } # clean memory %Interface_Impl = (); } sub canonifyImpl($) { my $FuncBody= $_[0]; return "" if(not $FuncBody); $FuncBody=~s/0x[a-f\d]+/0x?/g;# addr $FuncBody=~s/((\A|\n)[a-z]+[\t ]+)[a-f\d]+([^x]|\Z)/$1?$3/g;# call, jump $FuncBody=~s/# [a-f\d]+ /# ? /g;# call, jump $FuncBody=~s/%([a-z]+[a-f\d]*)/\%reg/g;# registers while($FuncBody=~s/\nnop[ \t]*(\n|\Z)/$1/g){};# empty op $FuncBody=~s/<.+?\.cpp.+?>//g; $FuncBody=~s/(\A|\n)[a-f\d]+ ".htmlSpecChars($Line)."\n"; } else { $View .= "".htmlSpecChars($Line)."\n"; } } return "$View
\n"; } sub getImplementations($$) { my ($LibVersion, $Path) = @_; return if(not $LibVersion or not -e $Path); if($OSgroup eq "macos") { my $OtoolCmd = get_CmdPath("otool"); if(not $OtoolCmd) { exitStatus("Not_Found", "can't find \"otool\""); } my $CurInterface = ""; foreach my $Line (split(/\n/, `$OtoolCmd -tv \"$Path\" 2>\"$TMP_DIR/null\"`)) { if($Line=~/\A\s*_(\w+)\s*:/i) { $CurInterface = $1; } elsif($Line=~/\A\s*[\da-z]+\s+(.+?)\Z/i) { $Interface_Impl{$LibVersion}{$CurInterface} .= $1."\n"; } } } else { my $ObjdumpCmd = get_CmdPath("objdump"); if(not $ObjdumpCmd) { exitStatus("Not_Found", "can't find \"objdump\""); } my $CurInterface = ""; foreach my $Line (split(/\n/, `$ObjdumpCmd -d \"$Path\" 2>\"$TMP_DIR/null\"`)) { if($Line=~/\A[\da-z]+\s+<(\w+)>/i) { $CurInterface = $1; } else { # x86: 51fa:(\t)89 e5 (\t)mov %esp,%ebp # arm: 5020:(\t)e24cb004(\t)sub(\t)fp, ip, #4(\t); 0x4 if($Line=~/\A\s*[a-f\d]+:\s+([a-f\d]+\s+)+([a-z]+\s+.*?)\s*(;.*|)\Z/i) { $Interface_Impl{$LibVersion}{$CurInterface} .= $2."\n"; } } } } } sub detectAdded($) { my $Level = $_[0]; foreach my $Symbol (keys(%{$Symbol_Library{2}})) { if(link_symbol($Symbol, 1, "+Deps")) { # linker can find a new symbol # in the old-version library # So, it's not a new symbol next; } if(my $VSym = $SymVer{2}{$Symbol} and index($Symbol,"\@")==-1) { next; } $AddedInt{$Level}{$Symbol} = 1; } } sub detectRemoved($) { my $Level = $_[0]; foreach my $Symbol (keys(%{$Symbol_Library{1}})) { if($CheckObjectsOnly) { $CheckedSymbols{"Binary"}{$Symbol} = 1; } if(link_symbol($Symbol, 2, "+Deps")) { # linker can find an old symbol # in the new-version library next; } if(my $VSym = $SymVer{1}{$Symbol} and index($Symbol,"\@")==-1) { next; } $RemovedInt{$Level}{$Symbol} = 1; } } sub mergeLibs($) { my $Level = $_[0]; foreach my $Symbol (sort keys(%{$AddedInt{$Level}})) { # checking added symbols next if($CompleteSignature{2}{$Symbol}{"Private"}); next if(not $CompleteSignature{2}{$Symbol}{"Header"} and not $CheckObjectsOnly); next if(not symbolFilter($Symbol, 2, "Affected + InlineVirt", $Level)); %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=(); } foreach my $Symbol (sort keys(%{$RemovedInt{$Level}})) { # checking removed symbols next if($CompleteSignature{1}{$Symbol}{"Private"}); next if(not $CompleteSignature{1}{$Symbol}{"Header"} and not $CheckObjectsOnly); if(index($Symbol, "_ZTV")==0) { # skip v-tables for templates, that should not be imported by applications next if($tr_name{$Symbol}=~/=0)); } sub detectAdded_H($) { my $Level = $_[0]; foreach my $Symbol (sort keys(%{$CompleteSignature{2}})) { if($Level eq "Source") { # remove symbol version my ($SN, $SS, $SV) = separate_symbol($Symbol); $Symbol=$SN; if($CompleteSignature{2}{$Symbol}{"Artificial"}) { # skip artificial constructors next; } } if(not $CompleteSignature{2}{$Symbol}{"Header"} or not $CompleteSignature{2}{$Symbol}{"MnglName"}) { next; } if($ExtendedSymbols{$Symbol}) { next; } if(not defined $CompleteSignature{1}{$Symbol} or not $CompleteSignature{1}{$Symbol}{"MnglName"}) { if($UsedDump{2}{"SrcBin"}) { if($UsedDump{1}{"BinOnly"} or not checkDump(1, "2.11")) { # support for old and different (!) ABI dumps if(not $CompleteSignature{2}{$Symbol}{"Virt"} and not $CompleteSignature{2}{$Symbol}{"PureVirt"}) { if($CheckHeadersOnly) { if(my $Lang = $CompleteSignature{2}{$Symbol}{"Lang"}) { if($Lang eq "C") { # support for old ABI dumps: missed extern "C" functions next; } } } else { if(not link_symbol($Symbol, 2, "-Deps")) { # skip added inline symbols and const global data next; } } } } } $AddedInt{$Level}{$Symbol} = 1; } } } sub detectRemoved_H($) { my $Level = $_[0]; foreach my $Symbol (sort keys(%{$CompleteSignature{1}})) { if($Level eq "Source") { # remove symbol version my ($SN, $SS, $SV) = separate_symbol($Symbol); $Symbol=$SN; } if(not $CompleteSignature{1}{$Symbol}{"Header"} or not $CompleteSignature{1}{$Symbol}{"MnglName"}) { next; } if($ExtendedSymbols{$Symbol}) { next; } if(not defined $CompleteSignature{2}{$Symbol} or not $CompleteSignature{2}{$Symbol}{"MnglName"}) { if($UsedDump{1}{"SrcBin"}) { if($UsedDump{2}{"BinOnly"} or not checkDump(2, "2.11")) { # support for old and different (!) ABI dumps if(not $CompleteSignature{1}{$Symbol}{"Virt"} and not $CompleteSignature{1}{$Symbol}{"PureVirt"}) { if($CheckHeadersOnly) { # skip all removed symbols if(my $Lang = $CompleteSignature{1}{$Symbol}{"Lang"}) { if($Lang eq "C") { # support for old ABI dumps: missed extern "C" functions next; } } } else { if(not link_symbol($Symbol, 1, "-Deps")) { # skip removed inline symbols next; } } } } } if(not checkDump(1, "2.15")) { if($Symbol=~/_IT_E\Z/) { # _ZN28QExplicitlySharedDataPointerI22QSslCertificatePrivateEC1IT_EERKS_IT_E next; } } if(not $CompleteSignature{1}{$Symbol}{"Class"}) { if(my $Short = $CompleteSignature{1}{$Symbol}{"ShortName"}) { if(defined $Constants{2}{$Short}) { my $Val = $Constants{2}{$Short}{"Value"}; if(defined $Func_ShortName{2}{$Val}) { # old name defined to new next; } } } } $RemovedInt{$Level}{$Symbol} = 1; if($Level eq "Source") { # search for a source-compatible equivalent setAlternative($Symbol, $Level); } } } } sub mergeHeaders($) { my $Level = $_[0]; foreach my $Symbol (sort keys(%{$AddedInt{$Level}})) { # checking added symbols next if($CompleteSignature{2}{$Symbol}{"PureVirt"}); next if($CompleteSignature{2}{$Symbol}{"Private"}); next if(not symbolFilter($Symbol, 2, "Affected", $Level)); if($Level eq "Binary") { if($CompleteSignature{2}{$Symbol}{"InLine"}) { if(not $CompleteSignature{2}{$Symbol}{"Virt"}) { # skip inline non-virtual functions next; } } } else { # Source if($SourceAlternative_B{$Symbol}) { next; } } %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=(); } foreach my $Symbol (sort keys(%{$RemovedInt{$Level}})) { # checking removed symbols next if($CompleteSignature{1}{$Symbol}{"PureVirt"}); next if($CompleteSignature{1}{$Symbol}{"Private"}); next if(not symbolFilter($Symbol, 1, "Affected", $Level)); if($Level eq "Binary") { if($CompleteSignature{1}{$Symbol}{"InLine"}) { if(not $CompleteSignature{1}{$Symbol}{"Virt"}) { # skip inline non-virtual functions next; } } } else { # Source if(my $Alt = $SourceAlternative{$Symbol}) { if(defined $CompleteSignature{1}{$Alt} and $CompleteSignature{1}{$Symbol}{"Const"}) { my $Cid = $CompleteSignature{1}{$Symbol}{"Class"}; %{$CompatProblems{$Level}{$Symbol}{"Removed_Const_Overload"}{"this"}}=( "Type_Name"=>$TypeInfo{1}{$Cid}{"Name"}, "Target"=>get_Signature($Alt, 1)); } else { # do NOT show removed symbol next; } } } %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=(); } } sub addParamNames($) { my $LibraryVersion = $_[0]; return if(not keys(%AddIntParams)); my $SecondVersion = $LibraryVersion==1?2:1; foreach my $Interface (sort keys(%{$CompleteSignature{$LibraryVersion}})) { next if(not keys(%{$AddIntParams{$Interface}})); foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibraryVersion}{$Interface}{"Param"}})) { # add absent parameter names my $ParamName = $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"}; if($ParamName=~/\Ap\d+\Z/ and my $NewParamName = $AddIntParams{$Interface}{$ParamPos}) { # names from the external file if(defined $CompleteSignature{$SecondVersion}{$Interface} and defined $CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos}) { if($CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos}{"name"}=~/\Ap\d+\Z/) { $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName; } } else { $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName; } } } } } sub detectChangedTypedefs() { # detect changed typedefs to show # correct function signatures foreach my $Typedef (keys(%{$Typedef_BaseName{1}})) { next if(not $Typedef); my $BName1 = $Typedef_BaseName{1}{$Typedef}; if(not $BName1 or isAnon($BName1)) { next; } my $BName2 = $Typedef_BaseName{2}{$Typedef}; if(not $BName2 or isAnon($BName2)) { next; } if($BName1 ne $BName2) { $ChangedTypedef{$Typedef} = 1; } } } sub get_symbol_suffix($$) { my ($Symbol, $Full) = @_; my ($SN, $SO, $SV) = separate_symbol($Symbol); $Symbol=$SN; # remove version my $Signature = $tr_name{$Symbol}; my $Suffix = substr($Signature, find_center($Signature, "(")); if(not $Full) { $Suffix=~s/(\))\s*(const volatile|volatile const|const|volatile)\Z/$1/g; } return $Suffix; } sub get_symbol_prefix($$) { my ($Symbol, $LibVersion) = @_; my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"}; if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"}) { # methods $ShortName = $TypeInfo{$LibVersion}{$ClassId}{"Name"}."::".$ShortName; } return $ShortName; } sub setAlternative($) { my $Symbol = $_[0]; my $PSymbol = $Symbol; if(not defined $CompleteSignature{2}{$PSymbol} or (not $CompleteSignature{2}{$PSymbol}{"MnglName"} and not $CompleteSignature{2}{$PSymbol}{"ShortName"})) { # search for a pair if(my $ShortName = $CompleteSignature{1}{$PSymbol}{"ShortName"}) { if($CompleteSignature{1}{$PSymbol}{"Data"}) { if($PSymbol=~s/L(\d+$ShortName(E)\Z)/$1/ or $PSymbol=~s/(\d+$ShortName(E)\Z)/L$1/) { if(defined $CompleteSignature{2}{$PSymbol} and $CompleteSignature{2}{$PSymbol}{"MnglName"}) { $SourceAlternative{$Symbol} = $PSymbol; $SourceAlternative_B{$PSymbol} = $Symbol; if(not defined $CompleteSignature{1}{$PSymbol} or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) { $SourceReplacement{$Symbol} = $PSymbol; } } } } else { foreach my $Sp ("KV", "VK", "K", "V") { if($PSymbol=~s/\A_ZN$Sp/_ZN/ or $PSymbol=~s/\A_ZN/_ZN$Sp/) { if(defined $CompleteSignature{2}{$PSymbol} and $CompleteSignature{2}{$PSymbol}{"MnglName"}) { $SourceAlternative{$Symbol} = $PSymbol; $SourceAlternative_B{$PSymbol} = $Symbol; if(not defined $CompleteSignature{1}{$PSymbol} or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) { $SourceReplacement{$Symbol} = $PSymbol; } } } $PSymbol = $Symbol; } } } } return ""; } sub getSymKind($$) { my ($Symbol, $LibVersion) = @_; if($CompleteSignature{$LibVersion}{$Symbol}{"Data"}) { return "Global_Data"; } elsif($CompleteSignature{$LibVersion}{$Symbol}{"Class"}) { return "Method"; } return "Function"; } sub mergeSymbols($) { my $Level = $_[0]; my %SubProblems = (); mergeBases($Level); my %AddedOverloads = (); foreach my $Symbol (sort keys(%{$AddedInt{$Level}})) { # check all added exported symbols if(not $CompleteSignature{2}{$Symbol}{"Header"}) { next; } if(defined $CompleteSignature{1}{$Symbol} and $CompleteSignature{1}{$Symbol}{"Header"}) { # double-check added symbol next; } if(not symbolFilter($Symbol, 2, "Affected", $Level)) { next; } if($Symbol=~/\A(_Z|\?)/) { # C++ $AddedOverloads{get_symbol_prefix($Symbol, 2)}{get_symbol_suffix($Symbol, 1)} = $Symbol; } if(my $OverriddenMethod = $CompleteSignature{2}{$Symbol}{"Override"}) { # register virtual overridings my $Cid = $CompleteSignature{2}{$Symbol}{"Class"}; my $AffectedClass_Name = $TypeInfo{2}{$Cid}{"Name"}; if(defined $CompleteSignature{1}{$OverriddenMethod} and $CompleteSignature{1}{$OverriddenMethod}{"Virt"} and not $CompleteSignature{1}{$OverriddenMethod}{"Private"}) { if($TName_Tid{1}{$AffectedClass_Name}) { # class should exist in previous version if(not isCopyingClass($TName_Tid{1}{$AffectedClass_Name}, 1)) { # old v-table is NOT copied by old applications %{$CompatProblems{$Level}{$OverriddenMethod}{"Overridden_Virtual_Method"}{$tr_name{$Symbol}}}=( "Type_Name"=>$AffectedClass_Name, "Target"=>get_Signature($Symbol, 2), "Old_Value"=>get_Signature($OverriddenMethod, 2), "New_Value"=>get_Signature($Symbol, 2)); } } } } } foreach my $Symbol (sort keys(%{$RemovedInt{$Level}})) { # check all removed exported symbols if(not $CompleteSignature{1}{$Symbol}{"Header"}) { next; } if(defined $CompleteSignature{2}{$Symbol} and $CompleteSignature{2}{$Symbol}{"Header"}) { # double-check removed symbol next; } if($CompleteSignature{1}{$Symbol}{"Private"}) { # skip private methods next; } if(not symbolFilter($Symbol, 1, "Affected", $Level)) { next; } $CheckedSymbols{$Level}{$Symbol} = 1; if(my $OverriddenMethod = $CompleteSignature{1}{$Symbol}{"Override"}) { # register virtual overridings my $Cid = $CompleteSignature{1}{$Symbol}{"Class"}; my $AffectedClass_Name = $TypeInfo{1}{$Cid}{"Name"}; if(defined $CompleteSignature{2}{$OverriddenMethod} and $CompleteSignature{2}{$OverriddenMethod}{"Virt"}) { if($TName_Tid{2}{$AffectedClass_Name}) { # class should exist in newer version if(not isCopyingClass($CompleteSignature{1}{$Symbol}{"Class"}, 1)) { # old v-table is NOT copied by old applications %{$CompatProblems{$Level}{$Symbol}{"Overridden_Virtual_Method_B"}{$tr_name{$OverriddenMethod}}}=( "Type_Name"=>$AffectedClass_Name, "Target"=>get_Signature($OverriddenMethod, 1), "Old_Value"=>get_Signature($Symbol, 1), "New_Value"=>get_Signature($OverriddenMethod, 1)); } } } } if($Level eq "Binary" and $OSgroup eq "windows") { # register the reason of symbol name change if(my $NewSym = $mangled_name{2}{$tr_name{$Symbol}}) { if($AddedInt{$Level}{$NewSym}) { if($CompleteSignature{1}{$Symbol}{"Static"} ne $CompleteSignature{2}{$NewSym}{"Static"}) { if($CompleteSignature{2}{$NewSym}{"Static"}) { %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Static"}{$tr_name{$Symbol}}}=( "Target"=>$tr_name{$Symbol}, "Old_Value"=>$Symbol, "New_Value"=>$NewSym ); } else { %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Non_Static"}{$tr_name{$Symbol}}}=( "Target"=>$tr_name{$Symbol}, "Old_Value"=>$Symbol, "New_Value"=>$NewSym ); } } if($CompleteSignature{1}{$Symbol}{"Virt"} ne $CompleteSignature{2}{$NewSym}{"Virt"}) { if($CompleteSignature{2}{$NewSym}{"Virt"}) { %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Virtual"}{$tr_name{$Symbol}}}=( "Target"=>$tr_name{$Symbol}, "Old_Value"=>$Symbol, "New_Value"=>$NewSym ); } else { %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Non_Virtual"}{$tr_name{$Symbol}}}=( "Target"=>$tr_name{$Symbol}, "Old_Value"=>$Symbol, "New_Value"=>$NewSym ); } } my $RTId1 = $CompleteSignature{1}{$Symbol}{"Return"}; my $RTId2 = $CompleteSignature{2}{$NewSym}{"Return"}; my $RTName1 = $TypeInfo{1}{$RTId1}{"Name"}; my $RTName2 = $TypeInfo{2}{$RTId2}{"Name"}; if($RTName1 ne $RTName2) { my $ProblemType = "Symbol_Changed_Return"; if($CompleteSignature{1}{$Symbol}{"Data"}) { $ProblemType = "Global_Data_Symbol_Changed_Type"; } %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{$tr_name{$Symbol}}}=( "Target"=>$tr_name{$Symbol}, "Old_Type"=>$RTName1, "New_Type"=>$RTName2, "Old_Value"=>$Symbol, "New_Value"=>$NewSym ); } } } } if($Symbol=~/\A(_Z|\?)/) { # C++ my $Prefix = get_symbol_prefix($Symbol, 1); if(my @Overloads = sort keys(%{$AddedOverloads{$Prefix}}) and not $AddedOverloads{$Prefix}{get_symbol_suffix($Symbol, 1)}) { # changed signature: params, "const"-qualifier my $NewSym = $AddedOverloads{$Prefix}{$Overloads[0]}; if($CompleteSignature{1}{$Symbol}{"Constructor"}) { if($Symbol=~/(C[1-2][EI])/) { my $CtorType = $1; $NewSym=~s/(C[1-2][EI])/$CtorType/g; } } elsif($CompleteSignature{1}{$Symbol}{"Destructor"}) { if($Symbol=~/(D[0-2][EI])/) { my $DtorType = $1; $NewSym=~s/(D[0-2][EI])/$DtorType/g; } } my $NS1 = $CompleteSignature{1}{$Symbol}{"NameSpace"}; my $NS2 = $CompleteSignature{2}{$NewSym}{"NameSpace"}; if((not $NS1 and not $NS2) or ($NS1 and $NS2 and $NS1 eq $NS2)) { # from the same class and namespace if($CompleteSignature{1}{$Symbol}{"Const"} and not $CompleteSignature{2}{$NewSym}{"Const"}) { # "const" to non-"const" %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Non_Const"}{$tr_name{$Symbol}}}=( "Type_Name"=>$TypeInfo{1}{$CompleteSignature{1}{$Symbol}{"Class"}}{"Name"}, "Target"=>$tr_name{$Symbol}, "New_Signature"=>get_Signature($NewSym, 2), "Old_Value"=>$Symbol, "New_Value"=>$NewSym ); } elsif(not $CompleteSignature{1}{$Symbol}{"Const"} and $CompleteSignature{2}{$NewSym}{"Const"}) { # non-"const" to "const" %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Const"}{$tr_name{$Symbol}}}=( "Target"=>$tr_name{$Symbol}, "New_Signature"=>get_Signature($NewSym, 2), "Old_Value"=>$Symbol, "New_Value"=>$NewSym ); } if($CompleteSignature{1}{$Symbol}{"Volatile"} and not $CompleteSignature{2}{$NewSym}{"Volatile"}) { # "volatile" to non-"volatile" %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Non_Volatile"}{$tr_name{$Symbol}}}=( "Target"=>$tr_name{$Symbol}, "New_Signature"=>get_Signature($NewSym, 2), "Old_Value"=>$Symbol, "New_Value"=>$NewSym ); } elsif(not $CompleteSignature{1}{$Symbol}{"Volatile"} and $CompleteSignature{2}{$NewSym}{"Volatile"}) { # non-"volatile" to "volatile" %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Volatile"}{$tr_name{$Symbol}}}=( "Target"=>$tr_name{$Symbol}, "New_Signature"=>get_Signature($NewSym, 2), "Old_Value"=>$Symbol, "New_Value"=>$NewSym ); } if(get_symbol_suffix($Symbol, 0) ne get_symbol_suffix($NewSym, 0)) { # params list %{$CompatProblems{$Level}{$Symbol}{"Symbol_Changed_Parameters"}{$tr_name{$Symbol}}}=( "Target"=>$tr_name{$Symbol}, "New_Signature"=>get_Signature($NewSym, 2), "Old_Value"=>$Symbol, "New_Value"=>$NewSym ); } } } } } foreach my $Symbol (sort keys(%{$CompleteSignature{1}})) { # checking symbols $CurrentSymbol = $Symbol; my ($SN, $SS, $SV) = separate_symbol($Symbol); if($Level eq "Source") { # remove symbol version $Symbol=$SN; } else { # Binary if(not $SV) { # symbol without version if(my $VSym = $SymVer{1}{$Symbol}) { # the symbol is linked with versioned symbol if($CompleteSignature{2}{$VSym}{"MnglName"}) { # show report for symbol@ver only next; } elsif(not link_symbol($VSym, 2, "-Deps")) { # changed version: sym@v1 to sym@v2 # do NOT show report for symbol next; } } } } my $PSymbol = $Symbol; if($Level eq "Source" and my $S = $SourceReplacement{$Symbol}) { # take a source-compatible replacement function $PSymbol = $S; } if($CompleteSignature{1}{$Symbol}{"Private"}) { # private symbols next; } if(not defined $CompleteSignature{1}{$Symbol} or not defined $CompleteSignature{2}{$PSymbol}) { # no info next; } if(not $CompleteSignature{1}{$Symbol}{"MnglName"} or not $CompleteSignature{2}{$PSymbol}{"MnglName"}) { # no mangled name next; } if(not $CompleteSignature{1}{$Symbol}{"Header"} or not $CompleteSignature{2}{$PSymbol}{"Header"}) { # without a header next; } if(not $CompleteSignature{1}{$Symbol}{"PureVirt"} and $CompleteSignature{2}{$PSymbol}{"PureVirt"}) { # became pure next; } if($CompleteSignature{1}{$Symbol}{"PureVirt"} and not $CompleteSignature{2}{$PSymbol}{"PureVirt"}) { # became non-pure next; } if(not symbolFilter($Symbol, 1, "Affected + InlineVirt", $Level)) { # exported, target, inline virtual and pure virtual next; } if(not symbolFilter($PSymbol, 2, "Affected + InlineVirt", $Level)) { # exported, target, inline virtual and pure virtual next; } if(checkDump(1, "2.13") and checkDump(2, "2.13")) { if($CompleteSignature{1}{$Symbol}{"Data"} and $CompleteSignature{2}{$PSymbol}{"Data"}) { my $Value1 = $CompleteSignature{1}{$Symbol}{"Value"}; my $Value2 = $CompleteSignature{2}{$PSymbol}{"Value"}; if(defined $Value1) { $Value1 = showVal($Value1, $CompleteSignature{1}{$Symbol}{"Return"}, 1); if(defined $Value2) { $Value2 = showVal($Value2, $CompleteSignature{2}{$PSymbol}{"Return"}, 2); if($Value1 ne $Value2) { %{$CompatProblems{$Level}{$Symbol}{"Global_Data_Value_Changed"}{""}}=( "Old_Value"=>$Value1, "New_Value"=>$Value2, "Target"=>get_Signature($Symbol, 1) ); } } } } } if($CompleteSignature{2}{$PSymbol}{"Private"}) { %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Private"}{""}}=( "Target"=>get_Signature_M($PSymbol, 2) ); } elsif(not $CompleteSignature{1}{$Symbol}{"Protected"} and $CompleteSignature{2}{$PSymbol}{"Protected"}) { %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Protected"}{""}}=( "Target"=>get_Signature_M($PSymbol, 2) ); } elsif($CompleteSignature{1}{$Symbol}{"Protected"} and not $CompleteSignature{2}{$PSymbol}{"Protected"}) { %{$CompatProblems{$Level}{$Symbol}{getSymKind($Symbol, 1)."_Became_Public"}{""}}=( "Target"=>get_Signature_M($PSymbol, 2) ); } # checking virtual table mergeVirtualTables($Symbol, $Level); if($COMPILE_ERRORS) { # if some errors occurred at the compiling stage # then some false positives can be skipped here if(not $CompleteSignature{1}{$Symbol}{"Data"} and $CompleteSignature{2}{$PSymbol}{"Data"} and not $GlobalDataObject{2}{$Symbol}) { # missed information about parameters in newer version next; } if($CompleteSignature{1}{$Symbol}{"Data"} and not $GlobalDataObject{1}{$Symbol} and not $CompleteSignature{2}{$PSymbol}{"Data"}) { # missed information about parameters in older version next; } } my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol); # checking attributes if($CompleteSignature{2}{$PSymbol}{"Static"} and not $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/) { %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Static"}{""}}=( "Target"=>get_Signature($Symbol, 1) ); } elsif(not $CompleteSignature{2}{$PSymbol}{"Static"} and $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/) { %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Non_Static"}{""}}=( "Target"=>get_Signature($Symbol, 1) ); } if(($CompleteSignature{1}{$Symbol}{"Virt"} and $CompleteSignature{2}{$PSymbol}{"Virt"}) or ($CompleteSignature{1}{$Symbol}{"PureVirt"} and $CompleteSignature{2}{$PSymbol}{"PureVirt"})) { # relative position of virtual and pure virtual methods if($Level eq "Binary") { if(defined $CompleteSignature{1}{$Symbol}{"RelPos"} and defined $CompleteSignature{2}{$PSymbol}{"RelPos"} and $CompleteSignature{1}{$Symbol}{"RelPos"}!=$CompleteSignature{2}{$PSymbol}{"RelPos"}) { # top-level virtual methods only my $Class_Id = $CompleteSignature{1}{$Symbol}{"Class"}; my $Class_Name = $TypeInfo{1}{$Class_Id}{"Name"}; if(defined $VirtualTable{1}{$Class_Name} and defined $VirtualTable{2}{$Class_Name} and $VirtualTable{1}{$Class_Name}{$Symbol}!=$VirtualTable{2}{$Class_Name}{$Symbol}) { # check the absolute position of virtual method (including added and removed methods) my %Class_Type = get_Type($Class_Id, 1); my $ProblemType = "Virtual_Method_Position"; if($CompleteSignature{1}{$Symbol}{"PureVirt"}) { $ProblemType = "Pure_Virtual_Method_Position"; } if(isUsedClass($Class_Id, 1, $Level)) { my @Affected = ($Symbol, keys(%{$OverriddenMethods{1}{$Symbol}})); foreach my $ASymbol (@Affected) { if(not symbolFilter($ASymbol, 1, "Affected", $Level)) { next; } %{$CompatProblems{$Level}{$ASymbol}{$ProblemType}{$tr_name{$MnglName}}}=( "Type_Name"=>$Class_Type{"Name"}, "Old_Value"=>$CompleteSignature{1}{$Symbol}{"RelPos"}, "New_Value"=>$CompleteSignature{2}{$PSymbol}{"RelPos"}, "Target"=>get_Signature($Symbol, 1)); } $VTableChanged_M{$Class_Type{"Name"}} = 1; } } } } } if($CompleteSignature{1}{$Symbol}{"PureVirt"} or $CompleteSignature{2}{$PSymbol}{"PureVirt"}) { # do NOT check type changes in pure virtuals next; } $CheckedSymbols{$Level}{$Symbol} = 1; if($Symbol=~/\A(_Z|\?)/ or keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})==keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}})) { # C/C++: changes in parameters foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})) { # checking parameters mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level, 1); } } else { # C: added/removed parameters foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}})) { # checking added parameters my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"}; my $PType2_Name = $TypeInfo{2}{$PType2_Id}{"Name"}; last if($PType2_Name eq "..."); my $PName = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"}; my $PName_Old = (defined $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos})?$CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"}:""; my $ParamPos_Prev = "-1"; if($PName=~/\Ap\d+\Z/i) { # added unnamed parameter ( pN ) my @Positions1 = find_ParamPair_Pos_byTypeAndPos($PType2_Name, $ParamPos, "backward", $Symbol, 1); my @Positions2 = find_ParamPair_Pos_byTypeAndPos($PType2_Name, $ParamPos, "backward", $Symbol, 2); if($#Positions1==-1 or $#Positions2>$#Positions1) { $ParamPos_Prev = "lost"; } } else { $ParamPos_Prev = find_ParamPair_Pos_byName($PName, $Symbol, 1); } if($ParamPos_Prev eq "lost") { if($ParamPos>keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1) { my $ProblemType = "Added_Parameter"; if($PName=~/\Ap\d+\Z/) { $ProblemType = "Added_Unnamed_Parameter"; } %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=( "Target"=>$PName, "Param_Pos"=>adjustParamPos($ParamPos, $Symbol, 2), "Param_Type"=>$PType2_Name, "New_Signature"=>get_Signature($Symbol, 2) ); } else { my %ParamType_Pure = get_PureType($PType2_Id, $TypeInfo{2}); my $PairType_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"}; my %PairType_Pure = get_PureType($PairType_Id, $TypeInfo{1}); if(($ParamType_Pure{"Name"} eq $PairType_Pure{"Name"} or $PType2_Name eq $TypeInfo{1}{$PairType_Id}{"Name"}) and find_ParamPair_Pos_byName($PName_Old, $Symbol, 2) eq "lost") { if($PName_Old!~/\Ap\d+\Z/ and $PName!~/\Ap\d+\Z/) { %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos)." Parameter"}}=( "Target"=>$PName_Old, "Param_Pos"=>adjustParamPos($ParamPos, $Symbol, 2), "Param_Type"=>$PType2_Name, "Old_Value"=>$PName_Old, "New_Value"=>$PName, "New_Signature"=>get_Signature($Symbol, 2) ); } } else { my $ProblemType = "Added_Middle_Parameter"; if($PName=~/\Ap\d+\Z/) { $ProblemType = "Added_Middle_Unnamed_Parameter"; } %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=( "Target"=>$PName, "Param_Pos"=>adjustParamPos($ParamPos, $Symbol, 2), "Param_Type"=>$PType2_Name, "New_Signature"=>get_Signature($Symbol, 2) ); } } } } foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})) { # check relevant parameters my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"}; my $ParamName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"}; # FIXME: find relevant parameter by name if(defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}) { my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"}; my $ParamName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"}; if($TypeInfo{1}{$PType1_Id}{"Name"} eq $TypeInfo{2}{$PType2_Id}{"Name"} or ($ParamName1!~/\Ap\d+\Z/i and $ParamName1 eq $ParamName2)) { mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level, 0); } } } foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})) { # checking removed parameters my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"}; my $PType1_Name = $TypeInfo{1}{$PType1_Id}{"Name"}; last if($PType1_Name eq "..."); my $PName = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"}; my $PName_New = (defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})?$CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"}:""; my $ParamPos_New = "-1"; if($PName=~/\Ap\d+\Z/i) { # removed unnamed parameter ( pN ) my @Positions1 = find_ParamPair_Pos_byTypeAndPos($PType1_Name, $ParamPos, "forward", $Symbol, 1); my @Positions2 = find_ParamPair_Pos_byTypeAndPos($PType1_Name, $ParamPos, "forward", $Symbol, 2); if($#Positions2==-1 or $#Positions2<$#Positions1) { $ParamPos_New = "lost"; } } else { $ParamPos_New = find_ParamPair_Pos_byName($PName, $Symbol, 2); } if($ParamPos_New eq "lost") { if($ParamPos>keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}})-1) { my $ProblemType = "Removed_Parameter"; if($PName=~/\Ap\d+\Z/) { $ProblemType = "Removed_Unnamed_Parameter"; } %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=( "Target"=>$PName, "Param_Pos"=>adjustParamPos($ParamPos, $Symbol, 2), "Param_Type"=>$PType1_Name, "New_Signature"=>get_Signature($Symbol, 2) ); } elsif($ParamPos$PName, "Param_Pos"=>adjustParamPos($ParamPos, $Symbol, 2), "Param_Type"=>$PType1_Name, "Old_Value"=>$PName, "New_Value"=>$PName_New, "New_Signature"=>get_Signature($Symbol, 2) ); } } else { my $ProblemType = "Removed_Middle_Parameter"; if($PName=~/\Ap\d+\Z/) { $ProblemType = "Removed_Middle_Unnamed_Parameter"; } %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showPos($ParamPos)." Parameter"}}=( "Target"=>$PName, "Param_Pos"=>adjustParamPos($ParamPos, $Symbol, 2), "Param_Type"=>$PType1_Name, "New_Signature"=>get_Signature($Symbol, 2) ); } } } } } # checking return type my $ReturnType1_Id = $CompleteSignature{1}{$Symbol}{"Return"}; my $ReturnType2_Id = $CompleteSignature{2}{$PSymbol}{"Return"}; my %RC_SubProblems = detectTypeChange($ReturnType1_Id, $ReturnType2_Id, "Return", $Level); foreach my $SubProblemType (keys(%RC_SubProblems)) { my $New_Value = $RC_SubProblems{$SubProblemType}{"New_Value"}; my $Old_Value = $RC_SubProblems{$SubProblemType}{"Old_Value"}; my %ProblemTypes = (); if($CompleteSignature{1}{$Symbol}{"Data"}) { if($SubProblemType eq "Return_Type_And_Size") { $ProblemTypes{"Global_Data_Type_And_Size"} = 1; } elsif($SubProblemType eq "Return_Type_Format") { $ProblemTypes{"Global_Data_Type_Format"} = 1; } else { $ProblemTypes{"Global_Data_Type"} = 1; } # quals if($SubProblemType eq "Return_Type" or $SubProblemType eq "Return_Type_And_Size" or $SubProblemType eq "Return_Type_Format") { if(my $RR = removedQual($Old_Value, $New_Value, "const")) { # const to non-const if($RR==2) { $ProblemTypes{"Global_Data_Removed_Const"} = 1; } else { $ProblemTypes{"Global_Data_Became_Non_Const"} = 1; } $ProblemTypes{"Global_Data_Type"} = 1; } elsif(my $RA = addedQual($Old_Value, $New_Value, "const")) { # non-const to const if($RA==2) { $ProblemTypes{"Global_Data_Added_Const"} = 1; } else { $ProblemTypes{"Global_Data_Became_Const"} = 1; } $ProblemTypes{"Global_Data_Type"} = 1; } } } else { # quals if($SubProblemType eq "Return_Type" or $SubProblemType eq "Return_Type_And_Size" or $SubProblemType eq "Return_Type_Format") { if(checkDump(1, "2.6") and checkDump(2, "2.6")) { if(addedQual($Old_Value, $New_Value, "volatile")) { $ProblemTypes{"Return_Value_Became_Volatile"} = 1; if($Level ne "Source" or not cmpBTypes($Old_Value, $New_Value, 1, 2)) { $ProblemTypes{"Return_Type"} = 1; } } } if(my $RA = addedQual($Old_Value, $New_Value, "const")) { if($RA==2) { $ProblemTypes{"Return_Type_Added_Const"} = 1; } else { $ProblemTypes{"Return_Type_Became_Const"} = 1; } if($Level ne "Source" or not cmpBTypes($Old_Value, $New_Value, 1, 2)) { $ProblemTypes{"Return_Type"} = 1; } } } } if($Level eq "Binary" and not $CompleteSignature{1}{$Symbol}{"Data"}) { my ($Arch1, $Arch2) = (getArch(1), getArch(2)); if($Arch1 eq "unknown" or $Arch2 eq "unknown") { # if one of the architectures is unknown # then set other arhitecture to unknown too ($Arch1, $Arch2) = ("unknown", "unknown"); } my (%Conv1, %Conv2) = (); if($UseConv_Real{1}{"R"} and $UseConv_Real{2}{"R"}) { %Conv1 = callingConvention_R_Real($CompleteSignature{1}{$Symbol}); %Conv2 = callingConvention_R_Real($CompleteSignature{2}{$PSymbol}); } else { %Conv1 = callingConvention_R_Model($CompleteSignature{1}{$Symbol}, $TypeInfo{1}, $Arch1, $OStarget, $WORD_SIZE{1}); %Conv2 = callingConvention_R_Model($CompleteSignature{2}{$PSymbol}, $TypeInfo{2}, $Arch2, $OStarget, $WORD_SIZE{2}); } if($SubProblemType eq "Return_Type_Became_Void") { if(keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})) { # parameters stack has been affected if($Conv1{"Method"} eq "stack") { $ProblemTypes{"Return_Type_Became_Void_And_Stack_Layout"} = 1; } elsif($Conv1{"Hidden"}) { $ProblemTypes{"Return_Type_Became_Void_And_Register"} = 1; } } } elsif($SubProblemType eq "Return_Type_From_Void") { if(keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})) { # parameters stack has been affected if($Conv2{"Method"} eq "stack") { $ProblemTypes{"Return_Type_From_Void_And_Stack_Layout"} = 1; } elsif($Conv2{"Hidden"}) { $ProblemTypes{"Return_Type_From_Void_And_Register"} = 1; } } } elsif($SubProblemType eq "Return_Type" or $SubProblemType eq "Return_Type_And_Size" or $SubProblemType eq "Return_Type_Format") { if($Conv1{"Method"} ne $Conv2{"Method"}) { if($Conv1{"Method"} eq "stack") { # returns in a register instead of a hidden first parameter $ProblemTypes{"Return_Type_From_Stack_To_Register"} = 1; } else { $ProblemTypes{"Return_Type_From_Register_To_Stack"} = 1; } } else { if($Conv1{"Method"} eq "reg") { if($Conv1{"Registers"} ne $Conv2{"Registers"}) { if($Conv1{"Hidden"}) { $ProblemTypes{"Return_Type_And_Register_Was_Hidden_Parameter"} = 1; } elsif($Conv2{"Hidden"}) { $ProblemTypes{"Return_Type_And_Register_Became_Hidden_Parameter"} = 1; } else { $ProblemTypes{"Return_Type_And_Register"} = 1; } } } } } } if(not keys(%ProblemTypes)) { # default $ProblemTypes{$SubProblemType} = 1; } foreach my $ProblemType (keys(%ProblemTypes)) { # additional $CompatProblems{$Level}{$Symbol}{$ProblemType}{"retval"} = $RC_SubProblems{$SubProblemType}; } } if($ReturnType1_Id and $ReturnType2_Id) { @RecurTypes = (); my $Sub_SubProblems = mergeTypes($ReturnType1_Id, $ReturnType2_Id, $Level); my $AddProblems = {}; if($CompleteSignature{1}{$Symbol}{"Data"}) { if($Level eq "Binary") { if(get_PLevel($ReturnType1_Id, 1)==0) { if(defined $Sub_SubProblems->{"DataType_Size"}) { # add "Global_Data_Size" problem foreach my $Loc (keys(%{$Sub_SubProblems->{"DataType_Size"}})) { if(index($Loc,"->")==-1) { if($Loc eq $Sub_SubProblems->{"DataType_Size"}{$Loc}{"Type_Name"}) { $AddProblems->{"Global_Data_Size"}{$Loc} = $Sub_SubProblems->{"DataType_Size"}{$Loc}; # add a new problem last; } } } } } if(not defined $AddProblems->{"Global_Data_Size"}) { if(defined $GlobalDataObject{1}{$Symbol} and defined $GlobalDataObject{2}{$Symbol}) { my $Old_Size = $GlobalDataObject{1}{$Symbol}; my $New_Size = $GlobalDataObject{2}{$Symbol}; if($Old_Size!=$New_Size) { $AddProblems->{"Global_Data_Size"}{"retval"} = { "Old_Size"=>$Old_Size*$BYTE_SIZE, "New_Size"=>$New_Size*$BYTE_SIZE }; } } } } } foreach my $SubProblemType (keys(%{$AddProblems})) { foreach my $SubLocation (keys(%{$AddProblems->{$SubProblemType}})) { my $NewLocation = "retval"; if($SubLocation and $SubLocation ne "retval") { $NewLocation = "retval->".$SubLocation; } $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation} = $AddProblems->{$SubProblemType}{$SubLocation}; } } foreach my $SubProblemType (keys(%{$Sub_SubProblems})) { foreach my $SubLocation (keys(%{$Sub_SubProblems->{$SubProblemType}})) { my $NewLocation = "retval"; if($SubLocation and $SubLocation ne "retval") { $NewLocation = "retval->".$SubLocation; } $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation} = $Sub_SubProblems->{$SubProblemType}{$SubLocation}; } } } # checking object type my $ObjTId1 = $CompleteSignature{1}{$Symbol}{"Class"}; my $ObjTId2 = $CompleteSignature{2}{$PSymbol}{"Class"}; if($ObjTId1 and $ObjTId2 and not $CompleteSignature{1}{$Symbol}{"Static"}) { my $ThisPtr1_Id = getTypeIdByName($TypeInfo{1}{$ObjTId1}{"Name"}."*const", 1); my $ThisPtr2_Id = getTypeIdByName($TypeInfo{2}{$ObjTId2}{"Name"}."*const", 2); if($ThisPtr1_Id and $ThisPtr2_Id) { @RecurTypes = (); my $Sub_SubProblems = mergeTypes($ThisPtr1_Id, $ThisPtr2_Id, $Level); foreach my $SubProblemType (keys(%{$Sub_SubProblems})) { foreach my $SubLocation (keys(%{$Sub_SubProblems->{$SubProblemType}})) { my $NewLocation = ($SubLocation)?"this->".$SubLocation:"this"; $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation} = $Sub_SubProblems->{$SubProblemType}{$SubLocation}; } } } } } if($Level eq "Binary") { mergeVTables($Level); } foreach my $Symbol (keys(%{$CompatProblems{$Level}})) { $CheckedSymbols{$Level}{$Symbol} = 1; } } sub rmQuals($$) { my ($Value, $Qual) = @_; if(not $Qual) { return $Value; } if($Qual eq "all") { # all quals $Qual = "const|volatile|restrict"; } while($Value=~s/\b$Qual\b//) { $Value = formatName($Value, "T"); } return $Value; } sub cmpBTypes($$$$) { my ($T1, $T2, $V1, $V2) = @_; $T1 = uncover_typedefs($T1, $V1); $T2 = uncover_typedefs($T2, $V2); return (rmQuals($T1, "all") eq rmQuals($T2, "all")); } sub addedQual($$$) { my ($Old_Value, $New_Value, $Qual) = @_; return removedQual_I($New_Value, $Old_Value, 2, 1, $Qual); } sub removedQual($$$) { my ($Old_Value, $New_Value, $Qual) = @_; return removedQual_I($Old_Value, $New_Value, 1, 2, $Qual); } sub removedQual_I($$$$$) { my ($Old_Value, $New_Value, $V1, $V2, $Qual) = @_; $Old_Value = uncover_typedefs($Old_Value, $V1); $New_Value = uncover_typedefs($New_Value, $V2); if($Old_Value eq $New_Value) { # equal types return 0; } if($Old_Value!~/\b$Qual\b/) { # without a qual return 0; } elsif($New_Value!~/\b$Qual\b/) { # became non-qual return 1; } else { my @BQ1 = getQualModel($Old_Value, $Qual); my @BQ2 = getQualModel($New_Value, $Qual); foreach (0 .. $#BQ1) { # removed qual if($BQ1[$_]==1 and $BQ2[$_]!=1) { return 2; } } } return 0; } sub getQualModel($$) { my ($Value, $Qual) = @_; if(not $Qual) { return $Value; } # cleaning while($Value=~/(\w+)/ and $1 ne $Qual) { $Value=~s/\b$1\b//g; } $Value=~s/[^\*\&\w]+//g; # modeling # int*const*const == 011 # int**const == 001 my @Model = (); my @Elems = split(/[\*\&]/, $Value); if(not @Elems) { return (0); } foreach (@Elems) { if($_ eq $Qual) { push(@Model, 1); } else { push(@Model, 0); } } return @Model; } my %StringTypes = map {$_=>1} ( "char*", "char const*" ); my %CharTypes = map {$_=>1} ( "char", "char const" ); sub showVal($$$) { my ($Value, $TypeId, $LibVersion) = @_; my %PureType = get_PureType($TypeId, $TypeInfo{$LibVersion}); my $TName = uncover_typedefs($PureType{"Name"}, $LibVersion); if(substr($Value, 0, 2) eq "_Z") { if(my $Unmangled = $tr_name{$Value}) { return $Unmangled; } } elsif(defined $StringTypes{$TName} or $TName=~/string/i) { # strings return "\"$Value\""; } elsif(defined $CharTypes{$TName}) { # characters return "\'$Value\'"; } if($Value eq "") { # other return "\'\'"; } return $Value; } sub getRegs($$$) { my ($LibVersion, $Symbol, $Pos) = @_; if(defined $CompleteSignature{$LibVersion}{$Symbol}{"Reg"}) { my %Regs = (); foreach my $Elem (sort keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Reg"}})) { if($Elem=~/\A$Pos([\.\+]|\Z)/) { $Regs{$CompleteSignature{$LibVersion}{$Symbol}{"Reg"}{$Elem}} = 1; } } return join(", ", sort keys(%Regs)); } return undef; } sub mergeParameters($$$$$$) { my ($Symbol, $PSymbol, $ParamPos1, $ParamPos2, $Level, $ChkRnmd) = @_; if(not $Symbol) { return; } my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"type"}; my $PName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"name"}; my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"type"}; my $PName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"name"}; if(not $PType1_Id or not $PType2_Id) { return; } if($Symbol=~/\A(_Z|\?)/) { # do not merge "this" if($PName1 eq "this" or $PName2 eq "this") { return; } } my %Type1 = get_Type($PType1_Id, 1); my %Type2 = get_Type($PType2_Id, 2); my %BaseType1 = get_BaseType($PType1_Id, 1); my %BaseType2 = get_BaseType($PType2_Id, 2); my $Parameter_Location = ($PName1)?$PName1:showPos($ParamPos1)." Parameter"; if($Level eq "Binary") { if(checkDump(1, "2.6.1") and checkDump(2, "2.6.1")) { # "reg" attribute added in ACC 1.95.1 (dump 2.6.1 format) if($CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"} and not $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"}) { %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Non_Register"}{$Parameter_Location}}=( "Target"=>$PName1, "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1) ); } elsif(not $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"} and $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"}) { %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Register"}{$Parameter_Location}}=( "Target"=>$PName1, "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1) ); } } if(defined $UsedDump{1}{"DWARF"} and defined $UsedDump{2}{"DWARF"}) { if(checkDump(1, "3.0") and checkDump(2, "3.0")) { my $Old_Regs = getRegs(1, $Symbol, $ParamPos1); my $New_Regs = getRegs(2, $PSymbol, $ParamPos2); if($Old_Regs and $New_Regs) { if($Old_Regs ne $New_Regs) { %{$CompatProblems{$Level}{$Symbol}{"Parameter_Changed_Register"}{$Parameter_Location}}=( "Target"=>$PName1, "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), "Old_Value"=>$Old_Regs, "New_Value"=>$New_Regs ); } } elsif($Old_Regs and not $New_Regs) { %{$CompatProblems{$Level}{$Symbol}{"Parameter_From_Register"}{$Parameter_Location}}=( "Target"=>$PName1, "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), "Old_Value"=>$Old_Regs ); } elsif(not $Old_Regs and $New_Regs) { %{$CompatProblems{$Level}{$Symbol}{"Parameter_To_Register"}{$Parameter_Location}}=( "Target"=>$PName1, "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), "New_Value"=>$New_Regs ); } if((my $Old_Offset = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"offset"}) ne "" and (my $New_Offset = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"offset"}) ne "") { if($Old_Offset ne $New_Offset) { my $Start1 = $CompleteSignature{1}{$Symbol}{"Param"}{0}{"offset"}; my $Start2 = $CompleteSignature{2}{$Symbol}{"Param"}{0}{"offset"}; $Old_Offset = $Old_Offset - $Start1; $New_Offset = $New_Offset - $Start2; if($Old_Offset ne $New_Offset) { %{$CompatProblems{$Level}{$Symbol}{"Parameter_Changed_Offset"}{$Parameter_Location}}=( "Target"=>$PName1, "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), "Old_Value"=>$Old_Offset, "New_Value"=>$New_Offset ); } } } } } } if(checkDump(1, "2.0") and checkDump(2, "2.0") and $UsedDump{1}{"V"} ne "3.1" and $UsedDump{2}{"V"} ne "3.1") { # "default" attribute added in ACC 1.22 (dump 2.0 format) # broken in 3.1, fixed in 3.2 my $Value_Old = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"default"}; my $Value_New = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"default"}; if(not checkDump(1, "2.13") and checkDump(2, "2.13")) { # support for old ABI dumps if(defined $Value_Old and defined $Value_New) { if($Type1{"Name"} eq "bool" and $Value_Old eq "false" and $Value_New eq "0") { # int class::method ( bool p = 0 ); # old ABI dumps: "false" # new ABI dumps: "0" $Value_Old = "0"; } } } if(not checkDump(1, "2.18") and checkDump(2, "2.18")) { # support for old ABI dumps if(not defined $Value_Old and substr($Value_New, 0, 2) eq "_Z") { $Value_Old = $Value_New; } } if(defined $Value_Old) { $Value_Old = showVal($Value_Old, $PType1_Id, 1); if(defined $Value_New) { $Value_New = showVal($Value_New, $PType2_Id, 2); if($Value_Old ne $Value_New) { # FIXME: how to distinguish "0" and 0 (NULL) %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Changed"}{$Parameter_Location}}=( "Target"=>$PName1, "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), "Old_Value"=>$Value_Old, "New_Value"=>$Value_New ); } } else { %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Removed"}{$Parameter_Location}}=( "Target"=>$PName1, "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), "Old_Value"=>$Value_Old ); } } elsif(defined $Value_New) { $Value_New = showVal($Value_New, $PType2_Id, 2); %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Added"}{$Parameter_Location}}=( "Target"=>$PName1, "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), "New_Value"=>$Value_New ); } } if($ChkRnmd) { if($PName1 and $PName2 and $PName1 ne $PName2 and $PType1_Id!=-1 and $PType2_Id!=-1 and $PName1!~/\Ap\d+\Z/ and $PName2!~/\Ap\d+\Z/) { # except unnamed "..." value list (Id=-1) %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showPos($ParamPos1)." Parameter"}}=( "Target"=>$PName1, "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), "Param_Type"=>$TypeInfo{1}{$PType1_Id}{"Name"}, "Old_Value"=>$PName1, "New_Value"=>$PName2, "New_Signature"=>get_Signature($Symbol, 2) ); } } # checking type change (replace) my %SubProblems = detectTypeChange($PType1_Id, $PType2_Id, "Parameter", $Level); foreach my $SubProblemType (keys(%SubProblems)) { # add new problems, remove false alarms my $New_Value = $SubProblems{$SubProblemType}{"New_Value"}; my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"}; # quals if($SubProblemType eq "Parameter_Type" or $SubProblemType eq "Parameter_Type_And_Size" or $SubProblemType eq "Parameter_Type_Format") { if(checkDump(1, "2.6") and checkDump(2, "2.6")) { if(addedQual($Old_Value, $New_Value, "restrict")) { %{$SubProblems{"Parameter_Became_Restrict"}} = %{$SubProblems{$SubProblemType}}; } elsif(removedQual($Old_Value, $New_Value, "restrict")) { %{$SubProblems{"Parameter_Became_Non_Restrict"}} = %{$SubProblems{$SubProblemType}}; } } if(checkDump(1, "2.6") and checkDump(2, "2.6")) { if(removedQual($Old_Value, $New_Value, "volatile")) { %{$SubProblems{"Parameter_Became_Non_Volatile"}} = %{$SubProblems{$SubProblemType}}; } } if($Type2{"Type"} eq "Const" and $BaseType2{"Name"} eq $Type1{"Name"} and $Type1{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/) { # int to "int const" delete($SubProblems{$SubProblemType}); } elsif($Type1{"Type"} eq "Const" and $BaseType1{"Name"} eq $Type2{"Name"} and $Type2{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/) { # "int const" to int delete($SubProblems{$SubProblemType}); } elsif(my $RR = removedQual($Old_Value, $New_Value, "const")) { # "const" to non-"const" if($RR==2) { %{$SubProblems{"Parameter_Removed_Const"}} = %{$SubProblems{$SubProblemType}}; } else { %{$SubProblems{"Parameter_Became_Non_Const"}} = %{$SubProblems{$SubProblemType}}; } } } } if($Level eq "Source") { foreach my $SubProblemType (keys(%SubProblems)) { my $New_Value = $SubProblems{$SubProblemType}{"New_Value"}; my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"}; if($SubProblemType eq "Parameter_Type") { if(cmpBTypes($Old_Value, $New_Value, 1, 2)) { delete($SubProblems{$SubProblemType}); } } } } foreach my $SubProblemType (keys(%SubProblems)) { # modify/register problems my $New_Value = $SubProblems{$SubProblemType}{"New_Value"}; my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"}; my $New_Size = $SubProblems{$SubProblemType}{"New_Size"}; my $Old_Size = $SubProblems{$SubProblemType}{"Old_Size"}; my $NewProblemType = $SubProblemType; if($Old_Value eq "..." and $New_Value ne "...") { # change from "..." to "int" if($ParamPos1==0) { # ISO C requires a named argument before "..." next; } $NewProblemType = "Parameter_Became_Non_VaList"; } elsif($New_Value eq "..." and $Old_Value ne "...") { # change from "int" to "..." if($ParamPos2==0) { # ISO C requires a named argument before "..." next; } $NewProblemType = "Parameter_Became_VaList"; } elsif($Level eq "Binary" and ($SubProblemType eq "Parameter_Type_And_Size" or $SubProblemType eq "Parameter_Type" or $SubProblemType eq "Parameter_Type_Format")) { my ($Arch1, $Arch2) = (getArch(1), getArch(2)); if($Arch1 eq "unknown" or $Arch2 eq "unknown") { # if one of the architectures is unknown # then set other arhitecture to unknown too ($Arch1, $Arch2) = ("unknown", "unknown"); } my (%Conv1, %Conv2) = (); if($UseConv_Real{1}{"P"} and $UseConv_Real{2}{"P"}) { # real %Conv1 = callingConvention_P_Real($CompleteSignature{1}{$Symbol}, $ParamPos1); %Conv2 = callingConvention_P_Real($CompleteSignature{2}{$Symbol}, $ParamPos2); } else { # model %Conv1 = callingConvention_P_Model($CompleteSignature{1}{$Symbol}, $ParamPos1, $TypeInfo{1}, $Arch1, $OStarget, $WORD_SIZE{1}); %Conv2 = callingConvention_P_Model($CompleteSignature{2}{$Symbol}, $ParamPos2, $TypeInfo{2}, $Arch2, $OStarget, $WORD_SIZE{2}); } if($Conv1{"Method"} eq $Conv2{"Method"}) { if($Conv1{"Method"} eq "stack") { if($Old_Size ne $New_Size) { # FIXME: isMemPadded, getOffset $NewProblemType = "Parameter_Type_And_Stack"; } } elsif($Conv1{"Method"} eq "reg") { if($Conv1{"Registers"} ne $Conv2{"Registers"}) { $NewProblemType = "Parameter_Type_And_Register"; } } } else { if($Conv1{"Method"} eq "stack") { $NewProblemType = "Parameter_Type_From_Stack_To_Register"; } elsif($Conv1{"Method"} eq "register") { $NewProblemType = "Parameter_Type_From_Register_To_Stack"; } } $SubProblems{$SubProblemType}{"Old_Reg"} = $Conv1{"Registers"}; $SubProblems{$SubProblemType}{"New_Reg"} = $Conv2{"Registers"}; } %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}=( "Target"=>$PName1, "Param_Pos"=>adjustParamPos($ParamPos1, $Symbol, 1), "New_Signature"=>get_Signature($Symbol, 2) ); @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}}; } @RecurTypes = (); # checking type definition changes my $Sub_SubProblems = mergeTypes($PType1_Id, $PType2_Id, $Level); foreach my $SubProblemType (keys(%{$Sub_SubProblems})) { foreach my $SubLocation (keys(%{$Sub_SubProblems->{$SubProblemType}})) { my $NewProblemType = $SubProblemType; if($SubProblemType eq "DataType_Size") { if($Type1{"Type"}!~/\A(Pointer|Ref)\Z/ and $SubLocation!~/\-\>/) { # stack has been affected $NewProblemType = "DataType_Size_And_Stack"; } } my $NewLocation = ($SubLocation)?$Parameter_Location."->".$SubLocation:$Parameter_Location; $CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation} = $Sub_SubProblems->{$SubProblemType}{$SubLocation}; } } } sub find_ParamPair_Pos_byName($$$) { my ($Name, $Symbol, $LibVersion) = @_; foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}})) { next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}); if($CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"name"} eq $Name) { return $ParamPos; } } return "lost"; } sub find_ParamPair_Pos_byTypeAndPos($$$$$) { my ($TypeName, $MediumPos, $Order, $Symbol, $LibVersion) = @_; my @Positions = (); foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}})) { next if($Order eq "backward" and $ParamPos>$MediumPos); next if($Order eq "forward" and $ParamPos<$MediumPos); next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}); my $PTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"type"}; if($TypeInfo{$LibVersion}{$PTypeId}{"Name"} eq $TypeName) { push(@Positions, $ParamPos); } } return @Positions; } sub getTypeIdByName($$) { my ($TypeName, $LibVersion) = @_; return $TName_Tid{$LibVersion}{formatName($TypeName, "T")}; } sub diffTypes($$$) { if(defined $Cache{"diffTypes"}{$_[2]}{$_[0]}{$_[1]}) { return $Cache{"diffTypes"}{$_[2]}{$_[0]}{$_[1]}; } if(isRecurType($_[0], $_[1], \@RecurTypes_Diff)) { # skip recursive declarations return 0; } pushType($_[0], $_[1], \@RecurTypes_Diff); my $Diff = diffTypes_I(@_); pop(@RecurTypes_Diff); return ($Cache{"diffTypes"}{$_[2]}{$_[0]}{$_[1]} = $Diff); } sub diffTypes_I($$$) { my ($Type1_Id, $Type2_Id, $Level) = @_; my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1}); my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2}); if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}) { # equal types return 0; } if($Type1_Pure{"Name"} eq "void") { # from void* to something return 0; } if($Type1_Pure{"Name"}=~/\*/ or $Type2_Pure{"Name"}=~/\*/) { # compared in detectTypeChange() return 0; } my %FloatType = map {$_=>1} ( "float", "double", "long double" ); my $T1 = $Type1_Pure{"Type"}; my $T2 = $Type2_Pure{"Type"}; if($T1 eq "Struct" and $T2 eq "Class") { # compare as data structures $T2 = "Struct"; } if($T1 eq "Class" and $T2 eq "Struct") { # compare as data structures $T1 = "Struct"; } if($T1 ne $T2) { # different types if($T1 eq "Intrinsic" and $T2 eq "Enum") { # "int" to "enum" return 0; } elsif($T2 eq "Intrinsic" and $T1 eq "Enum") { # "enum" to "int" return 0; } else { # union to struct # ... return 1; } } else { if($T1 eq "Intrinsic") { if($FloatType{$Type1_Pure{"Name"}} or $FloatType{$Type2_Pure{"Name"}}) { # "float" to "double" # "float" to "int" if($Level eq "Source") { # Safe return 0; } else { return 1; } } } elsif($T1=~/Class|Struct|Union|Enum/) { my @Membs1 = keys(%{$Type1_Pure{"Memb"}}); my @Membs2 = keys(%{$Type2_Pure{"Memb"}}); if(not @Membs1 or not @Membs2) { # private return 0; } if($#Membs1!=$#Membs2) { # different number of elements return 1; } if($T1 eq "Enum") { foreach my $Pos (@Membs1) { # compare elements by name and value if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"} or $Type1_Pure{"Memb"}{$Pos}{"value"} ne $Type2_Pure{"Memb"}{$Pos}{"value"}) { # different names return 1; } } } else { foreach my $Pos (@Membs1) { if($Level eq "Source") { if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"}) { # different names return 1; } } my %MT1 = %{$TypeInfo{1}{$Type1_Pure{"Memb"}{$Pos}{"type"}}}; my %MT2 = %{$TypeInfo{2}{$Type2_Pure{"Memb"}{$Pos}{"type"}}}; if($MT1{"Name"} ne $MT2{"Name"} or isAnon($MT1{"Name"}) or isAnon($MT2{"Name"})) { my $PL1 = get_PLevel($MT1{"Tid"}, 1); my $PL2 = get_PLevel($MT2{"Tid"}, 2); if($PL1 ne $PL2) { # different pointer level return 1; } # compare base types my %BT1 = get_BaseType($MT1{"Tid"}, 1); my %BT2 = get_BaseType($MT2{"Tid"}, 2); if(diffTypes($BT1{"Tid"}, $BT2{"Tid"}, $Level)) { # different types return 1; } } } } } else { # TODO: arrays, etc. } } return 0; } sub detectTypeChange($$$$) { my ($Type1_Id, $Type2_Id, $Prefix, $Level) = @_; if(not $Type1_Id or not $Type2_Id) { return (); } my %LocalProblems = (); my %Type1 = get_Type($Type1_Id, 1); my %Type2 = get_Type($Type2_Id, 2); my %Type1_Pure = get_PureType($Type1_Id, $TypeInfo{1}); my %Type2_Pure = get_PureType($Type2_Id, $TypeInfo{2}); my %Type1_Base = ($Type1_Pure{"Type"} eq "Array")?get_OneStep_BaseType($Type1_Pure{"Tid"}, $TypeInfo{1}):get_BaseType($Type1_Id, 1); my %Type2_Base = ($Type2_Pure{"Type"} eq "Array")?get_OneStep_BaseType($Type2_Pure{"Tid"}, $TypeInfo{2}):get_BaseType($Type2_Id, 2); my $Type1_PLevel = get_PLevel($Type1_Id, 1); my $Type2_PLevel = get_PLevel($Type2_Id, 2); return () if(not $Type1{"Name"} or not $Type2{"Name"}); return () if(not $Type1_Base{"Name"} or not $Type2_Base{"Name"}); return () if($Type1_PLevel eq "" or $Type2_PLevel eq ""); if($Type1_Base{"Name"} ne $Type2_Base{"Name"} and ($Type1{"Name"} eq $Type2{"Name"} or ($Type1_PLevel>=1 and $Type1_PLevel==$Type2_PLevel and $Type1_Base{"Name"} ne "void" and $Type2_Base{"Name"} ne "void"))) { # base type change if($Type1{"Name"} eq $Type2{"Name"}) { if($Type1{"Type"} eq "Typedef" and $Type2{"Type"} eq "Typedef") { # will be reported in mergeTypes() as typedef problem return (); } my %Typedef_1 = goToFirst($Type1{"Tid"}, 1, "Typedef"); my %Typedef_2 = goToFirst($Type2{"Tid"}, 2, "Typedef"); if(%Typedef_1 and %Typedef_2) { if($Typedef_1{"Name"} eq $Typedef_2{"Name"} and $Typedef_1{"Type"} eq "Typedef" and $Typedef_2{"Type"} eq "Typedef") { # const Typedef return (); } } } if($Type1_Base{"Name"}!~/anon\-/ and $Type2_Base{"Name"}!~/anon\-/) { if($Level eq "Binary" and $Type1_Base{"Size"} and $Type2_Base{"Size"} and $Type1_Base{"Size"} ne $Type2_Base{"Size"}) { %{$LocalProblems{$Prefix."_BaseType_And_Size"}}=( "Old_Value"=>$Type1_Base{"Name"}, "New_Value"=>$Type2_Base{"Name"}, "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE, "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE); } else { if(diffTypes($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Level)) { # format change %{$LocalProblems{$Prefix."_BaseType_Format"}}=( "Old_Value"=>$Type1_Base{"Name"}, "New_Value"=>$Type2_Base{"Name"}, "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE, "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE); } elsif(tNameLock($Type1_Base{"Tid"}, $Type2_Base{"Tid"})) { %{$LocalProblems{$Prefix."_BaseType"}}=( "Old_Value"=>$Type1_Base{"Name"}, "New_Value"=>$Type2_Base{"Name"}, "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE, "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE); } } } } elsif($Type1{"Name"} ne $Type2{"Name"}) { # type change if($Type1{"Name"}!~/anon\-/ and $Type2{"Name"}!~/anon\-/) { if($Prefix eq "Return" and $Type1_Pure{"Name"} eq "void") { %{$LocalProblems{"Return_Type_From_Void"}}=( "New_Value"=>$Type2{"Name"}, "New_Size"=>$Type2{"Size"}*$BYTE_SIZE); } elsif($Prefix eq "Return" and $Type2_Pure{"Name"} eq "void") { %{$LocalProblems{"Return_Type_Became_Void"}}=( "Old_Value"=>$Type1{"Name"}, "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE); } else { if($Level eq "Binary" and $Type1{"Size"} and $Type2{"Size"} and $Type1{"Size"} ne $Type2{"Size"}) { %{$LocalProblems{$Prefix."_Type_And_Size"}}=( "Old_Value"=>$Type1{"Name"}, "New_Value"=>$Type2{"Name"}, "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE, "New_Size"=>$Type2{"Size"}*$BYTE_SIZE); } else { if(diffTypes($Type1_Id, $Type2_Id, $Level)) { # format change %{$LocalProblems{$Prefix."_Type_Format"}}=( "Old_Value"=>$Type1{"Name"}, "New_Value"=>$Type2{"Name"}, "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE, "New_Size"=>$Type2{"Size"}*$BYTE_SIZE); } elsif(tNameLock($Type1_Id, $Type2_Id)) { # FIXME: correct this condition %{$LocalProblems{$Prefix."_Type"}}=( "Old_Value"=>$Type1{"Name"}, "New_Value"=>$Type2{"Name"}, "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE, "New_Size"=>$Type2{"Size"}*$BYTE_SIZE); } } } } } if($Type1_PLevel!=$Type2_PLevel) { if($Type1{"Name"} ne "void" and $Type1{"Name"} ne "..." and $Type2{"Name"} ne "void" and $Type2{"Name"} ne "...") { if($Level eq "Source") { %{$LocalProblems{$Prefix."_PointerLevel"}}=( "Old_Value"=>$Type1_PLevel, "New_Value"=>$Type2_PLevel); } else { if($Type2_PLevel>$Type1_PLevel) { %{$LocalProblems{$Prefix."_PointerLevel_Increased"}}=( "Old_Value"=>$Type1_PLevel, "New_Value"=>$Type2_PLevel); } else { %{$LocalProblems{$Prefix."_PointerLevel_Decreased"}}=( "Old_Value"=>$Type1_PLevel, "New_Value"=>$Type2_PLevel); } } } } if($Type1_Pure{"Type"} eq "Array" and $Type1_Pure{"BaseType"}) { # base_type[N] -> base_type[N] # base_type: older_structure -> typedef to newer_structure my %SubProblems = detectTypeChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Prefix, $Level); foreach my $SubProblemType (keys(%SubProblems)) { $SubProblemType=~s/_Type/_BaseType/g; next if(defined $LocalProblems{$SubProblemType}); foreach my $Attr (keys(%{$SubProblems{$SubProblemType}})) { $LocalProblems{$SubProblemType}{$Attr} = $SubProblems{$SubProblemType}{$Attr}; } } } return %LocalProblems; } sub tNameLock($$) { my ($Tid1, $Tid2) = @_; my $Changed = 0; if(differentDumps("G")) { # different GCC versions $Changed = 1; } elsif(differentDumps("V")) { # different versions of ABI dumps if(not checkDump(1, "2.20") or not checkDump(2, "2.20")) { # latest names update # 2.6: added restrict qualifier # 2.13: added missed typedefs to qualified types # 2.20: prefix for struct, union and enum types $Changed = 1; } } my $TN1 = $TypeInfo{1}{$Tid1}{"Name"}; my $TN2 = $TypeInfo{2}{$Tid2}{"Name"}; my $TT1 = $TypeInfo{1}{$Tid1}{"Type"}; my $TT2 = $TypeInfo{2}{$Tid2}{"Type"}; if($Changed) { # different formats if($UseOldDumps) { # old dumps return 0; } my %Base1 = get_Type($Tid1, 1); while(defined $Base1{"Type"} and $Base1{"Type"} eq "Typedef") { %Base1 = get_OneStep_BaseType($Base1{"Tid"}, $TypeInfo{1}); } my %Base2 = get_Type($Tid2, 2); while(defined $Base2{"Type"} and $Base2{"Type"} eq "Typedef") { %Base2 = get_OneStep_BaseType($Base2{"Tid"}, $TypeInfo{2}); } my $BName1 = uncover_typedefs($Base1{"Name"}, 1); my $BName2 = uncover_typedefs($Base2{"Name"}, 2); if($BName1 eq $BName2) { # equal base types return 0; } if(not checkDump(1, "2.13") or not checkDump(2, "2.13")) { # broken array names in ABI dumps < 2.13 if($TT1 eq "Array" and $TT2 eq "Array") { return 0; } } if(not checkDump(1, "2.6") or not checkDump(2, "2.6")) { # added restrict attribute in 2.6 if($TN1!~/\brestrict\b/ and $TN2=~/\brestrict\b/) { return 0; } } if(not checkDump(1, "2.20") or not checkDump(2, "2.20")) { # added type prefix in 2.20 if($TN1=~/\A(struct|union|enum) \Q$TN2\E\Z/ or $TN2=~/\A(struct|union|enum) \Q$TN1\E\Z/) { return 0; } } } else { # typedef struct {...} type_t # typedef struct type_t {...} type_t if(index($TN1, " ".$TN2)!=-1) { if($TN1=~/\A(struct|union|enum) \Q$TN2\E\Z/) { return 0; } } if(index($TN2, " ".$TN1)!=-1) { if($TN2=~/\A(struct|union|enum) \Q$TN1\E\Z/) { return 0; } } if($TT1 eq "FuncPtr" and $TT2 eq "FuncPtr") { my $TN1_C = $TN1; my $TN2_C = $TN2; $TN1_C=~s/\b(struct|union) //g; $TN2_C=~s/\b(struct|union) //g; if($TN1_C eq $TN2_C) { return 0; } } } my ($N1, $N2) = ($TN1, $TN2); $N1=~s/\b(struct|union) //g; $N2=~s/\b(struct|union) //g; if($N1 eq $N2) { # QList and QList return 0; } return 1; } sub differentDumps($) { my $Check = $_[0]; if(defined $Cache{"differentDumps"}{$Check}) { return $Cache{"differentDumps"}{$Check}; } if($UsedDump{1}{"V"} and $UsedDump{2}{"V"}) { if($Check eq "G") { if(getGccVersion(1) ne getGccVersion(2)) { # different GCC versions return ($Cache{"differentDumps"}{$Check}=1); } } if($Check eq "V") { if(cmpVersions(formatVersion($UsedDump{1}{"V"}, 2), formatVersion($UsedDump{2}{"V"}, 2))!=0) { # different dump versions (skip micro version) return ($Cache{"differentDumps"}{$Check}=1); } } } return ($Cache{"differentDumps"}{$Check}=0); } sub formatVersion($$) { # cut off version digits my ($V, $Digits) = @_; my @Elems = split(/\./, $V); return join(".", splice(@Elems, 0, $Digits)); } sub htmlSpecChars($) { my $Str = $_[0]; if(not $Str) { return $Str; } $Str=~s/\&([^#]|\Z)/&$1/g; $Str=~s//->/g; # − $Str=~s/>/>/g; $Str=~s/([^ ]) ([^ ])/$1\@SP\@$2/g; $Str=~s/([^ ]) ([^ ])/$1\@SP\@$2/g; $Str=~s/ / /g; #   $Str=~s/\@SP\@/ /g; $Str=~s/\n//g; $Str=~s/\"/"/g; $Str=~s/\'/'/g; return $Str; } sub xmlSpecChars($) { my $Str = $_[0]; if(not $Str) { return $Str; } $Str=~s/\&([^#]|\Z)/&$1/g; $Str=~s//>/g; $Str=~s/\"/"/g; $Str=~s/\'/'/g; return $Str; } sub xmlSpecChars_R($) { my $Str = $_[0]; if(not $Str) { return $Str; } $Str=~s/&/&/g; $Str=~s/<//g; $Str=~s/"/"/g; $Str=~s/'/'/g; return $Str; } sub black_name($) { my $Name = $_[0]; return "".highLight_Signature($Name).""; } sub highLight_Signature($) { my $Signature = $_[0]; return highLight_Signature_PPos_Italic($Signature, "", 0, 0, 0); } sub highLight_Signature_Italic_Color($) { my $Signature = $_[0]; return highLight_Signature_PPos_Italic($Signature, "", 1, 1, 1); } sub separate_symbol($) { my $Symbol = $_[0]; my ($Name, $Spec, $Ver) = ($Symbol, "", ""); if($Symbol=~/\A([^\@\$\?]+)([\@\$]+)([^\@\$]+)\Z/) { ($Name, $Spec, $Ver) = ($1, $2, $3); } return ($Name, $Spec, $Ver); } sub cut_f_attrs($) { if($_[0]=~s/(\))((| (const volatile|const|volatile))(| \[static\]))\Z/$1/) { return $2; } return ""; } sub highLight_Signature_PPos_Italic($$$$$) { my ($FullSignature, $Param_Pos, $ItalicParams, $ColorParams, $ShowReturn) = @_; $Param_Pos = "" if(not defined $Param_Pos); if($CheckObjectsOnly) { $ItalicParams=$ColorParams=0; } my ($Signature, $VersionSpec, $SymbolVersion) = separate_symbol($FullSignature); my $Return = ""; if($ShowRetVal and $Signature=~s/([^:]):([^:].+?)\Z/$1/g) { $Return = $2; } my $SCenter = find_center($Signature, "("); if(not $SCenter) { # global data $Signature = htmlSpecChars($Signature); $Signature=~s!(\[data\])!$1!g; $Signature .= (($SymbolVersion)?" $VersionSpec $SymbolVersion":""); if($Return and $ShowReturn) { $Signature .= "  :  ".htmlSpecChars($Return).""; } return $Signature; } my ($Begin, $End) = (substr($Signature, 0, $SCenter), ""); $Begin.=" " if($Begin!~/ \Z/); $End = cut_f_attrs($Signature); my @Parts = (); my ($Short, $Params) = split_Signature($Signature); my @SParts = separate_Params($Params, 1, 1); foreach my $Pos (0 .. $#SParts) { my $Part = $SParts[$Pos]; $Part=~s/\A\s+|\s+\Z//g; my ($Part_Styled, $ParamName) = (htmlSpecChars($Part), ""); if($Part=~/\([\*]+(\w+)\)/i) { $ParamName = $1;#func-ptr } elsif($Part=~/(\w+)[\,\)]*\Z/i) { $ParamName = $1; } if(not $ParamName) { push(@Parts, $Part_Styled); next; } if($ItalicParams and not $TName_Tid{1}{$Part} and not $TName_Tid{2}{$Part}) { my $Style = "param"; if($Param_Pos ne "" and $Pos==$Param_Pos) { $Style = "focus_p"; } elsif($ColorParams) { $Style = "color_p"; } $Part_Styled =~ s!(\W)$ParamName([\,\)]|\Z)!$1$ParamName$2!ig; } $Part_Styled=~s/,(\w)/, $1/g; push(@Parts, $Part_Styled); } if(@Parts) { foreach my $Num (0 .. $#Parts) { if($Num==$#Parts) { # add ")" to the last parameter $Parts[$Num] = "".$Parts[$Num]." )"; } elsif(length($Parts[$Num])<=45) { $Parts[$Num] = "".$Parts[$Num].""; } } $Signature = htmlSpecChars($Begin)."( ".join(" ", @Parts)."".$End; } else { $Signature = htmlSpecChars($Begin)."( )".$End; } if($Return and $ShowReturn) { $Signature .= "  :  ".htmlSpecChars($Return).""; } $Signature=~s!\[\]![ ]!g; $Signature=~s!operator=!operator =!g; $Signature=~s!(\[in-charge\]|\[not-in-charge\]|\[in-charge-deleting\]|\[static\])!$1!g; if($SymbolVersion) { $Signature .= " $VersionSpec $SymbolVersion"; } return $Signature; } sub split_Signature($) { my $Signature = $_[0]; if(my $ShortName = substr($Signature, 0, find_center($Signature, "("))) { $Signature=~s/\A\Q$ShortName\E\(//g; cut_f_attrs($Signature); $Signature=~s/\)\Z//; return ($ShortName, $Signature); } # error return ($Signature, ""); } sub separate_Params($$$) { my ($Params, $Comma, $Sp) = @_; my @Parts = (); my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 ); my $Part = 0; foreach my $Pos (0 .. length($Params) - 1) { my $S = substr($Params, $Pos, 1); if(defined $B{$S}) { $B{$S} += 1; } if($S eq "," and $B{"("}==$B{")"} and $B{"<"}==$B{">"}) { if($Comma) { # include comma $Parts[$Part] .= $S; } $Part += 1; } else { $Parts[$Part] .= $S; } } if(not $Sp) { # remove spaces foreach (@Parts) { s/\A //g; s/ \Z//g; } } return @Parts; } sub find_center($$) { my ($Sign, $Target) = @_; my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 ); my $Center = 0; if($Sign=~s/(operator([^\w\s\(\)]+|\(\)))//g) { # operators $Center+=length($1); } foreach my $Pos (0 .. length($Sign)-1) { my $S = substr($Sign, $Pos, 1); if($S eq $Target) { if($B{"("}==$B{")"} and $B{"<"}==$B{">"}) { return $Center; } } if(defined $B{$S}) { $B{$S}+=1; } $Center+=1; } return 0; } sub appendFile($$) { my ($Path, $Content) = @_; return if(not $Path); if(my $Dir = get_dirname($Path)) { mkpath($Dir); } open(FILE, ">>", $Path) || die ("can't open file \'$Path\': $!\n"); print FILE $Content; close(FILE); } sub writeFile($$) { my ($Path, $Content) = @_; return if(not $Path); if(my $Dir = get_dirname($Path)) { mkpath($Dir); } open(FILE, ">", $Path) || die ("can't open file \'$Path\': $!\n"); print FILE $Content; close(FILE); } sub readFile($) { my $Path = $_[0]; return "" if(not $Path or not -f $Path); open(FILE, $Path); local $/ = undef; my $Content = ; close(FILE); if($Path!~/\.(tu|class|abi)\Z/) { $Content=~s/\r/\n/g; } return $Content; } sub get_filename($) { # much faster than basename() from File::Basename module if(defined $Cache{"get_filename"}{$_[0]}) { return $Cache{"get_filename"}{$_[0]}; } if($_[0] and $_[0]=~/([^\/\\]+)[\/\\]*\Z/) { return ($Cache{"get_filename"}{$_[0]}=$1); } return ($Cache{"get_filename"}{$_[0]}=""); } sub get_dirname($) { # much faster than dirname() from File::Basename module if(defined $Cache{"get_dirname"}{$_[0]}) { return $Cache{"get_dirname"}{$_[0]}; } if($_[0] and $_[0]=~/\A(.*?)[\/\\]+[^\/\\]*[\/\\]*\Z/) { return ($Cache{"get_dirname"}{$_[0]}=$1); } return ($Cache{"get_dirname"}{$_[0]}=""); } sub separate_path($) { return (get_dirname($_[0]), get_filename($_[0])); } sub esc($) { my $Str = $_[0]; $Str=~s/([()\[\]{}$ &'"`;,<>\+])/\\$1/g; return $Str; } sub readLineNum($$) { my ($Path, $Num) = @_; return "" if(not $Path or not -f $Path); open(FILE, $Path); foreach (1 ... $Num) { ; } my $Line = ; close(FILE); return $Line; } sub readAttributes($$) { my ($Path, $Num) = @_; return () if(not $Path or not -f $Path); my %Attributes = (); if(readLineNum($Path, $Num)=~//) { foreach my $AttrVal (split(/;/, $1)) { if($AttrVal=~/(.+):(.+)/) { my ($Name, $Value) = ($1, $2); $Attributes{$Name} = $Value; } } } return \%Attributes; } sub is_abs($) { return ($_[0]=~/\A(\/|\w+:[\/\\])/); } sub get_abs_path($) { # abs_path() should NOT be called for absolute inputs # because it can change them my $Path = $_[0]; if(not is_abs($Path)) { $Path = abs_path($Path); } return $Path; } sub get_OSgroup() { my $N = $Config{"osname"}; if($N=~/macos|darwin|rhapsody/i) { return "macos"; } elsif($N=~/freebsd|openbsd|netbsd/i) { return "bsd"; } elsif($N=~/haiku|beos/i) { return "beos"; } elsif($N=~/symbian|epoc/i) { return "symbian"; } elsif($N=~/win/i) { return "windows"; } else { return $N; } } sub getGccVersion($) { my $LibVersion = $_[0]; if($GCC_VERSION{$LibVersion}) { # dump version return $GCC_VERSION{$LibVersion}; } elsif($UsedDump{$LibVersion}{"V"}) { # old-version dumps return "unknown"; } my $GccVersion = get_dumpversion($GCC_PATH); # host version if(not $GccVersion) { return "unknown"; } return $GccVersion; } sub showArch($) { my $Arch = $_[0]; if($Arch eq "arm" or $Arch eq "mips") { return uc($Arch); } return $Arch; } sub getArch($) { my $LibVersion = $_[0]; if($CPU_ARCH{$LibVersion}) { # dump version return $CPU_ARCH{$LibVersion}; } elsif($UsedDump{$LibVersion}{"V"}) { # old-version dumps return "unknown"; } if(defined $Cache{"getArch"}{$LibVersion}) { return $Cache{"getArch"}{$LibVersion}; } my $Arch = get_dumpmachine($GCC_PATH); # host version if(not $Arch) { return "unknown"; } if($Arch=~/\A([\w]{3,})(-|\Z)/) { $Arch = $1; } $Arch = "x86" if($Arch=~/\Ai[3-7]86\Z/i); $Arch = "x86_64" if($Arch=~/\Aamd64\Z/i); if($OSgroup eq "windows") { $Arch = "x86" if($Arch=~/win32|mingw32/i); $Arch = "x86_64" if($Arch=~/win64|mingw64/i); } $Cache{"getArch"}{$LibVersion} = $Arch; return $Arch; } sub get_Report_Header($) { my $Level = $_[0]; my $ArchInfo = " on ".showArch(getArch(1)).""; if(getArch(1) ne getArch(2) or getArch(1) eq "unknown" or $Level eq "Source") { # don't show architecture in the header $ArchInfo=""; } my $Report_Header = "

"; if($Level eq "Source") { $Report_Header .= "Source compatibility"; } elsif($Level eq "Binary") { $Report_Header .= "Binary compatibility"; } else { $Report_Header .= "API compatibility"; } $Report_Header .= " report for the $TargetLibraryFName $TargetComponent"; $Report_Header .= "  between ".$Descriptor{1}{"Version"}." and ".$Descriptor{2}{"Version"}." versions$ArchInfo"; if($AppPath) { $Report_Header .= "  (relating to the portability of application ".get_filename($AppPath).")"; } $Report_Header .= "

\n"; return $Report_Header; } sub get_SourceInfo() { my ($CheckedHeaders, $CheckedSources, $CheckedLibs) = ("", ""); if(not $CheckObjectsOnly) { if(my @Headers = keys(%{$Registered_Headers{1}})) { $CheckedHeaders = "

Header Files (".($#Headers+1).")


\n"; $CheckedHeaders .= "
\n"; foreach my $Header_Path (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} @Headers) { my $Identity = $Registered_Headers{1}{$Header_Path}{"Identity"}; my $Name = get_filename($Identity); my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":""; $CheckedHeaders .= $Name.$Comment."
\n"; } $CheckedHeaders .= "
\n"; $CheckedHeaders .= "
$TOP_REF
\n"; } if(my @Sources = keys(%{$Registered_Sources{1}})) { $CheckedSources = "

Source Files (".($#Sources+1).")


\n"; $CheckedSources .= "
\n"; foreach my $Header_Path (sort {lc($Registered_Sources{1}{$a}{"Identity"}) cmp lc($Registered_Sources{1}{$b}{"Identity"})} @Sources) { my $Identity = $Registered_Sources{1}{$Header_Path}{"Identity"}; my $Name = get_filename($Identity); my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":""; $CheckedSources .= $Name.$Comment."
\n"; } $CheckedSources .= "
\n"; $CheckedSources .= "
$TOP_REF
\n"; } } if(not $CheckHeadersOnly) { $CheckedLibs = "

".get_ObjTitle()." (".keys(%{$Library_Symbol{1}}).")


\n"; $CheckedLibs .= "
\n"; foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$Library_Symbol{1}})) { $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/); $CheckedLibs .= $Library."
\n"; } $CheckedLibs .= "
\n"; $CheckedLibs .= "
$TOP_REF
\n"; } return $CheckedHeaders.$CheckedSources.$CheckedLibs; } sub get_ObjTitle() { if(defined $UsedDump{1}{"DWARF"}) { return "Objects"; } else { return ucfirst($SLIB_TYPE)." Libraries"; } } sub get_TypeProblems_Count($$$) { my ($TypeChanges, $TargetPriority, $Level) = @_; my $Type_Problems_Count = 0; foreach my $Type_Name (sort keys(%{$TypeChanges})) { my %Kinds_Target = (); foreach my $Kind (keys(%{$TypeChanges->{$Type_Name}})) { foreach my $Location (keys(%{$TypeChanges->{$Type_Name}{$Kind}})) { my $Target = $TypeChanges->{$Type_Name}{$Kind}{$Location}{"Target"}; my $Severity = $CompatRules{$Level}{$Kind}{"Severity"}; next if($Severity ne $TargetPriority); if($Kinds_Target{$Kind}{$Target}) { next; } if(my $MaxSeverity = $Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}) { if($Severity_Val{$MaxSeverity}>$Severity_Val{$Severity}) { # select a problem with the highest priority next; } } $Kinds_Target{$Kind}{$Target} = 1; $Type_Problems_Count += 1; } } } return $Type_Problems_Count; } sub get_Summary($) { my $Level = $_[0]; my ($Added, $Removed, $I_Problems_High, $I_Problems_Medium, $I_Problems_Low, $T_Problems_High, $C_Problems_Low, $T_Problems_Medium, $T_Problems_Low, $I_Other, $T_Other, $C_Other) = (0,0,0,0,0,0,0,0,0,0,0,0); %{$RESULT{$Level}} = ( "Problems"=>0, "Warnings"=>0, "Affected"=>0 ); # check rules foreach my $Interface (sort keys(%{$CompatProblems{$Level}})) { foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}})) { if(not defined $CompatRules{$Level}{$Kind}) { # unknown rule if(not $UnknownRules{$Level}{$Kind}) { # only one warning printMsg("WARNING", "unknown rule \"$Kind\" (\"$Level\")"); $UnknownRules{$Level}{$Kind}=1; } delete($CompatProblems{$Level}{$Interface}{$Kind}); } } } foreach my $Constant (sort keys(%{$CompatProblems_Constants{$Level}})) { foreach my $Kind (keys(%{$CompatProblems_Constants{$Level}{$Constant}})) { if(not defined $CompatRules{$Level}{$Kind}) { # unknown rule if(not $UnknownRules{$Level}{$Kind}) { # only one warning printMsg("WARNING", "unknown rule \"$Kind\" (\"$Level\")"); $UnknownRules{$Level}{$Kind}=1; } delete($CompatProblems_Constants{$Level}{$Constant}{$Kind}); } } } foreach my $Interface (sort keys(%{$CompatProblems{$Level}})) { foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}})) { if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols") { foreach my $Location (sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}})) { my $Severity = $CompatRules{$Level}{$Kind}{"Severity"}; if($Kind eq "Added_Symbol") { $Added += 1; } elsif($Kind eq "Removed_Symbol") { $Removed += 1; $TotalAffected{$Level}{$Interface} = $Severity; } else { if($Severity eq "Safe") { $I_Other += 1; } elsif($Severity eq "High") { $I_Problems_High += 1; } elsif($Severity eq "Medium") { $I_Problems_Medium += 1; } elsif($Severity eq "Low") { $I_Problems_Low += 1; } if(($Severity ne "Low" or $StrictCompat) and $Severity ne "Safe") { $TotalAffected{$Level}{$Interface} = $Severity; } } } } } } my %TypeChanges = (); foreach my $Interface (sort keys(%{$CompatProblems{$Level}})) { foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}})) { if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types") { foreach my $Location (sort {cmpLocations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}})) { my $Type_Name = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"}; my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"}; my $Severity = $CompatRules{$Level}{$Kind}{"Severity"}; my $MaxSeverity = $Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}; if($MaxSeverity and $Severity_Val{$MaxSeverity}>$Severity_Val{$Severity}) { # select a problem with the highest priority next; } if(($Severity ne "Low" or $StrictCompat) and $Severity ne "Safe") { if(defined $TotalAffected{$Level}{$Interface}) { if($Severity_Val{$Severity}>$Severity_Val{$TotalAffected{$Level}{$Interface}}) { $TotalAffected{$Level}{$Interface} = $Severity; } } else { $TotalAffected{$Level}{$Interface} = $Severity; } } $TypeChanges{$Type_Name}{$Kind}{$Location} = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}; if($MaxSeverity) { if($Severity_Val{$Severity}>$Severity_Val{$MaxSeverity}) { $Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target} = $Severity; } } else { $Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target} = $Severity; } } } } } $T_Problems_High = get_TypeProblems_Count(\%TypeChanges, "High", $Level); $T_Problems_Medium = get_TypeProblems_Count(\%TypeChanges, "Medium", $Level); $T_Problems_Low = get_TypeProblems_Count(\%TypeChanges, "Low", $Level); $T_Other = get_TypeProblems_Count(\%TypeChanges, "Safe", $Level); %TypeChanges = (); # free memory if($CheckObjectsOnly) { # only removed exported symbols $RESULT{$Level}{"Affected"} = $Removed*100/keys(%{$Symbol_Library{1}}); } else { # changed and removed public symbols my $SCount = keys(%{$CheckedSymbols{$Level}}); if($ExtendedCheck) { # don't count external_func_0 for constants $SCount-=1; } if($SCount) { my %Weight = ( "High" => 100, "Medium" => 50, "Low" => 25 ); foreach (keys(%{$TotalAffected{$Level}})) { $RESULT{$Level}{"Affected"}+=$Weight{$TotalAffected{$Level}{$_}}; } $RESULT{$Level}{"Affected"} = $RESULT{$Level}{"Affected"}/$SCount; } else { $RESULT{$Level}{"Affected"} = 0; } } $RESULT{$Level}{"Affected"} = show_number($RESULT{$Level}{"Affected"}); if($RESULT{$Level}{"Affected"}>=100) { $RESULT{$Level}{"Affected"} = 100; } $RESULT{$Level}{"Problems"} += $Removed; $RESULT{$Level}{"Problems"} += $T_Problems_High + $I_Problems_High; $RESULT{$Level}{"Problems"} += $T_Problems_Medium + $I_Problems_Medium; if($StrictCompat) { $RESULT{$Level}{"Problems"} += $T_Problems_Low + $I_Problems_Low; } else { $RESULT{$Level}{"Warnings"} += $T_Problems_Low + $I_Problems_Low; } foreach my $Constant (keys(%{$CompatProblems_Constants{$Level}})) { foreach my $Kind (keys(%{$CompatProblems_Constants{$Level}{$Constant}})) { my $Severity = $CompatRules{$Level}{$Kind}{"Severity"}; if($Severity eq "Safe") { $C_Other+=1; } elsif($Severity eq "Low") { $C_Problems_Low+=1; } } } if($C_Problems_Low) { if($StrictCompat) { $RESULT{$Level}{"Problems"} += $C_Problems_Low; } else { $RESULT{$Level}{"Warnings"} += $C_Problems_Low; } } if($CheckImpl and $Level eq "Binary") { if($StrictCompat) { $RESULT{$Level}{"Problems"} += keys(%CompatProblems_Impl); } else { $RESULT{$Level}{"Warnings"} += keys(%CompatProblems_Impl); } } if($RESULT{$Level}{"Problems"} and $RESULT{$Level}{"Affected"}) { $RESULT{$Level}{"Verdict"} = "incompatible"; } else { $RESULT{$Level}{"Verdict"} = "compatible"; } my $TotalTypes = keys(%{$CheckedTypes{$Level}}); if(not $TotalTypes) { # list all the types $TotalTypes = keys(%{$TName_Tid{1}}); } my ($Arch1, $Arch2) = (getArch(1), getArch(2)); my ($GccV1, $GccV2) = (getGccVersion(1), getGccVersion(2)); my ($TestInfo, $TestResults, $Problem_Summary) = (); if($ReportFormat eq "xml") { # XML # test info $TestInfo .= " $TargetLibraryName\n"; $TestInfo .= " \n"; $TestInfo .= " ".$Descriptor{1}{"Version"}."\n"; $TestInfo .= " $Arch1\n"; $TestInfo .= " $GccV1\n"; $TestInfo .= " \n"; $TestInfo .= " \n"; $TestInfo .= " ".$Descriptor{2}{"Version"}."\n"; $TestInfo .= " $Arch2\n"; $TestInfo .= " $GccV2\n"; $TestInfo .= " \n"; $TestInfo = "\n".$TestInfo."\n\n"; # test results if(my @Headers = keys(%{$Registered_Headers{1}})) { $TestResults .= " \n"; foreach my $Name (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} @Headers) { my $Identity = $Registered_Headers{1}{$Name}{"Identity"}; my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":""; $TestResults .= " ".get_filename($Name).$Comment."\n"; } $TestResults .= " \n"; } if(my @Sources = keys(%{$Registered_Sources{1}})) { $TestResults .= " \n"; foreach my $Name (sort {lc($Registered_Sources{1}{$a}{"Identity"}) cmp lc($Registered_Sources{1}{$b}{"Identity"})} @Sources) { my $Identity = $Registered_Sources{1}{$Name}{"Identity"}; my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":""; $TestResults .= " ".get_filename($Name).$Comment."\n"; } $TestResults .= " \n"; } $TestResults .= " \n"; foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$Library_Symbol{1}})) { $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/); $TestResults .= " $Library\n"; } $TestResults .= " \n"; $TestResults .= " ".(keys(%{$CheckedSymbols{$Level}}) - keys(%ExtendedSymbols))."\n"; $TestResults .= " ".$TotalTypes."\n"; $TestResults .= " ".$RESULT{$Level}{"Verdict"}."\n"; $TestResults .= " ".$RESULT{$Level}{"Affected"}."\n"; $TestResults = "\n".$TestResults."\n\n"; # problem summary $Problem_Summary .= " ".$Added."\n"; $Problem_Summary .= " ".$Removed."\n"; $Problem_Summary .= " \n"; $Problem_Summary .= " $T_Problems_High\n"; $Problem_Summary .= " $T_Problems_Medium\n"; $Problem_Summary .= " $T_Problems_Low\n"; $Problem_Summary .= " $T_Other\n"; $Problem_Summary .= " \n"; $Problem_Summary .= " \n"; $Problem_Summary .= " $I_Problems_High\n"; $Problem_Summary .= " $I_Problems_Medium\n"; $Problem_Summary .= " $I_Problems_Low\n"; $Problem_Summary .= " $I_Other\n"; $Problem_Summary .= " \n"; $Problem_Summary .= " \n"; $Problem_Summary .= " $C_Problems_Low\n"; $Problem_Summary .= " \n"; if($CheckImpl and $Level eq "Binary") { $Problem_Summary .= " \n"; $Problem_Summary .= " ".keys(%CompatProblems_Impl)."\n"; $Problem_Summary .= " \n"; } $Problem_Summary = "\n".$Problem_Summary."\n\n"; return ($TestInfo.$TestResults.$Problem_Summary, ""); } else { # HTML # test info $TestInfo = "

Test Info


\n"; $TestInfo .= "\n"; $TestInfo .= "\n"; my (@VInf1, @VInf2, $AddTestInfo) = (); if($Arch1 ne "unknown" and $Arch2 ne "unknown") { # CPU arch if($Arch1 eq $Arch2) { # go to the separate section $AddTestInfo .= "\n"; } else { # go to the version number push(@VInf1, showArch($Arch1)); push(@VInf2, showArch($Arch2)); } } if($GccV1 ne "unknown" and $GccV2 ne "unknown" and $OStarget ne "windows") { # GCC version if($GccV1 eq $GccV2) { # go to the separate section $AddTestInfo .= "\n"; } else { # go to the version number push(@VInf1, "gcc ".$GccV1); push(@VInf2, "gcc ".$GccV2); } } # show long version names with GCC version and CPU architecture name (if different) $TestInfo .= "\n"; $TestInfo .= "\n"; $TestInfo .= $AddTestInfo; #if($COMMON_LANGUAGE{1}) { # $TestInfo .= "\n"; #} if($ExtendedCheck) { $TestInfo .= "\n"; } if($JoinReport) { if($Level eq "Binary") { $TestInfo .= "\n"; # Run-time } if($Level eq "Source") { $TestInfo .= "\n"; # Build-time } } $TestInfo .= "
".ucfirst($TargetComponent)." Name$TargetLibraryFName
CPU Type".showArch($Arch1)."
GCC Version$GccV1
Version #1".$Descriptor{1}{"Version"}.(@VInf1?" (".join(", ", reverse(@VInf1)).")":"")."
Version #2".$Descriptor{2}{"Version"}.(@VInf2?" (".join(", ", reverse(@VInf2)).")":"")."
Language".$COMMON_LANGUAGE{1}."
ModeExtended
SubjectBinary Compatibility
SubjectSource Compatibility
\n"; # test results $TestResults = "

Test Results


\n"; $TestResults .= ""; if(my @Headers = keys(%{$Registered_Headers{1}})) { my $Headers_Link = "".($#Headers + 1).""; $TestResults .= "\n"; } elsif($CheckObjectsOnly) { $TestResults .= "\n"; } if(my @Sources = keys(%{$Registered_Sources{1}})) { my $Src_Link = "".($#Sources + 1).""; $TestResults .= "\n"; } if(not $ExtendedCheck) { my $Libs_Link = "0"; $Libs_Link = "".keys(%{$Library_Symbol{1}})."" if(keys(%{$Library_Symbol{1}})>0); $TestResults .= "\n"; } $TestResults .= "\n"; my $META_DATA = "verdict:".$RESULT{$Level}{"Verdict"}.";"; if($JoinReport) { $META_DATA = "kind:".lc($Level).";".$META_DATA; } $TestResults .= ""; if($RESULT{$Level}{"Verdict"} eq "incompatible") { $TestResults .= ""; } else { $TestResults .= ""; } $TestResults .= "\n"; $TestResults .= "
Total Header Files".$Headers_Link."
Total Header Files0 (not analyzed)
Total Source Files".$Src_Link."
Total ".get_ObjTitle()."".($CheckHeadersOnly?"0 (not analyzed)":$Libs_Link)."
Total Symbols / Types".(keys(%{$CheckedSymbols{$Level}}) - keys(%ExtendedSymbols))." / ".$TotalTypes."
VerdictIncompatible
(".$RESULT{$Level}{"Affected"}."%)
Compatible
\n"; $META_DATA .= "affected:".$RESULT{$Level}{"Affected"}.";";# in percents # problem summary $Problem_Summary = "

Problem Summary


\n"; $Problem_Summary .= ""; $Problem_Summary .= ""; my $Added_Link = "0"; if($Added>0) { if($JoinReport) { $Added_Link = "$Added"; } else { $Added_Link = "$Added"; } } $META_DATA .= "added:$Added;"; $Problem_Summary .= "$Added_Link\n"; my $Removed_Link = "0"; if($Removed>0) { if($JoinReport) { $Removed_Link = "$Removed" } else { $Removed_Link = "$Removed" } } $META_DATA .= "removed:$Removed;"; $Problem_Summary .= ""; $Problem_Summary .= "$Removed_Link\n"; my $TH_Link = "0"; $TH_Link = "$T_Problems_High" if($T_Problems_High>0); $TH_Link = "n/a" if($CheckObjectsOnly); $META_DATA .= "type_problems_high:$T_Problems_High;"; $Problem_Summary .= ""; $Problem_Summary .= "$TH_Link\n"; my $TM_Link = "0"; $TM_Link = "$T_Problems_Medium" if($T_Problems_Medium>0); $TM_Link = "n/a" if($CheckObjectsOnly); $META_DATA .= "type_problems_medium:$T_Problems_Medium;"; $Problem_Summary .= "$TM_Link\n"; my $TL_Link = "0"; $TL_Link = "$T_Problems_Low" if($T_Problems_Low>0); $TL_Link = "n/a" if($CheckObjectsOnly); $META_DATA .= "type_problems_low:$T_Problems_Low;"; $Problem_Summary .= "$TL_Link\n"; my $IH_Link = "0"; $IH_Link = "$I_Problems_High" if($I_Problems_High>0); $IH_Link = "n/a" if($CheckObjectsOnly); $META_DATA .= "interface_problems_high:$I_Problems_High;"; $Problem_Summary .= ""; $Problem_Summary .= "$IH_Link\n"; my $IM_Link = "0"; $IM_Link = "$I_Problems_Medium" if($I_Problems_Medium>0); $IM_Link = "n/a" if($CheckObjectsOnly); $META_DATA .= "interface_problems_medium:$I_Problems_Medium;"; $Problem_Summary .= "$IM_Link\n"; my $IL_Link = "0"; $IL_Link = "$I_Problems_Low" if($I_Problems_Low>0); $IL_Link = "n/a" if($CheckObjectsOnly); $META_DATA .= "interface_problems_low:$I_Problems_Low;"; $Problem_Summary .= "$IL_Link\n"; my $ChangedConstants_Link = "0"; if(keys(%{$CheckedSymbols{$Level}}) and $C_Problems_Low) { $ChangedConstants_Link = "$C_Problems_Low"; } $ChangedConstants_Link = "n/a" if($CheckObjectsOnly); $META_DATA .= "changed_constants:$C_Problems_Low;"; $Problem_Summary .= "$ChangedConstants_Link\n"; if($CheckImpl and $Level eq "Binary") { my $ChangedImpl_Link = "0"; $ChangedImpl_Link = "".keys(%CompatProblems_Impl)."" if(keys(%CompatProblems_Impl)>0); $ChangedImpl_Link = "n/a" if($CheckHeadersOnly); $META_DATA .= "changed_implementation:".keys(%CompatProblems_Impl).";"; $Problem_Summary .= "$ChangedImpl_Link\n"; } # Safe Changes if($T_Other and not $CheckObjectsOnly) { my $TS_Link = "$T_Other"; $Problem_Summary .= "$TS_Link\n"; } if($I_Other and not $CheckObjectsOnly) { my $IS_Link = "$I_Other"; $Problem_Summary .= "$IS_Link\n"; } if($C_Other and not $CheckObjectsOnly) { my $CS_Link = "$C_Other"; $Problem_Summary .= "$CS_Link\n"; } $META_DATA .= "tool_version:$TOOL_VERSION"; $Problem_Summary .= "
SeverityCount
Added Symbols-
Removed SymbolsHigh
Problems with
Data Types
High
Medium
Low
Problems with
Symbols
High
Medium
Low
Problems with
Constants
Low
Problems with
Implementation
Low
Other Changes
in Data Types
-
Other Changes
in Symbols
-
Other Changes
in Constants
-
\n"; # $TestInfo = getLegend().$TestInfo; return ($TestInfo.$TestResults.$Problem_Summary, $META_DATA); } } sub getStyle($$$) { my ($Subj, $Act, $Num) = @_; my %Style = ( "A"=>"new", "R"=>"failed", "S"=>"passed", "L"=>"warning", "M"=>"failed", "H"=>"failed" ); if($Num>0) { return " class='".$Style{$Act}."'"; } return ""; } sub show_number($) { if($_[0]) { my $Num = cut_off_number($_[0], 2, 0); if($Num eq "0") { foreach my $P (3 .. 7) { $Num = cut_off_number($_[0], $P, 1); if($Num ne "0") { last; } } } if($Num eq "0") { $Num = $_[0]; } return $Num; } return $_[0]; } sub cut_off_number($$$) { my ($num, $digs_to_cut, $z) = @_; if($num!~/\./) { $num .= "."; foreach (1 .. $digs_to_cut-1) { $num .= "0"; } } elsif($num=~/\.(.+)\Z/ and length($1)<$digs_to_cut-1) { foreach (1 .. $digs_to_cut - 1 - length($1)) { $num .= "0"; } } elsif($num=~/\d+\.(\d){$digs_to_cut,}/) { $num=sprintf("%.".($digs_to_cut-1)."f", $num); } $num=~s/\.[0]+\Z//g; if($z) { $num=~s/(\.[1-9]+)[0]+\Z/$1/g; } return $num; } sub get_Report_ChangedConstants($$) { my ($TargetSeverity, $Level) = @_; my $CHANGED_CONSTANTS = ""; my %ReportMap = (); foreach my $Constant (keys(%{$CompatProblems_Constants{$Level}})) { my $Header = $Constants{1}{$Constant}{"Header"}; if(not $Header) { # added $Header = $Constants{2}{$Constant}{"Header"} } foreach my $Kind (sort {lc($a) cmp lc($b)} keys(%{$CompatProblems_Constants{$Level}{$Constant}})) { if(not defined $CompatRules{$Level}{$Kind}) { next; } if($TargetSeverity ne $CompatRules{$Level}{$Kind}{"Severity"}) { next; } $ReportMap{$Header}{$Constant}{$Kind} = 1; } } if($ReportFormat eq "xml") { # XML foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap)) { $CHANGED_CONSTANTS .= "
\n"; foreach my $Constant (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}})) { $CHANGED_CONSTANTS .= " \n"; foreach my $Kind (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}{$Constant}})) { my $Change = $CompatRules{$Level}{$Kind}{"Change"}; my $Effect = $CompatRules{$Level}{$Kind}{"Effect"}; my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"}; $CHANGED_CONSTANTS .= " \n"; $CHANGED_CONSTANTS .= " $Change\n"; $CHANGED_CONSTANTS .= " $Effect\n"; if($Overcome) { $CHANGED_CONSTANTS .= " $Overcome\n"; } $CHANGED_CONSTANTS .= " \n"; } $CHANGED_CONSTANTS .= " \n"; } $CHANGED_CONSTANTS .= "
\n"; } $CHANGED_CONSTANTS = "\n".$CHANGED_CONSTANTS."\n\n"; } else { # HTML my $Number = 0; foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap)) { $CHANGED_CONSTANTS .= "$HeaderName
\n"; foreach my $Constant (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}})) { my $Report = ""; foreach my $Kind (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}{$Constant}})) { my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, $CompatProblems_Constants{$Level}{$Constant}{$Kind}); my $Effect = $CompatRules{$Level}{$Kind}{"Effect"}; $Report .= "1".$Change."$Effect\n"; $Number += 1; } if($Report) { $Report = $ContentDivStart."".$Report."
ChangeEffect

$ContentDivEnd\n"; $Report = $ContentSpanStart."[+] ".$Constant.$ContentSpanEnd."
\n".$Report; $Report = insertIDs($Report); } $CHANGED_CONSTANTS .= $Report; } $CHANGED_CONSTANTS .= "
\n"; } if($CHANGED_CONSTANTS) { my $Title = "Problems with Constants, $TargetSeverity Severity"; if($TargetSeverity eq "Safe") { # Safe Changes $Title = "Other Changes in Constants"; } $CHANGED_CONSTANTS = "

$Title ($Number)


\n".$CHANGED_CONSTANTS.$TOP_REF."
\n"; } } return $CHANGED_CONSTANTS; } sub get_Report_Impl() { my $CHANGED_IMPLEMENTATION = ""; my %ReportMap = (); foreach my $Interface (sort keys(%CompatProblems_Impl)) { my $HeaderName = $CompleteSignature{1}{$Interface}{"Header"}; my $DyLib = $Symbol_Library{1}{$Interface}; $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1; } my $Changed_Number = 0; foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap)) { foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}})) { my %NameSpaceSymbols = (); foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) { $NameSpaceSymbols{select_Symbol_NS($Interface, 2)}{$Interface} = 1; } foreach my $NameSpace (sort keys(%NameSpaceSymbols)) { $CHANGED_IMPLEMENTATION .= getTitle($HeaderName, $DyLib, $NameSpace); my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}}); foreach my $Interface (@SortedInterfaces) { $Changed_Number += 1; my $Signature = get_Signature($Interface, 1); if($NameSpace) { $Signature=~s/\b\Q$NameSpace\E::\b//g; } $CHANGED_IMPLEMENTATION .= $ContentSpanStart.highLight_Signature_Italic_Color($Signature).$ContentSpanEnd."
\n".$ContentDivStart."[symbol: $Interface]".$CompatProblems_Impl{$Interface}{"Diff"}."

".$ContentDivEnd."\n"; } $CHANGED_IMPLEMENTATION .= "
\n"; } } } if($CHANGED_IMPLEMENTATION) { $CHANGED_IMPLEMENTATION = insertIDs($CHANGED_IMPLEMENTATION); $CHANGED_IMPLEMENTATION = "

Problems with Implementation ($Changed_Number)


\n".$CHANGED_IMPLEMENTATION.$TOP_REF."
\n"; } # clean memory %CompatProblems_Impl = (); return $CHANGED_IMPLEMENTATION; } sub getTitle($$$) { my ($Header, $Library, $NameSpace) = @_; my $Title = ""; if($Library and $Library!~/\.\w+\Z/) { $Library .= " (.$LIB_EXT)"; } if($Header and $Library) { $Title .= "$Header"; $Title .= ", $Library
\n"; } elsif($Library) { $Title .= "$Library
\n"; } elsif($Header) { $Title .= "$Header
\n"; } if($NameSpace) { $Title .= "namespace $NameSpace
\n"; } return $Title; } sub get_Report_Added($) { my $Level = $_[0]; my $ADDED_INTERFACES = ""; my %ReportMap = (); foreach my $Interface (sort keys(%{$CompatProblems{$Level}})) { foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}})) { if($Kind eq "Added_Symbol") { my $HeaderName = $CompleteSignature{2}{$Interface}{"Header"}; my $DyLib = $Symbol_Library{2}{$Interface}; if($Level eq "Source" and $ReportFormat eq "html") { # do not show library name in HTML report $DyLib = ""; } $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1; } } } if($ReportFormat eq "xml") { # XML foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap)) { $ADDED_INTERFACES .= "
\n"; foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}})) { $ADDED_INTERFACES .= " \n"; foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) { $ADDED_INTERFACES .= " $Interface\n"; } $ADDED_INTERFACES .= " \n"; } $ADDED_INTERFACES .= "
\n"; } $ADDED_INTERFACES = "\n".$ADDED_INTERFACES."\n\n"; } else { # HTML my $Added_Number = 0; foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap)) { foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}})) { my %NameSpaceSymbols = (); foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) { $NameSpaceSymbols{select_Symbol_NS($Interface, 2)}{$Interface} = 1; } foreach my $NameSpace (sort keys(%NameSpaceSymbols)) { $ADDED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace); my @SortedInterfaces = sort {lc(get_Signature($a, 2)) cmp lc(get_Signature($b, 2))} keys(%{$NameSpaceSymbols{$NameSpace}}); foreach my $Interface (@SortedInterfaces) { $Added_Number += 1; my $Signature = get_Signature($Interface, 2); if($NameSpace) { $Signature=~s/\b\Q$NameSpace\E::\b//g; } if($Interface=~/\A(_Z|\?)/) { if($Signature) { $ADDED_INTERFACES .= insertIDs($ContentSpanStart.highLight_Signature_Italic_Color($Signature).$ContentSpanEnd."
\n".$ContentDivStart."[symbol: $Interface]

".$ContentDivEnd."\n"); } else { $ADDED_INTERFACES .= "".$Interface."
\n"; } } else { if($Signature) { $ADDED_INTERFACES .= "".highLight_Signature_Italic_Color($Signature)."
\n"; } else { $ADDED_INTERFACES .= "".$Interface."
\n"; } } } $ADDED_INTERFACES .= "
\n"; } } } if($ADDED_INTERFACES) { my $Anchor = ""; if($JoinReport) { $Anchor = ""; } $ADDED_INTERFACES = $Anchor."

Added Symbols ($Added_Number)


\n".$ADDED_INTERFACES.$TOP_REF."
\n"; } } return $ADDED_INTERFACES; } sub get_Report_Removed($) { my $Level = $_[0]; my $REMOVED_INTERFACES = ""; my %ReportMap = (); foreach my $Symbol (sort keys(%{$CompatProblems{$Level}})) { foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}})) { if($Kind eq "Removed_Symbol") { my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"}; my $DyLib = $Symbol_Library{1}{$Symbol}; if($Level eq "Source" and $ReportFormat eq "html") { # do not show library name in HTML report $DyLib = ""; } $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1; } } } if($ReportFormat eq "xml") { # XML foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap)) { $REMOVED_INTERFACES .= "
\n"; foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}})) { $REMOVED_INTERFACES .= " \n"; foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) { $REMOVED_INTERFACES .= " $Symbol\n"; } $REMOVED_INTERFACES .= " \n"; } $REMOVED_INTERFACES .= "
\n"; } $REMOVED_INTERFACES = "\n".$REMOVED_INTERFACES."\n\n"; } else { # HTML my $Removed_Number = 0; foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap)) { foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}})) { my %NameSpaceSymbols = (); foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) { $NameSpaceSymbols{select_Symbol_NS($Interface, 1)}{$Interface} = 1; } foreach my $NameSpace (sort keys(%NameSpaceSymbols)) { $REMOVED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace); my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}}); foreach my $Symbol (@SortedInterfaces) { $Removed_Number += 1; my $SubReport = ""; my $Signature = get_Signature($Symbol, 1); if($NameSpace) { $Signature=~s/\b\Q$NameSpace\E::\b//g; } if($Symbol=~/\A(_Z|\?)/) { if($Signature) { $REMOVED_INTERFACES .= insertIDs($ContentSpanStart.highLight_Signature_Italic_Color($Signature).$ContentSpanEnd."
\n".$ContentDivStart."[symbol: $Symbol]

".$ContentDivEnd."\n"); } else { $REMOVED_INTERFACES .= "".$Symbol."
\n"; } } else { if($Signature) { $REMOVED_INTERFACES .= "".highLight_Signature_Italic_Color($Signature)."
\n"; } else { $REMOVED_INTERFACES .= "".$Symbol."
\n"; } } } } $REMOVED_INTERFACES .= "
\n"; } } if($REMOVED_INTERFACES) { my $Anchor = ""; if($JoinReport) { $Anchor = ""; } $REMOVED_INTERFACES = $Anchor."

Removed Symbols ($Removed_Number)


\n".$REMOVED_INTERFACES.$TOP_REF."
\n"; } } return $REMOVED_INTERFACES; } sub getXmlParams($$) { my ($Content, $Problem) = @_; return "" if(not $Content or not $Problem); my %XMLparams = (); foreach my $Attr (sort {$b cmp $a} keys(%{$Problem})) { my $Macro = "\@".lc($Attr); if($Content=~/\Q$Macro\E/) { $XMLparams{lc($Attr)} = $Problem->{$Attr}; } } my @PString = (); foreach my $P (sort {$b cmp $a} keys(%XMLparams)) { push(@PString, $P."=\"".xmlSpecChars($XMLparams{$P})."\""); } if(@PString) { return " ".join(" ", @PString); } else { return ""; } } sub addMarkup($) { my $Content = $_[0]; # auto-markup $Content=~s/\n[ ]*//; # spaces $Content=~s!(\@\w+\s*\(\@\w+\))!$1!g; # @old_type (@old_size) $Content=~s!(... \(\w+\))!$1!g; # ... (va_list) $Content=~s!(.+?)!$1!g; $Content=~s!([2-9]\))!
$1!g; # 1), 2), ... if($Content=~/\ANOTE:/) { # notes $Content=~s!(NOTE):!$1:!g; } else { $Content=~s!(NOTE):!
$1:!g; } $Content=~s! (out)-! $1-!g; # out-parameters my @Keywords = ( "void", "const", "static", "restrict", "volatile", "register", "virtual" ); my $MKeys = join("|", @Keywords); foreach (@Keywords) { $MKeys .= "|non-".$_; } $Content=~s!(added\s*|to\s*|from\s*|became\s*)($MKeys)([^\w-]|\Z)!$1$2$3!ig; # intrinsic types, modifiers # Markdown $Content=~s!\*\*([\w\-]+)\*\*!$1!ig; $Content=~s!\*([\w\-]+)\*!$1!ig; return $Content; } sub applyMacroses($$$$) { my ($Level, $Kind, $Content, $Problem) = @_; return "" if(not $Content or not $Problem); $Problem->{"Word_Size"} = $WORD_SIZE{2}; $Content = addMarkup($Content); # macros foreach my $Attr (sort {$b cmp $a} keys(%{$Problem})) { my $Macro = "\@".lc($Attr); my $Value = $Problem->{$Attr}; if(not defined $Value or $Value eq "") { next; } if($Value=~/\s\(/ and $Value!~/['"]/) { # functions $Value=~s/\s*\[[\w\-]+\]//g; # remove quals $Value=~s/\s\w+(\)|,)/$1/g; # remove parameter names $Value = black_name($Value); } elsif($Value=~/\s/) { $Value = "".htmlSpecChars($Value).""; } elsif($Value=~/\A\d+\Z/ and ($Attr eq "Old_Size" or $Attr eq "New_Size")) { # bits to bytes if($Value % $BYTE_SIZE) { # bits if($Value==1) { $Value = "".$Value." bit"; } else { $Value = "".$Value." bits"; } } else { # bytes $Value /= $BYTE_SIZE; if($Value==1) { $Value = "".$Value." byte"; } else { $Value = "".$Value." bytes"; } } } else { $Value = "".htmlSpecChars($Value).""; } $Content=~s/\Q$Macro\E/$Value/g; } if($Content=~/(\A|[^\@\w])\@\w/) { if(not $IncompleteRules{$Level}{$Kind}) { # only one warning printMsg("WARNING", "incomplete rule \"$Kind\" (\"$Level\")"); $IncompleteRules{$Level}{$Kind} = 1; } } return $Content; } sub get_Report_SymbolProblems($$) { my ($TargetSeverity, $Level) = @_; my $INTERFACE_PROBLEMS = ""; my (%ReportMap, %SymbolChanges) = (); foreach my $Symbol (sort keys(%{$CompatProblems{$Level}})) { my ($SN, $SS, $SV) = separate_symbol($Symbol); if($SV and defined $CompatProblems{$Level}{$SN}) { next; } foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}})) { if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols" and $Kind ne "Added_Symbol" and $Kind ne "Removed_Symbol") { my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"}; my $DyLib = $Symbol_Library{1}{$Symbol}; if(not $DyLib and my $VSym = $SymVer{1}{$Symbol}) { # Symbol with Version $DyLib = $Symbol_Library{1}{$VSym}; } if(not $DyLib) { # const global data $DyLib = ""; } if($Level eq "Source" and $ReportFormat eq "html") { # do not show library name in HTML report $DyLib = ""; } %{$SymbolChanges{$Symbol}{$Kind}} = %{$CompatProblems{$Level}{$Symbol}{$Kind}}; foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}})) { my $Severity = $CompatRules{$Level}{$Kind}{"Severity"}; if($Severity ne $TargetSeverity) { delete($SymbolChanges{$Symbol}{$Kind}{$Location}); } } if(not keys(%{$SymbolChanges{$Symbol}{$Kind}})) { delete($SymbolChanges{$Symbol}{$Kind}); next; } $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1; } } if(not keys(%{$SymbolChanges{$Symbol}})) { delete($SymbolChanges{$Symbol}); } } if($ReportFormat eq "xml") { # XML foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap)) { $INTERFACE_PROBLEMS .= "
\n"; foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}})) { $INTERFACE_PROBLEMS .= " \n"; my @SortedInterfaces = sort {lc($tr_name{$a}?$tr_name{$a}:$a) cmp lc($tr_name{$b}?$tr_name{$b}:$b)} keys(%{$ReportMap{$HeaderName}{$DyLib}}); foreach my $Symbol (@SortedInterfaces) { $INTERFACE_PROBLEMS .= " \n"; foreach my $Kind (keys(%{$SymbolChanges{$Symbol}})) { foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}})) { my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}}; $Problem{"Param_Pos"} = showPos($Problem{"Param_Pos"}); $INTERFACE_PROBLEMS .= " \n"; my $Change = $CompatRules{$Level}{$Kind}{"Change"}; $INTERFACE_PROBLEMS .= " $Change\n"; my $Effect = $CompatRules{$Level}{$Kind}{"Effect"}; $INTERFACE_PROBLEMS .= " $Effect\n"; if(my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"}) { $INTERFACE_PROBLEMS .= " $Overcome\n"; } $INTERFACE_PROBLEMS .= " \n"; } } $INTERFACE_PROBLEMS .= " \n"; } $INTERFACE_PROBLEMS .= " \n"; } $INTERFACE_PROBLEMS .= "
\n"; } $INTERFACE_PROBLEMS = "\n".$INTERFACE_PROBLEMS."\n\n"; } else { # HTML my $ProblemsNum = 0; foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap)) { foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}})) { my (%NameSpaceSymbols, %NewSignature) = (); foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) { $NameSpaceSymbols{select_Symbol_NS($Symbol, 1)}{$Symbol} = 1; } foreach my $NameSpace (sort keys(%NameSpaceSymbols)) { $INTERFACE_PROBLEMS .= getTitle($HeaderName, $DyLib, $NameSpace); my @SortedInterfaces = sort {lc($tr_name{$a}?$tr_name{$a}:$a) cmp lc($tr_name{$b}?$tr_name{$b}:$b)} keys(%{$NameSpaceSymbols{$NameSpace}}); foreach my $Symbol (@SortedInterfaces) { my $Signature = get_Signature($Symbol, 1); my $SYMBOL_REPORT = ""; my $ProblemNum = 1; foreach my $Kind (keys(%{$SymbolChanges{$Symbol}})) { foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}})) { my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}}; $Problem{"Param_Pos"} = showPos($Problem{"Param_Pos"}); if($Problem{"New_Signature"}) { $NewSignature{$Symbol} = $Problem{"New_Signature"}; } if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem)) { my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem); $SYMBOL_REPORT .= "$ProblemNum".$Change."".$Effect."\n"; $ProblemNum += 1; $ProblemsNum += 1; } } } $ProblemNum -= 1; if($SYMBOL_REPORT) { $INTERFACE_PROBLEMS .= $ContentSpanStart."[+] "; if($Signature) { $INTERFACE_PROBLEMS .= highLight_Signature_Italic_Color($Signature); } else { $INTERFACE_PROBLEMS .= $Symbol; } $INTERFACE_PROBLEMS .= " ($ProblemNum)".$ContentSpanEnd."
\n"; $INTERFACE_PROBLEMS .= $ContentDivStart."\n"; if($NewSignature{$Symbol}) { # argument list changed to $INTERFACE_PROBLEMS .= "\nchanged to:
".highLight_Signature_Italic_Color($NewSignature{$Symbol})."
\n"; } if($Symbol=~/\A(_Z|\?)/) { $INTERFACE_PROBLEMS .= "    [symbol: $Symbol]
\n"; } $INTERFACE_PROBLEMS .= "$SYMBOL_REPORT
ChangeEffect

\n"; $INTERFACE_PROBLEMS .= $ContentDivEnd; if($NameSpace) { $INTERFACE_PROBLEMS=~s/\b\Q$NameSpace\E::\b//g; } } } $INTERFACE_PROBLEMS .= "
"; } } } if($INTERFACE_PROBLEMS) { $INTERFACE_PROBLEMS = insertIDs($INTERFACE_PROBLEMS); my $Title = "Problems with Symbols, $TargetSeverity Severity"; if($TargetSeverity eq "Safe") { # Safe Changes $Title = "Other Changes in Symbols"; } $INTERFACE_PROBLEMS = "\n

$Title ($ProblemsNum)


\n".$INTERFACE_PROBLEMS.$TOP_REF."
\n"; } } return $INTERFACE_PROBLEMS; } sub get_Report_TypeProblems($$) { my ($TargetSeverity, $Level) = @_; my $TYPE_PROBLEMS = ""; my (%ReportMap, %TypeChanges) = (); foreach my $Interface (sort keys(%{$CompatProblems{$Level}})) { foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}})) { if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types") { foreach my $Location (sort {cmpLocations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}})) { my $TypeName = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"}; my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"}; my $Severity = $CompatRules{$Level}{$Kind}{"Severity"}; if($Severity eq "Safe" and $TargetSeverity ne "Safe") { next; } if(my $MaxSeverity = $Type_MaxSeverity{$Level}{$TypeName}{$Kind}{$Target}) { if($Severity_Val{$MaxSeverity}>$Severity_Val{$Severity}) { # select a problem with the highest priority next; } } $TypeChanges{$TypeName}{$Kind}{$Location} = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}; } } } } my %Kinds_Locations = (); foreach my $TypeName (keys(%TypeChanges)) { my %Kind_Target = (); foreach my $Kind (sort keys(%{$TypeChanges{$TypeName}})) { foreach my $Location (sort {cmpLocations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}})) { my $Severity = $CompatRules{$Level}{$Kind}{"Severity"}; if($Severity ne $TargetSeverity) { # other priority delete($TypeChanges{$TypeName}{$Kind}{$Location}); next; } $Kinds_Locations{$TypeName}{$Kind}{$Location} = 1; my $Target = $TypeChanges{$TypeName}{$Kind}{$Location}{"Target"}; if($Kind_Target{$Kind}{$Target}) { # duplicate target delete($TypeChanges{$TypeName}{$Kind}{$Location}); next; } $Kind_Target{$Kind}{$Target} = 1; my $HeaderName = $TypeInfo{1}{$TName_Tid{1}{$TypeName}}{"Header"}; $ReportMap{$HeaderName}{$TypeName} = 1; } if(not keys(%{$TypeChanges{$TypeName}{$Kind}})) { delete($TypeChanges{$TypeName}{$Kind}); } } if(not keys(%{$TypeChanges{$TypeName}})) { delete($TypeChanges{$TypeName}); } } my @Symbols = sort {lc($tr_name{$a}?$tr_name{$a}:$a) cmp lc($tr_name{$b}?$tr_name{$b}:$b)} keys(%{$CompatProblems{$Level}}); if($ReportFormat eq "xml") { # XML foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap)) { $TYPE_PROBLEMS .= "
\n"; foreach my $TypeName (keys(%{$ReportMap{$HeaderName}})) { $TYPE_PROBLEMS .= " \n"; foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}})) { foreach my $Location (sort {cmpLocations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}})) { my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}}; $TYPE_PROBLEMS .= " \n"; my $Change = $CompatRules{$Level}{$Kind}{"Change"}; $TYPE_PROBLEMS .= " $Change\n"; my $Effect = $CompatRules{$Level}{$Kind}{"Effect"}; $TYPE_PROBLEMS .= " $Effect\n"; if(my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"}) { $TYPE_PROBLEMS .= " $Overcome\n"; } $TYPE_PROBLEMS .= " \n"; } } $TYPE_PROBLEMS .= getAffectedSymbols($Level, $TypeName, $Kinds_Locations{$TypeName}, \@Symbols); if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) { $TYPE_PROBLEMS .= showVTables($TypeName); } $TYPE_PROBLEMS .= " \n"; } $TYPE_PROBLEMS .= "
\n"; } $TYPE_PROBLEMS = "\n".$TYPE_PROBLEMS."\n\n"; } else { # HTML my $ProblemsNum = 0; foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap)) { my (%NameSpace_Type) = (); foreach my $TypeName (keys(%{$ReportMap{$HeaderName}})) { $NameSpace_Type{select_Type_NS($TypeName, 1)}{$TypeName} = 1; } foreach my $NameSpace (sort keys(%NameSpace_Type)) { $TYPE_PROBLEMS .= getTitle($HeaderName, "", $NameSpace); my @SortedTypes = sort {lc(show_Type($a, 0, 1)) cmp lc(show_Type($b, 0, 1))} keys(%{$NameSpace_Type{$NameSpace}}); foreach my $TypeName (@SortedTypes) { my $ProblemNum = 1; my $TYPE_REPORT = ""; foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}})) { foreach my $Location (sort {cmpLocations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}})) { my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}}; if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem)) { my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem); $TYPE_REPORT .= "$ProblemNum".$Change."$Effect\n"; $ProblemNum += 1; $ProblemsNum += 1; } } } $ProblemNum -= 1; if($TYPE_REPORT) { my $Affected = getAffectedSymbols($Level, $TypeName, $Kinds_Locations{$TypeName}, \@Symbols); my $ShowVTables = ""; if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) { $ShowVTables = showVTables($TypeName); } $TYPE_PROBLEMS .= $ContentSpanStart."[+] ".show_Type($TypeName, 1, 1)." ($ProblemNum)".$ContentSpanEnd; $TYPE_PROBLEMS .= "
\n".$ContentDivStart."\n"; $TYPE_PROBLEMS .= "\n"; $TYPE_PROBLEMS .= "".$TYPE_REPORT."
ChangeEffect
\n"; $TYPE_PROBLEMS .= $ShowVTables.$Affected."

".$ContentDivEnd."\n"; if($NameSpace) { $TYPE_PROBLEMS=~s/\b\Q$NameSpace\E::(\w|\~)/$1/g; } } } $TYPE_PROBLEMS .= "
"; } } if($TYPE_PROBLEMS) { $TYPE_PROBLEMS = insertIDs($TYPE_PROBLEMS); my $Title = "Problems with Data Types, $TargetSeverity Severity"; if($TargetSeverity eq "Safe") { # Safe Changes $Title = "Other Changes in Data Types"; } $TYPE_PROBLEMS = "\n

$Title ($ProblemsNum)


\n".$TYPE_PROBLEMS.$TOP_REF."
\n"; } } return $TYPE_PROBLEMS; } sub show_Type($$$) { my ($Name, $Html, $LibVersion) = @_; my $TType = $TypeInfo{$LibVersion}{$TName_Tid{$LibVersion}{$Name}}{"Type"}; $TType = lc($TType); if($TType=~/struct|union|enum/) { $Name=~s/\A\Q$TType\E //g; } if($Html) { $Name = "".$TType." ".htmlSpecChars($Name); } else { $Name = $TType." ".$Name; } return $Name; } sub get_Anchor($$$) { my ($Kind, $Level, $Severity) = @_; if($JoinReport) { if($Severity eq "Safe") { return "Other_".$Level."_Changes_In_".$Kind."s"; } else { return $Kind."_".$Level."_Problems_".$Severity; } } else { if($Severity eq "Safe") { return "Other_Changes_In_".$Kind."s"; } else { return $Kind."_Problems_".$Severity; } } } sub showVTables($) { my $TypeName = $_[0]; my $TypeId1 = $TName_Tid{1}{$TypeName}; my %Type1 = get_Type($TypeId1, 1); if(defined $Type1{"VTable"} and keys(%{$Type1{"VTable"}})) { my $TypeId2 = $TName_Tid{2}{$TypeName}; my %Type2 = get_Type($TypeId2, 2); if(defined $Type2{"VTable"} and keys(%{$Type2{"VTable"}})) { my %Indexes = map {$_=>1} (keys(%{$Type1{"VTable"}}), keys(%{$Type2{"VTable"}})); my %Entries = (); foreach my $Index (sort {int($a)<=>int($b)} (keys(%Indexes))) { $Entries{$Index}{"E1"} = simpleVEntry($Type1{"VTable"}{$Index}); $Entries{$Index}{"E2"} = simpleVEntry($Type2{"VTable"}{$Index}); } my $VTABLES = ""; if($ReportFormat eq "xml") { # XML $VTABLES .= " \n"; foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries))) { $VTABLES .= " \n"; $VTABLES .= " ".xmlSpecChars($Entries{$Index}{"E1"})."\n"; $VTABLES .= " ".xmlSpecChars($Entries{$Index}{"E2"})."\n"; $VTABLES .= " \n"; } $VTABLES .= " \n\n"; } else { # HTML $VTABLES .= ""; $VTABLES .= ""; $VTABLES .= ""; $VTABLES .= ""; foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries))) { my ($Color1, $Color2) = ("", ""); if($Entries{$Index}{"E1"} ne $Entries{$Index}{"E2"}) { if($Entries{$Index}{"E1"}) { $Color1 = " class='failed'"; $Color2 = " class='failed'"; } else { $Color2 = " class='warning'"; } } $VTABLES .= "\n"; $VTABLES .= "".htmlSpecChars($Entries{$Index}{"E1"})."\n"; $VTABLES .= "".htmlSpecChars($Entries{$Index}{"E2"})."\n"; } $VTABLES .= "
OffsetVirtual Table (Old) - ".(keys(%{$Type1{"VTable"}}))." entriesVirtual Table (New) - ".(keys(%{$Type2{"VTable"}}))." entries
".$Index."

\n"; $VTABLES = $ContentDivStart.$VTABLES.$ContentDivEnd; $VTABLES = $ContentSpanStart_Info."[+] show v-table (old and new)".$ContentSpanEnd."
\n".$VTABLES; } return $VTABLES; } } return ""; } sub simpleVEntry($) { my $VEntry = $_[0]; if(not defined $VEntry or $VEntry eq "") { return ""; } $VEntry=~s/\A(.+)::(_ZThn.+)\Z/$2/; # thunks $VEntry=~s/_ZTI\w+/typeinfo/g; # typeinfo if($VEntry=~/\A_ZThn.+\Z/) { $VEntry = "non-virtual thunk"; } $VEntry=~s/\A\(int \(\*\)\(...\)\)\s*([a-z_])/$1/i; # support for old GCC versions $VEntry=~s/\A0u\Z/(int (*)(...))0/; $VEntry=~s/\A4294967268u\Z/(int (*)(...))-0x000000004/; $VEntry=~s/\A&_Z\Z/& _Z/; $VEntry=~s/([^:]+)::\~([^:]+)\Z/~$1/; # destructors return $VEntry; } sub adjustParamPos($$$) { my ($Pos, $Symbol, $LibVersion) = @_; if(defined $CompleteSignature{$LibVersion}{$Symbol}) { if(not $CompleteSignature{$LibVersion}{$Symbol}{"Static"} and $CompleteSignature{$LibVersion}{$Symbol}{"Class"}) { return $Pos-1; } return $Pos; } return undef; } sub getParamPos($$$) { my ($Name, $Symbol, $LibVersion) = @_; if(defined $CompleteSignature{$LibVersion}{$Symbol} and defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}) { my $Info = $CompleteSignature{$LibVersion}{$Symbol}; foreach (keys(%{$Info->{"Param"}})) { if($Info->{"Param"}{$_}{"name"} eq $Name) { return $_; } } } return undef; } sub getParamName($) { my $Loc = $_[0]; $Loc=~s/\->.*//g; return $Loc; } sub getAffectedSymbols($$$$) { my ($Level, $Target_TypeName, $Kinds_Locations, $Syms) = @_; my $LIMIT = 1000; if(defined $AffectLimit) { $LIMIT = $AffectLimit; } else { if($#{$Syms}>=1999) { # reduce size of the report $AffectLimit = 10; printMsg("WARNING", "reducing limit of affected symbols shown in the report to $AffectLimit"); $LIMIT = $AffectLimit; } } my %SProblems = (); LOOP: foreach my $Symbol (@{$Syms}) { if(index($Symbol, "_Z")==0 and $Symbol=~/(C2|D2|D0)[EI]/) { # duplicated problems for C2 constructors, D2 and D0 destructors next; } my ($MinPath_Length, $ProblemLocation_Last) = (-1, ""); my $Severity_Max = 0; foreach my $Kind (keys(%{$Kinds_Locations})) { if(not defined $CompatProblems{$Level}{$Symbol} or not defined $CompatProblems{$Level}{$Symbol}{$Kind}) { next; } foreach my $Location (keys(%{$Kinds_Locations->{$Kind}})) { if(keys(%SProblems)>$LIMIT) { last LOOP; } if(not defined $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}) { next; } my ($SN, $SS, $SV) = separate_symbol($Symbol); if($Level eq "Source") { # remove symbol version $Symbol=$SN; } if($SV and defined $CompatProblems{$Level}{$SN} and defined $CompatProblems{$Level}{$SN}{$Kind}{$Location}) { # duplicated problems for versioned symbols next; } my $Type_Name = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Type_Name"}; if($Type_Name ne $Target_TypeName) { next; } my $PName = getParamName($Location); my $PPos = adjustParamPos(getParamPos($PName, $Symbol, 1), $Symbol, 1); my $Severity = $CompatRules{$Level}{$Kind}{"Severity"}; my $Path_Length = 0; my $ProblemLocation = $Location; if($Type_Name) { $ProblemLocation=~s/->\Q$Type_Name\E\Z//g; } while($ProblemLocation=~/\-\>/g) { $Path_Length += 1; } if($MinPath_Length==-1 or ($Path_Length<=$MinPath_Length and $Severity_Val{$Severity}>$Severity_Max) or (cmpLocations($ProblemLocation, $ProblemLocation_Last) and $Severity_Val{$Severity}==$Severity_Max)) { $MinPath_Length = $Path_Length; $Severity_Max = $Severity_Val{$Severity}; $ProblemLocation_Last = $ProblemLocation; %{$SProblems{$Symbol}} = ( "Descr"=>getAffectDesc($Level, $Symbol, $Kind, $Location), "Severity_Max"=>$Severity_Max, "Signature"=>get_Signature($Symbol, 1), "Position"=>$PPos, "Param_Name"=>$PName, "Location"=>$Location ); } } } } my @Symbols = keys(%SProblems); @Symbols = sort {lc($tr_name{$a}?$tr_name{$a}:$a) cmp lc($tr_name{$b}?$tr_name{$b}:$b)} @Symbols; @Symbols = sort {$SProblems{$b}{"Severity_Max"}<=>$SProblems{$a}{"Severity_Max"}} @Symbols; if($#Symbols+1>$LIMIT) { # remove last element pop(@Symbols); } my $Affected = ""; if($ReportFormat eq "xml") { # XML $Affected .= " \n"; foreach my $Symbol (@Symbols) { my $Param_Name = $SProblems{$Symbol}{"Param_Name"}; my $Description = $SProblems{$Symbol}{"Descr"}; my $Location = $SProblems{$Symbol}{"Location"}; my $Target = ""; if($Param_Name) { $Target .= " param=\"$Param_Name\""; $Description=~s/parameter $Param_Name /parameter \@param /; } elsif($Location=~/\Aretval(\-|\Z)/i) { $Target .= " affected=\"retval\""; } elsif($Location=~/\Athis(\-|\Z)/i) { $Target .= " affected=\"this\""; } if($Description=~s/\AField ([^\s]+) /Field \@field /) { $Target .= " field=\"$1\""; } $Affected .= " \n"; $Affected .= " ".xmlSpecChars($Description)."\n"; $Affected .= " \n"; } $Affected .= " \n"; } else { # HTML foreach my $Symbol (@Symbols) { my $Description = $SProblems{$Symbol}{"Descr"}; my $Signature = $SProblems{$Symbol}{"Signature"}; my $Pos = $SProblems{$Symbol}{"Position"}; $Affected .= "".highLight_Signature_PPos_Italic($Signature, $Pos, 1, 0, 0)."
".htmlSpecChars($Description)."
\n"; } if(keys(%SProblems)>$LIMIT) { $Affected .= " ...
"; # and others ... } $Affected = "
".$Affected."
"; if($Affected) { $Affected = $ContentDivStart.$Affected.$ContentDivEnd; $Affected = $ContentSpanStart_Affected."[+] affected symbols (".(keys(%SProblems)>$LIMIT?">".$LIMIT:keys(%SProblems)).")".$ContentSpanEnd.$Affected; } } return $Affected; } sub cmpLocations($$) { my ($L1, $L2) = @_; if($L2=~/\A(retval|this)\b/ and $L1!~/\A(retval|this)\b/) { if($L1!~/\-\>/) { return 1; } elsif($L2=~/\-\>/) { return 1; } } return 0; } sub getAffectDesc($$$$) { my ($Level, $Symbol, $Kind, $Location) = @_; my %Problem = %{$CompatProblems{$Level}{$Symbol}{$Kind}{$Location}}; my $Location_I = $Location; $Location=~s/\A(.*)\-\>(.+?)\Z/$1/; # without the latest affected field my @Sentence = (); if($Kind eq "Overridden_Virtual_Method" or $Kind eq "Overridden_Virtual_Method_B") { push(@Sentence, "The method '".$Problem{"New_Value"}."' will be called instead of this method."); } elsif($CompatRules{$Level}{$Kind}{"Kind"} eq "Types") { my %SymInfo = %{$CompleteSignature{1}{$Symbol}}; if($Location eq "this" or $Kind=~/(\A|_)Virtual(_|\Z)/) { my $METHOD_TYPE = $SymInfo{"Constructor"}?"constructor":"method"; my $ClassName = $TypeInfo{1}{$SymInfo{"Class"}}{"Name"}; if($ClassName eq $Problem{"Type_Name"}) { push(@Sentence, "This $METHOD_TYPE is from \'".$Problem{"Type_Name"}."\' class."); } else { push(@Sentence, "This $METHOD_TYPE is from derived class \'".$ClassName."\'."); } } else { my $TypeID = undef; if($Location=~/retval/) { # return value if(index($Location, "->")!=-1) { push(@Sentence, "Field \'".$Location."\' in return value"); } else { push(@Sentence, "Return value"); } $TypeID = $SymInfo{"Return"}; } elsif($Location=~/this/) { # "this" pointer if(index($Location, "->")!=-1) { push(@Sentence, "Field \'".$Location."\' in the object of this method"); } else { push(@Sentence, "\'this\' pointer"); } $TypeID = $SymInfo{"Class"}; } else { # parameters my $PName = getParamName($Location); my $PPos = getParamPos($PName, $Symbol, 1); if(index($Location, "->")!=-1) { push(@Sentence, "Field \'".$Location."\' in ".showPos(adjustParamPos($PPos, $Symbol, 1))." parameter"); } else { push(@Sentence, showPos(adjustParamPos($PPos, $Symbol, 1))." parameter"); } if($PName) { push(@Sentence, "\'".$PName."\'"); } $TypeID = $SymInfo{"Param"}{$PPos}{"type"}; } if($Location!~/this/) { if(my %PureType = get_PureType($TypeID, $TypeInfo{1})) { if($PureType{"Type"} eq "Pointer") { push(@Sentence, "(pointer)"); } elsif($PureType{"Type"} eq "Ref") { push(@Sentence, "(reference)"); } } } if($Location eq "this") { push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'."); } else { my $Location_T = $Location; $Location_T=~s/\A\w+(\->|\Z)//; # location in type my $TypeID_Problem = $TypeID; if($Location_T) { $TypeID_Problem = getFieldType($Location_T, $TypeID, 1); } if($TypeInfo{1}{$TypeID_Problem}{"Name"} eq $Problem{"Type_Name"}) { push(@Sentence, "has type \'".$Problem{"Type_Name"}."\'."); } else { push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'."); } } } } if($ExtendedSymbols{$Symbol}) { push(@Sentence, " This is a symbol from an external library that may use the \'$TargetLibraryName\' library and change the ABI after recompiling."); } my $Sent = join(" ", @Sentence); if($ReportFormat eq "xml") { $Sent=~s/->/./g; $Sent=~s/'//g; } return $Sent; } sub getFieldType($$$) { my ($Location, $TypeId, $LibVersion) = @_; my @Fields = split(/\->/, $Location); foreach my $Name (@Fields) { my %Info = get_BaseType($TypeId, $LibVersion); foreach my $Pos (keys(%{$Info{"Memb"}})) { if($Info{"Memb"}{$Pos}{"name"} eq $Name) { $TypeId = $Info{"Memb"}{$Pos}{"type"}; last; } } } return $TypeId; } sub get_XmlSign($$) { my ($Symbol, $LibVersion) = @_; my $Info = $CompleteSignature{$LibVersion}{$Symbol}; my $Report = ""; foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$Info->{"Param"}})) { my $Name = $Info->{"Param"}{$Pos}{"name"}; my $Type = $Info->{"Param"}{$Pos}{"type"}; my $TypeName = $TypeInfo{$LibVersion}{$Type}{"Name"}; foreach my $Typedef (keys(%ChangedTypedef)) { if(my $Base = $Typedef_BaseName{$LibVersion}{$Typedef}) { $TypeName=~s/\b\Q$Typedef\E\b/$Base/g; } } $Report .= " \n"; $Report .= " ".$Name."\n"; $Report .= " ".xmlSpecChars($TypeName)."\n"; $Report .= " \n"; } if(my $Return = $Info->{"Return"}) { my $RTName = $TypeInfo{$LibVersion}{$Return}{"Name"}; $Report .= " \n"; $Report .= " ".xmlSpecChars($RTName)."\n"; $Report .= " \n"; } return $Report; } sub get_Report_SymbolsInfo($) { my $Level = $_[0]; my $Report = "\n"; foreach my $Symbol (sort keys(%{$CompatProblems{$Level}})) { my ($SN, $SS, $SV) = separate_symbol($Symbol); if($SV and defined $CompatProblems{$Level}{$SN}) { next; } $Report .= " \n"; my ($S1, $P1, $S2, $P2) = (); if(not $AddedInt{$Level}{$Symbol}) { if(defined $CompleteSignature{1}{$Symbol} and defined $CompleteSignature{1}{$Symbol}{"Header"}) { $P1 = get_XmlSign($Symbol, 1); $S1 = get_Signature($Symbol, 1); } elsif($Symbol=~/\A(_Z|\?)/) { $S1 = $tr_name{$Symbol}; } } if(not $RemovedInt{$Level}{$Symbol}) { if(defined $CompleteSignature{2}{$Symbol} and defined $CompleteSignature{2}{$Symbol}{"Header"}) { $P2 = get_XmlSign($Symbol, 2); $S2 = get_Signature($Symbol, 2); } elsif($Symbol=~/\A(_Z|\?)/) { $S2 = $tr_name{$Symbol}; } } if($S1) { $Report .= " \n"; $Report .= $P1; $Report .= " \n"; } if($S2 and $S2 ne $S1) { $Report .= " \n"; $Report .= $P2; $Report .= " \n"; } $Report .= " \n"; } $Report .= "\n"; return $Report; } sub writeReport($$) { my ($Level, $Report) = @_; if($ReportFormat eq "xml") { $Report = "\n".$Report; } if($StdOut) { # --stdout option print STDOUT $Report; } else { my $RPath = getReportPath($Level); mkpath(get_dirname($RPath)); open(REPORT, ">", $RPath) || die ("can't open file \'$RPath\': $!\n"); print REPORT $Report; close(REPORT); if($Browse or $OpenReport) { # open in browser openReport($RPath); if($JoinReport or $DoubleReport) { if($Level eq "Binary") { # wait to open a browser sleep(1); } } } } } sub openReport($) { my $Path = $_[0]; my $Cmd = ""; if($Browse) { # user-defined browser $Cmd = $Browse." \"$Path\""; } if(not $Cmd) { # default browser if($OSgroup eq "macos") { $Cmd = "open \"$Path\""; } elsif($OSgroup eq "windows") { $Cmd = "start ".path_format($Path, $OSgroup); } else { # linux, freebsd, solaris my @Browsers = ( "x-www-browser", "sensible-browser", "firefox", "opera", "xdg-open", "lynx", "links" ); foreach my $Br (@Browsers) { if($Br = get_CmdPath($Br)) { $Cmd = $Br." \"$Path\""; last; } } } } if($Cmd) { if($Debug) { printMsg("INFO", "running $Cmd"); } if($OSgroup ne "windows" and $OSgroup ne "macos") { if($Cmd!~/lynx|links/) { $Cmd .= " >\"/dev/null\" 2>&1 &"; } } system($Cmd); } else { printMsg("ERROR", "cannot open report in browser"); } } sub getReport($) { my $Level = $_[0]; if($ReportFormat eq "xml") { # XML if($Level eq "Join") { my $Report = "\n"; $Report .= getReport("Binary"); $Report .= getReport("Source"); $Report .= "\n"; return $Report; } else { my $Report = "\n\n"; my ($Summary, $MetaData) = get_Summary($Level); $Report .= $Summary."\n"; $Report .= get_Report_Added($Level).get_Report_Removed($Level); $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level); # additional symbols info (if needed) # $Report .= get_Report_SymbolsInfo($Level); $Report .= "\n"; return $Report; } } else { # HTML my $CssStyles = readModule("Styles", "Report.css"); my $JScripts = readModule("Scripts", "Sections.js"); if($Level eq "Join") { $CssStyles .= "\n".readModule("Styles", "Tabs.css"); $JScripts .= "\n".readModule("Scripts", "Tabs.js"); my $Title = $TargetLibraryFName.": ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." compatibility report"; my $Keywords = $TargetLibraryFName.", compatibility, API, report"; my $Description = "Compatibility report for the $TargetLibraryFName $TargetComponent between ".$Descriptor{1}{"Version"}." and ".$Descriptor{2}{"Version"}." versions"; my ($BSummary, $BMetaData) = get_Summary("Binary"); my ($SSummary, $SMetaData) = get_Summary("Source"); my $Report = "\n\n".composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts).""; $Report .= get_Report_Header("Join")."
"; $Report .= "
\n$BSummary\n".get_Report_Added("Binary").get_Report_Removed("Binary").get_Report_Problems("High", "Binary").get_Report_Problems("Medium", "Binary").get_Report_Problems("Low", "Binary").get_Report_Problems("Safe", "Binary").get_SourceInfo()."


"; $Report .= "
\n$SSummary\n".get_Report_Added("Source").get_Report_Removed("Source").get_Report_Problems("High", "Source").get_Report_Problems("Medium", "Source").get_Report_Problems("Low", "Source").get_Report_Problems("Safe", "Source").get_SourceInfo()."


"; $Report .= getReportFooter($TargetLibraryFName, not $JoinReport); $Report .= "\n
\n"; return $Report; } else { my ($Summary, $MetaData) = get_Summary($Level); my $Title = $TargetLibraryFName.": ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." ".lc($Level)." compatibility report"; my $Keywords = $TargetLibraryFName.", ".lc($Level)." compatibility, API, report"; my $Description = "$Level compatibility report for the ".$TargetLibraryFName." ".$TargetComponent." between ".$Descriptor{1}{"Version"}." and ".$Descriptor{2}{"Version"}." versions"; if($Level eq "Binary") { if(getArch(1) eq getArch(2) and getArch(1) ne "unknown") { $Description .= " on ".showArch(getArch(1)); } } my $Report = "\n".composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."\n\n
\n"; $Report .= get_Report_Header($Level)."\n".$Summary."\n"; $Report .= get_Report_Added($Level).get_Report_Removed($Level); $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level); $Report .= get_SourceInfo(); $Report .= "
\n



\n"; $Report .= getReportFooter($TargetLibraryFName, not $JoinReport); $Report .= "\n
\n"; return $Report; } } } sub getLegend() { return "
added compatible
warning incompatible
\n"; } sub createReport() { if($JoinReport) { # --stdout writeReport("Join", getReport("Join")); } elsif($DoubleReport) { # default writeReport("Binary", getReport("Binary")); writeReport("Source", getReport("Source")); } elsif($BinaryOnly) { # --binary writeReport("Binary", getReport("Binary")); } elsif($SourceOnly) { # --source writeReport("Source", getReport("Source")); } } sub getReportFooter($$) { my ($LibName, $Wide) = @_; my $FooterStyle = $Wide?"width:99%":"width:97%;padding-top:3px"; my $Footer = "
Generated on ".(localtime time); # report date $Footer .= " for $LibName"; # tested library/system name $Footer .= " by ABI Compliance Checker"; # tool name my $ToolSummary = "
A tool for checking backward compatibility of a C/C++ library API  "; $Footer .= " $TOOL_VERSION  $ToolSummary
"; # tool version return $Footer; } sub get_Report_Problems($$) { my ($Severity, $Level) = @_; my $Report = get_Report_TypeProblems($Severity, $Level); if(my $SProblems = get_Report_SymbolProblems($Severity, $Level)) { $Report .= $SProblems; } if($Severity eq "Low") { $Report .= get_Report_ChangedConstants("Low", $Level); if($ReportFormat eq "html") { if($CheckImpl and $Level eq "Binary") { $Report .= get_Report_Impl(); } } } if($Severity eq "Safe") { $Report .= get_Report_ChangedConstants("Safe", $Level); } if($ReportFormat eq "html") { if($Report) { # add anchor if($JoinReport) { if($Severity eq "Safe") { $Report = "".$Report; } else { $Report = "".$Report; } } else { if($Severity eq "Safe") { $Report = "".$Report; } else { $Report = "".$Report; } } } } return $Report; } sub composeHTML_Head($$$$$) { my ($Title, $Keywords, $Description, $Styles, $Scripts) = @_; return " $Title "; } sub insertIDs($) { my $Text = $_[0]; while($Text=~/CONTENT_ID/) { if(int($Content_Counter)%2) { $ContentID -= 1; } $Text=~s/CONTENT_ID/c_$ContentID/; $ContentID += 1; $Content_Counter += 1; } return $Text; } sub checkPreprocessedUnit($) { my $Path = $_[0]; my ($CurHeader, $CurHeaderName) = ("", ""); my $CurClass = ""; # extra info open(PREPROC, $Path) || die ("can't open file \'$Path\': $!\n"); while(my $Line = ) { # detecting public and private constants if(substr($Line, 0, 1) eq "#") { chomp($Line); if($Line=~/\A\#\s+\d+\s+\"(.+)\"/) { $CurHeader = path_format($1, $OSgroup); $CurHeaderName = get_filename($CurHeader); $CurClass = ""; if(index($CurHeader, $TMP_DIR)==0) { next; } if(substr($CurHeaderName, 0, 1) eq "<") { # , , etc. $CurHeaderName = ""; $CurHeader = ""; } if($ExtraInfo) { if($CurHeaderName) { $PreprocessedHeaders{$Version}{$CurHeader} = 1; } } } if(not $ExtraDump) { if($CurHeaderName) { if(not $Include_Neighbors{$Version}{$CurHeaderName} and not $Registered_Headers{$Version}{$CurHeader}) { # not a target next; } if(not is_target_header($CurHeaderName, 1) and not is_target_header($CurHeaderName, 2)) { # user-defined header next; } } } if($Line=~/\A\#\s*define\s+(\w+)\s+(.+)\s*\Z/) { my ($Name, $Value) = ($1, $2); if(not $Constants{$Version}{$Name}{"Access"}) { $Constants{$Version}{$Name}{"Access"} = "public"; $Constants{$Version}{$Name}{"Value"} = $Value; if($CurHeaderName) { $Constants{$Version}{$Name}{"Header"} = $CurHeaderName; } } } elsif($Line=~/\A\#[ \t]*undef[ \t]+([_A-Z]+)[ \t]*/) { $Constants{$Version}{$1}{"Access"} = "private"; } } else { if(defined $ExtraDump) { if($Line=~/(\w+)\s*\(/) { # functions $SymbolHeader{$Version}{$CurClass}{$1} = $CurHeader; } #elsif($Line=~/(\w+)\s*;/) #{ # data # $SymbolHeader{$Version}{$CurClass}{$1} = $CurHeader; #} elsif($Line=~/(\A|\s)class\s+(\w+)/) { $CurClass = $2; } } } } close(PREPROC); foreach my $Constant (keys(%{$Constants{$Version}})) { if($Constants{$Version}{$Constant}{"Access"} eq "private") { delete($Constants{$Version}{$Constant}); next; } if(not $ExtraDump and ($Constant=~/_h\Z/i or isBuiltIn($Constants{$Version}{$Constant}{"Header"}))) { # skip delete($Constants{$Version}{$Constant}); } else { delete($Constants{$Version}{$Constant}{"Access"}); } } if($Debug) { mkpath($DEBUG_PATH{$Version}); copy($Path, $DEBUG_PATH{$Version}."/preprocessor.txt"); } } sub uncoverConstant($$) { my ($LibVersion, $Constant) = @_; return "" if(not $LibVersion or not $Constant); return $Constant if(isCyclical(\@RecurConstant, $Constant)); if(defined $Cache{"uncoverConstant"}{$LibVersion}{$Constant}) { return $Cache{"uncoverConstant"}{$LibVersion}{$Constant}; } if(defined $Constants{$LibVersion}{$Constant}) { my $Value = $Constants{$LibVersion}{$Constant}{"Value"}; if(defined $Constants{$LibVersion}{$Value}) { push(@RecurConstant, $Constant); my $Uncovered = uncoverConstant($LibVersion, $Value); if($Uncovered ne "") { $Value = $Uncovered; } pop(@RecurConstant); } # FIXME: uncover $Value using all the enum constants # USE CASE: change of define NC_LONG from NC_INT (enum value) to NC_INT (define) return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = $Value); } return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = ""); } sub simpleConstant($$) { my ($LibVersion, $Value) = @_; if($Value=~/\W/) { my $Value_Copy = $Value; while($Value_Copy=~s/([a-z_]\w+)/\@/i) { my $Word = $1; if($Value!~/$Word\s*\(/) { my $Val = uncoverConstant($LibVersion, $Word); if($Val ne "") { $Value=~s/\b$Word\b/$Val/g; } } } } return $Value; } sub computeValue($) { my $Value = $_[0]; if($Value=~/\A\((-?[\d]+)\)\Z/) { return $1; } if($Value=~/\A[\d\-\+()]+\Z/) { return eval($Value); } return $Value; } my %IgnoreConstant = map {$_=>1} ( "VERSION", "VERSIONCODE", "VERNUM", "VERS_INFO", "PATCHLEVEL", "INSTALLPREFIX", "VBUILD", "VPATCH", "VMINOR", "BUILD_STRING", "BUILD_TIME", "PACKAGE_STRING", "PRODUCTION", "CONFIGURE_COMMAND", "INSTALLDIR", "BINDIR", "CONFIG_FILE_PATH", "DATADIR", "EXTENSION_DIR", "INCLUDE_PATH", "LIBDIR", "LOCALSTATEDIR", "SBINDIR", "SYSCONFDIR", "RELEASE", "SOURCE_ID", "SUBMINOR", "MINOR", "MINNOR", "MINORVERSION", "MAJOR", "MAJORVERSION", "MICRO", "MICROVERSION", "BINARY_AGE", "INTERFACE_AGE", "CORE_ABI", "PATCH", "COPYRIGHT", "TIMESTAMP", "REVISION", "PACKAGE_TAG", "PACKAGEDATE", "NUMVERSION", "Release", "Version" ); sub constantFilter($$$) { my ($Name, $Value, $Level) = @_; if($Level eq "Binary") { if($Name=~/_t\Z/) { # __malloc_ptr_t return 1; } foreach (keys(%IgnoreConstant)) { if($Name=~/(\A|_)$_(_|\Z)/) { # version return 1; } if(/\A[A-Z].*[a-z]\Z/) { if($Name=~/(\A|[a-z])$_([A-Z]|\Z)/) { # version return 1; } } } if($Name=~/(\A|_)(lib|open|)$TargetLibraryShortName(_|)(VERSION|VER|DATE|API|PREFIX)(_|\Z)/i) { # version return 1; } if($Value=~/\A('|"|)[\/\\]\w+([\/\\]|:|('|"|)\Z)/ or $Value=~/[\/\\]\w+[\/\\]\w+/) { # /lib64:/usr/lib64:/lib:/usr/lib:/usr/X11R6/lib/Xaw3d ... return 1; } if($Value=~/\A["'].*['"]/i) { # string return 0; } if($Value=~/\A[({]*\s*[a-z_]+\w*(\s+|[\|,])/i) { # static int gcry_pth_init # extern ABC # (RE_BACKSLASH_ESCAPE_IN_LISTS | RE... # { H5FD_MEM_SUPER, H5FD_MEM_SUPER, ... return 1; } if($Value=~/\w+\s*\(/i) { # foo(p) return 1; } if($Value=~/\A[a-z_]+\w*\Z/i) { # asn1_node_st # __SMTH_P return 1; } } return 0; } sub mergeConstants($) { my $Level = $_[0]; foreach my $Constant (keys(%{$Constants{1}})) { if($SkipConstants{1}{$Constant}) { # skipped by the user next; } if(my $Header = $Constants{1}{$Constant}{"Header"}) { if(not is_target_header($Header, 1) and not is_target_header($Header, 2)) { # user-defined header next; } } else { next; } my $Old_Value = uncoverConstant(1, $Constant); if(constantFilter($Constant, $Old_Value, $Level)) { # separate binary and source problems next; } if(not defined $Constants{2}{$Constant}{"Value"}) { # removed %{$CompatProblems_Constants{$Level}{$Constant}{"Removed_Constant"}} = ( "Target"=>$Constant, "Old_Value"=>$Old_Value ); next; } if($Constants{2}{$Constant}{"Value"} eq "") { # empty value # TODO: implement a rule next; } my $New_Value = uncoverConstant(2, $Constant); my $Old_Value_Pure = $Old_Value; my $New_Value_Pure = $New_Value; $Old_Value_Pure=~s/(\W)\s+/$1/g; $Old_Value_Pure=~s/\s+(\W)/$1/g; $New_Value_Pure=~s/(\W)\s+/$1/g; $New_Value_Pure=~s/\s+(\W)/$1/g; next if($New_Value_Pure eq "" or $Old_Value_Pure eq ""); if($New_Value_Pure ne $Old_Value_Pure) { # different values if(simpleConstant(1, $Old_Value) eq simpleConstant(2, $New_Value)) { # complex values next; } if(computeValue($Old_Value) eq computeValue($New_Value)) { # expressions next; } if(convert_integer($Old_Value) eq convert_integer($New_Value)) { # 0x0001 and 0x1, 0x1 and 1 equal constants next; } if($Old_Value eq "0" and $New_Value eq "NULL") { # 0 => NULL next; } if($Old_Value eq "NULL" and $New_Value eq "0") { # NULL => 0 next; } %{$CompatProblems_Constants{$Level}{$Constant}{"Changed_Constant"}} = ( "Target"=>$Constant, "Old_Value"=>$Old_Value, "New_Value"=>$New_Value ); } } foreach my $Constant (keys(%{$Constants{2}})) { if(not defined $Constants{1}{$Constant}{"Value"}) { if($SkipConstants{2}{$Constant}) { # skipped by the user next; } if(my $Header = $Constants{2}{$Constant}{"Header"}) { if(not is_target_header($Header, 1) and not is_target_header($Header, 2)) { # user-defined header next; } } else { next; } my $New_Value = uncoverConstant(2, $Constant); if(not defined $New_Value or $New_Value eq "") { next; } if(constantFilter($Constant, $New_Value, $Level)) { # separate binary and source problems next; } %{$CompatProblems_Constants{$Level}{$Constant}{"Added_Constant"}} = ( "Target"=>$Constant, "New_Value"=>$New_Value ); } } } sub convert_integer($) { my $Value = $_[0]; if($Value=~/\A0x[a-f0-9]+\Z/) { # hexadecimal return hex($Value); } elsif($Value=~/\A0[0-7]+\Z/) { # octal return oct($Value); } elsif($Value=~/\A0b[0-1]+\Z/) { # binary return oct($Value); } else { return $Value; } } sub readSymbols($) { my $LibVersion = $_[0]; my @LibPaths = getSOPaths($LibVersion); if($#LibPaths==-1 and not $CheckHeadersOnly) { if($LibVersion==1) { printMsg("WARNING", "checking headers only"); $CheckHeadersOnly = 1; } else { exitStatus("Error", "$SLIB_TYPE libraries are not found in ".$Descriptor{$LibVersion}{"Version"}); } } foreach my $LibPath (@LibPaths) { readSymbols_Lib($LibVersion, $LibPath, 0, "+Weak", 1, 1); } if($CheckUndefined) { my %UndefinedLibs = (); my @Libs = (keys(%{$Library_Symbol{$LibVersion}}), keys(%{$DepLibrary_Symbol{$LibVersion}})); foreach my $LibName (sort @Libs) { if(defined $UndefinedSymbols{$LibVersion}{$LibName}) { foreach my $Symbol (keys(%{$UndefinedSymbols{$LibVersion}{$LibName}})) { if($Symbol_Library{$LibVersion}{$Symbol} or $DepSymbol_Library{$LibVersion}{$Symbol}) { # exported by target library next; } if(index($Symbol, '@')!=-1) { # exported default symbol version (@@) $Symbol=~s/\@/\@\@/; if($Symbol_Library{$LibVersion}{$Symbol} or $DepSymbol_Library{$LibVersion}{$Symbol}) { next; } } foreach my $Path (find_SymbolLibs($LibVersion, $Symbol)) { $UndefinedLibs{$Path} = 1; } } } } if($ExtraInfo) { # extra information for other tools if(my @Paths = sort keys(%UndefinedLibs)) { my $LibString = ""; my %Dirs = (); foreach (@Paths) { $KnownLibs{$_} = 1; my ($Dir, $Name) = separate_path($_); if(not grep {$Dir eq $_} (@{$SystemPaths{"lib"}})) { $Dirs{esc($Dir)} = 1; } $Name = parse_libname($Name, "name", $OStarget); $Name=~s/\Alib//; $LibString .= " -l$Name"; } foreach my $Dir (sort {$b cmp $a} keys(%Dirs)) { $LibString = " -L".esc($Dir).$LibString; } writeFile($ExtraInfo."/libs-string", $LibString); } } } if($ExtraInfo) { writeFile($ExtraInfo."/lib-paths", join("\n", sort keys(%KnownLibs))); } if(not $CheckHeadersOnly) { if($#LibPaths!=-1) { if(not keys(%{$Symbol_Library{$LibVersion}})) { printMsg("WARNING", "the set of public symbols in library(ies) is empty ($LibVersion)"); printMsg("WARNING", "checking headers only"); $CheckHeadersOnly = 1; } } } # clean memory %SystemObjects = (); } my %Prefix_Lib_Map=( # symbols for autodetecting library dependencies (by prefix) "pthread_" => ["libpthread"], "g_" => ["libglib-2.0", "libgobject-2.0", "libgio-2.0"], "cairo_" => ["libcairo"], "gtk_" => ["libgtk-x11-2.0"], "atk_" => ["libatk-1.0"], "gdk_" => ["libgdk-x11-2.0"], "gl" => ["libGL"], "glu" => ["libGLU"], "popt" => ["libpopt"], "Py" => ["libpython"], "jpeg_" => ["libjpeg"], "BZ2_" => ["libbz2"], "Fc" => ["libfontconfig"], "Xft" => ["libXft"], "SSL_" => ["libssl"], "sem_" => ["libpthread"], "snd_" => ["libasound"], "art_" => ["libart_lgpl_2"], "dbus_g" => ["libdbus-glib-1"], "GOMP_" => ["libgomp"], "omp_" => ["libgomp"], "cms" => ["liblcms"] ); my %Pattern_Lib_Map=( "SL[a-z]" => ["libslang"] ); my %Symbol_Lib_Map=( # symbols for autodetecting library dependencies (by name) "pow" => "libm", "fmod" => "libm", "sin" => "libm", "floor" => "libm", "cos" => "libm", "dlopen" => "libdl", "deflate" => "libz", "inflate" => "libz", "move_panel" => "libpanel", "XOpenDisplay" => "libX11", "resize_term" => "libncurses", "clock_gettime" => "librt", "crypt" => "libcrypt" ); sub find_SymbolLibs($$) { my ($LibVersion, $Symbol) = @_; if(index($Symbol, "g_")==0 and $Symbol=~/[A-Z]/) { # debug symbols return (); } my %Paths = (); if(my $LibName = $Symbol_Lib_Map{$Symbol}) { if(my $Path = get_LibPath($LibVersion, $LibName.".".$LIB_EXT)) { $Paths{$Path} = 1; } } if(my $SymbolPrefix = getPrefix($Symbol)) { if(defined $Cache{"find_SymbolLibs"}{$SymbolPrefix}) { return @{$Cache{"find_SymbolLibs"}{$SymbolPrefix}}; } if(not keys(%Paths)) { if(defined $Prefix_Lib_Map{$SymbolPrefix}) { foreach my $LibName (@{$Prefix_Lib_Map{$SymbolPrefix}}) { if(my $Path = get_LibPath($LibVersion, $LibName.".".$LIB_EXT)) { $Paths{$Path} = 1; } } } } if(not keys(%Paths)) { foreach my $Prefix (sort keys(%Pattern_Lib_Map)) { if($Symbol=~/\A$Prefix/) { foreach my $LibName (@{$Pattern_Lib_Map{$Prefix}}) { if(my $Path = get_LibPath($LibVersion, $LibName.".".$LIB_EXT)) { $Paths{$Path} = 1; } } } } } if(not keys(%Paths)) { if($SymbolPrefix) { # try to find a library by symbol prefix if($SymbolPrefix eq "inotify" and index($Symbol, "\@GLIBC")!=-1) { if(my $Path = get_LibPath($LibVersion, "libc.$LIB_EXT")) { $Paths{$Path} = 1; } } else { if(my $Path = get_LibPath_Prefix($LibVersion, $SymbolPrefix)) { $Paths{$Path} = 1; } } } } if(my @Paths = keys(%Paths)) { $Cache{"find_SymbolLibs"}{$SymbolPrefix} = \@Paths; } } return keys(%Paths); } sub get_LibPath_Prefix($$) { my ($LibVersion, $Prefix) = @_; $Prefix = lc($Prefix); $Prefix=~s/[_]+\Z//g; foreach ("-2", "2", "-1", "1", "") { # libgnome-2.so # libxml2.so # libdbus-1.so if(my $Path = get_LibPath($LibVersion, "lib".$Prefix.$_.".".$LIB_EXT)) { return $Path; } } return ""; } sub getPrefix($) { my $Str = $_[0]; if($Str=~/\A([_]*[A-Z][a-z]{1,5})[A-Z]/) { # XmuValidArea: Xmu return $1; } elsif($Str=~/\A([_]*[a-z]+)[A-Z]/) { # snfReadFont: snf return $1; } elsif($Str=~/\A([_]*[A-Z]{2,})[A-Z][a-z]+([A-Z][a-z]+|\Z)/) { # XRRTimes: XRR return $1; } elsif($Str=~/\A([_]*[a-z]{1,2}\d+)[a-z\d]*_[a-z]+/i) { # H5HF_delete: H5 return $1; } elsif($Str=~/\A([_]*[a-z0-9]{2,}_)[a-z]+/i) { # alarm_event_add: alarm_ return $1; } elsif($Str=~/\A(([a-z])\2{1,})/i) { # ffopen return $1; } return ""; } sub getSymbolSize($$) { # size from the shared library my ($Symbol, $LibVersion) = @_; return 0 if(not $Symbol); if(defined $Symbol_Library{$LibVersion}{$Symbol} and my $LibName = $Symbol_Library{$LibVersion}{$Symbol}) { if(defined $Library_Symbol{$LibVersion}{$LibName}{$Symbol} and my $Size = $Library_Symbol{$LibVersion}{$LibName}{$Symbol}) { if($Size<0) { return -$Size; } } } return 0; } sub canonifyName($$) { # make TIFFStreamOpen(char const*, std::basic_ostream >*) # to be TIFFStreamOpen(char const*, std::basic_ostream*) my ($Name, $Type) = @_; # single while($Name=~/([^<>,]+),\s*$DEFAULT_STD_PARMS<([^<>,]+)>\s*/ and $1 eq $3) { my $P = $1; $Name=~s/\Q$P\E,\s*$DEFAULT_STD_PARMS<\Q$P\E>\s*/$P/g; } # double if($Name=~/$DEFAULT_STD_PARMS/) { if($Type eq "S") { my ($ShortName, $FuncParams) = split_Signature($Name); foreach my $FParam (separate_Params($FuncParams, 0, 0)) { if(index($FParam, "<")!=-1) { $FParam=~s/>([^<>]+)\Z/>/; # remove quals my $FParam_N = canonifyName($FParam, "T"); if($FParam_N ne $FParam) { $Name=~s/\Q$FParam\E/$FParam_N/g; } } } } elsif($Type eq "T") { my ($ShortTmpl, $TmplParams) = template_Base($Name); my @TParams = separate_Params($TmplParams, 0, 0); if($#TParams>=1) { my $FParam = $TParams[0]; foreach my $Pos (1 .. $#TParams) { my $TParam = $TParams[$Pos]; if($TParam=~/\A$DEFAULT_STD_PARMS<\Q$FParam\E\s*>\Z/) { $Name=~s/\Q$FParam, $TParam\E\s*/$FParam/g; } } } } } if($Type eq "S") { return formatName($Name, "S"); } return $Name; } sub translateSymbols(@) { my $LibVersion = pop(@_); my (@MnglNames1, @MnglNames2, @UnmangledNames) = (); foreach my $Symbol (sort @_) { if(index($Symbol, "_Z")==0) { next if($tr_name{$Symbol}); $Symbol=~s/[\@\$]+(.*)\Z//; push(@MnglNames1, $Symbol); } elsif(index($Symbol, "?")==0) { next if($tr_name{$Symbol}); push(@MnglNames2, $Symbol); } else { # not mangled $tr_name{$Symbol} = $Symbol; $mangled_name_gcc{$Symbol} = $Symbol; $mangled_name{$LibVersion}{$Symbol} = $Symbol; } } if($#MnglNames1 > -1) { # GCC names @UnmangledNames = reverse(unmangleArray(@MnglNames1)); foreach my $MnglName (@MnglNames1) { if(my $Unmangled = pop(@UnmangledNames)) { $tr_name{$MnglName} = canonifyName($Unmangled, "S"); if(not $mangled_name_gcc{$tr_name{$MnglName}}) { $mangled_name_gcc{$tr_name{$MnglName}} = $MnglName; } if(index($MnglName, "_ZTV")==0 and $tr_name{$MnglName}=~/vtable for (.+)/) { # bind class name and v-table symbol my $ClassName = $1; $ClassVTable{$ClassName} = $MnglName; $VTableClass{$MnglName} = $ClassName; } } } } if($#MnglNames2 > -1) { # MSVC names @UnmangledNames = reverse(unmangleArray(@MnglNames2)); foreach my $MnglName (@MnglNames2) { if(my $Unmangled = pop(@UnmangledNames)) { $tr_name{$MnglName} = formatName($Unmangled, "S"); $mangled_name{$LibVersion}{$tr_name{$MnglName}} = $MnglName; } } } return \%tr_name; } sub link_symbol($$$) { my ($Symbol, $RunWith, $Deps) = @_; if(link_symbol_internal($Symbol, $RunWith, \%Symbol_Library)) { return 1; } if($Deps eq "+Deps") { # check the dependencies if(link_symbol_internal($Symbol, $RunWith, \%DepSymbol_Library)) { return 1; } } return 0; } sub link_symbol_internal($$$) { my ($Symbol, $RunWith, $Where) = @_; return 0 if(not $Where or not $Symbol); if($Where->{$RunWith}{$Symbol}) { # the exact match by symbol name return 1; } if(my $VSym = $SymVer{$RunWith}{$Symbol}) { # indirect symbol version, i.e. # foo_old and its symlink foo@v (or foo@@v) # foo_old may be in symtab table if($Where->{$RunWith}{$VSym}) { return 1; } } my ($Sym, $Spec, $Ver) = separate_symbol($Symbol); if($Sym and $Ver) { # search for the symbol with the same version # or without version if($Where->{$RunWith}{$Sym}) { # old: foo@v|foo@@v # new: foo return 1; } if($Where->{$RunWith}{$Sym."\@".$Ver}) { # old: foo|foo@@v # new: foo@v return 1; } if($Where->{$RunWith}{$Sym."\@\@".$Ver}) { # old: foo|foo@v # new: foo@@v return 1; } } return 0; } sub readSymbols_App($) { my $Path = $_[0]; return () if(not $Path); my @Imported = (); if($OSgroup eq "macos") { my $NM = get_CmdPath("nm"); if(not $NM) { exitStatus("Not_Found", "can't find \"nm\""); } open(APP, "$NM -g \"$Path\" 2>\"$TMP_DIR/null\" |"); while() { if(/ U _([\w\$]+)\s*\Z/) { push(@Imported, $1); } } close(APP); } elsif($OSgroup eq "windows") { my $DumpBinCmd = get_CmdPath("dumpbin"); if(not $DumpBinCmd) { exitStatus("Not_Found", "can't find \"dumpbin.exe\""); } open(APP, "$DumpBinCmd /IMPORTS \"$Path\" 2>\"$TMP_DIR/null\" |"); while() { if(/\s*\w+\s+\w+\s+\w+\s+([\w\?\@]+)\s*/) { push(@Imported, $1); } } close(APP); } else { my $ReadelfCmd = get_CmdPath("readelf"); if(not $ReadelfCmd) { exitStatus("Not_Found", "can't find \"readelf\""); } open(APP, "$ReadelfCmd -Ws \"$Path\" 2>\"$TMP_DIR/null\" |"); my $symtab = undef; # indicates that we are processing 'symtab' section of 'readelf' output while() { if(defined $symtab) { # do nothing with symtab if(index($_, "'.dynsym'")!=-1) { # dynamic table $symtab = undef; } } elsif(index($_, "'.symtab'")!=-1) { # symbol table $symtab = 1; } elsif(my @Info = readline_ELF($_)) { my ($Ndx, $Symbol) = ($Info[5], $Info[6]); if($Ndx eq "UND") { # only imported symbols push(@Imported, $Symbol); } } } close(APP); } return @Imported; } my %ELF_BIND = map {$_=>1} ( "WEAK", "GLOBAL" ); my %ELF_TYPE = map {$_=>1} ( "FUNC", "IFUNC", "OBJECT", "COMMON" ); my %ELF_VIS = map {$_=>1} ( "DEFAULT", "PROTECTED" ); sub readline_ELF($) { # read the line of 'readelf' output corresponding to the symbol my @Info = split(/\s+/, $_[0]); # Num: Value Size Type Bind Vis Ndx Name # 3629: 000b09c0 32 FUNC GLOBAL DEFAULT 13 _ZNSt12__basic_fileIcED1Ev@@GLIBCXX_3.4 # 135: 00000000 0 FUNC GLOBAL DEFAULT UND av_image_fill_pointers@LIBAVUTIL_52 (3) shift(@Info); # spaces shift(@Info); # num if($#Info==7) { # UND SYMBOL (N) if($Info[7]=~/\(\d+\)/) { pop(@Info); } } if($#Info!=6) { # other lines return (); } return () if(not defined $ELF_TYPE{$Info[2]} and $Info[5] ne "UND"); return () if(not defined $ELF_BIND{$Info[3]}); return () if(not defined $ELF_VIS{$Info[4]}); if($Info[5] eq "ABS" and $Info[0]=~/\A0+\Z/) { # 1272: 00000000 0 OBJECT GLOBAL DEFAULT ABS CXXABI_1.3 return (); } if($OStarget eq "symbian") { # _ZN12CCTTokenType4NewLE4TUid3RFs@@ctfinder{000a0000}[102020e5].dll if(index($Info[6], "_._.absent_export_")!=-1) { # "_._.absent_export_111"@@libstdcpp{00010001}[10282872].dll return (); } $Info[6]=~s/\@.+//g; # remove version } if(index($Info[2], "0x") == 0) { # size == 0x3d158 $Info[2] = hex($Info[2]); } return @Info; } sub get_LibPath($$) { my ($LibVersion, $Name) = @_; return "" if(not $LibVersion or not $Name); if(defined $Cache{"get_LibPath"}{$LibVersion}{$Name}) { return $Cache{"get_LibPath"}{$LibVersion}{$Name}; } return ($Cache{"get_LibPath"}{$LibVersion}{$Name} = get_LibPath_I($LibVersion, $Name)); } sub get_LibPath_I($$) { my ($LibVersion, $Name) = @_; if(is_abs($Name)) { if(-f $Name) { # absolute path return $Name; } else { # broken return ""; } } if(defined $RegisteredObjects{$LibVersion}{$Name}) { # registered paths return $RegisteredObjects{$LibVersion}{$Name}; } if(defined $RegisteredSONAMEs{$LibVersion}{$Name}) { # registered paths return $RegisteredSONAMEs{$LibVersion}{$Name}; } if(my $DefaultPath = $DyLib_DefaultPath{$Name}) { # ldconfig default paths return $DefaultPath; } foreach my $Dir (@DefaultLibPaths, @{$SystemPaths{"lib"}}) { # search in default linker directories # and then in all system paths if(-f $Dir."/".$Name) { return join_P($Dir,$Name); } } if(not defined $Cache{"checkSystemFiles"}) { checkSystemFiles(); } if(my @AllObjects = keys(%{$SystemObjects{$Name}})) { return $AllObjects[0]; } if(my $ShortName = parse_libname($Name, "name+ext", $OStarget)) { if($ShortName ne $Name) { # FIXME: check this case if(my $Path = get_LibPath($LibVersion, $ShortName)) { return $Path; } } } # can't find return ""; } sub readSymbols_Lib($$$$$$) { my ($LibVersion, $Lib_Path, $IsNeededLib, $Weak, $Deps, $Vers) = @_; return () if(not $LibVersion or not $Lib_Path); my $Real_Path = realpath($Lib_Path); if(not $Real_Path) { # broken link return (); } my $Lib_Name = get_filename($Real_Path); if($ExtraInfo) { $KnownLibs{$Real_Path} = 1; $KnownLibs{$Lib_Path} = 1; # links } if($IsNeededLib) { if($CheckedDyLib{$LibVersion}{$Lib_Name}) { return (); } } return () if(isCyclical(\@RecurLib, $Lib_Name) or $#RecurLib>=1); $CheckedDyLib{$LibVersion}{$Lib_Name} = 1; if($CheckImpl) { if(not $IsNeededLib) { getImplementations($LibVersion, $Lib_Path); } } push(@RecurLib, $Lib_Name); my (%Value_Interface, %Interface_Value, %NeededLib) = (); my $Lib_ShortName = parse_libname($Lib_Name, "name+ext", $OStarget); if(not $IsNeededLib) { # special cases: libstdc++ and libc if(my $ShortName = parse_libname($Lib_Name, "short", $OStarget)) { if($ShortName eq "libstdc++") { # libstdc++.so.6 $STDCXX_TESTING = 1; } elsif($ShortName eq "libc") { # libc-2.11.3.so $GLIBC_TESTING = 1; } } } my $DebugPath = ""; if($Debug and not $DumpSystem) { # debug mode $DebugPath = $DEBUG_PATH{$LibVersion}."/libs/".get_filename($Lib_Path).".txt"; mkpath(get_dirname($DebugPath)); } if($OStarget eq "macos") { # Mac OS X: *.dylib, *.a my $NM = get_CmdPath("nm"); if(not $NM) { exitStatus("Not_Found", "can't find \"nm\""); } $NM .= " -g \"$Lib_Path\" 2>\"$TMP_DIR/null\""; if($DebugPath) { # debug mode # write to file system($NM." >\"$DebugPath\""); open(LIB, $DebugPath); } else { # write to pipe open(LIB, $NM." |"); } while() { if($CheckUndefined) { if(not $IsNeededLib) { if(/ U _([\w\$]+)\s*\Z/) { $UndefinedSymbols{$LibVersion}{$Lib_Name}{$1} = 0; next; } } } if(/ [STD] _([\w\$]+)\s*\Z/) { my $Symbol = $1; if($IsNeededLib) { if(not defined $RegisteredObjects_Short{$LibVersion}{$Lib_ShortName}) { $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name; $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = 1; } } else { $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name; $Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = 1; if($COMMON_LANGUAGE{$LibVersion} ne "C++") { if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) { setLanguage($LibVersion, "C++"); } } if($CheckObjectsOnly and $LibVersion==1) { $CheckedSymbols{"Binary"}{$Symbol} = 1; } } } } close(LIB); if($Deps) { if($LIB_TYPE eq "dynamic") { # dependencies my $OtoolCmd = get_CmdPath("otool"); if(not $OtoolCmd) { exitStatus("Not_Found", "can't find \"otool\""); } open(LIB, "$OtoolCmd -L \"$Lib_Path\" 2>\"$TMP_DIR/null\" |"); while() { if(/\s*([\/\\].+\.$LIB_EXT)\s*/ and $1 ne $Lib_Path) { $NeededLib{$1} = 1; } } close(LIB); } } } elsif($OStarget eq "windows") { # Windows *.dll, *.lib my $DumpBinCmd = get_CmdPath("dumpbin"); if(not $DumpBinCmd) { exitStatus("Not_Found", "can't find \"dumpbin\""); } $DumpBinCmd .= " /EXPORTS \"".$Lib_Path."\" 2>$TMP_DIR/null"; if($DebugPath) { # debug mode # write to file system($DumpBinCmd." >\"$DebugPath\""); open(LIB, $DebugPath); } else { # write to pipe open(LIB, $DumpBinCmd." |"); } while() { # 1197 4AC 0000A620 SetThreadStackGuarantee # 1198 4AD SetThreadToken (forwarded to ...) # 3368 _o2i_ECPublicKey if(/\A\s*\d+\s+[a-f\d]+\s+[a-f\d]+\s+([\w\?\@]+)\s*\Z/i or /\A\s*\d+\s+[a-f\d]+\s+([\w\?\@]+)\s*\(\s*forwarded\s+/ or /\A\s*\d+\s+_([\w\?\@]+)\s*\Z/) { # dynamic, static and forwarded symbols my $realname = $1; if($IsNeededLib) { if(not defined $RegisteredObjects_Short{$LibVersion}{$Lib_ShortName}) { $DepSymbol_Library{$LibVersion}{$realname} = $Lib_Name; $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1; } } else { $Symbol_Library{$LibVersion}{$realname} = $Lib_Name; $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1; if($COMMON_LANGUAGE{$LibVersion} ne "C++") { if(index($realname, "_Z")==0 or index($realname, "?")==0) { setLanguage($LibVersion, "C++"); } } if($CheckObjectsOnly and $LibVersion==1) { $CheckedSymbols{"Binary"}{$realname} = 1; } } } } close(LIB); if($Deps) { if($LIB_TYPE eq "dynamic") { # dependencies open(LIB, "$DumpBinCmd /DEPENDENTS \"$Lib_Path\" 2>\"$TMP_DIR/null\" |"); while() { if(/\s*([^\s]+?\.$LIB_EXT)\s*/i and $1 ne $Lib_Path) { $NeededLib{path_format($1, $OSgroup)} = 1; } } close(LIB); } } } else { # Unix; *.so, *.a # Symbian: *.dso, *.lib my $ReadelfCmd = get_CmdPath("readelf"); if(not $ReadelfCmd) { exitStatus("Not_Found", "can't find \"readelf\""); } my $Cmd = $ReadelfCmd." -Ws \"$Lib_Path\" 2>\"$TMP_DIR/null\""; if($DebugPath) { # debug mode # write to file system($Cmd." >\"$DebugPath\""); open(LIB, $DebugPath); } else { # write to pipe open(LIB, $Cmd." |"); } my $symtab = undef; # indicates that we are processing 'symtab' section of 'readelf' output while() { if($LIB_TYPE eq "dynamic") { # dynamic library specifics if(defined $symtab) { if(index($_, "'.dynsym'")!=-1) { # dynamic table $symtab = undef; } # do nothing with symtab next; } elsif(index($_, "'.symtab'")!=-1) { # symbol table $symtab = 1; next; } } if(my ($Value, $Size, $Type, $Bind, $Vis, $Ndx, $Symbol) = readline_ELF($_)) { # read ELF entry if($Ndx eq "UND") { # ignore interfaces that are imported from somewhere else if($CheckUndefined) { if(not $IsNeededLib) { $UndefinedSymbols{$LibVersion}{$Lib_Name}{$Symbol} = 0; } } next; } if($Bind eq "WEAK") { $WeakSymbols{$LibVersion}{$Symbol} = 1; if($Weak eq "-Weak") { # skip WEAK symbols next; } } my $Short = $Symbol; $Short=~s/\@.+//g; if($Type eq "OBJECT") { # global data $GlobalDataObject{$LibVersion}{$Symbol} = $Size; $GlobalDataObject{$LibVersion}{$Short} = $Size; } if($IsNeededLib) { if(not defined $RegisteredObjects_Short{$LibVersion}{$Lib_ShortName}) { $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name; $DepLibrary_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = ($Type eq "OBJECT")?-$Size:1; } } else { $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name; $Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol} = ($Type eq "OBJECT")?-$Size:1; if($Vers) { if($LIB_EXT eq "so") { # value $Interface_Value{$LibVersion}{$Symbol} = $Value; $Value_Interface{$LibVersion}{$Value}{$Symbol} = 1; } } if($COMMON_LANGUAGE{$LibVersion} ne "C++") { if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) { setLanguage($LibVersion, "C++"); } } if($CheckObjectsOnly and $LibVersion==1) { $CheckedSymbols{"Binary"}{$Symbol} = 1; } } } } close(LIB); if($Deps and $LIB_TYPE eq "dynamic") { # dynamic library specifics $Cmd = $ReadelfCmd." -Wd \"$Lib_Path\" 2>\"$TMP_DIR/null\""; open(LIB, $Cmd." |"); while() { if(/NEEDED.+\[([^\[\]]+)\]/) { # dependencies: # 0x00000001 (NEEDED) Shared library: [libc.so.6] $NeededLib{$1} = 1; } } close(LIB); } } if($Vers) { if(not $IsNeededLib and $LIB_EXT eq "so") { # get symbol versions my %Found = (); # by value foreach my $Symbol (keys(%{$Library_Symbol{$LibVersion}{$Lib_Name}})) { next if(index($Symbol,"\@")==-1); if(my $Value = $Interface_Value{$LibVersion}{$Symbol}) { foreach my $Symbol_SameValue (keys(%{$Value_Interface{$LibVersion}{$Value}})) { if($Symbol_SameValue ne $Symbol and index($Symbol_SameValue,"\@")==-1) { $SymVer{$LibVersion}{$Symbol_SameValue} = $Symbol; $Found{$Symbol} = 1; last; } } } } # default foreach my $Symbol (keys(%{$Library_Symbol{$LibVersion}{$Lib_Name}})) { next if(defined $Found{$Symbol}); next if(index($Symbol,"\@\@")==-1); if($Symbol=~/\A([^\@]*)\@\@/ and not $SymVer{$LibVersion}{$1}) { $SymVer{$LibVersion}{$1} = $Symbol; $Found{$Symbol} = 1; } } # non-default foreach my $Symbol (keys(%{$Library_Symbol{$LibVersion}{$Lib_Name}})) { next if(defined $Found{$Symbol}); next if(index($Symbol,"\@")==-1); if($Symbol=~/\A([^\@]*)\@([^\@]*)/ and not $SymVer{$LibVersion}{$1}) { $SymVer{$LibVersion}{$1} = $Symbol; $Found{$Symbol} = 1; } } } } if($Deps) { foreach my $DyLib (sort keys(%NeededLib)) { $Library_Needed{$LibVersion}{$Lib_Name}{get_filename($DyLib)} = 1; if(my $DepPath = get_LibPath($LibVersion, $DyLib)) { if(not $CheckedDyLib{$LibVersion}{get_filename($DepPath)}) { readSymbols_Lib($LibVersion, $DepPath, 1, "+Weak", $Deps, $Vers); } } } } pop(@RecurLib); return $Library_Symbol{$LibVersion}; } sub get_prefixes($) { my %Prefixes = (); get_prefixes_I([$_[0]], \%Prefixes); return keys(%Prefixes); } sub get_prefixes_I($$) { foreach my $P (@{$_[0]}) { my @Parts = reverse(split(/[\/\\]+/, $P)); my $Name = $Parts[0]; foreach (1 .. $#Parts) { $_[1]->{$Name}{$P} = 1; last if($_>4 or $Parts[$_] eq "include"); $Name = $Parts[$_].$SLASH.$Name; } } } sub checkSystemFiles() { $Cache{"checkSystemFiles"} = 1; my @SysHeaders = (); foreach my $DevelPath (@{$SystemPaths{"lib"}}) { next if(not -d $DevelPath); my @Files = cmd_find($DevelPath,"f"); foreach my $Link (cmd_find($DevelPath,"l")) { # add symbolic links if(-f $Link) { push(@Files, $Link); } } if(not $CheckObjectsOnly) { # search for headers in /usr/lib my @Headers = grep { /\.h(pp|xx)?\Z|\/include\// } @Files; @Headers = grep { not /\/(gcc|jvm|syslinux|kbd|parrot|xemacs|perl|llvm)/ } @Headers; push(@SysHeaders, @Headers); } # search for libraries in /usr/lib (including symbolic links) my @Libs = grep { /\.$LIB_EXT[0-9.]*\Z/ } @Files; foreach my $Path (@Libs) { my $N = get_filename($Path); $SystemObjects{$N}{$Path} = 1; $SystemObjects{parse_libname($N, "name+ext", $OStarget)}{$Path} = 1; } } if(not $CheckObjectsOnly) { foreach my $DevelPath (@{$SystemPaths{"include"}}) { next if(not -d $DevelPath); # search for all header files in the /usr/include # with or without extension (ncurses.h, QtCore, ...) push(@SysHeaders, cmd_find($DevelPath,"f")); foreach my $Link (cmd_find($DevelPath,"l")) { # add symbolic links if(-f $Link) { push(@SysHeaders, $Link); } } } get_prefixes_I(\@SysHeaders, \%SystemHeaders); } } sub getSOPaths($) { my $LibVersion = $_[0]; my @Paths = (); foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Libs"})) { if(not -e $Dest) { exitStatus("Access_Error", "can't access \'$Dest\'"); } $Dest = get_abs_path($Dest); my @SoPaths_Dest = getSOPaths_Dest($Dest, $LibVersion); foreach (@SoPaths_Dest) { push(@Paths, $_); } } return sort @Paths; } sub skipLib($$) { my ($Path, $LibVersion) = @_; return 1 if(not $Path or not $LibVersion); my $Name = get_filename($Path); if($SkipLibs{$LibVersion}{"Name"}{$Name}) { return 1; } my $ShortName = parse_libname($Name, "name+ext", $OStarget); if($SkipLibs{$LibVersion}{"Name"}{$ShortName}) { return 1; } foreach my $Dir (keys(%{$SkipLibs{$LibVersion}{"Path"}})) { if($Path=~/\Q$Dir\E([\/\\]|\Z)/) { return 1; } } foreach my $P (keys(%{$SkipLibs{$LibVersion}{"Pattern"}})) { if($Name=~/$P/) { return 1; } if($P=~/[\/\\]/ and $Path=~/$P/) { return 1; } } return 0; } sub specificHeader($$) { my ($Header, $Spec) = @_; my $Name = get_filename($Header); if($Spec eq "windows") {# MS Windows return 1 if($Name=~/(\A|[._-])(win|wince|wnt)(\d\d|[._-]|\Z)/i); return 1 if($Name=~/([._-]w|win)(32|64)/i); return 1 if($Name=~/\A(Win|Windows)[A-Z]/); return 1 if($Name=~/\A(w|win|windows)(32|64|\.)/i); my @Dirs = ( "win32", "win64", "win", "windows", "msvcrt" ); # /gsf-win32/ if(my $DIRs = join("|", @Dirs)) { return 1 if($Header=~/[\/\\](|[^\/\\]+[._-])($DIRs)(|[._-][^\/\\]+)([\/\\]|\Z)/i); } } elsif($Spec eq "macos") { # Mac OS return 1 if($Name=~/(\A|[_-])mac[._-]/i); } return 0; } sub skipAlienHeader($) { my $Path = $_[0]; my $Name = get_filename($Path); my $Dir = get_dirname($Path); if($Tolerance=~/2/) { # 2 - skip internal headers my @Terms = ( "p", "priv", "int", "impl", "implementation", "internal", "private", "old", "compat", "debug", "test", "gen" ); my @Dirs = ( "private", "priv", "port", "impl", "internal", "detail", "details", "old", "compat", "debug", "config", "compiler", "platform", "test" ); if(my $TERMs = join("|", @Terms)) { return 1 if($Name=~/(\A|[._-])($TERMs)([._-]|\Z)/i); } if(my $DIRs = join("|", @Dirs)) { return 1 if($Dir=~/(\A|[\/\\])(|[^\/\\]+[._-])($DIRs)(|[._-][^\/\\]+)([\/\\]|\Z)/i); } return 1 if($Name=~/[a-z](Imp|Impl|I|P)(\.|\Z)/); } if($Tolerance=~/1/) { # 1 - skip non-Linux headers if($OSgroup ne "windows") { if(specificHeader($Path, "windows")) { return 1; } } if($OSgroup ne "macos") { if(specificHeader($Path, "macos")) { return 1; } } } # valid return 0; } sub skipHeader($$) { my ($Path, $LibVersion) = @_; return 1 if(not $Path or not $LibVersion); if(defined $Cache{"skipHeader"}{$Path}) { return $Cache{"skipHeader"}{$Path}; } if(defined $Tolerance and $Tolerance=~/1|2/) { # --tolerant if(skipAlienHeader($Path)) { return ($Cache{"skipHeader"}{$Path} = 1); } } if(not keys(%{$SkipHeaders{$LibVersion}})) { return 0; } return ($Cache{"skipHeader"}{$Path} = skipHeader_I(@_)); } sub skipHeader_I($$) { # returns: # 1 - if header should NOT be included and checked # 2 - if header should NOT be included, but should be checked my ($Path, $LibVersion) = @_; my $Name = get_filename($Path); if(my $Kind = $SkipHeaders{$LibVersion}{"Name"}{$Name}) { return $Kind; } foreach my $D (sort {$SkipHeaders{$LibVersion}{"Path"}{$a} cmp $SkipHeaders{$LibVersion}{"Path"}{$b}} keys(%{$SkipHeaders{$LibVersion}{"Path"}})) { if(index($Path, $D)!=-1) { if($Path=~/\Q$D\E([\/\\]|\Z)/) { return $SkipHeaders{$LibVersion}{"Path"}{$D}; } } } foreach my $P (sort {$SkipHeaders{$LibVersion}{"Pattern"}{$a} cmp $SkipHeaders{$LibVersion}{"Pattern"}{$b}} keys(%{$SkipHeaders{$LibVersion}{"Pattern"}})) { if(my $Kind = $SkipHeaders{$LibVersion}{"Pattern"}{$P}) { if($Name=~/$P/) { return $Kind; } if($P=~/[\/\\]/ and $Path=~/$P/) { return $Kind; } } } return 0; } sub registerObject_Dir($$) { my ($Dir, $LibVersion) = @_; if(grep {$_ eq $Dir} @{$SystemPaths{"lib"}}) { # system directory return; } if($RegisteredObject_Dirs{$LibVersion}{$Dir}) { # already registered return; } foreach my $Path (find_libs($Dir,"",1)) { next if(ignore_path($Path)); next if(skipLib($Path, $LibVersion)); registerObject($Path, $LibVersion); } $RegisteredObject_Dirs{$LibVersion}{$Dir} = 1; } sub registerObject($$) { my ($Path, $LibVersion) = @_; my $Name = get_filename($Path); $RegisteredObjects{$LibVersion}{$Name} = $Path; if($OSgroup=~/linux|bsd/i) { if(my $SONAME = getSONAME($Path)) { $RegisteredSONAMEs{$LibVersion}{$SONAME} = $Path; } } if(my $Short = parse_libname($Name, "name+ext", $OStarget)) { $RegisteredObjects_Short{$LibVersion}{$Short} = $Path; } } sub getSONAME($) { my $Path = $_[0]; return if(not $Path); if(defined $Cache{"getSONAME"}{$Path}) { return $Cache{"getSONAME"}{$Path}; } my $ObjdumpCmd = get_CmdPath("objdump"); if(not $ObjdumpCmd) { exitStatus("Not_Found", "can't find \"objdump\""); } my $SonameCmd = "$ObjdumpCmd -x $Path 2>$TMP_DIR/null"; if($OSgroup eq "windows") { $SonameCmd .= " | find \"SONAME\""; } else { $SonameCmd .= " | grep SONAME"; } if(my $SonameInfo = `$SonameCmd`) { if($SonameInfo=~/SONAME\s+([^\s]+)/) { return ($Cache{"getSONAME"}{$Path} = $1); } } return ($Cache{"getSONAME"}{$Path}=""); } sub getSOPaths_Dest($$) { my ($Dest, $LibVersion) = @_; if(skipLib($Dest, $LibVersion)) { return (); } if(-f $Dest) { if(not parse_libname($Dest, "name", $OStarget)) { exitStatus("Error", "incorrect format of library (should be *.$LIB_EXT): \'$Dest\'"); } registerObject($Dest, $LibVersion); registerObject_Dir(get_dirname($Dest), $LibVersion); return ($Dest); } elsif(-d $Dest) { $Dest=~s/[\/\\]+\Z//g; my %Libs = (); if(grep { $Dest eq $_ } @{$SystemPaths{"lib"}}) { # you have specified /usr/lib as the search directory () in the XML descriptor # and the real name of the library by -l option (bz2, stdc++, Xaw, ...) foreach my $Path (cmd_find($Dest,"","*".esc($TargetLibraryName)."*.$LIB_EXT*",2)) { # all files and symlinks that match the name of a library if(get_filename($Path)=~/\A(|lib)\Q$TargetLibraryName\E[\d\-]*\.$LIB_EXT[\d\.]*\Z/i) { registerObject($Path, $LibVersion); $Libs{realpath($Path)}=1; } } } else { # search for all files and symlinks foreach my $Path (find_libs($Dest,"","")) { next if(ignore_path($Path)); next if(skipLib($Path, $LibVersion)); registerObject($Path, $LibVersion); $Libs{realpath($Path)}=1; } if($OSgroup eq "macos") { # shared libraries on MacOS X may have no extension foreach my $Path (cmd_find($Dest,"f")) { next if(ignore_path($Path)); next if(skipLib($Path, $LibVersion)); if(get_filename($Path)!~/\./ and cmd_file($Path)=~/(shared|dynamic)\s+library/i) { registerObject($Path, $LibVersion); $Libs{realpath($Path)}=1; } } } } return keys(%Libs); } else { return (); } } sub isCyclical($$) { my ($Stack, $Value) = @_; return (grep {$_ eq $Value} @{$Stack}); } sub detectWordSize() { return "" if(not $GCC_PATH); if($Cache{"detectWordSize"}) { return $Cache{"detectWordSize"}; } writeFile("$TMP_DIR/empty.h", ""); my $Defines = `$GCC_PATH -E -dD \"$TMP_DIR/empty.h\"`; unlink("$TMP_DIR/empty.h"); my $WSize = 0; if($Defines=~/ __SIZEOF_POINTER__\s+(\d+)/) { # GCC 4 $WSize = $1; } elsif($Defines=~/ __PTRDIFF_TYPE__\s+(\w+)/) { # GCC 3 my $PTRDIFF = $1; if($PTRDIFF=~/long/) { $WSize = "8"; } else { $WSize = "4"; } } if(not $WSize) { exitStatus("Error", "can't check WORD size"); } return ($Cache{"detectWordSize"} = $WSize); } sub getWordSize($) { return $WORD_SIZE{$_[0]}; } sub majorVersion($) { my $V = $_[0]; return 0 if(not $V); my @VParts = split(/\./, $V); return $VParts[0]; } sub cmpVersions($$) { # compare two versions in dotted-numeric format my ($V1, $V2) = @_; return 0 if($V1 eq $V2); my @V1Parts = split(/\./, $V1); my @V2Parts = split(/\./, $V2); for (my $i = 0; $i <= $#V1Parts && $i <= $#V2Parts; $i++) { return -1 if(int($V1Parts[$i]) < int($V2Parts[$i])); return 1 if(int($V1Parts[$i]) > int($V2Parts[$i])); } return -1 if($#V1Parts < $#V2Parts); return 1 if($#V1Parts > $#V2Parts); return 0; } sub read_ABI_Dump($$) { my ($LibVersion, $Path) = @_; return if(not $LibVersion or not -e $Path); my $FilePath = ""; if(isDump_U($Path)) { # input *.abi $FilePath = $Path; } else { # input *.abi.tar.gz $FilePath = unpackDump($Path); if(not isDump_U($FilePath)) { exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it"); } } my $ABI = {}; my $Line = readLineNum($FilePath, 0); if($Line=~/xml/) { # XML format loadModule("XmlDump"); $ABI = readXmlDump($FilePath); } else { # Perl Data::Dumper format (default) open(DUMP, $FilePath); local $/ = undef; my $Content = ; close(DUMP); if(get_dirname($FilePath) eq $TMP_DIR."/unpack") { # remove temp file unlink($FilePath); } if($Content!~/};\s*\Z/) { exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it"); } $ABI = eval($Content); if(not $ABI) { exitStatus("Error", "internal error - eval() procedure seem to not working correctly, try to remove 'use strict' and try again"); } } # new dumps (>=1.22) have a personal versioning my $DVersion = $ABI->{"ABI_DUMP_VERSION"}; my $ToolVersion = $ABI->{"ABI_COMPLIANCE_CHECKER_VERSION"}; if(not $DVersion) { # old dumps (<=1.21.6) have been marked by the tool version $DVersion = $ToolVersion; } $UsedDump{$LibVersion}{"V"} = $DVersion; if($ABI->{"ABI_DUMP_VERSION"}) { if(cmpVersions($DVersion, $ABI_DUMP_VERSION)>0) { # Don't know how to parse future dump formats exitStatus("Dump_Version", "incompatible version \'$DVersion\' of specified ABI dump (newer than $ABI_DUMP_VERSION)"); } } else { # support for old ABI dumps if(cmpVersions($DVersion, $TOOL_VERSION)>0) { # Don't know how to parse future dump formats exitStatus("Dump_Version", "incompatible version \'$DVersion\' of specified ABI dump (newer than $TOOL_VERSION)"); } } if(majorVersion($DVersion)<2) { # support for old ABI dumps if($UseOldDumps) { if(cmpVersions($DVersion, $OLDEST_SUPPORTED_VERSION)<0) { exitStatus("Dump_Version", "incompatible version \'$DVersion\' of specified ABI dump (older than $OLDEST_SUPPORTED_VERSION)"); } } else { my $Msg = "incompatible version \'$DVersion\' of specified ABI dump (allowed only 2.0<=V<=$ABI_DUMP_VERSION)"; if(cmpVersions($DVersion, $OLDEST_SUPPORTED_VERSION)>=0) { $Msg .= "\nUse -old-dumps option to use old-version dumps ($OLDEST_SUPPORTED_VERSION<=V<2.0)"; } exitStatus("Dump_Version", $Msg); } } if(defined $ABI->{"ABI_DUMPER_VERSION"}) { # DWARF ABI Dump $UseConv_Real{$LibVersion}{"P"} = 1; $UseConv_Real{$LibVersion}{"R"} = 0; # not implemented yet $UsedDump{$LibVersion}{"DWARF"} = 1; $TargetComponent = "module"; } if(not checkDump($LibVersion, "2.11")) { # old ABI dumps $UsedDump{$LibVersion}{"BinOnly"} = 1; } elsif($ABI->{"BinOnly"}) { # ABI dump created with --binary option $UsedDump{$LibVersion}{"BinOnly"} = 1; } else { # default $UsedDump{$LibVersion}{"SrcBin"} = 1; } if(defined $ABI->{"Mode"} and $ABI->{"Mode"} eq "Extended") { # --ext option $ExtendedCheck = 1; } if($ABI->{"Extra"}) { $ExtraDump = 1; } if(my $Lang = $ABI->{"Language"}) { $UsedDump{$LibVersion}{"L"} = $Lang; setLanguage($LibVersion, $Lang); } if(checkDump($LibVersion, "2.15")) { $TypeInfo{$LibVersion} = $ABI->{"TypeInfo"}; } else { # support for old ABI dumps my $TInfo = $ABI->{"TypeInfo"}; if(not $TInfo) { # support for older ABI dumps $TInfo = $ABI->{"TypeDescr"}; } my %Tid_TDid = (); foreach my $TDid (keys(%{$TInfo})) { foreach my $Tid (keys(%{$TInfo->{$TDid}})) { $MAX_ID = $Tid if($Tid>$MAX_ID); $MAX_ID = $TDid if($TDid and $TDid>$MAX_ID); $Tid_TDid{$Tid}{$TDid} = 1; } } my %NewID = (); foreach my $Tid (keys(%Tid_TDid)) { my @TDids = keys(%{$Tid_TDid{$Tid}}); if($#TDids>=1) { foreach my $TDid (@TDids) { if($TDid) { %{$TypeInfo{$LibVersion}{$Tid}} = %{$TInfo->{$TDid}{$Tid}}; } else { my $ID = ++$MAX_ID; $NewID{$TDid}{$Tid} = $ID; %{$TypeInfo{$LibVersion}{$ID}} = %{$TInfo->{$TDid}{$Tid}}; $TypeInfo{$LibVersion}{$ID}{"Tid"} = $ID; } } } else { my $TDid = $TDids[0]; %{$TypeInfo{$LibVersion}{$Tid}} = %{$TInfo->{$TDid}{$Tid}}; } } foreach my $Tid (keys(%{$TypeInfo{$LibVersion}})) { my %Info = %{$TypeInfo{$LibVersion}{$Tid}}; if(defined $Info{"BaseType"}) { my $Bid = $Info{"BaseType"}{"Tid"}; my $BDid = $Info{"BaseType"}{"TDid"}; $BDid="" if(not defined $BDid); delete($TypeInfo{$LibVersion}{$Tid}{"BaseType"}{"TDid"}); if(defined $NewID{$BDid} and my $ID = $NewID{$BDid}{$Bid}) { $TypeInfo{$LibVersion}{$Tid}{"BaseType"} = $ID; } } delete($TypeInfo{$LibVersion}{$Tid}{"TDid"}); } } read_Machine_DumpInfo($ABI, $LibVersion); $SymbolInfo{$LibVersion} = $ABI->{"SymbolInfo"}; if(not $SymbolInfo{$LibVersion}) { # support for old dumps $SymbolInfo{$LibVersion} = $ABI->{"FuncDescr"}; } if(not keys(%{$SymbolInfo{$LibVersion}})) { # validation of old-version dumps if(not $ExtendedCheck) { exitStatus("Invalid_Dump", "the input dump d$LibVersion is invalid"); } } if(checkDump($LibVersion, "2.15")) { $DepLibrary_Symbol{$LibVersion} = $ABI->{"DepSymbols"}; } else { # support for old ABI dumps my $DepSymbols = $ABI->{"DepSymbols"}; if(not $DepSymbols) { $DepSymbols = $ABI->{"DepInterfaces"}; } if(not $DepSymbols) { # Cannot reconstruct DepSymbols. This may result in false # positives if the old dump is for library 2. Not a problem if # old dumps are only from old libraries. $DepSymbols = {}; } foreach my $Symbol (keys(%{$DepSymbols})) { $DepSymbol_Library{$LibVersion}{$Symbol} = 1; } } $SymVer{$LibVersion} = $ABI->{"SymbolVersion"}; if(my $V = $TargetVersion{$LibVersion}) { $Descriptor{$LibVersion}{"Version"} = $V; } else { $Descriptor{$LibVersion}{"Version"} = $ABI->{"LibraryVersion"}; } $SkipTypes{$LibVersion} = $ABI->{"SkipTypes"}; if(not $SkipTypes{$LibVersion}) { # support for old dumps $SkipTypes{$LibVersion} = $ABI->{"OpaqueTypes"}; } $SkipSymbols{$LibVersion} = $ABI->{"SkipSymbols"}; if(not $SkipSymbols{$LibVersion}) { # support for old dumps $SkipSymbols{$LibVersion} = $ABI->{"SkipInterfaces"}; } if(not $SkipSymbols{$LibVersion}) { # support for old dumps $SkipSymbols{$LibVersion} = $ABI->{"InternalInterfaces"}; } $SkipNameSpaces{$LibVersion} = $ABI->{"SkipNameSpaces"}; $TargetHeaders{$LibVersion} = $ABI->{"TargetHeaders"}; foreach my $Path (keys(%{$ABI->{"SkipHeaders"}})) { $SkipHeadersList{$LibVersion}{$Path} = $ABI->{"SkipHeaders"}{$Path}; my ($CPath, $Type) = classifyPath($Path); $SkipHeaders{$LibVersion}{$Type}{$CPath} = $ABI->{"SkipHeaders"}{$Path}; } read_Source_DumpInfo($ABI, $LibVersion); read_Libs_DumpInfo($ABI, $LibVersion); if(not checkDump($LibVersion, "2.10.1") or not $TargetHeaders{$LibVersion}) { # support for old ABI dumps: added target headers foreach (keys(%{$Registered_Headers{$LibVersion}})) { $TargetHeaders{$LibVersion}{get_filename($_)} = 1; } foreach (keys(%{$Registered_Sources{$LibVersion}})) { $TargetHeaders{$LibVersion}{get_filename($_)} = 1; } } $Constants{$LibVersion} = $ABI->{"Constants"}; if(defined $ABI->{"GccConstants"}) { # 3.0 foreach my $Name (keys(%{$ABI->{"GccConstants"}})) { $Constants{$LibVersion}{$Name}{"Value"} = $ABI->{"GccConstants"}{$Name}; } } $NestedNameSpaces{$LibVersion} = $ABI->{"NameSpaces"}; if(not $NestedNameSpaces{$LibVersion}) { # support for old dumps # Cannot reconstruct NameSpaces. This may affect design # of the compatibility report. $NestedNameSpaces{$LibVersion} = {}; } # target system type # needed to adopt HTML report if(not $DumpSystem) { # to use in createSymbolsList(...) $OStarget = $ABI->{"Target"}; } # recreate environment foreach my $Lib_Name (keys(%{$Library_Symbol{$LibVersion}})) { foreach my $Symbol (keys(%{$Library_Symbol{$LibVersion}{$Lib_Name}})) { $Symbol_Library{$LibVersion}{$Symbol} = $Lib_Name; if($Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol}<=-1) { # data marked as -size in the dump $GlobalDataObject{$LibVersion}{$Symbol} = -$Library_Symbol{$LibVersion}{$Lib_Name}{$Symbol}; } if($COMMON_LANGUAGE{$LibVersion} ne "C++") { if(index($Symbol, "_Z")==0 or index($Symbol, "?")==0) { setLanguage($LibVersion, "C++"); } } } } foreach my $Lib_Name (keys(%{$DepLibrary_Symbol{$LibVersion}})) { foreach my $Symbol (keys(%{$DepLibrary_Symbol{$LibVersion}{$Lib_Name}})) { $DepSymbol_Library{$LibVersion}{$Symbol} = $Lib_Name; } } my @VFunc = (); foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}})) { if(my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"}) { if(not $Symbol_Library{$LibVersion}{$MnglName} and not $DepSymbol_Library{$LibVersion}{$MnglName}) { push(@VFunc, $MnglName); } } } translateSymbols(@VFunc, $LibVersion); translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion); translateSymbols(keys(%{$DepSymbol_Library{$LibVersion}}), $LibVersion); if(not checkDump($LibVersion, "3.0")) { # support for old ABI dumps foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) { if(my $BaseType = $TypeInfo{$LibVersion}{$TypeId}{"BaseType"}) { if(ref($BaseType) eq "HASH") { $TypeInfo{$LibVersion}{$TypeId}{"BaseType"} = $TypeInfo{$LibVersion}{$TypeId}{"BaseType"}{"Tid"}; } } } } if(not checkDump($LibVersion, "3.2")) { # support for old ABI dumps foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) { if(defined $TypeInfo{$LibVersion}{$TypeId}{"VTable"}) { foreach my $Offset (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"VTable"}})) { $TypeInfo{$LibVersion}{$TypeId}{"VTable"}{$Offset} = simplifyVTable($TypeInfo{$LibVersion}{$TypeId}{"VTable"}{$Offset}); } } } # repair target headers list delete($TargetHeaders{$LibVersion}); foreach (keys(%{$Registered_Headers{$LibVersion}})) { $TargetHeaders{$LibVersion}{get_filename($_)} = 1; } foreach (keys(%{$Registered_Sources{$LibVersion}})) { $TargetHeaders{$LibVersion}{get_filename($_)} = 1; } # non-target constants from anon enums foreach my $Name (keys(%{$Constants{$LibVersion}})) { if(not $ExtraDump and not is_target_header($Constants{$LibVersion}{$Name}{"Header"}, $LibVersion)) { delete($Constants{$LibVersion}{$Name}); } } } if(not checkDump($LibVersion, "2.20")) { # support for old ABI dumps foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) { my $TType = $TypeInfo{$LibVersion}{$TypeId}{"Type"}; if($TType=~/Struct|Union|Enum|Typedef/) { # repair complex types first next; } if(my $BaseId = $TypeInfo{$LibVersion}{$TypeId}{"BaseType"}) { my $BType = lc($TypeInfo{$LibVersion}{$BaseId}{"Type"}); if($BType=~/Struct|Union|Enum/i) { my $BName = $TypeInfo{$LibVersion}{$BaseId}{"Name"}; $TypeInfo{$LibVersion}{$TypeId}{"Name"}=~s/\A\Q$BName\E\b/$BType $BName/g; } } } foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) { my $TType = $TypeInfo{$LibVersion}{$TypeId}{"Type"}; my $TName = $TypeInfo{$LibVersion}{$TypeId}{"Name"}; if($TType=~/Struct|Union|Enum/) { $TypeInfo{$LibVersion}{$TypeId}{"Name"} = lc($TType)." ".$TName; } } } foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}})) { # order is important if(defined $TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}) { # support for old ABI dumps < 2.0 (ACC 1.22) foreach my $BId (keys(%{$TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}})) { if(my $Access = $TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}{$BId}) { if($Access ne "public") { $TypeInfo{$LibVersion}{$TypeId}{"Base"}{$BId}{"access"} = $Access; } } $TypeInfo{$LibVersion}{$TypeId}{"Base"}{$BId} = {}; } delete($TypeInfo{$LibVersion}{$TypeId}{"BaseClass"}); } if(my $Header = $TypeInfo{$LibVersion}{$TypeId}{"Header"}) { # support for old ABI dumps $TypeInfo{$LibVersion}{$TypeId}{"Header"} = path_format($Header, $OSgroup); } elsif(my $Source = $TypeInfo{$LibVersion}{$TypeId}{"Source"}) { # DWARF ABI Dumps $TypeInfo{$LibVersion}{$TypeId}{"Header"} = $Source; } if(not defined $TypeInfo{$LibVersion}{$TypeId}{"Tid"}) { $TypeInfo{$LibVersion}{$TypeId}{"Tid"} = $TypeId; } my %TInfo = %{$TypeInfo{$LibVersion}{$TypeId}}; if(defined $TInfo{"Base"}) { foreach (keys(%{$TInfo{"Base"}})) { $Class_SubClasses{$LibVersion}{$_}{$TypeId}=1; } } if($TInfo{"Type"} eq "MethodPtr") { if(defined $TInfo{"Param"}) { # support for old ABI dumps <= 1.17 if(not defined $TInfo{"Param"}{"0"}) { my $Max = keys(%{$TInfo{"Param"}}); foreach my $Pos (1 .. $Max) { $TInfo{"Param"}{$Pos-1} = $TInfo{"Param"}{$Pos}; } delete($TInfo{"Param"}{$Max}); %{$TypeInfo{$LibVersion}{$TypeId}} = %TInfo; } } } if($TInfo{"BaseType"} eq $TypeId) { # fix ABI dump delete($TypeInfo{$LibVersion}{$TypeId}{"BaseType"}); } if($TInfo{"Type"} eq "Typedef" and not $TInfo{"Artificial"}) { if(my $BTid = $TInfo{"BaseType"}) { my $BName = $TypeInfo{$LibVersion}{$BTid}{"Name"}; if(not $BName) { # broken type next; } if($TInfo{"Name"} eq $BName) { # typedef to "class Class" # should not be registered in TName_Tid next; } if(not $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}}) { $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}} = $BName; } } } if(not $TName_Tid{$LibVersion}{$TInfo{"Name"}}) { # classes: class (id1), typedef (artificial, id2 > id1) $TName_Tid{$LibVersion}{formatName($TInfo{"Name"}, "T")} = $TypeId; } } if(not checkDump($LibVersion, "2.15")) { # support for old ABI dumps my %Dups = (); foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}})) { if(my $ClassId = $SymbolInfo{$LibVersion}{$InfoId}{"Class"}) { if(not defined $TypeInfo{$LibVersion}{$ClassId}) { # remove template decls delete($SymbolInfo{$LibVersion}{$InfoId}); next; } } my $MName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"}; if(not $MName and $SymbolInfo{$LibVersion}{$InfoId}{"Class"}) { # templates delete($SymbolInfo{$LibVersion}{$InfoId}); } } } foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}})) { if(my $Class = $SymbolInfo{$LibVersion}{$InfoId}{"Class"} and not $SymbolInfo{$LibVersion}{$InfoId}{"Static"} and not $SymbolInfo{$LibVersion}{$InfoId}{"Data"}) { # support for old ABI dumps (< 3.1) if(not defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"} or $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{0}{"name"} ne "this") { # add "this" first parameter my $ThisTid = getTypeIdByName($TypeInfo{$LibVersion}{$Class}{"Name"}."*const", $LibVersion); my %PInfo = ("name"=>"this", "type"=>"$ThisTid"); if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}) { my @Pos = sort {int($a)<=>int($b)} keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}}); foreach my $Pos (reverse(0 .. $#Pos)) { %{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$Pos+1}} = %{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$Pos}}; } } $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{"0"} = \%PInfo; } } if(not $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"}) { # ABI dumps have no mangled names for C-functions $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"}; } if(my $Header = $SymbolInfo{$LibVersion}{$InfoId}{"Header"}) { # support for old ABI dumps $SymbolInfo{$LibVersion}{$InfoId}{"Header"} = path_format($Header, $OSgroup); } elsif(my $Source = $SymbolInfo{$LibVersion}{$InfoId}{"Source"}) { # DWARF ABI Dumps $SymbolInfo{$LibVersion}{$InfoId}{"Header"} = $Source; } } $Descriptor{$LibVersion}{"Dump"} = 1; } sub read_Machine_DumpInfo($$) { my ($ABI, $LibVersion) = @_; if($ABI->{"Arch"}) { $CPU_ARCH{$LibVersion} = $ABI->{"Arch"}; } if($ABI->{"WordSize"}) { $WORD_SIZE{$LibVersion} = $ABI->{"WordSize"}; } else { # support for old dumps $WORD_SIZE{$LibVersion} = $ABI->{"SizeOfPointer"}; } if(not $WORD_SIZE{$LibVersion}) { # support for old dumps (<1.23) if(my $Tid = getTypeIdByName("char*", $LibVersion)) { # size of char* $WORD_SIZE{$LibVersion} = $TypeInfo{$LibVersion}{$Tid}{"Size"}; } else { my $PSize = 0; foreach my $Tid (keys(%{$TypeInfo{$LibVersion}})) { if($TypeInfo{$LibVersion}{$Tid}{"Type"} eq "Pointer") { # any "pointer"-type $PSize = $TypeInfo{$LibVersion}{$Tid}{"Size"}; last; } } if($PSize) { # a pointer type size $WORD_SIZE{$LibVersion} = $PSize; } else { printMsg("WARNING", "cannot identify a WORD size in the ABI dump (too old format)"); } } } if($ABI->{"GccVersion"}) { $GCC_VERSION{$LibVersion} = $ABI->{"GccVersion"}; } } sub read_Libs_DumpInfo($$) { my ($ABI, $LibVersion) = @_; $Library_Symbol{$LibVersion} = $ABI->{"Symbols"}; if(not $Library_Symbol{$LibVersion}) { # support for old dumps $Library_Symbol{$LibVersion} = $ABI->{"Interfaces"}; } if(keys(%{$Library_Symbol{$LibVersion}}) and not $DumpAPI) { $Descriptor{$LibVersion}{"Libs"} = "OK"; } } sub read_Source_DumpInfo($$) { my ($ABI, $LibVersion) = @_; if(keys(%{$ABI->{"Headers"}}) and not $DumpAPI) { $Descriptor{$LibVersion}{"Headers"} = "OK"; } foreach my $Identity (sort {$ABI->{"Headers"}{$a}<=>$ABI->{"Headers"}{$b}} keys(%{$ABI->{"Headers"}})) { # headers info is stored in the old dumps in the different way if($UseOldDumps and my $Name = $ABI->{"Headers"}{$Identity}{"Name"}) { # support for old dumps: headers info corrected in 1.22 $Identity = $Name; } $Registered_Headers{$LibVersion}{$Identity}{"Identity"} = $Identity; $Registered_Headers{$LibVersion}{$Identity}{"Pos"} = $ABI->{"Headers"}{$Identity}; } if(keys(%{$ABI->{"Sources"}}) and not $DumpAPI) { $Descriptor{$LibVersion}{"Sources"} = "OK"; } foreach my $Name (sort {$ABI->{"Sources"}{$a}<=>$ABI->{"Sources"}{$b}} keys(%{$ABI->{"Sources"}})) { # headers info is stored in the old dumps in the different way $Registered_Sources{$LibVersion}{$Name}{"Identity"} = $Name; $Registered_Sources{$LibVersion}{$Name}{"Pos"} = $ABI->{"Headers"}{$Name}; } } sub find_libs($$$) { my ($Path, $Type, $MaxDepth) = @_; # FIXME: correct the search pattern return cmd_find($Path, $Type, '\.'.$LIB_EXT.'[0-9.]*\Z', $MaxDepth, 1); } sub createDescriptor($$) { my ($LibVersion, $Path) = @_; if(not $LibVersion or not $Path or not -e $Path) { return ""; } if(-d $Path) { # directory with headers files and shared objects return " ".$TargetVersion{$LibVersion}." $Path $Path "; } else { # files if($Path=~/\.(xml|desc)\Z/i) { # standard XML-descriptor return readFile($Path); } elsif(is_header($Path, 2, $LibVersion)) { # header file return " ".$TargetVersion{$LibVersion}." $Path none "; } elsif(parse_libname($Path, "name", $OStarget)) { # shared object return " ".$TargetVersion{$LibVersion}." none $Path "; } else { # standard XML-descriptor return readFile($Path); } } } sub detect_lib_default_paths() { my %LPaths = (); if($OSgroup eq "bsd") { if(my $LdConfig = get_CmdPath("ldconfig")) { foreach my $Line (split(/\n/, `$LdConfig -r 2>\"$TMP_DIR/null\"`)) { if($Line=~/\A[ \t]*\d+:\-l(.+) \=\> (.+)\Z/) { my $Name = "lib".$1; if(not defined $LPaths{$Name}) { $LPaths{$Name} = $2; } } } } else { printMsg("WARNING", "can't find ldconfig"); } } else { if(my $LdConfig = get_CmdPath("ldconfig")) { if($SystemRoot and $OSgroup eq "linux") { # use host (x86) ldconfig with the target (arm) ld.so.conf if(-e $SystemRoot."/etc/ld.so.conf") { $LdConfig .= " -f ".$SystemRoot."/etc/ld.so.conf"; } } foreach my $Line (split(/\n/, `$LdConfig -p 2>\"$TMP_DIR/null\"`)) { if($Line=~/\A[ \t]*([^ \t]+) .* \=\> (.+)\Z/) { my ($Name, $Path) = ($1, $2); $Path=~s/[\/]{2,}/\//; if(not defined $LPaths{$Name}) { # get first element from the list of available paths # libstdc++.so.6 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 # libstdc++.so.6 (libc6) => /usr/lib/i386-linux-gnu/libstdc++.so.6 # libstdc++.so.6 (libc6) => /usr/lib32/libstdc++.so.6 $LPaths{$Name} = $Path; } } } } elsif($OSgroup eq "linux") { printMsg("WARNING", "can't find ldconfig"); } } return \%LPaths; } sub detect_bin_default_paths() { my $EnvPaths = $ENV{"PATH"}; if($OSgroup eq "beos") { $EnvPaths.=":".$ENV{"BETOOLS"}; } my $Sep = ($OSgroup eq "windows")?";":":|;"; foreach my $Path (split(/$Sep/, $EnvPaths)) { $Path = path_format($Path, $OSgroup); next if(not $Path); if($SystemRoot and $Path=~/\A\Q$SystemRoot\E\//) { # do NOT use binaries from target system next; } push_U(\@DefaultBinPaths, $Path); } } sub detect_inc_default_paths() { return () if(not $GCC_PATH); my %DPaths = ("Cpp"=>[],"Gcc"=>[],"Inc"=>[]); writeFile("$TMP_DIR/empty.h", ""); foreach my $Line (split(/\n/, `$GCC_PATH -v -x c++ -E \"$TMP_DIR/empty.h\" 2>&1`)) { # detecting GCC default include paths next if(index($Line, "/cc1plus ")!=-1); if($Line=~/\A[ \t]*((\/|\w+:\\).+)[ \t]*\Z/) { my $Path = realpath($1); $Path = path_format($Path, $OSgroup); if(index($Path, "c++")!=-1 or index($Path, "/g++/")!=-1) { push_U($DPaths{"Cpp"}, $Path); if(not defined $MAIN_CPP_DIR or get_depth($MAIN_CPP_DIR)>get_depth($Path)) { $MAIN_CPP_DIR = $Path; } } elsif(index($Path, "gcc")!=-1) { push_U($DPaths{"Gcc"}, $Path); } else { if($Path=~/local[\/\\]+include/) { # local paths next; } if($SystemRoot and $Path!~/\A\Q$SystemRoot\E(\/|\Z)/) { # The GCC include path for user headers is not a part of the system root # The reason: you are not specified the --cross-gcc option or selected a wrong compiler # or it is the internal cross-GCC path like arm-linux-gnueabi/include next; } push_U($DPaths{"Inc"}, $Path); } } } unlink("$TMP_DIR/empty.h"); return %DPaths; } sub detect_default_paths($) { my ($HSearch, $LSearch, $BSearch, $GSearch) = (1, 1, 1, 1); my $Search = $_[0]; if($Search!~/inc/) { $HSearch = 0; } if($Search!~/lib/) { $LSearch = 0; } if($Search!~/bin/) { $BSearch = 0; } if($Search!~/gcc/) { $GSearch = 0; } if(@{$SystemPaths{"include"}}) { # section of the XML descriptor # do NOT search for systems headers $HSearch = 0; } if(@{$SystemPaths{"lib"}}) { # section of the XML descriptor # do NOT search for systems headers $LSearch = 0; } foreach my $Type (keys(%{$OS_AddPath{$OSgroup}})) { # additional search paths next if($Type eq "include" and not $HSearch); next if($Type eq "lib" and not $LSearch); next if($Type eq "bin" and not $BSearch); push_U($SystemPaths{$Type}, grep { -d $_ } @{$OS_AddPath{$OSgroup}{$Type}}); } if($OSgroup ne "windows") { # unix-like foreach my $Type ("include", "lib", "bin") { # automatic detection of system "devel" directories next if($Type eq "include" and not $HSearch); next if($Type eq "lib" and not $LSearch); next if($Type eq "bin" and not $BSearch); my ($UsrDir, $RootDir) = ("/usr", "/"); if($SystemRoot and $Type ne "bin") { # 1. search for target headers and libraries # 2. use host commands: ldconfig, readelf, etc. ($UsrDir, $RootDir) = ("$SystemRoot/usr", $SystemRoot); } push_U($SystemPaths{$Type}, cmd_find($RootDir,"d","*$Type*",1)); if(-d $RootDir."/".$Type) { # if "/lib" is symbolic link if($RootDir eq "/") { push_U($SystemPaths{$Type}, "/".$Type); } else { push_U($SystemPaths{$Type}, $RootDir."/".$Type); } } if(-d $UsrDir) { push_U($SystemPaths{$Type}, cmd_find($UsrDir,"d","*$Type*",1)); if(-d $UsrDir."/".$Type) { # if "/usr/lib" is symbolic link push_U($SystemPaths{$Type}, $UsrDir."/".$Type); } } } } if($BSearch) { detect_bin_default_paths(); push_U($SystemPaths{"bin"}, @DefaultBinPaths); } # check environment variables if($OSgroup eq "beos") { foreach (my @Paths = @{$SystemPaths{"bin"}}) { if($_ eq ".") { next; } # search for /boot/develop/abi/x86/gcc4/tools/gcc-4.4.4-haiku-101111/bin/ if(my @Dirs = sort cmd_find($_, "d", "bin")) { push_U($SystemPaths{"bin"}, sort {get_depth($a)<=>get_depth($b)} @Dirs); } } if($HSearch) { push_U(\@DefaultIncPaths, grep { is_abs($_) } ( split(/:|;/, $ENV{"BEINCLUDES"}) )); } if($LSearch) { push_U(\@DefaultLibPaths, grep { is_abs($_) } ( split(/:|;/, $ENV{"BELIBRARIES"}), split(/:|;/, $ENV{"LIBRARY_PATH"}) )); } } if($LSearch) { # using linker to get system paths if(my $LPaths = detect_lib_default_paths()) { # unix-like my %Dirs = (); foreach my $Name (keys(%{$LPaths})) { if($SystemRoot and $LPaths->{$Name}!~/\A\Q$SystemRoot\E\//) { # wrong ldconfig configuration # check your /etc/ld.so.conf next; } $DyLib_DefaultPath{$Name} = $LPaths->{$Name}; if(my $Dir = get_dirname($LPaths->{$Name})) { $Dirs{$Dir} = 1; } } push_U(\@DefaultLibPaths, sort {get_depth($a)<=>get_depth($b)} sort keys(%Dirs)); } push_U($SystemPaths{"lib"}, @DefaultLibPaths); } if($BSearch) { if($CrossGcc) { # --cross-gcc=arm-linux-gcc if(-e $CrossGcc) { # absolute or relative path $GCC_PATH = get_abs_path($CrossGcc); } elsif($CrossGcc!~/\// and get_CmdPath($CrossGcc)) { # command name $GCC_PATH = $CrossGcc; } else { exitStatus("Access_Error", "can't access \'$CrossGcc\'"); } if($GCC_PATH=~/\s/) { $GCC_PATH = "\"".$GCC_PATH."\""; } } } if($GSearch) { # GCC path and default include dirs if(not $CrossGcc) { # try default gcc $GCC_PATH = get_CmdPath("gcc"); } if(not $GCC_PATH) { # try to find gcc-X.Y foreach my $Path (@{$SystemPaths{"bin"}}) { if(my @GCCs = cmd_find($Path, "", '/gcc-[0-9.]*\Z', 1, 1)) { # select the latest version @GCCs = sort {$b cmp $a} @GCCs; if(check_gcc($GCCs[0], "3")) { $GCC_PATH = $GCCs[0]; last; } } } } if(not $GCC_PATH) { exitStatus("Not_Found", "can't find GCC>=3.0 in PATH"); } if(not $CheckObjectsOnly_Opt) { if(my $GCC_Ver = get_dumpversion($GCC_PATH)) { my $GccTarget = get_dumpmachine($GCC_PATH); printMsg("INFO", "Using GCC $GCC_Ver ($GccTarget)"); if($GccTarget=~/symbian/) { $OStarget = "symbian"; $LIB_EXT = $OS_LibExt{$LIB_TYPE}{$OStarget}; } # check GCC version if($GCC_Ver=~/\A4\.8(|\.[012])\Z/) { # bug http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57850 # introduced in 4.8 # fixed in 4.8.3 printMsg("WARNING", "Not working properly with GCC $GCC_Ver. Please update or downgrade GCC or use a local installation by --gcc-path=PATH option."); $EMERGENCY_MODE_48 = 1; } } else { exitStatus("Error", "something is going wrong with the GCC compiler"); } } if($HSearch) { if(not $NoStdInc) { # do NOT search in GCC standard paths my %DPaths = detect_inc_default_paths(); @DefaultCppPaths = @{$DPaths{"Cpp"}}; @DefaultGccPaths = @{$DPaths{"Gcc"}}; @DefaultIncPaths = @{$DPaths{"Inc"}}; push_U($SystemPaths{"include"}, @DefaultIncPaths); } } } if($HSearch) { # users include paths my $IncPath = "/usr/include"; if($SystemRoot) { $IncPath = $SystemRoot.$IncPath; } if(-d $IncPath) { push_U(\@UsersIncPath, $IncPath); } } if($ExtraInfo) { writeFile($ExtraInfo."/default-libs", join("\n", @DefaultLibPaths)); writeFile($ExtraInfo."/default-includes", join("\n", (@DefaultCppPaths, @DefaultGccPaths, @DefaultIncPaths))); } } sub getLIB_EXT($) { my $Target = $_[0]; if(my $Ext = $OS_LibExt{$LIB_TYPE}{$Target}) { return $Ext; } return $OS_LibExt{$LIB_TYPE}{"default"}; } sub getAR_EXT($) { my $Target = $_[0]; if(my $Ext = $OS_Archive{$Target}) { return $Ext; } return $OS_Archive{"default"}; } sub get_dumpversion($) { my $Cmd = $_[0]; return "" if(not $Cmd); if($Cache{"get_dumpversion"}{$Cmd}) { return $Cache{"get_dumpversion"}{$Cmd}; } my $V = `$Cmd -dumpversion 2>\"$TMP_DIR/null\"`; chomp($V); return ($Cache{"get_dumpversion"}{$Cmd} = $V); } sub get_dumpmachine($) { my $Cmd = $_[0]; return "" if(not $Cmd); if($Cache{"get_dumpmachine"}{$Cmd}) { return $Cache{"get_dumpmachine"}{$Cmd}; } my $Machine = `$Cmd -dumpmachine 2>\"$TMP_DIR/null\"`; chomp($Machine); return ($Cache{"get_dumpmachine"}{$Cmd} = $Machine); } sub checkCmd($) { my $Cmd = $_[0]; return "" if(not $Cmd); my @Options = ( "--version", "-help" ); foreach my $Opt (@Options) { my $Info = `$Cmd $Opt 2>\"$TMP_DIR/null\"`; if($Info) { return 1; } } return 0; } sub check_gcc($$) { my ($Cmd, $ReqVer) = @_; return 0 if(not $Cmd or not $ReqVer); if(defined $Cache{"check_gcc"}{$Cmd}{$ReqVer}) { return $Cache{"check_gcc"}{$Cmd}{$ReqVer}; } if(my $GccVer = get_dumpversion($Cmd)) { $GccVer=~s/(-|_)[a-z_]+.*\Z//; # remove suffix (like "-haiku-100818") if(cmpVersions($GccVer, $ReqVer)>=0) { return ($Cache{"check_gcc"}{$Cmd}{$ReqVer} = $Cmd); } } return ($Cache{"check_gcc"}{$Cmd}{$ReqVer} = ""); } sub get_depth($) { if(defined $Cache{"get_depth"}{$_[0]}) { return $Cache{"get_depth"}{$_[0]}; } return ($Cache{"get_depth"}{$_[0]} = ($_[0]=~tr![\/\\]|\:\:!!)); } sub registerGccHeaders() { return if($Cache{"registerGccHeaders"}); # this function should be called once foreach my $Path (@DefaultGccPaths) { my @Headers = cmd_find($Path,"f"); @Headers = sort {get_depth($a)<=>get_depth($b)} @Headers; foreach my $HPath (@Headers) { my $FileName = get_filename($HPath); if(not defined $DefaultGccHeader{$FileName}) { # skip duplicated $DefaultGccHeader{$FileName} = $HPath; } } } $Cache{"registerGccHeaders"} = 1; } sub registerCppHeaders() { return if($Cache{"registerCppHeaders"}); # this function should be called once foreach my $CppDir (@DefaultCppPaths) { my @Headers = cmd_find($CppDir,"f"); @Headers = sort {get_depth($a)<=>get_depth($b)} @Headers; foreach my $Path (@Headers) { my $FileName = get_filename($Path); if(not defined $DefaultCppHeader{$FileName}) { # skip duplicated $DefaultCppHeader{$FileName} = $Path; } } } $Cache{"registerCppHeaders"} = 1; } sub parse_libname($$$) { return "" if(not $_[0]); if(defined $Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]}) { return $Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]}; } return ($Cache{"parse_libname"}{$_[2]}{$_[1]}{$_[0]} = parse_libname_I(@_)); } sub parse_libname_I($$$) { my ($Name, $Type, $Target) = @_; if($Target eq "symbian") { return parse_libname_symbian($Name, $Type); } elsif($Target eq "windows") { return parse_libname_windows($Name, $Type); } # unix my $Ext = getLIB_EXT($Target); if($Name=~/((((lib|).+?)([\-\_][\d\-\.\_]+.*?|))\.$Ext)(\.(.+)|)\Z/) { # libSDL-1.2.so.0.7.1 # libwbxml2.so.0.0.18 # libopcodes-2.21.53-system.20110810.so if($Type eq "name") { # libSDL-1.2 # libwbxml2 return $2; } elsif($Type eq "name+ext") { # libSDL-1.2.so # libwbxml2.so return $1; } elsif($Type eq "version") { if(defined $7 and $7 ne "") { # 0.7.1 return $7; } else { # libc-2.5.so (=>2.5 version) my $MV = $5; $MV=~s/\A[\-\_]+//g; return $MV; } } elsif($Type eq "short") { # libSDL # libwbxml2 return $3; } elsif($Type eq "shortest") { # SDL # wbxml return shortest_name($3); } } return "";# error } sub parse_libname_symbian($$) { my ($Name, $Type) = @_; my $Ext = getLIB_EXT("symbian"); if($Name=~/(((.+?)(\{.+\}|))\.$Ext)\Z/) { # libpthread{00010001}.dso if($Type eq "name") { # libpthread{00010001} return $2; } elsif($Type eq "name+ext") { # libpthread{00010001}.dso return $1; } elsif($Type eq "version") { # 00010001 my $V = $4; $V=~s/\{(.+)\}/$1/; return $V; } elsif($Type eq "short") { # libpthread return $3; } elsif($Type eq "shortest") { # pthread return shortest_name($3); } } return "";# error } sub parse_libname_windows($$) { my ($Name, $Type) = @_; my $Ext = getLIB_EXT("windows"); if($Name=~/((.+?)\.$Ext)\Z/) { # netapi32.dll if($Type eq "name") { # netapi32 return $2; } elsif($Type eq "name+ext") { # netapi32.dll return $1; } elsif($Type eq "version") { # DLL version embedded # at binary-level return ""; } elsif($Type eq "short") { # netapi32 return $2; } elsif($Type eq "shortest") { # netapi return shortest_name($2); } } return "";# error } sub shortest_name($) { my $Name = $_[0]; # remove prefix $Name=~s/\A(lib|open)//; # remove suffix $Name=~s/[\W\d_]+\Z//i; $Name=~s/([a-z]{2,})(lib)\Z/$1/i; return $Name; } sub createSymbolsList($$$$$) { my ($DPath, $SaveTo, $LName, $LVersion, $ArchName) = @_; read_ABI_Dump(1, $DPath); if(not $CheckObjectsOnly) { prepareSymbols(1); } my %SymbolHeaderLib = (); my $Total = 0; # Get List foreach my $Symbol (sort keys(%{$CompleteSignature{1}})) { if(not link_symbol($Symbol, 1, "-Deps")) { # skip src only and all external functions next; } if(not symbolFilter($Symbol, 1, "Public", "Binary")) { # skip other symbols next; } my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"}; if(not $HeaderName) { # skip src only and all external functions next; } my $DyLib = $Symbol_Library{1}{$Symbol}; if(not $DyLib) { # skip src only and all external functions next; } $SymbolHeaderLib{$HeaderName}{$DyLib}{$Symbol} = 1; $Total+=1; } # Draw List my $SYMBOLS_LIST = "

Public symbols in $LName ($LVersion)"; $SYMBOLS_LIST .= " on ".showArch($ArchName)."
Total: $Total


"; foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%SymbolHeaderLib)) { foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$SymbolHeaderLib{$HeaderName}})) { my %NS_Symbol = (); foreach my $Symbol (keys(%{$SymbolHeaderLib{$HeaderName}{$DyLib}})) { $NS_Symbol{select_Symbol_NS($Symbol, 1)}{$Symbol} = 1; } foreach my $NameSpace (sort keys(%NS_Symbol)) { $SYMBOLS_LIST .= getTitle($HeaderName, $DyLib, $NameSpace); my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NS_Symbol{$NameSpace}}); foreach my $Symbol (@SortedInterfaces) { my $SubReport = ""; my $Signature = get_Signature($Symbol, 1); if($NameSpace) { $Signature=~s/\b\Q$NameSpace\E::\b//g; } if($Symbol=~/\A(_Z|\?)/) { if($Signature) { $SubReport = insertIDs($ContentSpanStart.highLight_Signature_Italic_Color($Signature).$ContentSpanEnd."
\n".$ContentDivStart."[symbol: $Symbol]

".$ContentDivEnd."\n"); } else { $SubReport = "".$Symbol."
\n"; } } else { if($Signature) { $SubReport = "".highLight_Signature_Italic_Color($Signature)."
\n"; } else { $SubReport = "".$Symbol."
\n"; } } $SYMBOLS_LIST .= $SubReport; } } $SYMBOLS_LIST .= "
\n"; } } # clear info (%TypeInfo, %SymbolInfo, %Library_Symbol, %DepSymbol_Library, %DepLibrary_Symbol, %SymVer, %SkipTypes, %SkipSymbols, %NestedNameSpaces, %ClassMethods, %AllocableClass, %ClassNames, %CompleteSignature, %SkipNameSpaces, %Symbol_Library, %Library_Symbol) = (); ($Content_Counter, $ContentID) = (0, 0); # print report my $CssStyles = readModule("Styles", "SymbolsList.css"); my $JScripts = readModule("Scripts", "Sections.js"); $SYMBOLS_LIST = "".$SYMBOLS_LIST.$TOP_REF."
\n"; my $Title = "$LName: public symbols"; my $Keywords = "$LName, API, symbols"; my $Description = "List of symbols in $LName ($LVersion) on ".showArch($ArchName); $SYMBOLS_LIST = composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."
\n$SYMBOLS_LIST



\n".getReportFooter($LName, 1)."
"; writeFile($SaveTo, $SYMBOLS_LIST); } sub add_target_libs($) { foreach (@{$_[0]}) { $TargetLibs{$_} = 1; } } sub is_target_lib($) { my $LName = $_[0]; if(not $LName) { return 0; } if($TargetLibraryName and $LName!~/\Q$TargetLibraryName\E/) { return 0; } if(keys(%TargetLibs) and not $TargetLibs{$LName} and not $TargetLibs{parse_libname($LName, "name+ext", $OStarget)}) { return 0; } return 1; } sub is_target_header($$) { # --header, --headers-list my ($H, $V) = @_; if(keys(%{$TargetHeaders{$V}})) { if($TargetHeaders{$V}{$H}) { return 1; } } return 0; } sub checkVersionNum($$) { my ($LibVersion, $Path) = @_; if(my $VerNum = $TargetVersion{$LibVersion}) { return $VerNum; } my $UsedAltDescr = 0; foreach my $Part (split(/\s*,\s*/, $Path)) { # try to get version string from file path next if(isDump($Part)); # ABI dump next if($Part=~/\.(xml|desc)\Z/i); # XML descriptor my $VerNum = ""; if(parse_libname($Part, "name", $OStarget)) { $UsedAltDescr = 1; $VerNum = parse_libname($Part, "version", $OStarget); if(not $VerNum) { $VerNum = readStrVer($Part); } } elsif(is_header($Part, 2, $LibVersion) or -d $Part) { $UsedAltDescr = 1; $VerNum = readStrVer($Part); } if($VerNum ne "") { $TargetVersion{$LibVersion} = $VerNum; if($DumpAPI) { printMsg("WARNING", "setting version number to $VerNum (use -vnum option to change it)"); } else { printMsg("WARNING", "setting ".($LibVersion==1?"1st":"2nd")." version number to \"$VerNum\" (use -v$LibVersion option to change it)"); } return $TargetVersion{$LibVersion}; } } if($UsedAltDescr) { if($DumpAPI) { exitStatus("Error", "version number is not set (use -vnum option)"); } else { exitStatus("Error", ($LibVersion==1?"1st":"2nd")." version number is not set (use -v$LibVersion option)"); } } } sub readStrVer($) { my $Str = $_[0]; return "" if(not $Str); $Str=~s/\Q$TargetLibraryName\E//g; if($Str=~/(\/|\\|\w|\A)[\-\_]*(\d+[\d\.\-]+\d+|\d+)/) { # .../libssh-0.4.0/... return $2; } elsif(my $V = parse_libname($Str, "version", $OStarget)) { return $V; } return ""; } sub readLibs($) { my $LibVersion = $_[0]; if($OStarget eq "windows") { # dumpbin.exe will crash # without VS Environment check_win32_env(); } readSymbols($LibVersion); translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion); translateSymbols(keys(%{$DepSymbol_Library{$LibVersion}}), $LibVersion); } sub dump_sorting($) { my $Hash = $_[0]; return [] if(not $Hash); my @Keys = keys(%{$Hash}); return [] if($#Keys<0); if($Keys[0]=~/\A\d+\Z/) { # numbers return [sort {int($a)<=>int($b)} @Keys]; } else { # strings return [sort {$a cmp $b} @Keys]; } } sub printMsg($$) { my ($Type, $Msg) = @_; if($Type!~/\AINFO/) { $Msg = $Type.": ".$Msg; } if($Type!~/_C\Z/) { $Msg .= "\n"; } if($Quiet) { # --quiet option appendFile($COMMON_LOG_PATH, $Msg); } else { if($Type eq "ERROR") { print STDERR $Msg; } else { print $Msg; } } } sub exitStatus($$) { my ($Code, $Msg) = @_; printMsg("ERROR", $Msg); exit($ERROR_CODE{$Code}); } sub exitReport() { # the tool has run without any errors printReport(); if($COMPILE_ERRORS) { # errors in headers may add false positives/negatives exit($ERROR_CODE{"Compile_Error"}); } if($BinaryOnly and $RESULT{"Binary"}{"Problems"}) { # --binary exit($ERROR_CODE{"Incompatible"}); } elsif($SourceOnly and $RESULT{"Source"}{"Problems"}) { # --source exit($ERROR_CODE{"Incompatible"}); } elsif($RESULT{"Source"}{"Problems"} or $RESULT{"Binary"}{"Problems"}) { # default exit($ERROR_CODE{"Incompatible"}); } else { exit($ERROR_CODE{"Compatible"}); } } sub readRules($) { my $Kind = $_[0]; if(not -f $RULES_PATH{$Kind}) { exitStatus("Module_Error", "can't access \'".$RULES_PATH{$Kind}."\'"); } my $Content = readFile($RULES_PATH{$Kind}); while(my $Rule = parseTag(\$Content, "rule")) { my $RId = parseTag(\$Rule, "id"); my @Properties = ("Severity", "Change", "Effect", "Overcome", "Kind"); foreach my $Prop (@Properties) { if(my $Value = parseTag(\$Rule, lc($Prop))) { $Value=~s/\n[ ]*//; $CompatRules{$Kind}{$RId}{$Prop} = $Value; } } if($CompatRules{$Kind}{$RId}{"Kind"}=~/\A(Symbols|Parameters)\Z/) { $CompatRules{$Kind}{$RId}{"Kind"} = "Symbols"; } else { $CompatRules{$Kind}{$RId}{"Kind"} = "Types"; } } } sub getReportPath($) { my $Level = $_[0]; my $Dir = "compat_reports/$TargetLibraryName/".$Descriptor{1}{"Version"}."_to_".$Descriptor{2}{"Version"}; if($Level eq "Binary") { if($BinaryReportPath) { # --bin-report-path return $BinaryReportPath; } elsif($OutputReportPath) { # --report-path return $OutputReportPath; } else { # default return $Dir."/abi_compat_report.$ReportFormat"; } } elsif($Level eq "Source") { if($SourceReportPath) { # --src-report-path return $SourceReportPath; } elsif($OutputReportPath) { # --report-path return $OutputReportPath; } else { # default return $Dir."/src_compat_report.$ReportFormat"; } } else { if($OutputReportPath) { # --report-path return $OutputReportPath; } else { # default return $Dir."/compat_report.$ReportFormat"; } } } sub printStatMsg($) { my $Level = $_[0]; printMsg("INFO", "total \"$Level\" compatibility problems: ".$RESULT{$Level}{"Problems"}.", warnings: ".$RESULT{$Level}{"Warnings"}); } sub listAffected($) { my $Level = $_[0]; my $List = ""; foreach (keys(%{$TotalAffected{$Level}})) { if($StrictCompat and $TotalAffected{$Level}{$_} eq "Low") { # skip "Low"-severity problems next; } $List .= "$_\n"; } my $Dir = get_dirname(getReportPath($Level)); if($Level eq "Binary") { writeFile($Dir."/abi_affected.txt", $List); } elsif($Level eq "Source") { writeFile($Dir."/src_affected.txt", $List); } } sub printReport() { printMsg("INFO", "creating compatibility report ..."); createReport(); if($JoinReport or $DoubleReport) { if($RESULT{"Binary"}{"Problems"} or $RESULT{"Source"}{"Problems"}) { printMsg("INFO", "result: INCOMPATIBLE (Binary: ".$RESULT{"Binary"}{"Affected"}."\%, Source: ".$RESULT{"Source"}{"Affected"}."\%)"); } else { printMsg("INFO", "result: COMPATIBLE"); } printStatMsg("Binary"); printStatMsg("Source"); if($ListAffected) { # --list-affected listAffected("Binary"); listAffected("Source"); } } elsif($BinaryOnly) { if($RESULT{"Binary"}{"Problems"}) { printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Binary"}{"Affected"}."\%)"); } else { printMsg("INFO", "result: COMPATIBLE"); } printStatMsg("Binary"); if($ListAffected) { # --list-affected listAffected("Binary"); } } elsif($SourceOnly) { if($RESULT{"Source"}{"Problems"}) { printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Source"}{"Affected"}."\%)"); } else { printMsg("INFO", "result: COMPATIBLE"); } printStatMsg("Source"); if($ListAffected) { # --list-affected listAffected("Source"); } } if($StdOut) { if($JoinReport or not $DoubleReport) { # --binary or --source printMsg("INFO", "compatibility report has been generated to stdout"); } else { # default printMsg("INFO", "compatibility reports have been generated to stdout"); } } else { if($JoinReport) { printMsg("INFO", "see detailed report:\n ".getReportPath("Join")); } elsif($DoubleReport) { # default printMsg("INFO", "see detailed reports:\n ".getReportPath("Binary")."\n ".getReportPath("Source")); } elsif($BinaryOnly) { # --binary printMsg("INFO", "see detailed report:\n ".getReportPath("Binary")); } elsif($SourceOnly) { # --source printMsg("INFO", "see detailed report:\n ".getReportPath("Source")); } } } sub check_win32_env() { if(not $ENV{"DevEnvDir"} or not $ENV{"LIB"}) { exitStatus("Error", "can't start without VS environment (vsvars32.bat)"); } } sub diffSets($$) { my ($S1, $S2) = @_; my @SK1 = keys(%{$S1}); my @SK2 = keys(%{$S2}); if($#SK1!=$#SK2) { return 1; } foreach my $K1 (@SK1) { if(not defined $S2->{$K1}) { return 1; } } return 0; } sub create_ABI_Dump() { if(not -e $DumpAPI) { exitStatus("Access_Error", "can't access \'$DumpAPI\'"); } my @DParts = split(/\s*,\s*/, $DumpAPI); foreach my $Part (@DParts) { if(not -e $Part) { exitStatus("Access_Error", "can't access \'$Part\'"); } } checkVersionNum(1, $DumpAPI); foreach my $Part (@DParts) { if(isDump($Part)) { read_ABI_Dump(1, $Part); } else { readDescriptor(1, createDescriptor(1, $Part)); } } if(not $Descriptor{1}{"Version"}) { # set to default: X $Descriptor{1}{"Version"} = "X"; } initLogging(1); detect_default_paths("inc|lib|bin|gcc"); # complete analysis my $DumpPath = "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi"; $DumpPath .= ".".$AR_EXT; # gzipped by default if($OutputDumpPath) { # user defined path $DumpPath = $OutputDumpPath; } my $Archive = ($DumpPath=~s/\Q.$AR_EXT\E\Z//g); if(not $Archive and not $StdOut) { # check archive utilities if($OSgroup eq "windows") { # using zip my $ZipCmd = get_CmdPath("zip"); if(not $ZipCmd) { exitStatus("Not_Found", "can't find \"zip\""); } } else { # using tar and gzip my $TarCmd = get_CmdPath("tar"); if(not $TarCmd) { exitStatus("Not_Found", "can't find \"tar\""); } my $GzipCmd = get_CmdPath("gzip"); if(not $GzipCmd) { exitStatus("Not_Found", "can't find \"gzip\""); } } } if(not $Descriptor{1}{"Dump"}) { if(not $CheckHeadersOnly) { readLibs(1); } if($CheckHeadersOnly) { setLanguage(1, "C++"); } if(not $CheckObjectsOnly) { searchForHeaders(1); } $WORD_SIZE{1} = detectWordSize(); } if(not $Descriptor{1}{"Dump"}) { if($Descriptor{1}{"Headers"}) { readHeaders(1); } } cleanDump(1); if(not keys(%{$SymbolInfo{1}})) { # check if created dump is valid if(not $ExtendedCheck and not $CheckObjectsOnly) { if($CheckHeadersOnly) { exitStatus("Empty_Set", "the set of public symbols is empty"); } else { exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection"); } } } my %HeadersInfo = (); foreach my $HPath (keys(%{$Registered_Headers{1}})) { $HeadersInfo{$Registered_Headers{1}{$HPath}{"Identity"}} = $Registered_Headers{1}{$HPath}{"Pos"}; } if($ExtraDump) { # add unmangled names to the ABI dump my @Names = (); foreach my $InfoId (keys(%{$SymbolInfo{1}})) { if(my $MnglName = $SymbolInfo{1}{$InfoId}{"MnglName"}) { push(@Names, $MnglName); } } translateSymbols(@Names, 1); foreach my $InfoId (keys(%{$SymbolInfo{1}})) { if(my $MnglName = $SymbolInfo{1}{$InfoId}{"MnglName"}) { if(my $Unmangled = $tr_name{$MnglName}) { if($MnglName ne $Unmangled) { $SymbolInfo{1}{$InfoId}{"Unmangled"} = $Unmangled; } } } } } my %GccConstants = (); # built-in GCC constants foreach my $Name (keys(%{$Constants{1}})) { if(not defined $Constants{1}{$Name}{"Header"}) { $GccConstants{$Name} = $Constants{1}{$Name}{"Value"}; delete($Constants{1}{$Name}); } } printMsg("INFO", "creating library ABI dump ..."); my %ABI = ( "TypeInfo" => $TypeInfo{1}, "SymbolInfo" => $SymbolInfo{1}, "Symbols" => $Library_Symbol{1}, "DepSymbols" => $DepLibrary_Symbol{1}, "SymbolVersion" => $SymVer{1}, "LibraryVersion" => $Descriptor{1}{"Version"}, "LibraryName" => $TargetLibraryName, "Language" => $COMMON_LANGUAGE{1}, "SkipTypes" => $SkipTypes{1}, "SkipSymbols" => $SkipSymbols{1}, "SkipNameSpaces" => $SkipNameSpaces{1}, "SkipHeaders" => $SkipHeadersList{1}, "Headers" => \%HeadersInfo, "Constants" => $Constants{1}, "GccConstants" => \%GccConstants, "NameSpaces" => $NestedNameSpaces{1}, "Target" => $OStarget, "Arch" => getArch(1), "WordSize" => $WORD_SIZE{1}, "GccVersion" => get_dumpversion($GCC_PATH), "ABI_DUMP_VERSION" => $ABI_DUMP_VERSION, "ABI_COMPLIANCE_CHECKER_VERSION" => $TOOL_VERSION ); if(diffSets($TargetHeaders{1}, \%HeadersInfo)) { $ABI{"TargetHeaders"} = $TargetHeaders{1}; } if($UseXML) { $ABI{"XML_ABI_DUMP_VERSION"} = $XML_ABI_DUMP_VERSION; } if($ExtendedCheck) { # --ext option $ABI{"Mode"} = "Extended"; } if($BinaryOnly) { # --binary $ABI{"BinOnly"} = 1; } if($ExtraDump) { # --extra-dump $ABI{"Extra"} = 1; $ABI{"UndefinedSymbols"} = $UndefinedSymbols{1}; $ABI{"Needed"} = $Library_Needed{1}; } my $ABI_DUMP = ""; if($UseXML) { loadModule("XmlDump"); $ABI_DUMP = createXmlDump(\%ABI); } else { # default $ABI_DUMP = Dumper(\%ABI); } if($StdOut) { # --stdout option print STDOUT $ABI_DUMP; printMsg("INFO", "ABI dump has been generated to stdout"); return; } else { # write to gzipped file my ($DDir, $DName) = separate_path($DumpPath); my $DPath = $TMP_DIR."/".$DName; if(not $Archive) { $DPath = $DumpPath; } mkpath($DDir); open(DUMP, ">", $DPath) || die ("can't open file \'$DPath\': $!\n"); print DUMP $ABI_DUMP; close(DUMP); if(not -s $DPath) { exitStatus("Error", "can't create ABI dump because something is going wrong with the Data::Dumper module"); } if($Archive) { $DumpPath = createArchive($DPath, $DDir); } if($OutputDumpPath) { printMsg("INFO", "library ABI has been dumped to:\n $OutputDumpPath"); } else { printMsg("INFO", "library ABI has been dumped to:\n $DumpPath"); } printMsg("INFO", "you can transfer this dump everywhere and use instead of the ".$Descriptor{1}{"Version"}." version descriptor"); } } sub quickEmptyReports() { # Quick "empty" reports # 4 times faster than merging equal dumps # NOTE: the dump contains the "LibraryVersion" attribute # if you change the version, then your dump will be different # OVERCOME: use -v1 and v2 options for comparing dumps # and don't change version in the XML descriptor (and dumps) # OVERCOME 2: separate meta info from the dumps in ACC 2.0 if(-s $Descriptor{1}{"Path"} == -s $Descriptor{2}{"Path"}) { my $FilePath1 = unpackDump($Descriptor{1}{"Path"}); my $FilePath2 = unpackDump($Descriptor{2}{"Path"}); if($FilePath1 and $FilePath2) { my $Line = readLineNum($FilePath1, 0); if($Line=~/xml/) { # XML format # is not supported yet return; } local $/ = undef; open(DUMP1, $FilePath1); my $Content1 = ; close(DUMP1); open(DUMP2, $FilePath2); my $Content2 = ; close(DUMP2); if($Content1 eq $Content2) { # clean memory undef $Content2; # read a number of headers, libs, symbols and types my $ABIdump = eval($Content1); # clean memory undef $Content1; if(not $ABIdump) { exitStatus("Error", "internal error - eval() procedure seem to not working correctly, try to remove 'use strict' and try again"); } if(not $ABIdump->{"TypeInfo"}) { # support for old dumps $ABIdump->{"TypeInfo"} = $ABIdump->{"TypeDescr"}; } if(not $ABIdump->{"SymbolInfo"}) { # support for old dumps $ABIdump->{"SymbolInfo"} = $ABIdump->{"FuncDescr"}; } read_Source_DumpInfo($ABIdump, 1); read_Libs_DumpInfo($ABIdump, 1); read_Machine_DumpInfo($ABIdump, 1); read_Machine_DumpInfo($ABIdump, 2); %{$CheckedTypes{"Binary"}} = %{$ABIdump->{"TypeInfo"}}; %{$CheckedTypes{"Source"}} = %{$ABIdump->{"TypeInfo"}}; %{$CheckedSymbols{"Binary"}} = %{$ABIdump->{"SymbolInfo"}}; %{$CheckedSymbols{"Source"}} = %{$ABIdump->{"SymbolInfo"}}; $Descriptor{1}{"Version"} = $TargetVersion{1}?$TargetVersion{1}:$ABIdump->{"LibraryVersion"}; $Descriptor{2}{"Version"} = $TargetVersion{2}?$TargetVersion{2}:$ABIdump->{"LibraryVersion"}; exitReport(); } } } } sub initLogging($) { my $LibVersion = $_[0]; # create log directory my ($LOG_DIR, $LOG_FILE) = ("logs/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"}, "log.txt"); if($OutputLogPath{$LibVersion}) { # user-defined by -log-path option ($LOG_DIR, $LOG_FILE) = separate_path($OutputLogPath{$LibVersion}); } if($LogMode ne "n") { mkpath($LOG_DIR); } $LOG_PATH{$LibVersion} = get_abs_path($LOG_DIR)."/".$LOG_FILE; if($Debug) { # debug directory $DEBUG_PATH{$LibVersion} = "debug/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"}; if(not $ExtraInfo) { # enable --extra-info $ExtraInfo = $DEBUG_PATH{$LibVersion}."/extra-info"; } } resetLogging($LibVersion); } sub writeLog($$) { my ($LibVersion, $Msg) = @_; if($LogMode ne "n") { appendFile($LOG_PATH{$LibVersion}, $Msg); } } sub resetLogging($) { my $LibVersion = $_[0]; if($LogMode!~/a|n/) { # remove old log unlink($LOG_PATH{$LibVersion}); if($Debug) { rmtree($DEBUG_PATH{$LibVersion}); } } } sub printErrorLog($) { my $LibVersion = $_[0]; if($LogMode ne "n") { printMsg("ERROR", "see log for details:\n ".$LOG_PATH{$LibVersion}."\n"); } } sub isDump($) { if(get_filename($_[0])=~/\A(.+)\.(abi|abidump|dump)(\.tar\.gz|\.zip|\.xml|)(\.\w+|)\Z/) { return $1; } return 0; } sub isDump_U($) { if(get_filename($_[0])=~/\A(.+)\.(abi|abidump|dump)(\.xml|)(\.\w+|)\Z/) { return $1; } return 0; } sub compareInit() { # read input XML descriptors or ABI dumps if(not $Descriptor{1}{"Path"}) { exitStatus("Error", "-old option is not specified"); } my @DParts1 = split(/\s*,\s*/, $Descriptor{1}{"Path"}); foreach my $Part (@DParts1) { if(not -e $Part) { exitStatus("Access_Error", "can't access \'$Part\'"); } } if(not $Descriptor{2}{"Path"}) { exitStatus("Error", "-new option is not specified"); } my @DParts2 = split(/\s*,\s*/, $Descriptor{2}{"Path"}); foreach my $Part (@DParts2) { if(not -e $Part) { exitStatus("Access_Error", "can't access \'$Part\'"); } } detect_default_paths("bin"); # to extract dumps if($#DParts1==0 and $#DParts2==0 and isDump($Descriptor{1}{"Path"}) and isDump($Descriptor{2}{"Path"})) { # optimization: equal ABI dumps quickEmptyReports(); } checkVersionNum(1, $Descriptor{1}{"Path"}); checkVersionNum(2, $Descriptor{2}{"Path"}); printMsg("INFO", "preparation, please wait ..."); foreach my $Part (@DParts1) { if(isDump($Part)) { read_ABI_Dump(1, $Part); } else { readDescriptor(1, createDescriptor(1, $Part)); } } foreach my $Part (@DParts2) { if(isDump($Part)) { read_ABI_Dump(2, $Part); } else { readDescriptor(2, createDescriptor(2, $Part)); } } if(not $Descriptor{1}{"Version"}) { # set to default: X $Descriptor{1}{"Version"} = "X"; } if(not $Descriptor{2}{"Version"}) { # set to default: Y $Descriptor{2}{"Version"} = "Y"; } initLogging(1); initLogging(2); # check consistency if(not $Descriptor{1}{"Headers"} and not $Descriptor{1}{"Libs"}) { exitStatus("Error", "descriptor d1 does not contain both header files and libraries info"); } if(not $Descriptor{2}{"Headers"} and not $Descriptor{2}{"Libs"}) { exitStatus("Error", "descriptor d2 does not contain both header files and libraries info"); } if($Descriptor{1}{"Headers"} and not $Descriptor{1}{"Libs"} and not $Descriptor{2}{"Headers"} and $Descriptor{2}{"Libs"}) { exitStatus("Error", "can't compare headers with $SLIB_TYPE libraries"); } elsif(not $Descriptor{1}{"Headers"} and $Descriptor{1}{"Libs"} and $Descriptor{2}{"Headers"} and not $Descriptor{2}{"Libs"}) { exitStatus("Error", "can't compare $SLIB_TYPE libraries with headers"); } if(not $Descriptor{1}{"Headers"}) { if($CheckHeadersOnly_Opt) { exitStatus("Error", "can't find header files info in descriptor d1"); } } if(not $Descriptor{2}{"Headers"}) { if($CheckHeadersOnly_Opt) { exitStatus("Error", "can't find header files info in descriptor d2"); } } if(not $Descriptor{1}{"Headers"} or not $Descriptor{2}{"Headers"}) { if(not $CheckObjectsOnly_Opt) { printMsg("WARNING", "comparing $SLIB_TYPE libraries only"); $CheckObjectsOnly = 1; } } if(not $Descriptor{1}{"Libs"}) { if($CheckObjectsOnly_Opt) { exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d1"); } } if(not $Descriptor{2}{"Libs"}) { if($CheckObjectsOnly_Opt) { exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d2"); } } if(not $Descriptor{1}{"Libs"} or not $Descriptor{2}{"Libs"}) { # comparing standalone header files # comparing ABI dumps created with --headers-only if(not $CheckHeadersOnly_Opt) { printMsg("WARNING", "checking headers only"); $CheckHeadersOnly = 1; } } if($UseDumps) { # --use-dumps # parallel processing my $DumpPath1 = "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi.$AR_EXT"; my $DumpPath2 = "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{2}{"Version"}.".abi.$AR_EXT"; unlink($DumpPath1); unlink($DumpPath2); my $pid = fork(); if($pid) { # dump on two CPU cores my @PARAMS = ("-dump", $Descriptor{1}{"Path"}, "-l", $TargetLibraryName); if($RelativeDirectory{1}) { @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{1}); } if($OutputLogPath{1}) { @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{1}); } if($CrossGcc) { @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc); } if($Quiet) { @PARAMS = (@PARAMS, "-quiet"); @PARAMS = (@PARAMS, "-logging-mode", "a"); } elsif($LogMode and $LogMode ne "w") { # "w" is default @PARAMS = (@PARAMS, "-logging-mode", $LogMode); } if($ExtendedCheck) { @PARAMS = (@PARAMS, "-extended"); } if($UserLang) { @PARAMS = (@PARAMS, "-lang", $UserLang); } if($TargetVersion{1}) { @PARAMS = (@PARAMS, "-vnum", $TargetVersion{1}); } if($BinaryOnly) { @PARAMS = (@PARAMS, "-binary"); } if($SourceOnly) { @PARAMS = (@PARAMS, "-source"); } if($SortDump) { @PARAMS = (@PARAMS, "-sort"); } if($DumpFormat and $DumpFormat ne "perl") { @PARAMS = (@PARAMS, "-dump-format", $DumpFormat); } if($CheckHeadersOnly) { @PARAMS = (@PARAMS, "-headers-only"); } if($CheckObjectsOnly) { @PARAMS = (@PARAMS, "-objects-only"); } if($Debug) { @PARAMS = (@PARAMS, "-debug"); printMsg("INFO", "running perl $0 @PARAMS"); } system("perl", $0, @PARAMS); if(not -f $DumpPath1) { exit(1); } } else { # child my @PARAMS = ("-dump", $Descriptor{2}{"Path"}, "-l", $TargetLibraryName); if($RelativeDirectory{2}) { @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{2}); } if($OutputLogPath{2}) { @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{2}); } if($CrossGcc) { @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc); } if($Quiet) { @PARAMS = (@PARAMS, "-quiet"); @PARAMS = (@PARAMS, "-logging-mode", "a"); } elsif($LogMode and $LogMode ne "w") { # "w" is default @PARAMS = (@PARAMS, "-logging-mode", $LogMode); } if($ExtendedCheck) { @PARAMS = (@PARAMS, "-extended"); } if($UserLang) { @PARAMS = (@PARAMS, "-lang", $UserLang); } if($TargetVersion{2}) { @PARAMS = (@PARAMS, "-vnum", $TargetVersion{2}); } if($BinaryOnly) { @PARAMS = (@PARAMS, "-binary"); } if($SourceOnly) { @PARAMS = (@PARAMS, "-source"); } if($SortDump) { @PARAMS = (@PARAMS, "-sort"); } if($DumpFormat and $DumpFormat ne "perl") { @PARAMS = (@PARAMS, "-dump-format", $DumpFormat); } if($CheckHeadersOnly) { @PARAMS = (@PARAMS, "-headers-only"); } if($CheckObjectsOnly) { @PARAMS = (@PARAMS, "-objects-only"); } if($Debug) { @PARAMS = (@PARAMS, "-debug"); printMsg("INFO", "running perl $0 @PARAMS"); } system("perl", $0, @PARAMS); if(not -f $DumpPath2) { exit(1); } else { exit(0); } } waitpid($pid, 0); my @CMP_PARAMS = ("-l", $TargetLibraryName); @CMP_PARAMS = (@CMP_PARAMS, "-d1", $DumpPath1); @CMP_PARAMS = (@CMP_PARAMS, "-d2", $DumpPath2); if($TargetLibraryFName ne $TargetLibraryName) { @CMP_PARAMS = (@CMP_PARAMS, "-l-full", $TargetLibraryFName); } if($ShowRetVal) { @CMP_PARAMS = (@CMP_PARAMS, "-show-retval"); } if($CrossGcc) { @CMP_PARAMS = (@CMP_PARAMS, "-cross-gcc", $CrossGcc); } @CMP_PARAMS = (@CMP_PARAMS, "-logging-mode", "a"); if($Quiet) { @CMP_PARAMS = (@CMP_PARAMS, "-quiet"); } if($ReportFormat and $ReportFormat ne "html") { # HTML is default format @CMP_PARAMS = (@CMP_PARAMS, "-report-format", $ReportFormat); } if($OutputReportPath) { @CMP_PARAMS = (@CMP_PARAMS, "-report-path", $OutputReportPath); } if($BinaryReportPath) { @CMP_PARAMS = (@CMP_PARAMS, "-bin-report-path", $BinaryReportPath); } if($SourceReportPath) { @CMP_PARAMS = (@CMP_PARAMS, "-src-report-path", $SourceReportPath); } if($LoggingPath) { @CMP_PARAMS = (@CMP_PARAMS, "-log-path", $LoggingPath); } if($CheckHeadersOnly) { @CMP_PARAMS = (@CMP_PARAMS, "-headers-only"); } if($CheckObjectsOnly) { @CMP_PARAMS = (@CMP_PARAMS, "-objects-only"); } if($BinaryOnly) { @CMP_PARAMS = (@CMP_PARAMS, "-binary"); } if($SourceOnly) { @CMP_PARAMS = (@CMP_PARAMS, "-source"); } if($Browse) { @CMP_PARAMS = (@CMP_PARAMS, "-browse", $Browse); } if($OpenReport) { @CMP_PARAMS = (@CMP_PARAMS, "-open"); } if($Debug) { @CMP_PARAMS = (@CMP_PARAMS, "-debug"); printMsg("INFO", "running perl $0 @CMP_PARAMS"); } system("perl", $0, @CMP_PARAMS); exit($?>>8); } if(not $Descriptor{1}{"Dump"} or not $Descriptor{2}{"Dump"}) { # need GCC toolchain to analyze # header files and libraries detect_default_paths("inc|lib|gcc"); } if(not $Descriptor{1}{"Dump"}) { if(not $CheckHeadersOnly) { readLibs(1); } if($CheckHeadersOnly) { setLanguage(1, "C++"); } if(not $CheckObjectsOnly) { searchForHeaders(1); } $WORD_SIZE{1} = detectWordSize(); } if(not $Descriptor{2}{"Dump"}) { if(not $CheckHeadersOnly) { readLibs(2); } if($CheckHeadersOnly) { setLanguage(2, "C++"); } if(not $CheckObjectsOnly) { searchForHeaders(2); } $WORD_SIZE{2} = detectWordSize(); } if($WORD_SIZE{1} ne $WORD_SIZE{2}) { # support for old ABI dumps # try to synch different WORD sizes if(not checkDump(1, "2.1")) { $WORD_SIZE{1} = $WORD_SIZE{2}; printMsg("WARNING", "set WORD size to ".$WORD_SIZE{2}." bytes"); } elsif(not checkDump(2, "2.1")) { $WORD_SIZE{2} = $WORD_SIZE{1}; printMsg("WARNING", "set WORD size to ".$WORD_SIZE{1}." bytes"); } } elsif(not $WORD_SIZE{1} and not $WORD_SIZE{2}) { # support for old ABI dumps $WORD_SIZE{1} = "4"; $WORD_SIZE{2} = "4"; } if($Descriptor{1}{"Dump"}) { # support for old ABI dumps prepareTypes(1); } if($Descriptor{2}{"Dump"}) { # support for old ABI dumps prepareTypes(2); } if($AppPath and not keys(%{$Symbol_Library{1}})) { printMsg("WARNING", "the application ".get_filename($AppPath)." has no symbols imported from the $SLIB_TYPE libraries"); } # started to process input data if(not $CheckObjectsOnly) { if($Descriptor{1}{"Headers"} and not $Descriptor{1}{"Dump"}) { readHeaders(1); } if($Descriptor{2}{"Headers"} and not $Descriptor{2}{"Dump"}) { readHeaders(2); } } # clean memory %SystemHeaders = (); %mangled_name_gcc = (); prepareSymbols(1); prepareSymbols(2); # clean memory %SymbolInfo = (); # Virtual Tables registerVTable(1); registerVTable(2); if(not checkDump(1, "1.22") and checkDump(2, "1.22")) { # support for old ABI dumps foreach my $ClassName (keys(%{$VirtualTable{2}})) { if($ClassName=~/$OStarget, "Debug"=>$Debug, "Quiet"=>$Quiet, "LogMode"=>$LogMode, "CheckHeadersOnly"=>$CheckHeadersOnly, "SystemRoot"=>$SystemRoot, "MODULES_DIR"=>$MODULES_DIR, "GCC_PATH"=>$GCC_PATH, "TargetSysInfo"=>$TargetSysInfo, "CrossPrefix"=>$CrossPrefix, "TargetLibraryName"=>$TargetLibraryName, "CrossGcc"=>$CrossGcc, "UseStaticLibs"=>$UseStaticLibs, "NoStdInc"=>$NoStdInc, "BinaryOnly" => $BinaryOnly, "SourceOnly" => $SourceOnly ); return \%Opts; } sub get_CodeError($) { my %CODE_ERROR = reverse(%ERROR_CODE); return $CODE_ERROR{$_[0]}; } sub scenario() { if($StdOut) { # enable quiet mode $Quiet = 1; $JoinReport = 1; } if(not $LogMode) { # default $LogMode = "w"; } if($UserLang) { # --lang=C++ $UserLang = uc($UserLang); $COMMON_LANGUAGE{1}=$UserLang; $COMMON_LANGUAGE{2}=$UserLang; } if($LoggingPath) { $OutputLogPath{1} = $LoggingPath; $OutputLogPath{2} = $LoggingPath; if($Quiet) { $COMMON_LOG_PATH = $LoggingPath; } } if($Quick) { $ADD_TMPL_INSTANCES = 0; } if($OutputDumpPath) { # validate if(not isDump($OutputDumpPath)) { exitStatus("Error", "the dump path should be a path to *.abi.$AR_EXT or *.abi file"); } } if($BinaryOnly and $SourceOnly) { # both --binary and --source # is the default mode $DoubleReport = 1; $JoinReport = 0; $BinaryOnly = 0; $SourceOnly = 0; if($OutputReportPath) { # --report-path $DoubleReport = 0; $JoinReport = 1; } } elsif($BinaryOnly or $SourceOnly) { # --binary or --source $DoubleReport = 0; $JoinReport = 0; } if($UseXML) { # --xml option $ReportFormat = "xml"; $DumpFormat = "xml"; } if($ReportFormat) { # validate $ReportFormat = lc($ReportFormat); if($ReportFormat!~/\A(xml|html|htm)\Z/) { exitStatus("Error", "unknown report format \'$ReportFormat\'"); } if($ReportFormat eq "htm") { # HTM == HTML $ReportFormat = "html"; } elsif($ReportFormat eq "xml") { # --report-format=XML equal to --xml $UseXML = 1; } } else { # default: HTML $ReportFormat = "html"; } if($DumpFormat) { # validate $DumpFormat = lc($DumpFormat); if($DumpFormat!~/\A(xml|perl)\Z/) { exitStatus("Error", "unknown ABI dump format \'$DumpFormat\'"); } if($DumpFormat eq "xml") { # --dump-format=XML equal to --xml $UseXML = 1; } } else { # default: Perl Data::Dumper $DumpFormat = "perl"; } if($Quiet and $LogMode!~/a|n/) { # --quiet log if(-f $COMMON_LOG_PATH) { unlink($COMMON_LOG_PATH); } } if($ExtraInfo) { $CheckUndefined = 1; } if($TestTool and $UseDumps) { # --test && --use-dumps == --test-dump $TestDump = 1; } if($Tolerant) { # enable all $Tolerance = 1234; } if($Help) { HELP_MESSAGE(); exit(0); } if($InfoMsg) { INFO_MESSAGE(); exit(0); } if($ShowVersion) { printMsg("INFO", "ABI Compliance Checker (ACC) $TOOL_VERSION\nCopyright (C) 2014 ROSA Laboratory\nLicense: LGPL or GPL \nThis program is free software: you can redistribute it and/or modify it.\n\nWritten by Andrey Ponomarenko."); exit(0); } if($DumpVersion) { printMsg("INFO", $TOOL_VERSION); exit(0); } if($ExtendedCheck) { $CheckHeadersOnly = 1; } if($SystemRoot_Opt) { # user defined root if(not -e $SystemRoot_Opt) { exitStatus("Access_Error", "can't access \'$SystemRoot\'"); } $SystemRoot = $SystemRoot_Opt; $SystemRoot=~s/[\/]+\Z//g; if($SystemRoot) { $SystemRoot = get_abs_path($SystemRoot); } } $Data::Dumper::Sortkeys = 1; if($SortDump) { $Data::Dumper::Useperl = 1; $Data::Dumper::Sortkeys = \&dump_sorting; } if($TargetLibsPath) { if(not -f $TargetLibsPath) { exitStatus("Access_Error", "can't access file \'$TargetLibsPath\'"); } foreach my $Lib (split(/\s*\n\s*/, readFile($TargetLibsPath))) { $TargetLibs{$Lib} = 1; } } if($TargetHeadersPath) { # --headers-list if(not -f $TargetHeadersPath) { exitStatus("Access_Error", "can't access file \'$TargetHeadersPath\'"); } foreach my $Header (split(/\s*\n\s*/, readFile($TargetHeadersPath))) { $TargetHeaders{1}{$Header} = 1; $TargetHeaders{2}{$Header} = 1; } } if($TargetHeader) { # --header $TargetHeaders{1}{$TargetHeader} = 1; $TargetHeaders{2}{$TargetHeader} = 1; } if($TestTool or $TestDump) { # --test, --test-dump detect_default_paths("bin|gcc"); # to compile libs loadModule("RegTests"); testTool($TestDump, $Debug, $Quiet, $ExtendedCheck, $LogMode, $ReportFormat, $DumpFormat, $LIB_EXT, $GCC_PATH, $Browse, $OpenReport, $SortDump, $CheckHeadersOnly, $CheckObjectsOnly); exit(0); } if($DumpSystem) { # --dump-system loadModule("SysCheck"); if($DumpSystem=~/\.(xml|desc)\Z/) { # system XML descriptor if(not -f $DumpSystem) { exitStatus("Access_Error", "can't access file \'$DumpSystem\'"); } my $Ret = readSystemDescriptor(readFile($DumpSystem)); foreach (@{$Ret->{"Tools"}}) { push_U($SystemPaths{"bin"}, $_); $TargetTools{$_} = 1; } if($Ret->{"CrossPrefix"}) { $CrossPrefix = $Ret->{"CrossPrefix"}; } } elsif($SystemRoot_Opt) { # -sysroot "/" option # default target: /usr/lib, /usr/include # search libs: /usr/lib and /lib if(not -e $SystemRoot."/usr/lib") { exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/lib'"); } if(not -e $SystemRoot."/lib") { exitStatus("Access_Error", "can't access '".$SystemRoot."/lib'"); } if(not -e $SystemRoot."/usr/include") { exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/include'"); } readSystemDescriptor(" $DumpSystem $SystemRoot/usr/include $SystemRoot/usr/lib $SystemRoot/lib "); } else { exitStatus("Error", "-sysroot option should be specified, usually it's \"/\""); } detect_default_paths("bin|gcc"); # to check symbols if($OStarget eq "windows") { # to run dumpbin.exe # and undname.exe check_win32_env(); } dumpSystem(getSysOpts()); exit(0); } if($CmpSystems) { # --cmp-systems detect_default_paths("bin"); # to extract dumps loadModule("SysCheck"); cmpSystems($Descriptor{1}{"Path"}, $Descriptor{2}{"Path"}, getSysOpts()); exit(0); } if($GenerateTemplate) { writeFile("VERSION.xml", $DescriptorTemplate."\n"); printMsg("INFO", "XML-descriptor template ./VERSION.xml has been generated"); exit(0); } if(not $TargetLibraryName) { exitStatus("Error", "library name is not selected (-l option)"); } else { # validate library name if($TargetLibraryName=~/[\*\/\\]/) { exitStatus("Error", "\"\\\", \"\/\" and \"*\" symbols are not allowed in the library name"); } } if(not $TargetLibraryFName) { $TargetLibraryFName = $TargetLibraryName; } if($CheckHeadersOnly_Opt and $CheckObjectsOnly_Opt) { exitStatus("Error", "you can't specify both -headers-only and -objects-only options at the same time"); } if($SymbolsListPath) { if(not -f $SymbolsListPath) { exitStatus("Access_Error", "can't access file \'$SymbolsListPath\'"); } foreach my $Interface (split(/\s*\n\s*/, readFile($SymbolsListPath))) { $SymbolsList{$Interface} = 1; } } if($SkipSymbolsListPath) { if(not -f $SkipSymbolsListPath) { exitStatus("Access_Error", "can't access file \'$SkipSymbolsListPath\'"); } foreach my $Interface (split(/\s*\n\s*/, readFile($SkipSymbolsListPath))) { $SkipSymbolsList{$Interface} = 1; } } if($SkipHeadersPath) { if(not -f $SkipHeadersPath) { exitStatus("Access_Error", "can't access file \'$SkipHeadersPath\'"); } foreach my $Path (split(/\s*\n\s*/, readFile($SkipHeadersPath))) { # register for both versions $SkipHeadersList{1}{$Path} = 1; $SkipHeadersList{2}{$Path} = 1; my ($CPath, $Type) = classifyPath($Path); $SkipHeaders{1}{$Type}{$CPath} = 1; $SkipHeaders{2}{$Type}{$CPath} = 1; } } if($ParamNamesPath) { if(not -f $ParamNamesPath) { exitStatus("Access_Error", "can't access file \'$ParamNamesPath\'"); } foreach my $Line (split(/\n/, readFile($ParamNamesPath))) { if($Line=~s/\A(\w+)\;//) { my $Interface = $1; if($Line=~/;(\d+);/) { while($Line=~s/(\d+);(\w+)//) { $AddIntParams{$Interface}{$1}=$2; } } else { my $Num = 0; foreach my $Name (split(/;/, $Line)) { $AddIntParams{$Interface}{$Num++}=$Name; } } } } } if($AppPath) { if(not -f $AppPath) { exitStatus("Access_Error", "can't access file \'$AppPath\'"); } foreach my $Interface (readSymbols_App($AppPath)) { $SymbolsList_App{$Interface} = 1; } } if($DumpAPI) { # --dump-abi # make an API dump create_ABI_Dump(); exit($COMPILE_ERRORS); } # default: compare APIs # -d1 # -d2 compareInit(); if($JoinReport or $DoubleReport) { compareAPIs("Binary"); compareAPIs("Source"); } elsif($BinaryOnly) { compareAPIs("Binary"); } elsif($SourceOnly) { compareAPIs("Source"); } exitReport(); } scenario(); abi-compliance-checker-1.99.9/doc/000077500000000000000000000000001227016120300166275ustar00rootroot00000000000000abi-compliance-checker-1.99.9/doc/Changes.html000066400000000000000000002264131227016120300210750ustar00rootroot00000000000000 ABI Compliance Checker - Change Log

ABI Compliance Checker - Change Log

Thanks to all for reporting issues so the tool can continue to be improved!

Contents

Version 1.99.9 (January 23, 2014)

abi-compliance-checker-1.99.9.tar.gz

ACC 2.0 pre-release.

  • New Options
    • -skip-internal: do not check internal interfaces matched by the pattern
  • Bug Fixes
    • Fixed duplicated entries in the XML report
    • Reduced size of the XML report
    • Fixed duplicated problems related to changed size of a global data
    • Options -v1 and -v2 can now be used when comparing ABI dumps to change library versions shown in the report
    • Fixed false positives with the size change of a template instance type
    • Fixed false positives with the change of a parameter/field type name

Version 1.99.8.5 (October 03, 2013)

abi-compliance-checker-1.99.8.5.tar.gz

ACC 2.0 pre-release.

This is a bug-fix release with a few new features.

  • Improvements
    • Optimized performance and memory usage (up to 90%) on input objects with a huge number of changes and deep data type trees (e.g. Linux kernel)
    • Partial support for GCC 4.8.{0-1}, waiting for a fix for the bug 57850 in the next GCC versions
    • Support for incomplete ABI dumps
  • Bug Fixes
    • Fixed identification of template constructors and destructors
    • Do not show "this" first argument of methods in the report
    • Corrected descriptions of affected symbols in the report
    • Fixed false alarms on changed offset of parameters
    • Do not hang on class A<N>:public A<N-1>
    • Corrected identification of header files in the include_preamble
    • Corrected comparison of function pointer types
    • Corrected rule Global_Data_Size
  • Other
    • Code refactoring

Version 1.99.7 (July 01, 2013)

abi-compliance-checker-1.99.7.tar.gz

ACC 2.0 pre-release.

This is a bug-fix release with a few new features.

  • Improvements
    • Added missed fields of template instance types to the ABI dump
    • Improved support for old ABI dumps
    • Added Struct_Field_Size_Increased rule
    • Support for vector types (GCC extension)
    • Removed duplicates from the ABI dump
    • Corrected visualization of v-table content in the report
    • Corrected identification of target headers
    • Corrected source-compatibility check
    • Performance optimization (5%)
  • New Options
    • -check - to check completeness of the ABI dump
  • Bug Fixes
    • Fixed default arguments of methods (broken in 1.99.1 due to added "this" parameter)
  • Other
    • Extended test suite

Version 1.99.1 (June 07, 2013)

abi-compliance-checker-1.99.1.tar.gz

ACC 2.0 pre-release.

This is a bug-fix release with a few new features.

  • Improvements
    • Support for ABI Dumper 0.97
    • Show added/removed inline virtual functions in the binary compatibility report
    • Added "this" hidden parameter to non-static class methods in the ABI dump
  • Bug Fixes
    • Fixed XmlDump module
    • Fixed CallConv module
  • Other
    • Support for old ABI dumps

Version 1.99 (May 24, 2013)

abi-compliance-checker-1.99.tar.gz

ACC 2.0 pre-release.

This is a bug-fix release with a few new features.

  • Improvements
    • Support for ABI Dumper 0.95
    • Added 14 binary-compatibility rules
    • Added 10 source-compatibility rules
    • Improved model of type alignment
    • Changed version of ABI dump format to 3.0
    • Added _vptr member to virtual classes
    • Added constants defined by GCC to ABI dump
    • Improved analysis of constants
  • Bug Fixes
    • Increased severity of Field_Became_Non_Mutable rule
  • Other
    • Support for old ABI dumps
    • Extended test suite (+11 test cases)
    • Code cleaning

Version 1.98.8 (February 07, 2013)

abi-compliance-checker-1.98.8.tar.gz

ACC 2.0 pre-release.

This is a bug-fix release with a few new features.

  • Improvements
    • Show added and removed constants (#defines) in the report
    • Show changes in unnamed enumerations
    • Avoid false alarm about renamed field if old name of this field is defined to new (SC)
    • Recursive comparing of structured data types in *_Format rules
    • Added Typedef_BaseType_Format rule to check format changes in the typedef base type
  • Bug Fixes
    • Increased severity of Parameter_BaseType_And_Size BC rule (Low to Medium)
    • Increased severity of Added_Field SC rule (Safe to Low)
    • Corrected handling of the tool error codes in the test suite
    • Corrected handling of relative paths in descriptor options
    • Skipping linker-related options in gcc_options option of the descriptor
    • Corrected internal mangler for C++ functions
    • Corrected conditions for enabling of C++ compatibility mode
    • Corrected handling of C++ keywords in C-code
    • Corrected -extended option
    • Corrected Typedef_BaseType rule
    • Corrected parsing of default function arguments
    • Do not check presence of archive utilities if not used
    • Other fixes
  • Other
    • Extended test suite
    • Code cleaning

Version 1.98.7 (December 14, 2012)

abi-compliance-checker-1.98.7.tar.gz

ACC 2.0 pre-release.

This is a bug-fix release with a few new features.

  • Improvements
    • Extended extra info dumped by -extra-info option
    • Extended additional info dumped by -extra-dump option
    • Added specifiers for structs, unions and enums in the report and ABI dump
    • Improved support for old ABI dumps
  • Bug Fixes
    • Corrected -debug option
    • Corrected creating of archives with ABI dumps
    • Corrected parsing of includes in header files
    • Corrected processing of undefined symbols
    • Corrected -app option
    • Corrected processing of default paths to system libraries
    • Corrected Makefile
    • Other fixes
  • Other
    • Code cleaning and refactoring

Version 1.98.6 (December 04, 2012)

abi-compliance-checker-1.98.6.tar.gz

ACC 2.0 pre-release.

This is a bug-fix release.

  • Bug Fixes
    • Corrected processing of input XML descriptor
    • Corrected "Parameter_Default_Value_Removed" rule
    • Other fixes
  • Other
    • Code cleaning

Version 1.98.5 (November 30, 2012)

abi-compliance-checker-1.98.5.tar.gz

ACC 2.0 pre-release.

This is a bug-fix release with a few new features.

  • Improvements
    • Support for Mac OS X 10.8
    • Support for OpenBSD
    • Support for old GCC versions <= 4.2
    • Added "throw" and "weak" attributes of methods to ABI dump
  • Bug Fixes
    • Corrected order of user-defined include paths
    • Corrected internal C++ mangler
    • Removed false positives of the "Parameter_Type_Format" rule
    • Other fixes
  • Other
    • Extended test suite
    • Code cleaning
    • Docs cleaning

Version 1.98.4 (October 18, 2012)

abi-compliance-checker-1.98.4.tar.gz

ACC 2.0 pre-release.

This is a bug-fix release with a few new features.

  • Improvements
    • Optimization of memory usage (5%-10%) and performance (5%-10%)
    • Added "Used Reserved Field" rule of binary compatibility analysis
    • Improved design of the operating system compatibility report
    • Added meta descriptors for 334 libraries
  • Bug Fixes
    • Fixed an issue with diagnostics of added virtual functions
    • Corrected the list of functions affected by the compatibility problem
    • Avoid false alarm about removed function if this function became macro (SC)
    • Corrected parser of C header files
    • Other fixes
  • Other
    • Extended test suite
    • Code cleaning

Version 1.98.3 (July 19, 2012)

abi-compliance-checker-1.98.3.tar.gz

ACC 2.0 pre-release.

This is a bug-fix release with a few new features.

  • New Features
    • Implemented a model of calling conventions on x86 and x86_64
    • Improved diagnostics of changes in function parameters and return value (distribution on registers and stack)
  • Bug Fixes
    • Corrected parser of C++ header files to detect non-member functions inside namespaces
  • Other
    • Added requirement for Ctags (5.8 or newer)
    • Code cleaning

Version 1.98.2 (June 26, 2012)

abi-compliance-checker-1.98.2.tar.gz
ACC 2.0 pre-release.

This is a bug-fix release with a few new features.

  • New Features
    • Support for reading ABI dumps in XML format
    • Automatic enabling of c++0x support if needed to compile headers
  • Bug Fixes
    • Corrected XML and Perl (default) formats of ABI dumps
    • Improved support for old ABI dumps
    • Improved -dump-system option
  • Other
    • Improved documentation

Version 1.98.1 (June 18, 2012)

abi-compliance-checker-1.98.1.tar.gz
ACC 2.0 pre-release.

This is a bug-fix release.

  • Bug Fixes
    • Removed symbols marked as LOCAL in a shared library from lists of added/removed symbols in source-compatibility report
    • Fixed a false positive with some removed extern "C" symbols in source-compatibility report
    • Fixed a bug with removed debug/ directory when using -use-dumps and -debug options together
    • Added support for skip_including section of target system XML descriptors (modules/Targets) used by -dump-system option
    • Extended XML ABI dumps by size attribute of library symbols

Version 1.98.0 (June 14, 2012)

abi-compliance-checker-1.98.0.tar.gz
ACC 2.0 pre-release.

This is a bug-fix release with a few new features.

  • New Features
    • Implemented XML format of ABI dumps
  • Bug Fixes
    • Improved support for old ABI dumps
    • Other fixes

Version 1.97.8 (June 08, 2012)

abi-compliance-checker-1.97.8.tar.gz
ACC 2.0 pre-release.

This is a bug-fix release with a few new features.

  • Improvements
    • Redesigned format of ABI dump
    • Optimization of memory usage (5%-10%) and performance (5%-10%)
    • Improved support for GCC 4.0-4.5
    • Added <add_namespaces> section of the XML descriptor
  • Bug Fixes
    • Improved support for old ABI dumps
    • Fixed a bug with auto-detection of include paths when comparing two XML descriptors
    • Corrected output of -debug option
    • Corrected --dump-system and --cmp-systems options
    • Other fixes
  • Other
    • Code cleaning

Version 1.97.5 (May 14, 2012)

abi-compliance-checker-1.97.5.tar.gz
ACC 2.0 pre-release.

This is a bug-fix release.

  • Improvements
    • Extended ABI dumps by source-level type declarations
    • Improved support for old ABI dumps
    • Optimization of memory usage (20%-30%) and performance (10%-20%)
  • Bug Fixes
    • Corrected auto-detection of a set of target headers to check/dump in --headers-only mode
    • Other fixes
  • Other
    • Extended regression test suite
    • Code cleaning

Version 1.97.4 (April 16, 2012)

abi-compliance-checker-1.97.4.tar.gz
ACC 2.0 pre-release.

Improved quality of the compatibility analysis.

  • New Features
    • Added 16 new binary-compatibility rules
    • Added 17 new source-compatibility rules
  • Bug Fixes
    • Added some missed typedef types to function signatures
  • Other
    • Improved support for old ABI dumps
    • Support for GCC 4.7
    • Extended regression test suite
    • Code cleaning

Version 1.97.3 (April 03, 2012)

abi-compliance-checker-1.97.3.tar.gz
ACC 2.0 pre-release.

This is a next major release. The tool now checks for both binary and source-level compatibility issues with C/C++ APIs.

  • Completed Tasks
    • Implement source-level compatibility checks (1371)
    • Implement 2.0 architecture (1105)
  • Other Features
    • Improved debug mode (--debug)
    • Improved mark-up of the HTML report
    • Improved support for old ABI dumps
  • Bug Fixes
    • Corrected ABI dumps

Version 1.96.8 (February 17, 2012)

abi-compliance-checker-1.96.8.tar.gz
ACC 2.0 pre-release.

  • Completed Tasks
    • Implement XML format for compatibility report (1984)
    • Testing on MeeGo 1.2 Harmattan Beta2 (1955)
  • New Features
    • Add hidden statistics line to compatibility report for operating systems (2403)
    • Add --headers-list option (2400)
    • Add --lang option (2223)
    • Support for symbolic links in /usr/include and /usr/lib (2022)
    • Add <skip_include_paths> section of XML-descriptor (2021)
    • Add <skip_including> section of XML-descriptor (2012)
    • Add --list-affected option to create plain list of incompatible symbols (1994)
    • Add --quiet option to print all errors and warnings to the log file instead of stderr and stdout (1983)
    • Add --stdout option to print results to stdout (1982)
    • Add an option to check binary compatibility in the extended sense (1855)
    • Improve diagnostic messages for added base classes with virtual functions (1849)
    • Add -update option to installer (1837)
    • Add a relative default directory to locate modules after installation (1836)
    • Compatibility rate = (high+1/2*medium+1/4*low) / number of symbols (1794)
  • Bug Fixes
    • Some symbols with extern "C" linkage are missed in --headers-only mode (2401)
    • Changes in global data are not detected under Windows (2311)
    • False negative: change global data to be "const" (2310)
    • Removed middle enumeration value is reported as renamed (2114)
    • False positive: change parameter type from "const int" to "int" (2097)
    • Support for old ABI dump format of ACC 1.21.6 (2024)
    • The tool doesn't search for included headers in /usr/lib/qt4/include/ (2010)
    • False Negative: Header is incompatible with itself (1986)
    • Check libstdc++ in --headers-only mode (1960)
    • Restrict checked header files in the --headers-only mode (1944)
    • Problem with mangled C++-functions using old ABI dump formats in --headers-only mode (1899)
    • Incorrect size of method pointer in ABI dumps (1897)
    • False negative: add/remove "register" modifier of the parameter (1882)
    • Incorrect WORD size when using old ABI dump format (1881)
    • Conflict of a static method with a function of the same name in the ABI dump (1853)
    • Missed right bracket of "func-ptr" type in HTML report (1842)
    • Incorrect report for overridden methods (1824)
    • False negative: override a virtual that doesn't come from a primary base (1808)
    • False negative: change a function parameter to be "restrict" (1805)
    • False negative: change a field to be "volatile" (1803)
    • False negative: change "const"-ness of a return value (1802)
    • False negative: change "volatile" attribute of a method (1801)
    • False positive: removed symbols with inline virtual prototype in the leaf class with default constructor (1791)

Version 1.94 (September 09, 2011)

abi-compliance-checker-1.94.tar.gz
ACC 2.0 pre-release.

  • Completed Tasks
    • Separated regression tests into the module (1105)
  • Added Features
    • Add Makefile.pl installer (1759)

Version 1.93.8 (September 08, 2011)

abi-compliance-checker-1.93.8.tar.gz
ACC 2.0 pre-release.

  • Completed Tasks
    • Separated rules DB (1105)
    • Testing on Symbian SDK (1531)
    • Testing on Windows SDK (1629)
    • Support for OS3000 (1632)
  • Added Features
    • SONAME change in the OS comparison table (1527)
    • Add a compatibility percentage to the OS comparison table (1595)
    • Add "-debug" option (1596)
    • Add listing of symbols in OS comparison table (1597)
    • Use "zip" format of dumps in Windows (1598)
    • Add "-dump-system descriptor.xml" option (1602)
    • Analysis of static libraries (1635)
    • Add -sysinfo option (1681)
    • Add -component option (1682)
    • Add -nostdinc option (1683)
    • Add "weakly"- and "almost"-compatible verdicts (1178)
    • Add <skip_namespaces> to the library XML-descriptor (1740)
    • Search for modules/ directory in the system (1741)
  • Bug Fixes
    • Missed typedefs in the ABI dump using GCC 4.4.1 (1526)
    • False negative: change enum member value from zero to non-zero (1592)
    • False negative: interchange the positions of two fields in a structure (1593)
    • False positive: add a field instead of padding fields (1594)
    • Problems with "copied" classes (1599)
    • Changes in "private" fields (1600)
    • Illegal modulus zero at abi-compliance-checker.pl (1651)
    • Incorrect order of include paths (1653)
    • Change constness of a class method (1529)
    • False negative: change "struct Type" to "union Type" (1738)
    • Change parameter type from "..." to "int" (1750)
    • Remove/add "const"-qualifier of a method (1751)
    • False negative: renamed parameters (1753)
  • Other
    • Improved debug mode (1596)

Version 1.23.5 (July 01, 2011)

abi-compliance-checker-1.23.5.tar.gz
This is a next bug fix release. Tested on 335 libraries

  • Bug Fixes
    • Corrected exit codes: 0 - compatible, 1 - incompatible, 2 - error, ... (1351)
    • Corrected diagnostic messages for C++ functions with changed signature (1361)
    • Fixed regression with C++ non-member functions (1368)
    • Removed false positive with overridden private methods (1369)
    • Corrected functionality for checking binary compatibility of operating systems
    • Removed false positive for removed default version of a symbol (1386)
    • Adapted -dump-system option for MeeGo 1.2 Harmattan (1400)
    • Fixed hanging execution on "#include "../../file.h" (1448)
    • Fixed incorrect automatic include paths (1458)

Version 1.23 (June 07, 2011)

abi-compliance-checker-1.23.tar.gz
This release is sponsored by Nokia.

  • New Features
    • Added 42 compatibility checks (total: 83)
    • Improved diagnostics of compatibility problems
    • Opened an issue tracker
    • Support for cross-compilers
    • Ported to Mac OS X (10.5) and MS Windows (Xp, Vista, 7)
    • Added a viewer of "real" v-table layouts for changed C++ classes
    • Added functionality to check OS backward compatibility
    • Supports for old-version dump formats (>=1.18)
    • Separated versioning of dump formats
    • Improved design of the compatibility report
    • Improved performance
    • Support for old GCC 3.4.4
  • Bug Fixes
    • Reduced false positives
    • Support for C-headers containing C++ keywords
    • Corrected automatic include paths for headers

Version 1.21.12 (April 29, 2011)

abi-compliance-checker-1.21.12.tar.gz (previous bug-fix releases: 1.21.9, 1.21.6)
This is a next bug fix release. Tested on 280 libraries.

  • Bug Fixes
    • Corrected automatic detection of include paths for header files.
    • Removed false positives with overridden virtual functions.
    • Corrected processing of typedef type names, fixed potential program hangup.
    • Added some missed problems relating to the return type changes of a function.
    • Corrected processing of a translation unit dump generated by modern GCC versions.
    • Corrected identifying of inline functions (using the -fkeep-inline-functions GCC option).
    • Corrected parser for C++: analysis of const global data and functions inside a namespace.
    • Corrected names and v-table checks for template types.
    • Corrected checks for changes in enumerations.
    • Corrected ABI dumping and sorting of dumps.
    • Corrected analysis of added/removed virtual functions.
    • Corrected help message and documentation.
    • Documentation has been moved to "doc/" subdirectory.
    • Using File::Temp for storing temporary files.
    • Support for latest GCC 4.6.0 and old GCC v3.x series.
    • Fixed infinite loop finding the path for "which" command in the system.
    • Corrected distinction of descriptor kinds (headers, libraries, directories and XML-descriptors).
    • Corrected processing of <include_paths> section in the XML-descriptors.

Version 1.21 (August 19, 2010)

abi-compliance-checker-1.21.tar.gz
This release includes many improvements and bug fixes. Tested on 155 libraries.

  • New Features
    • Added --check-implementation option: compare disassembled binary code to detect changes in the interface implementation.
    • Added --objects-only option: compare shared objects without header files.
    • Added --v1 and --v2 options: specify version number outside the descriptor.
    • Improved help message.
    • Improved performance of the tool.
    • Removed template instances and stdc++ interfaces from the report (C++).
    • Added README.html and CHANGES.html to the package.
  • Bug Fixes
    • Corrected ABI compatibility report.
    • Corrected interface names and versions in the report.
    • Corrected number of problems in report summary.
    • Corrected ABI dump.

Version 1.20 (August 30, 2010)

abi-compliance-checker-1.20.tar.gz
This is a next bug fix release. Tested on 145 libraries.

  • Bug Fixes
    • Corrected reports about added/withdrawn members in the structure types and added/withdrawn parameters.
    • Corrected report about added/withdrawn virtual functions if -headers_only option specified.
    • Corrected processing of header paths containing special characters.
  • New Features
    • Added <defines> section to the library descriptor: this section allows to add defines at the headers compiling stage.

Version 1.19 (July 22, 2010)

Abi-compliance-checker-1.19.tar.gz
This is a next bug fix release with several new features. Tested on 130 libraries.

  • Bug Fixes
    • Removed duplicated problems from the report.
    • Corrected names of the template instances.
    • Corrected checking of reference type changes.
    • Corrected titles in the report.
    • Corrected size of some array types.
    • Corrected checking of added/withdrawn members in the structure types with reserved members.
    • Corrected checking of added/withdrawn parameters.
  • New Features
    • Added --library_full_name option to display full library name in title of the report.
    • Added --relpath option for replacing the {RELPATH} in the descriptor for ABI dumping.
    • Added <skip_libs> section to the library descriptor: this section contains a list of shared objects and/or directories with shared objects that should not be processed.
    • Improved performance on big libraries.

Version 1.18 (June 25, 2010)

Abi-compliance-checker-1.18.tar.gz
This is generally a bug fix release. Tested on 100 libraries.

  • New Features
    • Added --relpath1 and --relpath2 options for replacing the {RELPATH} in the descriptors. Old option -relpath was removed.
    • Added <add_include_paths> section to the library descriptor: this section contains a list of include paths that should be added to the automatically detected include paths.
  • Bug Fixes
    • Added some previously missed compatibility problems in the report.
    • Corrected techniques for auto-detection of header file dependencies (include paths).
    • Removed problems relating to the changes in the temporary header files.
    • Corrected interface signatures in the report.
    • Corrected checking of added/withdrawn parameters.
    • Corrected changes in the virtual tables of the libraries with symbol versioning.
    • Corrected checking of complex namespaces changes (C++).
    • Added namespaces information to the ABI dump.

Version 1.17.2 (June 16, 2010)

Abi-compliance-checker-1.17.2.tar.gz
This intermediate release includes several bug fixes.

  • Bug Fixes
    • Repaired --separately option.
    • Corrected permissions of LICENSE file.
    • Corrected tool description.

Version 1.17.1 (June 09, 2010)

Abi-compliance-checker-1.17.1.tar.gz
This intermediate release includes critical bug fixes.

  • New Features
    • Added --relpath option for adding prefixes to the paths in the library descriptor.
  • Bug Fixes
    • Corrected checking of added/withdrawn parameters.
    • Corrected processing of mixed C/C++ header sets.
    • Corrected checking of parameter type changes.

Version 1.17 (June 08, 2010)

Abi-compliance-checker-1.17.tar.gz
This is generally a bug fix release. Tested on 75 libraries.

  • New Features
    • Visualizing of the serious changes (added/withdrawn parameters) in the interface signature.
    • Recursive analysis of constant changes.
    • Separated stderr and stdout streams of the tool.
    • Added <skip_constants> section to the library descriptor for skipping checks of some constants.
    • Added --params option for adding function parameter names to the report.
  • Bug Fixes
    • Corrected analysis of virtual table layout changes.
    • Corrected analysis of parameter type changes.
    • Corrected complex array type names.
    • Corrected typedef names.
    • Corrected analysis of structure layout changes.
    • Fixed tool hanging on some C++ headers (with many namespaces).
    • Corrected analysis of Glibc headers.
    • Corrected analysis of library language changes (if added some C++ headers).
    • Corrected descriptions of some compatibility problems.
    • Corrected analysis of added/withdrawn parameters in C headers.

Version 1.16 (May 05, 2010)

Abi-compliance-checker-1.16.tar.gz
This release includes many bug fixes and new features after integration to the Upstream Tracker system.

  • New Features
    • Added --strict option for treating all compatibility warnings as problems.
    • Added --dumpversion option for printing tool version and don't do anything else.
    • Ignoring hidden .svn, .git, .bzr, .hg, and CVS directories.
    • Improved header files sorting for protecting from compilation errors on the intermediate phase of temporary header file compilation.
    • Improved techniques for auto-detection of header file dependencies (include paths).
    • Ignoring problems related to changes of constants (defines) describing library version (*_VERSION_*, *_COPYRIGHT_* and other).
    • New internal test cases.
  • Bug Fixes
    • Checking of some previously missed C++ namespaces.
    • Removed hidden "void const** __vtt_parm" parameters from signatures of some constructors.
    • Corrected dumping of C++ classes ABI.
    • Corrected checking of pure virtual destructors.
    • Removed unnecessary built-in constants from the ABI dump.

Version 1.15 (March 26, 2010)

Abi-compliance-checker-1.15.tar.gz
This is generally a bug fix release with the changed license.

  • New Features
    • The license was changed to dual GNU GPL and LGPL.
    • Added <skip_headers> section in the descriptor.
  • Bug Fixes
    • Corrected processing of <include_paths> section in the descriptor.
    • Corrected processing of relative paths in the <headers> and <include_paths> sections.
    • Directory with temporary files renamed from "temp" to hidden ".tmp_dir".
    • Corrected processing of shared object dependencies.
    • Corrected processing of some previously missed functions and conversion operators in C++.
    • Corrected internal test suite.
    • Corrected some error messages.

Version 1.14 (March 03, 2010)

Abi-compliance-checker-1.14.tar.gz

  • New Features
    • Added techniques for auto-detection of header file dependencies (include paths). Now providing of <include_paths> section in the descriptor is not necessary.
    • Ported to FreeBSD and Haiku.
    • Added check for gcc/g++ version (>=3.0.0).
    • Added sorting of interface problems by namespace in the report (C++).
    • Improved internal test suite.
    • Added log for describing tool actions and occurred errors.
    • Added exit error code (high/medium risk for ABI break).
  • Bug Fixes
    • Corrected ABI dumping.
    • Corrected styles in the report design.

Version 1.13 (February 16, 2010)

Abi-compliance-checker-1.13.tar.gz
This is generally a bug fix release.

  • Bug fixes
    • Corrected processing of tab characters in the descriptor.
    • Corrected help message.
    • Corrected descriptor template structure.
    • Corrected error and warning messages.
    • Corrected processing of shared object dependencies.

Version 1.12 (December 04, 2009)

Abi-compliance-checker-1.12.tar.gz
This is generally a bug fix release.

  • Bug fixes
    • Corrected classification of compatibility problems in the report.
    • Priority of problems related to changes in the methods object was reduced.
    • Corrected complex template type names.
  • New features
    • New help message.
    • Highlighting of [in-charge], [not-in-charge] constructors and destructors in the report was improved.
    • New option -time for enabling time measurements.
    • New internal test cases.

Version 1.11 (November 10, 2009)

Abi-compliance-checker-1.11.tar.gz

  • New Features
    • Added --app option to check portability of applications to the new library version.
    • Memory usage decreased twice.
  • Bug fixes
    • Corrected checking of added middle structure members.
    • Corrected names of template types (with intrinsic, bool and string parameters).
    • Corrected highlighting of function signatures in the report.

Version 1.10 (November 02, 2009)

Abi-compliance-checker-1.10.tar.gz

  • New Features
    • Checking added/dropped function parameters (C language only).
    • Improvements in the design of ABI compliance report.
    • New internal test cases.
  • Bug fixes
    • Incorrect checking of redefined virtual functions and differences in parameter types.
    • More careful checking of withdrawn interfaces using shared library dependencies.

Version 1.9 (October 12, 2009)

Abi-compliance-checker-1.9.tar.gz

  • Improvements
    • Improved design of ABI compliance report.
    • Improved algorithms of checking parameter/field type change.
  • Bug Fixes
    • Fixed incorrect names of typedefs and function pointer types.
    • Checking of some previously missed C++-functions.
    • Removed some false positives from the report (for anon-types).
  • Other
    • New internal test cases.

Version 1.8 (September 29, 2009)

Abi-compliance-checker-1.8.tar.gz
It is the bug fix release after integration to the Moblin SigChk and testing Moblin-2.0 libraries for ABI compatibility with Ubuntu-Moblin-Remix-9.10 libraries.

  • Bug fixes
    • Size of ABI info dumps have been reduced through removing of unnecessary information.
    • Incorrect names of template instances and function pointer types.
    • Incorrect positions of function parameters in the section 'Interface Problems' in the report.
    • Removed some false positives from the report.
    • Incorrect handling of special symbols in the paths to header files and shared objects.
  • New features
    • Added ability to specify a file with a list of interfaces that should be checked.

Version 1.7 (September 11, 2009)

Abi-compliance-checker-1.7.tar.gz

  • New features
    • Checking of incorrect symbols versioning.
    • Checking the values of defines (constants).
    • Ability to check header files without shared objects. It is easy to run, but may provide a low quality ABI compliance report
      with a lot of false positives and without detecting of added/withdrawn interfaces.
    • Number of checked interfaces and data types in the report.
    • Added tests for checking new features.
  • Bug fixes
    • Incorrect processing of duplicated headers in the input set (headers with the same name but different paths).
    • Incorrect header files include order.
    • Sorting in the ABI dumps.
    • Incorrect processing of redefined virtual methods.
    • Incorrect processing of anon types.
    • Absence of some necessary information about C++-functions in the ABI dumps.

Version 1.6 (August 31, 2009)

Abi-compliance-checker-1.6.tar.gz

  • Bug Fixes
    • Corrected processing of relative paths in library descriptors
    • Displaying of machine hardware name instead of processor type in the ABI compliance report
    • Many grammar/spelling errors have been fixed
    • Section "internal_interfaces" in the library descriptor has been renamed to "skip_interfaces"
    • Cosmetic changes in the code

Version 1.5 (August 25, 2009)

Abi-compliance-checker-1.5.tar.gz

  • Bug Fixes
    • Absent information about opaque types and internal interfaces has been added to the ABI dump
    • Some fixes in the design of ABI compliance report
    • Some fixes in grammar/spelling
    • The section "internal_functions" in the library descriptor has been renamed to "internal_interfaces"
    • ABI dump has been renamed to "*.abi.tar.gz" (previously it was "*.info.tar.gz")
    • Corrected interface names in the ABI compliance report (for -separately option)

Version 1.4 (August 18, 2009)

Abi-compliance-checker-1.4.tar.gz

  • Improvements
    • Added ability to check ABI compliance of library versions placed on different machines
    • Header files checking mode by default has been changed: checking all header files together instead of separate checking
  • Bug Fixes
    • Incorrect description for affected interfaces
    • Incorrect virtual table checking

Version 1.3 (August 14, 2009)

Abi-compliance-checker-1.3.tar.gz
This is the bug fix release.

  • Bug Fixes
    • Incorrect number of binary compatibility problems in the report summary
    • Incorrect design of problem descriptions in the report

Version 1.2 (August 07, 2009)

Abi-compliance-checker-1.2.tar.gz
New email address for bug reports and feature requests.

Version 1.1 (August 06, 2009)

Abi-compliance-checker-1.1.tar.gz

  • Improvements
    • Design of the ABI compliance report has been greatly improved

Version 1.0 (July 31, 2009)

Abi-compliance-checker-1.0.0.tar.gz
Initial prototype of the tool.

abi-compliance-checker-1.99.9/doc/Descriptor.html000066400000000000000000000500211227016120300216310ustar00rootroot00000000000000 Library Descriptor

Library Descriptor

Library descriptor is a simple XML-file that specifies version number, paths to header files and shared libraries and optionally some other information.

Contents

Primary Sections

 <version>
     /* Version of the library */
 </version>
   
 <headers>
     /* The list of paths to header files or/and
        directories with header files, one per line */
 </headers>
   
 <libs>
     /* The list of paths to shared libraries or/and
        directories with shared libraries, one per line */
 </libs>

Optional Sections

 <include_paths>
     /* The list of paths to be searched for header files
        needed for compiling of library headers, one per line.
        NOTE: If you define this section then the tool
        will not automatically detect include paths */
 </include_paths>
 
 <add_include_paths>
     /* The list of include paths that should be added
        to the automatically detected include paths, one per line */
 </add_include_paths>
 
 <skip_include_paths>
     /* The list of include paths that will be removed from the
        list of automatically generated include paths, one per line */
 </skip_include_paths>
 
 <gcc_options>
     /* Additional GCC options, one per line */
 </gcc_options>
 
 <include_preamble>
     /* The list of header files that should be included before other headers, one per line.
        For example, it is a tree.h for libxml2 and ft2build.h for freetype2 library */
 </include_preamble>
 
 <defines>
     /* Add defines at the headers compiling stage, one per line:
          #define A B
          #define C D */
 </defines>
 
 <add_namespaces>
     /* The list of namespaces that should be added to the alanysis	
        if the tool cannot find them automatically, one per line */	
 </add_namespaces>
 
 <skip_types>
     /* The list of data types, that
        should not be checked, one per line */
 </skip_types>
   
 <skip_symbols>
     /* The list of functions (mangled/symbol names in C++),
        that should not be checked, one per line */
 </skip_symbols>
 
 <skip_namespaces>
     /* The list of C++ namespaces, that
        should not be checked, one per line */
 </skip_namespaces>
 
 <skip_constants>
     /* The list of constants that should not be checked, one name per line */
 </skip_constants>
 
 <skip_headers>
     /* The list of header files and/or directories
        with header files that should not be checked, one per line */
 </skip_headers>
 
 <skip_libs>
     /* The list of shared libraries and/or directories
        with shared libraries that should not be checked, one per line */
 </skip_libs>
 
 <skip_including>
     /* The list of header files, that cannot be included
        directly (or non-self compiled ones), one per line */
 </skip_including>
 
 <search_headers>
     /* List of directories to be searched
        for header files to automatically
        generate include paths, one per line */
 </search_headers>
 
 <search_libs>
     /* List of directories to be searched
        for shared librariess to resolve
        dependencies, one per line */
 </search_libs>
 
 <tools>
     /* List of directories with tools used
        for analysis (GCC toolchain), one per line */
 </tools>
 
 <cross_prefix>
     /* GCC toolchain prefix.
        Examples:
            arm-linux-gnueabi
            arm-none-symbianelf */
 </cross_prefix>

Extra Sections (API Sanity Checker)

 <test_include_preamble>
     /* The list of header files that should be
        included in each test case before other
        headers, one per line */
 </test_include_preamble>
 
 <test_defines>
     /* Add defines to test cases */
 </test_defines>

Examples

  • libssh
 <version>
     0.3.4
 </version>
 
 <headers>
     /usr/local/libssh/0.3.4/include/
 </headers>
 
 <libs>
     /usr/local/libssh/0.3.4/lib/
 </libs>
  • ATK
 <version>
     1.28.0
 </version>
 
 <headers>
     /usr/local/atk-1.28.0/include/atk-1.0/atk/atk.h
 </headers>
 
 <libs>
     /usr/local/atk-1.28.0/lib/
 </libs>
 
 <include_paths>
     /usr/include/glib-2.0/
     /usr/lib/glib-2.0/include/
 </include_paths>
  • libxml2
 <version>
     2.7.6
 </version>
 
 <headers>
     /usr/local/libxml2-2.7.6/include/
 </headers>
 
 <libs>
     /usr/local/libxml2-2.7.6/lib/libxml2.so.2.7.6
 </libs>
 
 <include_preamble>
     tree.h
 </include_preamble>
  • libX11
 <version>
     1.3.2
 </version>
 
 <headers>
     /usr/local/libX11-1.3.2/include/
 </headers>
 
 <libs>
     /usr/local/libX11-1.3.2/lib/
 </libs>
 
 <include_preamble>
     Xlib.h
 </include_preamble>
  • BlackBerry 10 Native SDK
 <version>
     10
 </version>
 
 <headers>
     /home/RIM/bbndk/target_10_0_9_1673/qnx6/usr/include/bb/
 </headers>
 
 <search_headers>
     /home/RIM/bbndk/target_10_0_9_1673/qnx6/usr/include/
 </search_headers>
 
 <libs>
     /home/RIM/bbndk/target_10_0_9_1673/qnx6/x86/usr/lib/
 </libs>
 
 <tools>
     /home/RIM/bbndk/host_10_0_9_404/linux/x86/usr/bin/
 </tools>
 
 <cross_prefix>
     i486-pc-nto-qnx8.0.0
 </cross_prefix>
  • libQtCore
 <version>
     4.6.0
 </version>
 
 <headers>
     /usr/local/Qt-4.6.0/include/QtCore/QtCore
 </headers>
 
 <libs>
     /usr/local/Qt-4.6.0/lib/libQtCore.so.4
 </libs>
 
 <include_paths>
     /usr/local/Qt-4.6.0/include/
 </include_paths>
 
 <gcc_options>
    -fvisibility=hidden
    -fvisibility-inlines-hidden
    -fPIC
    -Wall
    -W
    -D_REENTRANT
    -DQT_NO_CAST_FROM_ASCII
    -DQT_NO_CAST_TO_ASCII
    -DQT_NO_STL
    -DQT_SHARED
    -DQT3_SUPPORT
 </gcc_options>
  • libxslt
 <version>
     1.1.22
 </version>
 
 <headers>
     /usr/local/libxslt-1.1.22/include/
 </headers>
 
 <libs>
     /usr/local/libxslt-1.1.22/lib/libxslt.so
     /usr/local/libxslt-1.1.22/lib/libexslt.so
 </libs>
 
 <include_paths>
     /usr/include/libxml2/
 </include_paths>
 
 <include_preamble>
     xsltInternals.h
 </include_preamble>
  • libxml++
 <version>
     2.26.1
 </version>
 
 <headers>
     /usr/local/libxml++-2.26.1/include/
     /usr/local/libxml++-2.26.1/lib/libxml++-2.6/include/
 </headers>
 
 <libs>
     /usr/local/libxml++-2.26.1/lib/
 </libs>
 
 <include_paths>
     /usr/include/glib-2.0/
     /usr/lib/glib-2.0/include/
     /usr/include/glibmm-2.4/
     /usr/lib/glibmm-2.4/include/
 </include_paths>
  • pango
 <version>
     1.26.0
 </version>
 
 <headers>
     /usr/local/pango-1.26.0/include/
 </headers>
 
 <libs>
     /usr/local/pango-1.26.0/lib/
 </libs>
 
 <include_paths>
     /usr/include/glib-2.0/
     /usr/lib/glib-2.0/include/
     /usr/include/cairo/
     /usr/include/freetype2/
     /usr/include/X11/
 </include_paths>
 
 <include_preamble>
     pango.h
 </include_preamble>
  • gtk+
 <version>
     2.18.4
 </version>
 
 <headers>
     /usr/local/gtk+-2.18.4/include/gtk-2.0/gdk/gdk.h
     /usr/local/gtk+-2.18.4/include/gtk-2.0/gtk/gtk.h
     /usr/local/gtk+-2.18.4/include/gail-1.0/
     /usr/local/gtk+-2.18.4/include/gtk-unix-print-2.0/
 </headers>
 
 <libs>
     /usr/local/gtk+-2.18.4/lib/
 </libs>
 
 <include_paths>
     /usr/include/atk-1.0/
     /usr/include/glib-2.0/
     /usr/lib/glib-2.0/include/
     /usr/include/cairo/
     /usr/include/pango-1.0/
 </include_paths>
  • glib
 <version>
     2.22.2
 </version>
 
 <headers>
     /usr/local/glib-2.22.2/include/glib-2.0/glib.h
     /usr/local/glib-2.22.2/include/glib-2.0/glib-object.h
     /usr/local/glib-2.22.2/include/glib-2.0/gmodule.h
 </headers>
 
 <libs>
     /usr/local/glib-2.22.2/lib/
 </libs>
 
 <include_paths>
     /usr/local/glib-2.22.2/lib/glib-2.0/include/
 </include_paths>
  • libsoup
 <version>
     2.28.0
 </version>
 
 <headers>
     /usr/local/libsoup-2.28.0/include/
 </headers>
 
 <libs>
     /usr/local/libsoup-2.28.0/lib/
 </libs>
 
 <include_paths>
     /usr/include/glib-2.0/
     /usr/lib/glib-2.0/include/
 </include_paths>
  • allegro
 <version>
     4.9.9.1
 </version>
 
 <headers>
     /usr/local/include/allegro5/allegro.h
 </headers>
 
 <libs>
     /usr/local/lib/liballegro-4.9.9.so
 </libs>
  • mathgl
 <version>
     1.9.0.1
 </version>
 
 <headers>
     /usr/local/mathgl-1.9.0.1/include/
 </headers>
 
 <libs>
     /usr/local/mathgl-1.9.0.1/lib/
 </libs>
 
 <include_paths>
     /usr/local/gsl-1.9/include/
 </include_paths>
  • gsl
 <version>
     1.9
 </version>
 
 <headers>
     /usr/local/gsl-1.9/include/
 </headers>
 
 <libs>
     /usr/local/gsl-1.9/lib/
 </libs>
 
 <include_preamble>
     stdlib.h
 </include_preamble>
  • libjpeg
 <version>
     7
 </version>
 
 <headers>
     /usr/local/libjpeg-7/include/jpeglib.h
 </headers>
 
 <libs>
     /usr/local/libjpeg-7/lib/
 </libs>
 
 <include_preamble>
     stdio.h
 </include_preamble>
abi-compliance-checker-1.99.9/doc/Options.html000066400000000000000000000445251227016120300211620ustar00rootroot00000000000000 ABI Compliance Checker Options

ABI Compliance Checker Options

Contents

Information Options

  • -h|-help
Print help message.

  • -i|-info
Print complete info.

  • -v|-version
Print version information.

  • -dumpversion
Print the tool version and don't do anything else.

General Options

  • -l|-lib|-library NAME
Library name (without version). It affects only on the path and the title of the report.

  • -d1|-old|-o PATH
Path to the descriptor of 1st (old) library version.

  • -d2|-new|-n PATH
Path to the descriptor of 2nd (new) library version.

  • -dump|-dump-abi PATH
Create library ABI dump for the input XML descriptor. You can transfer it anywhere and pass instead of the descriptor. Also it can be used for debugging the tool.

  • -old-dumps
Enable support for old-version ABI dumps.

Extra Options

  • -d|-descriptor-template
Create XML-descriptor template ./VERSION.xml

  • -app|-application PATH
This option allow to specify the application that should be tested for portability to the new library version.

  • -static-libs
Check static libraries instead of the shared ones. The <libs> section of the XML-descriptor should point to static libraries location.

  • -cross-gcc|-gcc-path PATH
Path to the cross GCC compiler to use instead of the usual (host) GCC.

  • -cross-prefix|-gcc-prefix PREFIX
GCC toolchain prefix.

  • -sysroot DIR
Specify the alternative root directory. The tool will search for include paths in the DIR/usr/include and DIR/usr/lib directories.

  • -v1|-version1 NUM
Specify 1st library version outside the descriptor.

  • -v2|-version2 NUM
Specify 2nd library version outside the descriptor.

  • -s|-strict
Treat all compatibility warnings as problems.

  • -headers-only
Check header files without shared libraries. It is easy to run, but may provide provide a low quality compatibility report with false positives and without detecting of added/removed symbols.

  • -objects-only
Check shared libraries without header files. It is easy to run, but may a low quality report with false positives and without analysis of changes in parameters and data types.

  • -check-impl|-check-implementation
Compare canonified disassembled binary code of shared objects to detect changes in the implementation. Create section 'Changes in Implementation' in the report.

  • -show-retval
Show the symbol's return type in the report.

  • -symbols-list PATH
This option allow to specify a file with a list of interfaces (mangled names in C++) that should be checked, other library interfaces will not be checked.

  • -skip-symbols PATH
The list of symbols that should NOT be checked.

  • -headers-list PATH
The file with a list of headers, that should be checked/dumped.

  • -skip-headers PATH
The file with the list of header files, that should not be checked.

  • -header NAME
Check/Dump ABI of this header only.

  • -use-dumps
Make dumps for two versions of a library and compare dumps. This should increase the performance of the tool and decrease the operative memory usage.

  • -nostdinc
Do not search the GCC standard system directories for header files.

  • -dump-system NAME -sysroot DIR
Find all the shared libraries and header files in DIR directory, create XML descriptors and make ABI dumps for each library. The result set of ABI dumps can be compared (-cmp-systems) with the other one created for other version of operating system in order to check them for compatibility. Do not forget to specify -cross-gcc option if your target system requires some specific version of GCC compiler (different from the host GCC). The system ABI dump will be generated to: sys_dumps/NAME/ARCH.

  • -dump-system PATH
The same as the previous option but takes an XML descriptor of the target system.

  • -sysinfo DIR
This option may be used with -dump-system to dump ABI of operating systems and configure the dumping process. Default: modules/SysInfo/<target> {unix, symbian, windows}

  • -cmp-systems
Compare two system ABI dumps. Create compatibility reports for each library and the common HTML report including the summary of test results for all checked libraries. Report will be generated to: sys_compat_reports/NAME1_to_NAME2/ARCH.

  • -libs-list PATH
The file with a list of libraries, that should be dumped by the -dump-system option or should be checked by the -cmp-systems option.

  • -ext|-extended
If your library A is supposed to be used by other library B and you want to control the ABI of B, then you should enable this option. The tool will check for changes in all data types, even if they are not used by any function in the library A. Such data types are not part of the A library ABI, but may be a part of the ABI of the B library.

  • -q|-quiet
Print all messages to the file instead of stdout and stderr.

  • -stdout
Print analysis results (compatibility reports and ABI dumps) to stdout instead of creating a file. This would allow piping data to other programs.

  • -report-format FORMAT
Change format of compatibility report: html (default) or xml.

  • -dump-format FORMAT
Change format of ABI dump: perl (default) or xml.

  • -xml
Alias for: --report-format=xml or --dump-format=xml

  • -lang LANG
Set library language (C or C++). You can use this option if the tool cannot auto-detect a language. This option may be useful for checking C-library headers (--lang=C) in -headers-only or -extended modes.

  • -binary|-bin|-abi
Show binary-compatibility problems only. Generate report to: compat_reports/LIB_NAME/V1_to_V2/abi_compat_report.html

  • -source|-src|-api
Show source-compatibility problems only. Generate report to: compat_reports/LIB_NAME/V1_to_V2/src_compat_report.html

  • -affected-limit LIMIT
The maximum number of affected symbols listed under the description of the changed type in the report.

Other Options

  • -test
Run internal tests. Create two binary incompatible versions of a sample library and run the tool to check them for compatibility. This option allows to check if the tool works correctly in the current environment.

  • -test-dump
Test ability to create, restore and compare ABI dumps.

  • -debug
Debugging mode. Print debug info on the screen. Save intermediate analysis stages in the debug directory: debug/LIB_NAME/VER/.

  • -cpp-compatible
If your header file is written in C language and can be compiled by the C++ compiler (i.e. doesn't contain C++-keywords), then you can tell ACC about this and speedup the analysis.

  • -cpp-incompatible
Set this option if input C header files use C++ keywords.

  • -p|-params PATH
Path to file with the function parameter names. It can be used for improving report view if the library header files don't contain parameter names. File format:

func1;param1;param2;param3 ...

func2;param1;param2;param3 ...

  ...

  • -relpath PATH
Replace {RELPATH} macros to PATH in the XML-descriptor used for dumping the library ABI (see -dump option).

  • -relpath1 PATH
Replace {RELPATH} macros to PATH in the 1st XML-descriptor (see -d1 option).

  • -relpath2 PATH
Replace {RELPATH} macros to PATH in the 2nd XML-descriptor (see -d2 option).

  • -dump-path PATH
Specify a *.abi.tar.gz or *.abi file path where to generate an ABI dump. Default path: abi_dumps/LIB_NAME/LIB_NAME_VERSION.abi.tar.gz

  • -sort
Enable sorting of data in ABI dumps.

  • -report-path PATH
Specify the file path where to generate the compatibility report. Default report path: compat_reports/LIB_NAME/V1_to_V2/abi_compat_report.html

  • -bin-report-path PATH
Path to binary-compatibility report. Default: compat_reports/LIB_NAME/V1_to_V2/abi_compat_report.html

  • -src-report-path PATH
Path to source-compatibility report. Default: compat_reports/LIB_NAME/V1_to_V2/src_compat_report.html

  • -log-path PATH
Log path for all messages. Default log path: logs/LIB_NAME/VER/log.txt

  • -log1-path PATH
Log path for 1st version of a library. Default log path: logs/LIB_NAME/V1/log.txt

  • -log2-path PATH
Log path for 2nd version of a library. Default log path: logs/LIB_NAME/V1/log.txt

  • -logging-mode MODE
Change logging mode. Modes: w - overwrite old logs (default), a - append old logs, n - do not write any logs

  • -list-affected
Generate file with the list of incompatible symbols beside the HTML compatibility report. Use 'c++filt @file' command from GNU Binutils to unmangle C++ symbols in the generated file. Default name: abi_affected.txt

  • -component NAME
The component name in the title and summary of the HTML report. Default: library

  • -l-full|-lib-full NAME
Change library name in the report title to NAME. By default will be displayed a name specified by -l option.

  • -b|-browse PROGRAM
Open report(s) in the browser (firefox, opera, etc.).

  • -open
Open report(s) in the default browser.

  • -extra-info DIR
Dump extra info to DIR.

  • -extra-dump
Create extended ABI dump containing all symbols from the translation unit.

  • -force
Try to use this option if the tool doesn't work.

  • -tolerance LEVEL
Apply a set of heuristics to successfully compile input header files. You can enable several tolerance levels by joining them into one string (e.g. 13, 124, etc.). Levels: 1 - skip non-Linux headers (e.g. win32_*.h, etc.), 2 - skip internal headers (e.g. *_p.h, impl/*.h, etc.), 3 - skip headers that iclude non-Linux headers, 4 - skip headers included by others.

  • -tolerant
Enable highest tolerance level [1234].

  • -check
Check completeness of the ABI dump.

  • -quick
Quick analysis. Disable check of some template instances.

  • -skip-internal PATTERN
Do not check internal interfaces matched by the pattern.

abi-compliance-checker-1.99.9/doc/Readme.html000066400000000000000000001233261227016120300207210ustar00rootroot00000000000000 ABI Compliance Checker

ABI Compliance Checker

ABI Compliance Checker (ACC) is a tool for checking backward binary and source-level compatibility of a C/C++ library. The tool checks header files and shared libraries of old and new versions and analyzes changes in API and ABI (ABI=API+compiler ABI) that may break binary and/or source compatibility: changes in calling stack, v-table changes, removed symbols, renamed fields, etc. Binary incompatibility may result in crashing or incorrect behavior of applications built with an old version of a library if they run on a new one. Source incompatibility may result in recompilation errors with a new library version. The tool is intended for developers of software libraries and maintainers of operating systems who are interested in ensuring backward compatibility, i.e. allow old applications to run or to be recompiled with newer library versions.

See also:


Contents

Downloads

Releases

All releases can be downloaded from this page or github.com.

Latest release: 1.99.9

Git

Read-only access to the latest development version:
   git clone git://github.com/lvc/abi-compliance-checker.git  

License

This program is free software. You may use, redistribute and/or modify it under the terms of either the GNU GPL or LGPL.

Supported Platforms

GNU/Linux, FreeBSD, Mac OS X, MS Windows, Haiku/BeOS.

System Requirements

  • Linux, FreeBSD
    • G++ (3.0-4.7, 4.8.3, recommended 4.5 or newer)
    • GNU Binutils (readelf, c++filt, objdump)
    • Perl 5 (5.8 or newer)
    • Ctags (5.8 or newer)
    • WARNING: if you are using ccache program (i.e. gcc points to /usr/lib/ccache/gcc) then it should be newer than 3.1.2 or disabled.
  • Mac OS X
    • Xcode (gcc, c++filt, nm, otool)
    • Ctags (5.8 or newer)
  • MS Windows
    • MinGW (3.0-4.7, recommended 4.5 or newer)
    • MS Visual C++ (dumpbin, undname, cl)
    • Active Perl 5 (5.8 or newer)
    • Sigcheck v1.71 or newer
    • Ctags (5.8 or newer)
    • Info-ZIP 3.0 (zip, unzip)
    • Add tool locations to the PATH environment variable
    • Run vsvars32.bat script (C:\Microsoft Visual Studio 9.0\Common7\Tools\)

Detectable Compatibility Problems

The tool searches for the following list of changes in the API that may break binary/source-level compatibility. See this list of articles for more info.

Binary Compatibility

  • Removed Symbols (functions, global data)
  • Problems with Data Types
    • Structures and Classes
      • added/removed fields (change of a memory layout)
      • change of size
      • changed order of fields
      • change of a field type
      • changes in fields (recursive analysis)
    • Classes
      • added/removed virtual functions (change of a v-table layout)
      • change of virtual function position
      • overridden virtual functions
      • added/removed base classes
      • changes in base classes (recursive analysis)
    • Unions
      • added/removed fields
      • change of size
      • change of a field type
      • changes in fields (recursive analysis)
    • Enumerations
      • change of a member value
      • removed/renamed members
  • Problems with Symbols
    • Stack Frame
      • added/removed parameters
      • change of a parameter/return value type
      • change of default parameter value
      • renamed parameters
    • Other
      • incorrect version change
      • changed attributes (const, volatile, static, etc.)
  • Problems with Constants (#defines)
    • changed value
  • Problems with Implementation
    • changes in disassembled binary code

Source Compatibility

  • Removed Symbols (functions, global data)
  • Problems with Data Types
    • Structures, Classes and Unions
      • removed/renamed fields
      • change of a field type
      • changes in fields (recursive analysis)
    • Classes
      • added/removed base classes
      • change access level of a field or method
      • added pure virtual methods
    • Enumerations
      • removed/renamed members
  • Problems with Symbols
    • Parameters
      • added/removed parameters
      • change of a parameter type
      • removed default value
    • Other
      • change of return value type
      • changed attributes (const, static, etc.)
  • Problems with Constants (#defines)
    • changed value


You can see detailed problem descriptions in the visual interactive HTML-format compatibility report (see this example) generated by the tool.

Installation

The tool is ready-to-use after extracting the archive. You can also use a Makefile to install the tool into the system:
 cd abi-compliance-checker-x.y.z/ 

 sudo perl Makefile.pl -install --prefix=PREFIX [/usr, /usr/local, ...] 

This command will install an  abi-compliance-checker  program in the  PREFIX/bin  system directory and private modules into the  PREFIX/share .

To verify that the tool is installed correctly and it works on your host run:
 cd tmp/ 

 abi-compliance-checker -test 

Usage

For using the tool, you should provide the XML descriptors for two library versions: v1.xml and v2.xml files. Library descriptor is a simple XML-file that specifies version number, paths to header files and shared libraries and other optional information. An example of the descriptor is the following (0.3.4.xml):

<version>
    0.3.4
</version>

<headers>
    /usr/local/libssh/0.3.4/include/
</headers>

<libs>
    /usr/local/libssh/0.3.4/lib/
</libs>

Compare Libraries

Command to compare two versions of a library:
   abi-compliance-checker -lib NAME -old V1.xml -new V2.xml 

The compatibility report will be generated to:
   compat_reports/NAME/V1_to_V2/compat_report.html 

Create ABI Dumps

The library ABI is a representation of the library API at the binary level. The ABI dump is a dump of the model of the ABI used in the tool.

The ABI dump consists of:

  • Types Information
    • Attributes (name, size, header, access, base types, etc.)
    • Fields (name, type, size, position, alignment, access, specifiers, etc.)
    • V-table structure (offsets, entries)
    • Etc.
  • Symbols Information
    • Attributes (name, mangled name, header, access, specifiers, etc.)
    • Parameters (name, type, position, alignment, etc.)
    • Etc.
  • Etc.

The ABI dump can be used to create a snapshot of a library ABI in the particular environment and then compare it with any other state of the ABI changed due to changes in the environment (compiler version, external libraries, etc.) or changes in the library API (header files). The typical case is the comparing of two versions of the same library that require incompatible states of the environment (i.e. these versions cannot be installed simultaneously). In this case one can create a dump for one version of the library and then switch the environment and create ABI dump for other version of the library. Two ABI dumps can be compared by the tool to create the API compatibility report.

To create an ABI dump use -dump option:
   abi-compliance-checker -lib NAME -dump VER.xml 

The ABI dump will be generated to:
   abi_dumps/NAME/NAME_VER.abi.tar.gz 

To compare ABI dumps pass them as the descriptors:
   abi-compliance-checker -lib NAME -old V1.abi.tar.gz -new V2.abi.tar.gz 

Usage with ABI Dumper

Library should be compiled with -g option to contain DWARF debug info.

Create ABI dumps for both library versions using the ABI Dumper tool:

   abi-dumper OLD.so -o ABI-0.dump -lver 0 

   abi-dumper NEW.so -o ABI-1.dump -lver 1 

Compare ABI dumps:

   abi-compliance-checker -l NAME -old ABI-0.dump -new ABI-1.dump 

Usage as a Parser of API

The tool can be used as a parser of C/C++ API. Use -dump and -xml options to create ABI dump in the XML format:
   abi-compliance-checker -lib NAME -dump VER.xml -xml 

The ABI dump will be generated to:
   abi_dumps/NAME/NAME_VER.abi.tar.gz 

You can use additional -stdout option to print ABI dump on the screen instead of creating gzipped file:
   abi-compliance-checker -lib NAME -dump VER.xml -xml -stdout 

See examples of ABI dumps for MeeGo Touch library in XML and Perl (default) formats.

Compare Operating Systems

The detailed explanation on how to check compatibility between operating systems you can read on this page.

See current test results for Symbian, Windows, MeeGo and Maemo on this page.

Check Applications Portability

The ACC tool can be used by independent software vendors (ISV) to check applications portability to new library versions by specifying of its binary using -app option:
   abi-compliance-checker -lib NAME -old V1.xml -new V2.xml -app APP 

Found issues can be taken into account when adapting the application to a new library version.

Command-Line Options

See the list of all options on this page.

Up-to-date list of all supported options can be obtained by this command:

   abi-compliance-checker --info 

Most useful options:

Examples

Check the libssh library versions for ABI compatibility:
   abi-compliance-checker -l libssh -old 0.3.4.xml -new 0.4.0.xml 

The compatibility report will be generated to:
   compat_reports/libssh/0.3.4_to_0.4.0/compat_report.html 

Dump library ABI:
   abi-compliance-checker -l libssh -dump 0.3.4.xml 

The ABI will be dumped to:
   abi_dumps/libssh/libssh_0.3.4.abi.tar.gz 

Use previously dumped ABI:
   abi-compliance-checker -l libssh -old libssh_0.3.4.abi.tar.gz -new libssh_0.4.0.abi.tar.gz 

Check client application portability between libssh versions:
   abi-compliance-checker -l libssh -old 0.3.4.xml -new 0.4.0.xml -app /usr/bin/csync 

Tutorial

An excellent tutorial "ABI: stability check" is available at Les RPM de Remi Blog. See also ABI Compliance Checker Notes at glibc wiki.

Report Format

The tool supports two formats of a compatibility report: visual interactive HTML (default) and XML. To generate XML report you should specify -xml additional option.

The HTML-format compatibility report consists of:

  • Test Info - The library name and compared version numbers. Environment info: GCC version and CPU type;
  • Test Results - Verdict on compatibility. Number of header files, shared libraries, symbols and data types checked by the tool;
  • Problem Summary - Classification of compatibility problems;
  • Added Symbols - The list of added symbols;
  • Removed Symbols - The list of removed symbols;
  • Problems with Data Types - The list of compatibility problems caused by changes in data types (divided by the severity level: High, Medium and Low). List of affected symbols;
  • Problems with Symbols - The list of compatibility problems caused by changes in symbol parameters or attributes (divided by the severity level);
  • Problems with Constants - The list of changed constants (#defines);
  • Other Changes in Data Types - The list of compatible changes in data types;
  • Other Changes in Symbols - The list of compatible changes in symbols;
  • Problems with Implementation - The list of changes in disassembled binary code. Use -check-implementation option to enable this section.

Examples of HTML-format report:

  • NetCDF: 4.0.1 to 4.1.1 API compatibility report
  • MySQL++: 3.0.9 to 3.1.0 binary compatibility report
  • libssh: 0.3.4 to 0.4.0 binary compatibility report

Verdict on Compatibility

If the tool detected problems with high or medium level of severity or at least one removed symbol then the compatibility verdict is incompatible (otherwise compatible). Low-severity problems can be considered as warnings and don't affect the compatibility verdict unless the -strict option is specified.

Error Codes

Code Meaning
0 Compatible. The tool has run without any errors.
1 Incompatible. The tool has run without any errors.
2 Common error code (undifferentiated).
3 A system command is not found.
4 Cannot access input files.
5 Cannot compile header files.
6 Headers have been compiled with minor errors.
7 Invalid input ABI dump.
8 Unsupported version of input ABI dump.
9 Cannot find a module.
10 Empty intersection between headers and shared objects.
11 Empty set of symbols in headers.

FAQ

  • What is an ABI and how does it differ from an API?

An Application Binary Interface (ABI) is the set of supported run-time interfaces provided by a software component or set of components for applications to use, whereas an Application Programming Interface (API) is the set of build-time interfaces. The ABI may be defined by the formula:

   ABI = API + compiler ABI
  • Why does this tool need both shared libraries and header files to check ABI compliance?

Without header files it is impossible to determine public symbols in ABI and data type definitions. Without shared libraries it is impossible to determine exported symbols in the ABI of the target library and also impossible to detect added/removed symbols.

Similar Tools

  1. icheck - C interface ABI/API checker
  2. BCS - The Symbian binary compatibility suite
  3. shlib-compat - ABI compatibility checker that uses DWARF debug info
  4. qbic - A tool to check for binary incompatibilities in Qt4 Toolkit
  5. chkshlib, cmpdylib, cmpshlib - Tools to compare binary symbols

Bugs

Please send your bug reports, feature requests and questions to the the maintainer, post to issue tracker or mailing list.

Maintainers

The tool was originally developed by the Russian Linux Verification Center at ISPRAS and since 1.93 version it's developed by the ROSA Laboratory in Russia. Andrey Ponomarenko is the leader of this project.

Credits

We would like to thank everyone who has contributed to the success of this project!

Articles

Here is the list of articles about shared libraries and binary compatibility:

  1. “Binary Compatibility Issues With C++”, KDE TechBase
  2. “Binary Compatibility Examples”, KDE TechBase
  3. "Itanium C++ ABI", linux-foundation.org
  4. "ABI Compatibility", Josh Faust
  5. "ABI : stability check", Les RPM de Remi - Blog
  6. “Calling conventions for different C++ compilers and operating systems”, Agner Fog
  7. "Calling conventions on the x86 platform", Andreas Jonsson
  8. “Some thoughts on binary compatibility”, Thiago Macieira
  9. "Binary Compatibility of C++ shared libraries on GNU/Linux", Pavel Shved, Denis Silakov
  10. "Library Interface Versioning in Solaris and Linux", David J. Brown and Karl Runge
  11. "Steps to Version Your Shared Library", hp.com
  12. "Macintosh C/C++ ABI Overview", developer.apple.com
  13. “Binary-compatible C++ Interfaces”, Chad Austin
  14. "ABI Policy and Guidelines", gnu.org
  15. "Binary Compatibility", gnu.org
  16. "Stability of the C++ ABI: Evolution of a Programing Language", Stephen Clamage
  17. "When binary compatibility breaks", Debian Library Packaging guide
  18. “Library Code Policy”, KDE TechBase
  19. "How To Write Shared Libraries", Ulrich Drepper
  20. "Application Binary Interface", Computer Desktop Encyclopedia
  21. “Program Library HOWTO”, linux.org
  22. “Writing shared libraries”, Mike Hearn
  23. "Shared libraries in Linux: growing pains or fundamental problem?", Sergey Ayukov
  24. “What's the Fragile Base Class (FBC) Problem?”, Peter Potrebic
  25. “Fragile Binary Interface Problem”, Steven Newton
  26. “The amazing world of library incompatibility”, oocities.org
  27. “The Theory of Binary Compatibility”, Forum.Nokia
  28. “How to control binary compatibility”, Forum.Nokia
  29. “ABI compatibility in C++”, elpauer.org
  30. “The impact of C++ templates on library ABI”, Michał Górny
  31. “ABI Compliance Checker Notes”, sourceware.org
  32. "Preserving Compatibility", symbian.org
  33. "Automated Verification of Shared Libraries for Backward Binary Compatibility", A. Ponomarenko and V. Rubanov, VALID 2010
  34. "Backward compatibility of software interfaces: Steps towards automatic verification", A. Ponomarenko and V. Rubanov, Programming and Computer Software 2012
  35. "Architectures and ABIs detailed", Thiago Macieira's blog
  36. "Interface Versioning in C++", ACCU
  37. "Generic ABI Standard", "ELF and ABI Standards", freestandards.org
  38. Processor ABI standards: Intel386, AMD64, ARM, PowerPC, S/390, Itanium, MIPS, SPARC, PA-RISK, M32R
  39. Translation of this article to Serbo-Croatian, Jovana Milutinovich
abi-compliance-checker-1.99.9/doc/SysCheck/000077500000000000000000000000001227016120300203435ustar00rootroot00000000000000abi-compliance-checker-1.99.9/doc/SysCheck/Descriptor.html000066400000000000000000000240041227016120300233470ustar00rootroot00000000000000 Operating System Descriptor

Operating System Descriptor

Primary Sections

   <name>
       /* Name of the system */
   </name>
   
   <headers>
       /* The list of paths to header files and/or
          directories with header files, one per line */
   </headers>
   
   <libs>
       /* The list of paths to shared libraries and/or
          directories with shared libraries, one per line */
   </libs>

Optional Sections

   <search_headers>
       /* List of directories to be searched
          for header files to automatically
          generate include paths, one per line */
   </search_headers>
   
   <search_libs>
       /* List of directories to be searched
          for shared libraries to resolve
          dependencies, one per line */
   </search_libs>
   
   <tools>
       /* List of directories with tools used
          for analysis (GCC toolchain), one per line */
   </tools>
   
   <cross_prefix>
       /* GCC toolchain prefix.
          Examples:
              arm-linux-gnueabi
              arm-none-symbianelf */
   </cross_prefix>
   
   <gcc_options>
       /* Additional GCC options,
          one per line */
   </gcc_options>

Examples

  • Symbian^3
   <name>
       Symbian^3
   </name>
   
   <headers>
       c:\Nokia\devices\Nokia_Symbian3_SDK_v1.0\epoc32\include\
   </headers>
   
   <libs>
       c:\Nokia\devices\Nokia_Symbian3_SDK_v1.0\epoc32\release\armv5\lib\
   </libs>
   
   <tools>
       c:\Program Files\CodeSourcery\Sourcery G++ Lite\bin\
   </tools>
   
   <cross_prefix>
       arm-none-symbianelf
   </cross_prefix>
  • S60 5th Edition
   <name>
       S60 5th Edition
   </name>
   
   <headers>
       c:\Nokia\devices\S60_5th_Edition_SDK_v1.0\epoc32\include\
   </headers>
   
   <libs>
       c:\Nokia\devices\S60_5th_Edition_SDK_v1.0\epoc32\release\armv5\lib\
   </libs>
   
   <tools>
       c:\Program Files\CSL Arm Toolchain\bin\
   </tools>
   
   <cross_prefix>
       arm-none-symbianelf
   </cross_prefix>
  • S60 3rd Edition
   <name>
       S60 3rd Edition
   </name>
   
   <headers>
       c:\Nokia\devices\S60_3rd_FP2_SDK_v1.1\epoc32\include
   </headers>
   
   <libs>
       c:\Nokia\devices\S60_3rd_FP2_SDK_v1.1\epoc32\release\armv5\lib\
   </libs>
   
   <tools>
       c:\Program Files\CSL Arm Toolchain\bin\
   </tools>
   
   <cross_prefix>
       arm-none-symbianelf
   </cross_prefix>
  • Windows SDK 7.1
   <name>
       Windows SDK 7.1
   </name>
   
   <headers>
       c:\Program Files\Microsoft SDKs\Windows\v7.1\Include\
   </headers>
   
   <libs>
       c:\Windows\system32\
   </libs>
   
   <tools>
       c:\MinGW\bin\
   </tools>
   
   <gcc_options>
       -D_WIN32_WINNT=0x0700
   </gcc_options>
   
   <search_headers>
       c:\Program Files\Microsoft Visual Studio 9.0\VC\include\
   </search_headers>
  • Windows SDK 6.0
   <name>
       Windows SDK 6.0
   </name>
   
   <headers>
       c:\Program Files\Microsoft SDKs\Windows\v6.0A\Include\
   </headers>
   
   <libs>
       c:\Windows\system32\
   </libs>
   
   <tools>
       c:\MinGW\bin\
   </tools>
   
   <gcc_options>
       -D_WIN32_WINNT=0x0600
   </gcc_options>
   
   <search_headers>
       c:\Program Files\Microsoft Visual Studio 9.0\VC\include\
   </search_headers>
  • Windows SDK 5.0
   <name>
       Windows SDK 5.0
   </name>
   
   <headers>
       c:\Program Files\Microsoft SDKs\Windows\v5.0\Include\
   </headers>
   
   <libs>
       c:\Windows\system32\
   </libs>
   
   <tools>
       c:\MinGW\bin\
   </tools>
   
   <gcc_options>
       -D_WIN32_WINNT=0x0500
   </gcc_options>
abi-compliance-checker-1.99.9/doc/SysCheck/Examples.html000066400000000000000000000461031227016120300230130ustar00rootroot00000000000000 Operating Systems Compatibility Examples

Operating Systems Compatibility Examples

Contents

Compatibility of Maemo 4.1.2 and Maemo 5.0

Setup Maemo 4.1.2

Follow this tutorial to install Maemo 4.1.2 SDK.

Setup scratchbox for Maemo 4.1.2:
   sudo /home/maemo/4.1.2/scratchbox/sbin/sbox_ctl start 

Login to the Maemo 4.1.2:
   /home/maemo/4.1.2/scratchbox/login 

Select the ARMEL target:
   sb-conf select DIABLO_ARMEL 

Install all devel packages:
   apt-get update 

   apt-cache search "\-dev"|awk '{print $1;}'>install.txt 

   for i in `cat install.txt`;do apt-get --force-yes -y install $i;done 

Dump Maemo 4.1.2 ABI

Command to dump system ABI:
   abi-compliance-checker -dump-system "Maemo-4.1.2" -sysroot / 

The system ABI dump will be generated to:
   sys_dumps/Maemo-4.1.2/arm/ 

Exit and shutdown the scratchbox for Maemo 4.1.2:
   exit 

   sudo /home/maemo/4.1.2/scratchbox/sbin/sbox_ctl stop 

Setup Maemo 5.0

Follow this tutorial to install Maemo 5.0 SDK.

Login to the Maemo 5.0:
   /home/maemo/5.0/scratchbox/login 

Select the ARMEL target:
   sb-conf select FREMANTLE_ARMEL 

Install all devel packages:
   apt-get update 

   apt-cache search "\-dev"|awk '{print $1;}'>install.txt 

   for i in `cat install.txt`;do apt-get --force-yes -y install $i;done 

Dump Maemo 5.0 ABI

Command to dump the Maemo 5.0 ABI:
   abi-compliance-checker -dump-system "Maemo-5.0" -sysroot / 

The system ABI dump will be generated to:
   sys_dumps/Maemo-5.0/arm/ 

Exit and shutdown the scratchbox for Maemo 5.0:
   exit 

   sudo /home/maemo/5.0/scratchbox/sbin/sbox_ctl stop 

Compare ABI Dumps

Command to check Maemo 4.1.2 and Maemo 5.0 for backward compatibility:
   abi-compliance-checker -cmp-systems -d1 sys_dumps/Maemo-4.1.2/arm/ -d2 sys_dumps/Maemo-5.0/arm/ 

The compatibility report will be generated to:
   sys_compat_reports/Maemo-4.1.2_to_Maemo-5.0/arm/abi_compat_report.html 

Compatibility of MeeGo 1.2 Core and MeeGo 1.2 Harmattan

Setup MeeGo 1.2 Core

Follow this tutorial to install Intel's MeeGo 1.2 on VirtualBox and enter to the system terminal.

Install all devel packages:
   zypper search -u dev|awk '{print $2;}'|grep 'dev'>install.txt 

   for i in `cat install.txt`;do zypper -n install $i;done 

Install G++ compiler:
   zypper install gcc-c++ 

Dump MeeGo 1.2 Core ABI

Dump the MeeGo 1.2 ABI:
   abi-compliance-checker -dump-system "MeeGo-1.2-Core" -sysroot / 

The system ABI dump will be generated to:
   sys_dumps/MeeGo-1.2-Core/x86/ 

Setup MeeGo 1.2 Harmattan

Follow this tutorial to install MeeGo 1.2 Harmattan SDK.

Setup scratchbox for MeeGo 1.2 Harmattan:
   sudo /home/meego/1.2-harmattan/scratchbox/sbin/sbox_ctl start 

Login to the MeeGo 1.2 Harmattan:
   /home/meego/1.2-harmattan/scratchbox/login 

Select the X86 target:
   sb-conf select HARMATTAN_X86 

Install all devel packages:
   apt-get update 

   apt-cache search '\-dev'|awk '{print $1;}'>install.txt 

   for i in `cat install.txt`;do apt-get --force-yes -y install $i;done 

Dump MeeGo 1.2 Harmattan ABI

Dump the MeeGo 1.2 Harmattan ABI:
   abi-compliance-checker -dump-system "MeeGo-1.2-Harmattan" -sysroot / 

The system ABI dump will be generated to:
   sys_dumps/MeeGo-1.2-Harmattan/x86/ 

Exit and shutdown the scratchbox for MeeGo 1.2 Harmattan:
   exit 

   sudo /home/meego/1.2-harmattan/scratchbox/sbin/sbox_ctl stop 

Compare ABI Dumps

Check MeeGo 1.2 Harmattan and Intel's MeeGo 1.2 for compatibility:
   abi-compliance-checker -cmp-systems -d1 sys_dumps/MeeGo-1.2-Core/x86/ -d2 sys_dumps/MeeGo-1.2-Harmattan/x86/ 

The compatibility report will be generated to:
   sys_compat_reports/MeeGo-1.2-Core_to_MeeGo-1.2-Harmattan/x86/abi_compat_report.html 

Compatibility of S60 5th Edition and Symbian^3

Setup S60 5th Edition SDK

Follow this page to install S60 5th Edition SDK.

Dump S60 5th Edition ABI

Create XML-descriptor for S60 5th Edition (S60-5th.xml):

   <name>
       S60 5th Edition
   </name>
   
   <headers>
       c:\Nokia\devices\S60_5th_Edition_SDK_v1.0\epoc32\include
   </headers>
   
   <libs>
       c:\Nokia\devices\S60_5th_Edition_SDK_v1.0\epoc32\release\armv5\lib\
   </libs>
   
   <tools>
       c:\Program Files\CSL Arm Toolchain\bin\
   </tools>
   
   <cross_prefix>
       arm-none-symbianelf
   </cross_prefix>

Dump the S60 5th Edition ABI:
   abi-compliance-checker -dump-system S60-5th.xml  

The system ABI dump will be generated to:
   sys_dumps/S60 5th Edition/arm/ 

Setup Symbian^3 SDK

Follow this page to install Symbian^3 SDK.

Dump Symbian^3 ABI

Create XML-descriptor for Symbian^3 (Symbian^3.xml):

   <name>
       Symbian^3
   </name>
   
   <headers>
       c:\Nokia\devices\Nokia_Symbian3_SDK_v1.0\epoc32\include
   </headers>
   
   <libs>
       c:\Nokia\devices\Nokia_Symbian3_SDK_v1.0\epoc32\release\armv5\lib\
   </libs>
   
   <tools>
       c:\Program Files\CodeSourcery\Sourcery G++ Lite\bin\
   </tools>
   
   <cross_prefix>
       arm-none-symbianelf
   </cross_prefix>

Dump the Symbian^3 ABI:
   abi-compliance-checker -dump-system Symbian^3.xml  

The system ABI dump will be generated to:
   sys_dumps/Symbian^3/arm/ 

Compare ABI Dumps

Check S60 5th Edition and Symbian^3 for compatibility:
   abi-compliance-checker -cmp-systems -d1 "sys_dumps/S60 5th Edition/arm/" -d2 "sys_dumps/Symbian^3/arm/" 

The compatibility report will be generated to:
   sys_compat_reports/S60 5th Edition_to_Symbian^3/arm/abi_compat_report.html 

abi-compliance-checker-1.99.9/doc/SysCheck/Usage.html000066400000000000000000000256241227016120300223060ustar00rootroot00000000000000 Operating Systems Compatibility

Operating Systems Compatibility

This tutorial describes how to test operating systems for binary compatibility using the ABI Compliance Checker tool. The tool is able to find all C/C++ libraries and appropriate header files in system directories, create dump of system ABI (API + compiler ABI) including ABIs of all found libraries and then compare dumps created on different operating systems to produce the HTML report containing detailed comparison results.

Contents

Setting Up Environment

The first step is to setup development environment on target operating systems:

  • Install G++, Perl, Binutils, Ctags and File utility
  • Install all "devel" packages or SDK.

Apt-based OS (Ubuntu, Debian, Maemo)

   apt-get update 

   apt-cache search "\-dev"|awk '{print $1;}'>install.txt 

   for i in `cat install.txt`;do sudo apt-get --force-yes -y install $i;done 

   sudo apt-get install gcc perl binutils file ctags 

Zypper-based OS (Fedora, openSUSE, MeeGo)

   zypper search -u dev|awk '{print $2;}'|grep "dev">install.txt 

   for i in `cat install.txt`;do sudo zypper -n install $i;done 

   sudo zypper install gcc-c++ perl binutils file ctags 

Urpmi-based OS (Mandriva, ROSA, Mageia)

   urpmq|grep "\-devel">install.txt 

   for i in `cat install.txt`;do sudo urpmi --auto --force $i;done 

   sudo urpmi install gcc-c++ perl binutils file ctags 

Apk-based OS (Alpine Linux)

   apk update 

   apk search|grep "\-dev\-"|sed s/-dev-.*$/-dev/>install.txt 

   for i in `cat install.txt`;do sudo apk add $i;done 

   sudo apk add perl 

Other Systems (Symbian, Windows)

Download and install the SDK.

Dumping System ABI

The next step is to create an XML-descriptor of target OS.

Then enter to the target operating system and dump the system ABI using the following command:
   abi-compliance-checker -dump-system <descriptor.xml> 

If you want to analyze libraries from /usr/include and /usr/lib, then you may use the following short command instead:
   abi-compliance-checker -dump-system <name> -sysroot / 

The system ABI dump will be generated to:
   sys_dumps/<name>/<arch>/ 

Repeat this step for other operating system or other version of the same system if you want to check backward compatibility.

Compare ABI Dumps

The last step is to compare ABI dumps of two operating systems:
   abi-compliance-checker -cmp-systems -d1 sys_dumps/<name1>/<arch> -d2 sys_dumps/<name2>/<arch> 

The compatibility report will be generated to:
   sys_compat_reports/<name1>_to_<name2>/<arch>/abi_compat_report.html 

Examples

See examples for Maemo, MeeGo and Symbian operating systems on this page.

abi-compliance-checker-1.99.9/modules/000077500000000000000000000000001227016120300175325ustar00rootroot00000000000000abi-compliance-checker-1.99.9/modules/Internals/000077500000000000000000000000001227016120300214715ustar00rootroot00000000000000abi-compliance-checker-1.99.9/modules/Internals/CallConv.pm000066400000000000000000001137401227016120300235360ustar00rootroot00000000000000########################################################################### # Module for ACC tool to create a model of calling conventions # # Copyright (C) 2009-2010 The Linux Foundation # Copyright (C) 2009-2011 Institute for System Programming, RAS # Copyright (C) 2011-2012 Nokia Corporation and/or its subsidiary(-ies) # Copyright (C) 2011-2013 ROSA Laboratory # # Written by Andrey Ponomarenko # # PLATFORMS # ========= # Linux, FreeBSD and Mac OS X # x86 - System V ABI Intel386 Architecture Processor Supplement # x86_64 - System V ABI AMD64 Architecture Processor Supplement # # MS Windows # x86 - MSDN Argument Passing and Naming Conventions # x86_64 - MSDN x64 Software Conventions # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License or the GNU Lesser # General Public License as published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # and the GNU Lesser General Public License along with this program. # If not, see . ########################################################################### use strict; my $BYTE = 8; my %UsedReg = (); my %UsedStack = (); my %IntAlgn = ( "x86"=>{ "double"=>4, "long double"=>4 } ); sub classifyType($$$$$) { my ($Tid, $TInfo, $Arch, $System, $Word) = @_; my %Type = get_PureType($Tid, $TInfo); my %Classes = (); if($Type{"Name"} eq "void") { $Classes{0}{"Class"} = "VOID"; return %Classes; } if($System=~/\A(unix|linux|macos|freebsd)\Z/) { # GCC if($Arch eq "x86") { if(isFloat($Type{"Name"})) { $Classes{0}{"Class"} = "FLOAT"; } elsif($Type{"Type"}=~/Intrinsic|Enum|Pointer|Ptr/) { $Classes{0}{"Class"} = "INTEGRAL"; } else { # Struct, Class, Union $Classes{0}{"Class"} = "MEMORY"; } } elsif($Arch eq "x86_64") { if($Type{"Type"}=~/Enum|Pointer|Ptr/ or isScalar($Type{"Name"}) or $Type{"Name"}=~/\A(_Bool|bool)\Z/) { $Classes{0}{"Class"} = "INTEGER"; } elsif($Type{"Name"} eq "__int128" or $Type{"Name"} eq "unsigned __int128") { $Classes{0}{"Class"} = "INTEGER"; $Classes{1}{"Class"} = "INTEGER"; } elsif($Type{"Name"}=~/\A(float|double|_Decimal32|_Decimal64|__m64)\Z/) { $Classes{0}{"Class"} = "SSE"; } elsif($Type{"Name"}=~/\A(__float128|_Decimal128|__m128)\Z/) { $Classes{0}{"Class"} = "SSE"; $Classes{8}{"Class"} = "SSEUP"; } elsif($Type{"Name"} eq "__m256") { $Classes{0}{"Class"} = "SSE"; $Classes{24}{"Class"} = "SSEUP"; } elsif($Type{"Name"} eq "long double") { $Classes{0}{"Class"} = "X87"; $Classes{8}{"Class"} = "X87UP"; } elsif($Type{"Name"}=~/\Acomplex (float|double)\Z/) { $Classes{0}{"Class"} = "MEMORY"; } elsif($Type{"Name"} eq "complex long double") { $Classes{0}{"Class"} = "COMPLEX_X87"; } elsif($Type{"Type"}=~/Struct|Class|Union|Array/) { if($Type{"Size"}>4*8) { $Classes{0}{"Class"} = "MEMORY"; } else { %Classes = classifyAggregate($Tid, $TInfo, $Arch, $System, $Word); } } else { $Classes{0}{"Class"} = "MEMORY"; } } elsif($Arch eq "arm") { } } elsif($System eq "windows") { # MS C++ Compiler if($Arch eq "x86") { if(isFloat($Type{"Name"})) { $Classes{0}{"Class"} = "FLOAT"; } elsif($Type{"Type"}=~/Intrinsic|Enum|Pointer|Ptr/) { $Classes{0}{"Class"} = "INTEGRAL"; } elsif($Type{"Type"}=~/\A(Struct|Union)\Z/ and $Type{"Size"}<=8) { $Classes{0}{"Class"} = "POD"; } else { # Struct, Class, Union $Classes{0}{"Class"} = "MEMORY"; } } elsif($Arch eq "x86_64") { if($Type{"Name"}=~/\A(float|double|long double)\Z/) { $Classes{0}{"Class"} = "FLOAT"; } elsif($Type{"Name"}=~/\A__m128(|i|d)\Z/) { $Classes{0}{"Class"} = "M128"; } elsif(isScalar($Type{"Name"}) or $Type{"Type"}=~/Enum|Pointer|Ptr/ or $Type{"Name"}=~/\A(_Bool|bool)\Z/ or ($Type{"Type"}=~/\A(Struct|Union)\Z/ and $Type{"Size"}<=8) or $Type{"Name"} eq "__m64") { $Classes{0}{"Class"} = "INTEGRAL"; } else { $Classes{0}{"Class"} = "MEMORY"; } } } return %Classes; } sub classifyAggregate($$$$$) { my ($Tid, $TInfo, $Arch, $System, $Word) = @_; my %Type = get_PureType($Tid, $TInfo); my %Group = (); my $GroupID = 0; my %Classes = (); my %Offsets = (); if($Type{"Type"} eq "Array") { my %Base = get_OneStep_BaseType($Tid, $TInfo); my %BaseType = get_PureType($Base{"Tid"}, $TInfo); my $Pos = 0; my $Max = 0; if(my $BSize = $BaseType{"Size"}) { $Max = ($Type{"Size"}/$BSize) - 1; } foreach my $Pos (0 .. $Max) { # if($TInfo->{1}{"Name"} eq "void") # { # DWARF ABI Dump # $Type{"Memb"}{$Pos}{"offset"} = $Type{"Size"}/($Max+1); # } $Type{"Memb"}{$Pos}{"algn"} = getAlignment_Model($BaseType{"Tid"}, $TInfo, $Arch); $Type{"Memb"}{$Pos}{"type"} = $BaseType{"Tid"}; $Type{"Memb"}{$Pos}{"name"} = "[$Pos]"; } } if($Type{"Type"} eq "Union") { foreach my $Pos (keys(%{$Type{"Memb"}})) { $Offsets{$Pos} = $Pos; $Group{0}{$Pos} = 1; } } else { # Struct, Class foreach my $Pos (keys(%{$Type{"Memb"}})) { my $Offset = getOffset($Pos, \%Type, $TInfo, $Arch, $Word)/$BYTE; $Offsets{$Pos} = $Offset; my $GroupOffset = int($Offset/$Word)*$Word; $Group{$GroupOffset}{$Pos} = 1; } } foreach my $GroupOffset (sort {int($a)<=>int($b)} (keys(%Group))) { my %GroupClasses = (); foreach my $Pos (sort {int($a)<=>int($b)} (keys(%{$Group{$GroupOffset}}))) { # split the field into the classes my $MTid = $Type{"Memb"}{$Pos}{"type"}; my $MName = $Type{"Memb"}{$Pos}{"name"}; my %SubClasses = classifyType($MTid, $TInfo, $Arch, $System, $Word); foreach my $Offset (sort {int($a)<=>int($b)} keys(%SubClasses)) { if(defined $SubClasses{$Offset}{"Elems"}) { foreach (keys(%{$SubClasses{$Offset}{"Elems"}})) { $SubClasses{$Offset}{"Elems"}{$_} = joinFields($MName, $SubClasses{$Offset}{"Elems"}{$_}); } } else { $SubClasses{$Offset}{"Elems"}{0} = $MName; } } # add to the group foreach my $Offset (sort {int($a)<=>int($b)} keys(%SubClasses)) { $GroupClasses{$Offsets{$Pos}+$Offset} = $SubClasses{$Offset}; } } # merge classes in the group my %MergeGroup = (); foreach my $Offset (sort {int($a)<=>int($b)} keys(%GroupClasses)) { $MergeGroup{int($Offset/$Word)}{$Offset} = $GroupClasses{$Offset}; } foreach my $Offset (sort {int($a)<=>int($b)} keys(%MergeGroup)) { while(postMerger($Arch, $System, $MergeGroup{$Offset})) { }; } %GroupClasses = (); foreach my $M_Offset (sort {int($a)<=>int($b)} keys(%MergeGroup)) { foreach my $Offset (sort {int($a)<=>int($b)} keys(%{$MergeGroup{$M_Offset}})) { $GroupClasses{$Offset} = $MergeGroup{$M_Offset}{$Offset}; } } # add to the result list of classes foreach my $Offset (sort {int($a)<=>int($b)} keys(%GroupClasses)) { if($Type{"Type"} eq "Union") { foreach my $P (keys(%{$GroupClasses{$Offset}{"Elems"}})) { if($P!=0) { delete($GroupClasses{$Offset}{"Elems"}{$P}); } } } $Classes{$Offset} = $GroupClasses{$Offset}; } } return %Classes; } sub postMerger($$$) { my ($Arch, $System, $PreClasses) = @_; my @Offsets = sort {int($a)<=>int($b)} keys(%{$PreClasses}); if($#Offsets==0) { return 0; } my %PostClasses = (); my $Num = 0; my $Merged = 0; while($Num<=$#Offsets-1) { my $Offset1 = $Offsets[$Num]; my $Offset2 = $Offsets[$Num+1]; my $Class1 = $PreClasses->{$Offset1}{"Class"}; my $Class2 = $PreClasses->{$Offset2}{"Class"}; my $ResClass = ""; if($System=~/\A(unix|linux|macos|freebsd)\Z/) { # GCC if($Arch eq "x86_64") { if($Class1 eq $Class2) { $ResClass = $Class1; } elsif($Class1 eq "MEMORY" or $Class2 eq "MEMORY") { $ResClass = "MEMORY"; } elsif($Class1 eq "INTEGER" or $Class2 eq "INTEGER") { $ResClass = "INTEGER"; } elsif($Class1=~/X87/ or $Class2=~/X87/) { $ResClass = "MEMORY"; } else { $ResClass = "SSE"; } } } if($ResClass) { # combine $PostClasses{$Offset1}{"Class"} = $ResClass; foreach (keys(%{$PreClasses->{$Offset1}{"Elems"}})) { $PostClasses{$Offset1}{"Elems"}{$Offset1+$_} = $PreClasses->{$Offset1}{"Elems"}{$_}; } foreach (keys(%{$PreClasses->{$Offset2}{"Elems"}})) { $PostClasses{$Offset1}{"Elems"}{$Offset2+$_} = $PreClasses->{$Offset2}{"Elems"}{$_}; } $Merged = 1; } else { # save unchanged $PostClasses{$Offset1} = $PreClasses->{$Offset1}; $PostClasses{$Offset2} = $PreClasses->{$Offset2}; } $Num += 2; } if($Num==$#Offsets) { $PostClasses{$Offsets[$Num]} = $PreClasses->{$Offsets[$Num]}; } %{$PreClasses} = %PostClasses; return $Merged; } sub callingConvention_R_Model($$$$$$) { return callingConvention_R_I_Model(@_, 1); } sub joinFields($$) { my ($F1, $F2) = @_; if(substr($F2, 0, 1) eq "[") { # array elements return $F1.$F2; } else { # fields return $F1.".".$F2; } } sub callingConvention_R_I_Model($$$$$$) { my ($SInfo, $TInfo, $Arch, $System, $Word, $Target) = @_; my %Conv = (); my $RTid = $SInfo->{"Return"}; my %Type = get_PureType($RTid, $TInfo); if($Target) { %UsedReg = (); } my %UsedReg_Copy = %UsedReg; my %Classes = classifyType($RTid, $TInfo, $Arch, $System, $Word); foreach my $Offset (sort {int($a)<=>int($b)} keys(%Classes)) { my $Elems = undef; if(defined $Classes{$Offset}{"Elems"}) { foreach (keys(%{$Classes{$Offset}{"Elems"}})) { $Classes{$Offset}{"Elems"}{$_} = joinFields(".result", $Classes{$Offset}{"Elems"}{$_}); } $Elems = $Classes{$Offset}{"Elems"}; } else { $Elems = { 0 => ".result" }; } my $CName = $Classes{$Offset}{"Class"}; if($CName eq "VOID") { next; } if($System=~/\A(unix|linux|macos|freebsd)\Z/) { # GCC if($Arch eq "x86") { if($CName eq "FLOAT") { # x87 register useRegister("st0", "f", $Elems, $SInfo); } elsif($CName eq "INTEGRAL") { useRegister("eax", "f", $Elems, $SInfo); } elsif($CName eq "MEMORY") { pushStack_R($SInfo, $Word); } } elsif($Arch eq "x86_64") { my @INT = ("rax", "rdx"); my @SSE = ("xmm0", "xmm1"); if($CName eq "INTEGER") { if(my $R = getLastAvailable($SInfo, "f", @INT)) { useRegister($R, "f", $Elems, $SInfo); } else { # revert registers # pass as MEMORY %UsedReg = %UsedReg_Copy; useHidden($SInfo, $Arch, $System, $Word); $Conv{"Hidden"} = 1; last; } } elsif($CName eq "SSE") { if(my $R = getLastAvailable($SInfo, "8l", @SSE)) { useRegister($R, "8l", $Elems, $SInfo); } else { %UsedReg = %UsedReg_Copy; useHidden($SInfo, $Arch, $System, $Word); $Conv{"Hidden"} = 1; last; } } elsif($CName eq "SSEUP") { if(my $R = getLastUsed($SInfo, "xmm0", "xmm1")) { useRegister($R, "8h", $Elems, $SInfo); } else { %UsedReg = %UsedReg_Copy; useHidden($SInfo, $Arch, $System, $Word); $Conv{"Hidden"} = 1; last; } } elsif($CName eq "X87") { useRegister("st0", "8l", $Elems, $SInfo); } elsif($CName eq "X87UP") { useRegister("st0", "8h", $Elems, $SInfo); } elsif($CName eq "COMPLEX_X87") { useRegister("st0", "f", $Elems, $SInfo); useRegister("st1", "f", $Elems, $SInfo); } elsif($CName eq "MEMORY") { useHidden($SInfo, $Arch, $System, $Word); $Conv{"Hidden"} = 1; last; } } elsif($Arch eq "arm") { # TODO } } elsif($System eq "windows") { # MS C++ Compiler if($Arch eq "x86") { if($CName eq "FLOAT") { useRegister("fp0", "f", $Elems, $SInfo); } elsif($CName eq "INTEGRAL") { useRegister("eax", "f", $Elems, $SInfo); } elsif($CName eq "POD") { useRegister("eax", "f", $Elems, $SInfo); useRegister("edx", "f", $Elems, $SInfo); } elsif($CName eq "MEMORY" or $CName eq "M128") { useHidden($SInfo, $Arch, $System, $Word); $Conv{"Hidden"} = 1; } } elsif($Arch eq "x86_64") { if($CName eq "FLOAT" or $CName eq "M128") { useRegister("xmm0", "f", $Elems, $SInfo); } elsif($CName eq "INTEGRAL") { useRegister("eax", "f", $Elems, $SInfo); } elsif($CName eq "MEMORY") { useHidden($SInfo, $Arch, $System, $Word); $Conv{"Hidden"} = 1; } } } } if(my %Regs = usedBy(".result", $SInfo)) { $Conv{"Method"} = "reg"; $Conv{"Registers"} = join(", ", sort(keys(%Regs))); } elsif(my %Regs = usedBy(".result_ptr", $SInfo)) { $Conv{"Method"} = "reg"; $Conv{"Registers"} = join(", ", sort(keys(%Regs))); } if(not $Conv{"Method"}) { # unknown if($Type{"Name"} ne "void") { $Conv{"Method"} = "stack"; $Conv{"Hidden"} = 1; } } return %Conv; } sub usedBy($$) { my ($Name, $SInfo) = @_; my %Regs = (); foreach my $Reg (sort keys(%{$UsedReg{$SInfo}})) { foreach my $Size (sort keys(%{$UsedReg{$SInfo}{$Reg}})) { foreach my $Offset (sort keys(%{$UsedReg{$SInfo}{$Reg}{$Size}})) { if($UsedReg{$SInfo}{$Reg}{$Size}{$Offset}=~/\A\Q$Name\E(\.|\Z)/) { $Regs{$Reg} = 1; } } } } return %Regs; } sub useHidden($$$$) { my ($SInfo, $Arch, $System, $Word) = @_; if($System=~/\A(unix|linux|macos|freebsd)\Z/) { # GCC if($Arch eq "x86") { pushStack_R($SInfo, $Word); } elsif($Arch eq "x86_64") { my $Elems = { 0 => ".result_ptr" }; useRegister("rdi", "f", $Elems, $SInfo); } } elsif($System eq "windows") { # MS C++ Compiler if($Arch eq "x86") { pushStack_R($SInfo, $Word); } elsif($Arch eq "x86_64") { my $Elems = { 0 => ".result_ptr" }; useRegister("rcx", "f", $Elems, $SInfo); } } } sub pushStack_P($$$$) { my ($SInfo, $Pos, $TInfo, $StackAlgn) = @_; my $PTid = $SInfo->{"Param"}{$Pos}{"type"}; my $PName = $SInfo->{"Param"}{$Pos}{"name"}; if(my $Offset = $SInfo->{"Param"}{$Pos}{"offset"}) { # DWARF ABI Dump return pushStack_Offset($SInfo, $Offset, $TInfo->{$PTid}{"Size"}, { 0 => $PName }); } else { my $Alignment = $SInfo->{"Param"}{$Pos}{"algn"}; if($Alignment<$StackAlgn) { $Alignment = $StackAlgn; } return pushStack($SInfo, $Alignment, $TInfo->{$PTid}{"Size"}, { 0 => $PName }); } } sub pushStack_R($$) { my ($SInfo, $Word) = @_; return pushStack($SInfo, $Word, $Word, { 0 => ".result_ptr" }); } sub pushStack_C($$$) { my ($SInfo, $Class, $TInfo) = @_; return pushStack($SInfo, $Class->{"Algn"}, $Class->{"Size"}, $Class->{"Elems"}); } sub pushStack($$$$) { my ($SInfo, $Algn, $Size, $Elem) = @_; my $Offset = 0; if(my @Offsets = sort {int($a)<=>int($b)} keys(%{$UsedStack{$SInfo}})) { $Offset = $Offsets[$#Offsets]; $Offset += $UsedStack{$SInfo}{$Offset}{"Size"}; $Offset += getPadding($Offset, $Algn); } return pushStack_Offset($SInfo, $Offset, $Size, $Elem); } sub pushStack_Offset($$$$) { my ($SInfo, $Offset, $Size, $Elem) = @_; my %Info = ( "Size" => $Size, "Elem" => $Elem ); $UsedStack{$SInfo}{$Offset} = \%Info; return $Offset; } sub useRegister($$$$) { my ($R, $Offset, $Elems, $SInfo) = @_; if(defined $UsedReg{$SInfo}{$R}) { if(defined $UsedReg{$SInfo}{$R}{$Offset}) { # busy return 0; } } $UsedReg{$SInfo}{$R}{$Offset}=$Elems; return $R; } sub getLastAvailable(@) { my $SInfo = shift(@_); my $Offset = shift(@_); my $Pos = 0; foreach (@_) { if(not defined $UsedReg{$SInfo}{$_}) { return $_; } elsif(not defined $UsedReg{$SInfo}{$_}{$Offset}) { return $_; } } return undef; } sub getLastUsed(@) { my $SInfo = shift(@_); my $Pos = 0; foreach (@_) { if(not defined $UsedReg{$SInfo}{$_}) { if($Pos>0) { return @_[$Pos-1]; } else { return @_[0]; } } $Pos+=1; } return undef; } sub callingConvention_P_Model($$$$$$) { return callingConvention_P_I_Model(@_, 1); } sub callingConvention_P_I_Model($$$$$$$) { # calling conventions for different compilers and operating systems my ($SInfo, $Pos, $TInfo, $Arch, $System, $Word, $Target) = @_; my %Conv = (); my $ParamTypeId = $SInfo->{"Param"}{$Pos}{"type"}; my $PName = $SInfo->{"Param"}{$Pos}{"name"}; my %Type = get_PureType($ParamTypeId, $TInfo); if($Target) { %UsedReg = (); # distribute return value if(my $RTid = $SInfo->{"Return"}) { callingConvention_R_I_Model($SInfo, $TInfo, $Arch, $System, $Word, 0); } # distribute other parameters if($Pos>0) { my %PConv = (); my $PPos = 0; while($PConv{"Next"} ne $Pos) { %PConv = callingConvention_P_I_Model($SInfo, $PPos++, $TInfo, $Arch, $System, $Word, 0); if(not $PConv{"Next"}) { last; } } } } my %UsedReg_Copy = %UsedReg; my %Classes = classifyType($ParamTypeId, $TInfo, $Arch, $System, $Word); my $Error = 0; foreach my $Offset (sort {int($a)<=>int($b)} keys(%Classes)) { my $Elems = undef; if(defined $Classes{$Offset}{"Elems"}) { foreach (keys(%{$Classes{$Offset}{"Elems"}})) { $Classes{$Offset}{"Elems"}{$_} = joinFields($PName, $Classes{$Offset}{"Elems"}{$_}); } $Elems = $Classes{$Offset}{"Elems"}; } else { $Elems = { 0 => $PName }; } my $CName = $Classes{$Offset}{"Class"}; if($CName eq "VOID") { next; } if($System=~/\A(unix|linux|macos|freebsd)\Z/) { # GCC if($Arch eq "x86") { pushStack_P($SInfo, $Pos, $TInfo, $Word); last; } elsif($Arch eq "x86_64") { my @INT = ("rdi", "rsi", "rdx", "rcx", "r8", "r9"); my @SSE = ("xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"); if($CName eq "INTEGER") { if(my $R = getLastAvailable($SInfo, "f", @INT)) { useRegister($R, "f", $Elems, $SInfo); } else { # revert registers and # push the argument on the stack %UsedReg = %UsedReg_Copy; pushStack_P($SInfo, $Pos, $TInfo, $Word); last; } } elsif($CName eq "SSE") { if(my $R = getLastAvailable($SInfo, "8l", @SSE)) { useRegister($R, "8l", $Elems, $SInfo); } else { %UsedReg = %UsedReg_Copy; pushStack_P($SInfo, $Pos, $TInfo, $Word); last; } } elsif($CName eq "SSEUP") { if(my $R = getLastUsed($SInfo, @SSE)) { useRegister($R, "8h", $Elems, $SInfo); } else { %UsedReg = %UsedReg_Copy; pushStack_P($SInfo, $Pos, $TInfo, $Word); last; } } elsif($CName=~/X87|MEMORY/) { # MEMORY, X87, X87UP, COMPLEX_X87 pushStack_P($SInfo, $Pos, $TInfo, $Word); last; } else { pushStack_P($SInfo, $Pos, $TInfo, $Word); last; } } elsif($Arch eq "arm") { # Procedure Call Standard for the ARM Architecture # TODO pushStack_P($SInfo, $Pos, $TInfo, $Word); last; } else { # TODO pushStack_P($SInfo, $Pos, $TInfo, $Word); last; } } elsif($System eq "windows") { # MS C++ Compiler if($Arch eq "x86") { pushStack_P($SInfo, $Pos, $TInfo, $Word); last; } elsif($Arch eq "x86_64") { if($Pos<=3) { if($CName eq "FLOAT") { useRegister("xmm".$Pos, "8l", $Elems, $SInfo); } elsif($CName eq "INTEGRAL") { if($Pos==0) { useRegister("rcx", "f", $Elems, $SInfo); } elsif($Pos==1) { useRegister("rdx", "f", $Elems, $SInfo); } elsif($Pos==2) { useRegister("r8", "f", $Elems, $SInfo); } elsif($Pos==3) { useRegister("r9", "f", $Elems, $SInfo); } else { pushStack_P($SInfo, $Pos, $TInfo, $Word); last; } } else { pushStack_P($SInfo, $Pos, $TInfo, $Word); last; } } else { pushStack_P($SInfo, $Pos, $TInfo, $Word); last; } } } else { # TODO pushStack_P($SInfo, $Pos, $TInfo, $Word); last; } } if(my %Regs = usedBy($PName, $SInfo)) { $Conv{"Method"} = "reg"; $Conv{"Registers"} = join(", ", sort(keys(%Regs))); } else { if($Type{"Name"} ne "void") { $Conv{"Method"} = "stack"; } } if(defined $SInfo->{"Param"}{$Pos+1}) { # TODO $Conv{"Next"} = $Pos+1; } return %Conv; } sub getAlignment_Model($$$) { my ($Tid, $TInfo, $Arch) = @_; if(not $Tid) { # incomplete ABI dump return 0; } if(defined $TInfo->{$Tid}{"Algn"}) { return $TInfo->{$Tid}{"Algn"}; } else { if($TInfo->{$Tid}{"Type"}=~/Struct|Class|Union|MethodPtr/) { if(defined $TInfo->{$Tid}{"Memb"}) { my $Max = 0; foreach my $Pos (keys(%{$TInfo->{$Tid}{"Memb"}})) { my $Algn = $TInfo->{$Tid}{"Memb"}{$Pos}{"algn"}; if(not $Algn) { $Algn = getAlignment_Model($TInfo->{$Tid}{"Memb"}{$Pos}{"type"}, $TInfo, $Arch); } if($Algn>$Max) { $Max = $Algn; } } return $Max; } return 0; } elsif($TInfo->{$Tid}{"Type"} eq "Array") { my %Base = get_OneStep_BaseType($Tid, $TInfo); if($Base{"Tid"} eq $Tid) { # emergency exit return 0; } return getAlignment_Model($Base{"Tid"}, $TInfo, $Arch); } elsif($TInfo->{$Tid}{"Type"}=~/Intrinsic|Enum|Pointer|FuncPtr/) { # model return getInt_Algn($Tid, $TInfo, $Arch); } else { my %PureType = get_PureType($Tid, $TInfo); if($PureType{"Tid"} eq $Tid) { # emergency exit return 0; } return getAlignment_Model($PureType{"Tid"}, $TInfo, $Arch); } } } sub getInt_Algn($$$) { my ($Tid, $TInfo, $Arch) = @_; my $Name = $TInfo->{$Tid}{"Name"}; if(my $Algn = $IntAlgn{$Arch}{$Name}) { return $Algn; } else { my $Size = $TInfo->{$Tid}{"Size"}; if($Arch eq "x86_64") { # x86_64: sizeof==alignment return $Size; } elsif($Arch eq "arm") { if($Size>8) { # 128-bit vector (16) return 8; } return $Size; } elsif($Arch eq "x86") { if($Size>4) { # "double" (8) and "long double" (12) return 4; } return $Size; } return $Size; } } sub getAlignment($$$$$) { my ($Pos, $TypePtr, $TInfo, $Arch, $Word) = @_; my $Tid = $TypePtr->{"Memb"}{$Pos}{"type"}; my %Type = get_PureType($Tid, $TInfo); my $Computed = $TypePtr->{"Memb"}{$Pos}{"algn"}; my $Alignment = 0; if(my $BSize = $TypePtr->{"Memb"}{$Pos}{"bitfield"}) { # bitfields if($Computed) { # real in bits $Alignment = $Computed; } else { # model if($BSize eq $Type{"Size"}*$BYTE) { $Alignment = $BSize; } else { $Alignment = 1; } } return ($Alignment, $BSize); } else { # other fields if($Computed) { # real in bytes $Alignment = $Computed*$BYTE; } else { # model $Alignment = getAlignment_Model($Tid, $TInfo, $Arch)*$BYTE; } return ($Alignment, $Type{"Size"}*$BYTE); } } sub getOffset($$$$$) { # offset of the field including padding my ($FieldPos, $TypePtr, $TInfo, $Arch, $Word) = @_; if($TypePtr->{"Type"} eq "Union") { return 0; } # if((my $Off = $TypePtr->{"Memb"}{$FieldPos}{"offset"}) ne "") # { # DWARF ABI Dump (generated by the ABI Dumper tool) # return $Off*$BYTE; # } my $Offset = 0; my $Buffer=0; foreach my $Pos (0 .. keys(%{$TypePtr->{"Memb"}})-1) { my ($Alignment, $MSize) = getAlignment($Pos, $TypePtr, $TInfo, $Arch, $Word); if(not $Alignment) { # support for old ABI dumps if($MSize=~/\A(8|16|32|64)\Z/) { if($Buffer+$MSize<$Word*$BYTE) { $Alignment = 1; $Buffer += $MSize; } else { $Alignment = $MSize; $Buffer = 0; } } else { $Alignment = 1; $Buffer += $MSize; } } # padding $Offset += getPadding($Offset, $Alignment); if($Pos==$FieldPos) { # after the padding # before the field return $Offset; } $Offset += $MSize; } return $FieldPos; # if something is going wrong } sub getPadding($$) { my ($Offset, $Alignment) = @_; my $Padding = 0; if($Offset % $Alignment!=0) { # not aligned, add padding $Padding = $Alignment - $Offset % $Alignment; } return $Padding; } sub isMemPadded($$$$$$) { # check if the target field can be added/removed/changed # without shifting other fields because of padding bits my ($FieldPos, $Size, $TypePtr, $Skip, $TInfo, $Arch, $Word) = @_; return 0 if($FieldPos==0); delete($TypePtr->{"Memb"}{""}); my $Offset = 0; my (%Alignment, %MSize) = (); my $MaxAlgn = 0; my $End = keys(%{$TypePtr->{"Memb"}})-1; my $NextField = $FieldPos+1; foreach my $Pos (0 .. $End) { if($Skip and $Skip->{$Pos}) { # skip removed/added fields if($Pos > $FieldPos) { # after the target $NextField += 1; next; } } ($Alignment{$Pos}, $MSize{$Pos}) = getAlignment($Pos, $TypePtr, $TInfo, $Arch, $Word); if(not $Alignment{$Pos}) { # emergency exit return 0; } if($Alignment{$Pos}>$MaxAlgn) { $MaxAlgn = $Alignment{$Pos}; } if($Pos==$FieldPos) { if($Size==-1) { # added/removed fields if($Pos!=$End) { # skip target field and see # if enough padding will be # created on the next step # to include this field next; } } } # padding my $Padding = 0; if($Offset % $Alignment{$Pos}!=0) { # not aligned, add padding $Padding = $Alignment{$Pos} - $Offset % $Alignment{$Pos}; } if($Pos==$NextField) { # try to place target field in the padding if($Size==-1) { # added/removed fields my $TPadding = 0; if($Offset % $Alignment{$FieldPos}!=0) {# padding of the target field $TPadding = $Alignment{$FieldPos} - $Offset % $Alignment{$FieldPos}; } if($TPadding+$MSize{$FieldPos}<=$Padding) { # enough padding to place target field return 1; } else { return 0; } } else { # changed fields my $Delta = $Size-$MSize{$FieldPos}; if($Delta>=0) { # increased if($Size-$MSize{$FieldPos}<=$Padding) { # enough padding to change target field return 1; } else { return 0; } } else { # decreased $Delta = abs($Delta); if($Delta+$Padding>=$MSize{$Pos}) { # try to place the next field if(($Offset-$Delta) % $Alignment{$Pos} != 0) { # padding of the next field in new place my $NPadding = $Alignment{$Pos} - ($Offset-$Delta) % $Alignment{$Pos}; if($NPadding+$MSize{$Pos}<=$Delta+$Padding) { # enough delta+padding to store next field return 0; } } else { return 0; } } return 1; } } } elsif($Pos==$End) { # target field is the last field if($Size==-1) { # added/removed fields if($Offset % $MaxAlgn!=0) { # tail padding my $TailPadding = $MaxAlgn - $Offset % $MaxAlgn; if($Padding+$MSize{$Pos}<=$TailPadding) { # enough tail padding to place the last field return 1; } } return 0; } else { # changed fields # scenario #1 my $Offset1 = $Offset+$Padding+$MSize{$Pos}; if($Offset1 % $MaxAlgn != 0) { # tail padding $Offset1 += $MaxAlgn - $Offset1 % $MaxAlgn; } # scenario #2 my $Offset2 = $Offset+$Padding+$Size; if($Offset2 % $MaxAlgn != 0) { # tail padding $Offset2 += $MaxAlgn - $Offset2 % $MaxAlgn; } if($Offset1!=$Offset2) { # different sizes of structure return 0; } return 1; } } $Offset += $Padding+$MSize{$Pos}; } return 0; } sub isScalar($) { return ($_[0]=~/\A(unsigned |)(char|short|int|long|long long)\Z/); } sub isFloat($) { return ($_[0]=~/\A(float|double|long double)\Z/); } sub callingConvention_R_Real($) { my $SInfo = $_[0]; my %Conv = (); my %Regs = (); my $Hidden = 0; foreach my $Elem (keys(%{$SInfo->{"Reg"}})) { my $Reg = $SInfo->{"Reg"}{$Elem}; if($Elem eq ".result_ptr") { $Hidden = 1; $Regs{$Reg} = 1; } elsif(index($Elem, ".result")==0) { $Regs{$Reg} = 1; } } if(my @R = sort keys(%Regs)) { $Conv{"Method"} = "reg"; $Conv{"Registers"} = join(", ", @R); if($Hidden) { $Conv{"Hidden"} = 1; } } else { $Conv{"Method"} = "stack"; $Conv{"Hidden"} = 1; } return %Conv; } sub callingConvention_P_Real($$) { my ($SInfo, $Pos) = @_; my %Conv = (); my %Regs = (); foreach my $Elem (keys(%{$SInfo->{"Reg"}})) { my $Reg = $SInfo->{"Reg"}{$Elem}; if($Elem=~/\A$Pos([\.\+]|\Z)/) { $Regs{$Reg} = 1; } } if(my @R = sort keys(%Regs)) { $Conv{"Method"} = "reg"; $Conv{"Registers"} = join(", ", @R); } else { $Conv{"Method"} = "stack"; } return %Conv; } return 1;abi-compliance-checker-1.99.9/modules/Internals/RegTests.pm000066400000000000000000004555631227016120300236110ustar00rootroot00000000000000########################################################################### # Module for ABI Compliance Checker with regression test suite # # Copyright (C) 2009-2010 The Linux Foundation # Copyright (C) 2009-2011 Institute for System Programming, RAS # Copyright (C) 2011-2012 Nokia Corporation and/or its subsidiary(-ies) # Copyright (C) 2011-2013 ROSA Laboratory # # Written by Andrey Ponomarenko # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License or the GNU Lesser # General Public License as published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # and the GNU Lesser General Public License along with this program. # If not, see . ########################################################################### use strict; my ($TestDump, $Debug, $Quiet, $ExtendedCheck, $LogMode, $ReportFormat, $DumpFormat, $LIB_EXT, $GCC_PATH, $Browse, $OpenReport, $SortDump, $CheckHeadersOnly, $CheckObjectsOnly); my $OSgroup = get_OSgroup(); sub testTool($$$$$$$$$$$) { ($TestDump, $Debug, $Quiet, $ExtendedCheck, $LogMode, $ReportFormat, $DumpFormat, $LIB_EXT, $GCC_PATH, $Browse, $OpenReport, $SortDump, $CheckHeadersOnly, $CheckObjectsOnly) = @_; testC(); testCpp(); } sub testCpp() { printMsg("INFO", "verifying detectable C++ library changes"); my ($HEADER1, $SOURCE1, $HEADER2, $SOURCE2) = (); my $DECL_SPEC = ($OSgroup eq "windows")?"__declspec( dllexport )":""; my $EXTERN = ($OSgroup eq "windows")?"extern ":""; # add "extern" for CL compiler # Class outside namespace $HEADER1 .= " class $DECL_SPEC OutsideNS { public: int someMethod(); int field; };"; $SOURCE1 .= " int OutsideNS::someMethod() { return 0; }"; $HEADER2 .= " class $DECL_SPEC OutsideNS { public: int someMethod(); int field; int field2; };"; $SOURCE2 .= " int OutsideNS::someMethod() { return 0; }"; # Begin namespace $HEADER1 .= "namespace TestNS {\n"; $HEADER2 .= "namespace TestNS {\n"; $SOURCE1 .= "namespace TestNS {\n"; $SOURCE2 .= "namespace TestNS {\n"; # Changed template internals $HEADER1 .= " template class $DECL_SPEC ChangedTemplate { public: T value; T*const field; T array[_P]; typedef int My; My var; }; ChangedTemplate* changedTemplate();"; $SOURCE1 .= " ChangedTemplate* changedTemplate() { return new ChangedTemplate(); }"; $HEADER2 .= " template class $DECL_SPEC ChangedTemplate { public: double value; T* field; double array[_P]; typedef int My; My var; }; ChangedTemplate* changedTemplate();"; $SOURCE2 .= " ChangedTemplate* changedTemplate() { return new ChangedTemplate(); }"; # Removed inline method $HEADER1 .= " class $DECL_SPEC RemovedInlineMethod { public: int someMethod(); inline int removedMethod() { return 0; }; int field; };"; $SOURCE1 .= " int RemovedInlineMethod::someMethod() { return removedMethod(); }"; $HEADER2 .= " class $DECL_SPEC RemovedInlineMethod { public: int someMethod(); int field; };"; $SOURCE2 .= " int RemovedInlineMethod::someMethod() { return 0; }"; # Pure_Virtual_Replacement $HEADER1 .= " class $DECL_SPEC PureVirtualReplacement { public: virtual int methodOld(int param) = 0; int otherMethod(); }; class $DECL_SPEC PureVirtualReplacement_Derived: public PureVirtualReplacement { public: int methodOld(int param); };"; $SOURCE1 .= " int PureVirtualReplacement::otherMethod() { return 0; } int PureVirtualReplacement_Derived::methodOld(int param) { return 0; }"; $HEADER2 .= " class $DECL_SPEC PureVirtualReplacement { public: virtual int methodNew(int param) = 0; int otherMethod(); }; class $DECL_SPEC PureVirtualReplacement_Derived: public PureVirtualReplacement { public: int methodNew(int param); };"; $SOURCE2 .= " int PureVirtualReplacement::otherMethod() { return 0; } int PureVirtualReplacement_Derived::methodNew(int param) { return 0; }"; # Virtual_Replacement $HEADER1 .= " class $DECL_SPEC VirtualReplacement { public: virtual int methodOld(int param); };"; $SOURCE1 .= " int VirtualReplacement::methodOld(int param) { return 0; }"; $HEADER2 .= " class $DECL_SPEC VirtualReplacement { public: virtual int methodNew(int param); };"; $SOURCE2 .= " int VirtualReplacement::methodNew(int param) { return 0; }"; # Removed_Symbol (renamed, source-compatible) $HEADER1 .= " int $DECL_SPEC renamedFunc(int param);"; $SOURCE1 .= " int renamedFunc(int param) { return 0; }"; $HEADER2 .= " int $DECL_SPEC renamedFunc_NewName(int param); #define renamedFunc renamedFunc_NewName"; $SOURCE2 .= " int renamedFunc_NewName(int param) { return 0; }"; # Removed_Symbol $HEADER1 .= " int $DECL_SPEC functionBecameInline(int param);"; $SOURCE1 .= " int functionBecameInline(int param) { return 0; }"; $HEADER2 .= " inline int functionBecameInline(int param) { return 0; }"; # Removed_Symbol (safe) $HEADER1 .= " inline int removedInlineFunction(int param) { return 0; }"; # Became Non-Opaque $HEADER1 .= " struct OpaqueStruct; int paramBecameNonOpaque(OpaqueStruct* p);"; $SOURCE1 .= " int paramBecameNonOpaque(OpaqueStruct* p) { return 0; }"; $HEADER2 .= " struct OpaqueStruct { int i; short j; OpaqueStruct(); }; int paramBecameNonOpaque(OpaqueStruct* p);"; $SOURCE2 .= " int paramBecameNonOpaque(OpaqueStruct* p) { return 0; }"; # Field_Became_Const # Typedef $HEADER1 .= " typedef int*const CONST_INT_PTR; class $DECL_SPEC FieldBecameConstTypedef { public: int* f; int*const f2; int method(CONST_INT_PTR p); };"; $SOURCE1 .= " int FieldBecameConstTypedef::method(CONST_INT_PTR p) { return 0; }"; $HEADER2 .= " typedef int*const CONST_INT_PTR; class $DECL_SPEC FieldBecameConstTypedef { public: CONST_INT_PTR f; int*const f2; int method(CONST_INT_PTR p); };"; $SOURCE2 .= " int FieldBecameConstTypedef::method(CONST_INT_PTR p) { return 0; }"; # Field_Removed_Const $HEADER1 .= " class $DECL_SPEC FieldRemovedConst { public: int*const*const f; int method(); };"; $SOURCE1 .= " int FieldRemovedConst::method() { return 0; }"; $HEADER2 .= " class $DECL_SPEC FieldRemovedConst { public: int**const f; int method(); };"; $SOURCE2 .= " int FieldRemovedConst::method() { return 0; }"; # Field_Became_Const $HEADER1 .= " class $DECL_SPEC FieldBecameConst { public: int* f; int method(); };"; $SOURCE1 .= " int FieldBecameConst::method() { return 0; }"; $HEADER2 .= " class $DECL_SPEC FieldBecameConst { public: int*const f; int method(); };"; $SOURCE2 .= " int FieldBecameConst::method() { return 0; }"; # Field_Became_Private $HEADER1 .= " class $DECL_SPEC FieldBecamePrivate { public: int* f; int method(); };"; $SOURCE1 .= " int FieldBecamePrivate::method() { return 0; }"; $HEADER2 .= " class $DECL_SPEC FieldBecamePrivate { private: int* f; public: int method(); };"; $SOURCE2 .= " int FieldBecamePrivate::method() { return 0; }"; # Field_Became_Protected $HEADER1 .= " class $DECL_SPEC FieldBecameProtected { public: int* f; int method(); };"; $SOURCE1 .= " int FieldBecameProtected::method() { return 0; }"; $HEADER2 .= " class $DECL_SPEC FieldBecameProtected { protected: int* f; public: int method(); };"; $SOURCE2 .= " int FieldBecameProtected::method() { return 0; }"; # Global_Data_Became_Private $HEADER1 .= " class $DECL_SPEC GlobalDataBecamePrivate { public: static int data; };"; $SOURCE1 .= " int GlobalDataBecamePrivate::data = 10;"; $HEADER2 .= " class $DECL_SPEC GlobalDataBecamePrivate { private: static int data; };"; $SOURCE2 .= " int GlobalDataBecamePrivate::data = 10;"; # Method_Became_Private $HEADER1 .= " class $DECL_SPEC MethodBecamePrivate { public: int method(); };"; $SOURCE1 .= " int MethodBecamePrivate::method() { return 0; }"; $HEADER2 .= " class $DECL_SPEC MethodBecamePrivate { private: int method(); };"; $SOURCE2 .= " int MethodBecamePrivate::method() { return 0; }"; # Method_Became_Protected $HEADER1 .= " class $DECL_SPEC MethodBecameProtected { public: int method(); };"; $SOURCE1 .= " int MethodBecameProtected::method() { return 0; }"; $HEADER2 .= " class $DECL_SPEC MethodBecameProtected { protected: int method(); };"; $SOURCE2 .= " int MethodBecameProtected::method() { return 0; }"; # Method_Became_Public $HEADER1 .= " class $DECL_SPEC MethodBecamePublic { protected: int method(); };"; $SOURCE1 .= " int MethodBecamePublic::method() { return 0; }"; $HEADER2 .= " class $DECL_SPEC MethodBecamePublic { public: int method(); };"; $SOURCE2 .= " int MethodBecamePublic::method() { return 0; }"; # Removed_Const_Overload $HEADER1 .= " class $DECL_SPEC RemovedConstOverload { public: int removed(); int removed() const; };"; $SOURCE1 .= " int RemovedConstOverload::removed() { return 0; } int RemovedConstOverload::removed() const { return 0; }"; $HEADER2 .= " class $DECL_SPEC RemovedConstOverload { public: int removed(); };"; $SOURCE2 .= " int RemovedConstOverload::removed() { return 0; }"; # Inline method $HEADER1 .= " class $DECL_SPEC InlineMethod { public: inline int foo() { return 0; } };"; $HEADER2 .= " class $DECL_SPEC InlineMethod { public: inline long foo() { return 0; } };"; # Global_Data_Became_Non_Const $HEADER1 .= " $EXTERN $DECL_SPEC const int globalDataBecameNonConst = 10;"; $HEADER2 .= " extern $DECL_SPEC int globalDataBecameNonConst;"; $SOURCE2 .= " int globalDataBecameNonConst = 15;"; # Global_Data_Became_Non_Const # Class Member $HEADER1 .= " class $DECL_SPEC GlobalDataBecameNonConst { public: static const int data; };"; $SOURCE1 .= " const int GlobalDataBecameNonConst::data = 10;"; $HEADER2 .= " class $DECL_SPEC GlobalDataBecameNonConst { public: static int data; };"; $SOURCE2 .= " int GlobalDataBecameNonConst::data = 10;"; # Global_Data_Became_Const $HEADER1 .= " extern $DECL_SPEC int globalDataBecameConst;"; $SOURCE1 .= " int globalDataBecameConst = 10;"; $HEADER2 .= " $EXTERN $DECL_SPEC const int globalDataBecameConst = 15;"; # Global_Data_Became_Const # Class Member $HEADER1 .= " class $DECL_SPEC GlobalDataBecameConst { public: static int Data; };"; $SOURCE1 .= " int GlobalDataBecameConst::Data = 10;"; $HEADER2 .= " class $DECL_SPEC GlobalDataBecameConst { public: static const int Data = 15; };"; # Global_Data_Value_Changed $HEADER1 .= " class $DECL_SPEC GlobalDataValue { public: static const int Integer = 10; static const char Char = \'o\'; };"; $HEADER2 .= " class $DECL_SPEC GlobalDataValue { public: static const int Integer = 15; static const char Char = \'N\'; };"; # Global_Data_Value_Changed # Integer $HEADER1 .= " $EXTERN $DECL_SPEC const int globalDataValue_Integer = 10;"; $HEADER2 .= " $EXTERN $DECL_SPEC const int globalDataValue_Integer = 15;"; # Global_Data_Value_Changed # Character $HEADER1 .= " $EXTERN $DECL_SPEC const char globalDataValue_Char = \'o\';"; $HEADER2 .= " $EXTERN $DECL_SPEC const char globalDataValue_Char = \'N\';"; # Parameter_Became_Restrict $HEADER1 .= " class $DECL_SPEC ParameterBecameRestrict { public: int method(int* param); };"; $SOURCE1 .= " int ParameterBecameRestrict::method(int* param) { return 0; }"; $HEADER2 .= " class $DECL_SPEC ParameterBecameRestrict { public: int method(int* __restrict param); };"; $SOURCE2 .= " int ParameterBecameRestrict::method(int* __restrict param) { return 0; }"; # Parameter_Became_Non_Restrict $HEADER1 .= " class $DECL_SPEC ParameterBecameNonRestrict { public: int method(int* __restrict param); };"; $SOURCE1 .= " int ParameterBecameNonRestrict::method(int* __restrict param) { return 0; }"; $HEADER2 .= " class $DECL_SPEC ParameterBecameNonRestrict { public: int method(int* param); };"; $SOURCE2 .= " int ParameterBecameNonRestrict::method(int* param) { return 0; }"; # Field_Became_Volatile $HEADER1 .= " class $DECL_SPEC FieldBecameVolatile { public: int method(int param); int f; };"; $SOURCE1 .= " int FieldBecameVolatile::method(int param) { return param; }"; $HEADER2 .= " class $DECL_SPEC FieldBecameVolatile { public: int method(int param); volatile int f; };"; $SOURCE2 .= " int FieldBecameVolatile::method(int param) { return param; }"; # Field_Became_Non_Volatile $HEADER1 .= " class $DECL_SPEC FieldBecameNonVolatile { public: int method(int param); volatile int f; };"; $SOURCE1 .= " int FieldBecameNonVolatile::method(int param) { return param; }"; $HEADER2 .= " class $DECL_SPEC FieldBecameNonVolatile { public: int method(int param); int f; };"; $SOURCE2 .= " int FieldBecameNonVolatile::method(int param) { return param; }"; # Field_Became_Mutable $HEADER1 .= " class $DECL_SPEC FieldBecameMutable { public: int method(int param); int f; };"; $SOURCE1 .= " int FieldBecameMutable::method(int param) { return param; }"; $HEADER2 .= " class $DECL_SPEC FieldBecameMutable { public: int method(int param); mutable int f; };"; $SOURCE2 .= " int FieldBecameMutable::method(int param) { return param; }"; # Field_Became_Non_Mutable $HEADER1 .= " class $DECL_SPEC FieldBecameNonMutable { public: int method(int param); mutable int f; };"; $SOURCE1 .= " int FieldBecameNonMutable::method(int param) { return param; }"; $HEADER2 .= " class $DECL_SPEC FieldBecameNonMutable { public: int method(int param); int f; };"; $SOURCE2 .= " int FieldBecameNonMutable::method(int param) { return param; }"; # Method_Became_Const # Method_Became_Volatile $HEADER1 .= " class $DECL_SPEC MethodBecameConstVolatile { public: int method(int param); };"; $SOURCE1 .= " int MethodBecameConstVolatile::method(int param) { return param; }"; $HEADER2 .= " class $DECL_SPEC MethodBecameConstVolatile { public: int method(int param) volatile const; };"; $SOURCE2 .= " int MethodBecameConstVolatile::method(int param) volatile const { return param; }"; # Method_Became_Const $HEADER1 .= " class $DECL_SPEC MethodBecameConst { public: int method(int param); };"; $SOURCE1 .= " int MethodBecameConst::method(int param) { return param; }"; $HEADER2 .= " class $DECL_SPEC MethodBecameConst { public: int method(int param) const; };"; $SOURCE2 .= " int MethodBecameConst::method(int param) const { return param; }"; # Method_Became_Non_Const $HEADER1 .= " class $DECL_SPEC MethodBecameNonConst { public: int method(int param) const; };"; $SOURCE1 .= " int MethodBecameNonConst::method(int param) const { return param; }"; $HEADER2 .= " class $DECL_SPEC MethodBecameNonConst { public: int method(int param); };"; $SOURCE2 .= " int MethodBecameNonConst::method(int param) { return param; }"; # Method_Became_Volatile $HEADER1 .= " class $DECL_SPEC MethodBecameVolatile { public: int method(int param); };"; $SOURCE1 .= " int MethodBecameVolatile::method(int param) { return param; }"; $HEADER2 .= " class $DECL_SPEC MethodBecameVolatile { public: int method(int param) volatile; };"; $SOURCE2 .= " int MethodBecameVolatile::method(int param) volatile { return param; }"; # Virtual_Method_Position # Multiple bases $HEADER1 .= " class $DECL_SPEC PrimaryBase { public: virtual ~PrimaryBase(); virtual void foo(); }; class $DECL_SPEC SecondaryBase { public: virtual ~SecondaryBase(); virtual void bar(); }; class UnsafeVirtualOverride: public PrimaryBase, public SecondaryBase { public: UnsafeVirtualOverride(); ~UnsafeVirtualOverride(); void foo(); };"; $SOURCE1 .= " PrimaryBase::~PrimaryBase() { } void PrimaryBase::foo() { } SecondaryBase::~SecondaryBase() { } void SecondaryBase::bar() { } UnsafeVirtualOverride::UnsafeVirtualOverride() { } UnsafeVirtualOverride::~UnsafeVirtualOverride() { } void UnsafeVirtualOverride::foo() { }"; $HEADER2 .= " class $DECL_SPEC PrimaryBase { public: virtual ~PrimaryBase(); virtual void foo(); }; class $DECL_SPEC SecondaryBase { public: virtual ~SecondaryBase(); virtual void bar(); }; class UnsafeVirtualOverride: public PrimaryBase, public SecondaryBase { public: UnsafeVirtualOverride(); ~UnsafeVirtualOverride(); void foo(); void bar(); };"; $SOURCE2 .= " PrimaryBase::~PrimaryBase() { } void PrimaryBase::foo() { } SecondaryBase::~SecondaryBase() { } void SecondaryBase::bar() { } UnsafeVirtualOverride::UnsafeVirtualOverride() { } UnsafeVirtualOverride::~UnsafeVirtualOverride() { } void UnsafeVirtualOverride::foo() { } void UnsafeVirtualOverride::bar() { }"; # Removed_Interface (inline virtual d-tor) $HEADER1 .= " template class $DECL_SPEC BaseTemplate { public: BaseTemplate() { } virtual int method(int param) { return param; }; virtual ~BaseTemplate() { }; }; class $DECL_SPEC RemovedVirtualDestructor: public BaseTemplate { public: RemovedVirtualDestructor() { }; virtual int method2(int param); };"; $SOURCE1 .= " int RemovedVirtualDestructor::method2(int param) { return param; }"; $HEADER2 .= " template class $DECL_SPEC BaseTemplate { public: BaseTemplate() { } virtual int method(int param) { return param; }; //virtual ~BaseTemplate() { }; }; class $DECL_SPEC RemovedVirtualDestructor: public BaseTemplate { public: RemovedVirtualDestructor() { }; virtual int method2(int param); };"; $SOURCE2 .= " int RemovedVirtualDestructor::method2(int param) { return param; }"; # Added_Virtual_Method_At_End $HEADER1 .= " class $DECL_SPEC DefaultConstructor { public: DefaultConstructor() { } virtual int method(int param); };"; $SOURCE1 .= " int DefaultConstructor::method(int param) { return param; }"; $HEADER2 .= " class $DECL_SPEC DefaultConstructor { public: DefaultConstructor() { } virtual int method(int param); virtual int addedMethod(int param); };"; $SOURCE2 .= " int DefaultConstructor::method(int param) { return addedMethod(param); } int DefaultConstructor::addedMethod(int param) { return param; }"; # Added_Enum_Member $HEADER1 .= " enum AddedEnumMember { OldMember }; $DECL_SPEC int addedEnumMember(enum AddedEnumMember param);"; $SOURCE1 .= " int addedEnumMember(enum AddedEnumMember param) { return 0; }"; $HEADER2 .= " enum AddedEnumMember { OldMember, NewMember }; $DECL_SPEC int addedEnumMember(enum AddedEnumMember param);"; $SOURCE2 .= " int addedEnumMember(enum AddedEnumMember param) { return 0; }"; # Parameter_Type_Format (Safe) $HEADER1 .= " struct DType { int i; double j; }; $DECL_SPEC int parameterTypeFormat_Safe(struct DType param);"; $SOURCE1 .= " int parameterTypeFormat_Safe(struct DType param) { return 0; }"; $HEADER2 .= " class DType { int i; double j; }; $DECL_SPEC int parameterTypeFormat_Safe(class DType param);"; $SOURCE2 .= " int parameterTypeFormat_Safe(class DType param) { return 0; }"; # Type_Became_Opaque (Struct) $HEADER1 .= " struct StructBecameOpaque { int i, j; }; $DECL_SPEC int structBecameOpaque(struct StructBecameOpaque* param);"; $SOURCE1 .= " int structBecameOpaque(struct StructBecameOpaque* param) { return 0; }"; $HEADER2 .= " struct StructBecameOpaque; $DECL_SPEC int structBecameOpaque(struct StructBecameOpaque* param);"; $SOURCE2 .= " int structBecameOpaque(struct StructBecameOpaque* param) { return 0; }"; # Type_Became_Opaque (Union) $HEADER1 .= " union UnionBecameOpaque { int i, j; }; $DECL_SPEC int unionBecameOpaque(union UnionBecameOpaque* param);"; $SOURCE1 .= " int unionBecameOpaque(union UnionBecameOpaque* param) { return 0; }"; $HEADER2 .= " union UnionBecameOpaque; $DECL_SPEC int unionBecameOpaque(union UnionBecameOpaque* param);"; $SOURCE2 .= " int unionBecameOpaque(union UnionBecameOpaque* param) { return 0; }"; # Field_Type_Format $HEADER1 .= " struct DType1 { int i; double j[7]; }; struct FieldTypeFormat { int i; struct DType1 j; }; $DECL_SPEC int fieldTypeFormat(struct FieldTypeFormat param);"; $SOURCE1 .= " int fieldTypeFormat(struct FieldTypeFormat param) { return 0; }"; $HEADER2 .= " struct DType2 { double i[7]; int j; }; struct FieldTypeFormat { int i; struct DType2 j; }; $DECL_SPEC int fieldTypeFormat(struct FieldTypeFormat param);"; $SOURCE2 .= " int fieldTypeFormat(struct FieldTypeFormat param) { return 0; }"; # Field_Type_Format (func ptr) $HEADER1 .= " typedef void (*FuncPtr_Old) (int a); struct FieldTypeFormat_FuncPtr { int i; FuncPtr_Old j; }; $DECL_SPEC int fieldTypeFormat_FuncPtr(struct FieldTypeFormat_FuncPtr param);"; $SOURCE1 .= " int fieldTypeFormat_FuncPtr(struct FieldTypeFormat_FuncPtr param) { return 0; }"; $HEADER2 .= " typedef void (*FuncPtr_New) (int a, int b); struct FieldTypeFormat_FuncPtr { int i; FuncPtr_New j; }; $DECL_SPEC int fieldTypeFormat_FuncPtr(struct FieldTypeFormat_FuncPtr param);"; $SOURCE2 .= " int fieldTypeFormat_FuncPtr(struct FieldTypeFormat_FuncPtr param) { return 0; }"; # Removed_Virtual_Method (inline) $HEADER1 .= " class $DECL_SPEC RemovedInlineVirtualFunction { public: RemovedInlineVirtualFunction(); virtual int removedMethod(int param) { return 0; } virtual int method(int param); };"; $SOURCE1 .= " int RemovedInlineVirtualFunction::method(int param) { return param; } RemovedInlineVirtualFunction::RemovedInlineVirtualFunction() { }"; $HEADER2 .= " class $DECL_SPEC RemovedInlineVirtualFunction { public: RemovedInlineVirtualFunction(); virtual int method(int param); };"; $SOURCE2 .= " int RemovedInlineVirtualFunction::method(int param) { return param; } RemovedInlineVirtualFunction::RemovedInlineVirtualFunction() { }"; # MethodPtr $HEADER1 .= " class TestMethodPtr { public: typedef void (TestMethodPtr::*Method)(int*); Method _method; TestMethodPtr(); void method(); };"; $SOURCE1 .= " TestMethodPtr::TestMethodPtr() { } void TestMethodPtr::method() { }"; $HEADER2 .= " class TestMethodPtr { public: typedef void (TestMethodPtr::*Method)(int*, void*); Method _method; TestMethodPtr(); void method(); };"; $SOURCE2 .= " TestMethodPtr::TestMethodPtr() { } void TestMethodPtr::method() { }"; # FieldPtr $HEADER1 .= " class TestFieldPtr { public: typedef void* (TestFieldPtr::*Field); Field _field; TestFieldPtr(); void method(void*); };"; $SOURCE1 .= " TestFieldPtr::TestFieldPtr(){ } void TestFieldPtr::method(void*) { }"; $HEADER2 .= " class TestFieldPtr { public: typedef int (TestFieldPtr::*Field); Field _field; TestFieldPtr(); void method(void*); };"; $SOURCE2 .= " TestFieldPtr::TestFieldPtr(){ } void TestFieldPtr::method(void*) { }"; # Removed_Symbol (Template Specializations) $HEADER1 .= " template class Template { public: char const *field; }; template class TestRemovedTemplate { public: char const *field; void method(int); }; template <> class TestRemovedTemplate<7, char> { public: char const *field; void method(int); };"; $SOURCE1 .= " void TestRemovedTemplate<7, char>::method(int){ }"; # Removed_Symbol (Template Specializations) $HEADER1 .= " template int removedTemplateSpec(TName); template <> int removedTemplateSpec(char);"; $SOURCE1 .= " template <> int removedTemplateSpec(char){return 0;}"; # Removed_Field (Ref) $HEADER1 .= " struct TestRefChange { int a, b, c; }; $DECL_SPEC int paramRefChange(const TestRefChange & p1, int p2);"; $SOURCE1 .= " int paramRefChange(const TestRefChange & p1, int p2) { return p2; }"; $HEADER2 .= " struct TestRefChange { int a, b; }; $DECL_SPEC int paramRefChange(const TestRefChange & p1, int p2);"; $SOURCE2 .= " int paramRefChange(const TestRefChange & p1, int p2) { return p2; }"; # Removed_Parameter $HEADER1 .= " $DECL_SPEC int removedParameter(int param, int removed_param);"; $SOURCE1 .= " int removedParameter(int param, int removed_param) { return 0; }"; $HEADER2 .= " $DECL_SPEC int removedParameter(int param);"; $SOURCE2 .= " int removedParameter(int param) { return 0; }"; # Added_Parameter $HEADER1 .= " $DECL_SPEC int addedParameter(int param);"; $SOURCE1 .= " int addedParameter(int param) { return 0; }"; $HEADER2 .= " $DECL_SPEC int addedParameter(int param, int added_param);"; $SOURCE2 .= " int addedParameter(int param, int added_param) { return 0; }"; # Added $HEADER2 .= " typedef int (*FUNCPTR_TYPE)(int a, int b); $DECL_SPEC int addedFunc(FUNCPTR_TYPE*const** f);"; $SOURCE2 .= " int addedFunc(FUNCPTR_TYPE*const** f) { return 0; }"; # Added (3) $HEADER2 .= " struct DStruct { int i, j, k; }; int addedFunc3(struct DStruct* p);"; $SOURCE2 .= " int addedFunc3(struct DStruct* p) { return 0; }"; # Added_Virtual_Method $HEADER1 .= " class $DECL_SPEC AddedVirtualMethod { public: virtual int method(int param); };"; $SOURCE1 .= " int AddedVirtualMethod::method(int param) { return param; }"; $HEADER2 .= " class $DECL_SPEC AddedVirtualMethod { public: virtual int addedMethod(int param); virtual int method(int param); };"; $SOURCE2 .= " int AddedVirtualMethod::addedMethod(int param) { return param; } int AddedVirtualMethod::method(int param) { return param; }"; # Added_Virtual_Method (added "virtual" attribute) $HEADER1 .= " class $DECL_SPEC BecameVirtualMethod { public: int becameVirtual(int param); virtual int method(int param); };"; $SOURCE1 .= " int BecameVirtualMethod::becameVirtual(int param) { return param; } int BecameVirtualMethod::method(int param) { return param; }"; $HEADER2 .= " class $DECL_SPEC BecameVirtualMethod { public: virtual int becameVirtual(int param); virtual int method(int param); };"; $SOURCE2 .= " int BecameVirtualMethod::becameVirtual(int param) { return param; } int BecameVirtualMethod::method(int param) { return param; }"; # Added_Pure_Virtual_Method $HEADER1 .= " class $DECL_SPEC AddedPureVirtualMethod { public: virtual int method(int param); int otherMethod(int param); };"; $SOURCE1 .= " int AddedPureVirtualMethod::method(int param) { return param; } int AddedPureVirtualMethod::otherMethod(int param) { return param; }"; $HEADER2 .= " class $DECL_SPEC AddedPureVirtualMethod { public: virtual int addedMethod(int param)=0; virtual int method(int param); int otherMethod(int param); };"; $SOURCE2 .= " int AddedPureVirtualMethod::method(int param) { return param; } int AddedPureVirtualMethod::otherMethod(int param) { return param; }"; # Added_Virtual_Method_At_End (Safe) $HEADER1 .= " class $DECL_SPEC AddedVirtualMethodAtEnd { public: AddedVirtualMethodAtEnd(); int method1(int param); virtual int method2(int param); };"; $SOURCE1 .= " AddedVirtualMethodAtEnd::AddedVirtualMethodAtEnd() { } int AddedVirtualMethodAtEnd::method1(int param) { return param; } int AddedVirtualMethodAtEnd::method2(int param) { return param; }"; $HEADER2 .= " class $DECL_SPEC AddedVirtualMethodAtEnd { public: AddedVirtualMethodAtEnd(); int method1(int param); virtual int method2(int param); virtual int addedMethod(int param); };"; $SOURCE2 .= " AddedVirtualMethodAtEnd::AddedVirtualMethodAtEnd() { } int AddedVirtualMethodAtEnd::method1(int param) { return param; } int AddedVirtualMethodAtEnd::method2(int param) { return param; } int AddedVirtualMethodAtEnd::addedMethod(int param) { return param; }"; # Added_Virtual_Method_At_End (With Default Constructor) $HEADER1 .= " class $DECL_SPEC AddedVirtualMethodAtEnd_DefaultConstructor { public: int method1(int param); virtual int method2(int param); };"; $SOURCE1 .= " int AddedVirtualMethodAtEnd_DefaultConstructor::method1(int param) { return param; } int AddedVirtualMethodAtEnd_DefaultConstructor::method2(int param) { return param; }"; $HEADER2 .= " class $DECL_SPEC AddedVirtualMethodAtEnd_DefaultConstructor { public: int method1(int param); virtual int method2(int param); virtual int addedMethod(int param); };"; $SOURCE2 .= " int AddedVirtualMethodAtEnd_DefaultConstructor::method1(int param) { return param; } int AddedVirtualMethodAtEnd_DefaultConstructor::method2(int param) { return param; } int AddedVirtualMethodAtEnd_DefaultConstructor::addedMethod(int param) { return param; }"; # Added_First_Virtual_Method $HEADER1 .= " class $DECL_SPEC AddedFirstVirtualMethod { public: int method(int param); };"; $SOURCE1 .= " int AddedFirstVirtualMethod::method(int param) { return param; }"; $HEADER2 .= " class $DECL_SPEC AddedFirstVirtualMethod { public: int method(int param); virtual int addedMethod(int param); };"; $SOURCE2 .= " int AddedFirstVirtualMethod::method(int param) { return param; } int AddedFirstVirtualMethod::addedMethod(int param) { return param; }"; # Removed_Virtual_Method $HEADER1 .= " class $DECL_SPEC RemovedVirtualFunction { public: int a, b, c; virtual int removedMethod(int param); virtual int vMethod(int param); };"; $SOURCE1 .= " int RemovedVirtualFunction::removedMethod(int param) { return param; } int RemovedVirtualFunction::vMethod(int param) { return param; }"; $HEADER2 .= " class $DECL_SPEC RemovedVirtualFunction { public: int a, b, c; int removedMethod(int param); virtual int vMethod(int param); };"; $SOURCE2 .= " int RemovedVirtualFunction::removedMethod(int param) { return param; } int RemovedVirtualFunction::vMethod(int param) { return param; }"; # Removed_Virtual_Method (Pure, From the End) $HEADER1 .= " class $DECL_SPEC RemovedPureVirtualMethodFromEnd { public: virtual int method(int param); virtual int removedMethod(int param)=0; };"; $SOURCE1 .= " int RemovedPureVirtualMethodFromEnd::method(int param) { return param; } int RemovedPureVirtualMethodFromEnd::removedMethod(int param) { return param; }"; $HEADER2 .= " class $DECL_SPEC RemovedPureVirtualMethodFromEnd { public: virtual int method(int param); int removedMethod(int param); };"; $SOURCE2 .= " int RemovedPureVirtualMethodFromEnd::method(int param) { return param; } int RemovedPureVirtualMethodFromEnd::removedMethod(int param) { return param; }"; # Removed_Symbol (Pure with Implementation) $HEADER1 .= " class $DECL_SPEC RemovedPureSymbol { public: virtual int method(int param); virtual int removedMethod(int param)=0; };"; $SOURCE1 .= " int RemovedPureSymbol::method(int param) { return param; } int RemovedPureSymbol::removedMethod(int param) { return param; }"; $HEADER2 .= " class $DECL_SPEC RemovedPureSymbol { public: virtual int method(int param); };"; $SOURCE2 .= " int RemovedPureSymbol::method(int param) { return param; }"; # Removed_Virtual_Method (From the End) $HEADER1 .= " class $DECL_SPEC RemovedVirtualMethodFromEnd { public: virtual int method(int param); virtual int removedMethod(int param); };"; $SOURCE1 .= " int RemovedVirtualMethodFromEnd::method(int param) { return param; } int RemovedVirtualMethodFromEnd::removedMethod(int param) { return param; }"; $HEADER2 .= " class $DECL_SPEC RemovedVirtualMethodFromEnd { public: virtual int method(int param); int removedMethod(int param); };"; $SOURCE2 .= " int RemovedVirtualMethodFromEnd::method(int param) { return param; } int RemovedVirtualMethodFromEnd::removedMethod(int param) { return param; }"; # Removed_Last_Virtual_Method $HEADER1 .= " class $DECL_SPEC RemovedLastVirtualMethod { public: int method(int param); virtual int removedMethod(int param); };"; $SOURCE1 .= " int RemovedLastVirtualMethod::method(int param) { return param; }"; $SOURCE1 .= " int RemovedLastVirtualMethod::removedMethod(int param) { return param; }"; $HEADER2 .= " class $DECL_SPEC RemovedLastVirtualMethod { public: int method(int param); int removedMethod(int param); };"; $SOURCE2 .= " int RemovedLastVirtualMethod::method(int param) { return param; }"; $SOURCE2 .= " int RemovedLastVirtualMethod::removedMethod(int param) { return param; }"; # Virtual_Table_Size $HEADER1 .= " class $DECL_SPEC VirtualTableSize { public: virtual int method1(int param); virtual int method2(int param); }; class $DECL_SPEC VirtualTableSize_SubClass: public VirtualTableSize { public: virtual int method3(int param); virtual int method4(int param); };"; $SOURCE1 .= " int VirtualTableSize::method1(int param) { return param; } int VirtualTableSize::method2(int param) { return param; } int VirtualTableSize_SubClass::method3(int param) { return param; } int VirtualTableSize_SubClass::method4(int param) { return param; }"; $HEADER2 .= " class $DECL_SPEC VirtualTableSize { public: virtual int method1(int param); virtual int method2(int param); virtual int addedMethod(int param); }; class $DECL_SPEC VirtualTableSize_SubClass: public VirtualTableSize { public: virtual int method3(int param); virtual int method4(int param); };"; $SOURCE2 .= " int VirtualTableSize::method1(int param) { return param; } int VirtualTableSize::method2(int param) { return param; } int VirtualTableSize::addedMethod(int param) { return param; } int VirtualTableSize_SubClass::method3(int param) { return param; } int VirtualTableSize_SubClass::method4(int param) { return param; }"; # Virtual_Method_Position $HEADER1 .= " class $DECL_SPEC VirtualMethodPosition { public: virtual int method1(int param); virtual int method2(int param); };"; $SOURCE1 .= " int VirtualMethodPosition::method1(int param) { return param; }"; $SOURCE1 .= " int VirtualMethodPosition::method2(int param) { return param; }"; $HEADER2 .= " class $DECL_SPEC VirtualMethodPosition { public: virtual int method2(int param); virtual int method1(int param); };"; $SOURCE2 .= " int VirtualMethodPosition::method1(int param) { return param; }"; $SOURCE2 .= " int VirtualMethodPosition::method2(int param) { return param; }"; # Pure_Virtual_Method_Position $HEADER1 .= " class $DECL_SPEC PureVirtualFunctionPosition { public: virtual int method1(int param)=0; virtual int method2(int param)=0; int method3(int param); };"; $SOURCE1 .= " int PureVirtualFunctionPosition::method3(int param) { return method1(7)+method2(7); }"; $HEADER2 .= " class $DECL_SPEC PureVirtualFunctionPosition { public: virtual int method2(int param)=0; virtual int method1(int param)=0; int method3(int param); };"; $SOURCE2 .= " int PureVirtualFunctionPosition::method3(int param) { return method1(7)+method2(7); }"; # Virtual_Method_Position $HEADER1 .= " class $DECL_SPEC VirtualFunctionPosition { public: virtual int method1(int param); virtual int method2(int param); };"; $SOURCE1 .= " int VirtualFunctionPosition::method1(int param) { return 1; } int VirtualFunctionPosition::method2(int param) { return 2; }"; $HEADER2 .= " class $DECL_SPEC VirtualFunctionPosition { public: virtual int method2(int param); virtual int method1(int param); };"; $SOURCE2 .= " int VirtualFunctionPosition::method1(int param) { return 1; } int VirtualFunctionPosition::method2(int param) { return 2; }"; # Virtual_Method_Position (safe) $HEADER1 .= " class $DECL_SPEC VirtualFunctionPositionSafe_Base { public: virtual int method1(int param); virtual int method2(int param); }; class $DECL_SPEC VirtualFunctionPositionSafe: public VirtualFunctionPositionSafe_Base { public: virtual int method1(int param); virtual int method2(int param); };"; $SOURCE1 .= " int VirtualFunctionPositionSafe_Base::method1(int param) { return param; } int VirtualFunctionPositionSafe_Base::method2(int param) { return param; } int VirtualFunctionPositionSafe::method1(int param) { return param; } int VirtualFunctionPositionSafe::method2(int param) { return param; }"; $HEADER2 .= " class $DECL_SPEC VirtualFunctionPositionSafe_Base { public: virtual int method1(int param); virtual int method2(int param); }; class $DECL_SPEC VirtualFunctionPositionSafe: public VirtualFunctionPositionSafe_Base { public: virtual int method2(int param); virtual int method1(int param); };"; $SOURCE2 .= " int VirtualFunctionPositionSafe_Base::method1(int param) { return param; } int VirtualFunctionPositionSafe_Base::method2(int param) { return param; } int VirtualFunctionPositionSafe::method1(int param) { return param; } int VirtualFunctionPositionSafe::method2(int param) { return param; }"; # Overridden_Virtual_Method $HEADER1 .= " class $DECL_SPEC OverriddenVirtualMethod_Base { public: virtual int method1(int param); virtual int method2(int param); }; class $DECL_SPEC OverriddenVirtualMethod: public OverriddenVirtualMethod_Base { public: OverriddenVirtualMethod(); virtual int method3(int param); };"; $SOURCE1 .= " int OverriddenVirtualMethod_Base::method1(int param) { return param; } int OverriddenVirtualMethod_Base::method2(int param) { return param; } OverriddenVirtualMethod::OverriddenVirtualMethod() {} int OverriddenVirtualMethod::method3(int param) { return param; }"; $HEADER2 .= " class $DECL_SPEC OverriddenVirtualMethod_Base { public: virtual int method1(int param); virtual int method2(int param); }; class $DECL_SPEC OverriddenVirtualMethod:public OverriddenVirtualMethod_Base { OverriddenVirtualMethod(); virtual int method2(int param); virtual int method3(int param); };"; $SOURCE2 .= " int OverriddenVirtualMethod_Base::method1(int param) { return param; } int OverriddenVirtualMethod_Base::method2(int param) { return param; } OverriddenVirtualMethod::OverriddenVirtualMethod() {} int OverriddenVirtualMethod::method2(int param) { return param; } int OverriddenVirtualMethod::method3(int param) { return param; }"; # Overridden_Virtual_Method_B (+ removed) $HEADER1 .= " class $DECL_SPEC OverriddenVirtualMethodB: public OverriddenVirtualMethod_Base { public: OverriddenVirtualMethodB(); virtual int method2(int param); virtual int method3(int param); };"; $SOURCE1 .= " OverriddenVirtualMethodB::OverriddenVirtualMethodB() {} int OverriddenVirtualMethodB::method2(int param) { return param; } int OverriddenVirtualMethodB::method3(int param) { return param; }"; $HEADER2 .= " class $DECL_SPEC OverriddenVirtualMethodB:public OverriddenVirtualMethod_Base { public: OverriddenVirtualMethodB(); virtual int method3(int param); };"; $SOURCE2 .= " OverriddenVirtualMethodB::OverriddenVirtualMethodB() {} int OverriddenVirtualMethodB::method3(int param) { return param; }"; # Size $HEADER1 .= " struct $DECL_SPEC TypeSize { public: TypeSize method(TypeSize param); int i[5]; long j; double k; TypeSize* p; };"; $SOURCE1 .= " TypeSize TypeSize::method(TypeSize param) { return param; }"; $HEADER2 .= " struct $DECL_SPEC TypeSize { public: TypeSize method(TypeSize param); int i[15]; long j; double k; TypeSize* p; int added_member; };"; $SOURCE2 .= " TypeSize TypeSize::method(TypeSize param) { return param; }"; # Size_Of_Allocable_Class_Increased $HEADER1 .= " class $DECL_SPEC AllocableClassSize { public: AllocableClassSize(); int method(); double p[5]; };"; $SOURCE1 .= " AllocableClassSize::AllocableClassSize() { }"; $SOURCE1 .= " int AllocableClassSize::method() { return 0; }"; $HEADER2 .= " struct $DECL_SPEC AllocableClassSize { public: AllocableClassSize(); int method(); double p[15]; };"; $SOURCE2 .= " AllocableClassSize::AllocableClassSize() { }"; $SOURCE2 .= " int AllocableClassSize::method() { return 0; }"; # Size_Of_Allocable_Class_Decreased (decreased size, has derived class, has public members) $HEADER1 .= " class $DECL_SPEC DecreasedClassSize { public: DecreasedClassSize(); int method(); double p[15]; };"; $SOURCE1 .= " DecreasedClassSize::DecreasedClassSize() { }"; $SOURCE1 .= " int DecreasedClassSize::method() { return 0; }"; $HEADER1 .= " class $DECL_SPEC DecreasedClassSize_SubClass: public DecreasedClassSize { public: DecreasedClassSize_SubClass(); int method(); int f; };"; $SOURCE1 .= " DecreasedClassSize_SubClass::DecreasedClassSize_SubClass() { f=7; }"; $SOURCE1 .= " int DecreasedClassSize_SubClass::method() { return f; }"; $HEADER2 .= " struct $DECL_SPEC DecreasedClassSize { public: DecreasedClassSize(); int method(); double p[5]; };"; $SOURCE2 .= " DecreasedClassSize::DecreasedClassSize() { }"; $SOURCE2 .= " int DecreasedClassSize::method() { return 0; }"; $HEADER2 .= " class $DECL_SPEC DecreasedClassSize_SubClass: public DecreasedClassSize { public: DecreasedClassSize_SubClass(); int method(); int f; };"; $SOURCE2 .= " DecreasedClassSize_SubClass::DecreasedClassSize_SubClass() { f=7; }"; $SOURCE2 .= " int DecreasedClassSize_SubClass::method() { return f; }"; # Size_Of_Copying_Class $HEADER1 .= " class $DECL_SPEC CopyingClassSize { public: int method(); int p[5]; };"; $SOURCE1 .= " int CopyingClassSize::method() { return p[4]; }"; $HEADER2 .= " struct $DECL_SPEC CopyingClassSize { public: int method(); int p[15]; };"; $SOURCE2 .= " int CopyingClassSize::method() { return p[10]; }"; # Base_Class_Became_Virtually_Inherited $HEADER1 .= " class $DECL_SPEC BecameVirtualBase { public: BecameVirtualBase(); int method(); double p[5]; };"; $SOURCE1 .= " BecameVirtualBase::BecameVirtualBase() { }"; $SOURCE1 .= " int BecameVirtualBase::method() { return 0; }"; $HEADER1 .= " class $DECL_SPEC AddedVirtualBase1:public BecameVirtualBase { public: AddedVirtualBase1(); int method(); };"; $SOURCE1 .= " AddedVirtualBase1::AddedVirtualBase1() { }"; $SOURCE1 .= " int AddedVirtualBase1::method() { return 0; }"; $HEADER1 .= " class $DECL_SPEC AddedVirtualBase2: public BecameVirtualBase { public: AddedVirtualBase2(); int method(); };"; $SOURCE1 .= " AddedVirtualBase2::AddedVirtualBase2() { }"; $SOURCE1 .= " int AddedVirtualBase2::method() { return 0; }"; $HEADER1 .= " class $DECL_SPEC BaseClassBecameVirtuallyInherited:public AddedVirtualBase1, public AddedVirtualBase2 { public: BaseClassBecameVirtuallyInherited(); };"; $SOURCE1 .= " BaseClassBecameVirtuallyInherited::BaseClassBecameVirtuallyInherited() { }"; $HEADER2 .= " class $DECL_SPEC BecameVirtualBase { public: BecameVirtualBase(); int method(); double p[5]; };"; $SOURCE2 .= " BecameVirtualBase::BecameVirtualBase() { }"; $SOURCE2 .= " int BecameVirtualBase::method() { return 0; }"; $HEADER2 .= " class $DECL_SPEC AddedVirtualBase1:public virtual BecameVirtualBase { public: AddedVirtualBase1(); int method(); };"; $SOURCE2 .= " AddedVirtualBase1::AddedVirtualBase1() { }"; $SOURCE2 .= " int AddedVirtualBase1::method() { return 0; }"; $HEADER2 .= " class $DECL_SPEC AddedVirtualBase2: public virtual BecameVirtualBase { public: AddedVirtualBase2(); int method(); };"; $SOURCE2 .= " AddedVirtualBase2::AddedVirtualBase2() { }"; $SOURCE2 .= " int AddedVirtualBase2::method() { return 0; }"; $HEADER2 .= " class $DECL_SPEC BaseClassBecameVirtuallyInherited:public AddedVirtualBase1, public AddedVirtualBase2 { public: BaseClassBecameVirtuallyInherited(); };"; $SOURCE2 .= " BaseClassBecameVirtuallyInherited::BaseClassBecameVirtuallyInherited() { }"; # Added_Base_Class, Removed_Base_Class $HEADER1 .= " class $DECL_SPEC BaseClass { public: BaseClass(); int method(); double p[5]; }; class $DECL_SPEC RemovedBaseClass { public: RemovedBaseClass(); int method(); }; class $DECL_SPEC ChangedBaseClass:public BaseClass, public RemovedBaseClass { public: ChangedBaseClass(); };"; $SOURCE1 .= " BaseClass::BaseClass() { } int BaseClass::method() { return 0; } RemovedBaseClass::RemovedBaseClass() { } int RemovedBaseClass::method() { return 0; } ChangedBaseClass::ChangedBaseClass() { }"; $HEADER2 .= " class $DECL_SPEC BaseClass { public: BaseClass(); int method(); double p[5]; }; class $DECL_SPEC AddedBaseClass { public: AddedBaseClass(); int method(); }; class $DECL_SPEC ChangedBaseClass:public BaseClass, public AddedBaseClass { public: ChangedBaseClass(); };"; $SOURCE2 .= " BaseClass::BaseClass() { } int BaseClass::method() { return 0; } AddedBaseClass::AddedBaseClass() { } int AddedBaseClass::method() { return 0; } ChangedBaseClass::ChangedBaseClass() { }"; # Added_Base_Class_And_Shift, Removed_Base_Class_And_Shift $HEADER1 .= " struct $DECL_SPEC BaseClass2 { BaseClass2(); int method(); double p[15]; }; class $DECL_SPEC ChangedBaseClassAndSize:public BaseClass { public: ChangedBaseClassAndSize(); };"; $SOURCE1 .= " BaseClass2::BaseClass2() { } int BaseClass2::method() { return 0; } ChangedBaseClassAndSize::ChangedBaseClassAndSize() { }"; $HEADER2 .= " struct $DECL_SPEC BaseClass2 { BaseClass2(); int method(); double p[15]; }; class $DECL_SPEC ChangedBaseClassAndSize:public BaseClass2 { public: ChangedBaseClassAndSize(); };"; $SOURCE2 .= " BaseClass2::BaseClass2() { } int BaseClass2::method() { return 0; } ChangedBaseClassAndSize::ChangedBaseClassAndSize() { }"; # Added_Field_And_Size $HEADER1 .= " struct $DECL_SPEC AddedFieldAndSize { int method(AddedFieldAndSize param); double i, j, k; AddedFieldAndSize* p; };"; $SOURCE1 .= " int AddedFieldAndSize::method(AddedFieldAndSize param) { return 0; }"; $HEADER2 .= " struct $DECL_SPEC AddedFieldAndSize { int method(AddedFieldAndSize param); double i, j, k; AddedFieldAndSize* p; int added_member1; long long added_member2; };"; $SOURCE2 .= " int AddedFieldAndSize::method(AddedFieldAndSize param) { return 0; }"; # Added_Field $HEADER1 .= " class $DECL_SPEC ObjectAddedMember { public: int method(int param); double i, j, k; AddedFieldAndSize* p; };"; $SOURCE1 .= " int ObjectAddedMember::method(int param) { return param; }"; $HEADER2 .= " class $DECL_SPEC ObjectAddedMember { public: int method(int param); double i, j, k; AddedFieldAndSize* p; int added_member1; long long added_member2; };"; $SOURCE2 .= " int ObjectAddedMember::method(int param) { return param; }"; # Added_Field (safe) $HEADER1 .= " struct $DECL_SPEC AddedBitfield { int method(AddedBitfield param); double i, j, k; int b1 : 32; int b2 : 31; AddedBitfield* p; };"; $SOURCE1 .= " int AddedBitfield::method(AddedBitfield param) { return 0; }"; $HEADER2 .= " struct $DECL_SPEC AddedBitfield { int method(AddedBitfield param); double i, j, k; int b1 : 32; int b2 : 31; int added_bitfield : 1; int added_bitfield2 : 1; AddedBitfield* p; };"; $SOURCE2 .= " int AddedBitfield::method(AddedBitfield param) { return 0; }"; # Bit_Field_Size $HEADER1 .= " struct $DECL_SPEC BitfieldSize { int method(BitfieldSize param); short changed_bitfield : 1; };"; $SOURCE1 .= " int BitfieldSize::method(BitfieldSize param) { return 0; }"; $HEADER2 .= " struct $DECL_SPEC BitfieldSize { int method(BitfieldSize param); short changed_bitfield : 7; };"; $SOURCE2 .= " int BitfieldSize::method(BitfieldSize param) { return 0; }"; # Removed_Field $HEADER1 .= " struct $DECL_SPEC RemovedBitfield { int method(RemovedBitfield param); double i, j, k; int b1 : 32; int b2 : 31; int removed_bitfield : 1; RemovedBitfield* p; };"; $SOURCE1 .= " int RemovedBitfield::method(RemovedBitfield param) { return 0; }"; $HEADER2 .= " struct $DECL_SPEC RemovedBitfield { int method(RemovedBitfield param); double i, j, k; int b1 : 32; int b2 : 31; RemovedBitfield* p; };"; $SOURCE2 .= " int RemovedBitfield::method(RemovedBitfield param) { return 0; }"; # Removed_Middle_Field $HEADER1 .= " struct $DECL_SPEC RemovedMiddleBitfield { int method(RemovedMiddleBitfield param); double i, j, k; int b1 : 32; int removed_middle_bitfield : 1; int b2 : 31; RemovedMiddleBitfield* p; };"; $SOURCE1 .= " int RemovedMiddleBitfield::method(RemovedMiddleBitfield param) { return 0; }"; $HEADER2 .= " struct $DECL_SPEC RemovedMiddleBitfield { int method(RemovedMiddleBitfield param); double i, j, k; int b1 : 32; int b2 : 31; RemovedMiddleBitfield* p; };"; $SOURCE2 .= " int RemovedMiddleBitfield::method(RemovedMiddleBitfield param) { return 0; }"; # Added_Middle_Field_And_Size $HEADER1 .= " struct $DECL_SPEC AddedMiddleFieldAndSize { int method(AddedMiddleFieldAndSize param); int i; long j; double k; AddedMiddleFieldAndSize* p; };"; $SOURCE1 .= " int AddedMiddleFieldAndSize::method(AddedMiddleFieldAndSize param) { return 0; }"; $HEADER2 .= " struct $DECL_SPEC AddedMiddleFieldAndSize { int method(AddedMiddleFieldAndSize param); int i; int added_middle_member; long j; double k; AddedMiddleFieldAndSize* p; };"; $SOURCE2 .= " int AddedMiddleFieldAndSize::method(AddedMiddleFieldAndSize param) { return 0; }"; # Added_Field (padding) $HEADER1 .= " struct $DECL_SPEC AddedMiddlePaddedField { int method(int param); short i; long j; double k; };"; $SOURCE1 .= " int AddedMiddlePaddedField::method(int param) { return 0; }"; $HEADER2 .= " struct $DECL_SPEC AddedMiddlePaddedField { int method(int param); short i; short added_padded_field; long j; double k; };"; $SOURCE2 .= " int AddedMiddlePaddedField::method(int param) { return 0; }"; # Added_Field (tail padding) $HEADER1 .= " struct $DECL_SPEC AddedTailField { int method(int param); int i1, i2, i3, i4, i5, i6, i7; short s; };"; $SOURCE1 .= " int AddedTailField::method(int param) { return 0; }"; $HEADER2 .= " struct $DECL_SPEC AddedTailField { int method(int param); int i1, i2, i3, i4, i5, i6, i7; short s; short added_tail_field; };"; $SOURCE2 .= " int AddedTailField::method(int param) { return 0; }"; # Test Alignment $HEADER1 .= " struct $DECL_SPEC TestAlignment { int method(int param); short s:9; short j:9; char c; short t:9; short u:9; char d; };"; $SOURCE1 .= " int TestAlignment::method(int param) { return 0; }"; $HEADER2 .= " struct $DECL_SPEC TestAlignment { int method(int param); short s:9; short j:9; char c; short t:9; short u:9; char d; };"; $SOURCE2 .= " int TestAlignment::method(int param) { return 0; }"; # Renamed_Field $HEADER1 .= " struct $DECL_SPEC RenamedField { int method(RenamedField param); long i; long j; double k; RenamedField* p; };"; $SOURCE1 .= " int RenamedField::method(RenamedField param) { return 0; }"; $HEADER2 .= " struct $DECL_SPEC RenamedField { int method(RenamedField param); long renamed_member; long j; double k; RenamedField* p; };"; $SOURCE2 .= " int RenamedField::method(RenamedField param) { return 0; }"; # Removed_Field_And_Size $HEADER1 .= " struct $DECL_SPEC RemovedFieldAndSize { int method(RemovedFieldAndSize param); double i, j, k; RemovedFieldAndSize* p; int removed_member1; long removed_member2; };"; $SOURCE1 .= " int RemovedFieldAndSize::method(RemovedFieldAndSize param) { return 0; }"; $HEADER2 .= " struct $DECL_SPEC RemovedFieldAndSize { int method(RemovedFieldAndSize param); double i, j, k; RemovedFieldAndSize* p; };"; $SOURCE2 .= " int RemovedFieldAndSize::method(RemovedFieldAndSize param) { return 0; }"; # Field Position $HEADER1 .= " struct $DECL_SPEC MovedField { int method(int param); double i; int j; };"; $SOURCE1 .= " int MovedField::method(int param) { return 0; }"; $HEADER2 .= " struct $DECL_SPEC MovedField { int method(int param); int j; double i; };"; $SOURCE2 .= " int MovedField::method(int param) { return 0; }"; # Removed_Middle_Field_And_Size $HEADER1 .= " struct $DECL_SPEC RemovedMiddleFieldAndSize { int method(RemovedMiddleFieldAndSize param); int i; int removed_middle_member; long j; double k; RemovedMiddleFieldAndSize* p; };"; $SOURCE1 .= " int RemovedMiddleFieldAndSize::method(RemovedMiddleFieldAndSize param) { return 0; }"; $HEADER2 .= " struct $DECL_SPEC RemovedMiddleFieldAndSize { int method(RemovedMiddleFieldAndSize param); int i; long j; double k; RemovedMiddleFieldAndSize* p; };"; $SOURCE2 .= " int RemovedMiddleFieldAndSize::method(RemovedMiddleFieldAndSize param) { return 0; }"; # Enum_Member_Value $HEADER1 .= " enum EnumMemberValue { MEMBER_1=1, MEMBER_2=2 };"; $HEADER1 .= " $DECL_SPEC int enumMemberValueChange(enum EnumMemberValue param);"; $SOURCE1 .= " int enumMemberValueChange(enum EnumMemberValue param) { return 0; }"; $HEADER2 .= " enum EnumMemberValue { MEMBER_1=2, MEMBER_2=1 };"; $HEADER2 .= " $DECL_SPEC int enumMemberValueChange(enum EnumMemberValue param);"; $SOURCE2 .= " int enumMemberValueChange(enum EnumMemberValue param) { return 0; }"; # Enum_Member_Name $HEADER1 .= " enum EnumMemberRename { BRANCH_1=1, BRANCH_2=2 };"; $HEADER1 .= " $DECL_SPEC int enumMemberRename(enum EnumMemberRename param);"; $SOURCE1 .= " int enumMemberRename(enum EnumMemberRename param) { return 0; }"; $HEADER2 .= " enum EnumMemberRename { BRANCH_FIRST=1, BRANCH_SECOND=2 };"; $HEADER2 .= " $DECL_SPEC int enumMemberRename(enum EnumMemberRename param);"; $SOURCE2 .= " int enumMemberRename(enum EnumMemberRename param) { return 0; }"; # Field_Type_And_Size $HEADER1 .= " struct $DECL_SPEC FieldTypeAndSize { int method(FieldTypeAndSize param); int i; long j; double k; FieldTypeAndSize* p; };"; $SOURCE1 .= " int FieldTypeAndSize::method(FieldTypeAndSize param) { return 0; }"; $HEADER2 .= " struct $DECL_SPEC FieldTypeAndSize { int method(FieldTypeAndSize param); long long i; long j; double k; FieldTypeAndSize* p; };"; $SOURCE2 .= " int FieldTypeAndSize::method(FieldTypeAndSize param) { return 0; }"; # Member_Type $HEADER1 .= " struct $DECL_SPEC MemberType { int method(MemberType param); int i; long j; double k; MemberType* p; };"; $SOURCE1 .= " int MemberType::method(MemberType param) { return 0; }"; $HEADER2 .= " struct $DECL_SPEC MemberType { int method(MemberType param); float i; long j; double k; MemberType* p; };"; $SOURCE2 .= " int MemberType::method(MemberType param) { return 0; }"; # Field_BaseType $HEADER1 .= " struct $DECL_SPEC FieldBaseType { int method(FieldBaseType param); int *i; long j; double k; FieldBaseType* p; };"; $SOURCE1 .= " int FieldBaseType::method(FieldBaseType param) { return 0; }"; $HEADER2 .= " struct $DECL_SPEC FieldBaseType { int method(FieldBaseType param); long long *i; long j; double k; FieldBaseType* p; };"; $SOURCE2 .= " int FieldBaseType::method(FieldBaseType param) { return 0; }"; # Field_PointerLevel_Increased (and size) $HEADER1 .= " struct $DECL_SPEC FieldPointerLevelAndSize { int method(FieldPointerLevelAndSize param); long long i; long j; double k; FieldPointerLevelAndSize* p; };"; $SOURCE1 .= " int FieldPointerLevelAndSize::method(FieldPointerLevelAndSize param) { return 0; }"; $HEADER2 .= " struct $DECL_SPEC FieldPointerLevelAndSize { int method(FieldPointerLevelAndSize param); long long *i; long j; double k; FieldPointerLevelAndSize* p; };"; $SOURCE2 .= " int FieldPointerLevelAndSize::method(FieldPointerLevelAndSize param) { return 0; }"; # Field_PointerLevel $HEADER1 .= " struct $DECL_SPEC FieldPointerLevel { int method(FieldPointerLevel param); int **i; long j; double k; FieldPointerLevel* p; };"; $SOURCE1 .= " int FieldPointerLevel::method(FieldPointerLevel param) { return 0; }"; $HEADER2 .= " struct $DECL_SPEC FieldPointerLevel { int method(FieldPointerLevel param); int *i; long j; double k; FieldPointerLevel* p; };"; $SOURCE2 .= " int FieldPointerLevel::method(FieldPointerLevel param) { return 0; }"; # Added_Interface (method) $HEADER1 .= " struct $DECL_SPEC AddedInterface { int method(AddedInterface param); int i; long j; double k; AddedInterface* p; };"; $SOURCE1 .= " int AddedInterface::method(AddedInterface param) { return 0; }"; $HEADER2 .= " struct $DECL_SPEC AddedInterface { int method(AddedInterface param); int added_func(AddedInterface param); int i; long j; double k; AddedInterface* p; };"; $SOURCE2 .= " int AddedInterface::method(AddedInterface param) { return 0; }"; $SOURCE2 .= " int AddedInterface::added_func(AddedInterface param) { return 0; }"; # Added_Interface (function) $HEADER2 .= " $DECL_SPEC int addedFunc2(void *** param);"; $SOURCE2 .= " int addedFunc2(void *** param) { return 0; }"; # Added_Interface (global variable) $HEADER1 .= " struct $DECL_SPEC AddedVariable { int method(AddedVariable param); int i1, i2; long j; double k; AddedVariable* p; };"; $SOURCE1 .= " int AddedVariable::method(AddedVariable param) { return i1; }"; $HEADER2 .= " struct $DECL_SPEC AddedVariable { int method(AddedVariable param); static int i1; static int i2; long j; double k; AddedVariable* p; };"; $SOURCE2 .= " int AddedVariable::method(AddedVariable param) { return AddedVariable::i1; }"; $SOURCE2 .= " int AddedVariable::i1=0;"; $SOURCE2 .= " int AddedVariable::i2=0;"; # Removed_Interface (method) $HEADER1 .= " struct $DECL_SPEC RemovedInterface { int method(RemovedInterface param); int removed_func(RemovedInterface param); int i; long j; double k; RemovedInterface* p; };"; $SOURCE1 .= " int RemovedInterface::method(RemovedInterface param) { return 0; }"; $SOURCE1 .= " int RemovedInterface::removed_func(RemovedInterface param) { return 0; }"; $HEADER2 .= " struct $DECL_SPEC RemovedInterface { int method(RemovedInterface param); int i; long j; double k; RemovedInterface* p; };"; $SOURCE2 .= " int RemovedInterface::method(RemovedInterface param) { return 0; }"; # Removed_Interface (function) $HEADER1 .= " $DECL_SPEC int removedFunc2(void *** param);"; $SOURCE1 .= " int removedFunc2(void *** param) { return 0; }"; # Method_Became_Static $HEADER1 .= " struct $DECL_SPEC MethodBecameStatic { MethodBecameStatic becameStatic(MethodBecameStatic param); int **i; long j; double k; MethodBecameStatic* p; };"; $SOURCE1 .= " MethodBecameStatic MethodBecameStatic::becameStatic(MethodBecameStatic param) { return param; }"; $HEADER2 .= " struct $DECL_SPEC MethodBecameStatic { static MethodBecameStatic becameStatic(MethodBecameStatic param); int **i; long j; double k; MethodBecameStatic* p; };"; $SOURCE2 .= " MethodBecameStatic MethodBecameStatic::becameStatic(MethodBecameStatic param) { return param; }"; # Method_Became_Non_Static $HEADER1 .= " struct $DECL_SPEC MethodBecameNonStatic { static MethodBecameNonStatic becameNonStatic(MethodBecameNonStatic param); int **i; long j; double k; MethodBecameNonStatic* p; };"; $SOURCE1 .= " MethodBecameNonStatic MethodBecameNonStatic::becameNonStatic(MethodBecameNonStatic param) { return param; }"; $HEADER2 .= " struct $DECL_SPEC MethodBecameNonStatic { MethodBecameNonStatic becameNonStatic(MethodBecameNonStatic param); int **i; long j; double k; MethodBecameNonStatic* p; };"; $SOURCE2 .= " MethodBecameNonStatic MethodBecameNonStatic::becameNonStatic(MethodBecameNonStatic param) { return param; }"; # Parameter_Type_And_Size $HEADER1 .= " $DECL_SPEC int funcParameterTypeAndSize(int param, int other_param);"; $SOURCE1 .= " int funcParameterTypeAndSize(int param, int other_param) { return other_param; }"; $HEADER2 .= " $DECL_SPEC int funcParameterTypeAndSize(long long param, int other_param);"; $SOURCE2 .= " int funcParameterTypeAndSize(long long param, int other_param) { return other_param; }"; # Parameter_Type $HEADER1 .= " $DECL_SPEC int funcParameterType(int param, int other_param);"; $SOURCE1 .= " int funcParameterType(int param, int other_param) { return other_param; }"; $HEADER2 .= " $DECL_SPEC int funcParameterType(float param, int other_param);"; $SOURCE2 .= " int funcParameterType(float param, int other_param) { return other_param; }"; # Parameter_BaseType $HEADER1 .= " $DECL_SPEC int funcParameterBaseType(int *param);"; $SOURCE1 .= " int funcParameterBaseType(int *param) { return sizeof(*param); }"; $HEADER2 .= " $DECL_SPEC int funcParameterBaseType(long long *param);"; $SOURCE2 .= " int funcParameterBaseType(long long *param) { return sizeof(*param); }"; # Parameter_PointerLevel $HEADER1 .= " $DECL_SPEC long long funcParameterPointerLevelAndSize(long long param);"; $SOURCE1 .= " long long funcParameterPointerLevelAndSize(long long param) { return param; }"; $HEADER2 .= " $DECL_SPEC long long funcParameterPointerLevelAndSize(long long *param);"; $SOURCE2 .= " long long funcParameterPointerLevelAndSize(long long *param) { return param[5]; }"; # Parameter_PointerLevel $HEADER1 .= " $DECL_SPEC int funcParameterPointerLevel(int *param);"; $SOURCE1 .= " int funcParameterPointerLevel(int *param) { return param[5]; }"; $HEADER2 .= " $DECL_SPEC int funcParameterPointerLevel(int **param);"; $SOURCE2 .= " int funcParameterPointerLevel(int **param) { return param[5][5]; }"; # Return_Type_And_Size $HEADER1 .= " $DECL_SPEC int funcReturnTypeAndSize(int param);"; $SOURCE1 .= " int funcReturnTypeAndSize(int param) { return 0; }"; $HEADER2 .= " $DECL_SPEC long long funcReturnTypeAndSize(int param);"; $SOURCE2 .= " long long funcReturnTypeAndSize(int param) { return 0; }"; # Return_Type $HEADER1 .= " $DECL_SPEC int funcReturnType(int param);"; $SOURCE1 .= " int funcReturnType(int param) { return 0; }"; $HEADER2 .= " $DECL_SPEC float funcReturnType(int param);"; $SOURCE2 .= " float funcReturnType(int param) { return 0.7; }"; # Return_Type_Became_Void ("int" to "void") $HEADER1 .= " $DECL_SPEC int funcReturnTypeBecameVoid(int param);"; $SOURCE1 .= " int funcReturnTypeBecameVoid(int param) { return 0; }"; $HEADER2 .= " $DECL_SPEC void funcReturnTypeBecameVoid(int param);"; $SOURCE2 .= " void funcReturnTypeBecameVoid(int param) { return; }"; # Return_BaseType $HEADER1 .= " $DECL_SPEC int* funcReturnBaseType(int param);"; $SOURCE1 .= " int* funcReturnBaseType(int param) { int *x = new int[10]; return x; }"; $HEADER2 .= " $DECL_SPEC long long* funcReturnBaseType(int param);"; $SOURCE2 .= " long long* funcReturnBaseType(int param) { long long *x = new long long[10]; return x; }"; # Return_PointerLevel $HEADER1 .= " $DECL_SPEC long long funcReturnPointerLevelAndSize(int param);"; $SOURCE1 .= " long long funcReturnPointerLevelAndSize(int param) { return 0; }"; $HEADER2 .= " $DECL_SPEC long long* funcReturnPointerLevelAndSize(int param);"; $SOURCE2 .= " long long* funcReturnPointerLevelAndSize(int param) { return new long long[10]; }"; # Return_PointerLevel $HEADER1 .= " $DECL_SPEC int* funcReturnPointerLevel(int param);"; $SOURCE1 .= " int* funcReturnPointerLevel(int param) { return new int[10]; }"; $HEADER2 .= " $DECL_SPEC int** funcReturnPointerLevel(int param);"; $SOURCE2 .= " int** funcReturnPointerLevel(int param) { return new int*[10]; }"; # Size (anon type) $HEADER1 .= " typedef struct { int i; long j; double k; } AnonTypedef; $DECL_SPEC int funcAnonTypedef(AnonTypedef param);"; $SOURCE1 .= " int funcAnonTypedef(AnonTypedef param) { return 0; }"; $HEADER2 .= " typedef struct { int i; long j; double k; union { int dummy[256]; struct { char q_skiptable[256]; const char *p; int l; } p; }; } AnonTypedef; $DECL_SPEC int funcAnonTypedef(AnonTypedef param);"; $SOURCE2 .= " int funcAnonTypedef(AnonTypedef param) { return 0; }"; # Added_Field (safe: opaque) $HEADER1 .= " struct $DECL_SPEC OpaqueType { public: OpaqueType method(OpaqueType param); int i; long j; double k; OpaqueType* p; };"; $SOURCE1 .= " OpaqueType OpaqueType::method(OpaqueType param) { return param; }"; $HEADER2 .= " struct $DECL_SPEC OpaqueType { public: OpaqueType method(OpaqueType param); int i; long j; double k; OpaqueType* p; int added_member; };"; $SOURCE2 .= " OpaqueType OpaqueType::method(OpaqueType param) { return param; }"; # Added_Field (safe: internal) $HEADER1 .= " struct $DECL_SPEC InternalType { InternalType method(InternalType param); int i; long j; double k; InternalType* p; };"; $SOURCE1 .= " InternalType InternalType::method(InternalType param) { return param; }"; $HEADER2 .= " struct $DECL_SPEC InternalType { InternalType method(InternalType param); int i; long j; double k; InternalType* p; int added_member; };"; $SOURCE2 .= " InternalType InternalType::method(InternalType param) { return param; }"; # Size (unnamed struct/union fields within structs/unions) $HEADER1 .= " typedef struct { int a; struct { int u1; float u2; }; int d; } UnnamedTypeSize; $DECL_SPEC int unnamedTypeSize(UnnamedTypeSize param);"; $SOURCE1 .= " int unnamedTypeSize(UnnamedTypeSize param) { return 0; }"; $HEADER2 .= " typedef struct { int a; struct { long double u1; float u2; }; int d; } UnnamedTypeSize; $DECL_SPEC int unnamedTypeSize(UnnamedTypeSize param);"; $SOURCE2 .= " int unnamedTypeSize(UnnamedTypeSize param) { return 0; }"; # Changed_Constant $HEADER1 .= " #define PUBLIC_CONSTANT \"old_value\""; $HEADER2 .= " #define PUBLIC_CONSTANT \"new_value\""; $HEADER1 .= " #define PUBLIC_VERSION \"1.2 (3.4)\""; $HEADER2 .= " #define PUBLIC_VERSION \"1.2 (3.5)\""; $HEADER1 .= " #define PRIVATE_CONSTANT \"old_value\" #undef PRIVATE_CONSTANT"; $HEADER2 .= " #define PRIVATE_CONSTANT \"new_value\" #undef PRIVATE_CONSTANT"; # Added_Field (union) $HEADER1 .= " union UnionAddedField { int a; struct { int b; float c; }; int d; }; $DECL_SPEC int unionAddedField(UnionAddedField param);"; $SOURCE1 .= " int unionAddedField(UnionAddedField param) { return 0; }"; $HEADER2 .= " union UnionAddedField { int a; struct { long double x, y; } new_field; struct { int b; float c; }; int d; }; $DECL_SPEC int unionAddedField(UnionAddedField param);"; $SOURCE2 .= " int unionAddedField(UnionAddedField param) { return 0; }"; # Removed_Field (union) $HEADER1 .= " union UnionRemovedField { int a; struct { long double x, y; } removed_field; struct { int b; float c; }; int d; }; $DECL_SPEC int unionRemovedField(UnionRemovedField param);"; $SOURCE1 .= " int unionRemovedField(UnionRemovedField param) { return 0; }"; $HEADER2 .= " union UnionRemovedField { int a; struct { int b; float c; }; int d; }; $DECL_SPEC int unionRemovedField(UnionRemovedField param);"; $SOURCE2 .= " int unionRemovedField(UnionRemovedField param) { return 0; }"; # Added (typedef change) $HEADER1 .= " typedef float TYPEDEF_TYPE; $DECL_SPEC int parameterTypedefChange(TYPEDEF_TYPE param);"; $SOURCE1 .= " int parameterTypedefChange(TYPEDEF_TYPE param) { return 1; }"; $HEADER2 .= " typedef int TYPEDEF_TYPE; $DECL_SPEC int parameterTypedefChange(TYPEDEF_TYPE param);"; $SOURCE2 .= " int parameterTypedefChange(TYPEDEF_TYPE param) { return 1; }"; # Parameter_Default_Value_Changed (safe) # Converted from void* to const char* $HEADER1 .= " $DECL_SPEC int paramDefaultValue_Converted(const char* arg = 0); "; $SOURCE1 .= " int paramDefaultValue_Converted(const char* arg) { return 0; }"; $HEADER2 .= " $DECL_SPEC int paramDefaultValue_Converted(const char* arg = (const char*)((void*) 0)); "; $SOURCE2 .= " int paramDefaultValue_Converted(const char* arg) { return 0; }"; # Parameter_Default_Value_Changed # Integer $HEADER1 .= " $DECL_SPEC int paramDefaultValueChanged_Integer(int param = 0xf00f); "; $SOURCE1 .= " int paramDefaultValueChanged_Integer(int param) { return param; }"; $HEADER2 .= " $DECL_SPEC int paramDefaultValueChanged_Integer(int param = 0xf00b); "; $SOURCE2 .= " int paramDefaultValueChanged_Integer(int param) { return param; }"; # Parameter_Default_Value_Changed # String $HEADER1 .= " $DECL_SPEC int paramDefaultValueChanged_String(char const* param = \" str 1 \"); "; $SOURCE1 .= " int paramDefaultValueChanged_String(char const* param) { return 0; }"; $HEADER2 .= " $DECL_SPEC int paramDefaultValueChanged_String(char const* param = \" str 2 \"); "; $SOURCE2 .= " int paramDefaultValueChanged_String(char const* param) { return 0; }"; # Parameter_Default_Value_Changed # Character $HEADER1 .= " $DECL_SPEC int paramDefaultValueChanged_Char(char param = \'A\'); "; $SOURCE1 .= " int paramDefaultValueChanged_Char(char param) { return 0; }"; $HEADER2 .= " $DECL_SPEC int paramDefaultValueChanged_Char(char param = \'B\'); "; $SOURCE2 .= " int paramDefaultValueChanged_Char(char param) { return 0; }"; # Parameter_Default_Value_Changed # Bool $HEADER1 .= " $DECL_SPEC int paramDefaultValueChanged_Bool(bool param = true); "; $SOURCE1 .= " int paramDefaultValueChanged_Bool(bool param) { return 0; }"; $HEADER2 .= " $DECL_SPEC int paramDefaultValueChanged_Bool(bool param = false); "; $SOURCE2 .= " int paramDefaultValueChanged_Bool(bool param) { return 0; }"; # Parameter_Default_Value_Removed $HEADER1 .= " $DECL_SPEC int parameterDefaultValueRemoved(int param = 15); "; $SOURCE1 .= " int parameterDefaultValueRemoved(int param) { return param; }"; $HEADER2 .= " $DECL_SPEC int parameterDefaultValueRemoved(int param);"; $SOURCE2 .= " int parameterDefaultValueRemoved(int param) { return param; }"; # Parameter_Default_Value_Added $HEADER1 .= " $DECL_SPEC int parameterDefaultValueAdded(int param); "; $SOURCE1 .= " int parameterDefaultValueAdded(int param) { return param; }"; $HEADER2 .= " $DECL_SPEC int parameterDefaultValueAdded(int param = 15);"; $SOURCE2 .= " int parameterDefaultValueAdded(int param) { return param; }"; # Field_Type (typedefs in member type) $HEADER1 .= " typedef float TYPEDEF_TYPE_2; struct $DECL_SPEC FieldTypedefChange{ public: TYPEDEF_TYPE_2 m; TYPEDEF_TYPE_2 n; }; $DECL_SPEC int fieldTypedefChange(FieldTypedefChange param);"; $SOURCE1 .= " int fieldTypedefChange(FieldTypedefChange param) { return 1; }"; $HEADER2 .= " typedef int TYPEDEF_TYPE_2; struct $DECL_SPEC FieldTypedefChange{ public: TYPEDEF_TYPE_2 m; TYPEDEF_TYPE_2 n; }; $DECL_SPEC int fieldTypedefChange(FieldTypedefChange param);"; $SOURCE2 .= " int fieldTypedefChange(FieldTypedefChange param) { return 1; }"; # Callback (testCallback symbol should be affected # instead of callback1 and callback2) $HEADER1 .= " class $DECL_SPEC Callback { public: virtual int callback1(int x, int y)=0; virtual int callback2(int x, int y)=0; }; $DECL_SPEC int testCallback(Callback* p);"; $SOURCE1 .= " int testCallback(Callback* p) { p->callback2(1, 2); return 0; }"; $HEADER2 .= " class $DECL_SPEC Callback { public: virtual int callback1(int x, int y)=0; virtual int added_callback(int x, int y)=0; virtual int callback2(int x, int y)=0; }; $DECL_SPEC int testCallback(Callback* p);"; $SOURCE2 .= " int testCallback(Callback* p) { p->callback2(1, 2); return 0; }"; # End namespace $HEADER1 .= "\n}\n"; $HEADER2 .= "\n}\n"; $SOURCE1 .= "\n}\n"; $SOURCE2 .= "\n}\n"; runTests("libsample_cpp", "C++", $HEADER1, $SOURCE1, $HEADER2, $SOURCE2, "TestNS::OpaqueType", "_ZN6TestNS12InternalType6methodES0_"); } sub testC() { printMsg("INFO", "\nverifying detectable C library changes"); my ($HEADER1, $SOURCE1, $HEADER2, $SOURCE2) = (); my $DECL_SPEC = ($OSgroup eq "windows")?"__declspec( dllexport )":""; my $EXTERN = ($OSgroup eq "windows")?"extern ":""; # add "extern" for CL compiler # Typedef to function $HEADER1 .= " typedef int(TypedefToFunction)(int pX); $DECL_SPEC int typedefToFunction(TypedefToFunction* p);"; $SOURCE1 .= " int typedefToFunction(TypedefToFunction* p) { return 0; }"; $HEADER2 .= " typedef int(TypedefToFunction)(int pX, int pY); $DECL_SPEC int typedefToFunction(TypedefToFunction* p);"; $SOURCE2 .= " int typedefToFunction(TypedefToFunction* p) { return 0; }"; # Used_Reserved $HEADER1 .= " typedef struct { int f; void* reserved0; void* reserved1; } UsedReserved; $DECL_SPEC int usedReserved(UsedReserved p);"; $SOURCE1 .= " int usedReserved(UsedReserved p) { return 0; }"; $HEADER2 .= " typedef struct { int f; void* f0; void* f1; } UsedReserved; $DECL_SPEC int usedReserved(UsedReserved p);"; $SOURCE2 .= " int usedReserved(UsedReserved p) { return 0; }"; # Parameter_Type_And_Register $HEADER1 .= " typedef struct { int a[4]; } ARRAY; $DECL_SPEC void callConv5 (ARRAY i, int j);"; $SOURCE1 .= " void callConv5 (ARRAY i, int j) { }"; $HEADER2 .= " typedef struct { int a[4]; } ARRAY; $DECL_SPEC void callConv5 (ARRAY i, double j);"; $SOURCE2 .= " void callConv5 (ARRAY i, double j) { }"; # Parameter_Type_And_Register $HEADER1 .= " typedef union { int a; double b; } UNION; $DECL_SPEC void callConv4 (UNION i, int j);"; $SOURCE1 .= " void callConv4 (UNION i, int j) { }"; $HEADER2 .= " typedef union { int a; double b; } UNION; $DECL_SPEC void callConv4 (UNION i, double j);"; $SOURCE2 .= " void callConv4 (UNION i, double j) { }"; # Parameter_Type_And_Register $HEADER1 .= " typedef struct { long a:4; long b:16; } POD2; $DECL_SPEC void callConv3 (POD2 i, int j);"; $SOURCE1 .= " void callConv3 (POD2 i, int j) { }"; $HEADER2 .= " typedef struct { long a:4; long b:16; } POD2; $DECL_SPEC void callConv3 (POD2 i, double j);"; $SOURCE2 .= " void callConv3 (POD2 i, double j) { }"; # Parameter_Type_And_Register $HEADER1 .= " typedef struct { short s:9; int j:9; char c; short t:9; short u:9; char d; } POD; $DECL_SPEC void callConv2 (POD i, int j);"; $SOURCE1 .= " void callConv2 (POD i, int j) { }"; $HEADER2 .= " typedef struct { short s:9; int j:9; char c; short t:9; short u:9; char d; } POD; $DECL_SPEC void callConv2 (POD i, double j);"; $SOURCE2 .= " void callConv2 (POD i, double j) { }"; # Parameter_Type_And_Register $HEADER1 .= " typedef struct { int a, b; double d; } POD1; $DECL_SPEC void callConv (int e, int f, POD1 s, int g, int h, long double ld, double m, double n, int i, int j, int k);"; $SOURCE1 .= " void callConv(int e, int f, POD1 s, int g, int h, long double ld, double m, double n, int i, int j, int k) { }"; $HEADER2 .= " typedef struct { int a, b; double d; } POD1; $DECL_SPEC void callConv (int e, int f, POD1 s, int g, int h, long double ld, double m, double n, int i, int j, double k);"; $SOURCE2 .= " void callConv(int e, int f, POD1 s, int g, int h, long double ld, double m, double n, int i, int j, double k) { }"; # Parameter_Type (int to "int const") $HEADER1 .= " $DECL_SPEC void parameterBecameConstInt(int arg);"; $SOURCE1 .= " void parameterBecameConstInt(int arg) { }"; $HEADER2 .= " $DECL_SPEC void parameterBecameConstInt(const int arg);"; $SOURCE2 .= " void parameterBecameConstInt(const int arg) { }"; # Parameter_Type ("int const" to int) $HEADER1 .= " $DECL_SPEC void parameterBecameNonConstInt(const int arg);"; $SOURCE1 .= " void parameterBecameNonConstInt(const int arg) { }"; $HEADER2 .= " $DECL_SPEC void parameterBecameNonConstInt(int arg);"; $SOURCE2 .= " void parameterBecameNonConstInt(int arg) { }"; # Parameter_Became_Register $HEADER1 .= " $DECL_SPEC void parameterBecameRegister(int arg);"; $SOURCE1 .= " void parameterBecameRegister(int arg) { }"; $HEADER2 .= " $DECL_SPEC void parameterBecameRegister(register int arg);"; $SOURCE2 .= " void parameterBecameRegister(register int arg) { }"; # Return_Type_Became_Const $HEADER1 .= " $DECL_SPEC char* returnTypeBecameConst(int param);"; $SOURCE1 .= " char* returnTypeBecameConst(int param) { return (char*)malloc(256); }"; $HEADER2 .= " $DECL_SPEC const char* returnTypeBecameConst(int param);"; $SOURCE2 .= " const char* returnTypeBecameConst(int param) { return \"abc\"; }"; # Return_Type_Became_Const (2) $HEADER1 .= " $DECL_SPEC char* returnTypeBecameConst2(int param);"; $SOURCE1 .= " char* returnTypeBecameConst2(int param) { return (char*)malloc(256); }"; $HEADER2 .= " $DECL_SPEC char*const returnTypeBecameConst2(int param);"; $SOURCE2 .= " char*const returnTypeBecameConst2(int param) { return (char*const)malloc(256); }"; # Return_Type_Became_Const (3) $HEADER1 .= " $DECL_SPEC char* returnTypeBecameConst3(int param);"; $SOURCE1 .= " char* returnTypeBecameConst3(int param) { return (char*)malloc(256); }"; $HEADER2 .= " $DECL_SPEC char const*const returnTypeBecameConst3(int param);"; $SOURCE2 .= " char const*const returnTypeBecameConst3(int param) { return (char const*const)malloc(256); }"; # Return_Type_Became_Volatile $HEADER1 .= " $DECL_SPEC char* returnTypeBecameVolatile(int param);"; $SOURCE1 .= " char* returnTypeBecameVolatile(int param) { return (char*)malloc(256); }"; $HEADER2 .= " $DECL_SPEC volatile char* returnTypeBecameVolatile(int param);"; $SOURCE2 .= " volatile char* returnTypeBecameVolatile(int param) { return \"abc\"; }"; # Added_Enum_Member $HEADER1 .= " enum AddedEnumMember { OldMember }; $DECL_SPEC int addedEnumMember(enum AddedEnumMember param);"; $SOURCE1 .= " int addedEnumMember(enum AddedEnumMember param) { return 0; }"; $HEADER2 .= " enum AddedEnumMember { OldMember, NewMember }; $DECL_SPEC int addedEnumMember(enum AddedEnumMember param);"; $SOURCE2 .= " int addedEnumMember(enum AddedEnumMember param) { return 0; }"; # Parameter_Type (Array) $HEADER1 .= " $DECL_SPEC int arrayParameterType(int param[5]);"; $SOURCE1 .= " int arrayParameterType(int param[5]) { return 0; }"; $HEADER2 .= " $DECL_SPEC int arrayParameterType(int param[7]);"; $SOURCE2 .= " int arrayParameterType(int param[7]) { return 0; }"; # Field_Type $HEADER1 .= " struct ArrayFieldType { int f; int i[1]; }; $DECL_SPEC int arrayFieldType(struct ArrayFieldType param);"; $SOURCE1 .= " int arrayFieldType(struct ArrayFieldType param) { return param.i[0]; }"; $HEADER2 .= " struct ArrayFieldType { int f; int i[]; }; $DECL_SPEC int arrayFieldType(struct ArrayFieldType param);"; $SOURCE2 .= " int arrayFieldType(struct ArrayFieldType param) { return param.i[0]; }"; # Field_Type_And_Size (Array) $HEADER1 .= " struct ArrayFieldSize { int i[5]; }; $DECL_SPEC int arrayFieldSize(struct ArrayFieldSize param);"; $SOURCE1 .= " int arrayFieldSize(struct ArrayFieldSize param) { return 0; }"; $HEADER2 .= " struct ArrayFieldSize { int i[7]; }; $DECL_SPEC int arrayFieldSize(struct ArrayFieldSize param);"; $SOURCE2 .= " int arrayFieldSize(struct ArrayFieldSize param) { return 0; }"; # Parameter_Became_Non_VaList $HEADER1 .= " $DECL_SPEC int parameterNonVaList(int param, ...);"; $SOURCE1 .= " int parameterNonVaList(int param, ...) { return param; }"; $HEADER2 .= " $DECL_SPEC int parameterNonVaList(int param1, int param2);"; $SOURCE2 .= " int parameterNonVaList(int param1, int param2) { return param1; }"; # Parameter_Became_VaList $HEADER1 .= " $DECL_SPEC int parameterVaList(int param1, int param2);"; $SOURCE1 .= " int parameterVaList(int param1, int param2) { return param1; }"; $HEADER2 .= " $DECL_SPEC int parameterVaList(int param, ...);"; $SOURCE2 .= " int parameterVaList(int param, ...) { return param; }"; # Field_Type_And_Size $HEADER1 .= " struct FieldSizePadded { int i; char changed_field; // padding (3 bytes) int j; }; $DECL_SPEC int fieldSizePadded(struct FieldSizePadded param);"; $SOURCE1 .= " int fieldSizePadded(struct FieldSizePadded param) { return 0; }"; $HEADER2 .= " struct FieldSizePadded { int i; int changed_field; int j; }; $DECL_SPEC int fieldSizePadded(struct FieldSizePadded param);"; $SOURCE2 .= " int fieldSizePadded(struct FieldSizePadded param) { return 0; }"; # Parameter_Type_Format $HEADER1 .= " struct DType1 { int i; double j[7]; }; $DECL_SPEC int parameterTypeFormat(struct DType1 param);"; $SOURCE1 .= " int parameterTypeFormat(struct DType1 param) { return 0; }"; $HEADER2 .= " struct DType2 { double i[7]; int j; }; $DECL_SPEC int parameterTypeFormat(struct DType2 param);"; $SOURCE2 .= " int parameterTypeFormat(struct DType2 param) { return 0; }"; # Field_Type_Format $HEADER1 .= " struct FieldTypeFormat { int i; struct DType1 j; }; $DECL_SPEC int fieldTypeFormat(struct FieldTypeFormat param);"; $SOURCE1 .= " int fieldTypeFormat(struct FieldTypeFormat param) { return 0; }"; $HEADER2 .= " struct FieldTypeFormat { int i; struct DType2 j; }; $DECL_SPEC int fieldTypeFormat(struct FieldTypeFormat param);"; $SOURCE2 .= " int fieldTypeFormat(struct FieldTypeFormat param) { return 0; }"; # Parameter_Type_Format (struct to union) $HEADER1 .= " struct DType { int i; double j; }; $DECL_SPEC int parameterTypeFormat2(struct DType param);"; $SOURCE1 .= " int parameterTypeFormat2(struct DType param) { return 0; }"; $HEADER2 .= " union DType { int i; long double j; }; $DECL_SPEC int parameterTypeFormat2(union DType param);"; $SOURCE2 .= " int parameterTypeFormat2(union DType param) { return 0; }"; # Global_Data_Size $HEADER1 .= " struct GlobalDataSize { int a; }; $EXTERN $DECL_SPEC struct GlobalDataSize globalDataSize;"; $HEADER2 .= " struct GlobalDataSize { int a, b; }; $EXTERN $DECL_SPEC struct GlobalDataSize globalDataSize;"; # Global_Data_Type $HEADER1 .= " $EXTERN $DECL_SPEC int globalDataType;"; $HEADER2 .= " $EXTERN $DECL_SPEC float globalDataType;"; # Global_Data_Type_And_Size $HEADER1 .= " $EXTERN $DECL_SPEC int globalDataTypeAndSize;"; $HEADER2 .= " $EXTERN $DECL_SPEC short globalDataTypeAndSize;"; # Global_Data_Value_Changed # Integer $HEADER1 .= " $EXTERN $DECL_SPEC const int globalDataValue_Integer = 10;"; $HEADER2 .= " $EXTERN $DECL_SPEC const int globalDataValue_Integer = 15;"; # Global_Data_Value_Changed # Character $HEADER1 .= " $EXTERN $DECL_SPEC const char globalDataValue_Char = \'o\';"; $HEADER2 .= " $EXTERN $DECL_SPEC const char globalDataValue_Char = \'N\';"; # Global_Data_Became_Non_Const $HEADER1 .= " $EXTERN $DECL_SPEC const int globalDataBecameNonConst = 10;"; $HEADER2 .= " extern $DECL_SPEC int globalDataBecameNonConst;"; $SOURCE2 .= " int globalDataBecameNonConst = 15;"; # Global_Data_Became_Non_Const # Typedef $HEADER1 .= " typedef const int CONST_INT; $EXTERN $DECL_SPEC CONST_INT globalDataBecameNonConst_Typedef = 10;"; $HEADER2 .= " extern $DECL_SPEC int globalDataBecameNonConst_Typedef;"; $SOURCE2 .= " int globalDataBecameNonConst_Typedef = 15;"; # Global_Data_Became_Const $HEADER1 .= " extern $DECL_SPEC int globalDataBecameConst;"; $SOURCE1 .= " int globalDataBecameConst = 10;"; $HEADER2 .= " $EXTERN $DECL_SPEC const int globalDataBecameConst = 15;"; # Global_Data_Became_Non_Const $HEADER1 .= " struct GlobalDataType{int a;int b;struct GlobalDataType* p;}; $EXTERN $DECL_SPEC const struct GlobalDataType globalStructDataBecameNonConst = { 1, 2, (struct GlobalDataType*)0 };"; $HEADER2 .= " struct GlobalDataType{int a;int b;struct GlobalDataType* p;}; $EXTERN $DECL_SPEC struct GlobalDataType globalStructDataBecameNonConst = { 1, 2, (struct GlobalDataType*)0 };"; # Removed_Parameter $HEADER1 .= " $DECL_SPEC int removedParameter(int param, int removed_param);"; $SOURCE1 .= " int removedParameter(int param, int removed_param) { return 0; }"; $HEADER2 .= " $DECL_SPEC int removedParameter(int param);"; $SOURCE2 .= " int removedParameter(int param) { return 0; }"; # Added_Parameter $HEADER1 .= " $DECL_SPEC int addedParameter(int param);"; $SOURCE1 .= " int addedParameter(int param) { return param; }"; $HEADER2 .= " $DECL_SPEC int addedParameter(int param, int added_param, int added_param2);"; $SOURCE2 .= " int addedParameter(int param, int added_param, int added_param2) { return added_param2; }"; # Added_Interface (typedef to funcptr parameter) $HEADER2 .= " typedef int (*FUNCPTR_TYPE)(int a, int b); $DECL_SPEC int addedFunc(FUNCPTR_TYPE*const** f);"; $SOURCE2 .= " int addedFunc(FUNCPTR_TYPE*const** f) { return 0; }"; # Added_Interface (funcptr parameter) $HEADER2 .= " $DECL_SPEC int addedFunc2(int(*func)(int, int));"; $SOURCE2 .= " int addedFunc2(int(*func)(int, int)) { return 0; }"; # Added_Interface (no limited parameters) $HEADER2 .= " $DECL_SPEC int addedFunc3(float p1, ...);"; $SOURCE2 .= " int addedFunc3(float p1, ...) { return 0; }"; # Size $HEADER1 .= " struct TypeSize { long long i[5]; long j; double k; struct TypeSize* p; }; $DECL_SPEC int testSize(struct TypeSize param, int param_2);"; $SOURCE1 .= " int testSize(struct TypeSize param, int param_2) { return param_2; }"; $HEADER2 .= " struct TypeSize { long long i[15]; long long j; double k; struct TypeSize* p; }; $DECL_SPEC int testSize(struct TypeSize param, int param_2);"; $SOURCE2 .= " int testSize(struct TypeSize param, int param_2) { return param_2; }"; # Added_Field_And_Size $HEADER1 .= " struct AddedFieldAndSize { int i; long j; double k; struct AddedFieldAndSize* p; }; $DECL_SPEC int addedFieldAndSize(struct AddedFieldAndSize param, int param_2);"; $SOURCE1 .= " int addedFieldAndSize(struct AddedFieldAndSize param, int param_2) { return param_2; }"; $HEADER2 .= " struct AddedFieldAndSize { int i; long j; double k; struct AddedFieldAndSize* p; int added_member1; int added_member2; }; $DECL_SPEC int addedFieldAndSize(struct AddedFieldAndSize param, int param_2);"; $SOURCE2 .= " int addedFieldAndSize(struct AddedFieldAndSize param, int param_2) { return param_2; }"; # Added_Middle_Field_And_Size $HEADER1 .= " struct AddedMiddleFieldAndSize { int i; long j; double k; struct AddedMiddleFieldAndSize* p; }; $DECL_SPEC int addedMiddleFieldAndSize(struct AddedMiddleFieldAndSize param, int param_2);"; $SOURCE1 .= " int addedMiddleFieldAndSize(struct AddedMiddleFieldAndSize param, int param_2) { return param_2; }"; $HEADER2 .= " struct AddedMiddleFieldAndSize { int i; int added_middle_member; long j; double k; struct AddedMiddleFieldAndSize* p; }; $DECL_SPEC int addedMiddleFieldAndSize(struct AddedMiddleFieldAndSize param, int param_2);"; $SOURCE2 .= " int addedMiddleFieldAndSize(struct AddedMiddleFieldAndSize param, int param_2) { return param_2; }"; # Added_Middle_Field $HEADER1 .= " struct AddedMiddleField { unsigned char field1; unsigned short field2; }; $DECL_SPEC int addedMiddleField(struct AddedMiddleField param, int param_2);"; $SOURCE1 .= " int addedMiddleField(struct AddedMiddleField param, int param_2) { return param_2; }"; $HEADER2 .= " struct AddedMiddleField { unsigned char field1; unsigned char added_field; unsigned short field2; }; $DECL_SPEC int addedMiddleField(struct AddedMiddleField param, int param_2);"; $SOURCE2 .= " int addedMiddleField(struct AddedMiddleField param, int param_2) { return param_2; }"; # Renamed_Field $HEADER1 .= " struct RenamedField { long i; long j; double k; struct RenamedField* p; }; $DECL_SPEC int renamedField(struct RenamedField param, int param_2);"; $SOURCE1 .= " int renamedField(struct RenamedField param, int param_2) { return param_2; }"; $HEADER2 .= " struct RenamedField { long renamed_member; long j; double k; struct RenamedField* p; }; $DECL_SPEC int renamedField(struct RenamedField param, int param_2);"; $SOURCE2 .= " int renamedField(struct RenamedField param, int param_2) { return param_2; }"; # Renamed_Field $HEADER1 .= " union RenamedUnionField { int renamed_from; double j; }; $DECL_SPEC int renamedUnionField(union RenamedUnionField param);"; $SOURCE1 .= " int renamedUnionField(union RenamedUnionField param) { return 0; }"; $HEADER2 .= " union RenamedUnionField { int renamed_to; double j; }; $DECL_SPEC int renamedUnionField(union RenamedUnionField param);"; $SOURCE2 .= " int renamedUnionField(union RenamedUnionField param) { return 0; }"; # Removed_Field_And_Size $HEADER1 .= " struct RemovedFieldAndSize { int i; long j; double k; struct RemovedFieldAndSize* p; int removed_member1; int removed_member2; }; $DECL_SPEC int removedFieldAndSize(struct RemovedFieldAndSize param, int param_2);"; $SOURCE1 .= " int removedFieldAndSize(struct RemovedFieldAndSize param, int param_2) { return param_2; }"; $HEADER2 .= " struct RemovedFieldAndSize { int i; long j; double k; struct RemovedFieldAndSize* p; }; $DECL_SPEC int removedFieldAndSize(struct RemovedFieldAndSize param, int param_2);"; $SOURCE2 .= " int removedFieldAndSize(struct RemovedFieldAndSize param, int param_2) { return param_2; }"; # Removed_Middle_Field $HEADER1 .= " struct RemovedMiddleField { int i; int removed_middle_member; long j; double k; struct RemovedMiddleField* p; }; $DECL_SPEC int removedMiddleField(struct RemovedMiddleField param, int param_2);"; $SOURCE1 .= " int removedMiddleField(struct RemovedMiddleField param, int param_2) { return param_2; }"; $HEADER2 .= " struct RemovedMiddleField { int i; long j; double k; struct RemovedMiddleField* p; }; $DECL_SPEC int removedMiddleField(struct RemovedMiddleField param, int param_2);"; $SOURCE2 .= " int removedMiddleField(struct RemovedMiddleField param, int param_2) { return param_2; }"; # Enum_Member_Value $HEADER1 .= " enum EnumMemberValue { MEMBER1=1, MEMBER2=2 }; $DECL_SPEC int enumMemberValue(enum EnumMemberValue param);"; $SOURCE1 .= " int enumMemberValue(enum EnumMemberValue param) { return 0; }"; $HEADER2 .= " enum EnumMemberValue { MEMBER1=2, MEMBER2=1 }; $DECL_SPEC int enumMemberValue(enum EnumMemberValue param);"; $SOURCE2 .= " int enumMemberValue(enum EnumMemberValue param) { return 0; }"; # Enum_Member_Removed $HEADER1 .= " enum EnumMemberRemoved { MEMBER=1, MEMBER_REMOVED=2 }; $DECL_SPEC int enumMemberRemoved(enum EnumMemberRemoved param);"; $SOURCE1 .= " int enumMemberRemoved(enum EnumMemberRemoved param) { return 0; }"; $HEADER2 .= " enum EnumMemberRemoved { MEMBER=1 }; $DECL_SPEC int enumMemberRemoved(enum EnumMemberRemoved param);"; $SOURCE2 .= " int enumMemberRemoved(enum EnumMemberRemoved param) { return 0; }"; # Enum_Member_Removed (middle) $HEADER1 .= " enum EnumMiddleMemberRemoved { MEM_REMOVED, MEM1, MEM2 }; $DECL_SPEC int enumMiddleMemberRemoved(enum EnumMiddleMemberRemoved param);"; $SOURCE1 .= " int enumMiddleMemberRemoved(enum EnumMiddleMemberRemoved param) { return 0; }"; $HEADER2 .= " enum EnumMiddleMemberRemoved { MEM1, MEM2 }; $DECL_SPEC int enumMiddleMemberRemoved(enum EnumMiddleMemberRemoved param);"; $SOURCE2 .= " int enumMiddleMemberRemoved(enum EnumMiddleMemberRemoved param) { return 0; }"; # Enum_Member_Name $HEADER1 .= " enum EnumMemberName { BRANCH1=1, BRANCH2=2 }; $DECL_SPEC int enumMemberName(enum EnumMemberName param);"; $SOURCE1 .= " int enumMemberName(enum EnumMemberName param) { return 0; }"; $HEADER2 .= " enum EnumMemberName { BRANCH_FIRST=1, BRANCH_SECOND=2 }; $DECL_SPEC int enumMemberName(enum EnumMemberName param);"; $SOURCE2 .= " int enumMemberName(enum EnumMemberName param) { return 0; }"; # Field_Type_And_Size $HEADER1 .= " struct FieldTypeAndSize { int i; long j; double k; struct FieldTypeAndSize* p; }; $DECL_SPEC int fieldTypeAndSize(struct FieldTypeAndSize param, int param_2);"; $SOURCE1 .= " int fieldTypeAndSize(struct FieldTypeAndSize param, int param_2) { return param_2; }"; $HEADER2 .= " struct FieldTypeAndSize { int i; long long j; double k; struct FieldTypeAndSize* p; }; $DECL_SPEC int fieldTypeAndSize(struct FieldTypeAndSize param, int param_2);"; $SOURCE2 .= " int fieldTypeAndSize(struct FieldTypeAndSize param, int param_2) { return param_2; }"; # Field_Type $HEADER1 .= " struct FieldType { int i; long j; double k; struct FieldType* p; }; $DECL_SPEC int fieldType(struct FieldType param, int param_2);"; $SOURCE1 .= " int fieldType(struct FieldType param, int param_2) { return param_2; }"; $HEADER2 .= " struct FieldType { float i; long j; double k; struct FieldType* p; }; $DECL_SPEC int fieldType(struct FieldType param, int param_2);"; $SOURCE2 .= " int fieldType(struct FieldType param, int param_2) { return param_2; }"; # Field_BaseType $HEADER1 .= " struct FieldBaseType { int i; long *j; double k; struct FieldBaseType* p; }; $DECL_SPEC int fieldBaseType(struct FieldBaseType param, int param_2);"; $SOURCE1 .= " int fieldBaseType(struct FieldBaseType param, int param_2) { return param_2; }"; $HEADER2 .= " struct FieldBaseType { int i; long long *j; double k; struct FieldBaseType* p; }; $DECL_SPEC int fieldBaseType(struct FieldBaseType param, int param_2);"; $SOURCE2 .= " int fieldBaseType(struct FieldBaseType param, int param_2) { return param_2; }"; # Field_PointerLevel (and Size) $HEADER1 .= " struct FieldPointerLevelAndSize { int i; long long j; double k; struct FieldPointerLevelAndSize* p; }; $DECL_SPEC int fieldPointerLevelAndSize(struct FieldPointerLevelAndSize param, int param_2);"; $SOURCE1 .= " int fieldPointerLevelAndSize(struct FieldPointerLevelAndSize param, int param_2) { return param_2; }"; $HEADER2 .= " struct FieldPointerLevelAndSize { int i; long long *j; double k; struct FieldPointerLevelAndSize* p; }; $DECL_SPEC int fieldPointerLevelAndSize(struct FieldPointerLevelAndSize param, int param_2);"; $SOURCE2 .= " int fieldPointerLevelAndSize(struct FieldPointerLevelAndSize param, int param_2) { return param_2; }"; # Field_PointerLevel $HEADER1 .= " struct FieldPointerLevel { int i; long *j; double k; struct FieldPointerLevel* p; }; $DECL_SPEC int fieldPointerLevel(struct FieldPointerLevel param, int param_2);"; $SOURCE1 .= " int fieldPointerLevel(struct FieldPointerLevel param, int param_2) { return param_2; }"; $HEADER2 .= " struct FieldPointerLevel { int i; long **j; double k; struct FieldPointerLevel* p; }; $DECL_SPEC int fieldPointerLevel(struct FieldPointerLevel param, int param_2);"; $SOURCE2 .= " int fieldPointerLevel(struct FieldPointerLevel param, int param_2) { return param_2; }"; # Added_Interface $HEADER2 .= " $DECL_SPEC int addedFunc4(int param);"; $SOURCE2 .= " int addedFunc4(int param) { return param; }"; # Removed_Interface $HEADER1 .= " $DECL_SPEC int removedFunc(int param);"; $SOURCE1 .= " int removedFunc(int param) { return param; }"; # Parameter_Type_And_Size $HEADER1 .= " $DECL_SPEC int parameterTypeAndSize(int param, int other_param);"; $SOURCE1 .= " int parameterTypeAndSize(int param, int other_param) { return other_param; }"; $HEADER2 .= " $DECL_SPEC int parameterTypeAndSize(long long param, int other_param);"; $SOURCE2 .= " int parameterTypeAndSize(long long param, int other_param) { return other_param; }"; # Parameter_Type_And_Size + Parameter_Became_Non_Const $HEADER1 .= " $DECL_SPEC int parameterTypeAndSizeBecameNonConst(int* const param, int other_param);"; $SOURCE1 .= " int parameterTypeAndSizeBecameNonConst(int* const param, int other_param) { return other_param; }"; $HEADER2 .= " $DECL_SPEC int parameterTypeAndSizeBecameNonConst(long double param, int other_param);"; $SOURCE2 .= " int parameterTypeAndSizeBecameNonConst(long double param, int other_param) { return other_param; }"; # Parameter_Type_And_Size (test calling conventions) $HEADER1 .= " $DECL_SPEC int parameterCallingConvention(int p1, int p2, int p3);"; $SOURCE1 .= " int parameterCallingConvention(int p1, int p2, int p3) { return 0; }"; $HEADER2 .= " $DECL_SPEC float parameterCallingConvention(char p1, int p2, int p3);"; $SOURCE2 .= " float parameterCallingConvention(char p1, int p2, int p3) { return 7.0f; }"; # Parameter_Type $HEADER1 .= " $DECL_SPEC int parameterType(int param, int other_param);"; $SOURCE1 .= " int parameterType(int param, int other_param) { return other_param; }"; $HEADER2 .= " $DECL_SPEC int parameterType(float param, int other_param);"; $SOURCE2 .= " int parameterType(float param, int other_param) { return other_param; }"; # Parameter_Became_Non_Const $HEADER1 .= " $DECL_SPEC int parameterBecameNonConst(int const* param);"; $SOURCE1 .= " int parameterBecameNonConst(int const* param) { return *param; }"; $HEADER2 .= " $DECL_SPEC int parameterBecameNonConst(int* param);"; $SOURCE2 .= " int parameterBecameNonConst(int* param) { *param=10; return *param; }"; # Parameter_Became_Non_Const + Parameter_Became_Non_Volatile $HEADER1 .= " $DECL_SPEC int parameterBecameNonConstNonVolatile(int const volatile* param);"; $SOURCE1 .= " int parameterBecameNonConstNonVolatile(int const volatile* param) { return *param; }"; $HEADER2 .= " $DECL_SPEC int parameterBecameNonConstNonVolatile(int* param);"; $SOURCE2 .= " int parameterBecameNonConstNonVolatile(int* param) { *param=10; return *param; }"; # Parameter_BaseType (Typedef) $HEADER1 .= " typedef int* PARAM_TYPEDEF; $DECL_SPEC int parameterBaseTypedefChange(PARAM_TYPEDEF param);"; $SOURCE1 .= " int parameterBaseTypedefChange(PARAM_TYPEDEF param) { return 0; }"; $HEADER2 .= " typedef const int* PARAM_TYPEDEF; $DECL_SPEC int parameterBaseTypedefChange(PARAM_TYPEDEF param);"; $SOURCE2 .= " int parameterBaseTypedefChange(PARAM_TYPEDEF param) { return 0; }"; # Parameter_BaseType $HEADER1 .= " $DECL_SPEC int parameterBaseTypeChange(int *param);"; $SOURCE1 .= " int parameterBaseTypeChange(int *param) { return sizeof(*param); }"; $HEADER2 .= " $DECL_SPEC int parameterBaseTypeChange(long long *param);"; $SOURCE2 .= " int parameterBaseTypeChange(long long *param) { return sizeof(*param); }"; # Parameter_PointerLevel $HEADER1 .= " $DECL_SPEC long long parameterPointerLevelAndSize(long long param);"; $SOURCE1 .= " long long parameterPointerLevelAndSize(long long param) { return param; }"; $HEADER2 .= " $DECL_SPEC long long parameterPointerLevelAndSize(long long *param);"; $SOURCE2 .= " long long parameterPointerLevelAndSize(long long *param) { return param[5]; }"; # Parameter_PointerLevel $HEADER1 .= " $DECL_SPEC int parameterPointerLevel(int *param);"; $SOURCE1 .= " int parameterPointerLevel(int *param) { return param[5]; }"; $HEADER2 .= " $DECL_SPEC int parameterPointerLevel(int **param);"; $SOURCE2 .= " int parameterPointerLevel(int **param) { return param[5][5]; }"; # Return_Type_And_Size $HEADER1 .= " $DECL_SPEC int returnTypeAndSize(int param);"; $SOURCE1 .= " int returnTypeAndSize(int param) { return 0; }"; $HEADER2 .= " $DECL_SPEC long long returnTypeAndSize(int param);"; $SOURCE2 .= " long long returnTypeAndSize(int param) { return 0; }"; # Return_Type $HEADER1 .= " $DECL_SPEC int returnType(int param);"; $SOURCE1 .= " int returnType(int param) { return 1; }"; $HEADER2 .= " $DECL_SPEC float returnType(int param);"; $SOURCE2 .= " float returnType(int param) { return 1; }"; # Return_Type_Became_Void ("int" to "void") $HEADER1 .= " $DECL_SPEC int returnTypeChangeToVoid(int param);"; $SOURCE1 .= " int returnTypeChangeToVoid(int param) { return 0; }"; $HEADER2 .= " $DECL_SPEC void returnTypeChangeToVoid(int param);"; $SOURCE2 .= " void returnTypeChangeToVoid(int param) { return; }"; # Return_Type ("struct" to "void*") $HEADER1 .= " struct SomeStruct { int a; double b, c, d; }; $DECL_SPEC struct SomeStruct* returnTypeChangeToVoidPtr(int param);"; $SOURCE1 .= " struct SomeStruct* returnTypeChangeToVoidPtr(int param) { return (struct SomeStruct*)0; }"; $HEADER2 .= " struct SomeStruct { int a; double b, c, d; }; $DECL_SPEC void* returnTypeChangeToVoidPtr(int param);"; $SOURCE2 .= " void* returnTypeChangeToVoidPtr(int param) { return (void*)0; }"; # Return_Type_From_Void_And_Stack_Layout ("void" to "struct") $HEADER1 .= " $DECL_SPEC void returnTypeChangeFromVoidToStruct(int param);"; $SOURCE1 .= " void returnTypeChangeFromVoidToStruct(int param) { return; }"; $HEADER2 .= " $DECL_SPEC struct SomeStruct returnTypeChangeFromVoidToStruct(int param);"; $SOURCE2 .= " struct SomeStruct returnTypeChangeFromVoidToStruct(int param) { struct SomeStruct obj = {1,2}; return obj; }"; # Return_Type_Became_Void_And_Stack_Layout ("struct" to "void") $HEADER1 .= " $DECL_SPEC struct SomeStruct returnTypeChangeFromStructToVoid(int param);"; $SOURCE1 .= " struct SomeStruct returnTypeChangeFromStructToVoid(int param) { struct SomeStruct obj = {1,2}; return obj; }"; $HEADER2 .= " $DECL_SPEC void returnTypeChangeFromStructToVoid(int param);"; $SOURCE2 .= " void returnTypeChangeFromStructToVoid(int param) { return; }"; # Return_Type_From_Void_And_Stack_Layout (safe, "void" to "long") $HEADER1 .= " $DECL_SPEC void returnTypeChangeFromVoidToLong(int param);"; $SOURCE1 .= " void returnTypeChangeFromVoidToLong(int param) { return; }"; $HEADER2 .= " $DECL_SPEC long returnTypeChangeFromVoidToLong(int param);"; $SOURCE2 .= " long returnTypeChangeFromVoidToLong(int param) { return 0; }"; # Return_Type_From_Void_And_Stack_Layout (safe, "void" to "void*") $HEADER1 .= " $DECL_SPEC void returnTypeChangeFromVoidToVoidPtr(int param);"; $SOURCE1 .= " void returnTypeChangeFromVoidToVoidPtr(int param) { return; }"; $HEADER2 .= " $DECL_SPEC void* returnTypeChangeFromVoidToVoidPtr(int param);"; $SOURCE2 .= " void* returnTypeChangeFromVoidToVoidPtr(int param) { return 0; }"; # Return_Type_From_Register_To_Stack ("int" to "struct") $HEADER1 .= " $DECL_SPEC int returnTypeChangeFromIntToStruct(int param);"; $SOURCE1 .= " int returnTypeChangeFromIntToStruct(int param) { return param; }"; $HEADER2 .= " $DECL_SPEC struct SomeStruct returnTypeChangeFromIntToStruct(int param);"; $SOURCE2 .= " struct SomeStruct returnTypeChangeFromIntToStruct(int param) { struct SomeStruct obj = {1,2}; return obj; }"; # Return_Type_From_Stack_To_Register (from struct to int) $HEADER1 .= " $DECL_SPEC struct SomeStruct returnTypeChangeFromStructToInt(int param);"; $SOURCE1 .= " struct SomeStruct returnTypeChangeFromStructToInt(int param) { struct SomeStruct obj = {1,2}; return obj; }"; $HEADER2 .= " $DECL_SPEC int returnTypeChangeFromStructToInt(int param);"; $SOURCE2 .= " int returnTypeChangeFromStructToInt(int param) { return param; }"; # Return_Type_From_Stack_To_Register (from struct to int, without parameters) $HEADER1 .= " $DECL_SPEC struct SomeStruct returnTypeChangeFromStructToIntWithNoParams();"; $SOURCE1 .= " struct SomeStruct returnTypeChangeFromStructToIntWithNoParams() { struct SomeStruct obj = {1,2}; return obj; }"; $HEADER2 .= " $DECL_SPEC int returnTypeChangeFromStructToIntWithNoParams();"; $SOURCE2 .= " int returnTypeChangeFromStructToIntWithNoParams() { return 0; }"; # Return_BaseType $HEADER1 .= " $DECL_SPEC int *returnBaseTypeChange(int param);"; $SOURCE1 .= " int *returnBaseTypeChange(int param) { return (int*)0; }"; $HEADER2 .= " $DECL_SPEC long long *returnBaseTypeChange(int param);"; $SOURCE2 .= " long long *returnBaseTypeChange(int param) { return (long long*)0; }"; # Return_PointerLevel $HEADER1 .= " $DECL_SPEC long long returnPointerLevelAndSize(int param);"; $SOURCE1 .= " long long returnPointerLevelAndSize(int param) { return 100; }"; $HEADER2 .= " $DECL_SPEC long long *returnPointerLevelAndSize(int param);"; $SOURCE2 .= " long long *returnPointerLevelAndSize(int param) { return (long long *)0; }"; # Return_PointerLevel $HEADER1 .= " $DECL_SPEC long long *returnPointerLevel(int param);"; $SOURCE1 .= " long long *returnPointerLevel(int param) { return (long long *)0; }"; $HEADER2 .= " $DECL_SPEC long long **returnPointerLevel(int param);"; $SOURCE2 .= " long long **returnPointerLevel(int param) { return (long long **)0; }"; # Size (typedef to anon structure) $HEADER1 .= " typedef struct { int i; long j; double k; } AnonTypedef; $DECL_SPEC int anonTypedef(AnonTypedef param);"; $SOURCE1 .= " int anonTypedef(AnonTypedef param) { return 0; }"; $HEADER2 .= " typedef struct { int i; long j; double k; union { int dummy[256]; struct { char q_skiptable[256]; const char *p; int l; } p; }; } AnonTypedef; $DECL_SPEC int anonTypedef(AnonTypedef param);"; $SOURCE2 .= " int anonTypedef(AnonTypedef param) { return 0; }"; # Size (safe: opaque) $HEADER1 .= " struct OpaqueType { long long i[5]; long j; double k; struct OpaqueType* p; }; $DECL_SPEC int opaqueTypeUse(struct OpaqueType param, int param_2);"; $SOURCE1 .= " int opaqueTypeUse(struct OpaqueType param, int param_2) { return param_2; }"; $HEADER2 .= " struct OpaqueType { long long i[5]; long long j; double k; struct OpaqueType* p; }; $DECL_SPEC int opaqueTypeUse(struct OpaqueType param, int param_2);"; $SOURCE2 .= " int opaqueTypeUse(struct OpaqueType param, int param_2) { return param_2; }"; # Size (safe: internal) $HEADER1 .= " struct InternalType { long long i[5]; long j; double k; struct InternalType* p; }; $DECL_SPEC int internalTypeUse(struct InternalType param, int param_2);"; $SOURCE1 .= " int internalTypeUse(struct InternalType param, int param_2) { return param_2; }"; $HEADER2 .= " struct InternalType { long long i[5]; long long j; double k; struct InternalType* p; }; $DECL_SPEC int internalTypeUse(struct InternalType param, int param_2);"; $SOURCE2 .= " int internalTypeUse(struct InternalType param, int param_2) { return param_2; }"; if($OSgroup eq "linux") { # Changed version $HEADER1 .= " $DECL_SPEC int changedVersion(int param); $DECL_SPEC int changedDefaultVersion(int param);"; $SOURCE1 .= " int changedVersion(int param) { return 0; } __asm__(\".symver changedVersion,changedVersion\@VERSION_2.0\"); int changedDefaultVersion(int param) { return 0; }"; $HEADER2 .= " $DECL_SPEC int changedVersion(int param); $DECL_SPEC int changedDefaultVersion(long param);"; $SOURCE2 .= " int changedVersion(int param) { return 0; } __asm__(\".symver changedVersion,changedVersion\@VERSION_3.0\"); int changedDefaultVersion(long param) { return 0; }"; # Unchanged version $HEADER1 .= " $DECL_SPEC int unchangedVersion(int param); $DECL_SPEC int unchangedDefaultVersion(int param);"; $SOURCE1 .= " int unchangedVersion(int param) { return 0; } __asm__(\".symver unchangedVersion,unchangedVersion\@VERSION_1.0\"); int unchangedDefaultVersion(int param) { return 0; }"; $HEADER2 .= " $DECL_SPEC int unchangedVersion(int param); $DECL_SPEC int unchangedDefaultVersion(int param);"; $SOURCE2 .= " int unchangedVersion(int param) { return 0; } __asm__(\".symver unchangedVersion,unchangedVersion\@VERSION_1.0\"); int unchangedDefaultVersion(int param) { return 0; }"; # Non-Default to Default $HEADER1 .= " $DECL_SPEC int changedVersionToDefault(int param);"; $SOURCE1 .= " int changedVersionToDefault(int param) { return 0; } __asm__(\".symver changedVersionToDefault,changedVersionToDefault\@VERSION_1.0\");"; $HEADER2 .= " $DECL_SPEC int changedVersionToDefault(long param);"; $SOURCE2 .= " int changedVersionToDefault(long param) { return 0; }"; # Default to Non-Default $HEADER1 .= " $DECL_SPEC int changedVersionToNonDefault(int param);"; $SOURCE1 .= " int changedVersionToNonDefault(int param) { return 0; }"; $HEADER2 .= " $DECL_SPEC int changedVersionToNonDefault(long param);"; $SOURCE2 .= " int changedVersionToNonDefault(long param) { return 0; } __asm__(\".symver changedVersionToNonDefault,changedVersionToNonDefault\@VERSION_3.0\");"; # Added version $HEADER1 .= " $DECL_SPEC int addedVersion(int param); $DECL_SPEC int addedDefaultVersion(int param);"; $SOURCE1 .= " int addedVersion(int param) { return 0; } int addedDefaultVersion(int param) { return 0; }"; $HEADER2 .= " $DECL_SPEC int addedVersion(int param); $DECL_SPEC int addedDefaultVersion(int param);"; $SOURCE2 .= " int addedVersion(int param) { return 0; } __asm__(\".symver addedVersion,addedVersion\@VERSION_2.0\"); int addedDefaultVersion(int param) { return 0; }"; # Removed version $HEADER1 .= " $DECL_SPEC int removedVersion(int param); $DECL_SPEC int removedVersion2(int param); $DECL_SPEC int removedDefaultVersion(int param);"; $SOURCE1 .= " int removedVersion(int param) { return 0; } __asm__(\".symver removedVersion,removedVersion\@VERSION_1.0\"); int removedVersion2(int param) { return 0; } __asm__(\".symver removedVersion2,removedVersion\@VERSION_3.0\"); int removedDefaultVersion(int param) { return 0; }"; $HEADER2 .= " $DECL_SPEC int removedVersion(int param); $DECL_SPEC int removedVersion2(int param); $DECL_SPEC int removedDefaultVersion(int param);"; $SOURCE2 .= " int removedVersion(int param) { return 0; } int removedVersion2(int param) { return 0; } __asm__(\".symver removedVersion2,removedVersion\@VERSION_3.0\"); int removedDefaultVersion(int param) { return 0; }"; # Return_Type (good versioning) $HEADER1 .= " $DECL_SPEC int goodVersioning(int param);"; $SOURCE1 .= " int goodVersioning(int param) { return 0; } __asm__(\".symver goodVersioning,goodVersioning\@VERSION_1.0\");"; $HEADER2 .= " $DECL_SPEC int goodVersioningOld(int param);"; $SOURCE2 .= " int goodVersioningOld(int param) { return 0; } __asm__(\".symver goodVersioningOld,goodVersioning\@VERSION_1.0\");"; $HEADER2 .= " $DECL_SPEC float goodVersioning(int param);"; $SOURCE2 .= " float goodVersioning(int param) { return 0.7; } __asm__(\".symver goodVersioning,goodVersioning\@VERSION_2.0\");"; # Return_Type (bad versioning) $HEADER1 .= " $DECL_SPEC int badVersioning(int param);"; $SOURCE1 .= " int badVersioning(int param) { return 0; } __asm__(\".symver badVersioning,badVersioning\@VERSION_1.0\");"; $HEADER2 .= " $DECL_SPEC float badVersioningOld(int param);"; $SOURCE2 .= " float badVersioningOld(int param) { return 0.7; } __asm__(\".symver badVersioningOld,badVersioning\@VERSION_1.0\");"; $HEADER2 .= " $DECL_SPEC float badVersioning(int param);"; $SOURCE2 .= " float badVersioning(int param) { return 0.7; } __asm__(\".symver badVersioning,badVersioning\@VERSION_2.0\");"; } # unnamed struct/union fields within structs/unions $HEADER1 .= " typedef struct { int a; union { int b; float c; }; int d; } UnnamedTypeSize; $DECL_SPEC int unnamedTypeSize(UnnamedTypeSize param);"; $SOURCE1 .= " int unnamedTypeSize(UnnamedTypeSize param) { return 0; }"; $HEADER2 .= " typedef struct { int a; union { long double b; float c; }; int d; } UnnamedTypeSize; $DECL_SPEC int unnamedTypeSize(UnnamedTypeSize param);"; $SOURCE2 .= " int unnamedTypeSize(UnnamedTypeSize param) { return 0; }"; # Changed_Constant (#define) $HEADER1 .= " #define PUBLIC_CONSTANT \"old_value\""; $HEADER2 .= " #define PUBLIC_CONSTANT \"new_value\""; # Changed_Constant (Safe) $HEADER1 .= " #define INTEGER_CONSTANT 0x01"; $HEADER2 .= " #define INTEGER_CONSTANT 1"; # Changed_Constant (Safe) $HEADER1 .= " #define PRIVATE_CONSTANT \"old_value\" #undef PRIVATE_CONSTANT"; $HEADER2 .= " #define PRIVATE_CONSTANT \"new_value\" #undef PRIVATE_CONSTANT"; # Changed_Constant (enum) $HEADER1 .= " enum { SOME_CONSTANT=0x1 };"; $HEADER2 .= " enum { SOME_CONSTANT=0x2 };"; # Added_Constant (#define) $HEADER2 .= " #define ADDED_CNST \"value\""; # Added_Constant (enum) $HEADER1 .= " enum { CONSTANT1 };"; $HEADER2 .= " enum { CONSTANT1, ADDED_CONSTANT };"; # Removed_Constant (#define) $HEADER1 .= " #define REMOVED_CNST \"value\""; # Removed_Constant (enum) $HEADER1 .= " enum { CONSTANT2, REMOVED_CONSTANT };"; $HEADER2 .= " enum { CONSTANT2 };"; # Added_Field (union) $HEADER1 .= " union UnionTypeAddedField { int a; struct { int b; float c; }; int d; }; $DECL_SPEC int unionTypeAddedField(union UnionTypeAddedField param);"; $SOURCE1 .= " int unionTypeAddedField(union UnionTypeAddedField param) { return 0; }"; $HEADER2 .= " union UnionTypeAddedField { int a; struct { long double x, y; } new_field; struct { int b; float c; }; int d; }; $DECL_SPEC int unionTypeAddedField(union UnionTypeAddedField param);"; $SOURCE2 .= " int unionTypeAddedField(union UnionTypeAddedField param) { return 0; }"; # Prameter_BaseType (typedef) $HEADER1 .= " typedef float TYPEDEF_TYPE; $DECL_SPEC int parameterTypedefChange(TYPEDEF_TYPE param);"; $SOURCE1 .= " int parameterTypedefChange(TYPEDEF_TYPE param) { return 1.0; }"; $HEADER2 .= " typedef int TYPEDEF_TYPE; $DECL_SPEC int parameterTypedefChange(TYPEDEF_TYPE param);"; $SOURCE2 .= " int parameterTypedefChange(TYPEDEF_TYPE param) { return 1; }"; # Field_BaseType (typedef in member type) $HEADER1 .= " typedef float TYPEDEF_TYPE_2; struct FieldBaseTypedefChange { TYPEDEF_TYPE_2 m; }; $DECL_SPEC int fieldBaseTypedefChange(struct FieldBaseTypedefChange param);"; $SOURCE1 .= " int fieldBaseTypedefChange(struct FieldBaseTypedefChange param) { return 1; }"; $HEADER2 .= " typedef int TYPEDEF_TYPE_2; struct FieldBaseTypedefChange { TYPEDEF_TYPE_2 m; }; $DECL_SPEC int fieldBaseTypedefChange(struct FieldBaseTypedefChange param);"; $SOURCE2 .= " int fieldBaseTypedefChange(struct FieldBaseTypedefChange param) { return 1; }"; # C++ keywords in C code $HEADER1 .= " $DECL_SPEC int testCppKeywords1(int class, int virtual, int (*new)(int));"; $SOURCE1 .= " $DECL_SPEC int testCppKeywords1(int class, int virtual, int (*new)(int)) { return 0; }"; $HEADER2 .= " $DECL_SPEC int testCppKeywords1(int class, int virtual); $DECL_SPEC int testCppKeywords2(int operator, int other); $DECL_SPEC int testCppKeywords3(int operator); $DECL_SPEC int operator(int class, int this); $DECL_SPEC int delete(int virtual, int* this); struct CppKeywords { int bool: 8; //int*this; }; #ifdef __cplusplus class TestCppKeywords { void operator delete(void*); void operator ()(int); void operator,(int); void delete() { delete this; }; }; #endif"; $SOURCE2 .= " $DECL_SPEC int testCppKeywords1(int class, int virtual) { return 0; }"; # Regression $HEADER1 .= " $DECL_SPEC int* testRegression(int *pointer, char const *name, ...);"; $SOURCE1 .= " int* testRegression(int *pointer, char const *name, ...) { return 0; }"; $HEADER2 .= " $DECL_SPEC int* testRegression(int *pointer, char const *name, ...);"; $SOURCE2 .= " int* testRegression(int *pointer, char const *name, ...) { return 0; }"; runTests("libsample_c", "C", $HEADER1, $SOURCE1, $HEADER2, $SOURCE2, "struct OpaqueType", "internalTypeUse"); } sub runTests($$$$$$$$) { my ($LibName, $Lang, $HEADER1, $SOURCE1, $HEADER2, $SOURCE2, $Opaque, $Private) = @_; my $Ext = ($Lang eq "C++")?"cpp":"c"; rmtree($LibName); # creating test suite my $Path_v1 = "$LibName/libsample.v1"; my $Path_v2 = "$LibName/libsample.v2"; mkpath($Path_v1); mkpath($Path_v2); writeFile("$Path_v1/libsample.h", $HEADER1."\n"); writeFile("$Path_v1/libsample.$Ext", "#include \"libsample.h\"\n".$SOURCE1."\n"); writeFile("$LibName/v1.xml", " 1.0 ".get_abs_path($Path_v1)." ".get_abs_path($Path_v1)." $Opaque $Private ".get_abs_path($Path_v1)." \n"); writeFile("$Path_v1/test.$Ext", " #include \"libsample.h\" #include ".($Lang eq "C++"?"using namespace TestNS;":"")." int main() { int ret = 0; printf(\"\%d\\n\", ret); return 0; }\n"); writeFile("$Path_v2/libsample.h", $HEADER2."\n"); writeFile("$Path_v2/libsample.$Ext", "#include \"libsample.h\"\n".$SOURCE2."\n"); writeFile("$LibName/v2.xml", " 2.0 ".get_abs_path($Path_v2)." ".get_abs_path($Path_v2)." $Opaque $Private ".get_abs_path($Path_v2)." \n"); writeFile("$Path_v2/test.$Ext", " #include \"libsample.h\" #include ".($Lang eq "C++"?"using namespace TestNS;":"")." int main() { int ret = 0; printf(\"\%d\\n\", ret); return 0; }\n"); my ($BuildCmd, $BuildCmd_Test) = ("", ""); if($OSgroup eq "windows") { check_win32_env(); # to run MS VC++ compiler my $CL = get_CmdPath("cl"); if(not $CL) { exitStatus("Not_Found", "can't find \"cl\" compiler"); } $BuildCmd = "$CL /LD libsample.$Ext >build_log.txt 2>&1"; $BuildCmd_Test = "$CL test.$Ext libsample.$LIB_EXT"; } elsif($OSgroup eq "linux") { if($Lang eq "C") { # tests for symbol versioning writeFile("$Path_v1/version", " VERSION_1.0 { unchangedDefaultVersion; removedDefaultVersion; }; VERSION_2.0 { changedDefaultVersion; }; VERSION_3.0 { changedVersionToNonDefault; }; "); writeFile("$Path_v2/version", " VERSION_1.0 { unchangedDefaultVersion; changedVersionToDefault; }; VERSION_2.0 { addedDefaultVersion; }; VERSION_3.0 { changedDefaultVersion; }; "); $BuildCmd = $GCC_PATH." -Wl,--version-script version -shared libsample.$Ext -o libsample.$LIB_EXT -g"; $BuildCmd_Test = $GCC_PATH." -Wl,--version-script version test.$Ext -Wl,libsample.$LIB_EXT -o test"; } else { $BuildCmd = $GCC_PATH." -shared -x c++ libsample.$Ext -lstdc++ -o libsample.$LIB_EXT -g"; $BuildCmd_Test = $GCC_PATH." -x c++ test.$Ext -lstdc++ -Wl,libsample.$LIB_EXT -o test"; } if(getArch(1)=~/\A(arm|x86_64)\Z/i) { # relocation R_ARM_MOVW_ABS_NC against `a local symbol' can not be used when making a shared object; recompile with -fPIC $BuildCmd .= " -fPIC"; $BuildCmd_Test .= " -fPIC"; } } elsif($OSgroup eq "macos") { # using GCC -dynamiclib if($Lang eq "C") { $BuildCmd = $GCC_PATH." -dynamiclib libsample.$Ext -o libsample.$LIB_EXT"; $BuildCmd_Test = $GCC_PATH." test.$Ext libsample.$LIB_EXT -o test"; } else { # C++ $BuildCmd = $GCC_PATH." -dynamiclib -x c++ libsample.$Ext -lstdc++ -o libsample.$LIB_EXT"; $BuildCmd_Test = $GCC_PATH." -x c++ test.$Ext libsample.$LIB_EXT -o test"; } } else { # default unix-like # symbian target if($Lang eq "C") { $BuildCmd = $GCC_PATH." -shared libsample.$Ext -o libsample.$LIB_EXT -g"; $BuildCmd_Test = $GCC_PATH." test.$Ext -Wl,libsample.$LIB_EXT -o test"; } else { # C++ $BuildCmd = $GCC_PATH." -shared -x c++ libsample.$Ext -lstdc++ -o libsample.$LIB_EXT -g"; $BuildCmd_Test = $GCC_PATH." -x c++ test.$Ext -Wl,libsample.$LIB_EXT -o test"; } } my $MkContent = "all:\n\t$BuildCmd\ntest:\n\t$BuildCmd_Test\n"; if($OSgroup eq "windows") { $MkContent .= "clean:\n\tdel test libsample.so\n"; } else { $MkContent .= "clean:\n\trm test libsample.so\n"; } writeFile("$Path_v1/Makefile", $MkContent); writeFile("$Path_v2/Makefile", $MkContent); system("cd $Path_v1 && $BuildCmd >build-log.txt 2>&1"); if($?) { my $Msg = "can't compile $LibName v.1: \'$Path_v1/build-log.txt\'"; if(readFile("$Path_v1/build-log.txt")=~/error trying to exec \W+cc1plus\W+/) { $Msg .= "\nDid you install G++?"; } exitStatus("Error", $Msg); } system("cd $Path_v2 && $BuildCmd >build-log.txt 2>&1"); if($?) { exitStatus("Error", "can't compile $LibName v.2: \'$Path_v2/build-log.txt\'"); } # running the tool my @Cmd = ("perl", $0, "-l", $LibName, "-d1", "$LibName/v1.xml", "-d2", "$LibName/v2.xml"); if($TestDump) { @Cmd = (@Cmd, "-use-dumps"); if($SortDump) { @Cmd = (@Cmd, "-sort"); } } if($DumpFormat and $DumpFormat ne "perl") { # Perl Data::Dumper is default format @Cmd = (@Cmd, "-dump-format", $DumpFormat); } if($GCC_PATH ne "gcc") { @Cmd = (@Cmd, "-cross-gcc", $GCC_PATH); } if($Quiet) { # quiet mode @Cmd = (@Cmd, "-quiet"); @Cmd = (@Cmd, "-logging-mode", "a"); } elsif($LogMode and $LogMode ne "w") { # "w" is default @Cmd = (@Cmd, "-logging-mode", $LogMode); } if($ExtendedCheck) { # extended mode @Cmd = (@Cmd, "-extended"); if($Lang eq "C") { @Cmd = (@Cmd, "-lang", "C"); } } if($ReportFormat and $ReportFormat ne "html") { # HTML is default format @Cmd = (@Cmd, "-report-format", $ReportFormat); } if($CheckHeadersOnly) { @Cmd = (@Cmd, "-headers-only"); } if($CheckObjectsOnly) { @Cmd = (@Cmd, "-objects-only"); } if($Browse) { @Cmd = (@Cmd, "-browse", $Browse); } if($OpenReport) { @Cmd = (@Cmd, "-open"); } if($Debug) { # debug mode @Cmd = (@Cmd, "-debug"); printMsg("INFO", "running @Cmd"); } system(@Cmd); my $ECode = $?>>8; if($ECode!~/\A[0-1]\Z/) { # error exitStatus("Error", "analysis has failed"); } my $RPath = "compat_reports/$LibName/1.0_to_2.0/compat_report.$ReportFormat"; my $NProblems = 0; if($ReportFormat eq "xml") { my $Content = readFile($RPath); # binary if(my $PSummary = parseTag(\$Content, "problem_summary")) { $NProblems += int(parseTag(\$PSummary, "removed_symbols")); if(my $TProblems = parseTag(\$PSummary, "problems_with_types")) { $NProblems += int(parseTag(\$TProblems, "high")); $NProblems += int(parseTag(\$TProblems, "medium")); } if(my $IProblems = parseTag(\$PSummary, "problems_with_symbols")) { $NProblems += int(parseTag(\$IProblems, "high")); $NProblems += int(parseTag(\$IProblems, "medium")); } } # source if(my $PSummary = parseTag(\$Content, "problem_summary")) { $NProblems += int(parseTag(\$PSummary, "removed_symbols")); if(my $TProblems = parseTag(\$PSummary, "problems_with_types")) { $NProblems += int(parseTag(\$TProblems, "high")); $NProblems += int(parseTag(\$TProblems, "medium")); } if(my $IProblems = parseTag(\$PSummary, "problems_with_symbols")) { $NProblems += int(parseTag(\$IProblems, "high")); $NProblems += int(parseTag(\$IProblems, "medium")); } } } else { my $BReport = readAttributes($RPath, 0); $NProblems += $BReport->{"removed"}; $NProblems += $BReport->{"type_problems_high"}+$BReport->{"type_problems_medium"}; $NProblems += $BReport->{"interface_problems_high"}+$BReport->{"interface_problems_medium"}; my $SReport = readAttributes($RPath, 1); $NProblems += $SReport->{"removed"}; $NProblems += $SReport->{"type_problems_high"}+$SReport->{"type_problems_medium"}; $NProblems += $SReport->{"interface_problems_high"}+$SReport->{"interface_problems_medium"}; } if(($LibName eq "libsample_c" and $NProblems>70) or ($LibName eq "libsample_cpp" and $NProblems>150)) { printMsg("INFO", "result: SUCCESS ($NProblems problems found)\n"); } else { printMsg("ERROR", "result: FAILED ($NProblems problems found)\n"); } } return 1;abi-compliance-checker-1.99.9/modules/Internals/Scripts/000077500000000000000000000000001227016120300231205ustar00rootroot00000000000000abi-compliance-checker-1.99.9/modules/Internals/Scripts/Sections.js000066400000000000000000000006761227016120300252560ustar00rootroot00000000000000function showContent(header, id) { e = document.getElementById(id); if(e.style.display == 'none') { e.style.display = 'block'; e.style.visibility = 'visible'; header.innerHTML = header.innerHTML.replace(/\[[^0-9 ]\]/gi,"[−]"); } else { e.style.display = 'none'; e.style.visibility = 'hidden'; header.innerHTML = header.innerHTML.replace(/\[[^0-9 ]\]/gi,"[+]"); } }abi-compliance-checker-1.99.9/modules/Internals/Scripts/Tabs.js000066400000000000000000000047501227016120300243550ustar00rootroot00000000000000function initTabs() { var url = window.location.href; if(url.indexOf('_Source_')!=-1 || url.indexOf('#Source')!=-1) { var tab1 = document.getElementById('BinaryID'); var tab2 = document.getElementById('SourceID'); tab1.className='tab disabled'; tab2.className='tab active'; } var sets = document.getElementsByTagName('div'); for (var i = 0; i < sets.length; i++) { if (sets[i].className.indexOf('tabset') != -1) { var tabs = []; var links = sets[i].getElementsByTagName('a'); for (var j = 0; j < links.length; j++) { if (links[j].className.indexOf('tab') != -1) { tabs.push(links[j]); links[j].tabs = tabs; var tab = document.getElementById(links[j].href.substr(links[j].href.indexOf('#') + 1)); //reset all tabs on start if (tab) { if (links[j].className.indexOf('active')!=-1) { tab.style.display = 'block'; } else { tab.style.display = 'none'; } } links[j].onclick = function() { var tab = document.getElementById(this.href.substr(this.href.indexOf('#') + 1)); if (tab) { //reset all tabs before change for (var k = 0; k < this.tabs.length; k++) { document.getElementById(this.tabs[k].href.substr(this.tabs[k].href.indexOf('#') + 1)).style.display = 'none'; this.tabs[k].className = this.tabs[k].className.replace('active', 'disabled'); } this.className = 'tab active'; tab.style.display = 'block'; // window.location.hash = this.id.replace('ID', ''); return false; } } } } } } if(url.indexOf('#')!=-1) { location.href=location.href; } } if (window.addEventListener) window.addEventListener('load', initTabs, false); else if (window.attachEvent) window.attachEvent('onload', initTabs);abi-compliance-checker-1.99.9/modules/Internals/Styles/000077500000000000000000000000001227016120300227545ustar00rootroot00000000000000abi-compliance-checker-1.99.9/modules/Internals/Styles/CmpSystems.css000066400000000000000000000026341227016120300256020ustar00rootroot00000000000000body { font-family:Arial, sans-serif; font-size:14px; background:#FFFFFF; color:Black; } hr { color:Black; background-color:Black; height:1px; border:0; } h1 { font-size:26px; white-space:nowrap; } h2 { margin-bottom:0px; padding-bottom:0px; font-size:20px; white-space:nowrap; } table.summary, table.wikitable { border-collapse:collapse; border:1px outset black; } table.summary td, table.summary th { border:1px inset gray; padding: 3px 5px 3px 5px; white-space:nowrap; } table.summary th { background-color:#EEEEEE; font-weight:100; text-align:left; padding: 3px; font-size:15px; } table.summary td { text-align:right; padding-left:10px; padding: 3px 5px 3px 10px; font-size:16px; } table.wikitable td, table.wikitable th { border:1px inset gray; text-align:center; padding: 3px; white-space:nowrap; } table.wikitable th { background-color:#EEEEEE; font-size:15px; } table.wikitable td { font-size:16px; } table.wikitable td.left { text-align:left; font-size:16px; padding-left:5px; background-color:#F9F9F9; } td.passed { background-color:#CCFFCC; } td.warning { background-color:#F4F4AF; } td.failed { background-color:#FFCCCC; } td.new { background-color:#C6DEFF; } a.default { color:#336699; } th.severity { width:55px; } sup { font-size:10px; }abi-compliance-checker-1.99.9/modules/Internals/Styles/Report.css000066400000000000000000000100041227016120300247340ustar00rootroot00000000000000body { font-family:Arial, sans-serif; color:Black; font-size:14px; } hr { color:Black; background-color:Black; height:1px; border:0; } h1 { margin-bottom:0px; padding-bottom:0px; font-size:26px; } h2 { margin-bottom:0px; padding-bottom:0px; font-size:20px; white-space:nowrap; } span.section { font-weight:bold; cursor:pointer; font-size:16px; color:#003E69; white-space:nowrap; margin-left:5px; } span.new_sign { font-weight:bold; margin-left:26px; font-size:16px; color:#003E69; } span.new_sign_lbl { margin-left:28px; font-size:14px; color:Black; } span:hover.section { color:#336699; } span.section_affected { cursor:pointer; margin-left:7px; padding-left:15px; font-size:14px; color:#cc3300; } span.section_info { cursor:pointer; margin-left:7px; padding-left:15px; font-size:14px; color:Black; } span.extendable { font-weight:100; font-size:16px; } span.h_name { color:#cc3300; font-size:14px; font-weight:bold; } div.h_list { font-size:15px; padding-left:5px; } span.ns { color:#408080; font-size:15px; } div.lib_list { font-size:15px; padding-left:5px; } span.lib_name { color:Green; font-size:14px; font-weight:bold; } span.iname { font-weight:bold; font-size:16px; color:#003E69; margin-left:5px; } span.iname_b { font-weight:bold; font-size:15px; } span.iname_a { color:#333333; font-weight:bold; font-size:15px; } span.sym_p { font-weight:normal; white-space:normal; } div.affect { padding-left:15px; padding-bottom:4px; font-size:14px; font-style:italic; line-height:13px; } div.affected { padding-left:30px; padding-top:5px; } table.ptable { border-collapse:collapse; border:1px outset black; line-height:16px; margin-left:15px; margin-top:3px; margin-bottom:3px; width:900px; } table.ptable td { border:1px solid gray; padding: 3px; } table.vtable { border-collapse:collapse; border:1px outset black; line-height:16px; margin-left:30px; margin-top:10px; width:100px; } table.vtable td { border:1px solid gray; white-space:nowrap; padding: 3px; } table.ptable th, table.vtable th { background-color:#eeeeee; font-weight:bold; color:#333333; font-family:Verdana, Arial; font-size:13px; border:1px solid gray; text-align:center; vertical-align:top; white-space:nowrap; padding: 3px; } table.summary { border-collapse:collapse; border:1px outset black; } table.summary th { background-color:#eeeeee; font-weight:100; text-align:left; font-size:15px; white-space:nowrap; border:1px inset gray; padding: 3px; } table.summary td { text-align:right; font-size:16px; white-space:nowrap; border:1px inset gray; padding: 3px 5px 3px 10px; } table.code_view { cursor:text; margin-top:7px; margin-left:15px; font-family:Monaco, Consolas, 'DejaVu Sans Mono', 'Droid Sans Mono', Monospace; font-size:14px; padding:10px; border:1px solid #e0e8e5; color:#444444; background-color:#eff3f2; overflow:auto; } table.code_view td { padding-left:15px; text-align:left; white-space:nowrap; } span.mangled { padding-left:15px; font-size:14px; cursor:text; color:#444444; } span.sym_ver { color:#333333; white-space:nowrap; font-family:"DejaVu Sans Mono", Monospace; } span.attr { color:#333333; font-weight:100; } span.color_p { font-style:italic; color:Brown; } span.param { font-style:italic; } span.focus_p { font-style:italic; color:Red; } span.ttype { font-weight:100; } span.nowrap { white-space:nowrap; } span.value { white-space:nowrap; font-weight:bold; } td.passed { background-color:#CCFFCC; } td.warning { background-color:#F4F4AF; } td.failed { background-color:#FFCCCC; } td.new { background-color:#C6DEFF; }abi-compliance-checker-1.99.9/modules/Internals/Styles/SymbolsList.css000066400000000000000000000021011227016120300257440ustar00rootroot00000000000000body { font-family:Arial, sans-serif; color:Black; font-size:14px; } hr { color:Black; background-color:Black; height:1px; border:0; } h1 { font-size:26px; } span.iname { font-weight:bold; font-size:16px; color:#003E69; margin-left:5px; } span.section { font-weight:bold; cursor:pointer; font-size:16px; color:#003E69; white-space:nowrap; margin-left:5px; } span:hover.section { color:#336699; } span.h_name { color:#cc3300; font-size:14px; font-weight:bold; } span.ns { color:#408080; font-size:15px; } span.lib_name { color:Green; font-size:14px; font-weight:bold; } span.sym_p { font-weight:normal; white-space:normal; } span.sym_kind { color:Black; font-weight:normal; } span.mangled { padding-left:15px; font-size:13px; cursor:text; color:#444444; } span.sym_ver { color:#333333; white-space:nowrap; } span.color_p { font-style:italic; color:Brown; } span.param { font-style:italic; } span.nowrap { white-space:nowrap; }abi-compliance-checker-1.99.9/modules/Internals/Styles/Tabs.css000066400000000000000000000010301227016120300243510ustar00rootroot00000000000000.tabset { float:left; } a.tab { border:1px solid #AAA; float:left; margin:0px 5px -1px 0px; padding:3px 5px 3px 5px; position:relative; font-size:14px; background-color:#DDD; text-decoration:none; color:Black; } a.disabled:hover { color:Black; background:#EEE; } a.active:hover { color:Black; background:White; } a.active { border-bottom-color:White; background-color:White; } div.tab { border:1px solid #AAA; padding:0 7px 0 12px; width:97%; clear:both; }abi-compliance-checker-1.99.9/modules/Internals/SysCheck.pm000066400000000000000000002641361227016120300235570ustar00rootroot00000000000000########################################################################### # Module for ABI Compliance Checker to compare Operating Systems # # Copyright (C) 2009-2010 The Linux Foundation # Copyright (C) 2009-2011 Institute for System Programming, RAS # Copyright (C) 2011-2012 Nokia Corporation and/or its subsidiary(-ies) # Copyright (C) 2011-2013 ROSA Laboratory # # Written by Andrey Ponomarenko # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License or the GNU Lesser # General Public License as published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # and the GNU Lesser General Public License along with this program. # If not, see . ########################################################################### use strict; use File::Temp qw(tempdir); use Cwd qw(abs_path cwd); use Fcntl; my ($Debug, $Quiet, $LogMode, $CheckHeadersOnly, $SystemRoot, $MODULES_DIR, $GCC_PATH, $CrossPrefix, $TargetSysInfo, $TargetLibraryName, $CrossGcc, $UseStaticLibs, $NoStdInc, $OStarget, $BinaryOnly, $SourceOnly); my $OSgroup = get_OSgroup(); my $TMP_DIR = tempdir(CLEANUP=>1); my $ORIG_DIR = cwd(); my $LIB_EXT = getLIB_EXT($OSgroup); my %SysDescriptor; my %Cache; my %NonPrefix; sub cmpSystems($$$) { # -cmp-systems option handler # should be used with -d1 and -d2 options my ($SPath1, $SPath2, $Opts) = @_; initModule($Opts); if(not $SPath1) { exitStatus("Error", "the option -d1 should be specified"); } elsif(not -d $SPath1) { exitStatus("Access_Error", "can't access directory \'".$SPath1."\'"); } elsif(not -d $SPath1."/abi_dumps") { exitStatus("Access_Error", "can't access directory \'".$SPath1."/abi_dumps\'"); } if(not $SPath2) { exitStatus("Error", "the option -d2 should be specified"); } elsif(not -d $SPath2) { exitStatus("Access_Error", "can't access directory \'".$SPath2."\'"); } elsif(not -d $SPath2."/abi_dumps") { exitStatus("Access_Error", "can't access directory \'".$SPath2."/abi_dumps\'"); } # sys_dumps///... my $SystemName1 = get_filename(get_dirname($SPath1)); my $SystemName2 = get_filename(get_dirname($SPath2)); # sys_dumps///... my $ArchName = get_filename($SPath1); if($ArchName ne get_filename($SPath2)) { exitStatus("Error", "can't compare systems of different CPU architecture"); } if(my $OStarget_Dump = readFile($SPath1."/target.txt")) { # change target $OStarget = $OStarget_Dump; $LIB_EXT = getLIB_EXT($OStarget); } my $GroupByHeaders = 0; if(my $Mode = readFile($SPath1."/mode.txt")) { # change mode if($Mode eq "headers-only") { # -headers-only mode $CheckHeadersOnly = 1; $GroupByHeaders = 1; } if($Mode eq "group-by-headers") { $GroupByHeaders = 1; } } my $SYS_REPORT_PATH = "sys_compat_reports/".$SystemName1."_to_".$SystemName2."/$ArchName"; rmtree($SYS_REPORT_PATH); my (%LibSoname1, %LibSoname2) = (); foreach (split(/\n/, readFile($SPath1."/sonames.txt"))) { if(my ($LFName, $Soname) = split(/;/, $_)) { if($OStarget eq "symbian") { $Soname=~s/\{.+\}//; } $LibSoname1{$LFName} = $Soname; } } foreach (split(/\n/, readFile($SPath2."/sonames.txt"))) { if(my ($LFName, $Soname) = split(/;/, $_)) { if($OStarget eq "symbian") { $Soname=~s/\{.+\}//; } $LibSoname2{$LFName} = $Soname; } } my (%LibV1, %LibV2) = (); foreach (split(/\n/, readFile($SPath1."/versions.txt"))) { if(my ($LFName, $V) = split(/;/, $_)) { $LibV1{$LFName} = $V; } } foreach (split(/\n/, readFile($SPath2."/versions.txt"))) { if(my ($LFName, $V) = split(/;/, $_)) { $LibV2{$LFName} = $V; } } my @Dumps1 = cmd_find($SPath1."/abi_dumps","f","*.tar.gz",1); if(not @Dumps1) { # zip-based dump @Dumps1 = cmd_find($SPath1."/abi_dumps","f","*.zip",1); } my @Dumps2 = cmd_find($SPath2."/abi_dumps","f","*.tar.gz",1); if(not @Dumps2) { # zip-based dump @Dumps2 = cmd_find($SPath2."/abi_dumps","f","*.zip",1); } my (%LibVers1, %LibVers2) = (); my (%ShortNames1, %ShortNames2) = (); foreach my $DPath (@Dumps1) { if(my $Name = isDump($DPath)) { my ($Soname, $V) = ($LibSoname1{$Name}, $LibV1{$Name}); if(not $V) { $V = parse_libname($Name, "version", $OStarget); } if($GroupByHeaders) { $Soname = $Name; } $LibVers1{$Soname}{$V} = $DPath; $ShortNames1{parse_libname($Soname, "short", $OStarget)}{$Soname} = 1; } } foreach my $DPath (@Dumps2) { if(my $Name = isDump($DPath)) { my ($Soname, $V) = ($LibSoname2{$Name}, $LibV2{$Name}); if(not $V) { $V = parse_libname($Name, "version", $OStarget); } if($GroupByHeaders) { $Soname = $Name; } $LibVers2{$Soname}{$V} = $DPath; $ShortNames2{parse_libname($Soname, "short", $OStarget)}{$Soname} = 1; } } my (%Added, %Removed) = (); my (%ChangedSoname, %TestResults) = (); my (%AddedShort, %RemovedShort) = (); if(not $GroupByHeaders) { my %ChangedSoname_Safe = (); foreach my $LName (sort keys(%LibSoname2)) { # libcurl.so.3 -> libcurl.so.4 (search for SONAME by the file name) # OS #1 => OS #2 if(defined $LibVers2{$LName}) { # already registered next; } my $Soname = $LibSoname2{$LName}; if(defined $LibVers2{$Soname} and defined $LibVers1{$LName}) { $LibVers2{$LName} = $LibVers2{$Soname}; $ChangedSoname_Safe{$Soname}=$LName; } } foreach my $LName (sort keys(%LibSoname1)) { # libcurl.so.3 -> libcurl.so.4 (search for SONAME by the file name) # OS #1 <= OS #2 if(defined $LibVers1{$LName}) { # already registered next; } my $Soname = $LibSoname1{$LName}; if(defined $LibVers1{$Soname} and defined $LibVers2{$LName}) { $LibVers1{$LName} = $LibVers1{$Soname}; } } if(not $GroupByHeaders) { printMsg("INFO", "Checking added/removed libs"); } foreach my $LName (sort {lc($a) cmp lc($b)} keys(%LibVers1)) { # removed libs if(not is_target_lib($LName)) { next; } if(not defined $LibVers1{$LName}) { next; } my @Versions1 = keys(%{$LibVers1{$LName}}); if($#Versions1>=1) { # should be only one version next; } if(not defined $LibVers2{$LName} or not keys(%{$LibVers2{$LName}})) { # removed library if(not $LibSoname2{$LName}) { my $LSName = parse_libname($LName, "short", $OStarget); $RemovedShort{$LSName}{$LName} = 1; my $V = $Versions1[0]; $Removed{$LName}{"version"} = $V; my $ListPath = "info/$LName/symbols.html"; my $FV = $SystemName1; if($V) { $FV = $V."-".$FV; } createSymbolsList($LibVers1{$LName}{$V}, $SYS_REPORT_PATH."/".$ListPath, $LName, $FV, $ArchName); $Removed{$LName}{"list"} = $ListPath; } } } foreach my $LName (sort {lc($a) cmp lc($b)} keys(%LibVers2)) { # added libs if(not is_target_lib($LName)) { next; } if(not defined $LibVers2{$LName}) { next; } my @Versions2 = keys(%{$LibVers2{$LName}}); if($#Versions2>=1) { # should be only one version next; } if($ChangedSoname_Safe{$LName}) { # changed soname but added the symbolic link for old-version library next; } if(not defined $LibVers1{$LName} or not keys(%{$LibVers1{$LName}})) { # added library if(not $LibSoname1{$LName}) { my $LSName = parse_libname($LName, "short", $OStarget); $AddedShort{$LSName}{$LName} = 1; my $V = $Versions2[0]; $Added{$LName}{"version"} = $V; my $ListPath = "info/$LName/symbols.html"; my $FV = $SystemName2; if($V) { $FV = $V."-".$FV; } createSymbolsList($LibVers2{$LName}{$V}, $SYS_REPORT_PATH."/".$ListPath, $LName, $FV, $ArchName); $Added{$LName}{"list"} = $ListPath; } } } foreach my $LSName (keys(%AddedShort)) { # changed SONAME my @AddedSonames = keys(%{$AddedShort{$LSName}}); next if($#AddedSonames!=0); if(defined $RemovedShort{$LSName}) { # removed old soname my @RemovedSonames = keys(%{$RemovedShort{$LSName}}); $ChangedSoname{$AddedSonames[0]} = $RemovedSonames[0]; $ChangedSoname{$RemovedSonames[0]} = $AddedSonames[0]; } elsif(defined $ShortNames1{$LSName}) { # saved old soname my @Sonames = keys(%{$ShortNames1{$LSName}}); $ChangedSoname{$AddedSonames[0]} = $Sonames[0]; $ChangedSoname{$Sonames[0]} = $AddedSonames[0]; } } } my %SONAME_Changed = (); my %SONAME_Added = (); foreach my $LName (sort {lc($a) cmp lc($b)} keys(%LibVers1)) { if(not is_target_lib($LName)) { next; } my @Versions1 = keys(%{$LibVers1{$LName}}); if(not @Versions1 or $#Versions1>=1) { # should be only one version next; } my $LV1 = $Versions1[0]; my $DPath1 = $LibVers1{$LName}{$LV1}; my @Versions2 = keys(%{$LibVers2{$LName}}); if($#Versions2>=1) { # should be only one version next; } my ($LV2, $LName2, $DPath2) = (); my $LName_Short = parse_libname($LName, "name+ext", $OStarget); if($LName2 = $ChangedSoname{$LName}) { # changed SONAME @Versions2 = keys(%{$LibVers2{$LName2}}); if(not @Versions2 or $#Versions2>=1) { next; } $LV2 = $Versions2[0]; $DPath2 = $LibVers2{$LName2}{$LV2}; if(defined $LibVers2{$LName}) { # show old soname in the table $TestResults{$LName}{"v1"} = $LV1; $TestResults{$LName}{"v2"} = $LV1; } if(defined $LibVers2{$LName}) { # do not count results $SONAME_Added{$LName_Short} = 1; } $SONAME_Changed{$LName_Short} = 1; $LName = $LName_Short; } elsif(@Versions2) { $LV2 = $Versions2[0]; $DPath2 = $LibVers2{$LName}{$LV2}; } else { # removed next; } my $ACC_compare = "perl $0 -l $LName -d1 \"$DPath1\" -d2 \"$DPath2\""; my $BinReportPath = "compat_reports/$LName/abi_compat_report.html"; my $SrcReportPath = "compat_reports/$LName/src_compat_report.html"; my $BinReportPath_Full = $SYS_REPORT_PATH."/".$BinReportPath; my $SrcReportPath_Full = $SYS_REPORT_PATH."/".$SrcReportPath; if($BinaryOnly) { $ACC_compare .= " -binary"; $ACC_compare .= " -bin-report-path \"$BinReportPath_Full\""; } if($SourceOnly) { $ACC_compare .= " -source"; $ACC_compare .= " -src-report-path \"$SrcReportPath_Full\""; } if($CheckHeadersOnly) { $ACC_compare .= " -headers-only"; } if($GroupByHeaders) { $ACC_compare .= " -component header"; } if($Quiet) { # quiet mode $ACC_compare .= " -quiet"; } if($LogMode eq "n") { $ACC_compare .= " -logging-mode n"; } elsif($Quiet) { $ACC_compare .= " -logging-mode a"; } if($Debug) { # debug mode $ACC_compare .= " -debug"; printMsg("INFO", "$ACC_compare"); } printMsg("INFO_C", "Checking $LName: "); system($ACC_compare." 1>$TMP_DIR/null 2>$TMP_DIR/$LName.stderr"); if(-s "$TMP_DIR/$LName.stderr") { my $ErrorLog = readFile("$TMP_DIR/$LName.stderr"); chomp($ErrorLog); printMsg("INFO", "Failed ($ErrorLog)"); } else { printMsg("INFO", "Ok"); if($BinaryOnly) { $TestResults{$LName}{"Binary"} = readAttributes($BinReportPath_Full, 0); $TestResults{$LName}{"Binary"}{"path"} = $BinReportPath; } if($SourceOnly) { $TestResults{$LName}{"Source"} = readAttributes($SrcReportPath_Full, 0); $TestResults{$LName}{"Source"}{"path"} = $SrcReportPath; } $TestResults{$LName}{"v1"} = $LV1; $TestResults{$LName}{"v2"} = $LV2; } } my %META_DATA = (); my %STAT = (); foreach my $Comp ("Binary", "Source") { $STAT{$Comp}{"total"} = keys(%TestResults) - keys(%SONAME_Changed); $STAT{$Comp}{"added"} = keys(%Added); $STAT{$Comp}{"removed"} = keys(%Removed); foreach ("added", "removed") { my $Kind = $_."_interfaces"; foreach my $LName (keys(%TestResults)) { next if($SONAME_Changed{$LName}); $STAT{$Comp}{$Kind} += $TestResults{$LName}{$Comp}{$_}; } push(@{$META_DATA{$Comp}}, $Kind.":".$STAT{$Comp}{$Kind}); } foreach my $T ("type", "interface") { foreach my $S ("high", "medium", "low") { my $Kind = $T."_problems_".$S; foreach my $LName (keys(%TestResults)) { next if($SONAME_Changed{$LName}); $STAT{$Comp}{$Kind} += $TestResults{$LName}{$Comp}{$Kind}; } push(@{$META_DATA{$Comp}}, $Kind.":".$STAT{$Comp}{$Kind}); } } foreach my $LName (keys(%TestResults)) { next if($SONAME_Changed{$LName}); foreach ("affected", "changed_constants") { $STAT{$Comp}{$_} += $TestResults{$LName}{$Comp}{$_}; } if(not defined $STAT{$Comp}{"verdict"} and $TestResults{$LName}{$Comp}{"verdict"} eq "incompatible") { $STAT{$Comp}{"verdict"} = "incompatible"; } } if(not defined $STAT{$Comp}{"verdict"}) { $STAT{$Comp}{"verdict"} = "compatible"; } if($STAT{$Comp}{"total"}) { $STAT{$Comp}{"affected"} /= $STAT{$Comp}{"total"}; } else { $STAT{$Comp}{"affected"} = 0; } $STAT{$Comp}{"affected"} = show_number($STAT{$Comp}{"affected"}); if($STAT{$Comp}{"verdict"}>1) { $STAT{$Comp}{"verdict"} = 1; } push(@{$META_DATA{$Comp}}, "changed_constants:".$STAT{$Comp}{"changed_constants"}); push(@{$META_DATA{$Comp}}, "tool_version:".get_dumpversion("perl $0")); foreach ("removed", "added", "total", "affected", "verdict") { @{$META_DATA{$Comp}} = ($_.":".$STAT{$Comp}{$_}, @{$META_DATA{$Comp}}); } } my $SONAME_Title = "SONAME"; if($OStarget eq "windows") { $SONAME_Title = "DLL"; } elsif($OStarget eq "symbian") { $SONAME_Title = "DSO"; } if($GroupByHeaders) { # show the list of headers $SONAME_Title = "Header File"; } my $SYS_REPORT = "

"; if($BinaryOnly and $SourceOnly) { $SYS_REPORT .= "API compatibility"; } elsif($BinaryOnly) { $SYS_REPORT .= "Binary compatibility"; } elsif($SourceOnly) { $SYS_REPORT .= "Source compatibility"; } $SYS_REPORT .= " report between $SystemName1 and $SystemName2"; $SYS_REPORT .= " on ".showArch($ArchName)."\n"; $SYS_REPORT .= "

"; # legend my $LEGEND = "\n"; $LEGEND .= "\n"; $LEGEND .= "\n"; $LEGEND .= "\n"; $LEGEND .= "\n"; $LEGEND .= "\n"; $LEGEND .= "
AddedCompatible
WarningIncompatible
\n"; $SYS_REPORT .= $LEGEND; # test info my $TEST_INFO = "

Test Info


\n"; $TEST_INFO .= "\n"; $TEST_INFO .= "\n"; $TEST_INFO .= "\n"; $TEST_INFO .= "\n"; $TEST_INFO .= "
System #1$SystemName1
System #2$SystemName2
CPU Type".showArch($ArchName)."
\n"; # $SYS_REPORT .= $TEST_INFO; my $Total = (keys(%TestResults) + keys(%Added) + keys(%Removed) - keys(%SONAME_Changed)); # test results my $TEST_RES = "

Test Results


\n"; $TEST_RES .= "\n"; $TEST_RES .= "\n"; if($BinaryOnly and $SourceOnly) { if(my $Affected = $STAT{"Binary"}{"affected"}) { $TEST_RES .= "\n"; } else { $TEST_RES .= "\n"; } if(my $Affected = $STAT{"Source"}{"affected"}) { $TEST_RES .= "\n"; } else { $TEST_RES .= "\n"; } } elsif($BinaryOnly) { if(my $Affected = $STAT{"Binary"}{"affected"}) { $TEST_RES .= "\n"; } else { $TEST_RES .= "\n"; } } elsif($SourceOnly) { if(my $Affected = $STAT{"Source"}{"affected"}) { $TEST_RES .= "\n"; } else { $TEST_RES .= "\n"; } } $TEST_RES .= "
Total Libraries$Total
Binary Compatibility".cut_off_number(100 - $Affected, 3, 1)."%
Binary Compatibility100%
Source Compatibility".cut_off_number(100 - $Affected, 3, 1)."%
Source Compatibility100%
Compatibility".cut_off_number(100 - $Affected, 3, 1)."%
Compatibility100%
Compatibility".cut_off_number(100 - $Affected, 3, 1)."%
Compatibility100%
\n"; $SYS_REPORT .= $TEST_RES; # problem summary foreach my $Comp ("Binary", "Source") { my $PSUMMARY = "

Problem Summary"; if(not $BinaryOnly or not $SourceOnly) { next if($BinaryOnly and $Comp eq "Source"); next if($SourceOnly and $Comp eq "Binary"); } else { $PSUMMARY .= " ($Comp Compatibility)\n"; } $PSUMMARY .= "


\n"; $PSUMMARY .= "\n"; $PSUMMARY .= "\n"; if(my $Added = $STAT{$Comp}{"added_interfaces"}) { $PSUMMARY .= "\n"; } else { $PSUMMARY .= "\n"; } if(my $Removed = $STAT{$Comp}{"removed_interfaces"}) { $PSUMMARY .= "\n"; } else { $PSUMMARY .= "\n"; } $PSUMMARY .= ""; if($BinaryOnly and $SourceOnly) { $PSUMMARY .= ""; } else { $PSUMMARY .= ""; } if(my $High = $STAT{$Comp}{"interface_problems_high"}+$STAT{$Comp}{"type_problems_high"}) { $PSUMMARY .= "\n"; } else { $PSUMMARY .= "\n"; } $PSUMMARY .= ""; $PSUMMARY .= ""; if(my $Medium = $STAT{$Comp}{"interface_problems_medium"}+$STAT{$Comp}{"type_problems_medium"}) { $PSUMMARY .= "\n"; } else { $PSUMMARY .= "\n"; } $PSUMMARY .= ""; $PSUMMARY .= ""; if(my $Low = $STAT{$Comp}{"interface_problems_low"}+$STAT{$Comp}{"type_problems_low"}+$STAT{$Comp}{"changed_constants"}) { $PSUMMARY .= "\n"; } else { $PSUMMARY .= "\n"; } $PSUMMARY .= ""; $PSUMMARY .= "
SeverityCount
Added Symbols-$Added
Added Symbols-0
Removed SymbolsHigh$Removed
Removed SymbolsHigh0
$Comp Compatibility
Problems
Compatibility
Problems
High$HighHigh0
Medium$MediumMedium0
Low$LowLow0
\n"; $SYS_REPORT .= $PSUMMARY; } # added/removed libraries my $LIB_PROBLEMS = "

Added/Removed Libraries


\n"; $LIB_PROBLEMS .= "\n"; $LIB_PROBLEMS .= "\n"; if(my $Added = keys(%Added)) { $LIB_PROBLEMS .= "\n"; } else { $LIB_PROBLEMS .= "\n"; } if(my $Removed = keys(%Removed)) { $LIB_PROBLEMS .= "\n"; } else { $LIB_PROBLEMS .= "\n"; } $LIB_PROBLEMS .= "
SeverityCount
Added-$Added
Added-0
RemovedHigh$Removed
RemovedHigh0
\n"; $SYS_REPORT .= $LIB_PROBLEMS; # report table $SYS_REPORT .= "\n"; $SYS_REPORT .= "

Report


\n"; # $SYS_REPORT .= "
"; $SYS_REPORT .= ""; $SYS_REPORT .= ""; $SYS_REPORT .= ""; if(not $GroupByHeaders) { $SYS_REPORT .= ""; } if($BinaryOnly and $SourceOnly) { $SYS_REPORT .= ""; } else { $SYS_REPORT .= ""; } $SYS_REPORT .= ""; if($BinaryOnly and $SourceOnly) { $SYS_REPORT .= ""; $SYS_REPORT .= ""; } else { $SYS_REPORT .= ""; } $SYS_REPORT .= ""; $SYS_REPORT .= ""; if(not $GroupByHeaders) { $SYS_REPORT .= ""; } if($BinaryOnly and $SourceOnly) { $SYS_REPORT .= ""; } $SYS_REPORT .= "\n" if($BinaryOnly); $SYS_REPORT .= "\n" if($SourceOnly); $SYS_REPORT .= ""; my %RegisteredPairs = (); my $Columns = 2; if($BinaryOnly) { $Columns += 3; } if($SourceOnly) { $Columns += 3; } foreach my $LName (sort {lc($a) cmp lc($b)} (keys(%TestResults), keys(%Added), keys(%Removed))) { next if($SONAME_Changed{$LName}); my $LName_Short = parse_libname($LName, "name+ext", $OStarget); my $Anchor = $LName; $Anchor=~s/\+/p/g; # anchor for libFLAC++ is libFLACpp $Anchor=~s/\~/-/g; # libqttracker.so.1~6 $SYS_REPORT .= "\n\n"; if(defined $Removed{$LName}) { $SYS_REPORT .= "\n"; } elsif(defined $Added{$LName}) { $SYS_REPORT .= "\n"; } elsif(not $GroupByHeaders) { $SYS_REPORT .= "\n"; } my $SONAME_report = ""; if(defined $Added{$LName}) { # added library $SYS_REPORT .= "\n"; $SYS_REPORT .= "\n" if($BinaryOnly); $SYS_REPORT .= "\n" if($SourceOnly); if($RegisteredPairs{$LName}) { # do nothing } elsif(my $To = $ChangedSoname{$LName}) { $RegisteredPairs{$To}=1; $SYS_REPORT .= $SONAME_report; } else { foreach (1 .. $Columns) { $SYS_REPORT .= "\n"; # colspan='5' } } $SYS_REPORT .= "\n"; next; } elsif(defined $Removed{$LName}) { # removed library $SYS_REPORT .= "\n"; $SYS_REPORT .= "\n" if($BinaryOnly); $SYS_REPORT .= "\n" if($SourceOnly); if($RegisteredPairs{$LName}) { # do nothing } elsif(my $To = $ChangedSoname{$LName}) { $RegisteredPairs{$To}=1; $SYS_REPORT .= $SONAME_report; } else { foreach (1 .. $Columns) { $SYS_REPORT .= "\n"; # colspan='5' } } $SYS_REPORT .= "\n"; next; } elsif(defined $ChangedSoname{$LName}) { # added library $SYS_REPORT .= "\n"; $SYS_REPORT .= "\n" if($BinaryOnly); $SYS_REPORT .= "\n" if($SourceOnly); if($RegisteredPairs{$LName}) { # do nothing } elsif(my $To = $ChangedSoname{$LName}) { $RegisteredPairs{$To}=1; $SYS_REPORT .= $SONAME_report; } else { foreach (1 .. $Columns) { $SYS_REPORT .= "\n"; # colspan='5' } } $SYS_REPORT .= "\n"; next; } elsif(not $GroupByHeaders) { $SYS_REPORT .= "\n"; } my $BinCompatReport = $TestResults{$LName}{"Binary"}{"path"}; my $SrcCompatReport = $TestResults{$LName}{"Source"}{"path"}; if($BinaryOnly) { if($TestResults{$LName}{"Binary"}{"verdict"} eq "compatible") { $SYS_REPORT .= "\n"; } else { my $Compatible = 100 - $TestResults{$LName}{"Binary"}{"affected"}; $SYS_REPORT .= "\n"; } } if($SourceOnly) { if($TestResults{$LName}{"Source"}{"verdict"} eq "compatible") { $SYS_REPORT .= "\n"; } else { my $Compatible = 100 - $TestResults{$LName}{"Source"}{"affected"}; $SYS_REPORT .= "\n"; } } if($BinaryOnly) { # show added/removed symbols at binary level # for joined and -binary-only reports my $AddedSym=""; if(my $Count = $TestResults{$LName}{"Binary"}{"added"}) { $AddedSym="$Count new"; } if($AddedSym) { $SYS_REPORT.=""; } else { $SYS_REPORT.=""; } my $RemovedSym=""; if(my $Count = $TestResults{$LName}{"Binary"}{"removed"}) { $RemovedSym="$Count removed"; } if($RemovedSym) { $SYS_REPORT.=""; } else { $SYS_REPORT.=""; } } elsif($SourceOnly) { my $AddedSym=""; if(my $Count = $TestResults{$LName}{"Source"}{"added"}) { $AddedSym="$Count new"; } if($AddedSym) { $SYS_REPORT.=""; } else { $SYS_REPORT.=""; } my $RemovedSym=""; if(my $Count = $TestResults{$LName}{"Source"}{"removed"}) { $RemovedSym="$Count removed"; } if($RemovedSym) { $SYS_REPORT.=""; } else { $SYS_REPORT.=""; } } if($BinaryOnly) { my $High=""; if(my $Count = $TestResults{$LName}{"Binary"}{"type_problems_high"}+$TestResults{$LName}{"Binary"}{"interface_problems_high"}) { $High="".problem_title($Count).""; } if($High) { $SYS_REPORT.=""; } else { $SYS_REPORT.=""; } my $Medium=""; if(my $Count = $TestResults{$LName}{"Binary"}{"type_problems_medium"}+$TestResults{$LName}{"Binary"}{"interface_problems_medium"}) { $Medium="".problem_title($Count).""; } if($Medium) { $SYS_REPORT.=""; } else { $SYS_REPORT.=""; } my $Low=""; if(my $Count = $TestResults{$LName}{"Binary"}{"type_problems_low"}+$TestResults{$LName}{"Binary"}{"interface_problems_low"}+$TestResults{$LName}{"Binary"}{"changed_constants"}) { $Low="".warning_title($Count).""; } if($Low) { $SYS_REPORT.=""; } else { $SYS_REPORT.=""; } } if($SourceOnly) { my $High=""; if(my $Count = $TestResults{$LName}{"Source"}{"type_problems_high"}+$TestResults{$LName}{"Source"}{"interface_problems_high"}) { $High="".problem_title($Count).""; } if($High) { $SYS_REPORT.=""; } else { $SYS_REPORT.=""; } my $Medium=""; if(my $Count = $TestResults{$LName}{"Source"}{"type_problems_medium"}+$TestResults{$LName}{"Source"}{"interface_problems_medium"}) { $Medium="".problem_title($Count).""; } if($Medium) { $SYS_REPORT.=""; } else { $SYS_REPORT.=""; } my $Low=""; if(my $Count = $TestResults{$LName}{"Source"}{"type_problems_low"}+$TestResults{$LName}{"Source"}{"interface_problems_low"}+$TestResults{$LName}{"Source"}{"changed_constants"}) { $Low="".warning_title($Count).""; } if($Low) { $SYS_REPORT.=""; } else { $SYS_REPORT.=""; } } $SYS_REPORT .= "\n"; } # bottom header $SYS_REPORT .= ""; $SYS_REPORT .= ""; if(not $GroupByHeaders) { $SYS_REPORT .= ""; } if($BinaryOnly and $SourceOnly) { $SYS_REPORT .= ""; } else { $SYS_REPORT .= ""; } $SYS_REPORT .= ""; $SYS_REPORT .= "" if($BinaryOnly); $SYS_REPORT .= "" if($SourceOnly); $SYS_REPORT .= ""; $SYS_REPORT .= ""; if(not $GroupByHeaders) { $SYS_REPORT .= ""; } if($BinaryOnly and $SourceOnly) { $SYS_REPORT .= ""; } if($BinaryOnly and $SourceOnly) { $SYS_REPORT .= ""; $SYS_REPORT .= ""; } else { $SYS_REPORT .= ""; } $SYS_REPORT .= ""; $SYS_REPORT .= "
$SONAME_Title$TotalVersionCompatibleCompatibleAdded
Symbols
Removed
Symbols
API Changes / Binary CompatibilityAPI Changes / Source CompatibilityAPI Changes / Compatibility
$SystemName1$SystemName2BinarySourceHighMediumLowHighMediumLow
$LName".printVer($Removed{$LName}{"version"})."added".printVer($TestResults{$LName}{"v1"}).""; if($BinaryOnly and $SourceOnly) { $SONAME_report .= "SONAME has been changed (see binary and source compatibility reports)\n"; } elsif($BinaryOnly) { $SONAME_report .= "SONAME has been changed\n"; } elsif($SourceOnly) { $SONAME_report .= "SONAME has been changed\n"; } $SONAME_report .= "".printVer($Added{$LName}{"version"})."100%100%n/a
removed0%0%n/a
".printVer($TestResults{$LName}{"v2"})."100%100%n/a
".printVer($TestResults{$LName}{"v2"})."100%$Compatible%100%$Compatible%$AddedSym0$RemovedSym0$AddedSym0$RemovedSym0$High0$Medium0$Low0$High0$Medium0$Low0
$SONAME_Title$SystemName1$SystemName2BinarySourceCompatibleAdded
Symbols
Removed
Symbols
HighMediumLowHighMediumLow
VersionCompatibleAPI Changes / Binary CompatibilityAPI Changes / Source CompatibilityAPI Changes / Compatibility
"; my $Title = "$SystemName1 to $SystemName2 compatibility report"; my $Keywords = "compatibility, $SystemName1, $SystemName2, API, changes"; my $Description = "API compatibility report between $SystemName1 and $SystemName2 on ".showArch($ArchName); my $Styles = readModule("Styles", "CmpSystems.css"); $SYS_REPORT = composeHTML_Head($Title, $Keywords, $Description, $Styles, "")."\n\n
".$SYS_REPORT."
\n"; $SYS_REPORT .= "



\n".getReportFooter($SystemName2, 1)."
\n"; if($SourceOnly) { $SYS_REPORT = "\n".$SYS_REPORT; } if($BinaryOnly) { $SYS_REPORT = "\n".$SYS_REPORT; } my $REPORT_PATH = $SYS_REPORT_PATH."/"; if($BinaryOnly and $SourceOnly) { $REPORT_PATH .= "compat_report.html"; } elsif($BinaryOnly) { $REPORT_PATH .= "abi_compat_report.html"; } elsif($SourceOnly) { $REPORT_PATH .= "src_compat_report.html"; } writeFile($REPORT_PATH, $SYS_REPORT); printMsg("INFO", "see detailed report:\n $REPORT_PATH"); } sub printVer($) { if($_[0] eq "") { return 0; } return $_[0]; } sub getPrefix_S($) { my $Prefix = getPrefix($_[0]); if(not $Prefix or defined $NonPrefix{lc($Prefix)}) { return "NONE"; } return $Prefix; } sub problem_title($) { if($_[0]==1) { return "1 change"; } else { return $_[0]." changes"; } } sub warning_title($) { if($_[0]==1) { return "1 warning"; } else { return $_[0]." warnings"; } } sub readSystemDescriptor($) { my $Content = $_[0]; $Content=~s/\/\*(.|\n)+?\*\///g; $Content=~s/<\!--(.|\n)+?-->//g; $SysDescriptor{"Name"} = parseTag(\$Content, "name"); my @Tools = (); if(not $SysDescriptor{"Name"}) { exitStatus("Error", "system name is not specified ( section)"); } foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "libs"))) { # target libs if(not -e $Path) { exitStatus("Access_Error", "can't access \'$Path\'"); } $Path = get_abs_path($Path); $SysDescriptor{"Libs"}{clean_path($Path)} = 1; } foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_libs"))) { # target libs if(not -d $Path) { exitStatus("Access_Error", "can't access directory \'$Path\'"); } $Path = get_abs_path($Path); $SysDescriptor{"SearchLibs"}{clean_path($Path)} = 1; } foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_libs"))) { # skip libs $SysDescriptor{"SkipLibs"}{$Path} = 1; } foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "headers"))) { if(not -e $Path) { exitStatus("Access_Error", "can't access \'$Path\'"); } $Path = get_abs_path($Path); $SysDescriptor{"Headers"}{clean_path($Path)} = 1; } foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_headers"))) { if(not -d $Path) { exitStatus("Access_Error", "can't access directory \'$Path\'"); } $Path = get_abs_path($Path); $SysDescriptor{"SearchHeaders"}{clean_path($Path)} = 1; } foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "tools"))) { if(not -d $Path) { exitStatus("Access_Error", "can't access directory \'$Path\'"); } $Path = get_abs_path($Path); $Path = clean_path($Path); $SysDescriptor{"Tools"}{$Path} = 1; push(@Tools, $Path); } foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "gcc_options"))) { $SysDescriptor{"GccOpts"}{clean_path($Path)} = 1; } if($SysDescriptor{"CrossPrefix"} = parseTag(\$Content, "cross_prefix")) { # section of XML descriptor $CrossPrefix = $SysDescriptor{"CrossPrefix"}; } elsif($CrossPrefix) { # -cross-prefix tool option $SysDescriptor{"CrossPrefix"} = $CrossPrefix; } $SysDescriptor{"Defines"} = parseTag(\$Content, "defines"); if($SysDescriptor{"Image"} = parseTag(\$Content, "image")) { # # FIXME: isn't implemented yet if(not -f $SysDescriptor{"Image"}) { exitStatus("Access_Error", "can't access \'".$SysDescriptor{"Image"}."\'"); } } return {"Tools"=>\@Tools,"CrossPrefix"=>$CrossPrefix}; } sub initModule($) { my $S = $_[0]; $OStarget = $S->{"OStarget"}; $Debug = $S->{"Debug"}; $Quiet = $S->{"Quiet"}; $LogMode = $S->{"LogMode"}; $CheckHeadersOnly = $S->{"CheckHeadersOnly"}; $SystemRoot = $S->{"SystemRoot"}; $MODULES_DIR = $S->{"MODULES_DIR"}; $GCC_PATH = $S->{"GCC_PATH"}; $TargetSysInfo = $S->{"TargetSysInfo"}; $CrossPrefix = $S->{"CrossPrefix"}; $TargetLibraryName = $S->{"TargetLibraryName"}; $CrossGcc = $S->{"CrossGcc"}; $UseStaticLibs = $S->{"UseStaticLibs"}; $NoStdInc = $S->{"NoStdInc"}; $BinaryOnly = $S->{"BinaryOnly"}; $SourceOnly = $S->{"SourceOnly"}; if(not $BinaryOnly and not $SourceOnly) { # default $BinaryOnly = 1; } } sub check_list($$) { my ($Item, $Skip) = @_; return 0 if(not $Skip); foreach (@{$Skip}) { my $Pattern = $_; if(index($Pattern, "*")!=-1) { # wildcards $Pattern=~s/\*/.*/g; # to perl format if($Item=~/$Pattern/) { return 1; } } elsif(index($Pattern, "/")!=-1 or index($Pattern, "\\")!=-1) { # directory if(index($Item, $Pattern)!=-1) { return 1; } } elsif($Item eq $Pattern or get_filename($Item) eq $Pattern) { # by name return 1; } } return 0; } sub filter_format($) { my $FiltRef = $_[0]; foreach my $Entry (keys(%{$FiltRef})) { foreach my $Filt (@{$FiltRef->{$Entry}}) { if($Filt=~/[\/\\]/) { $Filt = path_format($Filt, $OSgroup); } } } } sub read_sys_descriptor($) { my $Path = $_[0]; my $Content = readFile($Path); my %Tags = ( "headers" => "mf", "skip_headers" => "mf", "skip_including" => "mf", "skip_include_paths" => "mf", "skip_libs" => "mf", "include_preamble" => "mf", "add_include_paths" => "mf", "gcc_options" => "m", "skip_symbols" => "m", "skip_types" => "m", "ignore_symbols" => "h", "non_prefix" => "h", "defines" => "s" ); my %DInfo = (); foreach my $Tag (keys(%Tags)) { if(my $TContent = parseTag(\$Content, $Tag)) { if($Tags{$Tag}=~/m/) { # multi-line (+order) my @Items = split(/\s*\n\s*/, $TContent); $DInfo{$Tag} = []; foreach my $Item (@Items) { if($Tags{$Tag}=~/f/) { $Item = path_format($Item, $OSgroup); } push(@{$DInfo{$Tag}}, $Item); } } elsif($Tags{$Tag}=~/s/) { # single element $DInfo{$Tag} = $TContent; } else { # hash array my @Items = split(/\s*\n\s*/, $TContent); foreach my $Item (@Items) { $DInfo{$Tag}{$Item}=1; } } } } if(defined $DInfo{"non_self_compiled"}) { # support for old ABI dumps $DInfo{"skip_including"} = $DInfo{"non_self_compiled"}; } return \%DInfo; } sub read_sys_info($) { my $Target = $_[0]; my $SYS_INFO_PATH = $MODULES_DIR."/Targets"; if(-d $SYS_INFO_PATH."/".$Target) { # symbian, windows $SYS_INFO_PATH .= "/".$Target; } else { # default $SYS_INFO_PATH .= "/unix"; } if($TargetSysInfo) { # user-defined target $SYS_INFO_PATH = $TargetSysInfo; } if(not -d $SYS_INFO_PATH) { exitStatus("Module_Error", "can't access \'$SYS_INFO_PATH\'"); } # Library Specific Info my %SysInfo = (); if(not -d $SYS_INFO_PATH."/descriptors/") { exitStatus("Module_Error", "can't access \'$SYS_INFO_PATH/descriptors\'"); } foreach my $DPath (cmd_find($SYS_INFO_PATH."/descriptors/","f","",1)) { my $LSName = get_filename($DPath); $LSName=~s/\.xml\Z//; $SysInfo{$LSName} = read_sys_descriptor($DPath); } # Exceptions if(check_gcc($GCC_PATH, "4.4")) { # exception for libstdc++ $SysInfo{"libstdc++"}{"gcc_options"} = ["-std=c++0x"]; } if($OStarget eq "symbian") { # exception for libstdcpp $SysInfo{"libstdcpp"}{"defines"} = "namespace std { struct nothrow_t {}; }"; } if($SysDescriptor{"Name"}=~/maemo/i) { # GL/gl.h: No such file $SysInfo{"libSDL"}{"skip_headers"}=["SDL_opengl.h"]; } # Common Info if(not -f $SYS_INFO_PATH."/common.xml") { exitStatus("Module_Error", "can't access \'$SYS_INFO_PATH/common.xml\'"); } my $SysCInfo = read_sys_descriptor($SYS_INFO_PATH."/common.xml"); my @CompilerOpts = (); if($SysDescriptor{"Name"}=~/maemo|meego/i) { push(@CompilerOpts, "-DMAEMO_CHANGES", "-DM_APPLICATION_NAME=\\\"app\\\""); } if(my @Opts = keys(%{$SysDescriptor{"GccOpts"}})) { push(@CompilerOpts, @Opts); } if(@CompilerOpts) { if(not $SysCInfo->{"gcc_options"}) { $SysCInfo->{"gcc_options"} = []; } push(@{$SysCInfo->{"gcc_options"}}, @CompilerOpts); } return (\%SysInfo, $SysCInfo); } sub get_binversion($) { my $Path = $_[0]; if($OStarget eq "windows" and $LIB_EXT eq "dll") { # get version of DLL using "sigcheck" my $SigcheckCmd = get_CmdPath("sigcheck"); if(not $SigcheckCmd) { return ""; } my $VInfo = `$SigcheckCmd -n $Path 2>$TMP_DIR/null`; $VInfo=~s/\s*\(.*\)\s*//; chomp($VInfo); return $VInfo; } return ""; } sub readBytes($) { sysopen(FILE, $_[0], O_RDONLY); sysread(FILE, my $Header, 4); close(FILE); my @Bytes = map { sprintf('%02x', ord($_)) } split (//, $Header); return join("", @Bytes); } sub dumpSystem($) { # -dump-system option handler # should be used with -sysroot and -cross-gcc options my $Opts = $_[0]; initModule($Opts); my $SYS_DUMP_PATH = "sys_dumps/".$SysDescriptor{"Name"}."/".getArch(1); if(not $TargetLibraryName) { rmtree($SYS_DUMP_PATH); } my (@SystemLibs, @SysHeaders) = (); foreach my $Path (keys(%{$SysDescriptor{"Libs"}})) { if(not -e $Path) { exitStatus("Access_Error", "can't access \'$Path\'"); } if(-d $Path) { if(my @SubLibs = find_libs($Path,"",1)) { push(@SystemLibs, @SubLibs); } $SysDescriptor{"SearchLibs"}{$Path}=1; } else { # single file push(@SystemLibs, $Path); $SysDescriptor{"SearchLibs"}{get_dirname($Path)}=1; } } foreach my $Path (keys(%{$SysDescriptor{"Headers"}})) { if(not -e $Path) { exitStatus("Access_Error", "can't access \'$Path\'"); } if(-d $Path) { if(my @SubHeaders = cmd_find($Path,"f","","")) { push(@SysHeaders, @SubHeaders); } $SysDescriptor{"SearchHeaders"}{$Path}=1; } else { # single file push(@SysHeaders, $Path); $SysDescriptor{"SearchHeaders"}{get_dirname($Path)}=1; } } my $GroupByHeaders = 0; if($CheckHeadersOnly) { # -headers-only $GroupByHeaders = 1; # @SysHeaders = optimize_set(@SysHeaders); } elsif($SysDescriptor{"Image"}) { # one big image $GroupByHeaders = 1; @SystemLibs = ($SysDescriptor{"Image"}); } writeFile($SYS_DUMP_PATH."/target.txt", $OStarget); my (%SysLib_Symbols, %SymbolGroup, %Symbol_SysHeaders, %SysHeader_Symbols, %SysLib_SysHeaders) = (); my (%Skipped, %Failed) = (); my (%SysHeaderDir_Used, %SysHeaderDir_SysHeaders) = (); my (%SymbolCounter, %TotalLibs) = (); my (%PrefixToLib, %LibPrefix, %PrefixSymbols) = (); my %Glibc = map {$_=>1} ( "libc", "libpthread" ); my ($SysInfo, $SysCInfo) = read_sys_info($OStarget); foreach (keys(%{$SysCInfo->{"non_prefix"}})) { $NonPrefix{$_} = 1; $NonPrefix{$_."_"} = 1; $NonPrefix{"_".$_} = 1; $NonPrefix{"_".$_."_"} = 1; } if(not $GroupByHeaders) { if($Debug) { printMsg("INFO", localtime(time)); } printMsg("INFO", "Indexing sonames ...\n"); } my (%LibSoname, %SysLibVersion) = (); my %DevelPaths = map {$_=>1} @SystemLibs; foreach my $Path (sort keys(%{$SysDescriptor{"SearchLibs"}})) { foreach my $LPath (find_libs($Path,"",1)) { $DevelPaths{$LPath}=1; } } foreach my $LPath (keys(%DevelPaths)) { # register SONAMEs my $LName = get_filename($LPath); if(not is_target_lib($LName)) { next; } if($OSgroup=~/\A(linux|macos|freebsd)\Z/ and $LName!~/\Alib/) { next; } if(my $Soname = getSONAME($LPath)) { if($OStarget eq "symbian") { if($Soname=~/[\/\\]/) { # L://epoc32/release/armv5/lib/gfxtrans{000a0000}.dso $Soname = get_filename($Soname); } $Soname = lc($Soname); } if(not defined $LibSoname{$LName}) { $LibSoname{$LName}=$Soname; } if(-l $LPath and my $Path = resolve_symlink($LPath)) { my $Name = get_filename($Path); if(not defined $LibSoname{$Name}) { $LibSoname{$Name}=$Soname; } } } else { # windows and others $LibSoname{$LName}=$LName; } } my $SONAMES = ""; foreach (sort {lc($a) cmp lc($b)} keys(%LibSoname)) { $SONAMES .= $_.";".$LibSoname{$_}."\n"; } if(not $GroupByHeaders) { writeFile($SYS_DUMP_PATH."/sonames.txt", $SONAMES); } foreach my $LPath (sort keys(%DevelPaths)) { # register VERSIONs my $LName = get_filename($LPath); if(not is_target_lib($LName) and not is_target_lib($LibSoname{$LName})) { next; } if(my $BV = get_binversion($LPath)) { # binary version $SysLibVersion{$LName} = $BV; } elsif(my $PV = parse_libname($LName, "version", $OStarget)) { # source version $SysLibVersion{$LName} = $PV; } elsif(my $SV = parse_libname(getSONAME($LPath), "version", $OStarget)) { # soname version $SysLibVersion{$LName} = $SV; } elsif($LName=~/(\d[\d\.\-\_]*)\.$LIB_EXT\Z/) { # libfreebl3.so if($1 ne 32 and $1 ne 64) { $SysLibVersion{$LName} = $1; } } } my $VERSIONS = ""; foreach (sort {lc($a) cmp lc($b)} keys(%SysLibVersion)) { $VERSIONS .= $_.";".$SysLibVersion{$_}."\n"; } if(not $GroupByHeaders) { writeFile($SYS_DUMP_PATH."/versions.txt", $VERSIONS); } # create target list my @SkipLibs = keys(%{$SysDescriptor{"SkipLibs"}}); if(my $CSkip = $SysCInfo->{"skip_libs"}) { push(@SkipLibs, @{$CSkip}); } if(@SkipLibs and not $TargetLibraryName) { my %SkipLibs = map {$_ => 1} @SkipLibs; my @Target = (); foreach my $LPath (@SystemLibs) { my $LName = get_filename($LPath); my $LName_Short = parse_libname($LName, "name+ext", $OStarget); if(not defined $SkipLibs{$LName_Short} and not defined $SkipLibs{$LName} and not check_list($LPath, \@SkipLibs)) { push(@Target, $LName); } } add_target_libs(\@Target); } my %SysLibs = (); foreach my $LPath (sort @SystemLibs) { my $LName = get_filename($LPath); my $LSName = parse_libname($LName, "short", $OStarget); my $LRelPath = cut_path_prefix($LPath, $SystemRoot); if(not is_target_lib($LName)) { next; } if($OSgroup=~/\A(linux|macos|freebsd)\Z/ and $LName!~/\Alib/) { next; } if($OStarget eq "symbian") { if(my $V = parse_libname($LName, "version", $OStarget)) { # skip qtcore.dso # register qtcore{00040604}.dso delete($SysLibs{get_dirname($LPath)."\\".$LSName.".".$LIB_EXT}); my $MV = parse_libname($LibSoname{$LSName.".".$LIB_EXT}, "version", $OStarget); if($MV and $V ne $MV) { # skip other versions: # qtcore{00040700}.dso # qtcore{00040702}.dso next; } } } if(-l $LPath) { # symlinks if(my $Path = resolve_symlink($LPath)) { $SysLibs{$Path} = 1; } } elsif(-f $LPath) { if($Glibc{$LSName} and cmd_file($LPath)=~/ASCII/) { # GNU ld scripts (libc.so, libpthread.so) my @Candidates = cmd_find($SystemRoot."/lib","",$LSName.".".$LIB_EXT."*","1"); if(@Candidates) { my $Candidate = $Candidates[0]; if(-l $Candidate and my $Path = resolve_symlink($Candidate)) { $Candidate = $Path; } $SysLibs{$Candidate} = 1; } } else { $SysLibs{$LPath} = 1; } } } @SystemLibs = (); # clear memory if(not $CheckHeadersOnly) { if($Debug) { printMsg("INFO", localtime(time)); } if($SysDescriptor{"Image"}) { printMsg("INFO", "Reading symbols from image ...\n"); } else { printMsg("INFO", "Reading symbols from libraries ...\n"); } } my %Syms = (); my @AllSyms = {}; my %ShortestNames = (); foreach my $LPath (sort {lc($a) cmp lc($b)} keys(%SysLibs)) { my $LRelPath = cut_path_prefix($LPath, $SystemRoot); my $LName = get_filename($LPath); $ShortestNames{$LPath} = parse_libname($LName, "shortest", $OStarget); my $Res = readSymbols_Lib(1, $LPath, 0, "-Weak", 0, 0); $Syms{$LPath} = $Res->{$LName}; push(@AllSyms, keys(%{$Syms{$LPath}})); } my $Translate = translateSymbols(@AllSyms, 1); my %DupSymbols = (); foreach my $LPath (sort {lc($a) cmp lc($b)} keys(%SysLibs)) { my $LRelPath = cut_path_prefix($LPath, $SystemRoot); my $LName = get_filename($LPath); foreach my $Symbol (keys(%{$Syms{$LPath}})) { $Symbol=~s/[\@\$]+(.*)\Z//g; if($Symbol=~/\A(_Z|\?)/) { if(isPrivateData($Symbol)) { next; } if($Symbol=~/(C1|C2|D0|D1|D2)E/) { # do NOT analyze constructors # and destructors next; } my $Unmangled = $Translate->{$Symbol}; $Unmangled=~s/<.+>//g; if($Unmangled=~/\A([\w:]+)/) { # cut out the parameters my @Elems = split(/::/, $1); my ($Class, $Short) = ("", ""); $Short = $Elems[$#Elems]; if($#Elems>=1) { $Class = $Elems[$#Elems-1]; pop(@Elems); } # the short and class name should be # matched in one header file $SymbolGroup{$LRelPath}{$Class} = $Short; foreach my $Sym (@Elems) { if($SysCInfo->{"ignore_symbols"}{$Symbol}) { # do NOT match this symbol next; } $SysLib_Symbols{$LPath}{$Sym} = 1; if(my $Prefix = getPrefix_S($Sym)) { $PrefixToLib{$Prefix}{$LName} += 1; $LibPrefix{$LPath}{$Prefix} += 1; $PrefixSymbols{$LPath}{$Prefix}{$Sym} = 1; } $SymbolCounter{$Sym}{$LPath} = 1; if(my @Libs = keys(%{$SymbolCounter{$Sym}})) { if($#Libs>=1) { foreach (@Libs) { $DupSymbols{$_}{$Sym} = 1; } } } } } } else { if($SysCInfo->{"ignore_symbols"}{$Symbol}) { # do NOT match this symbol next; } $SysLib_Symbols{$LPath}{$Symbol} = 1; if(my $Prefix = getPrefix_S($Symbol)) { $PrefixToLib{$Prefix}{$LName} += 1; $LibPrefix{$LPath}{$Prefix} += 1; $PrefixSymbols{$LPath}{$Prefix}{$Symbol} = 1; } $SymbolCounter{$Symbol}{$LPath} = 1; if(my @Libs = keys(%{$SymbolCounter{$Symbol}})) { if($#Libs>=1) { foreach (@Libs) { $DupSymbols{$_}{$Symbol} = 1; } } } } } } %Syms = (); %{$Translate} = (); # remove minor symbols foreach my $LPath (keys(%SysLib_Symbols)) { my $SName = $ShortestNames{$LPath}; my $Count = keys(%{$SysLib_Symbols{$LPath}}); my %Prefixes = %{$LibPrefix{$LPath}}; my @Prefixes = sort {$Prefixes{$b}<=>$Prefixes{$a}} keys(%Prefixes); # print "$LPath ".Dumper(\%Prefixes); if($#Prefixes>=1) { my $MaxPrefix = $Prefixes[0]; if($MaxPrefix eq "NONE") { $MaxPrefix = $Prefixes[1]; } my $Max = $Prefixes{$MaxPrefix}; my $None = $Prefixes{"NONE"}; next if($None*100/$Count>=50); next if($None>=$Max); foreach my $Prefix (@Prefixes) { next if($Prefix eq $MaxPrefix); my $Num = $Prefixes{$Prefix}; my $Rm = 0; if($Prefix eq "NONE") { $Rm = 1; } else { if($Num*100/$Max<5) { $Rm = 1; } } if($Rm) { next if($Prefix=~/\Q$MaxPrefix\E/i); next if($MaxPrefix=~/\Q$Prefix\E/i); next if($Prefix=~/\Q$SName\E/i); # print "Removing $Prefix $Num\n"; foreach my $Symbol (keys(%{$PrefixSymbols{$LPath}{$Prefix}})) { delete($SysLib_Symbols{$LPath}{$Symbol}); } } } } } %PrefixSymbols = (); # free memory if(not $CheckHeadersOnly) { writeFile($SYS_DUMP_PATH."/debug/symbols.txt", Dumper(\%SysLib_Symbols)); } my (%DupLibs, %VersionedLibs) = (); foreach my $LPath (sort keys(%DupSymbols)) { # match duplicated libs # libmenu contains all symbols from libmenuw my @Syms = keys(%{$SysLib_Symbols{$LPath}}); next if($#Syms==-1); if($#Syms+1==keys(%{$DupSymbols{$LPath}})) { $DupLibs{$LPath} = 1; } } foreach my $Prefix (keys(%PrefixToLib)) { my @Libs = keys(%{$PrefixToLib{$Prefix}}); @Libs = sort {$PrefixToLib{$Prefix}{$b}<=>$PrefixToLib{$Prefix}{$a}} @Libs; $PrefixToLib{$Prefix} = $Libs[0]; } my %PackageFile = (); # to improve results my %FilePackage = (); my %LibraryFile = (); if(0) { if($Debug) { printMsg("INFO", localtime(time)); } printMsg("INFO", "Reading info from packages ...\n"); if(my $Urpmf = get_CmdPath("urpmf")) { # Mandriva, ROSA my $Out = $TMP_DIR."/urpmf.out"; system("urpmf : >\"$Out\""); open(FILE, $Out); while() { chomp($_); if(my $M = index($_, ":")) { my $Pkg = substr($_, 0, $M); my $File = substr($_, $M+1); $PackageFile{$Pkg}{$File} = 1; $FilePackage{$File} = $Pkg; } } close(FILE); } } if(keys(%FilePackage)) { foreach my $LPath (sort {lc($a) cmp lc($b)} keys(%SysLibs)) { my $LName = get_filename($LPath); my $LDir = get_dirname($LPath); my $LName_Short = parse_libname($LName, "name+ext", $OStarget); my $Pkg = $FilePackage{$LDir."/".$LName_Short}; if(not $Pkg) { my $RPkg = $FilePackage{$LPath}; if(defined $PackageFile{$RPkg."-devel"}) { $Pkg = $RPkg."-devel"; } if($RPkg=~s/[\d\.]+\Z//g) { if(defined $PackageFile{$RPkg."-devel"}) { $Pkg = $RPkg."-devel"; } } } if($Pkg) { foreach (keys(%{$PackageFile{$Pkg}})) { if(index($_, "/usr/include/")==0) { $LibraryFile{$LPath}{$_} = 1; } } } $LName_Short=~s/\.so\Z/.a/; if($Pkg = $FilePackage{$LDir."/".$LName_Short}) { # headers for static library foreach (keys(%{$PackageFile{$Pkg}})) { if(index($_, "/usr/include/")==0) { $LibraryFile{$LPath}{$_} = 1; } } } } } my %HeaderFile_Path = (); if($Debug) { printMsg("INFO", localtime(time)); } printMsg("INFO", "Reading symbols from headers ...\n"); foreach my $HPath (@SysHeaders) { $HPath = path_format($HPath, $OSgroup); if(readBytes($HPath) eq "7f454c46") { # skip ELF files next; } my $HRelPath = cut_path_prefix($HPath, $SystemRoot); my ($HDir, $HName) = separate_path($HRelPath); if(is_not_header($HName)) { # have a wrong extension: .gch, .in next; } if($HName=~/~\Z/) { # reserved copy next; } if(index($HRelPath, "/_gen")!=-1) { # telepathy-1.0/telepathy-glib/_gen # telepathy-1.0/libtelepathy/_gen-tp-constants-deprecated.h next; } if(index($HRelPath, "include/linux/")!=-1) { # kernel-space headers next; } if(index($HRelPath, "include/asm/")!=-1) { # asm headers next; } if(index($HRelPath, "/microb-engine/")!=-1) { # MicroB engine (Maemo 4) next; } if($HRelPath=~/\Wprivate(\W|\Z)/) { # private directories (include/tcl-private, ...) next; } if(index($HRelPath, "/lib/")!=-1) { if(not is_header_file($HName)) { # without or with a wrong extension # under the /lib directory next; } } my $Content = readFile($HPath); $Content=~s/\/\*(.|\n)+?\*\///g; $Content=~s/\/\/.*?\n//g; # remove comments $Content=~s/#\s*define[^\n\\]*(\\\n[^\n\\]*)+\n*//g; # remove defines $Content=~s/#[^\n]*?\n//g; # remove directives $Content=~s/(\A|\n)class\s+\w+;\n//g; # remove forward declarations # FIXME: try to add preprocessing stage foreach my $Symbol (split(/\W+/, $Content)) { next if(not $Symbol); $Symbol_SysHeaders{$Symbol}{$HRelPath} = 1; $SysHeader_Symbols{$HRelPath}{$Symbol} = 1; } $SysHeaderDir_SysHeaders{$HDir}{$HName} = 1; $HeaderFile_Path{get_filename($HRelPath)}{$HRelPath} = 1; } # writeFile($SYS_DUMP_PATH."/debug/headers.txt", Dumper(\%SysHeader_Symbols)); my %SkipDHeaders = ( # header files, that should be in the section # but should be matched in the algorithm # MeeGo 1.2 Harmattan "libtelepathy-qt4" => ["TelepathyQt4/_gen", "client.h", "TelepathyQt4/*-*", "debug.h", "global.h", "properties.h", "Channel", "channel.h", "message.h"], ); filter_format(\%SkipDHeaders); if(not $GroupByHeaders) { if($Debug) { printMsg("INFO", localtime(time)); } printMsg("INFO", "Matching symbols ...\n"); } foreach my $LPath (sort {lc($a) cmp lc($b)} keys(%SysLibs)) { # matching my $LName = get_filename($LPath); } foreach my $LPath (sort {lc($a) cmp lc($b)} keys(%SysLibs)) { # matching my $LName = get_filename($LPath); my $LName_Short = parse_libname($LName, "name", $OStarget); my $LRelPath = cut_path_prefix($LPath, $SystemRoot); my $LSName = parse_libname($LName, "short", $OStarget); my $SName = $ShortestNames{$LPath}; my @TryNames = (); # libX-N.so.M if(my $Ver = $SysLibVersion{$LName}) { # libX-N-M if($LSName."-".$Ver ne $LName_Short) { push(@TryNames, $LName_Short."-".$Ver); #while($Ver=~s/\.\d+\Z//) { # partial versions # push(@TryNames, $LName_Short."-".$Ver); #} } } push(@TryNames, $LName_Short); # libX-N if($LSName ne $LName_Short) { # libX push(@TryNames, $LSName); } if($LRelPath=~/\/debug\//) { # debug libs $Skipped{$LRelPath} = 1; next; } $TotalLibs{$LRelPath} = 1; $SysLib_SysHeaders{$LRelPath} = (); my (%SymbolDirs, %SymbolFiles) = (); foreach my $Symbol (sort {length($b) cmp length($a)} sort keys(%{$SysLib_Symbols{$LPath}})) { if($SysCInfo->{"ignore_symbols"}{$Symbol}) { next; } if(not $DupLibs{$LPath} and not $VersionedLibs{$LPath} and keys(%{$SymbolCounter{$Symbol}})>=2 and my $Prefix = getPrefix_S($Symbol)) { # duplicated symbols if($PrefixToLib{$Prefix} and $PrefixToLib{$Prefix} ne $LName and not $Glibc{$LSName}) { next; } } if(length($Symbol)<=2) { next; } if($Symbol!~/[A-Z_0-9]/ and length($Symbol)<10 and keys(%{$Symbol_SysHeaders{$Symbol}})>=3) { # undistinguished symbols # FIXME: improve this filter # signalfd (libc.so) # regcomp (libpcreposix.so) next; } if($Symbol=~/\A(_M_|_Rb_|_S_)/) { # _M_insert, _Rb_tree, _S_destroy_c_locale next; } if($Symbol=~/\A[A-Z][a-z]+\Z/) { # Clone, Initialize, Skip, Unlock, Terminate, Chunk next; } if($Symbol=~/\A[A-Z][A-Z]\Z/) { # BC, PC, UP, SP next; } if($Symbol=~/_t\Z/) { # pthread_mutex_t, wchar_t next; } my @SymHeaders = keys(%{$Symbol_SysHeaders{$Symbol}}); @SymHeaders = sort {lc($a) cmp lc($b)} @SymHeaders; # sort by name @SymHeaders = sort {length(get_dirname($a))<=>length(get_dirname($b))} @SymHeaders; # sort by length if(length($SName)>=3) { # sort candidate headers by name @SymHeaders = sort {$b=~/\Q$SName\E/i<=>$a=~/\Q$SName\E/i} @SymHeaders; } else { # libz, libX11 @SymHeaders = sort {$b=~/lib\Q$SName\E/i<=>$a=~/lib\Q$SName\E/i} @SymHeaders; @SymHeaders = sort {$b=~/\Q$SName\Elib/i<=>$a=~/\Q$SName\Elib/i} @SymHeaders; } @SymHeaders = sort {$b=~/\Q$LSName\E/i<=>$a=~/\Q$LSName\E/i} @SymHeaders; @SymHeaders = sort {$SymbolDirs{get_dirname($b)}<=>$SymbolDirs{get_dirname($a)}} @SymHeaders; @SymHeaders = sort {$SymbolFiles{get_filename($b)}<=>$SymbolFiles{get_filename($a)}} @SymHeaders; foreach my $HRelPath (@SymHeaders) { my $HDir = get_dirname($HRelPath); my $HName = get_filename($HRelPath); if(my $Group = $SymbolGroup{$LRelPath}{$Symbol}) { if(not $SysHeader_Symbols{$HRelPath}{$Group}) { next; } } my $Filter = 0; foreach (@TryNames) { if(my $Filt = $SysInfo->{$_}{"headers"}) { # search for specified headers if(not check_list($HRelPath, $Filt)) { $Filter = 1; last; } } if(my $Filt = $SysInfo->{$_}{"skip_headers"}) { # do NOT search for some headers if(check_list($HRelPath, $Filt)) { $Filter = 1; last; } } if(my $Filt = $SysInfo->{$_}{"skip_including"}) { # do NOT search for some headers if(check_list($HRelPath, $Filt)) { $SymbolDirs{$HDir}+=1; $SymbolFiles{$HName}+=1; $Filter = 1; last; } } } if($Filter) { next; } if(my $Filt = $SysCInfo->{"skip_headers"}) { # do NOT search for some headers if(check_list($HRelPath, $Filt)) { next; } } if(my $Filt = $SysCInfo->{"skip_including"}) { # do NOT search for some headers if(check_list($HRelPath, $Filt)) { next; } } if(defined $LibraryFile{$LRelPath}) { # skip wrongly matched headers if(not defined $LibraryFile{$LRelPath}{$HRelPath}) { print "WRONG: $LRelPath $HRelPath\n"; # next; } } $SysLib_SysHeaders{$LRelPath}{$HRelPath} = $Symbol; $SysHeaderDir_Used{$HDir}{$LName_Short} = 1; $SysHeaderDir_Used{get_dirname($HDir)}{$LName_Short} = 1; $SymbolDirs{$HDir} += 1; $SymbolFiles{$HName} +=1 ; # select one header for one symbol last; } } if(keys(%{$SysLib_Symbols{$LPath}}) and not $SysInfo->{$_}{"headers"}) { # try to match by name of the header if(length($SName)>=3) { my @Paths = (); foreach my $Path (keys(%{$HeaderFile_Path{$SName.".h"}}), keys(%{$HeaderFile_Path{$LSName.".h"}})) { my $Dir = get_dirname($Path); if(defined $SymbolDirs{$Dir} or $Dir eq "/usr/include") { push(@Paths, $Path); } } if($#Paths==0) { my $Path = $Paths[0]; if(not defined $SysLib_SysHeaders{$LRelPath}{$Path}) { $SysLib_SysHeaders{$LRelPath}{$Path} = "by name ($LSName)"; } } } } if(not keys(%{$SysLib_SysHeaders{$LRelPath}})) { foreach (@TryNames) { if(my $List = $SysInfo->{$_}{"headers"}) { foreach my $HName (@{$List}) { next if($HName=~/[\*\/\\]/); if(my $HPath = selectSystemHeader($HName, 1)) { my $HRelPath = cut_path_prefix($HPath, $SystemRoot); $SysLib_SysHeaders{$LRelPath}{$HRelPath} = "by descriptor"; } } } } } if(not keys(%{$SysLib_SysHeaders{$LRelPath}})) { $Failed{$LRelPath} = 1; } } if(not $GroupByHeaders) { # matching results writeFile($SYS_DUMP_PATH."/debug/match.txt", Dumper(\%SysLib_SysHeaders)); writeFile($SYS_DUMP_PATH."/debug/skipped.txt", join("\n", sort keys(%Skipped))); writeFile($SYS_DUMP_PATH."/debug/failed.txt", join("\n", sort keys(%Failed))); } (%SysLib_Symbols, %SymbolGroup, %Symbol_SysHeaders, %SysHeader_Symbols) = (); # free memory if($GroupByHeaders) { if($SysDescriptor{"Image"} and not $CheckHeadersOnly) { @SysHeaders = keys(%{$SysLib_SysHeaders{$SysDescriptor{"Image"}}}); } %SysLib_SysHeaders = (); foreach my $Path (@SysHeaders) { if(my $Skip = $SysCInfo->{"skip_headers"}) { # do NOT search for some headers if(check_list($Path, $Skip)) { next; } } if(my $Skip = $SysCInfo->{"skip_including"}) { # do NOT search for some headers if(check_list($Path, $Skip)) { next; } } $SysLib_SysHeaders{$Path}{$Path} = 1; } if($CheckHeadersOnly) { writeFile($SYS_DUMP_PATH."/mode.txt", "headers-only"); } else { writeFile($SYS_DUMP_PATH."/mode.txt", "group-by-headers"); } } @SysHeaders = (); # clear memory if($Debug) { printMsg("INFO", localtime(time)); } printMsg("INFO", "Generating XML descriptors ..."); my %Generated = (); foreach my $LRelPath (keys(%SysLib_SysHeaders)) { my $LName = get_filename($LRelPath); my $DPath = $SYS_DUMP_PATH."/descriptors/$LName.xml"; unlink($DPath); if(my @LibHeaders = keys(%{$SysLib_SysHeaders{$LRelPath}})) { my $LSName = parse_libname($LName, "short", $OStarget); my $LName_Short = parse_libname($LName, "name", $OStarget); my $LName_Shortest = parse_libname($LName, "shortest", $OStarget); if($GroupByHeaders) { # header short name $LSName = $LName; $LSName=~s/\.(.+?)\Z//; } my (%DirsHeaders, %Includes, %MainDirs) = (); foreach my $HRelPath (@LibHeaders) { my $Dir = get_dirname($HRelPath); $DirsHeaders{$Dir}{$HRelPath} = 1; if($Dir=~/\/\Q$LName_Shortest\E(\/|\Z)/i or $Dir=~/\/\Q$LName_Short\E(\/|\Z)/i) { if(get_filename($Dir) ne "include") { # except /usr/include $MainDirs{$Dir} += 1; } } } if($#LibHeaders==0) { # one header at all $Includes{$LibHeaders[0]} = 1; } else { foreach my $Dir (keys(%DirsHeaders)) { if(keys(%MainDirs) and not defined $MainDirs{$Dir}) { # search in /X/ dir for libX headers if(get_filename($Dir) ne "include") { # except /usr/include next; } } my $DirPart = 0; my $TotalHeaders = keys(%{$SysHeaderDir_SysHeaders{$Dir}}); if($TotalHeaders) { $DirPart = (keys(%{$DirsHeaders{$Dir}})*100)/$TotalHeaders; } my $Neighbourhoods = keys(%{$SysHeaderDir_Used{$Dir}}); if($Neighbourhoods==1) { # one lib in this directory if(get_filename($Dir) ne "include" and $DirPart>=5) { # complete directory $Includes{$Dir} = 1; } else { # list of headers foreach (keys(%{$DirsHeaders{$Dir}})) { $Includes{$_} = 1; } } } elsif((keys(%{$DirsHeaders{$Dir}})*100)/($#LibHeaders+1)>5) { # remove 5% divergence if(get_filename($Dir) ne "include" and $DirPart>=50) { # complete directory if more than 50% $Includes{$Dir} = 1; } else { # list of headers foreach (keys(%{$DirsHeaders{$Dir}})) { $Includes{$_} = 1; } } } else { # noise foreach (keys(%{$DirsHeaders{$Dir}})) { # NOTE: /usr/include/libX.h if(/\Q$LName_Shortest\E/i) { $Includes{$_} = 1; } } } } } if($GroupByHeaders) { # one header in one ABI dump %Includes = ($LibHeaders[0] => 1); } my $LVersion = $SysLibVersion{$LName}; if($LVersion) { # append by system name $LVersion .= "-".$SysDescriptor{"Name"}; } else { $LVersion = $SysDescriptor{"Name"}; } my @Content = ("\n $LVersion\n"); my @IncHeaders = keys(%Includes); # sort files up @IncHeaders = sort {$b=~/\.h\Z/<=>$a=~/\.h\Z/} @IncHeaders; # sort by name @IncHeaders = sort {sortHeaders($a, $b)} @IncHeaders; # sort by library name sortByWord(\@IncHeaders, parse_libname($LName, "shortest", $OStarget)); if(is_abs($IncHeaders[0]) or -f $IncHeaders[0]) { push(@Content, "\n ".join("\n ", @IncHeaders)."\n"); } else { push(@Content, "\n {RELPATH}/".join("\n {RELPATH}/", @IncHeaders)."\n"); } if($GroupByHeaders) { if($SysDescriptor{"Image"}) { push(@Content, "\n ".$SysDescriptor{"Image"}."\n"); } } else { if(is_abs($LRelPath) or -f $LRelPath) { push(@Content, "\n $LRelPath\n"); } else { push(@Content, "\n {RELPATH}/$LRelPath\n"); } } # system if(my @SearchHeaders = keys(%{$SysDescriptor{"SearchHeaders"}})) { push(@Content, "\n ".join("\n ", @SearchHeaders)."\n"); } if(my @SearchLibs = keys(%{$SysDescriptor{"SearchLibs"}})) { push(@Content, "\n ".join("\n ", @SearchLibs)."\n"); } if(my @Tools = keys(%{$SysDescriptor{"Tools"}})) { push(@Content, "\n ".join("\n ", @Tools)."\n"); } if(my $Prefix = $SysDescriptor{"CrossPrefix"}) { push(@Content, "\n $Prefix\n"); } # library my (@Skip, @SkipInc, @AddIncPath, @SkipIncPath, @SkipTypes, @SkipSymb, @Preamble, @Defines, @CompilerOpts) = (); my @TryNames = (); if(my $Ver = $SysLibVersion{$LName}) { if($LSName."-".$Ver ne $LName_Short) { push(@TryNames, $LName_Short."-".$Ver); } } push(@TryNames, $LName_Short); if($LSName ne $LName_Short) { push(@TryNames, $LSName); } foreach (@TryNames) { if(my $List = $SysInfo->{$_}{"include_preamble"}) { push(@Preamble, @{$List}); } if(my $List = $SysInfo->{$_}{"skip_headers"}) { @Skip = (@Skip, @{$List}); } if(my $List = $SysInfo->{$_}{"skip_including"}) { @SkipInc = (@SkipInc, @{$List}); } if(my $List = $SysInfo->{$_}{"add_include_paths"}) { @AddIncPath = (@AddIncPath, @{$List}); } if(my $List = $SysInfo->{$_}{"skip_include_paths"}) { @SkipIncPath = (@SkipIncPath, @{$List}); } if(my $List = $SysInfo->{$_}{"skip_symbols"}) { push(@SkipSymb, @{$List}); } if(my $List = $SysInfo->{$_}{"skip_types"}) { @SkipTypes = (@SkipTypes, @{$List}); } if(my $List = $SysInfo->{$_}{"gcc_options"}) { push(@CompilerOpts, @{$List}); } if(my $List = $SysInfo->{$_}{"defines"}) { push(@Defines, $List); } } # common if(my $List = $SysCInfo->{"include_preamble"}) { push(@Preamble, @{$List}); } if(my $List = $SysCInfo->{"skip_headers"}) { @Skip = (@Skip, @{$List}); } if(my $List = $SysCInfo->{"skip_including"}) { @SkipInc = (@SkipInc, @{$List}); } if(my $List = $SysCInfo->{"skip_symbols"}) { push(@SkipSymb, @{$List}); } if(my $List = $SysCInfo->{"gcc_options"}) { push(@CompilerOpts, @{$List}); } if($SysCInfo->{"defines"}) { push(@Defines, $SysCInfo->{"defines"}); } # common other if($LSName=~/\AlibX\w+\Z/) { # add Xlib.h for libXt, libXaw, libXext and others push(@Preamble, "Xlib.h", "X11/Intrinsic.h"); } if($SkipDHeaders{$LSName}) { @SkipInc = (@SkipInc, @{$SkipDHeaders{$LSName}}); } if($SysDescriptor{"Defines"}) { push(@Defines, $SysDescriptor{"Defines"}); } # add sections if(@Preamble) { push(@Content, "\n ".join("\n ", @Preamble)."\n"); } if(@Skip) { push(@Content, "\n ".join("\n ", @Skip)."\n"); } if(@SkipInc) { push(@Content, "\n ".join("\n ", @SkipInc)."\n"); } if(@AddIncPath) { push(@Content, "\n ".join("\n ", @AddIncPath)."\n"); } if(@SkipIncPath) { push(@Content, "\n ".join("\n ", @SkipIncPath)."\n"); } if(@SkipSymb) { push(@Content, "\n ".join("\n ", @SkipSymb)."\n"); } if(@SkipTypes) { push(@Content, "\n ".join("\n ", @SkipTypes)."\n"); } if(@CompilerOpts) { push(@Content, "\n ".join("\n ", @CompilerOpts)."\n"); } if(@Defines) { push(@Content, "\n ".join("\n ", @Defines)."\n"); } writeFile($DPath, join("\n\n", @Content)); $Generated{$LRelPath}=1; } } printMsg("INFO", "Created descriptors: ".keys(%Generated)." ($SYS_DUMP_PATH/descriptors/)\n"); if($Debug) { printMsg("INFO", localtime(time)); } printMsg("INFO", "Dumping ABIs:"); my %Dumped = (); my @Descriptors = cmd_find($SYS_DUMP_PATH."/descriptors","f","*.xml","1"); if(-d $SYS_DUMP_PATH."/descriptors" and $#Descriptors==-1) { printMsg("ERROR", "internal problem with \'find\' utility"); } foreach my $DPath (sort {lc($a) cmp lc($b)} @Descriptors) { my $DName = get_filename($DPath); my $LName = ""; if($DName=~/\A(.+).xml\Z/) { $LName = $1; } else { next; } if(not is_target_lib($LName) and not is_target_lib($LibSoname{$LName})) { next; } $DPath = cut_path_prefix($DPath, $ORIG_DIR); my $ACC_dump = "perl $0"; if($GroupByHeaders) { # header name is going here $ACC_dump .= " -l $LName"; } else { $ACC_dump .= " -l ".parse_libname($LName, "name", $OStarget); } $ACC_dump .= " -dump \"$DPath\""; if($SystemRoot) { $ACC_dump .= " -relpath \"$SystemRoot\""; $ACC_dump .= " -sysroot \"$SystemRoot\""; } my $DumpPath = "$SYS_DUMP_PATH/abi_dumps/$LName.abi.".getAR_EXT($OSgroup); $ACC_dump .= " -dump-path \"$DumpPath\""; my $LogPath = "$SYS_DUMP_PATH/logs/$LName.txt"; unlink($LogPath); $ACC_dump .= " -log-path \"$LogPath\""; if($CrossGcc) { $ACC_dump .= " -cross-gcc \"$CrossGcc\""; } if($CheckHeadersOnly) { $ACC_dump .= " -headers-only"; } if($UseStaticLibs) { $ACC_dump .= " -static-libs"; } if($GroupByHeaders) { $ACC_dump .= " -header $LName"; } if($NoStdInc or $OStarget=~/windows|symbian/) { # 1. user-defined # 2. windows/minGW # 3. symbian/GCC $ACC_dump .= " -nostdinc"; } if($Quiet) { # quiet mode $ACC_dump .= " -quiet"; } if($LogMode eq "n") { $ACC_dump .= " -logging-mode n"; } elsif($Quiet) { $ACC_dump .= " -logging-mode a"; } if($Debug) { # debug mode $ACC_dump .= " -debug"; printMsg("INFO", "$ACC_dump"); } printMsg("INFO_C", "Dumping $LName: "); system($ACC_dump." 1>$TMP_DIR/null 2>$TMP_DIR/$LName.stderr"); appendFile("$SYS_DUMP_PATH/logs/$LName.txt", "The ACC parameters:\n $ACC_dump\n"); if(-s "$TMP_DIR/$LName.stderr") { appendFile("$SYS_DUMP_PATH/logs/$LName.txt", readFile("$TMP_DIR/$LName.stderr")); if(get_CodeError($?>>8) eq "Invalid_Dump") { printMsg("INFO", "Empty"); } else { printMsg("INFO", "Failed (\'$SYS_DUMP_PATH/logs/$LName.txt\')"); } } elsif(not -f $DumpPath) { printMsg("INFO", "Failed (\'$SYS_DUMP_PATH/logs/$LName.txt\')"); } else { $Dumped{$LName}=1; printMsg("INFO", "Ok"); } } printMsg("INFO", "\n"); if(not $GroupByHeaders) { # general mode printMsg("INFO", "Total libraries: ".keys(%TotalLibs)); printMsg("INFO", "Skipped libraries: ".keys(%Skipped)." ($SYS_DUMP_PATH/skipped.txt)"); printMsg("INFO", "Failed to find headers: ".keys(%Failed)." ($SYS_DUMP_PATH/failed.txt)"); } printMsg("INFO", "Dumped ABIs: ".keys(%Dumped)." ($SYS_DUMP_PATH/abi_dumps/)"); printMsg("INFO", "The ".$SysDescriptor{"Name"}." system ABI has been dumped to:\n $SYS_DUMP_PATH"); } return 1;abi-compliance-checker-1.99.9/modules/Internals/XmlDump.pm000066400000000000000000000732351227016120300234270ustar00rootroot00000000000000########################################################################### # Module for ABI Compliance Checker to create ABI dumps in XML format # # Copyright (C) 2009-2010 The Linux Foundation # Copyright (C) 2009-2011 Institute for System Programming, RAS # Copyright (C) 2011-2012 Nokia Corporation and/or its subsidiary(-ies) # Copyright (C) 2011-2013 ROSA Laboratory # # Written by Andrey Ponomarenko # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License or the GNU Lesser # General Public License as published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # and the GNU Lesser General Public License along with this program. # If not, see . ########################################################################### use strict; my $TAG_ID = 0; my $INDENT = " "; sub createXmlDump($) { my $ABI = $_[0]; my $ABI_DUMP = "\n"; $ABI_DUMP .= "{"ABI_DUMP_VERSION"}."\""; $ABI_DUMP .= " xml_format=\"".$ABI->{"XML_ABI_DUMP_VERSION"}."\""; $ABI_DUMP .= " acc=\"".$ABI->{"ABI_COMPLIANCE_CHECKER_VERSION"}."\">\n"; $ABI_DUMP .= addTag("library", $ABI->{"LibraryName"}); $ABI_DUMP .= addTag("library_version", $ABI->{"LibraryVersion"}); $ABI_DUMP .= addTag("language", $ABI->{"Language"}); $ABI_DUMP .= addTag("gcc", $ABI->{"GccVersion"}); $ABI_DUMP .= addTag("architecture", $ABI->{"Arch"}); $ABI_DUMP .= addTag("target", $ABI->{"Target"}); $ABI_DUMP .= addTag("word_size", $ABI->{"WordSize"}); if($ABI->{"Mode"}) { $ABI_DUMP .= addTag("mode", $ABI->{"Mode"}); } if($ABI->{"SrcBin"}) { $ABI_DUMP .= addTag("kind", "SrcBin"); } elsif($ABI->{"BinOnly"}) { $ABI_DUMP .= addTag("kind", "BinOnly"); } if(my @Headers = keys(%{$ABI->{"Headers"}})) { @Headers = sort {$ABI->{"Headers"}{$a}<=>$ABI->{"Headers"}{$b}} @Headers; $ABI_DUMP .= openTag("headers"); foreach my $Name (@Headers) { $ABI_DUMP .= addTag("name", $Name); } $ABI_DUMP .= closeTag("headers"); } if(my @NameSpaces = keys(%{$ABI->{"NameSpaces"}})) { $ABI_DUMP .= openTag("namespaces"); foreach my $NameSpace (sort {lc($a) cmp lc($b)} @NameSpaces) { $ABI_DUMP .= addTag("name", $NameSpace); } $ABI_DUMP .= closeTag("namespaces"); } if(my @TypeInfo = keys(%{$ABI->{"TypeInfo"}})) { $ABI_DUMP .= openTag("type_info"); foreach my $ID (sort {$a<=>$b} @TypeInfo) { my %TInfo = %{$ABI->{"TypeInfo"}{$ID}}; $ABI_DUMP .= openTag("data_type"); $ABI_DUMP .= addTag("id", $ID); foreach my $Attr ("Name", "Type", "Size", "Header", "Line", "NameSpace", "Class", "Return", "Algn") { if(defined $TInfo{$Attr}) { $ABI_DUMP .= addTag(lc($Attr), $TInfo{$Attr}); } } if($TInfo{"Private"}) { $ABI_DUMP .= addTag("access", "private"); } if($TInfo{"Protected"}) { $ABI_DUMP .= addTag("access", "protected"); } if(my @Positions = keys(%{$TInfo{"Memb"}})) { $ABI_DUMP .= openTag("members"); foreach my $Pos (sort { $a<=>$b } @Positions) { $ABI_DUMP .= openTag("field"); $ABI_DUMP .= addTag("name", $TInfo{"Memb"}{$Pos}{"name"}); if(my $MTid = $TInfo{"Memb"}{$Pos}{"type"}) { $ABI_DUMP .= addTag("type", $MTid); } if(my $Access = $TInfo{"Memb"}{$Pos}{"access"}) { $ABI_DUMP .= addTag("access", $Access); } my $Val = $TInfo{"Memb"}{$Pos}{"value"}; if(defined $Val) { $ABI_DUMP .= addTag("value", $Val); } if(my $Align = $TInfo{"Memb"}{$Pos}{"algn"}) { $ABI_DUMP .= addTag("algn", $Align); } if(my $Bitfield = $TInfo{"Memb"}{$Pos}{"bitfield"}) { $ABI_DUMP .= addTag("bitfield", $Bitfield); } if($TInfo{"Memb"}{$Pos}{"mutable"}) { $ABI_DUMP .= addTag("spec", "mutable"); } $ABI_DUMP .= addTag("pos", $Pos); $ABI_DUMP .= closeTag("field"); } $ABI_DUMP .= closeTag("members"); } if(my @Positions = keys(%{$TInfo{"Param"}})) { $ABI_DUMP .= openTag("parameters"); foreach my $Pos (sort { $a<=>$b } @Positions) { $ABI_DUMP .= openTag("param"); if(my $PTid = $TInfo{"Param"}{$Pos}{"type"}) { $ABI_DUMP .= addTag("type", $PTid); } $ABI_DUMP .= addTag("pos", $Pos); $ABI_DUMP .= closeTag("param"); } $ABI_DUMP .= closeTag("parameters"); } if(my @Positions = keys(%{$TInfo{"TParam"}})) { $ABI_DUMP .= openTag("template_parameters"); foreach my $Pos (sort { $a<=>$b } @Positions) { $ABI_DUMP .= openTag("param"); $ABI_DUMP .= addTag("name", $TInfo{"TParam"}{$Pos}{"name"}); $ABI_DUMP .= addTag("pos", $Pos); $ABI_DUMP .= closeTag("param"); } $ABI_DUMP .= closeTag("template_parameters"); } if(my @Offsets = keys(%{$TInfo{"VTable"}})) { $ABI_DUMP .= openTag("vtable"); foreach my $Offset (sort { $a<=>$b } @Offsets) { $ABI_DUMP .= openTag("entry"); $ABI_DUMP .= addTag("offset", $Offset); $ABI_DUMP .= addTag("value", $TInfo{"VTable"}{$Offset}); $ABI_DUMP .= closeTag("entry"); } $ABI_DUMP .= closeTag("vtable"); } if(my $BTid = $TInfo{"BaseType"}) { $ABI_DUMP .= addTag("base_type", $BTid); } if(my @BaseIDs = keys(%{$TInfo{"Base"}})) { @BaseIDs = sort { $TInfo{"Base"}{$a}{"pos"}<=>$TInfo{"Base"}{$b}{"pos"} } @BaseIDs; $ABI_DUMP .= openTag("base"); foreach my $BaseID (@BaseIDs) { $ABI_DUMP .= openTag("class"); $ABI_DUMP .= addTag("id", $BaseID); if(my $Access = $TInfo{"Base"}{$BaseID}{"access"}) { $ABI_DUMP .= addTag("access", $Access); } if(my $Virt = $TInfo{"Base"}{$BaseID}{"virtual"}) { $ABI_DUMP .= addTag("inherit", "virtual"); } $ABI_DUMP .= addTag("pos", $TInfo{"Base"}{$BaseID}{"pos"}); $ABI_DUMP .= closeTag("class"); } $ABI_DUMP .= closeTag("base"); } if($TInfo{"Copied"}) { $ABI_DUMP .= addTag("note", "copied"); } if($TInfo{"Spec"}) { $ABI_DUMP .= addTag("note", "specialization"); } if($TInfo{"Forward"}) { $ABI_DUMP .= addTag("note", "forward"); } $ABI_DUMP .= closeTag("data_type"); } $ABI_DUMP .= closeTag("type_info"); } if(my @Constants = keys(%{$ABI->{"Constants"}})) { $ABI_DUMP .= openTag("constants"); foreach my $Constant (@Constants) { my %CInfo = %{$ABI->{"Constants"}{$Constant}}; $ABI_DUMP .= openTag("constant"); $ABI_DUMP .= addTag("name", $Constant); $ABI_DUMP .= addTag("value", $CInfo{"Value"}); $ABI_DUMP .= addTag("header", $CInfo{"Header"}); $ABI_DUMP .= closeTag("constant"); } $ABI_DUMP .= closeTag("constants"); } if(my @SymbolInfo = keys(%{$ABI->{"SymbolInfo"}})) { my %TR = ( "MnglName" => "mangled", "ShortName" => "short" ); $ABI_DUMP .= openTag("symbol_info"); foreach my $ID (sort {$a<=>$b} @SymbolInfo) { my %SInfo = %{$ABI->{"SymbolInfo"}{$ID}}; $ABI_DUMP .= openTag("symbol"); $ABI_DUMP .= addTag("id", $ID); foreach my $Attr ("MnglName", "ShortName", "Class", "Header", "Line", "Return", "NameSpace", "Value") { if(defined $SInfo{$Attr}) { my $Tag = $Attr; if($TR{$Attr}) { $Tag = $TR{$Attr}; } $ABI_DUMP .= addTag(lc($Tag), $SInfo{$Attr}); } } if($SInfo{"Constructor"}) { $ABI_DUMP .= addTag("kind", "constructor"); } if($SInfo{"Destructor"}) { $ABI_DUMP .= addTag("kind", "destructor"); } if($SInfo{"Data"}) { $ABI_DUMP .= addTag("kind", "data"); } if($SInfo{"Virt"}) { $ABI_DUMP .= addTag("spec", "virtual"); } elsif($SInfo{"PureVirt"}) { $ABI_DUMP .= addTag("spec", "pure virtual"); } elsif($SInfo{"Static"}) { $ABI_DUMP .= addTag("spec", "static"); } if($SInfo{"InLine"}) { $ABI_DUMP .= addTag("spec", "inline"); } if($SInfo{"Const"}) { $ABI_DUMP .= addTag("spec", "const"); } if($SInfo{"Volatile"}) { $ABI_DUMP .= addTag("spec", "volatile"); } if($SInfo{"Private"}) { $ABI_DUMP .= addTag("access", "private"); } if($SInfo{"Protected"}) { $ABI_DUMP .= addTag("access", "protected"); } if($SInfo{"Artificial"}) { $ABI_DUMP .= addTag("note", "artificial"); } if(my $Lang = $SInfo{"Lang"}) { $ABI_DUMP .= addTag("lang", $Lang); } if(my @Positions = keys(%{$SInfo{"Param"}})) { $ABI_DUMP .= openTag("parameters"); foreach my $Pos (sort { $a<=>$b } @Positions) { $ABI_DUMP .= openTag("param"); if(my $PName = $SInfo{"Param"}{$Pos}{"name"}) { $ABI_DUMP .= addTag("name", $PName); } if(my $PTid = $SInfo{"Param"}{$Pos}{"type"}) { $ABI_DUMP .= addTag("type", $PTid); } my $Default = $SInfo{"Param"}{$Pos}{"default"}; if(defined $Default) { $ABI_DUMP .= addTag("default", $Default); } if(my $Align = $SInfo{"Param"}{$Pos}{"algn"}) { $ABI_DUMP .= addTag("algn", $Align); } if(defined $SInfo{"Param"}{$Pos}{"reg"}) { $ABI_DUMP .= addTag("call", "register"); } $ABI_DUMP .= addTag("pos", $Pos); $ABI_DUMP .= closeTag("param"); } $ABI_DUMP .= closeTag("parameters"); } if(my @Positions = keys(%{$SInfo{"TParam"}})) { $ABI_DUMP .= openTag("template_parameters"); foreach my $Pos (sort { $a<=>$b } @Positions) { $ABI_DUMP .= openTag("param"); $ABI_DUMP .= addTag("name", $SInfo{"TParam"}{$Pos}{"name"}); $ABI_DUMP .= closeTag("param"); } $ABI_DUMP .= closeTag("template_parameters"); } $ABI_DUMP .= closeTag("symbol"); } $ABI_DUMP .= closeTag("symbol_info"); } if(my @Libs = keys(%{$ABI->{"Symbols"}})) { $ABI_DUMP .= openTag("symbols"); foreach my $Lib (sort {lc($a) cmp lc($b)} @Libs) { $ABI_DUMP .= openTag("library", "name", $Lib); foreach my $Symbol (sort {lc($a) cmp lc($b)} keys(%{$ABI->{"Symbols"}{$Lib}})) { if((my $Size = $ABI->{"Symbols"}{$Lib}{$Symbol})<0) { # data $ABI_DUMP .= addTag("symbol", $Symbol, "size", -$Size); } else { # functions $ABI_DUMP .= addTag("symbol", $Symbol); } } $ABI_DUMP .= closeTag("library"); } $ABI_DUMP .= closeTag("symbols"); } if(my @DepLibs = keys(%{$ABI->{"DepSymbols"}})) { $ABI_DUMP .= openTag("dep_symbols"); foreach my $Lib (sort {lc($a) cmp lc($b)} @DepLibs) { $ABI_DUMP .= openTag("library", "name", $Lib); foreach my $Symbol (sort {lc($a) cmp lc($b)} keys(%{$ABI->{"DepSymbols"}{$Lib}})) { if((my $Size = $ABI->{"DepSymbols"}{$Lib}{$Symbol})<0) { # data $ABI_DUMP .= addTag("symbol", $Symbol, "size", -$Size); } else { # functions $ABI_DUMP .= addTag("symbol", $Symbol); } } $ABI_DUMP .= closeTag("library"); } $ABI_DUMP .= closeTag("dep_symbols"); } if(my @VSymbols = keys(%{$ABI->{"SymbolVersion"}})) { $ABI_DUMP .= openTag("symbol_version"); foreach my $Symbol (sort {lc($a) cmp lc($b)} @VSymbols) { $ABI_DUMP .= openTag("symbol"); $ABI_DUMP .= addTag("name", $Symbol); $ABI_DUMP .= addTag("version", $ABI->{"SymbolVersion"}{$Symbol}); $ABI_DUMP .= closeTag("symbol"); } $ABI_DUMP .= closeTag("symbol_version"); } if(my @SkipTypes = keys(%{$ABI->{"SkipTypes"}})) { $ABI_DUMP .= openTag("skip_types"); foreach my $Name (sort {lc($a) cmp lc($b)} @SkipTypes) { $ABI_DUMP .= addTag("name", $Name); } $ABI_DUMP .= closeTag("skip_types"); } if(my @SkipSymbols = keys(%{$ABI->{"SkipSymbols"}})) { $ABI_DUMP .= openTag("skip_symbols"); foreach my $Name (sort {lc($a) cmp lc($b)} @SkipSymbols) { $ABI_DUMP .= addTag("name", $Name); } $ABI_DUMP .= closeTag("skip_symbols"); } if(my @SkipNameSpaces = keys(%{$ABI->{"SkipNameSpaces"}})) { $ABI_DUMP .= openTag("skip_namespaces"); foreach my $Name (sort {lc($a) cmp lc($b)} @SkipNameSpaces) { $ABI_DUMP .= addTag("name", $Name); } $ABI_DUMP .= closeTag("skip_namespaces"); } if(my @SkipHeaders = keys(%{$ABI->{"SkipHeaders"}})) { $ABI_DUMP .= openTag("skip_headers"); foreach my $Name (sort {lc($a) cmp lc($b)} @SkipHeaders) { $ABI_DUMP .= addTag("name", $Name); } $ABI_DUMP .= closeTag("skip_headers"); } if(my @TargetHeaders = keys(%{$ABI->{"TargetHeaders"}})) { $ABI_DUMP .= openTag("target_headers"); foreach my $Name (sort {lc($a) cmp lc($b)} @TargetHeaders) { $ABI_DUMP .= addTag("name", $Name); } $ABI_DUMP .= closeTag("target_headers"); } $ABI_DUMP .= "\n"; checkTags(); return $ABI_DUMP; } sub readXmlDump($) { my $ABI_DUMP = readFile($_[0]); my %ABI = {}; $ABI{"LibraryName"} = parseTag(\$ABI_DUMP, "library"); $ABI{"LibraryVersion"} = parseTag(\$ABI_DUMP, "library_version"); $ABI{"Language"} = parseTag(\$ABI_DUMP, "language"); $ABI{"GccVersion"} = parseTag(\$ABI_DUMP, "gcc"); $ABI{"Arch"} = parseTag(\$ABI_DUMP, "architecture"); $ABI{"Target"} = parseTag(\$ABI_DUMP, "target"); $ABI{"WordSize"} = parseTag(\$ABI_DUMP, "word_size"); my $Pos = 0; if(my $Headers = parseTag(\$ABI_DUMP, "headers")) { while(my $Name = parseTag(\$Headers, "name")) { $ABI{"Headers"}{$Name} = $Pos++; } } if(my $NameSpaces = parseTag(\$ABI_DUMP, "namespaces")) { while(my $Name = parseTag(\$NameSpaces, "name")) { $ABI{"NameSpaces"}{$Name} = 1; } } if(my $TypeInfo = parseTag(\$ABI_DUMP, "type_info")) { while(my $DataType = parseTag(\$TypeInfo, "data_type")) { my %TInfo = (); my $ID = parseTag(\$DataType, "id"); if(my $Members = parseTag(\$DataType, "members")) { $Pos = 0; while(my $Field = parseTag(\$Members, "field")) { my %MInfo = (); $MInfo{"name"} = parseTag(\$Field, "name"); if(my $Tid = parseTag(\$Field, "type")) { $MInfo{"type"} = $Tid; } if(my $Access = parseTag(\$Field, "access")) { $MInfo{"access"} = $Access; } my $Val = parseTag(\$Field, "value"); if(defined $Val) { $MInfo{"value"} = $Val; } if(my $Align = parseTag(\$Field, "algn")) { $MInfo{"algn"} = $Align; } if(my $Bitfield = parseTag(\$Field, "bitfield")) { $MInfo{"bitfield"} = $Bitfield; } if(my $Spec = parseTag(\$Field, "spec")) { $MInfo{$Spec} = 1; } $TInfo{"Memb"}{$Pos++} = \%MInfo; } } if(my $Parameters = parseTag(\$DataType, "parameters")) { $Pos = 0; while(my $Parameter = parseTag(\$Parameters, "param")) { my %PInfo = (); if(my $Tid = parseTag(\$Parameter, "type")) { $PInfo{"type"} = $Tid; } $TInfo{"Param"}{$Pos++} = \%PInfo; } } if(my $TParams = parseTag(\$DataType, "template_parameters")) { $Pos = 0; while(my $TParam = parseTag(\$TParams, "param")) { $TInfo{"TParam"}{$Pos++}{"name"} = parseTag(\$TParam, "name"); } } if(my $VTable = parseTag(\$DataType, "vtable")) { $Pos = 0; while(my $Entry = parseTag(\$VTable, "entry")) { $TInfo{"VTable"}{parseTag(\$Entry, "offset")} = parseTag(\$Entry, "value"); } } if(my $BTid = parseTag(\$DataType, "base_type")) { $TInfo{"BaseType"} = $BTid; } if(my $Base = parseTag(\$DataType, "base")) { $Pos = 0; while(my $Class = parseTag(\$Base, "class")) { my %CInfo = (); $CInfo{"pos"} = parseTag(\$Class, "pos"); if(my $Access = parseTag(\$Class, "access")) { $CInfo{"access"} = $Access; } if(my $Inherit = parseTag(\$Class, "inherit")) { if($Inherit eq "virtual") { $CInfo{"virtual"} = 1; } } $TInfo{"Base"}{parseTag(\$Class, "id")} = \%CInfo; } } while(my $Note = parseTag(\$DataType, "note")) { if($Note eq "copied") { $TInfo{"Copied"} = 1; } elsif($Note eq "specialization") { $TInfo{"Spec"} = 1; } elsif($Note eq "forward") { $TInfo{"Forward"} = 1; } } foreach my $Attr ("Name", "Type", "Size", "Header", "Line", "NameSpace", "Class", "Return", "Algn") { my $Val = parseTag(\$DataType, lc($Attr)); if(defined $Val) { $TInfo{$Attr} = $Val; } } if(my $Access = parseTag(\$DataType, "access")) { $TInfo{ucfirst($Access)} = 1; } $ABI{"TypeInfo"}{$ID} = \%TInfo; } } if(my $Constants = parseTag(\$ABI_DUMP, "constants")) { while(my $Constant = parseTag(\$Constants, "constant")) { if(my $Name = parseTag(\$Constant, "name")) { my %CInfo = (); $CInfo{"Value"} = parseTag(\$Constant, "value"); $CInfo{"Header"} = parseTag(\$Constant, "header"); $ABI{"Constants"}{$Name} = \%CInfo; } } } if(my $SymbolInfo = parseTag(\$ABI_DUMP, "symbol_info")) { my %TR = ( "MnglName"=>"mangled", "ShortName"=>"short" ); while(my $Symbol = parseTag(\$SymbolInfo, "symbol")) { my %SInfo = (); my $ID = parseTag(\$Symbol, "id"); if(my $Parameters = parseTag(\$Symbol, "parameters")) { $Pos = 0; while(my $Parameter = parseTag(\$Parameters, "param")) { my %PInfo = (); if(my $PName = parseTag(\$Parameter, "name")) { $PInfo{"name"} = $PName; } if(my $PTid = parseTag(\$Parameter, "type")) { $PInfo{"type"} = $PTid; } my $Default = parseTag(\$Parameter, "default", "spaces"); if(defined $Default) { $PInfo{"default"} = $Default; } if(my $Align = parseTag(\$Parameter, "algn")) { $PInfo{"algn"} = $Align; } if(my $Call = parseTag(\$Parameter, "call")) { if($Call eq "register") { $PInfo{"reg"} = 1; } } $SInfo{"Param"}{$Pos++} = \%PInfo; } } if(my $TParams = parseTag(\$Symbol, "template_parameters")) { $Pos = 0; while(my $TParam = parseTag(\$TParams, "param")) { $SInfo{"TParam"}{$Pos++}{"name"} = parseTag(\$TParam, "name"); } } foreach my $Attr ("MnglName", "ShortName", "Class", "Header", "Line", "Return", "NameSpace", "Value") { my $Tag = lc($Attr); if($TR{$Attr}) { $Tag = $TR{$Attr}; } my $Val = parseTag(\$Symbol, $Tag); if(defined $Val) { $SInfo{$Attr} = $Val; } } if(my $Kind = parseTag(\$Symbol, "kind")) { $SInfo{ucfirst($Kind)} = 1; } while(my $Spec = parseTag(\$Symbol, "spec")) { if($Spec eq "virtual") { $SInfo{"Virt"} = 1; } elsif($Spec eq "pure virtual") { $SInfo{"PureVirt"} = 1; } elsif($Spec eq "inline") { $SInfo{"InLine"} = 1; } else { # const, volatile, static $SInfo{ucfirst($Spec)} = 1; } } if(my $Access = parseTag(\$Symbol, "access")) { $SInfo{ucfirst($Access)} = 1; } if(my $Note = parseTag(\$Symbol, "note")) { $SInfo{ucfirst($Note)} = 1; } if(my $Lang = parseTag(\$Symbol, "lang")) { $SInfo{"Lang"} = $Lang; } $ABI{"SymbolInfo"}{$ID} = \%SInfo; } } if(my $Symbols = parseTag(\$ABI_DUMP, "symbols")) { my %LInfo = (); while(my $LibSymbols = parseTag_E(\$Symbols, "library", \%LInfo)) { my %SInfo = (); while(my $Symbol = parseTag_E(\$LibSymbols, "symbol", \%SInfo)) { if(my $Size = $SInfo{"size"}) { $ABI{"Symbols"}{$LInfo{"name"}}{$Symbol} = -$Size; } else { $ABI{"Symbols"}{$LInfo{"name"}}{$Symbol} = 1; } %SInfo = (); } %LInfo = (); } } if(my $DepSymbols = parseTag(\$ABI_DUMP, "dep_symbols")) { my %LInfo = (); while(my $LibSymbols = parseTag_E(\$DepSymbols, "library", \%LInfo)) { my %SInfo = (); while(my $Symbol = parseTag_E(\$LibSymbols, "symbol", \%SInfo)) { if(my $Size = $SInfo{"size"}) { $ABI{"DepSymbols"}{$LInfo{"name"}}{$Symbol} = -$Size; } else { $ABI{"DepSymbols"}{$LInfo{"name"}}{$Symbol} = 1; } %SInfo = (); } %LInfo = (); } } $ABI{"SymbolVersion"} = {}; if(my $SymbolVersion = parseTag(\$ABI_DUMP, "symbol_version")) { while(my $Symbol = parseTag(\$SymbolVersion, "symbol")) { $ABI{"SymbolVersion"}{parseTag(\$Symbol, "name")} = parseTag(\$Symbol, "version"); } } $ABI{"SkipTypes"} = {}; if(my $SkipTypes = parseTag(\$ABI_DUMP, "skip_types")) { while(my $Name = parseTag(\$SkipTypes, "name")) { $ABI{"SkipTypes"}{$Name} = 1; } } $ABI{"SkipSymbols"} = {}; if(my $SkipSymbols = parseTag(\$ABI_DUMP, "skip_symbols")) { while(my $Name = parseTag(\$SkipSymbols, "name")) { $ABI{"SkipSymbols"}{$Name} = 1; } } $ABI{"SkipNameSpaces"} = {}; if(my $SkipNameSpaces = parseTag(\$ABI_DUMP, "skip_namespaces")) { while(my $Name = parseTag(\$SkipNameSpaces, "name")) { $ABI{"SkipNameSpaces"}{$Name} = 1; } } $ABI{"SkipHeaders"} = {}; if(my $SkipHeaders = parseTag(\$ABI_DUMP, "skip_headers")) { while(my $Name = parseTag(\$SkipHeaders, "name")) { $ABI{"SkipHeaders"}{$Name} = 1; } } if(my $TargetHeaders = parseTag(\$ABI_DUMP, "target_headers")) { while(my $Name = parseTag(\$TargetHeaders, "name")) { $ABI{"TargetHeaders"}{$Name} = 1; } } if(my $Mode = parseTag(\$ABI_DUMP, "mode")) { $ABI{"Mode"} = $Mode; } if(my $Kind = parseTag(\$ABI_DUMP, "kind")) { if($Kind eq "BinOnly") { $ABI{"BinOnly"} = 1; } elsif($Kind eq "SrcBin") { $ABI{"SrcBin"} = 1; } } my %RInfo = (); parseTag_E(\$ABI_DUMP, "ABI_dump", \%RInfo); $ABI{"ABI_DUMP_VERSION"} = $RInfo{"version"}; $ABI{"XML_ABI_DUMP_VERSION"} = $RInfo{"xml_format"}; $ABI{"ABI_COMPLIANCE_CHECKER_VERSION"} = $RInfo{"acc"}; return \%ABI; } sub parseTag_E($$$) { my ($CodeRef, $Tag, $Info) = @_; if(not $Tag or not $CodeRef or not $Info) { return undef; } if(${$CodeRef}=~s/\<\Q$Tag\E(\s+([^<>]+)|)\>((.|\n)*?)\<\/\Q$Tag\E\>//) { my ($Ext, $Content) = ($2, $3); $Content=~s/\A\s+//g; $Content=~s/\s+\Z//g; if($Ext) { while($Ext=~s/(\w+)\=\"([^\"]*)\"//) { my ($K, $V) = ($1, $2); $Info->{$K} = xmlSpecChars_R($V); } } if(substr($Content, 0, 1) ne "<") { $Content = xmlSpecChars_R($Content); } return $Content; } return undef; } sub addTag(@) { my $Tag = shift(@_); my $Val = shift(@_); my @Ext = @_; my $Content = openTag($Tag, @Ext); chomp($Content); $Content .= xmlSpecChars($Val); $Content .= "\n"; $TAG_ID-=1; return $Content; } sub openTag(@) { my $Tag = shift(@_); my @Ext = @_; my $Content = ""; foreach (1 .. $TAG_ID) { $Content .= $INDENT; } $TAG_ID+=1; if(@Ext) { $Content .= "<".$Tag; my $P = 0; while($P<=$#Ext-1) { $Content .= " ".$Ext[$P]; $Content .= "=\"".xmlSpecChars($Ext[$P+1])."\""; $P+=2; } $Content .= ">\n"; } else { $Content .= "<".$Tag.">\n"; } return $Content; } sub closeTag($) { my $Tag = $_[0]; my $Content = ""; $TAG_ID-=1; foreach (1 .. $TAG_ID) { $Content .= $INDENT; } $Content .= "\n"; return $Content; } sub checkTags() { if($TAG_ID!=0) { printMsg("WARNING", "the number of opened tags is not equal to number of closed tags"); } } return 1;abi-compliance-checker-1.99.9/modules/RulesBin.xml000066400000000000000000002400561227016120300220060ustar00rootroot00000000000000 Added_Virtual_Method High V-table Virtual method @target has been added to this class. The layout of v-table has been changed. Call of any virtual method at higher position in this class or its subclasses may result in crash or incorrect behavior of applications. You should add several padding virtual methods at end of class declaration and use them one by one in the course of interface evolution. Added_Pure_Virtual_Method High V-table Pure virtual method @target has been added to this class. 1) Applications will not provide the implementation for this pure virtual method and therefore cause a crash in the library trying to call this method. 2) The layout of v-table has been changed. Call of any virtual method at higher position in this class or its subclasses may result in crash or incorrect behavior of applications. Added_Virtual_Method_At_End_Of_Leaf_Copying_Class Medium V-table Virtual method @target has been added to this class. The layout of v-table has been changed. This leaf class has no exported constructors and therefore applications will copy an old v-table of the class that will not contain a pointer to added virtual method. Call of any method in this class may result in crash or incorrect behavior of applications. NOTE: if new virtual method is called only from other new methods, then binary compatibility should not be affected. Added_Virtual_Method_At_End_Of_Leaf_Allocable_Class Safe V-table Virtual method @target has been added to this class. No effect. You can add virtual functions at end of leaf classes with exported constructors. Added_First_Virtual_Method High V-table First virtual method @target has been added to this class. 1) The layout of type structure has been shifted by @word_size bytes by the added v-table pointer. 2) Size of class has been increased by @word_size bytes. Removed_Virtual_Method High V-table Virtual method @target has been removed from this class. The layout of v-table has been changed. Call of this virtual method or any virtual method at higher position in this class or its subclasses may result in crash or incorrect behavior of applications. Removed_Pure_Virtual_Method High V-table Pure virtual method @target has been removed from this class. The layout of v-table has been changed. Call of this virtual method or any virtual method at higher position in this class or its subclasses may result in crash or incorrect behavior of applications. Removed_Last_Virtual_Method High V-table Last virtual method @target has been removed from this class. 1) The layout of type structure has been shifted by @word_size bytes by the removed v-table pointer. 2) Size of class has been decreased by @word_size bytes. Virtual_Replacement Medium V-table Virtual method @target has been added to this class instead of @old_value. Applications will pass parameters of older replaced method to newly added virtual method. This may result in crash or incorrect behavior of applications. Pure_Virtual_Replacement Medium V-table Pure virtual method @target has been added to this class instead of @old_value. Applications will provide an older method to the library instead of expected newely added virtual method. This may result in crash or incorrect behavior of applications. Virtual_Table_Changed_Unknown Medium V-table The layout of v-table has been changed for **unknown** reason. Call of any method in this class may result in crash or incorrect behavior of applications. Virtual_Method_Position High V-table The relative position of virtual method @target has been changed from @old_value to @new_value. The layout of v-table has been changed. Call of this virtual method may result in crash or incorrect behavior of applications. Pure_Virtual_Method_Position High V-table The relative position of pure virtual method @target has been changed from @old_value to @new_value. The layout of v-table has been changed. Call of this pure virtual method implementation may result in crash or incorrect behavior of applications. Overridden_Virtual_Method Low V-table Virtual method @old_value has been overridden by @new_value. Method @new_value will be called instead of @old_value by old applications. Overridden_Virtual_Method_B Low V-table Virtual method @old_value has been overridden by @new_value. Method @new_value will be called instead of @old_value by old applications. Size_Of_Allocable_Class_Increased High Classes Size of this class has been increased from @old_size to @new_size. 1) An object of this class can be allocated by the applications and old size will be hardcoded at the compile time. Call of any exported constructor will break the memory of neighboring objects on the stack or heap. 2) The memory layout and size of subclasses will be changed. Size_Of_Allocable_Class_Decreased Medium Classes Size of this class has been decreased from @old_size to @new_size. Previous accesses of applications to public fields of this class or its subclasses may be incorrect. Size_Of_Copying_Class High Classes Size of this class has been changed from @old_size to @new_size. 1) The class has only inline or auto-generated constructors which will be copied to applications at compile time and will allocate an older memory layout. Call of any exported method of this class may access a memory outside the allocated objects or inside the older memory structure and result in crash or incorrect behavior of applications. 2) The memory layout and size of subclasses will be changed. Base_Class_Position Low Classes The relative position of class @target has been changed from @old_value to @new_value in the list of base classes. Possible incorrect access of applications to the memory occupied by the base classes. Base_Class_Became_Virtually_Inherited Medium Classes Base class @target became **virtually** inherited. Size, memory layout and v-table layout of this class and subclasses may change. Base_Class_Became_Non_Virtually_Inherited Medium Classes Base class @target became **non-virtually** inherited. Size, memory layout and v-table layout of this class and subclasses may change. Added_Base_Class_And_Shift High Classes Base class @target has been added. The memory layout in this class has been shifted by @shift bytes. Added_Base_Class_And_Size High Classes Base class @target has been added. 1) Size of the class has been changed from @old_size to @new_size. 2) The memory layout in this class has been shifted by @shift bytes. Added_Base_Class_And_Shift_And_VTable High Classes Base class @target has been added. 1) The layout of v-table in this class has been changed. 2) The memory layout in this class has been shifted by @shift bytes. Added_Base_Class_And_Size_And_VTable High Classes Base class @target has been added. 1) The layout of v-table in this class has been changed. 2) Size of the class has been changed from @old_size to @new_size. 3) The memory layout in this class has been shifted by @shift bytes. Added_Base_Class_And_VTable High Classes Base class @target has been added. The layout of v-table in this class has been changed. Added_Base_Class Low Classes Base class @target has been added. Possible incorrect access of applications to the memory occupied by the base classes. Removed_Base_Class_And_Size High Classes Base class @target has been removed. 1) Size of the class has been changed from @old_size to @new_size. 2) The memory layout in this class has been shifted by @shift bytes. Removed_Base_Class_And_Shift High Classes Base class @target has been removed. The memory layout in this class has been shifted by @shift bytes. Removed_Base_Class_And_Shift_And_VTable High Classes Base class @target has been removed. 1) The layout of v-table in this class has been changed. 2) The memory layout in this class has been shifted by @shift bytes. Removed_Base_Class_And_Size_And_VTable High Classes Base class @target has been removed. 1) The layout of v-table in this class has been changed. 2) Size of the class has been changed from @old_size to @new_size. 3) The memory layout in this class has been shifted by @shift bytes. Removed_Base_Class_And_VTable High Classes Base class @target has been removed. The layout of v-table in this class has been changed. Removed_Base_Class Low Classes Base class @target has been removed. Possible incorrect access of applications to the memory occupied by the base classes. DataType_Size Low Types Size of this type has been changed from @old_size to @new_size. The fields or parameters of such data type may be incorrectly initialized or accessed by old client applications. DataType_Type Medium Types Type of this type has been changed from @old_value to @new_value. The fields or parameters of such data type may be incorrectly initialized or accessed by old client applications. DataType_Size_And_Stack High Types Size of this type has been changed from @old_size to @new_size. Layout of parameter's stack of several functions has been changed and therefore parameters at higher positions in the stack may be incorrectly initialized by applications. Moved_Field Medium Fields The relative position of field @target has been changed from @old_value to @new_value. Applications will access incorrect memory when attempting to access this field. Moved_Field_And_Size Medium Fields The relative position of field @target has been changed from @old_value to @new_value. 1) Applications will access incorrect memory when attempting to access this field. 2) Size of the inclusive type has been changed. Moved_Private_Field_And_Size Low Fields The relative position of private field @target has been changed from @old_value to @new_value. Size of the inclusive type has been changed. Added_Field Low Fields Field @target has been added to this type. This field will not be initialized by old clients. NOTE: this field should be accessed only from the new library functions, otherwise it may result in crash or incorrect behavior of applications. Added_Field_And_Size Low Fields Field @target has been added to this type. 1) This field will not be initialized by old clients. 2) Size of the inclusive type has been changed. NOTE: this field should be accessed only from the new library functions, otherwise it may result in crash or incorrect behavior of applications. Added_Field_And_Layout Medium Fields Field @target has been added at the middle position of this structural type. Layout of structure fields has been changed and therefore fields at higher positions of the structure definition may be incorrectly accessed by applications. Added_Field_And_Layout_And_Size Medium Fields Field @target has been added at the middle position of this structural type. 1) Size of the inclusive type has been changed. 2) Layout of structure fields has been changed and therefore fields at higher positions of the structure definition may be incorrectly accessed by applications. Added_Private_Field_And_Size Low Fields Field @target has been added to this type. Size of the inclusive type has been changed. NOTE: this field should be accessed only from the new library functions, otherwise it may result in crash or incorrect behavior of applications. Added_Private_Field_And_Layout Medium Fields Field @target has been added at the middle position of this structural type. Layout of structure fields has been changed and therefore fields at higher positions of the structure definition may be incorrectly accessed by applications. Added_Private_Field_And_Layout_And_Size Medium Fields Field @target has been added at the middle position of this structural type. 1) Size of the inclusive type has been changed. 2) Layout of structure fields has been changed and therefore fields at higher positions of the structure definition may be incorrectly accessed by applications. Added_Union_Field_And_Size Medium Fields Field @target has been added to this type. Size of the union has been changed. NOTE: this field should be accessed only from the new library functions, otherwise it may result in crash or incorrect behavior of applications. Added_Union_Field Low Fields Field @target has been added to this type. NOTE: this field should be accessed only from the new library functions, otherwise it may result in crash or incorrect behavior of applications. Removed_Field Medium Fields Field @target has been removed from this type. Applications will access incorrect memory when attempting to access this field. Removed_Field_And_Layout Medium Fields Field @target has been removed from the middle position of this structural type. 1) Applications will access incorrect memory when attempting to access this field. 2) Layout of structure fields has been changed and therefore fields at higher positions of the structure definition may be incorrectly accessed by applications. Removed_Field_And_Size Medium Fields Field @target has been removed from this type. 1) Applications will access incorrect memory when attempting to access this field. 2) Size of the inclusive type has been changed. Removed_Field_And_Layout_And_Size High Fields Field @target has been removed from the middle position of this structural type. 1) Previous accesses of applications to the removed field will be incorrect. 2) Layout of structure fields has been changed and therefore fields at higher positions of the structure definition may be incorrectly accessed by applications. Removed_Private_Field_And_Size Low Fields Field @target has been removed from this type. Size of the inclusive type has been changed. Removed_Private_Field_And_Layout Medium Fields Field @target has been removed from the middle position of this structural type. Layout of structure fields has been changed and therefore fields at higher positions of the structure definition may be incorrectly accessed by applications. Removed_Private_Field_And_Layout_And_Size Medium Fields Field @target has been removed from the middle position of this structural type. 1) Layout of structure fields has been changed and therefore fields at higher positions of the structure definition may be incorrectly accessed by applications. 2) Size of the inclusive type has been changed. Removed_Union_Field_And_Size Medium Fields Field @target has been removed from this union. 1) Applications may access incorrect memory when attempting to access this field. 2) Size of the union has been changed. Removed_Union_Field Low Fields Field @target has been removed from this union. Applications may access incorrect memory when attempting to access this field. Renamed_Field Low Fields Field @target has been renamed to @new_value. Renaming of a field in data type may indicate a change in the semantic meaning of the field. Used_Reserved_Field Low Fields Reserved field @target has been replaced by @new_value. This field will not be initialized by old clients. Enum_Member_Value Medium Constants Value of member @target has been changed from @old_value to @new_value. Applications may execute a wrong branch of code in the library and therefore change the behavior. Enum_Member_Removed Low Constants The member @target has been removed. This may result in crash or incorrect behavior of applications because the library may not handle removed member anymore. Enum_Last_Member_Value Low Constants Value of member @target has been changed from @old_value to @new_value. Applications may execute a wrong branch of code in the library and therefore change the behavior. Enum_Private_Member_Value Safe Constants Value of private member @target has been changed from @old_value to @new_value. No effect. Enum_Member_Name Low Constants Name of member with value @target has been changed from @old_value to @new_value. Applications may execute a wrong branch of code in the library and therefore change the behavior. Field_Type Low Fields Type of field @target has been changed from @old_value to @new_value. Replacement of the field data type may indicate a change in the semantic meaning of the field. Field_Type_And_Size Medium Fields Type of field @target has been changed from @old_value (@old_size) to @new_value (@new_size). This field may be incorrectly initialized or accessed by applications. Field_Type_And_Size_And_Layout Medium Fields Type of field @target has been changed from @old_value (@old_size) to @new_value (@new_size). Previous accesses of applications and library functions to this field and fields at higher positions of the structure definition may be broken. Field_Type_And_Size_And_Type_Size Medium Fields Type of field @target has been changed from @old_value (@old_size) to @new_value (@new_size). 1) This field may be incorrectly initialized or accessed by applications. 2) Size of the inclusive type has been changed. Field_Type_And_Size_And_Layout_And_Type_Size Medium Fields Type of field @target has been changed from @old_value (@old_size) to @new_value (@new_size). 1) Size of the inclusive type has been changed. 2) Previous accesses of applications and library functions to this field and fields at higher positions of the structure definition may be broken. Private_Field_Type_And_Size_And_Layout Medium Fields Type of field @target has been changed from @old_value (@old_size) to @new_value (@new_size). Previous accesses of applications and library functions to the fields at higher positions of the structure definition may be broken. Private_Field_Type_And_Size_And_Type_Size Low Fields Type of field @target has been changed from @old_value (@old_size) to @new_value (@new_size). Size of the inclusive type has been changed. Private_Field_Type_And_Size_And_Layout_And_Type_Size Medium Fields Type of field @target has been changed from @old_value (@old_size) to @new_value (@new_size). 1) Size of the inclusive type has been changed. 2) Previous accesses of applications and library functions to the fields at higher positions of the structure definition may be broken. Field_BaseType_And_Size Low Fields Base type of field @target has been changed from @old_value (@old_size) to @new_value (@new_size). Possible access of applications to incorrect memory through the pointer. Field_BaseType Low Fields Base type of field @target has been changed from @old_value to @new_value. Replacement of field base type may indicate a change in the semantic meaning of the field. Field_PointerLevel_Increased Medium Fields The pointer level of field @target has been increased from @old_value to @new_value. The library functions may try to access unallocated memory by the dereferencing of old field value and therefore cause a crash of applications. Field_PointerLevel_Decreased Low Fields The pointer level of field @target has been decreased from @old_value to @new_value. The library functions will treat the value of this field as the lower-dimension array and will not read all elements. This may change the behavior of applications. Field_Size Medium Fields Size of field @target has been changed from @old_size to @new_size. Previous accesses of applications and library functions to this field may be broken. Struct_Field_Size_Increased Low Fields Size of field @target has been changed from @old_size to @new_size. Previous accesses of applications and library functions to this field may be broken. Field_Size_And_Layout Medium Fields Size of field @target has been changed from @old_size to @new_size. Previous accesses of applications and library functions to this field and fields at higher positions of the structure definition may be broken. Field_Size_And_Type_Size Medium Fields Size of field @target has been changed from @old_size to @new_size. 1) Size of the inclusive type has been changed. 2) Previous accesses of applications and library functions to this field may be broken. Field_Size_And_Layout_And_Type_Size Medium Fields Size of field @target has been changed from @old_size to @new_size. 1) Size of the inclusive type has been changed. 2) Previous accesses of applications and library functions to this field and fields at higher positions of the structure definition may be broken. Private_Field_Size_And_Layout Medium Fields Size of field @target has been changed from @old_size to @new_size. Previous accesses of applications and library functions to the fields at higher positions of the structure definition may be broken. Private_Field_Size_And_Type_Size Low Fields Size of field @target has been changed from @old_size to @new_size. Size of the inclusive type has been changed. Private_Field_Size_And_Layout_And_Type_Size Medium Fields Size of field @target has been changed from @old_size to @new_size. 1) Size of the inclusive type has been changed. 2) Previous accesses of applications and library functions to the fields at higher positions of the structure definition may be broken. Typedef_BaseType Low Types Base type has been changed from @old_value to @new_value. Replacement of the base data type may indicate a change in its semantic meaning. Typedef_BaseType_Format Medium Types Base type has been changed from @old_value to @new_value of different format. The fields or parameters of such data type may be incorrectly initialized or accessed by old client applications. Added_Symbol Safe Symbols Removed_Symbol High Symbols Method_Became_Static High Symbols Method became static. Layout of parameter's stack has been changed and therefore parameters at higher positions in the stack may be incorrectly initialized by applications. Method_Became_Non_Static High Symbols Method became non-static. Layout of parameter's stack has been changed and therefore parameters at higher positions in the stack may be incorrectly initialized by applications. Parameter_Default_Value_Changed Low Parameters The default argument of @param_pos parameter @target has been changed from @old_value to @new_value. Applications will pass an old default (compile-time) argument that may not be properly handled anymore. This may result in crash or incorrect behavior of applications. Parameter_Default_Value_Removed Low Parameters The default argument @old_value of @param_pos parameter @target has been removed. Applications will pass an old default argument (that is not default any more) that may not be properly handled anymore. This may result in crash or incorrect behavior of applications. Parameter_Default_Value_Added Safe Parameters The default argument @new_value of @param_pos parameter @target has been added. No effect. Parameter_Type_And_Register Medium Symbols Type of @param_pos parameter @target has been changed from @old_value (@old_size) to @new_value (@new_size). The parameter became passed in different register. Applications will read the wrong memory block instead of the parameter value. Also, distribution of other parameters on the available registers and stack may be changed. Parameter_Type_And_Stack High Parameters Type of @param_pos parameter @target has been changed from @old_value (@old_size) to @new_value (@new_size). Layout of parameter's stack has been changed and therefore parameters at higher positions in the stack may be incorrectly initialized by applications. Parameter_Type_And_Size High Parameters Type of @param_pos parameter @target has been changed from @old_value (@old_size) to @new_value (@new_size). Layout of parameter's stack has been changed and therefore parameters at higher positions in the stack may be incorrectly initialized by applications. Parameter_Type_From_Stack_To_Register High Parameters Type of @param_pos parameter @target has been changed from @old_value (@old_size) to @new_value (@new_size). The parameter became passed in the register instead of the stack. This may result in crash or incorrect behavior of applications. Parameter_Type_From_Register_To_Stack High Parameters Type of @param_pos parameter @target has been changed from @old_value (@old_size) to @new_value (@new_size). The parameter became passed through the stack instead of the register. This may result in crash or incorrect behavior of applications. Parameter_Type Low Parameters Type of @param_pos parameter @target has been changed from @old_value to @new_value. Replacement of parameter data type may indicate a change in its semantic meaning. Parameter_Became_Non_Const Medium Parameters Type of @param_pos parameter @target has been changed from @old_value to @new_value (became non-const). This function may change parameter @target, but it will be treated as const by old client applications. This may result in crash or incorrect behavior of applications. Parameter_Removed_Const Medium Parameters Type of @param_pos parameter @target has been changed from @old_value to @new_value (removed const qualifier). This function may change parameter @target, but it will be treated as const by old client applications. This may result in crash or incorrect behavior of applications. Parameter_Became_Restrict Medium Parameters Parameter @target became restrict. Added a new restriction on the parameter: if the memory addressed by the restrict-qualified pointer is modified, no other pointer will access that same memory. The compiler may choose to optimize new library code involving restrict-qualified pointers in a way that might result in incorrect behavior of old applications, that don't meet this restriction. Parameter_Became_Non_Restrict Safe Parameters Parameter @target became non-restrict. No effect. Parameter_Became_Register Medium Parameters Added register modifier to the parameter @target. The parameter may be passed in a register instead of the calling stack. Parameter_Became_Non_Register Medium Parameters Removed register modifier from the parameter @target. The parameter will be passed on the calling stack instead of a register. Parameter_To_Register Medium Parameters The parameter @target became passed in @new_value register instead of stack. Violation of the calling convention. This may result in crash or incorrect behavior of applications. Parameter_From_Register Medium Parameters The parameter @target became passed on stack instead of @old_value register. Violation of the calling convention. This may result in crash or incorrect behavior of applications. Parameter_Changed_Register High Symbols The parameter @target became passed in @new_value register instead of @old_value. Applications will read the wrong memory block instead of the parameter value. Parameter_Changed_Offset High Symbols The parameter @target became passed at the different offset on the stack (@new_value instead of @old_value). Violation of the calling convention. This may result in crash or incorrect behavior of applications. Return_Type_Became_Const Medium Symbols Type of return value became const (has been changed from @old_value to @new_value). The return value will be treated as non-const by old client applications. This may result in crash or incorrect behavior of applications. Return_Type_Added_Const Medium Symbols Added **const** qualifier to return value (has been changed from @old_value to @new_value). The return value will be treated as non-const by old client applications. This may result in crash or incorrect behavior of applications. Parameter_BaseType_And_Size Medium Parameters Base type of @param_pos parameter @target has been changed from @old_value (@old_size) to @new_value (@new_size). This parameter may be incorrectly initialized by applications. Parameter_BaseType Low Parameters Base type of @param_pos parameter @target has been changed from @old_value to @new_value. Replacement of parameter base type may indicate a change in its semantic meaning. Parameter_PointerLevel_Increased High Parameters The pointer level of @param_pos parameter @target has been increased from @old_value to @new_value. The library function may try to access unallocated memory by the dereferencing of old parameter value and therefore cause a crash of applications. Parameter_PointerLevel_Decreased Medium Parameters The pointer level of @param_pos parameter @target has been decreased from @old_value to @new_value. The library function will treat the parameter as the lower-dimension array and will not read all elements. This may change the behavior of applications. NOTE: if this is out-parameter then this change may cause a crash of applications. Return_Type_And_Size Medium Symbols Type of return value has been changed from @old_value (@old_size) to @new_value (@new_size). Applications will obtain a different return value and execution may change. Global_Data_Type_And_Size Medium Symbols Type of this global data has been changed from @old_value (@old_size) to @new_value (@new_size). Applications will obtain a different value and execution may change. Return_Type Low Symbols Type of return value has been changed from @old_value to @new_value. Replacement of return type may indicate a change in its semantic meaning. Global_Data_Type Low Symbols Type of this global data has been changed from @old_value to @new_value. Replacement of data type may indicate a change in semantic meaning. Global_Data_Type_Format Medium Symbols Type of this global data has been changed from @old_value to @new_value of different format. This global data may be incorrectly accessed by applications. Global_Data_Size Medium Symbols Size of this global data has been changed from @old_size to @new_size. Applications will obtain a different value and execution may change. Return_Type_Became_Void Medium Symbols Type of return value has been changed from @old_value (@old_size) to void. Applications will not obtain a return value and execution may change. Return_Type_Became_Void_And_Stack_Layout High Symbols Type of return value has been changed from @old_value (@old_size) to void. 1) Applications will read the wrong memory block instead of the return value. 2) Layout of parameter's stack has been shifted by @word_size bytes because the hidden first argument, that is used to pass the return value, has been removed. All the parameters will be incorrectly initialized by applications. Return_Type_Became_Void_And_Register High Symbols Type of return value has been changed from @old_value (@old_size) to void. 1) Applications will read the wrong memory block instead of the return value. 2) Distribution of parameters on the available registers and stack has been changed because the hidden first argument, that is used to pass the return value, has been removed. All the parameters will be incorrectly initialized by applications. Return_Type_From_Void_And_Stack_Layout High Symbols Type of return value has been changed from void to @new_value (@new_size). Layout of parameter's stack has been shifted by @word_size bytes because the return value became passed in memory as the hidden first argument, that was used to pass the return value. All the parameters will be incorrectly initialized by applications. Return_Type_From_Void_And_Register High Symbols Type of return value has been changed from void to @new_value (@new_size). Distribution of parameters on the available registers and stack has been changed because the return value became passed in memory as the hidden first argument, that is used to pass the return value. All the parameters will be incorrectly initialized by applications. Return_Type_From_Void Low Symbols Type of return value has been changed from void to @new_value (@new_size). Replacement of return type may indicate a change in its semantic meaning. Return_Type_From_Register_To_Stack High Symbols Type of return value has been changed from @old_value (@old_size) to @new_value (@new_size). 1) The return value became passed in memory as the hidden first argument (address of the space on the stack provided by the caller) instead of the register and therefore the layout of parameter's stack has been shifted by @word_size bytes. All the parameters will be incorrectly initialized by applications. 2) Applications will read the wrong memory block instead of the return value. Return_Type_And_Register_Became_Hidden_Parameter High Symbols Type of return value has been changed from @old_value (@old_size) to @new_value (@new_size). 1) The return value became passed in different register as the hidden first argument (address of the space on the stack provided by the caller) and therefore distribution of parameters on the available registers and stack will be changed. All the parameters will be incorrectly initialized by applications. 2) Applications will read the wrong memory block instead of the return value. Return_Type_From_Stack_To_Register High Symbols Type of return value has been changed from @old_value (@old_size) to @new_value (@new_size). 1) The return value became passed in register instead of the hidden first argument (address of the space on the stack provided by the caller) and therefore the layout of parameter's stack has been shifted by @word_size bytes. All the parameters will be incorrectly initialized by applications. 2) Applications will read the wrong memory block instead of the return value. Return_Type_And_Register_Was_Hidden_Parameter High Symbols Type of return value has been changed from @old_value (@old_size) to @new_value (@new_size). 1) The return value became passed in register instead of the hidden first argument, that is passed in different register, and therefore distribution of parameters on the available registers and stack will be changed. All the parameters will be incorrectly initialized by applications. 2) Applications will read the wrong memory block instead of the return value. Global_Data_Became_Non_Const Medium Symbols This global data became non-const. This data will be copied to applications at compile time. Any attempts to change this global data by library functions may result in crash of applications. Global_Data_Removed_Const Low Symbols Removed **const** qualifier from the type of this global data. This data will be treated as const by old client applications. Any attempts to change this global data by library functions may result in undefined behavior. Global_Data_Became_Const Medium Symbols This global data became const. Any attempts of old applications to change this global data may result in crash. Global_Data_Added_Const Medium Symbols Added **const** qualifier to the type of this global data. Any attempts of old applications to change this global data may result in crash. Return_BaseType_And_Size Medium Symbols Base type of return value has been changed from @old_value (@old_size) to @new_value (@new_size). Applications will obtain a different return value and execution may change. Return_BaseType Low Symbols Base type of return value has been changed from @old_value to @new_value. Replacement of return base type may indicate a change in its semantic meaning. Return_PointerLevel_Increased Low Symbols The pointer level of return value has been increased from @old_value to @new_value. Applications will treat the return value as the lower-dimension array and will not read all elements. This may change the behavior of applications. Return_PointerLevel_Decreased Medium Symbols The pointer level of return value has been decreased from @old_value to @new_value. Applications may try to access unallocated memory by the dereferencing of new return value and therefore cause a crash. Removed_Parameter Medium Parameters @param_pos parameter @target has been removed from the calling stack. This parameter will be ignored by the function. Removed_Unnamed_Parameter Medium Parameters Parameter @target of type @param_type has been removed from the calling stack. This parameter will be ignored by the function. Added_Parameter Medium Parameters Parameter @target of type @param_type has been added to the calling stack. This parameter will not be initialized by old clients. Added_Unnamed_Parameter Medium Parameters @param_pos parameter @target has been added to the calling stack. This parameter will not be initialized by old clients. Removed_Middle_Parameter High Parameters @param_pos middle parameter @target has been removed from the calling stack. Layout of parameter's stack has been changed and therefore parameters at higher positions in the stack may be incorrectly initialized by applications. Removed_Middle_Unnamed_Parameter High Parameters Middle parameter @target of type @param_type has been removed from the calling stack. Layout of parameter's stack has been changed and therefore parameters at higher positions in the stack may be incorrectly initialized by applications. Added_Middle_Parameter High Parameters Parameter @target of type @param_type has been added to the calling stack at the middle position. Layout of parameter's stack has been changed and therefore parameters at higher positions in the stack may be incorrectly initialized by applications. Added_Middle_Unnamed_Parameter High Parameters @param_pos parameter @target has been added to the calling stack at the middle position. Layout of parameter's stack has been changed and therefore parameters at higher positions in the stack may be incorrectly initialized by applications. Renamed_Parameter Low Parameters @param_pos parameter @target has been renamed to @new_value. Renaming of a parameter may indicate a change in its semantic meaning. Symbol_Became_Static High Symbols Method became static. The name of the appropriate symbol for this function on binary level has been changed from @old_value to @new_value. This may cause "undefined reference" linker error in old client applications. Symbol_Became_Non_Static High Symbols Method became non-static. The name of the appropriate symbol for this function on binary level has been changed from @old_value to @new_value. This may cause "undefined reference" linker error in old client applications. Symbol_Became_Virtual High Symbols Method became virtual. The name of the appropriate symbol for this function on binary level has been changed from @old_value to @new_value. This may cause "undefined reference" linker error in old client applications. Symbol_Became_Non_Virtual High Symbols Method became non-virtual. The name of the appropriate symbol for this function on binary level has been changed from @old_value to @new_value. This may cause "undefined reference" linker error in old client applications. Symbol_Changed_Return High Symbols Type of return value has been changed from @old_type to @new_type. The name of the appropriate symbol for this function on binary level has been changed from @old_value to @new_value. This may cause "undefined reference" linker error in old client applications. Global_Data_Symbol_Changed_Type High Symbols Type of this global data has been changed from @old_type to @new_type. The name of the appropriate symbol for this data on binary level has been changed from @old_value to @new_value. This may cause "undefined reference" linker error in old client applications. Symbol_Changed_Parameters High Symbols Parameters list has been changed. The name of the appropriate symbol for this function on binary level has been changed from @old_value to @new_value. This may cause "undefined reference" linker error in old client applications. Method_Became_Non_Const High Symbols Method became non-const. The name of the appropriate symbol for this function on binary level has been changed from @old_value to @new_value. This may cause "undefined reference" linker error in old client applications. Method_Became_Const High Symbols Method became const. The name of the appropriate symbol for this function on binary level has been changed from @old_value to @new_value. This may cause "undefined reference" linker error in old client applications. Method_Became_Volatile High Symbols Method became volatile. The name of the appropriate symbol for this function on binary level has been changed from @old_value to @new_value. This may cause "undefined reference" linker error in old client applications. Method_Became_Non_Volatile High Symbols Method became non-volatile. The name of the appropriate symbol for this function on binary level has been changed from @old_value to @new_value. This may cause "undefined reference" linker error in old client applications. Changed_Constant Low Constants The value of constant @target has been changed from @old_value to @new_value. Applications will pass an old value of this constant as the parameter to the new-version library functions, that expect a new one. This may result in crash of incorrect behavior of applications. Added_Constant Safe Constants The constant @target with value @new_value has been added. No effect. Removed_Constant Low Constants The constant @target with value @old_value has been removed. The value of this constant may no longer be properly handled by new-version library functions. Field_Became_Volatile Low Fields Field @target became volatile. The value of this field can begin to change in ways outside the control of old client applications. Field_Became_Non_Volatile Safe Fields Field @target became non-volatile. No effect. Return_Value_Became_Volatile Low Symbols Return value became volatile. Old client applications will get volatile object instead of non-volatile, but may be optimized by the compiler and cannot handle volatile objects. Parameter_Became_Non_Volatile Low Symbols Parameter @target became non-volatile. Old client applications will pass volatile object to the function that may be optimized by the compiler and cannot handle volatile objects. Field_Type_Format Medium Fields Type of field @target has been changed from @old_value to @new_value of different format. This field may be incorrectly initialized or accessed by applications. Field_BaseType_Format Medium Fields Base type of field @target has been changed from @old_value to @new_value of different format. This field may be incorrectly initialized or accessed by applications. Parameter_Type_Format Medium Parameters Type of parameter @target has been changed from @old_value to @new_value of different format. This parameter may be incorrectly initialized by applications. Parameter_BaseType_Format Medium Parameters Base type of parameter @target has been changed from @old_value to @new_value of different format. This parameter may be incorrectly initialized by applications. Return_Type_Format Medium Symbols Type of return value has been changed from @old_value to @new_value of different format. Applications will obtain a different return value and execution may change. Return_Type_And_Register Medium Symbols Type of return value has been changed from @old_value to @new_value. The return value became passed in different register. Applications will read the wrong memory block instead of the return value. Also, distribution of parameters on the available registers and stack may be changed. Return_BaseType_Format Medium Symbols Base type of return value has been changed from @old_value to @new_value of different format. This parameter may be incorrectly initialized by applications. Parameter_Became_Non_VaList Low Parameters Type of @param_pos parameter has been changed from ... (va_list) to @new_value. This parameter may not be initialized by old clients. Parameter_Became_VaList Low Parameters Type of @param_pos parameter @target has been changed from @old_value to ... (va_list). The semantic meaning of the parameter may change. Added_Enum_Member Safe Constants The member @target with value @new_value has been added. No effect. Global_Data_Value_Changed Low Symbols The initial value of this global data has been changed from @old_value to @new_value. Applications will use an old value of this data instead of the new one. This may cause incorrect behavior of applications. Field_Became_Mutable Low Fields Field @target became **mutable**. The value of this field can begin to change in ways outside the control of old client applications. Field_Became_Non_Mutable Low Fields Field @target became **non-mutable**. The value of this field can still be changed by const methods of old client applications, but it's not expected by new-version library. Method_Became_Private Low Symbols This method became **private**. Old applications will continue using this method, but it may require a different initialization of the environment and parameters. Method_Became_Protected Low Symbols This method became **protected**. Old applications will continue using this method, but it may require a different initialization of the environment and parameters. Method_Became_Public Safe Symbols This method became **public**. No effect. Global_Data_Became_Private Low Symbols This global data became **private**. Old applications will continue using this global data, but it may require a different initialization of the environment. Global_Data_Became_Protected Low Symbols This global data became **protected**. Old applications will continue using this global data, but it may require a different initialization of the environment. Global_Data_Became_Public Safe Symbols This global data became **public**. No effect. Field_Became_Const Low Types Field @target became **const**. The value of this field is expected to be **const** in new library version, but can be modified by old applications. Field_Became_Non_Const Safe Types Field @target became **non-const**. No effect. Field_Added_Const Low Types Added **const** qualifier to field @target. The value of this field is expected to be **const** in new library version, but can be modified by old applications. Field_Removed_Const Safe Types Removed **const** qualifier from field @target. No effect. Field_Became_Private Low Types Field @target became **private**. Old applications will continue using this field, but it may require a different initialization of class object. Field_Became_Protected Low Types Field @target became **protected**. Old applications will continue using this field, but it may require a different initialization of class object. Virtual_Method_Became_Pure Medium Types Virtual method @target became **pure**. Old applications will not provide implementation for this pure virtual method. This may result in crash or incorrect behavior of applications. Virtual_Method_Became_Non_Pure Safe Types Virtual method @target became **non-pure**. No effect. Type_Became_Opaque Medium Types This type became **opaque**. The internal structure of this type is hidden in the new library version and may be different. This may result in crash or incorrect behavior of applications. abi-compliance-checker-1.99.9/modules/RulesSrc.xml000066400000000000000000001002271227016120300220200ustar00rootroot00000000000000 Renamed_Field High Fields Field @target has been renamed to @new_value. Recompilation of a client program may be broken with the error message: @type_name has no member named @target. Used_Reserved_Field Safe Fields Reserved field @target has been replaced by @new_value. No effect. Field_Type Low Fields Type of field @target has been changed from @old_value to @new_value. Recompilation of a client program may be broken. Added_Pure_Virtual_Method High V-table Pure virtual method @target has been added to this class. Recompilation of a client program may be broken with the error message: cannot allocate an object of abstract type @type_name because the following virtual functions are pure within @type_name: virtual @target. Removed_Pure_Virtual_Method High V-table Pure_Virtual method @target has been removed from this class. Recompilation of a client program may be broken. Overridden_Virtual_Method Low V-table Virtual method @old_value has been overridden by @new_value. Method @new_value will be called after recompilation instead of @old_value. Overridden_Virtual_Method_B Low V-table Virtual method @old_value has been overridden by @new_value. Method @new_value will be called after recompilation instead of @old_value. Added_Base_Class Low Classes Base class @target has been added. Recompilation of a client program may be broken. Removed_Base_Class Low Classes Base class @target has been removed. Recompilation of a client program may be broken. DataType_Type Medium Types Type of this type has been changed from @old_value to @new_value. Recompilation of a client program may be broken. Moved_Field Safe Fields The relative position of field @target has been changed from @old_value to @new_value. No effect. Added_Field Low Fields Field @target has been added to this type. This field will not be initialized or used by old client applications. Added_Union_Field Safe Fields Field @target has been added to this type. No effect. Removed_Field High Fields Field @target has been removed from this type. Recompilation of a client program may be broken with the error message: '@type_name' has no member named '@target'. Removed_Union_Field High Fields Field @target has been removed from this union. Recompilation of a client program may be broken. Enum_Member_Value Safe Constants Value of member @target has been changed from @old_value to @new_value. No effect. Enum_Last_Member_Value Safe Constants Value of member @target has been changed from @old_value to @new_value. No effect. Enum_Private_Member_Value Safe Constants Value of private member @target has been changed from @old_value to @new_value. No effect. Enum_Member_Removed High Constants The member @target has been removed. Recompilation of a client program may be broken. Enum_Member_Name High Constants Name of member with value @target has been changed from @old_value to @new_value. Recompilation of a client program may be broken with the error message: '@old_value' was not declared in this scope. Field_BaseType Low Fields Base type of field @target has been changed from @old_value to @new_value. Recompilation of a client program may be broken. Field_PointerLevel Medium Fields The pointer level of field @target has been increased from @old_value to @new_value. Recompilation of a client program may be broken. Typedef_BaseType Low Types Base type has been changed from @old_value to @new_value. Recompilation of a client program may be broken. Typedef_BaseType_Format Low Types Base type has been changed from @old_value to @new_value of different format. Recompilation of a client program may be broken. Added_Symbol Safe Symbols Removed_Symbol High Symbols Method_Became_Static Safe Symbols Method became static. No effect. Method_Became_Non_Static High Symbols Method became non-static. Recompilation of a client program may be broken with the error message: cannot call member function @target without object. Parameter_Default_Value_Changed Safe Parameters The default argument of @param_pos parameter @target has been changed from @old_value to @new_value. No effect. Parameter_Default_Value_Removed Medium Parameters The default argument @old_value of @param_pos parameter @target has been removed. Recompilation of a client program may be broken. Parameter_Default_Value_Added Safe Parameters The default argument @new_value of @param_pos parameter @target has been added. No effect. Parameter_Type Low Parameters Type of @param_pos parameter @target has been changed from @old_value to @new_value. Recompilation of a client program may be broken. Parameter_Type_Format Medium Parameters Type of parameter @target has been changed from @old_value to @new_value of different format. Recompilation of a client program may be broken. Parameter_BaseType_Format Medium Parameters Base type of parameter @target has been changed from @old_value to @new_value of different format. Recompilation of a client program may be broken. Parameter_BaseType Low Parameters Base type of @param_pos parameter @target has been changed from @old_value to @new_value. Recompilation of a client program may be broken. Parameter_Became_Non_Const Medium Parameters Type of @param_pos parameter @target has been changed from @old_value to @new_value (became non-const). Recompilation of a client program may be broken. Parameter_Removed_Const Medium Parameters Type of @param_pos parameter @target has been changed from @old_value to @new_value (removed const qualifier). Recompilation of a client program may be broken. Return_Type_Became_Const Medium Symbols Type of return value became const (has been changed from @old_value to @new_value). Recompilation of a client program may be broken. Return_Type_Added_Const Medium Symbols Added **const** qualifier to return value (has been changed from @old_value to @new_value). Recompilation of a client program may be broken. Parameter_PointerLevel Medium Parameters The pointer level of @param_pos parameter @target has been increased from @old_value to @new_value. Recompilation of a client program may be broken. Return_Type Low Symbols Type of return value has been changed from @old_value to @new_value. Recompilation of a client program may be broken. Return_Type_From_Void Safe Symbols Type of return value has been changed from void to @new_value. No effect. Global_Data_Type Low Symbols Type of this global data has been changed from @old_value to @new_value. Recompilation of a client program may be broken. Global_Data_Type_Format Medium Symbols Type of this global data has been changed from @old_value to @new_value of different format. Recompilation of a client program may be broken. Return_Type_Became_Void Medium Symbols Type of return value has been changed from @old_value (@old_size) to void. Recompilation of a client program may be broken. Global_Data_Became_Non_Const Safe Symbols This global data became non-const. No effect. Global_Data_Removed_Const Safe Symbols Removed **const** qualifier from the type of this global data. No effect. Global_Data_Became_Const Medium Symbols This global data became const. Recompilation of a client program may be broken. Global_Data_Added_Const Medium Symbols Added **const** qualifier to the type of this global data. Recompilation of a client program may be broken. Return_BaseType Low Symbols Base type of return value has been changed from @old_value to @new_value. Recompilation of a client program may be broken. Return_PointerLevel Medium Symbols The pointer level of return value has been increased from @old_value to @new_value. Recompilation of a client program may be broken. Removed_Parameter Medium Parameters @param_pos parameter @target has been removed from the calling stack. Recompilation of a client program may be broken. Removed_Unnamed_Parameter Medium Parameters Parameter @target of type @param_type has been removed from the calling stack. Recompilation of a client program may be broken. Added_Parameter Medium Parameters Parameter @target of type @param_type has been added to the calling stack. Recompilation of a client program may be broken. Added_Unnamed_Parameter Medium Parameters @param_pos parameter @target has been added to the calling stack. Recompilation of a client program may be broken. Removed_Middle_Parameter High Parameters @param_pos middle parameter @target has been removed from the calling stack. Recompilation of a client program may be broken. Removed_Middle_Unnamed_Parameter High Parameters Middle parameter @target of type @param_type has been removed from the calling stack. Recompilation of a client program may be broken. Added_Middle_Parameter High Parameters Parameter @target of type @param_type has been added to the calling stack at the middle position. Recompilation of a client program may be broken. Added_Middle_Unnamed_Parameter High Parameters @param_pos parameter @target has been added to the calling stack at the middle position. Recompilation of a client program may be broken. Renamed_Parameter Safe Parameters @param_pos parameter @target has been renamed to @new_value. No effect. Changed_Constant Low Constants The value of constant @target has been changed from @old_value to @new_value. Recompilation of a client program may be broken. Added_Constant Safe Constants The constant @target with value @new_value has been added. No effect. Removed_Constant Low Constants The constant @target with value @old_value has been removed. Recompilation of a client program may be broken. Field_Type_Format Medium Fields Type of field @target has been changed from @old_value to @new_value of different format. Recompilation of a client program may be broken. Field_BaseType_Format Medium Fields Base type of field @target has been changed from @old_value to @new_value of different format. Recompilation of a client program may be broken. Return_Type_Format Medium Symbols Type of return value has been changed from @old_value to @new_value of different format. Recompilation of a client program may be broken. Return_BaseType_Format Medium Symbols Base type of return value has been changed from @old_value to @new_value of different format. Recompilation of a client program may be broken. Parameter_Became_Non_VaList Medium Parameters Type of @param_pos parameter has been changed from ... (va_list) to @new_value. Recompilation of a client program may be broken. Parameter_Became_VaList Safe Parameters Type of @param_pos parameter @target has been changed from @old_value to ... (va_list). No effect. Added_Enum_Member Safe Constants The member @target with value @new_value has been added. No effect. Symbol_Changed_Parameters Medium Symbols Parameters list has been changed. Recompilation of a client program may be broken. Method_Became_Non_Const Medium Symbols Method became non-const. Recompilation of a client program may be broken with the error message: passing 'const @type_name' as 'this' argument of '@target' discards qualifiers. Method_Became_Const Safe Symbols Method became const. No effect. Method_Became_Volatile Safe Symbols Method became volatile. No effect. Method_Became_Non_Volatile Safe Symbols Method became non-volatile. No effect. Parameter_Became_Restrict Safe Parameters Parameter @target became restrict. No effect. Parameter_Became_Non_Restrict Safe Parameters Parameter @target became non-restrict. No effect. Field_Became_Volatile Safe Fields Field @target became volatile. No effect. Field_Became_Non_Volatile Safe Fields Field @target became non-volatile. No effect. Return_Value_Became_Volatile Safe Symbols Return value became volatile. No effect. Parameter_Became_Non_Volatile Safe Symbols Parameter @target became non-volatile. No effect. Global_Data_Value_Changed Safe Symbols The initial value of this global data has been changed from @old_value to @new_value. No effect. Field_Became_Mutable Safe Fields Field @target became **mutable**. No effect. Field_Became_Non_Mutable Medium Fields Field @target became **non-mutable**. Recompilation of a client program may be broken with the error message: assignment of member '@type_name::@target' in read-only object. Removed_Const_Overload Medium Types The **const** overload of the method @target has been removed from this class. Recompilation of a client program may be broken with the error message: passing 'const @type_name' as 'this' argument of '@target' discards qualifiers. Method_Became_Private High Symbols This method became **private**. Recompilation of a client program may be broken with the error message: '@target' is private. Method_Became_Protected Medium Symbols This method became **protected**. Recompilation of a client program may be broken with the error message: '@target' is protected. Method_Became_Public Safe Symbols This method became **public**. No effect. Global_Data_Became_Private High Symbols This global data became **private**. Recompilation of a client program may be broken with the error message: '@target' is private. Global_Data_Became_Protected Medium Symbols This global data became **protected**. Recompilation of a client program may be broken with the error message: '@target' is protected. Global_Data_Became_Public Safe Symbols This global data became **public**. No effect. Field_Became_Const Medium Types Field @target became **const**. Recompilation of a client program may be broken with the error message: assignment of read-only member/location '@type_name::@target'. Field_Became_Non_Const Safe Types Field @target became **non-const**. No effect. Field_Added_Const Low Types Added **const** qualifier to field @target. Recompilation of a client program may be broken with the error message: assignment of read-only member/location '@type_name::@target'. Field_Removed_Const Safe Types Removed **const** qualifier from field @target. No effect. Field_Became_Private Medium Types Field @target became **private**. Recompilation of a client program may be broken with the error message: '@type_name::@target' is private. Field_Became_Protected Medium Types Field @target became **protected**. Recompilation of a client program may be broken with the error message: '@type_name::@target' is protected. Virtual_Method_Became_Pure Medium Types Virtual method @target became **pure**. Recompilation of a client program may be broken with the error message: cannot allocate an object of abstract type '@type_name' because the following virtual functions are pure within '@type_name': virtual @target. Virtual_Method_Became_Non_Pure Safe Types Virtual method @target became **non-pure**. No effect. Type_Became_Opaque Medium Types This type became **opaque**. The internal structure of this type is hidden in the new library version and recompilation of a client program may be broken. abi-compliance-checker-1.99.9/modules/Targets/000077500000000000000000000000001227016120300211435ustar00rootroot00000000000000abi-compliance-checker-1.99.9/modules/Targets/symbian/000077500000000000000000000000001227016120300226055ustar00rootroot00000000000000abi-compliance-checker-1.99.9/modules/Targets/symbian/common.xml000066400000000000000000000005321227016120300246170ustar00rootroot00000000000000 gcce/gcce.h e32base.h ekern{000a0000}.dso iic{000a0000}.dso drtaeabi{000a0000}.dso resman{000a0000}.dso rm_debug_ext{000a0000}.dso javascriptcore{000a0000}.dso obcmanager{000a0000}.dso kernel/ abi-compliance-checker-1.99.9/modules/Targets/symbian/descriptors/000077500000000000000000000000001227016120300251465ustar00rootroot00000000000000abi-compliance-checker-1.99.9/modules/Targets/symbian/descriptors/cone.xml000066400000000000000000000000661227016120300266160ustar00rootroot00000000000000 coemain.h abi-compliance-checker-1.99.9/modules/Targets/symbian/descriptors/drmaudioplayutility.xml000066400000000000000000000000631227016120300320050ustar00rootroot00000000000000 -DSYMBIAN_CAF_V2 abi-compliance-checker-1.99.9/modules/Targets/symbian/descriptors/egul.xml000066400000000000000000000000661227016120300266260ustar00rootroot00000000000000 gulutil.h abi-compliance-checker-1.99.9/modules/Targets/symbian/descriptors/ekern.xml000066400000000000000000000002171227016120300267740ustar00rootroot00000000000000 e32*.h /win32/ /memmodel/ estring.h -D__KERNEL_MODE__ abi-compliance-checker-1.99.9/modules/Targets/symbian/descriptors/esocksvr.xml000066400000000000000000000001461227016120300275300ustar00rootroot00000000000000 /comms-infras/ -D__GCCXML__ abi-compliance-checker-1.99.9/modules/Targets/symbian/descriptors/estlib.xml000066400000000000000000000001701227016120300271500ustar00rootroot00000000000000 ieeefp.h nameser.h sys/types.h abi-compliance-checker-1.99.9/modules/Targets/symbian/descriptors/libc.xml000066400000000000000000000003061227016120300266000ustar00rootroot00000000000000 event.h /stdapis/ arp.h ip_icmp.h ip.h estlib.h nameser.h ieeefp.h sys/types.h abi-compliance-checker-1.99.9/modules/Targets/symbian/descriptors/libgles_cm.xml000066400000000000000000000001371227016120300277710ustar00rootroot00000000000000 /egl/ gl.h abi-compliance-checker-1.99.9/modules/Targets/symbian/descriptors/libglib.xml000066400000000000000000000000751227016120300272760ustar00rootroot00000000000000 gi18n.h gi18n-lib.h abi-compliance-checker-1.99.9/modules/Targets/symbian/descriptors/libstdcpp.xml000066400000000000000000000007321227016120300276560ustar00rootroot00000000000000 /stlportv5/ c_locale.h _prolog.h _epilog.h /config/ _relops_cont.h _function_adaptors.h _null_stream.h _ptrs_specialize.h _relops_hash_cont.h /debug/ /tools/ /wrappers/ e32base.h _ostreambuf_iterator.h _streambuf_iterator.h stdapis/stlport/cstdlib -D__SYMBIAN_STDCPP_SUPPORT__ abi-compliance-checker-1.99.9/modules/Targets/symbian/descriptors/libstdcppv5.xml000066400000000000000000000005571227016120300301360ustar00rootroot00000000000000 /tools/ /stlport/ _windows.h _prolog.h _epilog.h /config/ _relops_cont.h _function_adaptors.h _null_stream.h _ptrs_specialize.h _relops_hash_cont.h stlportv5/cstdlib -D__SYMBIAN_STDCPP_SUPPORT__ abi-compliance-checker-1.99.9/modules/Targets/symbian/descriptors/libz.xml000066400000000000000000000000731227016120300266300ustar00rootroot00000000000000 ezlib.h /stdapis/ abi-compliance-checker-1.99.9/modules/Targets/symbian/descriptors/mbufmgr.xml000066400000000000000000000001051227016120300273230ustar00rootroot00000000000000 es_mbuf.h es_mbuf.h abi-compliance-checker-1.99.9/modules/Targets/symbian/descriptors/mediaclientaudio.xml000066400000000000000000000000631227016120300311670ustar00rootroot00000000000000 -DSYMBIAN_CAF_V2 abi-compliance-checker-1.99.9/modules/Targets/symbian/descriptors/meshmachine.xml000066400000000000000000000000571227016120300301530ustar00rootroot00000000000000 -D__GCCXML__ abi-compliance-checker-1.99.9/modules/Targets/symbian/descriptors/netsm.xml000066400000000000000000000000531227016120300270140ustar00rootroot00000000000000 mm_*.h abi-compliance-checker-1.99.9/modules/Targets/symbian/descriptors/nodemessages.xml000066400000000000000000000001361227016120300303450ustar00rootroot00000000000000 mm_*.h -D__GCCXML__ abi-compliance-checker-1.99.9/modules/Targets/symbian/descriptors/phonon.xml000066400000000000000000000000751227016120300271730ustar00rootroot00000000000000 /private/ /private/ abi-compliance-checker-1.99.9/modules/Targets/symbian/descriptors/pkcs10.xml000066400000000000000000000000661227016120300267730ustar00rootroot00000000000000 asn1enc.h abi-compliance-checker-1.99.9/modules/Targets/symbian/descriptors/qtcore.xml000066400000000000000000000002301227016120300271600ustar00rootroot00000000000000 *._p /private/ qatomic_sh4a.h qt_windows.h qatomic_*.h qsharedpointer_impl.h qconfig* abi-compliance-checker-1.99.9/modules/Targets/symbian/descriptors/qtdeclarative.xml000066400000000000000000000000561227016120300305210ustar00rootroot00000000000000 /private/ abi-compliance-checker-1.99.9/modules/Targets/symbian/descriptors/qtgui.xml000066400000000000000000000001321227016120300270150ustar00rootroot00000000000000 /private/ qwindowdefs_win.h qx11embed_x11.h abi-compliance-checker-1.99.9/modules/Targets/symbian/descriptors/qtmultimedia.xml000066400000000000000000000000561227016120300303700ustar00rootroot00000000000000 /private/ abi-compliance-checker-1.99.9/modules/Targets/symbian/descriptors/qtnetwork.xml000066400000000000000000000000561227016120300277270ustar00rootroot00000000000000 /private/ abi-compliance-checker-1.99.9/modules/Targets/symbian/descriptors/qtscript.xml000066400000000000000000000000751227016120300275430ustar00rootroot00000000000000 /private/ /private/ abi-compliance-checker-1.99.9/modules/Targets/symbian/descriptors/qtsql.xml000066400000000000000000000000741227016120300270350ustar00rootroot00000000000000 /private/ qsql_*.h abi-compliance-checker-1.99.9/modules/Targets/symbian/descriptors/qtwebkit.xml000066400000000000000000000000561227016120300275230ustar00rootroot00000000000000 /private/ abi-compliance-checker-1.99.9/modules/Targets/symbian/descriptors/qtxmlpatterns.xml000066400000000000000000000000561227016120300306170ustar00rootroot00000000000000 /private/ abi-compliance-checker-1.99.9/modules/Targets/symbian/descriptors/redircli.xml000066400000000000000000000000641227016120300274650ustar00rootroot00000000000000 -D__HIDE_IPC_V1__ abi-compliance-checker-1.99.9/modules/Targets/symbian/descriptors/securesocket.xml000066400000000000000000000000741227016120300303700ustar00rootroot00000000000000 securesocket_internal.h abi-compliance-checker-1.99.9/modules/Targets/symbian/descriptors/stdnew.xml000066400000000000000000000001411227016120300271700ustar00rootroot00000000000000 -D__SYMBIAN_STDCPP_SUPPORT__ -D__SYMBIAN_STDCPP_SUPPORT__ abi-compliance-checker-1.99.9/modules/Targets/symbian/descriptors/wpeng.xml000066400000000000000000000001111227016120300270010ustar00rootroot00000000000000 -D__SECURE_API__ -D__SECURE_API__ abi-compliance-checker-1.99.9/modules/Targets/unix/000077500000000000000000000000001227016120300221265ustar00rootroot00000000000000abi-compliance-checker-1.99.9/modules/Targets/unix/common.xml000066400000000000000000000272641227016120300241530ustar00rootroot00000000000000 stddef.h stdint.h _init _fini key_free create_module program_name get_version open64 __open64 __h_errno_location GetProperty SetProperty stat64 DeleteProperty ReadBuffer WriteBuffer MD5_CTX get_volume client_name HMAC asn1_free MD5Final MD5Init MD5Update next_token get_interface gconf_client multiline_error multiline_warning MD5 pthread_create disassembler basic_string qDebug QtMobility qWarning const_iterator QSharedDataPointer sha1 sha1_hash addGroup qHash timeStamping new_item RSAPublicKey RSAPrivateKey errorType trace_level get_attribute _LIB_VERSION FileExists prog_name open_file close_file antialiasing master_volume make_vector exit_failure get_file_size log_info string_set loc2 is_blank getChar is_number CharType image_type runTests addTest initArgs __assert_fail utf8_strlen threadName __allocator isAbsolutePath pool_free next_line DBus gst_plugin_desc fs_init_plugin null_driver_open gstreamer_driver_open pulse_driver_open gconf_backend_get_vtable C_GetFunctionList query_module _res icu xmalloc xrealloc dist2 BorderColor get_num isdir fileName readFile readLine cfree openFile mergesort __clone inet_addr fallocate locs __select MD5Transform xfree ply_read nindex durations md5_final BackgroundColor ForegroundColor HighlightColor auths default_auth confs current_var GetMimeType OpenStream DrawPoint domain_id init_commands value_pos draw_lines old_flags ReadString WriteString MyFree initialized initialize sighandler copy_file store_int64 itemlist lts onset lexicon MutexLock request_id_counter set_attributes xmap voices flac safe_malloc vorbis MetaFile curl_handle idProduct concurrent motion_vectors bufLength facilitynames prioritynames get_elem add_elem list_size timeout_connect catstring list_new list_append window_size block_mode feature_tags list_next __rb fmap LogError ExpandEnvVars lucene path_list test_fn getIndex lineIndex find_lock active_list _des_crypt all_fields all_classes getBoolean sqlite3_key f_open amf base64 parse_line search_init GetNode RemoveList concatenate set_error cmd_data rsp_data get_server schemes add_field prp item_p stack_size restricted default_font KCal KSettings period_size buffer_time KParts QTest KLDAP NET KDevelop FunctionType mem_free new_group file_format event_names vmap gen_load can_create urlType get_date _Link getFields getTerms rtab encode_init write_header end_element min3 userAgent http_post data_callback charset_convert sha1_init xml_parse validate_method FileOpen RequestRead win32 FileSize ListRemove NextToken MPList SString UTF8Length report_error view_type read_string free_string old_mode lock_file free_list read_only get_field concurrency is_equal bitmap_xor init_tree make_time rmid _Rep calcCRC disableExtensions toString downloadManager PacketType shiftBits print_parents significance wcsrev unilen in_options copyright_notice init_file cpu_num list_info fileCount updateFile init_proc print_handler command_handler conf_init conf_get_str area2 makePath visibility hexDump INACTIVE helpers in_hash SAXHandler isPrimary inet_pton sys_errlist sys_nerr copy_list new_list new_elem free_elem characters setNamespace xmlRef logError Tcl_UniCharToUpper jinit_2pass_quantizer contrib file_close file_read process_group idlist setdebuglevel xasprintf g_verbose firstkey dbmclose registered on_finish on_cancel listPosition listCount c_toupper classmap BufLen lrm param_name free_f hexdump load_module str_size str_pad input_len num_modules input_buffer mime_name log_err readList UserAction CType memicmp x_type x_value NONE ErrMsg _cmp list_find list_count list_remove list_sort list_delete frequencies md5_update setVObjectName UString PropertyMap mfile ber_len int2str read_all write_all read_event sha256_init MD4Init bufferLength dictionary newBuffer fileOffset default_callback double_int next_bit region_size step_size statement_handler toXMLString declarations selections projection userName arg_list selectionlist linecount random_access handle_set sinks add_subtree UnicodeToChar preprocessing PageSize ToString addFilter ulaw2linear register_printf_function debug_flag MapFunction BackUp base_name base_len set_program_name node_copy set_id print_node is_active update_action UserList getHomeDir executeCommand loaders getTicks interpolate factor1 autoConvert ProviderManager initialised current_entry libiconv hash_string get_unit_size re_set_syntax debugger GetMessage setLang nameLength getFuncName doStart decode_table VALUES versionString interpreter read_options memdup type_info quietFlag StringValue current_file xmemdup EmptyString repository is_newline cert_data release_mutex InvertMatrix new_state source_changed display_blocks file_type begin_element gtab trace_flag read_info LCD file_list safe_free NPN_Status file_eof doubleToString StreamIO __assert _compare ToLower device_open set_verify set_credentials value_list operator cbuf_size hash_create list_insert hash_remove chat_send server_disconnect player_list is_enum suffixcmp test_stats appendToPath DrawColor median_ ch_free FindToken Interface_Class resultBuffer color_mode glValidateProgram get_char get_int get_encoding print_pool os_close ch_free res_color human_readable home time save img small static matrix sample wave output initialize restart shutdown feature status finish prepare put zoom struct info goto app script tool widget final align import key entity trash numeric self public volume drive cell title push mount method volume cmd format font random sheet layout pixmap bit unit pixel internal atom video drag icon rename view data export sound common option invalid fast native master complex part plugin serial buffer pool mutex panel return single draw param window import linux play remote release link quick micro media status host button scroll filter tab color format use audio frame unique header leave recent program show scan index query node sensor res light report folder mouse region sub model edit parent dialog form simple access wired all descriptor digit zone disk local music max min job task data size symbol user need handle gen extend catch fork signal page sys int unix trace func system mem module live core cache auto depend range uri stack repl swap url socket short relation record pseudo options move item label last change channel parser define path global event apply result good flush extended lock unlock basic shared void archive base connection attach selection full post throw must thread safe convert alloc discard bitmap do arch class dict enum exception function insert collection connect peek sock style string is input catalog render make plot row try words block edges fixed column destroy enlarge reset graph keyboard map line append date current decode external generate log setup skip store tree version zero which tag config build error html custom memory input vector split source motion codec byte undo was verify unpack test sort merge group clone register print lookup alarm delete clean action state text table object document component process message send enable file map macro image get set extract find copy read write new compute free next chunk dup fill default atomic array value type elem list parse secure debug hash err init clear about cancel main first load support server select update create client launch ask start login player chat embedded entries props can sleep interpret opt connected open remove add name count close probe str cmp join run search exists dump have has detect device check dir true field rate on stream end abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/000077500000000000000000000000001227016120300244675ustar00rootroot00000000000000abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/lib3dkit.xml000066400000000000000000000000631227016120300267150ustar00rootroot00000000000000 triangle.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libABRTUtils.xml000066400000000000000000000000371227016120300274510ustar00rootroot00000000000000 /abrt/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libCosmo.xml000066400000000000000000000001451227016120300267600ustar00rootroot00000000000000 #define USE_SERIAL_COSMO winDirent.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libEGL.xml000066400000000000000000000002141227016120300263040ustar00rootroot00000000000000 eglplatform.h eglplatform.h -DSUPPORT_X11 -DSUPPORT_X11 abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libFestival.xml000066400000000000000000000000541227016120300274540ustar00rootroot00000000000000 /EST/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libGLESv2.xml000066400000000000000000000001611227016120300267000ustar00rootroot00000000000000 /GL/ /GLES/ GLES2/gl2.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libGLw.xml000066400000000000000000000000611227016120300263660ustar00rootroot00000000000000 Xlib.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libGraphicsMagick.xml000066400000000000000000000002021227016120300305460ustar00rootroot00000000000000 /ImageMagick/ /libltdl/ ltdl.h magick/api.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libGraphicsMagickWand.xml000066400000000000000000000000601227016120300313620ustar00rootroot00000000000000 /ImageMagick/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libI810XvMC.xml000066400000000000000000000000611227016120300270540ustar00rootroot00000000000000 Xlib.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libIlmImf.xml000066400000000000000000000000711227016120300270530ustar00rootroot00000000000000 ImfB44Compressor.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libIntelXvMC.xml000066400000000000000000000000611227016120300275060ustar00rootroot00000000000000 Xlib.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libMagick.xml000066400000000000000000000002631227016120300270740ustar00rootroot00000000000000 mac.h nt-base.h nt-feature.h vms.h *-private.h /libltdl/ MagickCore.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libMagickCore.xml000066400000000000000000000001041227016120300276770ustar00rootroot00000000000000 /GraphicsMagick/ widget.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libMagickWand.xml000066400000000000000000000001411227016120300277010ustar00rootroot00000000000000 /vtk/ MagickWand.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libMapReduceMPI.xml000066400000000000000000000001121227016120300301050ustar00rootroot00000000000000 /usr/include/vtk/vtksys/ios abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libMrm.xml000066400000000000000000000001231227016120300264270ustar00rootroot00000000000000 Xlib.h X11/Intrinsic.h MrmAppl.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libNAccountsUI.xml000066400000000000000000000000571227016120300300350ustar00rootroot00000000000000 n-client.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libPropList.xml000066400000000000000000000000431227016120300274510ustar00rootroot00000000000000 proplist.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libQtCore.xml000066400000000000000000000001351227016120300270740ustar00rootroot00000000000000 qt_windows.h qatomic_*.h qsharedpointer_impl.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libQtGui.xml000066400000000000000000000000661227016120300267330ustar00rootroot00000000000000 qwindowdefs_win.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libQtMessaging.xml000066400000000000000000000000621227016120300301200ustar00rootroot00000000000000 QMessageStore abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libQtSparql.xml000066400000000000000000000001271227016120300274470ustar00rootroot00000000000000 qsparql_tracker_direct.h QTrackerDirectDriver abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libQtSql.xml000066400000000000000000000001071227016120300267420ustar00rootroot00000000000000 qsql_*.h *Driver *Result abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libWand.xml000066400000000000000000000000711227016120300265670ustar00rootroot00000000000000 MagickWand.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libWindowsWM.xml000066400000000000000000000000611227016120300275730ustar00rootroot00000000000000 Xlib.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libX11.xml000066400000000000000000000002311227016120300262450ustar00rootroot00000000000000 /wx/ /perl5/ /extensions/ CoreP.h ResourceI.h /xorg/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libXRes.xml000066400000000000000000000000621227016120300265570ustar00rootroot00000000000000 Xmd.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libXTrap.xml000066400000000000000000000000651227016120300267370ustar00rootroot00000000000000 xtraplib.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libXaw3d.xml000066400000000000000000000000731227016120300266660ustar00rootroot00000000000000 Xmu/WidgetNode.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libXaw6.xml000066400000000000000000000002161227016120300265240ustar00rootroot00000000000000 [a-z]P VendorEP.h SmeBSBP.h X11/Intrinsic.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libXaw7.xml000066400000000000000000000002161227016120300265250ustar00rootroot00000000000000 [a-z]P VendorEP.h SmeBSBP.h X11/Intrinsic.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libXext.xml000066400000000000000000000000711227016120300266260ustar00rootroot00000000000000 X11/Xproto.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libXfont.xml000066400000000000000000000002661227016120300270020ustar00rootroot00000000000000 /xorg/ ft2build.h freetype2/freetype/freetype.h fntfilst.h fontenc.h bitmap.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libXt.xml000066400000000000000000000000731227016120300262730ustar00rootroot00000000000000 [a-z]P [a-z]I abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libaegis_certman.xml000066400000000000000000000000561227016120300305020ustar00rootroot00000000000000 pkcs11f.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libanthyinput.xml000066400000000000000000000000641227016120300301030ustar00rootroot00000000000000 anthy.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libaoss.xml000066400000000000000000000000621227016120300266430ustar00rootroot00000000000000 /c++/ /bcc/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libapogeee.xml000066400000000000000000000000511227016120300273010ustar00rootroot00000000000000 /wine/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libapt-pkg-libc6.4.xml000066400000000000000000000000511227016120300303760ustar00rootroot00000000000000 SubstVar abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libapt-pkg-libc6.5.xml000066400000000000000000000000511227016120300303770ustar00rootroot00000000000000 SubstVar abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libapt-pkg-libc6.9.xml000066400000000000000000000000511227016120300304030ustar00rootroot00000000000000 SubstVar abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libasound.xml000066400000000000000000000001471227016120300271730ustar00rootroot00000000000000 emu10k1.h mixer_abst.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libatkmm.xml000066400000000000000000000000601227016120300270050ustar00rootroot00000000000000 /private/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libattica.xml000066400000000000000000000001501227016120300271410ustar00rootroot00000000000000 commentparser.h distributionparser.h homepagetypeparser.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libattr.xml000066400000000000000000000000701227016120300266470ustar00rootroot00000000000000 sys/types.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libaudio.xml000066400000000000000000000002031227016120300267740ustar00rootroot00000000000000 mutex.h Alibint.h Xlib.h X11/Intrinsic.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libavahi-core.xml000066400000000000000000000000651227016120300277170ustar00rootroot00000000000000 /avahi-client/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libavcodec.xml000066400000000000000000000002241227016120300273020ustar00rootroot00000000000000 #define __STDC_CONSTANT_MACROS /mythtv/ dxva2.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libavdevice.xml000066400000000000000000000002241227016120300274640ustar00rootroot00000000000000 #define __STDC_CONSTANT_MACROS /mythtv/ dxva2.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libavfilter.xml000066400000000000000000000002241227016120300275120ustar00rootroot00000000000000 #define __STDC_CONSTANT_MACROS /mythtv/ dxva2.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libavformat.xml000066400000000000000000000002241227016120300275150ustar00rootroot00000000000000 #define __STDC_CONSTANT_MACROS /mythtv/ dxva2.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libavutil.xml000066400000000000000000000002241227016120300272020ustar00rootroot00000000000000 #define __STDC_CONSTANT_MACROS /mythtv/ dxva2.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libbeecrypt.xml000066400000000000000000000000661227016120300275170ustar00rootroot00000000000000 /c++/ win.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libbeecrypt_cxx.xml000066400000000000000000000002541227016120300304000ustar00rootroot00000000000000 /beeyond/ /interfaces/ /java/ ByteBuffer.h ReadOnlyBufferException.h String.h UnsupportedOperationException.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libbluetooth.xml000066400000000000000000000002101227016120300276760ustar00rootroot00000000000000 eds_abi_wrapper.h bluetooth.h hci.h sdp.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libbmpeg.xml000066400000000000000000000000401227016120300267640ustar00rootroot00000000000000 bmpeg.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libbonobo-activation.xml000066400000000000000000000000601227016120300313110ustar00rootroot00000000000000 /libgnomevfs/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libbonoboui-2.xml000066400000000000000000000000541227016120300276520ustar00rootroot00000000000000 /gtk-3.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libboost_date_time.xml000066400000000000000000000002351227016120300310410ustar00rootroot00000000000000 date_formatting_limited.hpp formatters_limited.hpp boost/date_time.hpp abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libboost_filesystem.xml000066400000000000000000000002621227016120300312720ustar00rootroot00000000000000 /v2/ /detail/ #define BOOST_FILESYSTEM_VERSION 3 boost/filesystem.hpp abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libboost_iostreams.xml000066400000000000000000000000541227016120300311130ustar00rootroot00000000000000 array.hpp abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libboost_program_options.xml000066400000000000000000000002641227016120300323320ustar00rootroot00000000000000 value_semantic.hpp utf8_codecvt_facet.hpp program_options.hpp abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libboost_python.xml000066400000000000000000000002401227016120300304230ustar00rootroot00000000000000 make_tuple.hpp object_call.hpp type_list_impl_no_pts.hpp boost/python.hpp abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libboost_random.xml000066400000000000000000000000731227016120300303660ustar00rootroot00000000000000 boost/random.hpp abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libboost_regex.xml000066400000000000000000000000501227016120300302130ustar00rootroot00000000000000 boost/regex.hpp abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libboost_serialization.xml000066400000000000000000000002641227016120300317650ustar00rootroot00000000000000 vector_135.hpp shared_ptr_nmt_132.hpp vector.hpp /detail/ /archive/ serialization.hpp abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libboost_signals.xml000066400000000000000000000001641227016120300305470ustar00rootroot00000000000000 signal_template.hpp boost/signals.hpp abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libboost_thread.xml000066400000000000000000000001541227016120300303550ustar00rootroot00000000000000 /detail/ boost/thread.hpp abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libboost_wave.xml000066400000000000000000000000711227016120300300460ustar00rootroot00000000000000 boost/wave.hpp abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libbsd.xml000066400000000000000000000003241227016120300264470ustar00rootroot00000000000000 stdint.h time.h types.h in_systm.h inet.h /usr/include/sys/cdefs.h /usr/include/endian.h /usr/include/stdio.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libc-client.xml000066400000000000000000000002131227016120300273720ustar00rootroot00000000000000 /dovecot/ /inn/ sslio.h c-client.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libc.xml000066400000000000000000000011041227016120300261160ustar00rootroot00000000000000 kde_file.h gpsd.h math.h onigposix.h /pulsecore/ pcreposix.h /gssrpc/ /bind/ /file/ /wine/ /dietlibc/ /gcc/ /bcc/ /c++/ /boost/ /git/ /freeradius/ /tirpc/ /ptlib/ file.h /imap/ /w3c-libwww/ /openldap/ /lib/ regexp.h /bits/ /scsi/ /arpa/ /rpcsvc/ net/if_packet.h net/if.h asoundlib.h elf.h stdio.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libcairo.xml000066400000000000000000000000511227016120300267710ustar00rootroot00000000000000 /GL/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libcdda_paranoia.xml000066400000000000000000000000731227016120300304450ustar00rootroot00000000000000 cdda_interface.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libcddb.xml000066400000000000000000000001531227016120300265730ustar00rootroot00000000000000 /eet-1/ cddb_log.h cdaudio.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libcdio++.xml000066400000000000000000000000411227016120300267370ustar00rootroot00000000000000 cdio.hpp abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libcfitsio.xml000066400000000000000000000000421227016120300273340ustar00rootroot00000000000000 /cfitsio/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libchipcard.xml000066400000000000000000000000551227016120300274550ustar00rootroot00000000000000 misc.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libchromeXvMC.xml000066400000000000000000000000611227016120300277100ustar00rootroot00000000000000 Xlib.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libchromeXvMCPro.xml000066400000000000000000000000611227016120300303710ustar00rootroot00000000000000 Xlib.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libcim.xml000066400000000000000000000000361227016120300264470ustar00rootroot00000000000000 cim.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libclamav.xml000066400000000000000000000000411227016120300271360ustar00rootroot00000000000000 clamav.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libclanDisplay.xml000066400000000000000000000001561227016120300301450ustar00rootroot00000000000000 provider_dynamic.h string.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libclanPNG.xml000066400000000000000000000000751227016120300271640ustar00rootroot00000000000000 /usr/include/png.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libclanSound.xml000066400000000000000000000000631227016120300276250ustar00rootroot00000000000000 string.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libclinkc.xml000066400000000000000000000000701227016120300271400ustar00rootroot00000000000000 csubscription.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libcloog-ppl.xml000066400000000000000000000000561227016120300275750ustar00rootroot00000000000000 #define CLOOG_INT_INT abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libcloog.xml000066400000000000000000000001151227016120300270000ustar00rootroot00000000000000 ppl_backend.h polylib_backend.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libclucene.xml000066400000000000000000000003231227016120300273140ustar00rootroot00000000000000 #define _CL_DISABLE_MULTITHREADING /config/ FieldDoc.h CLBackwards.h InputStream.h OutputStream.h dirent.h LuceneThreads.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libconfig++.xml000066400000000000000000000001221227016120300272660ustar00rootroot00000000000000 libconfig.h++ /cyrus/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libconfig.xml000066400000000000000000000001201227016120300271360ustar00rootroot00000000000000 libconfig.h /cyrus/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libcontactsutils.xml000066400000000000000000000000761227016120300306020ustar00rootroot00000000000000 contactssettingsstorage.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libcppunit.xml000066400000000000000000000001411227016120300273560ustar00rootroot00000000000000 ExceptionTestCaseDecorator.h MfcTestRunner.h /mfc/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libcrypto.xml000066400000000000000000000000671227016120300272230ustar00rootroot00000000000000 /gnutls/ /boost/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libcrypto1.xml000066400000000000000000000001251227016120300272770ustar00rootroot00000000000000 camellia.h obj_mac.h cms.h seed.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libdb.xml000066400000000000000000000000701227016120300262620ustar00rootroot00000000000000 db_185.h /db2/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libdb2.xml000066400000000000000000000000651227016120300263500ustar00rootroot00000000000000 db_185.h /db1/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libdb_cxx.xml000066400000000000000000000000761227016120300271520ustar00rootroot00000000000000 exception.h db_185.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libdbus-glib.xml000066400000000000000000000002001227016120300275400ustar00rootroot00000000000000 dbus-glib-bindings.h -DDBUS_API_SUBJECT_TO_CHANGE abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libdbus.xml000066400000000000000000000002701227016120300266340ustar00rootroot00000000000000 dbus-glib-error-enum.h dbus-glib-bindings.h dbus-glib-error-enum.h -DDBUS_API_SUBJECT_TO_CHANGE abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libdevicelock.xml000066400000000000000000000001261227016120300300070ustar00rootroot00000000000000 devicelockif.h devicelockuiplugininterface.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libdevkit-power-gobject.xml000066400000000000000000000001301227016120300317250ustar00rootroot00000000000000 -DI_KNOW_THE_DEVICEKIT_POWER_API_IS_SUBJECT_TO_CHANGE abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libdirect.xml000066400000000000000000000001011227016120300271420ustar00rootroot00000000000000 interface_implementation.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libdistcache.xml000066400000000000000000000000671227016120300276320ustar00rootroot00000000000000 libnal/nal.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libdistcacheserver.xml000066400000000000000000000000671227016120300310610ustar00rootroot00000000000000 libnal/nal.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libdlmcontrol.xml000066400000000000000000000001201227016120300300460ustar00rootroot00000000000000 stdint.h sys/types.h libdlm.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libdmx.xml000066400000000000000000000000611227016120300264650ustar00rootroot00000000000000 Xlib.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libdres.xml000066400000000000000000000000641227016120300266350ustar00rootroot00000000000000 stdio.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libdrm_intel.xml000066400000000000000000000001071227016120300276530ustar00rootroot00000000000000 stdlib.h libdrm/drm.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libdrm_nouveau.xml000066400000000000000000000001131227016120300302170ustar00rootroot00000000000000 nv04_pushbuf.h nvc0_pushbuf.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libduicontrolpanel.xml000066400000000000000000000001461227016120300311030ustar00rootroot00000000000000 -DDESKTOP_DIR=\"\" -DDESKTOP_DIR2=\"\" -DAPPLET_LIBS=\"\" abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libdvbpsi.xml000066400000000000000000000002301227016120300271620ustar00rootroot00000000000000 stdint.h dvbpsi.h dvbpsi/descriptor.h dvbpsi/demux.h dr.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libebook.xml000066400000000000000000000003021227016120300267720ustar00rootroot00000000000000 e-data-book-bindings.h e-data-book-factory-bindings.h e-data-book-view-bindings.h glib/gtypes.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libedataserver.xml000066400000000000000000000001151227016120300302020ustar00rootroot00000000000000 e-component-listener.h e-sexp.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libedit.xml000066400000000000000000000000431227016120300266220ustar00rootroot00000000000000 readline.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libeggdbus.xml000066400000000000000000000001151227016120300273150ustar00rootroot00000000000000 -DEGG_DBUS_I_KNOW_API_IS_SUBJECT_TO_CHANGE abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libegroupwise.xml000066400000000000000000000000611227016120300300660ustar00rootroot00000000000000 e-gw-proxy.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libelf.xml000066400000000000000000000000631227016120300264450ustar00rootroot00000000000000 elf_repl.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libepub.xml000066400000000000000000000000371227016120300266330ustar00rootroot00000000000000 epub.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libesddsp.xml000066400000000000000000000000361227016120300271610ustar00rootroot00000000000000 esd.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libesmtp.xml000066400000000000000000000000431227016120300270250ustar00rootroot00000000000000 libesmtp.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libestbase.xml000066400000000000000000000002551227016120300273300ustar00rootroot00000000000000 /EST/ /ling_class/ /sigpr/ /rxp/ /unix/ EST_track_aux.h EST_wave_aux.h EST_viterbi.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libestools.xml000066400000000000000000000002361227016120300273710ustar00rootroot00000000000000 /EST/ EST_SCFG_Chart.h EST_tilt.h EST_types.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libevent.xml000066400000000000000000000000631227016120300270200ustar00rootroot00000000000000 rpc_struct.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libexif-gtk-5.0.0.xml000066400000000000000000000000541227016120300300530ustar00rootroot00000000000000 /gtk-3.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libexpect.xml000066400000000000000000000000601227016120300271640ustar00rootroot00000000000000 tcl.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libext2fs.xml000066400000000000000000000001301227016120300271050ustar00rootroot00000000000000 /ext2fs/ bitops.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libfalcon_engine.xml000066400000000000000000000002161227016120300304660ustar00rootroot00000000000000 *_win.h refstring.h xtree_fix.h spage.h heap_linux.h itm_deref.h stringwithid.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libffado.xml000066400000000000000000000001131227016120300267520ustar00rootroot00000000000000 /arpa/ ffado.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libfftw3.xml000066400000000000000000000000401227016120300267230ustar00rootroot00000000000000 fftw3.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libflake.xml000066400000000000000000000000551227016120300267620ustar00rootroot00000000000000 *Command.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libflask.xml000066400000000000000000000000601227016120300267740ustar00rootroot00000000000000 xen.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libflimage.xml000066400000000000000000000000661227016120300273060ustar00rootroot00000000000000 Fl_Window.H abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libfm-gtk-1.0.0.xml000066400000000000000000000000541227016120300275160ustar00rootroot00000000000000 /gtk-3.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libformsGL.xml000066400000000000000000000000621227016120300272470ustar00rootroot00000000000000 FL/FL.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libformw.xml000066400000000000000000000000541227016120300270310ustar00rootroot00000000000000 /ncurses/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libfreebl3.xml000066400000000000000000000000771227016120300272260ustar00rootroot00000000000000 ssl.h hasht.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libfreetype.xml000066400000000000000000000002131227016120300275170ustar00rootroot00000000000000 ftmac.h ftmodule.h fterrdef.h ft2build.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libfuse.xml000066400000000000000000000001631227016120300266420ustar00rootroot00000000000000 -D_FILE_OFFSET_BITS=64 *_lowlevel *_compat abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgailutil-3.xml000066400000000000000000000000431227016120300276470ustar00rootroot00000000000000 /gail-3.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgc.xml000066400000000000000000000001061227016120300262660ustar00rootroot00000000000000 new_gc_alloc.h gc_version.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgck.xml000066400000000000000000000000721227016120300264430ustar00rootroot00000000000000 #define GCK_API_SUBJECT_TO_CHANGE abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgcr.xml000066400000000000000000000001611227016120300264510ustar00rootroot00000000000000 #define GCR_API_SUBJECT_TO_CHANGE gcr-renderer.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgd.xml000066400000000000000000000000531227016120300262700ustar00rootroot00000000000000 /libwmf/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgda-3.0.xml000066400000000000000000000001651227016120300267330ustar00rootroot00000000000000 /libgda-4.0/ gda-server-provider-private.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgda-4.0.xml000066400000000000000000000001651227016120300267340ustar00rootroot00000000000000 /libgda-3.0/ gda-server-provider-private.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgda-report-3.0.xml000066400000000000000000000000571227016120300302440ustar00rootroot00000000000000 /libgda-4.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgda-report-4.0.xml000066400000000000000000000000571227016120300302450ustar00rootroot00000000000000 /libgda-3.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgda-ui-3.0.xml000066400000000000000000000000571227016120300273460ustar00rootroot00000000000000 /libgda-4.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgda-ui-4.0.xml000066400000000000000000000000571227016120300273470ustar00rootroot00000000000000 /libgda-3.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgda-xslt-3.0.xml000066400000000000000000000000571227016120300277230ustar00rootroot00000000000000 /libgda-4.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgda-xslt-4.0.xml000066400000000000000000000000571227016120300277240ustar00rootroot00000000000000 /libgda-3.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgdasql-3.0.xml000066400000000000000000000001101227016120300274410ustar00rootroot00000000000000 /libgda-4.0/ /dovecot/ /pqxx/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgdasql-4.0.xml000066400000000000000000000001101227016120300274420ustar00rootroot00000000000000 /libgda-3.0/ /dovecot/ /pqxx/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgdbm_compat.xml000066400000000000000000000000771227016120300301600ustar00rootroot00000000000000 db.h dbm.h /db1/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgdigicam.xml000066400000000000000000000000631227016120300274430ustar00rootroot00000000000000 glib.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgdiplus.xml000066400000000000000000000000631227016120300273460ustar00rootroot00000000000000 wtypes.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgdk-1.2.xml000066400000000000000000000000721227016120300267420ustar00rootroot00000000000000 /gtk-2.0/ /gtk-3.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgdk-3.xml000066400000000000000000000000541227016120300266040ustar00rootroot00000000000000 /gtk-2.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgdk-x11-2.0.xml000066400000000000000000000002721227016120300273520ustar00rootroot00000000000000 gdkalias.h gdkalias.h gdkalias.h gdkprivate.h /gtk-3.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgdkglext-x11-1.0.xml000066400000000000000000000000541227016120300304130ustar00rootroot00000000000000 /gtk-3.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgdkmm-2.4.xml000066400000000000000000000000541227016120300272770ustar00rootroot00000000000000 /gtk-3.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgdu.xml000066400000000000000000000000751227016120300264610ustar00rootroot00000000000000 #define GDU_API_IS_SUBJECT_TO_CHANGE abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgegl.xml000066400000000000000000000000631227016120300266150ustar00rootroot00000000000000 gegl-chant.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgeoclue.xml000066400000000000000000000000721227016120300273220ustar00rootroot00000000000000 gc-provider.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgettextlib.xml000066400000000000000000000000541227016120300300520ustar00rootroot00000000000000 libxml2 abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libggadget-1.0.xml000066400000000000000000000002651227016120300276010ustar00rootroot00000000000000 /scribus/ /gtk-3.0/ stdint.h gadget.h #define UINT64_C(c) c ## ULL abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libggadget-gtk-1.0.xml000066400000000000000000000002651227016120300303640ustar00rootroot00000000000000 /scribus/ /gtk-3.0/ stdint.h gadget.h #define UINT64_C(c) c ## ULL abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libggadget-qt-1.0.xml000066400000000000000000000002651227016120300302230ustar00rootroot00000000000000 /scribus/ /gtk-3.0/ stdint.h gadget.h #define UINT64_C(c) c ## ULL abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libggi.xml000066400000000000000000000000611227016120300264430ustar00rootroot00000000000000 /internal/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgii.xml000066400000000000000000000000611227016120300264450ustar00rootroot00000000000000 /internal/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgimp-2.0.xml000066400000000000000000000001541227016120300271310ustar00rootroot00000000000000 /gtk-3.0/ gimp.h gimpui.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgimpbase-2.0.xml000066400000000000000000000001371227016120300277650ustar00rootroot00000000000000 /gtk-3.0/ gimp.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgimpcolor-2.0.xml000066400000000000000000000001371227016120300301710ustar00rootroot00000000000000 /gtk-3.0/ gimp.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgimpconfig-2.0.xml000066400000000000000000000001371227016120300303200ustar00rootroot00000000000000 /gtk-3.0/ gimp.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgimpmath-2.0.xml000066400000000000000000000001371227016120300300040ustar00rootroot00000000000000 /gtk-3.0/ gimp.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgimpmodule-2.0.xml000066400000000000000000000001371227016120300303400ustar00rootroot00000000000000 /gtk-3.0/ gimp.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgimpthumb-2.0.xml000066400000000000000000000001541227016120300301710ustar00rootroot00000000000000 /gtk-3.0/ gimp.h gimpui.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgimpui-2.0.xml000066400000000000000000000001541227016120300274670ustar00rootroot00000000000000 /gtk-3.0/ gimp.h gimpui.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgimpwidgets-2.0.xml000066400000000000000000000002721227016120300305210ustar00rootroot00000000000000 /gtk-3.0/ gimp.h gimpui.h -DGIMP_ENABLE_CONTROLLER_UNDER_CONSTRUCTION abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgio.xml000066400000000000000000000000761227016120300264610ustar00rootroot00000000000000 -DG_SETTINGS_ENABLE_BACKEND abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgiomm.xml000066400000000000000000000000601227016120300270040ustar00rootroot00000000000000 /private/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libglademm-2.4.xml000066400000000000000000000000541227016120300276060ustar00rootroot00000000000000 /gtk-3.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgladeui-1.xml000066400000000000000000000000541227016120300274470ustar00rootroot00000000000000 /gtk-3.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libglib.xml000066400000000000000000000000641227016120300266150ustar00rootroot00000000000000 gi18n-lib.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libglut.xml000066400000000000000000000000471227016120300266540ustar00rootroot00000000000000 /FL/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgnc-core-utils.xml000066400000000000000000000000611227016120300305300ustar00rootroot00000000000000 #define HAVE_SCANF_LLD 1 abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgnc-gnome.xml000066400000000000000000000000611227016120300275470ustar00rootroot00000000000000 #define HAVE_SCANF_LLD 1 abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgnc-qof.xml000066400000000000000000000000611227016120300272270ustar00rootroot00000000000000 #define HAVE_SCANF_LLD 1 abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgnokii.xml000066400000000000000000000000601227016120300271540ustar00rootroot00000000000000 wappush.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgnome-desktop-2.xml000066400000000000000000000001551227016120300306140ustar00rootroot00000000000000 /gtk-3.0/ #define GNOME_DESKTOP_USE_UNSTABLE_API abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgnome-menu.xml000066400000000000000000000001471227016120300277510ustar00rootroot00000000000000 -DGMENU_I_KNOW_THIS_IS_UNSTABLE -DGMENU_I_KNOW_THIS_IS_UNSTABLE abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgnomecanvas-2.xml000066400000000000000000000000541227016120300303370ustar00rootroot00000000000000 /gtk-3.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgnomecanvasmm-2.6.xml000066400000000000000000000000541227016120300310350ustar00rootroot00000000000000 /gtk-3.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgnomedb-4.0.xml000066400000000000000000000000541227016120300276110ustar00rootroot00000000000000 /gtk-3.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgnomedb_extra-4.0.xml000066400000000000000000000000541227016120300310140ustar00rootroot00000000000000 /gtk-3.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgnomedb_graph-4.0.xml000066400000000000000000000000541227016120300307720ustar00rootroot00000000000000 /gtk-3.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgnomekbdui-4.2.0.xml000066400000000000000000000000541227016120300304620ustar00rootroot00000000000000 /gtk-3.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgnomeprint-2-2.xml000066400000000000000000000000721227016120300303570ustar00rootroot00000000000000 /private/ /gtk-3.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgnomeprintui-2-2.xml000066400000000000000000000000721227016120300307150ustar00rootroot00000000000000 /private/ /gtk-3.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgnomeui-2.xml000066400000000000000000000000541227016120300275010ustar00rootroot00000000000000 /gtk-3.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgnomeuimm-2.6.xml000066400000000000000000000000541227016120300301770ustar00rootroot00000000000000 /gtk-3.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgnomevfs.xml000066400000000000000000000001431227016120300275220ustar00rootroot00000000000000 gnome-vfs-cancellable-ops.h gnome-vfs-module-shared.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgnomevfsmm-2.6.xml000066400000000000000000000000601227016120300303550ustar00rootroot00000000000000 /private/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgnutls.xml000066400000000000000000000000571227016120300272160ustar00rootroot00000000000000 gnutlsxx.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgoffice-0.8.xml000066400000000000000000000000541227016120300276040ustar00rootroot00000000000000 /gtk-3.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgoocanvas-3.5.0.xml000066400000000000000000000000541227016120300303200ustar00rootroot00000000000000 /gtk-3.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgpgme++.xml000066400000000000000000000000651227016120300271260ustar00rootroot00000000000000 #define _FILE_OFFSET_BITS 64 abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgpgme-pth.xml000066400000000000000000000000651227016120300275710ustar00rootroot00000000000000 #define _FILE_OFFSET_BITS 64 abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgpgme-pthread.xml000066400000000000000000000000651227016120300304250ustar00rootroot00000000000000 #define _FILE_OFFSET_BITS 64 abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgpgme.xml000066400000000000000000000000651227016120300270000ustar00rootroot00000000000000 #define _FILE_OFFSET_BITS 64 abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgpilotd-5.0.0.xml000066400000000000000000000000541227016120300277770ustar00rootroot00000000000000 /gtk-3.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgpilotdcm-4.0.0.xml000066400000000000000000000001611227016120300303150ustar00rootroot00000000000000 /gtk-3.0/ gnome-pilot-conduit-config.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgpilotdconduit-3.0.0.xml000066400000000000000000000000541227016120300313630ustar00rootroot00000000000000 /gtk-3.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgpsd.xml000066400000000000000000000000531227016120300266330ustar00rootroot00000000000000 resolv.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgraph.xml000066400000000000000000000001501227016120300267750ustar00rootroot00000000000000 graphviz/types.h cgraph.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgs.xml000066400000000000000000000000501227016120300263040ustar00rootroot00000000000000 /ghostscript/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgsl.xml000066400000000000000000000000641227016120300264650ustar00rootroot00000000000000 gsl_wavelet.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgsmext.xml000066400000000000000000000000661227016120300272110ustar00rootroot00000000000000 gsm_me_ta.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgssrpc.xml000066400000000000000000000000551227016120300272010ustar00rootroot00000000000000 rename.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgstbase.xml000066400000000000000000000000701227016120300273250ustar00rootroot00000000000000 gstbytereader.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgstreamer.xml000066400000000000000000000004041227016120300276670ustar00rootroot00000000000000 gstbasemcsrc.h gstcheck.h gstbytereader.h gstbufferstraw.h gstbytewriter.h gstconsistencychecker.h -DGST_USE_UNSTABLE_API abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgtest.xml000066400000000000000000000000611227016120300270230ustar00rootroot00000000000000 /internal/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgtk-1.2.xml000066400000000000000000000000721227016120300267620ustar00rootroot00000000000000 /gtk-2.0/ /gtk-3.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgtk-3.xml000066400000000000000000000002131227016120300266210ustar00rootroot00000000000000 /gtk-2.0/ gtktextdisplay.h gtktextlayout.h gtktextview.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgtk-vnc-1.0.xml000066400000000000000000000000541227016120300275440ustar00rootroot00000000000000 /gtk-3.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgtk-x11-2.0.xml000066400000000000000000000002131227016120300273650ustar00rootroot00000000000000 gtktextdisplay.h gtkitemfactory.h gtkprivate.h /gtk-3.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgtkfilesystemmemorypublic.xml000066400000000000000000000000771227016120300332260ustar00rootroot00000000000000 gtk/gtktreemodel.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgtkgl-2.0.xml000066400000000000000000000000541227016120300273040ustar00rootroot00000000000000 /gtk-3.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgtkglext-x11-1.0.xml000066400000000000000000000000541227016120300304330ustar00rootroot00000000000000 /gtk-3.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgtkhtml-2.xml000066400000000000000000000000541227016120300275100ustar00rootroot00000000000000 /gtk-3.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgtkhtml-4.0.xml000066400000000000000000000000511227016120300276450ustar00rootroot00000000000000 /libgtkhtml-4.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgtkimageview-0.0.0.xml000066400000000000000000000000541227016120300310130ustar00rootroot00000000000000 /gtk-3.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgtksourceview-1.0.xml000066400000000000000000000000711227016120300310730ustar00rootroot00000000000000 /pidgin/ /gtk-3.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgtksourceview-2.0.xml000066400000000000000000000000711227016120300310740ustar00rootroot00000000000000 /pidgin/ /gtk-3.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgtkspell-0.0.0.xml000066400000000000000000000000541227016120300301550ustar00rootroot00000000000000 /gtk-3.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libguile-srfi-srfi-1-v-3.xml000066400000000000000000000000651227016120300314510ustar00rootroot00000000000000 libguile.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libguile-srfi-srfi-60-v-2.xml000066400000000000000000000000651227016120300315350ustar00rootroot00000000000000 libguile.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libguile.xml000066400000000000000000000001111227016120300267760ustar00rootroot00000000000000 null-threads.h gdb_interface.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libguilereadline-v-17.xml000066400000000000000000000000651227016120300312020ustar00rootroot00000000000000 libguile.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgutenprintui2.xml000066400000000000000000000000541227016120300305160ustar00rootroot00000000000000 /gtk-3.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgvc.xml000066400000000000000000000000431227016120300264540ustar00rootroot00000000000000 /graphviz/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgvfsdaemon.xml000066400000000000000000000000531227016120300300270ustar00rootroot00000000000000 /dbus/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgvpr.xml000066400000000000000000000001321227016120300266520ustar00rootroot00000000000000 gvpr.h unistd.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgweather.xml000066400000000000000000000001011227016120300274760ustar00rootroot00000000000000 #define GWEATHER_I_KNOW_THIS_IS_UNSTABLE abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libgxim-2.1.1.xml000066400000000000000000000000541227016120300273000ustar00rootroot00000000000000 /gtk-3.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libhandle.xml000066400000000000000000000000641227016120300271330ustar00rootroot00000000000000 xfs/xfs.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libhbmgmt.xml000066400000000000000000000000441227016120300271540ustar00rootroot00000000000000 /heartbeat/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libhdf5.xml000066400000000000000000000000611227016120300265230ustar00rootroot00000000000000 hdf5.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libhdf5_cpp.xml000066400000000000000000000000751227016120300273720ustar00rootroot00000000000000 hdf5.h H5Cpp.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libhdf5_hl.xml000066400000000000000000000000611227016120300272060ustar00rootroot00000000000000 hdf5.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libhdf5_hl_cpp.xml000066400000000000000000000000751227016120300300550ustar00rootroot00000000000000 hdf5.h H5Cpp.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libhildon-im-ui.xml000066400000000000000000000000731227016120300301730ustar00rootroot00000000000000 hildon-im-ui.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libhildon.xml000066400000000000000000000000671227016120300271600ustar00rootroot00000000000000 gtkenums.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libhildonwidgets.xml000066400000000000000000000000751227016120300305460ustar00rootroot00000000000000 hildon-time-editor.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libhistory.xml000066400000000000000000000000641227016120300274010ustar00rootroot00000000000000 stdio.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libhowl.xml000066400000000000000000000000611227016120300266460ustar00rootroot00000000000000 howl.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libicalss.xml000066400000000000000000000000631227016120300271550ustar00rootroot00000000000000 ical.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libicuio.xml000066400000000000000000000000561227016120300270110ustar00rootroot00000000000000 urename.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libinchi.xml000066400000000000000000000000401227016120300267640ustar00rootroot00000000000000 /inchi/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libindicate-qt.xml000066400000000000000000000000601227016120300300760ustar00rootroot00000000000000 QtGui abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libinotifytools.xml000066400000000000000000000000641227016120300304420ustar00rootroot00000000000000 inotify-nosys.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libiodbc.xml000066400000000000000000000000401227016120300267520ustar00rootroot00000000000000 /iodbc/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libiodbcinst.xml000066400000000000000000000000401227016120300276500ustar00rootroot00000000000000 /iodbc/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libipmimonitoring.xml000066400000000000000000000000521227016120300307410ustar00rootroot00000000000000 ipmi_monitoring.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libipq.xml000066400000000000000000000000411227016120300264640ustar00rootroot00000000000000 /libipq/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libipsec.xml000066400000000000000000000001161227016120300270010ustar00rootroot00000000000000 #undef linux #define PATH_IPSEC_H abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libirman.xml000066400000000000000000000000551227016120300270060ustar00rootroot00000000000000 /openldap/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libjinglebase.xml000066400000000000000000000000631227016120300300020ustar00rootroot00000000000000 stl_decl.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libjinglep2pbase.xml000066400000000000000000000000521227016120300304220ustar00rootroot00000000000000 -DPOSIX abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libjinglep2pclient.xml000066400000000000000000000001551227016120300307720ustar00rootroot00000000000000 string string -DPOSIX abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libjpeg.xml000066400000000000000000000001721227016120300266250ustar00rootroot00000000000000 jmorecfg.h jpegint.h stdio.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libk3blib.xml000066400000000000000000000002151227016120300270440ustar00rootroot00000000000000 k3bmetawriter.h k3bcdrecordwriter.h k3bcdrdaowriter.h k3bgrowisofswriter.h k3bvcddoc.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libkasten1okteta1controllers.xml000066400000000000000000000001641227016120300330270ustar00rootroot00000000000000 checksumtool.h poddecodertool.h stringsextracttool.h structtool.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libkcal.xml000066400000000000000000000000541227016120300266110ustar00rootroot00000000000000 /libical/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libkcalcore.xml000066400000000000000000000000541227016120300274620ustar00rootroot00000000000000 /libical/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libkcalcoren.xml000066400000000000000000000002301227016120300276340ustar00rootroot00000000000000 kcalendarsystem.h /mkcal/ /unicode/ -DMKCAL_EXPORT="" abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libkde3support.xml000066400000000000000000000001461227016120300301640ustar00rootroot00000000000000 QtGui k3popupmenu.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libkdevplatformutil.xml000066400000000000000000000000751227016120300312760ustar00rootroot00000000000000 sparseconfig_windows.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libkeyutils.xml000066400000000000000000000001031227016120300275430ustar00rootroot00000000000000 unistd.h unistd.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libkiten.xml000066400000000000000000000001151227016120300270070ustar00rootroot00000000000000 dictfileedict.h dictfilekanjidic.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libkmfl.xml000066400000000000000000000000761227016120300266340ustar00rootroot00000000000000 kmfl.h setjmp.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libkmflcomp.xml000066400000000000000000000001651227016120300275120ustar00rootroot00000000000000 kmflcomp.h kmflutfconv.h kmfl.h setjmp.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libkok.xml000066400000000000000000000000461227016120300264640ustar00rootroot00000000000000 /kcalcoren/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libkopete.xml000066400000000000000000000001641227016120300271700ustar00rootroot00000000000000 addressbookselectorwidget.h QtGui abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libkpathsea.xml000066400000000000000000000000761227016120300275030ustar00rootroot00000000000000 mingw32.h win32lib.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libkrdccore.xml000066400000000000000000000000701227016120300274710ustar00rootroot00000000000000 hostpreferences.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libksba.xml000066400000000000000000000000641227016120300266200ustar00rootroot00000000000000 stdio.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libktorrent.xml000066400000000000000000000000561227016120300275510ustar00rootroot00000000000000 win32.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/liblbxutil.xml000066400000000000000000000001271227016120300273630ustar00rootroot00000000000000 Xlib.h Xmd.h Xproto.h lbxproto.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libldap_r.xml000066400000000000000000000001661227016120300271440ustar00rootroot00000000000000 sys/time.h ldap.h portable.h ldap_queue.h ldap_pvt_thread.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/liblpc10.xml000066400000000000000000000000521227016120300266140ustar00rootroot00000000000000 /boost/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/liblqr-1.xml000066400000000000000000000000601227016120300266300ustar00rootroot00000000000000 lqr.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/liblzma.xml000066400000000000000000000000601227016120300266370ustar00rootroot00000000000000 lzma/lzma.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libm.xml000066400000000000000000000000511227016120300261300ustar00rootroot00000000000000 /bits/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libmagic.xml000066400000000000000000000000531227016120300267560ustar00rootroot00000000000000 /file/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libmal.xml000066400000000000000000000005101227016120300264450ustar00rootroot00000000000000 AGUtilWin.h AGUtilPalmOS.h AGUtilMac.h MALCommonWin.h AGDesktopInfoWinCE.h AGShlapi.h AGResourceManager.h /usr/include/isc /usr/include/vtk /usr/include/svnqt stdio.h time.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libmalaga.xml000066400000000000000000000000411227016120300271150ustar00rootroot00000000000000 malaga.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libmarblewidget.xml000066400000000000000000000002031227016120300303410ustar00rootroot00000000000000 QtMarbleConfigDialog.h CurrentLocationWidget.h PositionTracking.h RunnerPlugin.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libmcclient.xml000066400000000000000000000000731227016120300274760ustar00rootroot00000000000000 /libmcclient/_gen/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libmcompositor.xml000066400000000000000000000002161227016120300302520ustar00rootroot00000000000000 *_p.h QtCore QtGui mcompositemanagerextension.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libmeegotouchhome.xml000066400000000000000000000002101227016120300307010ustar00rootroot00000000000000 /meegotouchhome/stubs/ *_p.h QtCore QtGui abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libmenuw.xml000066400000000000000000000000431227016120300270300ustar00rootroot00000000000000 /ncursesw/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libmikmod.xml000066400000000000000000000000531227016120300271560ustar00rootroot00000000000000 /eigen2/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libming.xml000066400000000000000000000000541227016120300266310ustar00rootroot00000000000000 ming.h mingpp.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libmissioncontrol-server.xml000066400000000000000000000000771227016120300322720ustar00rootroot00000000000000 /mission-control/_gen/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libmkcal.xml000066400000000000000000000001061227016120300267640ustar00rootroot00000000000000 /usr/include/kcalcoren/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libmng.xml000066400000000000000000000000641227016120300264610ustar00rootroot00000000000000 stdio.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libmodplug.xml000066400000000000000000000001001227016120300273360ustar00rootroot00000000000000 stdint.h stdafx.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libmodprobe.xml000066400000000000000000000001531227016120300275060ustar00rootroot00000000000000 modprobe.h logging.h list.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libmozjs185.xml000066400000000000000000000001171227016120300272770ustar00rootroot00000000000000 jsbuiltins.h jstracer.h Writer.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libmpeg2convert.xml000066400000000000000000000000771227016120300303170ustar00rootroot00000000000000 stdint.h mpeg2.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libmpfr.xml000066400000000000000000000000571227016120300266460ustar00rootroot00000000000000 mpf2mpfr.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libmsn.xml000066400000000000000000000001241227016120300264720ustar00rootroot00000000000000 /msn/ sstream_fix.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libmulticobex.xml000066400000000000000000000000611227016120300300500ustar00rootroot00000000000000 obex.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libmysqlclient.xml000066400000000000000000000002431227016120300302430ustar00rootroot00000000000000 mysql.h sql_state.h mysqld_ername.h innodb_priv.h thread_pool_priv.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libmysqld.xml000066400000000000000000000003421227016120300272100ustar00rootroot00000000000000 mysql.h plugin.h my_global.h /mysql/ mysqld_ername.h innodb_priv.h thread_pool_priv.h sql_state.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libmysqlservices.xml000066400000000000000000000003421227016120300306100ustar00rootroot00000000000000 mysql.h plugin.h my_global.h /mysql/ mysqld_ername.h innodb_priv.h thread_pool_priv.h sql_state.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libmyth.xml000066400000000000000000000000411227016120300266540ustar00rootroot00000000000000 /mythtv/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libmythavcodec.xml000066400000000000000000000002611227016120300302050ustar00rootroot00000000000000 /mythtv/ # if __WORDSIZE == 64 # define UINT64_C(c) c ## UL # else # define UINT64_C(c) c ## ULL # endif abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libmythavcore.xml000066400000000000000000000000411227016120300300540ustar00rootroot00000000000000 /mythtv/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libmythavdevice.xml000066400000000000000000000000431227016120300303650ustar00rootroot00000000000000 /mythtv/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libmythavfilter.xml000066400000000000000000000000431227016120300304130ustar00rootroot00000000000000 /mythtv/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libmythavformat.xml000066400000000000000000000000411227016120300304140ustar00rootroot00000000000000 /mythtv/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libmythavutil.xml000066400000000000000000000000411227016120300301010ustar00rootroot00000000000000 /mythtv/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libmythlivemedia.xml000066400000000000000000000000371227016120300305410ustar00rootroot00000000000000 /live/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libmythpostproc.xml000066400000000000000000000000411227016120300304460ustar00rootroot00000000000000 /mythtv/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libmythtv.xml000066400000000000000000000000411227016120300272260ustar00rootroot00000000000000 /mythtv/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libnetcdf.xml000066400000000000000000000000501227016120300271360ustar00rootroot00000000000000 /vtk/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libnetcdf_c++.xml000066400000000000000000000000501227016120300275660ustar00rootroot00000000000000 /vtk/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libnetpbm.xml000066400000000000000000000000601227016120300271610ustar00rootroot00000000000000 pnm.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libnetsnmpmibs.xml000066400000000000000000000000431227016120300302340ustar00rootroot00000000000000 /net-snmp/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libnice.xml000066400000000000000000000000671227016120300266210ustar00rootroot00000000000000 win32_common.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libnl.xml000066400000000000000000000000631227016120300263100ustar00rootroot00000000000000 rtnl.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libnn.xml000066400000000000000000000000501227016120300263060ustar00rootroot00000000000000 /inn/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libnsl.xml000066400000000000000000000001371227016120300264750ustar00rootroot00000000000000 nislib.h nfs_prot.h yp_prot.h yp_prot.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libnssutil3.xml000066400000000000000000000000621227016120300274620ustar00rootroot00000000000000 nss.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libodbc.xml000066400000000000000000000000521227016120300266040ustar00rootroot00000000000000 /iodbc/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/liboil.xml000066400000000000000000000000741227016120300264640ustar00rootroot00000000000000 -DOIL_ENABLE_UNSTABLE_API abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/liboldX.xml000066400000000000000000000000531227016120300266040ustar00rootroot00000000000000 TextFP.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libonig.xml000066400000000000000000000000751227016120300266360ustar00rootroot00000000000000 onigposix.h regex.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libopal.xml000066400000000000000000000000371227016120300266330ustar00rootroot00000000000000 /opal/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libopencv_objdetect.xml000066400000000000000000000000421227016120300312110ustar00rootroot00000000000000 /opencv2/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/liborc.xml000066400000000000000000000000561227016120300264640ustar00rootroot00000000000000 opcodes.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libosp.xml000066400000000000000000000001511227016120300264760ustar00rootroot00000000000000 /sp/ OpenSP/config.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libospgrove.xml000066400000000000000000000002001227016120300275340ustar00rootroot00000000000000 /sp/ OpenSP/config.h OpenJade/config.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libosso-ic.xml000066400000000000000000000000771227016120300272600ustar00rootroot00000000000000 -DDBUS_API_SUBJECT_TO_CHANGE abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libossoemailinterface.xml000066400000000000000000000001051227016120300315500ustar00rootroot00000000000000 libosso.h libosso.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libossohelp.xml000066400000000000000000000000771227016120300275400ustar00rootroot00000000000000 osso-helplib-private.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libostyle.xml000066400000000000000000000002001227016120300272070ustar00rootroot00000000000000 /sp/ OpenSP/config.h OpenJade/config.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libpackagekit-glib2.xml000066400000000000000000000001311227016120300307730ustar00rootroot00000000000000 -DI_KNOW_THE_PACKAGEKIT_GLIB2_API_IS_SUBJECT_TO_CHANGE abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libpanelw.xml000066400000000000000000000000431227016120300271630ustar00rootroot00000000000000 /ncursesw/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libpathplan.xml000066400000000000000000000000431227016120300275040ustar00rootroot00000000000000 /graphviz/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libpbm.xml000066400000000000000000000000601227016120300264520ustar00rootroot00000000000000 pbm.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libpcap.xml000066400000000000000000000000371227016120300266230ustar00rootroot00000000000000 /pcap/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libpgm.xml000066400000000000000000000000601227016120300264570ustar00rootroot00000000000000 pnm.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libphp5_common.xml000066400000000000000000000000361227016120300301230ustar00rootroot00000000000000 php.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libpigmentcms.xml000066400000000000000000000000661227016120300300500ustar00rootroot00000000000000 KoColorSpaceMaths.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libplasma.xml000066400000000000000000000000501227016120300271500ustar00rootroot00000000000000 /qt4/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libplds4.xml000066400000000000000000000000641227016120300267260ustar00rootroot00000000000000 prtypes.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libplist++.xml000066400000000000000000000000521227016120300271560ustar00rootroot00000000000000 Array.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libply.xml000066400000000000000000000000521227016120300265010ustar00rootroot00000000000000 /vtk/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libpng12.xml000066400000000000000000000000641227016120300266270ustar00rootroot00000000000000 stdio.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libpolkit-agent.xml000066400000000000000000000001211227016120300302700ustar00rootroot00000000000000 -DPOLKIT_AGENT_I_KNOW_API_IS_SUBJECT_TO_CHANGE abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libpolkit-backend.xml000066400000000000000000000001231227016120300305630ustar00rootroot00000000000000 -DPOLKIT_BACKEND_I_KNOW_API_IS_SUBJECT_TO_CHANGE abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libpolkit-gobject.xml000066400000000000000000000000641227016120300306150ustar00rootroot00000000000000 polkitprivate.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libpoppler.xml000066400000000000000000000005131227016120300273600ustar00rootroot00000000000000 JPEG2000Stream.h DCTStream.h UnicodeCClassTables.h UnicodeCompTables.h FlateStream.h gfile.h Annot.h Array.h BaseFile.h /glib/ Dict.h time.h stdio.h Object.h PDFDoc.h GfxFont.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libppm.xml000066400000000000000000000000601227016120300264700ustar00rootroot00000000000000 pnm.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libpt.xml000066400000000000000000000000551227016120300263230ustar00rootroot00000000000000 tinyjpeg.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libpthread.xml000066400000000000000000000001421227016120300273240ustar00rootroot00000000000000 /bits/ /dietlibc/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libpulsecommon.xml000066400000000000000000000002541227016120300302420ustar00rootroot00000000000000 poll.h /pulsecore/modules/ stdbool.h pulseaudio.h pulsecore-config.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libpulsecore.xml000066400000000000000000000002541227016120300277020ustar00rootroot00000000000000 poll.h /pulsecore/modules/ stdbool.h pulseaudio.h pulsecore-config.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libpyglib-2.0-python2.5.xml000066400000000000000000000001011227016120300312170ustar00rootroot00000000000000 /python2.6/ /python3.1/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libpyglib-2.0-python2.6.xml000066400000000000000000000001011227016120300312200ustar00rootroot00000000000000 /python2.5/ /python3.1/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libpyside-python2.6.xml000066400000000000000000000003241227016120300307410ustar00rootroot00000000000000 pyside_phonon_python.h pyside_global.h pyside_qtsql_python.h pyside_qtsql_python.h pyside_qttest_python.h /PySide/Qt /python2.5/ /python3.1/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libpython2.5.xml000066400000000000000000000001571227016120300274510ustar00rootroot00000000000000 ast.h pyexpat.h pymactoolbox.h /python2.6/ /python3.1/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libpython2.6.xml000066400000000000000000000001571227016120300274520ustar00rootroot00000000000000 ast.h pyexpat.h pymactoolbox.h /python2.5/ /python3.1/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libpython3.1.xml000066400000000000000000000001571227016120300274460ustar00rootroot00000000000000 ast.h pyexpat.h pymactoolbox.h /python2.5/ /python2.6/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libqca.xml000066400000000000000000000000531227016120300264420ustar00rootroot00000000000000 /gnutls/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libqmfclient.xml000066400000000000000000000002151227016120300276600ustar00rootroot00000000000000 QMailNewEmailHandler QMailNewMessageHandler qprivateimplementationdef.h qcopchannel_qws.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libqtruby4shared.xml000066400000000000000000000000531227016120300304770ustar00rootroot00000000000000 /perlqt/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libqttracker.xml000066400000000000000000000000771227016120300277040ustar00rootroot00000000000000 QTracker /ontologies/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libqyoto.xml000066400000000000000000000000401227016120300270450ustar00rootroot00000000000000 /qyoto/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libraptor.xml000066400000000000000000000000411227016120300272020ustar00rootroot00000000000000 raptor.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libraptor2.xml000066400000000000000000000000421227016120300272650ustar00rootroot00000000000000 raptor2.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libreadline.xml000066400000000000000000000001471227016120300274650ustar00rootroot00000000000000 stdio.h /editline/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/librecode.xml000066400000000000000000000000601227016120300271350ustar00rootroot00000000000000 recode.h recodext.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libresolv.xml000066400000000000000000000001211227016120300272040ustar00rootroot00000000000000 /isc/ /bind/ /dietlibc/ /c++/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/librt.xml000066400000000000000000000001061227016120300263220ustar00rootroot00000000000000 bits/mqueue.h bits/mqueue2.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libsablot.xml000066400000000000000000000000521227016120300271610ustar00rootroot00000000000000 /boost/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libsasl2.xml000066400000000000000000000000521227016120300267210ustar00rootroot00000000000000 md5.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libsensorfw.xml000066400000000000000000000000711227016120300275440ustar00rootroot00000000000000 calibrationhandler.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libshadowappd.xml000066400000000000000000000001441227016120300300310ustar00rootroot00000000000000 glib.h gconf-client.h libosso.h unistd.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libshare-ui-common.xml000066400000000000000000000001061227016120300307000ustar00rootroot00000000000000 #define DBUS_SERVICE "org.freedesktop.DBus" abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libshare-widgets.xml000066400000000000000000000001061227016120300304430ustar00rootroot00000000000000 #define DBUS_SERVICE "org.freedesktop.DBus" abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libshiboken-python2.6.xml000066400000000000000000000000761227016120300312520ustar00rootroot00000000000000 /python3.1/ /python2.5/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libsignon-glib.xml000066400000000000000000000000641227016120300301100ustar00rootroot00000000000000 signon-errors.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libsmi.xml000066400000000000000000000000361227016120300264670ustar00rootroot00000000000000 smi.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libsmltk.xml000066400000000000000000000000631227016120300270310ustar00rootroot00000000000000 sysync_utils.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libsmokeqtuitools.xml000066400000000000000000000000401227016120300307740ustar00rootroot00000000000000 /smoke/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libsofia-sip-ua.xml000066400000000000000000000002041227016120300301710ustar00rootroot00000000000000 string0.h sip_parser.h sip_util.h sl_utils.h tstdef.h sres_cache.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libsofia-tools.xml000066400000000000000000000000661227016120300301410ustar00rootroot00000000000000 sres_record.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libsource-highlight.xml000066400000000000000000000000441227016120300311430ustar00rootroot00000000000000 /srchilite/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libsp.xml000066400000000000000000000000701227016120300263170ustar00rootroot00000000000000 sp/config.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libspgrove.xml000066400000000000000000000000701227016120300273620ustar00rootroot00000000000000 sp/config.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libsqlite.xml000066400000000000000000000000551227016120300272010ustar00rootroot00000000000000 /corosync/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libsrv_um_r.xml000066400000000000000000000001041227016120300275270ustar00rootroot00000000000000 -DSUPPORT_SGX_HWPERF -DLINUX abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libsrv_um_r125.xml000066400000000000000000000001041227016120300277570ustar00rootroot00000000000000 -DSUPPORT_SGX_HWPERF -DLINUX abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libstdc++.xml000066400000000000000000000006201227016120300267610ustar00rootroot00000000000000 /c++/ /java/ /javax/ /gcj/ /gnu/ /sun/ /org/ /parallel/ /bits/ /tr1_impl/ atomic stdatomic.h c++0xwarning.h exception_ptr.h /profile/ multiset.h /backward/ /bits/ /debug/ /tr1/ /ext/ c++config.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libstonithd.xml000066400000000000000000000000421227016120300275300ustar00rootroot00000000000000 /stonith/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libstyle.xml000066400000000000000000000000701227016120300270350ustar00rootroot00000000000000 sp/config.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libsyncevolution.xml000066400000000000000000000001501227016120300306150ustar00rootroot00000000000000 dbitem.h syncexception.h lineartime.h sysync_utils.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libsyncmlcommon.xml000066400000000000000000000000731227016120300304160ustar00rootroot00000000000000 SyncMLConfig.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libt1.xml000066400000000000000000000000401227016120300262160ustar00rootroot00000000000000 t1lib.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libt1x.xml000066400000000000000000000001011227016120300264040ustar00rootroot00000000000000 t1lib.h t1lib.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libtcl8.4.xml000066400000000000000000000001001227016120300267030ustar00rootroot00000000000000 /tcl-private/ /tcl8.5/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libtcl8.5.xml000066400000000000000000000001001227016120300267040ustar00rootroot00000000000000 /tcl-private/ /tcl8.4/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libtclink.xml000066400000000000000000000000411227016120300271570ustar00rootroot00000000000000 tclink.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libtdsodbc.xml000066400000000000000000000000651227016120300273230ustar00rootroot00000000000000 sql.h sqlext.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libtelepathy-glib.xml000066400000000000000000000000741227016120300306130ustar00rootroot00000000000000 telepathy-glib/_gen abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libtelepathy-qt4.xml000066400000000000000000000003571227016120300304120ustar00rootroot00000000000000 /_gen/ profile.h incoming-file-transfer-channel.h outgoing-file-transfer-channel.h IncomingFileTransferChannel OutgoingFileTransferChannel abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libtelepathy.xml000066400000000000000000000007341227016120300277030ustar00rootroot00000000000000 telepathy/_gen *-gen.h -DDBUS_GLIB_CLIENT_WRAPPERS_org_freedesktop_Telepathy_Channel -DDBUS_GLIB_CLIENT_WRAPPERS_org_freedesktop_Telepathy_Connection -DDBUS_GLIB_CLIENT_WRAPPERS_org_freedesktop_Telepathy_Connection_Interface_Forwarding -DDBUS_GLIB_CLIENT_WRAPPERS_org_freedesktop_Telepathy_ConnectionManager -DDBUS_GLIB_CLIENT_WRAPPERS_org_freedesktop_Telepathy_Properties abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libtesseract_dict.xml000066400000000000000000000000441227016120300306760ustar00rootroot00000000000000 /tesseract/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libtesseract_main.xml000066400000000000000000000000441227016120300306770ustar00rootroot00000000000000 /tesseract/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libthai.xml000066400000000000000000000000661227016120300266270ustar00rootroot00000000000000 thwchar.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libtiffxx.xml000066400000000000000000000001031227016120300272020ustar00rootroot00000000000000 tiffio.h tiffio.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libtimed.xml000066400000000000000000000001101227016120300267720ustar00rootroot00000000000000 exception event interface abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libtirpc.xml000066400000000000000000000002141227016120300270160ustar00rootroot00000000000000 /bsd/ /gssrpc/ /usr/include/rpc/ /dietlibc/ /rpcsecgss/ /tirpc/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libts.xml000066400000000000000000000000661227016120300263300ustar00rootroot00000000000000 /linux/netfilter/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libunwind.xml000066400000000000000000000000701227016120300272010ustar00rootroot00000000000000 libunwind-dynamic.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libusb-0.1.xml000066400000000000000000000000571227016120300267670ustar00rootroot00000000000000 /libusb-1.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libusbmuxd.xml000066400000000000000000000000421227016120300273630ustar00rootroot00000000000000 usbmuxd.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libva-egl.xml000066400000000000000000000000651227016120300270540ustar00rootroot00000000000000 va_backend_egl.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libva-glx.xml000066400000000000000000000000651227016120300270770ustar00rootroot00000000000000 va_backend_glx.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libva-tpi.xml000066400000000000000000000000651227016120300271010ustar00rootroot00000000000000 va_backend_tpi.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libva-x11.xml000066400000000000000000000002001227016120300267050ustar00rootroot00000000000000 va_backend.h va_dummy.h va_dricommon.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libvcdinfo.xml000066400000000000000000000000411227016120300273230ustar00rootroot00000000000000 /libvcd/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libvncclient.xml000066400000000000000000000000361227016120300276640ustar00rootroot00000000000000 /rfb/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libvncserver.xml000066400000000000000000000000361227016120300277140ustar00rootroot00000000000000 /rfb/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libvtkCharts.xml000066400000000000000000000002331227016120300276470ustar00rootroot00000000000000 string.h /usr/include/vtk/vtkstd /usr/include/vtk/vtksys/ios abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libvtkNetCDF_cxx.xml000066400000000000000000000000361227016120300303510ustar00rootroot00000000000000 /vtk/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwbclient.xml000066400000000000000000000000621227016120300275050ustar00rootroot00000000000000 wbc_async.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwbxml2.xml000066400000000000000000000000641227016120300271130ustar00rootroot00000000000000 wbxml.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwebkitgtk-1.0.xml000066400000000000000000000000451227016120300301660ustar00rootroot00000000000000 /webkit-1.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwebkitgtk-3.0.xml000066400000000000000000000000451227016120300301700ustar00rootroot00000000000000 /webkit-3.0/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwine.xml000066400000000000000000000001131227016120300266350ustar00rootroot00000000000000 wine/debug.h wine/library.h wine/unicode.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwiretap.xml000066400000000000000000000002451227016120300273540ustar00rootroot00000000000000 file_wrappers.h wtap-int.h -D_U_= sys/time.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwnck.xml000066400000000000000000000000751227016120300266440ustar00rootroot00000000000000 #define WNCK_I_KNOW_THIS_IS_UNSTABLE abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwvbase.xml000066400000000000000000000001431227016120300271650ustar00rootroot00000000000000 #define UNSTABLE xplc/delete.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwvstreams.xml000066400000000000000000000003601227016120300277320ustar00rootroot00000000000000 #define UNSTABLE unipstoregen.h wvwin32task.h wvwinstreamclone.h uniregistrygen.h wvqtstreamclone.h wvwin32-sanitize.h wvwindebuglog.h wvbellpull.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwwwapp.xml000066400000000000000000000002341227016120300272240ustar00rootroot00000000000000 stdio.h stdlib.h netinet/in.h wwwsys.h WWWLib.h -DHAVE_STRERROR abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwwwcache.xml000066400000000000000000000002341227016120300275070ustar00rootroot00000000000000 stdio.h stdlib.h netinet/in.h wwwsys.h WWWLib.h -DHAVE_STRERROR abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwwwcore.xml000066400000000000000000000002341227016120300273740ustar00rootroot00000000000000 stdio.h stdlib.h netinet/in.h wwwsys.h WWWLib.h -DHAVE_STRERROR abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwwwdir.xml000066400000000000000000000002341227016120300272220ustar00rootroot00000000000000 stdio.h stdlib.h netinet/in.h wwwsys.h WWWLib.h -DHAVE_STRERROR abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwwwfile.xml000066400000000000000000000002341227016120300273630ustar00rootroot00000000000000 stdio.h stdlib.h netinet/in.h wwwsys.h WWWLib.h -DHAVE_STRERROR abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwwwftp.xml000066400000000000000000000002341227016120300272350ustar00rootroot00000000000000 stdio.h stdlib.h netinet/in.h wwwsys.h WWWLib.h -DHAVE_STRERROR abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwwwgopher.xml000066400000000000000000000002341227016120300277300ustar00rootroot00000000000000 stdio.h stdlib.h netinet/in.h wwwsys.h WWWLib.h -DHAVE_STRERROR abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwwwhtml.xml000066400000000000000000000002341227016120300274100ustar00rootroot00000000000000 stdio.h stdlib.h netinet/in.h wwwsys.h WWWLib.h -DHAVE_STRERROR abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwwwhttp.xml000066400000000000000000000003401227016120300274210ustar00rootroot00000000000000 stdio.h stdlib.h netinet/in.h wwwsys.h WWWLib.h -DHAVE_STRERROR /usr/include/openssl/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwwwinit.xml000066400000000000000000000002341227016120300274070ustar00rootroot00000000000000 stdio.h stdlib.h netinet/in.h wwwsys.h WWWLib.h -DHAVE_STRERROR abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwwwmime.xml000066400000000000000000000002341227016120300273730ustar00rootroot00000000000000 stdio.h stdlib.h netinet/in.h wwwsys.h WWWLib.h -DHAVE_STRERROR abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwwwmux.xml000066400000000000000000000002341227016120300272550ustar00rootroot00000000000000 stdio.h stdlib.h netinet/in.h wwwsys.h WWWLib.h -DHAVE_STRERROR abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwwwnews.xml000066400000000000000000000002341227016120300274200ustar00rootroot00000000000000 stdio.h stdlib.h netinet/in.h wwwsys.h WWWLib.h -DHAVE_STRERROR abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwwwssl.xml000066400000000000000000000002341227016120300272450ustar00rootroot00000000000000 stdio.h stdlib.h netinet/in.h wwwsys.h WWWLib.h -DHAVE_STRERROR abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwwwstream.xml000066400000000000000000000002341227016120300277370ustar00rootroot00000000000000 stdio.h stdlib.h netinet/in.h wwwsys.h WWWLib.h -DHAVE_STRERROR abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwwwtelnet.xml000066400000000000000000000002341227016120300277370ustar00rootroot00000000000000 stdio.h stdlib.h netinet/in.h wwwsys.h WWWLib.h -DHAVE_STRERROR abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwwwtrans.xml000066400000000000000000000002341227016120300275730ustar00rootroot00000000000000 stdio.h stdlib.h netinet/in.h wwwsys.h WWWLib.h -DHAVE_STRERROR abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwwwutils.xml000066400000000000000000000002341227016120300276040ustar00rootroot00000000000000 stdio.h stdlib.h netinet/in.h wwwsys.h WWWLib.h -DHAVE_STRERROR abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwwwxml.xml000066400000000000000000000002341227016120300272440ustar00rootroot00000000000000 stdio.h stdlib.h netinet/in.h wwwsys.h WWWLib.h -DHAVE_STRERROR abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwwwzip.xml000066400000000000000000000002341227016120300272460ustar00rootroot00000000000000 stdio.h stdlib.h netinet/in.h wwwsys.h WWWLib.h -DHAVE_STRERROR abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwx_base.xml000066400000000000000000000004741227016120300273350ustar00rootroot00000000000000 /usr/lib/wx/include /usr/include/wx-2.8/wx #define __WXGTK__ #define wxUSE_GUI 1 wx/wx.h /generic/ /unix/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwx_base_net.xml000066400000000000000000000004741227016120300302030ustar00rootroot00000000000000 /usr/lib/wx/include /usr/include/wx-2.8/wx #define __WXGTK__ #define wxUSE_GUI 1 wx/wx.h /generic/ /unix/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwx_base_xml.xml000066400000000000000000000004741227016120300302150ustar00rootroot00000000000000 /usr/lib/wx/include /usr/include/wx-2.8/wx #define __WXGTK__ #define wxUSE_GUI 1 wx/wx.h /generic/ /unix/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwx_baseu.xml000066400000000000000000000004741227016120300275220ustar00rootroot00000000000000 /usr/lib/wx/include /usr/include/wx-2.8/wx #define __WXGTK__ #define wxUSE_GUI 1 wx/wx.h /generic/ /unix/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwx_baseu_net.xml000066400000000000000000000004741227016120300303700ustar00rootroot00000000000000 /usr/lib/wx/include /usr/include/wx-2.8/wx #define __WXGTK__ #define wxUSE_GUI 1 wx/wx.h /generic/ /unix/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwx_baseu_xml.xml000066400000000000000000000004741227016120300304020ustar00rootroot00000000000000 /usr/lib/wx/include /usr/include/wx-2.8/wx #define __WXGTK__ #define wxUSE_GUI 1 wx/wx.h /generic/ /unix/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwx_gtk2_adv.xml000066400000000000000000000004741227016120300301240ustar00rootroot00000000000000 /usr/lib/wx/include /usr/include/wx-2.8/wx #define __WXGTK__ #define wxUSE_GUI 1 wx/wx.h /generic/ /unix/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwx_gtk2_aui.xml000066400000000000000000000004741227016120300301300ustar00rootroot00000000000000 /usr/lib/wx/include /usr/include/wx-2.8/wx #define __WXGTK__ #define wxUSE_GUI 1 wx/wx.h /generic/ /unix/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwx_gtk2_core.xml000066400000000000000000000005321227016120300302750ustar00rootroot00000000000000 /usr/lib/wx/include /usr/include/wx-2.8/wx #define __WXGTK__ #define wxUSE_GUI 1 wx/wx.h /generic/ /unix/ /gtk/ assertdlg_gtk.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwx_gtk2_fl.xml000066400000000000000000000004741227016120300277530ustar00rootroot00000000000000 /usr/lib/wx/include /usr/include/wx-2.8/wx #define __WXGTK__ #define wxUSE_GUI 1 wx/wx.h /generic/ /unix/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwx_gtk2_gizmos.xml000066400000000000000000000004741227016120300306620ustar00rootroot00000000000000 /usr/lib/wx/include /usr/include/wx-2.8/wx #define __WXGTK__ #define wxUSE_GUI 1 wx/wx.h /generic/ /unix/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwx_gtk2_gl.xml000066400000000000000000000005161227016120300277510ustar00rootroot00000000000000 /usr/lib/wx/include /usr/include/wx-2.8/wx #define __WXGTK__ #define wxUSE_GUI 1 wx/wx.h wx/glcanvas.h /generic/ /unix/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwx_gtk2_html.xml000066400000000000000000000004741227016120300303160ustar00rootroot00000000000000 /usr/lib/wx/include /usr/include/wx-2.8/wx #define __WXGTK__ #define wxUSE_GUI 1 wx/wx.h /generic/ /unix/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwx_gtk2_ogl.xml000066400000000000000000000004741227016120300301330ustar00rootroot00000000000000 /usr/lib/wx/include /usr/include/wx-2.8/wx #define __WXGTK__ #define wxUSE_GUI 1 wx/wx.h /generic/ /unix/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwx_gtk2_plot.xml000066400000000000000000000004741227016120300303300ustar00rootroot00000000000000 /usr/lib/wx/include /usr/include/wx-2.8/wx #define __WXGTK__ #define wxUSE_GUI 1 wx/wx.h /generic/ /unix/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwx_gtk2_qa.xml000066400000000000000000000004741227016120300277530ustar00rootroot00000000000000 /usr/lib/wx/include /usr/include/wx-2.8/wx #define __WXGTK__ #define wxUSE_GUI 1 wx/wx.h /generic/ /unix/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwx_gtk2_richtext.xml000066400000000000000000000004741227016120300312040ustar00rootroot00000000000000 /usr/lib/wx/include /usr/include/wx-2.8/wx #define __WXGTK__ #define wxUSE_GUI 1 wx/wx.h /generic/ /unix/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwx_gtk2_stc.xml000066400000000000000000000004741227016120300301430ustar00rootroot00000000000000 /usr/lib/wx/include /usr/include/wx-2.8/wx #define __WXGTK__ #define wxUSE_GUI 1 wx/wx.h /generic/ /unix/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwx_gtk2_svg.xml000066400000000000000000000004741227016120300301510ustar00rootroot00000000000000 /usr/lib/wx/include /usr/include/wx-2.8/wx #define __WXGTK__ #define wxUSE_GUI 1 wx/wx.h /generic/ /unix/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libwx_gtk2_xrc.xml000066400000000000000000000004741227016120300301460ustar00rootroot00000000000000 /usr/lib/wx/include /usr/include/wx-2.8/wx #define __WXGTK__ #define wxUSE_GUI 1 wx/wx.h /generic/ /unix/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libxbase64.xml000066400000000000000000000000561227016120300271550ustar00rootroot00000000000000 xbntx.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libxcb-aux.xml000066400000000000000000000000621227016120300272450ustar00rootroot00000000000000 xcb.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libxcb.xml000066400000000000000000000000611227016120300264510ustar00rootroot00000000000000 xcb_bitops.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libxenguest.xml000066400000000000000000000000641227016120300275420ustar00rootroot00000000000000 xenctrl.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libxenlight.xml000066400000000000000000000000621227016120300275200ustar00rootroot00000000000000 libxl.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libxkbfile.xml000066400000000000000000000002131227016120300273200ustar00rootroot00000000000000 /xorg/ XKBsrv.h Xlib.h XKBstr.h stdio.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libxml.xml000066400000000000000000000002001227016120300264700ustar00rootroot00000000000000 /gnome-xml/ /wx/ tree.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libxml2.xml000066400000000000000000000001521227016120300265600ustar00rootroot00000000000000 /gnome-xml/ /wx/ tree.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libxmlrpc.xml000066400000000000000000000000501227016120300272000ustar00rootroot00000000000000 /php/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libxmlrpc_abyss.xml000066400000000000000000000001341227016120300304040ustar00rootroot00000000000000 /xmlrpc-c/ abyss_unixsock.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libxnee.xml000066400000000000000000000000621227016120300266350ustar00rootroot00000000000000 #define HAVE_STDARG_H 1 abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libxplc.xml000066400000000000000000000002231227016120300266430ustar00rootroot00000000000000 #define UNSTABLE xplc/delete.h /wvstreams/ abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libxslt.xml000066400000000000000000000000701227016120300266670ustar00rootroot00000000000000 xsltutils.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libzypp.xml000066400000000000000000000001361227016120300267020ustar00rootroot00000000000000 /parser/ws/ /parser/yum/ knownid.h Debug.h abi-compliance-checker-1.99.9/modules/Targets/unix/descriptors/libzzip.xml000066400000000000000000000001101227016120300266640ustar00rootroot00000000000000 fetch.h format.h fseeko.h abi-compliance-checker-1.99.9/modules/Targets/windows/000077500000000000000000000000001227016120300226355ustar00rootroot00000000000000abi-compliance-checker-1.99.9/modules/Targets/windows/common.xml000066400000000000000000000011551227016120300246510ustar00rootroot00000000000000 windows.h struct IUnknown; DllRegisterServer DllUnregisterServer DllCanUnloadNow DllGetClassObject /mfc/ /atl/ quote execute DllRegisterServer DllUnregisterServer GetModuleInfo GetToken DllCanUnloadNow DllGetClassObject DebugBreak GetVersion OpenFile LoadModule RegisterModule SetEvent LoadResource FreeLibrary GetFileSize abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/000077500000000000000000000000001227016120300251765ustar00rootroot00000000000000abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/activeds.xml000066400000000000000000000000631227016120300275210ustar00rootroot00000000000000 iads.h abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/advapi32.xml000066400000000000000000000001471227016120300273330ustar00rootroot00000000000000 mschapp.h wmistr.h abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/certpoleng.xml000066400000000000000000000001361227016120300300620ustar00rootroot00000000000000 sspi.h schannel.h ntsecapi.h ntsecpkg.h abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/comctl32.xml000066400000000000000000000000651227016120300273470ustar00rootroot00000000000000 /atl/ /mfc/ abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/d3d10.xml000066400000000000000000000000741227016120300265340ustar00rootroot00000000000000 -DD3D10_IGNORE_SDK_LAYERS abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/dhcpcsvc.xml000066400000000000000000000000671227016120300275200ustar00rootroot00000000000000 winternl.h abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/dhcpcsvc6.xml000066400000000000000000000000671227016120300276060ustar00rootroot00000000000000 winternl.h abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/drt.xml000066400000000000000000000000561227016120300265120ustar00rootroot00000000000000 windows.h abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/drtprov.xml000066400000000000000000000000561227016120300274210ustar00rootroot00000000000000 windows.h abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/drttransport.xml000066400000000000000000000000561227016120300304670ustar00rootroot00000000000000 windows.h abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/dsprop.xml000066400000000000000000000001411227016120300272230ustar00rootroot00000000000000 /mfc/ iads.h abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/dsuiext.xml000066400000000000000000000000651227016120300274060ustar00rootroot00000000000000 shlobj.h abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/dxva2.xml000066400000000000000000000000631227016120300267430ustar00rootroot00000000000000 d3d9.h abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/eappprxy.xml000066400000000000000000000001171227016120300275670ustar00rootroot00000000000000 eaptypes.h eaphostpeertypes.h abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/esent.xml000066400000000000000000000000561227016120300270370ustar00rootroot00000000000000 windows.h abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/fwpuclnt.xml000066400000000000000000000002541227016120300275630ustar00rootroot00000000000000 windows.h ws2tcpip.h fwpsu.h guiddef.h abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/gdi32.xml000066400000000000000000000001571227016120300266330ustar00rootroot00000000000000 /atl/ /mfc/ gdiplus.h abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/httpapi.xml000066400000000000000000000000561227016120300273720ustar00rootroot00000000000000 windows.h abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/iscsidsc.xml000066400000000000000000000000671227016120300275270ustar00rootroot00000000000000 iscsierr.h abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/kernel32.xml000066400000000000000000000001731227016120300273460ustar00rootroot00000000000000 winbase.h winnls.h wincon.h tlhelp32.h winver.h winnt.h winternl.h abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/mapi32.xml000066400000000000000000000000741227016120300270140ustar00rootroot00000000000000 -D_NATIVE_WCHAR_T_DEFINED abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/mfreadwrite.xml000066400000000000000000000000641227016120300302310ustar00rootroot00000000000000 mfidl.h abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/mprapi.xml000066400000000000000000000000561227016120300272110ustar00rootroot00000000000000 rassapi.h abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/msacm32.xml000066400000000000000000000000641227016120300271650ustar00rootroot00000000000000 mmreg.h abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/msdmo.xml000066400000000000000000000000621227016120300270350ustar00rootroot00000000000000 dmo.h abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/mswsock.xml000066400000000000000000000001511227016120300274030ustar00rootroot00000000000000 windows.h winsock2.h abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/netapi32.xml000066400000000000000000000000611227016120300273420ustar00rootroot00000000000000 lm.h abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/odbcbcp.xml000066400000000000000000000000621227016120300273120ustar00rootroot00000000000000 sql.h abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/ole32.xml000066400000000000000000000001371227016120300266450ustar00rootroot00000000000000 mspenum.h /atl/ ole.h /mfc/ rpcproxy.h abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/p2p.xml000066400000000000000000000000561227016120300264220ustar00rootroot00000000000000 windows.h abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/p2pgraph.xml000066400000000000000000000000561227016120300274440ustar00rootroot00000000000000 windows.h abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/psapi.xml000066400000000000000000000000641227016120300270340ustar00rootroot00000000000000 -DPSAPI_VERSION=1 abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/qwave.xml000066400000000000000000000000751227016120300270450ustar00rootroot00000000000000 windows.h windows.h abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/riched20.xml000066400000000000000000000000671227016120300273230ustar00rootroot00000000000000 richedit.h abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/rpcrt4.xml000066400000000000000000000001501227016120300271320ustar00rootroot00000000000000 objidl.h -DCINTERFACE abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/rtm.xml000066400000000000000000000000671227016120300265250ustar00rootroot00000000000000 iprtrmib.h abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/secur32.xml000066400000000000000000000000631227016120300272050ustar00rootroot00000000000000 sspi.h abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/tdh.xml000066400000000000000000000000651227016120300265000ustar00rootroot00000000000000 wmistr.h abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/traffic.xml000066400000000000000000000001021227016120300273270ustar00rootroot00000000000000 ntddndis.h qos.h abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/uiautomationcore.xml000066400000000000000000000000771227016120300313130ustar00rootroot00000000000000 uiautomationcore.h abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/url.xml000066400000000000000000000000521227016120300265170ustar00rootroot00000000000000 /mfc/ abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/user32.xml000066400000000000000000000000521227016120300270400ustar00rootroot00000000000000 /atl/ abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/vssapi.xml000066400000000000000000000001021227016120300272160ustar00rootroot00000000000000 vss.h vswriter.h abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/wldap32.xml000066400000000000000000000000661227016120300271760ustar00rootroot00000000000000 winldap.h abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/ws2_32.xml000066400000000000000000000000561227016120300267400ustar00rootroot00000000000000 windows.h abi-compliance-checker-1.99.9/modules/Targets/windows/descriptors/wsock32.xml000066400000000000000000000002051227016120300272100ustar00rootroot00000000000000 windows.h mswsock.h windef.h winsock.h