From c83cca1d878ac73f8dc0bd4383b88281602a2a92 Mon Sep 17 00:00:00 2001 From: chaoticgd <43898262+chaoticgd@users.noreply.github.com> Date: Mon, 26 Aug 2024 21:14:17 +0100 Subject: [PATCH] Debugger: Add GNU demangler This code is taken from GCC 13.2.0 with a number of modifications applied. See the included readme for more information. --- 3rdparty/demangler/CMakeLists.txt | 27 + 3rdparty/demangler/DemanglerLicenseGPL.txt | 340 + 3rdparty/demangler/DemanglerLicenseLGPL.txt | 482 ++ 3rdparty/demangler/README | 33 + 3rdparty/demangler/copy_demangler_files.sh | 40 + 3rdparty/demangler/demangler.vcxproj | 67 + 3rdparty/demangler/demangler.vcxproj.filters | 87 + 3rdparty/demangler/include/ansidecl.h | 354 + 3rdparty/demangler/include/cp-demangle.h | 201 + 3rdparty/demangler/include/demangle.h | 756 ++ 3rdparty/demangler/include/dyn-string.h | 72 + 3rdparty/demangler/include/environ.h | 35 + 3rdparty/demangler/include/getopt.h | 143 + 3rdparty/demangler/include/libiberty.h | 761 ++ 3rdparty/demangler/include/safe-ctype.h | 150 + 3rdparty/demangler/src/alloca.c | 483 ++ 3rdparty/demangler/src/argv.c | 568 ++ 3rdparty/demangler/src/cp-demangle.c | 7326 +++++++++++++++++ 3rdparty/demangler/src/cplus-dem.c | 5052 ++++++++++++ 3rdparty/demangler/src/d-demangle.c | 1982 +++++ 3rdparty/demangler/src/dyn-string.c | 397 + 3rdparty/demangler/src/getopt.c | 1051 +++ 3rdparty/demangler/src/getopt1.c | 179 + 3rdparty/demangler/src/rust-demangle.c | 1604 ++++ 3rdparty/demangler/src/safe-ctype.c | 254 + 3rdparty/demangler/src/xexit.c | 52 + 3rdparty/demangler/src/xmalloc.c | 186 + 3rdparty/demangler/src/xmemdup.c | 41 + 3rdparty/demangler/src/xstrdup.c | 36 + .../demangler/testsuite/demangle-expected | 5048 ++++++++++++ .../demangler/testsuite/demangler-fuzzer.c | 108 + 3rdparty/demangler/testsuite/test-demangle.c | 352 + PCSX2_qt.sln | 42 + cmake/SearchForStuff.cmake | 3 + pcsx2-qt/pcsx2-qt.vcxproj | 1 + pcsx2/CMakeLists.txt | 1 + pcsx2/DebugTools/SymbolGuardian.cpp | 3 + pcsx2/pcsx2.vcxproj | 4 + 38 files changed, 28321 insertions(+) create mode 100644 3rdparty/demangler/CMakeLists.txt create mode 100644 3rdparty/demangler/DemanglerLicenseGPL.txt create mode 100644 3rdparty/demangler/DemanglerLicenseLGPL.txt create mode 100644 3rdparty/demangler/README create mode 100755 3rdparty/demangler/copy_demangler_files.sh create mode 100644 3rdparty/demangler/demangler.vcxproj create mode 100644 3rdparty/demangler/demangler.vcxproj.filters create mode 100644 3rdparty/demangler/include/ansidecl.h create mode 100644 3rdparty/demangler/include/cp-demangle.h create mode 100644 3rdparty/demangler/include/demangle.h create mode 100644 3rdparty/demangler/include/dyn-string.h create mode 100644 3rdparty/demangler/include/environ.h create mode 100644 3rdparty/demangler/include/getopt.h create mode 100644 3rdparty/demangler/include/libiberty.h create mode 100644 3rdparty/demangler/include/safe-ctype.h create mode 100644 3rdparty/demangler/src/alloca.c create mode 100644 3rdparty/demangler/src/argv.c create mode 100644 3rdparty/demangler/src/cp-demangle.c create mode 100644 3rdparty/demangler/src/cplus-dem.c create mode 100644 3rdparty/demangler/src/d-demangle.c create mode 100644 3rdparty/demangler/src/dyn-string.c create mode 100644 3rdparty/demangler/src/getopt.c create mode 100644 3rdparty/demangler/src/getopt1.c create mode 100644 3rdparty/demangler/src/rust-demangle.c create mode 100644 3rdparty/demangler/src/safe-ctype.c create mode 100644 3rdparty/demangler/src/xexit.c create mode 100644 3rdparty/demangler/src/xmalloc.c create mode 100644 3rdparty/demangler/src/xmemdup.c create mode 100644 3rdparty/demangler/src/xstrdup.c create mode 100644 3rdparty/demangler/testsuite/demangle-expected create mode 100644 3rdparty/demangler/testsuite/demangler-fuzzer.c create mode 100644 3rdparty/demangler/testsuite/test-demangle.c diff --git a/3rdparty/demangler/CMakeLists.txt b/3rdparty/demangler/CMakeLists.txt new file mode 100644 index 0000000000..d610dd3dba --- /dev/null +++ b/3rdparty/demangler/CMakeLists.txt @@ -0,0 +1,27 @@ +add_library(demanglegnu STATIC + src/alloca.c + src/cp-demangle.c + src/cplus-dem.c + src/d-demangle.c + src/dyn-string.c + src/getopt1.c + src/getopt.c + src/rust-demangle.c + src/safe-ctype.c + src/xexit.c + src/xmalloc.c + src/xmemdup.c + src/xstrdup.c +) + +set(GNU_DEMANGLER_FLAGS -DHAVE_DECL_BASENAME=1 -DHAVE_LIMITS_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1) + +target_include_directories(demanglegnu PUBLIC include) +target_compile_definitions(demanglegnu PUBLIC ${GNU_DEMANGLER_FLAGS}) + +add_executable(demangler_fuzzer testsuite/demangler-fuzzer.c) +add_executable(demangler_test testsuite/test-demangle.c) +target_link_libraries(demangler_fuzzer demanglegnu) +target_link_libraries(demangler_test demanglegnu) +target_compile_definitions(demangler_fuzzer PUBLIC ${GNU_DEMANGLER_FLAGS}) +target_compile_definitions(demangler_test PUBLIC ${GNU_DEMANGLER_FLAGS}) diff --git a/3rdparty/demangler/DemanglerLicenseGPL.txt b/3rdparty/demangler/DemanglerLicenseGPL.txt new file mode 100644 index 0000000000..623b6258a1 --- /dev/null +++ b/3rdparty/demangler/DemanglerLicenseGPL.txt @@ -0,0 +1,340 @@ + 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 Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + 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 Library General +Public License instead of this License. diff --git a/3rdparty/demangler/DemanglerLicenseLGPL.txt b/3rdparty/demangler/DemanglerLicenseLGPL.txt new file mode 100644 index 0000000000..778d0bb5b2 --- /dev/null +++ b/3rdparty/demangler/DemanglerLicenseLGPL.txt @@ -0,0 +1,482 @@ + 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 + + Appendix: 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 + 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. + +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! diff --git a/3rdparty/demangler/README b/3rdparty/demangler/README new file mode 100644 index 0000000000..3d74969a95 --- /dev/null +++ b/3rdparty/demangler/README @@ -0,0 +1,33 @@ +This code was taken from GCC 13.2.0 and specifically the libiberty library which +contains files licensed under the GPL and the LGPL. + +Support for GCC 2.x-style symbols has been reintroduced by reversing the changes +made by the commit that removed it: + + From: Jason Merrill + Date: Sun, 23 Dec 2018 00:06:34 +0000 (-0500) + Subject: Remove support for demangling GCC 2.x era mangling schemes. + X-Git-Tag: releases/gcc-9.1.0~2159 + X-Git-Url: https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff_plain;h=6c8120c5ff130e03d32ff15a8f0d0e703592a2af + + Remove support for demangling GCC 2.x era mangling schemes. + + libiberty/ + * cplus-dem.c: Remove cplus_mangle_opname, cplus_demangle_opname, + internal_cplus_demangle, and all subroutines. + (libiberty_demanglers): Remove entries for ancient GNU (pre-3.0), + Lucid, ARM, HP, and EDG demangling styles. + (cplus_demangle): Remove 'work' variable. Don't call + internal_cplus_demangle. + include/ + * demangle.h: Remove support for ancient GNU (pre-3.0), Lucid, + ARM, HP, and EDG demangling styles. + + From-SVN: r267363 + +In addition, the cplus_demangle_opname function has been modified to address a +memory safety issue: + + /* CCC: Allocate the result on the heap to prevent buffer overruns. */ + extern char * + cplus_demangle_opname (const char *opname, int options); diff --git a/3rdparty/demangler/copy_demangler_files.sh b/3rdparty/demangler/copy_demangler_files.sh new file mode 100755 index 0000000000..366b6eadbc --- /dev/null +++ b/3rdparty/demangler/copy_demangler_files.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +set -e + +# This script copies all the source files needed for the GNU demangler from a +# copy of GCC to the specified output directory. + +if [ "$#" -ne 2 ]; then + echo "usage: $0 " + exit 1 +fi + +GCC_DIR=$1 +OUT_DIR=$2 + +cp "$GCC_DIR/include/ansidecl.h" "$OUT_DIR/include/" +cp "$GCC_DIR/include/demangle.h" "$OUT_DIR/include/" +cp "$GCC_DIR/include/dyn-string.h" "$OUT_DIR/include/" +cp "$GCC_DIR/include/environ.h" "$OUT_DIR/include/" +cp "$GCC_DIR/include/getopt.h" "$OUT_DIR/include/" +cp "$GCC_DIR/include/libiberty.h" "$OUT_DIR/include/" +cp "$GCC_DIR/include/safe-ctype.h" "$OUT_DIR/include/" +cp "$GCC_DIR/libiberty/alloca.c" "$OUT_DIR/src/" +cp "$GCC_DIR/libiberty/argv.c" "$OUT_DIR/src/" +cp "$GCC_DIR/libiberty/cp-demangle.c" "$OUT_DIR/src/" +cp "$GCC_DIR/libiberty/cp-demangle.h" "$OUT_DIR/src/" +cp "$GCC_DIR/libiberty/cplus-dem.c" "$OUT_DIR/src/" +cp "$GCC_DIR/libiberty/d-demangle.c" "$OUT_DIR/src/" +cp "$GCC_DIR/libiberty/dyn-string.c" "$OUT_DIR/src/" +cp "$GCC_DIR/libiberty/getopt.c" "$OUT_DIR/src/" +cp "$GCC_DIR/libiberty/getopt1.c" "$OUT_DIR/src/" +cp "$GCC_DIR/libiberty/rust-demangle.c" "$OUT_DIR/src/" +cp "$GCC_DIR/libiberty/safe-ctype.c" "$OUT_DIR/src/" +cp "$GCC_DIR/libiberty/xexit.c" "$OUT_DIR/src/" +cp "$GCC_DIR/libiberty/xmalloc.c" "$OUT_DIR/src/" +cp "$GCC_DIR/libiberty/xmemdup.c" "$OUT_DIR/src/" +cp "$GCC_DIR/libiberty/xstrdup.c" "$OUT_DIR/src/" +cp "$GCC_DIR/libiberty/testsuite/demangle-expected" "$OUT_DIR/testsuite/" +cp "$GCC_DIR/libiberty/testsuite/demangler-fuzzer.c" "$OUT_DIR/testsuite/" +cp "$GCC_DIR/libiberty/testsuite/test-demangle.c" "$OUT_DIR/testsuite/" diff --git a/3rdparty/demangler/demangler.vcxproj b/3rdparty/demangler/demangler.vcxproj new file mode 100644 index 0000000000..2e82eeeadf --- /dev/null +++ b/3rdparty/demangler/demangler.vcxproj @@ -0,0 +1,67 @@ + + + + + + {D31A6DD1-99CA-41D8-A230-1FAE913C8989} + + + + StaticLibrary + $(DefaultPlatformToolset) + ClangCL + MultiByte + true + true + false + + + + + + + + + + + + + + AllRules.ruleset + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + HAVE_DECL_BASENAME=1;HAVE_LIMITS_H;HAVE_STDLIB_H=1;HAVE_STRING_H=1;%(PreprocessorDefinitions) + TurnOffAllWarnings + $(ProjectDir)include;%(AdditionalIncludeDirectories) + + + + + diff --git a/3rdparty/demangler/demangler.vcxproj.filters b/3rdparty/demangler/demangler.vcxproj.filters new file mode 100644 index 0000000000..f989658c41 --- /dev/null +++ b/3rdparty/demangler/demangler.vcxproj.filters @@ -0,0 +1,87 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + diff --git a/3rdparty/demangler/include/ansidecl.h b/3rdparty/demangler/include/ansidecl.h new file mode 100644 index 0000000000..39375e1715 --- /dev/null +++ b/3rdparty/demangler/include/ansidecl.h @@ -0,0 +1,354 @@ +/* Compiler compatibility macros + Copyright (C) 1991-2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + +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. */ + +/* For ease of writing code which uses GCC extensions but needs to be + portable to other compilers, we provide the GCC_VERSION macro that + simplifies testing __GNUC__ and __GNUC_MINOR__ together, and various + wrappers around __attribute__. Also, __extension__ will be #defined + to nothing if it doesn't work. See below. */ + +#ifndef _ANSIDECL_H +#define _ANSIDECL_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* Every source file includes this file, + so they will all get the switch for lint. */ +/* LINTLIBRARY */ + +/* Using MACRO(x,y) in cpp #if conditionals does not work with some + older preprocessors. Thus we can't define something like this: + +#define HAVE_GCC_VERSION(MAJOR, MINOR) \ + (__GNUC__ > (MAJOR) || (__GNUC__ == (MAJOR) && __GNUC_MINOR__ >= (MINOR))) + +and then test "#if HAVE_GCC_VERSION(2,7)". + +So instead we use the macro below and test it against specific values. */ + +/* This macro simplifies testing whether we are using gcc, and if it + is of a particular minimum version. (Both major & minor numbers are + significant.) This macro will evaluate to 0 if we are not using + gcc at all. */ +#ifndef GCC_VERSION +#define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__) +#endif /* GCC_VERSION */ + +/* inline requires special treatment; it's in C99, and GCC >=2.7 supports + it too, but it's not in C89. */ +#undef inline +#if (!defined(__cplusplus) && __STDC_VERSION__ >= 199901L) || defined(__cplusplus) || (defined(__SUNPRO_C) && defined(__C99FEATURES__)) +/* it's a keyword */ +#else +# if GCC_VERSION >= 2007 +# define inline __inline__ /* __inline__ prevents -pedantic warnings */ +# else +# define inline /* nothing */ +# endif +#endif + +/* Define macros for some gcc attributes. This permits us to use the + macros freely, and know that they will come into play for the + version of gcc in which they are supported. */ + +#if (GCC_VERSION < 2007) +# define __attribute__(x) +#endif + +/* Attribute __malloc__ on functions was valid as of gcc 2.96. */ +#ifndef ATTRIBUTE_MALLOC +# if (GCC_VERSION >= 2096) +# define ATTRIBUTE_MALLOC __attribute__ ((__malloc__)) +# else +# define ATTRIBUTE_MALLOC +# endif /* GNUC >= 2.96 */ +#endif /* ATTRIBUTE_MALLOC */ + +/* Attributes on labels were valid as of gcc 2.93 and g++ 4.5. For + g++ an attribute on a label must be followed by a semicolon. */ +#ifndef ATTRIBUTE_UNUSED_LABEL +# ifndef __cplusplus +# if GCC_VERSION >= 2093 +# define ATTRIBUTE_UNUSED_LABEL ATTRIBUTE_UNUSED +# else +# define ATTRIBUTE_UNUSED_LABEL +# endif +# else +# if GCC_VERSION >= 4005 +# define ATTRIBUTE_UNUSED_LABEL ATTRIBUTE_UNUSED ; +# else +# define ATTRIBUTE_UNUSED_LABEL +# endif +# endif +#endif + +/* Similarly to ARG_UNUSED below. Prior to GCC 3.4, the C++ frontend + couldn't parse attributes placed after the identifier name, and now + the entire compiler is built with C++. */ +#ifndef ATTRIBUTE_UNUSED +#if GCC_VERSION >= 3004 +# define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) +#else +#define ATTRIBUTE_UNUSED +#endif +#endif /* ATTRIBUTE_UNUSED */ + +/* Before GCC 3.4, the C++ frontend couldn't parse attributes placed after the + identifier name. */ +#if ! defined(__cplusplus) || (GCC_VERSION >= 3004) +# define ARG_UNUSED(NAME) NAME ATTRIBUTE_UNUSED +#else /* !__cplusplus || GNUC >= 3.4 */ +# define ARG_UNUSED(NAME) NAME +#endif /* !__cplusplus || GNUC >= 3.4 */ + +#ifndef ATTRIBUTE_NORETURN +#define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__)) +#endif /* ATTRIBUTE_NORETURN */ + +/* Attribute `nonnull' was valid as of gcc 3.3. */ +#ifndef ATTRIBUTE_NONNULL +# if (GCC_VERSION >= 3003) +# define ATTRIBUTE_NONNULL(m) __attribute__ ((__nonnull__ (m))) +# else +# define ATTRIBUTE_NONNULL(m) +# endif /* GNUC >= 3.3 */ +#endif /* ATTRIBUTE_NONNULL */ + +/* Attribute `returns_nonnull' was valid as of gcc 4.9. */ +#ifndef ATTRIBUTE_RETURNS_NONNULL +# if (GCC_VERSION >= 4009) +# define ATTRIBUTE_RETURNS_NONNULL __attribute__ ((__returns_nonnull__)) +# else +# define ATTRIBUTE_RETURNS_NONNULL +# endif /* GNUC >= 4.9 */ +#endif /* ATTRIBUTE_RETURNS_NONNULL */ + +/* Attribute `pure' was valid as of gcc 3.0. */ +#ifndef ATTRIBUTE_PURE +# if (GCC_VERSION >= 3000) +# define ATTRIBUTE_PURE __attribute__ ((__pure__)) +# else +# define ATTRIBUTE_PURE +# endif /* GNUC >= 3.0 */ +#endif /* ATTRIBUTE_PURE */ + +/* Use ATTRIBUTE_PRINTF when the format specifier must not be NULL. + This was the case for the `printf' format attribute by itself + before GCC 3.3, but as of 3.3 we need to add the `nonnull' + attribute to retain this behavior. */ +#ifndef ATTRIBUTE_PRINTF +#define ATTRIBUTE_PRINTF(m, n) __attribute__ ((__format__ (__printf__, m, n))) ATTRIBUTE_NONNULL(m) +#define ATTRIBUTE_PRINTF_1 ATTRIBUTE_PRINTF(1, 2) +#define ATTRIBUTE_PRINTF_2 ATTRIBUTE_PRINTF(2, 3) +#define ATTRIBUTE_PRINTF_3 ATTRIBUTE_PRINTF(3, 4) +#define ATTRIBUTE_PRINTF_4 ATTRIBUTE_PRINTF(4, 5) +#define ATTRIBUTE_PRINTF_5 ATTRIBUTE_PRINTF(5, 6) +#endif /* ATTRIBUTE_PRINTF */ + +/* Use ATTRIBUTE_FPTR_PRINTF when the format attribute is to be set on + a function pointer. Format attributes were allowed on function + pointers as of gcc 3.1. */ +#ifndef ATTRIBUTE_FPTR_PRINTF +# if (GCC_VERSION >= 3001) +# define ATTRIBUTE_FPTR_PRINTF(m, n) ATTRIBUTE_PRINTF(m, n) +# else +# define ATTRIBUTE_FPTR_PRINTF(m, n) +# endif /* GNUC >= 3.1 */ +# define ATTRIBUTE_FPTR_PRINTF_1 ATTRIBUTE_FPTR_PRINTF(1, 2) +# define ATTRIBUTE_FPTR_PRINTF_2 ATTRIBUTE_FPTR_PRINTF(2, 3) +# define ATTRIBUTE_FPTR_PRINTF_3 ATTRIBUTE_FPTR_PRINTF(3, 4) +# define ATTRIBUTE_FPTR_PRINTF_4 ATTRIBUTE_FPTR_PRINTF(4, 5) +# define ATTRIBUTE_FPTR_PRINTF_5 ATTRIBUTE_FPTR_PRINTF(5, 6) +#endif /* ATTRIBUTE_FPTR_PRINTF */ + +/* Use ATTRIBUTE_NULL_PRINTF when the format specifier may be NULL. A + NULL format specifier was allowed as of gcc 3.3. */ +#ifndef ATTRIBUTE_NULL_PRINTF +# if (GCC_VERSION >= 3003) +# define ATTRIBUTE_NULL_PRINTF(m, n) __attribute__ ((__format__ (__printf__, m, n))) +# else +# define ATTRIBUTE_NULL_PRINTF(m, n) +# endif /* GNUC >= 3.3 */ +# define ATTRIBUTE_NULL_PRINTF_1 ATTRIBUTE_NULL_PRINTF(1, 2) +# define ATTRIBUTE_NULL_PRINTF_2 ATTRIBUTE_NULL_PRINTF(2, 3) +# define ATTRIBUTE_NULL_PRINTF_3 ATTRIBUTE_NULL_PRINTF(3, 4) +# define ATTRIBUTE_NULL_PRINTF_4 ATTRIBUTE_NULL_PRINTF(4, 5) +# define ATTRIBUTE_NULL_PRINTF_5 ATTRIBUTE_NULL_PRINTF(5, 6) +#endif /* ATTRIBUTE_NULL_PRINTF */ + +/* Attribute `sentinel' was valid as of gcc 3.5. */ +#ifndef ATTRIBUTE_SENTINEL +# if (GCC_VERSION >= 3005) +# define ATTRIBUTE_SENTINEL __attribute__ ((__sentinel__)) +# else +# define ATTRIBUTE_SENTINEL +# endif /* GNUC >= 3.5 */ +#endif /* ATTRIBUTE_SENTINEL */ + + +#ifndef ATTRIBUTE_ALIGNED_ALIGNOF +# if (GCC_VERSION >= 3000) +# define ATTRIBUTE_ALIGNED_ALIGNOF(m) __attribute__ ((__aligned__ (__alignof__ (m)))) +# else +# define ATTRIBUTE_ALIGNED_ALIGNOF(m) +# endif /* GNUC >= 3.0 */ +#endif /* ATTRIBUTE_ALIGNED_ALIGNOF */ + +/* Useful for structures whose layout must match some binary specification + regardless of the alignment and padding qualities of the compiler. */ +#ifndef ATTRIBUTE_PACKED +# define ATTRIBUTE_PACKED __attribute__ ((packed)) +#endif + +/* Attribute `hot' and `cold' was valid as of gcc 4.3. */ +#ifndef ATTRIBUTE_COLD +# if (GCC_VERSION >= 4003) +# define ATTRIBUTE_COLD __attribute__ ((__cold__)) +# else +# define ATTRIBUTE_COLD +# endif /* GNUC >= 4.3 */ +#endif /* ATTRIBUTE_COLD */ +#ifndef ATTRIBUTE_HOT +# if (GCC_VERSION >= 4003) +# define ATTRIBUTE_HOT __attribute__ ((__hot__)) +# else +# define ATTRIBUTE_HOT +# endif /* GNUC >= 4.3 */ +#endif /* ATTRIBUTE_HOT */ + +/* Attribute 'no_sanitize_undefined' was valid as of gcc 4.9. */ +#ifndef ATTRIBUTE_NO_SANITIZE_UNDEFINED +# if (GCC_VERSION >= 4009) +# define ATTRIBUTE_NO_SANITIZE_UNDEFINED __attribute__ ((no_sanitize_undefined)) +# else +# define ATTRIBUTE_NO_SANITIZE_UNDEFINED +# endif /* GNUC >= 4.9 */ +#endif /* ATTRIBUTE_NO_SANITIZE_UNDEFINED */ + +/* Attribute 'nonstring' was valid as of gcc 8. */ +#ifndef ATTRIBUTE_NONSTRING +# if GCC_VERSION >= 8000 +# define ATTRIBUTE_NONSTRING __attribute__ ((__nonstring__)) +# else +# define ATTRIBUTE_NONSTRING +# endif +#endif + +/* Attribute `alloc_size' was valid as of gcc 4.3. */ +#ifndef ATTRIBUTE_RESULT_SIZE_1 +# if (GCC_VERSION >= 4003) +# define ATTRIBUTE_RESULT_SIZE_1 __attribute__ ((alloc_size (1))) +# else +# define ATTRIBUTE_RESULT_SIZE_1 +#endif +#endif + +#ifndef ATTRIBUTE_RESULT_SIZE_2 +# if (GCC_VERSION >= 4003) +# define ATTRIBUTE_RESULT_SIZE_2 __attribute__ ((alloc_size (2))) +# else +# define ATTRIBUTE_RESULT_SIZE_2 +#endif +#endif + +#ifndef ATTRIBUTE_RESULT_SIZE_1_2 +# if (GCC_VERSION >= 4003) +# define ATTRIBUTE_RESULT_SIZE_1_2 __attribute__ ((alloc_size (1, 2))) +# else +# define ATTRIBUTE_RESULT_SIZE_1_2 +#endif +#endif + +/* Attribute `warn_unused_result' was valid as of gcc 3.3. */ +#ifndef ATTRIBUTE_WARN_UNUSED_RESULT +# if GCC_VERSION >= 3003 +# define ATTRIBUTE_WARN_UNUSED_RESULT __attribute__ ((__warn_unused_result__)) +# else +# define ATTRIBUTE_WARN_UNUSED_RESULT +# endif +#endif + +/* We use __extension__ in some places to suppress -pedantic warnings + about GCC extensions. This feature didn't work properly before + gcc 2.8. */ +#if GCC_VERSION < 2008 +#define __extension__ +#endif + +/* This is used to declare a const variable which should be visible + outside of the current compilation unit. Use it as + EXPORTED_CONST int i = 1; + This is because the semantics of const are different in C and C++. + "extern const" is permitted in C but it looks strange, and gcc + warns about it when -Wc++-compat is not used. */ +#ifdef __cplusplus +#define EXPORTED_CONST extern const +#else +#define EXPORTED_CONST const +#endif + +/* Be conservative and only use enum bitfields with C++ or GCC. + FIXME: provide a complete autoconf test for buggy enum bitfields. */ + +#ifdef __cplusplus +#define ENUM_BITFIELD(TYPE) enum TYPE +#elif (GCC_VERSION > 2000) +#define ENUM_BITFIELD(TYPE) __extension__ enum TYPE +#else +#define ENUM_BITFIELD(TYPE) unsigned int +#endif + +#if defined(__cplusplus) && __cpp_constexpr >= 200704 +#define CONSTEXPR constexpr +#else +#define CONSTEXPR +#endif + +/* A macro to disable the copy constructor and assignment operator. + When building with C++11 and above, the methods are explicitly + deleted, causing a compile-time error if something tries to copy. + For C++03, this just declares the methods, causing a link-time + error if the methods end up called (assuming you don't + define them). For C++03, for best results, place the macro + under the private: access specifier, like this, + + class name_lookup + { + private: + DISABLE_COPY_AND_ASSIGN (name_lookup); + }; + + so that most attempts at copy are caught at compile-time. */ + +#if defined(__cplusplus) && __cplusplus >= 201103 +#define DISABLE_COPY_AND_ASSIGN(TYPE) \ + TYPE (const TYPE&) = delete; \ + void operator= (const TYPE &) = delete + #else +#define DISABLE_COPY_AND_ASSIGN(TYPE) \ + TYPE (const TYPE&); \ + void operator= (const TYPE &) +#endif /* __cplusplus >= 201103 */ + +#ifdef __cplusplus +} +#endif + +#endif /* ansidecl.h */ diff --git a/3rdparty/demangler/include/cp-demangle.h b/3rdparty/demangler/include/cp-demangle.h new file mode 100644 index 0000000000..8563f91602 --- /dev/null +++ b/3rdparty/demangler/include/cp-demangle.h @@ -0,0 +1,201 @@ +/* Internal demangler interface for g++ V3 ABI. + Copyright (C) 2003-2023 Free Software Foundation, Inc. + Written by Ian Lance Taylor . + + This file is part of the libiberty library, which is part of GCC. + + This file 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. + + In addition to the permissions in the GNU General Public License, the + Free Software Foundation gives you unlimited permission to link the + compiled version of this file into combinations with other programs, + and to distribute those combinations without any restriction coming + from the use of this file. (The General Public License restrictions + do apply in other respects; for example, they cover modification of + the file, and distribution when not linked into a combined + executable.) + + 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. +*/ + +/* This file provides some definitions shared by cp-demangle.c and + cp-demint.c. It should not be included by any other files. */ + +/* Information we keep for operators. */ + +struct demangle_operator_info +{ + /* Mangled name. */ + const char *code; + /* Real name. */ + const char *name; + /* Length of real name. */ + int len; + /* Number of arguments. */ + int args; +}; + +/* How to print the value of a builtin type. */ + +enum d_builtin_type_print +{ + /* Print as (type)val. */ + D_PRINT_DEFAULT, + /* Print as integer. */ + D_PRINT_INT, + /* Print as unsigned integer, with trailing "u". */ + D_PRINT_UNSIGNED, + /* Print as long, with trailing "l". */ + D_PRINT_LONG, + /* Print as unsigned long, with trailing "ul". */ + D_PRINT_UNSIGNED_LONG, + /* Print as long long, with trailing "ll". */ + D_PRINT_LONG_LONG, + /* Print as unsigned long long, with trailing "ull". */ + D_PRINT_UNSIGNED_LONG_LONG, + /* Print as bool. */ + D_PRINT_BOOL, + /* Print as float--put value in square brackets. */ + D_PRINT_FLOAT, + /* Print in usual way, but here to detect void. */ + D_PRINT_VOID +}; + +/* Information we keep for a builtin type. */ + +struct demangle_builtin_type_info +{ + /* Type name. */ + const char *name; + /* Length of type name. */ + int len; + /* Type name when using Java. */ + const char *java_name; + /* Length of java name. */ + int java_len; + /* How to print a value of this type. */ + enum d_builtin_type_print print; +}; + +/* The information structure we pass around. */ + +struct d_info +{ + /* The string we are demangling. */ + const char *s; + /* The end of the string we are demangling. */ + const char *send; + /* The options passed to the demangler. */ + int options; + /* The next character in the string to consider. */ + const char *n; + /* The array of components. */ + struct demangle_component *comps; + /* The index of the next available component. */ + int next_comp; + /* The number of available component structures. */ + int num_comps; + /* The array of substitutions. */ + struct demangle_component **subs; + /* The index of the next substitution. */ + int next_sub; + /* The number of available entries in the subs array. */ + int num_subs; + /* The last name we saw, for constructors and destructors. */ + struct demangle_component *last_name; + /* A running total of the length of large expansions from the + mangled name to the demangled name, such as standard + substitutions and builtin types. */ + int expansion; + /* Non-zero if we are parsing an expression. */ + int is_expression; + /* Non-zero if we are parsing the type operand of a conversion + operator, but not when in an expression. */ + int is_conversion; + /* 1: using new unresolved-name grammar. + -1: using new unresolved-name grammar and saw an unresolved-name. + 0: using old unresolved-name grammar. */ + int unresolved_name_state; + /* If DMGL_NO_RECURSE_LIMIT is not active then this is set to + the current recursion level. */ + unsigned int recursion_level; +}; + +/* To avoid running past the ending '\0', don't: + - call d_peek_next_char if d_peek_char returned '\0' + - call d_advance with an 'i' that is too large + - call d_check_char(di, '\0') + Everything else is safe. */ +#define d_peek_char(di) (*((di)->n)) +#ifndef CHECK_DEMANGLER +# define d_peek_next_char(di) ((di)->n[1]) +# define d_advance(di, i) ((di)->n += (i)) +#endif +#define d_check_char(di, c) (d_peek_char(di) == c ? ((di)->n++, 1) : 0) +#define d_next_char(di) (d_peek_char(di) == '\0' ? '\0' : *((di)->n++)) +#define d_str(di) ((di)->n) + +#ifdef CHECK_DEMANGLER +static inline char +d_peek_next_char (const struct d_info *di) +{ + if (!di->n[0]) + abort (); + return di->n[1]; +} + +static inline void +d_advance (struct d_info *di, int i) +{ + if (i < 0) + abort (); + while (i--) + { + if (!di->n[0]) + abort (); + di->n++; + } +} +#endif + +/* Functions and arrays in cp-demangle.c which are referenced by + functions in cp-demint.c. */ +#ifdef IN_GLIBCPP_V3 +#define CP_STATIC_IF_GLIBCPP_V3 static +#else +#define CP_STATIC_IF_GLIBCPP_V3 extern +#endif + +#ifndef IN_GLIBCPP_V3 +extern const struct demangle_operator_info cplus_demangle_operators[]; +#endif + +#define D_BUILTIN_TYPE_COUNT (36) + +CP_STATIC_IF_GLIBCPP_V3 +const struct demangle_builtin_type_info +cplus_demangle_builtin_types[D_BUILTIN_TYPE_COUNT]; + +CP_STATIC_IF_GLIBCPP_V3 +struct demangle_component * +cplus_demangle_mangled_name (struct d_info *, int); + +CP_STATIC_IF_GLIBCPP_V3 +struct demangle_component * +cplus_demangle_type (struct d_info *); + +extern void +cplus_demangle_init_info (const char *, int, size_t, struct d_info *); + +/* cp-demangle.c needs to define this a little differently */ +#undef CP_STATIC_IF_GLIBCPP_V3 diff --git a/3rdparty/demangler/include/demangle.h b/3rdparty/demangler/include/demangle.h new file mode 100644 index 0000000000..45b52e7678 --- /dev/null +++ b/3rdparty/demangler/include/demangle.h @@ -0,0 +1,756 @@ +/* Defs for interface to demanglers. + Copyright (C) 1992-2023 Free Software Foundation, Inc. + + This program 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, or + (at your option) any later version. + + In addition to the permissions in the GNU Library General Public + License, the Free Software Foundation gives you unlimited + permission to link the compiled version of this file into + combinations with other programs, and to distribute those + combinations without any restriction coming from the use of this + file. (The Library Public License restrictions do apply in other + respects; for example, they cover modification of the file, and + distribution when not linked into a combined executable.) + + 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library 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. */ + + +#if !defined (DEMANGLE_H) +#define DEMANGLE_H + +#include "libiberty.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Options passed to cplus_demangle (in 2nd parameter). */ + +#define DMGL_NO_OPTS 0 /* For readability... */ +#define DMGL_PARAMS (1 << 0) /* Include function args */ +#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ +#define DMGL_JAVA (1 << 2) /* Demangle as Java rather than C++. */ +#define DMGL_VERBOSE (1 << 3) /* Include implementation details. */ +#define DMGL_TYPES (1 << 4) /* Also try to demangle type encodings. */ +#define DMGL_RET_POSTFIX (1 << 5) /* Print function return types (when + present) after function signature. + It applies only to the toplevel + function type. */ +#define DMGL_RET_DROP (1 << 6) /* Suppress printing function return + types, even if present. It applies + only to the toplevel function type. + */ + +#define DMGL_AUTO (1 << 8) +#define DMGL_GNU (1 << 9) +#define DMGL_LUCID (1 << 10) +#define DMGL_ARM (1 << 11) +#define DMGL_HP (1 << 12) /* For the HP aCC compiler; + same as ARM except for + template arguments, etc. */ +#define DMGL_EDG (1 << 13) +#define DMGL_GNU_V3 (1 << 14) +#define DMGL_GNAT (1 << 15) +#define DMGL_DLANG (1 << 16) +#define DMGL_RUST (1 << 17) /* Rust wraps GNU_V3 style mangling. */ + +/* If none of these are set, use 'current_demangling_style' as the default. */ +#define DMGL_STYLE_MASK (DMGL_AUTO|DMGL_GNU|DMGL_LUCID|DMGL_ARM|DMGL_HP|DMGL_EDG|DMGL_GNU_V3|DMGL_JAVA|DMGL_GNAT|DMGL_DLANG|DMGL_RUST) + +/* Disable a limit on the depth of recursion in mangled strings. + Note if this limit is disabled then stack exhaustion is possible when + demangling pathologically complicated strings. Bug reports about stack + exhaustion when the option is enabled will be rejected. */ +#define DMGL_NO_RECURSE_LIMIT (1 << 18) + +/* If DMGL_NO_RECURSE_LIMIT is not enabled, then this is the value used as + the maximum depth of recursion allowed. It should be enough for any + real-world mangled name. */ +#define DEMANGLE_RECURSION_LIMIT 2048 + +/* Enumeration of possible demangling styles. + + Lucid and ARM styles are still kept logically distinct, even though + they now both behave identically. The resulting style is actual the + union of both. I.E. either style recognizes both "__pt__" and "__rf__" + for operator "->", even though the first is lucid style and the second + is ARM style. (FIXME?) */ + +extern enum demangling_styles +{ + no_demangling = -1, + unknown_demangling = 0, + auto_demangling = DMGL_AUTO, + gnu_demangling = DMGL_GNU, + lucid_demangling = DMGL_LUCID, + arm_demangling = DMGL_ARM, + hp_demangling = DMGL_HP, + edg_demangling = DMGL_EDG, + gnu_v3_demangling = DMGL_GNU_V3, + java_demangling = DMGL_JAVA, + gnat_demangling = DMGL_GNAT, + dlang_demangling = DMGL_DLANG, + rust_demangling = DMGL_RUST +} current_demangling_style; + +/* Define string names for the various demangling styles. */ + +#define NO_DEMANGLING_STYLE_STRING "none" +#define AUTO_DEMANGLING_STYLE_STRING "auto" +#define GNU_DEMANGLING_STYLE_STRING "gnu" +#define LUCID_DEMANGLING_STYLE_STRING "lucid" +#define ARM_DEMANGLING_STYLE_STRING "arm" +#define HP_DEMANGLING_STYLE_STRING "hp" +#define EDG_DEMANGLING_STYLE_STRING "edg" +#define GNU_V3_DEMANGLING_STYLE_STRING "gnu-v3" +#define JAVA_DEMANGLING_STYLE_STRING "java" +#define GNAT_DEMANGLING_STYLE_STRING "gnat" +#define DLANG_DEMANGLING_STYLE_STRING "dlang" +#define RUST_DEMANGLING_STYLE_STRING "rust" + +/* Some macros to test what demangling style is active. */ + +#define CURRENT_DEMANGLING_STYLE current_demangling_style +#define AUTO_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_AUTO) +#define GNU_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNU) +#define LUCID_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_LUCID) +#define ARM_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_ARM) +#define HP_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_HP) +#define EDG_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_EDG) +#define GNU_V3_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNU_V3) +#define JAVA_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_JAVA) +#define GNAT_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNAT) +#define DLANG_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_DLANG) +#define RUST_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_RUST) + +/* Provide information about the available demangle styles. This code is + pulled from gdb into libiberty because it is useful to binutils also. */ + +extern const struct demangler_engine +{ + const char *const demangling_style_name; + const enum demangling_styles demangling_style; + const char *const demangling_style_doc; +} libiberty_demanglers[]; + +extern char * +cplus_demangle (const char *mangled, int options); + +/* CCC: Allocate the result on the heap to prevent buffer overruns. */ +extern char * +cplus_demangle_opname (const char *opname, int options); + +extern const char * +cplus_mangle_opname (const char *opname, int options); + +/* Note: This sets global state. FIXME if you care about multi-threading. */ + +extern void +set_cplus_marker_for_demangling (int ch); + +extern enum demangling_styles +cplus_demangle_set_style (enum demangling_styles style); + +extern enum demangling_styles +cplus_demangle_name_to_style (const char *name); + +/* Callback typedef for allocation-less demangler interfaces. */ +typedef void (*demangle_callbackref) (const char *, size_t, void *); + +/* V3 ABI demangling entry points, defined in cp-demangle.c. Callback + variants return non-zero on success, zero on error. char* variants + return a string allocated by malloc on success, NULL on error. */ +extern int +cplus_demangle_v3_callback (const char *mangled, int options, + demangle_callbackref callback, void *opaque); + +extern char* +cplus_demangle_v3 (const char *mangled, int options); + +extern int +java_demangle_v3_callback (const char *mangled, + demangle_callbackref callback, void *opaque); + +extern char* +java_demangle_v3 (const char *mangled); + +char * +ada_demangle (const char *mangled, int options); + +extern char * +dlang_demangle (const char *mangled, int options); + +extern int +rust_demangle_callback (const char *mangled, int options, + demangle_callbackref callback, void *opaque); + + +extern char * +rust_demangle (const char *mangled, int options); + +enum gnu_v3_ctor_kinds { + gnu_v3_complete_object_ctor = 1, + gnu_v3_base_object_ctor, + gnu_v3_complete_object_allocating_ctor, + /* These are not part of the V3 ABI. Unified constructors are generated + as a speed-for-space optimization when the -fdeclone-ctor-dtor option + is used, and are always internal symbols. */ + gnu_v3_unified_ctor, + gnu_v3_object_ctor_group +}; + +/* Return non-zero iff NAME is the mangled form of a constructor name + in the G++ V3 ABI demangling style. Specifically, return an `enum + gnu_v3_ctor_kinds' value indicating what kind of constructor + it is. */ +extern enum gnu_v3_ctor_kinds + is_gnu_v3_mangled_ctor (const char *name); + + +enum gnu_v3_dtor_kinds { + gnu_v3_deleting_dtor = 1, + gnu_v3_complete_object_dtor, + gnu_v3_base_object_dtor, + /* These are not part of the V3 ABI. Unified destructors are generated + as a speed-for-space optimization when the -fdeclone-ctor-dtor option + is used, and are always internal symbols. */ + gnu_v3_unified_dtor, + gnu_v3_object_dtor_group +}; + +/* Return non-zero iff NAME is the mangled form of a destructor name + in the G++ V3 ABI demangling style. Specifically, return an `enum + gnu_v3_dtor_kinds' value, indicating what kind of destructor + it is. */ +extern enum gnu_v3_dtor_kinds + is_gnu_v3_mangled_dtor (const char *name); + +/* The V3 demangler works in two passes. The first pass builds a tree + representation of the mangled name, and the second pass turns the + tree representation into a demangled string. Here we define an + interface to permit a caller to build their own tree + representation, which they can pass to the demangler to get a + demangled string. This can be used to canonicalize user input into + something which the demangler might output. It could also be used + by other demanglers in the future. */ + +/* These are the component types which may be found in the tree. Many + component types have one or two subtrees, referred to as left and + right (a component type with only one subtree puts it in the left + subtree). */ + +enum demangle_component_type +{ + /* A name, with a length and a pointer to a string. */ + DEMANGLE_COMPONENT_NAME, + /* A qualified name. The left subtree is a class or namespace or + some such thing, and the right subtree is a name qualified by + that class. */ + DEMANGLE_COMPONENT_QUAL_NAME, + /* A local name. The left subtree describes a function, and the + right subtree is a name which is local to that function. */ + DEMANGLE_COMPONENT_LOCAL_NAME, + /* A typed name. The left subtree is a name, and the right subtree + describes that name as a function. */ + DEMANGLE_COMPONENT_TYPED_NAME, + /* A template. The left subtree is a template name, and the right + subtree is a template argument list. */ + DEMANGLE_COMPONENT_TEMPLATE, + /* A template parameter. This holds a number, which is the template + parameter index. */ + DEMANGLE_COMPONENT_TEMPLATE_PARAM, + /* A function parameter. This holds a number, which is the index. */ + DEMANGLE_COMPONENT_FUNCTION_PARAM, + /* A constructor. This holds a name and the kind of + constructor. */ + DEMANGLE_COMPONENT_CTOR, + /* A destructor. This holds a name and the kind of destructor. */ + DEMANGLE_COMPONENT_DTOR, + /* A vtable. This has one subtree, the type for which this is a + vtable. */ + DEMANGLE_COMPONENT_VTABLE, + /* A VTT structure. This has one subtree, the type for which this + is a VTT. */ + DEMANGLE_COMPONENT_VTT, + /* A construction vtable. The left subtree is the type for which + this is a vtable, and the right subtree is the derived type for + which this vtable is built. */ + DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE, + /* A typeinfo structure. This has one subtree, the type for which + this is the tpeinfo structure. */ + DEMANGLE_COMPONENT_TYPEINFO, + /* A typeinfo name. This has one subtree, the type for which this + is the typeinfo name. */ + DEMANGLE_COMPONENT_TYPEINFO_NAME, + /* A typeinfo function. This has one subtree, the type for which + this is the tpyeinfo function. */ + DEMANGLE_COMPONENT_TYPEINFO_FN, + /* A thunk. This has one subtree, the name for which this is a + thunk. */ + DEMANGLE_COMPONENT_THUNK, + /* A virtual thunk. This has one subtree, the name for which this + is a virtual thunk. */ + DEMANGLE_COMPONENT_VIRTUAL_THUNK, + /* A covariant thunk. This has one subtree, the name for which this + is a covariant thunk. */ + DEMANGLE_COMPONENT_COVARIANT_THUNK, + /* A Java class. This has one subtree, the type. */ + DEMANGLE_COMPONENT_JAVA_CLASS, + /* A guard variable. This has one subtree, the name for which this + is a guard variable. */ + DEMANGLE_COMPONENT_GUARD, + /* The init and wrapper functions for C++11 thread_local variables. */ + DEMANGLE_COMPONENT_TLS_INIT, + DEMANGLE_COMPONENT_TLS_WRAPPER, + /* A reference temporary. This has one subtree, the name for which + this is a temporary. */ + DEMANGLE_COMPONENT_REFTEMP, + /* A hidden alias. This has one subtree, the encoding for which it + is providing alternative linkage. */ + DEMANGLE_COMPONENT_HIDDEN_ALIAS, + /* A standard substitution. This holds the name of the + substitution. */ + DEMANGLE_COMPONENT_SUB_STD, + /* The restrict qualifier. The one subtree is the type which is + being qualified. */ + DEMANGLE_COMPONENT_RESTRICT, + /* The volatile qualifier. The one subtree is the type which is + being qualified. */ + DEMANGLE_COMPONENT_VOLATILE, + /* The const qualifier. The one subtree is the type which is being + qualified. */ + DEMANGLE_COMPONENT_CONST, + /* The restrict qualifier modifying a member function. The one + subtree is the type which is being qualified. */ + DEMANGLE_COMPONENT_RESTRICT_THIS, + /* The volatile qualifier modifying a member function. The one + subtree is the type which is being qualified. */ + DEMANGLE_COMPONENT_VOLATILE_THIS, + /* The const qualifier modifying a member function. The one subtree + is the type which is being qualified. */ + DEMANGLE_COMPONENT_CONST_THIS, + /* C++11 A reference modifying a member function. The one subtree is the + type which is being referenced. */ + DEMANGLE_COMPONENT_REFERENCE_THIS, + /* C++11: An rvalue reference modifying a member function. The one + subtree is the type which is being referenced. */ + DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS, + /* A vendor qualifier. The left subtree is the type which is being + qualified, and the right subtree is the name of the + qualifier. */ + DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL, + /* A pointer. The one subtree is the type which is being pointed + to. */ + DEMANGLE_COMPONENT_POINTER, + /* A reference. The one subtree is the type which is being + referenced. */ + DEMANGLE_COMPONENT_REFERENCE, + /* C++0x: An rvalue reference. The one subtree is the type which is + being referenced. */ + DEMANGLE_COMPONENT_RVALUE_REFERENCE, + /* A complex type. The one subtree is the base type. */ + DEMANGLE_COMPONENT_COMPLEX, + /* An imaginary type. The one subtree is the base type. */ + DEMANGLE_COMPONENT_IMAGINARY, + /* A builtin type. This holds the builtin type information. */ + DEMANGLE_COMPONENT_BUILTIN_TYPE, + /* A vendor's builtin type. This holds the name of the type. */ + DEMANGLE_COMPONENT_VENDOR_TYPE, + /* A function type. The left subtree is the return type. The right + subtree is a list of ARGLIST nodes. Either or both may be + NULL. */ + DEMANGLE_COMPONENT_FUNCTION_TYPE, + /* An array type. The left subtree is the dimension, which may be + NULL, or a string (represented as DEMANGLE_COMPONENT_NAME), or an + expression. The right subtree is the element type. */ + DEMANGLE_COMPONENT_ARRAY_TYPE, + /* A pointer to member type. The left subtree is the class type, + and the right subtree is the member type. CV-qualifiers appear + on the latter. */ + DEMANGLE_COMPONENT_PTRMEM_TYPE, + /* A fixed-point type. */ + DEMANGLE_COMPONENT_FIXED_TYPE, + /* A vector type. The left subtree is the number of elements, + the right subtree is the element type. */ + DEMANGLE_COMPONENT_VECTOR_TYPE, + /* An argument list. The left subtree is the current argument, and + the right subtree is either NULL or another ARGLIST node. */ + DEMANGLE_COMPONENT_ARGLIST, + /* A template argument list. The left subtree is the current + template argument, and the right subtree is either NULL or + another TEMPLATE_ARGLIST node. */ + DEMANGLE_COMPONENT_TEMPLATE_ARGLIST, + /* A template parameter object (C++20). The left subtree is the + corresponding template argument. */ + DEMANGLE_COMPONENT_TPARM_OBJ, + /* An initializer list. The left subtree is either an explicit type or + NULL, and the right subtree is a DEMANGLE_COMPONENT_ARGLIST. */ + DEMANGLE_COMPONENT_INITIALIZER_LIST, + /* An operator. This holds information about a standard + operator. */ + DEMANGLE_COMPONENT_OPERATOR, + /* An extended operator. This holds the number of arguments, and + the name of the extended operator. */ + DEMANGLE_COMPONENT_EXTENDED_OPERATOR, + /* A typecast, represented as a unary operator. The one subtree is + the type to which the argument should be cast. */ + DEMANGLE_COMPONENT_CAST, + /* A conversion operator, represented as a unary operator. The one + subtree is the type to which the argument should be converted + to. */ + DEMANGLE_COMPONENT_CONVERSION, + /* A nullary expression. The left subtree is the operator. */ + DEMANGLE_COMPONENT_NULLARY, + /* A unary expression. The left subtree is the operator, and the + right subtree is the single argument. */ + DEMANGLE_COMPONENT_UNARY, + /* A binary expression. The left subtree is the operator, and the + right subtree is a BINARY_ARGS. */ + DEMANGLE_COMPONENT_BINARY, + /* Arguments to a binary expression. The left subtree is the first + argument, and the right subtree is the second argument. */ + DEMANGLE_COMPONENT_BINARY_ARGS, + /* A trinary expression. The left subtree is the operator, and the + right subtree is a TRINARY_ARG1. */ + DEMANGLE_COMPONENT_TRINARY, + /* Arguments to a trinary expression. The left subtree is the first + argument, and the right subtree is a TRINARY_ARG2. */ + DEMANGLE_COMPONENT_TRINARY_ARG1, + /* More arguments to a trinary expression. The left subtree is the + second argument, and the right subtree is the third argument. */ + DEMANGLE_COMPONENT_TRINARY_ARG2, + /* A literal. The left subtree is the type, and the right subtree + is the value, represented as a DEMANGLE_COMPONENT_NAME. */ + DEMANGLE_COMPONENT_LITERAL, + /* A negative literal. Like LITERAL, but the value is negated. + This is a minor hack: the NAME used for LITERAL points directly + to the mangled string, but since negative numbers are mangled + using 'n' instead of '-', we want a way to indicate a negative + number which involves neither modifying the mangled string nor + allocating a new copy of the literal in memory. */ + DEMANGLE_COMPONENT_LITERAL_NEG, + /* A vendor's builtin expression. The left subtree holds the + expression's name, and the right subtree is a argument list. */ + DEMANGLE_COMPONENT_VENDOR_EXPR, + /* A libgcj compiled resource. The left subtree is the name of the + resource. */ + DEMANGLE_COMPONENT_JAVA_RESOURCE, + /* A name formed by the concatenation of two parts. The left + subtree is the first part and the right subtree the second. */ + DEMANGLE_COMPONENT_COMPOUND_NAME, + /* A name formed by a single character. */ + DEMANGLE_COMPONENT_CHARACTER, + /* A number. */ + DEMANGLE_COMPONENT_NUMBER, + /* A decltype type. */ + DEMANGLE_COMPONENT_DECLTYPE, + /* Global constructors keyed to name. */ + DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS, + /* Global destructors keyed to name. */ + DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS, + /* A lambda closure type. */ + DEMANGLE_COMPONENT_LAMBDA, + /* A default argument scope. */ + DEMANGLE_COMPONENT_DEFAULT_ARG, + /* An unnamed type. */ + DEMANGLE_COMPONENT_UNNAMED_TYPE, + /* A transactional clone. This has one subtree, the encoding for + which it is providing alternative linkage. */ + DEMANGLE_COMPONENT_TRANSACTION_CLONE, + /* A non-transactional clone entry point. In the i386/x86_64 abi, + the unmangled symbol of a tm_callable becomes a thunk and the + non-transactional function version is mangled thus. */ + DEMANGLE_COMPONENT_NONTRANSACTION_CLONE, + /* A pack expansion. */ + DEMANGLE_COMPONENT_PACK_EXPANSION, + /* A name with an ABI tag. */ + DEMANGLE_COMPONENT_TAGGED_NAME, + /* A transaction-safe function type. */ + DEMANGLE_COMPONENT_TRANSACTION_SAFE, + /* A cloned function. */ + DEMANGLE_COMPONENT_CLONE, + DEMANGLE_COMPONENT_NOEXCEPT, + DEMANGLE_COMPONENT_THROW_SPEC, + + DEMANGLE_COMPONENT_STRUCTURED_BINDING, + + DEMANGLE_COMPONENT_MODULE_NAME, + DEMANGLE_COMPONENT_MODULE_PARTITION, + DEMANGLE_COMPONENT_MODULE_ENTITY, + DEMANGLE_COMPONENT_MODULE_INIT, + + DEMANGLE_COMPONENT_TEMPLATE_HEAD, + DEMANGLE_COMPONENT_TEMPLATE_TYPE_PARM, + DEMANGLE_COMPONENT_TEMPLATE_NON_TYPE_PARM, + DEMANGLE_COMPONENT_TEMPLATE_TEMPLATE_PARM, + DEMANGLE_COMPONENT_TEMPLATE_PACK_PARM, + + /* A builtin type with argument. This holds the builtin type + information. */ + DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE + +}; + +/* Types which are only used internally. */ + +struct demangle_operator_info; +struct demangle_builtin_type_info; + +/* A node in the tree representation is an instance of a struct + demangle_component. Note that the field names of the struct are + not well protected against macros defined by the file including + this one. We can fix this if it ever becomes a problem. */ + +struct demangle_component +{ + /* The type of this component. */ + enum demangle_component_type type; + + /* Guard against recursive component printing. + Initialize to zero. Private to d_print_comp. + All other fields are final after initialization. */ + int d_printing; + int d_counting; + + union + { + /* For DEMANGLE_COMPONENT_NAME. */ + struct + { + /* A pointer to the name (which need not NULL terminated) and + its length. */ + const char *s; + int len; + } s_name; + + /* For DEMANGLE_COMPONENT_OPERATOR. */ + struct + { + /* Operator. */ + const struct demangle_operator_info *op; + } s_operator; + + /* For DEMANGLE_COMPONENT_EXTENDED_OPERATOR. */ + struct + { + /* Number of arguments. */ + int args; + /* Name. */ + struct demangle_component *name; + } s_extended_operator; + + /* For DEMANGLE_COMPONENT_FIXED_TYPE. */ + struct + { + /* The length, indicated by a C integer type name. */ + struct demangle_component *length; + /* _Accum or _Fract? */ + short accum; + /* Saturating or not? */ + short sat; + } s_fixed; + + /* For DEMANGLE_COMPONENT_CTOR. */ + struct + { + /* Kind of constructor. */ + enum gnu_v3_ctor_kinds kind; + /* Name. */ + struct demangle_component *name; + } s_ctor; + + /* For DEMANGLE_COMPONENT_DTOR. */ + struct + { + /* Kind of destructor. */ + enum gnu_v3_dtor_kinds kind; + /* Name. */ + struct demangle_component *name; + } s_dtor; + + /* For DEMANGLE_COMPONENT_BUILTIN_TYPE. */ + struct + { + /* Builtin type. */ + const struct demangle_builtin_type_info *type; + } s_builtin; + + /* For DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE. */ + struct + { + /* Builtin type. */ + const struct demangle_builtin_type_info *type; + short arg; + char suffix; + } s_extended_builtin; + + /* For DEMANGLE_COMPONENT_SUB_STD. */ + struct + { + /* Standard substitution string. */ + const char* string; + /* Length of string. */ + int len; + } s_string; + + /* For DEMANGLE_COMPONENT_*_PARAM. */ + struct + { + /* Parameter index. */ + long number; + } s_number; + + /* For DEMANGLE_COMPONENT_CHARACTER. */ + struct + { + int character; + } s_character; + + /* For other types. */ + struct + { + /* Left (or only) subtree. */ + struct demangle_component *left; + /* Right subtree. */ + struct demangle_component *right; + } s_binary; + + struct + { + /* subtree, same place as d_left. */ + struct demangle_component *sub; + /* integer. */ + int num; + } s_unary_num; + + } u; +}; + +/* People building mangled trees are expected to allocate instances of + struct demangle_component themselves. They can then call one of + the following functions to fill them in. */ + +/* Fill in most component types with a left subtree and a right + subtree. Returns non-zero on success, zero on failure, such as an + unrecognized or inappropriate component type. */ + +extern int +cplus_demangle_fill_component (struct demangle_component *fill, + enum demangle_component_type, + struct demangle_component *left, + struct demangle_component *right); + +/* Fill in a DEMANGLE_COMPONENT_NAME. Returns non-zero on success, + zero for bad arguments. */ + +extern int +cplus_demangle_fill_name (struct demangle_component *fill, + const char *, int); + +/* Fill in a DEMANGLE_COMPONENT_BUILTIN_TYPE, using the name of the + builtin type (e.g., "int", etc.). Returns non-zero on success, + zero if the type is not recognized. */ + +extern int +cplus_demangle_fill_builtin_type (struct demangle_component *fill, + const char *type_name); + +/* Fill in a DEMANGLE_COMPONENT_OPERATOR, using the name of the + operator and the number of arguments which it takes (the latter is + used to disambiguate operators which can be both binary and unary, + such as '-'). Returns non-zero on success, zero if the operator is + not recognized. */ + +extern int +cplus_demangle_fill_operator (struct demangle_component *fill, + const char *opname, int args); + +/* Fill in a DEMANGLE_COMPONENT_EXTENDED_OPERATOR, providing the + number of arguments and the name. Returns non-zero on success, + zero for bad arguments. */ + +extern int +cplus_demangle_fill_extended_operator (struct demangle_component *fill, + int numargs, + struct demangle_component *nm); + +/* Fill in a DEMANGLE_COMPONENT_CTOR. Returns non-zero on success, + zero for bad arguments. */ + +extern int +cplus_demangle_fill_ctor (struct demangle_component *fill, + enum gnu_v3_ctor_kinds kind, + struct demangle_component *name); + +/* Fill in a DEMANGLE_COMPONENT_DTOR. Returns non-zero on success, + zero for bad arguments. */ + +extern int +cplus_demangle_fill_dtor (struct demangle_component *fill, + enum gnu_v3_dtor_kinds kind, + struct demangle_component *name); + +/* This function translates a mangled name into a struct + demangle_component tree. The first argument is the mangled name. + The second argument is DMGL_* options. This returns a pointer to a + tree on success, or NULL on failure. On success, the third + argument is set to a block of memory allocated by malloc. This + block should be passed to free when the tree is no longer + needed. */ + +extern struct demangle_component * +cplus_demangle_v3_components (const char *mangled, int options, void **mem); + +/* This function takes a struct demangle_component tree and returns + the corresponding demangled string. The first argument is DMGL_* + options. The second is the tree to demangle. The third is a guess + at the length of the demangled string, used to initially allocate + the return buffer. The fourth is a pointer to a size_t. On + success, this function returns a buffer allocated by malloc(), and + sets the size_t pointed to by the fourth argument to the size of + the allocated buffer (not the length of the returned string). On + failure, this function returns NULL, and sets the size_t pointed to + by the fourth argument to 0 for an invalid tree, or to 1 for a + memory allocation error. */ + +extern char * +cplus_demangle_print (int options, + struct demangle_component *tree, + int estimated_length, + size_t *p_allocated_size); + +/* This function takes a struct demangle_component tree and passes back + a demangled string in one or more calls to a callback function. + The first argument is DMGL_* options. The second is the tree to + demangle. The third is a pointer to a callback function; on each call + this receives an element of the demangled string, its length, and an + opaque value. The fourth is the opaque value passed to the callback. + The callback is called once or more to return the full demangled + string. The demangled element string is always nul-terminated, though + its length is also provided for convenience. In contrast to + cplus_demangle_print(), this function does not allocate heap memory + to grow output strings (except perhaps where alloca() is implemented + by malloc()), and so is normally safe for use where the heap has been + corrupted. On success, this function returns 1; on failure, 0. */ + +extern int +cplus_demangle_print_callback (int options, + struct demangle_component *tree, + demangle_callbackref callback, void *opaque); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* DEMANGLE_H */ diff --git a/3rdparty/demangler/include/dyn-string.h b/3rdparty/demangler/include/dyn-string.h new file mode 100644 index 0000000000..20750d2cdc --- /dev/null +++ b/3rdparty/demangler/include/dyn-string.h @@ -0,0 +1,72 @@ +/* An abstract string datatype. + Copyright (C) 1998-2023 Free Software Foundation, Inc. + Contributed by Mark Mitchell (mark@markmitchell.com). + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even 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 GCC; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#ifndef DYN_STRING_H +#define DYN_STRING_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct dyn_string +{ + int allocated; /* The amount of space allocated for the string. */ + int length; /* The actual length of the string. */ + char *s; /* The string itself, NUL-terminated. */ +}* dyn_string_t; + +/* The length STR, in bytes, not including the terminating NUL. */ +#define dyn_string_length(STR) \ + ((STR)->length) + +/* The NTBS in which the contents of STR are stored. */ +#define dyn_string_buf(STR) \ + ((STR)->s) + +/* Compare DS1 to DS2 with strcmp. */ +#define dyn_string_compare(DS1, DS2) \ + (strcmp ((DS1)->s, (DS2)->s)) + + +extern int dyn_string_init (struct dyn_string *, int); +extern dyn_string_t dyn_string_new (int); +extern void dyn_string_delete (dyn_string_t); +extern char *dyn_string_release (dyn_string_t); +extern dyn_string_t dyn_string_resize (dyn_string_t, int); +extern void dyn_string_clear (dyn_string_t); +extern int dyn_string_copy (dyn_string_t, dyn_string_t); +extern int dyn_string_copy_cstr (dyn_string_t, const char *); +extern int dyn_string_prepend (dyn_string_t, dyn_string_t); +extern int dyn_string_prepend_cstr (dyn_string_t, const char *); +extern int dyn_string_insert (dyn_string_t, int, dyn_string_t); +extern int dyn_string_insert_cstr (dyn_string_t, int, const char *); +extern int dyn_string_insert_char (dyn_string_t, int, int); +extern int dyn_string_append (dyn_string_t, dyn_string_t); +extern int dyn_string_append_cstr (dyn_string_t, const char *); +extern int dyn_string_append_char (dyn_string_t, int); +extern int dyn_string_substring (dyn_string_t, dyn_string_t, int, int); +extern int dyn_string_eq (dyn_string_t, dyn_string_t); + +#ifdef __cplusplus +} +#endif + +#endif /* !defined (DYN_STRING_H) */ diff --git a/3rdparty/demangler/include/environ.h b/3rdparty/demangler/include/environ.h new file mode 100644 index 0000000000..9e1dbd119b --- /dev/null +++ b/3rdparty/demangler/include/environ.h @@ -0,0 +1,35 @@ +/* Declare the environ system variable. + Copyright (C) 2015-2023 Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty 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. + +Libiberty is distributed in the hope that 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 libiberty; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* On OSX, the environ variable can be used directly in the code of an + executable, but cannot be used in the code of a shared library (such as + GCC's liblto_plugin, which links in libiberty code). Instead, the + function _NSGetEnviron can be called to get the address of environ. */ + +#ifndef HAVE_ENVIRON_DECL +# ifdef __APPLE__ +# include +# define environ (*_NSGetEnviron ()) +# else +# ifndef environ +extern char **environ; +# endif +# endif +# define HAVE_ENVIRON_DECL +#endif diff --git a/3rdparty/demangler/include/getopt.h b/3rdparty/demangler/include/getopt.h new file mode 100644 index 0000000000..80ce0d31cb --- /dev/null +++ b/3rdparty/demangler/include/getopt.h @@ -0,0 +1,143 @@ +/* Declarations for getopt. + Copyright (C) 1989-2023 Free Software Foundation, Inc. + + NOTE: The canonical source of this file is maintained with the GNU C Library. + Bugs can be reported to bug-glibc@gnu.org. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, 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. */ + +#ifndef _GETOPT_H +#define _GETOPT_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +extern char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int opterr; + +/* Set to an option character which was unrecognized. */ + +extern int optopt; + +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ +#if defined (__STDC__) && __STDC__ + const char *name; +#else + char *name; +#endif + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct option'. */ + +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +#if defined (__STDC__) && __STDC__ +/* HAVE_DECL_* is a three-state macro: undefined, 0 or 1. If it is + undefined, we haven't run the autoconf check so provide the + declaration without arguments. If it is 0, we checked and failed + to find the declaration so provide a fully prototyped one. If it + is 1, we found it so don't provide any declaration at all. */ +#if !HAVE_DECL_GETOPT +#if defined (__GNU_LIBRARY__) || defined (HAVE_DECL_GETOPT) +/* Many other libraries have conflicting prototypes for getopt, with + differences in the consts, in unistd.h. To avoid compilation + errors, only prototype getopt for the GNU C library. */ +extern int getopt (int argc, char *const *argv, const char *shortopts); +#else +#ifndef __cplusplus +extern int getopt (); +#endif /* __cplusplus */ +#endif +#endif /* !HAVE_DECL_GETOPT */ + +extern int getopt_long (int argc, char *const *argv, const char *shortopts, + const struct option *longopts, int *longind); +extern int getopt_long_only (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind); + +/* Internal only. Users should not call this directly. */ +extern int _getopt_internal (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind, + int long_only); +#else /* not __STDC__ */ +extern int getopt (); +extern int getopt_long (); +extern int getopt_long_only (); + +extern int _getopt_internal (); +#endif /* __STDC__ */ + +#ifdef __cplusplus +} +#endif + +#endif /* getopt.h */ diff --git a/3rdparty/demangler/include/libiberty.h b/3rdparty/demangler/include/libiberty.h new file mode 100644 index 0000000000..1d5c779fcf --- /dev/null +++ b/3rdparty/demangler/include/libiberty.h @@ -0,0 +1,761 @@ +/* Function declarations for libiberty. + + Copyright (C) 1997-2023 Free Software Foundation, Inc. + + Note - certain prototypes declared in this header file are for + functions whoes implementation copyright does not belong to the + FSF. Those prototypes are present in this file for reference + purposes only and their presence in this file should not construed + as an indication of ownership by the FSF of the implementation of + those functions in any way or form whatsoever. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + 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. + + Written by Cygnus Support, 1994. + + The libiberty library provides a number of functions which are + missing on some operating systems. We do not declare those here, + to avoid conflicts with the system header files on operating + systems that do support those functions. In this file we only + declare those functions which are specific to libiberty. */ + +#ifndef LIBIBERTY_H +#define LIBIBERTY_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ansidecl.h" + +/* Get a definition for size_t. */ +#include +/* Get a definition for va_list. */ +#include + +#include + +/* If the OS supports it, ensure that the supplied stream is setup to + avoid any multi-threaded locking. Otherwise leave the FILE pointer + unchanged. If the stream is NULL do nothing. */ + +extern void unlock_stream (FILE *); + +/* If the OS supports it, ensure that the standard I/O streams, stdin, + stdout and stderr are setup to avoid any multi-threaded locking. + Otherwise do nothing. */ + +extern void unlock_std_streams (void); + +/* Open and return a FILE pointer. If the OS supports it, ensure that + the stream is setup to avoid any multi-threaded locking. Otherwise + return the FILE pointer unchanged. */ + +extern FILE *fopen_unlocked (const char *, const char *); +extern FILE *fdopen_unlocked (int, const char *); +extern FILE *freopen_unlocked (const char *, const char *, FILE *); + +/* Build an argument vector from a string. Allocates memory using + malloc. Use freeargv to free the vector. */ + +extern char **buildargv (const char *) ATTRIBUTE_MALLOC; + +/* Free a vector returned by buildargv. */ + +extern void freeargv (char **); + +/* Duplicate an argument vector. Allocates memory using malloc. Use + freeargv to free the vector. */ + +extern char **dupargv (char * const *) ATTRIBUTE_MALLOC; + +/* Expand "@file" arguments in argv. */ + +extern void expandargv (int *, char ***); + +/* Write argv to an @-file, inserting necessary quoting. */ + +extern int writeargv (char * const *, FILE *); + +/* Return the number of elements in argv. */ + +extern int countargv (char * const *); + +/* Return the last component of a path name. Note that we can't use a + prototype here because the parameter is declared inconsistently + across different systems, sometimes as "char *" and sometimes as + "const char *" */ + +/* HAVE_DECL_* is a three-state macro: undefined, 0 or 1. If it is + undefined, we haven't run the autoconf check so provide the + declaration without arguments. If it is 0, we checked and failed + to find the declaration so provide a fully prototyped one. If it + is 1, we found it so don't provide any declaration at all. */ +#if !HAVE_DECL_BASENAME +#if defined (__GNU_LIBRARY__ ) || defined (__linux__) \ + || defined (__FreeBSD__) || defined (__OpenBSD__) || defined (__NetBSD__) \ + || defined (__CYGWIN__) || defined (__CYGWIN32__) || defined (__MINGW32__) \ + || defined (__DragonFly__) || defined (HAVE_DECL_BASENAME) +extern char *basename (const char *) ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_NONNULL(1); +#else +/* Do not allow basename to be used if there is no prototype seen. We + either need to use the above prototype or have one from + autoconf which would result in HAVE_DECL_BASENAME being set. */ +#define basename basename_cannot_be_used_without_a_prototype +#endif +#endif + +/* A well-defined basename () that is always compiled in. */ + +extern const char *lbasename (const char *) ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_NONNULL(1); + +/* Same, but assumes DOS semantics (drive name, backslash is also a + dir separator) regardless of host. */ + +extern const char *dos_lbasename (const char *) ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_NONNULL(1); + +/* Same, but assumes Unix semantics (absolute paths always start with + a slash, only forward slash is accepted as dir separator) + regardless of host. */ + +extern const char *unix_lbasename (const char *) ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_NONNULL(1); + +/* A well-defined realpath () that is always compiled in. */ + +extern char *lrealpath (const char *); + +/* Return true when FD file descriptor exists. */ + +extern int is_valid_fd (int fd); + +/* Concatenate an arbitrary number of strings. You must pass NULL as + the last argument of this function, to terminate the list of + strings. Allocates memory using xmalloc. */ + +extern char *concat (const char *, ...) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_SENTINEL; + +/* Concatenate an arbitrary number of strings. You must pass NULL as + the last argument of this function, to terminate the list of + strings. Allocates memory using xmalloc. The first argument is + not one of the strings to be concatenated, but if not NULL is a + pointer to be freed after the new string is created, similar to the + way xrealloc works. */ + +extern char *reconcat (char *, const char *, ...) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_SENTINEL; + +/* Determine the length of concatenating an arbitrary number of + strings. You must pass NULL as the last argument of this function, + to terminate the list of strings. */ + +extern unsigned long concat_length (const char *, ...) ATTRIBUTE_SENTINEL; + +/* Concatenate an arbitrary number of strings into a SUPPLIED area of + memory. You must pass NULL as the last argument of this function, + to terminate the list of strings. The supplied memory is assumed + to be large enough. */ + +extern char *concat_copy (char *, const char *, ...) ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_NONNULL(1) ATTRIBUTE_SENTINEL; + +/* Concatenate an arbitrary number of strings into a GLOBAL area of + memory. You must pass NULL as the last argument of this function, + to terminate the list of strings. The supplied memory is assumed + to be large enough. */ + +extern char *concat_copy2 (const char *, ...) ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_SENTINEL; + +/* This is the global area used by concat_copy2. */ + +extern char *libiberty_concat_ptr; + +/* Concatenate an arbitrary number of strings. You must pass NULL as + the last argument of this function, to terminate the list of + strings. Allocates memory using alloca. The arguments are + evaluated twice! */ +#define ACONCAT(ACONCAT_PARAMS) \ + (libiberty_concat_ptr = (char *) alloca (concat_length ACONCAT_PARAMS + 1), \ + concat_copy2 ACONCAT_PARAMS) + +/* Check whether two file descriptors refer to the same file. */ + +extern int fdmatch (int fd1, int fd2); + +/* Return the position of the first bit set in the argument. */ +/* Prototypes vary from system to system, so we only provide a + prototype on systems where we know that we need it. */ +#if defined (HAVE_DECL_FFS) && !HAVE_DECL_FFS +extern int ffs(int); +#endif + +/* Get the working directory. The result is cached, so don't call + chdir() between calls to getpwd(). */ + +extern char * getpwd (void); + +/* Get the current time. */ +/* Prototypes vary from system to system, so we only provide a + prototype on systems where we know that we need it. */ +#ifdef __MINGW32__ +/* Forward declaration to avoid #include . */ +struct timeval; +extern int gettimeofday (struct timeval *, void *); +#endif + +/* Get the amount of time the process has run, in microseconds. */ + +extern long get_run_time (void); + +/* Generate a relocated path to some installation directory. Allocates + return value using malloc. */ + +extern char *make_relative_prefix (const char *, const char *, + const char *) ATTRIBUTE_MALLOC; + +/* Generate a relocated path to some installation directory without + attempting to follow any soft links. Allocates + return value using malloc. */ + +extern char *make_relative_prefix_ignore_links (const char *, const char *, + const char *) ATTRIBUTE_MALLOC; + +/* Returns a pointer to a directory path suitable for creating temporary + files in. */ + +extern const char *choose_tmpdir (void) ATTRIBUTE_RETURNS_NONNULL; + +/* Choose a temporary directory to use for scratch files. */ + +extern char *choose_temp_base (void) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL; + +/* Return a temporary file name or NULL if unable to create one. */ + +extern char *make_temp_file (const char *) ATTRIBUTE_MALLOC; + +/* Return a temporary file name with given PREFIX and SUFFIX + or NULL if unable to create one. */ + +extern char *make_temp_file_with_prefix (const char *, const char *) ATTRIBUTE_MALLOC; + +/* Remove a link to a file unless it is special. */ + +extern int unlink_if_ordinary (const char *); + +/* Allocate memory filled with spaces. Allocates using malloc. */ + +extern const char *spaces (int count); + +/* Return the maximum error number for which strerror will return a + string. */ + +extern int errno_max (void); + +/* Return the name of an errno value (e.g., strerrno (EINVAL) returns + "EINVAL"). */ + +extern const char *strerrno (int); + +/* Given the name of an errno value, return the value. */ + +extern int strtoerrno (const char *); + +/* ANSI's strerror(), but more robust. */ + +extern char *xstrerror (int) ATTRIBUTE_RETURNS_NONNULL; + +/* Return the maximum signal number for which strsignal will return a + string. */ + +extern int signo_max (void); + +/* Return a signal message string for a signal number + (e.g., strsignal (SIGHUP) returns something like "Hangup"). */ +/* This is commented out as it can conflict with one in system headers. + We still document its existence though. */ + +/*extern const char *strsignal (int);*/ + +/* Return the name of a signal number (e.g., strsigno (SIGHUP) returns + "SIGHUP"). */ + +extern const char *strsigno (int); + +/* Given the name of a signal, return its number. */ + +extern int strtosigno (const char *); + +/* Register a function to be run by xexit. Returns 0 on success. */ + +extern int xatexit (void (*fn) (void)); + +/* Exit, calling all the functions registered with xatexit. */ + +extern void xexit (int status) ATTRIBUTE_NORETURN; + +/* Set the program name used by xmalloc. */ + +extern void xmalloc_set_program_name (const char *); + +/* Report an allocation failure. */ +extern void xmalloc_failed (size_t) ATTRIBUTE_NORETURN; + +/* Allocate memory without fail. If malloc fails, this will print a + message to stderr (using the name set by xmalloc_set_program_name, + if any) and then call xexit. */ + +extern void *xmalloc (size_t) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_RESULT_SIZE_1 ATTRIBUTE_WARN_UNUSED_RESULT; + +/* Reallocate memory without fail. This works like xmalloc. Note, + realloc type functions are not suitable for attribute malloc since + they may return the same address across multiple calls. */ + +extern void *xrealloc (void *, size_t) ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_RESULT_SIZE_2 ATTRIBUTE_WARN_UNUSED_RESULT; + +/* Allocate memory without fail and set it to zero. This works like + xmalloc. */ + +extern void *xcalloc (size_t, size_t) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_RESULT_SIZE_1_2 ATTRIBUTE_WARN_UNUSED_RESULT; + +/* Copy a string into a memory buffer without fail. */ + +extern char *xstrdup (const char *) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_WARN_UNUSED_RESULT; + +/* Copy at most N characters from string into a buffer without fail. */ + +extern char *xstrndup (const char *, size_t) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_WARN_UNUSED_RESULT; + +/* Copy an existing memory buffer to a new memory buffer without fail. */ + +extern void *xmemdup (const void *, size_t, size_t) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_WARN_UNUSED_RESULT; + +/* Physical memory routines. Return values are in BYTES. */ +extern double physmem_total (void); +extern double physmem_available (void); + +/* Compute the 32-bit CRC of a block of memory. */ +extern unsigned int xcrc32 (const unsigned char *, int, unsigned int); + +/* These macros provide a K&R/C89/C++-friendly way of allocating structures + with nice encapsulation. The XDELETE*() macros are technically + superfluous, but provided here for symmetry. Using them consistently + makes it easier to update client code to use different allocators such + as new/delete and new[]/delete[]. */ + +/* Scalar allocators. */ + +#define XALLOCA(T) ((T *) alloca (sizeof (T))) +#define XNEW(T) ((T *) xmalloc (sizeof (T))) +#define XCNEW(T) ((T *) xcalloc (1, sizeof (T))) +#define XDUP(T, P) ((T *) xmemdup ((P), sizeof (T), sizeof (T))) +#define XDELETE(P) free ((void*) (P)) + +/* Array allocators. */ + +#define XALLOCAVEC(T, N) ((T *) alloca (sizeof (T) * (N))) +#define XNEWVEC(T, N) ((T *) xmalloc (sizeof (T) * (N))) +#define XCNEWVEC(T, N) ((T *) xcalloc ((N), sizeof (T))) +#define XDUPVEC(T, P, N) ((T *) xmemdup ((P), sizeof (T) * (N), sizeof (T) * (N))) +#define XRESIZEVEC(T, P, N) ((T *) xrealloc ((void *) (P), sizeof (T) * (N))) +#define XDELETEVEC(P) free ((void*) (P)) + +/* Allocators for variable-sized structures and raw buffers. */ + +#define XALLOCAVAR(T, S) ((T *) alloca ((S))) +#define XNEWVAR(T, S) ((T *) xmalloc ((S))) +#define XCNEWVAR(T, S) ((T *) xcalloc (1, (S))) +#define XDUPVAR(T, P, S1, S2) ((T *) xmemdup ((P), (S1), (S2))) +#define XRESIZEVAR(T, P, S) ((T *) xrealloc ((P), (S))) + +/* Type-safe obstack allocator. */ + +#define XOBNEW(O, T) ((T *) obstack_alloc ((O), sizeof (T))) +#define XOBNEWVEC(O, T, N) ((T *) obstack_alloc ((O), sizeof (T) * (N))) +#define XOBNEWVAR(O, T, S) ((T *) obstack_alloc ((O), (S))) +#define XOBFINISH(O, T) ((T) obstack_finish ((O))) + +/* hex character manipulation routines */ + +#define _hex_array_size 256 +#define _hex_bad 99 +extern const unsigned char _hex_value[_hex_array_size]; +extern void hex_init (void); +#define hex_p(c) (hex_value (c) != _hex_bad) +/* If you change this, note well: Some code relies on side effects in + the argument being performed exactly once. */ +#define hex_value(c) ((unsigned int) _hex_value[(unsigned char) (c)]) + +/* Flags for pex_init. These are bits to be or'ed together. */ + +/* Record subprocess times, if possible. */ +#define PEX_RECORD_TIMES 0x1 + +/* Use pipes for communication between processes, if possible. */ +#define PEX_USE_PIPES 0x2 + +/* Save files used for communication between processes. */ +#define PEX_SAVE_TEMPS 0x4 + +/* Max number of alloca bytes per call before we must switch to malloc. + + ?? Swiped from gnulib's regex_internal.h header. Is this actually + the case? This number seems arbitrary, though sane. + + The OS usually guarantees only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + allocate anything larger than 4096 bytes. Also care for the possibility + of a few compiler-allocated temporary stack slots. */ +#define MAX_ALLOCA_SIZE 4032 + +/* Prepare to execute one or more programs, with standard output of + each program fed to standard input of the next. + FLAGS As above. + PNAME The name of the program to report in error messages. + TEMPBASE A base name to use for temporary files; may be NULL to + use a random name. + Returns NULL on error. */ + +extern struct pex_obj *pex_init (int flags, const char *pname, + const char *tempbase) ATTRIBUTE_RETURNS_NONNULL; + +/* Flags for pex_run. These are bits to be or'ed together. */ + +/* Last program in pipeline. Standard output of program goes to + OUTNAME, or, if OUTNAME is NULL, to standard output of caller. Do + not set this if you want to call pex_read_output. After this is + set, pex_run may no longer be called with the same struct + pex_obj. */ +#define PEX_LAST 0x1 + +/* Search for program in executable search path. */ +#define PEX_SEARCH 0x2 + +/* OUTNAME is a suffix. */ +#define PEX_SUFFIX 0x4 + +/* Send program's standard error to standard output. */ +#define PEX_STDERR_TO_STDOUT 0x8 + +/* Input file should be opened in binary mode. This flag is ignored + on Unix. */ +#define PEX_BINARY_INPUT 0x10 + +/* Output file should be opened in binary mode. This flag is ignored + on Unix. For proper behaviour PEX_BINARY_INPUT and + PEX_BINARY_OUTPUT have to match appropriately--i.e., a call using + PEX_BINARY_OUTPUT should be followed by a call using + PEX_BINARY_INPUT. */ +#define PEX_BINARY_OUTPUT 0x20 + +/* Capture stderr to a pipe. The output can be read by + calling pex_read_err and reading from the returned + FILE object. This flag may be specified only for + the last program in a pipeline. + + This flag is supported only on Unix and Windows. */ +#define PEX_STDERR_TO_PIPE 0x40 + +/* Capture stderr in binary mode. This flag is ignored + on Unix. */ +#define PEX_BINARY_ERROR 0x80 + +/* Append stdout to existing file instead of truncating it. */ +#define PEX_STDOUT_APPEND 0x100 + +/* Thes same as PEX_STDOUT_APPEND, but for STDERR. */ +#define PEX_STDERR_APPEND 0x200 + +/* Execute one program. Returns NULL on success. On error returns an + error string (typically just the name of a system call); the error + string is statically allocated. + + OBJ Returned by pex_init. + + FLAGS As above. + + EXECUTABLE The program to execute. + + ARGV NULL terminated array of arguments to pass to the program. + + OUTNAME Sets the output file name as follows: + + PEX_SUFFIX set (OUTNAME may not be NULL): + TEMPBASE parameter to pex_init not NULL: + Output file name is the concatenation of TEMPBASE + and OUTNAME. + TEMPBASE is NULL: + Output file name is a random file name ending in + OUTNAME. + PEX_SUFFIX not set: + OUTNAME not NULL: + Output file name is OUTNAME. + OUTNAME NULL, TEMPBASE not NULL: + Output file name is randomly chosen using + TEMPBASE. + OUTNAME NULL, TEMPBASE NULL: + Output file name is randomly chosen. + + If PEX_LAST is not set, the output file name is the + name to use for a temporary file holding stdout, if + any (there will not be a file if PEX_USE_PIPES is set + and the system supports pipes). If a file is used, it + will be removed when no longer needed unless + PEX_SAVE_TEMPS is set. + + If PEX_LAST is set, and OUTNAME is not NULL, standard + output is written to the output file name. The file + will not be removed. If PEX_LAST and PEX_SUFFIX are + both set, TEMPBASE may not be NULL. + + ERRNAME If not NULL, this is the name of a file to which + standard error is written. If NULL, standard error of + the program is standard error of the caller. + + ERR On an error return, *ERR is set to an errno value, or + to 0 if there is no relevant errno. +*/ + +extern const char *pex_run (struct pex_obj *obj, int flags, + const char *executable, char * const *argv, + const char *outname, const char *errname, + int *err); + +/* As for pex_run (), but takes an extra parameter to enable the + environment for the child process to be specified. + + ENV The environment for the child process, specified as + an array of character pointers. Each element of the + array should point to a string of the form VAR=VALUE, + with the exception of the last element which must be + a null pointer. +*/ + +extern const char *pex_run_in_environment (struct pex_obj *obj, int flags, + const char *executable, + char * const *argv, + char * const *env, + const char *outname, + const char *errname, int *err); + +/* Return a stream for a temporary file to pass to the first program + in the pipeline as input. The file name is chosen as for pex_run. + pex_run closes the file automatically; don't close it yourself. */ + +extern FILE *pex_input_file (struct pex_obj *obj, int flags, + const char *in_name); + +/* Return a stream for a pipe connected to the standard input of the + first program in the pipeline. You must have passed + `PEX_USE_PIPES' to `pex_init'. Close the returned stream + yourself. */ + +extern FILE *pex_input_pipe (struct pex_obj *obj, int binary); + +/* Read the standard output of the last program to be executed. + pex_run cannot be called after this. BINARY should be non-zero if + the file should be opened in binary mode; this is ignored on Unix. + Returns NULL on error. Don't call fclose on the returned FILE; it + will be closed by pex_free. */ + +extern FILE *pex_read_output (struct pex_obj *, int binary); + +/* Read the standard error of the last program to be executed. + pex_run cannot be called after this. BINARY should be non-zero if + the file should be opened in binary mode; this is ignored on Unix. + Returns NULL on error. Don't call fclose on the returned FILE; it + will be closed by pex_free. */ + +extern FILE *pex_read_err (struct pex_obj *, int binary); + +/* Return exit status of all programs in VECTOR. COUNT indicates the + size of VECTOR. The status codes in the vector are in the order of + the calls to pex_run. Returns 0 on error, 1 on success. */ + +extern int pex_get_status (struct pex_obj *, int count, int *vector); + +/* Return times of all programs in VECTOR. COUNT indicates the size + of VECTOR. struct pex_time is really just struct timeval, but that + is not portable to all systems. Returns 0 on error, 1 on + success. */ + +struct pex_time +{ + unsigned long user_seconds; + unsigned long user_microseconds; + unsigned long system_seconds; + unsigned long system_microseconds; +}; + +extern int pex_get_times (struct pex_obj *, int count, + struct pex_time *vector); + +/* Clean up a pex_obj. If you have not called pex_get_times or + pex_get_status, this will try to kill the subprocesses. */ + +extern void pex_free (struct pex_obj *); + +/* Just execute one program. Return value is as for pex_run. + FLAGS Combination of PEX_SEARCH and PEX_STDERR_TO_STDOUT. + EXECUTABLE As for pex_run. + ARGV As for pex_run. + PNAME As for pex_init. + OUTNAME As for pex_run when PEX_LAST is set. + ERRNAME As for pex_run. + STATUS Set to exit status on success. + ERR As for pex_run. +*/ + +extern const char *pex_one (int flags, const char *executable, + char * const *argv, const char *pname, + const char *outname, const char *errname, + int *status, int *err); + +/* pexecute and pwait are the old pexecute interface, still here for + backward compatibility. Don't use these for new code. Instead, + use pex_init/pex_run/pex_get_status/pex_free, or pex_one. */ + +/* Definitions used by the pexecute routine. */ + +#define PEXECUTE_FIRST 1 +#define PEXECUTE_LAST 2 +#define PEXECUTE_ONE (PEXECUTE_FIRST + PEXECUTE_LAST) +#define PEXECUTE_SEARCH 4 +#define PEXECUTE_VERBOSE 8 + +/* Execute a program. */ + +extern int pexecute (const char *, char * const *, const char *, + const char *, char **, char **, int); + +/* Wait for pexecute to finish. */ + +extern int pwait (int, int *, int); + +/* Like bsearch, but takes and passes on an argument like qsort_r. */ + +extern void *bsearch_r (const void *, const void *, + size_t, size_t, + int (*)(const void *, const void *, void *), + void *); + +#if defined(HAVE_DECL_ASPRINTF) && !HAVE_DECL_ASPRINTF +/* Like sprintf but provides a pointer to malloc'd storage, which must + be freed by the caller. */ + +extern int asprintf (char **, const char *, ...) ATTRIBUTE_PRINTF_2; +#endif + +/* Like asprintf but allocates memory without fail. This works like + xmalloc. */ + +extern char *xasprintf (const char *, ...) ATTRIBUTE_MALLOC ATTRIBUTE_PRINTF_1; + +#if defined(HAVE_DECL_VASPRINTF) && !HAVE_DECL_VASPRINTF +/* Like vsprintf but provides a pointer to malloc'd storage, which + must be freed by the caller. */ + +extern int vasprintf (char **, const char *, va_list) ATTRIBUTE_PRINTF(2,0); +#endif + +/* Like vasprintf but allocates memory without fail. This works like + xmalloc. */ + +extern char *xvasprintf (const char *, va_list) ATTRIBUTE_MALLOC ATTRIBUTE_PRINTF(1,0); + +#if defined(HAVE_DECL_SNPRINTF) && !HAVE_DECL_SNPRINTF +/* Like sprintf but prints at most N characters. */ +extern int snprintf (char *, size_t, const char *, ...) ATTRIBUTE_PRINTF_3; +#endif + +#if defined(HAVE_DECL_VSNPRINTF) && !HAVE_DECL_VSNPRINTF +/* Like vsprintf but prints at most N characters. */ +extern int vsnprintf (char *, size_t, const char *, va_list) ATTRIBUTE_PRINTF(3,0); +#endif + +#if defined (HAVE_DECL_STRNLEN) && !HAVE_DECL_STRNLEN +extern size_t strnlen (const char *, size_t); +#endif + +#if defined(HAVE_DECL_STRVERSCMP) && !HAVE_DECL_STRVERSCMP +/* Compare version strings. */ +extern int strverscmp (const char *, const char *); +#endif + +#if defined(HAVE_DECL_STRTOL) && !HAVE_DECL_STRTOL +extern long int strtol (const char *nptr, + char **endptr, int base); +#endif + +#if defined(HAVE_DECL_STRTOUL) && !HAVE_DECL_STRTOUL +extern unsigned long int strtoul (const char *nptr, + char **endptr, int base); +#endif + +#if defined(HAVE_LONG_LONG) && defined(HAVE_DECL_STRTOLL) && !HAVE_DECL_STRTOLL +__extension__ +extern long long int strtoll (const char *nptr, + char **endptr, int base); +#endif + +#if defined(HAVE_LONG_LONG) && defined(HAVE_DECL_STRTOULL) && !HAVE_DECL_STRTOULL +__extension__ +extern unsigned long long int strtoull (const char *nptr, + char **endptr, int base); +#endif + +/* Set the title of a process */ +extern void setproctitle (const char *name, ...); + +/* Increase stack limit if possible. */ +extern void stack_limit_increase (unsigned long); + +#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) + +/* Drastically simplified alloca configurator. If we're using GCC, + we use __builtin_alloca; otherwise we use the C alloca. The C + alloca is always available. You can override GCC by defining + USE_C_ALLOCA yourself. The canonical autoconf macro C_ALLOCA is + also set/unset as it is often used to indicate whether code needs + to call alloca(0). */ +extern void *C_alloca (size_t) ATTRIBUTE_MALLOC; +#undef alloca +#if GCC_VERSION >= 2000 && !defined USE_C_ALLOCA +# define alloca(x) __builtin_alloca(x) +# undef C_ALLOCA +# define ASTRDUP(X) \ + (__extension__ ({ const char *const libiberty_optr = (X); \ + const unsigned long libiberty_len = strlen (libiberty_optr) + 1; \ + char *const libiberty_nptr = (char *) alloca (libiberty_len); \ + (char *) memcpy (libiberty_nptr, libiberty_optr, libiberty_len); })) +#else +# define alloca(x) C_alloca(x) +# undef USE_C_ALLOCA +# define USE_C_ALLOCA 1 +# undef C_ALLOCA +# define C_ALLOCA 1 +extern const char *libiberty_optr; +extern char *libiberty_nptr; +extern unsigned long libiberty_len; +# define ASTRDUP(X) \ + (libiberty_optr = (X), \ + libiberty_len = strlen (libiberty_optr) + 1, \ + libiberty_nptr = (char *) alloca (libiberty_len), \ + (char *) memcpy (libiberty_nptr, libiberty_optr, libiberty_len)) +#endif + +#ifdef __cplusplus +} +#endif + + +#endif /* ! defined (LIBIBERTY_H) */ diff --git a/3rdparty/demangler/include/safe-ctype.h b/3rdparty/demangler/include/safe-ctype.h new file mode 100644 index 0000000000..a3cb1858ef --- /dev/null +++ b/3rdparty/demangler/include/safe-ctype.h @@ -0,0 +1,150 @@ +/* replacement macros. + + Copyright (C) 2000-2023 Free Software Foundation, Inc. + Contributed by Zack Weinberg . + +This file is part of the libiberty library. +Libiberty 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. + +Libiberty is distributed in the hope that 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 libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* This is a compatible replacement of the standard C library's + with the following properties: + + - Implements all isxxx() macros required by C99. + - Also implements some character classes useful when + parsing C-like languages. + - Does not change behavior depending on the current locale. + - Behaves properly for all values in the range of a signed or + unsigned char. + + To avoid conflicts, this header defines the isxxx functions in upper + case, e.g. ISALPHA not isalpha. */ + +#ifndef SAFE_CTYPE_H +#define SAFE_CTYPE_H + +/* Determine host character set. */ +#define HOST_CHARSET_UNKNOWN 0 +#define HOST_CHARSET_ASCII 1 +#define HOST_CHARSET_EBCDIC 2 + +#if '\n' == 0x0A && ' ' == 0x20 && '0' == 0x30 \ + && 'A' == 0x41 && 'a' == 0x61 && '!' == 0x21 +# define HOST_CHARSET HOST_CHARSET_ASCII +#else +# if '\n' == 0x15 && ' ' == 0x40 && '0' == 0xF0 \ + && 'A' == 0xC1 && 'a' == 0x81 && '!' == 0x5A +# define HOST_CHARSET HOST_CHARSET_EBCDIC +# else +# define HOST_CHARSET HOST_CHARSET_UNKNOWN +# endif +#endif + +/* Categories. */ + +enum { + /* In C99 */ + _sch_isblank = 0x0001, /* space \t */ + _sch_iscntrl = 0x0002, /* nonprinting characters */ + _sch_isdigit = 0x0004, /* 0-9 */ + _sch_islower = 0x0008, /* a-z */ + _sch_isprint = 0x0010, /* any printing character including ' ' */ + _sch_ispunct = 0x0020, /* all punctuation */ + _sch_isspace = 0x0040, /* space \t \n \r \f \v */ + _sch_isupper = 0x0080, /* A-Z */ + _sch_isxdigit = 0x0100, /* 0-9A-Fa-f */ + + /* Extra categories useful to cpplib. */ + _sch_isidst = 0x0200, /* A-Za-z_ */ + _sch_isvsp = 0x0400, /* \n \r */ + _sch_isnvsp = 0x0800, /* space \t \f \v \0 */ + + /* Combinations of the above. */ + _sch_isalpha = _sch_isupper|_sch_islower, /* A-Za-z */ + _sch_isalnum = _sch_isalpha|_sch_isdigit, /* A-Za-z0-9 */ + _sch_isidnum = _sch_isidst|_sch_isdigit, /* A-Za-z0-9_ */ + _sch_isgraph = _sch_isalnum|_sch_ispunct, /* isprint and not space */ + _sch_iscppsp = _sch_isvsp|_sch_isnvsp, /* isspace + \0 */ + _sch_isbasic = _sch_isprint|_sch_iscppsp /* basic charset of ISO C + (plus ` and @) */ +}; + +/* Character classification. */ +extern const unsigned short _sch_istable[256]; + +#define _sch_test(c, bit) (_sch_istable[(c) & 0xff] & (unsigned short)(bit)) + +#define ISALPHA(c) _sch_test(c, _sch_isalpha) +#define ISALNUM(c) _sch_test(c, _sch_isalnum) +#define ISBLANK(c) _sch_test(c, _sch_isblank) +#define ISCNTRL(c) _sch_test(c, _sch_iscntrl) +#define ISDIGIT(c) _sch_test(c, _sch_isdigit) +#define ISGRAPH(c) _sch_test(c, _sch_isgraph) +#define ISLOWER(c) _sch_test(c, _sch_islower) +#define ISPRINT(c) _sch_test(c, _sch_isprint) +#define ISPUNCT(c) _sch_test(c, _sch_ispunct) +#define ISSPACE(c) _sch_test(c, _sch_isspace) +#define ISUPPER(c) _sch_test(c, _sch_isupper) +#define ISXDIGIT(c) _sch_test(c, _sch_isxdigit) + +#define ISIDNUM(c) _sch_test(c, _sch_isidnum) +#define ISIDST(c) _sch_test(c, _sch_isidst) +#define IS_ISOBASIC(c) _sch_test(c, _sch_isbasic) +#define IS_VSPACE(c) _sch_test(c, _sch_isvsp) +#define IS_NVSPACE(c) _sch_test(c, _sch_isnvsp) +#define IS_SPACE_OR_NUL(c) _sch_test(c, _sch_iscppsp) + +/* Character transformation. */ +extern const unsigned char _sch_toupper[256]; +extern const unsigned char _sch_tolower[256]; +#define TOUPPER(c) _sch_toupper[(c) & 0xff] +#define TOLOWER(c) _sch_tolower[(c) & 0xff] + +/* Prevent the users of safe-ctype.h from accidently using the routines + from ctype.h. Initially, the approach was to produce an error when + detecting that ctype.h has been included. But this was causing + trouble as ctype.h might get indirectly included as a result of + including another system header (for instance gnulib's stdint.h). + So we include ctype.h here and then immediately redefine its macros. */ + +#include +#undef isalpha +#define isalpha(c) do_not_use_isalpha_with_safe_ctype +#undef isalnum +#define isalnum(c) do_not_use_isalnum_with_safe_ctype +#undef iscntrl +#define iscntrl(c) do_not_use_iscntrl_with_safe_ctype +#undef isdigit +#define isdigit(c) do_not_use_isdigit_with_safe_ctype +#undef isgraph +#define isgraph(c) do_not_use_isgraph_with_safe_ctype +#undef islower +#define islower(c) do_not_use_islower_with_safe_ctype +#undef isprint +#define isprint(c) do_not_use_isprint_with_safe_ctype +#undef ispunct +#define ispunct(c) do_not_use_ispunct_with_safe_ctype +#undef isspace +#define isspace(c) do_not_use_isspace_with_safe_ctype +#undef isupper +#define isupper(c) do_not_use_isupper_with_safe_ctype +#undef isxdigit +#define isxdigit(c) do_not_use_isxdigit_with_safe_ctype +#undef toupper +#define toupper(c) do_not_use_toupper_with_safe_ctype +#undef tolower +#define tolower(c) do_not_use_tolower_with_safe_ctype + +#endif /* SAFE_CTYPE_H */ diff --git a/3rdparty/demangler/src/alloca.c b/3rdparty/demangler/src/alloca.c new file mode 100644 index 0000000000..b75f7560f9 --- /dev/null +++ b/3rdparty/demangler/src/alloca.c @@ -0,0 +1,483 @@ +/* alloca.c -- allocate automatically reclaimed memory + (Mostly) portable public-domain implementation -- D A Gwyn + + This implementation of the PWB library alloca function, + which is used to allocate space off the run-time stack so + that it is automatically reclaimed upon procedure exit, + was inspired by discussions with J. Q. Johnson of Cornell. + J.Otto Tennant contributed the Cray support. + + There are some preprocessor constants that can + be defined when compiling for your specific system, for + improved efficiency; however, the defaults should be okay. + + The general concept of this implementation is to keep + track of all alloca-allocated blocks, and reclaim any + that are found to be deeper in the stack than the current + invocation. This heuristic does not reclaim storage as + soon as it becomes invalid, but it will do so eventually. + + As a special case, alloca(0) reclaims storage without + allocating any. It is a good idea to use alloca(0) in + your main control loop, etc. to force garbage collection. */ + +/* + +@deftypefn Replacement void* alloca (size_t @var{size}) + +This function allocates memory which will be automatically reclaimed +after the procedure exits. The @libib{} implementation does not free +the memory immediately but will do so eventually during subsequent +calls to this function. Memory is allocated using @code{xmalloc} under +normal circumstances. + +The header file @file{alloca-conf.h} can be used in conjunction with the +GNU Autoconf test @code{AC_FUNC_ALLOCA} to test for and properly make +available this function. The @code{AC_FUNC_ALLOCA} test requires that +client code use a block of preprocessor code to be safe (see the Autoconf +manual for more); this header incorporates that logic and more, including +the possibility of a GCC built-in function. + +@end deftypefn + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif + +/* These variables are used by the ASTRDUP implementation that relies + on C_alloca. */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ +const char *libiberty_optr; +char *libiberty_nptr; +unsigned long libiberty_len; +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +/* If your stack is a linked list of frames, you have to + provide an "address metric" ADDRESS_FUNCTION macro. */ + +#if defined (CRAY) && defined (CRAY_STACKSEG_END) +static long i00afunc (); +#define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg)) +#else +#define ADDRESS_FUNCTION(arg) &(arg) +#endif + +#ifndef NULL +#define NULL 0 +#endif + +/* Define STACK_DIRECTION if you know the direction of stack + growth for your system; otherwise it will be automatically + deduced at run-time. + + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown */ + +#ifndef STACK_DIRECTION +#define STACK_DIRECTION 0 /* Direction unknown. */ +#endif + +#if STACK_DIRECTION != 0 + +#define STACK_DIR STACK_DIRECTION /* Known at compile-time. */ + +#else /* STACK_DIRECTION == 0; need run-time code. */ + +static int stack_dir; /* 1 or -1 once known. */ +#define STACK_DIR stack_dir + +static void +find_stack_direction (void) +{ + static char *addr = NULL; /* Address of first `dummy', once known. */ + auto char dummy; /* To get stack address. */ + + if (addr == NULL) + { /* Initial entry. */ + addr = ADDRESS_FUNCTION (dummy); + + find_stack_direction (); /* Recurse once. */ + } + else + { + /* Second entry. */ + if (ADDRESS_FUNCTION (dummy) > addr) + stack_dir = 1; /* Stack grew upward. */ + else + stack_dir = -1; /* Stack grew downward. */ + } +} + +#endif /* STACK_DIRECTION == 0 */ + +/* An "alloca header" is used to: + (a) chain together all alloca'ed blocks; + (b) keep track of stack depth. + + It is very important that sizeof(header) agree with malloc + alignment chunk size. The following default should work okay. */ + +#ifndef ALIGN_SIZE +#define ALIGN_SIZE sizeof(double) +#endif + +typedef union hdr +{ + char align[ALIGN_SIZE]; /* To force sizeof(header). */ + struct + { + union hdr *next; /* For chaining headers. */ + char *deep; /* For stack depth measure. */ + } h; +} header; + +static header *last_alloca_header = NULL; /* -> last alloca header. */ + +/* Return a pointer to at least SIZE bytes of storage, + which will be automatically reclaimed upon exit from + the procedure that called alloca. Originally, this space + was supposed to be taken from the current stack frame of the + caller, but that method cannot be made to work for some + implementations of C, for example under Gould's UTX/32. */ + +/* @undocumented C_alloca */ + +void * +C_alloca (size_t size) +{ + auto char probe; /* Probes stack depth: */ + register char *depth = ADDRESS_FUNCTION (probe); + +#if STACK_DIRECTION == 0 + if (STACK_DIR == 0) /* Unknown growth direction. */ + find_stack_direction (); +#endif + + /* Reclaim garbage, defined as all alloca'd storage that + was allocated from deeper in the stack than currently. */ + + { + register header *hp; /* Traverses linked list. */ + + for (hp = last_alloca_header; hp != NULL;) + if ((STACK_DIR > 0 && hp->h.deep > depth) + || (STACK_DIR < 0 && hp->h.deep < depth)) + { + register header *np = hp->h.next; + + free ((void *) hp); /* Collect garbage. */ + + hp = np; /* -> next header. */ + } + else + break; /* Rest are not deeper. */ + + last_alloca_header = hp; /* -> last valid storage. */ + } + + if (size == 0) + return NULL; /* No allocation required. */ + + /* Allocate combined header + user data storage. */ + + { + register void *new_storage = XNEWVEC (char, sizeof (header) + size); + /* Address of header. */ + + if (new_storage == 0) + abort(); + + ((header *) new_storage)->h.next = last_alloca_header; + ((header *) new_storage)->h.deep = depth; + + last_alloca_header = (header *) new_storage; + + /* User storage begins just after header. */ + + return (void *) ((char *) new_storage + sizeof (header)); + } +} + +#if defined (CRAY) && defined (CRAY_STACKSEG_END) + +#ifdef DEBUG_I00AFUNC +#include +#endif + +#ifndef CRAY_STACK +#define CRAY_STACK +#ifndef CRAY2 +/* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */ +struct stack_control_header + { + long shgrow:32; /* Number of times stack has grown. */ + long shaseg:32; /* Size of increments to stack. */ + long shhwm:32; /* High water mark of stack. */ + long shsize:32; /* Current size of stack (all segments). */ + }; + +/* The stack segment linkage control information occurs at + the high-address end of a stack segment. (The stack + grows from low addresses to high addresses.) The initial + part of the stack segment linkage control information is + 0200 (octal) words. This provides for register storage + for the routine which overflows the stack. */ + +struct stack_segment_linkage + { + long ss[0200]; /* 0200 overflow words. */ + long sssize:32; /* Number of words in this segment. */ + long ssbase:32; /* Offset to stack base. */ + long:32; + long sspseg:32; /* Offset to linkage control of previous + segment of stack. */ + long:32; + long sstcpt:32; /* Pointer to task common address block. */ + long sscsnm; /* Private control structure number for + microtasking. */ + long ssusr1; /* Reserved for user. */ + long ssusr2; /* Reserved for user. */ + long sstpid; /* Process ID for pid based multi-tasking. */ + long ssgvup; /* Pointer to multitasking thread giveup. */ + long sscray[7]; /* Reserved for Cray Research. */ + long ssa0; + long ssa1; + long ssa2; + long ssa3; + long ssa4; + long ssa5; + long ssa6; + long ssa7; + long sss0; + long sss1; + long sss2; + long sss3; + long sss4; + long sss5; + long sss6; + long sss7; + }; + +#else /* CRAY2 */ +/* The following structure defines the vector of words + returned by the STKSTAT library routine. */ +struct stk_stat + { + long now; /* Current total stack size. */ + long maxc; /* Amount of contiguous space which would + be required to satisfy the maximum + stack demand to date. */ + long high_water; /* Stack high-water mark. */ + long overflows; /* Number of stack overflow ($STKOFEN) calls. */ + long hits; /* Number of internal buffer hits. */ + long extends; /* Number of block extensions. */ + long stko_mallocs; /* Block allocations by $STKOFEN. */ + long underflows; /* Number of stack underflow calls ($STKRETN). */ + long stko_free; /* Number of deallocations by $STKRETN. */ + long stkm_free; /* Number of deallocations by $STKMRET. */ + long segments; /* Current number of stack segments. */ + long maxs; /* Maximum number of stack segments so far. */ + long pad_size; /* Stack pad size. */ + long current_address; /* Current stack segment address. */ + long current_size; /* Current stack segment size. This + number is actually corrupted by STKSTAT to + include the fifteen word trailer area. */ + long initial_address; /* Address of initial segment. */ + long initial_size; /* Size of initial segment. */ + }; + +/* The following structure describes the data structure which trails + any stack segment. I think that the description in 'asdef' is + out of date. I only describe the parts that I am sure about. */ + +struct stk_trailer + { + long this_address; /* Address of this block. */ + long this_size; /* Size of this block (does not include + this trailer). */ + long unknown2; + long unknown3; + long link; /* Address of trailer block of previous + segment. */ + long unknown5; + long unknown6; + long unknown7; + long unknown8; + long unknown9; + long unknown10; + long unknown11; + long unknown12; + long unknown13; + long unknown14; + }; + +#endif /* CRAY2 */ +#endif /* not CRAY_STACK */ + +#ifdef CRAY2 +/* Determine a "stack measure" for an arbitrary ADDRESS. + I doubt that "lint" will like this much. */ + +static long +i00afunc (long *address) +{ + struct stk_stat status; + struct stk_trailer *trailer; + long *block, size; + long result = 0; + + /* We want to iterate through all of the segments. The first + step is to get the stack status structure. We could do this + more quickly and more directly, perhaps, by referencing the + $LM00 common block, but I know that this works. */ + + STKSTAT (&status); + + /* Set up the iteration. */ + + trailer = (struct stk_trailer *) (status.current_address + + status.current_size + - 15); + + /* There must be at least one stack segment. Therefore it is + a fatal error if "trailer" is null. */ + + if (trailer == 0) + abort (); + + /* Discard segments that do not contain our argument address. */ + + while (trailer != 0) + { + block = (long *) trailer->this_address; + size = trailer->this_size; + if (block == 0 || size == 0) + abort (); + trailer = (struct stk_trailer *) trailer->link; + if ((block <= address) && (address < (block + size))) + break; + } + + /* Set the result to the offset in this segment and add the sizes + of all predecessor segments. */ + + result = address - block; + + if (trailer == 0) + { + return result; + } + + do + { + if (trailer->this_size <= 0) + abort (); + result += trailer->this_size; + trailer = (struct stk_trailer *) trailer->link; + } + while (trailer != 0); + + /* We are done. Note that if you present a bogus address (one + not in any segment), you will get a different number back, formed + from subtracting the address of the first block. This is probably + not what you want. */ + + return (result); +} + +#else /* not CRAY2 */ +/* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP. + Determine the number of the cell within the stack, + given the address of the cell. The purpose of this + routine is to linearize, in some sense, stack addresses + for alloca. */ + +static long +i00afunc (long address) +{ + long stkl = 0; + + long size, pseg, this_segment, stack; + long result = 0; + + struct stack_segment_linkage *ssptr; + + /* Register B67 contains the address of the end of the + current stack segment. If you (as a subprogram) store + your registers on the stack and find that you are past + the contents of B67, you have overflowed the segment. + + B67 also points to the stack segment linkage control + area, which is what we are really interested in. */ + + stkl = CRAY_STACKSEG_END (); + ssptr = (struct stack_segment_linkage *) stkl; + + /* If one subtracts 'size' from the end of the segment, + one has the address of the first word of the segment. + + If this is not the first segment, 'pseg' will be + nonzero. */ + + pseg = ssptr->sspseg; + size = ssptr->sssize; + + this_segment = stkl - size; + + /* It is possible that calling this routine itself caused + a stack overflow. Discard stack segments which do not + contain the target address. */ + + while (!(this_segment <= address && address <= stkl)) + { +#ifdef DEBUG_I00AFUNC + fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl); +#endif + if (pseg == 0) + break; + stkl = stkl - pseg; + ssptr = (struct stack_segment_linkage *) stkl; + size = ssptr->sssize; + pseg = ssptr->sspseg; + this_segment = stkl - size; + } + + result = address - this_segment; + + /* If you subtract pseg from the current end of the stack, + you get the address of the previous stack segment's end. + This seems a little convoluted to me, but I'll bet you save + a cycle somewhere. */ + + while (pseg != 0) + { +#ifdef DEBUG_I00AFUNC + fprintf (stderr, "%011o %011o\n", pseg, size); +#endif + stkl = stkl - pseg; + ssptr = (struct stack_segment_linkage *) stkl; + size = ssptr->sssize; + pseg = ssptr->sspseg; + result += size; + } + return (result); +} + +#endif /* not CRAY2 */ +#endif /* CRAY */ diff --git a/3rdparty/demangler/src/argv.c b/3rdparty/demangler/src/argv.c new file mode 100644 index 0000000000..a95a10e14f --- /dev/null +++ b/3rdparty/demangler/src/argv.c @@ -0,0 +1,568 @@ +/* Create and destroy argument vectors (argv's) + Copyright (C) 1992-2023 Free Software Foundation, Inc. + Written by Fred Fish @ Cygnus Support + +This file is part of the libiberty library. +Libiberty 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. + +Libiberty is distributed in the hope that 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 libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + + +/* Create and destroy argument vectors. An argument vector is simply an + array of string pointers, terminated by a NULL pointer. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "ansidecl.h" +#include "libiberty.h" +#include "safe-ctype.h" + +/* Routines imported from standard C runtime libraries. */ + +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#if HAVE_SYS_STAT_H +#include +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef EOS +#define EOS '\0' +#endif + +#define INITIAL_MAXARGC 8 /* Number of args + NULL in initial argv */ + + +/* + +@deftypefn Extension char** dupargv (char * const *@var{vector}) + +Duplicate an argument vector. Simply scans through @var{vector}, +duplicating each argument until the terminating @code{NULL} is found. +Returns a pointer to the argument vector if successful. Returns +@code{NULL} if there is insufficient memory to complete building the +argument vector. + +@end deftypefn + +*/ + +char ** +dupargv (char * const *argv) +{ + int argc; + char **copy; + + if (argv == NULL) + return NULL; + + /* the vector */ + for (argc = 0; argv[argc] != NULL; argc++); + copy = (char **) xmalloc ((argc + 1) * sizeof (char *)); + + /* the strings */ + for (argc = 0; argv[argc] != NULL; argc++) + copy[argc] = xstrdup (argv[argc]); + copy[argc] = NULL; + return copy; +} + +/* + +@deftypefn Extension void freeargv (char **@var{vector}) + +Free an argument vector that was built using @code{buildargv}. Simply +scans through @var{vector}, freeing the memory for each argument until +the terminating @code{NULL} is found, and then frees @var{vector} +itself. + +@end deftypefn + +*/ + +void freeargv (char **vector) +{ + register char **scan; + + if (vector != NULL) + { + for (scan = vector; *scan != NULL; scan++) + { + free (*scan); + } + free (vector); + } +} + +static void +consume_whitespace (const char **input) +{ + while (ISSPACE (**input)) + { + (*input)++; + } +} + +static int +only_whitespace (const char* input) +{ + while (*input != EOS && ISSPACE (*input)) + input++; + + return (*input == EOS); +} + +/* + +@deftypefn Extension char** buildargv (char *@var{sp}) + +Given a pointer to a string, parse the string extracting fields +separated by whitespace and optionally enclosed within either single +or double quotes (which are stripped off), and build a vector of +pointers to copies of the string for each field. The input string +remains unchanged. The last element of the vector is followed by a +@code{NULL} element. + +All of the memory for the pointer array and copies of the string +is obtained from @code{xmalloc}. All of the memory can be returned to the +system with the single function call @code{freeargv}, which takes the +returned result of @code{buildargv}, as it's argument. + +Returns a pointer to the argument vector if successful. Returns +@code{NULL} if @var{sp} is @code{NULL} or if there is insufficient +memory to complete building the argument vector. + +If the input is a null string (as opposed to a @code{NULL} pointer), +then buildarg returns an argument vector that has one arg, a null +string. + +@end deftypefn + +The memory for the argv array is dynamically expanded as necessary. + +In order to provide a working buffer for extracting arguments into, +with appropriate stripping of quotes and translation of backslash +sequences, we allocate a working buffer at least as long as the input +string. This ensures that we always have enough space in which to +work, since the extracted arg is never larger than the input string. + +The argument vector is always kept terminated with a @code{NULL} arg +pointer, so it can be passed to @code{freeargv} at any time, or +returned, as appropriate. + +*/ + +char **buildargv (const char *input) +{ + char *arg; + char *copybuf; + int squote = 0; + int dquote = 0; + int bsquote = 0; + int argc = 0; + int maxargc = 0; + char **argv = NULL; + char **nargv; + + if (input != NULL) + { + copybuf = (char *) xmalloc (strlen (input) + 1); + /* Is a do{}while to always execute the loop once. Always return an + argv, even for null strings. See NOTES above, test case below. */ + do + { + /* Pick off argv[argc] */ + consume_whitespace (&input); + + if ((maxargc == 0) || (argc >= (maxargc - 1))) + { + /* argv needs initialization, or expansion */ + if (argv == NULL) + { + maxargc = INITIAL_MAXARGC; + nargv = (char **) xmalloc (maxargc * sizeof (char *)); + } + else + { + maxargc *= 2; + nargv = (char **) xrealloc (argv, maxargc * sizeof (char *)); + } + argv = nargv; + argv[argc] = NULL; + } + /* Begin scanning arg */ + arg = copybuf; + while (*input != EOS) + { + if (ISSPACE (*input) && !squote && !dquote && !bsquote) + { + break; + } + else + { + if (bsquote) + { + bsquote = 0; + *arg++ = *input; + } + else if (*input == '\\') + { + bsquote = 1; + } + else if (squote) + { + if (*input == '\'') + { + squote = 0; + } + else + { + *arg++ = *input; + } + } + else if (dquote) + { + if (*input == '"') + { + dquote = 0; + } + else + { + *arg++ = *input; + } + } + else + { + if (*input == '\'') + { + squote = 1; + } + else if (*input == '"') + { + dquote = 1; + } + else + { + *arg++ = *input; + } + } + input++; + } + } + *arg = EOS; + argv[argc] = xstrdup (copybuf); + argc++; + argv[argc] = NULL; + + consume_whitespace (&input); + } + while (*input != EOS); + + free (copybuf); + } + return (argv); +} + +/* + +@deftypefn Extension int writeargv (char * const *@var{argv}, FILE *@var{file}) + +Write each member of ARGV, handling all necessary quoting, to the file +named by FILE, separated by whitespace. Return 0 on success, non-zero +if an error occurred while writing to FILE. + +@end deftypefn + +*/ + +int +writeargv (char * const *argv, FILE *f) +{ + int status = 0; + + if (f == NULL) + return 1; + + while (*argv != NULL) + { + const char *arg = *argv; + + while (*arg != EOS) + { + char c = *arg; + + if (ISSPACE(c) || c == '\\' || c == '\'' || c == '"') + if (EOF == fputc ('\\', f)) + { + status = 1; + goto done; + } + + if (EOF == fputc (c, f)) + { + status = 1; + goto done; + } + arg++; + } + + /* Write out a pair of quotes for an empty argument. */ + if (arg == *argv) + if (EOF == fputs ("\"\"", f)) + { + status = 1; + goto done; + } + + if (EOF == fputc ('\n', f)) + { + status = 1; + goto done; + } + argv++; + } + + done: + return status; +} + +/* + +@deftypefn Extension void expandargv (int *@var{argcp}, char ***@var{argvp}) + +The @var{argcp} and @code{argvp} arguments are pointers to the usual +@code{argc} and @code{argv} arguments to @code{main}. This function +looks for arguments that begin with the character @samp{@@}. Any such +arguments are interpreted as ``response files''. The contents of the +response file are interpreted as additional command line options. In +particular, the file is separated into whitespace-separated strings; +each such string is taken as a command-line option. The new options +are inserted in place of the option naming the response file, and +@code{*argcp} and @code{*argvp} will be updated. If the value of +@code{*argvp} is modified by this function, then the new value has +been dynamically allocated and can be deallocated by the caller with +@code{freeargv}. However, most callers will simply call +@code{expandargv} near the beginning of @code{main} and allow the +operating system to free the memory when the program exits. + +@end deftypefn + +*/ + +void +expandargv (int *argcp, char ***argvp) +{ + /* The argument we are currently processing. */ + int i = 0; + /* To check if ***argvp has been dynamically allocated. */ + char ** const original_argv = *argvp; + /* Limit the number of response files that we parse in order + to prevent infinite recursion. */ + unsigned int iteration_limit = 2000; + /* Loop over the arguments, handling response files. We always skip + ARGVP[0], as that is the name of the program being run. */ + while (++i < *argcp) + { + /* The name of the response file. */ + const char *filename; + /* The response file. */ + FILE *f; + /* An upper bound on the number of characters in the response + file. */ + long pos; + /* The number of characters in the response file, when actually + read. */ + size_t len; + /* A dynamically allocated buffer used to hold options read from a + response file. */ + char *buffer; + /* Dynamically allocated storage for the options read from the + response file. */ + char **file_argv; + /* The number of options read from the response file, if any. */ + size_t file_argc; +#ifdef S_ISDIR + struct stat sb; +#endif + /* We are only interested in options of the form "@file". */ + filename = (*argvp)[i]; + if (filename[0] != '@') + continue; + /* If we have iterated too many times then stop. */ + if (-- iteration_limit == 0) + { + fprintf (stderr, "%s: error: too many @-files encountered\n", (*argvp)[0]); + xexit (1); + } +#ifdef S_ISDIR + if (stat (filename+1, &sb) < 0) + continue; + if (S_ISDIR(sb.st_mode)) + { + fprintf (stderr, "%s: error: @-file refers to a directory\n", (*argvp)[0]); + xexit (1); + } +#endif + /* Read the contents of the file. */ + f = fopen (++filename, "r"); + if (!f) + continue; + if (fseek (f, 0L, SEEK_END) == -1) + goto error; + pos = ftell (f); + if (pos == -1) + goto error; + if (fseek (f, 0L, SEEK_SET) == -1) + goto error; + buffer = (char *) xmalloc (pos * sizeof (char) + 1); + len = fread (buffer, sizeof (char), pos, f); + if (len != (size_t) pos + /* On Windows, fread may return a value smaller than POS, + due to CR/LF->CR translation when reading text files. + That does not in-and-of itself indicate failure. */ + && ferror (f)) + { + free (buffer); + goto error; + } + /* Add a NUL terminator. */ + buffer[len] = '\0'; + /* If the file is empty or contains only whitespace, buildargv would + return a single empty argument. In this context we want no arguments, + instead. */ + if (only_whitespace (buffer)) + { + file_argv = (char **) xmalloc (sizeof (char *)); + file_argv[0] = NULL; + } + else + /* Parse the string. */ + file_argv = buildargv (buffer); + /* If *ARGVP is not already dynamically allocated, copy it. */ + if (*argvp == original_argv) + *argvp = dupargv (*argvp); + /* Count the number of arguments. */ + file_argc = 0; + while (file_argv[file_argc]) + ++file_argc; + /* Free the original option's memory. */ + free ((*argvp)[i]); + /* Now, insert FILE_ARGV into ARGV. The "+1" below handles the + NULL terminator at the end of ARGV. */ + *argvp = ((char **) + xrealloc (*argvp, + (*argcp + file_argc + 1) * sizeof (char *))); + memmove (*argvp + i + file_argc, *argvp + i + 1, + (*argcp - i) * sizeof (char *)); + memcpy (*argvp + i, file_argv, file_argc * sizeof (char *)); + /* The original option has been replaced by all the new + options. */ + *argcp += file_argc - 1; + /* Free up memory allocated to process the response file. We do + not use freeargv because the individual options in FILE_ARGV + are now in the main ARGV. */ + free (file_argv); + free (buffer); + /* Rescan all of the arguments just read to support response + files that include other response files. */ + --i; + error: + /* We're all done with the file now. */ + fclose (f); + } +} + +/* + +@deftypefn Extension int countargv (char * const *@var{argv}) + +Return the number of elements in @var{argv}. +Returns zero if @var{argv} is NULL. + +@end deftypefn + +*/ + +int +countargv (char * const *argv) +{ + int argc; + + if (argv == NULL) + return 0; + for (argc = 0; argv[argc] != NULL; argc++) + continue; + return argc; +} + +#ifdef MAIN + +/* Simple little test driver. */ + +static const char *const tests[] = +{ + "a simple command line", + "arg 'foo' is single quoted", + "arg \"bar\" is double quoted", + "arg \"foo bar\" has embedded whitespace", + "arg 'Jack said \\'hi\\'' has single quotes", + "arg 'Jack said \\\"hi\\\"' has double quotes", + "a b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9", + + /* This should be expanded into only one argument. */ + "trailing-whitespace ", + + "", + NULL +}; + +int +main (void) +{ + char **argv; + const char *const *test; + char **targs; + + for (test = tests; *test != NULL; test++) + { + printf ("buildargv(\"%s\")\n", *test); + if ((argv = buildargv (*test)) == NULL) + { + printf ("failed!\n\n"); + } + else + { + for (targs = argv; *targs != NULL; targs++) + { + printf ("\t\"%s\"\n", *targs); + } + printf ("\n"); + } + freeargv (argv); + } + + return 0; +} + +#endif /* MAIN */ diff --git a/3rdparty/demangler/src/cp-demangle.c b/3rdparty/demangler/src/cp-demangle.c new file mode 100644 index 0000000000..f2b36bcad6 --- /dev/null +++ b/3rdparty/demangler/src/cp-demangle.c @@ -0,0 +1,7326 @@ +/* Demangler for g++ V3 ABI. + Copyright (C) 2003-2023 Free Software Foundation, Inc. + Written by Ian Lance Taylor . + + This file is part of the libiberty library, which is part of GCC. + + This file 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. + + In addition to the permissions in the GNU General Public License, the + Free Software Foundation gives you unlimited permission to link the + compiled version of this file into combinations with other programs, + and to distribute those combinations without any restriction coming + from the use of this file. (The General Public License restrictions + do apply in other respects; for example, they cover modification of + the file, and distribution when not linked into a combined + executable.) + + 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. +*/ + +/* This code implements a demangler for the g++ V3 ABI. The ABI is + described on this web page: + https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling + + This code was written while looking at the demangler written by + Alex Samuel . + + This code first pulls the mangled name apart into a list of + components, and then walks the list generating the demangled + name. + + This file will normally define the following functions, q.v.: + char *cplus_demangle_v3(const char *mangled, int options) + char *java_demangle_v3(const char *mangled) + int cplus_demangle_v3_callback(const char *mangled, int options, + demangle_callbackref callback) + int java_demangle_v3_callback(const char *mangled, + demangle_callbackref callback) + enum gnu_v3_ctor_kinds is_gnu_v3_mangled_ctor (const char *name) + enum gnu_v3_dtor_kinds is_gnu_v3_mangled_dtor (const char *name) + + Also, the interface to the component list is public, and defined in + demangle.h. The interface consists of these types, which are + defined in demangle.h: + enum demangle_component_type + struct demangle_component + demangle_callbackref + and these functions defined in this file: + cplus_demangle_fill_name + cplus_demangle_fill_extended_operator + cplus_demangle_fill_ctor + cplus_demangle_fill_dtor + cplus_demangle_print + cplus_demangle_print_callback + and other functions defined in the file cp-demint.c. + + This file also defines some other functions and variables which are + only to be used by the file cp-demint.c. + + Preprocessor macros you can define while compiling this file: + + IN_LIBGCC2 + If defined, this file defines the following functions, q.v.: + char *__cxa_demangle (const char *mangled, char *buf, size_t *len, + int *status) + int __gcclibcxx_demangle_callback (const char *, + void (*) + (const char *, size_t, void *), + void *) + instead of cplus_demangle_v3[_callback]() and + java_demangle_v3[_callback](). + + IN_GLIBCPP_V3 + If defined, this file defines only __cxa_demangle() and + __gcclibcxx_demangle_callback(), and no other publically visible + functions or variables. + + STANDALONE_DEMANGLER + If defined, this file defines a main() function which demangles + any arguments, or, if none, demangles stdin. + + CP_DEMANGLE_DEBUG + If defined, turns on debugging mode, which prints information on + stdout about the mangled string. This is not generally useful. + + CHECK_DEMANGLER + If defined, additional sanity checks will be performed. It will + cause some slowdown, but will allow to catch out-of-bound access + errors earlier. This macro is intended for testing and debugging. */ + +#if defined (_AIX) && !defined (__GNUC__) + #pragma alloca +#endif + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif + +#ifdef HAVE_ALLOCA_H +# include +#else +# ifndef alloca +# ifdef __GNUC__ +# define alloca __builtin_alloca +# else +extern char *alloca (); +# endif /* __GNUC__ */ +# endif /* alloca */ +#endif /* HAVE_ALLOCA_H */ + +#ifdef HAVE_LIMITS_H +#include +#endif +#ifndef INT_MAX +# define INT_MAX (int)(((unsigned int) ~0) >> 1) /* 0x7FFFFFFF */ +#endif + +#include "ansidecl.h" +#include "libiberty.h" +#include "demangle.h" +#include "cp-demangle.h" + +/* If IN_GLIBCPP_V3 is defined, some functions are made static. We + also rename them via #define to avoid compiler errors when the + static definition conflicts with the extern declaration in a header + file. */ +#ifdef IN_GLIBCPP_V3 + +#define CP_STATIC_IF_GLIBCPP_V3 static + +#define cplus_demangle_fill_name d_fill_name +static int d_fill_name (struct demangle_component *, const char *, int); + +#define cplus_demangle_fill_extended_operator d_fill_extended_operator +static int +d_fill_extended_operator (struct demangle_component *, int, + struct demangle_component *); + +#define cplus_demangle_fill_ctor d_fill_ctor +static int +d_fill_ctor (struct demangle_component *, enum gnu_v3_ctor_kinds, + struct demangle_component *); + +#define cplus_demangle_fill_dtor d_fill_dtor +static int +d_fill_dtor (struct demangle_component *, enum gnu_v3_dtor_kinds, + struct demangle_component *); + +#define cplus_demangle_mangled_name d_mangled_name +static struct demangle_component *d_mangled_name (struct d_info *, int); + +#define cplus_demangle_type d_type +static struct demangle_component *d_type (struct d_info *); + +#define cplus_demangle_print d_print +static char *d_print (int, struct demangle_component *, int, size_t *); + +#define cplus_demangle_print_callback d_print_callback +static int d_print_callback (int, struct demangle_component *, + demangle_callbackref, void *); + +#define cplus_demangle_init_info d_init_info +static void d_init_info (const char *, int, size_t, struct d_info *); + +#else /* ! defined(IN_GLIBCPP_V3) */ +#define CP_STATIC_IF_GLIBCPP_V3 +#endif /* ! defined(IN_GLIBCPP_V3) */ + +/* See if the compiler supports dynamic arrays. */ + +#ifdef __GNUC__ +#define CP_DYNAMIC_ARRAYS +#else +#ifdef __STDC__ +#ifdef __STDC_VERSION__ +#if __STDC_VERSION__ >= 199901L && !__STDC_NO_VLA__ +#define CP_DYNAMIC_ARRAYS +#endif /* __STDC_VERSION__ >= 199901L && !__STDC_NO_VLA__ */ +#endif /* defined (__STDC_VERSION__) */ +#endif /* defined (__STDC__) */ +#endif /* ! defined (__GNUC__) */ + +/* We avoid pulling in the ctype tables, to prevent pulling in + additional unresolved symbols when this code is used in a library. + FIXME: Is this really a valid reason? This comes from the original + V3 demangler code. + + As of this writing this file has the following undefined references + when compiled with -DIN_GLIBCPP_V3: realloc, free, memcpy, strcpy, + strcat, strlen. */ + +#define IS_DIGIT(c) ((c) >= '0' && (c) <= '9') +#define IS_UPPER(c) ((c) >= 'A' && (c) <= 'Z') +#define IS_LOWER(c) ((c) >= 'a' && (c) <= 'z') + +/* The prefix prepended by GCC to an identifier represnting the + anonymous namespace. */ +#define ANONYMOUS_NAMESPACE_PREFIX "_GLOBAL_" +#define ANONYMOUS_NAMESPACE_PREFIX_LEN \ + (sizeof (ANONYMOUS_NAMESPACE_PREFIX) - 1) + +/* Information we keep for the standard substitutions. */ + +struct d_standard_sub_info +{ + /* The code for this substitution. */ + char code; + /* The simple string it expands to. */ + const char *simple_expansion; + /* The length of the simple expansion. */ + int simple_len; + /* The results of a full, verbose, expansion. This is used when + qualifying a constructor/destructor, or when in verbose mode. */ + const char *full_expansion; + /* The length of the full expansion. */ + int full_len; + /* What to set the last_name field of d_info to; NULL if we should + not set it. This is only relevant when qualifying a + constructor/destructor. */ + const char *set_last_name; + /* The length of set_last_name. */ + int set_last_name_len; +}; + +/* Accessors for subtrees of struct demangle_component. */ + +#define d_left(dc) ((dc)->u.s_binary.left) +#define d_right(dc) ((dc)->u.s_binary.right) + +/* A list of templates. This is used while printing. */ + +struct d_print_template +{ + /* Next template on the list. */ + struct d_print_template *next; + /* This template. */ + const struct demangle_component *template_decl; +}; + +/* A list of type modifiers. This is used while printing. */ + +struct d_print_mod +{ + /* Next modifier on the list. These are in the reverse of the order + in which they appeared in the mangled string. */ + struct d_print_mod *next; + /* The modifier. */ + struct demangle_component *mod; + /* Whether this modifier was printed. */ + int printed; + /* The list of templates which applies to this modifier. */ + struct d_print_template *templates; +}; + +/* We use these structures to hold information during printing. */ + +struct d_growable_string +{ + /* Buffer holding the result. */ + char *buf; + /* Current length of data in buffer. */ + size_t len; + /* Allocated size of buffer. */ + size_t alc; + /* Set to 1 if we had a memory allocation failure. */ + int allocation_failure; +}; + +/* Stack of components, innermost first, used to avoid loops. */ + +struct d_component_stack +{ + /* This component. */ + const struct demangle_component *dc; + /* This component's parent. */ + const struct d_component_stack *parent; +}; + +/* A demangle component and some scope captured when it was first + traversed. */ + +struct d_saved_scope +{ + /* The component whose scope this is. */ + const struct demangle_component *container; + /* The list of templates, if any, that was current when this + scope was captured. */ + struct d_print_template *templates; +}; + +/* Checkpoint structure to allow backtracking. This holds copies + of the fields of struct d_info that need to be restored + if a trial parse needs to be backtracked over. */ + +struct d_info_checkpoint +{ + const char *n; + int next_comp; + int next_sub; + int expansion; +}; + +/* Maximum number of times d_print_comp may be called recursively. */ +#define MAX_RECURSION_COUNT 1024 + +enum { D_PRINT_BUFFER_LENGTH = 256 }; +struct d_print_info +{ + /* Fixed-length allocated buffer for demangled data, flushed to the + callback with a NUL termination once full. */ + char buf[D_PRINT_BUFFER_LENGTH]; + /* Current length of data in buffer. */ + size_t len; + /* The last character printed, saved individually so that it survives + any buffer flush. */ + char last_char; + /* Callback function to handle demangled buffer flush. */ + demangle_callbackref callback; + /* Opaque callback argument. */ + void *opaque; + /* The current list of templates, if any. */ + struct d_print_template *templates; + /* The current list of modifiers (e.g., pointer, reference, etc.), + if any. */ + struct d_print_mod *modifiers; + /* Set to 1 if we saw a demangling error. */ + int demangle_failure; + /* Number of times d_print_comp was recursively called. Should not + be bigger than MAX_RECURSION_COUNT. */ + int recursion; + /* 1 more than the number of explicit template parms of a lambda. Template + parm references >= are actually 'auto'. */ + int lambda_tpl_parms; + /* The current index into any template argument packs we are using + for printing, or -1 to print the whole pack. */ + int pack_index; + /* Number of d_print_flush calls so far. */ + unsigned long int flush_count; + /* Stack of components, innermost first, used to avoid loops. */ + const struct d_component_stack *component_stack; + /* Array of saved scopes for evaluating substitutions. */ + struct d_saved_scope *saved_scopes; + /* Index of the next unused saved scope in the above array. */ + int next_saved_scope; + /* Number of saved scopes in the above array. */ + int num_saved_scopes; + /* Array of templates for saving into scopes. */ + struct d_print_template *copy_templates; + /* Index of the next unused copy template in the above array. */ + int next_copy_template; + /* Number of copy templates in the above array. */ + int num_copy_templates; + /* The nearest enclosing template, if any. */ + const struct demangle_component *current_template; +}; + +#ifdef CP_DEMANGLE_DEBUG +static void d_dump (struct demangle_component *, int); +#endif + +static struct demangle_component * +d_make_empty (struct d_info *); + +static struct demangle_component * +d_make_comp (struct d_info *, enum demangle_component_type, + struct demangle_component *, + struct demangle_component *); + +static struct demangle_component * +d_make_name (struct d_info *, const char *, int); + +static struct demangle_component * +d_make_demangle_mangled_name (struct d_info *, const char *); + +static struct demangle_component * +d_make_builtin_type (struct d_info *, + const struct demangle_builtin_type_info *); + +static struct demangle_component * +d_make_operator (struct d_info *, + const struct demangle_operator_info *); + +static struct demangle_component * +d_make_extended_operator (struct d_info *, int, + struct demangle_component *); + +static struct demangle_component * +d_make_ctor (struct d_info *, enum gnu_v3_ctor_kinds, + struct demangle_component *); + +static struct demangle_component * +d_make_dtor (struct d_info *, enum gnu_v3_dtor_kinds, + struct demangle_component *); + +static struct demangle_component * +d_make_template_param (struct d_info *, int); + +static struct demangle_component * +d_make_sub (struct d_info *, const char *, int); + +static int +has_return_type (struct demangle_component *); + +static int +is_ctor_dtor_or_conversion (struct demangle_component *); + +static struct demangle_component *d_encoding (struct d_info *, int); + +static struct demangle_component *d_name (struct d_info *, int substable); + +static struct demangle_component *d_nested_name (struct d_info *); + +static int d_maybe_module_name (struct d_info *, struct demangle_component **); + +static struct demangle_component *d_prefix (struct d_info *, int); + +static struct demangle_component *d_unqualified_name (struct d_info *, + struct demangle_component *scope, struct demangle_component *module); + +static struct demangle_component *d_source_name (struct d_info *); + +static int d_number (struct d_info *); + +static struct demangle_component *d_identifier (struct d_info *, int); + +static struct demangle_component *d_operator_name (struct d_info *); + +static struct demangle_component *d_special_name (struct d_info *); + +static struct demangle_component *d_parmlist (struct d_info *); + +static int d_call_offset (struct d_info *, int); + +static struct demangle_component *d_ctor_dtor_name (struct d_info *); + +static struct demangle_component ** +d_cv_qualifiers (struct d_info *, struct demangle_component **, int); + +static struct demangle_component * +d_ref_qualifier (struct d_info *, struct demangle_component *); + +static struct demangle_component * +d_function_type (struct d_info *); + +static struct demangle_component * +d_bare_function_type (struct d_info *, int); + +static struct demangle_component * +d_class_enum_type (struct d_info *, int); + +static struct demangle_component *d_array_type (struct d_info *); + +static struct demangle_component *d_vector_type (struct d_info *); + +static struct demangle_component * +d_pointer_to_member_type (struct d_info *); + +static struct demangle_component * +d_template_param (struct d_info *); + +static struct demangle_component *d_template_args (struct d_info *); +static struct demangle_component *d_template_args_1 (struct d_info *); + +static struct demangle_component * +d_template_arg (struct d_info *); + +static struct demangle_component *d_expression (struct d_info *); + +static struct demangle_component *d_expr_primary (struct d_info *); + +static struct demangle_component *d_local_name (struct d_info *); + +static int d_discriminator (struct d_info *); + +static struct demangle_component *d_template_parm (struct d_info *, int *bad); + +static struct demangle_component *d_template_head (struct d_info *, int *bad); + +static struct demangle_component *d_lambda (struct d_info *); + +static struct demangle_component *d_unnamed_type (struct d_info *); + +static struct demangle_component * +d_clone_suffix (struct d_info *, struct demangle_component *); + +static int +d_add_substitution (struct d_info *, struct demangle_component *); + +static struct demangle_component *d_substitution (struct d_info *, int); + +static void d_checkpoint (struct d_info *, struct d_info_checkpoint *); + +static void d_backtrack (struct d_info *, struct d_info_checkpoint *); + +static void d_growable_string_init (struct d_growable_string *, size_t); + +static inline void +d_growable_string_resize (struct d_growable_string *, size_t); + +static inline void +d_growable_string_append_buffer (struct d_growable_string *, + const char *, size_t); +static void +d_growable_string_callback_adapter (const char *, size_t, void *); + +static void +d_print_init (struct d_print_info *, demangle_callbackref, void *, + struct demangle_component *); + +static inline void d_print_error (struct d_print_info *); + +static inline int d_print_saw_error (struct d_print_info *); + +static inline void d_print_flush (struct d_print_info *); + +static inline void d_append_char (struct d_print_info *, char); + +static inline void d_append_buffer (struct d_print_info *, + const char *, size_t); + +static inline void d_append_string (struct d_print_info *, const char *); + +static inline char d_last_char (struct d_print_info *); + +static void +d_print_comp (struct d_print_info *, int, struct demangle_component *); + +static void +d_print_java_identifier (struct d_print_info *, const char *, int); + +static void +d_print_mod_list (struct d_print_info *, int, struct d_print_mod *, int); + +static void +d_print_mod (struct d_print_info *, int, struct demangle_component *); + +static void +d_print_function_type (struct d_print_info *, int, + struct demangle_component *, + struct d_print_mod *); + +static void +d_print_array_type (struct d_print_info *, int, + struct demangle_component *, + struct d_print_mod *); + +static void +d_print_expr_op (struct d_print_info *, int, struct demangle_component *); + +static void d_print_cast (struct d_print_info *, int, + struct demangle_component *); +static void d_print_conversion (struct d_print_info *, int, + struct demangle_component *); + +static int d_demangle_callback (const char *, int, + demangle_callbackref, void *); +static char *d_demangle (const char *, int, size_t *); + +#define FNQUAL_COMPONENT_CASE \ + case DEMANGLE_COMPONENT_RESTRICT_THIS: \ + case DEMANGLE_COMPONENT_VOLATILE_THIS: \ + case DEMANGLE_COMPONENT_CONST_THIS: \ + case DEMANGLE_COMPONENT_REFERENCE_THIS: \ + case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS: \ + case DEMANGLE_COMPONENT_TRANSACTION_SAFE: \ + case DEMANGLE_COMPONENT_NOEXCEPT: \ + case DEMANGLE_COMPONENT_THROW_SPEC + +/* True iff TYPE is a demangling component representing a + function-type-qualifier. */ + +static int +is_fnqual_component_type (enum demangle_component_type type) +{ + switch (type) + { + FNQUAL_COMPONENT_CASE: + return 1; + default: + break; + } + return 0; +} + + +#ifdef CP_DEMANGLE_DEBUG + +static void +d_dump (struct demangle_component *dc, int indent) +{ + int i; + + if (dc == NULL) + { + if (indent == 0) + printf ("failed demangling\n"); + return; + } + + for (i = 0; i < indent; ++i) + putchar (' '); + + switch (dc->type) + { + case DEMANGLE_COMPONENT_NAME: + printf ("name '%.*s'\n", dc->u.s_name.len, dc->u.s_name.s); + return; + case DEMANGLE_COMPONENT_TAGGED_NAME: + printf ("tagged name\n"); + d_dump (dc->u.s_binary.left, indent + 2); + d_dump (dc->u.s_binary.right, indent + 2); + return; + case DEMANGLE_COMPONENT_TEMPLATE_PARAM: + printf ("template parameter %ld\n", dc->u.s_number.number); + return; + case DEMANGLE_COMPONENT_TPARM_OBJ: + printf ("template parameter object\n"); + break; + case DEMANGLE_COMPONENT_FUNCTION_PARAM: + printf ("function parameter %ld\n", dc->u.s_number.number); + return; + case DEMANGLE_COMPONENT_CTOR: + printf ("constructor %d\n", (int) dc->u.s_ctor.kind); + d_dump (dc->u.s_ctor.name, indent + 2); + return; + case DEMANGLE_COMPONENT_DTOR: + printf ("destructor %d\n", (int) dc->u.s_dtor.kind); + d_dump (dc->u.s_dtor.name, indent + 2); + return; + case DEMANGLE_COMPONENT_SUB_STD: + printf ("standard substitution %s\n", dc->u.s_string.string); + return; + case DEMANGLE_COMPONENT_BUILTIN_TYPE: + printf ("builtin type %s\n", dc->u.s_builtin.type->name); + return; + case DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE: + { + char suffix[2] = { dc->u.s_extended_builtin.type->suffix, 0 }; + printf ("builtin type %s%d%s\n", dc->u.s_extended_builtin.type->name, + dc->u.s_extended_builtin.type->arg, suffix); + } + return; + case DEMANGLE_COMPONENT_OPERATOR: + printf ("operator %s\n", dc->u.s_operator.op->name); + return; + case DEMANGLE_COMPONENT_EXTENDED_OPERATOR: + printf ("extended operator with %d args\n", + dc->u.s_extended_operator.args); + d_dump (dc->u.s_extended_operator.name, indent + 2); + return; + + case DEMANGLE_COMPONENT_QUAL_NAME: + printf ("qualified name\n"); + break; + case DEMANGLE_COMPONENT_LOCAL_NAME: + printf ("local name\n"); + break; + case DEMANGLE_COMPONENT_TYPED_NAME: + printf ("typed name\n"); + break; + case DEMANGLE_COMPONENT_TEMPLATE: + printf ("template\n"); + break; + case DEMANGLE_COMPONENT_VTABLE: + printf ("vtable\n"); + break; + case DEMANGLE_COMPONENT_VTT: + printf ("VTT\n"); + break; + case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE: + printf ("construction vtable\n"); + break; + case DEMANGLE_COMPONENT_TYPEINFO: + printf ("typeinfo\n"); + break; + case DEMANGLE_COMPONENT_TYPEINFO_NAME: + printf ("typeinfo name\n"); + break; + case DEMANGLE_COMPONENT_TYPEINFO_FN: + printf ("typeinfo function\n"); + break; + case DEMANGLE_COMPONENT_THUNK: + printf ("thunk\n"); + break; + case DEMANGLE_COMPONENT_VIRTUAL_THUNK: + printf ("virtual thunk\n"); + break; + case DEMANGLE_COMPONENT_COVARIANT_THUNK: + printf ("covariant thunk\n"); + break; + case DEMANGLE_COMPONENT_JAVA_CLASS: + printf ("java class\n"); + break; + case DEMANGLE_COMPONENT_GUARD: + printf ("guard\n"); + break; + case DEMANGLE_COMPONENT_REFTEMP: + printf ("reference temporary\n"); + break; + case DEMANGLE_COMPONENT_HIDDEN_ALIAS: + printf ("hidden alias\n"); + break; + case DEMANGLE_COMPONENT_TRANSACTION_CLONE: + printf ("transaction clone\n"); + break; + case DEMANGLE_COMPONENT_NONTRANSACTION_CLONE: + printf ("non-transaction clone\n"); + break; + case DEMANGLE_COMPONENT_RESTRICT: + printf ("restrict\n"); + break; + case DEMANGLE_COMPONENT_VOLATILE: + printf ("volatile\n"); + break; + case DEMANGLE_COMPONENT_CONST: + printf ("const\n"); + break; + case DEMANGLE_COMPONENT_RESTRICT_THIS: + printf ("restrict this\n"); + break; + case DEMANGLE_COMPONENT_VOLATILE_THIS: + printf ("volatile this\n"); + break; + case DEMANGLE_COMPONENT_CONST_THIS: + printf ("const this\n"); + break; + case DEMANGLE_COMPONENT_REFERENCE_THIS: + printf ("reference this\n"); + break; + case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS: + printf ("rvalue reference this\n"); + break; + case DEMANGLE_COMPONENT_TRANSACTION_SAFE: + printf ("transaction_safe this\n"); + break; + case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL: + printf ("vendor type qualifier\n"); + break; + case DEMANGLE_COMPONENT_POINTER: + printf ("pointer\n"); + break; + case DEMANGLE_COMPONENT_REFERENCE: + printf ("reference\n"); + break; + case DEMANGLE_COMPONENT_RVALUE_REFERENCE: + printf ("rvalue reference\n"); + break; + case DEMANGLE_COMPONENT_COMPLEX: + printf ("complex\n"); + break; + case DEMANGLE_COMPONENT_IMAGINARY: + printf ("imaginary\n"); + break; + case DEMANGLE_COMPONENT_VENDOR_TYPE: + printf ("vendor type\n"); + break; + case DEMANGLE_COMPONENT_FUNCTION_TYPE: + printf ("function type\n"); + break; + case DEMANGLE_COMPONENT_ARRAY_TYPE: + printf ("array type\n"); + break; + case DEMANGLE_COMPONENT_PTRMEM_TYPE: + printf ("pointer to member type\n"); + break; + case DEMANGLE_COMPONENT_ARGLIST: + printf ("argument list\n"); + break; + case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST: + printf ("template argument list\n"); + break; + case DEMANGLE_COMPONENT_INITIALIZER_LIST: + printf ("initializer list\n"); + break; + case DEMANGLE_COMPONENT_CAST: + printf ("cast\n"); + break; + case DEMANGLE_COMPONENT_CONVERSION: + printf ("conversion operator\n"); + break; + case DEMANGLE_COMPONENT_NULLARY: + printf ("nullary operator\n"); + break; + case DEMANGLE_COMPONENT_UNARY: + printf ("unary operator\n"); + break; + case DEMANGLE_COMPONENT_BINARY: + printf ("binary operator\n"); + break; + case DEMANGLE_COMPONENT_BINARY_ARGS: + printf ("binary operator arguments\n"); + break; + case DEMANGLE_COMPONENT_TRINARY: + printf ("trinary operator\n"); + break; + case DEMANGLE_COMPONENT_TRINARY_ARG1: + printf ("trinary operator arguments 1\n"); + break; + case DEMANGLE_COMPONENT_TRINARY_ARG2: + printf ("trinary operator arguments 1\n"); + break; + case DEMANGLE_COMPONENT_LITERAL: + printf ("literal\n"); + break; + case DEMANGLE_COMPONENT_LITERAL_NEG: + printf ("negative literal\n"); + break; + case DEMANGLE_COMPONENT_VENDOR_EXPR: + printf ("vendor expression\n"); + break; + case DEMANGLE_COMPONENT_JAVA_RESOURCE: + printf ("java resource\n"); + break; + case DEMANGLE_COMPONENT_COMPOUND_NAME: + printf ("compound name\n"); + break; + case DEMANGLE_COMPONENT_CHARACTER: + printf ("character '%c'\n", dc->u.s_character.character); + return; + case DEMANGLE_COMPONENT_NUMBER: + printf ("number %ld\n", dc->u.s_number.number); + return; + case DEMANGLE_COMPONENT_DECLTYPE: + printf ("decltype\n"); + break; + case DEMANGLE_COMPONENT_PACK_EXPANSION: + printf ("pack expansion\n"); + break; + case DEMANGLE_COMPONENT_TLS_INIT: + printf ("tls init function\n"); + break; + case DEMANGLE_COMPONENT_TLS_WRAPPER: + printf ("tls wrapper function\n"); + break; + case DEMANGLE_COMPONENT_DEFAULT_ARG: + printf ("default argument %d\n", dc->u.s_unary_num.num); + d_dump (dc->u.s_unary_num.sub, indent+2); + return; + case DEMANGLE_COMPONENT_LAMBDA: + printf ("lambda %d\n", dc->u.s_unary_num.num); + d_dump (dc->u.s_unary_num.sub, indent+2); + return; + } + + d_dump (d_left (dc), indent + 2); + d_dump (d_right (dc), indent + 2); +} + +#endif /* CP_DEMANGLE_DEBUG */ + +/* Fill in a DEMANGLE_COMPONENT_NAME. */ + +CP_STATIC_IF_GLIBCPP_V3 +int +cplus_demangle_fill_name (struct demangle_component *p, const char *s, int len) +{ + if (p == NULL || s == NULL || len <= 0) + return 0; + p->d_printing = 0; + p->d_counting = 0; + p->type = DEMANGLE_COMPONENT_NAME; + p->u.s_name.s = s; + p->u.s_name.len = len; + return 1; +} + +/* Fill in a DEMANGLE_COMPONENT_EXTENDED_OPERATOR. */ + +CP_STATIC_IF_GLIBCPP_V3 +int +cplus_demangle_fill_extended_operator (struct demangle_component *p, int args, + struct demangle_component *name) +{ + if (p == NULL || args < 0 || name == NULL) + return 0; + p->d_printing = 0; + p->d_counting = 0; + p->type = DEMANGLE_COMPONENT_EXTENDED_OPERATOR; + p->u.s_extended_operator.args = args; + p->u.s_extended_operator.name = name; + return 1; +} + +/* Fill in a DEMANGLE_COMPONENT_CTOR. */ + +CP_STATIC_IF_GLIBCPP_V3 +int +cplus_demangle_fill_ctor (struct demangle_component *p, + enum gnu_v3_ctor_kinds kind, + struct demangle_component *name) +{ + if (p == NULL + || name == NULL + || (int) kind < gnu_v3_complete_object_ctor + || (int) kind > gnu_v3_object_ctor_group) + return 0; + p->d_printing = 0; + p->d_counting = 0; + p->type = DEMANGLE_COMPONENT_CTOR; + p->u.s_ctor.kind = kind; + p->u.s_ctor.name = name; + return 1; +} + +/* Fill in a DEMANGLE_COMPONENT_DTOR. */ + +CP_STATIC_IF_GLIBCPP_V3 +int +cplus_demangle_fill_dtor (struct demangle_component *p, + enum gnu_v3_dtor_kinds kind, + struct demangle_component *name) +{ + if (p == NULL + || name == NULL + || (int) kind < gnu_v3_deleting_dtor + || (int) kind > gnu_v3_object_dtor_group) + return 0; + p->d_printing = 0; + p->d_counting = 0; + p->type = DEMANGLE_COMPONENT_DTOR; + p->u.s_dtor.kind = kind; + p->u.s_dtor.name = name; + return 1; +} + +/* Add a new component. */ + +static struct demangle_component * +d_make_empty (struct d_info *di) +{ + struct demangle_component *p; + + if (di->next_comp >= di->num_comps) + return NULL; + p = &di->comps[di->next_comp]; + p->d_printing = 0; + p->d_counting = 0; + ++di->next_comp; + return p; +} + +/* Add a new generic component. */ + +static struct demangle_component * +d_make_comp (struct d_info *di, enum demangle_component_type type, + struct demangle_component *left, + struct demangle_component *right) +{ + struct demangle_component *p; + + /* We check for errors here. A typical error would be a NULL return + from a subroutine. We catch those here, and return NULL + upward. */ + switch (type) + { + /* These types require two parameters. */ + case DEMANGLE_COMPONENT_QUAL_NAME: + case DEMANGLE_COMPONENT_LOCAL_NAME: + case DEMANGLE_COMPONENT_TYPED_NAME: + case DEMANGLE_COMPONENT_TAGGED_NAME: + case DEMANGLE_COMPONENT_TEMPLATE: + case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE: + case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL: + case DEMANGLE_COMPONENT_PTRMEM_TYPE: + case DEMANGLE_COMPONENT_UNARY: + case DEMANGLE_COMPONENT_BINARY: + case DEMANGLE_COMPONENT_BINARY_ARGS: + case DEMANGLE_COMPONENT_TRINARY: + case DEMANGLE_COMPONENT_TRINARY_ARG1: + case DEMANGLE_COMPONENT_LITERAL: + case DEMANGLE_COMPONENT_LITERAL_NEG: + case DEMANGLE_COMPONENT_VENDOR_EXPR: + case DEMANGLE_COMPONENT_COMPOUND_NAME: + case DEMANGLE_COMPONENT_VECTOR_TYPE: + case DEMANGLE_COMPONENT_CLONE: + case DEMANGLE_COMPONENT_MODULE_ENTITY: + if (left == NULL || right == NULL) + return NULL; + break; + + /* These types only require one parameter. */ + case DEMANGLE_COMPONENT_VTABLE: + case DEMANGLE_COMPONENT_VTT: + case DEMANGLE_COMPONENT_TYPEINFO: + case DEMANGLE_COMPONENT_TYPEINFO_NAME: + case DEMANGLE_COMPONENT_TYPEINFO_FN: + case DEMANGLE_COMPONENT_THUNK: + case DEMANGLE_COMPONENT_VIRTUAL_THUNK: + case DEMANGLE_COMPONENT_COVARIANT_THUNK: + case DEMANGLE_COMPONENT_JAVA_CLASS: + case DEMANGLE_COMPONENT_GUARD: + case DEMANGLE_COMPONENT_TLS_INIT: + case DEMANGLE_COMPONENT_TLS_WRAPPER: + case DEMANGLE_COMPONENT_REFTEMP: + case DEMANGLE_COMPONENT_HIDDEN_ALIAS: + case DEMANGLE_COMPONENT_TRANSACTION_CLONE: + case DEMANGLE_COMPONENT_NONTRANSACTION_CLONE: + case DEMANGLE_COMPONENT_POINTER: + case DEMANGLE_COMPONENT_REFERENCE: + case DEMANGLE_COMPONENT_RVALUE_REFERENCE: + case DEMANGLE_COMPONENT_COMPLEX: + case DEMANGLE_COMPONENT_IMAGINARY: + case DEMANGLE_COMPONENT_VENDOR_TYPE: + case DEMANGLE_COMPONENT_CAST: + case DEMANGLE_COMPONENT_CONVERSION: + case DEMANGLE_COMPONENT_JAVA_RESOURCE: + case DEMANGLE_COMPONENT_DECLTYPE: + case DEMANGLE_COMPONENT_PACK_EXPANSION: + case DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS: + case DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS: + case DEMANGLE_COMPONENT_NULLARY: + case DEMANGLE_COMPONENT_TRINARY_ARG2: + case DEMANGLE_COMPONENT_TPARM_OBJ: + case DEMANGLE_COMPONENT_STRUCTURED_BINDING: + case DEMANGLE_COMPONENT_MODULE_INIT: + case DEMANGLE_COMPONENT_TEMPLATE_HEAD: + case DEMANGLE_COMPONENT_TEMPLATE_NON_TYPE_PARM: + case DEMANGLE_COMPONENT_TEMPLATE_TEMPLATE_PARM: + case DEMANGLE_COMPONENT_TEMPLATE_PACK_PARM: + if (left == NULL) + return NULL; + break; + + /* This needs a right parameter, but the left parameter can be + empty. */ + case DEMANGLE_COMPONENT_ARRAY_TYPE: + case DEMANGLE_COMPONENT_INITIALIZER_LIST: + case DEMANGLE_COMPONENT_MODULE_NAME: + case DEMANGLE_COMPONENT_MODULE_PARTITION: + if (right == NULL) + return NULL; + break; + + /* These are allowed to have no parameters--in some cases they + will be filled in later. */ + case DEMANGLE_COMPONENT_FUNCTION_TYPE: + case DEMANGLE_COMPONENT_RESTRICT: + case DEMANGLE_COMPONENT_VOLATILE: + case DEMANGLE_COMPONENT_CONST: + case DEMANGLE_COMPONENT_ARGLIST: + case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST: + case DEMANGLE_COMPONENT_TEMPLATE_TYPE_PARM: + FNQUAL_COMPONENT_CASE: + break; + + /* Other types should not be seen here. */ + default: + return NULL; + } + + p = d_make_empty (di); + if (p != NULL) + { + p->type = type; + p->u.s_binary.left = left; + p->u.s_binary.right = right; + } + return p; +} + +/* Add a new demangle mangled name component. */ + +static struct demangle_component * +d_make_demangle_mangled_name (struct d_info *di, const char *s) +{ + if (d_peek_char (di) != '_' || d_peek_next_char (di) != 'Z') + return d_make_name (di, s, strlen (s)); + d_advance (di, 2); + return d_encoding (di, 0); +} + +/* Add a new name component. */ + +static struct demangle_component * +d_make_name (struct d_info *di, const char *s, int len) +{ + struct demangle_component *p; + + p = d_make_empty (di); + if (! cplus_demangle_fill_name (p, s, len)) + return NULL; + return p; +} + +/* Add a new builtin type component. */ + +static struct demangle_component * +d_make_builtin_type (struct d_info *di, + const struct demangle_builtin_type_info *type) +{ + struct demangle_component *p; + + if (type == NULL) + return NULL; + p = d_make_empty (di); + if (p != NULL) + { + p->type = DEMANGLE_COMPONENT_BUILTIN_TYPE; + p->u.s_builtin.type = type; + } + return p; +} + +/* Add a new extended builtin type component. */ + +static struct demangle_component * +d_make_extended_builtin_type (struct d_info *di, + const struct demangle_builtin_type_info *type, + short arg, char suffix) +{ + struct demangle_component *p; + + if (type == NULL) + return NULL; + p = d_make_empty (di); + if (p != NULL) + { + p->type = DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE; + p->u.s_extended_builtin.type = type; + p->u.s_extended_builtin.arg = arg; + p->u.s_extended_builtin.suffix = suffix; + } + return p; +} + +/* Add a new operator component. */ + +static struct demangle_component * +d_make_operator (struct d_info *di, const struct demangle_operator_info *op) +{ + struct demangle_component *p; + + p = d_make_empty (di); + if (p != NULL) + { + p->type = DEMANGLE_COMPONENT_OPERATOR; + p->u.s_operator.op = op; + } + return p; +} + +/* Add a new extended operator component. */ + +static struct demangle_component * +d_make_extended_operator (struct d_info *di, int args, + struct demangle_component *name) +{ + struct demangle_component *p; + + p = d_make_empty (di); + if (! cplus_demangle_fill_extended_operator (p, args, name)) + return NULL; + return p; +} + +static struct demangle_component * +d_make_default_arg (struct d_info *di, int num, + struct demangle_component *sub) +{ + struct demangle_component *p = d_make_empty (di); + if (p) + { + p->type = DEMANGLE_COMPONENT_DEFAULT_ARG; + p->u.s_unary_num.num = num; + p->u.s_unary_num.sub = sub; + } + return p; +} + +/* Add a new constructor component. */ + +static struct demangle_component * +d_make_ctor (struct d_info *di, enum gnu_v3_ctor_kinds kind, + struct demangle_component *name) +{ + struct demangle_component *p; + + p = d_make_empty (di); + if (! cplus_demangle_fill_ctor (p, kind, name)) + return NULL; + return p; +} + +/* Add a new destructor component. */ + +static struct demangle_component * +d_make_dtor (struct d_info *di, enum gnu_v3_dtor_kinds kind, + struct demangle_component *name) +{ + struct demangle_component *p; + + p = d_make_empty (di); + if (! cplus_demangle_fill_dtor (p, kind, name)) + return NULL; + return p; +} + +/* Add a new template parameter. */ + +static struct demangle_component * +d_make_template_param (struct d_info *di, int i) +{ + struct demangle_component *p; + + p = d_make_empty (di); + if (p != NULL) + { + p->type = DEMANGLE_COMPONENT_TEMPLATE_PARAM; + p->u.s_number.number = i; + } + return p; +} + +/* Add a new function parameter. */ + +static struct demangle_component * +d_make_function_param (struct d_info *di, int i) +{ + struct demangle_component *p; + + p = d_make_empty (di); + if (p != NULL) + { + p->type = DEMANGLE_COMPONENT_FUNCTION_PARAM; + p->u.s_number.number = i; + } + return p; +} + +/* Add a new standard substitution component. */ + +static struct demangle_component * +d_make_sub (struct d_info *di, const char *name, int len) +{ + struct demangle_component *p; + + p = d_make_empty (di); + if (p != NULL) + { + p->type = DEMANGLE_COMPONENT_SUB_STD; + p->u.s_string.string = name; + p->u.s_string.len = len; + } + return p; +} + +/* ::= _Z []* + + TOP_LEVEL is non-zero when called at the top level. */ + +CP_STATIC_IF_GLIBCPP_V3 +struct demangle_component * +cplus_demangle_mangled_name (struct d_info *di, int top_level) +{ + struct demangle_component *p; + + if (! d_check_char (di, '_') + /* Allow missing _ if not at toplevel to work around a + bug in G++ abi-version=2 mangling; see the comment in + write_template_arg. */ + && top_level) + return NULL; + if (! d_check_char (di, 'Z')) + return NULL; + p = d_encoding (di, top_level); + + /* If at top level and parsing parameters, check for a clone + suffix. */ + if (top_level && (di->options & DMGL_PARAMS) != 0) + while (d_peek_char (di) == '.' + && (IS_LOWER (d_peek_next_char (di)) + || d_peek_next_char (di) == '_' + || IS_DIGIT (d_peek_next_char (di)))) + p = d_clone_suffix (di, p); + + return p; +} + +/* Return whether a function should have a return type. The argument + is the function name, which may be qualified in various ways. The + rules are that template functions have return types with some + exceptions, function types which are not part of a function name + mangling have return types with some exceptions, and non-template + function names do not have return types. The exceptions are that + constructors, destructors, and conversion operators do not have + return types. */ + +static int +has_return_type (struct demangle_component *dc) +{ + if (dc == NULL) + return 0; + switch (dc->type) + { + default: + return 0; + case DEMANGLE_COMPONENT_LOCAL_NAME: + return has_return_type (d_right (dc)); + case DEMANGLE_COMPONENT_TEMPLATE: + return ! is_ctor_dtor_or_conversion (d_left (dc)); + FNQUAL_COMPONENT_CASE: + return has_return_type (d_left (dc)); + } +} + +/* Return whether a name is a constructor, a destructor, or a + conversion operator. */ + +static int +is_ctor_dtor_or_conversion (struct demangle_component *dc) +{ + if (dc == NULL) + return 0; + switch (dc->type) + { + default: + return 0; + case DEMANGLE_COMPONENT_QUAL_NAME: + case DEMANGLE_COMPONENT_LOCAL_NAME: + return is_ctor_dtor_or_conversion (d_right (dc)); + case DEMANGLE_COMPONENT_CTOR: + case DEMANGLE_COMPONENT_DTOR: + case DEMANGLE_COMPONENT_CONVERSION: + return 1; + } +} + +/* ::= <(function) name> + ::= <(data) name> + ::= + + TOP_LEVEL is non-zero when called at the top level, in which case + if DMGL_PARAMS is not set we do not demangle the function + parameters. We only set this at the top level, because otherwise + we would not correctly demangle names in local scopes. */ + +static struct demangle_component * +d_encoding (struct d_info *di, int top_level) +{ + char peek = d_peek_char (di); + struct demangle_component *dc; + + if (peek == 'G' || peek == 'T') + dc = d_special_name (di); + else + { + dc = d_name (di, 0); + + if (!dc) + /* Failed already. */; + else if (top_level && (di->options & DMGL_PARAMS) == 0) + { + /* Strip off any initial CV-qualifiers, as they really apply + to the `this' parameter, and they were not output by the + v2 demangler without DMGL_PARAMS. */ + while (is_fnqual_component_type (dc->type)) + dc = d_left (dc); + + /* If the top level is a DEMANGLE_COMPONENT_LOCAL_NAME, then + there may be function-qualifiers on its right argument which + really apply here; this happens when parsing a class + which is local to a function. */ + if (dc->type == DEMANGLE_COMPONENT_LOCAL_NAME) + { + while (d_right (dc) != NULL + && is_fnqual_component_type (d_right (dc)->type)) + d_right (dc) = d_left (d_right (dc)); + + if (d_right (dc) == NULL) + dc = NULL; + } + } + else + { + peek = d_peek_char (di); + if (peek != '\0' && peek != 'E') + { + struct demangle_component *ftype; + + ftype = d_bare_function_type (di, has_return_type (dc)); + if (ftype) + { + /* If this is a non-top-level local-name, clear the + return type, so it doesn't confuse the user by + being confused with the return type of whaever + this is nested within. */ + if (!top_level && dc->type == DEMANGLE_COMPONENT_LOCAL_NAME + && ftype->type == DEMANGLE_COMPONENT_FUNCTION_TYPE) + d_left (ftype) = NULL; + + dc = d_make_comp (di, DEMANGLE_COMPONENT_TYPED_NAME, + dc, ftype); + } + else + dc = NULL; + } + } + } + + return dc; +} + +/* ::= B */ + +static struct demangle_component * +d_abi_tags (struct d_info *di, struct demangle_component *dc) +{ + struct demangle_component *hold_last_name; + char peek; + + /* Preserve the last name, so the ABI tag doesn't clobber it. */ + hold_last_name = di->last_name; + + while (peek = d_peek_char (di), + peek == 'B') + { + struct demangle_component *tag; + d_advance (di, 1); + tag = d_source_name (di); + dc = d_make_comp (di, DEMANGLE_COMPONENT_TAGGED_NAME, dc, tag); + } + + di->last_name = hold_last_name; + + return dc; +} + +/* ::= + ::= + ::= + ::= + + ::= + ::= St + + ::= + ::= +*/ + +static struct demangle_component * +d_name (struct d_info *di, int substable) +{ + char peek = d_peek_char (di); + struct demangle_component *dc = NULL; + struct demangle_component *module = NULL; + int subst = 0; + + switch (peek) + { + case 'N': + dc = d_nested_name (di); + break; + + case 'Z': + dc = d_local_name (di); + break; + + case 'U': + dc = d_unqualified_name (di, NULL, NULL); + break; + + case 'S': + { + if (d_peek_next_char (di) == 't') + { + d_advance (di, 2); + dc = d_make_name (di, "std", 3); + di->expansion += 3; + } + + if (d_peek_char (di) == 'S') + { + module = d_substitution (di, 0); + if (!module) + return NULL; + if (!(module->type == DEMANGLE_COMPONENT_MODULE_NAME + || module->type == DEMANGLE_COMPONENT_MODULE_PARTITION)) + { + if (dc) + return NULL; + subst = 1; + dc = module; + module = NULL; + } + } + } + /* FALLTHROUGH */ + + case 'L': + default: + if (!subst) + dc = d_unqualified_name (di, dc, module); + if (d_peek_char (di) == 'I') + { + /* This is , which means that we just saw + , which is a substitution + candidate. */ + if (!subst && !d_add_substitution (di, dc)) + return NULL; + dc = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, dc, + d_template_args (di)); + subst = 0; + } + break; + } + if (substable && !subst && !d_add_substitution (di, dc)) + return NULL; + return dc; +} + +/* ::= N [] [] E + ::= N [] [] E +*/ + +static struct demangle_component * +d_nested_name (struct d_info *di) +{ + struct demangle_component *ret; + struct demangle_component **pret; + struct demangle_component *rqual; + + if (! d_check_char (di, 'N')) + return NULL; + + pret = d_cv_qualifiers (di, &ret, 1); + if (pret == NULL) + return NULL; + + /* Parse the ref-qualifier now and then attach it + once we have something to attach it to. */ + rqual = d_ref_qualifier (di, NULL); + + *pret = d_prefix (di, 1); + if (*pret == NULL) + return NULL; + + if (rqual) + { + d_left (rqual) = ret; + ret = rqual; + } + + if (! d_check_char (di, 'E')) + return NULL; + + return ret; +} + +/* ::= + ::= + ::= + ::= + ::= + ::= + + ::= <(template) unqualified-name> + ::= + ::= + + SUBST is true if we should add substitutions (as normal), false + if not (in an unresolved-name). */ + +static struct demangle_component * +d_prefix (struct d_info *di, int substable) +{ + struct demangle_component *ret = NULL; + + for (;;) + { + char peek = d_peek_char (di); + + /* The older code accepts a here, but I don't see + that in the grammar. The older code does not accept a + here. */ + + if (peek == 'D' + && (d_peek_next_char (di) == 'T' + || d_peek_next_char (di) == 't')) + { + /* Decltype. */ + if (ret) + return NULL; + ret = cplus_demangle_type (di); + } + else if (peek == 'I') + { + if (ret == NULL) + return NULL; + struct demangle_component *dc = d_template_args (di); + if (!dc) + return NULL; + ret = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, ret, dc); + } + else if (peek == 'T') + { + if (ret) + return NULL; + ret = d_template_param (di); + } + else if (peek == 'M') + { + /* Initializer scope for a lambda. We already added it as a + substitution candidate, don't do that again. */ + d_advance (di, 1); + continue; + } + else + { + struct demangle_component *module = NULL; + if (peek == 'S') + { + module = d_substitution (di, 1); + if (!module) + return NULL; + if (!(module->type == DEMANGLE_COMPONENT_MODULE_NAME + || module->type == DEMANGLE_COMPONENT_MODULE_PARTITION)) + { + if (ret) + return NULL; + ret = module; + continue; + } + } + ret = d_unqualified_name (di, ret, module); + } + + if (!ret) + break; + + if (d_peek_char (di) == 'E') + break; + + if (substable && !d_add_substitution (di, ret)) + return NULL; + } + + return ret; +} + +static int +d_maybe_module_name (struct d_info *di, struct demangle_component **name) +{ + while (d_peek_char (di) == 'W') + { + d_advance (di, 1); + enum demangle_component_type code = DEMANGLE_COMPONENT_MODULE_NAME; + if (d_peek_char (di) == 'P') + { + code = DEMANGLE_COMPONENT_MODULE_PARTITION; + d_advance (di, 1); + } + + *name = d_make_comp (di, code, *name, d_source_name (di)); + if (!*name) + return 0; + if (!d_add_substitution (di, *name)) + return 0; + } + return 1; +} + +/* ::= [] [] + ::= [] [] + ::= [] [] + ::= [] [] + ::= [] DC + E [] + ::= L [] +*/ + +static struct demangle_component * +d_unqualified_name (struct d_info *di, struct demangle_component *scope, + struct demangle_component *module) +{ + struct demangle_component *ret; + char peek; + + if (!d_maybe_module_name (di, &module)) + return NULL; + + peek = d_peek_char (di); + if (IS_DIGIT (peek)) + ret = d_source_name (di); + else if (IS_LOWER (peek)) + { + int was_expr = di->is_expression; + if (peek == 'o' && d_peek_next_char (di) == 'n') + { + d_advance (di, 2); + /* Treat cv as naming a conversion operator. */ + di->is_expression = 0; + } + ret = d_operator_name (di); + di->is_expression = was_expr; + if (ret != NULL && ret->type == DEMANGLE_COMPONENT_OPERATOR) + { + di->expansion += sizeof "operator" + ret->u.s_operator.op->len - 2; + if (!strcmp (ret->u.s_operator.op->code, "li")) + ret = d_make_comp (di, DEMANGLE_COMPONENT_UNARY, ret, + d_source_name (di)); + } + } + else if (peek == 'D' && d_peek_next_char (di) == 'C') + { + // structured binding + d_advance (di, 2); + struct demangle_component *prev = NULL; + do + { + struct demangle_component *next = + d_make_comp (di, DEMANGLE_COMPONENT_STRUCTURED_BINDING, + d_source_name (di), NULL); + if (prev) + d_right (prev) = next; + else + ret = next; + prev = next; + } + while (prev && d_peek_char (di) != 'E'); + if (prev) + d_advance (di, 1); + else + ret = NULL; + } + else if (peek == 'C' || peek == 'D') + ret = d_ctor_dtor_name (di); + else if (peek == 'L') + { + d_advance (di, 1); + + ret = d_source_name (di); + if (ret == NULL) + return NULL; + if (! d_discriminator (di)) + return NULL; + } + else if (peek == 'U') + { + switch (d_peek_next_char (di)) + { + case 'l': + ret = d_lambda (di); + break; + case 't': + ret = d_unnamed_type (di); + break; + default: + return NULL; + } + } + else + return NULL; + + if (module) + ret = d_make_comp (di, DEMANGLE_COMPONENT_MODULE_ENTITY, ret, module); + if (d_peek_char (di) == 'B') + ret = d_abi_tags (di, ret); + if (scope) + ret = d_make_comp (di, DEMANGLE_COMPONENT_QUAL_NAME, scope, ret); + + return ret; +} + +/* ::= <(positive length) number> */ + +static struct demangle_component * +d_source_name (struct d_info *di) +{ + int len; + struct demangle_component *ret; + + len = d_number (di); + if (len <= 0) + return NULL; + ret = d_identifier (di, len); + di->last_name = ret; + return ret; +} + +/* number ::= [n] <(non-negative decimal integer)> */ + +static int +d_number (struct d_info *di) +{ + int negative; + char peek; + int ret; + + negative = 0; + peek = d_peek_char (di); + if (peek == 'n') + { + negative = 1; + d_advance (di, 1); + peek = d_peek_char (di); + } + + ret = 0; + while (1) + { + if (! IS_DIGIT (peek)) + { + if (negative) + ret = - ret; + return ret; + } + if (ret > ((INT_MAX - (peek - '0')) / 10)) + return -1; + ret = ret * 10 + (peek - '0'); + d_advance (di, 1); + peek = d_peek_char (di); + } +} + +/* Like d_number, but returns a demangle_component. */ + +static struct demangle_component * +d_number_component (struct d_info *di) +{ + struct demangle_component *ret = d_make_empty (di); + if (ret) + { + ret->type = DEMANGLE_COMPONENT_NUMBER; + ret->u.s_number.number = d_number (di); + } + return ret; +} + +/* identifier ::= <(unqualified source code identifier)> */ + +static struct demangle_component * +d_identifier (struct d_info *di, int len) +{ + const char *name; + + name = d_str (di); + + if (di->send - name < len) + return NULL; + + d_advance (di, len); + + /* A Java mangled name may have a trailing '$' if it is a C++ + keyword. This '$' is not included in the length count. We just + ignore the '$'. */ + if ((di->options & DMGL_JAVA) != 0 + && d_peek_char (di) == '$') + d_advance (di, 1); + + /* Look for something which looks like a gcc encoding of an + anonymous namespace, and replace it with a more user friendly + name. */ + if (len >= (int) ANONYMOUS_NAMESPACE_PREFIX_LEN + 2 + && memcmp (name, ANONYMOUS_NAMESPACE_PREFIX, + ANONYMOUS_NAMESPACE_PREFIX_LEN) == 0) + { + const char *s; + + s = name + ANONYMOUS_NAMESPACE_PREFIX_LEN; + if ((*s == '.' || *s == '_' || *s == '$') + && s[1] == 'N') + { + di->expansion -= len - sizeof "(anonymous namespace)"; + return d_make_name (di, "(anonymous namespace)", + sizeof "(anonymous namespace)" - 1); + } + } + + return d_make_name (di, name, len); +} + +/* operator_name ::= many different two character encodings. + ::= cv + ::= v + + This list is sorted for binary search. */ + +#define NL(s) s, (sizeof s) - 1 + +CP_STATIC_IF_GLIBCPP_V3 +const struct demangle_operator_info cplus_demangle_operators[] = +{ + { "aN", NL ("&="), 2 }, + { "aS", NL ("="), 2 }, + { "aa", NL ("&&"), 2 }, + { "ad", NL ("&"), 1 }, + { "an", NL ("&"), 2 }, + { "at", NL ("alignof "), 1 }, + { "aw", NL ("co_await "), 1 }, + { "az", NL ("alignof "), 1 }, + { "cc", NL ("const_cast"), 2 }, + { "cl", NL ("()"), 2 }, + { "cm", NL (","), 2 }, + { "co", NL ("~"), 1 }, + { "dV", NL ("/="), 2 }, + { "dX", NL ("[...]="), 3 }, /* [expr...expr] = expr */ + { "da", NL ("delete[] "), 1 }, + { "dc", NL ("dynamic_cast"), 2 }, + { "de", NL ("*"), 1 }, + { "di", NL ("="), 2 }, /* .name = expr */ + { "dl", NL ("delete "), 1 }, + { "ds", NL (".*"), 2 }, + { "dt", NL ("."), 2 }, + { "dv", NL ("/"), 2 }, + { "dx", NL ("]="), 2 }, /* [expr] = expr */ + { "eO", NL ("^="), 2 }, + { "eo", NL ("^"), 2 }, + { "eq", NL ("=="), 2 }, + { "fL", NL ("..."), 3 }, + { "fR", NL ("..."), 3 }, + { "fl", NL ("..."), 2 }, + { "fr", NL ("..."), 2 }, + { "ge", NL (">="), 2 }, + { "gs", NL ("::"), 1 }, + { "gt", NL (">"), 2 }, + { "ix", NL ("[]"), 2 }, + { "lS", NL ("<<="), 2 }, + { "le", NL ("<="), 2 }, + { "li", NL ("operator\"\" "), 1 }, + { "ls", NL ("<<"), 2 }, + { "lt", NL ("<"), 2 }, + { "mI", NL ("-="), 2 }, + { "mL", NL ("*="), 2 }, + { "mi", NL ("-"), 2 }, + { "ml", NL ("*"), 2 }, + { "mm", NL ("--"), 1 }, + { "na", NL ("new[]"), 3 }, + { "ne", NL ("!="), 2 }, + { "ng", NL ("-"), 1 }, + { "nt", NL ("!"), 1 }, + { "nw", NL ("new"), 3 }, + { "oR", NL ("|="), 2 }, + { "oo", NL ("||"), 2 }, + { "or", NL ("|"), 2 }, + { "pL", NL ("+="), 2 }, + { "pl", NL ("+"), 2 }, + { "pm", NL ("->*"), 2 }, + { "pp", NL ("++"), 1 }, + { "ps", NL ("+"), 1 }, + { "pt", NL ("->"), 2 }, + { "qu", NL ("?"), 3 }, + { "rM", NL ("%="), 2 }, + { "rS", NL (">>="), 2 }, + { "rc", NL ("reinterpret_cast"), 2 }, + { "rm", NL ("%"), 2 }, + { "rs", NL (">>"), 2 }, + { "sP", NL ("sizeof..."), 1 }, + { "sZ", NL ("sizeof..."), 1 }, + { "sc", NL ("static_cast"), 2 }, + { "ss", NL ("<=>"), 2 }, + { "st", NL ("sizeof "), 1 }, + { "sz", NL ("sizeof "), 1 }, + { "tr", NL ("throw"), 0 }, + { "tw", NL ("throw "), 1 }, + { NULL, NULL, 0, 0 } +}; + +static struct demangle_component * +d_operator_name (struct d_info *di) +{ + char c1; + char c2; + + c1 = d_next_char (di); + c2 = d_next_char (di); + if (c1 == 'v' && IS_DIGIT (c2)) + return d_make_extended_operator (di, c2 - '0', d_source_name (di)); + else if (c1 == 'c' && c2 == 'v') + { + struct demangle_component *type; + int was_conversion = di->is_conversion; + struct demangle_component *res; + + di->is_conversion = ! di->is_expression; + type = cplus_demangle_type (di); + if (di->is_conversion) + res = d_make_comp (di, DEMANGLE_COMPONENT_CONVERSION, type, NULL); + else + res = d_make_comp (di, DEMANGLE_COMPONENT_CAST, type, NULL); + di->is_conversion = was_conversion; + return res; + } + else + { + /* LOW is the inclusive lower bound. */ + int low = 0; + /* HIGH is the exclusive upper bound. We subtract one to ignore + the sentinel at the end of the array. */ + int high = ((sizeof (cplus_demangle_operators) + / sizeof (cplus_demangle_operators[0])) + - 1); + + while (1) + { + int i; + const struct demangle_operator_info *p; + + i = low + (high - low) / 2; + p = cplus_demangle_operators + i; + + if (c1 == p->code[0] && c2 == p->code[1]) + return d_make_operator (di, p); + + if (c1 < p->code[0] || (c1 == p->code[0] && c2 < p->code[1])) + high = i; + else + low = i + 1; + if (low == high) + return NULL; + } + } +} + +static struct demangle_component * +d_make_character (struct d_info *di, int c) +{ + struct demangle_component *p; + p = d_make_empty (di); + if (p != NULL) + { + p->type = DEMANGLE_COMPONENT_CHARACTER; + p->u.s_character.character = c; + } + return p; +} + +static struct demangle_component * +d_java_resource (struct d_info *di) +{ + struct demangle_component *p = NULL; + struct demangle_component *next = NULL; + int len, i; + char c; + const char *str; + + len = d_number (di); + if (len <= 1) + return NULL; + + /* Eat the leading '_'. */ + if (d_next_char (di) != '_') + return NULL; + len--; + + str = d_str (di); + i = 0; + + while (len > 0) + { + c = str[i]; + if (!c) + return NULL; + + /* Each chunk is either a '$' escape... */ + if (c == '$') + { + i++; + switch (str[i++]) + { + case 'S': + c = '/'; + break; + case '_': + c = '.'; + break; + case '$': + c = '$'; + break; + default: + return NULL; + } + next = d_make_character (di, c); + d_advance (di, i); + str = d_str (di); + len -= i; + i = 0; + if (next == NULL) + return NULL; + } + /* ... or a sequence of characters. */ + else + { + while (i < len && str[i] && str[i] != '$') + i++; + + next = d_make_name (di, str, i); + d_advance (di, i); + str = d_str (di); + len -= i; + i = 0; + if (next == NULL) + return NULL; + } + + if (p == NULL) + p = next; + else + { + p = d_make_comp (di, DEMANGLE_COMPONENT_COMPOUND_NAME, p, next); + if (p == NULL) + return NULL; + } + } + + p = d_make_comp (di, DEMANGLE_COMPONENT_JAVA_RESOURCE, p, NULL); + + return p; +} + +/* ::= TV + ::= TT + ::= TI + ::= TS + ::= TA + ::= GV <(object) name> + ::= T <(base) encoding> + ::= Tc <(base) encoding> + Also g++ extensions: + ::= TC <(offset) number> _ <(base) type> + ::= TF + ::= TJ + ::= GR + ::= GA + ::= Gr + ::= GTt + ::= GTn +*/ + +static struct demangle_component * +d_special_name (struct d_info *di) +{ + di->expansion += 20; + if (d_check_char (di, 'T')) + { + switch (d_next_char (di)) + { + case 'V': + di->expansion -= 5; + return d_make_comp (di, DEMANGLE_COMPONENT_VTABLE, + cplus_demangle_type (di), NULL); + case 'T': + di->expansion -= 10; + return d_make_comp (di, DEMANGLE_COMPONENT_VTT, + cplus_demangle_type (di), NULL); + case 'I': + return d_make_comp (di, DEMANGLE_COMPONENT_TYPEINFO, + cplus_demangle_type (di), NULL); + case 'S': + return d_make_comp (di, DEMANGLE_COMPONENT_TYPEINFO_NAME, + cplus_demangle_type (di), NULL); + + case 'h': + if (! d_call_offset (di, 'h')) + return NULL; + return d_make_comp (di, DEMANGLE_COMPONENT_THUNK, + d_encoding (di, 0), NULL); + + case 'v': + if (! d_call_offset (di, 'v')) + return NULL; + return d_make_comp (di, DEMANGLE_COMPONENT_VIRTUAL_THUNK, + d_encoding (di, 0), NULL); + + case 'c': + if (! d_call_offset (di, '\0')) + return NULL; + if (! d_call_offset (di, '\0')) + return NULL; + return d_make_comp (di, DEMANGLE_COMPONENT_COVARIANT_THUNK, + d_encoding (di, 0), NULL); + + case 'C': + { + struct demangle_component *derived_type; + int offset; + struct demangle_component *base_type; + + derived_type = cplus_demangle_type (di); + offset = d_number (di); + if (offset < 0) + return NULL; + if (! d_check_char (di, '_')) + return NULL; + base_type = cplus_demangle_type (di); + /* We don't display the offset. FIXME: We should display + it in verbose mode. */ + di->expansion += 5; + return d_make_comp (di, DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE, + base_type, derived_type); + } + + case 'F': + return d_make_comp (di, DEMANGLE_COMPONENT_TYPEINFO_FN, + cplus_demangle_type (di), NULL); + case 'J': + return d_make_comp (di, DEMANGLE_COMPONENT_JAVA_CLASS, + cplus_demangle_type (di), NULL); + + case 'H': + return d_make_comp (di, DEMANGLE_COMPONENT_TLS_INIT, + d_name (di, 0), NULL); + + case 'W': + return d_make_comp (di, DEMANGLE_COMPONENT_TLS_WRAPPER, + d_name (di, 0), NULL); + + case 'A': + return d_make_comp (di, DEMANGLE_COMPONENT_TPARM_OBJ, + d_template_arg (di), NULL); + + default: + return NULL; + } + } + else if (d_check_char (di, 'G')) + { + switch (d_next_char (di)) + { + case 'V': + return d_make_comp (di, DEMANGLE_COMPONENT_GUARD, + d_name (di, 0), NULL); + + case 'R': + { + struct demangle_component *name = d_name (di, 0); + return d_make_comp (di, DEMANGLE_COMPONENT_REFTEMP, name, + d_number_component (di)); + } + + case 'A': + return d_make_comp (di, DEMANGLE_COMPONENT_HIDDEN_ALIAS, + d_encoding (di, 0), NULL); + + case 'I': + { + struct demangle_component *module = NULL; + if (!d_maybe_module_name (di, &module) || !module) + return NULL; + return d_make_comp (di, DEMANGLE_COMPONENT_MODULE_INIT, + module, NULL); + } + case 'T': + switch (d_next_char (di)) + { + case 'n': + return d_make_comp (di, DEMANGLE_COMPONENT_NONTRANSACTION_CLONE, + d_encoding (di, 0), NULL); + default: + /* ??? The proposal is that other letters (such as 'h') stand + for different variants of transaction cloning, such as + compiling directly for hardware transaction support. But + they still should all be transactional clones of some sort + so go ahead and call them that. */ + case 't': + return d_make_comp (di, DEMANGLE_COMPONENT_TRANSACTION_CLONE, + d_encoding (di, 0), NULL); + } + + case 'r': + return d_java_resource (di); + + default: + return NULL; + } + } + else + return NULL; +} + +/* ::= h _ + ::= v _ + + ::= <(offset) number> + + ::= <(offset) number> _ <(virtual offset) number> + + The C parameter, if not '\0', is a character we just read which is + the start of the . + + We don't display the offset information anywhere. FIXME: We should + display it in verbose mode. */ + +static int +d_call_offset (struct d_info *di, int c) +{ + if (c == '\0') + c = d_next_char (di); + + if (c == 'h') + d_number (di); + else if (c == 'v') + { + d_number (di); + if (! d_check_char (di, '_')) + return 0; + d_number (di); + } + else + return 0; + + if (! d_check_char (di, '_')) + return 0; + + return 1; +} + +/* ::= C1 + ::= C2 + ::= C3 + ::= D0 + ::= D1 + ::= D2 +*/ + +static struct demangle_component * +d_ctor_dtor_name (struct d_info *di) +{ + if (di->last_name != NULL) + { + if (di->last_name->type == DEMANGLE_COMPONENT_NAME) + di->expansion += di->last_name->u.s_name.len; + else if (di->last_name->type == DEMANGLE_COMPONENT_SUB_STD) + di->expansion += di->last_name->u.s_string.len; + } + switch (d_peek_char (di)) + { + case 'C': + { + enum gnu_v3_ctor_kinds kind; + int inheriting = 0; + + if (d_peek_next_char (di) == 'I') + { + inheriting = 1; + d_advance (di, 1); + } + + switch (d_peek_next_char (di)) + { + case '1': + kind = gnu_v3_complete_object_ctor; + break; + case '2': + kind = gnu_v3_base_object_ctor; + break; + case '3': + kind = gnu_v3_complete_object_allocating_ctor; + break; + case '4': + kind = gnu_v3_unified_ctor; + break; + case '5': + kind = gnu_v3_object_ctor_group; + break; + default: + return NULL; + } + + d_advance (di, 2); + + if (inheriting) + cplus_demangle_type (di); + + return d_make_ctor (di, kind, di->last_name); + } + + case 'D': + { + enum gnu_v3_dtor_kinds kind; + + switch (d_peek_next_char (di)) + { + case '0': + kind = gnu_v3_deleting_dtor; + break; + case '1': + kind = gnu_v3_complete_object_dtor; + break; + case '2': + kind = gnu_v3_base_object_dtor; + break; + /* digit '3' is not used */ + case '4': + kind = gnu_v3_unified_dtor; + break; + case '5': + kind = gnu_v3_object_dtor_group; + break; + default: + return NULL; + } + d_advance (di, 2); + return d_make_dtor (di, kind, di->last_name); + } + + default: + return NULL; + } +} + +/* True iff we're looking at an order-insensitive type-qualifier, including + function-type-qualifiers. */ + +static int +next_is_type_qual (struct d_info *di) +{ + char peek = d_peek_char (di); + if (peek == 'r' || peek == 'V' || peek == 'K') + return 1; + if (peek == 'D') + { + peek = d_peek_next_char (di); + if (peek == 'x' || peek == 'o' || peek == 'O' || peek == 'w') + return 1; + } + return 0; +} + +/* ::= + ::= + ::= + ::= + ::= + ::= + ::= + ::= + ::= + ::= P + ::= R + ::= O (C++0x) + ::= C + ::= G + ::= U + + ::= various one letter codes + ::= u +*/ + +CP_STATIC_IF_GLIBCPP_V3 +const struct demangle_builtin_type_info +cplus_demangle_builtin_types[D_BUILTIN_TYPE_COUNT] = +{ + /* a */ { NL ("signed char"), NL ("signed char"), D_PRINT_DEFAULT }, + /* b */ { NL ("bool"), NL ("boolean"), D_PRINT_BOOL }, + /* c */ { NL ("char"), NL ("byte"), D_PRINT_DEFAULT }, + /* d */ { NL ("double"), NL ("double"), D_PRINT_FLOAT }, + /* e */ { NL ("long double"), NL ("long double"), D_PRINT_FLOAT }, + /* f */ { NL ("float"), NL ("float"), D_PRINT_FLOAT }, + /* g */ { NL ("__float128"), NL ("__float128"), D_PRINT_FLOAT }, + /* h */ { NL ("unsigned char"), NL ("unsigned char"), D_PRINT_DEFAULT }, + /* i */ { NL ("int"), NL ("int"), D_PRINT_INT }, + /* j */ { NL ("unsigned int"), NL ("unsigned"), D_PRINT_UNSIGNED }, + /* k */ { NULL, 0, NULL, 0, D_PRINT_DEFAULT }, + /* l */ { NL ("long"), NL ("long"), D_PRINT_LONG }, + /* m */ { NL ("unsigned long"), NL ("unsigned long"), D_PRINT_UNSIGNED_LONG }, + /* n */ { NL ("__int128"), NL ("__int128"), D_PRINT_DEFAULT }, + /* o */ { NL ("unsigned __int128"), NL ("unsigned __int128"), + D_PRINT_DEFAULT }, + /* p */ { NULL, 0, NULL, 0, D_PRINT_DEFAULT }, + /* q */ { NULL, 0, NULL, 0, D_PRINT_DEFAULT }, + /* r */ { NULL, 0, NULL, 0, D_PRINT_DEFAULT }, + /* s */ { NL ("short"), NL ("short"), D_PRINT_DEFAULT }, + /* t */ { NL ("unsigned short"), NL ("unsigned short"), D_PRINT_DEFAULT }, + /* u */ { NULL, 0, NULL, 0, D_PRINT_DEFAULT }, + /* v */ { NL ("void"), NL ("void"), D_PRINT_VOID }, + /* w */ { NL ("wchar_t"), NL ("char"), D_PRINT_DEFAULT }, + /* x */ { NL ("long long"), NL ("long"), D_PRINT_LONG_LONG }, + /* y */ { NL ("unsigned long long"), NL ("unsigned long long"), + D_PRINT_UNSIGNED_LONG_LONG }, + /* z */ { NL ("..."), NL ("..."), D_PRINT_DEFAULT }, + /* 26 */ { NL ("decimal32"), NL ("decimal32"), D_PRINT_DEFAULT }, + /* 27 */ { NL ("decimal64"), NL ("decimal64"), D_PRINT_DEFAULT }, + /* 28 */ { NL ("decimal128"), NL ("decimal128"), D_PRINT_DEFAULT }, + /* 29 */ { NL ("half"), NL ("half"), D_PRINT_FLOAT }, + /* 30 */ { NL ("char8_t"), NL ("char8_t"), D_PRINT_DEFAULT }, + /* 31 */ { NL ("char16_t"), NL ("char16_t"), D_PRINT_DEFAULT }, + /* 32 */ { NL ("char32_t"), NL ("char32_t"), D_PRINT_DEFAULT }, + /* 33 */ { NL ("decltype(nullptr)"), NL ("decltype(nullptr)"), + D_PRINT_DEFAULT }, + /* 34 */ { NL ("_Float"), NL ("_Float"), D_PRINT_FLOAT }, + /* 35 */ { NL ("std::bfloat16_t"), NL ("std::bfloat16_t"), D_PRINT_FLOAT }, +}; + +CP_STATIC_IF_GLIBCPP_V3 +struct demangle_component * +cplus_demangle_type (struct d_info *di) +{ + char peek; + struct demangle_component *ret; + int can_subst; + + /* The ABI specifies that when CV-qualifiers are used, the base type + is substitutable, and the fully qualified type is substitutable, + but the base type with a strict subset of the CV-qualifiers is + not substitutable. The natural recursive implementation of the + CV-qualifiers would cause subsets to be substitutable, so instead + we pull them all off now. + + FIXME: The ABI says that order-insensitive vendor qualifiers + should be handled in the same way, but we have no way to tell + which vendor qualifiers are order-insensitive and which are + order-sensitive. So we just assume that they are all + order-sensitive. g++ 3.4 supports only one vendor qualifier, + __vector, and it treats it as order-sensitive when mangling + names. */ + + if (next_is_type_qual (di)) + { + struct demangle_component **pret; + + pret = d_cv_qualifiers (di, &ret, 0); + if (pret == NULL) + return NULL; + if (d_peek_char (di) == 'F') + { + /* cv-qualifiers before a function type apply to 'this', + so avoid adding the unqualified function type to + the substitution list. */ + *pret = d_function_type (di); + } + else + *pret = cplus_demangle_type (di); + if (!*pret) + return NULL; + if ((*pret)->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS + || (*pret)->type == DEMANGLE_COMPONENT_REFERENCE_THIS) + { + /* Move the ref-qualifier outside the cv-qualifiers so that + they are printed in the right order. */ + struct demangle_component *fn = d_left (*pret); + d_left (*pret) = ret; + ret = *pret; + *pret = fn; + } + if (! d_add_substitution (di, ret)) + return NULL; + return ret; + } + + can_subst = 1; + + peek = d_peek_char (di); + switch (peek) + { + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': + case 'h': case 'i': case 'j': case 'l': case 'm': case 'n': + case 'o': case 's': case 't': + case 'v': case 'w': case 'x': case 'y': case 'z': + ret = d_make_builtin_type (di, + &cplus_demangle_builtin_types[peek - 'a']); + di->expansion += ret->u.s_builtin.type->len; + can_subst = 0; + d_advance (di, 1); + break; + + case 'u': + d_advance (di, 1); + ret = d_make_comp (di, DEMANGLE_COMPONENT_VENDOR_TYPE, + d_source_name (di), NULL); + break; + + case 'F': + ret = d_function_type (di); + break; + + case 'A': + ret = d_array_type (di); + break; + + case 'M': + ret = d_pointer_to_member_type (di); + break; + + case 'T': + ret = d_template_param (di); + if (d_peek_char (di) == 'I') + { + /* This may be . + If this is the type for a conversion operator, we can + have a here only by following + a derivation like this: + + + -> + -> + -> + -> + -> + -> cv + -> cv + + where the is followed by another. + Otherwise, we must have a derivation like this: + + + -> + -> + -> + -> + -> + -> cv + -> cv + + where we need to leave the to be processed + by d_prefix (following the ). + + The part is a substitution + candidate. */ + if (! di->is_conversion) + { + if (! d_add_substitution (di, ret)) + return NULL; + ret = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, ret, + d_template_args (di)); + } + else + { + struct demangle_component *args; + struct d_info_checkpoint checkpoint; + + d_checkpoint (di, &checkpoint); + args = d_template_args (di); + if (d_peek_char (di) == 'I') + { + if (! d_add_substitution (di, ret)) + return NULL; + ret = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, ret, + args); + } + else + d_backtrack (di, &checkpoint); + } + } + break; + + case 'O': + d_advance (di, 1); + ret = d_make_comp (di, DEMANGLE_COMPONENT_RVALUE_REFERENCE, + cplus_demangle_type (di), NULL); + break; + + case 'P': + d_advance (di, 1); + ret = d_make_comp (di, DEMANGLE_COMPONENT_POINTER, + cplus_demangle_type (di), NULL); + break; + + case 'R': + d_advance (di, 1); + ret = d_make_comp (di, DEMANGLE_COMPONENT_REFERENCE, + cplus_demangle_type (di), NULL); + break; + + case 'C': + d_advance (di, 1); + ret = d_make_comp (di, DEMANGLE_COMPONENT_COMPLEX, + cplus_demangle_type (di), NULL); + break; + + case 'G': + d_advance (di, 1); + ret = d_make_comp (di, DEMANGLE_COMPONENT_IMAGINARY, + cplus_demangle_type (di), NULL); + break; + + case 'U': + d_advance (di, 1); + ret = d_source_name (di); + if (d_peek_char (di) == 'I') + ret = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, ret, + d_template_args (di)); + ret = d_make_comp (di, DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL, + cplus_demangle_type (di), ret); + break; + + case 'D': + can_subst = 0; + d_advance (di, 1); + peek = d_next_char (di); + switch (peek) + { + case 'T': + case 't': + /* decltype (expression) */ + ret = d_make_comp (di, DEMANGLE_COMPONENT_DECLTYPE, + d_expression (di), NULL); + if (ret && d_next_char (di) != 'E') + ret = NULL; + can_subst = 1; + break; + + case 'p': + /* Pack expansion. */ + ret = d_make_comp (di, DEMANGLE_COMPONENT_PACK_EXPANSION, + cplus_demangle_type (di), NULL); + can_subst = 1; + break; + + case 'a': + /* auto */ + ret = d_make_name (di, "auto", 4); + break; + case 'c': + /* decltype(auto) */ + ret = d_make_name (di, "decltype(auto)", 14); + break; + + case 'f': + /* 32-bit decimal floating point */ + ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[26]); + di->expansion += ret->u.s_builtin.type->len; + break; + case 'd': + /* 64-bit DFP */ + ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[27]); + di->expansion += ret->u.s_builtin.type->len; + break; + case 'e': + /* 128-bit DFP */ + ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[28]); + di->expansion += ret->u.s_builtin.type->len; + break; + case 'h': + /* 16-bit half-precision FP */ + ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[29]); + di->expansion += ret->u.s_builtin.type->len; + break; + case 'u': + /* char8_t */ + ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[30]); + di->expansion += ret->u.s_builtin.type->len; + break; + case 's': + /* char16_t */ + ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[31]); + di->expansion += ret->u.s_builtin.type->len; + break; + case 'i': + /* char32_t */ + ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[32]); + di->expansion += ret->u.s_builtin.type->len; + break; + + case 'F': + /* DF_ - _Float. + DFx - _Floatx + DF16b - std::bfloat16_t. */ + { + int arg = d_number (di); + char buf[12]; + char suffix = 0; + if (d_peek_char (di) == 'b') + { + if (arg != 16) + return NULL; + d_advance (di, 1); + ret = d_make_builtin_type (di, + &cplus_demangle_builtin_types[35]); + di->expansion += ret->u.s_builtin.type->len; + break; + } + if (d_peek_char (di) == 'x') + suffix = 'x'; + if (!suffix && d_peek_char (di) != '_') + return NULL; + ret + = d_make_extended_builtin_type (di, + &cplus_demangle_builtin_types[34], + arg, suffix); + d_advance (di, 1); + sprintf (buf, "%d", arg); + di->expansion += ret->u.s_extended_builtin.type->len + + strlen (buf) + (suffix != 0); + break; + } + + case 'v': + ret = d_vector_type (di); + can_subst = 1; + break; + + case 'n': + /* decltype(nullptr) */ + ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[33]); + di->expansion += ret->u.s_builtin.type->len; + break; + + default: + return NULL; + } + break; + + default: + return d_class_enum_type (di, 1); + } + + if (can_subst) + { + if (! d_add_substitution (di, ret)) + return NULL; + } + + return ret; +} + +/* ::= [r] [V] [K] [Dx] */ + +static struct demangle_component ** +d_cv_qualifiers (struct d_info *di, + struct demangle_component **pret, int member_fn) +{ + struct demangle_component **pstart; + char peek; + + pstart = pret; + peek = d_peek_char (di); + while (next_is_type_qual (di)) + { + enum demangle_component_type t; + struct demangle_component *right = NULL; + + d_advance (di, 1); + if (peek == 'r') + { + t = (member_fn + ? DEMANGLE_COMPONENT_RESTRICT_THIS + : DEMANGLE_COMPONENT_RESTRICT); + di->expansion += sizeof "restrict"; + } + else if (peek == 'V') + { + t = (member_fn + ? DEMANGLE_COMPONENT_VOLATILE_THIS + : DEMANGLE_COMPONENT_VOLATILE); + di->expansion += sizeof "volatile"; + } + else if (peek == 'K') + { + t = (member_fn + ? DEMANGLE_COMPONENT_CONST_THIS + : DEMANGLE_COMPONENT_CONST); + di->expansion += sizeof "const"; + } + else + { + peek = d_next_char (di); + if (peek == 'x') + { + t = DEMANGLE_COMPONENT_TRANSACTION_SAFE; + di->expansion += sizeof "transaction_safe"; + } + else if (peek == 'o' + || peek == 'O') + { + t = DEMANGLE_COMPONENT_NOEXCEPT; + di->expansion += sizeof "noexcept"; + if (peek == 'O') + { + right = d_expression (di); + if (right == NULL) + return NULL; + if (! d_check_char (di, 'E')) + return NULL; + } + } + else if (peek == 'w') + { + t = DEMANGLE_COMPONENT_THROW_SPEC; + di->expansion += sizeof "throw"; + right = d_parmlist (di); + if (right == NULL) + return NULL; + if (! d_check_char (di, 'E')) + return NULL; + } + else + return NULL; + } + + *pret = d_make_comp (di, t, NULL, right); + if (*pret == NULL) + return NULL; + pret = &d_left (*pret); + + peek = d_peek_char (di); + } + + if (!member_fn && peek == 'F') + { + while (pstart != pret) + { + switch ((*pstart)->type) + { + case DEMANGLE_COMPONENT_RESTRICT: + (*pstart)->type = DEMANGLE_COMPONENT_RESTRICT_THIS; + break; + case DEMANGLE_COMPONENT_VOLATILE: + (*pstart)->type = DEMANGLE_COMPONENT_VOLATILE_THIS; + break; + case DEMANGLE_COMPONENT_CONST: + (*pstart)->type = DEMANGLE_COMPONENT_CONST_THIS; + break; + default: + break; + } + pstart = &d_left (*pstart); + } + } + + return pret; +} + +/* ::= R + ::= O */ + +static struct demangle_component * +d_ref_qualifier (struct d_info *di, struct demangle_component *sub) +{ + struct demangle_component *ret = sub; + char peek; + + peek = d_peek_char (di); + if (peek == 'R' || peek == 'O') + { + enum demangle_component_type t; + if (peek == 'R') + { + t = DEMANGLE_COMPONENT_REFERENCE_THIS; + di->expansion += sizeof "&"; + } + else + { + t = DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS; + di->expansion += sizeof "&&"; + } + d_advance (di, 1); + + ret = d_make_comp (di, t, ret, NULL); + } + + return ret; +} + +/* ::= F [Y] [] [T] E */ + +static struct demangle_component * +d_function_type (struct d_info *di) +{ + struct demangle_component *ret = NULL; + + if ((di->options & DMGL_NO_RECURSE_LIMIT) == 0) + { + if (di->recursion_level > DEMANGLE_RECURSION_LIMIT) + /* FIXME: There ought to be a way to report + that the recursion limit has been reached. */ + return NULL; + + di->recursion_level ++; + } + + if (d_check_char (di, 'F')) + { + if (d_peek_char (di) == 'Y') + { + /* Function has C linkage. We don't print this information. + FIXME: We should print it in verbose mode. */ + d_advance (di, 1); + } + ret = d_bare_function_type (di, 1); + ret = d_ref_qualifier (di, ret); + + if (! d_check_char (di, 'E')) + ret = NULL; + } + + if ((di->options & DMGL_NO_RECURSE_LIMIT) == 0) + di->recursion_level --; + return ret; +} + +/* + */ + +static struct demangle_component * +d_parmlist (struct d_info *di) +{ + struct demangle_component *tl; + struct demangle_component **ptl; + + tl = NULL; + ptl = &tl; + while (1) + { + struct demangle_component *type; + + char peek = d_peek_char (di); + if (peek == '\0' || peek == 'E' || peek == '.') + break; + if ((peek == 'R' || peek == 'O') + && d_peek_next_char (di) == 'E') + /* Function ref-qualifier, not a ref prefix for a parameter type. */ + break; + type = cplus_demangle_type (di); + if (type == NULL) + return NULL; + *ptl = d_make_comp (di, DEMANGLE_COMPONENT_ARGLIST, type, NULL); + if (*ptl == NULL) + return NULL; + ptl = &d_right (*ptl); + } + + /* There should be at least one parameter type besides the optional + return type. A function which takes no arguments will have a + single parameter type void. */ + if (tl == NULL) + return NULL; + + /* If we have a single parameter type void, omit it. */ + if (d_right (tl) == NULL + && d_left (tl)->type == DEMANGLE_COMPONENT_BUILTIN_TYPE + && d_left (tl)->u.s_builtin.type->print == D_PRINT_VOID) + { + di->expansion -= d_left (tl)->u.s_builtin.type->len; + d_left (tl) = NULL; + } + + return tl; +} + +/* ::= [J]+ */ + +static struct demangle_component * +d_bare_function_type (struct d_info *di, int has_return_type) +{ + struct demangle_component *return_type; + struct demangle_component *tl; + char peek; + + /* Detect special qualifier indicating that the first argument + is the return type. */ + peek = d_peek_char (di); + if (peek == 'J') + { + d_advance (di, 1); + has_return_type = 1; + } + + if (has_return_type) + { + return_type = cplus_demangle_type (di); + if (return_type == NULL) + return NULL; + } + else + return_type = NULL; + + tl = d_parmlist (di); + if (tl == NULL) + return NULL; + + return d_make_comp (di, DEMANGLE_COMPONENT_FUNCTION_TYPE, + return_type, tl); +} + +/* ::= */ + +static struct demangle_component * +d_class_enum_type (struct d_info *di, int substable) +{ + return d_name (di, substable); +} + +/* ::= A <(positive dimension) number> _ <(element) type> + ::= A [<(dimension) expression>] _ <(element) type> +*/ + +static struct demangle_component * +d_array_type (struct d_info *di) +{ + char peek; + struct demangle_component *dim; + + if (! d_check_char (di, 'A')) + return NULL; + + peek = d_peek_char (di); + if (peek == '_') + dim = NULL; + else if (IS_DIGIT (peek)) + { + const char *s; + + s = d_str (di); + do + { + d_advance (di, 1); + peek = d_peek_char (di); + } + while (IS_DIGIT (peek)); + dim = d_make_name (di, s, d_str (di) - s); + if (dim == NULL) + return NULL; + } + else + { + dim = d_expression (di); + if (dim == NULL) + return NULL; + } + + if (! d_check_char (di, '_')) + return NULL; + + return d_make_comp (di, DEMANGLE_COMPONENT_ARRAY_TYPE, dim, + cplus_demangle_type (di)); +} + +/* ::= Dv _ + ::= Dv _ _ */ + +static struct demangle_component * +d_vector_type (struct d_info *di) +{ + char peek; + struct demangle_component *dim; + + peek = d_peek_char (di); + if (peek == '_') + { + d_advance (di, 1); + dim = d_expression (di); + } + else + dim = d_number_component (di); + + if (dim == NULL) + return NULL; + + if (! d_check_char (di, '_')) + return NULL; + + return d_make_comp (di, DEMANGLE_COMPONENT_VECTOR_TYPE, dim, + cplus_demangle_type (di)); +} + +/* ::= M <(class) type> <(member) type> */ + +static struct demangle_component * +d_pointer_to_member_type (struct d_info *di) +{ + struct demangle_component *cl; + struct demangle_component *mem; + + if (! d_check_char (di, 'M')) + return NULL; + + cl = cplus_demangle_type (di); + if (cl == NULL) + return NULL; + + /* The ABI says, "The type of a non-static member function is considered + to be different, for the purposes of substitution, from the type of a + namespace-scope or static member function whose type appears + similar. The types of two non-static member functions are considered + to be different, for the purposes of substitution, if the functions + are members of different classes. In other words, for the purposes of + substitution, the class of which the function is a member is + considered part of the type of function." + + For a pointer to member function, this call to cplus_demangle_type + will end up adding a (possibly qualified) non-member function type to + the substitution table, which is not correct; however, the member + function type will never be used in a substitution, so putting the + wrong type in the substitution table is harmless. */ + + mem = cplus_demangle_type (di); + if (mem == NULL) + return NULL; + + return d_make_comp (di, DEMANGLE_COMPONENT_PTRMEM_TYPE, cl, mem); +} + +/* _ */ + +static int +d_compact_number (struct d_info *di) +{ + int num; + if (d_peek_char (di) == '_') + num = 0; + else if (d_peek_char (di) == 'n') + return -1; + else + num = d_number (di) + 1; + + if (num < 0 || ! d_check_char (di, '_')) + return -1; + return num; +} + +/* ::= T_ + ::= T <(parameter-2 non-negative) number> _ +*/ + +static struct demangle_component * +d_template_param (struct d_info *di) +{ + int param; + + if (! d_check_char (di, 'T')) + return NULL; + + param = d_compact_number (di); + if (param < 0) + return NULL; + + return d_make_template_param (di, param); +} + +/* ::= I + E */ + +static struct demangle_component * +d_template_args (struct d_info *di) +{ + if (d_peek_char (di) != 'I' + && d_peek_char (di) != 'J') + return NULL; + d_advance (di, 1); + + return d_template_args_1 (di); +} + +/* * E */ + +static struct demangle_component * +d_template_args_1 (struct d_info *di) +{ + struct demangle_component *hold_last_name; + struct demangle_component *al; + struct demangle_component **pal; + + /* Preserve the last name we saw--don't let the template arguments + clobber it, as that would give us the wrong name for a subsequent + constructor or destructor. */ + hold_last_name = di->last_name; + + if (d_peek_char (di) == 'E') + { + /* An argument pack can be empty. */ + d_advance (di, 1); + return d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE_ARGLIST, NULL, NULL); + } + + al = NULL; + pal = &al; + while (1) + { + struct demangle_component *a; + + a = d_template_arg (di); + if (a == NULL) + return NULL; + + *pal = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE_ARGLIST, a, NULL); + if (*pal == NULL) + return NULL; + pal = &d_right (*pal); + + if (d_peek_char (di) == 'E') + { + d_advance (di, 1); + break; + } + } + + di->last_name = hold_last_name; + + return al; +} + +/* ::= + ::= X E + ::= +*/ + +static struct demangle_component * +d_template_arg (struct d_info *di) +{ + struct demangle_component *ret; + + switch (d_peek_char (di)) + { + case 'X': + d_advance (di, 1); + ret = d_expression (di); + if (! d_check_char (di, 'E')) + return NULL; + return ret; + + case 'L': + return d_expr_primary (di); + + case 'I': + case 'J': + /* An argument pack. */ + return d_template_args (di); + + default: + return cplus_demangle_type (di); + } +} + +/* Parse a sequence of expressions until we hit the terminator + character. */ + +static struct demangle_component * +d_exprlist (struct d_info *di, char terminator) +{ + struct demangle_component *list = NULL; + struct demangle_component **p = &list; + + if (d_peek_char (di) == terminator) + { + d_advance (di, 1); + return d_make_comp (di, DEMANGLE_COMPONENT_ARGLIST, NULL, NULL); + } + + while (1) + { + struct demangle_component *arg = d_expression (di); + if (arg == NULL) + return NULL; + + *p = d_make_comp (di, DEMANGLE_COMPONENT_ARGLIST, arg, NULL); + if (*p == NULL) + return NULL; + p = &d_right (*p); + + if (d_peek_char (di) == terminator) + { + d_advance (di, 1); + break; + } + } + + return list; +} + +/* Returns nonzero iff OP is an operator for a C++ cast: const_cast, + dynamic_cast, static_cast or reinterpret_cast. */ + +static int +op_is_new_cast (struct demangle_component *op) +{ + const char *code = op->u.s_operator.op->code; + return (code[1] == 'c' + && (code[0] == 's' || code[0] == 'd' + || code[0] == 'c' || code[0] == 'r')); +} + +/* ::= [gs] # x or (with "gs") ::x + ::= sr # T::x / decltype(p)::x + # T::N::x /decltype(p)::N::x + ::= srN + E + # A::x, N::y, A::z; "gs" means leading "::" + ::= [gs] sr + E + + "gs" is handled elsewhere, as a unary operator. */ + +static struct demangle_component * +d_unresolved_name (struct d_info *di) +{ + struct demangle_component *type; + struct demangle_component *name; + char peek; + + /* Consume the "sr". */ + d_advance (di, 2); + + peek = d_peek_char (di); + if (di->unresolved_name_state + && (IS_DIGIT (peek) + || IS_LOWER (peek) + || peek == 'C' + || peek == 'U' + || peek == 'L')) + { + /* The third production is ambiguous with the old unresolved-name syntax + of ; in the old mangling, A::x was mangled + as sr1A1x, now sr1AE1x. So we first try to demangle using the new + mangling, then with the old if that fails. */ + di->unresolved_name_state = -1; + type = d_prefix (di, 0); + if (d_peek_char (di) == 'E') + d_advance (di, 1); + } + else + type = cplus_demangle_type (di); + name = d_unqualified_name (di, type, NULL); + if (d_peek_char (di) == 'I') + name = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, name, + d_template_args (di)); + return name; +} + +/* ::= <(unary) operator-name> + ::= <(binary) operator-name> + ::= <(trinary) operator-name> + ::= cl + E + ::= st + ::= + ::= u * E # vendor extended expression + ::= + ::= + + ::= + ::= di # .name = expr + ::= dx # [expr] = expr + ::= dX + # [expr ... expr] = expr +*/ + +static struct demangle_component * +d_expression_1 (struct d_info *di) +{ + char peek; + + peek = d_peek_char (di); + if (peek == 'L') + return d_expr_primary (di); + else if (peek == 'T') + return d_template_param (di); + else if (peek == 's' && d_peek_next_char (di) == 'r') + return d_unresolved_name (di); + else if (peek == 's' && d_peek_next_char (di) == 'p') + { + d_advance (di, 2); + return d_make_comp (di, DEMANGLE_COMPONENT_PACK_EXPANSION, + d_expression_1 (di), NULL); + } + else if (peek == 'f' && d_peek_next_char (di) == 'p') + { + /* Function parameter used in a late-specified return type. */ + int index; + d_advance (di, 2); + if (d_peek_char (di) == 'T') + { + /* 'this' parameter. */ + d_advance (di, 1); + index = 0; + } + else + { + index = d_compact_number (di); + if (index == INT_MAX || index == -1) + return NULL; + index++; + } + return d_make_function_param (di, index); + } + else if (IS_DIGIT (peek) + || (peek == 'o' && d_peek_next_char (di) == 'n')) + { + /* We can get an unqualified name as an expression in the case of + a dependent function call, i.e. decltype(f(t)). */ + struct demangle_component *name; + + if (peek == 'o') + /* operator-function-id, i.e. operator+(t). */ + d_advance (di, 2); + + name = d_unqualified_name (di, NULL, NULL); + if (name == NULL) + return NULL; + if (d_peek_char (di) == 'I') + return d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, name, + d_template_args (di)); + else + return name; + } + else if ((peek == 'i' || peek == 't') + && d_peek_next_char (di) == 'l') + { + /* Brace-enclosed initializer list, untyped or typed. */ + struct demangle_component *type = NULL; + d_advance (di, 2); + if (peek == 't') + type = cplus_demangle_type (di); + if (!d_peek_char (di) || !d_peek_next_char (di)) + return NULL; + return d_make_comp (di, DEMANGLE_COMPONENT_INITIALIZER_LIST, + type, d_exprlist (di, 'E')); + } + else if (peek == 'u') + { + /* A vendor extended expression. */ + struct demangle_component *name, *args; + d_advance (di, 1); + name = d_source_name (di); + args = d_template_args_1 (di); + return d_make_comp (di, DEMANGLE_COMPONENT_VENDOR_EXPR, name, args); + } + else + { + struct demangle_component *op; + const char *code = NULL; + int args; + + op = d_operator_name (di); + if (op == NULL) + return NULL; + + if (op->type == DEMANGLE_COMPONENT_OPERATOR) + { + code = op->u.s_operator.op->code; + di->expansion += op->u.s_operator.op->len - 2; + if (strcmp (code, "st") == 0) + return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op, + cplus_demangle_type (di)); + } + + switch (op->type) + { + default: + return NULL; + case DEMANGLE_COMPONENT_OPERATOR: + args = op->u.s_operator.op->args; + break; + case DEMANGLE_COMPONENT_EXTENDED_OPERATOR: + args = op->u.s_extended_operator.args; + break; + case DEMANGLE_COMPONENT_CAST: + args = 1; + break; + } + + switch (args) + { + case 0: + return d_make_comp (di, DEMANGLE_COMPONENT_NULLARY, op, NULL); + + case 1: + { + struct demangle_component *operand; + int suffix = 0; + + if (code && (code[0] == 'p' || code[0] == 'm') + && code[1] == code[0]) + /* pp_ and mm_ are the prefix variants. */ + suffix = !d_check_char (di, '_'); + + if (op->type == DEMANGLE_COMPONENT_CAST + && d_check_char (di, '_')) + operand = d_exprlist (di, 'E'); + else if (code && !strcmp (code, "sP")) + operand = d_template_args_1 (di); + else + operand = d_expression_1 (di); + + if (suffix) + /* Indicate the suffix variant for d_print_comp. */ + operand = d_make_comp (di, DEMANGLE_COMPONENT_BINARY_ARGS, + operand, operand); + + return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op, operand); + } + case 2: + { + struct demangle_component *left; + struct demangle_component *right; + + if (code == NULL) + return NULL; + if (op_is_new_cast (op)) + left = cplus_demangle_type (di); + else if (code[0] == 'f') + /* fold-expression. */ + left = d_operator_name (di); + else if (!strcmp (code, "di")) + left = d_unqualified_name (di, NULL, NULL); + else + left = d_expression_1 (di); + if (!strcmp (code, "cl")) + right = d_exprlist (di, 'E'); + else if (!strcmp (code, "dt") || !strcmp (code, "pt")) + { + peek = d_peek_char (di); + /* These codes start a qualified name. */ + if ((peek == 'g' && d_peek_next_char (di) == 's') + || (peek == 's' && d_peek_next_char (di) == 'r')) + right = d_expression_1 (di); + else + { + /* Otherwise it's an unqualified name. We use + d_unqualified_name rather than d_expression_1 here for + old mangled names that didn't add 'on' before operator + names. */ + right = d_unqualified_name (di, NULL, NULL); + if (d_peek_char (di) == 'I') + right = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, + right, d_template_args (di)); + } + } + else + right = d_expression_1 (di); + + return d_make_comp (di, DEMANGLE_COMPONENT_BINARY, op, + d_make_comp (di, + DEMANGLE_COMPONENT_BINARY_ARGS, + left, right)); + } + case 3: + { + struct demangle_component *first; + struct demangle_component *second; + struct demangle_component *third; + + if (code == NULL) + return NULL; + else if (!strcmp (code, "qu") + || !strcmp (code, "dX")) + { + /* ?: expression. */ + first = d_expression_1 (di); + second = d_expression_1 (di); + third = d_expression_1 (di); + if (third == NULL) + return NULL; + } + else if (code[0] == 'f') + { + /* fold-expression. */ + first = d_operator_name (di); + second = d_expression_1 (di); + third = d_expression_1 (di); + if (third == NULL) + return NULL; + } + else if (code[0] == 'n') + { + /* new-expression. */ + if (code[1] != 'w' && code[1] != 'a') + return NULL; + first = d_exprlist (di, '_'); + second = cplus_demangle_type (di); + if (d_peek_char (di) == 'E') + { + d_advance (di, 1); + third = NULL; + } + else if (d_peek_char (di) == 'p' + && d_peek_next_char (di) == 'i') + { + /* Parenthesized initializer. */ + d_advance (di, 2); + third = d_exprlist (di, 'E'); + } + else if (d_peek_char (di) == 'i' + && d_peek_next_char (di) == 'l') + /* initializer-list. */ + third = d_expression_1 (di); + else + return NULL; + } + else + return NULL; + return d_make_comp (di, DEMANGLE_COMPONENT_TRINARY, op, + d_make_comp (di, + DEMANGLE_COMPONENT_TRINARY_ARG1, + first, + d_make_comp (di, + DEMANGLE_COMPONENT_TRINARY_ARG2, + second, third))); + } + default: + return NULL; + } + } +} + +static struct demangle_component * +d_expression (struct d_info *di) +{ + struct demangle_component *ret; + int was_expression = di->is_expression; + + di->is_expression = 1; + ret = d_expression_1 (di); + di->is_expression = was_expression; + return ret; +} + +/* ::= L <(value) number> E + ::= L <(value) float> E + ::= L E +*/ + +static struct demangle_component * +d_expr_primary (struct d_info *di) +{ + struct demangle_component *ret; + + if (! d_check_char (di, 'L')) + return NULL; + if (d_peek_char (di) == '_' + /* Workaround for G++ bug; see comment in write_template_arg. */ + || d_peek_char (di) == 'Z') + ret = cplus_demangle_mangled_name (di, 0); + else + { + struct demangle_component *type; + enum demangle_component_type t; + const char *s; + + type = cplus_demangle_type (di); + if (type == NULL) + return NULL; + + /* If we have a type we know how to print, we aren't going to + print the type name itself. */ + if (type->type == DEMANGLE_COMPONENT_BUILTIN_TYPE + && type->u.s_builtin.type->print != D_PRINT_DEFAULT) + di->expansion -= type->u.s_builtin.type->len; + + if (type->type == DEMANGLE_COMPONENT_BUILTIN_TYPE + && strcmp (type->u.s_builtin.type->name, + cplus_demangle_builtin_types[33].name) == 0) + { + if (d_peek_char (di) == 'E') + { + d_advance (di, 1); + return type; + } + } + + /* Rather than try to interpret the literal value, we just + collect it as a string. Note that it's possible to have a + floating point literal here. The ABI specifies that the + format of such literals is machine independent. That's fine, + but what's not fine is that versions of g++ up to 3.2 with + -fabi-version=1 used upper case letters in the hex constant, + and dumped out gcc's internal representation. That makes it + hard to tell where the constant ends, and hard to dump the + constant in any readable form anyhow. We don't attempt to + handle these cases. */ + + t = DEMANGLE_COMPONENT_LITERAL; + if (d_peek_char (di) == 'n') + { + t = DEMANGLE_COMPONENT_LITERAL_NEG; + d_advance (di, 1); + } + s = d_str (di); + while (d_peek_char (di) != 'E') + { + if (d_peek_char (di) == '\0') + return NULL; + d_advance (di, 1); + } + ret = d_make_comp (di, t, type, d_make_name (di, s, d_str (di) - s)); + } + if (! d_check_char (di, 'E')) + return NULL; + return ret; +} + +/* ::= Z <(function) encoding> E <(entity) name> [] + ::= Z <(function) encoding> E s [] + ::= Z <(function) encoding> E d [ number>] _ +*/ + +static struct demangle_component * +d_local_name (struct d_info *di) +{ + struct demangle_component *function; + struct demangle_component *name; + + if (! d_check_char (di, 'Z')) + return NULL; + + function = d_encoding (di, 0); + if (!function) + return NULL; + + if (! d_check_char (di, 'E')) + return NULL; + + if (d_peek_char (di) == 's') + { + d_advance (di, 1); + if (! d_discriminator (di)) + return NULL; + name = d_make_name (di, "string literal", sizeof "string literal" - 1); + } + else + { + int num = -1; + + if (d_peek_char (di) == 'd') + { + /* Default argument scope: d _. */ + d_advance (di, 1); + num = d_compact_number (di); + if (num < 0) + return NULL; + } + + name = d_name (di, 0); + + if (name + /* Lambdas and unnamed types have internal discriminators + and are not functions. */ + && name->type != DEMANGLE_COMPONENT_LAMBDA + && name->type != DEMANGLE_COMPONENT_UNNAMED_TYPE) + { + /* Read and ignore an optional discriminator. */ + if (! d_discriminator (di)) + return NULL; + } + + if (num >= 0) + name = d_make_default_arg (di, num, name); + } + + /* Elide the return type of the containing function so as to not + confuse the user thinking it is the return type of whatever local + function we might be containing. */ + if (function->type == DEMANGLE_COMPONENT_TYPED_NAME + && d_right (function)->type == DEMANGLE_COMPONENT_FUNCTION_TYPE) + d_left (d_right (function)) = NULL; + + return d_make_comp (di, DEMANGLE_COMPONENT_LOCAL_NAME, function, name); +} + +/* ::= _ # when number < 10 + ::= __ _ # when number >= 10 + + ::= _ # when number >=10 + is also accepted to support gcc versions that wrongly mangled that way. + + We demangle the discriminator, but we don't print it out. FIXME: + We should print it out in verbose mode. */ + +static int +d_discriminator (struct d_info *di) +{ + int discrim, num_underscores = 1; + + if (d_peek_char (di) != '_') + return 1; + d_advance (di, 1); + if (d_peek_char (di) == '_') + { + ++num_underscores; + d_advance (di, 1); + } + + discrim = d_number (di); + if (discrim < 0) + return 0; + if (num_underscores > 1 && discrim >= 10) + { + if (d_peek_char (di) == '_') + d_advance (di, 1); + else + return 0; + } + + return 1; +} + +/* ::= Ty + ::= Tn + ::= Tt E + ::= Tp */ + +static struct demangle_component * +d_template_parm (struct d_info *di, int *bad) +{ + if (d_peek_char (di) != 'T') + return NULL; + + struct demangle_component *op; + enum demangle_component_type kind; + switch (d_peek_next_char (di)) + { + default: + return NULL; + + case 'p': /* Pack */ + d_advance (di, 2); + op = d_template_parm (di, bad); + kind = DEMANGLE_COMPONENT_TEMPLATE_PACK_PARM; + if (!op) + { + *bad = 1; + return NULL; + } + break; + + case 'y': /* Typename */ + d_advance (di, 2); + op = NULL; + kind = DEMANGLE_COMPONENT_TEMPLATE_TYPE_PARM; + break; + + case 'n': /* Non-Type */ + d_advance (di, 2); + op = cplus_demangle_type (di); + kind = DEMANGLE_COMPONENT_TEMPLATE_NON_TYPE_PARM; + if (!op) + { + *bad = 1; + return NULL; + } + break; + + case 't': /* Template */ + d_advance (di, 2); + op = d_template_head (di, bad); + kind = DEMANGLE_COMPONENT_TEMPLATE_TEMPLATE_PARM; + if (!op || !d_check_char (di, 'E')) + { + *bad = 1; + return NULL; + } + } + + return d_make_comp (di, kind, op, NULL); +} + +/* ::= ? */ + +static struct demangle_component * +d_template_head (struct d_info *di, int *bad) +{ + struct demangle_component *res = NULL, **slot = &res; + struct demangle_component *op; + + while ((op = d_template_parm (di, bad))) + { + *slot = op; + slot = &d_right (op); + } + + /* Wrap it in a template head, to make concatenating with any parm list, and + printing simpler. */ + if (res) + res = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE_HEAD, res, NULL); + + return res; +} + +/* ::= Ul ? E [ ] _ */ + +static struct demangle_component * +d_lambda (struct d_info *di) +{ + if (! d_check_char (di, 'U')) + return NULL; + if (! d_check_char (di, 'l')) + return NULL; + + int bad = 0; + struct demangle_component *head = d_template_head (di, &bad); + if (bad) + return NULL; + + struct demangle_component *tl = d_parmlist (di); + if (tl == NULL) + return NULL; + if (head) + { + d_right (head) = tl; + tl = head; + } + + if (! d_check_char (di, 'E')) + return NULL; + + int num = d_compact_number (di); + if (num < 0) + return NULL; + + struct demangle_component *ret = d_make_empty (di); + if (ret) + { + ret->type = DEMANGLE_COMPONENT_LAMBDA; + ret->u.s_unary_num.sub = tl; + ret->u.s_unary_num.num = num; + } + + return ret; +} + +/* ::= Ut [ ] _ */ + +static struct demangle_component * +d_unnamed_type (struct d_info *di) +{ + struct demangle_component *ret; + int num; + + if (! d_check_char (di, 'U')) + return NULL; + if (! d_check_char (di, 't')) + return NULL; + + num = d_compact_number (di); + if (num < 0) + return NULL; + + ret = d_make_empty (di); + if (ret) + { + ret->type = DEMANGLE_COMPONENT_UNNAMED_TYPE; + ret->u.s_number.number = num; + } + + if (! d_add_substitution (di, ret)) + return NULL; + + return ret; +} + +/* ::= [ . ] [ . ]* +*/ + +static struct demangle_component * +d_clone_suffix (struct d_info *di, struct demangle_component *encoding) +{ + const char *suffix = d_str (di); + const char *pend = suffix; + struct demangle_component *n; + + if (*pend == '.' && (IS_LOWER (pend[1]) || IS_DIGIT (pend[1]) + || pend[1] == '_')) + { + pend += 2; + while (IS_LOWER (*pend) || IS_DIGIT (*pend) || *pend == '_') + ++pend; + } + while (*pend == '.' && IS_DIGIT (pend[1])) + { + pend += 2; + while (IS_DIGIT (*pend)) + ++pend; + } + d_advance (di, pend - suffix); + n = d_make_name (di, suffix, pend - suffix); + return d_make_comp (di, DEMANGLE_COMPONENT_CLONE, encoding, n); +} + +/* Add a new substitution. */ + +static int +d_add_substitution (struct d_info *di, struct demangle_component *dc) +{ + if (dc == NULL) + return 0; + if (di->next_sub >= di->num_subs) + return 0; + di->subs[di->next_sub] = dc; + ++di->next_sub; + return 1; +} + +/* ::= S _ + ::= S_ + ::= St + ::= Sa + ::= Sb + ::= Ss + ::= Si + ::= So + ::= Sd + + If PREFIX is non-zero, then this type is being used as a prefix in + a qualified name. In this case, for the standard substitutions, we + need to check whether we are being used as a prefix for a + constructor or destructor, and return a full template name. + Otherwise we will get something like std::iostream::~iostream() + which does not correspond particularly well to any function which + actually appears in the source. +*/ + +static const struct d_standard_sub_info standard_subs[] = +{ + { 't', NL ("std"), + NL ("std"), + NULL, 0 }, + { 'a', NL ("std::allocator"), + NL ("std::allocator"), + NL ("allocator") }, + { 'b', NL ("std::basic_string"), + NL ("std::basic_string"), + NL ("basic_string") }, + { 's', NL ("std::string"), + NL ("std::basic_string, std::allocator >"), + NL ("basic_string") }, + { 'i', NL ("std::istream"), + NL ("std::basic_istream >"), + NL ("basic_istream") }, + { 'o', NL ("std::ostream"), + NL ("std::basic_ostream >"), + NL ("basic_ostream") }, + { 'd', NL ("std::iostream"), + NL ("std::basic_iostream >"), + NL ("basic_iostream") } +}; + +static struct demangle_component * +d_substitution (struct d_info *di, int prefix) +{ + char c; + + if (! d_check_char (di, 'S')) + return NULL; + + c = d_next_char (di); + if (c == '_' || IS_DIGIT (c) || IS_UPPER (c)) + { + unsigned int id; + + id = 0; + if (c != '_') + { + do + { + unsigned int new_id; + + if (IS_DIGIT (c)) + new_id = id * 36 + c - '0'; + else if (IS_UPPER (c)) + new_id = id * 36 + c - 'A' + 10; + else + return NULL; + if (new_id < id) + return NULL; + id = new_id; + c = d_next_char (di); + } + while (c != '_'); + + ++id; + } + + if (id >= (unsigned int) di->next_sub) + return NULL; + + return di->subs[id]; + } + else + { + int verbose; + const struct d_standard_sub_info *p; + const struct d_standard_sub_info *pend; + + verbose = (di->options & DMGL_VERBOSE) != 0; + if (! verbose && prefix) + { + char peek; + + peek = d_peek_char (di); + if (peek == 'C' || peek == 'D') + verbose = 1; + } + + pend = (&standard_subs[0] + + sizeof standard_subs / sizeof standard_subs[0]); + for (p = &standard_subs[0]; p < pend; ++p) + { + if (c == p->code) + { + const char *s; + int len; + struct demangle_component *dc; + + if (p->set_last_name != NULL) + di->last_name = d_make_sub (di, p->set_last_name, + p->set_last_name_len); + if (verbose) + { + s = p->full_expansion; + len = p->full_len; + } + else + { + s = p->simple_expansion; + len = p->simple_len; + } + di->expansion += len; + dc = d_make_sub (di, s, len); + if (d_peek_char (di) == 'B') + { + /* If there are ABI tags on the abbreviation, it becomes + a substitution candidate. */ + dc = d_abi_tags (di, dc); + if (! d_add_substitution (di, dc)) + return NULL; + } + return dc; + } + } + + return NULL; + } +} + +static void +d_checkpoint (struct d_info *di, struct d_info_checkpoint *checkpoint) +{ + checkpoint->n = di->n; + checkpoint->next_comp = di->next_comp; + checkpoint->next_sub = di->next_sub; + checkpoint->expansion = di->expansion; +} + +static void +d_backtrack (struct d_info *di, struct d_info_checkpoint *checkpoint) +{ + di->n = checkpoint->n; + di->next_comp = checkpoint->next_comp; + di->next_sub = checkpoint->next_sub; + di->expansion = checkpoint->expansion; +} + +/* Initialize a growable string. */ + +static void +d_growable_string_init (struct d_growable_string *dgs, size_t estimate) +{ + dgs->buf = NULL; + dgs->len = 0; + dgs->alc = 0; + dgs->allocation_failure = 0; + + if (estimate > 0) + d_growable_string_resize (dgs, estimate); +} + +/* Grow a growable string to a given size. */ + +static inline void +d_growable_string_resize (struct d_growable_string *dgs, size_t need) +{ + size_t newalc; + char *newbuf; + + if (dgs->allocation_failure) + return; + + /* Start allocation at two bytes to avoid any possibility of confusion + with the special value of 1 used as a return in *palc to indicate + allocation failures. */ + newalc = dgs->alc > 0 ? dgs->alc : 2; + while (newalc < need) + newalc <<= 1; + + newbuf = (char *) realloc (dgs->buf, newalc); + if (newbuf == NULL) + { + free (dgs->buf); + dgs->buf = NULL; + dgs->len = 0; + dgs->alc = 0; + dgs->allocation_failure = 1; + return; + } + dgs->buf = newbuf; + dgs->alc = newalc; +} + +/* Append a buffer to a growable string. */ + +static inline void +d_growable_string_append_buffer (struct d_growable_string *dgs, + const char *s, size_t l) +{ + size_t need; + + need = dgs->len + l + 1; + if (need > dgs->alc) + d_growable_string_resize (dgs, need); + + if (dgs->allocation_failure) + return; + + memcpy (dgs->buf + dgs->len, s, l); + dgs->buf[dgs->len + l] = '\0'; + dgs->len += l; +} + +/* Bridge growable strings to the callback mechanism. */ + +static void +d_growable_string_callback_adapter (const char *s, size_t l, void *opaque) +{ + struct d_growable_string *dgs = (struct d_growable_string*) opaque; + + d_growable_string_append_buffer (dgs, s, l); +} + +/* Walk the tree, counting the number of templates encountered, and + the number of times a scope might be saved. These counts will be + used to allocate data structures for d_print_comp, so the logic + here must mirror the logic d_print_comp will use. It is not + important that the resulting numbers are exact, so long as they + are larger than the actual numbers encountered. */ + +static void +d_count_templates_scopes (struct d_print_info *dpi, + struct demangle_component *dc) +{ + if (dc == NULL || dc->d_counting > 1 || dpi->recursion > MAX_RECURSION_COUNT) + return; + + ++ dc->d_counting; + + switch (dc->type) + { + case DEMANGLE_COMPONENT_NAME: + case DEMANGLE_COMPONENT_TEMPLATE_PARAM: + case DEMANGLE_COMPONENT_FUNCTION_PARAM: + case DEMANGLE_COMPONENT_SUB_STD: + case DEMANGLE_COMPONENT_BUILTIN_TYPE: + case DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE: + case DEMANGLE_COMPONENT_OPERATOR: + case DEMANGLE_COMPONENT_CHARACTER: + case DEMANGLE_COMPONENT_NUMBER: + case DEMANGLE_COMPONENT_UNNAMED_TYPE: + case DEMANGLE_COMPONENT_STRUCTURED_BINDING: + case DEMANGLE_COMPONENT_MODULE_NAME: + case DEMANGLE_COMPONENT_MODULE_PARTITION: + case DEMANGLE_COMPONENT_MODULE_INIT: + case DEMANGLE_COMPONENT_FIXED_TYPE: + case DEMANGLE_COMPONENT_TEMPLATE_HEAD: + case DEMANGLE_COMPONENT_TEMPLATE_TYPE_PARM: + case DEMANGLE_COMPONENT_TEMPLATE_NON_TYPE_PARM: + case DEMANGLE_COMPONENT_TEMPLATE_TEMPLATE_PARM: + case DEMANGLE_COMPONENT_TEMPLATE_PACK_PARM: + break; + + case DEMANGLE_COMPONENT_TEMPLATE: + dpi->num_copy_templates++; + goto recurse_left_right; + + case DEMANGLE_COMPONENT_REFERENCE: + case DEMANGLE_COMPONENT_RVALUE_REFERENCE: + if (d_left (dc)->type == DEMANGLE_COMPONENT_TEMPLATE_PARAM) + dpi->num_saved_scopes++; + goto recurse_left_right; + + case DEMANGLE_COMPONENT_QUAL_NAME: + case DEMANGLE_COMPONENT_LOCAL_NAME: + case DEMANGLE_COMPONENT_TYPED_NAME: + case DEMANGLE_COMPONENT_VTABLE: + case DEMANGLE_COMPONENT_VTT: + case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE: + case DEMANGLE_COMPONENT_TYPEINFO: + case DEMANGLE_COMPONENT_TYPEINFO_NAME: + case DEMANGLE_COMPONENT_TYPEINFO_FN: + case DEMANGLE_COMPONENT_THUNK: + case DEMANGLE_COMPONENT_VIRTUAL_THUNK: + case DEMANGLE_COMPONENT_COVARIANT_THUNK: + case DEMANGLE_COMPONENT_JAVA_CLASS: + case DEMANGLE_COMPONENT_GUARD: + case DEMANGLE_COMPONENT_TLS_INIT: + case DEMANGLE_COMPONENT_TLS_WRAPPER: + case DEMANGLE_COMPONENT_REFTEMP: + case DEMANGLE_COMPONENT_HIDDEN_ALIAS: + case DEMANGLE_COMPONENT_RESTRICT: + case DEMANGLE_COMPONENT_VOLATILE: + case DEMANGLE_COMPONENT_CONST: + case DEMANGLE_COMPONENT_RESTRICT_THIS: + case DEMANGLE_COMPONENT_VOLATILE_THIS: + case DEMANGLE_COMPONENT_CONST_THIS: + case DEMANGLE_COMPONENT_REFERENCE_THIS: + case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS: + case DEMANGLE_COMPONENT_TRANSACTION_SAFE: + case DEMANGLE_COMPONENT_NOEXCEPT: + case DEMANGLE_COMPONENT_THROW_SPEC: + case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL: + case DEMANGLE_COMPONENT_POINTER: + case DEMANGLE_COMPONENT_COMPLEX: + case DEMANGLE_COMPONENT_IMAGINARY: + case DEMANGLE_COMPONENT_VENDOR_TYPE: + case DEMANGLE_COMPONENT_FUNCTION_TYPE: + case DEMANGLE_COMPONENT_ARRAY_TYPE: + case DEMANGLE_COMPONENT_PTRMEM_TYPE: + case DEMANGLE_COMPONENT_VECTOR_TYPE: + case DEMANGLE_COMPONENT_ARGLIST: + case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST: + case DEMANGLE_COMPONENT_TPARM_OBJ: + case DEMANGLE_COMPONENT_INITIALIZER_LIST: + case DEMANGLE_COMPONENT_CAST: + case DEMANGLE_COMPONENT_CONVERSION: + case DEMANGLE_COMPONENT_NULLARY: + case DEMANGLE_COMPONENT_UNARY: + case DEMANGLE_COMPONENT_BINARY: + case DEMANGLE_COMPONENT_BINARY_ARGS: + case DEMANGLE_COMPONENT_TRINARY: + case DEMANGLE_COMPONENT_TRINARY_ARG1: + case DEMANGLE_COMPONENT_TRINARY_ARG2: + case DEMANGLE_COMPONENT_LITERAL: + case DEMANGLE_COMPONENT_LITERAL_NEG: + case DEMANGLE_COMPONENT_VENDOR_EXPR: + case DEMANGLE_COMPONENT_JAVA_RESOURCE: + case DEMANGLE_COMPONENT_COMPOUND_NAME: + case DEMANGLE_COMPONENT_DECLTYPE: + case DEMANGLE_COMPONENT_TRANSACTION_CLONE: + case DEMANGLE_COMPONENT_NONTRANSACTION_CLONE: + case DEMANGLE_COMPONENT_PACK_EXPANSION: + case DEMANGLE_COMPONENT_TAGGED_NAME: + case DEMANGLE_COMPONENT_CLONE: + recurse_left_right: + /* PR 89394 - Check for too much recursion. */ + if (dpi->recursion > DEMANGLE_RECURSION_LIMIT) + /* FIXME: There ought to be a way to report to the + user that the recursion limit has been reached. */ + return; + + ++ dpi->recursion; + d_count_templates_scopes (dpi, d_left (dc)); + d_count_templates_scopes (dpi, d_right (dc)); + -- dpi->recursion; + break; + + case DEMANGLE_COMPONENT_CTOR: + d_count_templates_scopes (dpi, dc->u.s_ctor.name); + break; + + case DEMANGLE_COMPONENT_DTOR: + d_count_templates_scopes (dpi, dc->u.s_dtor.name); + break; + + case DEMANGLE_COMPONENT_EXTENDED_OPERATOR: + d_count_templates_scopes (dpi, dc->u.s_extended_operator.name); + break; + + case DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS: + case DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS: + case DEMANGLE_COMPONENT_MODULE_ENTITY: + d_count_templates_scopes (dpi, d_left (dc)); + break; + + case DEMANGLE_COMPONENT_LAMBDA: + case DEMANGLE_COMPONENT_DEFAULT_ARG: + d_count_templates_scopes (dpi, dc->u.s_unary_num.sub); + break; + } +} + +/* Initialize a print information structure. */ + +static void +d_print_init (struct d_print_info *dpi, demangle_callbackref callback, + void *opaque, struct demangle_component *dc) +{ + dpi->len = 0; + dpi->last_char = '\0'; + dpi->templates = NULL; + dpi->modifiers = NULL; + dpi->pack_index = 0; + dpi->flush_count = 0; + + dpi->callback = callback; + dpi->opaque = opaque; + + dpi->demangle_failure = 0; + dpi->recursion = 0; + dpi->lambda_tpl_parms = 0; + + dpi->component_stack = NULL; + + dpi->saved_scopes = NULL; + dpi->next_saved_scope = 0; + dpi->num_saved_scopes = 0; + + dpi->copy_templates = NULL; + dpi->next_copy_template = 0; + dpi->num_copy_templates = 0; + + d_count_templates_scopes (dpi, dc); + /* If we did not reach the recursion limit, then reset the + current recursion value back to 0, so that we can print + the templates. */ + if (dpi->recursion < DEMANGLE_RECURSION_LIMIT) + dpi->recursion = 0; + dpi->num_copy_templates *= dpi->num_saved_scopes; + + dpi->current_template = NULL; +} + +/* Indicate that an error occurred during printing, and test for error. */ + +static inline void +d_print_error (struct d_print_info *dpi) +{ + dpi->demangle_failure = 1; +} + +static inline int +d_print_saw_error (struct d_print_info *dpi) +{ + return dpi->demangle_failure != 0; +} + +/* Flush buffered characters to the callback. */ + +static inline void +d_print_flush (struct d_print_info *dpi) +{ + dpi->buf[dpi->len] = '\0'; + dpi->callback (dpi->buf, dpi->len, dpi->opaque); + dpi->len = 0; + dpi->flush_count++; +} + +/* Append characters and buffers for printing. */ + +static inline void +d_append_char (struct d_print_info *dpi, char c) +{ + if (dpi->len == sizeof (dpi->buf) - 1) + d_print_flush (dpi); + + dpi->buf[dpi->len++] = c; + dpi->last_char = c; +} + +static inline void +d_append_buffer (struct d_print_info *dpi, const char *s, size_t l) +{ + size_t i; + + for (i = 0; i < l; i++) + d_append_char (dpi, s[i]); +} + +static inline void +d_append_string (struct d_print_info *dpi, const char *s) +{ + d_append_buffer (dpi, s, strlen (s)); +} + +static inline void +d_append_num (struct d_print_info *dpi, int l) +{ + char buf[25]; + sprintf (buf,"%d", l); + d_append_string (dpi, buf); +} + +static inline char +d_last_char (struct d_print_info *dpi) +{ + return dpi->last_char; +} + +/* Turn components into a human readable string. OPTIONS is the + options bits passed to the demangler. DC is the tree to print. + CALLBACK is a function to call to flush demangled string segments + as they fill the intermediate buffer, and OPAQUE is a generalized + callback argument. On success, this returns 1. On failure, + it returns 0, indicating a bad parse. It does not use heap + memory to build an output string, so cannot encounter memory + allocation failure. */ + +CP_STATIC_IF_GLIBCPP_V3 +int +cplus_demangle_print_callback (int options, + struct demangle_component *dc, + demangle_callbackref callback, void *opaque) +{ + struct d_print_info dpi; + + d_print_init (&dpi, callback, opaque, dc); + + { +#ifdef CP_DYNAMIC_ARRAYS + /* Avoid zero-length VLAs, which are prohibited by the C99 standard + and flagged as errors by Address Sanitizer. */ + __extension__ struct d_saved_scope scopes[(dpi.num_saved_scopes > 0) + ? dpi.num_saved_scopes : 1]; + __extension__ struct d_print_template temps[(dpi.num_copy_templates > 0) + ? dpi.num_copy_templates : 1]; + + dpi.saved_scopes = scopes; + dpi.copy_templates = temps; +#else + dpi.saved_scopes = alloca (dpi.num_saved_scopes + * sizeof (*dpi.saved_scopes)); + dpi.copy_templates = alloca (dpi.num_copy_templates + * sizeof (*dpi.copy_templates)); +#endif + + d_print_comp (&dpi, options, dc); + } + + d_print_flush (&dpi); + + return ! d_print_saw_error (&dpi); +} + +/* Turn components into a human readable string. OPTIONS is the + options bits passed to the demangler. DC is the tree to print. + ESTIMATE is a guess at the length of the result. This returns a + string allocated by malloc, or NULL on error. On success, this + sets *PALC to the size of the allocated buffer. On failure, this + sets *PALC to 0 for a bad parse, or to 1 for a memory allocation + failure. */ + +CP_STATIC_IF_GLIBCPP_V3 +char * +cplus_demangle_print (int options, struct demangle_component *dc, + int estimate, size_t *palc) +{ + struct d_growable_string dgs; + + d_growable_string_init (&dgs, estimate); + + if (! cplus_demangle_print_callback (options, dc, + d_growable_string_callback_adapter, + &dgs)) + { + free (dgs.buf); + *palc = 0; + return NULL; + } + + *palc = dgs.allocation_failure ? 1 : dgs.alc; + return dgs.buf; +} + +/* Returns the I'th element of the template arglist ARGS, or NULL on + failure. If I is negative, return the entire arglist. */ + +static struct demangle_component * +d_index_template_argument (struct demangle_component *args, int i) +{ + struct demangle_component *a; + + if (i < 0) + /* Print the whole argument pack. */ + return args; + + for (a = args; + a != NULL; + a = d_right (a)) + { + if (a->type != DEMANGLE_COMPONENT_TEMPLATE_ARGLIST) + return NULL; + if (i <= 0) + break; + --i; + } + if (i != 0 || a == NULL) + return NULL; + + return d_left (a); +} + +/* Returns the template argument from the current context indicated by DC, + which is a DEMANGLE_COMPONENT_TEMPLATE_PARAM, or NULL. */ + +static struct demangle_component * +d_lookup_template_argument (struct d_print_info *dpi, + const struct demangle_component *dc) +{ + if (dpi->templates == NULL) + { + d_print_error (dpi); + return NULL; + } + + return d_index_template_argument + (d_right (dpi->templates->template_decl), + dc->u.s_number.number); +} + +/* Returns a template argument pack used in DC (any will do), or NULL. */ + +static struct demangle_component * +d_find_pack (struct d_print_info *dpi, + const struct demangle_component *dc) +{ + struct demangle_component *a; + if (dc == NULL) + return NULL; + + switch (dc->type) + { + case DEMANGLE_COMPONENT_TEMPLATE_PARAM: + a = d_lookup_template_argument (dpi, dc); + if (a && a->type == DEMANGLE_COMPONENT_TEMPLATE_ARGLIST) + return a; + return NULL; + + case DEMANGLE_COMPONENT_PACK_EXPANSION: + return NULL; + + case DEMANGLE_COMPONENT_LAMBDA: + case DEMANGLE_COMPONENT_NAME: + case DEMANGLE_COMPONENT_TAGGED_NAME: + case DEMANGLE_COMPONENT_OPERATOR: + case DEMANGLE_COMPONENT_BUILTIN_TYPE: + case DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE: + case DEMANGLE_COMPONENT_SUB_STD: + case DEMANGLE_COMPONENT_CHARACTER: + case DEMANGLE_COMPONENT_FUNCTION_PARAM: + case DEMANGLE_COMPONENT_UNNAMED_TYPE: + case DEMANGLE_COMPONENT_DEFAULT_ARG: + case DEMANGLE_COMPONENT_NUMBER: + return NULL; + + case DEMANGLE_COMPONENT_EXTENDED_OPERATOR: + return d_find_pack (dpi, dc->u.s_extended_operator.name); + case DEMANGLE_COMPONENT_CTOR: + return d_find_pack (dpi, dc->u.s_ctor.name); + case DEMANGLE_COMPONENT_DTOR: + return d_find_pack (dpi, dc->u.s_dtor.name); + + default: + a = d_find_pack (dpi, d_left (dc)); + if (a) + return a; + return d_find_pack (dpi, d_right (dc)); + } +} + +/* Returns the length of the template argument pack DC. */ + +static int +d_pack_length (const struct demangle_component *dc) +{ + int count = 0; + while (dc && dc->type == DEMANGLE_COMPONENT_TEMPLATE_ARGLIST + && d_left (dc) != NULL) + { + ++count; + dc = d_right (dc); + } + return count; +} + +/* Returns the number of template args in DC, expanding any pack expansions + found there. */ + +static int +d_args_length (struct d_print_info *dpi, const struct demangle_component *dc) +{ + int count = 0; + for (; dc && dc->type == DEMANGLE_COMPONENT_TEMPLATE_ARGLIST; + dc = d_right (dc)) + { + struct demangle_component *elt = d_left (dc); + if (elt == NULL) + break; + if (elt->type == DEMANGLE_COMPONENT_PACK_EXPANSION) + { + struct demangle_component *a = d_find_pack (dpi, d_left (elt)); + count += d_pack_length (a); + } + else + ++count; + } + return count; +} + +/* DC is a component of a mangled expression. Print it, wrapped in parens + if needed. */ + +static void +d_print_subexpr (struct d_print_info *dpi, int options, + struct demangle_component *dc) +{ + int simple = 0; + if (dc->type == DEMANGLE_COMPONENT_NAME + || dc->type == DEMANGLE_COMPONENT_QUAL_NAME + || dc->type == DEMANGLE_COMPONENT_INITIALIZER_LIST + || dc->type == DEMANGLE_COMPONENT_FUNCTION_PARAM) + simple = 1; + if (!simple) + d_append_char (dpi, '('); + d_print_comp (dpi, options, dc); + if (!simple) + d_append_char (dpi, ')'); +} + +/* Save the current scope. */ + +static void +d_save_scope (struct d_print_info *dpi, + const struct demangle_component *container) +{ + struct d_saved_scope *scope; + struct d_print_template *src, **link; + + if (dpi->next_saved_scope >= dpi->num_saved_scopes) + { + d_print_error (dpi); + return; + } + scope = &dpi->saved_scopes[dpi->next_saved_scope]; + dpi->next_saved_scope++; + + scope->container = container; + link = &scope->templates; + + for (src = dpi->templates; src != NULL; src = src->next) + { + struct d_print_template *dst; + + if (dpi->next_copy_template >= dpi->num_copy_templates) + { + d_print_error (dpi); + return; + } + dst = &dpi->copy_templates[dpi->next_copy_template]; + dpi->next_copy_template++; + + dst->template_decl = src->template_decl; + *link = dst; + link = &dst->next; + } + + *link = NULL; +} + +/* Attempt to locate a previously saved scope. Returns NULL if no + corresponding saved scope was found. */ + +static struct d_saved_scope * +d_get_saved_scope (struct d_print_info *dpi, + const struct demangle_component *container) +{ + int i; + + for (i = 0; i < dpi->next_saved_scope; i++) + if (dpi->saved_scopes[i].container == container) + return &dpi->saved_scopes[i]; + + return NULL; +} + +/* If DC is a C++17 fold-expression, print it and return true; otherwise + return false. */ + +static int +d_maybe_print_fold_expression (struct d_print_info *dpi, int options, + struct demangle_component *dc) +{ + struct demangle_component *ops, *operator_, *op1, *op2; + int save_idx; + + const char *fold_code = d_left (dc)->u.s_operator.op->code; + if (fold_code[0] != 'f') + return 0; + + ops = d_right (dc); + operator_ = d_left (ops); + op1 = d_right (ops); + op2 = 0; + if (op1->type == DEMANGLE_COMPONENT_TRINARY_ARG2) + { + op2 = d_right (op1); + op1 = d_left (op1); + } + + /* Print the whole pack. */ + save_idx = dpi->pack_index; + dpi->pack_index = -1; + + switch (fold_code[1]) + { + /* Unary left fold, (... + X). */ + case 'l': + d_append_string (dpi, "(..."); + d_print_expr_op (dpi, options, operator_); + d_print_subexpr (dpi, options, op1); + d_append_char (dpi, ')'); + break; + + /* Unary right fold, (X + ...). */ + case 'r': + d_append_char (dpi, '('); + d_print_subexpr (dpi, options, op1); + d_print_expr_op (dpi, options, operator_); + d_append_string (dpi, "...)"); + break; + + /* Binary left fold, (42 + ... + X). */ + case 'L': + /* Binary right fold, (X + ... + 42). */ + case 'R': + d_append_char (dpi, '('); + d_print_subexpr (dpi, options, op1); + d_print_expr_op (dpi, options, operator_); + d_append_string (dpi, "..."); + d_print_expr_op (dpi, options, operator_); + d_print_subexpr (dpi, options, op2); + d_append_char (dpi, ')'); + break; + } + + dpi->pack_index = save_idx; + return 1; +} + +/* True iff DC represents a C99-style designated initializer. */ + +static int +is_designated_init (struct demangle_component *dc) +{ + if (dc->type != DEMANGLE_COMPONENT_BINARY + && dc->type != DEMANGLE_COMPONENT_TRINARY) + return 0; + + struct demangle_component *op = d_left (dc); + const char *code = op->u.s_operator.op->code; + return (code[0] == 'd' + && (code[1] == 'i' || code[1] == 'x' || code[1] == 'X')); +} + +/* If DC represents a C99-style designated initializer, print it and return + true; otherwise, return false. */ + +static int +d_maybe_print_designated_init (struct d_print_info *dpi, int options, + struct demangle_component *dc) +{ + if (!is_designated_init (dc)) + return 0; + + const char *code = d_left (dc)->u.s_operator.op->code; + + struct demangle_component *operands = d_right (dc); + struct demangle_component *op1 = d_left (operands); + struct demangle_component *op2 = d_right (operands); + + if (code[1] == 'i') + d_append_char (dpi, '.'); + else + d_append_char (dpi, '['); + + d_print_comp (dpi, options, op1); + if (code[1] == 'X') + { + d_append_string (dpi, " ... "); + d_print_comp (dpi, options, d_left (op2)); + op2 = d_right (op2); + } + if (code[1] != 'i') + d_append_char (dpi, ']'); + if (is_designated_init (op2)) + { + /* Don't put '=' or '(' between chained designators. */ + d_print_comp (dpi, options, op2); + } + else + { + d_append_char (dpi, '='); + d_print_subexpr (dpi, options, op2); + } + return 1; +} + +static void +d_print_lambda_parm_name (struct d_print_info *dpi, int type, unsigned index) +{ + const char *str; + switch (type) + { + default: + dpi->demangle_failure = 1; + str = ""; + break; + + case DEMANGLE_COMPONENT_TEMPLATE_TYPE_PARM: + str = "$T"; + break; + + case DEMANGLE_COMPONENT_TEMPLATE_NON_TYPE_PARM: + str = "$N"; + break; + + case DEMANGLE_COMPONENT_TEMPLATE_TEMPLATE_PARM: + str = "$TT"; + break; + } + d_append_string (dpi, str); + d_append_num (dpi, index); +} + +/* Subroutine to handle components. */ + +static void +d_print_comp_inner (struct d_print_info *dpi, int options, + struct demangle_component *dc) +{ + /* Magic variable to let reference smashing skip over the next modifier + without needing to modify *dc. */ + struct demangle_component *mod_inner = NULL; + + /* Variable used to store the current templates while a previously + captured scope is used. */ + struct d_print_template *saved_templates; + + /* Nonzero if templates have been stored in the above variable. */ + int need_template_restore = 0; + + if (dc == NULL) + { + d_print_error (dpi); + return; + } + if (d_print_saw_error (dpi)) + return; + + switch (dc->type) + { + case DEMANGLE_COMPONENT_NAME: + if ((options & DMGL_JAVA) == 0) + d_append_buffer (dpi, dc->u.s_name.s, dc->u.s_name.len); + else + d_print_java_identifier (dpi, dc->u.s_name.s, dc->u.s_name.len); + return; + + case DEMANGLE_COMPONENT_TAGGED_NAME: + d_print_comp (dpi, options, d_left (dc)); + d_append_string (dpi, "[abi:"); + d_print_comp (dpi, options, d_right (dc)); + d_append_char (dpi, ']'); + return; + + case DEMANGLE_COMPONENT_STRUCTURED_BINDING: + d_append_char (dpi, '['); + for (;;) + { + d_print_comp (dpi, options, d_left (dc)); + dc = d_right (dc); + if (!dc) + break; + d_append_string (dpi, ", "); + } + d_append_char (dpi, ']'); + return; + + case DEMANGLE_COMPONENT_MODULE_ENTITY: + d_print_comp (dpi, options, d_left (dc)); + d_append_char (dpi, '@'); + d_print_comp (dpi, options, d_right (dc)); + return; + + case DEMANGLE_COMPONENT_MODULE_NAME: + case DEMANGLE_COMPONENT_MODULE_PARTITION: + { + if (d_left (dc)) + d_print_comp (dpi, options, d_left (dc)); + char c = dc->type == DEMANGLE_COMPONENT_MODULE_PARTITION + ? ':' : d_left (dc) ? '.' : 0; + if (c) + d_append_char (dpi, c); + d_print_comp (dpi, options, d_right (dc)); + } + return; + + case DEMANGLE_COMPONENT_QUAL_NAME: + case DEMANGLE_COMPONENT_LOCAL_NAME: + d_print_comp (dpi, options, d_left (dc)); + if ((options & DMGL_JAVA) == 0) + d_append_string (dpi, "::"); + else + d_append_char (dpi, '.'); + { + struct demangle_component *local_name = d_right (dc); + if (local_name->type == DEMANGLE_COMPONENT_DEFAULT_ARG) + { + d_append_string (dpi, "{default arg#"); + d_append_num (dpi, local_name->u.s_unary_num.num + 1); + d_append_string (dpi, "}::"); + local_name = local_name->u.s_unary_num.sub; + } + d_print_comp (dpi, options, local_name); + } + return; + + case DEMANGLE_COMPONENT_TYPED_NAME: + { + struct d_print_mod *hold_modifiers; + struct demangle_component *typed_name; + struct d_print_mod adpm[4]; + unsigned int i; + struct d_print_template dpt; + + /* Pass the name down to the type so that it can be printed in + the right place for the type. We also have to pass down + any CV-qualifiers, which apply to the this parameter. */ + hold_modifiers = dpi->modifiers; + dpi->modifiers = 0; + i = 0; + typed_name = d_left (dc); + while (typed_name != NULL) + { + if (i >= sizeof adpm / sizeof adpm[0]) + { + d_print_error (dpi); + return; + } + + adpm[i].next = dpi->modifiers; + dpi->modifiers = &adpm[i]; + adpm[i].mod = typed_name; + adpm[i].printed = 0; + adpm[i].templates = dpi->templates; + ++i; + + if (!is_fnqual_component_type (typed_name->type)) + break; + + typed_name = d_left (typed_name); + } + + if (typed_name == NULL) + { + d_print_error (dpi); + return; + } + + /* If typed_name is a DEMANGLE_COMPONENT_LOCAL_NAME, then + there may be CV-qualifiers on its right argument which + really apply here; this happens when parsing a class that + is local to a function. */ + if (typed_name->type == DEMANGLE_COMPONENT_LOCAL_NAME) + { + typed_name = d_right (typed_name); + if (typed_name->type == DEMANGLE_COMPONENT_DEFAULT_ARG) + typed_name = typed_name->u.s_unary_num.sub; + while (typed_name != NULL + && is_fnqual_component_type (typed_name->type)) + { + if (i >= sizeof adpm / sizeof adpm[0]) + { + d_print_error (dpi); + return; + } + + adpm[i] = adpm[i - 1]; + adpm[i].next = &adpm[i - 1]; + dpi->modifiers = &adpm[i]; + + adpm[i - 1].mod = typed_name; + adpm[i - 1].printed = 0; + adpm[i - 1].templates = dpi->templates; + ++i; + + typed_name = d_left (typed_name); + } + if (typed_name == NULL) + { + d_print_error (dpi); + return; + } + } + + /* If typed_name is a template, then it applies to the + function type as well. */ + if (typed_name->type == DEMANGLE_COMPONENT_TEMPLATE) + { + dpt.next = dpi->templates; + dpi->templates = &dpt; + dpt.template_decl = typed_name; + } + + d_print_comp (dpi, options, d_right (dc)); + + if (typed_name->type == DEMANGLE_COMPONENT_TEMPLATE) + dpi->templates = dpt.next; + + /* If the modifiers didn't get printed by the type, print them + now. */ + while (i > 0) + { + --i; + if (! adpm[i].printed) + { + d_append_char (dpi, ' '); + d_print_mod (dpi, options, adpm[i].mod); + } + } + + dpi->modifiers = hold_modifiers; + + return; + } + + case DEMANGLE_COMPONENT_TEMPLATE: + { + struct d_print_mod *hold_dpm; + struct demangle_component *dcl; + const struct demangle_component *hold_current; + + /* This template may need to be referenced by a cast operator + contained in its subtree. */ + hold_current = dpi->current_template; + dpi->current_template = dc; + + /* Don't push modifiers into a template definition. Doing so + could give the wrong definition for a template argument. + Instead, treat the template essentially as a name. */ + + hold_dpm = dpi->modifiers; + dpi->modifiers = NULL; + + dcl = d_left (dc); + + if ((options & DMGL_JAVA) != 0 + && dcl->type == DEMANGLE_COMPONENT_NAME + && dcl->u.s_name.len == 6 + && strncmp (dcl->u.s_name.s, "JArray", 6) == 0) + { + /* Special-case Java arrays, so that JArray appears + instead as TYPE[]. */ + + d_print_comp (dpi, options, d_right (dc)); + d_append_string (dpi, "[]"); + } + else + { + d_print_comp (dpi, options, dcl); + if (d_last_char (dpi) == '<') + d_append_char (dpi, ' '); + d_append_char (dpi, '<'); + d_print_comp (dpi, options, d_right (dc)); + /* Avoid generating two consecutive '>' characters, to avoid + the C++ syntactic ambiguity. */ + if (d_last_char (dpi) == '>') + d_append_char (dpi, ' '); + d_append_char (dpi, '>'); + } + + dpi->modifiers = hold_dpm; + dpi->current_template = hold_current; + + return; + } + + case DEMANGLE_COMPONENT_TEMPLATE_PARAM: + if (dpi->lambda_tpl_parms > dc->u.s_number.number + 1) + { + const struct demangle_component *a + = d_left (dpi->templates->template_decl); + unsigned c; + for (c = dc->u.s_number.number; a && c; c--) + a = d_right (a); + if (a && a->type == DEMANGLE_COMPONENT_TEMPLATE_PACK_PARM) + a = d_left (a); + if (!a) + dpi->demangle_failure = 1; + else + d_print_lambda_parm_name (dpi, a->type, dc->u.s_number.number); + } + else if (dpi->lambda_tpl_parms) + { + /* Show the template parm index, as that's how g++ displays + these, and future proofs us against potential + '[] (T *a, T *b) {...}'. */ + d_append_buffer (dpi, "auto:", 5); + d_append_num (dpi, dc->u.s_number.number + 1); + } + else + { + struct d_print_template *hold_dpt; + struct demangle_component *a = d_lookup_template_argument (dpi, dc); + + if (a && a->type == DEMANGLE_COMPONENT_TEMPLATE_ARGLIST) + a = d_index_template_argument (a, dpi->pack_index); + + if (a == NULL) + { + d_print_error (dpi); + return; + } + + /* While processing this parameter, we need to pop the list + of templates. This is because the template parameter may + itself be a reference to a parameter of an outer + template. */ + + hold_dpt = dpi->templates; + dpi->templates = hold_dpt->next; + + d_print_comp (dpi, options, a); + + dpi->templates = hold_dpt; + } + return; + + case DEMANGLE_COMPONENT_TPARM_OBJ: + d_append_string (dpi, "template parameter object for "); + d_print_comp (dpi, options, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_CTOR: + d_print_comp (dpi, options, dc->u.s_ctor.name); + return; + + case DEMANGLE_COMPONENT_DTOR: + d_append_char (dpi, '~'); + d_print_comp (dpi, options, dc->u.s_dtor.name); + return; + + case DEMANGLE_COMPONENT_MODULE_INIT: + d_append_string (dpi, "initializer for module "); + d_print_comp (dpi, options, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_VTABLE: + d_append_string (dpi, "vtable for "); + d_print_comp (dpi, options, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_VTT: + d_append_string (dpi, "VTT for "); + d_print_comp (dpi, options, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE: + d_append_string (dpi, "construction vtable for "); + d_print_comp (dpi, options, d_left (dc)); + d_append_string (dpi, "-in-"); + d_print_comp (dpi, options, d_right (dc)); + return; + + case DEMANGLE_COMPONENT_TYPEINFO: + d_append_string (dpi, "typeinfo for "); + d_print_comp (dpi, options, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_TYPEINFO_NAME: + d_append_string (dpi, "typeinfo name for "); + d_print_comp (dpi, options, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_TYPEINFO_FN: + d_append_string (dpi, "typeinfo fn for "); + d_print_comp (dpi, options, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_THUNK: + d_append_string (dpi, "non-virtual thunk to "); + d_print_comp (dpi, options, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_VIRTUAL_THUNK: + d_append_string (dpi, "virtual thunk to "); + d_print_comp (dpi, options, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_COVARIANT_THUNK: + d_append_string (dpi, "covariant return thunk to "); + d_print_comp (dpi, options, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_JAVA_CLASS: + d_append_string (dpi, "java Class for "); + d_print_comp (dpi, options, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_GUARD: + d_append_string (dpi, "guard variable for "); + d_print_comp (dpi, options, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_TLS_INIT: + d_append_string (dpi, "TLS init function for "); + d_print_comp (dpi, options, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_TLS_WRAPPER: + d_append_string (dpi, "TLS wrapper function for "); + d_print_comp (dpi, options, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_REFTEMP: + d_append_string (dpi, "reference temporary #"); + d_print_comp (dpi, options, d_right (dc)); + d_append_string (dpi, " for "); + d_print_comp (dpi, options, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_HIDDEN_ALIAS: + d_append_string (dpi, "hidden alias for "); + d_print_comp (dpi, options, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_TRANSACTION_CLONE: + d_append_string (dpi, "transaction clone for "); + d_print_comp (dpi, options, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_NONTRANSACTION_CLONE: + d_append_string (dpi, "non-transaction clone for "); + d_print_comp (dpi, options, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_SUB_STD: + d_append_buffer (dpi, dc->u.s_string.string, dc->u.s_string.len); + return; + + case DEMANGLE_COMPONENT_RESTRICT: + case DEMANGLE_COMPONENT_VOLATILE: + case DEMANGLE_COMPONENT_CONST: + { + struct d_print_mod *pdpm; + + /* When printing arrays, it's possible to have cases where the + same CV-qualifier gets pushed on the stack multiple times. + We only need to print it once. */ + + for (pdpm = dpi->modifiers; pdpm != NULL; pdpm = pdpm->next) + { + if (! pdpm->printed) + { + if (pdpm->mod->type != DEMANGLE_COMPONENT_RESTRICT + && pdpm->mod->type != DEMANGLE_COMPONENT_VOLATILE + && pdpm->mod->type != DEMANGLE_COMPONENT_CONST) + break; + if (pdpm->mod->type == dc->type) + { + d_print_comp (dpi, options, d_left (dc)); + return; + } + } + } + } + goto modifier; + + case DEMANGLE_COMPONENT_REFERENCE: + case DEMANGLE_COMPONENT_RVALUE_REFERENCE: + { + /* Handle reference smashing: & + && = &. */ + struct demangle_component *sub = d_left (dc); + if (!dpi->lambda_tpl_parms + && sub->type == DEMANGLE_COMPONENT_TEMPLATE_PARAM) + { + struct d_saved_scope *scope = d_get_saved_scope (dpi, sub); + struct demangle_component *a; + + if (scope == NULL) + { + /* This is the first time SUB has been traversed. + We need to capture the current templates so + they can be restored if SUB is reentered as a + substitution. */ + d_save_scope (dpi, sub); + if (d_print_saw_error (dpi)) + return; + } + else + { + const struct d_component_stack *dcse; + int found_self_or_parent = 0; + + /* This traversal is reentering SUB as a substition. + If we are not beneath SUB or DC in the tree then we + need to restore SUB's template stack temporarily. */ + for (dcse = dpi->component_stack; dcse != NULL; + dcse = dcse->parent) + { + if (dcse->dc == sub + || (dcse->dc == dc + && dcse != dpi->component_stack)) + { + found_self_or_parent = 1; + break; + } + } + + if (!found_self_or_parent) + { + saved_templates = dpi->templates; + dpi->templates = scope->templates; + need_template_restore = 1; + } + } + + a = d_lookup_template_argument (dpi, sub); + if (a && a->type == DEMANGLE_COMPONENT_TEMPLATE_ARGLIST) + a = d_index_template_argument (a, dpi->pack_index); + + if (a == NULL) + { + if (need_template_restore) + dpi->templates = saved_templates; + + d_print_error (dpi); + return; + } + + sub = a; + } + + if (sub->type == DEMANGLE_COMPONENT_REFERENCE + || sub->type == dc->type) + dc = sub; + else if (sub->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE) + mod_inner = d_left (sub); + } + /* Fall through. */ + + case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL: + case DEMANGLE_COMPONENT_POINTER: + case DEMANGLE_COMPONENT_COMPLEX: + case DEMANGLE_COMPONENT_IMAGINARY: + FNQUAL_COMPONENT_CASE: + modifier: + { + /* We keep a list of modifiers on the stack. */ + struct d_print_mod dpm; + + dpm.next = dpi->modifiers; + dpi->modifiers = &dpm; + dpm.mod = dc; + dpm.printed = 0; + dpm.templates = dpi->templates; + + if (!mod_inner) + mod_inner = d_left (dc); + + d_print_comp (dpi, options, mod_inner); + + /* If the modifier didn't get printed by the type, print it + now. */ + if (! dpm.printed) + d_print_mod (dpi, options, dc); + + dpi->modifiers = dpm.next; + + if (need_template_restore) + dpi->templates = saved_templates; + + return; + } + + case DEMANGLE_COMPONENT_BUILTIN_TYPE: + if ((options & DMGL_JAVA) == 0) + d_append_buffer (dpi, dc->u.s_builtin.type->name, + dc->u.s_builtin.type->len); + else + d_append_buffer (dpi, dc->u.s_builtin.type->java_name, + dc->u.s_builtin.type->java_len); + return; + + case DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE: + d_append_buffer (dpi, dc->u.s_extended_builtin.type->name, + dc->u.s_extended_builtin.type->len); + d_append_num (dpi, dc->u.s_extended_builtin.arg); + if (dc->u.s_extended_builtin.suffix) + d_append_buffer (dpi, &dc->u.s_extended_builtin.suffix, 1); + return; + + case DEMANGLE_COMPONENT_VENDOR_TYPE: + d_print_comp (dpi, options, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_FUNCTION_TYPE: + { + if ((options & DMGL_RET_POSTFIX) != 0) + d_print_function_type (dpi, + options & ~(DMGL_RET_POSTFIX | DMGL_RET_DROP), + dc, dpi->modifiers); + + /* Print return type if present */ + if (d_left (dc) != NULL && (options & DMGL_RET_POSTFIX) != 0) + d_print_comp (dpi, options & ~(DMGL_RET_POSTFIX | DMGL_RET_DROP), + d_left (dc)); + else if (d_left (dc) != NULL && (options & DMGL_RET_DROP) == 0) + { + struct d_print_mod dpm; + + /* We must pass this type down as a modifier in order to + print it in the right location. */ + dpm.next = dpi->modifiers; + dpi->modifiers = &dpm; + dpm.mod = dc; + dpm.printed = 0; + dpm.templates = dpi->templates; + + d_print_comp (dpi, options & ~(DMGL_RET_POSTFIX | DMGL_RET_DROP), + d_left (dc)); + + dpi->modifiers = dpm.next; + + if (dpm.printed) + return; + + /* In standard prefix notation, there is a space between the + return type and the function signature. */ + if ((options & DMGL_RET_POSTFIX) == 0) + d_append_char (dpi, ' '); + } + + if ((options & DMGL_RET_POSTFIX) == 0) + d_print_function_type (dpi, + options & ~(DMGL_RET_POSTFIX | DMGL_RET_DROP), + dc, dpi->modifiers); + + return; + } + + case DEMANGLE_COMPONENT_ARRAY_TYPE: + { + struct d_print_mod *hold_modifiers; + struct d_print_mod adpm[4]; + unsigned int i; + struct d_print_mod *pdpm; + + /* We must pass this type down as a modifier in order to print + multi-dimensional arrays correctly. If the array itself is + CV-qualified, we act as though the element type were + CV-qualified. We do this by copying the modifiers down + rather than fiddling pointers, so that we don't wind up + with a d_print_mod higher on the stack pointing into our + stack frame after we return. */ + + hold_modifiers = dpi->modifiers; + + adpm[0].next = hold_modifiers; + dpi->modifiers = &adpm[0]; + adpm[0].mod = dc; + adpm[0].printed = 0; + adpm[0].templates = dpi->templates; + + i = 1; + pdpm = hold_modifiers; + while (pdpm != NULL + && (pdpm->mod->type == DEMANGLE_COMPONENT_RESTRICT + || pdpm->mod->type == DEMANGLE_COMPONENT_VOLATILE + || pdpm->mod->type == DEMANGLE_COMPONENT_CONST)) + { + if (! pdpm->printed) + { + if (i >= sizeof adpm / sizeof adpm[0]) + { + d_print_error (dpi); + return; + } + + adpm[i] = *pdpm; + adpm[i].next = dpi->modifiers; + dpi->modifiers = &adpm[i]; + pdpm->printed = 1; + ++i; + } + + pdpm = pdpm->next; + } + + d_print_comp (dpi, options, d_right (dc)); + + dpi->modifiers = hold_modifiers; + + if (adpm[0].printed) + return; + + while (i > 1) + { + --i; + d_print_mod (dpi, options, adpm[i].mod); + } + + d_print_array_type (dpi, options, dc, dpi->modifiers); + + return; + } + + case DEMANGLE_COMPONENT_PTRMEM_TYPE: + case DEMANGLE_COMPONENT_VECTOR_TYPE: + { + struct d_print_mod dpm; + + dpm.next = dpi->modifiers; + dpi->modifiers = &dpm; + dpm.mod = dc; + dpm.printed = 0; + dpm.templates = dpi->templates; + + d_print_comp (dpi, options, d_right (dc)); + + /* If the modifier didn't get printed by the type, print it + now. */ + if (! dpm.printed) + d_print_mod (dpi, options, dc); + + dpi->modifiers = dpm.next; + + return; + } + + case DEMANGLE_COMPONENT_ARGLIST: + case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST: + if (d_left (dc) != NULL) + d_print_comp (dpi, options, d_left (dc)); + if (d_right (dc) != NULL) + { + size_t len; + unsigned long int flush_count; + /* Make sure ", " isn't flushed by d_append_string, otherwise + dpi->len -= 2 wouldn't work. */ + if (dpi->len >= sizeof (dpi->buf) - 2) + d_print_flush (dpi); + d_append_string (dpi, ", "); + len = dpi->len; + flush_count = dpi->flush_count; + d_print_comp (dpi, options, d_right (dc)); + /* If that didn't print anything (which can happen with empty + template argument packs), remove the comma and space. */ + if (dpi->flush_count == flush_count && dpi->len == len) + dpi->len -= 2; + } + return; + + case DEMANGLE_COMPONENT_INITIALIZER_LIST: + { + struct demangle_component *type = d_left (dc); + struct demangle_component *list = d_right (dc); + + if (type) + d_print_comp (dpi, options, type); + d_append_char (dpi, '{'); + d_print_comp (dpi, options, list); + d_append_char (dpi, '}'); + } + return; + + case DEMANGLE_COMPONENT_OPERATOR: + { + const struct demangle_operator_info *op = dc->u.s_operator.op; + int len = op->len; + + d_append_string (dpi, "operator"); + /* Add a space before new/delete. */ + if (IS_LOWER (op->name[0])) + d_append_char (dpi, ' '); + /* Omit a trailing space. */ + if (op->name[len-1] == ' ') + --len; + d_append_buffer (dpi, op->name, len); + return; + } + + case DEMANGLE_COMPONENT_EXTENDED_OPERATOR: + d_append_string (dpi, "operator "); + d_print_comp (dpi, options, dc->u.s_extended_operator.name); + return; + + case DEMANGLE_COMPONENT_CONVERSION: + d_append_string (dpi, "operator "); + d_print_conversion (dpi, options, dc); + return; + + case DEMANGLE_COMPONENT_NULLARY: + d_print_expr_op (dpi, options, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_UNARY: + { + struct demangle_component *op = d_left (dc); + struct demangle_component *operand = d_right (dc); + const char *code = NULL; + + if (op->type == DEMANGLE_COMPONENT_OPERATOR) + { + code = op->u.s_operator.op->code; + if (!strcmp (code, "ad")) + { + /* Don't print the argument list for the address of a + function. */ + if (operand->type == DEMANGLE_COMPONENT_TYPED_NAME + && d_left (operand)->type == DEMANGLE_COMPONENT_QUAL_NAME + && d_right (operand)->type == DEMANGLE_COMPONENT_FUNCTION_TYPE) + operand = d_left (operand); + } + if (operand->type == DEMANGLE_COMPONENT_BINARY_ARGS) + { + /* This indicates a suffix operator. */ + operand = d_left (operand); + d_print_subexpr (dpi, options, operand); + d_print_expr_op (dpi, options, op); + return; + } + } + + /* For sizeof..., just print the pack length. */ + if (code && !strcmp (code, "sZ")) + { + struct demangle_component *a = d_find_pack (dpi, operand); + int len = d_pack_length (a); + d_append_num (dpi, len); + return; + } + else if (code && !strcmp (code, "sP")) + { + int len = d_args_length (dpi, operand); + d_append_num (dpi, len); + return; + } + + if (op->type != DEMANGLE_COMPONENT_CAST) + d_print_expr_op (dpi, options, op); + else + { + d_append_char (dpi, '('); + d_print_cast (dpi, options, op); + d_append_char (dpi, ')'); + } + if (code && !strcmp (code, "gs")) + /* Avoid parens after '::'. */ + d_print_comp (dpi, options, operand); + else if (code && !strcmp (code, "st")) + /* Always print parens for sizeof (type). */ + { + d_append_char (dpi, '('); + d_print_comp (dpi, options, operand); + d_append_char (dpi, ')'); + } + else + d_print_subexpr (dpi, options, operand); + } + return; + + case DEMANGLE_COMPONENT_BINARY: + if (d_right (dc)->type != DEMANGLE_COMPONENT_BINARY_ARGS) + { + d_print_error (dpi); + return; + } + + if (op_is_new_cast (d_left (dc))) + { + d_print_expr_op (dpi, options, d_left (dc)); + d_append_char (dpi, '<'); + d_print_comp (dpi, options, d_left (d_right (dc))); + d_append_string (dpi, ">("); + d_print_comp (dpi, options, d_right (d_right (dc))); + d_append_char (dpi, ')'); + return; + } + + if (d_maybe_print_fold_expression (dpi, options, dc)) + return; + + if (d_maybe_print_designated_init (dpi, options, dc)) + return; + + /* We wrap an expression which uses the greater-than operator in + an extra layer of parens so that it does not get confused + with the '>' which ends the template parameters. */ + if (d_left (dc)->type == DEMANGLE_COMPONENT_OPERATOR + && d_left (dc)->u.s_operator.op->len == 1 + && d_left (dc)->u.s_operator.op->name[0] == '>') + d_append_char (dpi, '('); + + if (strcmp (d_left (dc)->u.s_operator.op->code, "cl") == 0 + && d_left (d_right (dc))->type == DEMANGLE_COMPONENT_TYPED_NAME) + { + /* Function call used in an expression should not have printed types + of the function arguments. Values of the function arguments still + get printed below. */ + + const struct demangle_component *func = d_left (d_right (dc)); + + if (d_right (func)->type != DEMANGLE_COMPONENT_FUNCTION_TYPE) + d_print_error (dpi); + d_print_subexpr (dpi, options, d_left (func)); + } + else + d_print_subexpr (dpi, options, d_left (d_right (dc))); + if (strcmp (d_left (dc)->u.s_operator.op->code, "ix") == 0) + { + d_append_char (dpi, '['); + d_print_comp (dpi, options, d_right (d_right (dc))); + d_append_char (dpi, ']'); + } + else + { + if (strcmp (d_left (dc)->u.s_operator.op->code, "cl") != 0) + d_print_expr_op (dpi, options, d_left (dc)); + d_print_subexpr (dpi, options, d_right (d_right (dc))); + } + + if (d_left (dc)->type == DEMANGLE_COMPONENT_OPERATOR + && d_left (dc)->u.s_operator.op->len == 1 + && d_left (dc)->u.s_operator.op->name[0] == '>') + d_append_char (dpi, ')'); + + return; + + case DEMANGLE_COMPONENT_BINARY_ARGS: + /* We should only see this as part of DEMANGLE_COMPONENT_BINARY. */ + d_print_error (dpi); + return; + + case DEMANGLE_COMPONENT_TRINARY: + if (d_right (dc)->type != DEMANGLE_COMPONENT_TRINARY_ARG1 + || d_right (d_right (dc))->type != DEMANGLE_COMPONENT_TRINARY_ARG2) + { + d_print_error (dpi); + return; + } + if (d_maybe_print_fold_expression (dpi, options, dc)) + return; + if (d_maybe_print_designated_init (dpi, options, dc)) + return; + { + struct demangle_component *op = d_left (dc); + struct demangle_component *first = d_left (d_right (dc)); + struct demangle_component *second = d_left (d_right (d_right (dc))); + struct demangle_component *third = d_right (d_right (d_right (dc))); + + if (!strcmp (op->u.s_operator.op->code, "qu")) + { + d_print_subexpr (dpi, options, first); + d_print_expr_op (dpi, options, op); + d_print_subexpr (dpi, options, second); + d_append_string (dpi, " : "); + d_print_subexpr (dpi, options, third); + } + else + { + d_append_string (dpi, "new "); + if (d_left (first) != NULL) + { + d_print_subexpr (dpi, options, first); + d_append_char (dpi, ' '); + } + d_print_comp (dpi, options, second); + if (third) + d_print_subexpr (dpi, options, third); + } + } + return; + + case DEMANGLE_COMPONENT_TRINARY_ARG1: + case DEMANGLE_COMPONENT_TRINARY_ARG2: + /* We should only see these are part of DEMANGLE_COMPONENT_TRINARY. */ + d_print_error (dpi); + return; + + case DEMANGLE_COMPONENT_LITERAL: + case DEMANGLE_COMPONENT_LITERAL_NEG: + { + enum d_builtin_type_print tp; + + /* For some builtin types, produce simpler output. */ + tp = D_PRINT_DEFAULT; + if (d_left (dc)->type == DEMANGLE_COMPONENT_BUILTIN_TYPE) + { + tp = d_left (dc)->u.s_builtin.type->print; + switch (tp) + { + case D_PRINT_INT: + case D_PRINT_UNSIGNED: + case D_PRINT_LONG: + case D_PRINT_UNSIGNED_LONG: + case D_PRINT_LONG_LONG: + case D_PRINT_UNSIGNED_LONG_LONG: + if (d_right (dc)->type == DEMANGLE_COMPONENT_NAME) + { + if (dc->type == DEMANGLE_COMPONENT_LITERAL_NEG) + d_append_char (dpi, '-'); + d_print_comp (dpi, options, d_right (dc)); + switch (tp) + { + default: + break; + case D_PRINT_UNSIGNED: + d_append_char (dpi, 'u'); + break; + case D_PRINT_LONG: + d_append_char (dpi, 'l'); + break; + case D_PRINT_UNSIGNED_LONG: + d_append_string (dpi, "ul"); + break; + case D_PRINT_LONG_LONG: + d_append_string (dpi, "ll"); + break; + case D_PRINT_UNSIGNED_LONG_LONG: + d_append_string (dpi, "ull"); + break; + } + return; + } + break; + + case D_PRINT_BOOL: + if (d_right (dc)->type == DEMANGLE_COMPONENT_NAME + && d_right (dc)->u.s_name.len == 1 + && dc->type == DEMANGLE_COMPONENT_LITERAL) + { + switch (d_right (dc)->u.s_name.s[0]) + { + case '0': + d_append_string (dpi, "false"); + return; + case '1': + d_append_string (dpi, "true"); + return; + default: + break; + } + } + break; + + default: + break; + } + } + + d_append_char (dpi, '('); + d_print_comp (dpi, options, d_left (dc)); + d_append_char (dpi, ')'); + if (dc->type == DEMANGLE_COMPONENT_LITERAL_NEG) + d_append_char (dpi, '-'); + if (tp == D_PRINT_FLOAT) + d_append_char (dpi, '['); + d_print_comp (dpi, options, d_right (dc)); + if (tp == D_PRINT_FLOAT) + d_append_char (dpi, ']'); + } + return; + + case DEMANGLE_COMPONENT_VENDOR_EXPR: + d_print_comp (dpi, options, d_left (dc)); + d_append_char (dpi, '('); + d_print_comp (dpi, options, d_right (dc)); + d_append_char (dpi, ')'); + return; + + case DEMANGLE_COMPONENT_NUMBER: + d_append_num (dpi, dc->u.s_number.number); + return; + + case DEMANGLE_COMPONENT_JAVA_RESOURCE: + d_append_string (dpi, "java resource "); + d_print_comp (dpi, options, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_COMPOUND_NAME: + d_print_comp (dpi, options, d_left (dc)); + d_print_comp (dpi, options, d_right (dc)); + return; + + case DEMANGLE_COMPONENT_CHARACTER: + d_append_char (dpi, dc->u.s_character.character); + return; + + case DEMANGLE_COMPONENT_DECLTYPE: + d_append_string (dpi, "decltype ("); + d_print_comp (dpi, options, d_left (dc)); + d_append_char (dpi, ')'); + return; + + case DEMANGLE_COMPONENT_PACK_EXPANSION: + { + struct demangle_component *a = NULL; + + if (!dpi->lambda_tpl_parms) + a = d_find_pack (dpi, d_left (dc)); + if (a == NULL) + { + /* d_find_pack won't find anything if the only packs involved + in this expansion are function parameter packs; in that + case, just print the pattern and "...". */ + d_print_subexpr (dpi, options, d_left (dc)); + d_append_string (dpi, "..."); + } + else + { + int len = d_pack_length (a); + int i; + + dc = d_left (dc); + for (i = 0; i < len; ++i) + { + if (i) + d_append_string (dpi, ", "); + dpi->pack_index = i; + d_print_comp (dpi, options, dc); + } + } + } + return; + + case DEMANGLE_COMPONENT_FUNCTION_PARAM: + { + long num = dc->u.s_number.number; + if (num == 0) + d_append_string (dpi, "this"); + else + { + d_append_string (dpi, "{parm#"); + d_append_num (dpi, num); + d_append_char (dpi, '}'); + } + } + return; + + case DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS: + d_append_string (dpi, "global constructors keyed to "); + d_print_comp (dpi, options, dc->u.s_binary.left); + return; + + case DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS: + d_append_string (dpi, "global destructors keyed to "); + d_print_comp (dpi, options, dc->u.s_binary.left); + return; + + case DEMANGLE_COMPONENT_LAMBDA: + { + d_append_string (dpi, "{lambda"); + struct demangle_component *parms = dc->u.s_unary_num.sub; + struct d_print_template dpt; + /* Generic lambda auto parms are mangled as the (synthedic) template + type parm they are. We need to tell the printer that (a) we're in + a lambda, and (b) the number of synthetic parms. */ + int saved_tpl_parms = dpi->lambda_tpl_parms; + dpi->lambda_tpl_parms = 0; + /* Hang any lambda head as-if template args. */ + dpt.template_decl = NULL; + dpt.next = dpi->templates; + dpi->templates = &dpt; + if (parms && parms->type == DEMANGLE_COMPONENT_TEMPLATE_HEAD) + { + dpt.template_decl = parms; + + d_append_char (dpi, '<'); + struct demangle_component *parm; + for (parm = d_left (parms); parm; parm = d_right (parm)) + { + if (dpi->lambda_tpl_parms++) + d_append_string (dpi, ", "); + d_print_comp (dpi, options, parm); + d_append_char (dpi, ' '); + if (parm->type == DEMANGLE_COMPONENT_TEMPLATE_PACK_PARM) + parm = d_left (parm); + d_print_lambda_parm_name (dpi, parm->type, + dpi->lambda_tpl_parms - 1); + } + d_append_char (dpi, '>'); + + parms = d_right (parms); + } + dpi->lambda_tpl_parms++; + + d_append_char (dpi, '('); + d_print_comp (dpi, options, parms); + dpi->lambda_tpl_parms = saved_tpl_parms; + dpi->templates = dpt.next; + d_append_string (dpi, ")#"); + d_append_num (dpi, dc->u.s_unary_num.num + 1); + d_append_char (dpi, '}'); + } + return; + + case DEMANGLE_COMPONENT_UNNAMED_TYPE: + d_append_string (dpi, "{unnamed type#"); + d_append_num (dpi, dc->u.s_number.number + 1); + d_append_char (dpi, '}'); + return; + + case DEMANGLE_COMPONENT_CLONE: + d_print_comp (dpi, options, d_left (dc)); + d_append_string (dpi, " [clone "); + d_print_comp (dpi, options, d_right (dc)); + d_append_char (dpi, ']'); + return; + + case DEMANGLE_COMPONENT_TEMPLATE_HEAD: + { + d_append_char (dpi, '<'); + int count = 0; + struct demangle_component *parm; + for (parm = d_left (dc); parm; parm = d_right (parm)) + { + if (count++) + d_append_string (dpi, ", "); + d_print_comp (dpi, options, parm); + } + d_append_char (dpi, '>'); + } + return; + + case DEMANGLE_COMPONENT_TEMPLATE_TYPE_PARM: + d_append_string (dpi, "typename"); + return; + + case DEMANGLE_COMPONENT_TEMPLATE_NON_TYPE_PARM: + d_print_comp (dpi, options, d_left (dc)); + return; + + case DEMANGLE_COMPONENT_TEMPLATE_TEMPLATE_PARM: + d_append_string (dpi, "template"); + d_print_comp (dpi, options, d_left (dc)); + d_append_string (dpi, " class"); + return; + + case DEMANGLE_COMPONENT_TEMPLATE_PACK_PARM: + d_print_comp (dpi, options, d_left (dc)); + d_append_string (dpi, "..."); + return; + + default: + d_print_error (dpi); + return; + } +} + +static void +d_print_comp (struct d_print_info *dpi, int options, + struct demangle_component *dc) +{ + struct d_component_stack self; + if (dc == NULL || dc->d_printing > 1 || dpi->recursion > MAX_RECURSION_COUNT) + { + d_print_error (dpi); + return; + } + + dc->d_printing++; + dpi->recursion++; + + self.dc = dc; + self.parent = dpi->component_stack; + dpi->component_stack = &self; + + d_print_comp_inner (dpi, options, dc); + + dpi->component_stack = self.parent; + dc->d_printing--; + dpi->recursion--; +} + +/* Print a Java dentifier. For Java we try to handle encoded extended + Unicode characters. The C++ ABI doesn't mention Unicode encoding, + so we don't it for C++. Characters are encoded as + __U+_. */ + +static void +d_print_java_identifier (struct d_print_info *dpi, const char *name, int len) +{ + const char *p; + const char *end; + + end = name + len; + for (p = name; p < end; ++p) + { + if (end - p > 3 + && p[0] == '_' + && p[1] == '_' + && p[2] == 'U') + { + unsigned long c; + const char *q; + + c = 0; + for (q = p + 3; q < end; ++q) + { + int dig; + + if (IS_DIGIT (*q)) + dig = *q - '0'; + else if (*q >= 'A' && *q <= 'F') + dig = *q - 'A' + 10; + else if (*q >= 'a' && *q <= 'f') + dig = *q - 'a' + 10; + else + break; + + c = c * 16 + dig; + } + /* If the Unicode character is larger than 256, we don't try + to deal with it here. FIXME. */ + if (q < end && *q == '_' && c < 256) + { + d_append_char (dpi, c); + p = q; + continue; + } + } + + d_append_char (dpi, *p); + } +} + +/* Print a list of modifiers. SUFFIX is 1 if we are printing + qualifiers on this after printing a function. */ + +static void +d_print_mod_list (struct d_print_info *dpi, int options, + struct d_print_mod *mods, int suffix) +{ + struct d_print_template *hold_dpt; + + if (mods == NULL || d_print_saw_error (dpi)) + return; + + if (mods->printed + || (! suffix + && (is_fnqual_component_type (mods->mod->type)))) + { + d_print_mod_list (dpi, options, mods->next, suffix); + return; + } + + mods->printed = 1; + + hold_dpt = dpi->templates; + dpi->templates = mods->templates; + + if (mods->mod->type == DEMANGLE_COMPONENT_FUNCTION_TYPE) + { + d_print_function_type (dpi, options, mods->mod, mods->next); + dpi->templates = hold_dpt; + return; + } + else if (mods->mod->type == DEMANGLE_COMPONENT_ARRAY_TYPE) + { + d_print_array_type (dpi, options, mods->mod, mods->next); + dpi->templates = hold_dpt; + return; + } + else if (mods->mod->type == DEMANGLE_COMPONENT_LOCAL_NAME) + { + struct d_print_mod *hold_modifiers; + struct demangle_component *dc; + + /* When this is on the modifier stack, we have pulled any + qualifiers off the right argument already. Otherwise, we + print it as usual, but don't let the left argument see any + modifiers. */ + + hold_modifiers = dpi->modifiers; + dpi->modifiers = NULL; + d_print_comp (dpi, options, d_left (mods->mod)); + dpi->modifiers = hold_modifiers; + + if ((options & DMGL_JAVA) == 0) + d_append_string (dpi, "::"); + else + d_append_char (dpi, '.'); + + dc = d_right (mods->mod); + + if (dc->type == DEMANGLE_COMPONENT_DEFAULT_ARG) + { + d_append_string (dpi, "{default arg#"); + d_append_num (dpi, dc->u.s_unary_num.num + 1); + d_append_string (dpi, "}::"); + dc = dc->u.s_unary_num.sub; + } + + while (is_fnqual_component_type (dc->type)) + dc = d_left (dc); + + d_print_comp (dpi, options, dc); + + dpi->templates = hold_dpt; + return; + } + + d_print_mod (dpi, options, mods->mod); + + dpi->templates = hold_dpt; + + d_print_mod_list (dpi, options, mods->next, suffix); +} + +/* Print a modifier. */ + +static void +d_print_mod (struct d_print_info *dpi, int options, + struct demangle_component *mod) +{ + switch (mod->type) + { + case DEMANGLE_COMPONENT_RESTRICT: + case DEMANGLE_COMPONENT_RESTRICT_THIS: + d_append_string (dpi, " restrict"); + return; + case DEMANGLE_COMPONENT_VOLATILE: + case DEMANGLE_COMPONENT_VOLATILE_THIS: + d_append_string (dpi, " volatile"); + return; + case DEMANGLE_COMPONENT_CONST: + case DEMANGLE_COMPONENT_CONST_THIS: + d_append_string (dpi, " const"); + return; + case DEMANGLE_COMPONENT_TRANSACTION_SAFE: + d_append_string (dpi, " transaction_safe"); + return; + case DEMANGLE_COMPONENT_NOEXCEPT: + d_append_string (dpi, " noexcept"); + if (d_right (mod)) + { + d_append_char (dpi, '('); + d_print_comp (dpi, options, d_right (mod)); + d_append_char (dpi, ')'); + } + return; + case DEMANGLE_COMPONENT_THROW_SPEC: + d_append_string (dpi, " throw"); + if (d_right (mod)) + { + d_append_char (dpi, '('); + d_print_comp (dpi, options, d_right (mod)); + d_append_char (dpi, ')'); + } + return; + case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL: + d_append_char (dpi, ' '); + d_print_comp (dpi, options, d_right (mod)); + return; + case DEMANGLE_COMPONENT_POINTER: + /* There is no pointer symbol in Java. */ + if ((options & DMGL_JAVA) == 0) + d_append_char (dpi, '*'); + return; + case DEMANGLE_COMPONENT_REFERENCE_THIS: + /* For the ref-qualifier, put a space before the &. */ + d_append_char (dpi, ' '); + /* FALLTHRU */ + case DEMANGLE_COMPONENT_REFERENCE: + d_append_char (dpi, '&'); + return; + case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS: + d_append_char (dpi, ' '); + /* FALLTHRU */ + case DEMANGLE_COMPONENT_RVALUE_REFERENCE: + d_append_string (dpi, "&&"); + return; + case DEMANGLE_COMPONENT_COMPLEX: + d_append_string (dpi, " _Complex"); + return; + case DEMANGLE_COMPONENT_IMAGINARY: + d_append_string (dpi, " _Imaginary"); + return; + case DEMANGLE_COMPONENT_PTRMEM_TYPE: + if (d_last_char (dpi) != '(') + d_append_char (dpi, ' '); + d_print_comp (dpi, options, d_left (mod)); + d_append_string (dpi, "::*"); + return; + case DEMANGLE_COMPONENT_TYPED_NAME: + d_print_comp (dpi, options, d_left (mod)); + return; + case DEMANGLE_COMPONENT_VECTOR_TYPE: + d_append_string (dpi, " __vector("); + d_print_comp (dpi, options, d_left (mod)); + d_append_char (dpi, ')'); + return; + + default: + /* Otherwise, we have something that won't go back on the + modifier stack, so we can just print it. */ + d_print_comp (dpi, options, mod); + return; + } +} + +/* Print a function type, except for the return type. */ + +static void +d_print_function_type (struct d_print_info *dpi, int options, + struct demangle_component *dc, + struct d_print_mod *mods) +{ + int need_paren; + int need_space; + struct d_print_mod *p; + struct d_print_mod *hold_modifiers; + + need_paren = 0; + need_space = 0; + for (p = mods; p != NULL; p = p->next) + { + if (p->printed) + break; + + switch (p->mod->type) + { + case DEMANGLE_COMPONENT_POINTER: + case DEMANGLE_COMPONENT_REFERENCE: + case DEMANGLE_COMPONENT_RVALUE_REFERENCE: + need_paren = 1; + break; + case DEMANGLE_COMPONENT_RESTRICT: + case DEMANGLE_COMPONENT_VOLATILE: + case DEMANGLE_COMPONENT_CONST: + case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL: + case DEMANGLE_COMPONENT_COMPLEX: + case DEMANGLE_COMPONENT_IMAGINARY: + case DEMANGLE_COMPONENT_PTRMEM_TYPE: + need_space = 1; + need_paren = 1; + break; + FNQUAL_COMPONENT_CASE: + break; + default: + break; + } + if (need_paren) + break; + } + + if (need_paren) + { + if (! need_space) + { + if (d_last_char (dpi) != '(' + && d_last_char (dpi) != '*') + need_space = 1; + } + if (need_space && d_last_char (dpi) != ' ') + d_append_char (dpi, ' '); + d_append_char (dpi, '('); + } + + hold_modifiers = dpi->modifiers; + dpi->modifiers = NULL; + + d_print_mod_list (dpi, options, mods, 0); + + if (need_paren) + d_append_char (dpi, ')'); + + d_append_char (dpi, '('); + + if (d_right (dc) != NULL) + d_print_comp (dpi, options, d_right (dc)); + + d_append_char (dpi, ')'); + + d_print_mod_list (dpi, options, mods, 1); + + dpi->modifiers = hold_modifiers; +} + +/* Print an array type, except for the element type. */ + +static void +d_print_array_type (struct d_print_info *dpi, int options, + struct demangle_component *dc, + struct d_print_mod *mods) +{ + int need_space; + + need_space = 1; + if (mods != NULL) + { + int need_paren; + struct d_print_mod *p; + + need_paren = 0; + for (p = mods; p != NULL; p = p->next) + { + if (! p->printed) + { + if (p->mod->type == DEMANGLE_COMPONENT_ARRAY_TYPE) + { + need_space = 0; + break; + } + else + { + need_paren = 1; + need_space = 1; + break; + } + } + } + + if (need_paren) + d_append_string (dpi, " ("); + + d_print_mod_list (dpi, options, mods, 0); + + if (need_paren) + d_append_char (dpi, ')'); + } + + if (need_space) + d_append_char (dpi, ' '); + + d_append_char (dpi, '['); + + if (d_left (dc) != NULL) + d_print_comp (dpi, options, d_left (dc)); + + d_append_char (dpi, ']'); +} + +/* Print an operator in an expression. */ + +static void +d_print_expr_op (struct d_print_info *dpi, int options, + struct demangle_component *dc) +{ + if (dc->type == DEMANGLE_COMPONENT_OPERATOR) + d_append_buffer (dpi, dc->u.s_operator.op->name, + dc->u.s_operator.op->len); + else + d_print_comp (dpi, options, dc); +} + +/* Print a cast. */ + +static void +d_print_cast (struct d_print_info *dpi, int options, + struct demangle_component *dc) +{ + d_print_comp (dpi, options, d_left (dc)); +} + +/* Print a conversion operator. */ + +static void +d_print_conversion (struct d_print_info *dpi, int options, + struct demangle_component *dc) +{ + struct d_print_template dpt; + + /* For a conversion operator, we need the template parameters from + the enclosing template in scope for processing the type. */ + if (dpi->current_template != NULL) + { + dpt.next = dpi->templates; + dpi->templates = &dpt; + dpt.template_decl = dpi->current_template; + } + + if (d_left (dc)->type != DEMANGLE_COMPONENT_TEMPLATE) + { + d_print_comp (dpi, options, d_left (dc)); + if (dpi->current_template != NULL) + dpi->templates = dpt.next; + } + else + { + d_print_comp (dpi, options, d_left (d_left (dc))); + + /* For a templated cast operator, we need to remove the template + parameters from scope after printing the operator name, + so we need to handle the template printing here. */ + if (dpi->current_template != NULL) + dpi->templates = dpt.next; + + if (d_last_char (dpi) == '<') + d_append_char (dpi, ' '); + d_append_char (dpi, '<'); + d_print_comp (dpi, options, d_right (d_left (dc))); + /* Avoid generating two consecutive '>' characters, to avoid + the C++ syntactic ambiguity. */ + if (d_last_char (dpi) == '>') + d_append_char (dpi, ' '); + d_append_char (dpi, '>'); + } +} + +/* Initialize the information structure we use to pass around + information. */ + +CP_STATIC_IF_GLIBCPP_V3 +void +cplus_demangle_init_info (const char *mangled, int options, size_t len, + struct d_info *di) +{ + di->s = mangled; + di->send = mangled + len; + di->options = options; + + di->n = mangled; + + /* We cannot need more components than twice the number of chars in + the mangled string. Most components correspond directly to + chars, but the ARGLIST types are exceptions. */ + di->num_comps = 2 * len; + di->next_comp = 0; + + /* Similarly, we cannot need more substitutions than there are + chars in the mangled string. */ + di->num_subs = len; + di->next_sub = 0; + + di->last_name = NULL; + + di->expansion = 0; + di->is_expression = 0; + di->is_conversion = 0; + di->recursion_level = 0; +} + +/* Internal implementation for the demangler. If MANGLED is a g++ v3 ABI + mangled name, return strings in repeated callback giving the demangled + name. OPTIONS is the usual libiberty demangler options. On success, + this returns 1. On failure, returns 0. */ + +static int +d_demangle_callback (const char *mangled, int options, + demangle_callbackref callback, void *opaque) +{ + enum + { + DCT_TYPE, + DCT_MANGLED, + DCT_GLOBAL_CTORS, + DCT_GLOBAL_DTORS + } + type; + struct d_info di; + struct demangle_component *dc; + int status; + + if (mangled[0] == '_' && mangled[1] == 'Z') + type = DCT_MANGLED; + else if (strncmp (mangled, "_GLOBAL_", 8) == 0 + && (mangled[8] == '.' || mangled[8] == '_' || mangled[8] == '$') + && (mangled[9] == 'D' || mangled[9] == 'I') + && mangled[10] == '_') + type = mangled[9] == 'I' ? DCT_GLOBAL_CTORS : DCT_GLOBAL_DTORS; + else + { + if ((options & DMGL_TYPES) == 0) + return 0; + type = DCT_TYPE; + } + + di.unresolved_name_state = 1; + + again: + cplus_demangle_init_info (mangled, options, strlen (mangled), &di); + + /* PR 87675 - Check for a mangled string that is so long + that we do not have enough stack space to demangle it. */ + if (((options & DMGL_NO_RECURSE_LIMIT) == 0) + /* This check is a bit arbitrary, since what we really want to do is to + compare the sizes of the di.comps and di.subs arrays against the + amount of stack space remaining. But there is no portable way to do + this, so instead we use the recursion limit as a guide to the maximum + size of the arrays. */ + && (unsigned long) di.num_comps > DEMANGLE_RECURSION_LIMIT) + { + /* FIXME: We need a way to indicate that a stack limit has been reached. */ + return 0; + } + + { +#ifdef CP_DYNAMIC_ARRAYS + __extension__ struct demangle_component comps[di.num_comps]; + __extension__ struct demangle_component *subs[di.num_subs]; + + di.comps = comps; + di.subs = subs; +#else + di.comps = alloca (di.num_comps * sizeof (*di.comps)); + di.subs = alloca (di.num_subs * sizeof (*di.subs)); +#endif + + switch (type) + { + case DCT_TYPE: + dc = cplus_demangle_type (&di); + break; + case DCT_MANGLED: + dc = cplus_demangle_mangled_name (&di, 1); + break; + case DCT_GLOBAL_CTORS: + case DCT_GLOBAL_DTORS: + d_advance (&di, 11); + dc = d_make_comp (&di, + (type == DCT_GLOBAL_CTORS + ? DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS + : DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS), + d_make_demangle_mangled_name (&di, d_str (&di)), + NULL); + d_advance (&di, strlen (d_str (&di))); + break; + default: + abort (); /* We have listed all the cases. */ + } + + /* If DMGL_PARAMS is set, then if we didn't consume the entire + mangled string, then we didn't successfully demangle it. If + DMGL_PARAMS is not set, we didn't look at the trailing + parameters. */ + if (((options & DMGL_PARAMS) != 0) && d_peek_char (&di) != '\0') + dc = NULL; + + /* See discussion in d_unresolved_name. */ + if (dc == NULL && di.unresolved_name_state == -1) + { + di.unresolved_name_state = 0; + goto again; + } + +#ifdef CP_DEMANGLE_DEBUG + d_dump (dc, 0); +#endif + + status = (dc != NULL) + ? cplus_demangle_print_callback (options, dc, callback, opaque) + : 0; + } + + return status; +} + +/* Entry point for the demangler. If MANGLED is a g++ v3 ABI mangled + name, return a buffer allocated with malloc holding the demangled + name. OPTIONS is the usual libiberty demangler options. On + success, this sets *PALC to the allocated size of the returned + buffer. On failure, this sets *PALC to 0 for a bad name, or 1 for + a memory allocation failure, and returns NULL. */ + +static char * +d_demangle (const char *mangled, int options, size_t *palc) +{ + struct d_growable_string dgs; + int status; + + d_growable_string_init (&dgs, 0); + + status = d_demangle_callback (mangled, options, + d_growable_string_callback_adapter, &dgs); + if (status == 0) + { + free (dgs.buf); + *palc = 0; + return NULL; + } + + *palc = dgs.allocation_failure ? 1 : dgs.alc; + return dgs.buf; +} + +#if defined(IN_LIBGCC2) || defined(IN_GLIBCPP_V3) + +extern char *__cxa_demangle (const char *, char *, size_t *, int *); + +/* ia64 ABI-mandated entry point in the C++ runtime library for + performing demangling. MANGLED_NAME is a NUL-terminated character + string containing the name to be demangled. + + OUTPUT_BUFFER is a region of memory, allocated with malloc, of + *LENGTH bytes, into which the demangled name is stored. If + OUTPUT_BUFFER is not long enough, it is expanded using realloc. + OUTPUT_BUFFER may instead be NULL; in that case, the demangled name + is placed in a region of memory allocated with malloc. + + If LENGTH is non-NULL, the length of the buffer containing the + demangled name, is placed in *LENGTH. + + The return value is a pointer to the start of the NUL-terminated + demangled name, or NULL if the demangling fails. The caller is + responsible for deallocating this memory using free. + + *STATUS is set to one of the following values: + 0: The demangling operation succeeded. + -1: A memory allocation failure occurred. + -2: MANGLED_NAME is not a valid name under the C++ ABI mangling rules. + -3: One of the arguments is invalid. + + The demangling is performed using the C++ ABI mangling rules, with + GNU extensions. */ + +char * +__cxa_demangle (const char *mangled_name, char *output_buffer, + size_t *length, int *status) +{ + char *demangled; + size_t alc; + + if (mangled_name == NULL) + { + if (status != NULL) + *status = -3; + return NULL; + } + + if (output_buffer != NULL && length == NULL) + { + if (status != NULL) + *status = -3; + return NULL; + } + + demangled = d_demangle (mangled_name, DMGL_PARAMS | DMGL_TYPES, &alc); + + if (demangled == NULL) + { + if (status != NULL) + { + if (alc == 1) + *status = -1; + else + *status = -2; + } + return NULL; + } + + if (output_buffer == NULL) + { + if (length != NULL) + *length = alc; + } + else + { + if (strlen (demangled) < *length) + { + strcpy (output_buffer, demangled); + free (demangled); + demangled = output_buffer; + } + else + { + free (output_buffer); + *length = alc; + } + } + + if (status != NULL) + *status = 0; + + return demangled; +} + +extern int __gcclibcxx_demangle_callback (const char *, + void (*) + (const char *, size_t, void *), + void *); + +/* Alternative, allocationless entry point in the C++ runtime library + for performing demangling. MANGLED_NAME is a NUL-terminated character + string containing the name to be demangled. + + CALLBACK is a callback function, called with demangled string + segments as demangling progresses; it is called at least once, + but may be called more than once. OPAQUE is a generalized pointer + used as a callback argument. + + The return code is one of the following values, equivalent to + the STATUS values of __cxa_demangle() (excluding -1, since this + function performs no memory allocations): + 0: The demangling operation succeeded. + -2: MANGLED_NAME is not a valid name under the C++ ABI mangling rules. + -3: One of the arguments is invalid. + + The demangling is performed using the C++ ABI mangling rules, with + GNU extensions. */ + +int +__gcclibcxx_demangle_callback (const char *mangled_name, + void (*callback) (const char *, size_t, void *), + void *opaque) +{ + int status; + + if (mangled_name == NULL || callback == NULL) + return -3; + + status = d_demangle_callback (mangled_name, DMGL_PARAMS | DMGL_TYPES, + callback, opaque); + if (status == 0) + return -2; + + return 0; +} + +#else /* ! (IN_LIBGCC2 || IN_GLIBCPP_V3) */ + +/* Entry point for libiberty demangler. If MANGLED is a g++ v3 ABI + mangled name, return a buffer allocated with malloc holding the + demangled name. Otherwise, return NULL. */ + +char * +cplus_demangle_v3 (const char *mangled, int options) +{ + size_t alc; + + return d_demangle (mangled, options, &alc); +} + +int +cplus_demangle_v3_callback (const char *mangled, int options, + demangle_callbackref callback, void *opaque) +{ + return d_demangle_callback (mangled, options, callback, opaque); +} + +/* Demangle a Java symbol. Java uses a subset of the V3 ABI C++ mangling + conventions, but the output formatting is a little different. + This instructs the C++ demangler not to emit pointer characters ("*"), to + use Java's namespace separator symbol ("." instead of "::"), and to output + JArray as TYPE[]. */ + +char * +java_demangle_v3 (const char *mangled) +{ + size_t alc; + + return d_demangle (mangled, DMGL_JAVA | DMGL_PARAMS | DMGL_RET_POSTFIX, &alc); +} + +int +java_demangle_v3_callback (const char *mangled, + demangle_callbackref callback, void *opaque) +{ + return d_demangle_callback (mangled, + DMGL_JAVA | DMGL_PARAMS | DMGL_RET_POSTFIX, + callback, opaque); +} + +#endif /* IN_LIBGCC2 || IN_GLIBCPP_V3 */ + +#ifndef IN_GLIBCPP_V3 + +/* Demangle a string in order to find out whether it is a constructor + or destructor. Return non-zero on success. Set *CTOR_KIND and + *DTOR_KIND appropriately. */ + +static int +is_ctor_or_dtor (const char *mangled, + enum gnu_v3_ctor_kinds *ctor_kind, + enum gnu_v3_dtor_kinds *dtor_kind) +{ + struct d_info di; + struct demangle_component *dc; + int ret; + + *ctor_kind = (enum gnu_v3_ctor_kinds) 0; + *dtor_kind = (enum gnu_v3_dtor_kinds) 0; + + cplus_demangle_init_info (mangled, DMGL_GNU_V3, strlen (mangled), &di); + + { +#ifdef CP_DYNAMIC_ARRAYS + __extension__ struct demangle_component comps[di.num_comps]; + __extension__ struct demangle_component *subs[di.num_subs]; + + di.comps = comps; + di.subs = subs; +#else + di.comps = alloca (di.num_comps * sizeof (*di.comps)); + di.subs = alloca (di.num_subs * sizeof (*di.subs)); +#endif + + dc = cplus_demangle_mangled_name (&di, 1); + + /* Note that because we did not pass DMGL_PARAMS, we don't expect + to demangle the entire string. */ + + ret = 0; + while (dc != NULL) + { + switch (dc->type) + { + /* These cannot appear on a constructor or destructor. */ + case DEMANGLE_COMPONENT_RESTRICT_THIS: + case DEMANGLE_COMPONENT_VOLATILE_THIS: + case DEMANGLE_COMPONENT_CONST_THIS: + case DEMANGLE_COMPONENT_REFERENCE_THIS: + case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS: + default: + dc = NULL; + break; + case DEMANGLE_COMPONENT_TYPED_NAME: + case DEMANGLE_COMPONENT_TEMPLATE: + dc = d_left (dc); + break; + case DEMANGLE_COMPONENT_QUAL_NAME: + case DEMANGLE_COMPONENT_LOCAL_NAME: + dc = d_right (dc); + break; + case DEMANGLE_COMPONENT_CTOR: + *ctor_kind = dc->u.s_ctor.kind; + ret = 1; + dc = NULL; + break; + case DEMANGLE_COMPONENT_DTOR: + *dtor_kind = dc->u.s_dtor.kind; + ret = 1; + dc = NULL; + break; + } + } + } + + return ret; +} + +/* Return whether NAME is the mangled form of a g++ V3 ABI constructor + name. A non-zero return indicates the type of constructor. */ + +enum gnu_v3_ctor_kinds +is_gnu_v3_mangled_ctor (const char *name) +{ + enum gnu_v3_ctor_kinds ctor_kind; + enum gnu_v3_dtor_kinds dtor_kind; + + if (! is_ctor_or_dtor (name, &ctor_kind, &dtor_kind)) + return (enum gnu_v3_ctor_kinds) 0; + return ctor_kind; +} + + +/* Return whether NAME is the mangled form of a g++ V3 ABI destructor + name. A non-zero return indicates the type of destructor. */ + +enum gnu_v3_dtor_kinds +is_gnu_v3_mangled_dtor (const char *name) +{ + enum gnu_v3_ctor_kinds ctor_kind; + enum gnu_v3_dtor_kinds dtor_kind; + + if (! is_ctor_or_dtor (name, &ctor_kind, &dtor_kind)) + return (enum gnu_v3_dtor_kinds) 0; + return dtor_kind; +} + +#endif /* IN_GLIBCPP_V3 */ + +#ifdef STANDALONE_DEMANGLER + +#include "getopt.h" +#include "dyn-string.h" + +static void print_usage (FILE* fp, int exit_value); + +#define IS_ALPHA(CHAR) \ + (((CHAR) >= 'a' && (CHAR) <= 'z') \ + || ((CHAR) >= 'A' && (CHAR) <= 'Z')) + +/* Non-zero if CHAR is a character than can occur in a mangled name. */ +#define is_mangled_char(CHAR) \ + (IS_ALPHA (CHAR) || IS_DIGIT (CHAR) \ + || (CHAR) == '_' || (CHAR) == '.' || (CHAR) == '$') + +/* The name of this program, as invoked. */ +const char* program_name; + +/* Prints usage summary to FP and then exits with EXIT_VALUE. */ + +static void +print_usage (FILE* fp, int exit_value) +{ + fprintf (fp, "Usage: %s [options] [names ...]\n", program_name); + fprintf (fp, "Options:\n"); + fprintf (fp, " -h,--help Display this message.\n"); + fprintf (fp, " -p,--no-params Don't display function parameters\n"); + fprintf (fp, " -v,--verbose Produce verbose demanglings.\n"); + fprintf (fp, "If names are provided, they are demangled. Otherwise filters standard input.\n"); + + exit (exit_value); +} + +/* Option specification for getopt_long. */ +static const struct option long_options[] = +{ + { "help", no_argument, NULL, 'h' }, + { "no-params", no_argument, NULL, 'p' }, + { "verbose", no_argument, NULL, 'v' }, + { NULL, no_argument, NULL, 0 }, +}; + +/* Main entry for a demangling filter executable. It will demangle + its command line arguments, if any. If none are provided, it will + filter stdin to stdout, replacing any recognized mangled C++ names + with their demangled equivalents. */ + +int +main (int argc, char *argv[]) +{ + int i; + int opt_char; + int options = DMGL_PARAMS | DMGL_ANSI | DMGL_TYPES; + + /* Use the program name of this program, as invoked. */ + program_name = argv[0]; + + /* Parse options. */ + do + { + opt_char = getopt_long (argc, argv, "hpv", long_options, NULL); + switch (opt_char) + { + case '?': /* Unrecognized option. */ + print_usage (stderr, 1); + break; + + case 'h': + print_usage (stdout, 0); + break; + + case 'p': + options &= ~ DMGL_PARAMS; + break; + + case 'v': + options |= DMGL_VERBOSE; + break; + } + } + while (opt_char != -1); + + if (optind == argc) + /* No command line arguments were provided. Filter stdin. */ + { + dyn_string_t mangled = dyn_string_new (3); + char *s; + + /* Read all of input. */ + while (!feof (stdin)) + { + char c; + + /* Pile characters into mangled until we hit one that can't + occur in a mangled name. */ + c = getchar (); + while (!feof (stdin) && is_mangled_char (c)) + { + dyn_string_append_char (mangled, c); + if (feof (stdin)) + break; + c = getchar (); + } + + if (dyn_string_length (mangled) > 0) + { +#ifdef IN_GLIBCPP_V3 + s = __cxa_demangle (dyn_string_buf (mangled), NULL, NULL, NULL); +#else + s = cplus_demangle_v3 (dyn_string_buf (mangled), options); +#endif + + if (s != NULL) + { + fputs (s, stdout); + free (s); + } + else + { + /* It might not have been a mangled name. Print the + original text. */ + fputs (dyn_string_buf (mangled), stdout); + } + + dyn_string_clear (mangled); + } + + /* If we haven't hit EOF yet, we've read one character that + can't occur in a mangled name, so print it out. */ + if (!feof (stdin)) + putchar (c); + } + + dyn_string_delete (mangled); + } + else + /* Demangle command line arguments. */ + { + /* Loop over command line arguments. */ + for (i = optind; i < argc; ++i) + { + char *s; +#ifdef IN_GLIBCPP_V3 + int status; +#endif + + /* Attempt to demangle. */ +#ifdef IN_GLIBCPP_V3 + s = __cxa_demangle (argv[i], NULL, NULL, &status); +#else + s = cplus_demangle_v3 (argv[i], options); +#endif + + /* If it worked, print the demangled name. */ + if (s != NULL) + { + printf ("%s\n", s); + free (s); + } + else + { +#ifdef IN_GLIBCPP_V3 + fprintf (stderr, "Failed: %s (status %d)\n", argv[i], status); +#else + fprintf (stderr, "Failed: %s\n", argv[i]); +#endif + } + } + } + + return 0; +} + +#endif /* STANDALONE_DEMANGLER */ diff --git a/3rdparty/demangler/src/cplus-dem.c b/3rdparty/demangler/src/cplus-dem.c new file mode 100644 index 0000000000..2b2bba30e7 --- /dev/null +++ b/3rdparty/demangler/src/cplus-dem.c @@ -0,0 +1,5052 @@ +/* Demangler for GNU C++ + Copyright (C) 1989-2023 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.uucp) + Rewritten by Fred Fish (fnf@cygnus.com) for ARM and Lucid demangling + Modified by Satish Pai (pai@apollo.hp.com) for HP demangling + +This file is part of the libiberty library. +Libiberty 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. + +In addition to the permissions in the GNU Library General Public +License, the Free Software Foundation gives you unlimited permission +to link the compiled version of this file into combinations with other +programs, and to distribute those combinations without any restriction +coming from the use of this file. (The Library Public License +restrictions do apply in other respects; for example, they cover +modification of the file, and distribution when not linked into a +combined executable.) + +Libiberty is distributed in the hope that 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 libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* This file exports six functions; cplus_demangle_opname, cplus_mangle_opname, + cplus_demangle_set_style, cplus_demangle_name_to_style, cplus_demangle and + ada_demangle. + + This file imports xmalloc and xrealloc, which are like malloc and + realloc except that they generate a fatal error if there is no + available memory. */ + +/* This file lives in both GCC and libiberty. When making changes, please + try not to break either. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "safe-ctype.h" + +#include +#include +#include + +#ifdef HAVE_STDLIB_H +#include +#else +void * malloc (); +void * realloc (); +#endif + +#ifdef HAVE_LIMITS_H +#include +#endif +#ifndef INT_MAX +# define INT_MAX (int)(((unsigned int) ~0) >> 1) /* 0x7FFFFFFF */ +#endif + +#include +#undef CURRENT_DEMANGLING_STYLE +#define CURRENT_DEMANGLING_STYLE work->options + +#include "libiberty.h" + +#define min(X,Y) (((X) < (Y)) ? (X) : (Y)) + +/* A value at least one greater than the maximum number of characters + that will be output when using the `%d' format with `printf'. */ +#define INTBUF_SIZE 32 + +extern void fancy_abort (void) ATTRIBUTE_NORETURN; + +/* In order to allow a single demangler executable to demangle strings + using various common values of CPLUS_MARKER, as well as any specific + one set at compile time, we maintain a string containing all the + commonly used ones, and check to see if the marker we are looking for + is in that string. CPLUS_MARKER is usually '$' on systems where the + assembler can deal with that. Where the assembler can't, it's usually + '.' (but on many systems '.' is used for other things). We put the + current defined CPLUS_MARKER first (which defaults to '$'), followed + by the next most common value, followed by an explicit '$' in case + the value of CPLUS_MARKER is not '$'. + + We could avoid this if we could just get g++ to tell us what the actual + cplus marker character is as part of the debug information, perhaps by + ensuring that it is the character that terminates the gcc_compiled + marker symbol (FIXME). */ + +#if !defined (CPLUS_MARKER) +#define CPLUS_MARKER '$' +#endif + +enum demangling_styles current_demangling_style = auto_demangling; + +static char cplus_markers[] = { CPLUS_MARKER, '.', '$', '\0' }; + +static char char_str[2] = { '\000', '\000' }; + +void +set_cplus_marker_for_demangling (int ch) +{ + cplus_markers[0] = ch; +} + +typedef struct string /* Beware: these aren't required to be */ +{ /* '\0' terminated. */ + char *b; /* pointer to start of string */ + char *p; /* pointer after last character */ + char *e; /* pointer after end of allocated space */ +} string; + +/* Stuff that is shared between sub-routines. + Using a shared structure allows cplus_demangle to be reentrant. */ + +struct work_stuff +{ + int options; + char **typevec; + char **ktypevec; + char **btypevec; + int numk; + int numb; + int ksize; + int bsize; + int ntypes; + int typevec_size; + int constructor; + int destructor; + int static_type; /* A static member function */ + int temp_start; /* index in demangled to start of template args */ + int type_quals; /* The type qualifiers. */ + int dllimported; /* Symbol imported from a PE DLL */ + char **tmpl_argvec; /* Template function arguments. */ + int ntmpl_args; /* The number of template function arguments. */ + int forgetting_types; /* Nonzero if we are not remembering the types + we see. */ + string* previous_argument; /* The last function argument demangled. */ + int nrepeats; /* The number of times to repeat the previous + argument. */ + int *proctypevec; /* Indices of currently processed remembered typevecs. */ + int proctypevec_size; + int nproctypes; + unsigned int recursion_level; +}; + +#define PRINT_ANSI_QUALIFIERS (work -> options & DMGL_ANSI) +#define PRINT_ARG_TYPES (work -> options & DMGL_PARAMS) + +static const struct optable +{ + const char *const in; + const char *const out; + const int flags; +} optable[] = { + {"nw", " new", DMGL_ANSI}, /* new (1.92, ansi) */ + {"dl", " delete", DMGL_ANSI}, /* new (1.92, ansi) */ + {"new", " new", 0}, /* old (1.91, and 1.x) */ + {"delete", " delete", 0}, /* old (1.91, and 1.x) */ + {"vn", " new []", DMGL_ANSI}, /* GNU, pending ansi */ + {"vd", " delete []", DMGL_ANSI}, /* GNU, pending ansi */ + {"as", "=", DMGL_ANSI}, /* ansi */ + {"ne", "!=", DMGL_ANSI}, /* old, ansi */ + {"eq", "==", DMGL_ANSI}, /* old, ansi */ + {"ge", ">=", DMGL_ANSI}, /* old, ansi */ + {"gt", ">", DMGL_ANSI}, /* old, ansi */ + {"le", "<=", DMGL_ANSI}, /* old, ansi */ + {"lt", "<", DMGL_ANSI}, /* old, ansi */ + {"plus", "+", 0}, /* old */ + {"pl", "+", DMGL_ANSI}, /* ansi */ + {"apl", "+=", DMGL_ANSI}, /* ansi */ + {"minus", "-", 0}, /* old */ + {"mi", "-", DMGL_ANSI}, /* ansi */ + {"ami", "-=", DMGL_ANSI}, /* ansi */ + {"mult", "*", 0}, /* old */ + {"ml", "*", DMGL_ANSI}, /* ansi */ + {"amu", "*=", DMGL_ANSI}, /* ansi (ARM/Lucid) */ + {"aml", "*=", DMGL_ANSI}, /* ansi (GNU/g++) */ + {"convert", "+", 0}, /* old (unary +) */ + {"negate", "-", 0}, /* old (unary -) */ + {"trunc_mod", "%", 0}, /* old */ + {"md", "%", DMGL_ANSI}, /* ansi */ + {"amd", "%=", DMGL_ANSI}, /* ansi */ + {"trunc_div", "/", 0}, /* old */ + {"dv", "/", DMGL_ANSI}, /* ansi */ + {"adv", "/=", DMGL_ANSI}, /* ansi */ + {"truth_andif", "&&", 0}, /* old */ + {"aa", "&&", DMGL_ANSI}, /* ansi */ + {"truth_orif", "||", 0}, /* old */ + {"oo", "||", DMGL_ANSI}, /* ansi */ + {"truth_not", "!", 0}, /* old */ + {"nt", "!", DMGL_ANSI}, /* ansi */ + {"postincrement","++", 0}, /* old */ + {"pp", "++", DMGL_ANSI}, /* ansi */ + {"postdecrement","--", 0}, /* old */ + {"mm", "--", DMGL_ANSI}, /* ansi */ + {"bit_ior", "|", 0}, /* old */ + {"or", "|", DMGL_ANSI}, /* ansi */ + {"aor", "|=", DMGL_ANSI}, /* ansi */ + {"bit_xor", "^", 0}, /* old */ + {"er", "^", DMGL_ANSI}, /* ansi */ + {"aer", "^=", DMGL_ANSI}, /* ansi */ + {"bit_and", "&", 0}, /* old */ + {"ad", "&", DMGL_ANSI}, /* ansi */ + {"aad", "&=", DMGL_ANSI}, /* ansi */ + {"bit_not", "~", 0}, /* old */ + {"co", "~", DMGL_ANSI}, /* ansi */ + {"call", "()", 0}, /* old */ + {"cl", "()", DMGL_ANSI}, /* ansi */ + {"alshift", "<<", 0}, /* old */ + {"ls", "<<", DMGL_ANSI}, /* ansi */ + {"als", "<<=", DMGL_ANSI}, /* ansi */ + {"arshift", ">>", 0}, /* old */ + {"rs", ">>", DMGL_ANSI}, /* ansi */ + {"ars", ">>=", DMGL_ANSI}, /* ansi */ + {"component", "->", 0}, /* old */ + {"pt", "->", DMGL_ANSI}, /* ansi; Lucid C++ form */ + {"rf", "->", DMGL_ANSI}, /* ansi; ARM/GNU form */ + {"indirect", "*", 0}, /* old */ + {"method_call", "->()", 0}, /* old */ + {"addr", "&", 0}, /* old (unary &) */ + {"array", "[]", 0}, /* old */ + {"vc", "[]", DMGL_ANSI}, /* ansi */ + {"compound", ", ", 0}, /* old */ + {"cm", ", ", DMGL_ANSI}, /* ansi */ + {"cond", "?:", 0}, /* old */ + {"cn", "?:", DMGL_ANSI}, /* pseudo-ansi */ + {"max", ">?", 0}, /* old */ + {"mx", ">?", DMGL_ANSI}, /* pseudo-ansi */ + {"min", "*", DMGL_ANSI}, /* ansi */ + {"sz", "sizeof ", DMGL_ANSI} /* pseudo-ansi */ +}; + +/* These values are used to indicate the various type varieties. + They are all non-zero so that they can be used as `success' + values. */ +typedef enum type_kind_t +{ + tk_none, + tk_pointer, + tk_reference, + tk_rvalue_reference, + tk_integral, + tk_bool, + tk_char, + tk_real +} type_kind_t; + +const struct demangler_engine libiberty_demanglers[] = +{ + { + NO_DEMANGLING_STYLE_STRING, + no_demangling, + "Demangling disabled" + } + , + { + AUTO_DEMANGLING_STYLE_STRING, + auto_demangling, + "Automatic selection based on executable" + } + , + { + GNU_DEMANGLING_STYLE_STRING, + gnu_demangling, + "GNU (g++) style demangling" + } + , + { + LUCID_DEMANGLING_STYLE_STRING, + lucid_demangling, + "Lucid (lcc) style demangling" + } + , + { + ARM_DEMANGLING_STYLE_STRING, + arm_demangling, + "ARM style demangling" + } + , + { + HP_DEMANGLING_STYLE_STRING, + hp_demangling, + "HP (aCC) style demangling" + } + , + { + EDG_DEMANGLING_STYLE_STRING, + edg_demangling, + "EDG style demangling" + } + , + { + GNU_V3_DEMANGLING_STYLE_STRING, + gnu_v3_demangling, + "GNU (g++) V3 (Itanium C++ ABI) style demangling" + } + , + { + JAVA_DEMANGLING_STYLE_STRING, + java_demangling, + "Java style demangling" + } + , + { + GNAT_DEMANGLING_STYLE_STRING, + gnat_demangling, + "GNAT style demangling" + } + , + { + DLANG_DEMANGLING_STYLE_STRING, + dlang_demangling, + "DLANG style demangling" + } + , + { + RUST_DEMANGLING_STYLE_STRING, + rust_demangling, + "Rust style demangling" + } + , + { + NULL, unknown_demangling, NULL + } +}; + +#define STRING_EMPTY(str) ((str) -> b == (str) -> p) +#define APPEND_BLANK(str) {if (!STRING_EMPTY(str)) \ + string_append(str, " ");} +#define LEN_STRING(str) ( (STRING_EMPTY(str))?0:((str)->p - (str)->b)) + +/* The scope separator appropriate for the language being demangled. */ + +#define SCOPE_STRING(work) ((work->options & DMGL_JAVA) ? "." : "::") + +#define ARM_VTABLE_STRING "__vtbl__" /* Lucid/ARM virtual table prefix */ +#define ARM_VTABLE_STRLEN 8 /* strlen (ARM_VTABLE_STRING) */ + +/* Prototypes for local functions */ + +static void delete_work_stuff (struct work_stuff *); + +static void delete_non_B_K_work_stuff (struct work_stuff *); + +static char *mop_up (struct work_stuff *, string *, int); + +static void squangle_mop_up (struct work_stuff *); + +static void work_stuff_copy_to_from (struct work_stuff *, struct work_stuff *); + +#if 0 +static int +demangle_method_args (struct work_stuff *, const char **, string *); +#endif + +static char * +internal_cplus_demangle (struct work_stuff *, const char *); + +static int +demangle_template_template_parm (struct work_stuff *work, + const char **, string *); + +static int +demangle_template (struct work_stuff *work, const char **, string *, + string *, int, int); + +static int +arm_pt (struct work_stuff *, const char *, int, const char **, + const char **); + +static int +demangle_class_name (struct work_stuff *, const char **, string *); + +static int +demangle_qualified (struct work_stuff *, const char **, string *, + int, int); + +static int demangle_class (struct work_stuff *, const char **, string *); + +static int demangle_fund_type (struct work_stuff *, const char **, string *); + +static int demangle_signature (struct work_stuff *, const char **, string *); + +static int demangle_prefix (struct work_stuff *, const char **, string *); + +static int gnu_special (struct work_stuff *, const char **, string *); + +static int arm_special (const char **, string *); + +static void string_need (string *, int); + +static void string_delete (string *); + +static void +string_init (string *); + +static void string_clear (string *); + +#if 0 +static int string_empty (string *); +#endif + +static void string_append (string *, const char *); + +static void string_appends (string *, string *); + +static void string_appendn (string *, const char *, int); + +static void string_prepend (string *, const char *); + +static void string_prependn (string *, const char *, int); + +static void string_append_template_idx (string *, int); + +static int get_count (const char **, int *); + +static int consume_count (const char **); + +static int consume_count_with_underscores (const char**); + +static int demangle_args (struct work_stuff *, const char **, string *); + +static int demangle_nested_args (struct work_stuff*, const char**, string*); + +static int do_type (struct work_stuff *, const char **, string *); + +static int do_arg (struct work_stuff *, const char **, string *); + +static int +demangle_function_name (struct work_stuff *, const char **, string *, + const char *); + +static int +iterate_demangle_function (struct work_stuff *, + const char **, string *, const char *); + +static void remember_type (struct work_stuff *, const char *, int); + +static void push_processed_type (struct work_stuff *, int); + +static void pop_processed_type (struct work_stuff *); + +static void remember_Btype (struct work_stuff *, const char *, int, int); + +static int register_Btype (struct work_stuff *); + +static void remember_Ktype (struct work_stuff *, const char *, int); + +static void forget_types (struct work_stuff *); + +static void forget_B_and_K_types (struct work_stuff *); + +static void string_prepends (string *, string *); + +static int +demangle_template_value_parm (struct work_stuff*, const char**, + string*, type_kind_t); + +static int +do_hpacc_template_const_value (struct work_stuff *, const char **, string *); + +static int +do_hpacc_template_literal (struct work_stuff *, const char **, string *); + +static int snarf_numeric_literal (const char **, string *); + +/* There is a TYPE_QUAL value for each type qualifier. They can be + combined by bitwise-or to form the complete set of qualifiers for a + type. */ + +#define TYPE_UNQUALIFIED 0x0 +#define TYPE_QUAL_CONST 0x1 +#define TYPE_QUAL_VOLATILE 0x2 +#define TYPE_QUAL_RESTRICT 0x4 + +static int code_for_qualifier (int); + +static const char* qualifier_string (int); + +static const char* demangle_qualifier (int); + +static int demangle_expression (struct work_stuff *, const char **, string *, + type_kind_t); + +static int +demangle_integral_value (struct work_stuff *, const char **, string *); + +static int +demangle_real_value (struct work_stuff *, const char **, string *); + +static void +demangle_arm_hp_template (struct work_stuff *, const char **, int, string *); + +static void +recursively_demangle (struct work_stuff *, const char **, string *, int); + +/* Translate count to integer, consuming tokens in the process. + Conversion terminates on the first non-digit character. + + Trying to consume something that isn't a count results in no + consumption of input and a return of -1. + + Overflow consumes the rest of the digits, and returns -1. */ + +static int +consume_count (const char **type) +{ + int count = 0; + + if (! ISDIGIT ((unsigned char)**type)) + return -1; + + while (ISDIGIT ((unsigned char)**type)) + { + const int digit = **type - '0'; + /* Check for overflow. */ + if (count > ((INT_MAX - digit) / 10)) + { + while (ISDIGIT ((unsigned char) **type)) + (*type)++; + return -1; + } + + count *= 10; + count += digit; + (*type)++; + } + + if (count < 0) + count = -1; + + return (count); +} + + +/* Like consume_count, but for counts that are preceded and followed + by '_' if they are greater than 10. Also, -1 is returned for + failure, since 0 can be a valid value. */ + +static int +consume_count_with_underscores (const char **mangled) +{ + int idx; + + if (**mangled == '_') + { + (*mangled)++; + if (!ISDIGIT ((unsigned char)**mangled)) + return -1; + + idx = consume_count (mangled); + if (**mangled != '_') + /* The trailing underscore was missing. */ + return -1; + + (*mangled)++; + } + else + { + if (**mangled < '0' || **mangled > '9') + return -1; + + idx = **mangled - '0'; + (*mangled)++; + } + + return idx; +} + +/* C is the code for a type-qualifier. Return the TYPE_QUAL + corresponding to this qualifier. */ + +static int +code_for_qualifier (int c) +{ + switch (c) + { + case 'C': + return TYPE_QUAL_CONST; + + case 'V': + return TYPE_QUAL_VOLATILE; + + case 'u': + return TYPE_QUAL_RESTRICT; + + default: + break; + } + + /* C was an invalid qualifier. */ + abort (); +} + +/* Return the string corresponding to the qualifiers given by + TYPE_QUALS. */ + +static const char* +qualifier_string (int type_quals) +{ + switch (type_quals) + { + case TYPE_UNQUALIFIED: + return ""; + + case TYPE_QUAL_CONST: + return "const"; + + case TYPE_QUAL_VOLATILE: + return "volatile"; + + case TYPE_QUAL_RESTRICT: + return "__restrict"; + + case TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE: + return "const volatile"; + + case TYPE_QUAL_CONST | TYPE_QUAL_RESTRICT: + return "const __restrict"; + + case TYPE_QUAL_VOLATILE | TYPE_QUAL_RESTRICT: + return "volatile __restrict"; + + case TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE | TYPE_QUAL_RESTRICT: + return "const volatile __restrict"; + + default: + break; + } + + /* TYPE_QUALS was an invalid qualifier set. */ + abort (); +} + +/* C is the code for a type-qualifier. Return the string + corresponding to this qualifier. This function should only be + called with a valid qualifier code. */ + +static const char* +demangle_qualifier (int c) +{ + return qualifier_string (code_for_qualifier (c)); +} + +char* +cplus_demangle_opname (const char *opname, int options) +{ + char* result; + int len, len1; + string type; + struct work_stuff work[1]; + const char *tem; + + result = NULL; + len = strlen(opname); + memset ((char *) work, 0, sizeof (work)); + work->options = options; + + if (opname[0] == '_' && opname[1] == '_' + && opname[2] == 'o' && opname[3] == 'p') + { + /* ANSI. */ + /* type conversion operator. */ + tem = opname + 4; + if (do_type (work, &tem, &type)) + { + /* CCC: Allocate the result string on the heap. */ + result = XNEWVEC (char, (type.p - type.b) + 10); + result[0] = '\0'; + strcat (result, "operator "); + strncat (result, type.b, type.p - type.b); + string_delete (&type); + } + } + else if (opname[0] == '_' && opname[1] == '_' + && ISLOWER((unsigned char)opname[2]) + && ISLOWER((unsigned char)opname[3])) + { + if (opname[4] == '\0') + { + /* Operator. */ + size_t i; + for (i = 0; i < ARRAY_SIZE (optable); i++) + { + if (strlen (optable[i].in) == 2 + && memcmp (optable[i].in, opname + 2, 2) == 0) + { + /* CCC: Allocate the result string on the heap. */ + result = XNEWVEC (char, strlen(optable[i].out) + 9); + result[0] = '\0'; + strcat (result, "operator"); + strcat (result, optable[i].out); + break; + } + } + } + else + { + if (opname[2] == 'a' && opname[5] == '\0') + { + /* Assignment. */ + size_t i; + for (i = 0; i < ARRAY_SIZE (optable); i++) + { + if (strlen (optable[i].in) == 3 + && memcmp (optable[i].in, opname + 2, 3) == 0) + { + /* CCC: Allocate the result string on the heap. */ + result = XNEWVEC (char, strlen(optable[i].out) + 9); + result[0] = '\0'; + strcat (result, "operator"); + strcat (result, optable[i].out); + break; + } + } + } + } + } + else if (len >= 3 + && opname[0] == 'o' + && opname[1] == 'p' + && strchr (cplus_markers, opname[2]) != NULL) + { + /* see if it's an assignment expression */ + if (len >= 10 /* op$assign_ */ + && memcmp (opname + 3, "assign_", 7) == 0) + { + size_t i; + for (i = 0; i < ARRAY_SIZE (optable); i++) + { + len1 = len - 10; + if ((int) strlen (optable[i].in) == len1 + && memcmp (optable[i].in, opname + 10, len1) == 0) + { + /* CCC: Allocate the result string on the heap. */ + result = XNEWVEC (char, strlen(optable[i].out) + 10); + result[0] = '\0'; + strcat (result, "operator"); + strcat (result, optable[i].out); + strcat (result, "="); + break; + } + } + } + else + { + size_t i; + for (i = 0; i < ARRAY_SIZE (optable); i++) + { + len1 = len - 3; + if ((int) strlen (optable[i].in) == len1 + && memcmp (optable[i].in, opname + 3, len1) == 0) + { + /* CCC: Allocate the result string on the heap. */ + result = XNEWVEC (char, strlen(optable[i].out) + 9); + result[0] = '\0'; + strcat (result, "operator"); + strcat (result, optable[i].out); + break; + } + } + } + } + else if (len >= 5 && memcmp (opname, "type", 4) == 0 + && strchr (cplus_markers, opname[4]) != NULL) + { + /* type conversion operator */ + tem = opname + 5; + if (do_type (work, &tem, &type)) + { + /* CCC: Allocate the result string on the heap. */ + result = XNEWVEC (char, type.p - type.b + 10); + result[0] = '\0'; + strcat (result, "operator "); + strncat (result, type.b, type.p - type.b); + string_delete (&type); + } + } + squangle_mop_up (work); + return result; + +} + +/* Takes operator name as e.g. "++" and returns mangled + operator name (e.g. "postincrement_expr"), or NULL if not found. + + If OPTIONS & DMGL_ANSI == 1, return the ANSI name; + if OPTIONS & DMGL_ANSI == 0, return the old GNU name. */ + +const char * +cplus_mangle_opname (const char *opname, int options) +{ + size_t i; + int len; + + len = strlen (opname); + for (i = 0; i < ARRAY_SIZE (optable); i++) + { + if ((int) strlen (optable[i].out) == len + && (options & DMGL_ANSI) == (optable[i].flags & DMGL_ANSI) + && memcmp (optable[i].out, opname, len) == 0) + return optable[i].in; + } + return (0); +} + +/* Add a routine to set the demangling style to be sure it is valid and + allow for any demangler initialization that maybe necessary. */ + +enum demangling_styles +cplus_demangle_set_style (enum demangling_styles style) +{ + const struct demangler_engine *demangler = libiberty_demanglers; + + for (; demangler->demangling_style != unknown_demangling; ++demangler) + if (style == demangler->demangling_style) + { + current_demangling_style = style; + return current_demangling_style; + } + + return unknown_demangling; +} + +/* Do string name to style translation */ + +enum demangling_styles +cplus_demangle_name_to_style (const char *name) +{ + const struct demangler_engine *demangler = libiberty_demanglers; + + for (; demangler->demangling_style != unknown_demangling; ++demangler) + if (strcmp (name, demangler->demangling_style_name) == 0) + return demangler->demangling_style; + + return unknown_demangling; +} + +/* char *cplus_demangle (const char *mangled, int options) + + If MANGLED is a mangled function name produced by GNU C++, then + a pointer to a @code{malloc}ed string giving a C++ representation + of the name will be returned; otherwise NULL will be returned. + It is the caller's responsibility to free the string which + is returned. + + The OPTIONS arg may contain one or more of the following bits: + + DMGL_ANSI ANSI qualifiers such as `const' and `void' are + included. + DMGL_PARAMS Function parameters are included. + + For example, + + cplus_demangle ("foo__1Ai", DMGL_PARAMS) => "A::foo(int)" + cplus_demangle ("foo__1Ai", DMGL_PARAMS | DMGL_ANSI) => "A::foo(int)" + cplus_demangle ("foo__1Ai", 0) => "A::foo" + + cplus_demangle ("foo__1Afe", DMGL_PARAMS) => "A::foo(float,...)" + cplus_demangle ("foo__1Afe", DMGL_PARAMS | DMGL_ANSI)=> "A::foo(float,...)" + cplus_demangle ("foo__1Afe", 0) => "A::foo" + + Note that any leading underscores, or other such characters prepended by + the compilation system, are presumed to have already been stripped from + MANGLED. */ + +char * +cplus_demangle (const char *mangled, int options) +{ + char *ret; + struct work_stuff work[1]; + + if (current_demangling_style == no_demangling) + return xstrdup (mangled); + + memset ((char *) work, 0, sizeof (work)); + work->options = options; + if ((work->options & DMGL_STYLE_MASK) == 0) + work->options |= (int) current_demangling_style & DMGL_STYLE_MASK; + + /* The Rust demangling is implemented elsewhere. + Legacy Rust symbols overlap with GNU_V3, so try Rust first. */ + if (RUST_DEMANGLING || AUTO_DEMANGLING) + { + ret = rust_demangle (mangled, work->options); + if (ret || RUST_DEMANGLING) + return ret; + } + + /* The V3 ABI demangling is implemented elsewhere. */ + if (GNU_V3_DEMANGLING || AUTO_DEMANGLING) + { + ret = cplus_demangle_v3 (mangled, work->options); + if (ret || GNU_V3_DEMANGLING) + return ret; + } + + if (JAVA_DEMANGLING) + { + ret = java_demangle_v3 (mangled); + if (ret) + return ret; + } + + if (GNAT_DEMANGLING) + return ada_demangle (mangled, work->options); + + if (DLANG_DEMANGLING) + { + ret = dlang_demangle (mangled, work->options); + if (ret) + return ret; + } + + ret = internal_cplus_demangle (work, mangled); + squangle_mop_up (work); + return (ret); +} + +/* Demangle ada names. The encoding is documented in gcc/ada/exp_dbug.ads. */ + +char * +ada_demangle (const char *mangled, int option ATTRIBUTE_UNUSED) +{ + int len0; + const char* p; + char *d; + char *demangled = NULL; + + /* Discard leading _ada_, which is used for library level subprograms. */ + if (strncmp (mangled, "_ada_", 5) == 0) + mangled += 5; + + /* All ada unit names are lower-case. */ + if (!ISLOWER (mangled[0])) + goto unknown; + + /* Most of the demangling will trivially remove chars. Operator names + may add one char but because they are always preceeded by '__' which is + replaced by '.', they eventually never expand the size. + A few special names such as '___elabs' add a few chars (at most 7), but + they occur only once. */ + len0 = strlen (mangled) + 7 + 1; + demangled = XNEWVEC (char, len0); + + d = demangled; + p = mangled; + while (1) + { + /* An entity names is expected. */ + if (ISLOWER (*p)) + { + /* An identifier, which is always lower case. */ + do + *d++ = *p++; + while (ISLOWER(*p) || ISDIGIT (*p) + || (p[0] == '_' && (ISLOWER (p[1]) || ISDIGIT (p[1])))); + } + else if (p[0] == 'O') + { + /* An operator name. */ + static const char * const operators[][2] = + {{"Oabs", "abs"}, {"Oand", "and"}, {"Omod", "mod"}, + {"Onot", "not"}, {"Oor", "or"}, {"Orem", "rem"}, + {"Oxor", "xor"}, {"Oeq", "="}, {"One", "/="}, + {"Olt", "<"}, {"Ole", "<="}, {"Ogt", ">"}, + {"Oge", ">="}, {"Oadd", "+"}, {"Osubtract", "-"}, + {"Oconcat", "&"}, {"Omultiply", "*"}, {"Odivide", "/"}, + {"Oexpon", "**"}, {NULL, NULL}}; + int k; + + for (k = 0; operators[k][0] != NULL; k++) + { + size_t slen = strlen (operators[k][0]); + if (strncmp (p, operators[k][0], slen) == 0) + { + p += slen; + slen = strlen (operators[k][1]); + *d++ = '"'; + memcpy (d, operators[k][1], slen); + d += slen; + *d++ = '"'; + break; + } + } + /* Operator not found. */ + if (operators[k][0] == NULL) + goto unknown; + } + else + { + /* Not a GNAT encoding. */ + goto unknown; + } + + /* The name can be directly followed by some uppercase letters. */ + if (p[0] == 'T' && p[1] == 'K') + { + /* Task stuff. */ + if (p[2] == 'B' && p[3] == 0) + { + /* Subprogram for task body. */ + break; + } + else if (p[2] == '_' && p[3] == '_') + { + /* Inner declarations in a task. */ + p += 4; + *d++ = '.'; + continue; + } + else + goto unknown; + } + if (p[0] == 'E' && p[1] == 0) + { + /* Exception name. */ + goto unknown; + } + if ((p[0] == 'P' || p[0] == 'N') && p[1] == 0) + { + /* Protected type subprogram. */ + break; + } + if ((*p == 'N' || *p == 'S') && p[1] == 0) + { + /* Enumerated type name table. */ + goto unknown; + } + if (p[0] == 'X') + { + /* Body nested. */ + p++; + while (p[0] == 'n' || p[0] == 'b') + p++; + } + if (p[0] == 'S' && p[1] != 0 && (p[2] == '_' || p[2] == 0)) + { + /* Stream operations. */ + const char *name; + switch (p[1]) + { + case 'R': + name = "'Read"; + break; + case 'W': + name = "'Write"; + break; + case 'I': + name = "'Input"; + break; + case 'O': + name = "'Output"; + break; + default: + goto unknown; + } + p += 2; + strcpy (d, name); + d += strlen (name); + } + else if (p[0] == 'D') + { + /* Controlled type operation. */ + const char *name; + switch (p[1]) + { + case 'F': + name = ".Finalize"; + break; + case 'A': + name = ".Adjust"; + break; + default: + goto unknown; + } + strcpy (d, name); + d += strlen (name); + break; + } + + if (p[0] == '_') + { + /* Separator. */ + if (p[1] == '_') + { + /* Standard separator. Handled first. */ + p += 2; + + if (ISDIGIT (*p)) + { + /* Overloading number. */ + do + p++; + while (ISDIGIT (*p) || (p[0] == '_' && ISDIGIT (p[1]))); + if (*p == 'X') + { + p++; + while (p[0] == 'n' || p[0] == 'b') + p++; + } + } + else if (p[0] == '_' && p[1] != '_') + { + /* Special names. */ + static const char * const special[][2] = { + { "_elabb", "'Elab_Body" }, + { "_elabs", "'Elab_Spec" }, + { "_size", "'Size" }, + { "_alignment", "'Alignment" }, + { "_assign", ".\":=\"" }, + { NULL, NULL } + }; + int k; + + for (k = 0; special[k][0] != NULL; k++) + { + size_t slen = strlen (special[k][0]); + if (strncmp (p, special[k][0], slen) == 0) + { + p += slen; + slen = strlen (special[k][1]); + memcpy (d, special[k][1], slen); + d += slen; + break; + } + } + if (special[k][0] != NULL) + break; + else + goto unknown; + } + else + { + *d++ = '.'; + continue; + } + } + else if (p[1] == 'B' || p[1] == 'E') + { + /* Entry Body or barrier Evaluation. */ + p += 2; + while (ISDIGIT (*p)) + p++; + if (p[0] == 's' && p[1] == 0) + break; + else + goto unknown; + } + else + goto unknown; + } + + if (p[0] == '.' && ISDIGIT (p[1])) + { + /* Nested subprogram. */ + p += 2; + while (ISDIGIT (*p)) + p++; + } + if (*p == 0) + { + /* End of mangled name. */ + break; + } + else + goto unknown; + } + *d = 0; + return demangled; + + unknown: + XDELETEVEC (demangled); + len0 = strlen (mangled); + demangled = XNEWVEC (char, len0 + 3); + + if (mangled[0] == '<') + strcpy (demangled, mangled); + else + sprintf (demangled, "<%s>", mangled); + + return demangled; +} + +/* This function performs most of what cplus_demangle use to do, but + to be able to demangle a name with a B, K or n code, we need to + have a longer term memory of what types have been seen. The original + now initializes and cleans up the squangle code info, while internal + calls go directly to this routine to avoid resetting that info. */ + +static char * +internal_cplus_demangle (struct work_stuff *work, const char *mangled) +{ + + string decl; + int success = 0; + char *demangled = NULL; + int s1, s2, s3, s4; + s1 = work->constructor; + s2 = work->destructor; + s3 = work->static_type; + s4 = work->type_quals; + work->constructor = work->destructor = 0; + work->type_quals = TYPE_UNQUALIFIED; + work->dllimported = 0; + + if ((mangled != NULL) && (*mangled != '\0')) + { + string_init (&decl); + + /* First check to see if gnu style demangling is active and if the + string to be demangled contains a CPLUS_MARKER. If so, attempt to + recognize one of the gnu special forms rather than looking for a + standard prefix. In particular, don't worry about whether there + is a "__" string in the mangled string. Consider "_$_5__foo" for + example. */ + + if ((AUTO_DEMANGLING || GNU_DEMANGLING)) + { + success = gnu_special (work, &mangled, &decl); + if (!success) + { + delete_work_stuff (work); + string_delete (&decl); + } + } + if (!success) + { + success = demangle_prefix (work, &mangled, &decl); + } + if (success && (*mangled != '\0')) + { + success = demangle_signature (work, &mangled, &decl); + } + if (work->constructor == 2) + { + string_prepend (&decl, "global constructors keyed to "); + work->constructor = 0; + } + else if (work->destructor == 2) + { + string_prepend (&decl, "global destructors keyed to "); + work->destructor = 0; + } + else if (work->dllimported == 1) + { + string_prepend (&decl, "import stub for "); + work->dllimported = 0; + } + demangled = mop_up (work, &decl, success); + } + work->constructor = s1; + work->destructor = s2; + work->static_type = s3; + work->type_quals = s4; + return demangled; +} + + +/* Clear out and squangling related storage */ +static void +squangle_mop_up (struct work_stuff *work) +{ + /* clean up the B and K type mangling types. */ + forget_B_and_K_types (work); + if (work -> btypevec != NULL) + { + free ((char *) work -> btypevec); + work->btypevec = NULL; + work->bsize = 0; + work->numb = 0; + } + if (work -> ktypevec != NULL) + { + free ((char *) work -> ktypevec); + work->ktypevec = NULL; + work->ksize = 0; + work->numk = 0; + } +} + + +/* Copy the work state and storage. */ + +static void +work_stuff_copy_to_from (struct work_stuff *to, struct work_stuff *from) +{ + int i; + + delete_work_stuff (to); + + /* Shallow-copy scalars. */ + memcpy (to, from, sizeof (*to)); + + /* Deep-copy dynamic storage. */ + if (from->typevec_size) + to->typevec = XNEWVEC (char *, from->typevec_size); + + for (i = 0; i < from->ntypes; i++) + { + int len = strlen (from->typevec[i]) + 1; + + to->typevec[i] = XNEWVEC (char, len); + memcpy (to->typevec[i], from->typevec[i], len); + } + + if (from->ksize) + to->ktypevec = XNEWVEC (char *, from->ksize); + + for (i = 0; i < from->numk; i++) + { + int len; + + if (from->ktypevec[i] == NULL) + { + to->ktypevec[i] = NULL; + continue; + } + + len = strlen (from->ktypevec[i]) + 1; + to->ktypevec[i] = XNEWVEC (char, len); + memcpy (to->ktypevec[i], from->ktypevec[i], len); + } + + if (from->bsize) + to->btypevec = XNEWVEC (char *, from->bsize); + + for (i = 0; i < from->numb; i++) + { + int len; + + if (from->btypevec[i] == NULL) + { + to->btypevec[i] = NULL; + continue; + } + + len = strlen (from->btypevec[i]) + 1; + to->btypevec[i] = XNEWVEC (char , len); + memcpy (to->btypevec[i], from->btypevec[i], len); + } + + if (from->proctypevec) + to->proctypevec = + XDUPVEC (int, from->proctypevec, from->proctypevec_size); + + if (from->ntmpl_args) + to->tmpl_argvec = XNEWVEC (char *, from->ntmpl_args); + + for (i = 0; i < from->ntmpl_args; i++) + { + int len = strlen (from->tmpl_argvec[i]) + 1; + + to->tmpl_argvec[i] = XNEWVEC (char, len); + memcpy (to->tmpl_argvec[i], from->tmpl_argvec[i], len); + } + + if (from->previous_argument) + { + to->previous_argument = XNEW (string); + string_init (to->previous_argument); + string_appends (to->previous_argument, from->previous_argument); + } +} + + +/* Delete dynamic stuff in work_stuff that is not to be re-used. */ + +static void +delete_non_B_K_work_stuff (struct work_stuff *work) +{ + /* Discard the remembered types, if any. */ + + forget_types (work); + if (work->typevec != NULL) + { + free ((char *) work->typevec); + work->typevec = NULL; + work->typevec_size = 0; + } + if (work->proctypevec != NULL) + { + free (work->proctypevec); + work->proctypevec = NULL; + work->proctypevec_size = 0; + } + if (work->tmpl_argvec) + { + int i; + + for (i = 0; i < work->ntmpl_args; i++) + free ((char*) work->tmpl_argvec[i]); + + free ((char*) work->tmpl_argvec); + work->tmpl_argvec = NULL; + work->ntmpl_args = 0; + } + if (work->previous_argument) + { + string_delete (work->previous_argument); + free ((char*) work->previous_argument); + work->previous_argument = NULL; + } +} + + +/* Delete all dynamic storage in work_stuff. */ +static void +delete_work_stuff (struct work_stuff *work) +{ + delete_non_B_K_work_stuff (work); + squangle_mop_up (work); +} + + +/* Clear out any mangled storage */ + +static char * +mop_up (struct work_stuff *work, string *declp, int success) +{ + char *demangled = NULL; + + delete_non_B_K_work_stuff (work); + + /* If demangling was successful, ensure that the demangled string is null + terminated and return it. Otherwise, free the demangling decl. */ + + if (!success) + { + string_delete (declp); + } + else + { + string_appendn (declp, "", 1); + demangled = declp->b; + } + return (demangled); +} + +/* + +LOCAL FUNCTION + + demangle_signature -- demangle the signature part of a mangled name + +SYNOPSIS + + static int + demangle_signature (struct work_stuff *work, const char **mangled, + string *declp); + +DESCRIPTION + + Consume and demangle the signature portion of the mangled name. + + DECLP is the string where demangled output is being built. At + entry it contains the demangled root name from the mangled name + prefix. I.E. either a demangled operator name or the root function + name. In some special cases, it may contain nothing. + + *MANGLED points to the current unconsumed location in the mangled + name. As tokens are consumed and demangling is performed, the + pointer is updated to continuously point at the next token to + be consumed. + + Demangling GNU style mangled names is nasty because there is no + explicit token that marks the start of the outermost function + argument list. */ + +static int +demangle_signature (struct work_stuff *work, + const char **mangled, string *declp) +{ + int success = 1; + int func_done = 0; + int expect_func = 0; + int expect_return_type = 0; + const char *oldmangled = NULL; + string trawname; + string tname; + + while (success && (**mangled != '\0')) + { + switch (**mangled) + { + case 'Q': + oldmangled = *mangled; + success = demangle_qualified (work, mangled, declp, 1, 0); + if (success) + remember_type (work, oldmangled, *mangled - oldmangled); + if (AUTO_DEMANGLING || GNU_DEMANGLING) + expect_func = 1; + oldmangled = NULL; + break; + + case 'K': + oldmangled = *mangled; + success = demangle_qualified (work, mangled, declp, 1, 0); + if (AUTO_DEMANGLING || GNU_DEMANGLING) + { + expect_func = 1; + } + oldmangled = NULL; + break; + + case 'S': + /* Static member function */ + if (oldmangled == NULL) + { + oldmangled = *mangled; + } + (*mangled)++; + work -> static_type = 1; + break; + + case 'C': + case 'V': + case 'u': + work->type_quals |= code_for_qualifier (**mangled); + + /* a qualified member function */ + if (oldmangled == NULL) + oldmangled = *mangled; + (*mangled)++; + break; + + case 'L': + /* Local class name follows after "Lnnn_" */ + if (HP_DEMANGLING) + { + while (**mangled && (**mangled != '_')) + (*mangled)++; + if (!**mangled) + success = 0; + else + (*mangled)++; + } + else + success = 0; + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if (oldmangled == NULL) + { + oldmangled = *mangled; + } + work->temp_start = -1; /* uppermost call to demangle_class */ + success = demangle_class (work, mangled, declp); + if (success) + { + remember_type (work, oldmangled, *mangled - oldmangled); + } + if (AUTO_DEMANGLING || GNU_DEMANGLING || EDG_DEMANGLING) + { + /* EDG and others will have the "F", so we let the loop cycle + if we are looking at one. */ + if (**mangled != 'F') + expect_func = 1; + } + oldmangled = NULL; + break; + + case 'B': + { + string s; + success = do_type (work, mangled, &s); + if (success) + { + string_append (&s, SCOPE_STRING (work)); + string_prepends (declp, &s); + string_delete (&s); + } + oldmangled = NULL; + expect_func = 1; + } + break; + + case 'F': + /* Function */ + /* ARM/HP style demangling includes a specific 'F' character after + the class name. For GNU style, it is just implied. So we can + safely just consume any 'F' at this point and be compatible + with either style. */ + + oldmangled = NULL; + func_done = 1; + (*mangled)++; + + /* For lucid/ARM/HP style we have to forget any types we might + have remembered up to this point, since they were not argument + types. GNU style considers all types seen as available for + back references. See comment in demangle_args() */ + + if (LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) + { + forget_types (work); + } + success = demangle_args (work, mangled, declp); + /* After picking off the function args, we expect to either + find the function return type (preceded by an '_') or the + end of the string. */ + if (success && (AUTO_DEMANGLING || EDG_DEMANGLING) && **mangled == '_') + { + ++(*mangled); + /* At this level, we do not care about the return type. */ + success = do_type (work, mangled, &tname); + string_delete (&tname); + } + + break; + + case 't': + /* G++ Template */ + string_init(&trawname); + string_init(&tname); + if (oldmangled == NULL) + { + oldmangled = *mangled; + } + success = demangle_template (work, mangled, &tname, + &trawname, 1, 1); + if (success) + { + remember_type (work, oldmangled, *mangled - oldmangled); + } + string_append (&tname, SCOPE_STRING (work)); + + string_prepends(declp, &tname); + if (work -> destructor & 1) + { + string_prepend (&trawname, "~"); + string_appends (declp, &trawname); + work->destructor -= 1; + } + if ((work->constructor & 1) || (work->destructor & 1)) + { + string_appends (declp, &trawname); + work->constructor -= 1; + } + string_delete(&trawname); + string_delete(&tname); + oldmangled = NULL; + expect_func = 1; + break; + + case '_': + if ((AUTO_DEMANGLING || GNU_DEMANGLING) && expect_return_type) + { + /* Read the return type. */ + string return_type; + + (*mangled)++; + success = do_type (work, mangled, &return_type); + APPEND_BLANK (&return_type); + + string_prepends (declp, &return_type); + string_delete (&return_type); + break; + } + else + /* At the outermost level, we cannot have a return type specified, + so if we run into another '_' at this point we are dealing with + a mangled name that is either bogus, or has been mangled by + some algorithm we don't know how to deal with. So just + reject the entire demangling. */ + /* However, "_nnn" is an expected suffix for alternate entry point + numbered nnn for a function, with HP aCC, so skip over that + without reporting failure. pai/1997-09-04 */ + if (HP_DEMANGLING) + { + (*mangled)++; + while (**mangled && ISDIGIT ((unsigned char)**mangled)) + (*mangled)++; + } + else + success = 0; + break; + + case 'H': + if (AUTO_DEMANGLING || GNU_DEMANGLING) + { + /* A G++ template function. Read the template arguments. */ + success = demangle_template (work, mangled, declp, 0, 0, + 0); + if (!(work->constructor & 1)) + expect_return_type = 1; + if (!**mangled) + success = 0; + else + (*mangled)++; + break; + } + /* fall through */ + + default: + if (AUTO_DEMANGLING || GNU_DEMANGLING) + { + /* Assume we have stumbled onto the first outermost function + argument token, and start processing args. */ + func_done = 1; + success = demangle_args (work, mangled, declp); + } + else + { + /* Non-GNU demanglers use a specific token to mark the start + of the outermost function argument tokens. Typically 'F', + for ARM/HP-demangling, for example. So if we find something + we are not prepared for, it must be an error. */ + success = 0; + } + break; + } + /* + if (AUTO_DEMANGLING || GNU_DEMANGLING) + */ + { + if (success && expect_func) + { + func_done = 1; + if (LUCID_DEMANGLING || ARM_DEMANGLING || EDG_DEMANGLING) + { + forget_types (work); + } + success = demangle_args (work, mangled, declp); + /* Since template include the mangling of their return types, + we must set expect_func to 0 so that we don't try do + demangle more arguments the next time we get here. */ + expect_func = 0; + } + } + } + if (success && !func_done) + { + if (AUTO_DEMANGLING || GNU_DEMANGLING) + { + /* With GNU style demangling, bar__3foo is 'foo::bar(void)', and + bar__3fooi is 'foo::bar(int)'. We get here when we find the + first case, and need to ensure that the '(void)' gets added to + the current declp. Note that with ARM/HP, the first case + represents the name of a static data member 'foo::bar', + which is in the current declp, so we leave it alone. */ + success = demangle_args (work, mangled, declp); + } + } + if (success && PRINT_ARG_TYPES) + { + if (work->static_type) + string_append (declp, " static"); + if (work->type_quals != TYPE_UNQUALIFIED) + { + APPEND_BLANK (declp); + string_append (declp, qualifier_string (work->type_quals)); + } + } + + return (success); +} + +#if 0 + +static int +demangle_method_args (struct work_stuff *work, const char **mangled, + string *declp) +{ + int success = 0; + + if (work -> static_type) + { + string_append (declp, *mangled + 1); + *mangled += strlen (*mangled); + success = 1; + } + else + { + success = demangle_args (work, mangled, declp); + } + return (success); +} + +#endif + +static int +demangle_template_template_parm (struct work_stuff *work, + const char **mangled, string *tname) +{ + int i; + int r; + int need_comma = 0; + int success = 1; + string temp; + + string_append (tname, "template <"); + /* get size of template parameter list */ + if (get_count (mangled, &r)) + { + for (i = 0; i < r; i++) + { + if (need_comma) + { + string_append (tname, ", "); + } + + /* Z for type parameters */ + if (**mangled == 'Z') + { + (*mangled)++; + string_append (tname, "class"); + } + /* z for template parameters */ + else if (**mangled == 'z') + { + (*mangled)++; + success = + demangle_template_template_parm (work, mangled, tname); + if (!success) + { + break; + } + } + else + { + /* temp is initialized in do_type */ + success = do_type (work, mangled, &temp); + if (success) + { + string_appends (tname, &temp); + } + string_delete(&temp); + if (!success) + { + break; + } + } + need_comma = 1; + } + + } + if (tname->p[-1] == '>') + string_append (tname, " "); + string_append (tname, "> class"); + return (success); +} + +static int +demangle_expression (struct work_stuff *work, const char **mangled, + string *s, type_kind_t tk) +{ + int need_operator = 0; + int success; + + success = 1; + string_appendn (s, "(", 1); + (*mangled)++; + while (success && **mangled != 'W' && **mangled != '\0') + { + if (need_operator) + { + size_t i; + size_t len; + + success = 0; + + len = strlen (*mangled); + + for (i = 0; i < ARRAY_SIZE (optable); ++i) + { + size_t l = strlen (optable[i].in); + + if (l <= len + && memcmp (optable[i].in, *mangled, l) == 0) + { + string_appendn (s, " ", 1); + string_append (s, optable[i].out); + string_appendn (s, " ", 1); + success = 1; + (*mangled) += l; + break; + } + } + + if (!success) + break; + } + else + need_operator = 1; + + success = demangle_template_value_parm (work, mangled, s, tk); + } + + if (**mangled != 'W') + success = 0; + else + { + string_appendn (s, ")", 1); + (*mangled)++; + } + + return success; +} + +static int +demangle_integral_value (struct work_stuff *work, + const char **mangled, string *s) +{ + int success; + + if (**mangled == 'E') + success = demangle_expression (work, mangled, s, tk_integral); + else if (**mangled == 'Q' || **mangled == 'K') + success = demangle_qualified (work, mangled, s, 0, 1); + else + { + int value; + + /* By default, we let the number decide whether we shall consume an + underscore. */ + int multidigit_without_leading_underscore = 0; + int leave_following_underscore = 0; + + success = 0; + + if (**mangled == '_') + { + if (mangled[0][1] == 'm') + { + /* Since consume_count_with_underscores does not handle the + `m'-prefix we must do it here, using consume_count and + adjusting underscores: we have to consume the underscore + matching the prepended one. */ + multidigit_without_leading_underscore = 1; + string_appendn (s, "-", 1); + (*mangled) += 2; + } + else + { + /* Do not consume a following underscore; + consume_count_with_underscores will consume what + should be consumed. */ + leave_following_underscore = 1; + } + } + else + { + /* Negative numbers are indicated with a leading `m'. */ + if (**mangled == 'm') + { + string_appendn (s, "-", 1); + (*mangled)++; + } + /* Since consume_count_with_underscores does not handle + multi-digit numbers that do not start with an underscore, + and this number can be an integer template parameter, + we have to call consume_count. */ + multidigit_without_leading_underscore = 1; + /* These multi-digit numbers never end on an underscore, + so if there is one then don't eat it. */ + leave_following_underscore = 1; + } + + /* We must call consume_count if we expect to remove a trailing + underscore, since consume_count_with_underscores expects + the leading underscore (that we consumed) if it is to handle + multi-digit numbers. */ + if (multidigit_without_leading_underscore) + value = consume_count (mangled); + else + value = consume_count_with_underscores (mangled); + + if (value != -1) + { + char buf[INTBUF_SIZE]; + sprintf (buf, "%d", value); + string_append (s, buf); + + /* Numbers not otherwise delimited, might have an underscore + appended as a delimeter, which we should skip. + + ??? This used to always remove a following underscore, which + is wrong. If other (arbitrary) cases are followed by an + underscore, we need to do something more radical. */ + + if ((value > 9 || multidigit_without_leading_underscore) + && ! leave_following_underscore + && **mangled == '_') + (*mangled)++; + + /* All is well. */ + success = 1; + } + } + + return success; +} + +/* Demangle the real value in MANGLED. */ + +static int +demangle_real_value (struct work_stuff *work, + const char **mangled, string *s) +{ + if (**mangled == 'E') + return demangle_expression (work, mangled, s, tk_real); + + if (**mangled == 'm') + { + string_appendn (s, "-", 1); + (*mangled)++; + } + while (ISDIGIT ((unsigned char)**mangled)) + { + string_appendn (s, *mangled, 1); + (*mangled)++; + } + if (**mangled == '.') /* fraction */ + { + string_appendn (s, ".", 1); + (*mangled)++; + while (ISDIGIT ((unsigned char)**mangled)) + { + string_appendn (s, *mangled, 1); + (*mangled)++; + } + } + if (**mangled == 'e') /* exponent */ + { + string_appendn (s, "e", 1); + (*mangled)++; + while (ISDIGIT ((unsigned char)**mangled)) + { + string_appendn (s, *mangled, 1); + (*mangled)++; + } + } + + return 1; +} + +static int +demangle_template_value_parm (struct work_stuff *work, const char **mangled, + string *s, type_kind_t tk) +{ + int success = 1; + + if (**mangled == 'Y') + { + /* The next argument is a template parameter. */ + int idx; + + (*mangled)++; + idx = consume_count_with_underscores (mangled); + if (idx == -1 + || (work->tmpl_argvec && idx >= work->ntmpl_args) + || consume_count_with_underscores (mangled) == -1) + return -1; + if (work->tmpl_argvec) + string_append (s, work->tmpl_argvec[idx]); + else + string_append_template_idx (s, idx); + } + else if (tk == tk_integral) + success = demangle_integral_value (work, mangled, s); + else if (tk == tk_char) + { + char tmp[2]; + int val; + if (**mangled == 'm') + { + string_appendn (s, "-", 1); + (*mangled)++; + } + string_appendn (s, "'", 1); + val = consume_count(mangled); + if (val <= 0) + success = 0; + else + { + tmp[0] = (char)val; + tmp[1] = '\0'; + string_appendn (s, &tmp[0], 1); + string_appendn (s, "'", 1); + } + } + else if (tk == tk_bool) + { + int val = consume_count (mangled); + if (val == 0) + string_appendn (s, "false", 5); + else if (val == 1) + string_appendn (s, "true", 4); + else + success = 0; + } + else if (tk == tk_real) + success = demangle_real_value (work, mangled, s); + else if (tk == tk_pointer || tk == tk_reference + || tk == tk_rvalue_reference) + { + if (**mangled == 'Q') + success = demangle_qualified (work, mangled, s, + /*isfuncname=*/0, + /*append=*/1); + else + { + int symbol_len = consume_count (mangled); + if (symbol_len == -1 + || symbol_len > (long) strlen (*mangled)) + return -1; + if (symbol_len == 0) + string_appendn (s, "0", 1); + else + { + char *p = XNEWVEC (char, symbol_len + 1), *q; + strncpy (p, *mangled, symbol_len); + p [symbol_len] = '\0'; + /* We use cplus_demangle here, rather than + internal_cplus_demangle, because the name of the entity + mangled here does not make use of any of the squangling + or type-code information we have built up thus far; it is + mangled independently. */ + q = cplus_demangle (p, work->options); + if (tk == tk_pointer) + string_appendn (s, "&", 1); + /* FIXME: Pointer-to-member constants should get a + qualifying class name here. */ + if (q) + { + string_append (s, q); + free (q); + } + else + string_append (s, p); + free (p); + } + *mangled += symbol_len; + } + } + + return success; +} + +/* Demangle the template name in MANGLED. The full name of the + template (e.g., S) is placed in TNAME. The name without the + template parameters (e.g. S) is placed in TRAWNAME if TRAWNAME is + non-NULL. If IS_TYPE is nonzero, this template is a type template, + not a function template. If both IS_TYPE and REMEMBER are nonzero, + the template is remembered in the list of back-referenceable + types. */ + +static int +demangle_template (struct work_stuff *work, const char **mangled, + string *tname, string *trawname, + int is_type, int remember) +{ + int i; + int r; + int need_comma = 0; + int success = 0; + int is_java_array = 0; + string temp; + + (*mangled)++; + if (is_type) + { + /* get template name */ + if (**mangled == 'z') + { + int idx; + (*mangled)++; + if (**mangled == '\0') + return (0); + (*mangled)++; + + idx = consume_count_with_underscores (mangled); + if (idx == -1 + || (work->tmpl_argvec && idx >= work->ntmpl_args) + || consume_count_with_underscores (mangled) == -1) + return (0); + + if (work->tmpl_argvec) + { + string_append (tname, work->tmpl_argvec[idx]); + if (trawname) + string_append (trawname, work->tmpl_argvec[idx]); + } + else + { + string_append_template_idx (tname, idx); + if (trawname) + string_append_template_idx (trawname, idx); + } + } + else + { + if ((r = consume_count (mangled)) <= 0 + || (int) strlen (*mangled) < r) + { + return (0); + } + is_java_array = (work -> options & DMGL_JAVA) + && strncmp (*mangled, "JArray1Z", 8) == 0; + if (! is_java_array) + { + string_appendn (tname, *mangled, r); + } + if (trawname) + string_appendn (trawname, *mangled, r); + *mangled += r; + } + } + if (!is_java_array) + string_append (tname, "<"); + /* get size of template parameter list */ + if (!get_count (mangled, &r)) + { + return (0); + } + if (!is_type) + { + /* Create an array for saving the template argument values. */ + work->tmpl_argvec = XNEWVEC (char *, r); + work->ntmpl_args = r; + for (i = 0; i < r; i++) + work->tmpl_argvec[i] = 0; + } + for (i = 0; i < r; i++) + { + if (need_comma) + { + string_append (tname, ", "); + } + /* Z for type parameters */ + if (**mangled == 'Z') + { + (*mangled)++; + /* temp is initialized in do_type */ + success = do_type (work, mangled, &temp); + if (success) + { + string_appends (tname, &temp); + + if (!is_type) + { + /* Save the template argument. */ + int len = temp.p - temp.b; + work->tmpl_argvec[i] = XNEWVEC (char, len + 1); + memcpy (work->tmpl_argvec[i], temp.b, len); + work->tmpl_argvec[i][len] = '\0'; + } + } + string_delete(&temp); + if (!success) + { + break; + } + } + /* z for template parameters */ + else if (**mangled == 'z') + { + int r2; + (*mangled)++; + success = demangle_template_template_parm (work, mangled, tname); + + if (success + && (r2 = consume_count (mangled)) > 0 + && (int) strlen (*mangled) >= r2) + { + string_append (tname, " "); + string_appendn (tname, *mangled, r2); + if (!is_type) + { + /* Save the template argument. */ + int len = r2; + work->tmpl_argvec[i] = XNEWVEC (char, len + 1); + memcpy (work->tmpl_argvec[i], *mangled, len); + work->tmpl_argvec[i][len] = '\0'; + } + *mangled += r2; + } + if (!success) + { + break; + } + } + else + { + string param; + string* s; + + /* otherwise, value parameter */ + + /* temp is initialized in do_type */ + success = do_type (work, mangled, &temp); + string_delete(&temp); + if (!success) + break; + + if (!is_type) + { + s = ¶m; + string_init (s); + } + else + s = tname; + + success = demangle_template_value_parm (work, mangled, s, + (type_kind_t) success); + + if (!success) + { + if (!is_type) + string_delete (s); + success = 0; + break; + } + + if (!is_type) + { + int len = s->p - s->b; + work->tmpl_argvec[i] = XNEWVEC (char, len + 1); + memcpy (work->tmpl_argvec[i], s->b, len); + work->tmpl_argvec[i][len] = '\0'; + + string_appends (tname, s); + string_delete (s); + } + } + need_comma = 1; + } + if (is_java_array) + { + string_append (tname, "[]"); + } + else + { + if (tname->p[-1] == '>') + string_append (tname, " "); + string_append (tname, ">"); + } + + if (is_type && remember) + { + const int bindex = register_Btype (work); + remember_Btype (work, tname->b, LEN_STRING (tname), bindex); + } + + /* + if (work -> static_type) + { + string_append (declp, *mangled + 1); + *mangled += strlen (*mangled); + success = 1; + } + else + { + success = demangle_args (work, mangled, declp); + } + } + */ + return (success); +} + +static int +arm_pt (struct work_stuff *work, const char *mangled, + int n, const char **anchor, const char **args) +{ + /* Check if ARM template with "__pt__" in it ("parameterized type") */ + /* Allow HP also here, because HP's cfront compiler follows ARM to some extent */ + if ((ARM_DEMANGLING || HP_DEMANGLING) && (*anchor = strstr (mangled, "__pt__"))) + { + int len; + *args = *anchor + 6; + len = consume_count (args); + if (len == -1) + return 0; + if (*args + len == mangled + n && **args == '_') + { + ++*args; + return 1; + } + } + if (AUTO_DEMANGLING || EDG_DEMANGLING) + { + if ((*anchor = strstr (mangled, "__tm__")) + || (*anchor = strstr (mangled, "__ps__")) + || (*anchor = strstr (mangled, "__pt__"))) + { + int len; + *args = *anchor + 6; + len = consume_count (args); + if (len == -1) + return 0; + if (*args + len == mangled + n && **args == '_') + { + ++*args; + return 1; + } + } + else if ((*anchor = strstr (mangled, "__S"))) + { + int len; + *args = *anchor + 3; + len = consume_count (args); + if (len == -1) + return 0; + if (*args + len == mangled + n && **args == '_') + { + ++*args; + return 1; + } + } + } + + return 0; +} + +static void +demangle_arm_hp_template (struct work_stuff *work, const char **mangled, + int n, string *declp) +{ + const char *p; + const char *args; + const char *e = *mangled + n; + string arg; + + /* Check for HP aCC template spec: classXt1t2 where t1, t2 are + template args */ + if (HP_DEMANGLING && ((*mangled)[n] == 'X')) + { + char *start_spec_args = NULL; + int hold_options; + + /* First check for and omit template specialization pseudo-arguments, + such as in "Spec<#1,#1.*>" */ + start_spec_args = strchr (*mangled, '<'); + if (start_spec_args && (start_spec_args - *mangled < n)) + string_appendn (declp, *mangled, start_spec_args - *mangled); + else + string_appendn (declp, *mangled, n); + (*mangled) += n + 1; + string_init (&arg); + if (work->temp_start == -1) /* non-recursive call */ + work->temp_start = declp->p - declp->b; + + /* We want to unconditionally demangle parameter types in + template parameters. */ + hold_options = work->options; + work->options |= DMGL_PARAMS; + + string_append (declp, "<"); + while (1) + { + string_delete (&arg); + switch (**mangled) + { + case 'T': + /* 'T' signals a type parameter */ + (*mangled)++; + if (!do_type (work, mangled, &arg)) + goto hpacc_template_args_done; + break; + + case 'U': + case 'S': + /* 'U' or 'S' signals an integral value */ + if (!do_hpacc_template_const_value (work, mangled, &arg)) + goto hpacc_template_args_done; + break; + + case 'A': + /* 'A' signals a named constant expression (literal) */ + if (!do_hpacc_template_literal (work, mangled, &arg)) + goto hpacc_template_args_done; + break; + + default: + /* Today, 1997-09-03, we have only the above types + of template parameters */ + /* FIXME: maybe this should fail and return null */ + goto hpacc_template_args_done; + } + string_appends (declp, &arg); + /* Check if we're at the end of template args. + 0 if at end of static member of template class, + _ if done with template args for a function */ + if ((**mangled == '\000') || (**mangled == '_')) + break; + else + string_append (declp, ","); + } + hpacc_template_args_done: + string_append (declp, ">"); + string_delete (&arg); + if (**mangled == '_') + (*mangled)++; + work->options = hold_options; + return; + } + /* ARM template? (Also handles HP cfront extensions) */ + else if (arm_pt (work, *mangled, n, &p, &args)) + { + int hold_options; + string type_str; + + string_init (&arg); + string_appendn (declp, *mangled, p - *mangled); + if (work->temp_start == -1) /* non-recursive call */ + work->temp_start = declp->p - declp->b; + + /* We want to unconditionally demangle parameter types in + template parameters. */ + hold_options = work->options; + work->options |= DMGL_PARAMS; + + string_append (declp, "<"); + /* should do error checking here */ + while (args < e) { + string_delete (&arg); + + /* Check for type or literal here */ + switch (*args) + { + /* HP cfront extensions to ARM for template args */ + /* spec: Xt1Lv1 where t1 is a type, v1 is a literal value */ + /* FIXME: We handle only numeric literals for HP cfront */ + case 'X': + /* A typed constant value follows */ + args++; + if (!do_type (work, &args, &type_str)) + goto cfront_template_args_done; + string_append (&arg, "("); + string_appends (&arg, &type_str); + string_delete (&type_str); + string_append (&arg, ")"); + if (*args != 'L') + goto cfront_template_args_done; + args++; + /* Now snarf a literal value following 'L' */ + if (!snarf_numeric_literal (&args, &arg)) + goto cfront_template_args_done; + break; + + case 'L': + /* Snarf a literal following 'L' */ + args++; + if (!snarf_numeric_literal (&args, &arg)) + goto cfront_template_args_done; + break; + default: + /* Not handling other HP cfront stuff */ + { + const char* old_args = args; + if (!do_type (work, &args, &arg)) + goto cfront_template_args_done; + + /* Fail if we didn't make any progress: prevent infinite loop. */ + if (args == old_args) + { + work->options = hold_options; + return; + } + } + } + string_appends (declp, &arg); + string_append (declp, ","); + } + cfront_template_args_done: + string_delete (&arg); + if (args >= e) + --declp->p; /* remove extra comma */ + string_append (declp, ">"); + work->options = hold_options; + } + else if (n>10 && strncmp (*mangled, "_GLOBAL_", 8) == 0 + && (*mangled)[9] == 'N' + && (*mangled)[8] == (*mangled)[10] + && strchr (cplus_markers, (*mangled)[8])) + { + /* A member of the anonymous namespace. */ + string_append (declp, "{anonymous}"); + } + else + { + if (work->temp_start == -1) /* non-recursive call only */ + work->temp_start = 0; /* disable in recursive calls */ + string_appendn (declp, *mangled, n); + } + *mangled += n; +} + +/* Extract a class name, possibly a template with arguments, from the + mangled string; qualifiers, local class indicators, etc. have + already been dealt with */ + +static int +demangle_class_name (struct work_stuff *work, const char **mangled, + string *declp) +{ + int n; + int success = 0; + + n = consume_count (mangled); + if (n == -1) + return 0; + if ((int) strlen (*mangled) >= n) + { + demangle_arm_hp_template (work, mangled, n, declp); + success = 1; + } + + return (success); +} + +/* + +LOCAL FUNCTION + + demangle_class -- demangle a mangled class sequence + +SYNOPSIS + + static int + demangle_class (struct work_stuff *work, const char **mangled, + strint *declp) + +DESCRIPTION + + DECLP points to the buffer into which demangling is being done. + + *MANGLED points to the current token to be demangled. On input, + it points to a mangled class (I.E. "3foo", "13verylongclass", etc.) + On exit, it points to the next token after the mangled class on + success, or the first unconsumed token on failure. + + If the CONSTRUCTOR or DESTRUCTOR flags are set in WORK, then + we are demangling a constructor or destructor. In this case + we prepend "class::class" or "class::~class" to DECLP. + + Otherwise, we prepend "class::" to the current DECLP. + + Reset the constructor/destructor flags once they have been + "consumed". This allows demangle_class to be called later during + the same demangling, to do normal class demangling. + + Returns 1 if demangling is successful, 0 otherwise. + +*/ + +static int +demangle_class (struct work_stuff *work, const char **mangled, string *declp) +{ + int success = 0; + int btype; + string class_name; + char *save_class_name_end = 0; + + string_init (&class_name); + btype = register_Btype (work); + if (demangle_class_name (work, mangled, &class_name)) + { + save_class_name_end = class_name.p; + if ((work->constructor & 1) || (work->destructor & 1)) + { + /* adjust so we don't include template args */ + if (work->temp_start && (work->temp_start != -1)) + { + class_name.p = class_name.b + work->temp_start; + } + string_prepends (declp, &class_name); + if (work -> destructor & 1) + { + string_prepend (declp, "~"); + work -> destructor -= 1; + } + else + { + work -> constructor -= 1; + } + } + class_name.p = save_class_name_end; + remember_Ktype (work, class_name.b, LEN_STRING(&class_name)); + remember_Btype (work, class_name.b, LEN_STRING(&class_name), btype); + string_prepend (declp, SCOPE_STRING (work)); + string_prepends (declp, &class_name); + success = 1; + } + string_delete (&class_name); + return (success); +} + + +/* Called when there's a "__" in the mangled name, with `scan' pointing to + the rightmost guess. + + Find the correct "__"-sequence where the function name ends and the + signature starts, which is ambiguous with GNU mangling. + Call demangle_signature here, so we can make sure we found the right + one; *mangled will be consumed so caller will not make further calls to + demangle_signature. */ + +static int +iterate_demangle_function (struct work_stuff *work, const char **mangled, + string *declp, const char *scan) +{ + const char *mangle_init = *mangled; + int success = 0; + string decl_init; + struct work_stuff work_init; + + if (*(scan + 2) == '\0') + return 0; + + /* Do not iterate for some demangling modes, or if there's only one + "__"-sequence. This is the normal case. */ + if (ARM_DEMANGLING || LUCID_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING + || strstr (scan + 2, "__") == NULL) + return demangle_function_name (work, mangled, declp, scan); + + /* Save state so we can restart if the guess at the correct "__" was + wrong. */ + string_init (&decl_init); + string_appends (&decl_init, declp); + memset (&work_init, 0, sizeof work_init); + work_stuff_copy_to_from (&work_init, work); + + /* Iterate over occurrences of __, allowing names and types to have a + "__" sequence in them. We must start with the first (not the last) + occurrence, since "__" most often occur between independent mangled + parts, hence starting at the last occurence inside a signature + might get us a "successful" demangling of the signature. */ + + while (scan[2]) + { + if (demangle_function_name (work, mangled, declp, scan)) + { + success = demangle_signature (work, mangled, declp); + if (success) + break; + } + + /* Reset demangle state for the next round. */ + *mangled = mangle_init; + string_clear (declp); + string_appends (declp, &decl_init); + work_stuff_copy_to_from (work, &work_init); + + /* Leave this underscore-sequence. */ + scan += 2; + + /* Scan for the next "__" sequence. */ + while (*scan && (scan[0] != '_' || scan[1] != '_')) + scan++; + + /* Move to last "__" in this sequence. */ + while (*scan && *scan == '_') + scan++; + scan -= 2; + } + + /* Delete saved state. */ + delete_work_stuff (&work_init); + string_delete (&decl_init); + + return success; +} + +/* + +LOCAL FUNCTION + + demangle_prefix -- consume the mangled name prefix and find signature + +SYNOPSIS + + static int + demangle_prefix (struct work_stuff *work, const char **mangled, + string *declp); + +DESCRIPTION + + Consume and demangle the prefix of the mangled name. + While processing the function name root, arrange to call + demangle_signature if the root is ambiguous. + + DECLP points to the string buffer into which demangled output is + placed. On entry, the buffer is empty. On exit it contains + the root function name, the demangled operator name, or in some + special cases either nothing or the completely demangled result. + + MANGLED points to the current pointer into the mangled name. As each + token of the mangled name is consumed, it is updated. Upon entry + the current mangled name pointer points to the first character of + the mangled name. Upon exit, it should point to the first character + of the signature if demangling was successful, or to the first + unconsumed character if demangling of the prefix was unsuccessful. + + Returns 1 on success, 0 otherwise. + */ + +static int +demangle_prefix (struct work_stuff *work, const char **mangled, + string *declp) +{ + int success = 1; + const char *scan; + int i; + + if (strlen(*mangled) > 6 + && (strncmp(*mangled, "_imp__", 6) == 0 + || strncmp(*mangled, "__imp_", 6) == 0)) + { + /* it's a symbol imported from a PE dynamic library. Check for both + new style prefix _imp__ and legacy __imp_ used by older versions + of dlltool. */ + (*mangled) += 6; + work->dllimported = 1; + } + else if (strlen(*mangled) >= 11 && strncmp(*mangled, "_GLOBAL_", 8) == 0) + { + char *marker = strchr (cplus_markers, (*mangled)[8]); + if (marker != NULL && *marker == (*mangled)[10]) + { + if ((*mangled)[9] == 'D') + { + /* it's a GNU global destructor to be executed at program exit */ + (*mangled) += 11; + work->destructor = 2; + if (gnu_special (work, mangled, declp)) + return success; + } + else if ((*mangled)[9] == 'I') + { + /* it's a GNU global constructor to be executed at program init */ + (*mangled) += 11; + work->constructor = 2; + if (gnu_special (work, mangled, declp)) + return success; + } + } + } + else if ((ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) && strncmp(*mangled, "__std__", 7) == 0) + { + /* it's a ARM global destructor to be executed at program exit */ + (*mangled) += 7; + work->destructor = 2; + } + else if ((ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) && strncmp(*mangled, "__sti__", 7) == 0) + { + /* it's a ARM global constructor to be executed at program initial */ + (*mangled) += 7; + work->constructor = 2; + } + + /* This block of code is a reduction in strength time optimization + of: + scan = strstr (*mangled, "__"); */ + + { + scan = *mangled; + + do { + scan = strchr (scan, '_'); + } while (scan != NULL && *++scan != '_'); + + if (scan != NULL) --scan; + } + + if (scan != NULL) + { + /* We found a sequence of two or more '_', ensure that we start at + the last pair in the sequence. */ + i = strspn (scan, "_"); + if (i > 2) + { + scan += (i - 2); + } + } + + if (scan == NULL) + { + success = 0; + } + else if (work -> static_type) + { + if (!ISDIGIT ((unsigned char)scan[0]) && (scan[0] != 't')) + { + success = 0; + } + } + else if ((scan == *mangled) + && (ISDIGIT ((unsigned char)scan[2]) || (scan[2] == 'Q') + || (scan[2] == 't') || (scan[2] == 'K') || (scan[2] == 'H'))) + { + /* The ARM says nothing about the mangling of local variables. + But cfront mangles local variables by prepending __ + to them. As an extension to ARM demangling we handle this case. */ + if ((LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING) + && ISDIGIT ((unsigned char)scan[2])) + { + *mangled = scan + 2; + consume_count (mangled); + string_append (declp, *mangled); + *mangled += strlen (*mangled); + success = 1; + } + else + { + /* A GNU style constructor starts with __[0-9Qt]. But cfront uses + names like __Q2_3foo3bar for nested type names. So don't accept + this style of constructor for cfront demangling. A GNU + style member-template constructor starts with 'H'. */ + if (!(LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING)) + work -> constructor += 1; + *mangled = scan + 2; + } + } + else if (ARM_DEMANGLING && scan[2] == 'p' && scan[3] == 't') + { + /* Cfront-style parameterized type. Handled later as a signature. */ + success = 1; + + /* ARM template? */ + demangle_arm_hp_template (work, mangled, strlen (*mangled), declp); + } + else if (EDG_DEMANGLING && ((scan[2] == 't' && scan[3] == 'm') + || (scan[2] == 'p' && scan[3] == 's') + || (scan[2] == 'p' && scan[3] == 't'))) + { + /* EDG-style parameterized type. Handled later as a signature. */ + success = 1; + + /* EDG template? */ + demangle_arm_hp_template (work, mangled, strlen (*mangled), declp); + } + else if ((scan == *mangled) && !ISDIGIT ((unsigned char)scan[2]) + && (scan[2] != 't')) + { + /* Mangled name starts with "__". Skip over any leading '_' characters, + then find the next "__" that separates the prefix from the signature. + */ + if (!(ARM_DEMANGLING || LUCID_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) + || (arm_special (mangled, declp) == 0)) + { + while (*scan == '_') + { + scan++; + } + if ((scan = strstr (scan, "__")) == NULL || (*(scan + 2) == '\0')) + { + /* No separator (I.E. "__not_mangled"), or empty signature + (I.E. "__not_mangled_either__") */ + success = 0; + } + else + return iterate_demangle_function (work, mangled, declp, scan); + } + } + else if (*(scan + 2) != '\0') + { + /* Mangled name does not start with "__" but does have one somewhere + in there with non empty stuff after it. Looks like a global + function name. Iterate over all "__":s until the right + one is found. */ + return iterate_demangle_function (work, mangled, declp, scan); + } + else + { + /* Doesn't look like a mangled name */ + success = 0; + } + + if (!success && (work->constructor == 2 || work->destructor == 2)) + { + string_append (declp, *mangled); + *mangled += strlen (*mangled); + success = 1; + } + return (success); +} + +/* + +LOCAL FUNCTION + + gnu_special -- special handling of gnu mangled strings + +SYNOPSIS + + static int + gnu_special (struct work_stuff *work, const char **mangled, + string *declp); + + +DESCRIPTION + + Process some special GNU style mangling forms that don't fit + the normal pattern. For example: + + _$_3foo (destructor for class foo) + _vt$foo (foo virtual table) + _vt$foo$bar (foo::bar virtual table) + __vt_foo (foo virtual table, new style with thunks) + _3foo$varname (static data member) + _Q22rs2tu$vw (static data member) + __t6vector1Zii (constructor with template) + __thunk_4__$_7ostream (virtual function thunk) + */ + +static int +gnu_special (struct work_stuff *work, const char **mangled, string *declp) +{ + int n; + int success = 1; + const char *p; + + if ((*mangled)[0] == '_' && (*mangled)[1] != '\0' + && strchr (cplus_markers, (*mangled)[1]) != NULL + && (*mangled)[2] == '_') + { + /* Found a GNU style destructor, get past "__" */ + (*mangled) += 3; + work -> destructor += 1; + } + else if ((*mangled)[0] == '_' + && (((*mangled)[1] == '_' + && (*mangled)[2] == 'v' + && (*mangled)[3] == 't' + && (*mangled)[4] == '_') + || ((*mangled)[1] == 'v' + && (*mangled)[2] == 't' && (*mangled)[3] != '\0' + && strchr (cplus_markers, (*mangled)[3]) != NULL))) + { + /* Found a GNU style virtual table, get past "_vt" + and create the decl. Note that we consume the entire mangled + input string, which means that demangle_signature has no work + to do. */ + if ((*mangled)[2] == 'v') + (*mangled) += 5; /* New style, with thunks: "__vt_" */ + else + (*mangled) += 4; /* Old style, no thunks: "_vt" */ + while (**mangled != '\0') + { + switch (**mangled) + { + case 'Q': + case 'K': + success = demangle_qualified (work, mangled, declp, 0, 1); + break; + case 't': + success = demangle_template (work, mangled, declp, 0, 1, + 1); + break; + default: + if (ISDIGIT((unsigned char)*mangled[0])) + { + n = consume_count(mangled); + /* We may be seeing a too-large size, or else a + "." indicating a static local symbol. In + any case, declare victory and move on; *don't* try + to use n to allocate. */ + if (n > (int) strlen (*mangled)) + { + success = 1; + break; + } + else if (n == -1) + { + success = 0; + break; + } + } + else + { + n = strcspn (*mangled, cplus_markers); + } + string_appendn (declp, *mangled, n); + (*mangled) += n; + } + + p = strpbrk (*mangled, cplus_markers); + if (success && ((p == NULL) || (p == *mangled))) + { + if (p != NULL) + { + string_append (declp, SCOPE_STRING (work)); + (*mangled)++; + } + } + else + { + success = 0; + break; + } + } + if (success) + string_append (declp, " virtual table"); + } + else if ((*mangled)[0] == '_' + && (strchr("0123456789Qt", (*mangled)[1]) != NULL) + && (p = strpbrk (*mangled, cplus_markers)) != NULL) + { + /* static data member, "_3foo$varname" for example */ + (*mangled)++; + switch (**mangled) + { + case 'Q': + case 'K': + success = demangle_qualified (work, mangled, declp, 0, 1); + break; + case 't': + success = demangle_template (work, mangled, declp, 0, 1, 1); + break; + default: + n = consume_count (mangled); + if (n < 0 || n > (long) strlen (*mangled)) + { + success = 0; + break; + } + + if (n > 10 && strncmp (*mangled, "_GLOBAL_", 8) == 0 + && (*mangled)[9] == 'N' + && (*mangled)[8] == (*mangled)[10] + && strchr (cplus_markers, (*mangled)[8])) + { + /* A member of the anonymous namespace. There's information + about what identifier or filename it was keyed to, but + it's just there to make the mangled name unique; we just + step over it. */ + string_append (declp, "{anonymous}"); + (*mangled) += n; + + /* Now p points to the marker before the N, so we need to + update it to the first marker after what we consumed. */ + p = strpbrk (*mangled, cplus_markers); + break; + } + + string_appendn (declp, *mangled, n); + (*mangled) += n; + } + if (success && (p == *mangled)) + { + /* Consumed everything up to the cplus_marker, append the + variable name. */ + (*mangled)++; + string_append (declp, SCOPE_STRING (work)); + n = strlen (*mangled); + string_appendn (declp, *mangled, n); + (*mangled) += n; + } + else + { + success = 0; + } + } + else if (strncmp (*mangled, "__thunk_", 8) == 0) + { + int delta; + + (*mangled) += 8; + delta = consume_count (mangled); + if (delta == -1) + success = 0; + else if (**mangled != '_') + success = 0; + else + { + char *method = internal_cplus_demangle (work, ++*mangled); + + if (method) + { + char buf[50]; + sprintf (buf, "virtual function thunk (delta:%d) for ", -delta); + string_append (declp, buf); + string_append (declp, method); + free (method); + n = strlen (*mangled); + (*mangled) += n; + } + else + { + success = 0; + } + } + } + else if (strncmp (*mangled, "__t", 3) == 0 + && ((*mangled)[3] == 'i' || (*mangled)[3] == 'f')) + { + p = (*mangled)[3] == 'i' ? " type_info node" : " type_info function"; + (*mangled) += 4; + switch (**mangled) + { + case 'Q': + case 'K': + success = demangle_qualified (work, mangled, declp, 0, 1); + break; + case 't': + success = demangle_template (work, mangled, declp, 0, 1, 1); + break; + default: + success = do_type (work, mangled, declp); + break; + } + if (success && **mangled != '\0') + success = 0; + if (success) + string_append (declp, p); + } + else + { + success = 0; + } + return (success); +} + +static void +recursively_demangle(struct work_stuff *work, const char **mangled, + string *result, int namelength) +{ + char * recurse = (char *)NULL; + char * recurse_dem = (char *)NULL; + + recurse = XNEWVEC (char, namelength + 1); + memcpy (recurse, *mangled, namelength); + recurse[namelength] = '\000'; + + recurse_dem = cplus_demangle (recurse, work->options); + + if (recurse_dem) + { + string_append (result, recurse_dem); + free (recurse_dem); + } + else + { + string_appendn (result, *mangled, namelength); + } + free (recurse); + *mangled += namelength; +} + +/* + +LOCAL FUNCTION + + arm_special -- special handling of ARM/lucid mangled strings + +SYNOPSIS + + static int + arm_special (const char **mangled, + string *declp); + + +DESCRIPTION + + Process some special ARM style mangling forms that don't fit + the normal pattern. For example: + + __vtbl__3foo (foo virtual table) + __vtbl__3foo__3bar (bar::foo virtual table) + + */ + +static int +arm_special (const char **mangled, string *declp) +{ + int n; + int success = 1; + const char *scan; + + if (strncmp (*mangled, ARM_VTABLE_STRING, ARM_VTABLE_STRLEN) == 0) + { + /* Found a ARM style virtual table, get past ARM_VTABLE_STRING + and create the decl. Note that we consume the entire mangled + input string, which means that demangle_signature has no work + to do. */ + scan = *mangled + ARM_VTABLE_STRLEN; + while (*scan != '\0') /* first check it can be demangled */ + { + n = consume_count (&scan); + if (n == -1) + { + return (0); /* no good */ + } + scan += n; + if (scan[0] == '_' && scan[1] == '_') + { + scan += 2; + } + } + (*mangled) += ARM_VTABLE_STRLEN; + while (**mangled != '\0') + { + n = consume_count (mangled); + if (n == -1 + || n > (long) strlen (*mangled)) + return 0; + string_prependn (declp, *mangled, n); + (*mangled) += n; + if ((*mangled)[0] == '_' && (*mangled)[1] == '_') + { + string_prepend (declp, "::"); + (*mangled) += 2; + } + } + string_append (declp, " virtual table"); + } + else + { + success = 0; + } + return (success); +} + +/* + +LOCAL FUNCTION + + demangle_qualified -- demangle 'Q' qualified name strings + +SYNOPSIS + + static int + demangle_qualified (struct work_stuff *, const char *mangled, + string *result, int isfuncname, int append); + +DESCRIPTION + + Demangle a qualified name, such as "Q25Outer5Inner" which is + the mangled form of "Outer::Inner". The demangled output is + prepended or appended to the result string according to the + state of the append flag. + + If isfuncname is nonzero, then the qualified name we are building + is going to be used as a member function name, so if it is a + constructor or destructor function, append an appropriate + constructor or destructor name. I.E. for the above example, + the result for use as a constructor is "Outer::Inner::Inner" + and the result for use as a destructor is "Outer::Inner::~Inner". + +BUGS + + Numeric conversion is ASCII dependent (FIXME). + + */ + +static int +demangle_qualified (struct work_stuff *work, const char **mangled, + string *result, int isfuncname, int append) +{ + int qualifiers = 0; + int success = 1; + char num[2]; + string temp; + string last_name; + int bindex = register_Btype (work); + + /* We only make use of ISFUNCNAME if the entity is a constructor or + destructor. */ + isfuncname = (isfuncname + && ((work->constructor & 1) || (work->destructor & 1))); + + string_init (&temp); + string_init (&last_name); + + if ((*mangled)[0] == 'K') + { + /* Squangling qualified name reuse */ + int idx; + (*mangled)++; + idx = consume_count_with_underscores (mangled); + if (idx == -1 || idx >= work -> numk) + success = 0; + else + string_append (&temp, work -> ktypevec[idx]); + } + else + switch ((*mangled)[1]) + { + case '_': + /* GNU mangled name with more than 9 classes. The count is preceded + by an underscore (to distinguish it from the <= 9 case) and followed + by an underscore. */ + (*mangled)++; + qualifiers = consume_count_with_underscores (mangled); + if (qualifiers == -1) + success = 0; + break; + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + /* The count is in a single digit. */ + num[0] = (*mangled)[1]; + num[1] = '\0'; + qualifiers = atoi (num); + + /* If there is an underscore after the digit, skip it. This is + said to be for ARM-qualified names, but the ARM makes no + mention of such an underscore. Perhaps cfront uses one. */ + if ((*mangled)[2] == '_') + { + (*mangled)++; + } + (*mangled) += 2; + break; + + case '0': + default: + success = 0; + } + + if (!success) + return success; + + /* Pick off the names and collect them in the temp buffer in the order + in which they are found, separated by '::'. */ + + while (qualifiers-- > 0) + { + int remember_K = 1; + string_clear (&last_name); + + if (*mangled[0] == '_') + (*mangled)++; + + if (*mangled[0] == 't') + { + /* Here we always append to TEMP since we will want to use + the template name without the template parameters as a + constructor or destructor name. The appropriate + (parameter-less) value is returned by demangle_template + in LAST_NAME. We do not remember the template type here, + in order to match the G++ mangling algorithm. */ + success = demangle_template(work, mangled, &temp, + &last_name, 1, 0); + if (!success) + break; + } + else if (*mangled[0] == 'K') + { + int idx; + (*mangled)++; + idx = consume_count_with_underscores (mangled); + if (idx == -1 || idx >= work->numk) + success = 0; + else + string_append (&temp, work->ktypevec[idx]); + remember_K = 0; + + if (!success) break; + } + else + { + if (EDG_DEMANGLING) + { + int namelength; + /* Now recursively demangle the qualifier + * This is necessary to deal with templates in + * mangling styles like EDG */ + namelength = consume_count (mangled); + if (namelength == -1) + { + success = 0; + break; + } + recursively_demangle(work, mangled, &temp, namelength); + } + else + { + string_delete (&last_name); + success = do_type (work, mangled, &last_name); + if (!success) + break; + string_appends (&temp, &last_name); + } + } + + if (remember_K) + remember_Ktype (work, temp.b, LEN_STRING (&temp)); + + if (qualifiers > 0) + string_append (&temp, SCOPE_STRING (work)); + } + + remember_Btype (work, temp.b, LEN_STRING (&temp), bindex); + + /* If we are using the result as a function name, we need to append + the appropriate '::' separated constructor or destructor name. + We do this here because this is the most convenient place, where + we already have a pointer to the name and the length of the name. */ + + if (isfuncname) + { + string_append (&temp, SCOPE_STRING (work)); + if (work -> destructor & 1) + string_append (&temp, "~"); + string_appends (&temp, &last_name); + } + + /* Now either prepend the temp buffer to the result, or append it, + depending upon the state of the append flag. */ + + if (append) + string_appends (result, &temp); + else + { + if (!STRING_EMPTY (result)) + string_append (&temp, SCOPE_STRING (work)); + string_prepends (result, &temp); + } + + string_delete (&last_name); + string_delete (&temp); + return (success); +} + +/* + +LOCAL FUNCTION + + get_count -- convert an ascii count to integer, consuming tokens + +SYNOPSIS + + static int + get_count (const char **type, int *count) + +DESCRIPTION + + Assume that *type points at a count in a mangled name; set + *count to its value, and set *type to the next character after + the count. There are some weird rules in effect here. + + If *type does not point at a string of digits, return zero. + + If *type points at a string of digits followed by an + underscore, set *count to their value as an integer, advance + *type to point *after the underscore, and return 1. + + If *type points at a string of digits not followed by an + underscore, consume only the first digit. Set *count to its + value as an integer, leave *type pointing after that digit, + and return 1. + + The excuse for this odd behavior: in the ARM and HP demangling + styles, a type can be followed by a repeat count of the form + `Nxy', where: + + `x' is a single digit specifying how many additional copies + of the type to append to the argument list, and + + `y' is one or more digits, specifying the zero-based index of + the first repeated argument in the list. Yes, as you're + unmangling the name you can figure this out yourself, but + it's there anyway. + + So, for example, in `bar__3fooFPiN51', the first argument is a + pointer to an integer (`Pi'), and then the next five arguments + are the same (`N5'), and the first repeat is the function's + second argument (`1'). +*/ + +static int +get_count (const char **type, int *count) +{ + const char *p; + int n; + + if (!ISDIGIT ((unsigned char)**type)) + return (0); + else + { + *count = **type - '0'; + (*type)++; + if (ISDIGIT ((unsigned char)**type)) + { + p = *type; + n = *count; + do + { + n *= 10; + n += *p - '0'; + p++; + } + while (ISDIGIT ((unsigned char)*p)); + if (*p == '_') + { + *type = p + 1; + *count = n; + } + } + } + return (1); +} + +/* RESULT will be initialised here; it will be freed on failure. The + value returned is really a type_kind_t. */ + +static int +do_type (struct work_stuff *work, const char **mangled, string *result) +{ + int n; + int i; + int is_proctypevec; + int done; + int success; + string decl; + const char *remembered_type; + int type_quals; + type_kind_t tk = tk_none; + + string_init (&decl); + string_init (result); + + done = 0; + success = 1; + is_proctypevec = 0; + while (success && !done) + { + int member; + switch (**mangled) + { + + /* A pointer type */ + case 'P': + case 'p': + (*mangled)++; + if (! (work -> options & DMGL_JAVA)) + string_prepend (&decl, "*"); + if (tk == tk_none) + tk = tk_pointer; + break; + + /* A reference type */ + case 'R': + (*mangled)++; + string_prepend (&decl, "&"); + if (tk == tk_none) + tk = tk_reference; + break; + + /* An rvalue reference type */ + case 'O': + (*mangled)++; + string_prepend (&decl, "&&"); + if (tk == tk_none) + tk = tk_rvalue_reference; + break; + + /* An array */ + case 'A': + { + ++(*mangled); + if (!STRING_EMPTY (&decl) + && (decl.b[0] == '*' || decl.b[0] == '&')) + { + string_prepend (&decl, "("); + string_append (&decl, ")"); + } + string_append (&decl, "["); + if (**mangled != '_') + success = demangle_template_value_parm (work, mangled, &decl, + tk_integral); + if (**mangled == '_') + ++(*mangled); + string_append (&decl, "]"); + break; + } + + /* A back reference to a previously seen type */ + case 'T': + (*mangled)++; + if (!get_count (mangled, &n) || n < 0 || n >= work -> ntypes) + { + success = 0; + } + else + for (i = 0; i < work->nproctypes; i++) + if (work -> proctypevec [i] == n) + success = 0; + + if (success) + { + is_proctypevec = 1; + push_processed_type (work, n); + remembered_type = work->typevec[n]; + mangled = &remembered_type; + } + break; + + /* A function */ + case 'F': + (*mangled)++; + if (!STRING_EMPTY (&decl) + && (decl.b[0] == '*' || decl.b[0] == '&')) + { + string_prepend (&decl, "("); + string_append (&decl, ")"); + } + /* After picking off the function args, we expect to either find the + function return type (preceded by an '_') or the end of the + string. */ + if (!demangle_nested_args (work, mangled, &decl) + || (**mangled != '_' && **mangled != '\0')) + { + success = 0; + break; + } + if (success && (**mangled == '_')) + (*mangled)++; + break; + + case 'M': + { + type_quals = TYPE_UNQUALIFIED; + + member = **mangled == 'M'; + (*mangled)++; + + string_append (&decl, ")"); + + /* We don't need to prepend `::' for a qualified name; + demangle_qualified will do that for us. */ + if (**mangled != 'Q') + string_prepend (&decl, SCOPE_STRING (work)); + + if (ISDIGIT ((unsigned char)**mangled)) + { + n = consume_count (mangled); + if (n == -1 + || (int) strlen (*mangled) < n) + { + success = 0; + break; + } + string_prependn (&decl, *mangled, n); + *mangled += n; + } + else if (**mangled == 'X' || **mangled == 'Y') + { + string temp; + do_type (work, mangled, &temp); + string_prepends (&decl, &temp); + string_delete (&temp); + } + else if (**mangled == 't') + { + string temp; + string_init (&temp); + success = demangle_template (work, mangled, &temp, + NULL, 1, 1); + if (success) + { + string_prependn (&decl, temp.b, temp.p - temp.b); + string_delete (&temp); + } + else + { + string_delete (&temp); + break; + } + } + else if (**mangled == 'Q') + { + success = demangle_qualified (work, mangled, &decl, + /*isfuncnam=*/0, + /*append=*/0); + if (!success) + break; + } + else + { + success = 0; + break; + } + + string_prepend (&decl, "("); + if (member) + { + switch (**mangled) + { + case 'C': + case 'V': + case 'u': + type_quals |= code_for_qualifier (**mangled); + (*mangled)++; + break; + + default: + break; + } + + if (*(*mangled) != 'F') + { + success = 0; + break; + } + (*mangled)++; + } + if ((member && !demangle_nested_args (work, mangled, &decl)) + || **mangled != '_') + { + success = 0; + break; + } + (*mangled)++; + if (! PRINT_ANSI_QUALIFIERS) + { + break; + } + if (type_quals != TYPE_UNQUALIFIED) + { + APPEND_BLANK (&decl); + string_append (&decl, qualifier_string (type_quals)); + } + break; + } + case 'G': + (*mangled)++; + break; + + case 'C': + case 'V': + case 'u': + if (PRINT_ANSI_QUALIFIERS) + { + if (!STRING_EMPTY (&decl)) + string_prepend (&decl, " "); + + string_prepend (&decl, demangle_qualifier (**mangled)); + } + (*mangled)++; + break; + /* + } + */ + + /* fall through */ + default: + done = 1; + break; + } + } + + if (success) switch (**mangled) + { + /* A qualified name, such as "Outer::Inner". */ + case 'Q': + case 'K': + { + success = demangle_qualified (work, mangled, result, 0, 1); + break; + } + + /* A back reference to a previously seen squangled type */ + case 'B': + (*mangled)++; + if (!get_count (mangled, &n) || n < 0 || n >= work -> numb) + success = 0; + else + string_append (result, work->btypevec[n]); + break; + + case 'X': + case 'Y': + /* A template parm. We substitute the corresponding argument. */ + { + int idx; + + (*mangled)++; + idx = consume_count_with_underscores (mangled); + + if (idx == -1 + || (work->tmpl_argvec && idx >= work->ntmpl_args) + || consume_count_with_underscores (mangled) == -1) + { + success = 0; + break; + } + + if (work->tmpl_argvec) + string_append (result, work->tmpl_argvec[idx]); + else + string_append_template_idx (result, idx); + + success = 1; + } + break; + + default: + success = demangle_fund_type (work, mangled, result); + if (tk == tk_none) + tk = (type_kind_t) success; + break; + } + + if (success) + { + if (!STRING_EMPTY (&decl)) + { + string_append (result, " "); + string_appends (result, &decl); + } + } + else + string_delete (result); + string_delete (&decl); + + if (is_proctypevec) + pop_processed_type (work); + + if (success) + /* Assume an integral type, if we're not sure. */ + return (int) ((tk == tk_none) ? tk_integral : tk); + else + return 0; +} + +/* Given a pointer to a type string that represents a fundamental type + argument (int, long, unsigned int, etc) in TYPE, a pointer to the + string in which the demangled output is being built in RESULT, and + the WORK structure, decode the types and add them to the result. + + For example: + + "Ci" => "const int" + "Sl" => "signed long" + "CUs" => "const unsigned short" + + The value returned is really a type_kind_t. */ + +static int +demangle_fund_type (struct work_stuff *work, + const char **mangled, string *result) +{ + int done = 0; + int success = 1; + char buf[INTBUF_SIZE + 5 /* 'int%u_t' */]; + unsigned int dec = 0; + type_kind_t tk = tk_integral; + + /* First pick off any type qualifiers. There can be more than one. */ + + while (!done) + { + switch (**mangled) + { + case 'C': + case 'V': + case 'u': + if (PRINT_ANSI_QUALIFIERS) + { + if (!STRING_EMPTY (result)) + string_prepend (result, " "); + string_prepend (result, demangle_qualifier (**mangled)); + } + (*mangled)++; + break; + case 'U': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "unsigned"); + break; + case 'S': /* signed char only */ + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "signed"); + break; + case 'J': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "__complex"); + break; + default: + done = 1; + break; + } + } + + /* Now pick off the fundamental type. There can be only one. */ + + switch (**mangled) + { + case '\0': + case '_': + break; + case 'v': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "void"); + break; + case 'x': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "long long"); + break; + case 'l': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "long"); + break; + case 'i': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "int"); + break; + case 's': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "short"); + break; + case 'b': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "bool"); + tk = tk_bool; + break; + case 'c': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "char"); + tk = tk_char; + break; + case 'w': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "wchar_t"); + tk = tk_char; + break; + case 'r': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "long double"); + tk = tk_real; + break; + case 'd': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "double"); + tk = tk_real; + break; + case 'f': + (*mangled)++; + APPEND_BLANK (result); + string_append (result, "float"); + tk = tk_real; + break; + case 'G': + (*mangled)++; + if (!ISDIGIT ((unsigned char)**mangled)) + { + success = 0; + break; + } + /* fall through */ + case 'I': + (*mangled)++; + if (**mangled == '_') + { + int i; + (*mangled)++; + for (i = 0; + i < (long) sizeof (buf) - 1 && **mangled && **mangled != '_'; + (*mangled)++, i++) + buf[i] = **mangled; + if (**mangled != '_') + { + success = 0; + break; + } + buf[i] = '\0'; + (*mangled)++; + } + else + { + strncpy (buf, *mangled, 2); + buf[2] = '\0'; + *mangled += min (strlen (*mangled), 2); + } + sscanf (buf, "%x", &dec); + sprintf (buf, "int%u_t", dec); + APPEND_BLANK (result); + string_append (result, buf); + break; + + /* fall through */ + /* An explicit type, such as "6mytype" or "7integer" */ + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + int bindex = register_Btype (work); + string btype; + string_init (&btype); + if (demangle_class_name (work, mangled, &btype)) { + remember_Btype (work, btype.b, LEN_STRING (&btype), bindex); + APPEND_BLANK (result); + string_appends (result, &btype); + } + else + success = 0; + string_delete (&btype); + break; + } + case 't': + { + string btype; + string_init (&btype); + success = demangle_template (work, mangled, &btype, 0, 1, 1); + string_appends (result, &btype); + string_delete (&btype); + break; + } + default: + success = 0; + break; + } + + return success ? ((int) tk) : 0; +} + + +/* Handle a template's value parameter for HP aCC (extension from ARM) + **mangled points to 'S' or 'U' */ + +static int +do_hpacc_template_const_value (struct work_stuff *work ATTRIBUTE_UNUSED, + const char **mangled, string *result) +{ + int unsigned_const; + + if (**mangled != 'U' && **mangled != 'S') + return 0; + + unsigned_const = (**mangled == 'U'); + + (*mangled)++; + + switch (**mangled) + { + case 'N': + string_append (result, "-"); + /* fall through */ + case 'P': + (*mangled)++; + break; + case 'M': + /* special case for -2^31 */ + string_append (result, "-2147483648"); + (*mangled)++; + return 1; + default: + return 0; + } + + /* We have to be looking at an integer now */ + if (!(ISDIGIT ((unsigned char)**mangled))) + return 0; + + /* We only deal with integral values for template + parameters -- so it's OK to look only for digits */ + while (ISDIGIT ((unsigned char)**mangled)) + { + char_str[0] = **mangled; + string_append (result, char_str); + (*mangled)++; + } + + if (unsigned_const) + string_append (result, "U"); + + /* FIXME? Some day we may have 64-bit (or larger :-) ) constants + with L or LL suffixes. pai/1997-09-03 */ + + return 1; /* success */ +} + +/* Handle a template's literal parameter for HP aCC (extension from ARM) + **mangled is pointing to the 'A' */ + +static int +do_hpacc_template_literal (struct work_stuff *work, const char **mangled, + string *result) +{ + int literal_len = 0; + char * recurse; + char * recurse_dem; + + if (**mangled != 'A') + return 0; + + (*mangled)++; + + literal_len = consume_count (mangled); + + if (literal_len <= 0 + || literal_len > (long) strlen (*mangled)) + return 0; + + /* Literal parameters are names of arrays, functions, etc. and the + canonical representation uses the address operator */ + string_append (result, "&"); + + /* Now recursively demangle the literal name */ + recurse = XNEWVEC (char, literal_len + 1); + memcpy (recurse, *mangled, literal_len); + recurse[literal_len] = '\000'; + + recurse_dem = cplus_demangle (recurse, work->options); + + if (recurse_dem) + { + string_append (result, recurse_dem); + free (recurse_dem); + } + else + { + string_appendn (result, *mangled, literal_len); + } + (*mangled) += literal_len; + free (recurse); + + return 1; +} + +static int +snarf_numeric_literal (const char **args, string *arg) +{ + if (**args == '-') + { + char_str[0] = '-'; + string_append (arg, char_str); + (*args)++; + } + else if (**args == '+') + (*args)++; + + if (!ISDIGIT ((unsigned char)**args)) + return 0; + + while (ISDIGIT ((unsigned char)**args)) + { + char_str[0] = **args; + string_append (arg, char_str); + (*args)++; + } + + return 1; +} + +/* Demangle the next argument, given by MANGLED into RESULT, which + *should be an uninitialized* string. It will be initialized here, + and free'd should anything go wrong. */ + +static int +do_arg (struct work_stuff *work, const char **mangled, string *result) +{ + /* Remember where we started so that we can record the type, for + non-squangling type remembering. */ + const char *start = *mangled; + + string_init (result); + + if (work->nrepeats > 0) + { + --work->nrepeats; + + if (work->previous_argument == 0) + return 0; + + /* We want to reissue the previous type in this argument list. */ + string_appends (result, work->previous_argument); + return 1; + } + + if (**mangled == 'n') + { + /* A squangling-style repeat. */ + (*mangled)++; + work->nrepeats = consume_count(mangled); + + if (work->nrepeats <= 0) + /* This was not a repeat count after all. */ + return 0; + + if (work->nrepeats > 9) + { + if (**mangled != '_') + /* The repeat count should be followed by an '_' in this + case. */ + return 0; + else + (*mangled)++; + } + + /* Now, the repeat is all set up. */ + return do_arg (work, mangled, result); + } + + /* Save the result in WORK->previous_argument so that we can find it + if it's repeated. Note that saving START is not good enough: we + do not want to add additional types to the back-referenceable + type vector when processing a repeated type. */ + if (work->previous_argument) + string_delete (work->previous_argument); + else + work->previous_argument = XNEW (string); + + if (!do_type (work, mangled, work->previous_argument)) + return 0; + + string_appends (result, work->previous_argument); + + remember_type (work, start, *mangled - start); + return 1; +} + +static void +push_processed_type (struct work_stuff *work, int typevec_index) +{ + if (work->nproctypes >= work->proctypevec_size) + { + if (!work->proctypevec_size) + { + work->proctypevec_size = 4; + work->proctypevec = XNEWVEC (int, work->proctypevec_size); + } + else + { + if (work->proctypevec_size < 16) + /* Double when small. */ + work->proctypevec_size *= 2; + else + { + /* Grow slower when large. */ + if (work->proctypevec_size > (INT_MAX / 3) * 2) + xmalloc_failed (INT_MAX); + work->proctypevec_size = (work->proctypevec_size * 3 / 2); + } + work->proctypevec + = XRESIZEVEC (int, work->proctypevec, work->proctypevec_size); + } + } + work->proctypevec [work->nproctypes++] = typevec_index; +} + +static void +pop_processed_type (struct work_stuff *work) +{ + work->nproctypes--; +} + +static void +remember_type (struct work_stuff *work, const char *start, int len) +{ + char *tem; + + if (work->forgetting_types) + return; + + if (work -> ntypes >= work -> typevec_size) + { + if (work -> typevec_size == 0) + { + work -> typevec_size = 3; + work -> typevec = XNEWVEC (char *, work->typevec_size); + } + else + { + if (work -> typevec_size > INT_MAX / 2) + xmalloc_failed (INT_MAX); + work -> typevec_size *= 2; + work -> typevec + = XRESIZEVEC (char *, work->typevec, work->typevec_size); + } + } + tem = XNEWVEC (char, len + 1); + memcpy (tem, start, len); + tem[len] = '\0'; + work -> typevec[work -> ntypes++] = tem; +} + + +/* Remember a K type class qualifier. */ +static void +remember_Ktype (struct work_stuff *work, const char *start, int len) +{ + char *tem; + + if (work -> numk >= work -> ksize) + { + if (work -> ksize == 0) + { + work -> ksize = 5; + work -> ktypevec = XNEWVEC (char *, work->ksize); + } + else + { + if (work -> ksize > INT_MAX / 2) + xmalloc_failed (INT_MAX); + work -> ksize *= 2; + work -> ktypevec + = XRESIZEVEC (char *, work->ktypevec, work->ksize); + } + } + tem = XNEWVEC (char, len + 1); + memcpy (tem, start, len); + tem[len] = '\0'; + work -> ktypevec[work -> numk++] = tem; +} + +/* Register a B code, and get an index for it. B codes are registered + as they are seen, rather than as they are completed, so map > + registers map > as B0, and temp as B1 */ + +static int +register_Btype (struct work_stuff *work) +{ + int ret; + + if (work -> numb >= work -> bsize) + { + if (work -> bsize == 0) + { + work -> bsize = 5; + work -> btypevec = XNEWVEC (char *, work->bsize); + } + else + { + if (work -> bsize > INT_MAX / 2) + xmalloc_failed (INT_MAX); + work -> bsize *= 2; + work -> btypevec + = XRESIZEVEC (char *, work->btypevec, work->bsize); + } + } + ret = work -> numb++; + work -> btypevec[ret] = NULL; + return(ret); +} + +/* Store a value into a previously registered B code type. */ + +static void +remember_Btype (struct work_stuff *work, const char *start, + int len, int index) +{ + char *tem; + + tem = XNEWVEC (char, len + 1); + if (len > 0) + memcpy (tem, start, len); + tem[len] = '\0'; + work -> btypevec[index] = tem; +} + +/* Lose all the info related to B and K type codes. */ + +static void +forget_B_and_K_types (struct work_stuff *work) +{ + int i; + + while (work -> numk > 0) + { + i = --(work -> numk); + if (work -> ktypevec[i] != NULL) + { + free (work -> ktypevec[i]); + work -> ktypevec[i] = NULL; + } + } + + while (work -> numb > 0) + { + i = --(work -> numb); + if (work -> btypevec[i] != NULL) + { + free (work -> btypevec[i]); + work -> btypevec[i] = NULL; + } + } +} + +/* Forget the remembered types, but not the type vector itself. */ + +static void +forget_types (struct work_stuff *work) +{ + int i; + + while (work -> ntypes > 0) + { + i = --(work -> ntypes); + if (work -> typevec[i] != NULL) + { + free (work -> typevec[i]); + work -> typevec[i] = NULL; + } + } +} + +/* Process the argument list part of the signature, after any class spec + has been consumed, as well as the first 'F' character (if any). For + example: + + "__als__3fooRT0" => process "RT0" + "complexfunc5__FPFPc_PFl_i" => process "PFPc_PFl_i" + + DECLP must be already initialised, usually non-empty. It won't be freed + on failure. + + Note that g++ differs significantly from ARM and lucid style mangling + with regards to references to previously seen types. For example, given + the source fragment: + + class foo { + public: + foo::foo (int, foo &ia, int, foo &ib, int, foo &ic); + }; + + foo::foo (int, foo &ia, int, foo &ib, int, foo &ic) { ia = ib = ic; } + void foo (int, foo &ia, int, foo &ib, int, foo &ic) { ia = ib = ic; } + + g++ produces the names: + + __3fooiRT0iT2iT2 + foo__FiR3fooiT1iT1 + + while lcc (and presumably other ARM style compilers as well) produces: + + foo__FiR3fooT1T2T1T2 + __ct__3fooFiR3fooT1T2T1T2 + + Note that g++ bases its type numbers starting at zero and counts all + previously seen types, while lucid/ARM bases its type numbers starting + at one and only considers types after it has seen the 'F' character + indicating the start of the function args. For lucid/ARM style, we + account for this difference by discarding any previously seen types when + we see the 'F' character, and subtracting one from the type number + reference. + + */ + +static int +demangle_args (struct work_stuff *work, const char **mangled, + string *declp) +{ + string arg; + int need_comma = 0; + int r; + int t; + const char *tem; + char temptype; + + if (PRINT_ARG_TYPES) + { + string_append (declp, "("); + if (**mangled == '\0') + { + string_append (declp, "void"); + } + } + + while ((**mangled != '_' && **mangled != '\0' && **mangled != 'e') + || work->nrepeats > 0) + { + if ((**mangled == 'N') || (**mangled == 'T')) + { + temptype = *(*mangled)++; + + if (temptype == 'N') + { + if (!get_count (mangled, &r)) + { + return (0); + } + } + else + { + r = 1; + } + if ((HP_DEMANGLING || ARM_DEMANGLING || EDG_DEMANGLING) && work -> ntypes >= 10) + { + /* If we have 10 or more types we might have more than a 1 digit + index so we'll have to consume the whole count here. This + will lose if the next thing is a type name preceded by a + count but it's impossible to demangle that case properly + anyway. Eg if we already have 12 types is T12Pc "(..., type1, + Pc, ...)" or "(..., type12, char *, ...)" */ + if ((t = consume_count(mangled)) <= 0) + { + return (0); + } + } + else + { + if (!get_count (mangled, &t)) + { + return (0); + } + } + if (LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) + { + t--; + } + /* Validate the type index. Protect against illegal indices from + malformed type strings. */ + if ((t < 0) || (t >= work -> ntypes)) + { + return (0); + } + while (work->nrepeats > 0 || --r >= 0) + { + tem = work -> typevec[t]; + if (need_comma && PRINT_ARG_TYPES) + { + string_append (declp, ", "); + } + push_processed_type (work, t); + if (!do_arg (work, &tem, &arg)) + { + pop_processed_type (work); + return (0); + } + pop_processed_type (work); + if (PRINT_ARG_TYPES) + { + string_appends (declp, &arg); + } + string_delete (&arg); + need_comma = 1; + } + } + else + { + if (need_comma && PRINT_ARG_TYPES) + string_append (declp, ", "); + if (!do_arg (work, mangled, &arg)) + return (0); + if (PRINT_ARG_TYPES) + string_appends (declp, &arg); + string_delete (&arg); + need_comma = 1; + } + } + + if (**mangled == 'e') + { + (*mangled)++; + if (PRINT_ARG_TYPES) + { + if (need_comma) + { + string_append (declp, ","); + } + string_append (declp, "..."); + } + } + + if (PRINT_ARG_TYPES) + { + string_append (declp, ")"); + } + return (1); +} + +/* Like demangle_args, but for demangling the argument lists of function + and method pointers or references, not top-level declarations. */ + +static int +demangle_nested_args (struct work_stuff *work, const char **mangled, + string *declp) +{ + string* saved_previous_argument; + int result; + int saved_nrepeats; + + if ((work->options & DMGL_NO_RECURSE_LIMIT) == 0) + { + if (work->recursion_level > DEMANGLE_RECURSION_LIMIT) + /* FIXME: There ought to be a way to report + that the recursion limit has been reached. */ + return 0; + + work->recursion_level ++; + } + + /* The G++ name-mangling algorithm does not remember types on nested + argument lists, unless -fsquangling is used, and in that case the + type vector updated by remember_type is not used. So, we turn + off remembering of types here. */ + ++work->forgetting_types; + + /* For the repeat codes used with -fsquangling, we must keep track of + the last argument. */ + saved_previous_argument = work->previous_argument; + saved_nrepeats = work->nrepeats; + work->previous_argument = 0; + work->nrepeats = 0; + + /* Actually demangle the arguments. */ + result = demangle_args (work, mangled, declp); + + /* Restore the previous_argument field. */ + if (work->previous_argument) + { + string_delete (work->previous_argument); + free ((char *) work->previous_argument); + } + work->previous_argument = saved_previous_argument; + --work->forgetting_types; + work->nrepeats = saved_nrepeats; + + if ((work->options & DMGL_NO_RECURSE_LIMIT) == 0) + --work->recursion_level; + + return result; +} + +/* Returns 1 if a valid function name was found or 0 otherwise. */ + +static int +demangle_function_name (struct work_stuff *work, const char **mangled, + string *declp, const char *scan) +{ + size_t i; + string type; + const char *tem; + + string_appendn (declp, (*mangled), scan - (*mangled)); + string_need (declp, 1); + *(declp -> p) = '\0'; + + /* Consume the function name, including the "__" separating the name + from the signature. We are guaranteed that SCAN points to the + separator. */ + + (*mangled) = scan + 2; + /* We may be looking at an instantiation of a template function: + foo__Xt1t2_Ft3t4, where t1, t2, ... are template arguments and a + following _F marks the start of the function arguments. Handle + the template arguments first. */ + + if (HP_DEMANGLING && (**mangled == 'X')) + { + demangle_arm_hp_template (work, mangled, 0, declp); + /* This leaves MANGLED pointing to the 'F' marking func args */ + } + + if (LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) + { + + /* See if we have an ARM style constructor or destructor operator. + If so, then just record it, clear the decl, and return. + We can't build the actual constructor/destructor decl until later, + when we recover the class name from the signature. */ + + if (strcmp (declp -> b, "__ct") == 0) + { + work -> constructor += 1; + string_clear (declp); + return 1; + } + else if (strcmp (declp -> b, "__dt") == 0) + { + work -> destructor += 1; + string_clear (declp); + return 1; + } + } + + if (declp->p - declp->b >= 3 + && declp->b[0] == 'o' + && declp->b[1] == 'p' + && strchr (cplus_markers, declp->b[2]) != NULL) + { + /* see if it's an assignment expression */ + if (declp->p - declp->b >= 10 /* op$assign_ */ + && memcmp (declp->b + 3, "assign_", 7) == 0) + { + for (i = 0; i < ARRAY_SIZE (optable); i++) + { + int len = declp->p - declp->b - 10; + if ((int) strlen (optable[i].in) == len + && memcmp (optable[i].in, declp->b + 10, len) == 0) + { + string_clear (declp); + string_append (declp, "operator"); + string_append (declp, optable[i].out); + string_append (declp, "="); + break; + } + } + } + else + { + for (i = 0; i < ARRAY_SIZE (optable); i++) + { + int len = declp->p - declp->b - 3; + if ((int) strlen (optable[i].in) == len + && memcmp (optable[i].in, declp->b + 3, len) == 0) + { + string_clear (declp); + string_append (declp, "operator"); + string_append (declp, optable[i].out); + break; + } + } + } + } + else if (declp->p - declp->b >= 5 && memcmp (declp->b, "type", 4) == 0 + && strchr (cplus_markers, declp->b[4]) != NULL) + { + /* type conversion operator */ + tem = declp->b + 5; + if (do_type (work, &tem, &type)) + { + string_clear (declp); + string_append (declp, "operator "); + string_appends (declp, &type); + string_delete (&type); + } + } + else if (declp->b[0] == '_' && declp->b[1] == '_' + && declp->b[2] == 'o' && declp->b[3] == 'p') + { + /* ANSI. */ + /* type conversion operator. */ + tem = declp->b + 4; + if (do_type (work, &tem, &type)) + { + string_clear (declp); + string_append (declp, "operator "); + string_appends (declp, &type); + string_delete (&type); + } + } + else if (declp->b[0] == '_' && declp->b[1] == '_' + && ISLOWER((unsigned char)declp->b[2]) + && ISLOWER((unsigned char)declp->b[3])) + { + if (declp->b[4] == '\0') + { + /* Operator. */ + for (i = 0; i < ARRAY_SIZE (optable); i++) + { + if (strlen (optable[i].in) == 2 + && memcmp (optable[i].in, declp->b + 2, 2) == 0) + { + string_clear (declp); + string_append (declp, "operator"); + string_append (declp, optable[i].out); + break; + } + } + } + else + { + if (declp->b[2] == 'a' && declp->b[5] == '\0') + { + /* Assignment. */ + for (i = 0; i < ARRAY_SIZE (optable); i++) + { + if (strlen (optable[i].in) == 3 + && memcmp (optable[i].in, declp->b + 2, 3) == 0) + { + string_clear (declp); + string_append (declp, "operator"); + string_append (declp, optable[i].out); + break; + } + } + } + } + } + + /* If a function name was obtained but it's not valid, we were not + successful. */ + if (LEN_STRING (declp) == 1 && declp->b[0] == '.') + return 0; + else + return 1; +} + +/* a mini string-handling package */ + +static void +string_need (string *s, int n) +{ + int tem; + + if (s->b == NULL) + { + if (n < 32) + { + n = 32; + } + s->p = s->b = XNEWVEC (char, n); + s->e = s->b + n; + } + else if (s->e - s->p < n) + { + tem = s->p - s->b; + if (n > INT_MAX / 2 - tem) + xmalloc_failed (INT_MAX); + n += tem; + n *= 2; + s->b = XRESIZEVEC (char, s->b, n); + s->p = s->b + tem; + s->e = s->b + n; + } +} + +static void +string_delete (string *s) +{ + if (s->b != NULL) + { + free (s->b); + s->b = s->e = s->p = NULL; + } +} + +static void +string_init (string *s) +{ + s->b = s->p = s->e = NULL; +} + +static void +string_clear (string *s) +{ + s->p = s->b; +} + +#if 0 + +static int +string_empty (string *s) +{ + return (s->b == s->p); +} + +#endif + +static void +string_append (string *p, const char *s) +{ + int n; + if (s == NULL || *s == '\0') + return; + n = strlen (s); + string_need (p, n); + memcpy (p->p, s, n); + p->p += n; +} + +static void +string_appends (string *p, string *s) +{ + int n; + + if (s->b != s->p) + { + n = s->p - s->b; + string_need (p, n); + memcpy (p->p, s->b, n); + p->p += n; + } +} + +static void +string_appendn (string *p, const char *s, int n) +{ + if (n != 0) + { + string_need (p, n); + memcpy (p->p, s, n); + p->p += n; + } +} + +static void +string_prepend (string *p, const char *s) +{ + if (s != NULL && *s != '\0') + { + string_prependn (p, s, strlen (s)); + } +} + +static void +string_prepends (string *p, string *s) +{ + if (s->b != s->p) + { + string_prependn (p, s->b, s->p - s->b); + } +} + +static void +string_prependn (string *p, const char *s, int n) +{ + char *q; + + if (n != 0) + { + string_need (p, n); + for (q = p->p - 1; q >= p->b; q--) + { + q[n] = q[0]; + } + memcpy (p->b, s, n); + p->p += n; + } +} + +static void +string_append_template_idx (string *s, int idx) +{ + char buf[INTBUF_SIZE + 1 /* 'T' */]; + sprintf(buf, "T%d", idx); + string_append (s, buf); +} diff --git a/3rdparty/demangler/src/d-demangle.c b/3rdparty/demangler/src/d-demangle.c new file mode 100644 index 0000000000..c41ad02e2c --- /dev/null +++ b/3rdparty/demangler/src/d-demangle.c @@ -0,0 +1,1982 @@ +/* Demangler for the D programming language + Copyright (C) 2014-2023 Free Software Foundation, Inc. + Written by Iain Buclaw (ibuclaw@gdcproject.org) + +This file is part of the libiberty library. +Libiberty 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. + +In addition to the permissions in the GNU Library General Public +License, the Free Software Foundation gives you unlimited permission +to link the compiled version of this file into combinations with other +programs, and to distribute those combinations without any restriction +coming from the use of this file. (The Library Public License +restrictions do apply in other respects; for example, they cover +modification of the file, and distribution when not linked into a +combined executable.) + +Libiberty is distributed in the hope that 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 libiberty; see the file COPYING.LIB. +If not, see . */ + +/* This file exports one function; dlang_demangle. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef HAVE_LIMITS_H +#include +#endif + +#include "safe-ctype.h" + +#include +#include +#include + +#ifdef HAVE_STDLIB_H +#include +#endif + +#include +#include "libiberty.h" + +#ifndef ULONG_MAX +#define ULONG_MAX (~0UL) +#endif +#ifndef UINT_MAX +#define UINT_MAX (~0U) +#endif + +/* A mini string-handling package */ + +typedef struct string /* Beware: these aren't required to be */ +{ /* '\0' terminated. */ + char *b; /* pointer to start of string */ + char *p; /* pointer after last character */ + char *e; /* pointer after end of allocated space */ +} string; + +static void +string_need (string *s, size_t n) +{ + size_t tem; + + if (s->b == NULL) + { + if (n < 32) + { + n = 32; + } + s->p = s->b = XNEWVEC (char, n); + s->e = s->b + n; + } + else if ((size_t) (s->e - s->p) < n) + { + tem = s->p - s->b; + n += tem; + n *= 2; + s->b = XRESIZEVEC (char, s->b, n); + s->p = s->b + tem; + s->e = s->b + n; + } +} + +static void +string_delete (string *s) +{ + if (s->b != NULL) + { + XDELETEVEC (s->b); + s->b = s->e = s->p = NULL; + } +} + +static void +string_init (string *s) +{ + s->b = s->p = s->e = NULL; +} + +static int +string_length (string *s) +{ + if (s->p == s->b) + { + return 0; + } + return s->p - s->b; +} + +static void +string_setlength (string *s, int n) +{ + if (n - string_length (s) < 0) + { + s->p = s->b + n; + } +} + +static void +string_append (string *p, const char *s) +{ + size_t n = strlen (s); + string_need (p, n); + memcpy (p->p, s, n); + p->p += n; +} + +static void +string_appendn (string *p, const char *s, size_t n) +{ + if (n != 0) + { + string_need (p, n); + memcpy (p->p, s, n); + p->p += n; + } +} + +static void +string_prependn (string *p, const char *s, size_t n) +{ + char *q; + + if (n != 0) + { + string_need (p, n); + for (q = p->p - 1; q >= p->b; q--) + { + q[n] = q[0]; + } + memcpy (p->b, s, n); + p->p += n; + } +} + +static void +string_prepend (string *p, const char *s) +{ + if (s != NULL && *s != '\0') + { + string_prependn (p, s, strlen (s)); + } +} + +/* Demangle information structure we pass around. */ +struct dlang_info +{ + /* The string we are demangling. */ + const char *s; + /* The index of the last back reference. */ + int last_backref; +}; + +/* Pass as the LEN to dlang_parse_template if symbol length is not known. */ +#define TEMPLATE_LENGTH_UNKNOWN (-1UL) + +/* Prototypes for forward referenced functions */ +static const char *dlang_function_type (string *, const char *, + struct dlang_info *); + +static const char *dlang_function_args (string *, const char *, + struct dlang_info *); + +static const char *dlang_type (string *, const char *, struct dlang_info *); + +static const char *dlang_value (string *, const char *, const char *, char, + struct dlang_info *); + +static const char *dlang_parse_qualified (string *, const char *, + struct dlang_info *, int); + +static const char *dlang_parse_mangle (string *, const char *, + struct dlang_info *); + +static const char *dlang_parse_tuple (string *, const char *, + struct dlang_info *); + +static const char *dlang_parse_template (string *, const char *, + struct dlang_info *, unsigned long); + +static const char *dlang_lname (string *, const char *, unsigned long); + + +/* Extract the number from MANGLED, and assign the result to RET. + Return the remaining string on success or NULL on failure. + A result larger than UINT_MAX is considered a failure. */ +static const char * +dlang_number (const char *mangled, unsigned long *ret) +{ + /* Return NULL if trying to extract something that isn't a digit. */ + if (mangled == NULL || !ISDIGIT (*mangled)) + return NULL; + + unsigned long val = 0; + + while (ISDIGIT (*mangled)) + { + unsigned long digit = mangled[0] - '0'; + + /* Check for overflow. */ + if (val > (UINT_MAX - digit) / 10) + return NULL; + + val = val * 10 + digit; + mangled++; + } + + if (*mangled == '\0') + return NULL; + + *ret = val; + return mangled; +} + +/* Extract the hex-digit from MANGLED, and assign the result to RET. + Return the remaining string on success or NULL on failure. */ +static const char * +dlang_hexdigit (const char *mangled, char *ret) +{ + char c; + + /* Return NULL if trying to extract something that isn't a hexdigit. */ + if (mangled == NULL || !ISXDIGIT (mangled[0]) || !ISXDIGIT (mangled[1])) + return NULL; + + c = mangled[0]; + if (!ISDIGIT (c)) + *ret = c - (ISUPPER (c) ? 'A' : 'a') + 10; + else + *ret = c - '0'; + + c = mangled[1]; + if (!ISDIGIT (c)) + *ret = (*ret << 4) | (c - (ISUPPER (c) ? 'A' : 'a') + 10); + else + *ret = (*ret << 4) | (c - '0'); + + mangled += 2; + + return mangled; +} + +/* Extract the function calling convention from MANGLED and + return 1 on success or 0 on failure. */ +static int +dlang_call_convention_p (const char *mangled) +{ + switch (*mangled) + { + case 'F': case 'U': case 'V': + case 'W': case 'R': case 'Y': + return 1; + + default: + return 0; + } +} + +/* Extract the back reference position from MANGLED, and assign the result + to RET. Return the remaining string on success or NULL on failure. + A result <= 0 is a failure. */ +static const char * +dlang_decode_backref (const char *mangled, long *ret) +{ + /* Return NULL if trying to extract something that isn't a digit. */ + if (mangled == NULL || !ISALPHA (*mangled)) + return NULL; + + /* Any identifier or non-basic type that has been emitted to the mangled + symbol before will not be emitted again, but is referenced by a special + sequence encoding the relative position of the original occurrence in the + mangled symbol name. + + Numbers in back references are encoded with base 26 by upper case letters + A-Z for higher digits but lower case letters a-z for the last digit. + + NumberBackRef: + [a-z] + [A-Z] NumberBackRef + ^ + */ + unsigned long val = 0; + + while (ISALPHA (*mangled)) + { + /* Check for overflow. */ + if (val > (ULONG_MAX - 25) / 26) + break; + + val *= 26; + + if (mangled[0] >= 'a' && mangled[0] <= 'z') + { + val += mangled[0] - 'a'; + if ((long) val <= 0) + break; + *ret = val; + return mangled + 1; + } + + val += mangled[0] - 'A'; + mangled++; + } + + return NULL; +} + +/* Extract the symbol pointed at by the back reference and assign the result + to RET. Return the remaining string on success or NULL on failure. */ +static const char * +dlang_backref (const char *mangled, const char **ret, struct dlang_info *info) +{ + *ret = NULL; + + if (mangled == NULL || *mangled != 'Q') + return NULL; + + /* Position of 'Q'. */ + const char *qpos = mangled; + long refpos; + mangled++; + + mangled = dlang_decode_backref (mangled, &refpos); + if (mangled == NULL) + return NULL; + + if (refpos > qpos - info->s) + return NULL; + + /* Set the position of the back reference. */ + *ret = qpos - refpos; + + return mangled; +} + +/* Demangle a back referenced symbol from MANGLED and append it to DECL. + Return the remaining string on success or NULL on failure. */ +static const char * +dlang_symbol_backref (string *decl, const char *mangled, + struct dlang_info *info) +{ + /* An identifier back reference always points to a digit 0 to 9. + + IdentifierBackRef: + Q NumberBackRef + ^ + */ + const char *backref; + unsigned long len; + + /* Get position of the back reference. */ + mangled = dlang_backref (mangled, &backref, info); + + /* Must point to a simple identifier. */ + backref = dlang_number (backref, &len); + if (backref == NULL || strlen(backref) < len) + return NULL; + + backref = dlang_lname (decl, backref, len); + if (backref == NULL) + return NULL; + + return mangled; +} + +/* Demangle a back referenced type from MANGLED and append it to DECL. + IS_FUNCTION is 1 if the back referenced type is expected to be a function. + Return the remaining string on success or NULL on failure. */ +static const char * +dlang_type_backref (string *decl, const char *mangled, struct dlang_info *info, + int is_function) +{ + /* A type back reference always points to a letter. + + TypeBackRef: + Q NumberBackRef + ^ + */ + const char *backref; + + /* If we appear to be moving backwards through the mangle string, then + bail as this may be a recursive back reference. */ + if (mangled - info->s >= info->last_backref) + return NULL; + + int save_refpos = info->last_backref; + info->last_backref = mangled - info->s; + + /* Get position of the back reference. */ + mangled = dlang_backref (mangled, &backref, info); + + /* Must point to a type. */ + if (is_function) + backref = dlang_function_type (decl, backref, info); + else + backref = dlang_type (decl, backref, info); + + info->last_backref = save_refpos; + + if (backref == NULL) + return NULL; + + return mangled; +} + +/* Extract the beginning of a symbol name from MANGLED and + return 1 on success or 0 on failure. */ +static int +dlang_symbol_name_p (const char *mangled, struct dlang_info *info) +{ + long ret; + const char *qref = mangled; + + if (ISDIGIT (*mangled)) + return 1; + + if (mangled[0] == '_' && mangled[1] == '_' + && (mangled[2] == 'T' || mangled[2] == 'U')) + return 1; + + if (*mangled != 'Q') + return 0; + + mangled = dlang_decode_backref (mangled + 1, &ret); + if (mangled == NULL || ret > qref - info->s) + return 0; + + return ISDIGIT (qref[-ret]); +} + +/* Demangle the calling convention from MANGLED and append it to DECL. + Return the remaining string on success or NULL on failure. */ +static const char * +dlang_call_convention (string *decl, const char *mangled) +{ + if (mangled == NULL || *mangled == '\0') + return NULL; + + switch (*mangled) + { + case 'F': /* (D) */ + mangled++; + break; + case 'U': /* (C) */ + mangled++; + string_append (decl, "extern(C) "); + break; + case 'W': /* (Windows) */ + mangled++; + string_append (decl, "extern(Windows) "); + break; + case 'V': /* (Pascal) */ + mangled++; + string_append (decl, "extern(Pascal) "); + break; + case 'R': /* (C++) */ + mangled++; + string_append (decl, "extern(C++) "); + break; + case 'Y': /* (Objective-C) */ + mangled++; + string_append (decl, "extern(Objective-C) "); + break; + default: + return NULL; + } + + return mangled; +} + +/* Extract the type modifiers from MANGLED and append them to DECL. + Returns the remaining signature on success or NULL on failure. */ +static const char * +dlang_type_modifiers (string *decl, const char *mangled) +{ + if (mangled == NULL || *mangled == '\0') + return NULL; + + switch (*mangled) + { + case 'x': /* const */ + mangled++; + string_append (decl, " const"); + return mangled; + case 'y': /* immutable */ + mangled++; + string_append (decl, " immutable"); + return mangled; + case 'O': /* shared */ + mangled++; + string_append (decl, " shared"); + return dlang_type_modifiers (decl, mangled); + case 'N': + mangled++; + if (*mangled == 'g') /* wild */ + { + mangled++; + string_append (decl, " inout"); + return dlang_type_modifiers (decl, mangled); + } + else + return NULL; + + default: + return mangled; + } +} + +/* Demangle the D function attributes from MANGLED and append it to DECL. + Return the remaining string on success or NULL on failure. */ +static const char * +dlang_attributes (string *decl, const char *mangled) +{ + if (mangled == NULL || *mangled == '\0') + return NULL; + + while (*mangled == 'N') + { + mangled++; + switch (*mangled) + { + case 'a': /* pure */ + mangled++; + string_append (decl, "pure "); + continue; + case 'b': /* nothrow */ + mangled++; + string_append (decl, "nothrow "); + continue; + case 'c': /* ref */ + mangled++; + string_append (decl, "ref "); + continue; + case 'd': /* @property */ + mangled++; + string_append (decl, "@property "); + continue; + case 'e': /* @trusted */ + mangled++; + string_append (decl, "@trusted "); + continue; + case 'f': /* @safe */ + mangled++; + string_append (decl, "@safe "); + continue; + case 'g': + case 'h': + case 'k': + case 'n': + /* inout parameter is represented as 'Ng'. + vector parameter is represented as 'Nh'. + return parameter is represented as 'Nk'. + typeof(*null) parameter is represented as 'Nn'. + If we see this, then we know we're really in the + parameter list. Rewind and break. */ + mangled--; + break; + case 'i': /* @nogc */ + mangled++; + string_append (decl, "@nogc "); + continue; + case 'j': /* return */ + mangled++; + string_append (decl, "return "); + continue; + case 'l': /* scope */ + mangled++; + string_append (decl, "scope "); + continue; + case 'm': /* @live */ + mangled++; + string_append (decl, "@live "); + continue; + + default: /* unknown attribute */ + return NULL; + } + break; + } + + return mangled; +} + +/* Demangle the function type from MANGLED without the return type. + The arguments are appended to ARGS, the calling convention is appended + to CALL and attributes are appended to ATTR. Any of these can be NULL + to throw the information away. Return the remaining string on success + or NULL on failure. */ +static const char * +dlang_function_type_noreturn (string *args, string *call, string *attr, + const char *mangled, struct dlang_info *info) +{ + string dump; + string_init (&dump); + + /* Skip over calling convention and attributes. */ + mangled = dlang_call_convention (call ? call : &dump, mangled); + mangled = dlang_attributes (attr ? attr : &dump, mangled); + + if (args) + string_append (args, "("); + + mangled = dlang_function_args (args ? args : &dump, mangled, info); + if (args) + string_append (args, ")"); + + string_delete (&dump); + return mangled; +} + +/* Demangle the function type from MANGLED and append it to DECL. + Return the remaining string on success or NULL on failure. */ +static const char * +dlang_function_type (string *decl, const char *mangled, struct dlang_info *info) +{ + string attr, args, type; + + if (mangled == NULL || *mangled == '\0') + return NULL; + + /* The order of the mangled string is: + CallConvention FuncAttrs Arguments ArgClose Type + + The demangled string is re-ordered as: + CallConvention Type Arguments FuncAttrs + */ + string_init (&attr); + string_init (&args); + string_init (&type); + + mangled = dlang_function_type_noreturn (&args, decl, &attr, mangled, info); + + /* Function return type. */ + mangled = dlang_type (&type, mangled, info); + + /* Append to decl in order. */ + string_appendn (decl, type.b, string_length (&type)); + string_appendn (decl, args.b, string_length (&args)); + string_append (decl, " "); + string_appendn (decl, attr.b, string_length (&attr)); + + string_delete (&attr); + string_delete (&args); + string_delete (&type); + return mangled; +} + +/* Demangle the argument list from MANGLED and append it to DECL. + Return the remaining string on success or NULL on failure. */ +static const char * +dlang_function_args (string *decl, const char *mangled, struct dlang_info *info) +{ + size_t n = 0; + + while (mangled && *mangled != '\0') + { + switch (*mangled) + { + case 'X': /* (variadic T t...) style. */ + mangled++; + string_append (decl, "..."); + return mangled; + case 'Y': /* (variadic T t, ...) style. */ + mangled++; + if (n != 0) + string_append (decl, ", "); + string_append (decl, "..."); + return mangled; + case 'Z': /* Normal function. */ + mangled++; + return mangled; + } + + if (n++) + string_append (decl, ", "); + + if (*mangled == 'M') /* scope(T) */ + { + mangled++; + string_append (decl, "scope "); + } + + if (mangled[0] == 'N' && mangled[1] == 'k') /* return(T) */ + { + mangled += 2; + string_append (decl, "return "); + } + + switch (*mangled) + { + case 'I': /* in(T) */ + mangled++; + string_append (decl, "in "); + if (*mangled == 'K') /* in ref(T) */ + { + mangled++; + string_append (decl, "ref "); + } + break; + case 'J': /* out(T) */ + mangled++; + string_append (decl, "out "); + break; + case 'K': /* ref(T) */ + mangled++; + string_append (decl, "ref "); + break; + case 'L': /* lazy(T) */ + mangled++; + string_append (decl, "lazy "); + break; + } + mangled = dlang_type (decl, mangled, info); + } + + return mangled; +} + +/* Demangle the type from MANGLED and append it to DECL. + Return the remaining string on success or NULL on failure. */ +static const char * +dlang_type (string *decl, const char *mangled, struct dlang_info *info) +{ + if (mangled == NULL || *mangled == '\0') + return NULL; + + switch (*mangled) + { + case 'O': /* shared(T) */ + mangled++; + string_append (decl, "shared("); + mangled = dlang_type (decl, mangled, info); + string_append (decl, ")"); + return mangled; + case 'x': /* const(T) */ + mangled++; + string_append (decl, "const("); + mangled = dlang_type (decl, mangled, info); + string_append (decl, ")"); + return mangled; + case 'y': /* immutable(T) */ + mangled++; + string_append (decl, "immutable("); + mangled = dlang_type (decl, mangled, info); + string_append (decl, ")"); + return mangled; + case 'N': + mangled++; + if (*mangled == 'g') /* wild(T) */ + { + mangled++; + string_append (decl, "inout("); + mangled = dlang_type (decl, mangled, info); + string_append (decl, ")"); + return mangled; + } + else if (*mangled == 'h') /* vector(T) */ + { + mangled++; + string_append (decl, "__vector("); + mangled = dlang_type (decl, mangled, info); + string_append (decl, ")"); + return mangled; + } + else if (*mangled == 'n') /* typeof(*null) */ + { + mangled++; + string_append (decl, "typeof(*null)"); + return mangled; + } + else + return NULL; + case 'A': /* dynamic array (T[]) */ + mangled++; + mangled = dlang_type (decl, mangled, info); + string_append (decl, "[]"); + return mangled; + case 'G': /* static array (T[N]) */ + { + const char *numptr; + size_t num = 0; + mangled++; + + numptr = mangled; + while (ISDIGIT (*mangled)) + { + num++; + mangled++; + } + mangled = dlang_type (decl, mangled, info); + string_append (decl, "["); + string_appendn (decl, numptr, num); + string_append (decl, "]"); + return mangled; + } + case 'H': /* associative array (T[T]) */ + { + string type; + size_t sztype; + mangled++; + + string_init (&type); + mangled = dlang_type (&type, mangled, info); + sztype = string_length (&type); + + mangled = dlang_type (decl, mangled, info); + string_append (decl, "["); + string_appendn (decl, type.b, sztype); + string_append (decl, "]"); + + string_delete (&type); + return mangled; + } + case 'P': /* pointer (T*) */ + mangled++; + if (!dlang_call_convention_p (mangled)) + { + mangled = dlang_type (decl, mangled, info); + string_append (decl, "*"); + return mangled; + } + /* Fall through */ + case 'F': /* function T (D) */ + case 'U': /* function T (C) */ + case 'W': /* function T (Windows) */ + case 'V': /* function T (Pascal) */ + case 'R': /* function T (C++) */ + case 'Y': /* function T (Objective-C) */ + /* Function pointer types don't include the trailing asterisk. */ + mangled = dlang_function_type (decl, mangled, info); + string_append (decl, "function"); + return mangled; + case 'C': /* class T */ + case 'S': /* struct T */ + case 'E': /* enum T */ + case 'T': /* typedef T */ + mangled++; + return dlang_parse_qualified (decl, mangled, info, 0); + case 'D': /* delegate T */ + { + string mods; + size_t szmods; + mangled++; + + string_init (&mods); + mangled = dlang_type_modifiers (&mods, mangled); + szmods = string_length (&mods); + + /* Back referenced function type. */ + if (mangled && *mangled == 'Q') + mangled = dlang_type_backref (decl, mangled, info, 1); + else + mangled = dlang_function_type (decl, mangled, info); + + string_append (decl, "delegate"); + string_appendn (decl, mods.b, szmods); + + string_delete (&mods); + return mangled; + } + case 'B': /* tuple T */ + mangled++; + return dlang_parse_tuple (decl, mangled, info); + + /* Basic types */ + case 'n': + mangled++; + string_append (decl, "typeof(null)"); + return mangled; + case 'v': + mangled++; + string_append (decl, "void"); + return mangled; + case 'g': + mangled++; + string_append (decl, "byte"); + return mangled; + case 'h': + mangled++; + string_append (decl, "ubyte"); + return mangled; + case 's': + mangled++; + string_append (decl, "short"); + return mangled; + case 't': + mangled++; + string_append (decl, "ushort"); + return mangled; + case 'i': + mangled++; + string_append (decl, "int"); + return mangled; + case 'k': + mangled++; + string_append (decl, "uint"); + return mangled; + case 'l': + mangled++; + string_append (decl, "long"); + return mangled; + case 'm': + mangled++; + string_append (decl, "ulong"); + return mangled; + case 'f': + mangled++; + string_append (decl, "float"); + return mangled; + case 'd': + mangled++; + string_append (decl, "double"); + return mangled; + case 'e': + mangled++; + string_append (decl, "real"); + return mangled; + + /* Imaginary and Complex types */ + case 'o': + mangled++; + string_append (decl, "ifloat"); + return mangled; + case 'p': + mangled++; + string_append (decl, "idouble"); + return mangled; + case 'j': + mangled++; + string_append (decl, "ireal"); + return mangled; + case 'q': + mangled++; + string_append (decl, "cfloat"); + return mangled; + case 'r': + mangled++; + string_append (decl, "cdouble"); + return mangled; + case 'c': + mangled++; + string_append (decl, "creal"); + return mangled; + + /* Other types */ + case 'b': + mangled++; + string_append (decl, "bool"); + return mangled; + case 'a': + mangled++; + string_append (decl, "char"); + return mangled; + case 'u': + mangled++; + string_append (decl, "wchar"); + return mangled; + case 'w': + mangled++; + string_append (decl, "dchar"); + return mangled; + case 'z': + mangled++; + switch (*mangled) + { + case 'i': + mangled++; + string_append (decl, "cent"); + return mangled; + case 'k': + mangled++; + string_append (decl, "ucent"); + return mangled; + } + return NULL; + + /* Back referenced type. */ + case 'Q': + return dlang_type_backref (decl, mangled, info, 0); + + default: /* unhandled */ + return NULL; + } +} + +/* Extract the identifier from MANGLED and append it to DECL. + Return the remaining string on success or NULL on failure. */ +static const char * +dlang_identifier (string *decl, const char *mangled, struct dlang_info *info) +{ + unsigned long len; + + if (mangled == NULL || *mangled == '\0') + return NULL; + + if (*mangled == 'Q') + return dlang_symbol_backref (decl, mangled, info); + + /* May be a template instance without a length prefix. */ + if (mangled[0] == '_' && mangled[1] == '_' + && (mangled[2] == 'T' || mangled[2] == 'U')) + return dlang_parse_template (decl, mangled, info, TEMPLATE_LENGTH_UNKNOWN); + + const char *endptr = dlang_number (mangled, &len); + + if (endptr == NULL || len == 0) + return NULL; + + if (strlen (endptr) < len) + return NULL; + + mangled = endptr; + + /* May be a template instance with a length prefix. */ + if (len >= 5 && mangled[0] == '_' && mangled[1] == '_' + && (mangled[2] == 'T' || mangled[2] == 'U')) + return dlang_parse_template (decl, mangled, info, len); + + /* There can be multiple different declarations in the same function that have + the same mangled name. To make the mangled names unique, a fake parent in + the form `__Sddd' is added to the symbol. */ + if (len >= 4 && mangled[0] == '_' && mangled[1] == '_' && mangled[2] == 'S') + { + const char *numptr = mangled + 3; + while (numptr < (mangled + len) && ISDIGIT (*numptr)) + numptr++; + + if (mangled + len == numptr) + { + /* Skip over the fake parent. */ + mangled += len; + return dlang_identifier (decl, mangled, info); + } + + /* else demangle it as a plain identifier. */ + } + + return dlang_lname (decl, mangled, len); +} + +/* Extract the plain identifier from MANGLED and prepend/append it to DECL + with special treatment for some magic compiler generted symbols. + Return the remaining string on success or NULL on failure. */ +static const char * +dlang_lname (string *decl, const char *mangled, unsigned long len) +{ + switch (len) + { + case 6: + if (strncmp (mangled, "__ctor", len) == 0) + { + /* Constructor symbol for a class/struct. */ + string_append (decl, "this"); + mangled += len; + return mangled; + } + else if (strncmp (mangled, "__dtor", len) == 0) + { + /* Destructor symbol for a class/struct. */ + string_append (decl, "~this"); + mangled += len; + return mangled; + } + else if (strncmp (mangled, "__initZ", len + 1) == 0) + { + /* The static initialiser for a given symbol. */ + string_prepend (decl, "initializer for "); + string_setlength (decl, string_length (decl) - 1); + mangled += len; + return mangled; + } + else if (strncmp (mangled, "__vtblZ", len + 1) == 0) + { + /* The vtable symbol for a given class. */ + string_prepend (decl, "vtable for "); + string_setlength (decl, string_length (decl) - 1); + mangled += len; + return mangled; + } + break; + + case 7: + if (strncmp (mangled, "__ClassZ", len + 1) == 0) + { + /* The classinfo symbol for a given class. */ + string_prepend (decl, "ClassInfo for "); + string_setlength (decl, string_length (decl) - 1); + mangled += len; + return mangled; + } + break; + + case 10: + if (strncmp (mangled, "__postblitMFZ", len + 3) == 0) + { + /* Postblit symbol for a struct. */ + string_append (decl, "this(this)"); + mangled += len + 3; + return mangled; + } + break; + + case 11: + if (strncmp (mangled, "__InterfaceZ", len + 1) == 0) + { + /* The interface symbol for a given class. */ + string_prepend (decl, "Interface for "); + string_setlength (decl, string_length (decl) - 1); + mangled += len; + return mangled; + } + break; + + case 12: + if (strncmp (mangled, "__ModuleInfoZ", len + 1) == 0) + { + /* The ModuleInfo symbol for a given module. */ + string_prepend (decl, "ModuleInfo for "); + string_setlength (decl, string_length (decl) - 1); + mangled += len; + return mangled; + } + break; + } + + string_appendn (decl, mangled, len); + mangled += len; + + return mangled; +} + +/* Extract the integer value from MANGLED and append it to DECL, + where TYPE is the type it should be represented as. + Return the remaining string on success or NULL on failure. */ +static const char * +dlang_parse_integer (string *decl, const char *mangled, char type) +{ + if (type == 'a' || type == 'u' || type == 'w') + { + /* Parse character value. */ + char value[20]; + int pos = sizeof(value); + int width = 0; + unsigned long val; + + mangled = dlang_number (mangled, &val); + if (mangled == NULL) + return NULL; + + string_append (decl, "'"); + + if (type == 'a' && val >= 0x20 && val < 0x7F) + { + /* Represent as a character literal. */ + char c = (char) val; + string_appendn (decl, &c, 1); + } + else + { + /* Represent as a hexadecimal value. */ + switch (type) + { + case 'a': /* char */ + string_append (decl, "\\x"); + width = 2; + break; + case 'u': /* wchar */ + string_append (decl, "\\u"); + width = 4; + break; + case 'w': /* dchar */ + string_append (decl, "\\U"); + width = 8; + break; + } + + while (val > 0) + { + int digit = val % 16; + + if (digit < 10) + value[--pos] = (char)(digit + '0'); + else + value[--pos] = (char)((digit - 10) + 'a'); + + val /= 16; + width--; + } + + for (; width > 0; width--) + value[--pos] = '0'; + + string_appendn (decl, &(value[pos]), sizeof(value) - pos); + } + string_append (decl, "'"); + } + else if (type == 'b') + { + /* Parse boolean value. */ + unsigned long val; + + mangled = dlang_number (mangled, &val); + if (mangled == NULL) + return NULL; + + string_append (decl, val ? "true" : "false"); + } + else + { + /* Parse integer value. */ + const char *numptr = mangled; + size_t num = 0; + + if (! ISDIGIT (*mangled)) + return NULL; + + while (ISDIGIT (*mangled)) + { + num++; + mangled++; + } + string_appendn (decl, numptr, num); + + /* Append suffix. */ + switch (type) + { + case 'h': /* ubyte */ + case 't': /* ushort */ + case 'k': /* uint */ + string_append (decl, "u"); + break; + case 'l': /* long */ + string_append (decl, "L"); + break; + case 'm': /* ulong */ + string_append (decl, "uL"); + break; + } + } + + return mangled; +} + +/* Extract the floating-point value from MANGLED and append it to DECL. + Return the remaining string on success or NULL on failure. */ +static const char * +dlang_parse_real (string *decl, const char *mangled) +{ + /* Handle NAN and +-INF. */ + if (strncmp (mangled, "NAN", 3) == 0) + { + string_append (decl, "NaN"); + mangled += 3; + return mangled; + } + else if (strncmp (mangled, "INF", 3) == 0) + { + string_append (decl, "Inf"); + mangled += 3; + return mangled; + } + else if (strncmp (mangled, "NINF", 4) == 0) + { + string_append (decl, "-Inf"); + mangled += 4; + return mangled; + } + + /* Hexadecimal prefix and leading bit. */ + if (*mangled == 'N') + { + string_append (decl, "-"); + mangled++; + } + + if (!ISXDIGIT (*mangled)) + return NULL; + + string_append (decl, "0x"); + string_appendn (decl, mangled, 1); + string_append (decl, "."); + mangled++; + + /* Significand. */ + while (ISXDIGIT (*mangled)) + { + string_appendn (decl, mangled, 1); + mangled++; + } + + /* Exponent. */ + if (*mangled != 'P') + return NULL; + + string_append (decl, "p"); + mangled++; + + if (*mangled == 'N') + { + string_append (decl, "-"); + mangled++; + } + + while (ISDIGIT (*mangled)) + { + string_appendn (decl, mangled, 1); + mangled++; + } + + return mangled; +} + +/* Extract the string value from MANGLED and append it to DECL. + Return the remaining string on success or NULL on failure. */ +static const char * +dlang_parse_string (string *decl, const char *mangled) +{ + char type = *mangled; + unsigned long len; + + mangled++; + mangled = dlang_number (mangled, &len); + if (mangled == NULL || *mangled != '_') + return NULL; + + mangled++; + string_append (decl, "\""); + while (len--) + { + char val; + const char *endptr = dlang_hexdigit (mangled, &val); + + if (endptr == NULL) + return NULL; + + /* Sanitize white and non-printable characters. */ + switch (val) + { + case ' ': + string_append (decl, " "); + break; + case '\t': + string_append (decl, "\\t"); + break; + case '\n': + string_append (decl, "\\n"); + break; + case '\r': + string_append (decl, "\\r"); + break; + case '\f': + string_append (decl, "\\f"); + break; + case '\v': + string_append (decl, "\\v"); + break; + + default: + if (ISPRINT (val)) + string_appendn (decl, &val, 1); + else + { + string_append (decl, "\\x"); + string_appendn (decl, mangled, 2); + } + } + + mangled = endptr; + } + string_append (decl, "\""); + + if (type != 'a') + string_appendn (decl, &type, 1); + + return mangled; +} + +/* Extract the static array value from MANGLED and append it to DECL. + Return the remaining string on success or NULL on failure. */ +static const char * +dlang_parse_arrayliteral (string *decl, const char *mangled, + struct dlang_info *info) +{ + unsigned long elements; + + mangled = dlang_number (mangled, &elements); + if (mangled == NULL) + return NULL; + + string_append (decl, "["); + while (elements--) + { + mangled = dlang_value (decl, mangled, NULL, '\0', info); + if (mangled == NULL) + return NULL; + + if (elements != 0) + string_append (decl, ", "); + } + + string_append (decl, "]"); + return mangled; +} + +/* Extract the associative array value from MANGLED and append it to DECL. + Return the remaining string on success or NULL on failure. */ +static const char * +dlang_parse_assocarray (string *decl, const char *mangled, + struct dlang_info *info) +{ + unsigned long elements; + + mangled = dlang_number (mangled, &elements); + if (mangled == NULL) + return NULL; + + string_append (decl, "["); + while (elements--) + { + mangled = dlang_value (decl, mangled, NULL, '\0', info); + if (mangled == NULL) + return NULL; + + string_append (decl, ":"); + mangled = dlang_value (decl, mangled, NULL, '\0', info); + if (mangled == NULL) + return NULL; + + if (elements != 0) + string_append (decl, ", "); + } + + string_append (decl, "]"); + return mangled; +} + +/* Extract the struct literal value for NAME from MANGLED and append it to DECL. + Return the remaining string on success or NULL on failure. */ +static const char * +dlang_parse_structlit (string *decl, const char *mangled, const char *name, + struct dlang_info *info) +{ + unsigned long args; + + mangled = dlang_number (mangled, &args); + if (mangled == NULL) + return NULL; + + if (name != NULL) + string_append (decl, name); + + string_append (decl, "("); + while (args--) + { + mangled = dlang_value (decl, mangled, NULL, '\0', info); + if (mangled == NULL) + return NULL; + + if (args != 0) + string_append (decl, ", "); + } + + string_append (decl, ")"); + return mangled; +} + +/* Extract the value from MANGLED and append it to DECL. + Return the remaining string on success or NULL on failure. */ +static const char * +dlang_value (string *decl, const char *mangled, const char *name, char type, + struct dlang_info *info) +{ + if (mangled == NULL || *mangled == '\0') + return NULL; + + switch (*mangled) + { + /* Null value. */ + case 'n': + mangled++; + string_append (decl, "null"); + break; + + /* Integral values. */ + case 'N': + mangled++; + string_append (decl, "-"); + mangled = dlang_parse_integer (decl, mangled, type); + break; + + case 'i': + mangled++; + /* Fall through */ + + /* There really should always be an `i' before encoded numbers, but there + wasn't in early versions of D2, so this case range must remain for + backwards compatibility. */ + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + mangled = dlang_parse_integer (decl, mangled, type); + break; + + /* Real value. */ + case 'e': + mangled++; + mangled = dlang_parse_real (decl, mangled); + break; + + /* Complex value. */ + case 'c': + mangled++; + mangled = dlang_parse_real (decl, mangled); + string_append (decl, "+"); + if (mangled == NULL || *mangled != 'c') + return NULL; + mangled++; + mangled = dlang_parse_real (decl, mangled); + string_append (decl, "i"); + break; + + /* String values. */ + case 'a': /* UTF8 */ + case 'w': /* UTF16 */ + case 'd': /* UTF32 */ + mangled = dlang_parse_string (decl, mangled); + break; + + /* Array values. */ + case 'A': + mangled++; + if (type == 'H') + mangled = dlang_parse_assocarray (decl, mangled, info); + else + mangled = dlang_parse_arrayliteral (decl, mangled, info); + break; + + /* Struct values. */ + case 'S': + mangled++; + mangled = dlang_parse_structlit (decl, mangled, name, info); + break; + + /* Function literal symbol. */ + case 'f': + mangled++; + if (strncmp (mangled, "_D", 2) != 0 + || !dlang_symbol_name_p (mangled + 2, info)) + return NULL; + mangled = dlang_parse_mangle (decl, mangled, info); + break; + + default: + return NULL; + } + + return mangled; +} + +/* Extract and demangle the symbol in MANGLED and append it to DECL. + Returns the remaining signature on success or NULL on failure. */ +static const char * +dlang_parse_mangle (string *decl, const char *mangled, struct dlang_info *info) +{ + /* A D mangled symbol is comprised of both scope and type information. + + MangleName: + _D QualifiedName Type + _D QualifiedName Z + ^ + The caller should have guaranteed that the start pointer is at the + above location. + Note that type is never a function type, but only the return type of + a function or the type of a variable. + */ + mangled += 2; + + mangled = dlang_parse_qualified (decl, mangled, info, 1); + + if (mangled != NULL) + { + /* Artificial symbols end with 'Z' and have no type. */ + if (*mangled == 'Z') + mangled++; + else + { + /* Discard the declaration or return type. */ + string type; + + string_init (&type); + mangled = dlang_type (&type, mangled, info); + string_delete (&type); + } + } + + return mangled; +} + +/* Extract and demangle the qualified symbol in MANGLED and append it to DECL. + SUFFIX_MODIFIERS is 1 if we are printing modifiers on this after the symbol. + Returns the remaining signature on success or NULL on failure. */ +static const char * +dlang_parse_qualified (string *decl, const char *mangled, + struct dlang_info *info, int suffix_modifiers) +{ + /* Qualified names are identifiers separated by their encoded length. + Nested functions also encode their argument types without specifying + what they return. + + QualifiedName: + SymbolFunctionName + SymbolFunctionName QualifiedName + ^ + + SymbolFunctionName: + SymbolName + SymbolName TypeFunctionNoReturn + SymbolName M TypeFunctionNoReturn + SymbolName M TypeModifiers TypeFunctionNoReturn + + The start pointer should be at the above location. + */ + size_t n = 0; + do + { + /* Skip over anonymous symbols. */ + if (*mangled == '0') + { + do + mangled++; + while (*mangled == '0'); + + continue; + } + + if (n++) + string_append (decl, "."); + + mangled = dlang_identifier (decl, mangled, info); + + /* Consume the encoded arguments. However if this is not followed by the + next encoded length or mangle type, then this is not a continuation of + a qualified name, in which case we backtrack and return the current + unconsumed position of the mangled decl. */ + if (mangled && (*mangled == 'M' || dlang_call_convention_p (mangled))) + { + string mods; + const char *start = mangled; + int saved = string_length (decl); + + /* Save the type modifiers for appending at the end if needed. */ + string_init (&mods); + + /* Skip over 'this' parameter and type modifiers. */ + if (*mangled == 'M') + { + mangled++; + mangled = dlang_type_modifiers (&mods, mangled); + string_setlength (decl, saved); + } + + mangled = dlang_function_type_noreturn (decl, NULL, NULL, + mangled, info); + if (suffix_modifiers) + string_appendn (decl, mods.b, string_length (&mods)); + + if (mangled == NULL || *mangled == '\0') + { + /* Did not match the rule we were looking for. */ + mangled = start; + string_setlength (decl, saved); + } + + string_delete (&mods); + } + } + while (mangled && dlang_symbol_name_p (mangled, info)); + + return mangled; +} + +/* Demangle the tuple from MANGLED and append it to DECL. + Return the remaining string on success or NULL on failure. */ +static const char * +dlang_parse_tuple (string *decl, const char *mangled, struct dlang_info *info) +{ + unsigned long elements; + + mangled = dlang_number (mangled, &elements); + if (mangled == NULL) + return NULL; + + string_append (decl, "Tuple!("); + + while (elements--) + { + mangled = dlang_type (decl, mangled, info); + if (mangled == NULL) + return NULL; + + if (elements != 0) + string_append (decl, ", "); + } + + string_append (decl, ")"); + return mangled; +} + +/* Demangle the template symbol parameter from MANGLED and append it to DECL. + Return the remaining string on success or NULL on failure. */ +static const char * +dlang_template_symbol_param (string *decl, const char *mangled, + struct dlang_info *info) +{ + if (strncmp (mangled, "_D", 2) == 0 + && dlang_symbol_name_p (mangled + 2, info)) + return dlang_parse_mangle (decl, mangled, info); + + if (*mangled == 'Q') + return dlang_parse_qualified (decl, mangled, info, 0); + + unsigned long len; + const char *endptr = dlang_number (mangled, &len); + + if (endptr == NULL || len == 0) + return NULL; + + /* In template parameter symbols generated by the frontend up to 2.076, + the symbol length is encoded and the first character of the mangled + name can be a digit. This causes ambiguity issues because the digits + of the two numbers are adjacent. */ + long psize = len; + const char *pend; + int saved = string_length (decl); + + /* Work backwards until a match is found. */ + for (pend = endptr; endptr != NULL; pend--) + { + mangled = pend; + + /* Reached the beginning of the pointer to the name length, + try parsing the entire symbol. */ + if (psize == 0) + { + psize = len; + pend = endptr; + endptr = NULL; + } + + /* Check whether template parameter is a function with a valid + return type or an untyped identifier. */ + if (dlang_symbol_name_p (mangled, info)) + mangled = dlang_parse_qualified (decl, mangled, info, 0); + else if (strncmp (mangled, "_D", 2) == 0 + && dlang_symbol_name_p (mangled + 2, info)) + mangled = dlang_parse_mangle (decl, mangled, info); + + /* Check for name length mismatch. */ + if (mangled && (endptr == NULL || (mangled - pend) == psize)) + return mangled; + + psize /= 10; + string_setlength (decl, saved); + } + + /* No match on any combinations. */ + return NULL; +} + +/* Demangle the argument list from MANGLED and append it to DECL. + Return the remaining string on success or NULL on failure. */ +static const char * +dlang_template_args (string *decl, const char *mangled, struct dlang_info *info) +{ + size_t n = 0; + + while (mangled && *mangled != '\0') + { + switch (*mangled) + { + case 'Z': /* End of parameter list. */ + mangled++; + return mangled; + } + + if (n++) + string_append (decl, ", "); + + /* Skip over specialised template prefix. */ + if (*mangled == 'H') + mangled++; + + switch (*mangled) + { + case 'S': /* Symbol parameter. */ + mangled++; + mangled = dlang_template_symbol_param (decl, mangled, info); + break; + case 'T': /* Type parameter. */ + mangled++; + mangled = dlang_type (decl, mangled, info); + break; + case 'V': /* Value parameter. */ + { + string name; + char type; + + /* Peek at the type. */ + mangled++; + type = *mangled; + + if (type == 'Q') + { + /* Value type is a back reference, peek at the real type. */ + const char *backref; + if (dlang_backref (mangled, &backref, info) == NULL) + return NULL; + + type = *backref; + } + + /* In the few instances where the type is actually desired in + the output, it should precede the value from dlang_value. */ + string_init (&name); + mangled = dlang_type (&name, mangled, info); + string_need (&name, 1); + *(name.p) = '\0'; + + mangled = dlang_value (decl, mangled, name.b, type, info); + string_delete (&name); + break; + } + case 'X': /* Externally mangled parameter. */ + { + unsigned long len; + const char *endptr; + + mangled++; + endptr = dlang_number (mangled, &len); + if (endptr == NULL || strlen (endptr) < len) + return NULL; + + string_appendn (decl, endptr, len); + mangled = endptr + len; + break; + } + default: + return NULL; + } + } + + return mangled; +} + +/* Extract and demangle the template symbol in MANGLED, expected to + be made up of LEN characters (-1 if unknown), and append it to DECL. + Returns the remaining signature on success or NULL on failure. */ +static const char * +dlang_parse_template (string *decl, const char *mangled, + struct dlang_info *info, unsigned long len) +{ + const char *start = mangled; + string args; + + /* Template instance names have the types and values of its parameters + encoded into it. + + TemplateInstanceName: + Number __T LName TemplateArgs Z + Number __U LName TemplateArgs Z + ^ + The start pointer should be at the above location, and LEN should be + the value of the decoded number. + */ + + /* Template symbol. */ + if (!dlang_symbol_name_p (mangled + 3, info) || mangled[3] == '0') + return NULL; + + mangled += 3; + + /* Template identifier. */ + mangled = dlang_identifier (decl, mangled, info); + + /* Template arguments. */ + string_init (&args); + mangled = dlang_template_args (&args, mangled, info); + + string_append (decl, "!("); + string_appendn (decl, args.b, string_length (&args)); + string_append (decl, ")"); + + string_delete (&args); + + /* Check for template name length mismatch. */ + if (len != TEMPLATE_LENGTH_UNKNOWN + && mangled + && (unsigned long) (mangled - start) != len) + return NULL; + + return mangled; +} + +/* Initialize the information structure we use to pass around information. */ +static void +dlang_demangle_init_info (const char *mangled, int last_backref, + struct dlang_info *info) +{ + info->s = mangled; + info->last_backref = last_backref; +} + +/* Extract and demangle the symbol in MANGLED. Returns the demangled + signature on success or NULL on failure. */ + +char * +dlang_demangle (const char *mangled, int option ATTRIBUTE_UNUSED) +{ + string decl; + char *demangled = NULL; + + if (mangled == NULL || *mangled == '\0') + return NULL; + + if (strncmp (mangled, "_D", 2) != 0) + return NULL; + + string_init (&decl); + + if (strcmp (mangled, "_Dmain") == 0) + { + string_append (&decl, "D main"); + } + else + { + struct dlang_info info; + + dlang_demangle_init_info (mangled, strlen (mangled), &info); + mangled = dlang_parse_mangle (&decl, mangled, &info); + + /* Check that the entire symbol was successfully demangled. */ + if (mangled == NULL || *mangled != '\0') + string_delete (&decl); + } + + if (string_length (&decl) > 0) + { + string_need (&decl, 1); + *(decl.p) = '\0'; + demangled = decl.b; + } + + return demangled; +} + diff --git a/3rdparty/demangler/src/dyn-string.c b/3rdparty/demangler/src/dyn-string.c new file mode 100644 index 0000000000..addc3208b7 --- /dev/null +++ b/3rdparty/demangler/src/dyn-string.c @@ -0,0 +1,397 @@ +/* An abstract string datatype. + Copyright (C) 1998-2023 Free Software Foundation, Inc. + Contributed by Mark Mitchell (mark@markmitchell.com). + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file into combinations with other programs, +and to distribute those combinations without any restriction coming +from the use of this file. (The General Public License restrictions +do apply in other respects; for example, they cover modification of +the file, and distribution when not linked into a combined +executable.) + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even 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 GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#ifdef HAVE_STRING_H +#include +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif + +#include "libiberty.h" +#include "dyn-string.h" + +/* Performs in-place initialization of a dyn_string struct. This + function can be used with a dyn_string struct on the stack or + embedded in another object. The contents of of the string itself + are still dynamically allocated. The string initially is capable + of holding at least SPACE characeters, including the terminating + NUL. If SPACE is 0, it will silently be increated to 1. + + If RETURN_ON_ALLOCATION_FAILURE is defined and memory allocation + fails, returns 0. Otherwise returns 1. */ + +int +dyn_string_init (struct dyn_string *ds_struct_ptr, int space) +{ + /* We need at least one byte in which to store the terminating NUL. */ + if (space == 0) + space = 1; + +#ifdef RETURN_ON_ALLOCATION_FAILURE + ds_struct_ptr->s = (char *) malloc (space); + if (ds_struct_ptr->s == NULL) + return 0; +#else + ds_struct_ptr->s = XNEWVEC (char, space); +#endif + ds_struct_ptr->allocated = space; + ds_struct_ptr->length = 0; + ds_struct_ptr->s[0] = '\0'; + + return 1; +} + +/* Create a new dynamic string capable of holding at least SPACE + characters, including the terminating NUL. If SPACE is 0, it will + be silently increased to 1. If RETURN_ON_ALLOCATION_FAILURE is + defined and memory allocation fails, returns NULL. Otherwise + returns the newly allocated string. */ + +dyn_string_t +dyn_string_new (int space) +{ + dyn_string_t result; +#ifdef RETURN_ON_ALLOCATION_FAILURE + result = (dyn_string_t) malloc (sizeof (struct dyn_string)); + if (result == NULL) + return NULL; + if (!dyn_string_init (result, space)) + { + free (result); + return NULL; + } +#else + result = XNEW (struct dyn_string); + dyn_string_init (result, space); +#endif + return result; +} + +/* Free the memory used by DS. */ + +void +dyn_string_delete (dyn_string_t ds) +{ + free (ds->s); + free (ds); +} + +/* Returns the contents of DS in a buffer allocated with malloc. It + is the caller's responsibility to deallocate the buffer using free. + DS is then set to the empty string. Deletes DS itself. */ + +char* +dyn_string_release (dyn_string_t ds) +{ + /* Store the old buffer. */ + char* result = ds->s; + /* The buffer is no longer owned by DS. */ + ds->s = NULL; + /* Delete DS. */ + free (ds); + /* Return the old buffer. */ + return result; +} + +/* Increase the capacity of DS so it can hold at least SPACE + characters, plus the terminating NUL. This function will not (at + present) reduce the capacity of DS. Returns DS on success. + + If RETURN_ON_ALLOCATION_FAILURE is defined and a memory allocation + operation fails, deletes DS and returns NULL. */ + +dyn_string_t +dyn_string_resize (dyn_string_t ds, int space) +{ + int new_allocated = ds->allocated; + + /* Increase SPACE to hold the NUL termination. */ + ++space; + + /* Increase allocation by factors of two. */ + while (space > new_allocated) + new_allocated *= 2; + + if (new_allocated != ds->allocated) + { + ds->allocated = new_allocated; + /* We actually need more space. */ +#ifdef RETURN_ON_ALLOCATION_FAILURE + ds->s = (char *) realloc (ds->s, ds->allocated); + if (ds->s == NULL) + { + free (ds); + return NULL; + } +#else + ds->s = XRESIZEVEC (char, ds->s, ds->allocated); +#endif + } + + return ds; +} + +/* Sets the contents of DS to the empty string. */ + +void +dyn_string_clear (dyn_string_t ds) +{ + /* A dyn_string always has room for at least the NUL terminator. */ + ds->s[0] = '\0'; + ds->length = 0; +} + +/* Makes the contents of DEST the same as the contents of SRC. DEST + and SRC must be distinct. Returns 1 on success. On failure, if + RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */ + +int +dyn_string_copy (dyn_string_t dest, dyn_string_t src) +{ + if (dest == src) + abort (); + + /* Make room in DEST. */ + if (dyn_string_resize (dest, src->length) == NULL) + return 0; + /* Copy DEST into SRC. */ + strcpy (dest->s, src->s); + /* Update the size of DEST. */ + dest->length = src->length; + return 1; +} + +/* Copies SRC, a NUL-terminated string, into DEST. Returns 1 on + success. On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST + and returns 0. */ + +int +dyn_string_copy_cstr (dyn_string_t dest, const char *src) +{ + int length = strlen (src); + /* Make room in DEST. */ + if (dyn_string_resize (dest, length) == NULL) + return 0; + /* Copy DEST into SRC. */ + strcpy (dest->s, src); + /* Update the size of DEST. */ + dest->length = length; + return 1; +} + +/* Inserts SRC at the beginning of DEST. DEST is expanded as + necessary. SRC and DEST must be distinct. Returns 1 on success. + On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and + returns 0. */ + +int +dyn_string_prepend (dyn_string_t dest, dyn_string_t src) +{ + return dyn_string_insert (dest, 0, src); +} + +/* Inserts SRC, a NUL-terminated string, at the beginning of DEST. + DEST is expanded as necessary. Returns 1 on success. On failure, + if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */ + +int +dyn_string_prepend_cstr (dyn_string_t dest, const char *src) +{ + return dyn_string_insert_cstr (dest, 0, src); +} + +/* Inserts SRC into DEST starting at position POS. DEST is expanded + as necessary. SRC and DEST must be distinct. Returns 1 on + success. On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST + and returns 0. */ + +int +dyn_string_insert (dyn_string_t dest, int pos, dyn_string_t src) +{ + int i; + + if (src == dest) + abort (); + + if (dyn_string_resize (dest, dest->length + src->length) == NULL) + return 0; + /* Make room for the insertion. Be sure to copy the NUL. */ + for (i = dest->length; i >= pos; --i) + dest->s[i + src->length] = dest->s[i]; + /* Splice in the new stuff. */ + strncpy (dest->s + pos, src->s, src->length); + /* Compute the new length. */ + dest->length += src->length; + return 1; +} + +/* Inserts SRC, a NUL-terminated string, into DEST starting at + position POS. DEST is expanded as necessary. Returns 1 on + success. On failure, RETURN_ON_ALLOCATION_FAILURE, deletes DEST + and returns 0. */ + +int +dyn_string_insert_cstr (dyn_string_t dest, int pos, const char *src) +{ + int i; + int length = strlen (src); + + if (dyn_string_resize (dest, dest->length + length) == NULL) + return 0; + /* Make room for the insertion. Be sure to copy the NUL. */ + for (i = dest->length; i >= pos; --i) + dest->s[i + length] = dest->s[i]; + /* Splice in the new stuff. */ + memcpy (dest->s + pos, src, length); + /* Compute the new length. */ + dest->length += length; + return 1; +} + +/* Inserts character C into DEST starting at position POS. DEST is + expanded as necessary. Returns 1 on success. On failure, + RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */ + +int +dyn_string_insert_char (dyn_string_t dest, int pos, int c) +{ + int i; + + if (dyn_string_resize (dest, dest->length + 1) == NULL) + return 0; + /* Make room for the insertion. Be sure to copy the NUL. */ + for (i = dest->length; i >= pos; --i) + dest->s[i + 1] = dest->s[i]; + /* Add the new character. */ + dest->s[pos] = c; + /* Compute the new length. */ + ++dest->length; + return 1; +} + +/* Append S to DS, resizing DS if necessary. Returns 1 on success. + On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and + returns 0. */ + +int +dyn_string_append (dyn_string_t dest, dyn_string_t s) +{ + if (dyn_string_resize (dest, dest->length + s->length) == 0) + return 0; + strcpy (dest->s + dest->length, s->s); + dest->length += s->length; + return 1; +} + +/* Append the NUL-terminated string S to DS, resizing DS if necessary. + Returns 1 on success. On failure, if RETURN_ON_ALLOCATION_FAILURE, + deletes DEST and returns 0. */ + +int +dyn_string_append_cstr (dyn_string_t dest, const char *s) +{ + int len = strlen (s); + + /* The new length is the old length plus the size of our string, plus + one for the null at the end. */ + if (dyn_string_resize (dest, dest->length + len) == NULL) + return 0; + strcpy (dest->s + dest->length, s); + dest->length += len; + return 1; +} + +/* Appends C to the end of DEST. Returns 1 on success. On failure, + if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */ + +int +dyn_string_append_char (dyn_string_t dest, int c) +{ + /* Make room for the extra character. */ + if (dyn_string_resize (dest, dest->length + 1) == NULL) + return 0; + /* Append the character; it will overwrite the old NUL. */ + dest->s[dest->length] = c; + /* Add a new NUL at the end. */ + dest->s[dest->length + 1] = '\0'; + /* Update the length. */ + ++(dest->length); + return 1; +} + +/* Sets the contents of DEST to the substring of SRC starting at START + and ending before END. START must be less than or equal to END, + and both must be between zero and the length of SRC, inclusive. + Returns 1 on success. On failure, if RETURN_ON_ALLOCATION_FAILURE, + deletes DEST and returns 0. */ + +int +dyn_string_substring (dyn_string_t dest, dyn_string_t src, + int start, int end) +{ + int i; + int length = end - start; + + if (start > end || start > src->length || end > src->length) + abort (); + + /* Make room for the substring. */ + if (dyn_string_resize (dest, length) == NULL) + return 0; + /* Copy the characters in the substring, */ + for (i = length; --i >= 0; ) + dest->s[i] = src->s[start + i]; + /* NUL-terimate the result. */ + dest->s[length] = '\0'; + /* Record the length of the substring. */ + dest->length = length; + + return 1; +} + +/* Returns non-zero if DS1 and DS2 have the same contents. */ + +int +dyn_string_eq (dyn_string_t ds1, dyn_string_t ds2) +{ + /* If DS1 and DS2 have different lengths, they must not be the same. */ + if (ds1->length != ds2->length) + return 0; + else + return !strcmp (ds1->s, ds2->s); +} diff --git a/3rdparty/demangler/src/getopt.c b/3rdparty/demangler/src/getopt.c new file mode 100644 index 0000000000..7c8ded5d7f --- /dev/null +++ b/3rdparty/demangler/src/getopt.c @@ -0,0 +1,1051 @@ +/* Getopt for GNU. + NOTE: getopt is now part of the C library, so if you don't know what + "Keep this file name-space clean" means, talk to drepper@gnu.org + before changing it! + + Copyright (C) 1987-2023 Free Software Foundation, Inc. + + NOTE: This source is derived from an old version taken from the GNU C + Library (glibc). + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + 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. */ + +/* This tells Alpha OSF/1 not to define a getopt prototype in . + Ditto for AIX 3.2 and . */ +#ifndef _NO_PROTO +# define _NO_PROTO +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if !defined __STDC__ || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +# ifndef const +# define const +# endif +#endif + +#include "ansidecl.h" +#include + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#define GETOPT_INTERFACE_VERSION 2 +#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 +# include +# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +# define ELIDE_CODE +# endif +#endif + +#ifndef ELIDE_CODE + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +/* Don't include stdlib.h for non-GNU C libraries because some of them + contain conflicting prototypes for getopt. */ +# include +# include +#endif /* GNU C library. */ + +#ifdef VMS +# include +# if HAVE_STRING_H - 0 +# include +# endif +#endif + +#ifndef _ +/* This is for other GNU distributions with internationalized messages. + When compiling libc, the _ macro is predefined. */ +# if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC +# include +# define _(msgid) gettext (msgid) +# else +# define _(msgid) (msgid) +# endif +#endif + +/* This version of `getopt' appears to the caller like standard Unix `getopt' + but it behaves differently for the user, since it allows the user + to intersperse the options with the other arguments. + + As `getopt' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. + + Setting the environment variable POSIXLY_CORRECT disables permutation. + Then the behavior is completely standard. + + GNU application programs can use a third alternative mode in which + they can distinguish the relative order of options and other arguments. */ + +#include "getopt.h" + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +char *optarg = NULL; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +/* 1003.2 says this must be 1 before any call. */ +int optind = 1; + +/* Formerly, initialization of getopt depended on optind==0, which + causes problems with re-calling getopt as programs generally don't + know that. */ + +int __getopt_initialized = 0; + +/* The next char to be scanned in the option-element + in which the last option character we returned was found. + This allows us to pick up the scan where we left off. + + If this is zero, or a null string, it means resume the scan + by advancing to the next ARGV-element. */ + +static char *nextchar; + +/* Callers store zero here to inhibit the error message + for unrecognized options. */ + +int opterr = 1; + +/* Set to an option character which was unrecognized. + This must be initialized on some systems to avoid linking in the + system's own getopt implementation. */ + +int optopt = '?'; + +/* Describe how to deal with options that follow non-option ARGV-elements. + + If the caller did not specify anything, + the default is REQUIRE_ORDER if the environment variable + POSIXLY_CORRECT is defined, PERMUTE otherwise. + + REQUIRE_ORDER means don't recognize them as options; + stop option processing when the first non-option is seen. + This is what Unix does. + This mode of operation is selected by either setting the environment + variable POSIXLY_CORRECT, or using `+' as the first character + of the list of option characters. + + PERMUTE is the default. We permute the contents of ARGV as we scan, + so that eventually all the non-options are at the end. This allows options + to be given in any order, even with programs that were not written to + expect this. + + RETURN_IN_ORDER is an option available to programs that were written + to expect options and other ARGV-elements in any order and that care about + the ordering of the two. We describe each non-option ARGV-element + as if it were the argument of an option with character code 1. + Using `-' as the first character of the list of option characters + selects this mode of operation. + + The special argument `--' forces an end of option-scanning regardless + of the value of `ordering'. In the case of RETURN_IN_ORDER, only + `--' can cause `getopt' to return -1 with `optind' != ARGC. */ + +static enum +{ + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +} ordering; + +/* Value of POSIXLY_CORRECT environment variable. */ +static char *posixly_correct; + +#ifdef __GNU_LIBRARY__ +/* We want to avoid inclusion of string.h with non-GNU libraries + because there are many ways it can cause trouble. + On some systems, it contains special magic macros that don't work + in GCC. */ +# include +# define my_index strchr +#else + +# if HAVE_STRING_H +# include +# else +# if HAVE_STRINGS_H +# include +# endif +# endif + +/* Avoid depending on library functions or files + whose names are inconsistent. */ + +#if HAVE_STDLIB_H && HAVE_DECL_GETENV +# include +#elif !defined(getenv) +# ifdef __cplusplus +extern "C" { +# endif /* __cplusplus */ +extern char *getenv (const char *); +# ifdef __cplusplus +} +# endif /* __cplusplus */ +#endif + +static char * +my_index (const char *str, int chr) +{ + while (*str) + { + if (*str == chr) + return (char *) str; + str++; + } + return 0; +} + +/* If using GCC, we can safely declare strlen this way. + If not using GCC, it is ok not to declare it. */ +#ifdef __GNUC__ +/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. + That was relevant to code that was here before. */ +# if (!defined __STDC__ || !__STDC__) && !defined strlen +/* gcc with -traditional declares the built-in strlen to return int, + and has done so at least since version 2.4.5. -- rms. */ +extern int strlen (const char *); +# endif /* not __STDC__ */ +#endif /* __GNUC__ */ + +#endif /* not __GNU_LIBRARY__ */ + +/* Handle permutation of arguments. */ + +/* Describe the part of ARGV that contains non-options that have + been skipped. `first_nonopt' is the index in ARGV of the first of them; + `last_nonopt' is the index after the last of them. */ + +static int first_nonopt; +static int last_nonopt; + +#ifdef _LIBC +/* Bash 2.0 gives us an environment variable containing flags + indicating ARGV elements that should not be considered arguments. */ + +/* Defined in getopt_init.c */ +extern char *__getopt_nonoption_flags; + +static int nonoption_flags_max_len; +static int nonoption_flags_len; + +static int original_argc; +static char *const *original_argv; + +/* Make sure the environment variable bash 2.0 puts in the environment + is valid for the getopt call we must make sure that the ARGV passed + to getopt is that one passed to the process. */ +static void +__attribute__ ((unused)) +store_args_and_env (int argc, char *const *argv) +{ + /* XXX This is no good solution. We should rather copy the args so + that we can compare them later. But we must not use malloc(3). */ + original_argc = argc; + original_argv = argv; +} +# ifdef text_set_element +text_set_element (__libc_subinit, store_args_and_env); +# endif /* text_set_element */ + +# define SWAP_FLAGS(ch1, ch2) \ + if (nonoption_flags_len > 0) \ + { \ + char __tmp = __getopt_nonoption_flags[ch1]; \ + __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ + __getopt_nonoption_flags[ch2] = __tmp; \ + } +#else /* !_LIBC */ +# define SWAP_FLAGS(ch1, ch2) +#endif /* _LIBC */ + +/* Exchange two adjacent subsequences of ARGV. + One subsequence is elements [first_nonopt,last_nonopt) + which contains all the non-options that have been skipped so far. + The other is elements [last_nonopt,optind), which contains all + the options processed since those non-options were skipped. + + `first_nonopt' and `last_nonopt' are relocated so that they describe + the new indices of the non-options in ARGV after they are moved. */ + +#if defined __STDC__ && __STDC__ +static void exchange (char **); +#endif + +static void +exchange (char **argv) +{ + int bottom = first_nonopt; + int middle = last_nonopt; + int top = optind; + char *tem; + + /* Exchange the shorter segment with the far end of the longer segment. + That puts the shorter segment into the right place. + It leaves the longer segment in the right place overall, + but it consists of two parts that need to be swapped next. */ + +#ifdef _LIBC + /* First make sure the handling of the `__getopt_nonoption_flags' + string can work normally. Our top argument must be in the range + of the string. */ + if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) + { + /* We must extend the array. The user plays games with us and + presents new arguments. */ + char *new_str = (char *) malloc (top + 1); + if (new_str == NULL) + nonoption_flags_len = nonoption_flags_max_len = 0; + else + { + memset (mempcpy (new_str, __getopt_nonoption_flags, + nonoption_flags_max_len), + '\0', top + 1 - nonoption_flags_max_len); + nonoption_flags_max_len = top + 1; + __getopt_nonoption_flags = new_str; + } + } +#endif + + while (top > middle && middle > bottom) + { + if (top - middle > middle - bottom) + { + /* Bottom segment is the short one. */ + int len = middle - bottom; + register int i; + + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } + else + { + /* Top segment is the short one. */ + int len = top - middle; + register int i; + + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + SWAP_FLAGS (bottom + i, middle + i); + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } + } + + /* Update records for the slots the non-options now occupy. */ + + first_nonopt += (optind - last_nonopt); + last_nonopt = optind; +} + +/* Initialize the internal data when the first call is made. */ + +#if defined __STDC__ && __STDC__ +static const char *_getopt_initialize (int, char *const *, const char *); +#endif +static const char * +_getopt_initialize (int argc ATTRIBUTE_UNUSED, + char *const *argv ATTRIBUTE_UNUSED, + const char *optstring) +{ + /* Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + first_nonopt = last_nonopt = optind; + + nextchar = NULL; + + posixly_correct = getenv ("POSIXLY_CORRECT"); + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + ordering = REQUIRE_ORDER; + ++optstring; + } + else if (posixly_correct != NULL) + ordering = REQUIRE_ORDER; + else + ordering = PERMUTE; + +#ifdef _LIBC + if (posixly_correct == NULL + && argc == original_argc && argv == original_argv) + { + if (nonoption_flags_max_len == 0) + { + if (__getopt_nonoption_flags == NULL + || __getopt_nonoption_flags[0] == '\0') + nonoption_flags_max_len = -1; + else + { + const char *orig_str = __getopt_nonoption_flags; + int len = nonoption_flags_max_len = strlen (orig_str); + if (nonoption_flags_max_len < argc) + nonoption_flags_max_len = argc; + __getopt_nonoption_flags = + (char *) malloc (nonoption_flags_max_len); + if (__getopt_nonoption_flags == NULL) + nonoption_flags_max_len = -1; + else + memset (mempcpy (__getopt_nonoption_flags, orig_str, len), + '\0', nonoption_flags_max_len - len); + } + } + nonoption_flags_len = nonoption_flags_max_len; + } + else + nonoption_flags_len = 0; +#endif + + return optstring; +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters + given in OPTSTRING. + + If an element of ARGV starts with '-', and is not exactly "-" or "--", + then it is an option element. The characters of this element + (aside from the initial '-') are option characters. If `getopt' + is called repeatedly, it returns successively each of the option characters + from each of the option elements. + + If `getopt' finds another option character, it returns that character, + updating `optind' and `nextchar' so that the next call to `getopt' can + resume the scan with the following option character or ARGV-element. + + If there are no more option characters, `getopt' returns -1. + Then `optind' is the index in ARGV of the first ARGV-element + that is not an option. (The ARGV-elements have been permuted + so that those that are not options now come last.) + + OPTSTRING is a string containing the legitimate option characters. + If an option character is seen that is not listed in OPTSTRING, + return '?' after printing an error message. If you set `opterr' to + zero, the error message is suppressed but we still return '?'. + + If a char in OPTSTRING is followed by a colon, that means it wants an arg, + so the following text in the same ARGV-element, or the text of the following + ARGV-element, is returned in `optarg'. Two colons mean an option that + wants an optional arg; if there is text in the current ARGV-element, + it is returned in `optarg', otherwise `optarg' is set to zero. + + If OPTSTRING starts with `-' or `+', it requests different methods of + handling the non-option ARGV-elements. + See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + + Long-named options begin with `--' instead of `-'. + Their names may be abbreviated as long as the abbreviation is unique + or is an exact match for some defined option. If they have an + argument, it follows the option name in the same ARGV-element, separated + from the option name by a `=', or else the in next ARGV-element. + When `getopt' finds a long-named option, it returns 0 if that option's + `flag' field is nonzero, the value of the option's `val' field + if the `flag' field is zero. + + The elements of ARGV aren't really const, because we permute them. + But we pretend they're const in the prototype to be compatible + with other systems. + + LONGOPTS is a vector of `struct option' terminated by an + element containing a name which is zero. + + LONGIND returns the index in LONGOPT of the long-named option found. + It is only valid when a long-named option has been found by the most + recent call. + + If LONG_ONLY is nonzero, '-' as well as '--' can introduce + long-named options. */ + +int +_getopt_internal (int argc, char *const *argv, const char *optstring, + const struct option *longopts, + int *longind, int long_only) +{ + optarg = NULL; + + if (optind == 0 || !__getopt_initialized) + { + if (optind == 0) + optind = 1; /* Don't scan ARGV[0], the program name. */ + optstring = _getopt_initialize (argc, argv, optstring); + __getopt_initialized = 1; + } + + /* Test whether ARGV[optind] points to a non-option argument. + Either it does not have option syntax, or there is an environment flag + from the shell indicating it is not an option. The later information + is only used when the used in the GNU libc. */ +#ifdef _LIBC +# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ + || (optind < nonoption_flags_len \ + && __getopt_nonoption_flags[optind] == '1')) +#else +# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') +#endif + + if (nextchar == NULL || *nextchar == '\0') + { + /* Advance to the next ARGV-element. */ + + /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been + moved back by the user (who may also have changed the arguments). */ + if (last_nonopt > optind) + last_nonopt = optind; + if (first_nonopt > optind) + first_nonopt = optind; + + if (ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (last_nonopt != optind) + first_nonopt = optind; + + /* Skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (optind < argc && NONOPTION_P) + optind++; + last_nonopt = optind; + } + + /* The special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (optind != argc && !strcmp (argv[optind], "--")) + { + optind++; + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (first_nonopt == last_nonopt) + first_nonopt = optind; + last_nonopt = argc; + + optind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (optind == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (first_nonopt != last_nonopt) + optind = first_nonopt; + return -1; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if (NONOPTION_P) + { + if (ordering == REQUIRE_ORDER) + return -1; + optarg = argv[optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Skip the initial punctuation. */ + + nextchar = (argv[optind] + 1 + + (longopts != NULL && argv[optind][1] == '-')); + } + + /* Decode the current option-ARGV-element. */ + + /* Check whether the ARGV-element is a long option. + + If long_only and the ARGV-element has the form "-f", where f is + a valid short option, don't consider it an abbreviated form of + a long option that starts with f. Otherwise there would be no + way to give the -f short option. + + On the other hand, if there's a long option "fubar" and + the ARGV-element is "-fu", do consider that an abbreviation of + the long option, just like "--fu", and not "-f" with arg "u". + + This distinction seems to be the most useful approach. */ + + if (longopts != NULL + && (argv[optind][1] == '-' + || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = -1; + int option_index; + + for (nameend = nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int) (nameend - nextchar) + == (unsigned int) strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + if (opterr) + fprintf (stderr, _("%s: option `%s' is ambiguous\n"), + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + optopt = 0; + return '?'; + } + + if (pfound != NULL) + { + option_index = indfound; + optind++; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (opterr) + { + if (argv[optind - 1][1] == '-') + /* --option */ + fprintf (stderr, + _("%s: option `--%s' doesn't allow an argument\n"), + argv[0], pfound->name); + else + /* +option or -option */ + fprintf (stderr, + _("%s: option `%c%s' doesn't allow an argument\n"), + argv[0], argv[optind - 1][0], pfound->name); + + nextchar += strlen (nextchar); + + optopt = pfound->val; + return '?'; + } + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (opterr) + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + optopt = pfound->val; + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[optind][1] == '-' + || my_index (optstring, *nextchar) == NULL) + { + if (opterr) + { + if (argv[optind][1] == '-') + /* --option */ + fprintf (stderr, _("%s: unrecognized option `--%s'\n"), + argv[0], nextchar); + else + /* +option or -option */ + fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), + argv[0], argv[optind][0], nextchar); + } + nextchar = (char *) ""; + optind++; + optopt = 0; + return '?'; + } + } + + /* Look at and handle the next short option-character. */ + + { + char c = *nextchar++; + char *temp = my_index (optstring, c); + + /* Increment `optind' when we start to process its last character. */ + if (*nextchar == '\0') + ++optind; + + if (temp == NULL || c == ':') + { + if (opterr) + { + if (posixly_correct) + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, _("%s: illegal option -- %c\n"), + argv[0], c); + else + fprintf (stderr, _("%s: invalid option -- %c\n"), + argv[0], c); + } + optopt = c; + return '?'; + } + /* Convenience. Treat POSIX -W foo same as long option --foo */ + if (temp[0] == 'W' && temp[1] == ';') + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = 0; + int option_index; + + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (opterr) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + return c; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + + /* optarg is now the argument, see if it's in the + table of longopts. */ + + for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int) (nameend - nextchar) == strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + if (ambig && !exact) + { + if (opterr) + fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + return '?'; + } + if (pfound != NULL) + { + option_index = indfound; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (opterr) + fprintf (stderr, _("\ +%s: option `-W %s' doesn't allow an argument\n"), + argv[0], pfound->name); + + nextchar += strlen (nextchar); + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (opterr) + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + nextchar = NULL; + return 'W'; /* Let the application handle it. */ + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*nextchar != '\0') + { + optarg = nextchar; + optind++; + } + else + optarg = NULL; + nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (opterr) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, + _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + nextchar = NULL; + } + } + return c; + } +} + +int +getopt (int argc, char *const *argv, const char *optstring) +{ + return _getopt_internal (argc, argv, optstring, + (const struct option *) 0, + (int *) 0, + 0); +} + +#endif /* Not ELIDE_CODE. */ + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing + the above definition of `getopt'. */ + +int +main (int argc, char **argv) +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + + c = getopt (argc, argv, "abc:d:0123456789"); + if (c == -1) + break; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/3rdparty/demangler/src/getopt1.c b/3rdparty/demangler/src/getopt1.c new file mode 100644 index 0000000000..5e39128f20 --- /dev/null +++ b/3rdparty/demangler/src/getopt1.c @@ -0,0 +1,179 @@ +/* getopt_long and getopt_long_only entry points for GNU getopt. + Copyright (C) 1987-2023 Free Software Foundation, Inc. + + NOTE: This source is derived from an old version taken from the GNU C + Library (glibc). + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + 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. */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if !defined __STDC__ || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +#ifndef const +#define const +#endif +#endif + +#include + +#include "getopt.h" + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#define GETOPT_INTERFACE_VERSION 2 +#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 +#include +#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +#define ELIDE_CODE +#endif +#endif + +#ifndef ELIDE_CODE + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +#include +#endif + +#ifndef NULL +#define NULL 0 +#endif + +int +getopt_long (int argc, char *const *argv, const char *options, + const struct option *long_options, int *opt_index) +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 0); +} + +/* Like getopt_long, but '-' as well as '--' can indicate a long option. + If an option that starts with '-' (not '--') doesn't match a long option, + but does match a short option, it is parsed as a short option + instead. */ + +int +getopt_long_only (int argc, char *const *argv, const char *options, + const struct option *long_options, int *opt_index) +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 1); +} + + +#endif /* Not ELIDE_CODE. */ + +#ifdef TEST + +#include + +int +main (int argc, char **argv) +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = + { + {"add", 1, 0, 0}, + {"append", 0, 0, 0}, + {"delete", 1, 0, 0}, + {"verbose", 0, 0, 0}, + {"create", 0, 0, 0}, + {"file", 1, 0, 0}, + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "abc:d:0123456789", + long_options, &option_index); + if (c == -1) + break; + + switch (c) + { + case 0: + printf ("option %s", long_options[option_index].name); + if (optarg) + printf (" with arg %s", optarg); + printf ("\n"); + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case 'd': + printf ("option d with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/3rdparty/demangler/src/rust-demangle.c b/3rdparty/demangler/src/rust-demangle.c new file mode 100644 index 0000000000..c7630f103e --- /dev/null +++ b/3rdparty/demangler/src/rust-demangle.c @@ -0,0 +1,1604 @@ +/* Demangler for the Rust programming language + Copyright (C) 2016-2023 Free Software Foundation, Inc. + Written by David Tolnay (dtolnay@gmail.com). + Rewritten by Eduard-Mihai Burtescu (eddyb@lyken.rs) for v0 support. + +This file is part of the libiberty library. +Libiberty 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. + +In addition to the permissions in the GNU Library General Public +License, the Free Software Foundation gives you unlimited permission +to link the compiled version of this file into combinations with other +programs, and to distribute those combinations without any restriction +coming from the use of this file. (The Library Public License +restrictions do apply in other respects; for example, they cover +modification of the file, and distribution when not linked into a +combined executable.) + +Libiberty is distributed in the hope that 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 libiberty; see the file COPYING.LIB. +If not, see . */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "safe-ctype.h" + +#include +#include +#include +#include +#include + +#ifdef HAVE_STRING_H +#include +#else +extern size_t strlen(const char *s); +extern int strncmp(const char *s1, const char *s2, size_t n); +extern void *memset(void *s, int c, size_t n); +#endif + +#include +#include "libiberty.h" + +struct rust_demangler +{ + const char *sym; + size_t sym_len; + + void *callback_opaque; + demangle_callbackref callback; + + /* Position of the next character to read from the symbol. */ + size_t next; + + /* Non-zero if any error occurred. */ + int errored; + + /* Non-zero if nothing should be printed. */ + int skipping_printing; + + /* Non-zero if printing should be verbose (e.g. include hashes). */ + int verbose; + + /* Rust mangling version, with legacy mangling being -1. */ + int version; + + /* Recursion depth. */ + unsigned int recursion; + /* Maximum number of times demangle_path may be called recursively. */ +#define RUST_MAX_RECURSION_COUNT 1024 +#define RUST_NO_RECURSION_LIMIT ((unsigned int) -1) + + uint64_t bound_lifetime_depth; +}; + +/* Parsing functions. */ + +static char +peek (const struct rust_demangler *rdm) +{ + if (rdm->next < rdm->sym_len) + return rdm->sym[rdm->next]; + return 0; +} + +static int +eat (struct rust_demangler *rdm, char c) +{ + if (peek (rdm) == c) + { + rdm->next++; + return 1; + } + else + return 0; +} + +static char +next (struct rust_demangler *rdm) +{ + char c = peek (rdm); + if (!c) + rdm->errored = 1; + else + rdm->next++; + return c; +} + +static uint64_t +parse_integer_62 (struct rust_demangler *rdm) +{ + char c; + uint64_t x; + + if (eat (rdm, '_')) + return 0; + + x = 0; + while (!eat (rdm, '_') && !rdm->errored) + { + c = next (rdm); + x *= 62; + if (ISDIGIT (c)) + x += c - '0'; + else if (ISLOWER (c)) + x += 10 + (c - 'a'); + else if (ISUPPER (c)) + x += 10 + 26 + (c - 'A'); + else + { + rdm->errored = 1; + return 0; + } + } + return x + 1; +} + +static uint64_t +parse_opt_integer_62 (struct rust_demangler *rdm, char tag) +{ + if (!eat (rdm, tag)) + return 0; + return 1 + parse_integer_62 (rdm); +} + +static uint64_t +parse_disambiguator (struct rust_demangler *rdm) +{ + return parse_opt_integer_62 (rdm, 's'); +} + +static size_t +parse_hex_nibbles (struct rust_demangler *rdm, uint64_t *value) +{ + char c; + size_t hex_len; + + hex_len = 0; + *value = 0; + + while (!eat (rdm, '_')) + { + *value <<= 4; + + c = next (rdm); + if (ISDIGIT (c)) + *value |= c - '0'; + else if (c >= 'a' && c <= 'f') + *value |= 10 + (c - 'a'); + else + { + rdm->errored = 1; + return 0; + } + hex_len++; + } + + return hex_len; +} + +struct rust_mangled_ident +{ + /* ASCII part of the identifier. */ + const char *ascii; + size_t ascii_len; + + /* Punycode insertion codes for Unicode codepoints, if any. */ + const char *punycode; + size_t punycode_len; +}; + +static struct rust_mangled_ident +parse_ident (struct rust_demangler *rdm) +{ + char c; + size_t start, len; + int is_punycode = 0; + struct rust_mangled_ident ident; + + ident.ascii = NULL; + ident.ascii_len = 0; + ident.punycode = NULL; + ident.punycode_len = 0; + + if (rdm->version != -1) + is_punycode = eat (rdm, 'u'); + + c = next (rdm); + if (!ISDIGIT (c)) + { + rdm->errored = 1; + return ident; + } + len = c - '0'; + + if (c != '0') + while (ISDIGIT (peek (rdm))) + len = len * 10 + (next (rdm) - '0'); + + /* Skip past the optional `_` separator (v0). */ + if (rdm->version != -1) + eat (rdm, '_'); + + start = rdm->next; + rdm->next += len; + /* Check for overflows. */ + if ((start > rdm->next) || (rdm->next > rdm->sym_len)) + { + rdm->errored = 1; + return ident; + } + + ident.ascii = rdm->sym + start; + ident.ascii_len = len; + + if (is_punycode) + { + ident.punycode_len = 0; + while (ident.ascii_len > 0) + { + ident.ascii_len--; + + /* The last '_' is a separator between ascii & punycode. */ + if (ident.ascii[ident.ascii_len] == '_') + break; + + ident.punycode_len++; + } + if (!ident.punycode_len) + { + rdm->errored = 1; + return ident; + } + ident.punycode = ident.ascii + (len - ident.punycode_len); + } + + if (ident.ascii_len == 0) + ident.ascii = NULL; + + return ident; +} + +/* Printing functions. */ + +static void +print_str (struct rust_demangler *rdm, const char *data, size_t len) +{ + if (!rdm->errored && !rdm->skipping_printing) + rdm->callback (data, len, rdm->callback_opaque); +} + +#define PRINT(s) print_str (rdm, s, strlen (s)) + +static void +print_uint64 (struct rust_demangler *rdm, uint64_t x) +{ + char s[21]; + snprintf (s, 21, "%" PRIu64, x); + PRINT (s); +} + +static void +print_uint64_hex (struct rust_demangler *rdm, uint64_t x) +{ + char s[17]; + snprintf (s, 17, "%" PRIx64, x); + PRINT (s); +} + +/* Return a 0x0-0xf value if the char is 0-9a-f, and -1 otherwise. */ +static int +decode_lower_hex_nibble (char nibble) +{ + if ('0' <= nibble && nibble <= '9') + return nibble - '0'; + if ('a' <= nibble && nibble <= 'f') + return 0xa + (nibble - 'a'); + return -1; +} + +/* Return the unescaped character for a "$...$" escape, or 0 if invalid. */ +static char +decode_legacy_escape (const char *e, size_t len, size_t *out_len) +{ + char c = 0; + size_t escape_len = 0; + int lo_nibble = -1, hi_nibble = -1; + + if (len < 3 || e[0] != '$') + return 0; + + e++; + len--; + + if (e[0] == 'C') + { + escape_len = 1; + + c = ','; + } + else if (len > 2) + { + escape_len = 2; + + if (e[0] == 'S' && e[1] == 'P') + c = '@'; + else if (e[0] == 'B' && e[1] == 'P') + c = '*'; + else if (e[0] == 'R' && e[1] == 'F') + c = '&'; + else if (e[0] == 'L' && e[1] == 'T') + c = '<'; + else if (e[0] == 'G' && e[1] == 'T') + c = '>'; + else if (e[0] == 'L' && e[1] == 'P') + c = '('; + else if (e[0] == 'R' && e[1] == 'P') + c = ')'; + else if (e[0] == 'u' && len > 3) + { + escape_len = 3; + + hi_nibble = decode_lower_hex_nibble (e[1]); + if (hi_nibble < 0) + return 0; + lo_nibble = decode_lower_hex_nibble (e[2]); + if (lo_nibble < 0) + return 0; + + /* Only allow non-control ASCII characters. */ + if (hi_nibble > 7) + return 0; + c = (hi_nibble << 4) | lo_nibble; + if (c < 0x20) + return 0; + } + } + + if (!c || len <= escape_len || e[escape_len] != '$') + return 0; + + *out_len = 2 + escape_len; + return c; +} + +static void +print_ident (struct rust_demangler *rdm, struct rust_mangled_ident ident) +{ + char unescaped; + uint8_t *out, *p, d; + size_t len, cap, punycode_pos, j; + /* Punycode parameters and state. */ + uint32_t c; + size_t base, t_min, t_max, skew, damp, bias, i; + size_t delta, w, k, t; + + if (rdm->errored || rdm->skipping_printing) + return; + + if (rdm->version == -1) + { + /* Ignore leading underscores preceding escape sequences. + The mangler inserts an underscore to make sure the + identifier begins with a XID_Start character. */ + if (ident.ascii_len >= 2 && ident.ascii[0] == '_' + && ident.ascii[1] == '$') + { + ident.ascii++; + ident.ascii_len--; + } + + while (ident.ascii_len > 0) + { + /* Handle legacy escape sequences ("$...$", ".." or "."). */ + if (ident.ascii[0] == '$') + { + unescaped + = decode_legacy_escape (ident.ascii, ident.ascii_len, &len); + if (unescaped) + print_str (rdm, &unescaped, 1); + else + { + /* Unexpected escape sequence, print the rest verbatim. */ + print_str (rdm, ident.ascii, ident.ascii_len); + return; + } + } + else if (ident.ascii[0] == '.') + { + if (ident.ascii_len >= 2 && ident.ascii[1] == '.') + { + /* ".." becomes "::" */ + PRINT ("::"); + len = 2; + } + else + { + PRINT ("."); + len = 1; + } + } + else + { + /* Print everything before the next escape sequence, at once. */ + for (len = 0; len < ident.ascii_len; len++) + if (ident.ascii[len] == '$' || ident.ascii[len] == '.') + break; + + print_str (rdm, ident.ascii, len); + } + + ident.ascii += len; + ident.ascii_len -= len; + } + + return; + } + + if (!ident.punycode) + { + print_str (rdm, ident.ascii, ident.ascii_len); + return; + } + + len = 0; + cap = 4; + while (cap < ident.ascii_len) + { + cap *= 2; + /* Check for overflows. */ + if ((cap * 4) / 4 != cap) + { + rdm->errored = 1; + return; + } + } + + /* Store the output codepoints as groups of 4 UTF-8 bytes. */ + out = (uint8_t *)malloc (cap * 4); + if (!out) + { + rdm->errored = 1; + return; + } + + /* Populate initial output from ASCII fragment. */ + for (len = 0; len < ident.ascii_len; len++) + { + p = out + 4 * len; + p[0] = 0; + p[1] = 0; + p[2] = 0; + p[3] = ident.ascii[len]; + } + + /* Punycode parameters and initial state. */ + base = 36; + t_min = 1; + t_max = 26; + skew = 38; + damp = 700; + bias = 72; + i = 0; + c = 0x80; + + punycode_pos = 0; + while (punycode_pos < ident.punycode_len) + { + /* Read one delta value. */ + delta = 0; + w = 1; + k = 0; + do + { + k += base; + t = k < bias ? 0 : (k - bias); + if (t < t_min) + t = t_min; + if (t > t_max) + t = t_max; + + if (punycode_pos >= ident.punycode_len) + goto cleanup; + d = ident.punycode[punycode_pos++]; + + if (ISLOWER (d)) + d = d - 'a'; + else if (ISDIGIT (d)) + d = 26 + (d - '0'); + else + { + rdm->errored = 1; + goto cleanup; + } + + delta += d * w; + w *= base - t; + } + while (d >= t); + + /* Compute the new insert position and character. */ + len++; + i += delta; + c += i / len; + i %= len; + + /* Ensure enough space is available. */ + if (cap < len) + { + cap *= 2; + /* Check for overflows. */ + if ((cap * 4) / 4 != cap || cap < len) + { + rdm->errored = 1; + goto cleanup; + } + } + p = (uint8_t *)realloc (out, cap * 4); + if (!p) + { + rdm->errored = 1; + goto cleanup; + } + out = p; + + /* Move the characters after the insert position. */ + p = out + i * 4; + memmove (p + 4, p, (len - i - 1) * 4); + + /* Insert the new character, as UTF-8 bytes. */ + p[0] = c >= 0x10000 ? 0xf0 | (c >> 18) : 0; + p[1] = c >= 0x800 ? (c < 0x10000 ? 0xe0 : 0x80) | ((c >> 12) & 0x3f) : 0; + p[2] = (c < 0x800 ? 0xc0 : 0x80) | ((c >> 6) & 0x3f); + p[3] = 0x80 | (c & 0x3f); + + /* If there are no more deltas, decoding is complete. */ + if (punycode_pos == ident.punycode_len) + break; + + i++; + + /* Perform bias adaptation. */ + delta /= damp; + damp = 2; + + delta += delta / len; + k = 0; + while (delta > ((base - t_min) * t_max) / 2) + { + delta /= base - t_min; + k += base; + } + bias = k + ((base - t_min + 1) * delta) / (delta + skew); + } + + /* Remove all the 0 bytes to leave behind an UTF-8 string. */ + for (i = 0, j = 0; i < len * 4; i++) + if (out[i] != 0) + out[j++] = out[i]; + + print_str (rdm, (const char *)out, j); + +cleanup: + free (out); +} + +/* Print the lifetime according to the previously decoded index. + An index of `0` always refers to `'_`, but starting with `1`, + indices refer to late-bound lifetimes introduced by a binder. */ +static void +print_lifetime_from_index (struct rust_demangler *rdm, uint64_t lt) +{ + char c; + uint64_t depth; + + PRINT ("'"); + if (lt == 0) + { + PRINT ("_"); + return; + } + + depth = rdm->bound_lifetime_depth - lt; + /* Try to print lifetimes alphabetically first. */ + if (depth < 26) + { + c = 'a' + depth; + print_str (rdm, &c, 1); + } + else + { + /* Use `'_123` after running out of letters. */ + PRINT ("_"); + print_uint64 (rdm, depth); + } +} + +/* Demangling functions. */ + +static void demangle_binder (struct rust_demangler *rdm); +static void demangle_path (struct rust_demangler *rdm, int in_value); +static void demangle_generic_arg (struct rust_demangler *rdm); +static void demangle_type (struct rust_demangler *rdm); +static int demangle_path_maybe_open_generics (struct rust_demangler *rdm); +static void demangle_dyn_trait (struct rust_demangler *rdm); +static void demangle_const (struct rust_demangler *rdm); +static void demangle_const_uint (struct rust_demangler *rdm); +static void demangle_const_int (struct rust_demangler *rdm); +static void demangle_const_bool (struct rust_demangler *rdm); +static void demangle_const_char (struct rust_demangler *rdm); + +/* Optionally enter a binder ('G') for late-bound lifetimes, + printing e.g. `for<'a, 'b> `, and make those lifetimes visible + to the caller (via depth level, which the caller should reset). */ +static void +demangle_binder (struct rust_demangler *rdm) +{ + uint64_t i, bound_lifetimes; + + if (rdm->errored) + return; + + bound_lifetimes = parse_opt_integer_62 (rdm, 'G'); + if (bound_lifetimes > 0) + { + PRINT ("for<"); + for (i = 0; i < bound_lifetimes; i++) + { + if (i > 0) + PRINT (", "); + rdm->bound_lifetime_depth++; + print_lifetime_from_index (rdm, 1); + } + PRINT ("> "); + } +} + +static void +demangle_path (struct rust_demangler *rdm, int in_value) +{ + char tag, ns; + int was_skipping_printing; + size_t i, backref, old_next; + uint64_t dis; + struct rust_mangled_ident name; + + if (rdm->errored) + return; + + if (rdm->recursion != RUST_NO_RECURSION_LIMIT) + { + ++ rdm->recursion; + if (rdm->recursion > RUST_MAX_RECURSION_COUNT) + /* FIXME: There ought to be a way to report + that the recursion limit has been reached. */ + goto fail_return; + } + + switch (tag = next (rdm)) + { + case 'C': + dis = parse_disambiguator (rdm); + name = parse_ident (rdm); + + print_ident (rdm, name); + if (rdm->verbose) + { + PRINT ("["); + print_uint64_hex (rdm, dis); + PRINT ("]"); + } + break; + case 'N': + ns = next (rdm); + if (!ISLOWER (ns) && !ISUPPER (ns)) + goto fail_return; + + demangle_path (rdm, in_value); + + dis = parse_disambiguator (rdm); + name = parse_ident (rdm); + + if (ISUPPER (ns)) + { + /* Special namespaces, like closures and shims. */ + PRINT ("::{"); + switch (ns) + { + case 'C': + PRINT ("closure"); + break; + case 'S': + PRINT ("shim"); + break; + default: + print_str (rdm, &ns, 1); + } + if (name.ascii || name.punycode) + { + PRINT (":"); + print_ident (rdm, name); + } + PRINT ("#"); + print_uint64 (rdm, dis); + PRINT ("}"); + } + else + { + /* Implementation-specific/unspecified namespaces. */ + + if (name.ascii || name.punycode) + { + PRINT ("::"); + print_ident (rdm, name); + } + } + break; + case 'M': + case 'X': + /* Ignore the `impl`'s own path.*/ + parse_disambiguator (rdm); + was_skipping_printing = rdm->skipping_printing; + rdm->skipping_printing = 1; + demangle_path (rdm, in_value); + rdm->skipping_printing = was_skipping_printing; + /* fallthrough */ + case 'Y': + PRINT ("<"); + demangle_type (rdm); + if (tag != 'M') + { + PRINT (" as "); + demangle_path (rdm, 0); + } + PRINT (">"); + break; + case 'I': + demangle_path (rdm, in_value); + if (in_value) + PRINT ("::"); + PRINT ("<"); + for (i = 0; !rdm->errored && !eat (rdm, 'E'); i++) + { + if (i > 0) + PRINT (", "); + demangle_generic_arg (rdm); + } + PRINT (">"); + break; + case 'B': + backref = parse_integer_62 (rdm); + if (!rdm->skipping_printing) + { + old_next = rdm->next; + rdm->next = backref; + demangle_path (rdm, in_value); + rdm->next = old_next; + } + break; + default: + goto fail_return; + } + goto pass_return; + + fail_return: + rdm->errored = 1; + pass_return: + if (rdm->recursion != RUST_NO_RECURSION_LIMIT) + -- rdm->recursion; +} + +static void +demangle_generic_arg (struct rust_demangler *rdm) +{ + uint64_t lt; + if (eat (rdm, 'L')) + { + lt = parse_integer_62 (rdm); + print_lifetime_from_index (rdm, lt); + } + else if (eat (rdm, 'K')) + demangle_const (rdm); + else + demangle_type (rdm); +} + +static const char * +basic_type (char tag) +{ + switch (tag) + { + case 'b': + return "bool"; + case 'c': + return "char"; + case 'e': + return "str"; + case 'u': + return "()"; + case 'a': + return "i8"; + case 's': + return "i16"; + case 'l': + return "i32"; + case 'x': + return "i64"; + case 'n': + return "i128"; + case 'i': + return "isize"; + case 'h': + return "u8"; + case 't': + return "u16"; + case 'm': + return "u32"; + case 'y': + return "u64"; + case 'o': + return "u128"; + case 'j': + return "usize"; + case 'f': + return "f32"; + case 'd': + return "f64"; + case 'z': + return "!"; + case 'p': + return "_"; + case 'v': + return "..."; + + default: + return NULL; + } +} + +static void +demangle_type (struct rust_demangler *rdm) +{ + char tag; + size_t i, old_next, backref; + uint64_t lt, old_bound_lifetime_depth; + const char *basic; + struct rust_mangled_ident abi; + + if (rdm->errored) + return; + + tag = next (rdm); + + basic = basic_type (tag); + if (basic) + { + PRINT (basic); + return; + } + + if (rdm->recursion != RUST_NO_RECURSION_LIMIT) + { + ++ rdm->recursion; + if (rdm->recursion > RUST_MAX_RECURSION_COUNT) + /* FIXME: There ought to be a way to report + that the recursion limit has been reached. */ + { + rdm->errored = 1; + -- rdm->recursion; + return; + } + } + + switch (tag) + { + case 'R': + case 'Q': + PRINT ("&"); + if (eat (rdm, 'L')) + { + lt = parse_integer_62 (rdm); + if (lt) + { + print_lifetime_from_index (rdm, lt); + PRINT (" "); + } + } + if (tag != 'R') + PRINT ("mut "); + demangle_type (rdm); + break; + case 'P': + case 'O': + PRINT ("*"); + if (tag != 'P') + PRINT ("mut "); + else + PRINT ("const "); + demangle_type (rdm); + break; + case 'A': + case 'S': + PRINT ("["); + demangle_type (rdm); + if (tag == 'A') + { + PRINT ("; "); + demangle_const (rdm); + } + PRINT ("]"); + break; + case 'T': + PRINT ("("); + for (i = 0; !rdm->errored && !eat (rdm, 'E'); i++) + { + if (i > 0) + PRINT (", "); + demangle_type (rdm); + } + if (i == 1) + PRINT (","); + PRINT (")"); + break; + case 'F': + old_bound_lifetime_depth = rdm->bound_lifetime_depth; + demangle_binder (rdm); + + if (eat (rdm, 'U')) + PRINT ("unsafe "); + + if (eat (rdm, 'K')) + { + if (eat (rdm, 'C')) + { + abi.ascii = "C"; + abi.ascii_len = 1; + } + else + { + abi = parse_ident (rdm); + if (!abi.ascii || abi.punycode) + { + rdm->errored = 1; + goto restore; + } + } + + PRINT ("extern \""); + + /* If the ABI had any `-`, they were replaced with `_`, + so the parts between `_` have to be re-joined with `-`. */ + for (i = 0; i < abi.ascii_len; i++) + { + if (abi.ascii[i] == '_') + { + print_str (rdm, abi.ascii, i); + PRINT ("-"); + abi.ascii += i + 1; + abi.ascii_len -= i + 1; + i = 0; + } + } + print_str (rdm, abi.ascii, abi.ascii_len); + + PRINT ("\" "); + } + + PRINT ("fn("); + for (i = 0; !rdm->errored && !eat (rdm, 'E'); i++) + { + if (i > 0) + PRINT (", "); + demangle_type (rdm); + } + PRINT (")"); + + if (eat (rdm, 'u')) + { + /* Skip printing the return type if it's 'u', i.e. `()`. */ + } + else + { + PRINT (" -> "); + demangle_type (rdm); + } + + /* Restore `bound_lifetime_depth` to outside the binder. */ + restore: + rdm->bound_lifetime_depth = old_bound_lifetime_depth; + break; + case 'D': + PRINT ("dyn "); + + old_bound_lifetime_depth = rdm->bound_lifetime_depth; + demangle_binder (rdm); + + for (i = 0; !rdm->errored && !eat (rdm, 'E'); i++) + { + if (i > 0) + PRINT (" + "); + demangle_dyn_trait (rdm); + } + + /* Restore `bound_lifetime_depth` to outside the binder. */ + rdm->bound_lifetime_depth = old_bound_lifetime_depth; + + if (!eat (rdm, 'L')) + { + rdm->errored = 1; + return; + } + lt = parse_integer_62 (rdm); + if (lt) + { + PRINT (" + "); + print_lifetime_from_index (rdm, lt); + } + break; + case 'B': + backref = parse_integer_62 (rdm); + if (!rdm->skipping_printing) + { + old_next = rdm->next; + rdm->next = backref; + demangle_type (rdm); + rdm->next = old_next; + } + break; + default: + /* Go back to the tag, so `demangle_path` also sees it. */ + rdm->next--; + demangle_path (rdm, 0); + } + + if (rdm->recursion != RUST_NO_RECURSION_LIMIT) + -- rdm->recursion; +} + +/* A trait in a trait object may have some "existential projections" + (i.e. associated type bindings) after it, which should be printed + in the `<...>` of the trait, e.g. `dyn Trait`. + To this end, this method will keep the `<...>` of an 'I' path + open, by omitting the `>`, and return `Ok(true)` in that case. */ +static int +demangle_path_maybe_open_generics (struct rust_demangler *rdm) +{ + int open; + size_t i, old_next, backref; + + open = 0; + + if (rdm->errored) + return open; + + if (rdm->recursion != RUST_NO_RECURSION_LIMIT) + { + ++ rdm->recursion; + if (rdm->recursion > RUST_MAX_RECURSION_COUNT) + { + /* FIXME: There ought to be a way to report + that the recursion limit has been reached. */ + rdm->errored = 1; + goto end_of_func; + } + } + + if (eat (rdm, 'B')) + { + backref = parse_integer_62 (rdm); + if (!rdm->skipping_printing) + { + old_next = rdm->next; + rdm->next = backref; + open = demangle_path_maybe_open_generics (rdm); + rdm->next = old_next; + } + } + else if (eat (rdm, 'I')) + { + demangle_path (rdm, 0); + PRINT ("<"); + open = 1; + for (i = 0; !rdm->errored && !eat (rdm, 'E'); i++) + { + if (i > 0) + PRINT (", "); + demangle_generic_arg (rdm); + } + } + else + demangle_path (rdm, 0); + + end_of_func: + if (rdm->recursion != RUST_NO_RECURSION_LIMIT) + -- rdm->recursion; + + return open; +} + +static void +demangle_dyn_trait (struct rust_demangler *rdm) +{ + int open; + struct rust_mangled_ident name; + + if (rdm->errored) + return; + + open = demangle_path_maybe_open_generics (rdm); + + while (eat (rdm, 'p')) + { + if (!open) + PRINT ("<"); + else + PRINT (", "); + open = 1; + + name = parse_ident (rdm); + print_ident (rdm, name); + PRINT (" = "); + demangle_type (rdm); + } + + if (open) + PRINT (">"); +} + +static void +demangle_const (struct rust_demangler *rdm) +{ + char ty_tag; + size_t old_next, backref; + + if (rdm->errored) + return; + + if (rdm->recursion != RUST_NO_RECURSION_LIMIT) + { + ++ rdm->recursion; + if (rdm->recursion > RUST_MAX_RECURSION_COUNT) + /* FIXME: There ought to be a way to report + that the recursion limit has been reached. */ + goto fail_return; + } + + if (eat (rdm, 'B')) + { + backref = parse_integer_62 (rdm); + if (!rdm->skipping_printing) + { + old_next = rdm->next; + rdm->next = backref; + demangle_const (rdm); + rdm->next = old_next; + } + goto pass_return; + } + + ty_tag = next (rdm); + switch (ty_tag) + { + /* Placeholder. */ + case 'p': + PRINT ("_"); + goto pass_return; + + /* Unsigned integer types. */ + case 'h': + case 't': + case 'm': + case 'y': + case 'o': + case 'j': + demangle_const_uint (rdm); + break; + + /* Signed integer types. */ + case 'a': + case 's': + case 'l': + case 'x': + case 'n': + case 'i': + demangle_const_int (rdm); + break; + + /* Boolean. */ + case 'b': + demangle_const_bool (rdm); + break; + + /* Character. */ + case 'c': + demangle_const_char (rdm); + break; + + default: + goto fail_return; + } + + if (!rdm->errored && rdm->verbose) + { + PRINT (": "); + PRINT (basic_type (ty_tag)); + } + goto pass_return; + + fail_return: + rdm->errored = 1; + pass_return: + if (rdm->recursion != RUST_NO_RECURSION_LIMIT) + -- rdm->recursion; +} + +static void +demangle_const_uint (struct rust_demangler *rdm) +{ + size_t hex_len; + uint64_t value; + + if (rdm->errored) + return; + + hex_len = parse_hex_nibbles (rdm, &value); + + if (hex_len > 16) + { + /* Print anything that doesn't fit in `uint64_t` verbatim. */ + PRINT ("0x"); + print_str (rdm, rdm->sym + (rdm->next - hex_len), hex_len); + } + else if (hex_len > 0) + print_uint64 (rdm, value); + else + rdm->errored = 1; +} + +static void +demangle_const_int (struct rust_demangler *rdm) +{ + if (eat (rdm, 'n')) + PRINT ("-"); + demangle_const_uint (rdm); +} + +static void +demangle_const_bool (struct rust_demangler *rdm) +{ + uint64_t value; + + if (parse_hex_nibbles (rdm, &value) != 1) + { + rdm->errored = 1; + return; + } + + if (value == 0) + PRINT ("false"); + else if (value == 1) + PRINT ("true"); + else + rdm->errored = 1; +} + +static void +demangle_const_char (struct rust_demangler *rdm) +{ + size_t hex_len; + uint64_t value; + + hex_len = parse_hex_nibbles (rdm, &value); + + if (hex_len == 0 || hex_len > 8) + { + rdm->errored = 1; + return; + } + + /* Match Rust's character "debug" output as best as we can. */ + PRINT ("'"); + if (value == '\t') + PRINT ("\\t"); + else if (value == '\r') + PRINT ("\\r"); + else if (value == '\n') + PRINT ("\\n"); + else if (value > ' ' && value < '~') + { + /* Rust also considers many non-ASCII codepoints to be printable, but + that logic is not easily ported to C. */ + char c = value; + print_str (rdm, &c, 1); + } + else + { + PRINT ("\\u{"); + print_uint64_hex (rdm, value); + PRINT ("}"); + } + PRINT ("'"); +} + +/* A legacy hash is the prefix "h" followed by 16 lowercase hex digits. + The hex digits must contain at least 5 distinct digits. */ +static int +is_legacy_prefixed_hash (struct rust_mangled_ident ident) +{ + uint16_t seen; + int nibble; + size_t i, count; + + if (ident.ascii_len != 17 || ident.ascii[0] != 'h') + return 0; + + seen = 0; + for (i = 0; i < 16; i++) + { + nibble = decode_lower_hex_nibble (ident.ascii[1 + i]); + if (nibble < 0) + return 0; + seen |= (uint16_t)1 << nibble; + } + + /* Count how many distinct digits were seen. */ + count = 0; + while (seen) + { + if (seen & 1) + count++; + seen >>= 1; + } + + return count >= 5; +} + +int +rust_demangle_callback (const char *mangled, int options, + demangle_callbackref callback, void *opaque) +{ + const char *p; + struct rust_demangler rdm; + struct rust_mangled_ident ident; + + rdm.sym = mangled; + rdm.sym_len = 0; + + rdm.callback_opaque = opaque; + rdm.callback = callback; + + rdm.next = 0; + rdm.errored = 0; + rdm.skipping_printing = 0; + rdm.verbose = (options & DMGL_VERBOSE) != 0; + rdm.version = 0; + rdm.recursion = (options & DMGL_NO_RECURSE_LIMIT) ? RUST_NO_RECURSION_LIMIT : 0; + rdm.bound_lifetime_depth = 0; + + /* Rust symbols always start with _R (v0) or _ZN (legacy). */ + if (rdm.sym[0] == '_' && rdm.sym[1] == 'R') + rdm.sym += 2; + else if (rdm.sym[0] == '_' && rdm.sym[1] == 'Z' && rdm.sym[2] == 'N') + { + rdm.sym += 3; + rdm.version = -1; + } + else + return 0; + + /* Paths (v0) always start with uppercase characters. */ + if (rdm.version != -1 && !ISUPPER (rdm.sym[0])) + return 0; + + /* Rust symbols (v0) use only [_0-9a-zA-Z] characters. */ + for (p = rdm.sym; *p; p++) + { + /* Rust v0 symbols can have '.' suffixes, ignore those. */ + if (rdm.version == 0 && *p == '.') + break; + + rdm.sym_len++; + + if (*p == '_' || ISALNUM (*p)) + continue; + + /* Legacy Rust symbols can also contain [.:$] characters. + Or @ in the .suffix (which will be skipped, see below). */ + if (rdm.version == -1 && (*p == '$' || *p == '.' || *p == ':' + || *p == '@')) + continue; + + return 0; + } + + /* Legacy Rust symbols need to be handled separately. */ + if (rdm.version == -1) + { + /* Legacy Rust symbols always end with E. But can be followed by a + .suffix (which we want to ignore). */ + int dot_suffix = 1; + while (rdm.sym_len > 0 && + !(dot_suffix && rdm.sym[rdm.sym_len - 1] == 'E')) + { + dot_suffix = rdm.sym[rdm.sym_len - 1] == '.'; + rdm.sym_len--; + } + + if (!(rdm.sym_len > 0 && rdm.sym[rdm.sym_len - 1] == 'E')) + return 0; + rdm.sym_len--; + + /* Legacy Rust symbols also always end with a path segment + that encodes a 16 hex digit hash, i.e. '17h[a-f0-9]{16}'. + This early check, before any parse_ident calls, should + quickly filter out most C++ symbols unrelated to Rust. */ + if (!(rdm.sym_len > 19 + && !memcmp (&rdm.sym[rdm.sym_len - 19], "17h", 3))) + return 0; + + do + { + ident = parse_ident (&rdm); + if (rdm.errored || !ident.ascii) + return 0; + } + while (rdm.next < rdm.sym_len); + + /* The last path segment should be the hash. */ + if (!is_legacy_prefixed_hash (ident)) + return 0; + + /* Reset the state for a second pass, to print the symbol. */ + rdm.next = 0; + if (!rdm.verbose && rdm.sym_len > 19) + { + /* Hide the last segment, containing the hash, if not verbose. */ + rdm.sym_len -= 19; + } + + do + { + if (rdm.next > 0) + print_str (&rdm, "::", 2); + + ident = parse_ident (&rdm); + print_ident (&rdm, ident); + } + while (rdm.next < rdm.sym_len); + } + else + { + demangle_path (&rdm, 1); + + /* Skip instantiating crate. */ + if (!rdm.errored && rdm.next < rdm.sym_len) + { + rdm.skipping_printing = 1; + demangle_path (&rdm, 0); + } + + /* It's an error to not reach the end. */ + rdm.errored |= rdm.next != rdm.sym_len; + } + + return !rdm.errored; +} + +/* Growable string buffers. */ +struct str_buf +{ + char *ptr; + size_t len; + size_t cap; + int errored; +}; + +static void +str_buf_reserve (struct str_buf *buf, size_t extra) +{ + size_t available, min_new_cap, new_cap; + char *new_ptr; + + /* Allocation failed before. */ + if (buf->errored) + return; + + available = buf->cap - buf->len; + + if (extra <= available) + return; + + min_new_cap = buf->cap + (extra - available); + + /* Check for overflows. */ + if (min_new_cap < buf->cap) + { + buf->errored = 1; + return; + } + + new_cap = buf->cap; + + if (new_cap == 0) + new_cap = 4; + + /* Double capacity until sufficiently large. */ + while (new_cap < min_new_cap) + { + new_cap *= 2; + + /* Check for overflows. */ + if (new_cap < buf->cap) + { + buf->errored = 1; + return; + } + } + + new_ptr = (char *)realloc (buf->ptr, new_cap); + if (new_ptr == NULL) + { + free (buf->ptr); + buf->ptr = NULL; + buf->len = 0; + buf->cap = 0; + buf->errored = 1; + } + else + { + buf->ptr = new_ptr; + buf->cap = new_cap; + } +} + +static void +str_buf_append (struct str_buf *buf, const char *data, size_t len) +{ + str_buf_reserve (buf, len); + if (buf->errored) + return; + + memcpy (buf->ptr + buf->len, data, len); + buf->len += len; +} + +static void +str_buf_demangle_callback (const char *data, size_t len, void *opaque) +{ + str_buf_append ((struct str_buf *)opaque, data, len); +} + +char * +rust_demangle (const char *mangled, int options) +{ + struct str_buf out; + int success; + + out.ptr = NULL; + out.len = 0; + out.cap = 0; + out.errored = 0; + + success = rust_demangle_callback (mangled, options, + str_buf_demangle_callback, &out); + + if (!success) + { + free (out.ptr); + return NULL; + } + + str_buf_append (&out, "\0", 1); + return out.ptr; +} diff --git a/3rdparty/demangler/src/safe-ctype.c b/3rdparty/demangler/src/safe-ctype.c new file mode 100644 index 0000000000..483b41e94b --- /dev/null +++ b/3rdparty/demangler/src/safe-ctype.c @@ -0,0 +1,254 @@ +/* replacement macros. + + Copyright (C) 2000-2023 Free Software Foundation, Inc. + Contributed by Zack Weinberg . + +This file is part of the libiberty library. +Libiberty 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. + +Libiberty is distributed in the hope that 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 libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* + +@defvr Extension HOST_CHARSET +This macro indicates the basic character set and encoding used by the +host: more precisely, the encoding used for character constants in +preprocessor @samp{#if} statements (the C "execution character set"). +It is defined by @file{safe-ctype.h}, and will be an integer constant +with one of the following values: + +@ftable @code +@item HOST_CHARSET_UNKNOWN +The host character set is unknown - that is, not one of the next two +possibilities. + +@item HOST_CHARSET_ASCII +The host character set is ASCII. + +@item HOST_CHARSET_EBCDIC +The host character set is some variant of EBCDIC. (Only one of the +nineteen EBCDIC varying characters is tested; exercise caution.) +@end ftable +@end defvr + +@deffn Extension ISALPHA (@var{c}) +@deffnx Extension ISALNUM (@var{c}) +@deffnx Extension ISBLANK (@var{c}) +@deffnx Extension ISCNTRL (@var{c}) +@deffnx Extension ISDIGIT (@var{c}) +@deffnx Extension ISGRAPH (@var{c}) +@deffnx Extension ISLOWER (@var{c}) +@deffnx Extension ISPRINT (@var{c}) +@deffnx Extension ISPUNCT (@var{c}) +@deffnx Extension ISSPACE (@var{c}) +@deffnx Extension ISUPPER (@var{c}) +@deffnx Extension ISXDIGIT (@var{c}) + +These twelve macros are defined by @file{safe-ctype.h}. Each has the +same meaning as the corresponding macro (with name in lowercase) +defined by the standard header @file{ctype.h}. For example, +@code{ISALPHA} returns true for alphabetic characters and false for +others. However, there are two differences between these macros and +those provided by @file{ctype.h}: + +@itemize @bullet +@item These macros are guaranteed to have well-defined behavior for all +values representable by @code{signed char} and @code{unsigned char}, and +for @code{EOF}. + +@item These macros ignore the current locale; they are true for these +fixed sets of characters: +@multitable {@code{XDIGIT}} {yada yada yada yada yada yada yada yada} +@item @code{ALPHA} @tab @kbd{A-Za-z} +@item @code{ALNUM} @tab @kbd{A-Za-z0-9} +@item @code{BLANK} @tab @kbd{space tab} +@item @code{CNTRL} @tab @code{!PRINT} +@item @code{DIGIT} @tab @kbd{0-9} +@item @code{GRAPH} @tab @code{ALNUM || PUNCT} +@item @code{LOWER} @tab @kbd{a-z} +@item @code{PRINT} @tab @code{GRAPH ||} @kbd{space} +@item @code{PUNCT} @tab @kbd{`~!@@#$%^&*()_-=+[@{]@}\|;:'",<.>/?} +@item @code{SPACE} @tab @kbd{space tab \n \r \f \v} +@item @code{UPPER} @tab @kbd{A-Z} +@item @code{XDIGIT} @tab @kbd{0-9A-Fa-f} +@end multitable + +Note that, if the host character set is ASCII or a superset thereof, +all these macros will return false for all values of @code{char} outside +the range of 7-bit ASCII. In particular, both ISPRINT and ISCNTRL return +false for characters with numeric values from 128 to 255. +@end itemize +@end deffn + +@deffn Extension ISIDNUM (@var{c}) +@deffnx Extension ISIDST (@var{c}) +@deffnx Extension IS_VSPACE (@var{c}) +@deffnx Extension IS_NVSPACE (@var{c}) +@deffnx Extension IS_SPACE_OR_NUL (@var{c}) +@deffnx Extension IS_ISOBASIC (@var{c}) +These six macros are defined by @file{safe-ctype.h} and provide +additional character classes which are useful when doing lexical +analysis of C or similar languages. They are true for the following +sets of characters: + +@multitable {@code{SPACE_OR_NUL}} {yada yada yada yada yada yada yada yada} +@item @code{IDNUM} @tab @kbd{A-Za-z0-9_} +@item @code{IDST} @tab @kbd{A-Za-z_} +@item @code{VSPACE} @tab @kbd{\r \n} +@item @code{NVSPACE} @tab @kbd{space tab \f \v \0} +@item @code{SPACE_OR_NUL} @tab @code{VSPACE || NVSPACE} +@item @code{ISOBASIC} @tab @code{VSPACE || NVSPACE || PRINT} +@end multitable +@end deffn + +*/ + +#include "ansidecl.h" +#include +#include /* for EOF */ + +#if EOF != -1 + #error " requires EOF == -1" +#endif + +/* Shorthand */ +#define bl _sch_isblank +#define cn _sch_iscntrl +#define di _sch_isdigit +#define is _sch_isidst +#define lo _sch_islower +#define nv _sch_isnvsp +#define pn _sch_ispunct +#define pr _sch_isprint +#define sp _sch_isspace +#define up _sch_isupper +#define vs _sch_isvsp +#define xd _sch_isxdigit + +/* Masks. */ +#define L (const unsigned short) (lo|is |pr) /* lower case letter */ +#define XL (const unsigned short) (lo|is|xd|pr) /* lowercase hex digit */ +#define U (const unsigned short) (up|is |pr) /* upper case letter */ +#define XU (const unsigned short) (up|is|xd|pr) /* uppercase hex digit */ +#define D (const unsigned short) (di |xd|pr) /* decimal digit */ +#define P (const unsigned short) (pn |pr) /* punctuation */ +#define _ (const unsigned short) (pn|is |pr) /* underscore */ + +#define C (const unsigned short) ( cn) /* control character */ +#define Z (const unsigned short) (nv |cn) /* NUL */ +#define M (const unsigned short) (nv|sp |cn) /* cursor movement: \f \v */ +#define V (const unsigned short) (vs|sp |cn) /* vertical space: \r \n */ +#define T (const unsigned short) (nv|sp|bl|cn) /* tab */ +#define S (const unsigned short) (nv|sp|bl|pr) /* space */ + +/* Are we ASCII? */ +#if HOST_CHARSET == HOST_CHARSET_ASCII + +const unsigned short _sch_istable[256] = +{ + Z, C, C, C, C, C, C, C, /* NUL SOH STX ETX EOT ENQ ACK BEL */ + C, T, V, M, M, V, C, C, /* BS HT LF VT FF CR SO SI */ + C, C, C, C, C, C, C, C, /* DLE DC1 DC2 DC3 DC4 NAK SYN ETB */ + C, C, C, C, C, C, C, C, /* CAN EM SUB ESC FS GS RS US */ + S, P, P, P, P, P, P, P, /* SP ! " # $ % & ' */ + P, P, P, P, P, P, P, P, /* ( ) * + , - . / */ + D, D, D, D, D, D, D, D, /* 0 1 2 3 4 5 6 7 */ + D, D, P, P, P, P, P, P, /* 8 9 : ; < = > ? */ + P, XU, XU, XU, XU, XU, XU, U, /* @ A B C D E F G */ + U, U, U, U, U, U, U, U, /* H I J K L M N O */ + U, U, U, U, U, U, U, U, /* P Q R S T U V W */ + U, U, U, P, P, P, P, _, /* X Y Z [ \ ] ^ _ */ + P, XL, XL, XL, XL, XL, XL, L, /* ` a b c d e f g */ + L, L, L, L, L, L, L, L, /* h i j k l m n o */ + L, L, L, L, L, L, L, L, /* p q r s t u v w */ + L, L, L, P, P, P, P, C, /* x y z { | } ~ DEL */ + + /* high half of unsigned char is locale-specific, so all tests are + false in "C" locale */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +const unsigned char _sch_tolower[256] = +{ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, + + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + + 91, 92, 93, 94, 95, 96, + + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + + 123,124,125,126,127, + + 128,129,130,131, 132,133,134,135, 136,137,138,139, 140,141,142,143, + 144,145,146,147, 148,149,150,151, 152,153,154,155, 156,157,158,159, + 160,161,162,163, 164,165,166,167, 168,169,170,171, 172,173,174,175, + 176,177,178,179, 180,181,182,183, 184,185,186,187, 188,189,190,191, + + 192,193,194,195, 196,197,198,199, 200,201,202,203, 204,205,206,207, + 208,209,210,211, 212,213,214,215, 216,217,218,219, 220,221,222,223, + 224,225,226,227, 228,229,230,231, 232,233,234,235, 236,237,238,239, + 240,241,242,243, 244,245,246,247, 248,249,250,251, 252,253,254,255, +}; + +const unsigned char _sch_toupper[256] = +{ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, + + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + + 91, 92, 93, 94, 95, 96, + + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + + 123,124,125,126,127, + + 128,129,130,131, 132,133,134,135, 136,137,138,139, 140,141,142,143, + 144,145,146,147, 148,149,150,151, 152,153,154,155, 156,157,158,159, + 160,161,162,163, 164,165,166,167, 168,169,170,171, 172,173,174,175, + 176,177,178,179, 180,181,182,183, 184,185,186,187, 188,189,190,191, + + 192,193,194,195, 196,197,198,199, 200,201,202,203, 204,205,206,207, + 208,209,210,211, 212,213,214,215, 216,217,218,219, 220,221,222,223, + 224,225,226,227, 228,229,230,231, 232,233,234,235, 236,237,238,239, + 240,241,242,243, 244,245,246,247, 248,249,250,251, 252,253,254,255, +}; + +#else +# if HOST_CHARSET == HOST_CHARSET_EBCDIC + #error "FIXME: write tables for EBCDIC" +# else + #error "Unrecognized host character set" +# endif +#endif diff --git a/3rdparty/demangler/src/xexit.c b/3rdparty/demangler/src/xexit.c new file mode 100644 index 0000000000..03b69fdf21 --- /dev/null +++ b/3rdparty/demangler/src/xexit.c @@ -0,0 +1,52 @@ +/* xexit.c -- Run any exit handlers, then exit. + Copyright (C) 1994-2023 Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty 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. + +Libiberty is distributed in the hope that 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 libiberty; see the file COPYING.LIB. If not, write +to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* + +@deftypefn Replacement void xexit (int @var{code}) + +Terminates the program. If any functions have been registered with +the @code{xatexit} replacement function, they will be called first. +Termination is handled via the system's normal @code{exit} call. + +@end deftypefn + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#include "libiberty.h" + + +/* This variable is set by xatexit if it is called. This way, xmalloc + doesn't drag xatexit into the link. */ +void (*_xexit_cleanup) (void); + +void +xexit (int code) +{ + if (_xexit_cleanup != NULL) + (*_xexit_cleanup) (); + exit (code); +} diff --git a/3rdparty/demangler/src/xmalloc.c b/3rdparty/demangler/src/xmalloc.c new file mode 100644 index 0000000000..c30b8966ad --- /dev/null +++ b/3rdparty/demangler/src/xmalloc.c @@ -0,0 +1,186 @@ +/* memory allocation routines with error checking. + Copyright (C) 1989-2023 Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty 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. + +Libiberty is distributed in the hope that 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 libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* + +@deftypefn Replacement void* xmalloc (size_t) + +Allocate memory without fail. If @code{malloc} fails, this will print +a message to @code{stderr} (using the name set by +@code{xmalloc_set_program_name}, +if any) and then call @code{xexit}. Note that it is therefore safe for +a program to contain @code{#define malloc xmalloc} in its source. + +@end deftypefn + +@deftypefn Replacement void* xrealloc (void *@var{ptr}, size_t @var{size}) +Reallocate memory without fail. This routine functions like @code{realloc}, +but will behave the same as @code{xmalloc} if memory cannot be found. + +@end deftypefn + +@deftypefn Replacement void* xcalloc (size_t @var{nelem}, size_t @var{elsize}) + +Allocate memory without fail, and set it to zero. This routine functions +like @code{calloc}, but will behave the same as @code{xmalloc} if memory +cannot be found. + +@end deftypefn + +@deftypefn Replacement void xmalloc_set_program_name (const char *@var{name}) + +You can use this to set the name of the program used by +@code{xmalloc_failed} when printing a failure message. + +@end deftypefn + +@deftypefn Replacement void xmalloc_failed (size_t) + +This function is not meant to be called by client code, and is listed +here for completeness only. If any of the allocation routines fail, this +function will be called to print an error message and terminate execution. + +@end deftypefn + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "ansidecl.h" +#include "libiberty.h" +#include "environ.h" + +#include + +#include + +#if VMS +#include +#include +#else +/* For systems with larger pointers than ints, these must be declared. */ +# if HAVE_STDLIB_H && HAVE_UNISTD_H && HAVE_DECL_MALLOC \ + && HAVE_DECL_REALLOC && HAVE_DECL_CALLOC && HAVE_DECL_SBRK +# include +# include +# else +# ifdef __cplusplus +extern "C" { +# endif /* __cplusplus */ +void *malloc (size_t); +void *realloc (void *, size_t); +void *calloc (size_t, size_t); +#ifdef HAVE_SBRK +void *sbrk (ptrdiff_t); +#endif +# ifdef __cplusplus +} +# endif /* __cplusplus */ +# endif /* HAVE_STDLIB_H ... */ +#endif /* VMS */ + +/* The program name if set. */ +static const char *name = ""; + +#ifdef HAVE_SBRK +/* The initial sbrk, set when the program name is set. Not used for win32 + ports other than cygwin32. */ +static char *first_break = NULL; +#endif /* HAVE_SBRK */ + +void +xmalloc_set_program_name (const char *s) +{ + name = s; +#ifdef HAVE_SBRK + /* Win32 ports other than cygwin32 don't have brk() */ + if (first_break == NULL) + first_break = (char *) sbrk (0); +#endif /* HAVE_SBRK */ +} + +void +xmalloc_failed (size_t size) +{ +#ifdef HAVE_SBRK + size_t allocated; + + if (first_break != NULL) + allocated = (char *) sbrk (0) - first_break; + else + allocated = (char *) sbrk (0) - (char *) &environ; + fprintf (stderr, + "\n%s%sout of memory allocating %lu bytes after a total of %lu bytes\n", + name, *name ? ": " : "", + (unsigned long) size, (unsigned long) allocated); +#else /* HAVE_SBRK */ + fprintf (stderr, + "\n%s%sout of memory allocating %lu bytes\n", + name, *name ? ": " : "", + (unsigned long) size); +#endif /* HAVE_SBRK */ + xexit (1); +} + +void * +xmalloc (size_t size) +{ + void *newmem; + + if (size == 0) + size = 1; + newmem = malloc (size); + if (!newmem) + xmalloc_failed (size); + + return (newmem); +} + +void * +xcalloc (size_t nelem, size_t elsize) +{ + void *newmem; + + if (nelem == 0 || elsize == 0) + nelem = elsize = 1; + + newmem = calloc (nelem, elsize); + if (!newmem) + xmalloc_failed (nelem * elsize); + + return (newmem); +} + +void * +xrealloc (void *oldmem, size_t size) +{ + void *newmem; + + if (size == 0) + size = 1; + if (!oldmem) + newmem = malloc (size); + else + newmem = realloc (oldmem, size); + if (!newmem) + xmalloc_failed (size); + + return (newmem); +} diff --git a/3rdparty/demangler/src/xmemdup.c b/3rdparty/demangler/src/xmemdup.c new file mode 100644 index 0000000000..f2ed41f9b4 --- /dev/null +++ b/3rdparty/demangler/src/xmemdup.c @@ -0,0 +1,41 @@ +/* xmemdup.c -- Duplicate a memory buffer, using xmalloc. + This trivial function is in the public domain. + Jeff Garzik, September 1999. */ + +/* + +@deftypefn Replacement void* xmemdup (void *@var{input}, @ + size_t @var{copy_size}, size_t @var{alloc_size}) + +Duplicates a region of memory without fail. First, @var{alloc_size} bytes +are allocated, then @var{copy_size} bytes from @var{input} are copied into +it, and the new memory is returned. If fewer bytes are copied than were +allocated, the remaining memory is zeroed. + +@end deftypefn + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "ansidecl.h" +#include "libiberty.h" + +#include /* For size_t. */ +#ifdef HAVE_STRING_H +#include +#else +# ifdef HAVE_STRINGS_H +# include +# endif +#endif + +void * +xmemdup (const void *input, size_t copy_size, size_t alloc_size) +{ + void *output = xmalloc (alloc_size); + if (alloc_size > copy_size) + memset ((char *) output + copy_size, 0, alloc_size - copy_size); + return (void *) memcpy (output, input, copy_size); +} diff --git a/3rdparty/demangler/src/xstrdup.c b/3rdparty/demangler/src/xstrdup.c new file mode 100644 index 0000000000..fa12c96a3c --- /dev/null +++ b/3rdparty/demangler/src/xstrdup.c @@ -0,0 +1,36 @@ +/* xstrdup.c -- Duplicate a string in memory, using xmalloc. + This trivial function is in the public domain. + Ian Lance Taylor, Cygnus Support, December 1995. */ + +/* + +@deftypefn Replacement char* xstrdup (const char *@var{s}) + +Duplicates a character string without fail, using @code{xmalloc} to +obtain memory. + +@end deftypefn + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#ifdef HAVE_STRING_H +#include +#else +# ifdef HAVE_STRINGS_H +# include +# endif +#endif +#include "ansidecl.h" +#include "libiberty.h" + +char * +xstrdup (const char *s) +{ + register size_t len = strlen (s) + 1; + register char *ret = XNEWVEC (char, len); + return (char *) memcpy (ret, s, len); +} diff --git a/3rdparty/demangler/testsuite/demangle-expected b/3rdparty/demangler/testsuite/demangle-expected new file mode 100644 index 0000000000..16a819d261 --- /dev/null +++ b/3rdparty/demangler/testsuite/demangle-expected @@ -0,0 +1,5048 @@ +# This file holds test cases for the demangler. +# Each test case looks like this: +# options +# input to be demangled +# expected output +# +# Supported options: +# --format= Sets the demangling style. +# --no-params There are two lines of expected output; the first +# is with DMGL_PARAMS, the second is without it. +# --is-v3-ctor Calls is_gnu_v3_mangled_ctor on input; expected +# output is an integer representing ctor_kind. +# --is-v3-dtor Likewise, but for dtors. +# --ret-postfix Passes the DMGL_RET_POSTFIX option +# +# For compatibility, just in case it matters, the options line may be +# empty, to mean --format=auto. If it doesn't start with --, then it +# may contain only a format name. +# +# A line starting with `#' is ignored. +# However, blank lines in this file are NOT ignored. +# +--format=gnu --no-params +AddAlignment__9ivTSolverUiP12ivInteractorP7ivTGlue +ivTSolver::AddAlignment(unsigned int, ivInteractor *, ivTGlue *) +ivTSolver::AddAlignment +# +--format=gnu --no-params +ArrowheadIntersects__9ArrowLineP9ArrowheadR6BoxObjP7Graphic +ArrowLine::ArrowheadIntersects(Arrowhead *, BoxObj &, Graphic *) +ArrowLine::ArrowheadIntersects +# +--format=gnu --no-params +ArrowheadIntersects__9ArrowLineP9ArrowheadO6BoxObjP7Graphic +ArrowLine::ArrowheadIntersects(Arrowhead *, BoxObj &&, Graphic *) +ArrowLine::ArrowheadIntersects +# +--format=gnu --no-params +AtEnd__13ivRubberGroup +ivRubberGroup::AtEnd(void) +ivRubberGroup::AtEnd +# +--format=gnu --no-params +BgFilter__9ivTSolverP12ivInteractor +ivTSolver::BgFilter(ivInteractor *) +ivTSolver::BgFilter +# +--format=gnu --no-params +Check__6UArrayi +UArray::Check(int) +UArray::Check +# +--format=gnu --no-params +CoreConstDecls__8TextCodeR7ostream +TextCode::CoreConstDecls(ostream &) +TextCode::CoreConstDecls +# +--format=gnu --no-params +CoreConstDecls__8TextCodeO7ostream +TextCode::CoreConstDecls(ostream &&) +TextCode::CoreConstDecls +# +--format=gnu --no-params +Detach__8StateVarP12StateVarView +StateVar::Detach(StateVarView *) +StateVar::Detach +# +--format=gnu --no-params +Done__9ComponentG8Iterator +Component::Done(Iterator) +Component::Done +# +--format=gnu --no-params +Effect__11RelateManipR7ivEvent +RelateManip::Effect(ivEvent &) +RelateManip::Effect +# +--format=gnu --no-params +Effect__11RelateManipO7ivEvent +RelateManip::Effect(ivEvent &&) +RelateManip::Effect +# +--format=gnu --no-params +FindFixed__FRP4CNetP4CNet +FindFixed(CNet *&, CNet *) +FindFixed +# +--format=gnu --no-params +FindFixed__FOP4CNetP4CNet +FindFixed(CNet *&&, CNet *) +FindFixed +# +--format=gnu --no-params +Fix48_abort__FR8twolongs +Fix48_abort(twolongs &) +Fix48_abort +# +--format=gnu --no-params +Fix48_abort__FO8twolongs +Fix48_abort(twolongs &&) +Fix48_abort +# +--format=gnu --no-params +GetBarInfo__15iv2_6_VScrollerP13ivPerspectiveRiT2 +iv2_6_VScroller::GetBarInfo(ivPerspective *, int &, int &) +iv2_6_VScroller::GetBarInfo +# +--format=gnu --no-params +GetBarInfo__15iv2_6_VScrollerP13ivPerspectiveOiT2 +iv2_6_VScroller::GetBarInfo(ivPerspective *, int &&, int &&) +iv2_6_VScroller::GetBarInfo +# +--format=gnu --no-params +GetBgColor__C9ivPainter +ivPainter::GetBgColor(void) const +ivPainter::GetBgColor +# +--format=gnu --no-params +InsertBody__15H_PullrightMenuii +H_PullrightMenu::InsertBody(int, int) +H_PullrightMenu::InsertBody +# +--format=gnu --no-params +InsertCharacter__9TextManipc +TextManip::InsertCharacter(char) +TextManip::InsertCharacter +# +--format=gnu --no-params +InsertToplevel__7ivWorldP12ivInteractorT1 +ivWorld::InsertToplevel(ivInteractor *, ivInteractor *) +ivWorld::InsertToplevel +# +--format=gnu --no-params +InsertToplevel__7ivWorldP12ivInteractorT1iiUi +ivWorld::InsertToplevel(ivInteractor *, ivInteractor *, int, int, unsigned int) +ivWorld::InsertToplevel +# +--format=gnu --no-params +IsAGroup__FP11GraphicViewP11GraphicComp +IsAGroup(GraphicView *, GraphicComp *) +IsAGroup +# +--format=gnu --no-params +IsA__10ButtonCodeUl +ButtonCode::IsA(unsigned long) +ButtonCode::IsA +# +--format=gnu --no-params +ReadName__FR7istreamPc +ReadName(istream &, char *) +ReadName +# +--format=gnu --no-params +Redraw__13StringBrowseriiii +StringBrowser::Redraw(int, int, int, int) +StringBrowser::Redraw +# +--format=gnu --no-params +Rotate__13ivTransformerf +ivTransformer::Rotate(float) +ivTransformer::Rotate +# +--format=gnu --no-params +Rotated__C13ivTransformerf +ivTransformer::Rotated(float) const +ivTransformer::Rotated +# +--format=gnu --no-params +Round__Ff +Round(float) +Round +# +--format=gnu --no-params +SetExport__16MemberSharedNameUi +MemberSharedName::SetExport(unsigned int) +MemberSharedName::SetExport +# +--format=gnu --no-params +Set__14ivControlState13ControlStatusUi +ivControlState::Set(ControlStatus, unsigned int) +ivControlState::Set +# +--format=gnu --no-params +Set__5DFacePcii +DFace::Set(char *, int, int) +DFace::Set +# +--format=gnu --no-params +VConvert__9ivTSolverP12ivInteractorRP8TElementT2 +ivTSolver::VConvert(ivInteractor *, TElement *&, TElement *&) +ivTSolver::VConvert +# +--format=gnu --no-params +VConvert__9ivTSolverP7ivTGlueRP8TElement +ivTSolver::VConvert(ivTGlue *, TElement *&) +ivTSolver::VConvert +# +--format=gnu --no-params +VOrder__9ivTSolverUiRP12ivInteractorT2 +ivTSolver::VOrder(unsigned int, ivInteractor *&, ivInteractor *&) +ivTSolver::VOrder +# +--format=gnu --no-params +_10PageButton$__both +PageButton::__both +PageButton::__both +# +--format=gnu --no-params +_3RNG$singleMantissa +RNG::singleMantissa +RNG::singleMantissa +# +--format=gnu --no-params +_5IComp$_release +IComp::_release +IComp::_release +# +--format=gnu --no-params +_$_10BitmapComp +BitmapComp::~BitmapComp(void) +BitmapComp::~BitmapComp +# +--format=gnu --no-params +_$_9__io_defs +__io_defs::~__io_defs(void) +__io_defs::~__io_defs +# +--format=gnu --no-params +_$_Q23foo3bar +foo::bar::~bar(void) +foo::bar::~bar +# +--format=gnu --no-params +_$_Q33foo3bar4bell +foo::bar::bell::~bell(void) +foo::bar::bell::~bell +# +--format=gnu --no-params +__10ivTelltaleiP7ivGlyph +ivTelltale::ivTelltale(int, ivGlyph *) +ivTelltale::ivTelltale +# +--format=gnu --no-params +__10ivViewportiP12ivInteractorUi +ivViewport::ivViewport(int, ivInteractor *, unsigned int) +ivViewport::ivViewport +# +--format=gnu --no-params +__10ostrstream +ostrstream::ostrstream(void) +ostrstream::ostrstream +# +--format=gnu --no-params +__10ostrstreamPcii +ostrstream::ostrstream(char *, int, int) +ostrstream::ostrstream +# +--format=gnu --no-params +__11BitmapTablei +BitmapTable::BitmapTable(int) +BitmapTable::BitmapTable +# +--format=gnu --no-params +__12ViewportCodeP12ViewportComp +ViewportCode::ViewportCode(ViewportComp *) +ViewportCode::ViewportCode +# +--format=gnu --no-params +__12iv2_6_Borderii +iv2_6_Border::iv2_6_Border(int, int) +iv2_6_Border::iv2_6_Border +# +--format=gnu --no-params +__12ivBreak_Listl +ivBreak_List::ivBreak_List(long) +ivBreak_List::ivBreak_List +# +--format=gnu --no-params +__14iv2_6_MenuItemiP12ivInteractor +iv2_6_MenuItem::iv2_6_MenuItem(int, ivInteractor *) +iv2_6_MenuItem::iv2_6_MenuItem +# +--format=gnu --no-params +__20DisplayList_IteratorR11DisplayList +DisplayList_Iterator::DisplayList_Iterator(DisplayList &) +DisplayList_Iterator::DisplayList_Iterator +# +--format=gnu --no-params +__3fooRT0 +foo::foo(foo &) +foo::foo +# +--format=gnu --no-params +__3fooiN31 +foo::foo(int, int, int, int) +foo::foo +# +--format=gnu --no-params +__3fooiRT0iT2iT2 +foo::foo(int, foo &, int, foo &, int, foo &) +foo::foo +# +--format=gnu --no-params +__6KeyMapPT0 +KeyMap::KeyMap(KeyMap *) +KeyMap::KeyMap +# +--format=gnu --no-params +__8ArrowCmdP6EditorUiUi +ArrowCmd::ArrowCmd(Editor *, unsigned int, unsigned int) +ArrowCmd::ArrowCmd +# +--format=gnu --no-params +__9F_EllipseiiiiP7Graphic +F_Ellipse::F_Ellipse(int, int, int, int, Graphic *) +F_Ellipse::F_Ellipse +# +--format=gnu --no-params +__9FrameDataP9FrameCompi +FrameData::FrameData(FrameComp *, int) +FrameData::FrameData +# +--format=gnu --no-params +__9HVGraphicP9CanvasVarP7Graphic +HVGraphic::HVGraphic(CanvasVar *, Graphic *) +HVGraphic::HVGraphic +# +--format=gnu --no-params +__Q23foo3bar +foo::bar::bar(void) +foo::bar::bar +# +--format=gnu --no-params +__Q33foo3bar4bell +foo::bar::bell::bell(void) +foo::bar::bell::bell +# +--format=gnu --no-params +__aa__3fooRT0 +foo::operator&&(foo &) +foo::operator&& +# +--format=gnu --no-params +__aad__3fooRT0 +foo::operator&=(foo &) +foo::operator&= +# +--format=gnu --no-params +__ad__3fooRT0 +foo::operator&(foo &) +foo::operator& +# +--format=gnu --no-params +__adv__3fooRT0 +foo::operator/=(foo &) +foo::operator/= +# +--format=gnu --no-params +__aer__3fooRT0 +foo::operator^=(foo &) +foo::operator^= +# +--format=gnu --no-params +__als__3fooRT0 +foo::operator<<=(foo &) +foo::operator<<= +# +--format=gnu --no-params +__amd__3fooRT0 +foo::operator%=(foo &) +foo::operator%= +# +--format=gnu --no-params +__ami__3fooRT0 +foo::operator-=(foo &) +foo::operator-= +# +--format=gnu --no-params +__aml__3FixRT0 +Fix::operator*=(Fix &) +Fix::operator*= +# +--format=gnu --no-params +__aml__5Fix16i +Fix16::operator*=(int) +Fix16::operator*= +# +--format=gnu --no-params +__aml__5Fix32RT0 +Fix32::operator*=(Fix32 &) +Fix32::operator*= +# +--format=gnu --no-params +__aor__3fooRT0 +foo::operator|=(foo &) +foo::operator|= +# +--format=gnu --no-params +__apl__3fooRT0 +foo::operator+=(foo &) +foo::operator+= +# +--format=gnu --no-params +__ars__3fooRT0 +foo::operator>>=(foo &) +foo::operator>>= +# +--format=gnu --no-params +__as__3fooRT0 +foo::operator=(foo &) +foo::operator= +# +--format=gnu --no-params +__cl__3fooRT0 +foo::operator()(foo &) +foo::operator() +# +--format=gnu --no-params +__cl__6Normal +Normal::operator()(void) +Normal::operator() +# +--format=gnu --no-params +__cl__6Stringii +String::operator()(int, int) +String::operator() +# +--format=gnu --no-params +__cm__3fooRT0 +foo::operator, (foo &) +foo::operator, +# +--format=gnu --no-params +__co__3foo +foo::operator~(void) +foo::operator~ +# +--format=gnu --no-params +__dl__3fooPv +foo::operator delete(void *) +foo::operator delete +# +--format=gnu --no-params +__dv__3fooRT0 +foo::operator/(foo &) +foo::operator/ +# +--format=gnu --no-params +__eq__3fooRT0 +foo::operator==(foo &) +foo::operator== +# +--format=gnu --no-params +__er__3fooRT0 +foo::operator^(foo &) +foo::operator^ +# +--format=gnu --no-params +__ge__3fooRT0 +foo::operator>=(foo &) +foo::operator>= +# +--format=gnu --no-params +__gt__3fooRT0 +foo::operator>(foo &) +foo::operator> +# +--format=gnu --no-params +__le__3fooRT0 +foo::operator<=(foo &) +foo::operator<= +# +--format=gnu --no-params +__ls__3fooRT0 +foo::operator<<(foo &) +foo::operator<< +# +--format=gnu --no-params +__ls__FR7ostreamPFR3ios_R3ios +operator<<(ostream &, ios &(*)(ios &)) +operator<< +# +--format=gnu --no-params +__ls__FR7ostreamR3Fix +operator<<(ostream &, Fix &) +operator<< +# +--format=gnu --no-params +__lt__3fooRT0 +foo::operator<(foo &) +foo::operator< +# +--format=gnu --no-params +__md__3fooRT0 +foo::operator%(foo &) +foo::operator% +# +--format=gnu --no-params +__mi__3fooRT0 +foo::operator-(foo &) +foo::operator- +# +--format=gnu --no-params +__ml__3fooRT0 +foo::operator*(foo &) +foo::operator* +# +--format=gnu --no-params +__mm__3fooi +foo::operator--(int) +foo::operator-- +# +--format=gnu --no-params +__ne__3fooRT0 +foo::operator!=(foo &) +foo::operator!= +# +--format=gnu --no-params +__nt__3foo +foo::operator!(void) +foo::operator! +# +--format=gnu --no-params +__nw__3fooi +foo::operator new(int) +foo::operator new +# +--format=gnu --no-params +__oo__3fooRT0 +foo::operator||(foo &) +foo::operator|| +# +--format=gnu --no-params +__opPc__3foo +foo::operator char *(void) +foo::operator char * +# +--format=gnu --no-params +__opi__3foo +foo::operator int(void) +foo::operator int +# +--format=gnu --no-params +__or__3fooRT0 +foo::operator|(foo &) +foo::operator| +# +--format=gnu --no-params +__pl__3fooRT0 +foo::operator+(foo &) +foo::operator+ +# +--format=gnu --no-params +__pp__3fooi +foo::operator++(int) +foo::operator++ +# +--format=gnu --no-params +__rf__3foo +foo::operator->(void) +foo::operator-> +# +--format=gnu --no-params +__rm__3fooRT0 +foo::operator->*(foo &) +foo::operator->* +# +--format=gnu --no-params +__rs__3fooRT0 +foo::operator>>(foo &) +foo::operator>> +# +--format=gnu --no-params +_new_Fix__FUs +_new_Fix(unsigned short) +_new_Fix +# +--format=gnu --no-params +_vt.foo +foo virtual table +foo virtual table +# +--format=gnu --no-params +_vt.foo.bar +foo::bar virtual table +foo::bar virtual table +# +--format=gnu --no-params +_vt$foo +foo virtual table +foo virtual table +# +--format=gnu --no-params +_vt$foo$bar +foo::bar virtual table +foo::bar virtual table +# +--format=gnu --no-params +append__7ivGlyphPT0 +ivGlyph::append(ivGlyph *) +ivGlyph::append +# +--format=gnu --no-params +clearok__FP7_win_sti +clearok(_win_st *, int) +clearok +# +--format=gnu --no-params +complexfunc2__FPFPc_i +complexfunc2(int (*)(char *)) +complexfunc2 +# +--format=gnu --no-params +complexfunc3__FPFPFPl_s_i +complexfunc3(int (*)(short (*)(long *))) +complexfunc3 +# +--format=gnu --no-params +complexfunc4__FPFPFPc_s_i +complexfunc4(int (*)(short (*)(char *))) +complexfunc4 +# +--format=gnu --no-params +complexfunc5__FPFPc_PFl_i +complexfunc5(int (*(*)(char *))(long)) +complexfunc5 +# +--format=gnu --no-params +complexfunc6__FPFPi_PFl_i +complexfunc6(int (*(*)(int *))(long)) +complexfunc6 +# +--format=gnu --no-params +complexfunc7__FPFPFPc_i_PFl_i +complexfunc7(int (*(*)(int (*)(char *)))(long)) +complexfunc7 +# +--format=gnu --no-params +foo__FiN30 +foo(int, int, int, int) +foo +# +--format=gnu --no-params +foo__FiR3fooiT1iT1 +foo(int, foo &, int, foo &, int, foo &) +foo +# +--format=gnu --no-params +foo___3barl +bar::foo_(long) +bar::foo_ +# +--format=gnu --no-params +insert__15ivClippingStacklRP8_XRegion +ivClippingStack::insert(long, _XRegion *&) +ivClippingStack::insert +# +--format=gnu --no-params +insert__16ChooserInfo_ListlR11ChooserInfo +ChooserInfo_List::insert(long, ChooserInfo &) +ChooserInfo_List::insert +# +--format=gnu --no-params +insert__17FontFamilyRepListlRP15ivFontFamilyRep +FontFamilyRepList::insert(long, ivFontFamilyRep *&) +FontFamilyRepList::insert +# +--format=gnu --no-params +leaveok__FP7_win_stc +leaveok(_win_st *, char) +leaveok +# +--format=gnu --no-params +left_mover__C7ivMFKitP12ivAdjustableP7ivStyle +ivMFKit::left_mover(ivAdjustable *, ivStyle *) const +ivMFKit::left_mover +# +--format=gnu --no-params +overload1arg__FSc +overload1arg(signed char) +overload1arg +# +--format=gnu --no-params +overload1arg__FUc +overload1arg(unsigned char) +overload1arg +# +--format=gnu --no-params +overload1arg__FUi +overload1arg(unsigned int) +overload1arg +# +--format=gnu --no-params +overload1arg__FUl +overload1arg(unsigned long) +overload1arg +# +--format=gnu --no-params +overload1arg__FUs +overload1arg(unsigned short) +overload1arg +# +--format=gnu --no-params +overload1arg__Fc +overload1arg(char) +overload1arg +# +--format=gnu --no-params +overload1arg__Fd +overload1arg(double) +overload1arg +# +--format=gnu --no-params +overload1arg__Ff +overload1arg(float) +overload1arg +# +--format=gnu --no-params +overload1arg__Fi +overload1arg(int) +overload1arg +# +--format=gnu --no-params +overload1arg__Fl +overload1arg(long) +overload1arg +# +--format=gnu --no-params +overload1arg__Fs +overload1arg(short) +overload1arg +# +--format=gnu --no-params +overload1arg__Fv +overload1arg(void) +overload1arg +# +--format=gnu --no-params +overloadargs__Fi +overloadargs(int) +overloadargs +# +--format=gnu --no-params +overloadargs__Fii +overloadargs(int, int) +overloadargs +# +--format=gnu --no-params +overloadargs__Fiii +overloadargs(int, int, int) +overloadargs +# +--format=gnu --no-params +overloadargs__Fiiii +overloadargs(int, int, int, int) +overloadargs +# +--format=gnu --no-params +overloadargs__Fiiiii +overloadargs(int, int, int, int, int) +overloadargs +# +--format=gnu --no-params +overloadargs__Fiiiiii +overloadargs(int, int, int, int, int, int) +overloadargs +# +--format=gnu --no-params +overloadargs__Fiiiiiii +overloadargs(int, int, int, int, int, int, int) +overloadargs +# +--format=gnu --no-params +overloadargs__Fiiiiiiii +overloadargs(int, int, int, int, int, int, int, int) +overloadargs +# +--format=gnu --no-params +overloadargs__Fiiiiiiiii +overloadargs(int, int, int, int, int, int, int, int, int) +overloadargs +# +--format=gnu --no-params +overloadargs__Fiiiiiiiiii +overloadargs(int, int, int, int, int, int, int, int, int, int) +overloadargs +# +--format=gnu --no-params +overloadargs__Fiiiiiiiiiii +overloadargs(int, int, int, int, int, int, int, int, int, int, int) +overloadargs +# +--format=gnu --no-params +poke__8ivRasterUlUlffff +ivRaster::poke(unsigned long, unsigned long, float, float, float, float) +ivRaster::poke +# +--format=gnu --no-params +polar__Fdd +polar(double, double) +polar +# +--format=gnu --no-params +scale__13ivTransformerff +ivTransformer::scale(float, float) +ivTransformer::scale +# +--format=gnu --no-params +sgetn__7filebufPci +filebuf::sgetn(char *, int) +filebuf::sgetn +# +--format=gnu --no-params +shift__FP5_FrepiT0 +shift(_Frep *, int, _Frep *) +shift +# +--format=gnu --no-params +test__C6BitSeti +BitSet::test(int) const +BitSet::test +# +--format=gnu --no-params +test__C6BitSetii +BitSet::test(int, int) const +BitSet::test +# +--format=gnu --no-params +text_source__8Documentl +Document::text_source(long) +Document::text_source +# +--format=gnu --no-params +variance__6Erlangd +Erlang::variance(double) +Erlang::variance +# +--format=gnu --no-params +view__14DocumentViewerP8ItemViewP11TabularItem +DocumentViewer::view(ItemView *, TabularItem *) +DocumentViewer::view +# +--format=gnu --no-params +xy_extents__11ivExtensionffff +ivExtension::xy_extents(float, float, float, float) +ivExtension::xy_extents +# +--format=gnu --no-params +zero__8osMemoryPvUi +osMemory::zero(void *, unsigned int) +osMemory::zero +# +--format=gnu --no-params +_2T4$N +T4::N +T4::N +# +--format=gnu --no-params +_Q22T42t1$N +T4::t1::N +T4::t1::N +# +--format=gnu --no-params +get__2T1 +T1::get(void) +T1::get +# +--format=gnu --no-params +get__Q22T11a +T1::a::get(void) +T1::a::get +# +--format=gnu --no-params +get__Q32T11a1b +T1::a::b::get(void) +T1::a::b::get +# +--format=gnu --no-params +get__Q42T11a1b1c +T1::a::b::c::get(void) +T1::a::b::c::get +# +--format=gnu --no-params +get__Q52T11a1b1c1d +T1::a::b::c::d::get(void) +T1::a::b::c::d::get +# +--format=gnu --no-params +put__2T1i +T1::put(int) +T1::put +# +--format=gnu --no-params +put__Q22T11ai +T1::a::put(int) +T1::a::put +# +--format=gnu --no-params +put__Q32T11a1bi +T1::a::b::put(int) +T1::a::b::put +# +--format=gnu --no-params +put__Q42T11a1b1ci +T1::a::b::c::put(int) +T1::a::b::c::put +# +--format=gnu --no-params +put__Q52T11a1b1c1di +T1::a::b::c::d::put(int) +T1::a::b::c::d::put +# +--format=gnu --no-params +bar__3fooPv +foo::bar(void *) +foo::bar +# +--format=gnu --no-params +bar__C3fooPv +foo::bar(void *) const +foo::bar +# +--format=gnu --no-params +__eq__3fooRT0 +foo::operator==(foo &) +foo::operator== +# +--format=gnu --no-params +__eq__C3fooR3foo +foo::operator==(foo &) const +foo::operator== +# +--format=gnu --no-params +elem__t6vector1Zdi +vector::elem(int) +vector::elem +# +--format=gnu --no-params +elem__t6vector1Zii +vector::elem(int) +vector::elem +# +--format=gnu --no-params +__t6vector1Zdi +vector::vector(int) +vector::vector +# +--format=gnu --no-params +__t6vector1Zii +vector::vector(int) +vector::vector +# +--format=gnu --no-params +_$_t6vector1Zdi +vector::~vector(int) +vector::~vector +# +--format=gnu --no-params +_$_t6vector1Zii +vector::~vector(int) +vector::~vector +# +--format=gnu --no-params +__nw__t2T11ZcUi +T1::operator new(unsigned int) +T1::operator new +# +--format=gnu --no-params +__nw__t2T11Z1tUi +T1::operator new(unsigned int) +T1::operator new +# +--format=gnu --no-params +__dl__t2T11ZcPv +T1::operator delete(void *) +T1::operator delete +# +--format=gnu --no-params +__dl__t2T11Z1tPv +T1::operator delete(void *) +T1::operator delete +# +--format=gnu --no-params +__t2T11Zci +T1::T1(int) +T1::T1 +# +--format=gnu --no-params +__t2T11Zc +T1::T1(void) +T1::T1 +# +--format=gnu --no-params +__t2T11Z1ti +T1::T1(int) +T1::T1 +# +--format=gnu --no-params +__t2T11Z1t +T1::T1(void) +T1::T1 +# +--format=gnu --no-params +__Q2t4List1Z10VHDLEntity3Pix +List::Pix::Pix(void) +List::Pix::Pix +# +--format=gnu --no-params +__Q2t4List1Z10VHDLEntity3PixPQ2t4List1Z10VHDLEntity7element +List::Pix::Pix(List::element *) +List::Pix::Pix +# +--format=gnu --no-params +__Q2t4List1Z10VHDLEntity3PixRCQ2t4List1Z10VHDLEntity3Pix +List::Pix::Pix(List::Pix const &) +List::Pix::Pix +# +--format=gnu --no-params +__Q2t4List1Z10VHDLEntity3PixOCQ2t4List1Z10VHDLEntity3Pix +List::Pix::Pix(List::Pix const &&) +List::Pix::Pix +# +--format=gnu --no-params +__Q2t4List1Z10VHDLEntity7elementRC10VHDLEntityPT0 +List::element::element(VHDLEntity const &, List::element *) +List::element::element +# +--format=gnu --no-params +__Q2t4List1Z10VHDLEntity7elementOC10VHDLEntityPT0 +List::element::element(VHDLEntity const &&, List::element *) +List::element::element +# +--format=gnu --no-params +__Q2t4List1Z10VHDLEntity7elementRCQ2t4List1Z10VHDLEntity7element +List::element::element(List::element const &) +List::element::element +# +--format=gnu --no-params +__cl__C11VHDLLibraryGt4PixX3Z11VHDLLibraryZ14VHDLLibraryRepZt4List1Z10VHDLEntity +VHDLLibrary::operator()(PixX >) const +VHDLLibrary::operator() +# +--format=gnu --no-params +__cl__Ct4List1Z10VHDLEntityRCQ2t4List1Z10VHDLEntity3Pix +List::operator()(List::Pix const &) const +List::operator() +# +--format=gnu --no-params +__ne__FPvRCQ2t4List1Z10VHDLEntity3Pix +operator!=(void *, List::Pix const &) +operator!= +# +--format=gnu --no-params +__ne__FPvRCt4PixX3Z11VHDLLibraryZ14VHDLLibraryRepZt4List1Z10VHDLEntity +operator!=(void *, PixX > const &) +operator!= +# +--format=gnu --no-params +__t4List1Z10VHDLEntityRCt4List1Z10VHDLEntity +List::List(List const &) +List::List +# +--format=gnu --no-params +__t4PixX3Z11VHDLLibraryZ14VHDLLibraryRepZt4List1Z10VHDLEntity +PixX >::PixX(void) +PixX >::PixX +# +--format=gnu --no-params +__t4PixX3Z11VHDLLibraryZ14VHDLLibraryRepZt4List1Z10VHDLEntityP14VHDLLibraryRepGQ2t4List1Z10VHDLEntity3Pix +PixX >::PixX(VHDLLibraryRep *, List::Pix) +PixX >::PixX +# +--format=gnu --no-params +__t4PixX3Z11VHDLLibraryZ14VHDLLibraryRepZt4List1Z10VHDLEntityRCt4PixX3Z11VHDLLibraryZ14VHDLLibraryRepZt4List1Z10VHDLEntity +PixX >::PixX(PixX > const &) +PixX >::PixX +# +--format=gnu --no-params +__t4PixX3Z11VHDLLibraryZ14VHDLLibraryRepZt4List1Z10VHDLEntityOCt4PixX3Z11VHDLLibraryZ14VHDLLibraryRepZt4List1Z10VHDLEntity +PixX >::PixX(PixX > const &&) +PixX >::PixX +# +--format=gnu --no-params +nextE__C11VHDLLibraryRt4PixX3Z11VHDLLibraryZ14VHDLLibraryRepZt4List1Z10VHDLEntity +VHDLLibrary::nextE(PixX > &) const +VHDLLibrary::nextE +# +--format=gnu --no-params +next__Ct4List1Z10VHDLEntityRQ2t4List1Z10VHDLEntity3Pix +List::next(List::Pix &) const +List::next +# +--format=gnu --no-params +_GLOBAL_$D$set +global destructors keyed to set +global destructors keyed to set +# +--format=gnu --no-params +_GLOBAL_$I$set +global constructors keyed to set +global constructors keyed to set +# +--format=gnu --no-params +__as__t5ListS1ZUiRCt5ListS1ZUi +ListS::operator=(ListS const &) +ListS::operator= +# +--format=gnu --no-params +__cl__Ct5ListS1ZUiRCQ2t5ListS1ZUi3Vix +ListS::operator()(ListS::Vix const &) const +ListS::operator() +# +--format=gnu --no-params +__cl__Ct5SetLS1ZUiRCQ2t5SetLS1ZUi3Vix +SetLS::operator()(SetLS::Vix const &) const +SetLS::operator() +# +--format=gnu --no-params +__t10ListS_link1ZUiRCUiPT0 +ListS_link::ListS_link(unsigned int const &, ListS_link *) +ListS_link::ListS_link +# +--format=gnu --no-params +__t10ListS_link1ZUiRCt10ListS_link1ZUi +ListS_link::ListS_link(ListS_link const &) +ListS_link::ListS_link +# +--format=gnu --no-params +__t5ListS1ZUiRCt5ListS1ZUi +ListS::ListS(ListS const &) +ListS::ListS +# +--format=gnu --no-params +next__Ct5ListS1ZUiRQ2t5ListS1ZUi3Vix +ListS::next(ListS::Vix &) const +ListS::next +# +--format=gnu --no-params +__ne__FPvRCQ2t5SetLS1ZUi3Vix +operator!=(void *, SetLS::Vix const &) +operator!= +# +--format=gnu --no-params +__t8ListElem1Z5LabelRt4List1Z5Label +ListElem