diff --git a/.remill_commit_id b/.remill_commit_id index 892081d44..76e674a26 100644 --- a/.remill_commit_id +++ b/.remill_commit_id @@ -1 +1 @@ -86a6424d58cca6504a93bf7dc4363f14be9e216f +5af012219674f2e1b0691748e6d62ad4d1817b86 diff --git a/CMakeLists.txt b/CMakeLists.txt index 0995a80c1..20ec7940f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,16 +1,17 @@ -# Copyright (c) 2018 Trail of Bits, Inc. +# Copyright (c) 2020 Trail of Bits, Inc. # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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 Affero General Public License for more details. # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . project(mcsema) cmake_minimum_required(VERSION 3.2) @@ -81,19 +82,79 @@ set_source_files_properties(${PROJECT_PROTOBUFHEADERFILES} PROPERTIES COMPILE_FLAGS "-Wno-sign-conversion -Wno-shorten-64-to-32 -Wno-conversion" ) +# llvm +find_package(LLVM REQUIRED CONFIG HINTS ${FINDPACKAGE_LLVM_HINTS}) + +string(REPLACE "." ";" LLVM_VERSION_LIST ${LLVM_PACKAGE_VERSION}) +list(GET LLVM_VERSION_LIST 0 LLVM_MAJOR_VERSION) +list(GET LLVM_VERSION_LIST 1 LLVM_MINOR_VERSION) +set(REMILL_LLVM_VERSION "${LLVM_MAJOR_VERSION}.${LLVM_MINOR_VERSION}") + +# +# target settings +# + +set(MCSEMA_LIFT mcsema-lift-${REMILL_LLVM_VERSION}) + +add_executable(${MCSEMA_LIFT} + ${PROJECT_PROTOBUFSOURCEFILES} + + mcsema/Arch/Arch.cpp + + mcsema/CFG/CFG.cpp + + mcsema/BC/Callback.cpp + mcsema/BC/External.cpp + mcsema/BC/Function.cpp + mcsema/BC/Instruction.cpp + mcsema/BC/Legacy.cpp + mcsema/BC/Lift.cpp + mcsema/BC/Optimize.cpp + mcsema/BC/Segment.cpp + mcsema/BC/Util.cpp + + tools/mcsema_lift/Lift.cpp +) + +# Copy mcsema-disass in +add_custom_command( + TARGET protobuf_python_module_ida POST_BUILD + DEPENDS {PROJECT_PROTOBUFPYTHONMODULE} + COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_PROTOBUFPYTHONMODULE} ${CMAKE_CURRENT_SOURCE_DIR}/tools/mcsema_disass/ida7 +) + +# this is needed for the #include directives with absolutes paths to work correctly; it must +# also be set to PUBLIC since mcsema-lift includes some files directly +list(APPEND PROJECT_INCLUDEDIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}) + +add_dependencies(${MCSEMA_LIFT} + semantics + protobuf_python_module_ida + protobuf_python_module_binja) + +# +# libraries +# + # remill if(NOT TARGET remill) if("${PLATFORM_NAME}" STREQUAL "windows") set(REMILL_FINDPACKAGE_HINTS HINTS "${CMAKE_INSTALL_PREFIX}/remill/lib") endif() + find_package(remill REQUIRED ${REMILL_FINDPACKAGE_HINTS}) endif() list(APPEND PROJECT_LIBRARIES remill) -list(APPEND PROJECT_INCLUDEDIRECTORIES ${remill_INCLUDE_DIRS}) -# llvm -find_package(LLVM REQUIRED CONFIG HINTS ${FINDPACKAGE_LLVM_HINTS}) +# anvill +if(NOT TARGET anvill-${REMILL_LLVM_VERSION}) + find_package(anvill REQUIRED) + if(NOT anvill_FOUND) + message(FATAL_ERROR "McSema depends upon Anvill being cloned into Remill's tools directory") + endif() +endif() +list(APPEND PROJECT_LIBRARIES anvill-${REMILL_LLVM_VERSION}) if (LLVM_Z3_INSTALL_DIR) set(need_z3 TRUE) @@ -111,9 +172,6 @@ if(need_z3) endif() endif() -string(REPLACE "." ";" LLVM_VERSION_LIST ${LLVM_PACKAGE_VERSION}) -list(GET LLVM_VERSION_LIST 0 LLVM_MAJOR_VERSION) -list(GET LLVM_VERSION_LIST 1 LLVM_MINOR_VERSION) set(LLVM_LIBRARIES LLVMCore LLVMSupport LLVMAnalysis LLVMipo LLVMIRReader @@ -138,58 +196,6 @@ list(APPEND PROJECT_LIBRARIES glog::glog) find_package(gflags REQUIRED) list(APPEND PROJECT_LIBRARIES gflags) - -# -# target settings -# - -set(MCSEMA_LLVM_VERSION "${LLVM_MAJOR_VERSION}.${LLVM_MINOR_VERSION}") -set(MCSEMA_LIFT mcsema-lift-${MCSEMA_LLVM_VERSION}) - -add_executable(${MCSEMA_LIFT} - ${PROJECT_PROTOBUFSOURCEFILES} - - mcsema/Arch/ABI.cpp - mcsema/Arch/Arch.cpp - - mcsema/CFG/CFG.cpp - - mcsema/BC/Callback.cpp - mcsema/BC/External.cpp - mcsema/BC/Function.cpp - mcsema/BC/Instruction.cpp - mcsema/BC/Legacy.cpp - mcsema/BC/Lift.cpp - mcsema/BC/Optimize.cpp - mcsema/BC/Segment.cpp - mcsema/BC/Util.cpp - - tools/mcsema_lift/Lift.cpp -) - - -# Copy mcsema-disass in -add_custom_command( - TARGET protobuf_python_module_ida POST_BUILD - DEPENDS {PROJECT_PROTOBUFPYTHONMODULE} - COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_PROTOBUFPYTHONMODULE} ${CMAKE_CURRENT_SOURCE_DIR}/tools/mcsema_disass/ida -) - -add_custom_command( - TARGET protobuf_python_module_binja POST_BUILD - DEPENDS {PROJECT_PROTOBUFPYTHONMODULE} - COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_PROTOBUFPYTHONMODULE} ${CMAKE_CURRENT_SOURCE_DIR}/tools/mcsema_disass/binja -) - -# this is needed for the #include directives with absolutes paths to work correctly; it must -# also be set to PUBLIC since mcsema-lift includes some files directly -list(APPEND PROJECT_INCLUDEDIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}) - -add_dependencies(${MCSEMA_LIFT} - semantics protobuf_python_module_ida - protobuf_python_module_binja -) - # # target settings # diff --git a/Dockerfile b/Dockerfile index 7f645689e..baf3d409b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -23,18 +23,21 @@ RUN apt-get update && \ # Build-time dependencies go here FROM trailofbits/cxx-common:llvm${LLVM_VERSION}-${DISTRO_BASE}-${ARCH} as deps ARG LIBRARIES - RUN apt-get update && \ - apt-get install -qqy python2.7 libc6-dev wget liblzma-dev zlib1g-dev libtinfo-dev curl git build-essential ninja-build ccache && \ + apt-get install -qqy python2.7 python3 python3-pip libc6-dev wget liblzma-dev zlib1g-dev libtinfo-dev curl git build-essential ninja-build libselinux1-dev libbsd-dev ccache && \ if [ "$(uname -m)" = "x86_64" ]; then dpkg --add-architecture i386 && apt-get update && apt-get install -qqy gcc-multilib g++-multilib zip zlib1g-dev:i386; fi && \ - rm -rf /var/lib/apt/lists/* + rm -rf /var/lib/apt/lists/* && \ + pip3 install ccsyspath # needed for 20.04 support until we migrate to py3 RUN curl https://bootstrap.pypa.io/get-pip.py --output get-pip.py && python2.7 get-pip.py +RUN update-alternatives --install /usr/bin/python2 python2 /usr/bin/python2.7 1 + WORKDIR / COPY .remill_commit_id ./ RUN git clone https://github.com/lifting-bits/remill.git && \ + git clone https://github.com/lifting-bits/anvill.git remill/tools/anvill && \ cd remill && \ echo "Using remill commit $(cat ../.remill_commit_id)" && \ git checkout $(cat ../.remill_commit_id) diff --git a/LICENSE b/LICENSE index 2bb9ad240..0ad25db4b 100644 --- a/LICENSE +++ b/LICENSE @@ -1,176 +1,661 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. - 1. Definitions. + Preamble - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. + The precise terms and conditions for copying, distribution and +modification follow. - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." + TERMS AND CONDITIONS - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. + 0. Definitions. - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. + "This License" refers to version 3 of the GNU Affero General Public License. - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and + A "covered work" means either the unmodified Program or a work based +on the Program. - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. + 1. Source Code. - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. - END OF TERMS AND CONDITIONS \ No newline at end of file + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/README.md b/README.md index 762b15067..9e1139162 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,8 @@ Why would anyone translate binaries *back* to bitcode? | [Python](https://www.python.org/) | 2.7 | | [Python Package Index](https://pypi.python.org/pypi) | Latest | | [python-protobuf](https://pypi.python.org/pypi/protobuf) | 3.2.0 | +| [python-clang](https://pypi.org/project/clang/) | 3.5.0 | +| [ccsyspath](https://pypi.org/project/ccsyspath/) | 1.1.0 | | [IDA Pro](https://www.hex-rays.com/products/ida) | 7.1+ | | [Binary Ninja](https://binary.ninja/) | Latest | | [Dyninst](https://www.dyninst.org/) | 9.3.2 | @@ -87,16 +89,13 @@ Why would anyone translate binaries *back* to bitcode? ### Docker -#### Step 1: Clone McSema +#### Step 1: Download Dockerfile -```sh -git clone --depth 1 https://github.com/lifting-bits/mcsema.git -cd mcsema -``` +`wget https://raw.githubusercontent.com/lifting-bits/mcsema/master/tools/Dockerfile` -#### Step 2: Add your disassembler (optional) +#### Step 2: Add your disassembler -Currently IDA, Binary Ninja, and Dyninst are supported for control-flow recovery, it's left as an exercise to the reader to install your disassembler of choice in a Dockerfile, but an example of installing Binary Ninja is provided (remember for Docker that paths need to be relative to where you built from): +Currently IDA, Binary Ninja, and Dyninst are supported for control-flow recovery, it's left as an exercise to the reader to install your disassembler of choice, but an example of installing Binary Ninja is provided (remember for Docker that paths need to be relative to where you built from): ``` ADD local-relative/path/to/binaryninja/ /root/binaryninja/ ADD local-relative/path/to/.binaryninja/ /root/.binaryninja/ # <- Make sure there's no `lastrun` file diff --git a/mcsema/Arch/ABI.cpp b/mcsema/Arch/ABI.cpp deleted file mode 100644 index d84f6ec75..000000000 --- a/mcsema/Arch/ABI.cpp +++ /dev/null @@ -1,1248 +0,0 @@ -/* - * Copyright (c) 2017 Trail of Bits, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mcsema/Arch/ABI.h" -#include "mcsema/Arch/Arch.h" -#include "mcsema/BC/Util.h" - -#include "remill/Arch/Arch.h" -#include "remill/Arch/Name.h" -#include "remill/BC/Util.h" -#include "remill/BC/Version.h" -#include "remill/OS/OS.h" - -namespace mcsema { - -enum ValueKind { - kInvalidKind = 0, - kI8 = (1 << 0), - kI16 = (1 << 1), - kI32 = (1 << 2), - kI64 = (1 << 3), - kF32 = (1 << 4), - kF64 = (1 << 5), - kF80 = (1 << 6), - kVec = (1 << 7), - - kIntegralLeast32 = kI8 | kI16 | kI32, - kIntegralLeast64 = kI8 | kI16 | kI32 | kI64, -}; - -namespace { - -static ValueKind KindOfValue(llvm::Type *type) { - if (!type || type->isPointerTy()) { - return (32 == gArch->address_size) ? kI32 : kI64; - - } else if (type->isVectorTy()) { - return kVec; - } else if (type->isIntegerTy()) { - llvm::DataLayout dl(gModule.get()); - switch (dl.getTypeAllocSize(type)) { - case 8: return kI64; - case 4: return kI32; - case 2: return kI16; - case 1: return kI8; - default: - return kInvalidKind; - } - } else if (type->isX86_FP80Ty()) { - return kF80; - } else if (type->isDoubleTy()) { - return kF64; - } else if (type->isFloatTy()) { - return kF32; - } else { - return kInvalidKind; - } -} - -static const char *StackPointerName(void) { - static const char *sp_name = nullptr; - if (sp_name) { - return sp_name; - } - - switch (gArch->arch_name) { - case remill::kArchAArch64LittleEndian: - sp_name = "SP"; - break; - - case remill::kArchX86: - case remill::kArchX86_AVX: - case remill::kArchX86_AVX512: - sp_name = "ESP"; - break; - - case remill::kArchAMD64: - case remill::kArchAMD64_AVX: - case remill::kArchAMD64_AVX512: - sp_name = "RSP"; - break; - default: - LOG(FATAL) - << "Can't get stack pointer name for architecture: " - << remill::GetArchName(gArch->arch_name); - return nullptr; - } - - return sp_name; -} - -static const char *ThreadPointerNameX86(void) { - switch (gArch->os_name) { - case remill::kOSLinux: - return "GS_BASE"; - case remill::kOSWindows: - return "FS_BASE"; - default: - return nullptr; - } -} - -static const char *ThreadPointerNameAMD64(void) { - switch (gArch->os_name) { - case remill::kOSLinux: - return "FS_BASE"; - case remill::kOSWindows: - return "GS_BASE"; - default: - return nullptr; - } -} - -static const char *ThreadPointerName(void) { - static const char *tp_name = nullptr; - if (tp_name) { - return tp_name; - } - - switch (gArch->arch_name) { - case remill::kArchAArch64LittleEndian: - tp_name = "TPIDR_EL0"; - break; - - case remill::kArchX86: - case remill::kArchX86_AVX: - case remill::kArchX86_AVX512: - tp_name = ThreadPointerNameX86(); - break; - - case remill::kArchAMD64: - case remill::kArchAMD64_AVX: - case remill::kArchAMD64_AVX512: - tp_name = ThreadPointerNameAMD64(); - break; - - default: - break; - } - - LOG_IF(ERROR, !tp_name) - << "Can't get thread pointer name for architecture " - << remill::GetArchName(gArch->arch_name) << " and OS " - << remill::GetOSName(gArch->os_name); - return tp_name; -} - -static uint64_t GetVectorRegSize(void) { - switch (gArch->arch_name) { - case remill::kArchAMD64: - case remill::kArchX86: - return 16; - case remill::kArchAMD64_AVX: - case remill::kArchX86_AVX: - return 32; - case remill::kArchAMD64_AVX512: - case remill::kArchX86_AVX512: - return 64; - case remill::kArchAArch64LittleEndian: - return 16; - default: - LOG(FATAL) - << "Unknown vector register size for arch " - << GetArchName(gArch->arch_name); - return 0; - } -} - -struct VectorRegistersInfo { - const char* base_name; - size_t num_vec_regs; -}; - -static VectorRegistersInfo GetVectorRegisterInfo() { - switch(gArch->arch_name) { - case remill::kArchAArch64LittleEndian: - return {"V", 32}; - case remill::kArchAMD64_AVX: - return {"YMM", 16}; - case remill::kArchX86_AVX: - return {"YMM", 8}; - case remill::kArchAMD64_AVX512: - return {"ZMM", 32}; - case remill::kArchX86_AVX512: - return {"ZMM", 8}; - default: - return {"XMM", 8}; - } -} - -// TODO(lukas): Test kVec flag for AArch64 -struct CallingConventionInfo { - using ConstraintTable = std::vector; - - struct PackedReturnInfo { - std::vector names; - llvm::Type *unit_ptr_type; - const ValueKind accepted_kinds; - }; - - // Sometimes types will get returned in several registers, even though - // there is no indication of it in function signature - static const PackedReturnInfo &GetPackedReturn(ValueKind val_kind) { - static const PackedReturnInfo not_found = {{}, nullptr, kInvalidKind}; - auto ptr_size = static_cast(gArch->address_size); - - if (gArch->IsX86()) { - static const std::vector return_info = { - {{"EAX", "EDX"}, - llvm::Type::getIntNPtrTy(*gContext, ptr_size), - kI64}, - }; - for (const auto &entry : return_info) { - if (entry.accepted_kinds & val_kind) { - return entry; - } - } - } - return not_found; - } - - const ConstraintTable &GetArgumentTable( - llvm::CallingConv::ID cc) const { - for (const auto &t : arg_tables) { - if (t.first == cc) { - return t.second; - } - } - LOG(FATAL) - << "Unknown ABI/calling convention: " << cc; - return gInvalidTable; - } - - const ConstraintTable &GetReturnTable( - llvm::CallingConv::ID cc) const { - for (const auto &t : ret_tables) { - if (t.first == cc) { - return t.second; - } - } - LOG(FATAL) - << "Unknown ABI/calling convention: " << cc; - return gInvalidTable; - } - - static const CallingConventionInfo &Instance(void) { - static CallingConventionInfo instance; - return instance; - } - - CallingConventionInfo(const CallingConventionInfo &) = delete; - void operator=(const CallingConventionInfo &) = delete; - - private: - CallingConventionInfo(void) { - CreateArgumentsConstraintTables(); - CreateReturnConstraintTable(); - } - - void CreateArgumentsConstraintTables(void) { - const auto &vector_reg_info = GetVectorRegisterInfo(); - const auto &vector_base_name = vector_reg_info.base_name; - if (gArch->IsAMD64()) { - std::vector amd64_sysv_args = { - {"RDI", kIntegralLeast64}, - {"RSI", kIntegralLeast64}, - {"RDX", kIntegralLeast64}, - {"RCX", kIntegralLeast64}, - {"R8", kIntegralLeast64}, - {"R9", kIntegralLeast64} - }; - - for (unsigned i = 0; i < 8; ++i) { - auto name = vector_base_name + std::to_string(i); - amd64_sysv_args.push_back({name, kF32 | kF64 | kVec}); - } - arg_tables.emplace_back(llvm::CallingConv::X86_64_SysV, - std::move(amd64_sysv_args)); - - std::vector amd64_win64_args = { - {"RCX", kIntegralLeast64}, - {"RDX", kIntegralLeast64}, - {"R8", kIntegralLeast64}, - {"R9", kIntegralLeast64} - }; - - for (auto i = 0U; i < 4; ++i) { - auto name = vector_base_name + std::to_string(i); - amd64_win64_args.push_back({name, kF32 | kF64 | kVec}); - } - arg_tables.emplace_back(llvm::CallingConv::Win64, - std::move(amd64_win64_args)); - } else if (gArch->IsX86()) { - std::vector x86_fast_call_args = { - {"ECX", kIntegralLeast32}, - {"EDX", kIntegralLeast32}, - }; - arg_tables.emplace_back(llvm::CallingConv::X86_FastCall, - std::move(x86_fast_call_args)); - - std::vector x86_this_call_args = { - {"ECX", kIntegralLeast32}, - }; - arg_tables.emplace_back(llvm::CallingConv::X86_ThisCall, - std::move(x86_this_call_args)); - - // stdcall takes all args on the stack. - arg_tables.emplace_back(llvm::CallingConv::X86_StdCall, - ConstraintTable{}); - - // cdecl takes all args on the stack. - arg_tables.emplace_back(llvm::CallingConv::C, - ConstraintTable{}); - } else if (gArch->IsAArch64()) { - std::vector aarch64_args = { - {"X0", kIntegralLeast64}, - {"X1", kIntegralLeast64}, - {"X2", kIntegralLeast64}, - {"X3", kIntegralLeast64}, - {"X4", kIntegralLeast64}, - {"X5", kIntegralLeast64}, - {"X6", kIntegralLeast64}, - {"X7", kIntegralLeast64}, - - {"D0", kF32 | kF64}, - {"D1", kF32 | kF64}, - {"D2", kF32 | kF64}, - {"D3", kF32 | kF64}, - {"D4", kF32 | kF64}, - {"D5", kF32 | kF64}, - {"D6", kF32 | kF64}, - {"D7", kF32 | kF64}, - {"D8", kF32 | kF64}, - {"D9", kF32 | kF64}, - {"D10", kF32 | kF64}, - {"D11", kF32 | kF64}, - {"D12", kF32 | kF64}, - {"D13", kF32 | kF64}, - {"D14", kF32 | kF64}, - {"D15", kF32 | kF64}, - {"D16", kF32 | kF64}, - {"D17", kF32 | kF64}, - {"D18", kF32 | kF64}, - {"D19", kF32 | kF64}, - {"D20", kF32 | kF64}, - {"D21", kF32 | kF64}, - {"D22", kF32 | kF64}, - {"D23", kF32 | kF64}, - {"D24", kF32 | kF64}, - {"D25", kF32 | kF64}, - {"D26", kF32 | kF64}, - {"D27", kF32 | kF64}, - {"D28", kF32 | kF64}, - {"D29", kF32 | kF64}, - {"D30", kF32 | kF64}, - {"D31", kF32 | kF64}, - }; - - for(auto i = 0U; i < 8; ++i) { - auto vec_reg_name = vector_base_name + std::to_string(i); - aarch64_args.push_back({vec_reg_name, kVec}); - } - arg_tables.emplace_back(llvm::CallingConv::C, - std::move(aarch64_args)); - } - } - - void CreateReturnConstraintTable(void) { - const auto &vector_reg_info = GetVectorRegisterInfo(); - size_t size = vector_reg_info.num_vec_regs; - const auto &vector_base_name = vector_reg_info.base_name; - - if (gArch->IsAMD64()) { - ConstraintTable sysv64_table = { - {"RAX", kIntegralLeast64}, - {"RDX", kIntegralLeast64} - }; - - for (auto i = 0U; i < size; ++i) { - auto name = vector_base_name + std::to_string(i); - sysv64_table.push_back({name, kF32 | kF64 | kVec}); - } - sysv64_table.push_back({"ST0", kF80}); - sysv64_table.push_back({"ST1", kF80}); - ret_tables.emplace_back(llvm::CallingConv::X86_64_SysV, - std::move(sysv64_table)); - - ConstraintTable win64_table = {{"RAX", kIntegralLeast64}}; - for (auto i = 0U; i < size; ++i) { - auto name = vector_base_name + std::to_string(i); - win64_table.push_back({name, kF32 | kF64 | kVec}); - } - win64_table.push_back({"ST0", kF80}); - ret_tables.emplace_back(llvm::CallingConv::Win64, - std::move(win64_table)); - } else if (gArch->IsX86()) { - ConstraintTable x86_table = { - {"EAX", kIntegralLeast32}, - {"ST0", kF80}, - }; - ret_tables.emplace_back(llvm::CallingConv::X86_StdCall, - x86_table); - ret_tables.emplace_back(llvm::CallingConv::X86_FastCall, - x86_table); - ret_tables.emplace_back(llvm::CallingConv::X86_ThisCall, - std::move(x86_table)); - - ConstraintTable cdecl_table = { - {"EAX", kIntegralLeast32 | kF32}, - {"ST0", kF80}, - }; - ret_tables.emplace_back(llvm::CallingConv::C, - std::move(cdecl_table)); - - } else if (gArch->IsAArch64()) { - ConstraintTable AArch64_table = { - {"X0", kIntegralLeast64}, - {"D0", kF64}, - {"S0", kF32}, - }; - ret_tables.emplace_back(llvm::CallingConv::C, - std::move(AArch64_table)); - } - } - - std::vector> arg_tables; - std::vector> ret_tables; - - static const ConstraintTable gInvalidTable; -}; - -const CallingConventionInfo::ConstraintTable -CallingConventionInfo::gInvalidTable; - -static uint64_t DefaultUsedStackBytes(llvm::CallingConv::ID cc) { - switch (cc) { - case llvm::CallingConv::X86_64_SysV: - return 8; // Size of return address on the stack. - - case llvm::CallingConv::Win64: - return 8 + 32; // Return address + shadow space. - - case llvm::CallingConv::X86_FastCall: - case llvm::CallingConv::X86_StdCall: - case llvm::CallingConv::X86_ThisCall: - return 4; // Size of return address on the stack. - - default: - return 0; - } -} - -static llvm::Type* RetrieveArgumentType(llvm::Type *original_type, unsigned index) { - if (original_type->isPointerTy()) { - return original_type; - } - if (auto struct_type = llvm::dyn_cast(original_type)) { - return struct_type->getElementType(index); - } else { - return original_type; - } -} - -// llvm::CompositeType as common parent does not provide getNumElements -static uint64_t GetNumberOfElements(llvm::Type* original_type) { - if (auto struct_type = llvm::dyn_cast(original_type)) { - return struct_type->getNumElements(); - } else { - return 1; - } -} - -static void ExtractFromVector(llvm::BasicBlock *block, - llvm::Value *ret_val, - llvm::Value *reg_ptr, - size_t count, - size_t start=0) { - - llvm::IRBuilder<> ir(block); - - for (size_t i = 0; i < count; ++i) { - auto offset = ir.CreateGEP(reg_ptr, GetConstantInt(64, i)); - auto extract = ir.CreateExtractElement(ret_val, - GetConstantInt(64, i + start)); - ir.CreateStore(extract, offset); - } -} - -static llvm::Value *InsertIntoVector(llvm::BasicBlock *block, - llvm::Value *base_value, - llvm::Value *reg_ptr, - size_t count, - size_t start=0) { - - llvm::IRBuilder<> ir(block); - for (size_t i = 0; i < count; ++i) { - auto offset = ir.CreateGEP(reg_ptr, GetConstantInt(64, i)); - auto load = ir.CreateLoad(offset); - base_value = ir.CreateInsertElement( - base_value, - load, - GetConstantInt(64, i + start)); - } - return base_value; -} - -// Scan through the register table. If we can match this argument request -// to a register then do so. -static const char *GetVarImpl( - ValueKind val_kind, - const std::vector &table, - uint64_t &bitmap) { - - for (auto i = 0U; i < table.size(); ++i) { - const auto ®_loc = table[i]; - if (val_kind == (reg_loc.accepted_val_kinds & val_kind)) { - auto mask = 1ULL << i; - if (!(bitmap & mask)) { - bitmap |= mask; - return reg_loc.var_name.c_str(); - } - } - } - return nullptr; -} - -// In special cases one type can be returned via two registers -static bool TryStorePackedType(llvm::BasicBlock *block, llvm::Value *ret_val) { - const auto ®s = CallingConventionInfo::GetPackedReturn( - KindOfValue(ret_val->getType())); - - if (regs.names.empty() || regs.accepted_kinds == kInvalidKind) { - LOG(INFO) - << "Could not store return type " - << remill::LLVMThingToString(ret_val->getType()) - << " as packed type"; - return false; - } - - llvm::IRBuilder<> ir(block); - - // Need to get ptr to some type smaller than actual type is, as - // it will be split into multiple registers - auto ret_val_alloca = ir.CreateAlloca(ret_val->getType()); - ir.CreateStore(ret_val, ret_val_alloca); - auto ptr_ret_val = ir.CreateBitCast(ret_val_alloca, regs.unit_ptr_type); - - for (auto i = 0U; i < regs.names.size(); ++i) { - // Get partial value from offset - auto partial_value_ptr = ir.CreateGEP(ptr_ret_val, GetConstantInt(64, i)); - auto partial_value = ir.CreateLoad(partial_value_ptr); - - llvm::Value *dest_loc = remill::FindVarInFunction(block, regs.names[i]); - - // Store actual value - dest_loc = ir.CreateBitCast(dest_loc, - regs.unit_ptr_type); - ir.CreateStore(partial_value, dest_loc); - } - return true; -} - -} // namespace - -CallingConvention::CallingConvention(llvm::CallingConv::ID cc_) - : cc(cc_), - used_reg_bitmap(0), - used_return_bitmap(0), - num_loaded_stack_bytes(DefaultUsedStackBytes(cc)), - num_stored_stack_bytes(0), - sp_name(StackPointerName()), - tp_name(ThreadPointerName()), - reg_table(CallingConventionInfo::Instance().GetArgumentTable(cc)), - return_table(CallingConventionInfo::Instance().GetReturnTable(cc)) {} - -// TODO(lukas): Test win64 calling convention -const char *CallingConvention::GetVarForNextArgument(llvm::Type *val_type) { - auto val_kind = KindOfValue(val_type); - auto next_var = GetVarImpl(val_kind, reg_table, used_reg_bitmap); - - // Win64 calling convention chooses one from pair - // {gpr, xmm} and leaves the second one empty - // - // For example call of function foo(int32, float, int32) - // will fill registers %rcx, %xmm1, %r8 - if (llvm::CallingConv::Win64 == cc) { - val_kind = (val_kind == kIntegralLeast64) ? kF64 : kIntegralLeast64; - GetVarImpl(val_kind, reg_table, used_reg_bitmap); - } - return next_var; -} - -const char *CallingConvention::GetVarForNextReturn(llvm::Type *val_type) { - return GetVarImpl(KindOfValue(val_type), return_table, used_return_bitmap); -} - -static llvm::Function *ReadIntFromMemFunc(uint64_t size_bytes) { - if (8 == size_bytes) { - return gModule->getFunction("__remill_read_memory_64"); - } else if (4 == size_bytes) { - return gModule->getFunction("__remill_read_memory_32"); - } else if (2 == size_bytes) { - return gModule->getFunction("__remill_read_memory_16"); - } else if (1 == size_bytes) { - return gModule->getFunction("__remill_read_memory_8"); - } else { - LOG(FATAL) - << "Cannot find function to read " << size_bytes - << "-byte integer from memory."; - return nullptr; - } -} - -static llvm::Function *WriteIntToMemFunc(uint64_t size_bytes) { - if (8 == size_bytes) { - return gModule->getFunction("__remill_write_memory_64"); - } else if (4 == size_bytes) { - return gModule->getFunction("__remill_write_memory_32"); - } else if (2 == size_bytes) { - return gModule->getFunction("__remill_write_memory_16"); - } else if (1 == size_bytes) { - return gModule->getFunction("__remill_write_memory_8"); - } else { - LOG(FATAL) - << "Cannot find function to read " << size_bytes - << "-byte integer from memory."; - return nullptr; - } -} - -// In llvm types that are expected to go into vector registers will -// be of vector type, for example: <2 x float> will go into one %xmm. -// External library must be compiled for the same architecture that -// is passed to mcsema-lift, otherwise types may be wrong. -llvm::Value *CallingConvention::LoadVectorArgument( - llvm::BasicBlock *block, - llvm::VectorType *goal_type) { - - llvm::IRBuilder<> ir(block); - llvm::Value *base_value = llvm::Constant::getNullValue(goal_type); - - llvm::Type *under_type = goal_type->getElementType(); - llvm::DataLayout dl(gModule.get()); - const size_t num_elements = goal_type->getNumElements(); - const ssize_t element_size = static_cast( - dl.getTypeAllocSize(under_type)); - const ssize_t reg_size = static_cast(GetVectorRegSize()); - const ssize_t reg_element_capacity = reg_size / element_size; - ssize_t remaining = static_cast(num_elements); - - for (ssize_t i = 0; remaining > 0; ++i, remaining -= reg_size) { - auto reg_var_name = GetVarForNextArgument(goal_type); - LOG_IF(FATAL, !reg_var_name) - << "Could not find available vector register"; - - llvm::Value *dest_loc = remill::FindVarInFunction(block, reg_var_name); - dest_loc = ir.CreateBitCast(dest_loc, - llvm::PointerType::get(under_type, 0)); - - const auto count = std::min(reg_element_capacity, remaining); - base_value = InsertIntoVector( - block, base_value, dest_loc, - static_cast(count), - static_cast(i * reg_element_capacity)); - } - return base_value; -} - - -llvm::Value *CallingConvention::LoadNextSimpleArgument( - llvm::BasicBlock *block, - llvm::Type *goal_type) { - if (!goal_type) { - goal_type = gWordType; - } - - llvm::IRBuilder<> ir(block); - - if (auto vector_type = llvm::dyn_cast(goal_type)) { - return LoadVectorArgument(block, vector_type); - } - - if (auto reg_var_name = GetVarForNextArgument(goal_type)) { - auto reg_ptr = remill::FindVarInFunction(block, reg_var_name); - return ir.CreateLoad( - ir.CreateBitCast(reg_ptr, llvm::PointerType::get(goal_type, 0))); - } - - // We can't match the argument request to a register, so lets look for it on - // the stack. The supported calling conventions are sane, to the extent - // that they push arguments onto the stack in reverse order (i.e. last arg - // first). - auto sp = LoadStackPointer(block); - CHECK(sp->getType() == gWordType); - - auto addr_size = static_cast(gArch->address_size / 8U); - auto offset = llvm::ConstantInt::get(gWordType, num_loaded_stack_bytes); - - auto addr = ir.CreateAdd(sp, offset); - std::vector args = {remill::LoadMemoryPointer(block), addr}; - - llvm::DataLayout dl(gModule.get()); - auto alloc_size = static_cast(dl.getTypeAllocSize(goal_type)); - - llvm::Value *val = nullptr; - - if (goal_type->isX86_FP80Ty()) { - val = ir.CreateFPExt( - ir.CreateCall(gModule->getFunction("__remill_read_memory_f80"), args), - llvm::Type::getX86_FP80Ty(*gContext)); - - } else if (goal_type->isDoubleTy()) { - val = ir.CreateCall(gModule->getFunction("__remill_read_memory_f64"), args); - - } else if (goal_type->isFloatTy()) { - val = ir.CreateCall(gModule->getFunction("__remill_read_memory_f32"), args); - - } else if (goal_type->isIntegerTy()) { - auto read_mem = ReadIntFromMemFunc(alloc_size); - val = ir.CreateCall(read_mem, args); - if (dl.getTypeSizeInBits(goal_type) < - dl.getTypeAllocSizeInBits(goal_type)) { - val = ir.CreateTrunc(val, goal_type); - } - - } else if (goal_type->isPointerTy()) { - llvm::Function *func = nullptr; - if (32 == gArch->address_size) { - func = gModule->getFunction("__remill_read_memory_32"); - } else { - func = gModule->getFunction("__remill_read_memory_64"); - } - val = ir.CreateIntToPtr(ir.CreateCall(func, args), goal_type); - - } else { - LOG(FATAL) - << "Can't handle reading an " << remill::LLVMThingToString(goal_type) - << " value from the stack"; - } - - // Bump the stack pointer. - alloc_size = std::max(alloc_size, addr_size); - num_loaded_stack_bytes += alloc_size; - return val; -} - -llvm::Value *CallingConvention::LoadNextArgument(llvm::BasicBlock *block, - llvm::Type *target_type, - bool is_byval) { - if (!target_type) { - target_type = gWordType; - } - - llvm::IRBuilder<> ir(block); - - std::vector underlying_values; - llvm::Type *goal_type = target_type; - - if (target_type->isPointerTy() && !is_byval) { - return LoadNextSimpleArgument(block, target_type); - } - - if (auto struct_type = llvm::dyn_cast(goal_type)) { - std::vector underlying_values; - for (unsigned i = 0; i < struct_type->getNumElements(); ++i) { - llvm::Type *under_type = struct_type->getElementType(i); - underlying_values.push_back( - LoadNextSimpleArgument(block, under_type)); - } - - llvm::IRBuilder<> ir(block); - auto alloc_struct = ir.CreateAlloca(target_type); - for (unsigned i = 0; i < underlying_values.size(); ++i) { - llvm::Value *offsets[] = {GetConstantInt(64, 0), GetConstantInt(64, i)}; - auto gep = ir.CreateGEP(alloc_struct, offsets); - ir.CreateStore(underlying_values[i], gep); - } - return ir.CreateLoad(alloc_struct); - - } else if (is_byval) { - // byval attribute says that caller makes a copy of argument on the stack - // this happens if type of argument is bigger than 128 bits. - auto stack_ptr = LoadStackPointer(block); - auto offset = llvm::ConstantInt::get(gWordType, num_loaded_stack_bytes); - auto addr = ir.CreateAdd(stack_ptr, offset); - - llvm::DataLayout dl(gModule.get()); - auto ptr_type = llvm::dyn_cast(target_type); - - num_loaded_stack_bytes += dl.getTypeAllocSize(ptr_type->getElementType()); - return ir.CreateIntToPtr(addr, target_type); - } - - return LoadNextSimpleArgument(block, target_type); -} - -void CallingConvention::StoreVectorRetValue(llvm::BasicBlock *block, - llvm::Value *ret_val, - llvm::VectorType *goal_type) { - llvm::IRBuilder<> ir(block); - llvm::Type *under_type = goal_type->getElementType(); - llvm::DataLayout dl(gModule.get()); - - const size_t num_elements = goal_type->getNumElements(); - const ssize_t reg_size = static_cast(GetVectorRegSize()); - const ssize_t element_size = static_cast( - dl.getTypeAllocSize(under_type)); - const ssize_t reg_element_capacity = reg_size / element_size; - ssize_t remaining = static_cast(num_elements); - - for (ssize_t i = 0U; remaining > 0; ++i, remaining -= reg_element_capacity) { - auto reg_var_name = GetVarForNextReturn(goal_type); - LOG_IF(FATAL, !reg_var_name) - << "Could not find available vector register"; - llvm::Value *dest_loc = remill::FindVarInFunction(block, reg_var_name); - - // Clear out whatever was already there - auto storage_type = llvm::dyn_cast( - dest_loc->getType())->getElementType(); - ir.CreateStore(llvm::Constant::getNullValue(storage_type), dest_loc); - - dest_loc = ir.CreateBitCast(dest_loc, - llvm::PointerType::get(under_type, 0)); - - const auto count = std::min(reg_element_capacity, remaining); - const auto already_done = i * reg_element_capacity; - ExtractFromVector(block, ret_val, dest_loc, - static_cast(count), - static_cast(already_done)); - } -} - -void CallingConvention::StoreReturnValue(llvm::BasicBlock *block, - llvm::Value *ret_val) { - if (!ret_val) { - return; - } - - auto val_type = ret_val->getType(); - if (val_type->isVoidTy()) { - return; - } - - llvm::IRBuilder<> ir(block); - - for (unsigned i = 0; i < GetNumberOfElements(val_type); ++i) { - llvm::Value* target_val = ret_val; - - if (val_type->isStructTy()) { - target_val = ir.CreateExtractValue(ret_val, i); - } - auto under_type = RetrieveArgumentType(val_type, i); - - if (auto vector_type = llvm::dyn_cast(under_type)) { - StoreVectorRetValue(block, target_val, vector_type); - continue; - } - - auto val_var = GetVarForNextReturn(under_type); - - // If register was not found in default table it's possible - // that we are dealing with some special corner case - if (!val_var) { - if (GetNumberOfElements(val_type) == 1 && - TryStorePackedType(block, ret_val)) { - return; - } - - LOG(FATAL) - << "Cannot decide how to store " - << remill::LLVMThingToString(under_type) - << " part of " << remill::LLVMThingToString(val_type); - } - - // If it's a pointer then convert it to a pointer-sized integer. - if (under_type->isPointerTy()) { - target_val = ir.CreatePtrToInt(target_val, gWordType); - under_type = gWordType; - } - - // If it's an 80-bit float then convert it to a double. - if (under_type->isX86_FP80Ty()) { - under_type = llvm::Type::getDoubleTy(*gContext); - target_val = ir.CreateFPTrunc(target_val, under_type); - } - - CHECK(under_type->isIntegerTy() || under_type->isFloatTy() || - under_type->isDoubleTy()); - - llvm::DataLayout dl(gModule.get()); - - // Canonicalize integer return values into address-sized values. - if (under_type->isIntegerTy()) { - auto size = dl.getTypeSizeInBits(under_type); - if (size < gArch->address_size) { - under_type = gWordType; - target_val = ir.CreateZExt(target_val, under_type); - - } else if (size > gArch->address_size) { - LOG(ERROR) - << "Truncating value of type " - << remill::LLVMThingToString(under_type) - << " to store it into variable " << val_var - << " of type " << remill::LLVMThingToString(gWordType); - target_val = ir.CreateTrunc(target_val, gWordType); - under_type = gWordType; - } - - // Storing a `float` into an x87 register, convert it to a `double`. - } else if (under_type->isFloatTy()) { - if (val_var && val_var[0] == 'S' && val_var[1] == 'T') { - under_type = llvm::Type::getDoubleTy(*gContext); - target_val = ir.CreateFPExt(target_val, under_type); - } - } - - llvm::Value *dest_loc = remill::FindVarInFunction(block, val_var); - - // Clear out whatever was already there. - auto storage_type = llvm::dyn_cast( - dest_loc->getType())->getElementType(); - ir.CreateStore(llvm::Constant::getNullValue(storage_type), dest_loc); - - // Add in the new value. - dest_loc = ir.CreateBitCast(dest_loc, llvm::PointerType::get(under_type, 0)); - ir.CreateStore(target_val, dest_loc); - } - -} - -void CallingConvention::StoreArguments( - llvm::BasicBlock *block, const std::vector &arg_vals) { - - auto memory_ref = remill::LoadMemoryPointerRef(block); - - llvm::IRBuilder<> ir(block); - std::vector stack_arg_vals; - - // First try to put as many as possible into registers. - for (auto arg_val : arg_vals) { - auto arg_type = arg_val->getType(); - if (auto reg_var_name = GetVarForNextArgument(arg_type)) { - auto reg_ptr = remill::FindVarInFunction(block, reg_var_name); - ir.CreateStore( - arg_val, - ir.CreateBitCast(reg_ptr, llvm::PointerType::get(arg_type, 0))); - } else { - stack_arg_vals.push_back(arg_val); - } - } - - // Now we have some left that need to be pushed onto the stack. We're going - // to push them onto the stack in reverse order. - CHECK(gArch->IsX86() || gArch->IsAMD64() || gArch->IsAArch64()); - std::reverse(stack_arg_vals.begin(), stack_arg_vals.end()); - - auto addr_size = static_cast(gArch->address_size / 8U); - auto sp = LoadStackPointer(block); - llvm::Value *memory = ir.CreateLoad(memory_ref); - - llvm::DataLayout dl(gModule.get()); - - std::vector args(3, nullptr); - - for (auto arg_val : stack_arg_vals) { - auto arg_type = arg_val->getType(); - auto alloc_size = static_cast(dl.getTypeAllocSize(arg_type)); - llvm::Function *func = nullptr; - - if (arg_type->isX86_FP80Ty()) { - func = gModule->getFunction("__remill_write_memory_f80"); - arg_val = ir.CreateFPTrunc(arg_val, llvm::Type::getDoubleTy(*gContext)); - - } else if (arg_type->isDoubleTy()) { - func = gModule->getFunction("__remill_write_memory_f64"); - - } else if (arg_type->isFloatTy()) { - func = gModule->getFunction("__remill_write_memory_f32"); - - } else if (arg_type->isIntegerTy()) { - func = WriteIntToMemFunc(alloc_size); - - if (dl.getTypeSizeInBits(arg_type) < - dl.getTypeAllocSizeInBits(arg_type)) { - arg_type = llvm::Type::getIntNTy( - *gContext, static_cast(alloc_size * 8)); - arg_val = ir.CreateZExt(arg_val, arg_type); - } - - } else if (arg_type->isPointerTy()) { - if (32 == gArch->address_size) { - func = gModule->getFunction("__remill_write_memory_32"); - } else { - func = gModule->getFunction("__remill_write_memory_64"); - } - arg_val = ir.CreatePtrToInt(arg_val, gWordType); - } - - CHECK(func != nullptr) - << "Could not find remill memory write intrinsic to write a " - << alloc_size << "-byte value of type " - << remill::LLVMThingToString(arg_type) << " to the stack."; - - // Store the argument to the stack memory. - args[0] = memory; - args[1] = sp; - args[2] = arg_val; - memory = ir.CreateCall(func, args); - - // Bump the stack pointer. - alloc_size = std::max(alloc_size, addr_size); - sp = ir.CreateSub(sp, llvm::ConstantInt::get(gWordType, alloc_size)); - num_stored_stack_bytes += alloc_size; - } - - ir.CreateStore(memory, memory_ref); // Update the memory pointer. - - StoreStackPointer(block, sp); -} - -void CallingConvention::FreeArguments(llvm::BasicBlock *block) { - if (!num_stored_stack_bytes) { - return; - } - - if (llvm::CallingConv::X86_StdCall == cc || - llvm::CallingConv::X86_ThisCall == cc) { - return; // Callee cleanup. - } - - auto sp = LoadStackPointer(block); - - llvm::IRBuilder<> ir(block); - sp = ir.CreateAdd( - sp, llvm::ConstantInt::get(gWordType, num_stored_stack_bytes)); - - StoreStackPointer(block, sp); -} - -void CallingConvention::AllocateReturnAddress(llvm::BasicBlock *block) { - if (gArch->IsAArch64()) { - return; // Return address is passed through the link pointer. - - // The stack grows down on x86/amd64. - } else if (gArch->IsX86() || gArch->IsAMD64()) { - llvm::IRBuilder<> ir(block); - - auto addr_size = gArch->address_size / 8; - - if (llvm::CallingConv::Win64 == cc) { - CHECK(gArch->IsAMD64()); - addr_size += 32; // Shadow space. - } - - auto addr_size_bytes = llvm::ConstantInt::get(gWordType, addr_size); - StoreStackPointer( - block, ir.CreateSub(LoadStackPointer(block), addr_size_bytes)); - - } else { - LOG(FATAL) - << "Cannot allocate space for return address for architecture " - << remill::GetArchName(gArch->arch_name) << " and calling convention " - << cc; - } -} - -void CallingConvention::FreeReturnAddress(llvm::BasicBlock *block) { - if (gArch->IsAArch64()) { - auto x30 = remill::FindVarInFunction(block, "X30"); - llvm::IRBuilder<> ir(block); - auto ret_addr = ir.CreateLoad(x30); - remill::StoreProgramCounter(block, ret_addr); - - // The stack grows down on x86/amd64. - } else if (gArch->IsX86() || gArch->IsAMD64()) { - llvm::IRBuilder<> ir(block); - auto addr_size = gArch->address_size / 8; - auto addr_size_bytes = llvm::ConstantInt::get(gWordType, addr_size); - auto sp = LoadStackPointer(block); - auto read_ret_addr = ReadIntFromMemFunc(addr_size); - llvm::Value *read_ret_addr_args[] = {remill::LoadMemoryPointer(block), sp}; - auto ret_addr = ir.CreateCall(read_ret_addr, read_ret_addr_args); - remill::StoreProgramCounter(block, ret_addr); - - StoreStackPointer( - block, ir.CreateAdd(sp, addr_size_bytes)); - - } else { - LOG(FATAL) - << "Cannot allocate space for return address for architecture " - << remill::GetArchName(gArch->arch_name) << " and calling convention " - << cc; - } -} - -llvm::Value *CallingConvention::LoadReturnValue(llvm::BasicBlock *block, - llvm::Type *val_type) { - llvm::IRBuilder<> ir(block); - - if (!val_type) { - val_type = gWordType; - } - - //auto val_var = ReturnValVar(cc, val_type); - auto val_var = GetVarForNextReturn(val_type); - return ir.CreateLoad(ir.CreateBitCast( - remill::FindVarInFunction(block, val_var), - llvm::PointerType::get(val_type, 0))); -} - -llvm::Value *CallingConvention::LoadStackPointer(llvm::BasicBlock *block) { - llvm::IRBuilder<> ir(block); - return ir.CreateLoad(remill::FindVarInFunction(block, sp_name, false)); -} - -void CallingConvention::StoreStackPointer(llvm::BasicBlock *block, - llvm::Value *new_val) { - llvm::IRBuilder<> ir(block); - auto val_type = new_val->getType(); - if (val_type->isPointerTy()) { - new_val = ir.CreatePtrToInt(new_val, gWordType); - } - ir.CreateStore( - new_val, - remill::FindVarInFunction(block, StackPointerVarName())); -} - -void CallingConvention::StoreThreadPointer(llvm::BasicBlock *block, - llvm::Value *new_val) { - llvm::IRBuilder<> ir(block); - auto val_type = new_val->getType(); - if (val_type->isPointerTy()) { - new_val = ir.CreatePtrToInt(new_val, gWordType); - } - ir.CreateStore( - new_val, - remill::FindVarInFunction(block, ThreadPointerVarName())); -} - -// Return the address of the base of the TLS data. -llvm::Value *GetTLSBaseAddress(llvm::IRBuilder<> &ir) { - enum { - kGSAddressSpace = 256U, - kFSAddressSpace = 257U, - - // From inside of the TEB. - kWin32TLSPointerIndex = 0x2c, - kWin64TLSPointerIndex = 0x58 - }; - - if (gArch->IsAArch64()) { - -#if LLVM_VERSION(3, 7) >= LLVM_VERSION_NUMBER - LOG(ERROR) - << "LLVM 3.7 and below have no AArch64 thread pointer-related " - << "intrinsics; using NULL as the base of TLS."; - return llvm::ConstantInt::get(gWordType, 0); - -#elif LLVM_VERSION(3, 8) >= LLVM_VERSION_NUMBER - LOG(ERROR) - << "Assuming the `llvm.arm.thread.pointer` intrinsic gets us the base " - << "of thread-local storage."; - auto func = llvm::Intrinsic::getDeclaration( - gModule.get(), llvm::Intrinsic::arm_thread_pointer); - return ir.CreatePtrToInt(ir.CreateCall(func), gWordType); -#else - LOG(ERROR) - << "Assuming the `thread.pointer` intrinsic gets us the base " - << "of thread-local storage."; - auto func = llvm::Intrinsic::getDeclaration( - gModule.get(), llvm::Intrinsic::thread_pointer); - return ir.CreatePtrToInt(ir.CreateCall(func), gWordType); -#endif - - // 64-bit x86. - } else if (gArch->IsAMD64()) { - llvm::ConstantInt *base = nullptr; - unsigned addr_space = 0; - if (remill::kOSWindows == gArch->os_name) { - base = llvm::ConstantInt::get(gWordType, kWin64TLSPointerIndex); - addr_space = kGSAddressSpace; - } else if (remill::kOSLinux == gArch->os_name) { - base = llvm::ConstantInt::get(gWordType, 0); - addr_space = kFSAddressSpace; - } - - if (base) { - auto tls_base_ptr = ir.CreateIntToPtr( - base, llvm::PointerType::get(gWordType, addr_space)); - return ir.CreateLoad(tls_base_ptr); - } - - // 32-bit x86. - } else if (gArch->IsX86()) { - llvm::ConstantInt *base = nullptr; - unsigned addr_space = 0; - if (remill::kOSWindows == gArch->os_name) { - base = llvm::ConstantInt::get(gWordType, kWin32TLSPointerIndex); - addr_space = kFSAddressSpace; - } else if (remill::kOSLinux == gArch->os_name) { - base = llvm::ConstantInt::get(gWordType, 0); - addr_space = kGSAddressSpace; - } - - if (base) { - auto tls_base_ptr = ir.CreateIntToPtr( - base, llvm::PointerType::get(gWordType, addr_space)); - return ir.CreateLoad(tls_base_ptr); - } - } - - LOG(FATAL) - << "Cannot generate code to find the thread base pointer for arch " - << remill::GetArchName(gArch->arch_name) << " and OS " - << remill::GetOSName(gArch->os_name); - return nullptr; -} - -} // namespace mcsema diff --git a/mcsema/Arch/ABI.h b/mcsema/Arch/ABI.h deleted file mode 100644 index 7552c2e6b..000000000 --- a/mcsema/Arch/ABI.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2017 Trail of Bits, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef MCSEMA_ARCH_ABI_H_ -#define MCSEMA_ARCH_ABI_H_ - -#include -#include - -#include "remill/BC/Compat/CallingConvention.h" - -namespace llvm { -class Type; -} // namespace llvm -namespace mcsema { - -struct ArgConstraint { - std::string var_name; - const int accepted_val_kinds; -}; - -// Generic functions for reading/writing to the register/stack state in a way -// that respects a supplied calling convention. -class CallingConvention { - public: - explicit CallingConvention(llvm::CallingConv::ID cc_); - - llvm::Value *LoadNextArgument(llvm::BasicBlock *block, - llvm::Type *goal_type=nullptr, - bool is_byval=false); - - void StoreReturnValue(llvm::BasicBlock *block, llvm::Value *ret_val); - - void StoreArguments(llvm::BasicBlock *block, - const std::vector &arg_vals); - - void FreeArguments(llvm::BasicBlock *block); - - void AllocateReturnAddress(llvm::BasicBlock *block); - void FreeReturnAddress(llvm::BasicBlock *block); - - llvm::Value *LoadReturnValue(llvm::BasicBlock *block, - llvm::Type *goal_type=nullptr); - - llvm::Value *LoadStackPointer(llvm::BasicBlock *block); - - void StoreStackPointer(llvm::BasicBlock *block, llvm::Value *new_val); - - const char *StackPointerVarName(void) const { - return sp_name; - } - - void StoreThreadPointer(llvm::BasicBlock *block, llvm::Value *new_val); - - const char *ThreadPointerVarName(void) const { - return tp_name; - } - - private: - void StoreVectorRetValue(llvm::BasicBlock *block, - llvm::Value *ret_val, - llvm::VectorType *goal_type); - - llvm::Value *LoadVectorArgument(llvm::BasicBlock *block, - llvm::VectorType *goal_type); - llvm::Value *LoadNextSimpleArgument(llvm::BasicBlock *block, - llvm::Type *goal_type); - - const char *GetVarForNextArgument(llvm::Type *val_type); - const char *GetVarForNextReturn(llvm::Type *val_type); - - llvm::CallingConv::ID cc; - uint64_t used_reg_bitmap; - uint64_t used_return_bitmap; - uint64_t num_loaded_stack_bytes; - uint64_t num_stored_stack_bytes; - const char * const sp_name; - const char * const tp_name; - const std::vector ®_table; - const std::vector &return_table; - CallingConvention(void) = delete; -}; - -// Return the address of the base of the TLS data. -llvm::Value *GetTLSBaseAddress(llvm::IRBuilder<> &ir); - -} // namespace mcsema - -#endif // MCSEMA_ARCH_ABI_H_ diff --git a/mcsema/Arch/Arch.cpp b/mcsema/Arch/Arch.cpp index e20a03ad1..4b47806a4 100644 --- a/mcsema/Arch/Arch.cpp +++ b/mcsema/Arch/Arch.cpp @@ -1,19 +1,22 @@ /* - * Copyright (c) 2017 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ +#include "mcsema/Arch/Arch.h" + #include #include @@ -21,6 +24,7 @@ #include #include +#include #include #include #include @@ -31,24 +35,31 @@ #include #include -#include "remill/Arch/Arch.h" +#include -#include "mcsema/Arch/Arch.h" #include "mcsema/BC/Util.h" namespace mcsema { extern std::shared_ptr gContext; -const remill::Arch *gArch = nullptr; +std::unique_ptr gArch(nullptr); bool InitArch(const std::string &os, const std::string &arch) { LOG(INFO) << "Initializing for " << arch << " code on " << os; - gArch = remill::GetTargetArch(*gContext); + remill::Arch::GetTargetArch(*gContext).swap(gArch); gWordType = llvm::Type::getIntNTy( *gContext, static_cast(gArch->address_size)); + + gWordMask = 0; + if (32 == gArch->address_size) { + gWordMask = static_cast(~0u); + } else { + gWordMask = ~gWordMask; + } + return true; } diff --git a/mcsema/Arch/Arch.h b/mcsema/Arch/Arch.h index 0dbcaf604..9e54e5808 100644 --- a/mcsema/Arch/Arch.h +++ b/mcsema/Arch/Arch.h @@ -1,22 +1,23 @@ /* - * Copyright (c) 2017 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ -#ifndef MCSEMA_ARCH_ARCH_H_ -#define MCSEMA_ARCH_ARCH_H_ +#pragma once +#include #include namespace remill { @@ -25,10 +26,8 @@ class Arch; namespace mcsema { -extern const remill::Arch *gArch; +extern std::unique_ptr gArch; bool InitArch(const std::string &os, const std::string &arch); } // namespace mcsema - -#endif // MCSEMA_ARCH_ARCH_H_ diff --git a/mcsema/Arch/X86/Runtime/CMakeLists.txt b/mcsema/Arch/X86/Runtime/CMakeLists.txt index 6b5878d89..6af8adee5 100644 --- a/mcsema/Arch/X86/Runtime/CMakeLists.txt +++ b/mcsema/Arch/X86/Runtime/CMakeLists.txt @@ -1,16 +1,17 @@ -# Copyright (c) 2017 Trail of Bits, Inc. +# Copyright (c) 2020 Trail of Bits, Inc. # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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 Affero General Public License for more details. # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . enable_language(ASM) @@ -206,10 +207,19 @@ else() endif() endif() + +if(DEFINED REMILL_INCLUDE_LOCATION) + set(REMILL_INCLUDE "-I${REMILL_INCLUDE_LOCATION}") +endif() + +if(DEFINED REMILL_SOURCE_DIR) + set(REMILL_SOURCE "-I${REMILL_SOURCE_DIR}") +endif() + # Create a runtime. add_custom_command( OUTPUT runtime_32.o - COMMAND "${CMAKE_CXX_COMPILER}" -std=gnu++11 -isystem "${REMILL_INCLUDE_LOCATION}" -isystem "${MCSEMA_SOURCE_DIR}" -m32 -fPIC -c "${CMAKE_CURRENT_SOURCE_DIR}/Runtime.cpp" -o runtime_32.o + COMMAND "${CMAKE_CXX_COMPILER}" -std=gnu++11 "${REMILL_INCLUDE}" "${REMILL_SOURCE}" "${REMILL_SOURCE_DIR}" -I"${MCSEMA_SOURCE_DIR}" -m32 -fPIC -c "${CMAKE_CURRENT_SOURCE_DIR}/Runtime.cpp" -o runtime_32.o DEPENDS Runtime.cpp COMMENT "Building 32-bit runtime" ) @@ -225,7 +235,7 @@ set_source_files_properties( if(CMAKE_SIZEOF_VOID_P EQUAL 8) add_custom_command( OUTPUT runtime_64.o - COMMAND "${CMAKE_CXX_COMPILER}" -std=gnu++11 -isystem "${REMILL_INCLUDE_LOCATION}" -isystem "${MCSEMA_SOURCE_DIR}" -m64 -fPIC -c "${CMAKE_CURRENT_SOURCE_DIR}/Runtime.cpp" -o runtime_64.o + COMMAND "${CMAKE_CXX_COMPILER}" -std=gnu++11 "${REMILL_INCLUDE}" "${REMILL_SOURCE}" -I"${MCSEMA_SOURCE_DIR}" -m64 -fPIC -c "${CMAKE_CURRENT_SOURCE_DIR}/Runtime.cpp" -o runtime_64.o DEPENDS Runtime.cpp COMMENT "Building 64-bit runtime" ) @@ -237,3 +247,21 @@ if(CMAKE_SIZEOF_VOID_P EQUAL 8) GENERATED True ) endif() + +add_runtime(runtime_x86 + SOURCES "Runtime.cpp" + ADDRESS_SIZE 32 + BCFLAGS "-xc++" "-m32" "-std=gnu++17" "-Wno-deprecated-declarations" + INCLUDEDIRECTORIES "${CMAKE_SOURCE_DIR}" "${MCSEMA_SOURCE_DIR}" "${REMILL_INCLUDE_LOCATION}" + INSTALLDESTINATION "${install_folder}/lib" +) + +if(CMAKE_SIZEOF_VOID_P EQUAL 8) + add_runtime(runtime_amd64 + SOURCES "Runtime.cpp" + ADDRESS_SIZE 64 + BCFLAGS "-xc++" "-m64" "-std=gnu++17" "-Wno-deprecated-declarations" + INCLUDEDIRECTORIES "${CMAKE_SOURCE_DIR}" "${MCSEMA_SOURCE_DIR}" "${REMILL_INCLUDE_LOCATION}" + INSTALLDESTINATION "${install_folder}/lib" + ) +endif() diff --git a/mcsema/Arch/X86/Runtime/Registers.h b/mcsema/Arch/X86/Runtime/Registers.h index e75c62eff..16e4cb8a6 100644 --- a/mcsema/Arch/X86/Runtime/Registers.h +++ b/mcsema/Arch/X86/Runtime/Registers.h @@ -1,17 +1,18 @@ /* - * Copyright (c) 2017 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ #ifndef MCSEMA_ARCH_X86_RUNTIME_REGISTERS_H_ @@ -77,23 +78,23 @@ #define R14D gpr.r14.dword #define R15D gpr.r15.dword -#define RAX gpr.rax.qword -#define RBX gpr.rbx.qword -#define RCX gpr.rcx.qword -#define RDX gpr.rdx.qword -#define RSI gpr.rsi.qword -#define RDI gpr.rdi.qword -#define RSP gpr.rsp.qword -#define RBP gpr.rbp.qword -#define R8 gpr.r8.qword -#define R9 gpr.r9.qword -#define R10 gpr.r10.qword -#define R11 gpr.r11.qword -#define R12 gpr.r12.qword -#define R13 gpr.r13.qword -#define R14 gpr.r14.qword -#define R15 gpr.r15.qword -#define RIP gpr.rip.qword +#define RAX gpr.rax.aword +#define RBX gpr.rbx.aword +#define RCX gpr.rcx.aword +#define RDX gpr.rdx.aword +#define RSI gpr.rsi.aword +#define RDI gpr.rdi.aword +#define RSP gpr.rsp.aword +#define RBP gpr.rbp.aword +#define R8 gpr.r8.aword +#define R9 gpr.r9.aword +#define R10 gpr.r10.aword +#define R11 gpr.r11.aword +#define R12 gpr.r12.aword +#define R13 gpr.r13.aword +#define R14 gpr.r14.aword +#define R15 gpr.r15.aword +#define RIP gpr.rip.aword #define SS seg.ss #define ES seg.es diff --git a/mcsema/Arch/X86/Runtime/Runtime.cpp b/mcsema/Arch/X86/Runtime/Runtime.cpp index c03b70d4d..2dd058160 100644 --- a/mcsema/Arch/X86/Runtime/Runtime.cpp +++ b/mcsema/Arch/X86/Runtime/Runtime.cpp @@ -1,27 +1,32 @@ /* - * Copyright (c) 2017 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ #include #include #include #include +#include #define HAS_FEATURE_AVX 1 #define HAS_FEATURE_AVX512 0 -#define ADDRESS_SIZE_BITS 64 + +#ifndef ADDRESS_SIZE_BITS +# define ADDRESS_SIZE_BITS 64 +#endif #include "remill/Arch/X86/Runtime/State.h" #include "mcsema/Arch/X86/Runtime/Registers.h" @@ -34,6 +39,12 @@ # define PRIx32 "x" #endif +#if ADDRESS_SIZE_BITS == 64 +# define PRIxADDR PRIx64 +#else +# define PRIxADDR PRIx32 +#endif + extern "C" { // Debug registers. @@ -130,16 +141,15 @@ Memory *__remill_sync_hyper_call( } Memory *__mcsema_reg_tracer(State &state, addr_t, Memory *memory) { - const char *format = nullptr; if (sizeof(void *) == 8) { fprintf( stderr, - "RIP=%" PRIx64 ",RAX=%" PRIx64 ",RBX=%" PRIx64 - ",RCX=%" PRIx64 ",RDX=%" PRIx64 ",RSI=%" PRIx64 - ",RDI=%" PRIx64 ",RBP=%" PRIx64 ",RSP=%" PRIx64 - ",R8=%" PRIx64 ",R9=%" PRIx64 ",R10=%" PRIx64 - ",R11=%" PRIx64 ",R12=%" PRIx64 ",R13=%" PRIx64 - ",R14=%" PRIx64 ",R15=%" PRIx64 "\n", + "RIP=%" PRIxADDR ",RAX=%" PRIxADDR ",RBX=%" PRIxADDR + ",RCX=%" PRIxADDR ",RDX=%" PRIxADDR ",RSI=%" PRIxADDR + ",RDI=%" PRIxADDR ",RBP=%" PRIxADDR ",RSP=%" PRIxADDR + ",R8=%" PRIxADDR ",R9=%" PRIxADDR ",R10=%" PRIxADDR + ",R11=%" PRIxADDR ",R12=%" PRIxADDR ",R13=%" PRIxADDR + ",R14=%" PRIxADDR ",R15=%" PRIxADDR "\n", state.RIP, state.RAX, state.RBX, state.RCX, state.RDX, state.RSI, state.RDI, state.RBP, state.RSP, state.R8, state.R9, state.R10, diff --git a/mcsema/Arch/X86/Runtime/print_ELF_32_linux.cpp b/mcsema/Arch/X86/Runtime/print_ELF_32_linux.cpp index 753f84d09..9643425d3 100644 --- a/mcsema/Arch/X86/Runtime/print_ELF_32_linux.cpp +++ b/mcsema/Arch/X86/Runtime/print_ELF_32_linux.cpp @@ -1,17 +1,18 @@ /* - * Copyright (c) 2017 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ #include diff --git a/mcsema/Arch/X86/Runtime/print_ELF_64_linux.cpp b/mcsema/Arch/X86/Runtime/print_ELF_64_linux.cpp index 1e08484c1..ac8af3228 100644 --- a/mcsema/Arch/X86/Runtime/print_ELF_64_linux.cpp +++ b/mcsema/Arch/X86/Runtime/print_ELF_64_linux.cpp @@ -1,17 +1,18 @@ /* - * Copyright (c) 2017 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ #include diff --git a/mcsema/Arch/X86/Runtime/print_PE_32_windows.cpp b/mcsema/Arch/X86/Runtime/print_PE_32_windows.cpp index 7d0c73734..c40fc262e 100644 --- a/mcsema/Arch/X86/Runtime/print_PE_32_windows.cpp +++ b/mcsema/Arch/X86/Runtime/print_PE_32_windows.cpp @@ -1,17 +1,18 @@ /* - * Copyright (c) 2017 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ #include diff --git a/mcsema/Arch/X86/Runtime/print_PE_64_windows.cpp b/mcsema/Arch/X86/Runtime/print_PE_64_windows.cpp index a9fdd6443..c48835cbd 100644 --- a/mcsema/Arch/X86/Runtime/print_PE_64_windows.cpp +++ b/mcsema/Arch/X86/Runtime/print_PE_64_windows.cpp @@ -1,17 +1,18 @@ /* - * Copyright (c) 2017 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ #include diff --git a/mcsema/BC/Callback.cpp b/mcsema/BC/Callback.cpp index 12c3493ef..6f5f5145c 100644 --- a/mcsema/BC/Callback.cpp +++ b/mcsema/BC/Callback.cpp @@ -1,19 +1,22 @@ /* - * Copyright (c) 2017 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ +#include "mcsema/BC/Callback.h" + #include #include @@ -30,16 +33,19 @@ #include #include -#include "remill/Arch/Arch.h" -#include "remill/Arch/Name.h" -#include "remill/BC/ABI.h" -#include "remill/BC/Annotate.h" -#include "remill/BC/Util.h" -#include "remill/BC/Version.h" +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include -#include "mcsema/Arch/ABI.h" #include "mcsema/Arch/Arch.h" -#include "mcsema/BC/Callback.h" #include "mcsema/BC/Legacy.h" #include "mcsema/BC/Segment.h" #include "mcsema/BC/Util.h" @@ -54,15 +60,19 @@ DEFINE_bool(explicit_args, false, "bitcode, especially where floating point argument and return " "values are concerned."); -DEFINE_uint64(explicit_args_count, 8, +DEFINE_uint32(explicit_args_count, 8, "Number of explicit (integer) arguments to pass to an unknown " "function, or to accept from an unknown function. This value is " - "used when "); + "used when calling external functions for which no type " + "information is known, or who take a variable number of arguments."); -DEFINE_uint64(explicit_args_stack_size, 4096 * 256 /* 1 MiB */, +DEFINE_uint32(explicit_args_stack_size, 4096 * 256 /* 1 MiB */, "Size of the stack of the emulated program when the program " "is lifted using --explicit_args."); +DEFINE_uint32(explicit_args_tls_size, 4 * 4096, + "Number of bytes of thread local storage"); + DECLARE_bool(stack_protector); namespace mcsema { @@ -153,15 +163,17 @@ static llvm::Function *ImplementNativeToLiftedCallback( // Create the callback function that calls the inline assembly. auto callback_type = llvm::FunctionType::get(void_type, false); - auto callback_func = llvm::Function::Create( - callback_type, llvm::GlobalValue::InternalLinkage, // Tentative linkage. - callback_name, gModule.get()); + auto callback_func = gModule->getFunction(callback_name); + if (!callback_func) { + callback_func = llvm::Function::Create( + callback_type, llvm::GlobalValue::InternalLinkage, // Tentative linkage. + callback_name, gModule.get()); + } callback_func->setVisibility(llvm::GlobalValue::DefaultVisibility); callback_func->addFnAttr(llvm::Attribute::Naked); callback_func->addFnAttr(llvm::Attribute::NoInline); callback_func->addFnAttr(llvm::Attribute::NoBuiltin); - // Create the inline assembly. We use memory operands ( std::vector asm_arg_types; std::vector asm_args; @@ -222,7 +234,12 @@ static llvm::Function *ImplementNativeToLiftedCallback( asm_args.push_back(attach_func_ptr); ir.CreateCall(asm_func, asm_args); - ir.CreateRetVoid(); + + if (auto ret_type = callback_func->getReturnType(); ret_type->isVoidTy()) { + ir.CreateRetVoid(); + } else { + ir.CreateRet(llvm::UndefValue::get(ret_type)); + } if (!FLAGS_pc_annotation.empty()) { legacy::AnnotateInsts(callback_func, cfg_func->ea); @@ -238,20 +255,30 @@ static llvm::Function *ImplementNativeToLiftedCallback( // Create a stack and a variable that tracks the stack pointer. static llvm::Constant *InitialStackPointerValue(void) { - auto stack_type = llvm::ArrayType::get( - gWordType, FLAGS_explicit_args_stack_size / (gArch->address_size / 8)); + unsigned min_frame_size = 512u; + const auto num_bytes = std::max(FLAGS_explicit_args_stack_size, + 4096u + min_frame_size); + auto i8_type = llvm::Type::getInt8Ty(*gContext); + auto stack_type = llvm::ArrayType::get(i8_type, num_bytes); - static llvm::GlobalVariable *stack = nullptr; + static llvm::Constant *stack = nullptr; if (!stack) { - stack = new llvm::GlobalVariable( + auto stack_var = new llvm::GlobalVariable( *gModule, stack_type, false, llvm::GlobalValue::InternalLinkage, - llvm::Constant::getNullValue(stack_type), "__mcsema_stack"); - stack->setThreadLocal(true); + llvm::ConstantAggregateZero::get(stack_type), "__mcsema_stack", + nullptr, llvm::GlobalValue::InitialExecTLSModel); + stack = stack_var; + + if (stack_var->getType()->getAddressSpace()) { + stack = llvm::ConstantExpr::getAddrSpaceCast( + stack_var, llvm::PointerType::get(stack_type, 0)); + } } - std::vector indexes(2); - indexes[0] = llvm::ConstantInt::get(gWordType, 0); - indexes[1] = llvm::ConstantInt::get( - gWordType, stack_type->getNumElements() - 8); + + const auto i32_ty = llvm::Type::getInt32Ty(*gContext); + llvm::Constant *indexes[2]; + indexes[0] = llvm::ConstantInt::get(i32_ty, 0); + indexes[1] = llvm::ConstantInt::get(i32_ty, num_bytes - min_frame_size); #if LLVM_VERSION_NUMBER <= LLVM_VERSION(3, 6) auto gep = llvm::ConstantExpr::getInBoundsGetElementPtr(stack, indexes); @@ -262,88 +289,106 @@ static llvm::Constant *InitialStackPointerValue(void) { return llvm::ConstantExpr::getPtrToInt(gep, gWordType); } -// Create an array of data for holding thread-local storage. -static llvm::Constant *InitialThreadLocalStorage(void) { - static llvm::Constant *tls = nullptr; - if (tls) { - return tls; +static const char *ThreadPointerNameX86(void) { + switch (gArch->os_name) { + case remill::kOSLinux: + return "GS_BASE"; + case remill::kOSWindows: + return "FS_BASE"; + default: + return nullptr; + } +} + +static const char *ThreadPointerNameAMD64(void) { + switch (gArch->os_name) { + case remill::kOSLinux: + return "FS_BASE"; + case remill::kOSWindows: + return "GS_BASE"; + default: + return nullptr; + } +} + +static const char *ThreadPointerName(void) { + const char *tp_name = nullptr; + switch (gArch->arch_name) { + case remill::kArchAArch64LittleEndian: + return "TPIDR_EL0"; + + case remill::kArchX86: + case remill::kArchX86_AVX: + case remill::kArchX86_AVX512: + tp_name = ThreadPointerNameX86(); + break; + + case remill::kArchAMD64: + case remill::kArchAMD64_AVX: + case remill::kArchAMD64_AVX512: + tp_name = ThreadPointerNameAMD64(); + break; + + default: + break; } - auto tls_type = llvm::ArrayType::get( - gWordType, 4096 / (gArch->address_size / 8)); + LOG_IF(ERROR, !tp_name) + << "Can't get thread pointer name for architecture " + << remill::GetArchName(gArch->arch_name) << " and OS " + << remill::GetOSName(gArch->os_name); + return tp_name; +} + +// Create an array of data for holding thread-local storage. +static llvm::Constant *InitialThreadLocalStorage(void) { + + // Add some TLS pages. + llvm::ArrayType *tls_type = llvm::ArrayType::get( + gWordType, FLAGS_explicit_args_tls_size / (gArch->address_size / 8)); auto tls_var = new llvm::GlobalVariable( *gModule, tls_type, false, llvm::GlobalValue::InternalLinkage, - llvm::Constant::getNullValue(tls_type), "__mcsema_tls"); - tls_var->setThreadLocal(true); + llvm::Constant::getNullValue(tls_type), "__mcsema_tls", + nullptr, llvm::GlobalValue::InitialExecTLSModel); - std::vector indexes(2); - indexes[0] = llvm::ConstantInt::get(gWordType, 0); + llvm::Constant *tls = tls_var; + if (tls_var->getType()->getAddressSpace()) { + tls = llvm::ConstantExpr::getAddrSpaceCast( + tls_var, llvm::PointerType::get(tls_type, 0)); + } + + const auto i32_ty = llvm::Type::getInt32Ty(*gContext); + llvm::Constant *indexes[2]; + indexes[0] = llvm::ConstantInt::get(i32_ty, 0); indexes[1] = indexes[0]; #if LLVM_VERSION_NUMBER <= LLVM_VERSION(3, 6) - auto gep = llvm::ConstantExpr::getInBoundsGetElementPtr(tls_var, indexes); + tls = llvm::ConstantExpr::getInBoundsGetElementPtr(tls, indexes); #else - auto gep = llvm::ConstantExpr::getInBoundsGetElementPtr( - nullptr, tls_var, indexes); + tls = llvm::ConstantExpr::getInBoundsGetElementPtr( + nullptr, tls, indexes); #endif - tls = llvm::ConstantExpr::getPtrToInt(gep, gWordType); + tls = llvm::ConstantExpr::getPtrToInt(tls, gWordType); return tls; } -// Figure ouf the byte offset of the stack pointer register in the `State` -// structure. -static uint64_t GetStackPointerOffset(void) { - CallingConvention cc(gArch->DefaultCallingConv()); - std::string sp_name(cc.StackPointerVarName()); - auto reg = gArch->RegisterByName(sp_name); - CHECK(reg != nullptr) - << "Could not identify stack pointer " << sp_name - << " register in State structure"; - - return reg->offset; -} - -// Create a global register state pointer to pass to lifted functions. -static llvm::GlobalVariable *GetStatePointer(void) { - static llvm::GlobalVariable *state_ptr = nullptr; - if (state_ptr) { - return state_ptr; - } - - auto lifted_func_type = LiftedFunctionType(); - auto state_ptr_type = lifted_func_type->getFunctionParamType( - remill::kStatePointerArgNum); - auto state_type = llvm::dyn_cast( - state_ptr_type)->getElementType(); - - // State is initialized with zeroes. Each callback/entrypoint set - // appropriate value to stack pointer. This is needed because of - // thread_local - auto state_init = llvm::ConstantAggregateZero::get(state_type); - state_ptr = new llvm::GlobalVariable( - *gModule, state_type, false, llvm::GlobalValue::InternalLinkage, - state_init, "__mcsema_reg_state"); - state_ptr->setThreadLocal(true); - return state_ptr; -} - -// note(lukas): We don't need to annotate, it will always be inlined +// NOTE(lukas): We don't need to annotate, it will always be inlined. static llvm::Function *CreateVerifyRegState(void) { - auto *func_type = llvm::FunctionType::get(llvm::Type::getVoidTy(*gContext), - {}, false); + auto reg_state = GetStatePointer(); + auto *func_type = llvm::FunctionType::get(reg_state->getType(), false); auto new_func = gModule->getOrInsertFunction( - "__mcsema_verify_reg_state", + "__mcsema_init_reg_state", func_type); auto func = llvm::dyn_cast( new_func IF_LLVM_GTE_900(.getCallee())); CHECK(func != nullptr) - << "Could not get or create function '__mcsema_verify_reg_state'"; + << "Could not get or create function '__mcsema_init_reg_state'"; - auto sp_offset = GetStackPointerOffset(); - auto reg_state = GetStatePointer(); + const auto sp_name = gArch->StackPointerRegisterName(); + auto sp_reg = gArch->RegisterByName(sp_name); auto entry_block = llvm::BasicBlock::Create(*gContext, "entry", func); auto is_null_block = llvm::BasicBlock::Create(*gContext, "is_null", func); @@ -352,38 +397,63 @@ static llvm::Function *CreateVerifyRegState(void) { // Need to find out where stack pointer is and known information is // byte offset in state structure - auto byte_ty = llvm::Type::getInt8PtrTy(*gContext); +// auto byte_ty = llvm::Type::getInt8PtrTy(*gContext); unsigned ptr_size = static_cast(gArch->address_size); auto reg_ptr_ty = llvm::PointerType::getIntNPtrTy(*gContext, ptr_size); - - auto casted_reg_state = ir.CreateBitCast(reg_state, byte_ty); - auto rsp = ir.CreateGEP(casted_reg_state, ir.getInt64(sp_offset)); + //TODO(lukas): remove after abi_libraries patch gets merged into master + auto GetConstantInt = [&](unsigned size, uint64_t value) { + return llvm::ConstantInt::get( + llvm::Type::getIntNTy(*gContext, size), value); + }; +// auto casted_reg_state = ir.CreateBitCast(reg_state, byte_ty); + auto rsp = sp_reg->AddressOf(reg_state, entry_block); auto casted_rsp = ir.CreateBitCast(rsp, reg_ptr_ty); - auto rsp_val = ir.CreateLoad(casted_rsp, - llvm::Type::getIntNTy(*gContext, ptr_size)); + auto rsp_val = ir.CreateLoad( + casted_rsp, llvm::Type::getIntNTy(*gContext, ptr_size)); auto comparison = ir.CreateICmpEQ(rsp_val, GetConstantInt(ptr_size, 0)); ir.CreateCondBr(comparison, is_null_block, end_block); // Stack pointer is pointing at nothing, so we need to set it up ir.SetInsertPoint(is_null_block); ir.CreateStore(InitialStackPointerValue(), casted_rsp); + + // Store the address of `__mcsema_tls` into the TLS register. + if (auto tp_name = ThreadPointerName(); tp_name) { + if (auto tp_reg = gArch->RegisterByName(tp_name); tp_reg) { + ir.CreateStore( + InitialThreadLocalStorage(), + tp_reg->AddressOf(reg_state, is_null_block)); + } + } + + ir.SetInsertPoint(is_null_block); + + // Call the `__mcsema_early_init` function to make sure all lazy cross- + // reference initializers have been installed before any lifted bitcode + // is executed. + ir.CreateCall(GetOrCreateMcSemaInitializer()); + ir.CreateBr(end_block); // Last block just returns void ir.SetInsertPoint(end_block); - ir.CreateRetVoid(); + ir.CreateRet(reg_state); return func; } +// TODO(lukas): VerifyRegState is probably not the best name. +// Maybe VerifyStackPointer? +// Opened to suggestions. + // Because of possible parallelism, both global stack and state must be // thread_local. However after new thread is created, its stack and state // are initialized to default values. // Which means that state is zero initialized // This function verifies that the stack pointer points to some location // and if not then sets it up to point into stack with default offset -llvm::Function *GetVerifyRegState(void) { +static llvm::Function *GetVerifyRegState(void) { static llvm::Function *func = nullptr; if (!func) { func = CreateVerifyRegState(); @@ -391,163 +461,190 @@ llvm::Function *GetVerifyRegState(void) { return func; } -// Inserts call to __mcsema_verify_reg_state as first instruction in function -void InsertVerifyFunction(llvm::Function *func) { - auto &first_inst = func->front().front(); - auto verify_func = GetVerifyRegState(); - llvm::CallInst::Create(verify_func, {}, "", &first_inst); -} - // Implements a stub for an externally defined function in such a way that // the external is explicitly called, and arguments from the modeled CPU // state are passed into the external. static llvm::Function *ImplementExplicitArgsEntryPoint( - const NativeObject *cfg_func, const std::string &name) { + const NativeFunction *cfg_func, const std::string &name) { - auto num_args = FLAGS_explicit_args_count; - if (name == "main") { - num_args = 3; - } + auto func = gModule->getFunction(name); + if (!func) { + auto num_args = FLAGS_explicit_args_count; - // These function needs to be created with 0 arguments, otherwise - // lift could crash when using both --explicit_args - // and --libc_constructor (issue #424) - const static std::array zero_argument_functions = {{ - "__libc_csu_init", - "__libc_csu_fini", - "init", - "fini" - }}; - - for (const auto &zero_func_name : zero_argument_functions) { - if (cfg_func->name == zero_func_name) { - num_args = 0; - break; + // Get correct return type -> i32 for main + llvm::Type *ret_type = gWordType; + if (name == "main" || name == "_main") { + num_args = 3; + ret_type = llvm::Type::getInt32Ty(*gContext); } + + LOG(INFO) + << "Generating explicit argument entrypoint function for " + << name << ", calling into " << cfg_func->lifted_name; + + std::vector arg_types(num_args, gWordType); + + auto func_type = llvm::FunctionType::get(ret_type, arg_types, false); + func = llvm::Function::Create( + func_type, llvm::GlobalValue::InternalLinkage, name, gModule.get()); + DCHECK_EQ(func->getName().str(), name); } - // Get correct return type -> i32 for main - auto ret_type = [&]() -> llvm::Type* { - if (name == "main") { - return llvm::Type::getInt32Ty(*gContext); - } - return remill::AddressType(gModule.get()); - }(); - - // The the lifted function type so that we can get things like the memory - // pointer type and stuff. - auto bb = remill::BasicBlockFunction(gModule.get()); - auto state_ptr_arg = remill::NthArgument(bb, remill::kStatePointerArgNum); - auto mem_ptr_arg = remill::NthArgument(bb, remill::kMemoryPointerArgNum); - auto pc_arg = remill::NthArgument(bb, remill::kPCArgNum); - auto pc_type = pc_arg->getType(); - - LOG(INFO) - << "Generating explicit argument entrypoint function for " - << name << ", calling into " << cfg_func->lifted_name; - - std::vector arg_types(num_args, pc_type); - - auto func_type = llvm::FunctionType::get(ret_type, arg_types, false); - auto func = llvm::Function::Create( - func_type, llvm::GlobalValue::InternalLinkage, name, gModule.get()); - - remill::ValueMap value_map; - value_map[mem_ptr_arg] = llvm::Constant::getNullValue(mem_ptr_arg->getType()); - value_map[pc_arg] = llvm::ConstantInt::get(pc_type, cfg_func->ea); - value_map[state_ptr_arg] = GetStatePointer(); - - remill::CloneFunctionInto(bb, func, value_map); - - // NOTE(pag): Some versions of LLVM use `AttributeSet`, while others - // use `AttributeList`. - decltype(func->getAttributes()) attr_set_or_list; - func->setAttributes(attr_set_or_list); - func->addFnAttr(llvm::Attribute::NoInline); - func->addFnAttr(llvm::Attribute::NoBuiltin); - - InsertVerifyFunction(func); - - if (FLAGS_stack_protector) { - func->addFnAttr(llvm::Attribute::StackProtectReq); + if (!func->isDeclaration()) { + return func; } - // Remove the `return` in code cloned from `__remill_basic_block`. - auto block = &(func->front()); - auto term = block->getTerminator(); - term->eraseFromParent(); + auto maybe_decl = anvill::FunctionDecl::Create(*func, gArch); + if (remill::IsError(maybe_decl)) { + LOG(FATAL) + << remill::GetErrorString(maybe_decl); + } - CallingConvention loader(gArch->DefaultCallingConv()); + auto &decl = remill::GetReference(maybe_decl); + decl.address = cfg_func->ea; - loader.StoreThreadPointer(block, InitialThreadLocalStorage()); + // We have the decompiled function, or at least, a prefix of it, + // so we'll invent a state structure and a stack frame and we'll + // call the lifted function with that. The lifted function will + // get inlined into this function. - // Save off the old stack pointer for later. - auto old_sp = loader.LoadStackPointer(block); + auto block = llvm::BasicBlock::Create(*gContext, "", func); + llvm::IRBuilder<> ir(block); - // Call the `__mcsema_early_init` function to make sure all lazy cross- - // reference initializers have been installed before any lifted bitcode - // is executed. - llvm::CallInst::Create(GetOrCreateMcSemaInitializer(), "", block); + // Invent a memory pointer. + const auto mem_ptr_type = remill::MemoryPointerType(gModule.get()); + llvm::Value *mem_ptr = llvm::Constant::getNullValue(mem_ptr_type); - // Send in argument values. - std::vector explicit_args; + const auto state_ptr = ir.CreateCall(GetVerifyRegState()); + + const auto pc = llvm::ConstantInt::get(gWordType, cfg_func->ea); + + static remill::IntrinsicTable intrinsics(gModule); + + // Store the function parameters either into the state struct + // or into memory (likely the stack). + auto arg_index = 0u; for (auto &arg : func->args()) { - explicit_args.push_back(&arg); + const auto ¶m_decl = decl.params[arg_index++]; + mem_ptr = anvill::StoreNativeValue( + &arg, param_decl, intrinsics, + block, state_ptr, mem_ptr); } - loader.StoreArguments(block, explicit_args); - // Allocate any space needed on the stack for a return address. - loader.AllocateReturnAddress(block); + llvm::Value *lifted_func_args[remill::kNumBlockArgs] = {}; + lifted_func_args[remill::kStatePointerArgNum] = state_ptr; + lifted_func_args[remill::kMemoryPointerArgNum] = mem_ptr; + lifted_func_args[remill::kPCArgNum] = pc; + mem_ptr = ir.CreateCall(cfg_func->lifted_function, lifted_func_args); - // Call the lifted function. - std::vector args(3); - args[remill::kMemoryPointerArgNum] = remill::LoadMemoryPointer(block); - args[remill::kStatePointerArgNum] = value_map[state_ptr_arg]; - args[remill::kPCArgNum] = value_map[pc_arg]; + llvm::Value *ret_val = nullptr; - llvm::CallInst::Create( - gModule->getFunction(cfg_func->lifted_name), args, "", block); + if (decl.returns.size() == 1) { + ret_val = anvill::LoadLiftedValue( + decl.returns.front(), intrinsics, block, + state_ptr, mem_ptr); + ir.SetInsertPoint(block); - // Restore the old stack pointer. - loader.StoreStackPointer(block, old_sp); + } else if (1 < decl.returns.size()){ + ret_val = llvm::UndefValue::get(func->getReturnType()); + auto index = 0u; + for (auto &ret_decl : decl.returns) { + auto partial_ret_val = anvill::LoadLiftedValue( + ret_decl, intrinsics, block, + state_ptr, mem_ptr); + ir.SetInsertPoint(block); + unsigned indexes[] = {index}; + ret_val = ir.CreateInsertValue( + ret_val, partial_ret_val, indexes); + index += 1; + } + } - // Extract and return the return value from the state structure/memory. - auto ret = loader.LoadReturnValue(block, pc_type); - auto casted = llvm::CastInst::CreateTruncOrBitCast( - ret, func_type->getReturnType(), "", block); - llvm::ReturnInst::Create(*gContext, casted, block); - - if (!FLAGS_pc_annotation.empty()) { - legacy::AnnotateInsts(func, cfg_func->ea); + if (ret_val) { + ir.CreateRet(ret_val); + } else { + ir.CreateRetVoid(); } return func; } -static llvm::Function *GetOrCreateCallback(const NativeObject *cfg_func, +static llvm::Function *GetOrCreateCallback(const NativeFunction *cfg_func, const std::string &callback_name) { - CHECK(!cfg_func->is_external) - << "Cannot get entry point thunk for external function " - << cfg_func->name; - - auto callback_func = gModule->getFunction(callback_name); - if (callback_func) { - return callback_func; + if (cfg_func->function) { + return cfg_func->function; } + CHECK_NOTNULL(cfg_func->lifted_function); + if (FLAGS_explicit_args) { - return ImplementExplicitArgsEntryPoint(cfg_func, callback_name); + cfg_func->function = ImplementExplicitArgsEntryPoint( + cfg_func, callback_name); } else { - return ImplementNativeToLiftedCallback(cfg_func, callback_name); + cfg_func->function = ImplementNativeToLiftedCallback( + cfg_func, callback_name); } + + return cfg_func->function; +} + +// Adapt a variadic function type to have the same signature, but have additional +// explicit "padding" arguments so that the function has at least `num_args` +// parameters. +static llvm::FunctionType *AdaptFunctionType( + llvm::FunctionType *type, unsigned num_args) { + std::vector param_types( + std::max(num_args, type->getNumParams()), gWordType); + + auto i = 0u; + for (auto param_type : type->params()) { + param_types[i++] = param_type; + } + + return llvm::FunctionType::get( + type->getReturnType(), param_types, false); +} + +// If `va_func` is not variadic, then this returns `va_func`, otherwise +// `va_func` is wrapped with a function that may take in additional explicit +// integer arguments, and then will pass those to `va_func`. +static llvm::Function *WrapVarArgsFunction(llvm::Function *va_func) { + if (!va_func->isVarArg()) { + return va_func; + } + + auto func_type = AdaptFunctionType( + va_func->getFunctionType(), FLAGS_explicit_args_count); + + auto wrapper_function = llvm::Function::Create( + func_type, + llvm::GlobalValue::InternalLinkage, + va_func->getName() + "_novarargs", gModule.get()); + + std::vector params; + for (auto &arg : wrapper_function->args()) { + params.push_back(&arg); + } + + llvm::IRBuilder<> ir( + llvm::BasicBlock::Create(*gContext, "", wrapper_function)); + auto call = ir.CreateCall(va_func, params); + if (func_type->getReturnType()->isVoidTy()) { + ir.CreateRetVoid(); + } else { + ir.CreateRet(call); + } + + wrapper_function->setCallingConv(va_func->getCallingConv()); + + return wrapper_function; } // Implements a stub for an externally defined function in such a way that, // when executed, this stub redirects control flow into the actual external // function. static void ImplementLiftedToNativeCallback( - llvm::Function *callback_func, llvm::Function *extern_func, - const NativeExternalFunction *cfg_func) { + llvm::Function *callback_func, llvm::Function *extern_func) { callback_func->addFnAttr(llvm::Attribute::NoInline); @@ -571,141 +668,137 @@ static void ImplementLiftedToNativeCallback( // the external is explicitly called, and arguments from the modeled CPU // state are passed into the external. static void ImplementExplicitArgsExitPoint( - llvm::Function *callback_func, llvm::Function *extern_func, - const NativeExternalFunction *cfg_func) { + llvm::Function *callback_func, llvm::Function *extern_func) { + + extern_func = WrapVarArgsFunction(extern_func); + auto maybe_decl = anvill::FunctionDecl::Create(*extern_func, gArch); + if (remill::IsError(maybe_decl)) { + LOG(FATAL) + << remill::GetErrorString(maybe_decl); + } + + const auto &decl = remill::GetReference(maybe_decl); remill::CloneBlockFunctionInto(callback_func); + auto block = &(callback_func->getEntryBlock()); - // Inline so that static analyses of the bitcode don't need to dive - // into an extra function just to see the intended call. - // With explicit_args breaks DSE, so we rather not inline it - if (!FLAGS_explicit_args) { - callback_func->removeFnAttr(llvm::Attribute::NoInline); - callback_func->addFnAttr(llvm::Attribute::InlineHint); - callback_func->addFnAttr(llvm::Attribute::AlwaysInline); - callback_func->removeFnAttr(llvm::Attribute::NoUnwind); - } + auto pc = remill::NthArgument( + callback_func, remill::kPCArgNum); + auto mem_ptr = remill::NthArgument( + callback_func, remill::kMemoryPointerArgNum); + auto state_ptr = remill::NthArgument( + callback_func, remill::kStatePointerArgNum); + + llvm::IRBuilder<> ir(block); + + llvm::Value *next_pc_ref = nullptr; + next_pc_ref = ir.CreateAlloca( + gWordType, llvm::Constant::getNullValue(gWordType), "next_pc"); + ir.CreateStore(pc, next_pc_ref); + + const auto mem_ptr_ref = ir.CreateAlloca(mem_ptr->getType(), nullptr, "MEMORY"); + const auto pc_ref = ir.CreateAlloca(gWordType, nullptr, "PC"); + ir.CreateStore(mem_ptr, mem_ptr_ref); + ir.CreateStore(pc, pc_ref); + + // Optimization can sometimes result in memory accesses being reordered w.r.t. + // external calls if they are inlined, so we want to prevent their inlining. + callback_func->removeFnAttr(llvm::Attribute::InlineHint); + callback_func->removeFnAttr(llvm::Attribute::AlwaysInline); + callback_func->addFnAttr(llvm::Attribute::NoInline); if (FLAGS_stack_protector) { callback_func->addFnAttr(llvm::Attribute::StackProtectReq); } - LOG(INFO) - << "Generating " << cfg_func->num_args - << " argument getters in function " - << cfg_func->lifted_name << " for external " << cfg_func->name; + callback_func->setLinkage(llvm::GlobalValue::InternalLinkage); - auto func_type = extern_func->getFunctionType(); - auto num_params = func_type->getNumParams(); - CallingConvention loader(cfg_func->cc); + remill::IntrinsicTable intrinsics(gModule); + const auto new_mem_ptr = decl.CallFromLiftedBlock( + extern_func->getName().str(), + intrinsics, block, state_ptr, mem_ptr, true); - if (num_params > cfg_func->num_args) { - LOG(ERROR) - << "Function " << cfg_func->name << " may be incorrectly " - << "specified in the CFG with " << cfg_func->num_args - << " whereas the bitcode function has " << num_params - << ": " << remill::LLVMThingToString(extern_func); - - } else if (num_params != cfg_func->num_args) { - CHECK(num_params < cfg_func->num_args && func_type->isVarArg()) - << "Function " << remill::LLVMThingToString(extern_func) - << " is expected to be able to take " << cfg_func->num_args - << " arguments."; - } - - auto block = &(callback_func->back()); - auto actual_num_args = std::max(num_params, cfg_func->num_args); - - // create call to function and args - std::vector call_args; - auto arg_iter = extern_func->arg_begin(); - for (auto i = 0U; i < actual_num_args; i++) { - llvm::Type *param_type = nullptr; - bool is_byval = false; - if (i < num_params) { - param_type = func_type->getParamType(i); - is_byval = arg_iter->hasByValAttr(); - ++arg_iter; - } - call_args.push_back(loader.LoadNextArgument(block, param_type, is_byval)); - } - - // Now that we've read the argument values, we want to free up the space that - // the emulated caller set up, so that when we eventually return, things are - // in the expected state. - loader.FreeReturnAddress(block); - loader.FreeArguments(block); - - llvm::IRBuilder<> ir(block); - loader.StoreReturnValue(block, ir.CreateCall(extern_func, call_args)); - - ir.CreateRet(remill::LoadMemoryPointer(block)); + ir.CreateRet(new_mem_ptr); } } // namespace -// Get a callback function for an internal function that can be referenced by -// internal code. -llvm::Function *GetNativeToLiftedCallback(const NativeObject *cfg_func) { - if (cfg_func->is_exported) { - return GetNativeToLiftedEntryPoint(cfg_func); - } else { - std::stringstream ss; - ss << "callback_" << cfg_func->lifted_name; - return GetOrCreateCallback(cfg_func, ss.str()); +llvm::Constant *NativeFunction::Pointer(void) const { + if (function) { + return function; } + + if (name.empty()) { + std::stringstream ss; + ss << "callback_" << lifted_name; + name = ss.str(); + } + + module->AddNameToAddress(name, ea); + if (decl) { + decl->DeclareInModule(name, *gModule); + } + + function = GetOrCreateCallback(this, name); + + // Always set as external until we've lifted the data segments. + function->setLinkage(llvm::GlobalValue::ExternalLinkage); + + function->removeFnAttr(llvm::Attribute::InlineHint); + function->removeFnAttr(llvm::Attribute::AlwaysInline); + function->removeFnAttr(llvm::Attribute::ReadNone); + function->removeFnAttr(llvm::Attribute::ReadOnly); + function->removeFnAttr(llvm::Attribute::ArgMemOnly); + + function->addFnAttr(llvm::Attribute::NoInline); + function->addFnAttr(llvm::Attribute::NoBuiltin); + + return function; } -// Get a callback function for an internal function. -llvm::Function *GetNativeToLiftedEntryPoint(const NativeObject *cfg_func) { - return GetOrCreateCallback(cfg_func, cfg_func->name); +llvm::Constant *NativeFunction::Address(void) const { + return llvm::ConstantExpr::getPtrToInt(Pointer(), gWordType); } // Get a callback function for an external function that can be referenced by // internal code. -llvm::Function *GetLiftedToNativeExitPoint(const NativeObject *cfg_func_) { - CHECK(cfg_func_->is_external) - << "Cannot get exit point thunk for internal function " - << cfg_func_->name << " at " << std::hex << cfg_func_->ea; +llvm::Function *GetLiftedToNativeExitPoint(const NativeFunction *cfg_func) { - auto cfg_func = reinterpret_cast(cfg_func_); - CHECK(cfg_func->name != cfg_func->lifted_name); - - auto callback_func = gModule->getFunction(cfg_func->lifted_name); - if (callback_func) { - return callback_func; + if (cfg_func->callable_lifted_function) { + return cfg_func->callable_lifted_function; } - auto extern_func = gModule->getFunction(cfg_func->name); - CHECK(extern_func != nullptr) - << "Cannot find declaration or definition for external function " - << cfg_func->name; - // Stub that will marshal lifted state into the native state. - callback_func = llvm::Function::Create(LiftedFunctionType(), - llvm::GlobalValue::InternalLinkage, - cfg_func->lifted_name, gModule.get()); + const auto callback_func = llvm::Function::Create( + gArch->LiftedFunctionType(), llvm::GlobalValue::InternalLinkage, + cfg_func->lifted_name, gModule.get()); + + cfg_func->callable_lifted_function = callback_func; + + const auto extern_func = llvm::dyn_cast(cfg_func->Pointer()); // Pass through the memory and state pointers, and pass the destination // (native external function address) as the PC argument. - if (FLAGS_explicit_args || cfg_func->is_explicit) { - ImplementExplicitArgsExitPoint(callback_func, extern_func, cfg_func); + if (FLAGS_explicit_args) { + ImplementExplicitArgsExitPoint(callback_func, extern_func); // We are going from lifted to native code. We don't need an assembly stub // because `__remill_function_call` already does the right thing. } else { - ImplementLiftedToNativeCallback(callback_func, extern_func, cfg_func); + ImplementLiftedToNativeCallback(callback_func, extern_func); } - if (!FLAGS_pc_annotation.empty()) { - legacy::AnnotateInsts(callback_func, cfg_func->ea); + if (cfg_func->lifted_function && !FLAGS_pc_annotation.empty()) { + legacy::AnnotateInsts(cfg_func->lifted_function, cfg_func->ea); } + return callback_func; } // Get a function that goes from the current lifted state into native state, // where we don't know where the native destination actually is. llvm::Function *GetLiftedToNativeExitPoint(ExitPointKind kind) { + if (!FLAGS_explicit_args) { switch (kind) { case kExitPointJump: @@ -722,43 +815,66 @@ llvm::Function *GetLiftedToNativeExitPoint(ExitPointKind kind) { return callback_func; } - // Stub that will marshal lifted state into the native state. - callback_func = llvm::Function::Create(LiftedFunctionType(), - llvm::GlobalValue::InternalLinkage, - "__mcsema_detach_call_value", gModule.get()); + std::vector arg_types; + arg_types.insert(arg_types.end(), FLAGS_explicit_args_count, gWordType); - remill::CloneBlockFunctionInto(callback_func); + // We'll create and destroy this function a few times just for the sake of + // being able to get/use an anvill::FunctionDecl, and later, to get a function + // pointer of the right type. + auto func = llvm::Function::Create( + llvm::FunctionType::get(gWordType, arg_types, false), + llvm::GlobalValue::InternalLinkage, "__mcsema_do_detach_call_value", + gModule.get()); - CallingConvention loader(gArch->DefaultCallingConv()); + auto maybe_decl = anvill::FunctionDecl::Create(*func, gArch); + func->eraseFromParent(); - auto block = &(callback_func->back()); - - std::vector call_args; - for (uint64_t i = 0U; i < FLAGS_explicit_args_count; i++) { - call_args.push_back(loader.LoadNextArgument(block)); + if (remill::IsError(maybe_decl)) { + LOG(FATAL) + << "Unable to create exit point: " << remill::GetErrorString(maybe_decl); + return nullptr; } - std::vector arg_types(FLAGS_explicit_args_count, - remill::AddressType(gModule.get())); + const auto &decl = remill::GetReference(maybe_decl); + func = decl.DeclareInModule( + "__mcsema_do_detach_call_value", *gModule, true); + CHECK_NOTNULL(func); - auto pc = remill::LoadProgramCounter(block); - auto func_ptr_ty = llvm::PointerType::get( - llvm::FunctionType::get(remill::AddressType(gModule.get()), arg_types, false), 0); + // Stub that will marshal lifted state into the native state. + callback_func = llvm::Function::Create( + gArch->LiftedFunctionType(), llvm::GlobalValue::PrivateLinkage, + "__mcsema_detach_call_value", gModule.get()); + + remill::CloneBlockFunctionInto(callback_func); + auto block = &(callback_func->getEntryBlock()); + + auto pc = remill::NthArgument( + callback_func, remill::kPCArgNum); + auto mem_ptr = remill::NthArgument( + callback_func, remill::kMemoryPointerArgNum); + auto state_ptr = remill::NthArgument( + callback_func, remill::kStatePointerArgNum); llvm::IRBuilder<> ir(block); - loader.StoreReturnValue( - block, ir.CreateCall(ir.CreateIntToPtr(pc, func_ptr_ty), call_args)); + auto pc_as_func_ptr = ir.CreateIntToPtr(pc, func->getType()); - // This means that indirect call happened and caller pushed his return - // address, which he expects callee will pop. However callee is one - // of entrypoints/callbacks, which freeze the %rsp, so we need to pop it - // for callee - loader.FreeReturnAddress(block); + remill::IntrinsicTable intrinsics(gModule); + const auto new_mem_ptr = decl.CallFromLiftedBlock( + "__mcsema_do_detach_call_value", intrinsics, block, + state_ptr, mem_ptr, true); - ir.CreateRet(remill::LoadMemoryPointer(block)); + func->replaceAllUsesWith(pc_as_func_ptr); + func->eraseFromParent(); + + ir.CreateRet(new_mem_ptr); remill::Annotate(callback_func); + callback_func->removeFnAttr(llvm::Attribute::NoInline); + callback_func->addFnAttr(llvm::Attribute::InlineHint); + callback_func->addFnAttr(llvm::Attribute::AlwaysInline); + callback_func->addFnAttr(llvm::Attribute::NoUnwind); + return callback_func; } diff --git a/mcsema/BC/Callback.h b/mcsema/BC/Callback.h index d248cfb75..c59365c32 100644 --- a/mcsema/BC/Callback.h +++ b/mcsema/BC/Callback.h @@ -1,21 +1,21 @@ /* - * Copyright (c) 2017 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ -#ifndef MCSEMA_BC_CALLBACK_H_ -#define MCSEMA_BC_CALLBACK_H_ +#pragma once namespace llvm { @@ -23,19 +23,11 @@ class Function; } // namespace llvm namespace mcsema { -struct NativeObject; - -// Get a callback function for an internal function that can be referenced by -// internal code. -llvm::Function *GetNativeToLiftedCallback(const NativeObject *cfg_func); - -// Get a callback function for an internal function that can be referenced by -// external code. -llvm::Function *GetNativeToLiftedEntryPoint(const NativeObject *cfg_func); +struct NativeFunction; // Get a callback function for an external function that can be referenced by // internal code. -llvm::Function *GetLiftedToNativeExitPoint(const NativeObject *cfg_func); +llvm::Function *GetLiftedToNativeExitPoint(const NativeFunction *cfg_func); enum ExitPointKind { kExitPointJump, @@ -47,5 +39,3 @@ enum ExitPointKind { llvm::Function *GetLiftedToNativeExitPoint(ExitPointKind); } // namespace mcsema - -#endif // MCSEMA_BC_CALLBACK_H_ diff --git a/mcsema/BC/External.cpp b/mcsema/BC/External.cpp index baa4aa7e5..cbe285c8a 100644 --- a/mcsema/BC/External.cpp +++ b/mcsema/BC/External.cpp @@ -1,20 +1,24 @@ /* - * Copyright (c) 2017 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ +#include "mcsema/BC/External.h" + #include +#include #include #include @@ -24,144 +28,97 @@ #include #include -#include "remill/Arch/Arch.h" -#include "remill/Arch/Name.h" -#include "remill/BC/Annotate.h" +#include + +#include +#include +#include #include "mcsema/Arch/Arch.h" #include "mcsema/BC/Callback.h" -#include "mcsema/BC/External.h" #include "mcsema/BC/Util.h" #include "mcsema/CFG/CFG.h" +DECLARE_bool(explicit_args); + namespace mcsema { -namespace { -// For an external named `external`, return a function with the prototype -// `uintptr_t external(uintptr_t arg0, uintptr_t arg1, ...);`. -// -// TODO(pag,car,artem): Handle floating point types eventually. -static void DeclareExternal( - const NativeExternalFunction *cfg_func) { - - std::vector tys(cfg_func->num_args, gWordType); - - auto extfun = llvm::Function::Create( - llvm::FunctionType::get(gWordType, tys, false), - llvm::GlobalValue::ExternalLinkage, - cfg_func->name, gModule.get()); - - if (cfg_func->is_weak) { - extfun->setLinkage(llvm::GlobalValue::ExternalWeakLinkage); - } - - extfun->setCallingConv(cfg_func->cc); - extfun->addFnAttr(llvm::Attribute::NoInline); - - remill::Annotate(extfun); -} - -static llvm::GlobalValue::ThreadLocalMode ThreadLocalMode( - const NativeObject *cfg_obj) { - if (cfg_obj->is_thread_local) { - return llvm::GlobalValue::GeneralDynamicTLSModel; - } else { - return llvm::GlobalValue::NotThreadLocal; - } -} - -} // namespace - -// Declare external functions. -void DeclareExternals(const NativeModule *cfg_module) { - for (const auto &entry : cfg_module->name_to_extern_func) { - auto cfg_func = reinterpret_cast( - entry.second->Get()); - - CHECK(cfg_func->is_external) - << "Trying to declare function " << cfg_func->name << " as external."; - - CHECK_NE(cfg_func->name, cfg_func->lifted_name); - - // The "actual" external function. - if (!gModule->getFunction(cfg_func->name)) { - LOG(INFO) - << "Adding external function " << cfg_func->name; - DeclareExternal(cfg_func); +llvm::Constant *NativeExternalFunction::Pointer(void) const { + const auto prev_function = function; + function = gModule->getFunction(name); + if (!function && decl) { + function = decl->DeclareInModule(name, *gModule); + if (!prev_function) { + module->AddNameToAddress(name, ea); } } - // Declare external variables. - for (const auto &entry : cfg_module->name_to_extern_var) { - auto cfg_var = reinterpret_cast( - entry.second->Get()); + if (function) { - auto ll_var = gModule->getGlobalVariable(cfg_var->name, - true /* AllowInternal */); - if (!ll_var) { - LOG(INFO) - << "Adding external variable " << cfg_var->name; + if (function == prev_function) { + return prev_function; + } - llvm::Type* var_type = nullptr; - - CHECK_NE(0, cfg_var->size) - << "The size of the external variable [" - << cfg_var->name << "] cannot be zero"; - - // Handle external variables of up to 128 bits as intgers - // Anything else is treated as an array of bytes - switch(cfg_var->size) { - case 0: - // Why is this zero length? This should never happen - // Attempt a fix and output a warning - LOG(ERROR) - << "The variable [" << cfg_var->name - << "] has size of zero. Assuming it should be size 1"; - var_type = llvm::Type::getInt8Ty(*gContext); - break; - case 1: // 8 bit integer - case 2: // 16 bit integer - case 4: // 32 bit integer - case 8: // 64 bit integer - case 16: // 128 bit integer - var_type = llvm::Type::getIntNTy( - *gContext, static_cast(cfg_var->size * 8)); - break; - - // An array of bytes - default: { - auto byte_type = llvm::Type::getInt8Ty(*gContext); - var_type = llvm::ArrayType::get(byte_type, static_cast(cfg_var->size)); - break; - } + // The function exists and isn't varargs; use it. + if (is_weak) { + if (function->isDeclaration()) { + function->setLinkage(llvm::GlobalValue::ExternalWeakLinkage); + } else { + function->setLinkage(llvm::GlobalValue::AvailableExternallyLinkage); } - - auto linkage = llvm::GlobalValue::ExternalLinkage; - ll_var = new llvm::GlobalVariable(*gModule, var_type, false, - linkage, nullptr, cfg_var->name, - nullptr, ThreadLocalMode(cfg_var)); - if (cfg_var->ea) { - ll_var->setAlignment(1 << __builtin_ctzl(cfg_var->ea)); - } - - // This could happen if the variable is declared as a segment variable, - // but is not exported, and there is also another exported/imported - // global of the same name. - // - // TODO(pag): Another reasonable interpretation of this is to rename the - // existing symbol so that the names don't clash. } else { - LOG_IF(ERROR, !ll_var->hasExternalLinkage()) - << "Variable '" << cfg_var->name - << "' is external but was not previously declared as such"; - - ll_var->setLinkage(llvm::GlobalValue::ExternalLinkage); + function->setLinkage(llvm::GlobalValue::ExternalLinkage); } - if (!cfg_var->address) { - cfg_var->address = llvm::ConstantExpr::getPtrToInt(ll_var, gWordType); + remill::Annotate(function); + + return function; + + // The function doesn't exist in the module, and we need to declare it with + // the information we have from CFG extraction. + } else { + CHECK(is_external); + std::vector param_types(num_args, gWordType); + + module->AddNameToAddress(name, ea); + + function = llvm::Function::Create( + llvm::FunctionType::get(gWordType, param_types, false), + llvm::GlobalValue::ExternalLinkage, + name, gModule.get()); + + if (is_weak) { + function->setLinkage(llvm::GlobalValue::ExternalWeakLinkage); } + + function->setCallingConv(cc); + + function->removeFnAttr(llvm::Attribute::InlineHint); + function->removeFnAttr(llvm::Attribute::AlwaysInline); + function->removeFnAttr(llvm::Attribute::ReadNone); + function->removeFnAttr(llvm::Attribute::ReadOnly); + function->removeFnAttr(llvm::Attribute::ArgMemOnly); + + function->addFnAttr(llvm::Attribute::NoInline); + function->addFnAttr(llvm::Attribute::NoBuiltin); + + remill::Annotate(function); + return function; } } +llvm::Constant *NativeExternalVariable::Pointer(void) const { + CHECK(is_external); + CHECK_NOTNULL(segment); + const auto seg = segment->Get(); + CHECK(seg->is_external); + CHECK_EQ(ea, seg->ea); + CHECK(!seg->padding); + return seg->Pointer(); +} + +llvm::Constant *NativeExternalVariable::Address(void) const { + return llvm::ConstantExpr::getPtrToInt(Pointer(), gWordType); +} + } // namespace mcsema diff --git a/mcsema/BC/External.h b/mcsema/BC/External.h index cd833d982..5874a8cb2 100644 --- a/mcsema/BC/External.h +++ b/mcsema/BC/External.h @@ -1,21 +1,21 @@ /* - * Copyright (c) 2017 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ -#ifndef MCSEMA_BC_EXTERNAL_H_ -#define MCSEMA_BC_EXTERNAL_H_ +#pragma once #include @@ -30,8 +30,6 @@ namespace CallingConv { namespace mcsema { struct NativeModule; -void DeclareExternals(const NativeModule *cfg_module); +//void DeclareExternals(const NativeModule *cfg_module); } // namespace mcsema - -#endif // MCSEMA_BC_EXTERNAL_H_ diff --git a/mcsema/BC/Function.cpp b/mcsema/BC/Function.cpp index fe7c0f181..eefd3fb2c 100644 --- a/mcsema/BC/Function.cpp +++ b/mcsema/BC/Function.cpp @@ -1,19 +1,22 @@ /* - * Copyright (c) 2017 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ +#include "mcsema/BC/Function.h" + #include #include @@ -44,6 +47,7 @@ #include "remill/Arch/Instruction.h" #include "remill/BC/ABI.h" #include "remill/BC/Annotate.h" +#include "remill/BC/Compat/Error.h" #include "remill/BC/Compat/ScalarTransforms.h" #include "remill/BC/IntrinsicTable.h" #include "remill/BC/Lifter.h" @@ -52,7 +56,6 @@ #include "mcsema/Arch/Arch.h" #include "mcsema/BC/Callback.h" -#include "mcsema/BC/Function.h" #include "mcsema/BC/Instruction.h" #include "mcsema/BC/Legacy.h" #include "mcsema/BC/Lift.h" @@ -63,21 +66,32 @@ DECLARE_bool(legacy_mode); DECLARE_bool(explicit_args); -DECLARE_bool(disable_optimizer); -DEFINE_bool(add_reg_tracer, false, +DEFINE_bool(add_state_tracer, false, "Add a debug function that prints out the register state before " "each lifted instruction execution."); +DEFINE_bool(add_func_state_tracer, false, + "Add a debug function that prints out the register state before " + "each lifted function execution."); + +DEFINE_string(trace_reg_values, "", + "Add a debug function that prints out the specified register values " + "before each lifted instruction execution. The registers printed out " + "always include the current program counter, as well as the registers " + "in specified in this option (as a comma-separated list)."); + +DEFINE_bool(add_pc_tracer, false, + "Add a debug function that is invoked just before every lifted " + "instruction, where the PC of the instruction is passed into the " + "tracer. This is similar to --add_reg_tracer, but it doesn't " + "negatively impact optimizations."); + DEFINE_bool(add_breakpoints, false, "Add 'breakpoint' functions between every lifted instruction. This " "allows one to set a breakpoint, in the lifted code, just before a " "specific lifted instruction is executed. This is a debugging aid."); -DEFINE_bool(check_pc_at_breakpoints, false, - "Check whether or not the emulated program counter is correct at " - "each injected 'breakpoint' function. This is a debugging aid."); - DEFINE_string(exception_personality_func, "__gxx_personality_v0", "Add a personality function for lifting exception handling " "routine. Assigned __gxx_personality_v0 as default for c++ ABTs."); @@ -87,106 +101,250 @@ DEFINE_bool(stack_protector, false, "Annotate functions so that if the bitcode " "guards will be added."); namespace mcsema { - namespace { -// Get the personality function of exception handling ABIs. -// For libstdc++ it will be reference to `__gxx_personality_v0` -static llvm::Function *GetPersonalityFunction(void) { - const auto &personality_func_name = FLAGS_exception_personality_func; - - // The personality function is lifted as global variable. Check and erase the - // variable before declaring it as the function. - if (auto personality_func = gModule->getGlobalVariable(personality_func_name)) { - personality_func->eraseFromParent(); - } - - auto personality_func = gModule->getFunction(personality_func_name); - if (personality_func == nullptr) { - personality_func = llvm::Function::Create( - llvm::FunctionType::get(llvm::Type::getInt32Ty(*gContext), true), - llvm::Function::ExternalLinkage, personality_func_name, gModule.get()); - } - return personality_func; +static llvm::Value *LoadMemoryPointer( + const TranslationContext &ctx, llvm::BasicBlock *block) { + return ctx.lifter->LoadRegValue(block, "MEMORY"); } +static llvm::Value *LoadMemoryPointerRef( + const TranslationContext &ctx, llvm::BasicBlock *block) { + return ctx.lifter->LoadRegAddress(block, "MEMORY"); +} + +static llvm::Value *LoadStatePointer( + const TranslationContext &, llvm::BasicBlock *block) { + return remill::NthArgument(block->getParent(), remill::kStatePointerArgNum); +} + +static llvm::Value *LoadProgramCounter( + const TranslationContext &ctx, llvm::BasicBlock *block) { + return ctx.lifter->LoadRegValue(block, "PC"); +} + +static llvm::Value *LoadProgramCounterRef( + const TranslationContext &ctx, llvm::BasicBlock *block) { + return ctx.lifter->LoadRegAddress(block, "PC"); +} + +static llvm::Value *LoadNextProgramCounter( + const TranslationContext &ctx, llvm::BasicBlock *block) { + return ctx.lifter->LoadRegValue(block, "NEXT_PC"); +} + +static llvm::Value *LoadNextProgramCounterRef( + const TranslationContext &ctx, llvm::BasicBlock *block) { + return ctx.lifter->LoadRegAddress(block, "NEXT_PC"); +} + +// Get the register tracer. This is useful when debugging, where the runtime +// implements the register tracer in a way that prints out all general purpose +// register names and their values before each lifted instruction. This trace +// can help discover the source of an emulation divergence, among other things. +static llvm::Function *GetValueTracer(void) { + static llvm::Function *gValueTracer = nullptr; + if (gValueTracer) { + return gValueTracer; + } + + gValueTracer = gModule->getFunction("__mcsema_value_tracer"); + if (gValueTracer) { + return gValueTracer; + } + + gValueTracer = llvm::Function::Create( + gArch->LiftedFunctionType(), llvm::GlobalValue::PrivateLinkage, + "__mcsema_value_tracer", gModule.get()); + gValueTracer->removeFnAttr(llvm::Attribute::NoDuplicate); + gValueTracer->addFnAttr(llvm::Attribute::AlwaysInline); + gValueTracer->addFnAttr(llvm::Attribute::InlineHint); + gValueTracer->addFnAttr(llvm::Attribute::ReadNone); + gValueTracer->removeFnAttr(llvm::Attribute::OptimizeNone); + gValueTracer->removeFnAttr(llvm::Attribute::NoInline); + + llvm::Value *mem_ptr = remill::NthArgument( + gValueTracer, remill::kMemoryPointerArgNum); + auto printf = gModule->getFunction("__mcsema_printf"); + auto i32_type = llvm::Type::getInt8Ty(*gContext); + if (!printf) { + auto i8_type = llvm::Type::getInt8Ty(*gContext); + llvm::Type *param_types_2[] = { + mem_ptr->getType(), + llvm::PointerType::get(i8_type, 0)}; + + printf = llvm::Function::Create( + llvm::FunctionType::get(mem_ptr->getType(), param_types_2, true), + llvm::GlobalValue::ExternalLinkage, + "__mcsema_printf", + gModule.get()); + } + + printf->addFnAttr(llvm::Attribute::ReadNone); + + std::stringstream ss; + std::vector args; + args.push_back(remill::NthArgument(gValueTracer, remill::kMemoryPointerArgNum)); + args.push_back(nullptr); // Format. + args.push_back(remill::NthArgument(gValueTracer, remill::kPCArgNum)); + + auto format = gArch->address_size == 64 ? "=%016llx " : "=%018x "; + auto block = llvm::BasicBlock::Create(*gContext, "", gValueTracer); + auto state_ptr = remill::NthArgument( + gValueTracer, remill::kStatePointerArgNum); + + auto pc_reg = gArch->RegisterByName(gArch->ProgramCounterRegisterName()); + ss << "pc" << format; + + std::unordered_set regs; + std::stringstream rs; + rs << FLAGS_trace_reg_values; + for (std::string reg_name; std::getline(rs, reg_name, ',');) { + const auto reg = gArch->RegisterByName(reg_name); + if (reg->type == gWordType && reg != pc_reg) { + ss << reg->name << format; + args.push_back( + new llvm::LoadInst(reg->AddressOf(state_ptr, block), "", block)); + } + } + ss << '\n'; + + auto format_str = llvm::ConstantDataArray::getString(*gContext, ss.str(), true); + auto format_var = new llvm::GlobalVariable( + *gModule, format_str->getType(), true, llvm::GlobalValue::InternalLinkage, + format_str); + + llvm::Constant *indices[] = { + llvm::ConstantInt::getNullValue(i32_type), + llvm::ConstantInt::getNullValue(i32_type)}; + + llvm::IRBuilder<> ir(block); + args[1] = llvm::ConstantExpr::getInBoundsGetElementPtr( + format_str->getType(), format_var, indices); + mem_ptr = ir.CreateCall(printf, args); + ir.CreateRet(mem_ptr); + + return gValueTracer; +} + +// Get the register tracer. This is useful when debugging, where the runtime +// implements the register tracer in a way that prints out all general purpose +// register names and their values before each lifted instruction. This trace +// can help discover the source of an emulation divergence, among other things. static llvm::Function *GetRegTracer(void) { - auto reg_tracer = gModule->getFunction("__mcsema_reg_tracer"); - if (!reg_tracer) { - reg_tracer = llvm::Function::Create( - LiftedFunctionType(), llvm::GlobalValue::ExternalLinkage, - "__mcsema_reg_tracer", gModule.get()); + static llvm::Function *gRegTracer = nullptr; + if (!gRegTracer) { + gRegTracer = gModule->getFunction("__mcsema_reg_tracer"); + if (!gRegTracer) { + gRegTracer = llvm::Function::Create( + gArch->LiftedFunctionType(), llvm::GlobalValue::ExternalLinkage, + "__mcsema_reg_tracer", gModule.get()); + gRegTracer->addFnAttr(llvm::Attribute::NoDuplicate); + gRegTracer->removeFnAttr(llvm::Attribute::AlwaysInline); + gRegTracer->removeFnAttr(llvm::Attribute::InlineHint); + gRegTracer->addFnAttr(llvm::Attribute::OptimizeNone); + gRegTracer->addFnAttr(llvm::Attribute::NoInline); + gRegTracer->addFnAttr(llvm::Attribute::ReadNone); + } } - return reg_tracer; + return gRegTracer; } +// Get the PC tracer for a given program counter. This function is useful when +// integrating with KLEE. A call to this function is injected before every +// lifted instruction. If this function is implemented as a KLEE special +// function handler, then the second argument is the emulated program counter, +// and a logical stack trace feature can be implemented by recording these +// program counters into a KLEE execution state. +static llvm::Function *GetPCTracer(uint64_t pc) { + static llvm::Function *gPCTracer = nullptr; + if (!gPCTracer) { + gPCTracer = gModule->getFunction("__mcsema_pc_tracer"); + if (!gPCTracer) { + llvm::Type *arg_types[1] = {gWordType}; + auto func_type = llvm::FunctionType::get( + llvm::Type::getVoidTy(*gContext), arg_types, false); + gPCTracer = llvm::Function::Create( + func_type, llvm::GlobalValue::ExternalLinkage, + "__mcsema_pc_tracer", gModule.get()); + gPCTracer->addFnAttr(llvm::Attribute::NoDuplicate); + gPCTracer->removeFnAttr(llvm::Attribute::AlwaysInline); + gPCTracer->removeFnAttr(llvm::Attribute::InlineHint); + gPCTracer->addFnAttr(llvm::Attribute::OptimizeNone); + gPCTracer->addFnAttr(llvm::Attribute::NoInline); + gPCTracer->addFnAttr(llvm::Attribute::ReadNone); + } + } + return gPCTracer; +} + +// Get the breakpoint function for a given program counter. These functions +// are useful for debugging. For example, if you are debugging lifted bitcode, +// and want to stop execution at the logical location where the instruction +// at `0xf00` resides, then in a debugger, you would add your breakpoint on +// the `breakpoint_f00` function. static llvm::Function *GetBreakPoint(uint64_t pc) { std::stringstream ss; ss << "breakpoint_" << std::hex << pc; - auto func_name = ss.str(); + const auto func_name = ss.str(); auto func = gModule->getFunction(func_name); if (func) { return func; } + static const auto mem_ptr_type = remill::MemoryPointerType(gModule.get()); + llvm::Type * const params[1] = {mem_ptr_type}; + const auto fty = llvm::FunctionType::get(mem_ptr_type, params, false); func = llvm::Function::Create( - LiftedFunctionType(), llvm::GlobalValue::ExternalLinkage, + fty, llvm::GlobalValue::ExternalLinkage, func_name, gModule.get()); // Make sure to keep this function around (along with `ExternalLinkage`). - func->removeFnAttr(llvm::Attribute::ReadNone); func->addFnAttr(llvm::Attribute::OptimizeNone); + func->removeFnAttr(llvm::Attribute::AlwaysInline); + func->removeFnAttr(llvm::Attribute::InlineHint); func->addFnAttr(llvm::Attribute::NoInline); - -#if LLVM_VERSION_NUMBER < LLVM_VERSION(3, 7) - func->addFnAttr(llvm::Attribute::ReadOnly); -#else - func->addFnAttr(llvm::Attribute::ArgMemOnly); -#endif - - auto state_ptr = remill::NthArgument(func, remill::kStatePointerArgNum); - auto state_ptr_type = state_ptr->getType(); + func->addFnAttr(llvm::Attribute::ReadNone); llvm::IRBuilder<> ir(llvm::BasicBlock::Create(*gContext, "", func)); - - if (FLAGS_check_pc_at_breakpoints) { - auto trap = llvm::Intrinsic::getDeclaration(gModule.get(), llvm::Intrinsic::trap); - auto are_eq = ir.CreateICmpEQ( - remill::NthArgument(func, remill::kPCArgNum), - llvm::ConstantInt::get(gWordType, pc)); - - auto not_eq_bb = llvm::BasicBlock::Create(*gContext, "", func); - auto eq_bb = llvm::BasicBlock::Create(*gContext, "", func); - ir.CreateCondBr(are_eq, eq_bb, not_eq_bb); - - ir.SetInsertPoint(not_eq_bb); - ir.CreateCall(trap); - ir.CreateUnreachable(); - - ir.SetInsertPoint(eq_bb); - } - - // Basically some empty inline assembly that tells the compiler not to - // optimize away the `state` pointer before each `breakpoint_XXX` function. - auto asm_func_type = llvm::FunctionType::get( - llvm::Type::getVoidTy(*gContext), state_ptr_type, false); - - auto asm_func = llvm::InlineAsm::get( - asm_func_type, "", "*m,~{dirflag},~{fpsr},~{flags}", true); - - ir.CreateCall(asm_func, state_ptr); - ir.CreateRet(remill::NthArgument(func, remill::kMemoryPointerArgNum)); + ir.CreateRet(remill::NthArgument(func, 0)); return func; } -// Tries to get the lifted function beginning at `pc`. -static llvm::Function *GetLiftedFunction(const NativeModule *cfg_module, - uint64_t pc) { - if (auto cfg_func = cfg_module->TryGetFunction(pc)) { - return gModule->getFunction(cfg_func->lifted_name); +// Get the personality function of exception handling ABIs. +// For libstdc++ it will be reference to `__gxx_personality_v0` +static llvm::Function *GetPersonalityFunction(void) { + static llvm::Function *personality_func = nullptr; + if (personality_func) { + return personality_func; } - return nullptr; + + const auto &personality_func_name = FLAGS_exception_personality_func; + + // The personality function is lifted as global variable. Check and erase the + // variable before declaring it as the function. + if (auto personality_func_var = gModule->getGlobalVariable(personality_func_name); + personality_func_var) { + if (personality_func_var->hasNUsesOrMore(1)) { + LOG(ERROR) + << "Renaming existing exception personality variable " + << FLAGS_exception_personality_func; + personality_func_var->setName( + FLAGS_exception_personality_func + "__original"); + } else { + personality_func_var->eraseFromParent(); + } + } + + personality_func = gModule->getFunction(personality_func_name); + if (personality_func == nullptr) { + personality_func = llvm::Function::Create( + llvm::FunctionType::get(llvm::Type::getInt32Ty(*gContext), true), + llvm::Function::ExternalLinkage, personality_func_name, gModule.get()); + } + + return personality_func; } // The exception handling prologue function clears the stack and set the @@ -223,24 +381,24 @@ static llvm::Function *GetExceptionTypeIndex(void) { return get_index_func; } -// Add a call to another function, and then update the memory pointer with the -// result of the function. -static void InlineSubFuncCall(llvm::BasicBlock *block, - llvm::Function *sub) { - auto call = llvm::CallInst::Create( - sub, remill::LiftedFunctionArgs(block), "", block); - call->setCallingConv(sub->getCallingConv()); - auto mem_ptr = remill::LoadMemoryPointerRef(block); - (void) new llvm::StoreInst(call, mem_ptr, block); -} +enum class PCValueKind { + kSymbolicPC, + kConcretePC, + kUndefPC +}; // Add a invoke to another function and then update the memory pointer with the // result of the function. It also needs to stash the stack and frame pointer which // can be restored before handling the exception handler. -static void InlineSubFuncInvoke(llvm::BasicBlock *block, - llvm::Function *sub, llvm::BasicBlock *if_normal, - llvm::BasicBlock *if_exception, - const NativeFunction *cfg_func) { +static void InlineSubFuncInvoke( + const TranslationContext &ctx, + llvm::BasicBlock *block, + llvm::Function *sub, + llvm::BasicBlock *if_normal, + llvm::BasicBlock *if_exception, + const NativeFunction *cfg_func, + PCValueKind pc_kind=PCValueKind::kSymbolicPC) { + llvm::IRBuilder <> ir(block); auto get_sp_func = gModule->getFunction("__mcsema_get_stack_pointer"); if (!get_sp_func) { @@ -249,8 +407,9 @@ static void InlineSubFuncInvoke(llvm::BasicBlock *block, llvm::GlobalValue::ExternalLinkage, "__mcsema_get_stack_pointer", gModule.get()); } + auto sp_var = ir.CreateCall(get_sp_func); - ir.CreateStore(sp_var, cfg_func->stack_ptr_var); + ir.CreateStore(sp_var, ctx.stack_ptr_var); auto get_bp_func = gModule->getFunction("__mcsema_get_frame_pointer"); if (!get_bp_func) { @@ -259,21 +418,72 @@ static void InlineSubFuncInvoke(llvm::BasicBlock *block, llvm::GlobalValue::ExternalLinkage, "__mcsema_get_frame_pointer", gModule.get()); } + + llvm::Value *args[remill::kNumBlockArgs]; + args[remill::kMemoryPointerArgNum] = LoadMemoryPointer(ctx, block); + args[remill::kStatePointerArgNum] = LoadStatePointer(ctx, block); + + if (PCValueKind::kSymbolicPC == pc_kind) { + args[remill::kPCArgNum] = LoadNextProgramCounter(ctx, block); + } else if (PCValueKind::kUndefPC == pc_kind) { + args[remill::kPCArgNum] = llvm::UndefValue::get(gWordType); + } else { + args[remill::kPCArgNum] = llvm::ConstantInt::get(gWordType, ctx.inst.pc); + } + auto bp_var = ir.CreateCall(get_bp_func); - ir.CreateStore(bp_var, cfg_func->frame_ptr_var); + ir.CreateStore(bp_var, ctx.frame_ptr_var); auto invoke = ir.CreateInvoke( - sub, if_normal, if_exception, remill::LiftedFunctionArgs(block), ""); + sub, if_normal, if_exception, args, ""); invoke->setCallingConv(sub->getCallingConv()); + + // Store the memory pointer down the normal path of the invoked function. + auto mem_ptr_ref = LoadMemoryPointerRef(ctx, if_normal); + ir.SetInsertPoint(if_normal); + ir.CreateStore(invoke, mem_ptr_ref); } -// Find an external function associated with this indirect jump. -static llvm::Function *DevirtualizeIndirectFlow( - const NativeFunction *cfg_func, llvm::Function *fallback) { - if (cfg_func->is_external) { - return GetLiftedToNativeExitPoint(cfg_func); - } else if (auto func = gModule->getFunction(cfg_func->lifted_name)) { - return func; +// Add a call to another function, and then update the memory pointer with the +// result of the function. +static llvm::Value *LiftSubFuncCall( + const TranslationContext &ctx, + llvm::BasicBlock *block, + llvm::Function *sub, + PCValueKind pc_kind=PCValueKind::kSymbolicPC, + uint64_t concrete_pc=0) { + llvm::Value *args[remill::kNumBlockArgs]; + args[remill::kMemoryPointerArgNum] = LoadMemoryPointer(ctx, block); + args[remill::kStatePointerArgNum] = LoadStatePointer(ctx, block); + + if (PCValueKind::kSymbolicPC == pc_kind) { + args[remill::kPCArgNum] = LoadNextProgramCounter(ctx, block); + } else if (PCValueKind::kUndefPC == pc_kind) { + args[remill::kPCArgNum] = llvm::UndefValue::get(gWordType); + } else if (concrete_pc) { + args[remill::kPCArgNum] = llvm::ConstantInt::get(gWordType, concrete_pc); } else { + args[remill::kPCArgNum] = llvm::ConstantInt::get(gWordType, ctx.inst.pc); + } + + auto call = llvm::CallInst::Create(sub, args, "", block); + call->setCallingConv(sub->getCallingConv()); + auto mem_ptr = LoadMemoryPointerRef(ctx, block); + (void) new llvm::StoreInst(call, mem_ptr, block); + return call; +} + +// Wrap the lifted function `cfg_func` with its type specification, if any, and +// provide a lifted interface to it. +static llvm::Function *CallableLiftedFunc( + const NativeFunction *cfg_func, llvm::Function *fallback) { + + if (cfg_func->callable_lifted_function) { + return cfg_func->callable_lifted_function; + + } else { + LOG(ERROR) + << "Falling back on " << cfg_func->name; + cfg_func->callable_lifted_function = fallback; return fallback; } } @@ -281,34 +491,14 @@ static llvm::Function *DevirtualizeIndirectFlow( // Find an external function associated with this indirect jump. static llvm::Function *DevirtualizeIndirectFlow( TranslationContext &ctx, llvm::Function *fallback) { - if (ctx.cfg_inst->flow) { - if (auto cfg_func = ctx.cfg_inst->flow->func) { - return DevirtualizeIndirectFlow(cfg_func, fallback); - } + if (!ctx.cfg_inst) { + return fallback; } - // This is a bit sketchy, but let's assume that it might be a thunk - // (e.g in the PLT). If so, then we're doing a jump through a loaded - // pointer, where the pointer will be fixed up with an external EA, - // i.e. there should be a cross-reference entry at the target pointing - // to the destination function. - if (auto mem = ctx.cfg_inst->mem) { - auto seg = mem->target_segment; - - // In case there is a variable that has some default value, e.g. can - // be recognized both as xref and var on the same ea - // However later it can be changed to different value, so we can't - // devirtualize it (issue #474) - if (!mem->segment->is_read_only || seg == nullptr) { - return fallback; - } - auto target_ea_ptr_ea = mem->target_ea; - auto entry_it = seg->entries.find(target_ea_ptr_ea); - if (entry_it != seg->entries.end()) { - const NativeSegment::Entry &entry = entry_it->second; - if (entry.xref && entry.xref->func) { - return DevirtualizeIndirectFlow(entry.xref->func, fallback); - } + if (const auto flow = ctx.cfg_inst->flow; flow) { + if (auto cfg_func = ctx.cfg_module->TryGetFunction(flow->target_ea); + cfg_func) { + return CallableLiftedFunc(cfg_func, fallback); } } @@ -320,80 +510,72 @@ static llvm::Function *DevirtualizeIndirectFlow( // function calls internal to a binary. However, if the function is actually // an external function then we try to return the external version of the // function. -static llvm::Function *FindFunction(TranslationContext &ctx, - uint64_t target_pc) { +static std::pair +FindFunction(TranslationContext &ctx, uint64_t target_pc) { const NativeFunction *cfg_func = nullptr; - if (ctx.cfg_inst->flow) { - cfg_func = ctx.cfg_inst->flow->func; - if (cfg_func && cfg_func->is_external) { - return GetLiftedToNativeExitPoint(cfg_func); + if (ctx.cfg_inst) { + if (auto flow = ctx.cfg_inst->flow; flow) { + cfg_func = ctx.cfg_module->TryGetFunction(flow->target_ea); + if (cfg_func) { + return { + cfg_func, + CallableLiftedFunc(cfg_func, ctx.lifter->intrinsics->function_call)}; + } } } - auto func = GetLiftedFunction(ctx.cfg_module, target_pc); - if (func) { - return func; - } - + cfg_func = ctx.cfg_module->TryGetFunction(target_pc); if (cfg_func) { - auto lifted_func = gModule->getFunction(cfg_func->lifted_name); - if (lifted_func) { - LOG(WARNING) - << "Cannot find target of instruction at " << std::hex - << ctx.cfg_inst->ea << "; the static target " - << std::hex << target_pc << " is not associated with a lifted" - << " subroutine, but is associated with the function at " << std::hex - << cfg_func->ea << " in the CFG." << std::dec; - - return lifted_func; - } + return {cfg_func, + CallableLiftedFunc(cfg_func, ctx.lifter->intrinsics->function_call)}; } - LOG(ERROR) - << "Cannot find target of instruction at " << std::hex - << ctx.cfg_inst->ea << "; the static target " - << std::hex << target_pc << " is not associated with a lifted" - << " subroutine, and it does not have a known call target." - << std::dec; - - return ctx.lifter->intrinsics->error; + return {nullptr, nullptr}; } -// Get the basic block within this function associated with a specific program -// counter. -static llvm::BasicBlock *GetOrCreateBlock(TranslationContext &ctx, - uint64_t pc) { - auto &block = ctx.ea_to_block[pc]; - if (!block) { - std::stringstream ss; - ss << "block_" << std::hex << pc; - block = llvm::BasicBlock::Create(*gContext, ss.str(), ctx.lifted_func); +// Try to decode an instruction. +static bool TryDecodeInstruction( + TranslationContext &ctx, uint64_t pc, bool is_delayed) { - // First, try to see if it's actually related to another function. This is - // equivalent to a tail-call in the original code. - if (auto tail_called_func = FindFunction(ctx, pc)) { - LOG_IF(ERROR, !ctx.cfg_block->successor_eas.count(pc)) - << "Adding missing block " << std::hex << pc << " in function " - << ctx.cfg_func->lifted_name << " as a tail call to " - << tail_called_func->getName().str() << std::dec; + remill::Instruction &inst = is_delayed ? ctx.delayed_inst : ctx.inst; - remill::AddTerminatingTailCall(block, tail_called_func); + static const auto max_inst_size = gArch->MaxInstructionSize(); + inst.Reset(); - // Terminate the block with an unreachable inst. - } else { + auto byte = ctx.cfg_module->FindByte(pc); + if (!byte.IsExecutable()) { + return false; + } + + // Read the bytes. + auto &inst_bytes = inst.bytes; + inst_bytes.reserve(max_inst_size); + for (auto i = 0u; i < max_inst_size && byte && byte.IsExecutable(); + ++i, byte = ctx.cfg_module->FindNextByte(byte)) { + auto maybe_val = byte.Value(); + if (remill::IsError(maybe_val)) { LOG(ERROR) - << "Adding missing block " << std::hex << pc << " in function " - << ctx.cfg_func->lifted_name << " as a jump to the error intrinsic." - << std::dec; - - remill::AddTerminatingTailCall( - block, ctx.lifter->intrinsics->missing_block); + << "Unable to read balue of byte at " << std::hex + << byte.Address() << std::dec << ": " + << remill::GetErrorString(maybe_val); + break; + } else { + inst_bytes.push_back(static_cast(remill::GetReference(maybe_val))); } } - return block; + + if (is_delayed) { + return gArch->DecodeDelayedInstruction(pc, inst.bytes, inst); + } else { + return gArch->DecodeInstruction(pc, inst.bytes, inst); + } } +static llvm::BasicBlock *GetOrCreateBlock(TranslationContext &ctx, + uint64_t pc, + bool force_as_block=false); + // Create a landing pad basic block. static void CreateLandingPad(TranslationContext &ctx, struct NativeExceptionFrame *eh_entry) { @@ -401,7 +583,7 @@ static void CreateLandingPad(TranslationContext &ctx, auto dword_type = llvm::Type::getInt32Ty(*gContext); // `__mcsema_exception_ret` argument list - std::vector args(3); + llvm::Value *args[3]; auto is_catch = (eh_entry->action_index != 0); ss << "landingpad_" << std::hex << eh_entry->lp_ea; auto landing_bb = llvm::BasicBlock::Create( @@ -423,7 +605,7 @@ static void CreateLandingPad(TranslationContext &ctx, lpad->setCleanup(!is_catch); - if(is_catch) { + if (is_catch) { std::stringstream g_variable_name_ss; std::vectorarray_value_const; auto catch_all = false; @@ -495,26 +677,25 @@ static void CreateLandingPad(TranslationContext &ctx, auto var_value = ir.CreateGEP(gvar_landingpad, array_index_vec); - #if LLVM_VERSION_NUMBER > LLVM_VERSION(3, 6) - args[0] = ir.CreateLoad(gWordType, ctx.cfg_func->stack_ptr_var); - args[1] = ir.CreateLoad(gWordType, ctx.cfg_func->frame_ptr_var); + args[0] = ir.CreateLoad(gWordType, ctx.stack_ptr_var); + args[1] = ir.CreateLoad(gWordType, ctx.frame_ptr_var); args[2] = ir.CreateLoad(dword_type, var_value); #else - args[0] = ir.CreateLoad(ctx.cfg_func->stack_ptr_var, true); - args[1] = ir.CreateLoad(ctx.cfg_func->frame_ptr_var, true); + args[0] = ir.CreateLoad(ctx.stack_ptr_var, true); + args[1] = ir.CreateLoad(ctx.frame_ptr_var, true); args[2] = ir.CreateLoad(var_value, true); #endif } else { auto type_index_value = ir.CreateCall(GetExceptionTypeIndex()); #if LLVM_VERSION_NUMBER > LLVM_VERSION(3, 6) - args[0] = ir.CreateLoad(gWordType, ctx.cfg_func->stack_ptr_var); - args[1] = ir.CreateLoad(gWordType, ctx.cfg_func->frame_ptr_var); + args[0] = ir.CreateLoad(gWordType, ctx.stack_ptr_var); + args[1] = ir.CreateLoad(gWordType, ctx.frame_ptr_var); args[2] = ir.CreateTruncOrBitCast(type_index_value, dword_type); #else - args[0] = ir.CreateLoad(ctx.cfg_func->stack_ptr_var, true); - args[1] = ir.CreateLoad(ctx.cfg_func->frame_ptr_var, true); + args[0] = ir.CreateLoad(ctx.stack_ptr_var, true); + args[1] = ir.CreateLoad(ctx.frame_ptr_var, true); args[2] = ir.CreateTruncOrBitCast(type_index_value, dword_type); #endif } @@ -536,82 +717,85 @@ static void CreateLandingPad(TranslationContext &ctx, // Lift landing pads within the function. static void LiftExceptionFrameLP(TranslationContext &ctx, const NativeFunction *cfg_func) { - if (cfg_func->eh_frame.size() > 0) { - auto lifted_func = gModule->getFunction(cfg_func->lifted_name); - lifted_func->addFnAttr(llvm::Attribute::UWTable); - lifted_func->addFnAttr(llvm::Attribute::OptimizeNone); - lifted_func->removeFnAttr(llvm::Attribute::NoUnwind); -#if LLVM_VERSION_NUMBER > LLVM_VERSION(3, 6) - auto personality_func = GetPersonalityFunction(); - lifted_func->setPersonalityFn(personality_func); -#endif + + if (ctx.cfg_func->eh_frame.empty()) { + return; } - for (auto &entry : cfg_func->eh_frame) { + const auto lifted_func = ctx.lifted_func; + lifted_func->addFnAttr(llvm::Attribute::OptimizeNone); + lifted_func->removeFnAttr(llvm::Attribute::NoUnwind); + lifted_func->addFnAttr(llvm::Attribute::UWTable); + +#if LLVM_VERSION_NUMBER > LLVM_VERSION(3, 6) + auto personality_func = GetPersonalityFunction(); + lifted_func->setPersonalityFn(personality_func); +#endif + + for (const auto &entry : cfg_func->eh_frame) { if (entry->lp_ea) { - CreateLandingPad(ctx, entry); + CreateLandingPad(ctx, entry.get()); } } } -// Lift both targets of a conditional branch into a branch in the bitcode, -// where each side of the branch tail-calls to the functions associated with -// the lifted blocks for those branch targets. -static void LiftConditionalBranch(TranslationContext &ctx, - llvm::BasicBlock *source, - remill::Instruction &inst) { - auto block_true = GetOrCreateBlock(ctx, inst.branch_taken_pc); - auto block_false = GetOrCreateBlock(ctx, inst.branch_not_taken_pc); - llvm::IRBuilder<> cond_ir(source); - cond_ir.CreateCondBr( - remill::LoadBranchTaken(source), - block_true, - block_false); -} +static void LiftFuncRestoredRegs(TranslationContext &ctx, + llvm::BasicBlock *block, + bool force=false); // Lift an indirect jump into a switch instruction. -static void LiftIndirectJump(TranslationContext &ctx, - llvm::BasicBlock *block, - remill::Instruction &inst) { +static void LiftIndirectJump( + TranslationContext &ctx, llvm::BasicBlock *block, + const remill::Instruction &inst) { auto exit_point = GetLiftedToNativeExitPoint(kExitPointJump); auto fallback = DevirtualizeIndirectFlow(ctx, exit_point); std::unordered_map block_map; - for (auto target_ea : ctx.cfg_block->successor_eas) { - block_map[target_ea] = GetOrCreateBlock(ctx, target_ea); - fallback = ctx.lifter->intrinsics->missing_block; + if (ctx.cfg_block) { + for (auto target_ea : ctx.cfg_block->successor_eas) { + block_map.emplace(target_ea, GetOrCreateBlock(ctx, target_ea, true)); + } } - if (exit_point == fallback) { + // If we have no targets, then a reasonable target turns out to be the + // next program counter (if we assume that it's a jump table.). + if (block_map.empty()) { + block_map.emplace(inst.next_pc, GetOrCreateBlock(ctx, inst.next_pc)); + } - // If we have no targets, then a reasonable target turns out to be the - // next program counter (if we assume that it's a jump table.). - if (block_map.empty()) { - block_map[inst.next_pc] = GetOrCreateBlock(ctx, inst.next_pc); - } + // Build up a set of all reachable blocks that were known at disassembly + // time so that we can find blocks that have no predecessors. + std::unordered_set succ_eas; + succ_eas.insert(ctx.cfg_func->ea); + for (auto cfg_block : ctx.cfg_func->blocks) { + succ_eas.insert(cfg_block->successor_eas.begin(), + cfg_block->successor_eas.end()); + } - // Build up a set of all reachable blocks that were known at disassembly - // time so that we can find blocks that have no predecessors. - std::unordered_set succ_eas; - succ_eas.insert(ctx.cfg_func->ea); - for (auto &block_entry : ctx.cfg_func->blocks) { - auto &cfg_block = block_entry.second; - succ_eas.insert(cfg_block->successor_eas.begin(), - cfg_block->successor_eas.end()); - } + // We'll augment our block map to also target unreachable blocks, just in + // case our disassembly failed to find some of the targets. + for (auto cfg_block : ctx.cfg_func->blocks) { + const auto block_ea = cfg_block->ea; + if (block_map.count(block_ea)) { + continue; - // We'll augment our block map to also target unreachable blocks, just in - // case our disassembly failed to find some of the targets. - for (auto &block_entry : ctx.cfg_func->blocks) { - auto target_ea = block_entry.first; - if (!succ_eas.count(target_ea)) { - LOG(WARNING) - << "Adding block " << std::hex << target_ea - << " with no predecessors as additional target of the " - << " indirect jump at " << inst.pc << std::dec; - block_map[target_ea] = GetOrCreateBlock(ctx, target_ea); - } + } else if (!succ_eas.count(block_ea)) { + LOG(WARNING) + << "Adding block " << std::hex << block_ea + << " with no predecessors as additional target of the " + << " indirect jump at " << inst.pc << std::dec; + block_map.emplace(block_ea, GetOrCreateBlock(ctx, block_ea, true)); + + // This block is referenced by data, so it also makes a good jump table + // target. + } else if (cfg_block->is_referenced_by_data && + block_ea != ctx.cfg_func->ea) { + LOG(WARNING) + << "Adding block " << std::hex << block_ea + << " referenced by data as additional target of the " + << " indirect jump at " << inst.pc << std::dec; + block_map.emplace(block_ea, GetOrCreateBlock(ctx, block_ea, true)); } } @@ -625,16 +809,20 @@ static void LiftIndirectJump(TranslationContext &ctx, return; } - // Create a "default" fall-back block for the switch. - auto fallback_block = llvm::BasicBlock::Create( + // Create a "default" fall-back block for the switch. The idea here is that + // the xrefs might have been lifted to "block addresses" in the lifted + // `.text` section. + auto fallback_block1 = llvm::BasicBlock::Create( *gContext, "", block->getParent()); - remill::AddTerminatingTailCall(fallback_block, fallback); + // Create a "default" fall-back block for the switch. + auto fallback_block2 = llvm::BasicBlock::Create( + *gContext, "", block->getParent()); auto num_blocks = static_cast(block_map.size()); - auto switch_index = remill::LoadProgramCounter(block); + auto switch_index = LoadProgramCounter(ctx, block); - if (ctx.cfg_inst->offset_table) { + if (ctx.cfg_inst && ctx.cfg_inst->offset_table) { LOG(INFO) << "Indirect jump at " << std::hex << ctx.cfg_inst->ea << " is a jump through an offset table with offset " @@ -642,270 +830,634 @@ static void LiftIndirectJump(TranslationContext &ctx, llvm::IRBuilder<> ir(block); switch_index = ir.CreateAdd( - ir.CreateSub(switch_index, - LiftEA(ctx.cfg_inst->offset_table->target_segment, - ctx.cfg_inst->offset_table->target_ea)), + ir.CreateSub( + switch_index, + LiftXrefInCode(ctx.cfg_inst->offset_table->target_ea)), llvm::ConstantInt::get( gWordType, ctx.cfg_inst->offset_table->target_ea)); - remill::StoreProgramCounter(block, switch_index); +// // TODO(pag): Keep??? +// remill::StoreProgramCounter(block, switch_index); } + // Put the `switch` into its own block. This makes handling indirect jumps + // with delay slots easier, because then we can treat them as direct jumps + // to the switch block. + auto switch_block = llvm::BasicBlock::Create( + *gContext, "", block->getParent()); auto switch_inst = llvm::SwitchInst::Create( - switch_index, fallback_block, num_blocks, block); + switch_index, fallback_block1, num_blocks, switch_block); LOG(INFO) << "Indirect jump at " << std::hex << inst.pc << " has " << std::dec << num_blocks << " targets"; // Add the cases. - for (auto ea_to_block : block_map) { + std::vector fallback_block_eas; + std::vector fallback_funcs; + + auto any_are_64_bit = false; + + for (auto [ea, block] : block_map) { + if (ea != static_cast(ea)) { + any_are_64_bit = true; + } + if (ctx.cfg_module->TryGetFunction(ea)) { + fallback_funcs.push_back(ea); + } else { + fallback_block_eas.push_back(ea); + } + switch_inst->addCase( - llvm::ConstantInt::get(ctx.lifter->word_type, ea_to_block.first, false), - ea_to_block.second); + llvm::ConstantInt::get(ctx.lifter->word_type, ea, false), block); } + + llvm::BranchInst::Create(switch_block, block); + + const auto i32_type = llvm::Type::getInt32Ty(*gContext); + + if (!fallback_block_eas.empty()) { + std::sort(fallback_block_eas.begin(), fallback_block_eas.end()); + const auto max_ea = fallback_block_eas.back(); + + auto lifted_max_ea = LiftXrefInCode(max_ea); + llvm::Value *block_offset = llvm::BinaryOperator::Create( + llvm::Instruction::Sub, lifted_max_ea, switch_index, "", + fallback_block1); + + // The block addresses will be 64-bit values, but the lifted xrefs in the + // jump table may actually be 64-bit xrefs, casted down to 32 bits, so we're + // going to deal with truncated values to hopefully make things work. + if (gArch->address_size == 64 && !any_are_64_bit) { + block_offset = llvm::TruncInst::Create( + llvm::Instruction::Trunc, block_offset, i32_type, "", fallback_block1); + block_offset = llvm::ZExtInst::Create( + llvm::Instruction::ZExt, block_offset, + gWordType, "", fallback_block1); + } + + // Fallback switch on lifted block addresses. + switch_inst = llvm::SwitchInst::Create( + block_offset, fallback_block2, num_blocks, fallback_block1); + + for (auto [ea, block] : block_map) { + switch_inst->addCase( + llvm::ConstantInt::get(ctx.lifter->word_type, max_ea - ea, false), + block); + } + } else { + llvm::BranchInst::Create(fallback_block2, fallback_block1); + } + + // If any of the jump targets are functions, then handle them with a sequence + // of comparisons. + while (!fallback_funcs.empty()) { + auto target_func_ea = fallback_funcs.back(); + fallback_funcs.pop_back(); + + auto func_addr = LiftXrefInCode(target_func_ea); + + // The function addresses will be 64-bit values, but the lifted xrefs in the + // jump table may actually be 64-bit xrefs, casted down to 32 bits, so we're + // going to deal with truncated values to hopefully make things work. + if (gArch->address_size == 64 && !any_are_64_bit) { + func_addr = llvm::ConstantExpr::getTrunc(func_addr, i32_type); + func_addr = llvm::ConstantExpr::getZExt(func_addr, gWordType); + } + + auto cmp = llvm::CmpInst::Create( + llvm::Instruction::ICmp, llvm::CmpInst::ICMP_EQ, + switch_index, func_addr, + "", fallback_block2); + + auto next_fallback = llvm::BasicBlock::Create( + *gContext, "", block->getParent()); + + llvm::BranchInst::Create( + block_map[target_func_ea], + next_fallback, + cmp, + fallback_block2); + + fallback_block2 = next_fallback; + } + + // This is useful for debugging, so that we can see what instruction did + // the indirect jump. + // remill::StoreProgramCounter(fallback_block2, ctx.inst.pc); + + auto mem_ptr = LiftSubFuncCall(ctx, fallback_block2, fallback); + LiftFuncRestoredRegs(ctx, fallback_block2, true); // In case of tail-call. + (void) llvm::ReturnInst::Create(*gContext, mem_ptr, fallback_block2); } -// Returns `true` if `instr` should end a basic block and if a terminator was -// added to end the block. -static bool TryLiftTerminator(TranslationContext &ctx, - llvm::BasicBlock *block, - remill::Instruction &inst) { - switch (inst.category) { - case remill::Instruction::kCategoryInvalid: - case remill::Instruction::kCategoryError: - remill::AddTerminatingTailCall(block, ctx.lifter->intrinsics->error); - return true; +// Call instrumentation. These are useful for debugging. +static void Instrument( + const TranslationContext &ctx, llvm::BasicBlock *block, uint64_t inst_ea) { - case remill::Instruction::kCategoryNormal: - case remill::Instruction::kCategoryNoOp: - return false; - - case remill::Instruction::kCategoryDirectJump: - llvm::BranchInst::Create( - GetOrCreateBlock(ctx, inst.branch_taken_pc), block); - return true; - - case remill::Instruction::kCategoryIndirectJump: - LiftIndirectJump(ctx, block, inst); - return true; - - case remill::Instruction::kCategoryDirectFunctionCall: - - // Treat a `call +5` as not actually needing to call out to a - // new subroutine. - if (inst.branch_taken_pc != inst.next_pc) { - auto targ_func = FindFunction(ctx, inst.branch_taken_pc); - DLOG(INFO) - << "Function " << ctx.lifted_func->getName().str() - << " calls " << targ_func->getName().str() - << " at " << std::hex << inst.pc << std::dec; - if (!ctx.cfg_inst->lp_ea) { - InlineSubFuncCall(block, targ_func); - } else { - auto exception_block = ctx.lp_to_block[ctx.cfg_inst->lp_ea]; - auto normal_block = GetOrCreateBlock(ctx, inst.next_pc); - ctx.ea_to_block[inst.next_pc] = normal_block; - InlineSubFuncInvoke(block, targ_func, normal_block, exception_block, - ctx.cfg_func); - return true; - } - - } else { - LOG(WARNING) - << "Not adding a subroutine self-call at " - << std::hex << inst.pc << std::dec; - } - return false; - - case remill::Instruction::kCategoryIndirectFunctionCall: - InlineSubFuncCall( - block, - DevirtualizeIndirectFlow( - ctx, GetLiftedToNativeExitPoint(kExitPointFunctionCall))); - return false; - - case remill::Instruction::kCategoryFunctionReturn: - llvm::ReturnInst::Create( - *gContext, remill::LoadMemoryPointer(block), block); - return true; - - case remill::Instruction::kCategoryConditionalBranch: - case remill::Instruction::kCategoryConditionalAsyncHyperCall: - LiftConditionalBranch(ctx, block, inst); - return true; - - case remill::Instruction::kCategoryAsyncHyperCall: - InlineSubFuncCall(block, ctx.lifter->intrinsics->async_hyper_call); - remill::StoreProgramCounter(block, inst.next_pc); - return false; - } - return false; -} - -// Lift a decoded instruction into `block`. -static bool LiftInstIntoBlock(TranslationContext &ctx, - llvm::BasicBlock *block, - bool is_last) { - remill::Instruction inst; - - auto inst_addr = ctx.cfg_inst->ea; - auto &bytes = ctx.cfg_inst->bytes; - - if (FLAGS_legacy_mode) { - remill::StoreProgramCounter(block, inst_addr); + if (!FLAGS_trace_reg_values.empty()) { + LiftSubFuncCall( + ctx, block, GetValueTracer(), PCValueKind::kConcretePC, inst_ea); } - if (!gArch->DecodeInstruction(inst_addr, bytes, inst)) { - LOG(ERROR) - << "Unable to decode instruction " << inst.Serialize() - << " at " << std::hex << inst_addr << std::dec; - - remill::AddTerminatingTailCall(block, ctx.lifter->intrinsics->error); - return false; - } - - DLOG_IF(WARNING, bytes.size() != inst.NumBytes()) - << "Size of decoded instruction at " << std::hex << inst_addr - << " (" << std::dec << inst.NumBytes() - << ") doesn't match input instruction size (" - << bytes.size() << ")."; - - if (FLAGS_add_reg_tracer) { - InlineSubFuncCall(block, GetRegTracer()); + if (FLAGS_add_state_tracer) { + LiftSubFuncCall( + ctx, block, GetRegTracer(), PCValueKind::kConcretePC, inst_ea); } if (FLAGS_add_breakpoints) { - InlineSubFuncCall(block, GetBreakPoint(inst_addr)); + llvm::Value *args[1] = {LoadMemoryPointer(ctx, block)}; + auto call = llvm::CallInst::Create(GetBreakPoint(inst_ea), args, "", block); + auto mem_ptr = LoadMemoryPointerRef(ctx, block); + (void) new llvm::StoreInst(call, mem_ptr, block); } - ctx.lifter->LiftIntoBlock(inst, block); - - auto ret = true; - if (TryLiftTerminator(ctx, block, inst)) { - if (!is_last) { - LOG(ERROR) - << "Ending block early at " << std::hex << inst_addr; - ret = false; - } + if (FLAGS_add_pc_tracer) { + auto tracer = GetPCTracer(inst_ea); + llvm::Value *args[1] = {llvm::ConstantInt::get(gWordType, inst_ea)}; + (void) llvm::CallInst::Create(tracer, args, "", block); } +} + +// Lift a decoded instruction into `block`. Returns `false` if there was a +// problem lifting. +static void LiftInstIntoBlock(TranslationContext &ctx, + remill::Instruction &inst, + llvm::BasicBlock *block, + bool is_delayed) { + const auto inst_ea = inst.pc; + auto prev_cfg_inst = ctx.cfg_inst; + if (is_delayed) { + ctx.cfg_inst = ctx.cfg_module->TryGetInstruction(inst_ea); + } + + Instrument(ctx, block, inst_ea); + + // Even when something isn't supported or is invalid, we still lift + // a call to a semantic, e.g.`INVALID_INSTRUCTION`, so we really want + // to treat instruction lifting as an operation that can't fail. + (void) ctx.lifter->LiftIntoBlock(inst, block, is_delayed); // Annotate every un-annotated instruction in this function with the // program counter of the current instruction. if (FLAGS_legacy_mode) { - legacy::AnnotateInsts(ctx.lifted_func, inst_addr); + legacy::AnnotateInsts(ctx.lifted_func, inst_ea); } - return ret; + ctx.cfg_inst = prev_cfg_inst; +} + +static std::unordered_map gTypeToRestorer; + +// Get a type-specific register restorer. +static llvm::Function *GetRestorer(llvm::Type *type) { + auto &func = gTypeToRestorer[type]; + if (func) { + return func; + } + + std::stringstream ss; + ss << "__remill_restore." << remill::LLVMThingToString(type); + const auto name = ss.str(); + func = gModule->getFunction(name); + if (func) { + return func; + } + + llvm::Type *param_types[] = {type, type}; + func = llvm::Function::Create( + llvm::FunctionType::get(type, param_types, false), + llvm::GlobalValue::ExternalLinkage, + name, gModule.get()); + + // Tell LLVM that this function doesn't access memory; this improves LLVM's + // ability to optimize around this function. + func->addFnAttr(llvm::Attribute::ReadNone); + + return func; +} + +static std::unordered_map gTypeToKiller; + +// Get a type-specific register killer. +static llvm::Constant *GetKiller(llvm::Type *type) { + auto &gc = gTypeToKiller[type]; + if (gc) { + return gc; + } + + auto gv = gModule->getGlobalVariable("__remill_kill"); + if (!gv) { + gv = new llvm::GlobalVariable( + *gModule, type, false, llvm::GlobalValue::ExternalLinkage, + nullptr, "__remill_kill"); + } + + gc = llvm::ConstantExpr::getPtrToInt(gv, type); + return gc; +} + + +//static std::unordered_map gTypeToSavingKiller; +// +//// Get a type-specific register killer that lets us still store the right +//// value to the register. +//static llvm::Constant *GetSavingKiller(llvm::Type *type) { +// auto &killer = gTypeToSavingKiller[type]; +// if (killer) { +// return killer; +// } +// +// std::stringstream ss; +// ss << "__remill_saving_kill_" << std::hex +// << reinterpret_cast(type); +// const auto name = ss.str(); +// +// killer = gModule->getFunction(name); +// if (!killer) { +// llvm::Type *param_types[] = {type}; +// killer = llvm::Function::Create( +// llvm::FunctionType::get(type, param_types, false), +// llvm::GlobalValue::ExternalLinkage, name, gModule.get()); +// +// } +// +// killer->addFnAttr(llvm::Attribute::ReadNone); +// +// return killer; +//} + +// Save and restore registers around the body of a function. +void SaveAndRestoreFunctionPreservedRegs( + TranslationContext &ctx, llvm::BasicBlock *entry_block, + llvm::BasicBlock *inst_block, llvm::Value *state_ptr, + uint64_t end_ea, const NativePreservedRegisters ®s) { + + llvm::IRBuilder<> ir(entry_block); + llvm::IRBuilder<> restore_ir(inst_block); + for (const auto ®_name : regs.reg_names) { + if (!gArch->RegisterByName(reg_name)) { + continue; + } + + // If it's a register in the state structure, then we're going to use + // a special preservation pattern. The idea is this: + // + // We will say: + // %reg = load %reg_ptr + // ... + // %latest_val = load %reg_ptr + // %restore_val = call __mcsema_restore.i64(%reg, %latest_val) + // store %restore_val, %reg_ptr + // + // If after optimization, we end up with the following then we can + // eliminate the `store` entirely. + // %restore_val = call __mcsema_restore.i64(%reg, %reg) + // + // However, if after optimization the two parameters don't match, then + // we need to preserve the restore, and we'll replace all uses of + // `%restore_val` with `%reg`. + const auto reg_ptr = ctx.lifter->LoadRegAddress(entry_block, reg_name); + const auto reg = ir.CreateLoad(reg_ptr); + const auto reg_latest = restore_ir.CreateLoad(reg_ptr); + llvm::Value *restorer_args[] = {reg, reg_latest}; + + // NOTE(pag): We use volatile stores so that LLVM doesn't eliminate them + // if we're saving/restoring an `alloca`d object. + const auto restorer = GetRestorer(reg->getType()); + restore_ir.CreateStore( + restore_ir.CreateCall(restorer, restorer_args), + reg_ptr, + true /* IsVolatile */); + + // Restored ones should be inserted in reverse order. + restore_ir.SetInsertPoint(reg_latest); + } +} + +static void LiftDelayedInstIntoBlock(TranslationContext &ctx, + llvm::BasicBlock *block, + bool on_taken_path) { + if (ctx.delayed_inst.IsValid() && + gArch->NextInstructionIsDelayed(ctx.inst, ctx.delayed_inst, on_taken_path)) { + LiftInstIntoBlock( + ctx, ctx.delayed_inst, block, true /* is_delayed */); + } +} + +static void LiftSavedRegs(TranslationContext &ctx, llvm::BasicBlock *block) { + + llvm::IRBuilder<> ir(block); + DCHECK(ctx.inst.IsFunctionCall()); + ctx.cfg_module->ForEachInstructionPreservedRegister( + ctx.inst.pc, + [=, &ir, &ctx] (const std::string ®_name) { + if (const auto reg = gArch->RegisterByName(reg_name); reg) { + const auto reg_ptr = ctx.lifter->LoadRegAddress(block, reg_name); + const auto reg_val = ir.CreateLoad(reg_ptr); + ctx.preserved_regs.emplace_back(reg_ptr, reg_val); + } + }); +} + +static void LiftRestoredRegs(TranslationContext &ctx, llvm::BasicBlock *block) { + if (ctx.preserved_regs.empty()) { + return; + } + std::reverse(ctx.preserved_regs.begin(), ctx.preserved_regs.end()); + llvm::IRBuilder<> ir(block); + for (auto [reg_ptr, saved_val] : ctx.preserved_regs) { + ir.CreateStore(saved_val, reg_ptr); + } + ctx.preserved_regs.clear(); +} + +void LiftFuncRestoredRegs(TranslationContext &ctx, llvm::BasicBlock *block, + bool force) { + auto regs_it = ctx.func_preserved_regs.find(ctx.inst.pc); + if (regs_it == ctx.func_preserved_regs.end()) { + if (!force || ctx.func_preserved_regs.empty()) { + return; + } else { + regs_it = ctx.func_preserved_regs.begin(); + } + } + + const auto func = block->getParent(); + const auto state_ptr = LoadStatePointer(ctx, block); + SaveAndRestoreFunctionPreservedRegs( + ctx, &(func->getEntryBlock()), block, state_ptr, + ctx.inst.pc, *(regs_it->second)); +} + +static void KillPCAndNextPC(TranslationContext &ctx, llvm::BasicBlock *block) { + const auto pc_ref = LoadProgramCounterRef(ctx, block); + const auto npc_ref = LoadNextProgramCounterRef(ctx, block); + llvm::IRBuilder<> ir(block); + const auto kill_value = GetKiller(gWordType); + ir.CreateStore(kill_value, pc_ref); + ir.CreateStore(kill_value, npc_ref); +} + +static void LiftKilledRegs(TranslationContext &ctx, llvm::BasicBlock *block) { + llvm::IRBuilder<> ir(block); + ctx.cfg_module->ForEachInstructionKilledRegister( + ctx.inst.pc, + [=, &ir, &ctx](const std::string ®_name) { + const auto reg_ptr = ctx.lifter->LoadRegAddress(block, reg_name); + if (!reg_ptr) { + return; + } + auto reg_type = reg_ptr->getType()->getPointerElementType(); + ir.CreateStore(GetKiller(reg_type), reg_ptr); + }); +} + +// Get the basic block within this function associated with a specific program +// counter. +llvm::BasicBlock *GetOrCreateBlock(TranslationContext &ctx, + uint64_t pc, bool force_as_block) { + auto &block = ctx.ea_to_block[pc]; + if (block) { + return block; + } + + std::stringstream ss; + ss << "inst_" << std::hex << pc; + block = llvm::BasicBlock::Create(*gContext, ss.str(), ctx.lifted_func); + + // Missed an instruction?! This can happen when IDA merges two instructions + // into one larger synthetic instruction. This might also be a tail-call. + ctx.work_list.emplace_back(pc, force_as_block, ctx.inst.pc); + + return block; +} + +// Figure out the fall-through return address for a function call. On some +// architectures we need more logic here. +static uint64_t FunctionReturnAddress(TranslationContext &ctx) { + return ctx.inst.branch_not_taken_pc; } // Lift a decoded block into a function. -static void LiftBlockIntoFunction(TranslationContext &ctx) { - auto block_pc = ctx.cfg_block->ea; - auto block = ctx.ea_to_block[block_pc]; +static void LiftInstIntoFunction(TranslationContext &ctx, + llvm::BasicBlock *block) { + LiftInstIntoBlock(ctx, ctx.inst, block, false /* is_delayed */); - ctx.cfg_inst = nullptr; - - // Lift each instruction into the block. - size_t i = 0; - const auto num_insts = ctx.cfg_block->instructions.size(); - for (auto &cfg_inst : ctx.cfg_block->instructions) { - ctx.cfg_inst = cfg_inst.get(); - auto is_last = (++i) >= num_insts; - - if (!LiftInstIntoBlock(ctx, block, is_last)) { - return; - } - - LOG_IF(WARNING, cfg_inst->does_not_return && !is_last) - << "Instruction at " << std::hex << cfg_inst->ea - << " has a local no-return, but is not the last instruction" - << " in its block (" << std::hex << block_pc - << "). Terminating anyway." << std::dec; + // We might need to lift another instruction and execute it in the delay + // slot. `cont` contains enough info to redirect control flow after we've + // dealt with the lifting of the delayed instruction. + if (ctx.delayed_inst.IsValid()) { + ctx.delayed_inst.Reset(); } - const auto &follows = ctx.cfg_block->successor_eas; - if (!block->getTerminator()) { - if (!ctx.cfg_inst || ctx.cfg_inst->does_not_return) { - LOG_IF(ERROR, !ctx.cfg_inst) - << "Block " << std::hex << block_pc << " in function " - << ctx.cfg_func->ea << std::dec << " has no instructions; " - << "this could be because of an incorrectly disassembled jump table."; - - remill::AddTerminatingTailCall(block, ctx.lifter->intrinsics->error); - - } else if (follows.size() == 1) { - (void) llvm::BranchInst::Create( - GetOrCreateBlock(ctx, *(follows.begin())), block); - - } else { + if (gArch->MayHaveDelaySlot(ctx.inst)) { + if (!TryDecodeInstruction(ctx, ctx.inst.delayed_pc, true) || + !ctx.delayed_inst.IsValid()) { LOG(ERROR) - << "Block " << std::hex << block_pc << " has no terminator, and" - << " instruction at " << std::hex << ctx.cfg_inst->ea - << " is not a local no-return function call." << std::dec; - - remill::AddTerminatingTailCall( - block, ctx.lifter->intrinsics->missing_block); + << "Unable to decode or use delayed instruction at " << std::hex + << ctx.inst.delayed_pc << std::dec << " of " << ctx.inst.Serialize(); } } -} -// Allocate storage of the stack variables that we're going to lift. -static void AllocStackVars(llvm::BasicBlock *bb, - const NativeFunction *cfg_func) { - llvm::IRBuilder<> ir(bb); - llvm::Value *array_size = nullptr; - llvm::Type *array_type = nullptr; + ctx.preserved_regs.clear(); - for (auto s : cfg_func->stack_vars) { - switch(s->size){ - case 1: - case 2: - case 4: - case 8: - array_type = llvm::Type::getIntNTy( - *gContext, static_cast(s->size * 8U)); - array_size = llvm::ConstantInt::get(gWordType, 1); - break; + const auto intrinsics = ctx.lifter->intrinsics; - default: - array_type = llvm::Type::getInt8Ty(*gContext); - array_size = llvm::ConstantInt::get(gWordType, s->size); - break; + switch (ctx.inst.category) { + case remill::Instruction::kCategoryInvalid: + remill::AddTerminatingTailCall(block, intrinsics->error); + break; + + case remill::Instruction::kCategoryError: + LiftDelayedInstIntoBlock(ctx, block, true); + LiftFuncRestoredRegs(ctx, block, true); + KillPCAndNextPC(ctx, block); + LiftKilledRegs(ctx, block); + remill::AddTerminatingTailCall(block, intrinsics->error); + break; + + case remill::Instruction::kCategoryNormal: { + CHECK(!ctx.delayed_inst.IsValid()); + llvm::BranchInst::Create(GetOrCreateBlock(ctx, ctx.inst.next_pc), block); + break; } - LOG(INFO) - << "Inserting " << s->size << "-byte variable " << s->name - << " into function" << cfg_func->name; + case remill::Instruction::kCategoryNoOp: { + CHECK(!ctx.delayed_inst.IsValid()); + auto next_func = ctx.cfg_module->TryGetFunction(ctx.inst.next_pc); + if (next_func && (next_func->ea != ctx.cfg_func->ea)) { + LiftFuncRestoredRegs(ctx, block); + KillPCAndNextPC(ctx, block); + LiftKilledRegs(ctx, block); + llvm::ReturnInst::Create( + *gContext, LoadMemoryPointer(ctx, block), block); + } else { + llvm::BranchInst::Create(GetOrCreateBlock(ctx, ctx.inst.next_pc), block); + } + break; + } - // TODO(kumarak): Alignment of `alloca`s? - s->llvm_var = ir.CreateAlloca(array_type, array_size, s->name); + case remill::Instruction::kCategoryDirectJump: + LiftDelayedInstIntoBlock(ctx, block, true); + KillPCAndNextPC(ctx, block); + llvm::BranchInst::Create( + GetOrCreateBlock(ctx, ctx.inst.branch_taken_pc), block); + break; + + case remill::Instruction::kCategoryIndirectJump: + LiftDelayedInstIntoBlock(ctx, block, true); + LiftIndirectJump(ctx, block, ctx.inst); + break; + + case remill::Instruction::kCategoryDirectFunctionCall: { + LiftDelayedInstIntoBlock(ctx, block, true); + + if (auto [targ_cfg_func, targ_func] = FindFunction(ctx, ctx.inst.branch_taken_pc); + targ_cfg_func && targ_func) { + + if (!ctx.cfg_inst || !ctx.cfg_inst->lp_ea) { + LiftSavedRegs(ctx, block); + KillPCAndNextPC(ctx, block); + LiftKilledRegs(ctx, block); + LiftSubFuncCall(ctx, block, targ_func, PCValueKind::kUndefPC); + LiftRestoredRegs(ctx, block); + llvm::BranchInst::Create( + GetOrCreateBlock(ctx, FunctionReturnAddress(ctx)), block); + + // TODO(pag): The save/restore optimization will produce unexpected + // lifts when exceptions are involved. + } else { + auto exception_block = ctx.lp_to_block[ctx.cfg_inst->lp_ea]; + auto normal_block = GetOrCreateBlock(ctx, FunctionReturnAddress(ctx)); + KillPCAndNextPC(ctx, block); + LiftKilledRegs(ctx, block); + InlineSubFuncInvoke( + ctx, block, targ_func, normal_block, exception_block, + ctx.cfg_func, PCValueKind::kUndefPC); + } + + // Treat a `call +5` as not actually needing to call out to a + // new subroutine. + } else if (ctx.inst.branch_taken_pc != ctx.inst.next_pc) { + LOG(WARNING) + << "Not adding a subroutine self-call at " + << std::hex << ctx.inst.pc << std::dec; + llvm::BranchInst::Create( + GetOrCreateBlock(ctx, ctx.inst.branch_taken_pc), block); + + // This is a legitimate call to a function that seems to have been missed. + } else { + LOG(ERROR) + << "Cannot find target of instruction at " << std::hex + << ctx.inst.pc << "; the static target " + << std::hex << ctx.inst.branch_taken_pc + << " is not associated with a lifted subroutine, and it does not " + << "have a known call target" << std::dec; + + LiftSavedRegs(ctx, block); + KillPCAndNextPC(ctx, block); + LiftKilledRegs(ctx, block); + LiftSubFuncCall(ctx, block, intrinsics->function_call, + PCValueKind::kConcretePC, ctx.inst.branch_taken_pc); + LiftRestoredRegs(ctx, block); + llvm::BranchInst::Create( + GetOrCreateBlock(ctx, ctx.inst.branch_not_taken_pc), block); + } + break; + } + + case remill::Instruction::kCategoryIndirectFunctionCall: { + const auto fallback_func = GetLiftedToNativeExitPoint( + kExitPointFunctionCall); + const auto target_func = DevirtualizeIndirectFlow( + ctx, fallback_func); + + LOG_IF(ERROR, ctx.cfg_inst && ctx.cfg_inst->lp_ea) + << "Not treating call from " << std::hex << ctx.inst.pc + << " as invoke" << std::dec; + + LiftDelayedInstIntoBlock(ctx, block, true); + + if (!ctx.cfg_inst || !ctx.cfg_inst->lp_ea) { + LiftSavedRegs(ctx, block); + LiftKilledRegs(ctx, block); + if (fallback_func == target_func) { + LiftSubFuncCall(ctx, block, target_func); + } else { + KillPCAndNextPC(ctx, block); + LiftSubFuncCall(ctx, block, target_func, PCValueKind::kUndefPC); + } + LiftRestoredRegs(ctx, block); + llvm::BranchInst::Create( + GetOrCreateBlock(ctx, FunctionReturnAddress(ctx)), block); + + } else { + auto exception_block = ctx.lp_to_block[ctx.cfg_inst->lp_ea]; + auto normal_block = GetOrCreateBlock(ctx, FunctionReturnAddress(ctx)); + + if (fallback_func == target_func) { + InlineSubFuncInvoke( + ctx, block, target_func, normal_block, exception_block, + ctx.cfg_func); + + } else { + KillPCAndNextPC(ctx, block); + LiftKilledRegs(ctx, block); + InlineSubFuncInvoke( + ctx, block, target_func, normal_block, exception_block, + ctx.cfg_func, PCValueKind::kUndefPC); + } + } + break; + } + + case remill::Instruction::kCategoryFunctionReturn: + LiftDelayedInstIntoBlock(ctx, block, true); + LiftFuncRestoredRegs(ctx, block); + KillPCAndNextPC(ctx, block); + LiftKilledRegs(ctx, block); + llvm::ReturnInst::Create( + *gContext, LoadMemoryPointer(ctx, block), block); + break; + + case remill::Instruction::kCategoryConditionalBranch: + case remill::Instruction::kCategoryConditionalAsyncHyperCall: { + const auto cond = remill::LoadBranchTaken(block); + const auto taken_block = llvm::BasicBlock::Create( + *gContext, "", ctx.lifted_func); + const auto not_taken_block = llvm::BasicBlock::Create( + *gContext, "", ctx.lifted_func); + llvm::BranchInst::Create( + taken_block, not_taken_block, cond, block); + LiftDelayedInstIntoBlock(ctx, taken_block, true); + LiftDelayedInstIntoBlock(ctx, not_taken_block, false); + llvm::BranchInst::Create( + GetOrCreateBlock(ctx, ctx.inst.branch_taken_pc), taken_block); + llvm::BranchInst::Create( + GetOrCreateBlock(ctx, ctx.inst.branch_not_taken_pc), not_taken_block); + break; + } + + case remill::Instruction::kCategoryAsyncHyperCall: + LiftDelayedInstIntoBlock(ctx, block, true); + LiftSubFuncCall(ctx, block, ctx.lifter->intrinsics->async_hyper_call); + llvm::BranchInst::Create( + GetOrCreateBlock(ctx, ctx.inst.branch_taken_pc), block); + break; } - - cfg_func->stack_ptr_var = ir.CreateAlloca( - llvm::Type::getInt64Ty(*gContext), - llvm::ConstantInt::get(gWordType, 1), "stack_ptr_var"); - - cfg_func->frame_ptr_var = ir.CreateAlloca( - llvm::Type::getInt64Ty(*gContext), - llvm::ConstantInt::get(gWordType, 1), "frame_ptr_var"); } static llvm::Function *LiftFunction( - const NativeModule *cfg_module, const NativeFunction *cfg_func) { + const NativeModule *cfg_module, const NativeFunction *cfg_func, + const remill::IntrinsicTable &intrinsics) { CHECK(!cfg_func->is_external) << "Should not lift external function " << cfg_func->name; - static std::unique_ptr intrinsics; - if (!intrinsics.get()) { - intrinsics.reset(new remill::IntrinsicTable(gModule)); - } - - auto lifted_func = gModule->getFunction(cfg_func->lifted_name); + const auto lifted_func = cfg_func->lifted_function; CHECK(nullptr != lifted_func) << "Could not find declaration for " << cfg_func->lifted_name; - cfg_func->function = lifted_func; // This can happen due to deduplication of functions during the // CFG decoding process. In practice, though, that only really @@ -918,30 +1470,31 @@ static llvm::Function *LiftFunction( } if (cfg_func->blocks.empty()) { - LOG(ERROR) + LOG(WARNING) << "Function " << cfg_func->lifted_name << " is empty!"; - remill::AddTerminatingTailCall(lifted_func, intrinsics->missing_block); + remill::AddTerminatingTailCall(lifted_func, intrinsics.missing_block); return lifted_func; } remill::CloneBlockFunctionInto(lifted_func); - lifted_func->removeFnAttr(llvm::Attribute::AlwaysInline); - lifted_func->removeFnAttr(llvm::Attribute::InlineHint); lifted_func->removeFnAttr(llvm::Attribute::NoReturn); lifted_func->removeFnAttr(llvm::Attribute::NoUnwind); - lifted_func->addFnAttr(llvm::Attribute::NoInline); lifted_func->setVisibility(llvm::GlobalValue::DefaultVisibility); + lifted_func->setLinkage(llvm::GlobalValue::ExternalLinkage); + + lifted_func->removeFnAttr(llvm::Attribute::AlwaysInline); + lifted_func->removeFnAttr(llvm::Attribute::InlineHint); + lifted_func->addFnAttr(llvm::Attribute::NoInline); if (FLAGS_stack_protector) { lifted_func->addFnAttr(llvm::Attribute::StackProtectReq); } TranslationContext ctx; - std::unique_ptr lifter( - new InstructionLifter(intrinsics.get(), ctx)); + InstructionLifter lifter(&intrinsics, ctx); - ctx.lifter = lifter.get(); + ctx.lifter = &lifter; ctx.cfg_module = cfg_module; ctx.cfg_func = cfg_func; ctx.cfg_block = nullptr; @@ -951,76 +1504,130 @@ static llvm::Function *LiftFunction( std::unordered_set referenced_blocks; referenced_blocks.insert(cfg_func->ea); - - // Create basic blocks for each basic block in the original function. - for (auto &block_info : cfg_func->blocks) { - std::stringstream ss; - ss << "block_" << std::hex << block_info.first; - ctx.ea_to_block[block_info.first] = llvm::BasicBlock::Create( - *gContext, ss.str(), lifted_func); + // Collect the known set of blocks into a work list, and add basic blocks + // for each of them. + for (const auto cfg_block : cfg_func->blocks) { + const auto block_ea = cfg_block->ea; + (void) GetOrCreateBlock(ctx, block_ea, true /* force */); } - // Allocate the stack variable recovered in the function - auto entry_block = ctx.ea_to_block[cfg_func->ea]; - AllocStackVars(entry_block, cfg_func); + std::sort(ctx.work_list.begin(), ctx.work_list.end(), + [] (std::tuple a, + std::tuple b) { + return std::get<0>(a) < std::get<0>(b); + }); + auto unique_it = std::unique(ctx.work_list.begin(), ctx.work_list.end()); + ctx.work_list.erase(unique_it, ctx.work_list.end()); // Lift the landing pad if there are exception frames recovered. LiftExceptionFrameLP(ctx, cfg_func); - llvm::BranchInst::Create(ctx.ea_to_block[cfg_func->ea], - &(lifted_func->front())); + const auto entry_block = &(lifted_func->front()); - for (auto &block_info : cfg_func->blocks) { - ctx.cfg_block = block_info.second.get(); - LiftBlockIntoFunction(ctx); + if (FLAGS_add_func_state_tracer) { + LiftSubFuncCall(ctx, entry_block, GetRegTracer()); } - // Check the sanity of things. - for (auto block_info : ctx.ea_to_block) { - auto block = block_info.second; - CHECK(block->getTerminator() != nullptr) - << "Lifted block " << std::hex << block_info.first - << " has no terminator!" << std::dec; + const auto next_pc_ref = LoadNextProgramCounterRef(ctx, entry_block); + const auto pc_ref = LoadProgramCounterRef(ctx, entry_block); + const auto pc = LiftXrefInCode(cfg_func->ea); + llvm::IRBuilder<> ir(entry_block); + ir.CreateStore(pc, next_pc_ref); + ir.CreateStore(pc, pc_ref); + + // Used for exception handling. + ctx.stack_ptr_var = ir.CreateAlloca( + llvm::Type::getInt64Ty(*gContext), + llvm::ConstantInt::get(gWordType, 1), "stack_ptr_var"); + + ctx.frame_ptr_var = ir.CreateAlloca( + llvm::Type::getInt64Ty(*gContext), + llvm::ConstantInt::get(gWordType, 1), "frame_ptr_var"); + + // Preserve registers at a function granularity. + cfg_module->ForEachRangePreservedRegister( + cfg_func->ea, + [=, &ctx] (uint64_t end_ea, const NativePreservedRegisters ®s) { + ctx.func_preserved_regs.emplace(end_ea, ®s); + }); + + // Reverse the work list so that we can treat it like a stack. + std::reverse(ctx.work_list.begin(), ctx.work_list.end()); + + // Process the instructions in reverse order, filling up their basic blocks. + while (!ctx.work_list.empty()) { + auto [inst_ea, force_as_block, from_ea] = ctx.work_list.back(); + ctx.work_list.pop_back(); + + auto block = ctx.ea_to_block[inst_ea]; + CHECK_NOTNULL(block); + + if (!block->empty()) { + continue; // Already handled. + } + + // First, try to see if it's actually related to another function. This is + // equivalent to a tail-call in the original code. + if (inst_ea != cfg_func->ea) { + if (auto tail_called_func = cfg_module->TryGetFunction(inst_ea); + tail_called_func && !force_as_block) { + LOG(WARNING) + << "Adding tail-call from " << std::hex << inst_ea + << " in function " << ctx.cfg_func->lifted_name << " to " + << tail_called_func->lifted_name << " from " << from_ea << std::dec; + + auto mem_ptr = LiftSubFuncCall( + ctx, block, + CallableLiftedFunc(tail_called_func, + ctx.lifter->intrinsics->function_call)); + LiftFuncRestoredRegs(ctx, block, true); + (void) llvm::ReturnInst::Create(*gContext, mem_ptr, block); + continue; + } + } + + if (!TryDecodeInstruction(ctx, inst_ea, false)) { + if (from_ea) { + LOG(ERROR) + << "Could not decode instruction at " << std::hex << inst_ea + << " reachable from instruction " << from_ea << " in function " + << cfg_func->name << " at " << cfg_func->ea + << std::dec << ": " << ctx.inst.Serialize(); + } else { + LOG(ERROR) + << "Could not decode instruction at " << std::hex << inst_ea + << " in function " << cfg_func->name << " at " << cfg_func->ea + << std::dec << ": " << ctx.inst.Serialize(); + } + remill::AddTerminatingTailCall(block, intrinsics.error); + + } else if (!ctx.inst.IsValid() || ctx.inst.IsError()) { + remill::AddTerminatingTailCall(block, intrinsics.error); + + } else { + ctx.cfg_block = ctx.cfg_module->TryGetBlock(inst_ea, ctx.cfg_block); + ctx.cfg_inst = ctx.cfg_module->TryGetInstruction(inst_ea); + LiftInstIntoFunction(ctx, block); + } } - remill::Annotate(lifted_func); + // Connect the function to the first block. + llvm::BranchInst::Create(ctx.ea_to_block[cfg_func->ea], entry_block); + + // NOTE(pag): We may have unreachable blocks, especially on architectures + // like where instructions in delay slots might not be reachable + // on their own. + + const auto mut_cfg_func = const_cast(cfg_func); + mut_cfg_func->blocks.clear(); + mut_cfg_func->eh_frame.clear(); return lifted_func; } -} // namespace - -// Declare the lifted functions. This is a separate step from defining -// functions because it's important that all possible code- and data-cross -// references are resolved before any data or instructions can use -// those references. -void DeclareLiftedFunctions(const NativeModule *cfg_module) { - for (auto &func : cfg_module->ea_to_func) { - auto cfg_func = func.second->Get(); - if (cfg_func->is_external) { - continue; - } - - const auto &func_name = cfg_func->lifted_name; - auto lifted_func = gModule->getFunction(func_name); - - if (!lifted_func) { - lifted_func = remill::DeclareLiftedFunction(gModule.get(), func_name); - - // make local functions 'static' - LOG(INFO) - << "Inserted function: " << func_name; - - } else { - LOG(INFO) - << "Already inserted function: " << func_name << ", skipping."; - } - } -} - using Calls_t = std::vector; -bool ShouldInline(const llvm::CallSite &cs) { +static bool ShouldInline(const llvm::CallSite &cs) { if (!cs) { return false; } @@ -1028,7 +1635,7 @@ bool ShouldInline(const llvm::CallSite &cs) { return callee && remill::HasOriginType(callee); } -Calls_t InlinableCalls(llvm::Function &func) { +static Calls_t InlinableCalls(llvm::Function &func) { Calls_t out; for (auto &bb : func) { for (auto &inst : bb) { @@ -1041,7 +1648,7 @@ Calls_t InlinableCalls(llvm::Function &func) { return out; } -void InlineCalls(llvm::Function &func) { +static void InlineCalls(llvm::Function &func) { for (auto &cs : InlinableCalls(func)) { if (auto call = llvm::dyn_cast(cs.getInstruction())) { llvm::InlineFunctionInfo info; @@ -1050,6 +1657,44 @@ void InlineCalls(llvm::Function &func) { } } +} // namespace + +// Declare the lifted functions. This is a separate step from defining +// functions because it's important that all possible code- and data-cross +// references are resolved before any data or instructions can use +// those references. +void DeclareLiftedFunctions(const NativeModule *cfg_module) { + + for (const auto [ea, cfg_func] : cfg_module->ea_to_func) { + (void) ea; + + if (cfg_func->is_external) { + continue; + } + + const auto &func_name = cfg_func->lifted_name; + auto lifted_func = gModule->getFunction(func_name); + + if (!lifted_func) { + lifted_func = remill::DeclareLiftedFunction( + gModule.get(), func_name); + + // make local functions 'static' + LOG(INFO) + << "Inserted function: " << func_name; + + } else { + LOG(INFO) + << "Already inserted function: " << func_name << ", skipping."; + } + + // All lifted functions are marked as external so they aren't optimized + // away. + lifted_func->setLinkage(llvm::GlobalValue::ExternalLinkage); + cfg_func->lifted_function = lifted_func; + } +} + // Lift the blocks and instructions into the function. Some minor optimization // passes are applied to clean out any unneeded register variables brought // in from cloning the `__remill_basic_block` function. @@ -1062,17 +1707,35 @@ bool DefineLiftedFunctions(const NativeModule *cfg_module) { func_pass_manager.add(llvm::createDeadCodeEliminationPass()); func_pass_manager.doInitialization(); - for (auto &entry : cfg_module->ea_to_func) { - auto cfg_func = reinterpret_cast( - entry.second->Get()); + remill::IntrinsicTable intrinsics(gModule); + + // Make sure that `callable_lifted_function` is defined for each function. + for (auto [ea, cfg_func] : cfg_module->ea_to_func) { + (void) ea; + + DCHECK_EQ(cfg_func, cfg_func->Get()); + + if (cfg_func->is_external) { + (void) GetLiftedToNativeExitPoint(cfg_func); + + } else { + // For local calls between lifted functions, prefer our state-passing + // version, even if we generate an entry point + cfg_func->callable_lifted_function = cfg_func->lifted_function; + } + } + + for (auto [ea, cfg_func] : cfg_module->ea_to_func) { + (void) ea; + if (cfg_func->is_external) { continue; } - auto lifted_func = LiftFunction(cfg_module, cfg_func); + auto lifted_func = LiftFunction(cfg_module, cfg_func, intrinsics); if (!lifted_func) { LOG(ERROR) - << "Could lift function: " << cfg_func->name << " at " + << "Could not lift function: " << cfg_func->name << " at " << std::hex << cfg_func->ea << " into " << cfg_func->lifted_name << std::dec; return false; @@ -1081,9 +1744,10 @@ bool DefineLiftedFunctions(const NativeModule *cfg_module) { // Unfortunately there can be `return_twice` attribute on some external functions // (setjmp). This prevents llvm from inlining the `ext_` wrapper, but it is mandatory // that the actual call is behind a wrapper (due to how it is implemented). - if (FLAGS_explicit_args && !FLAGS_disable_optimizer) { + if (false && FLAGS_explicit_args) { InlineCalls(*lifted_func); } + func_pass_manager.run(*lifted_func); } diff --git a/mcsema/BC/Function.h b/mcsema/BC/Function.h index 4e2708f85..a7302c54f 100644 --- a/mcsema/BC/Function.h +++ b/mcsema/BC/Function.h @@ -1,21 +1,21 @@ /* - * Copyright (c) 2017 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ -#ifndef MCSEMA_BC_FUNCTION_H_ -#define MCSEMA_BC_FUNCTION_H_ +#pragma once namespace mcsema { struct NativeModule; @@ -25,5 +25,3 @@ void DeclareLiftedFunctions(const NativeModule *cfg_module); bool DefineLiftedFunctions(const NativeModule *cfg_module); } // namespace mcsema - -#endif // MCSEMA_BC_FUNCTION_H_ diff --git a/mcsema/BC/Instruction.cpp b/mcsema/BC/Instruction.cpp index 92328edf1..0e4e4c625 100644 --- a/mcsema/BC/Instruction.cpp +++ b/mcsema/BC/Instruction.cpp @@ -1,19 +1,22 @@ /* - * Copyright (c) 2017 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ +#include "Instruction.h" + #include #include @@ -28,137 +31,69 @@ #include #include -#include "Instruction.h" #include "remill/Arch/Arch.h" #include "remill/Arch/Instruction.h" #include "remill/BC/Util.h" #include "mcsema/Arch/Arch.h" - #include "mcsema/BC/Callback.h" -#include "mcsema/BC/Instruction.h" #include "mcsema/BC/Lift.h" #include "mcsema/BC/Util.h" - #include "mcsema/CFG/CFG.h" + namespace mcsema { -namespace { - -// Load the address of a register. -static llvm::Value *LoadRegAddress(llvm::BasicBlock *block, - std::string reg_name) { - return remill::FindVarInFunction(block->getParent(), reg_name); -} - -// Load the value of a register. -static llvm::Value *LoadRegValue(llvm::BasicBlock *block, - std::string reg_name) { - return new llvm::LoadInst(LoadRegAddress(block, reg_name), "", block); -} - -static llvm::Value *LoadAddressRegVal(llvm::BasicBlock *block, - const remill::Operand::Register ®, - llvm::ConstantInt *zero) { - if (reg.name.empty()) { - return zero; - } - - auto value = LoadRegValue(block, reg.name); - auto value_type = llvm::dyn_cast(value->getType()); - auto word_type = zero->getType(); - - CHECK(value_type) - << "Register " << reg.name << " expected to be an integer."; - - auto value_size = value_type->getBitWidth(); - auto word_size = word_type->getBitWidth(); - CHECK(value_size <= word_size) - << "Register " << reg.name << " expected to be no larger than the " - << "machine word size (" << word_type->getBitWidth() << " bits)."; - - if (value_size < word_size) { - value = new llvm::ZExtInst(value, word_type, "", block); - } - - return value; -} - -static bool IsFramePointerReg(const remill::Operand::Register ®) { - - if (reg.name.empty()) { - return false; - } - - if (mcsema::gArch->IsAMD64()) { - return reg.name == "RBP"; - } else if (mcsema::gArch->IsX86()) { - return reg.name == "EBP"; - } - return false; -} - -static bool IsStackPointerReg(const remill::Operand::Register ®) { - - if (reg.name.empty()) { - return false; - } - - if (mcsema::gArch->IsAMD64()) { - return reg.name == "RSP"; - } else if (mcsema::gArch->IsX86()) { - return reg.name == "ESP"; - } else if (mcsema::gArch->IsAArch64()) { - return reg.name == "SP" || reg.name == "WSP"; - } - return false; -} - -} // namespace - InstructionLifter::~InstructionLifter(void) {} InstructionLifter::InstructionLifter(const remill::IntrinsicTable *intrinsics_, TranslationContext &ctx_) - : remill::InstructionLifter(gArch, intrinsics_), + : remill::InstructionLifter(gArch.get(), intrinsics_), ctx(ctx_) {} // Lift a single instruction into a basic block. remill::LiftStatus InstructionLifter::LiftIntoBlock( - remill::Instruction &inst, llvm::BasicBlock *block_) { + remill::Instruction &inst, llvm::BasicBlock *block_, bool is_delayed) { inst_ptr = &inst; block = block_; - mem_ref = GetAddress(ctx.cfg_inst->mem); - imm_ref = GetMaskedAddress(ctx.cfg_inst->imm); - disp_ref = GetMaskedAddress(ctx.cfg_inst->disp); + + if (ctx.cfg_inst) { + mem_ref = GetAddress(ctx.cfg_inst->mem); + imm_ref = GetAddress(ctx.cfg_inst->imm); + disp_ref = GetAddress(ctx.cfg_inst->disp); + } else { + mem_ref = nullptr; + imm_ref = nullptr; + disp_ref = nullptr; + } mem_ref_used = false; disp_ref_used = false; imm_ref_used = false; - auto status = this->remill::InstructionLifter::LiftIntoBlock(inst, block); + auto status = this->remill::InstructionLifter::LiftIntoBlock( + inst, block, is_delayed); // If we have semantics for the instruction, then make sure that we were // able to match cross-reference information to the instruction's operands. if (remill::kLiftedInstruction == status) { if (mem_ref && !mem_ref_used) { - LOG(FATAL) + LOG(ERROR) << "Unused memory reference operand to " << std::hex << ctx.cfg_inst->mem->target_ea << " in instruction " << inst.Serialize() << std::dec; } if (imm_ref && !imm_ref_used) { - LOG(FATAL) + LOG(ERROR) << "Unused immediate operand reference to " << std::hex << ctx.cfg_inst->imm->target_ea << " in instruction " << inst.Serialize() << std::dec; } if (disp_ref && !disp_ref_used) { - LOG(FATAL) + LOG(ERROR) << "Unused displacement operand reference to " << std::hex << ctx.cfg_inst->disp->target_ea << " in instruction " << inst.Serialize() << std::dec; @@ -168,149 +103,72 @@ remill::LiftStatus InstructionLifter::LiftIntoBlock( return status; } -llvm::Value *InstructionLifter::GetMaskedAddress(const NativeXref *cfg_xref) { - auto addr = GetAddress(cfg_xref); - if (!addr || !cfg_xref->mask) { - return addr; - } +//// Returns `true` if a given cross-reference is self-referential. That is, +//// we'll have something like `jmp cs:EnterCriticalSection`, which references +//// `EnterCriticalSection` in the `.idata` section of a PE file. But this +//// location is our only "place" for the external `EnterCriticalSection`, so +//// we point it back at itself. +//static bool IsSelfReferential(const NativeXref *cfg_xref) { +// if (!cfg_xref->target_segment) { +// return false; +// } +// +// auto it = cfg_xref->target_segment->entries.find(cfg_xref->target_ea); +// if (it == cfg_xref->target_segment->entries.end()) { +// return false; +// } +// +// const auto &entry = it->second; +// if (!entry.xref) { +// return false; +// } +// +// return entry.xref->target_ea == entry.ea; +//} - auto mask = llvm::ConstantInt::get(word_type, cfg_xref->mask); - llvm::IRBuilder<> ir(block); - return ir.CreateAnd(addr, mask); -} - -// Returns `true` if a given cross-reference is self-referential. That is, -// we'll have something like `jmp cs:EnterCriticalSection`, which references -// `EnterCriticalSection` in the `.idata` section of a PE file. But this -// location is our only "place" for the external `EnterCriticalSection`, so -// we point it back at itself. -static bool IsSelfReferential(const NativeXref *cfg_xref) { - if (!cfg_xref->target_segment) { - return false; - } - - auto it = cfg_xref->target_segment->entries.find(cfg_xref->target_ea); - if (it == cfg_xref->target_segment->entries.end()) { - return false; - } - - const auto &entry = it->second; - if (!entry.xref) { - return false; - } - - return entry.xref->target_ea == entry.ea; -} - -llvm::Value *InstructionLifter::GetAddress(const NativeXref *cfg_xref) { +llvm::Value *InstructionLifter::GetAddress( + const NativeInstructionXref *cfg_xref) { if (!cfg_xref) { return nullptr; } - llvm::IRBuilder<> ir(block); - if (auto cfg_func = cfg_xref->func) { - llvm::Function *func = nullptr; - llvm::Value *func_val = nullptr; - - // If this is a lifted function, then create a wrapper around it. The - // idea is that this reference to a lifted function can be leaked to - // native code as a callback, and so native code calling it must be able - // to swap into the lifted context. - if (cfg_func->is_external) { - if (IsSelfReferential(cfg_xref)) { - LOG(WARNING) - << "Reference from " << std::hex << cfg_xref->ea - << " to self-referential function reference " - << cfg_xref->target_name << " at " << cfg_xref->target_ea - << " being lifted as address into " - << cfg_xref->target_segment->name << std::dec; - - return LiftEA(cfg_xref->target_segment, cfg_xref->target_ea); - - } else { - func = gModule->getFunction(cfg_func->name); - } - } else { - func = GetNativeToLiftedCallback(cfg_func); - } - - CHECK(func != nullptr) - << "Can't resolve reference to function " - << cfg_func->name << " from " << std::hex << inst_ptr->pc << std::dec; - - func_val = func; - - // Functions attributed with weak linkage may be defined, but aren't - // necessarily. What you end up getting is code that checks if the function - // pointer is non-null, and if so, calls the function. - // - // mov rax, cs:__gmon_start___ptr - // test rax, rax - // - // In the CFG, we get `__gmon_start__` instead of `__gmon_start___ptr`, - // but we don't want to actually read the machine code bytes of - // `__gmon_start__`, which is likely to be an ELF thunk. So we throw in - // an extra layer of indirection here. - // -#if 0 - // TODO(akshayk): Discuss a better solution to handle the weak external functions - // It causes the garbage address for _ZNSt12out_of_rangeD1Ev - - // TODO(pag): This is an awful hack for now that won't generalize. - if (func->hasExternalWeakLinkage()) { - LOG(ERROR) - << "Adding pseudo-load of weak function " << cfg_func->name - << " at " << std::hex << inst_ptr->pc << std::dec; - - auto temp_loc = ir.CreateAlloca(func->getType()); - ir.CreateStore(func, temp_loc); - func_val = temp_loc; - } -#endif - - return ir.CreatePtrToInt(func_val, word_type); - - } else if (auto cfg_var = cfg_xref->var) { - if (cfg_var->address) { - return cfg_var->address; - } - - LOG(ERROR) - << "Variable " << cfg_var->name << " at " << std::hex << cfg_var->ea - << std::dec << " was not lifted."; - // Fall through. + if (cfg_xref->mask) { + return LiftXrefInCode(cfg_xref->target_ea & cfg_xref->mask); + } else { + return LiftXrefInCode(cfg_xref->target_ea); } - - CHECK(cfg_xref->target_segment != nullptr) - << "A non-function, non-variable cross-reference from " - << std::hex << inst_ptr->pc << " to " << cfg_xref->target_ea << std::dec - << " must be in a known segment."; - - return LiftEA(cfg_xref->target_segment, cfg_xref->target_ea); } llvm::Value *InstructionLifter::LiftImmediateOperand( remill::Instruction &inst, llvm::BasicBlock *block, llvm::Argument *arg, remill::Operand &op) { auto arg_type = arg->getType(); - if (imm_ref) { + if (imm_ref && !imm_ref_used) { imm_ref_used = true; llvm::DataLayout data_layout(gModule.get()); auto arg_size = data_layout.getTypeSizeInBits(arg_type); - CHECK(arg_size <= gArch->address_size) + CHECK(arg_size <= arch->address_size) << "Immediate operand size " << op.size << " of " << op.Serialize() << " in instuction " << std::hex << inst.pc << " is wider than the architecture pointer size (" - << std::dec << gArch->address_size << ")."; + << std::dec << arch->address_size << ")."; - if (arg_type != imm_ref->getType() && arg_size < gArch->address_size) { + if (arg_type != imm_ref->getType() && arg_size < arch->address_size) { llvm::IRBuilder<> ir(block); imm_ref = ir.CreateTrunc(imm_ref, arg_type); } return imm_ref; + + } else if (op.size == arch->address_size && + 4096 <= op.imm.val) { + auto seg = ctx.cfg_module->TryGetSegment(op.imm.val); + LOG_IF(WARNING, seg != nullptr) + << "Immediate operand '" << op.Serialize() + << "' of instruction " << inst.Serialize() + << " is a missed cross-reference candidate"; } return this->remill::InstructionLifter::LiftImmediateOperand( @@ -331,31 +189,6 @@ llvm::Value *InstructionLifter::LiftAddressOperand( inst, block, arg, op); } - // Check if the instruction is referring to stack variable - if (ctx.cfg_inst->stack_var) { - llvm::IRBuilder<> ir(block); - auto base = ir.CreatePtrToInt(ctx.cfg_inst->stack_var->llvm_var, word_type); - auto map_it = ctx.cfg_inst->stack_var->refs.find(ctx.cfg_inst->ea); - if (map_it != ctx.cfg_inst->stack_var->refs.end()) { - auto var_offset = llvm::ConstantInt::get( - word_type, static_cast(map_it->second), true); - base = ir.CreateAdd(base, var_offset); - LOG(INFO) - << "Lifting stack variable access at : " << std::hex << map_it->first - << " var_offset " << map_it->second << std::dec - << " variable name " << ctx.cfg_inst->stack_var->name; - - if (!mem.index_reg.name.empty()) { - auto zero = llvm::ConstantInt::get(word_type, 0, false); - auto index = LoadAddressRegVal(block, mem.index_reg, zero); - auto scale = llvm::ConstantInt::get( - word_type, static_cast(mem.scale), true); - return ir.CreateAdd(base, ir.CreateMul(index, scale)); - } - } - return base; - } - if ((mem.base_reg.name.empty() && mem.index_reg.name.empty()) || (mem.base_reg.name == "PC" && mem.index_reg.name.empty())) { @@ -368,6 +201,18 @@ llvm::Value *InstructionLifter::LiftAddressOperand( return disp_ref; } + } else if ((mem.base_reg.name.empty() && mem.index_reg.name.empty()) || + (mem.base_reg.name == "NEXT_PC" && mem.index_reg.name.empty())) { + + if (mem_ref) { + mem_ref_used = true; + return mem_ref; + + } else if (disp_ref) { + disp_ref_used = true; + return disp_ref; + } + } else { // It's a reference located in the displacement. We'll clear out the @@ -381,8 +226,8 @@ llvm::Value *InstructionLifter::LiftAddressOperand( llvm::IRBuilder<> ir(block); return ir.CreateAdd(dynamic_addr, disp_ref); - } else if (mem_ref && static_cast(op.addr.displacement) == - ctx.cfg_inst->mem->target_ea) { + } else if (mem_ref && (static_cast(op.addr.displacement) == + ctx.cfg_inst->mem->target_ea)) { LOG(ERROR) << "IDA probably incorrectly decoded memory operand " << op.Serialize() << " of instruction " << std::hex << inst.pc @@ -401,36 +246,4 @@ llvm::Value *InstructionLifter::LiftAddressOperand( inst, block, arg, op); } -// Lift the register operand to a value. -llvm::Value *InstructionLifter::LiftRegisterOperand( - remill::Instruction &inst, llvm::BasicBlock *block, - llvm::Argument *arg, remill::Operand &op) { - - auto ® = op.reg; - - // Check if the instruction is referring to the base pointer which - // might be accessing stack variable indirectly - if (ctx.cfg_inst->stack_var) { - if ((IsFramePointerReg(reg) || IsStackPointerReg(reg)) && - (op.action == remill::Operand::kActionRead)) { - llvm::IRBuilder<> ir(block); - auto variable = ir.CreatePtrToInt( - ctx.cfg_inst->stack_var->llvm_var, word_type); - auto map_it = ctx.cfg_inst->stack_var->refs.find(ctx.cfg_inst->ea); - if (map_it != ctx.cfg_inst->stack_var->refs.end()) { - auto var_offset = llvm::ConstantInt::get( - word_type, static_cast(map_it->second), true); - variable = ir.CreateAdd(variable, var_offset); - } - LOG(INFO) - << "Lifting stack variable reference at : " << std::hex - << ctx.cfg_inst->ea << std::dec; - return variable; - } - } - - return this->remill::InstructionLifter::LiftRegisterOperand( - inst, block, arg, op); -} - } // namespace mcsema diff --git a/mcsema/BC/Instruction.h b/mcsema/BC/Instruction.h index 45dea9e65..83c533fdd 100644 --- a/mcsema/BC/Instruction.h +++ b/mcsema/BC/Instruction.h @@ -1,21 +1,21 @@ /* - * Copyright (c) 2017 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ -#ifndef MCSEMA_BC_INSTRUCTION_H_ -#define MCSEMA_BC_INSTRUCTION_H_ +#pragma once #include @@ -36,7 +36,7 @@ class IntrinsicTable; namespace mcsema { -struct NativeXref; +struct NativeInstructionXref; struct TranslationContext; class InstructionLifter : public remill::InstructionLifter { @@ -48,7 +48,8 @@ class InstructionLifter : public remill::InstructionLifter { // Lift a single instruction into a basic block. remill::LiftStatus LiftIntoBlock(remill::Instruction &inst, - llvm::BasicBlock *block) override; + llvm::BasicBlock *block, + bool is_delayed) override; protected: @@ -62,15 +63,9 @@ class InstructionLifter : public remill::InstructionLifter { remill::Instruction &inst, llvm::BasicBlock *block, llvm::Argument *arg, remill::Operand &mem) override; - // Lift a register operand to a value. - llvm::Value *LiftRegisterOperand( - remill::Instruction &inst, llvm::BasicBlock *block, - llvm::Argument *arg, remill::Operand ®) override; - private: - llvm::Value *GetAddress(const NativeXref *cfg_xref); - llvm::Value *GetMaskedAddress(const NativeXref *cfg_xref); + llvm::Value *GetAddress(const NativeInstructionXref *cfg_xref); TranslationContext &ctx; @@ -87,5 +82,3 @@ class InstructionLifter : public remill::InstructionLifter { }; } // namespace mcsema - -#endif // MCSEMA_BC_INSTRUCTION_H_ diff --git a/mcsema/BC/Legacy.cpp b/mcsema/BC/Legacy.cpp index 9f6b66764..f4179b9cd 100644 --- a/mcsema/BC/Legacy.cpp +++ b/mcsema/BC/Legacy.cpp @@ -1,19 +1,22 @@ /* - * Copyright (c) 2017 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ +#include "Legacy.h" + #include #include @@ -45,24 +48,6 @@ namespace mcsema { namespace legacy { namespace { -// Remove calls to error-related intrinsics. -static void ImplementErrorIntrinsic(const char *name) { - auto func = gModule->getFunction(name); - if (!func) { - return; - } - - auto void_type = llvm::Type::getVoidTy(*gContext); - auto abort_func = gModule->getOrInsertFunction( - "abort", llvm::FunctionType::get(void_type, false)); - - func->setLinkage(llvm::GlobalValue::InternalLinkage); - - llvm::IRBuilder<> ir(llvm::BasicBlock::Create(*gContext, "", func)); - ir.CreateCall(abort_func); - ir.CreateRet(remill::NthArgument(func, remill::kMemoryPointerArgNum)); -} - // Create the node for a `mcsema_real_eip` annotation. static llvm::MDNode *CreateInstAnnotation(llvm::Function *F, uint64_t addr) { auto addr_val = llvm::ConstantInt::get(gWordType, addr); @@ -146,10 +131,5 @@ void PropagateInstAnnotations(void) { } } -void DowngradeModule(void) { - ImplementErrorIntrinsic("__remill_error"); - ImplementErrorIntrinsic("__remill_missing_block"); -} - } // namespace legacy } // namespace mcsema diff --git a/mcsema/BC/Legacy.h b/mcsema/BC/Legacy.h index 3f07b4c2e..4af0ff5e5 100644 --- a/mcsema/BC/Legacy.h +++ b/mcsema/BC/Legacy.h @@ -1,21 +1,21 @@ /* - * Copyright (c) 2017 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ -#ifndef MCSEMA_BC_LEGACY_H_ -#define MCSEMA_BC_LEGACY_H_ +#pragma once #include @@ -25,8 +25,6 @@ class Function; namespace mcsema { namespace legacy { -void DowngradeModule(void); - // Create a `mcsema_real_eip` annotation, and annotate every unannotated // instruction with this new annotation. void AnnotateInsts(llvm::Function *func, uint64_t pc); @@ -37,4 +35,3 @@ void PropagateInstAnnotations(void); } // namespace legacy } // namespace mcsema -#endif // MCSEMA_BC_LEGACY_H_ diff --git a/mcsema/BC/Lift.cpp b/mcsema/BC/Lift.cpp index f18231977..73ff26352 100644 --- a/mcsema/BC/Lift.cpp +++ b/mcsema/BC/Lift.cpp @@ -1,19 +1,22 @@ /* - * Copyright (c) 2017 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ +#include "Lift.h" + #include #include @@ -55,7 +58,6 @@ #include "mcsema/BC/External.h" #include "mcsema/BC/Function.h" #include "mcsema/BC/Legacy.h" -#include "mcsema/BC/Lift.h" #include "mcsema/BC/Optimize.h" #include "mcsema/BC/Segment.h" #include "mcsema/BC/Util.h" @@ -70,22 +72,32 @@ namespace { // Add entrypoint functions for any exported functions. static void ExportFunctions(const NativeModule *cfg_module) { - for (auto ea : cfg_module->exported_funcs) { - auto cfg_func = cfg_module->ea_to_func.at(ea)->Get(); - CHECK(gModule->getFunction(cfg_func->lifted_name) != nullptr) - << "Cannot find lifted version of exported function " - << cfg_func->lifted_name; + for (auto [ea, cfg_func] : cfg_module->ea_to_func) { + (void) ea; - LOG(INFO) - << "Exporting function " << cfg_func->name; + if (cfg_func->function) { + cfg_func->function = gModule->getFunction(cfg_func->name); + } - auto ep = GetNativeToLiftedEntryPoint(cfg_func); - ep->setLinkage(llvm::GlobalValue::ExternalLinkage); - ep->setVisibility(llvm::GlobalValue::DefaultVisibility); - - remill::TieFunctions(ep, gModule->getFunction(cfg_func->lifted_name)); - remill::Annotate(ep); + if (auto ep = cfg_func->function; ep) { + if (cfg_func->is_exported) { + LOG(INFO) + << "Exporting function " << cfg_func->name; + // remill::TieFunctions(ep, gModule->getFunction(cfg_func->lifted_name)); + remill::Annotate(ep); + ep->setLinkage(llvm::GlobalValue::ExternalLinkage); + ep->setVisibility(llvm::GlobalValue::DefaultVisibility); + } else { + ep->setVisibility(llvm::GlobalValue::HiddenVisibility); + ep->setLinkage(llvm::GlobalValue::PrivateLinkage); + if (!ep->hasNUsesOrMore(1)) { + LOG(INFO) + << "Removing function " << cfg_func->name; + ep->eraseFromParent(); + } + } + } } } @@ -134,7 +146,8 @@ static void DefineDebugGetRegState(void) { auto state_ptr_type = reg_state->getType(); auto reg_func_type = llvm::FunctionType::get(state_ptr_type, false); - // ExternalWeakLinkage causes crash with --explicit_args. The function is not available in the library + // ExternalWeakLinkage causes crash with --explicit_args. The function is not + // available in the library get_reg_state = llvm::Function::Create( reg_func_type, llvm::GlobalValue::ExternalLinkage, "__mcsema_debug_get_reg_state", gModule.get()); @@ -146,43 +159,81 @@ static void DefineDebugGetRegState(void) { get_reg_state->addFnAttr(llvm::Attribute::OptimizeNone); } -// Define some of the remill error intrinsics. -static void DefineErrorIntrinsics(llvm::FunctionType *lifted_func_type) { - const char *func_names[] = {"__remill_error", "__remill_missing_block"}; - auto trap = llvm::Intrinsic::getDeclaration(gModule.get(), llvm::Intrinsic::trap); - for (auto func_name : func_names) { - auto func = gModule->getFunction(func_name); - if (!func) { - continue; - } - if (func->isDeclaration()) { - llvm::IRBuilder<> ir(llvm::BasicBlock::Create(*gContext, "", func)); - ir.CreateCall(trap); - ir.CreateUnreachable(); - } +// Remove calls to error-related intrinsics. +static void ImplementErrorIntrinsic(const char *name) { + auto func = gModule->getFunction(name); + if (!func || !func->isDeclaration()) { + return; } + + auto void_type = llvm::Type::getVoidTy(*gContext); + auto abort_func = gModule->getFunction("abort"); + if (!abort_func) { + abort_func = llvm::Function::Create( + llvm::FunctionType::get(void_type, false), + llvm::GlobalValue::ExternalLinkage, + "abort", + gModule.get()); + + abort_func->addFnAttr(llvm::Attribute::NoReturn); + + // Might be an externally-defined function :-/ + } else if (abort_func->getFunctionType()->getNumParams() || + !abort_func->getFunctionType()->getReturnType()->isVoidTy()) { + abort_func = llvm::Intrinsic::getDeclaration( + gModule.get(), llvm::Intrinsic::trap); + } + + func->setLinkage(llvm::GlobalValue::InternalLinkage); + func->removeFnAttr(llvm::Attribute::NoInline); + func->removeFnAttr(llvm::Attribute::OptimizeNone); + func->addFnAttr(llvm::Attribute::NoReturn); + func->addFnAttr(llvm::Attribute::InlineHint); + func->addFnAttr(llvm::Attribute::AlwaysInline); + + llvm::IRBuilder<> ir(llvm::BasicBlock::Create(*gContext, "", func)); + + ir.CreateCall(abort_func); + ir.CreateUnreachable(); +} + +// Define some of the remill error intrinsics. +static void DefineErrorIntrinsics(void) { + ImplementErrorIntrinsic("__remill_error"); + ImplementErrorIntrinsic("__remill_missing_block"); } } // namespace -bool LiftCodeIntoModule(const NativeModule *cfg_module) { +TranslationContext::TranslationContext(void) {} - DeclareExternals(cfg_module); +TranslationContext::~TranslationContext(void) {} + +bool LiftCodeIntoModule(const NativeModule *cfg_module) { DeclareLiftedFunctions(cfg_module); - DeclareDataSegments(cfg_module); + // Lift the blocks of instructions into the declared functions. + if (!DefineLiftedFunctions(cfg_module)) { + return false; + } + + DefineErrorIntrinsics(); + + // Optimize the lifted bitcode. + OptimizeModule(cfg_module); // Segments are only filled in after the lifted function declarations, // external vars, and segments are declared so that cross-references to // lifted things can be resolved. DefineDataSegments(cfg_module); - auto lifted_func_type = remill::LiftedFunctionType(gModule.get()); + // Generate code to call pre-`main` function static object constructors, and + // post-`main` functions destructors. + CallInitFiniCode(cfg_module); - // Lift the blocks of instructions into the declared functions. - if (!DefineLiftedFunctions(cfg_module)) { - return false; - } + // Remove leftover Remill intrinsics, and lower memory access intrincis into + // `load` and `store` instructions. + CleanUpModule(cfg_module); // Add entrypoint functions for any exported functions. ExportFunctions(cfg_module); @@ -190,20 +241,9 @@ bool LiftCodeIntoModule(const NativeModule *cfg_module) { // Export any variables that should be externally visible. ExportVariables(cfg_module); - // Generate code to call pre-`main` function static object constructors, and - // post-`main` functions destructors. - CallInitFiniCode(cfg_module); - - if (FLAGS_legacy_mode) { - legacy::DowngradeModule(); - } - - OptimizeModule(); - if (FLAGS_explicit_args) { DefineGCCStackGuard(); DefineDebugGetRegState(); - DefineErrorIntrinsics(lifted_func_type); } if (!FLAGS_pc_annotation.empty()) { diff --git a/mcsema/BC/Lift.h b/mcsema/BC/Lift.h index e8b087c14..48381f894 100644 --- a/mcsema/BC/Lift.h +++ b/mcsema/BC/Lift.h @@ -1,31 +1,38 @@ /* - * Copyright (c) 2017 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ -#ifndef MCSEMA_BC_LIFT_H_ -#define MCSEMA_BC_LIFT_H_ +#pragma once +#include +#include +#include #include +#include "remill/Arch/Instruction.h" + namespace remill { class InstructionLifter; } // namespace remill namespace llvm { +class AllocaInst; class BasicBlock; class Function; +class Value; } // namespace llvm namespace mcsema { @@ -34,20 +41,32 @@ struct NativeModule; struct NativeFunction; struct NativeBlock; struct NativeInstruction; +struct NativePreservedRegisters; struct TranslationContext { - remill::InstructionLifter *lifter; - const NativeModule *cfg_module; - const NativeFunction *cfg_func; - const NativeBlock *cfg_block; - const NativeInstruction *cfg_inst; - llvm::Function *lifted_func; + TranslationContext(void); + ~TranslationContext(void); + + remill::InstructionLifter *lifter = nullptr; + const NativeModule *cfg_module = nullptr; + const NativeFunction *cfg_func = nullptr; + const NativeBlock *cfg_block = nullptr; + const NativeInstruction *cfg_inst = nullptr; + llvm::Function *lifted_func = nullptr; std::unordered_map ea_to_block; std::unordered_map lp_to_block; + std::vector> preserved_regs; + std::unordered_map + func_preserved_regs; + remill::Instruction inst; + remill::Instruction delayed_inst; + std::vector> work_list; + + llvm::BasicBlock *entry_block{nullptr}; + llvm::Value *stack_ptr_var{nullptr}; + llvm::Value *frame_ptr_var{nullptr}; }; bool LiftCodeIntoModule(const NativeModule *cfg_module); } // namespace mcsema - -#endif // MCSEMA_BC_LIFT_H_ diff --git a/mcsema/BC/Optimize.cpp b/mcsema/BC/Optimize.cpp index e70c8562a..e94f997aa 100644 --- a/mcsema/BC/Optimize.cpp +++ b/mcsema/BC/Optimize.cpp @@ -1,19 +1,22 @@ /* - * Copyright (c) 2017 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ +#include "mcsema/BC/Optimize.h" + #include #include @@ -45,22 +48,41 @@ #include #include -#include "remill/Arch/Arch.h" -#include "remill/BC/ABI.h" -#include "remill/BC/Compat/TargetLibraryInfo.h" -#include "remill/BC/DeadStoreEliminator.h" -#include "remill/BC/Util.h" +#include + +#include +#include +#include +#include +#include +#include +#include #include "mcsema/Arch/Arch.h" #include "mcsema/BC/Optimize.h" #include "mcsema/BC/Util.h" - -DEFINE_bool(disable_optimizer, false, - "Disable interprocedural optimizations?"); +#include "mcsema/CFG/CFG.h" DEFINE_bool(keep_memops, false, "Should the memory intrinsics be replaced or not?"); +DEFINE_bool(check_for_lowmem_xrefs, false, + "Check every constant, even those less than 4096, to see " + "if they might be cross-reference targets. This might be " + "reasonable to enable for PIC code, .o files, etc."); + +DEFINE_bool(volatile_memops, false, "Mark all lowered loads/stores as volatile"); + +DEFINE_bool(local_state_pointer, true, + "Use the state pointer passed by argument to all lifted functions." + "Set local_state_pointer to false to disable it."); + +DEFINE_bool(restore_all_on_unreachable, false, + "Ensure that functions containing unreachable code end up " + "restoring all saved registers on returning paths."); + +DECLARE_bool(disable_aliases); + namespace mcsema { namespace { @@ -81,6 +103,12 @@ static void ReplaceUndefIntrinsic(llvm::Function *function) { static void RemoveFunction(llvm::Function *func) { if (!func->hasNUsesOrMore(1)) { func->eraseFromParent(); + } else { + auto ret_type = func->getReturnType(); + if (!ret_type->isVoidTy()) { + func->replaceAllUsesWith(llvm::UndefValue::get(func->getType())); + func->eraseFromParent(); + } } } @@ -109,41 +137,6 @@ static void RemoveUndefFuncCalls(void) { } } -static void RunO3(void) { - llvm::legacy::FunctionPassManager func_manager(gModule.get()); - llvm::legacy::PassManager module_manager; - - auto TLI = new llvm::TargetLibraryInfoImpl( - llvm::Triple(gModule->getTargetTriple())); - - TLI->disableAllFunctions(); // `-fno-builtin`. - - llvm::PassManagerBuilder builder; - builder.OptLevel = 3; - builder.SizeLevel = 2; - builder.Inliner = llvm::createFunctionInliningPass( - std::numeric_limits::max()); - builder.LibraryInfo = TLI; // Deleted by `llvm::~PassManagerBuilder`. - builder.DisableUnrollLoops = false; // Unroll loops! - IF_LLVM_LT_900(builder.DisableUnitAtATime = false;) - builder.SLPVectorize = false; - builder.LoopVectorize = false; - IF_LLVM_GTE_360(builder.VerifyInput = false;) - IF_LLVM_GTE_360(builder.VerifyOutput = false;) - - // TODO(pag): Not sure when this became available. - IF_LLVM_GTE_800(builder.MergeFunctions = false;) - - builder.populateFunctionPassManager(func_manager); - builder.populateModulePassManager(module_manager); - func_manager.doInitialization(); - for (auto &func : *gModule) { - func_manager.run(func); - } - func_manager.doFinalization(); - module_manager.run(*gModule); -} - // Get a list of all ISELs. static std::vector FindISELs(void) { std::vector isels; @@ -167,50 +160,6 @@ static void PrivatizeISELs(std::vector &isels) { } } -// Remove some of the remill intrinsics. -static void RemoveIntrinsics(void) { - if (auto llvm_used = gModule->getGlobalVariable("llvm.used")) { - llvm_used->eraseFromParent(); - } - - // This function makes removing intrinsics tricky, so if it's there, then - // we'll try to get the optimizer to inline it on our behalf, which should - // drop some references :-D - if (auto remill_used = gModule->getFunction("__remill_mark_as_used")) { - std::vector uses; - for (auto use : remill_used->users()) { - if (auto call = llvm::dyn_cast(use)) { - uses.push_back(call); - } - } - - for (auto call : uses) { - call->eraseFromParent(); - } - - if (remill_used->hasNUsesOrMore(1)) { - if (remill_used->isDeclaration()) { - remill_used->setLinkage(llvm::GlobalValue::InternalLinkage); - remill_used->removeFnAttr(llvm::Attribute::NoInline); - remill_used->addFnAttr(llvm::Attribute::InlineHint); - remill_used->addFnAttr(llvm::Attribute::AlwaysInline); - auto block = llvm::BasicBlock::Create(*gContext, "", remill_used); - (void) llvm::ReturnInst::Create(*gContext, block); - } - } - - RemoveFunction(remill_used); - } - -// if (auto intrinsics = gModule->getFunction("__remill_intrinsics")) { -// intrinsics->eraseFromParent(); -// } - - RemoveFunction("__remill_basic_block"); - RemoveFunction("__remill_defer_inlining"); - RemoveFunction("__remill_intrinsics"); -} - static void ReplaceBarrier(const char *name) { auto func = gModule->getFunction(name); if (!func) { @@ -228,8 +177,449 @@ static void ReplaceBarrier(const char *name) { } } +static llvm::Value *FindPointer( + llvm::IRBuilder<> &ir, llvm::Value *addr, llvm::Type *elem_type, + unsigned addr_space) { + + if (auto as_ptr_to_int = llvm::dyn_cast(addr)) { + if (!addr_space) { + addr_space = as_ptr_to_int->getPointerAddressSpace(); + } + auto curr = as_ptr_to_int->getPointerOperand(); + auto possible = FindPointer(ir, curr, elem_type, addr_space); + return possible ? possible : curr; + + } else { + return nullptr; + } +} + +unsigned GetPointerAddressSpace(llvm::Value *val, unsigned addr_space) { + if (addr_space || !val) { + return addr_space; + } + + if (auto source_type = llvm::dyn_cast(val->getType())) { + addr_space = source_type->getPointerAddressSpace(); + if (addr_space) { + return addr_space; + } + } + + if (auto as_bc = llvm::dyn_cast(val)) { + return GetPointerAddressSpace(as_bc->getOperand(0), addr_space); + + } else if (auto as_pti = llvm::dyn_cast(val)) { + return GetPointerAddressSpace(as_pti->getOperand(0), addr_space); + + } else if (auto as_itp = llvm::dyn_cast(val)) { + return GetPointerAddressSpace(as_itp->getOperand(0), addr_space); + + } else if (auto as_addr = llvm::dyn_cast(val)) { + return GetPointerAddressSpace(as_addr->getOperand(0), addr_space); + + } else { + return addr_space; + } +} + +// Try to get an Value representing the address of `ea` as an entity, or return +// `nullptr`. +static llvm::Constant *GetAddress(const NativeModule *cfg_module, uint64_t ea) { + if (auto cfg_var = cfg_module->TryGetVariable(ea); cfg_var) { + return cfg_var->Address(); + + } else if (auto cfg_func = cfg_module->TryGetFunction(ea); cfg_func) { + return cfg_func->Address(); + + } else if (auto cfg_seg = cfg_module->TryGetSegment(ea); cfg_seg) { + return LiftXrefInData(cfg_seg, ea); + + // Look to see if `ea - 1` is the last byte of an existing segment or + // variable, and if so, create a GEP that gets the address immediately + // following the segment. + // + // NOTE(pag): In practice, we don't need to worry about segment padding + // here, as we expect that this pointer is used as an upper bound + // for some computation, and the referenced address is not + // actually mapped, so it's OK that it points into "the next + // element's" padding. + } else { + if (auto cfg_var = cfg_module->TryGetVariable(ea - 1); cfg_var) { + auto i32_type = llvm::Type::getInt32Ty(*gContext); + auto var = cfg_var->Pointer(); + auto var_type = var->getType()->getPointerElementType(); + auto ptr = llvm::ConstantExpr::getGetElementPtr( + var_type, var, llvm::ConstantInt::get(i32_type, 1, false)); + return llvm::ConstantExpr::getPtrToInt(ptr, gWordType); + + } else if (auto cfg_seg = cfg_module->TryGetSegment(ea - 1); cfg_seg) { + auto i32_type = llvm::Type::getInt32Ty(*gContext); + auto seg_var = cfg_seg->Pointer(); + auto seg_type = seg_var->getType()->getPointerElementType(); + const auto ptr = llvm::ConstantExpr::getGetElementPtr( + seg_type, seg_var, llvm::ConstantInt::get(i32_type, 1, false)); + return llvm::ConstantExpr::getPtrToInt(ptr, gWordType); + } + } + + return nullptr; +} + +static llvm::Value *GetPointer( + const NativeModule *cfg_module, llvm::IRBuilder<> &ir, + llvm::Value *addr, llvm::Type *elem_type, unsigned addr_space); + +static llvm::Value *GetIndexedPointer( + const NativeModule *cfg_module, llvm::IRBuilder<> &ir, + llvm::Value *lhs, llvm::Value *rhs, llvm::Type *dest_type, + unsigned addr_space) { + + auto i32_ty = llvm::Type::getInt32Ty(*gContext); + auto i8_ty = llvm::Type::getInt8Ty(*gContext); + auto i8_ptr_ty = llvm::PointerType::get(i8_ty, addr_space); + + if (auto rhs_const = llvm::dyn_cast(rhs)) { + const auto rhs_index = static_cast(rhs_const->getSExtValue()); + + const auto &dl = gModule->getDataLayout(); + + const auto [new_lhs, index] = + remill::StripAndAccumulateConstantOffsets(dl, lhs); + + // It's possible that we will index into, but beyond, one global variable, + // intending to get to another global. + // + // NOTE(pag): We use `getTypeStoreSize` of `global_type` so that we deal + // with the defined bytes, and not any implied alignment of + // globals lifted due to things like section alignment. + if (auto lhs_global = llvm::dyn_cast(new_lhs)) { + + if (cfg_module) { + if (auto cfg_seg = cfg_module->TryGetSegment(lhs_global->getName())) { + const auto real_ea = static_cast( + static_cast(cfg_seg->ea) + index); + + if (auto addr = GetAddress(cfg_module, real_ea)) { + LOG_IF(WARNING, cfg_module->TryGetSegment(real_ea) != cfg_seg) + << "Fixing cross-reference to " << std::hex + << real_ea << std::dec << " that was misplaced into segment " + << cfg_seg->name; + + return GetPointer( + nullptr, ir, addr, dest_type->getPointerElementType(), + addr_space); + + } else { + LOG(ERROR) + << "Out-of-bounds reference to " << std::hex << real_ea + << std::dec << " tied to segment " << cfg_seg->name; + } + } + } + + if (!index) { + return ir.CreateBitCast(lhs_global, dest_type); + } + + // It's a global variable not associated with a native segment, try to + // index into it in a natural-ish way. We only apply this when the index + // is positive. + if (0 < index) { + auto offset = static_cast(index); + return remill::BuildPointerToOffset(ir, lhs_global, offset, dest_type); + } + } + + auto lhs_elem_type = lhs->getType()->getPointerElementType(); + auto dest_elem_type = dest_type->getPointerElementType(); + + const auto lhs_el_size = dl.getTypeAllocSize(lhs_elem_type); + const auto dest_el_size = dl.getTypeAllocSize(dest_elem_type); + + llvm::Value *ptr = nullptr; + + // If either the source or destination element size is divisible by the + // other then we might get lucky and be able to compute a pointer to the + // destination with a single GEP. + if (!(lhs_el_size % dest_el_size) || !(dest_el_size % lhs_el_size)) { + + if (0 > rhs_index) { + const auto pos_rhs_index = static_cast(-rhs_index); + if (!(pos_rhs_index % lhs_el_size)) { + const auto scaled_index = static_cast( + rhs_index / static_cast(lhs_el_size)); + llvm::Value *indices[1] = { + llvm::ConstantInt::get(i32_ty, scaled_index, true)}; + ptr = ir.CreateGEP(lhs_elem_type, lhs, indices); + } + } else { + const auto pos_rhs_index = static_cast(rhs_index); + if (!(pos_rhs_index % lhs_el_size)) { + const auto scaled_index = static_cast( + rhs_index / static_cast(lhs_el_size)); + llvm::Value *indices[1] = { + llvm::ConstantInt::get(i32_ty, scaled_index, false)}; + ptr = ir.CreateGEP(lhs_elem_type, lhs, indices); + } + } + } + + // We got a GEP for the dest, now make sure it's the right type. + if (ptr) { + if (lhs->getType() == dest_type) { + return ptr; + } else { + return ir.CreateBitCast(ptr, dest_type); + } + } + } + + auto base = ir.CreateBitCast(lhs, i8_ptr_ty); + llvm::Value *indices[1] = {ir.CreateTrunc(rhs, i32_ty)}; + auto gep = ir.CreateGEP(i8_ty, base, indices); + return ir.CreateBitCast(gep, dest_type); +} + +// Try to get a pointer for the address operand of a remill memory access +// intrinsic. +static llvm::Value *GetPointerFromInt( + llvm::IRBuilder<> &ir, llvm::Value *addr, llvm::Type *elem_type, + unsigned addr_space) { + auto dest_type = llvm::PointerType::get(elem_type, addr_space); + + if (auto phi = llvm::dyn_cast(addr)) { + const auto old_ipoint = &*(ir.GetInsertPoint()); + ir.SetInsertPoint(phi); + + const auto max = phi->getNumIncomingValues(); + const auto new_phi = ir.CreatePHI(dest_type, max); + + for (auto i = 0u; i < max; ++i) { + auto val = phi->getIncomingValue(i); + auto block = phi->getIncomingBlock(i); + llvm::IRBuilder<> sub_ir(block->getTerminator()); + auto ptr = FindPointer(sub_ir, val, elem_type, addr_space); + if (ptr) { + if (ptr->getType() != dest_type) { + ptr = sub_ir.CreateBitCast(ptr, dest_type); + } + } else { + ptr = sub_ir.CreateIntToPtr(val, dest_type); + } + new_phi->addIncoming(ptr, block); + } + + ir.SetInsertPoint(old_ipoint); + + return new_phi; + + } else { + return ir.CreateIntToPtr(addr, dest_type); + } +} + +// Try to get a pointer for the address operand of a remill memory access +// intrinsic. +llvm::Value *GetPointer( + const NativeModule *cfg_module, llvm::IRBuilder<> &ir, + llvm::Value *addr, llvm::Type *elem_type, unsigned addr_space) { + + addr_space = GetPointerAddressSpace(addr, addr_space); + const auto addr_type = addr->getType(); + auto dest_type = llvm::PointerType::get(elem_type, addr_space); + + // Handle this case first so that we don't return early on the `ptrtoint` that + // may directly reach into the address parameter of the memory access + // intrinsics. + if (auto as_itp = llvm::dyn_cast(addr); as_itp) { + llvm::IRBuilder<> sub_ir(as_itp); + return GetPointer( + cfg_module, sub_ir, as_itp->getOperand(0), elem_type, addr_space); + + // It's a `ptrtoint`, but of the wrong type; lets go back and try to use + // that pointer. + } else if (auto as_pti = llvm::dyn_cast(addr); as_pti) { + return GetPointer( + cfg_module, ir, as_pti->getPointerOperand(), elem_type, addr_space); + + // We've found a pointer of the desired type; return :-D + } else if (addr_type == dest_type) { + return addr; + + // A missed cross-reference! + } else if (auto ci = llvm::dyn_cast(addr); ci) { + const auto ea = ci->getZExtValue(); + if (auto addr = GetAddress(cfg_module, ea); addr) { + return GetPointer(cfg_module, ir, addr, elem_type, addr_space); + + } else { + LOG(ERROR) + << "Missed cross-reference target " << std::hex + << ea << " to pointer"; + return llvm::ConstantExpr::getIntToPtr(ci, dest_type); + } + + // It's a constant expression, the one we're interested in is `inttoptr` + // as we've already handled `ptrtoint` above. + } else if (auto ce = llvm::dyn_cast(addr); ce) { + if (ce->getOpcode() == llvm::Instruction::IntToPtr) { + return GetPointer( + cfg_module, ir, ce->getOperand(0), elem_type, addr_space); + + } else if (addr_type->isIntegerTy()) { + return llvm::ConstantExpr::getIntToPtr(ce, dest_type); + + } else { + CHECK(addr_type->isPointerTy()); + return llvm::ConstantExpr::getBitCast(ce, dest_type); + } + + } else if (llvm::isa(addr)) { + return ir.CreateBitCast(addr, dest_type); + + } else if (auto as_add = llvm::dyn_cast(addr); as_add) { + const auto lhs_op = as_add->getOperand(0); + const auto rhs_op = as_add->getOperand(1); + auto lhs = FindPointer(ir, lhs_op, elem_type, addr_space); + auto rhs = FindPointer(ir, rhs_op, elem_type, addr_space); + + if (!lhs && !rhs) { + + auto lhs_inst = llvm::dyn_cast(lhs_op); + auto lhs_const = llvm::dyn_cast(lhs_op); + + auto rhs_inst = llvm::dyn_cast(rhs_op); + auto rhs_const = llvm::dyn_cast(rhs_op); + + // If we see something like the following: + // + // %res = add %lhs_inst, + // %ptr = inttoptr %res + // + // Then go find/create a pointer for `%lhs_inst`, then generate a GEP + // based off of that. This is to address a common pattern that we observe + // with things like accesses through the stack pointer. + if (lhs_inst && rhs_const && lhs_inst->hasNUsesOrMore(2)) { + auto ipoint = lhs_inst->getNextNode(); + while (llvm::isa(ipoint)) { + ipoint = ipoint->getNextNode(); + } + llvm::IRBuilder<> sub_ir(ipoint); + lhs = GetPointer(cfg_module, sub_ir, lhs_inst, elem_type, addr_space); + + } else if (lhs_const && rhs_inst && rhs_inst->hasNUsesOrMore(2)) { + auto ipoint = rhs_inst->getNextNode(); + while (llvm::isa(ipoint)) { + ipoint = ipoint->getNextNode(); + } + llvm::IRBuilder<> sub_ir(ipoint); + rhs = GetPointer(cfg_module, sub_ir, rhs_inst, elem_type, addr_space); + + } else { + return GetPointerFromInt(ir, addr, elem_type, addr_space); + return ir.CreateIntToPtr(addr, dest_type); + } + } + + addr_space = GetPointerAddressSpace(lhs, addr_space); + addr_space = GetPointerAddressSpace(rhs, addr_space); + dest_type = llvm::PointerType::get(elem_type, addr_space); + + if (lhs && rhs) { + const auto bb = ir.GetInsertBlock(); + + LOG(ERROR) + << "Two pointers " + << remill::LLVMThingToString(lhs) << " and " + << remill::LLVMThingToString(rhs) << " are added together " + << remill::LLVMThingToString(addr) << " in block " + << bb->getName().str() << " in function " + << bb->getParent()->getName().str(); + + return ir.CreateIntToPtr(addr, dest_type); + } + + if (rhs) { + return GetIndexedPointer( + cfg_module, ir, rhs, lhs_op, dest_type, addr_space); + + } else { + return GetIndexedPointer( + cfg_module, ir, lhs, rhs_op, dest_type, addr_space); + } + + } else if (auto as_sub = llvm::dyn_cast(addr); as_sub) { + const auto lhs_op = as_sub->getOperand(0); + const auto rhs_op = as_sub->getOperand(1); + const auto rhs = llvm::dyn_cast(rhs_op); + const auto lhs = FindPointer(ir, lhs_op, elem_type, addr_space); + if (!lhs || !rhs) { + return ir.CreateIntToPtr(addr, dest_type); + + } else { + auto i32_ty = llvm::Type::getInt32Ty(*gContext); + auto neg_index = static_cast( + -static_cast(rhs->getZExtValue())); + auto const_index = llvm::ConstantInt::get( + i32_ty, static_cast(neg_index), true); + addr_space = GetPointerAddressSpace(lhs, addr_space); + dest_type = llvm::PointerType::get(elem_type, addr_space); + return GetIndexedPointer( + cfg_module, ir, lhs, const_index, dest_type, addr_space); + } + + } else if (auto as_bc = llvm::dyn_cast(addr); as_bc) { + return GetPointer(cfg_module, ir, as_bc->getOperand(0), + elem_type, addr_space); + + // E.g. loading an address-sized integer register. + } else if (addr_type->isIntegerTy()) { + const auto bb = ir.GetInsertBlock(); + const auto addr_inst = &*ir.GetInsertPoint(); + + // Go see if we can find multiple uses of `addr` in the same block, such + // that each use converts `addr` to a pointer. If so, go and re-use those + // `inttoptr` conversions instead of adding new ones. + for (auto user : addr->users()) { + const auto inst_user = llvm::dyn_cast(user); + if (!inst_user || + inst_user == addr_inst || + inst_user->getParent() != bb) { + continue; + } + + for (auto next_inst = inst_user->getNextNode(); + next_inst; + next_inst = next_inst->getNextNode()) { + DCHECK_EQ(next_inst->getParent(), bb); + + // We've found `addr_inst`, i.e. the address we're pointer that we're + // try to compute follows a previous equivalent computation in the same + // block, so we'll go take that one. + if (next_inst == addr_inst) { + return ir.CreateBitCast(inst_user, dest_type); + } + } + + // We found another computation of this pointer, but it follows + // `addr_inst` in the block, so we'll move it to where we need it. + inst_user->removeFromParent(); + inst_user->insertBefore(addr_inst); + return ir.CreateBitCast(inst_user, dest_type); + } + + return GetPointerFromInt(ir, addr, elem_type, addr_space); + + } else { + CHECK(addr_type->isPointerTy()); + return ir.CreateBitCast(addr, dest_type); + } +} + // Lower a memory read intrinsic into a `load` instruction. -static void ReplaceMemReadOp(const char *name, llvm::Type *val_type) { +static void ReplaceMemReadOp(const NativeModule *cfg_module, const char *name, + llvm::Type *val_type) { auto func = gModule->getFunction(name); if (!func) { return; @@ -241,20 +631,14 @@ static void ReplaceMemReadOp(const char *name, llvm::Type *val_type) { auto callers = remill::CallersOf(func); for (auto call_inst : callers) { auto addr = call_inst->getArgOperand(1); - llvm::IRBuilder<> ir(call_inst); - llvm::Value *ptr = nullptr; - if (auto as_int = llvm::dyn_cast(addr)) { - ptr = ir.CreateBitCast( - as_int->getPointerOperand(), - llvm::PointerType::get(val_type, as_int->getPointerAddressSpace())); - - } else { - ptr = ir.CreateIntToPtr(addr, llvm::PointerType::get(val_type, 0)); - } - + llvm::Value *ptr = GetPointer(cfg_module, ir, addr, val_type, 0); llvm::Value *val = ir.CreateLoad(ptr); - if (val_type->isX86_FP80Ty()) { + if (auto load_inst = llvm::dyn_cast(val); + FLAGS_volatile_memops && load_inst) { + load_inst->setVolatile(true); + } + if (val_type->isX86_FP80Ty() || val_type->isFP128Ty()) { val = ir.CreateFPTrunc(val, func->getReturnType()); } call_inst->replaceAllUsesWith(val); @@ -266,7 +650,8 @@ static void ReplaceMemReadOp(const char *name, llvm::Type *val_type) { } // Lower a memory write intrinsic into a `store` instruction. -static void ReplaceMemWriteOp(const char *name, llvm::Type *val_type) { +static void ReplaceMemWriteOp(const NativeModule *cfg_module, const char *name, + llvm::Type *val_type) { auto func = gModule->getFunction(name); if (!func) { return; @@ -283,21 +668,15 @@ static void ReplaceMemWriteOp(const char *name, llvm::Type *val_type) { auto val = call_inst->getArgOperand(2); llvm::IRBuilder<> ir(call_inst); - - llvm::Value *ptr = nullptr; - if (auto as_int = llvm::dyn_cast(addr)) { - ptr = ir.CreateBitCast( - as_int->getPointerOperand(), - llvm::PointerType::get(val_type, as_int->getPointerAddressSpace())); - } else { - ptr = ir.CreateIntToPtr(addr, llvm::PointerType::get(val_type, 0)); - } - - if (val_type->isX86_FP80Ty()) { + llvm::Value *ptr = GetPointer(cfg_module, ir, addr, val_type, 0); + if (val_type->isX86_FP80Ty() || val_type->isFP128Ty()) { val = ir.CreateFPExt(val, val_type); } - ir.CreateStore(val, ptr); + auto store_inst = ir.CreateStore(val, ptr); + if (FLAGS_volatile_memops) { + store_inst->setVolatile(true); + } call_inst->replaceAllUsesWith(mem_ptr); } for (auto call_inst : callers) { @@ -306,69 +685,1213 @@ static void ReplaceMemWriteOp(const char *name, llvm::Type *val_type) { RemoveFunction(func); } -static void LowerMemOps(void) { - ReplaceMemReadOp("__remill_read_memory_8", +static void LowerMemOps(const NativeModule *cfg_module) { + ReplaceMemReadOp(cfg_module, "__remill_read_memory_8", llvm::Type::getInt8Ty(*gContext)); - ReplaceMemReadOp("__remill_read_memory_16", + ReplaceMemReadOp(cfg_module, "__remill_read_memory_16", llvm::Type::getInt16Ty(*gContext)); - ReplaceMemReadOp("__remill_read_memory_32", + ReplaceMemReadOp(cfg_module, "__remill_read_memory_32", llvm::Type::getInt32Ty(*gContext)); - ReplaceMemReadOp("__remill_read_memory_64", + ReplaceMemReadOp(cfg_module, "__remill_read_memory_64", llvm::Type::getInt64Ty(*gContext)); - ReplaceMemReadOp("__remill_read_memory_f32", + ReplaceMemReadOp(cfg_module, "__remill_read_memory_f32", llvm::Type::getFloatTy(*gContext)); - ReplaceMemReadOp("__remill_read_memory_f64", + ReplaceMemReadOp(cfg_module, "__remill_read_memory_f64", llvm::Type::getDoubleTy(*gContext)); - ReplaceMemWriteOp("__remill_write_memory_8", + ReplaceMemWriteOp(cfg_module, "__remill_write_memory_8", llvm::Type::getInt8Ty(*gContext)); - ReplaceMemWriteOp("__remill_write_memory_16", + ReplaceMemWriteOp(cfg_module, "__remill_write_memory_16", llvm::Type::getInt16Ty(*gContext)); - ReplaceMemWriteOp("__remill_write_memory_32", + ReplaceMemWriteOp(cfg_module, "__remill_write_memory_32", llvm::Type::getInt32Ty(*gContext)); - ReplaceMemWriteOp("__remill_write_memory_64", + ReplaceMemWriteOp(cfg_module, "__remill_write_memory_64", llvm::Type::getInt64Ty(*gContext)); - ReplaceMemWriteOp("__remill_write_memory_f32", + ReplaceMemWriteOp(cfg_module, "__remill_write_memory_f32", llvm::Type::getFloatTy(*gContext)); - ReplaceMemWriteOp("__remill_write_memory_f64", + ReplaceMemWriteOp(cfg_module, "__remill_write_memory_f64", llvm::Type::getDoubleTy(*gContext)); - ReplaceMemReadOp("__remill_read_memory_f80", + ReplaceMemReadOp(cfg_module, "__remill_read_memory_f80", llvm::Type::getX86_FP80Ty(*gContext)); - ReplaceMemWriteOp("__remill_write_memory_f80", + ReplaceMemReadOp(cfg_module, "__remill_write_memory_f128", + llvm::Type::getFP128Ty(*gContext)); + + ReplaceMemWriteOp(cfg_module, "__remill_write_memory_f80", llvm::Type::getX86_FP80Ty(*gContext)); + ReplaceMemWriteOp(cfg_module, "__remill_write_memory_f128", + llvm::Type::getFP128Ty(*gContext)); +} + +static bool RemoveDeadRestores(llvm::Function *restorer) { + std::vector> to_replace; + std::vector to_remove; + std::vector try_to_remove; + std::vector> to_fixup; + + std::unordered_set functions_with_noreturn; + if (FLAGS_restore_all_on_unreachable) { + for (auto &func : *gModule) { + if (func.doesNotReturn()) { + for (auto user : func.users()) { + if (auto call_inst = llvm::dyn_cast(user); + call_inst && call_inst->getCalledFunction() == &func) { + functions_with_noreturn.insert(call_inst->getParent()->getParent()); + + } else if (auto invoke_inst = llvm::dyn_cast(user); + invoke_inst && invoke_inst->getCalledFunction() == &func) { + functions_with_noreturn.insert(invoke_inst->getParent()->getParent()); + } + } + } + for (auto &block : func) { + if (llvm::isa(block.getTerminator())) { + functions_with_noreturn.insert(&func); + } + } + } + } + + auto needs_restores = false; + do { + for (auto [use, new_val] : to_fixup) { + use->set(new_val); + } + + to_replace.clear(); + to_remove.clear(); + try_to_remove.clear(); + to_fixup.clear(); + + for (auto user : restorer->users()) { + const auto call = llvm::dyn_cast(user); + if (!call) { + continue; + } + + auto args = call->arg_begin(); + auto first_arg = args->get(); + auto second_arg = (++args)->get(); + auto func = call->getParent()->getParent(); + + // If the two arguments match, then it means that the register being + // restored didn't change over the course of this function. + // + // NOTE(pag): If a function has an unreachable instruction, then it might + // miss out on some optimizations, and so we want to always + // force some restores. + if (first_arg == second_arg && + (!FLAGS_restore_all_on_unreachable || !functions_with_noreturn.count(func))) { + auto all_users_are_stores = true; + + // Go find the store of the return value to the state structure, and + // schedule it for removal. + for (auto &call_use : call->uses()) { + const auto call_user = call_use.getUser(); + if (auto store_inst = llvm::dyn_cast(call_user); + store_inst) { + to_remove.emplace_back(store_inst); + + // Check to see if one `__remill_restore` function's output leads to + // another one's, and then queue up a replacement that will send us + // back around the main loop. + } else if (auto call_inst = llvm::dyn_cast(call_user); + call_inst) { + if (call_inst == call) { + continue; // Weird? + + } else if (call_inst->getCalledFunction() == restorer) { + to_fixup.emplace_back(&call_use, call_inst->arg_begin()->get()); + } else { + all_users_are_stores = false; + } + } else { + all_users_are_stores = false; + } + } + + // Go look for any stores of the first argument into the state structure, + // and remove them. If we find these, then they are likely leftovers from + // after function calls to other lifted functions. + if (auto reg_load = llvm::dyn_cast(first_arg); reg_load) { + for (auto reg_user : first_arg->users()) { + if (auto reg_restore = llvm::dyn_cast(reg_user); + reg_restore) { + + // Found a save of the register back into itself. + if (reg_load->getPointerOperand() == + reg_restore->getPointerOperand()) { + to_remove.push_back(reg_restore); + } + } + } + } + + if (!all_users_are_stores) { + to_replace.emplace_back(call, first_arg); + } + + } else { + needs_restores = true; + + for (auto call_user : call->users()) { + if (auto store_inst = llvm::dyn_cast(call_user)) { + store_inst->setVolatile(false); + } + } + to_replace.emplace_back(call, first_arg); + + // The `load` of the most recent value in that register. + if (auto inst = llvm::dyn_cast(second_arg)) { + try_to_remove.push_back(inst); + } + } + + to_remove.push_back(call); + } + } while (!to_fixup.empty()); + + std::unordered_set removed; + + for (auto [call_inst, orig_val] : to_replace) { + call_inst->replaceAllUsesWith(orig_val); + } + + removed.reserve(to_remove.size() + try_to_remove.size()); + + for (auto inst : to_remove) { + if (!removed.count(inst)) { + inst->eraseFromParent(); + removed.insert(inst); + } + } + + for (auto inst : try_to_remove) { + if (!removed.count(inst) && !inst->hasNUsesOrMore(1)) { + inst->eraseFromParent(); + removed.insert(inst); + } + } + + return needs_restores; +} + +static bool RemoveDeadRestores(void) { + auto needs_restores = false; + std::vector to_remove; + for (auto &func : *gModule) { + if (func.getName().startswith("__remill_restore.")) { + needs_restores = RemoveDeadRestores(&func) || needs_restores; + to_remove.push_back(&func); + } + } + for (auto func : to_remove) { + func->eraseFromParent(); + } + return needs_restores; +} + +static void RemoveKilledStores(void) { + if (auto killer = gModule->getGlobalVariable("__remill_kill"); killer) { + std::vector> to_replace; + std::vector to_remove; + std::vector work_list; + std::vector next_work_list; + next_work_list.push_back(killer); + + while (!next_work_list.empty()) { + work_list.swap(next_work_list); + next_work_list.clear(); + for (auto val : work_list) { + for (auto user : val->users()) { + if (auto si = llvm::dyn_cast(user); si) { + to_remove.emplace_back(si); + } else if (auto ce = llvm::dyn_cast(user); ce) { + next_work_list.push_back(ce); + } + } + } + } + + std::sort(to_remove.begin(), to_remove.end()); + auto it = std::unique(to_remove.begin(), to_remove.end()); + to_remove.erase(it, to_remove.end()); + for (auto inst : to_remove) { + inst->eraseFromParent(); + } + + killer->replaceAllUsesWith(llvm::UndefValue::get(killer->getType())); + killer->eraseFromParent(); + } +} + +// When implementing the save/restore optimization, we can sometimes have an +// annoying interaction with no-return functions. Here's an example: +// +// lifted_foo { +// orig_rbp = state->rbp +// ... +// state->rbp = state->rsp // From instruction semantics +// ... +// +// saved_rbp = state->rbp +// state->rbp = __remill_saving_kill_XXX(saved_rbp) // To kill `state->rbp` +// lifted_bar() // May be noreturn, and if so, the rest gets eliminated +// state->rbp = saved_rbp // To propagate `saved_rbp` around +// +// ... +// +// state->rbp = orig_rbp +// ret +// } +// +// So the issue that can happen is that if `lifted_bar` is `noreturn`, then a +// bunch of stores into the state struct can get eliminated. If those stores +// get eliminated, then it's possible that `state->rbp` is treated as being +// live when `state->rbp = state->rsp` happens, and so that store will happen +// and a caller might see the callee's `rbp` instead of `orig_rbp`. By +// introducing the call and store `state->rbp = __remill_saving_kill_XXX...`, +// we make sure that there is always a store to a saved/restored reg, even +// before noreturn functions, and so the store `state->rbp = state->rsp` is +// marked as dead, and so the calle sees the right `rbp` upon return. +static void RemoveSavingKilledStores(void) { + + std::vector> to_replace; + std::vector to_remove; + + for (auto &func : *gModule) { + if (func.getName().startswith("__remill_saving_kill_")) { + for (auto user : func.users()) { + if (auto call_inst = llvm::dyn_cast(user); + call_inst && call_inst->getCalledFunction() == &func) { + to_replace.emplace_back(call_inst, call_inst->getArgOperand(0)); + } + } + } + } + + for (auto [kill_val, reg_val] : to_replace) { + if (auto store_inst = llvm::dyn_cast(kill_val->getNextNode()); + store_inst && store_inst->getValueOperand() == kill_val) { + to_remove.push_back(store_inst); + } + + kill_val->replaceAllUsesWith(reg_val); + kill_val->eraseFromParent(); + } + + for (auto store_inst : to_remove) { + store_inst->eraseFromParent(); + } +} + +// Adapt a constant (possibly expression) of integral type in `src` to another +// integer type (likely `gWordType`) that is `dest_type`. +static llvm::Constant *AdaptToType(llvm::Constant *src, llvm::Type *dest_type) { + const auto src_type = src->getType(); + if (src_type == dest_type) { + return src; + } + CHECK(src_type->isIntegerTy()); + + if (dest_type->isIntegerTy()) { + auto src_size = src_type->getPrimitiveSizeInBits(); + auto dest_size = dest_type->getPrimitiveSizeInBits(); + if (src_size < dest_size) { + return llvm::ConstantExpr::getZExt(src, dest_type); + } else { + return llvm::ConstantExpr::getTrunc(src, dest_type); + } + } else if (dest_type->isPointerTy()) { + if (auto pti = llvm::dyn_cast(src); pti) { + src = llvm::cast(pti->getOperand(0)); + if (src->getType() == dest_type) { + return src; + } else { + return llvm::ConstantExpr::getBitCast(src, dest_type); + } + + } else { + return llvm::ConstantExpr::getIntToPtr(src, dest_type); + } + } else { + LOG(FATAL) + << "Unsupported destination type: " + << remill::LLVMThingToString(dest_type); + return nullptr; + } +} +// The add-on pass to merge the `GEP` instructions if they are operating +// on the same instruction operand +static void MergeGEPInstructions(llvm::Function &func) { + std::map, + std::vector> gep_map; + + for (auto &block : func) { + for (auto &inst : block) { + if ((inst.getNumOperands() != 2)) + continue; + + if ((inst.getOpcode() == llvm::Instruction::GetElementPtr) && + (llvm::isa(inst.getOperand(0))) && + (llvm::isa(inst.getOperand(1)))) { + gep_map[std::pair( + inst.getOperand(0), inst.getOperand(1))].push_back(&inst); + } + } + } + + for (auto it = gep_map.begin(); it != gep_map.end(); ++it) { + auto &inst_vec = it->second; + if (inst_vec.size() == 1) { + continue; + } + + auto opnd0 = llvm::dyn_cast(inst_vec[0]->getOperand(0)); + if ((opnd0->getOpcode() == llvm::Instruction::PHI)) + continue; + + inst_vec[0]->moveAfter(opnd0); + + for (auto i = 1u; i < inst_vec.size(); ++i) { + auto gep_to_merge = inst_vec[i]; + gep_to_merge->replaceAllUsesWith(inst_vec[0]); + + if (!gep_to_merge->hasNUsesOrMore(1)) { + gep_to_merge->eraseFromParent(); + } + } + } +} + +// Lower cross-references, and try to fixup pointers. +static void LowerXrefs(const NativeModule *cfg_module) { + std::vector work_list; + std::vector next_work_list; + std::vector> fixups; + std::unordered_map done_fixups; + + anvill::XrefExprFolder folder(*cfg_module, *gModule); + + auto get_fixup = [=, &folder, &done_fixups] (llvm::User *user, + llvm::Constant *ce) + -> llvm::Constant * { + + bool is_bitwise = false; + if (auto op = llvm::dyn_cast(user); op) { + switch (op->getOpcode()) { + case llvm::Instruction::AShr: + case llvm::Instruction::LShr: + case llvm::Instruction::Shl: + case llvm::Instruction::And: + case llvm::Instruction::Xor: + case llvm::Instruction::Or: + //is_bitwise = true; + break; + default: + break; + } + } + + const auto ce_type = ce->getType(); + auto &fixup = done_fixups[ce]; + if (!is_bitwise && fixup) { + return fixup; + } + + folder.Reset(); + const auto ea = folder.VisitConst(ce); + + if (remill::IsError(folder.error)) { + LOG(ERROR) + << remill::GetErrorString(folder.error); + } + + // Common to have a shift left by one, two, or three for common + // optimizations and address calculations (e.g. multiply by pointer or + // offset size). + //if (is_bitwise && folder.left_shift_amount <= 3) { + // is_bitwise = false; + //} + + // It's a small number, just treat it like a constant. + if (llvm::isa(ce_type) && + (ea < 128 || (ea < 4096 && !FLAGS_check_for_lowmem_xrefs))) { + fixup = llvm::ConstantInt::get(ce_type, ea); + + // Try to map it to a segment, external variable, or function. + } else if (auto addr = GetAddress(cfg_module, ea)) { + fixup = AdaptToType(addr, ce_type); + + // It doesn't reference anything known; treat it as a constant. + } else { + if (auto inst = llvm::dyn_cast(user); inst) { + LOG(WARNING) + << "Treating " << std::hex << ea << std::dec << " as a constant" + << " in " << inst->getParent()->getName().str(); + + } else { + LOG(WARNING) + << "Treating " << std::hex << ea << std::dec << " as a constant"; + } + + fixup = llvm::ConstantInt::get(ce_type, ea); + } + + if (is_bitwise) { + if (fixup) { + if (llvm::isa(fixup)) { + return fixup; + } else { + LOG(ERROR) + << "Previously lifted cross-reference to " << std::hex + << ea << std::dec << " is used in subsequent bitwise operations; " + << "assuming it is actually a constant in this instance"; + + return llvm::ConstantInt::get(ce_type, ea); + } + } else { + LOG(ERROR) + << "Cross-reference to " << std::hex << ea << std::dec + << " is used in bitwise operations; assuming it is a constant"; + fixup = llvm::ConstantInt::get(ce_type, ea); + } + + } else if (folder.bits_xor && !llvm::isa(fixup)) { + fixup = llvm::ConstantInt::get(ce_type, ea); + + if (auto inst = llvm::dyn_cast(user); inst) { + LOG(ERROR) + << "Cross-reference to " << std::hex << ea << std::dec + << " in " << inst->getParent()->getName().str() + << " is computed via a XOR; assuming it is a constant: " + << remill::LLVMThingToString(ce); + + } else { + LOG(ERROR) + << "Cross-reference to " << std::hex << ea << std::dec + << " is computed via a XOR; assuming it is a constant: " + << remill::LLVMThingToString(ce); + } + } + + return fixup; + }; + + if (auto pc = gModule->getGlobalVariable("__anvill_pc"); pc) { + next_work_list.push_back(pc); + } + + // Sometimes, after optimizations, we'll end up seeing expressions operating + // on our callback function pointers. + for (auto [func_ea, cfg_func] : cfg_module->ea_to_func) { + (void) func_ea; + + if (cfg_func->function) { + if (auto func = gModule->getFunction(cfg_func->lifted_name); func) { + cfg_func->function = func; + for (auto &use : func->uses()) { + const auto user = use.getUser(); + if (auto user_ce = llvm::dyn_cast(user)) { + next_work_list.push_back(user_ce); + } + } + } else { + cfg_func->function = nullptr; + } + } + } + + while (!next_work_list.empty()) { + next_work_list.swap(work_list); + next_work_list.clear(); + + for (auto ce : work_list) { + for (auto &use : ce->uses()) { + const auto user = use.getUser(); + if (auto inst = llvm::dyn_cast(user); inst) { + fixups.emplace_back(&use, get_fixup(inst, ce)); + + } else if (auto user_ce = llvm::dyn_cast(user)) { + next_work_list.push_back(user_ce); + + } else if (llvm::isa(user) || + llvm::isa(user) || + llvm::isa(user)) { + continue; + + } else { + LOG(ERROR) + << "Unexpected user of cross-reference: " + << remill::LLVMThingToString(user); + } + } + } + } + + for (auto [use, replacement] : fixups) { + use->set(replacement); + } + + auto find_missed_fixup = [&] (const char *func_name, llvm::Type *val_type) { + const auto func = gModule->getFunction(func_name); + if (!func) { + return; + } + + for (auto user : func->users()) { + const auto ci = llvm::dyn_cast(user); + if (!ci) { + continue; + } + + auto &addr_use = ci->getArgOperandUse(1); + auto addr_val = addr_use.get(); + + // If it's a constant integer, it means it was "missed" by the frontend + // and thus by constant folding on `__mcsema_zero`. + if (auto addr_int = llvm::dyn_cast(addr_val)) { + const auto new_addr_val = get_fixup(user, addr_int); + if (llvm::isa(new_addr_val)) { + LOG(ERROR) + << "Missed cross-reference to absolute address " << std::hex + << addr_int->getZExtValue() << std::dec << " in block " + << ci->getParent()->getName().str() << " in function " + << ci->getParent()->getParent()->getName().str(); + + } else { + LOG(WARNING) + << "Fixing absolute address " << std::hex + << addr_int->getZExtValue() << std::dec << " to be reference " + << remill::LLVMThingToString(new_addr_val); + } + + fixups.emplace_back(&addr_use, new_addr_val); + + // At this point, it should be an `ptrtoint` on a global, or an + // instruction that computes an integer. + } else { + llvm::IRBuilder<> ir(ci); + llvm::Value *ptr = GetPointer( + cfg_module, ir, addr_use.get(), val_type, 0); + fixups.emplace_back(&addr_use, ir.CreatePtrToInt(ptr, gWordType)); + } + } + }; + + // Clear out all prior fixups. + fixups.clear(); + folder.Reset(); + + const auto int8_ty = llvm::Type::getInt8Ty(*gContext); + const auto int16_ty = llvm::Type::getInt16Ty(*gContext); + const auto int32_ty = llvm::Type::getInt32Ty(*gContext); + const auto int64_ty = llvm::Type::getInt64Ty(*gContext); + const auto float_ty = llvm::Type::getFloatTy(*gContext); + const auto double_ty = llvm::Type::getDoubleTy(*gContext); + const auto fp80_ty = llvm::Type::getX86_FP80Ty(*gContext); + const auto fp128_ty = llvm::Type::getFP128Ty(*gContext); + + find_missed_fixup("__remill_read_memory_8", int8_ty); + find_missed_fixup("__remill_read_memory_16", int16_ty); + find_missed_fixup("__remill_read_memory_32", int32_ty); + find_missed_fixup("__remill_read_memory_64", int64_ty); + find_missed_fixup("__remill_read_memory_f32", float_ty); + find_missed_fixup("__remill_read_memory_f64", double_ty); + find_missed_fixup("__remill_read_memory_f80", fp80_ty); + find_missed_fixup("__remill_read_memory_f128", fp128_ty); + + find_missed_fixup("__remill_compare_exchange_memory_8", int8_ty); + find_missed_fixup("__remill_fetch_and_add_8", int8_ty); + find_missed_fixup("__remill_fetch_and_sub_8", int8_ty); + find_missed_fixup("__remill_fetch_and_or_8", int8_ty); + find_missed_fixup("__remill_fetch_and_and_8", int8_ty); + find_missed_fixup("__remill_fetch_and_xor_8", int8_ty); + + find_missed_fixup("__remill_compare_exchange_memory_16", int16_ty); + find_missed_fixup("__remill_fetch_and_add_16", int16_ty); + find_missed_fixup("__remill_fetch_and_sub_16", int16_ty); + find_missed_fixup("__remill_fetch_and_or_16", int16_ty); + find_missed_fixup("__remill_fetch_and_and_16", int16_ty); + find_missed_fixup("__remill_fetch_and_xor_16", int16_ty); + + find_missed_fixup("__remill_compare_exchange_memory_32", int32_ty); + find_missed_fixup("__remill_fetch_and_add_32", int32_ty); + find_missed_fixup("__remill_fetch_and_sub_32", int32_ty); + find_missed_fixup("__remill_fetch_and_or_32", int32_ty); + find_missed_fixup("__remill_fetch_and_and_32", int32_ty); + find_missed_fixup("__remill_fetch_and_xor_32", int32_ty); + + find_missed_fixup("__remill_compare_exchange_memory_64", int64_ty); + find_missed_fixup("__remill_fetch_and_add_64", int64_ty); + find_missed_fixup("__remill_fetch_and_sub_64", int64_ty); + find_missed_fixup("__remill_fetch_and_or_64", int64_ty); + find_missed_fixup("__remill_fetch_and_and_64", int64_ty); + find_missed_fixup("__remill_fetch_and_xor_64", int64_ty); + + find_missed_fixup("__remill_write_memory_8", int8_ty); + find_missed_fixup("__remill_write_memory_16", int16_ty); + find_missed_fixup("__remill_write_memory_32", int32_ty); + find_missed_fixup("__remill_write_memory_64", int64_ty); + find_missed_fixup("__remill_write_memory_f32", float_ty); + find_missed_fixup("__remill_write_memory_f64", double_ty); + find_missed_fixup("__remill_write_memory_f80", fp80_ty); + find_missed_fixup("__remill_write_memory_f128", fp128_ty); + + for (auto [use, replacement] : fixups) { + use->set(replacement); + } + + gZero = nullptr; + if (auto zero = gModule->getNamedGlobal("__anvill_pc")) { + zero->eraseFromParent(); + } +} + +// Looks for calls to a function like `__remill_function_return`, and +// replace its state pointer with a null pointer so that the state +// pointer never escapes. +static void MuteStateEscape(const char *func_name) { + auto func = gModule->getFunction(func_name); + if (!func) { + return; + } + + const auto state_ptr = GetStatePointer(); + for (auto user : func->users()) { + if (auto call_inst = llvm::dyn_cast(user)) { + call_inst->setArgOperand(remill::kStatePointerArgNum, state_ptr); + } + } +} + +static void SanitizeNameForLinking(std::string &name) { + for (auto &c : name) { + if (!std::isalnum(c)) { + c = '_'; + } + } +} + +// Try to get `ptr` as an alias to a register in the thread-local state +// structure. +static llvm::Value *TryGetRegAlias(llvm::Value *ptr, unsigned offset) { + if (FLAGS_disable_aliases) { + return ptr; + } + + auto reg = gArch->RegisterAtStateOffset(offset); + if (!reg) { + return ptr; + } + + reg = reg->EnclosingRegister(); + + auto ptr_const = llvm::dyn_cast(ptr); + if (!ptr_const) { + return ptr; + } + + const auto ptr_type = ptr_const->getType(); + const auto elem_type = ptr_type->getPointerElementType(); + + std::stringstream ss; + ss << reg->name << "_" << std::hex << reinterpret_cast(elem_type); + auto alias_name = ss.str(); + SanitizeNameForLinking(alias_name); + + auto alias = gModule->getNamedAlias(alias_name); + if (alias) { + return alias; + } + + alias = llvm::GlobalAlias::create( + elem_type, ptr_type->getPointerAddressSpace(), + llvm::GlobalValue::PrivateLinkage, alias_name, ptr_const, + gModule.get()); + alias->setThreadLocalMode(llvm::GlobalValue::InitialExecTLSModel); + return alias; +} + +// Go replace all uses of the state pointer argument with the global state +// pointer, and try to look for the following patterns and also fold them +// into constant expressions: +// +// %blah = ptrtoint %val load %val, %reg_ptr +// store %blah, %reg_ptr %blah = intoptr %val +// +// into +// +// store %val, (bitcast CE) %blah = load (bitcast CE) +// +// So as to reduce the total number of GEPs and inttoptr instructions. +static void GlobalizeStateStructures(void) { + const auto state_ptr = ::mcsema::GetStatePointer(); + const auto state_ptr_type = state_ptr->getType(); + //const auto undef_state = llvm::UndefValue::get(state_ptr_type); + + std::vector> work_list; + std::vector> next_work_list; + std::vector> to_replace; + std::vector to_remove; + + const auto &dl = gModule->getDataLayout(); + + for (auto &func : *gModule) { + if (func.isDeclaration()) { + continue; + } + + if (func.getFunctionType()->getNumParams() <= remill::kStatePointerArgNum) { + continue; + } + + auto func_state_ptr = remill::NthArgument(&func, remill::kStatePointerArgNum); + if (func_state_ptr->getType() != state_ptr_type) { + continue; + } +#if 0 + // Replace all state pointer args with `undef`. + for (auto user : func.users()) { + if (auto call_inst = llvm::dyn_cast(user); + call_inst && call_inst->getCalledFunction() == &func) { + call_inst->setArgOperand(remill::kStatePointerArgNum, undef_state); + } + } +#endif + to_replace.clear(); + to_remove.clear(); + next_work_list.clear(); + next_work_list.emplace_back(func_state_ptr, 0); + while (!next_work_list.empty()) { + work_list.clear(); + next_work_list.swap(work_list); + for (auto [ptr_, offset] : work_list) { + llvm::Value *ptr = ptr_; + for (auto &use : ptr->uses()) { + auto user = use.getUser(); + if (auto bc = llvm::dyn_cast(user); bc) { + next_work_list.emplace_back(bc, offset); + to_remove.push_back(bc); + + } else if (auto gep = llvm::dyn_cast(user); gep) { + llvm::APInt sub_offset(gArch->address_size, 0); + if (gep->accumulateConstantOffset(dl, sub_offset)) { + next_work_list.emplace_back( + gep, offset + sub_offset.getZExtValue()); + + } else { + to_replace.emplace_back(&use, offset); + } + to_remove.push_back(gep); + + } else if (llvm::isa(user) || + llvm::isa(user) || + llvm::isa(user)) { + to_replace.emplace_back(&use, offset); + + } else if (auto inst = llvm::dyn_cast(user); inst) { + + to_replace.emplace_back(&use, offset); + to_remove.push_back(inst); + + } else { + to_replace.emplace_back(&use, offset); + } + } + } + } + + llvm::IRBuilder<> ir(&(func.getEntryBlock()), + func.getEntryBlock().getFirstInsertionPt()); + + for (auto [use, offset] : to_replace) { + auto user = use->getUser(); + + // Match on the store pattern that we want to simplify, if possible. + if (auto store = llvm::dyn_cast(user); store) { + auto base = store->getValueOperand(); + + if (auto pti = llvm::dyn_cast(base); pti) { + auto ptr = remill::BuildPointerToOffset( + ir, state_ptr, offset, + llvm::PointerType::get(pti->getPointerOperandType(), 0)); + ptr = TryGetRegAlias(ptr, offset); + + if (auto pti_inst = llvm::dyn_cast(pti); pti_inst) { + to_remove.push_back(pti_inst); + } + + (void) new llvm::StoreInst( + pti->getPointerOperand(), ptr, store); + to_remove.push_back(store); + continue; + } + + // Match on the load pattern that we want to simplify, if possible. + } else if (auto load = llvm::dyn_cast(user); load) { + for (auto &load_use : load->uses()) { + auto user = load_use.getUser(); + if (auto itp = llvm::dyn_cast(user)) { + auto ptr = remill::BuildPointerToOffset( + ir, state_ptr, offset, + llvm::PointerType::get(itp->getType(), 0)); + ptr = TryGetRegAlias(ptr, offset); + itp->replaceAllUsesWith( + new llvm::LoadInst(ptr, load->getName(), load)); + to_remove.push_back(itp); + } + } + } + + auto ptr = remill::BuildPointerToOffset( + ir, state_ptr, offset, use->get()->getType()); + + ptr = TryGetRegAlias(ptr, offset); + use->set(ptr); + } + + std::sort(to_remove.begin(), to_remove.end()); + auto remove_it = std::unique(to_remove.begin(), to_remove.end()); + to_remove.erase(remove_it, to_remove.end()); + + while (!to_remove.empty()) { + auto inst = to_remove.back(); + to_remove.pop_back(); + if (!inst->hasNUsesOrMore(1)) { + inst->eraseFromParent(); + } + } + } +} + +static void MuteLinkerSymbol(const char *sym_name) { + if (auto gv = gModule->getGlobalVariable(sym_name); gv) { + gv->setLinkage(llvm::GlobalValue::PrivateLinkage); + } } } // namespace -void OptimizeModule(void) { +void OptimizeModule(const NativeModule *cfg_module) { + + if (auto llvm_used = gModule->getGlobalVariable("llvm.used")) { + llvm_used->eraseFromParent(); + } + + MuteStateEscape("__remill_function_return"); + MuteStateEscape("__remill_jump"); + MuteStateEscape("__remill_error"); + MuteStateEscape("__remill_missing_block"); + MuteStateEscape("__remill_async_hyper_call"); + auto isels = FindISELs(); - RemoveIntrinsics(); LOG(INFO) << "Optimizing module."; PrivatizeISELs(isels); - if (!FLAGS_disable_optimizer) { - auto bb_func = remill::BasicBlockFunction(gModule.get()); - auto slots = remill::StateSlots(gModule.get()); - RunO3(); - remill::RemoveDeadStores(gModule.get(), bb_func, slots); + auto bb_func = remill::BasicBlockFunction(gModule.get()); + auto slots = remill::StateSlots(gArch.get(), gModule.get()); + + if (auto llvm_used = gModule->getGlobalVariable("llvm.used")) { + llvm_used->eraseFromParent(); } - RemoveIntrinsics(); + llvm::legacy::PassManager mod_pm; + mod_pm.add(llvm::createFunctionInliningPass(250)); + mod_pm.run(*gModule); + + llvm::legacy::FunctionPassManager pm(gModule.get()); + +// pm.add(llvm::createGVNHoistPass()); +// pm.add(llvm::createGVNSinkPass()); +// pm.add(llvm::createMergedLoadStoreMotionPass()); + + pm.add(llvm::createEarlyCSEPass(true)); + pm.add(llvm::createDeadCodeEliminationPass()); + pm.add(llvm::createConstantPropagationPass()); + pm.add(llvm::createSinkingPass()); + pm.add(llvm::createNewGVNPass()); + pm.add(llvm::createSCCPPass()); + pm.add(llvm::createDeadStoreEliminationPass()); + pm.add(llvm::createSROAPass()); + pm.add(llvm::createPromoteMemoryToRegisterPass()); + pm.add(llvm::createBitTrackingDCEPass()); + pm.add(llvm::createCFGSimplificationPass()); + pm.add(llvm::createSinkingPass()); + pm.add(llvm::createCFGSimplificationPass()); + + pm.doInitialization(); + for (auto &func : *gModule) { + pm.run(func); + } + pm.doFinalization(); + + remill::RemoveDeadStores(gArch.get(), gModule.get(), bb_func, slots); + + + // If some of the restores are *not* dead, then we will have eliminated + // some loads and subsequent uses (in the `__remill_restore.*` argument lists) + // that made those registers look live. The addition of restoring stores thus + // means that there may be new DSE opportunities. + if (RemoveDeadRestores()) { + remill::RemoveDeadStores(gArch.get(), gModule.get(), bb_func, slots); + pm.doInitialization(); + for (auto &func : *gModule) { + pm.run(func); + } + pm.doFinalization(); + } + + RemoveKilledStores(); + + // NOTE(pag): These are not done in Function.cpp atm. + if (false) { + RemoveSavingKilledStores(); + } + +// anvill::RecoverMemoryAccesses(*cfg_module, *gModule); + LowerXrefs(cfg_module); + + for (auto &[ea, cfg_func] : cfg_module->ea_to_func) { + (void) ea; + + // Make sure things like `main` show up. + if (cfg_func->is_exported) { + (void) cfg_func->Pointer(); + } + + cfg_func->lifted_function = gModule->getFunction(cfg_func->lifted_name); + +// if (!cfg_func->is_exported && cfg_func->function) { +// if (cfg_func->function->hasNUsesOrMore(1)) { +// continue; +// } +// } + } + + pm.doInitialization(); + for (auto &func : *gModule) { + pm.run(func); + } + pm.doFinalization(); + + for (auto &func : *gModule) { + MergeGEPInstructions(func); + } + + pm.doInitialization(); + for (auto &func : *gModule) { + pm.run(func); + } + pm.doFinalization(); +} + +// Remove some of the Remill intrinsics. +void CleanUpModule(const NativeModule *cfg_module) { + RemoveUndefFuncCalls(); + + if (auto llvm_used = gModule->getGlobalVariable("llvm.used")) { + llvm_used->eraseFromParent(); + } if (!FLAGS_keep_memops) { - LowerMemOps(); + LowerMemOps(cfg_module); ReplaceBarrier("__remill_barrier_load_load"); ReplaceBarrier("__remill_barrier_load_store"); ReplaceBarrier("__remill_barrier_store_load"); ReplaceBarrier("__remill_barrier_store_store"); ReplaceBarrier("__remill_barrier_atomic_begin"); ReplaceBarrier("__remill_barrier_atomic_end"); + ReplaceBarrier("__remill_delay_slot_begin"); + ReplaceBarrier("__remill_delay_slot_end"); + ReplaceBarrier("__remill_atomic_begin"); + ReplaceBarrier("__remill_atomic_end"); + + llvm::legacy::FunctionPassManager pm(gModule.get()); + pm.add(llvm::createEarlyCSEPass(true)); + pm.add(llvm::createDeadCodeEliminationPass()); + pm.add(llvm::createCFGSimplificationPass()); + pm.doInitialization(); + for (auto &func : *gModule) { + pm.run(func); + } + pm.doFinalization(); } - RemoveUndefFuncCalls(); + LowerXrefs(cfg_module); + + for (auto &[ea, cfg_func] : cfg_module->ea_to_func) { + (void) ea; + + cfg_func->lifted_function = gModule->getFunction(cfg_func->lifted_name); + if (cfg_func->lifted_function) { + cfg_func->lifted_function->setLinkage(llvm::GlobalValue::InternalLinkage); + } + } + + +// // Go try to inline +// for (const auto &func : cfg_module->functions) { +// if (func->lifted_function) { +// func->lifted_function = gModule->getFunction(func->lifted_name); +// } +// +// if (func->lifted_function) +// +// if (func->function) { +// func->function = gModule->getFunction(func->name); +// } +// +// if (func->function && +// func->lifted_function && +// func->lifted_function->hasNUses(1)) { +// +// } +// } + + std::vector to_remove; + do { + to_remove.clear(); + for (auto &func : *gModule) { + if (!func.isDeclaration()) { + continue; + } + + if (!func.hasNUsesOrMore(1)) { + to_remove.push_back(&func); + + // E.g. `__libc_init`. + } else if (func.hasInternalLinkage()) { + func.setLinkage(llvm::GlobalValue::ExternalLinkage); + } + } + + for (auto func : to_remove) { + func->eraseFromParent(); + } + } while (!to_remove.empty()); + + // This function makes removing intrinsics tricky, so if it's there, then + // we'll try to get the optimizer to inline it on our behalf, which should + // drop some references :-D + if (auto remill_used = gModule->getFunction("__remill_mark_as_used")) { + std::vector uses; + std::vector to_remove; + for (auto use : remill_used->users()) { + if (auto call = llvm::dyn_cast(use)) { + uses.push_back(call); + } + } + + for (auto call : uses) { + for (const auto &arg : call->arg_operands()) { + to_remove.push_back(llvm::dyn_cast(arg.get())); + } + call->eraseFromParent(); + } + + for (auto inst : to_remove) { + if (inst && !inst->hasNUsesOrMore(1)) { + inst->eraseFromParent(); + } + } + + if (remill_used->hasNUsesOrMore(1)) { + if (remill_used->isDeclaration()) { + remill_used->setLinkage(llvm::GlobalValue::InternalLinkage); + remill_used->removeFnAttr(llvm::Attribute::NoInline); + remill_used->addFnAttr(llvm::Attribute::InlineHint); + remill_used->addFnAttr(llvm::Attribute::AlwaysInline); + auto block = llvm::BasicBlock::Create(*gContext, "", remill_used); + (void) llvm::ReturnInst::Create(*gContext, block); + } + } + + RemoveFunction(remill_used); + } + + if (auto intrinsics = gModule->getFunction("__remill_intrinsics")) { + intrinsics->eraseFromParent(); + } + + RemoveFunction("__remill_intrinsics"); + RemoveFunction("__remill_basic_block"); + RemoveFunction("__remill_defer_inlining"); + RemoveFunction("__remill_undefined_8"); + RemoveFunction("__remill_undefined_16"); + RemoveFunction("__remill_undefined_32"); + RemoveFunction("__remill_undefined_64"); + RemoveFunction("__remill_undefined_f32"); + RemoveFunction("__remill_undefined_f64"); + RemoveFunction("__remill_undefined_f80"); + RemoveFunction("__remill_undefined_f128"); + + if (!FLAGS_keep_memops) { + RemoveFunction("__remill_read_memory_8"); + RemoveFunction("__remill_read_memory_16"); + RemoveFunction("__remill_read_memory_32"); + RemoveFunction("__remill_read_memory_64"); + RemoveFunction("__remill_read_memory_f32"); + RemoveFunction("__remill_read_memory_f64"); + RemoveFunction("__remill_read_memory_f80"); + RemoveFunction("__remill_read_memory_f128"); + + RemoveFunction("__remill_write_memory_8"); + RemoveFunction("__remill_write_memory_16"); + RemoveFunction("__remill_write_memory_32"); + RemoveFunction("__remill_write_memory_64"); + RemoveFunction("__remill_write_memory_f32"); + RemoveFunction("__remill_write_memory_f64"); + RemoveFunction("__remill_write_memory_f80"); + RemoveFunction("__remill_write_memory_f128"); + + RemoveFunction("__remill_compare_exchange_memory_8"); + RemoveFunction("__remill_fetch_and_add_8"); + RemoveFunction("__remill_fetch_and_sub_8"); + RemoveFunction("__remill_fetch_and_or_8"); + RemoveFunction("__remill_fetch_and_and_8"); + RemoveFunction("__remill_fetch_and_xor_8"); + + RemoveFunction("__remill_compare_exchange_memory_16"); + RemoveFunction("__remill_fetch_and_add_16"); + RemoveFunction("__remill_fetch_and_sub_16"); + RemoveFunction("__remill_fetch_and_or_16"); + RemoveFunction("__remill_fetch_and_and_16"); + RemoveFunction("__remill_fetch_and_xor_16"); + + RemoveFunction("__remill_compare_exchange_memory_32"); + RemoveFunction("__remill_fetch_and_add_32"); + RemoveFunction("__remill_fetch_and_sub_32"); + RemoveFunction("__remill_fetch_and_or_32"); + RemoveFunction("__remill_fetch_and_and_32"); + RemoveFunction("__remill_fetch_and_xor_32"); + + RemoveFunction("__remill_compare_exchange_memory_64"); + RemoveFunction("__remill_fetch_and_add_64"); + RemoveFunction("__remill_fetch_and_sub_64"); + RemoveFunction("__remill_fetch_and_or_64"); + RemoveFunction("__remill_fetch_and_and_64"); + RemoveFunction("__remill_fetch_and_xor_64"); + } + + if (!FLAGS_local_state_pointer) { + GlobalizeStateStructures(); + + llvm::legacy::FunctionPassManager pm(gModule.get()); + pm.add(llvm::createEarlyCSEPass(true)); + pm.add(llvm::createDeadCodeEliminationPass()); + pm.add(llvm::createCFGSimplificationPass()); + pm.doInitialization(); + for (auto &func : *gModule) { + pm.run(func); + } + pm.doFinalization(); + } + + MuteLinkerSymbol("__TMC_END__"); + MuteLinkerSymbol("__TMC_LIST__"); } } // namespace mcsema diff --git a/mcsema/BC/Optimize.h b/mcsema/BC/Optimize.h index 58199750c..7de594aeb 100644 --- a/mcsema/BC/Optimize.h +++ b/mcsema/BC/Optimize.h @@ -1,26 +1,29 @@ /* - * Copyright (c) 2017 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ -#ifndef MCSEMA_BC_OPTIMIZE_H_ -#define MCSEMA_BC_OPTIMIZE_H_ +#pragma once namespace mcsema { -void OptimizeModule(void); +struct NativeModule; + +void OptimizeModule(const NativeModule *cfg_module); + +// Remove some of the Remill intrinsics. +void CleanUpModule(const NativeModule *cfg_module); } // namespace mcsema - -#endif // MCSEMA_BC_OPTIMIZE_H_ diff --git a/mcsema/BC/Segment.cpp b/mcsema/BC/Segment.cpp index 3cde02da1..5a6dfd808 100644 --- a/mcsema/BC/Segment.cpp +++ b/mcsema/BC/Segment.cpp @@ -1,23 +1,27 @@ /* - * Copyright (c) 2017 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ +#include "mcsema/BC/Segment.h" + #include #include #include +#include #include #include #include @@ -36,9 +40,7 @@ #include #include "mcsema/Arch/Arch.h" -#include "mcsema/Arch/ABI.h" #include "mcsema/BC/Callback.h" -#include "mcsema/BC/Segment.h" #include "mcsema/BC/Util.h" #include "mcsema/CFG/CFG.h" @@ -57,25 +59,23 @@ DEFINE_string(libc_destructor, "", "function returns. For example, on GNU-based systems, this is " "typically `__libc_csu_fini`."); +DEFINE_bool(force_embed_data_refs, false, + "Should data-to-code and data-to-data cross-references be force-" + "embedded within data segments? This is a good option to enable " + "when using McSema-produced bitcode in KLEE, as it avoids doing " + "lazy cross-reference initialization."); + +DECLARE_bool(disable_aliases); + namespace mcsema { namespace { -// Returns `true` if all the bytes in `data` are zero. -static bool IsZero(const std::string &data) { - for (auto b : data) { - if (b) { - return false; - } - } - return true; -} - // Lets us decide if we can use a constant aggregate zero value, i.e. // direct LLVM to put this data into the `.bss` segment. static bool IsZero(const NativeSegment *cfg_seg) { for (const auto &cfg_seg_entry : cfg_seg->entries) { - auto &entry = cfg_seg_entry.second; - if (!entry.blob || !IsZero(entry.blob->data)) { + const auto &entry = cfg_seg_entry.second; + if (!entry.blob || !entry.blob->is_zero) { return false; } } @@ -86,19 +86,38 @@ static bool IsZero(const NativeSegment *cfg_seg) { // byte arrays, interspersed with cross-references, which will be represented // as (pointers casted to) integers. static llvm::StructType *GetSegmentType(const NativeSegment *cfg_seg) { + std::stringstream ss; + ss << cfg_seg->lifted_name << "_type"; + const auto type_name = ss.str(); + + auto seg_type = gModule->getTypeByName(type_name); + if (seg_type) { + return seg_type; + } + std::vector entry_types; auto byte_type = llvm::Type::getInt8Ty(*gContext); + + if (cfg_seg->padding) { + auto arr_type = llvm::ArrayType::get(byte_type, cfg_seg->padding); + entry_types.push_back(arr_type); + } + for (const auto &cfg_seg_entry : cfg_seg->entries) { - auto &entry = cfg_seg_entry.second; + const auto &entry = cfg_seg_entry.second; if (entry.blob) { - auto arr_type = llvm::ArrayType::get(byte_type, entry.blob->data.size()); + auto arr_type = llvm::ArrayType::get(byte_type, entry.blob->size); entry_types.push_back(arr_type); } else if (entry.xref) { - auto val_type = llvm::Type::getIntNTy( - *gContext, static_cast(entry.xref->width * 8)); - entry_types.push_back(val_type); + const auto entry_size = entry.xref->width * 8; + if (entry_size == gArch->address_size) { + entry_types.push_back(llvm::Type::getInt8PtrTy(*gContext, 0)); + } else { + entry_types.push_back(llvm::Type::getIntNTy( + *gContext, static_cast(entry_size))); + } } else { LOG(FATAL) @@ -107,17 +126,14 @@ static llvm::StructType *GetSegmentType(const NativeSegment *cfg_seg) { } } - std::stringstream ss; - ss << cfg_seg->lifted_name << "_type"; - - auto seg_type = llvm::StructType::create(entry_types, ss.str(), true); + seg_type = llvm::StructType::create(entry_types, type_name, true); CHECK(nullptr != seg_type) << "Unable to create structure type for segment " << cfg_seg->name << " beginning at " << std::hex << cfg_seg->ea; llvm::DataLayout data_layout(gModule.get()); auto seg_size = data_layout.getTypeAllocSize(seg_type); - CHECK(seg_size == cfg_seg->size) + CHECK_EQ(seg_size, (cfg_seg->size + cfg_seg->padding)) << "Size of structure type of segment " << cfg_seg->name << " is " << seg_size << " but was expected to be " << cfg_seg->size; @@ -127,80 +143,12 @@ static llvm::StructType *GetSegmentType(const NativeSegment *cfg_seg) { static llvm::GlobalValue::ThreadLocalMode ThreadLocalMode( const NativeObject *cfg_obj) { if (cfg_obj->is_thread_local) { - return llvm::GlobalValue::GeneralDynamicTLSModel; + return llvm::GlobalValue::InitialExecTLSModel; } else { return llvm::GlobalValue::NotThreadLocal; } } -static llvm::GlobalVariable *GlobalVariable( - const NativeSegment *cfg_seg, std::string lifted_name) { - auto seg_type = GetSegmentType(cfg_seg); - - auto seg_var = new llvm::GlobalVariable( - *gModule, seg_type, cfg_seg->is_read_only, - llvm::GlobalValue::InternalLinkage, nullptr, - lifted_name, nullptr, ThreadLocalMode(cfg_seg)); - - if (cfg_seg->is_exported) { - seg_var->setLinkage(llvm::GlobalValue::ExternalLinkage); - } - - return seg_var; -} - -// Declare a data segment, and return a global value pointing to that segment. -static void DeclareSegment(const NativeSegment *cfg_seg) { - cfg_seg->seg_var = gModule->getGlobalVariable(cfg_seg->lifted_name); - - if (cfg_seg->seg_var) { - // If the variable is exported and zero initialized (not having xrefs), - // No need to initialize these variables - if (cfg_seg->is_exported && cfg_seg->seg_var->hasExternalLinkage()) { - cfg_seg->needs_initializer = !IsZero(cfg_seg); - } else { - // If there is a variable with the same name, rename the variable - // and set the needs_initializer flag; - std::stringstream ss; - ss << "internal_" << cfg_seg->lifted_name; - cfg_seg->seg_var = GlobalVariable(cfg_seg, ss.str()); - - LOG(ERROR) - << "Segment variable '" << cfg_seg->lifted_name - << "' was already defined"; - - cfg_seg->needs_initializer = true; - } - } else { - cfg_seg->seg_var = GlobalVariable(cfg_seg, cfg_seg->lifted_name); - } -} - -// Declare named variables that point into the data segment. The program being -// lifted may have cross-references that addresses meaningfully named (global) -// variables within a segment, so we want to try to preserve those names, -// treating them as GEPs into the segment's data. -static void DeclareVariables(const NativeModule *cfg_module) { - for (auto &entry : cfg_module->ea_to_var) { - auto cfg_var = reinterpret_cast( - entry.second->Get()); - - if (cfg_var && cfg_var->is_external) { - continue; - } - - CHECK(cfg_var && cfg_var->segment && !cfg_var->name.empty()) - << "Invalid variable at " << std::hex << entry.first; - - auto cfg_seg = cfg_var->segment; - CHECK(cfg_var->ea >= cfg_seg->ea) - << "Variable " << cfg_var->name << " at " << std::hex << cfg_var->ea - << " is incorrectly assigned to the segment " << cfg_seg->name; - - cfg_var->address = LiftEA(cfg_seg, cfg_var->ea); - } -} - // Create a McSema-specific constructor/destructor function, and add it to the // corresponding LLVM-specific array. static llvm::Function *CreateMcSemaInitFiniImpl( @@ -274,15 +222,13 @@ static llvm::Function *CreateMcSemaInitFiniImpl( static llvm::Function *GetOrCreateMcSemaConstructor(void) { static llvm::Function *gInitFunc = nullptr; - if (!gInitFunc) { - gInitFunc = CreateMcSemaInitFiniImpl( - "__mcsema_constructor", "llvm.global_ctors"); - - // Make sure that the `__mcsema_constructor` calls the xref initializer - // as it's first thing. - llvm::IRBuilder<> ir(&(gInitFunc->front().front())); - ir.CreateCall(GetOrCreateMcSemaInitializer()); + if (gInitFunc) { + return gInitFunc; } + + gInitFunc = CreateMcSemaInitFiniImpl( + "__mcsema_constructor", "llvm.global_ctors"); + return gInitFunc; } @@ -313,28 +259,33 @@ static llvm::Function *GetOrCreateMcSemaDestructor(void) { // handle them by emulating this runtime initialization. We create a special // constructor function of our own, `__mcsema_constructor`, that will contain // code that can do these initializations. -static void LazyInitXRef(const NativeXref *xref, llvm::Type *extern_addr_type, +static void LazyInitXRef(const NativeXref *xref, llvm::Constant *target_addr_const) { auto init_func = GetOrCreateMcSemaInitializer(); llvm::BasicBlock *block = &init_func->back(); llvm::IRBuilder<> ir(block); ir.SetInsertPoint(&block->front()); - auto seg = xref->segment->seg_var; - if (seg->isConstant()) { + if (xref->segment->is_external) { LOG(ERROR) + << "Ignoring lazy initialization of cross-reference to " + << std::hex << xref->target_ea << " at " << xref->ea + << " in external segment '" << xref->segment->name << "' at " + << xref->segment->ea << std::dec; + return; + } + + auto seg = llvm::dyn_cast(xref->segment->Pointer()); + if (seg->isConstant()) { + LOG(WARNING) << "Marking " << seg->getName().str() << " as non-constant to " - << "support lazy initialization of reference to " << xref->target_name - << " from " << std::hex << xref->ea; + << "support lazy initialization of reference to " << std::hex + << xref->target_ea << " from " << xref->ea << std::dec; seg->setConstant(false); } - if (!target_addr_const || target_addr_const->isNullValue()) { - LOG_IF(FATAL, !xref->var) - << "Cannot perform lazy relocation of non-variable cross-reference " - << "from " << std::hex << xref->ea << " to " << xref->target_ea - << std::dec << " (" << xref->target_name << ")"; - target_addr_const = xref->var->address; + if (target_addr_const->isNullValue()) { + return; } llvm::Value *target_addr = target_addr_const; @@ -343,8 +294,8 @@ static void LazyInitXRef(const NativeXref *xref, llvm::Type *extern_addr_type, case NativeXref::kAbsoluteFixup: { CHECK(!xref->var || !xref->var->is_thread_local) << "Cannot do absolute fixup from " << std::hex << xref->ea - << " to thread-local variable " << xref->target_name << " at " - << std::hex << xref->target_ea; + << " to thread-local variable at " + << std::hex << xref->target_ea << std::dec; // `target_addr` already has the right value. break; } @@ -352,13 +303,12 @@ static void LazyInitXRef(const NativeXref *xref, llvm::Type *extern_addr_type, case NativeXref::kThreadLocalOffsetFixup: { CHECK(xref->var != nullptr) << "Non-variable thread-local cross-reference from " - << std::hex << xref->ea << " to " << xref->target_ea << std::dec - << " (" << xref->target_name << ")"; + << std::hex << xref->ea << " to " << xref->target_ea << std::dec; CHECK(xref->var->is_thread_local) << "Cannot do thread-local fixup from " << std::hex << xref->ea - << " to non-thread-local variable " << xref->target_name << " at " - << std::hex << xref->target_ea; + << " to non-thread-local variable at " + << std::hex << xref->target_ea << std::dec; static llvm::Value *thread_base = nullptr; if (!thread_base) { @@ -369,40 +319,45 @@ static void LazyInitXRef(const NativeXref *xref, llvm::Type *extern_addr_type, } } - if (xref->width < gArch->address_size) { - target_addr = ir.CreateTrunc(target_addr, extern_addr_type); - } - - auto addr_of_xref = LiftEA(xref->segment, xref->ea); - auto ptr_to_xref = ir.CreateIntToPtr( - addr_of_xref, llvm::PointerType::get(extern_addr_type, 0)); - - ir.CreateStore(target_addr, ptr_to_xref); + auto addr_of_xref = LiftXrefInData(xref->segment, xref->ea, false); + ir.CreateStore(target_addr, addr_of_xref); } // Fill in the contents of the data segment. -static llvm::Constant *FillDataSegment(const NativeSegment *cfg_seg, +static llvm::Constant *FillDataSegment(const NativeModule *cfg_module, + const NativeSegment *cfg_seg, llvm::StructType *seg_type) { if (IsZero(cfg_seg)) { return llvm::ConstantAggregateZero::get(seg_type); } - unsigned i = 0; std::vector entry_vals; - for (const auto &cfg_seg_entry : cfg_seg->entries) { + // We might add some padding on the beginning of this + unsigned i = 0; + if (cfg_seg->padding) { + auto byte_type = llvm::Type::getInt8Ty(*gContext); + auto arr_type = llvm::ArrayType::get(byte_type, cfg_seg->padding); + entry_vals.push_back(llvm::ConstantAggregateZero::get(arr_type)); + ++i; + } + + for (auto &cfg_seg_entry : cfg_seg->entries) { auto &entry = cfg_seg_entry.second; auto entry_type = seg_type->getContainedType(i++); // This entry is an opaque sequence of bytes. if (entry.blob) { - if (IsZero(entry.blob->data)) { + if (entry.blob->is_zero) { entry_vals.push_back(llvm::ConstantAggregateZero::get(entry_type)); - } else { + } else if (auto bytes = cfg_module->FindBytes(entry.blob->ea, entry.blob->size); + bytes && bytes.Size() == entry.blob->size) { + + const llvm::StringRef str_data(bytes.ToString().data(), bytes.Size()); auto data = llvm::ConstantDataArray::getString( - *gContext, entry.blob->data, false /* AddNull */); + *gContext, str_data, false /* AddNull */); CHECK(data->getType() == entry_type) << "Type mismatch: Got " @@ -411,94 +366,91 @@ static llvm::Constant *FillDataSegment(const NativeSegment *cfg_seg, << remill::LLVMThingToString(entry_type); entry_vals.push_back(data); + + } else { + LOG(ERROR) + << "Could not find data backing " << std::hex << entry.blob->ea + << std::dec << " in segment " << cfg_seg->name; + entry_vals.push_back(llvm::ConstantAggregateZero::get(entry_type)); } // This entry is a cross-reference. - } else { - CHECK(nullptr != entry.xref) - << "Empty entry at " << std::hex << entry.ea - << " in segment " << cfg_seg->name; + } else if (entry.xref) { - auto val_size = static_cast(entry.xref->width * 8); - auto val_type = llvm::Type::getIntNTy(*gContext, val_size); auto &xref = entry.xref; llvm::Constant *val = nullptr; - CHECK(val_size <= gArch->address_size) + CHECK((entry.xref->width * 8) <= gArch->address_size) << "Cross-reference at " << std::hex << xref->ea << " to " << std::hex << xref->target_ea << " is too wide at " << entry.xref->width << " bytes"; - CHECK(val_type == entry_type) - << entry.xref->width << "-byte cross-reference at " << std::hex - << xref->ea << " to " << std::hex << xref->target_ea - << " doesn't match the type of the segment entry " - << remill::LLVMThingToString(entry_type); + auto be_lazy = false; // Pointer to a (possibly external) function. - if (auto cfg_func = xref->func) { - if (cfg_func->is_external) { - val = gModule->getFunction(cfg_func->name); - } else { - val = GetNativeToLiftedCallback(cfg_func); - } - - val = llvm::ConstantExpr::getPtrToInt(val, gWordType); - CHECK(val != nullptr) - << "Can't insert cross reference to function " - << cfg_func->name << " at " << std::hex << cfg_seg_entry.first - << " in segment " << cfg_seg->name; + if (xref->func) { + const auto cfg_func = xref->func->Get(); + val = cfg_func->Pointer(); // Pointer to a global (possibly external) variable. - } else if (auto cfg_var = xref->var) { - if (cfg_var->is_external || cfg_var->is_thread_local) { - LOG(INFO) - << "Adding runtime initializer for cross reference to variable " - << cfg_var->name << " at " << std::hex << cfg_seg_entry.first - << " in segment " << cfg_seg->name; - LazyInitXRef(xref.get(), val_type, val); - val = llvm::Constant::getNullValue(gWordType); - } else { - val = cfg_var->address; - } - - CHECK(val != nullptr) - << "Can't insert cross reference to variable " - << cfg_var->name << " at " << std::hex << cfg_seg_entry.first - << " in segment " << cfg_seg->name; + } else if (xref->var) { + const auto cfg_var = xref->var->Get(); + val = cfg_var->Pointer(); + be_lazy = cfg_var->is_external || cfg_var->is_thread_local; // Pointer to an unnamed location inside of a data segment. + } else if (xref->target_segment) { + const auto target_seg = xref->target_segment; + val = LiftXrefInData(target_seg, xref->target_ea, false); + be_lazy = target_seg->is_external || target_seg->is_thread_local; + } else { - val = LiftEA(xref->target_segment, xref->target_ea); - } - - // Scale and add the value in. We need to fit it to its original width. - if (val_size > gArch->address_size) { - val = llvm::ConstantExpr::getZExt(val, val_type); - - // Pointer truncation is generating the weird code for static - // initialization of segment variables which is causing problem - // during recompilations. Use Lazy initialization of the variable - // segXXXX__gcc_except_table - // Wrongly generated static initializer looks like following: - // .long _ZTI12out_of_range&-1 - // .long _ZTI17special_condition&-1 - } else if (val_size < gArch->address_size) { - if (xref->var != nullptr) { - LazyInitXRef(xref.get(), val_type, val); - val = llvm::ConstantInt::getNullValue(val_type); + val = llvm::ConstantInt::get(gWordType, xref->target_ea); + if (entry_type->isPointerTy()) { + val = llvm::ConstantExpr::getIntToPtr(val, entry_type); } else { - val = llvm::ConstantExpr::getTrunc(val, val_type); + val = llvm::ConstantExpr::getIntToPtr( + val, llvm::Type::getInt8PtrTy(*gContext)); } } - CHECK(val->getType() == entry_type) + auto val_type = llvm::dyn_cast(val->getType()); + CHECK_NOTNULL(val_type); + + if (val_type->getAddressSpace()) { + val_type = llvm::PointerType::get(val_type->getElementType(), 0); + val = llvm::ConstantExpr::getAddrSpaceCast(val, val_type); + } + + if (entry_type->isIntegerTy()) { + val = llvm::ConstantExpr::getPtrToInt(val, gWordType); + if ((gArch->address_size / 8) > xref->width) { + val = llvm::ConstantExpr::getTrunc(val, entry_type); + be_lazy = true; + } + + } else if (val_type != entry_type) { + CHECK(entry_type->isPointerTy()); + val = llvm::ConstantExpr::getBitCast(val, entry_type); + } + + if (be_lazy && !FLAGS_force_embed_data_refs) { + LazyInitXRef(xref.get(), val); + val = llvm::Constant::getNullValue(entry_type); + } + + CHECK_EQ(val->getType(), entry_type) << "Type mismatch: Got " << remill::LLVMThingToString(val->getType()) << " but expected " << remill::LLVMThingToString(entry_type); entry_vals.push_back(val); + + } else { + LOG(FATAL) + << "Empty entry at " << std::hex << entry.ea + << " in segment " << cfg_seg->name; } } @@ -506,68 +458,196 @@ static llvm::Constant *FillDataSegment(const NativeSegment *cfg_seg, } // Fill all the data segments in a given region. -static void FillSegment(const NativeSegment *cfg_seg) { - auto seg = cfg_seg->seg_var; - if (cfg_seg->needs_initializer) { - CHECK_NOTNULL(seg); - auto seg_type = llvm::dyn_cast(remill::GetValueType(seg)); - - // This might be null if there are two lifted variables with same name and one of them is exported - // and the exported variable is having xrefs or notnull. - CHECK_NOTNULL(seg_type); - seg->setInitializer(FillDataSegment(cfg_seg, seg_type)); +static void FillSegment(const NativeModule *cfg_module, + const NativeSegment *cfg_seg) { + if (cfg_seg->entries.empty()) { + CHECK(cfg_seg->is_external && !cfg_seg->is_exported); + return; } + + auto seg = llvm::dyn_cast(cfg_seg->Pointer()); + CHECK_NOTNULL(seg); + if (seg->hasInitializer()) { + return; // Already initialized, e.g. due to `->Get()`. + } + + auto seg_type = llvm::dyn_cast(remill::GetValueType(seg)); + + // This might be null if there are two lifted variables with same name and + // one of them is exported and the exported variable is having xrefs or + // notnull. + CHECK_NOTNULL(seg_type); + seg->setInitializer(FillDataSegment(cfg_module, cfg_seg, seg_type)); } } // namespace + +llvm::Constant *NativeVariable::Pointer(void) const { + CHECK(!is_external); + CHECK_NOTNULL(segment); + const auto cfg_seg = segment->Get(); + CHECK(!cfg_seg->is_external); + + const auto &alias_name = is_exported && !name.empty() ? name : lifted_name; + auto alias = gModule->getNamedAlias(alias_name); + if (alias) { + return alias; + } + + auto ret = LiftXrefInData(segment, ea, false /* cast_to_int */); + if (!FLAGS_disable_aliases && is_exported) { + auto ptr_type = llvm::dyn_cast(ret->getType()); + auto alias = llvm::GlobalAlias::create( + ptr_type->getElementType(), ptr_type->getAddressSpace(), + llvm::GlobalValue::ExternalLinkage, alias_name, ret, gModule.get()); + ret = alias; + + module->AddNameToAddress(alias_name, ea); + + if (cfg_seg->is_thread_local) { + alias->setThreadLocalMode(llvm::GlobalValue::InitialExecTLSModel); + } + } + return ret; +} + +llvm::Constant *NativeVariable::Address(void) const { + return llvm::ConstantExpr::getPtrToInt(Pointer(), gWordType); +} + +llvm::Constant *NativeSegment::Address(void) const { + auto ret = llvm::ConstantExpr::getPtrToInt(Pointer(), gWordType); + if (padding) { + ret = llvm::ConstantExpr::getAdd( + ret, llvm::ConstantInt::get(gWordType, padding)); + } + return ret; +} + +llvm::Constant *NativeSegment::Pointer(void) const { + const auto &var_name = (is_exported || is_external) ? name : lifted_name; + + auto lifted_var = gModule->getGlobalVariable( + var_name, true /* AllowInternal */); + + if (lifted_var) { + return lifted_var; + } + + module->AddNameToAddress(var_name, ea); + + if (is_external) { + LOG(INFO) + << "Adding external segment " << name << " at " + << std::hex << ea << std::dec; + + llvm::Type* var_type = nullptr; + + CHECK_NE(0, size) + << "The size of the external variable '" << name << "' at " + << std::hex << ea << std::dec << " cannot be zero"; + + // Handle external variables of up to 128 bits as intgers + // Anything else is treated as an array of bytes + switch(size) { + case 0: + // Why is this zero length? This should never happen + // Attempt a fix and output a warning + LOG(ERROR) + << "The variable '" << name << "' at " << std::hex << ea + << std::dec << " has size of zero; Assuming it should be size 1"; + var_type = llvm::Type::getInt8Ty(*gContext); + break; + case 1: // 8 bit integer + case 2: // 16 bit integer + case 4: // 32 bit integer + case 8: // 64 bit integer + case 16: // 128 bit integer + var_type = llvm::Type::getIntNTy( + *gContext, static_cast(size * 8u)); + break; + + // An array of bytes + default: { + auto byte_type = llvm::Type::getInt8Ty(*gContext); + var_type = llvm::ArrayType::get( + byte_type, static_cast(size)); + break; + } + } + + lifted_var = new llvm::GlobalVariable( + *gModule, var_type, false, llvm::GlobalValue::ExternalLinkage, + nullptr, var_name, nullptr, ThreadLocalMode(this)); + + } else { + const auto linkage = is_exported ? + llvm::GlobalValue::ExternalLinkage : + llvm::GlobalValue::InternalLinkage; + LOG(INFO) + << "Adding internal segment " << name; + + lifted_var = new llvm::GlobalVariable( + *gModule, GetSegmentType(this), is_read_only, + linkage, nullptr, var_name, nullptr, + ThreadLocalMode(this)); + } + + if (ea) { + const auto alignment = 1u << __builtin_ctzl(ea - padding); +#if LLVM_VERSION_NUMBER >= LLVM_VERSION(10, 0) + lifted_var->setAlignment(llvm::MaybeAlign(alignment)); +#else + lifted_var->setAlignment(alignment); +#endif + } + + return lifted_var; +} + llvm::Function *GetOrCreateMcSemaInitializer(void) { static llvm::Function *gInitFunc = nullptr; - if (!gInitFunc) { - LOG(INFO) - << "Creating __mcsema_early_init function to pre-initialize runtime."; - - gInitFunc = llvm::Function::Create( - llvm::FunctionType::get(llvm::Type::getVoidTy(*gContext), false), - llvm::GlobalValue::InternalLinkage, - "__mcsema_early_init", gModule.get()); - - auto bool_type = llvm::Type::getInt1Ty(*gContext); - auto check_var = new llvm::GlobalVariable( - *gModule, bool_type, false, llvm::GlobalValue::InternalLinkage, - llvm::Constant::getNullValue(bool_type)); - - auto entry = llvm::BasicBlock::Create(*gContext, "", gInitFunc); - auto already_done = llvm::BasicBlock::Create(*gContext, "", gInitFunc); - auto lazy_xref = llvm::BasicBlock::Create(*gContext, "", gInitFunc); - - llvm::IRBuilder<> ir(entry); - - auto guard = ir.CreateLoad(check_var, true); - ir.CreateCondBr(guard, already_done, lazy_xref); - - ir.SetInsertPoint(already_done); - ir.CreateRetVoid(); - - // Last basic block will have lazy xrefs injected into it. - ir.SetInsertPoint(lazy_xref); - ir.CreateStore(llvm::ConstantInt::get(bool_type, 1), check_var, true); - ir.CreateRetVoid(); + if (gInitFunc) { + return gInitFunc; } + + LOG(INFO) + << "Creating __mcsema_early_init function to pre-initialize runtime."; + + gInitFunc = llvm::Function::Create( + llvm::FunctionType::get(llvm::Type::getVoidTy(*gContext), false), + llvm::GlobalValue::InternalLinkage, + "__mcsema_early_init", gModule.get()); + + auto bool_type = llvm::Type::getInt1Ty(*gContext); + auto check_var = new llvm::GlobalVariable( + *gModule, bool_type, false, llvm::GlobalValue::InternalLinkage, + llvm::Constant::getNullValue(bool_type)); + + auto entry = llvm::BasicBlock::Create(*gContext, "", gInitFunc); + auto already_done = llvm::BasicBlock::Create(*gContext, "", gInitFunc); + auto lazy_xref = llvm::BasicBlock::Create(*gContext, "", gInitFunc); + + llvm::IRBuilder<> ir(entry); + + auto guard = ir.CreateLoad(check_var, true); + ir.CreateCondBr(guard, already_done, lazy_xref); + + ir.SetInsertPoint(already_done); + ir.CreateRetVoid(); + + // Last basic block will have lazy xrefs injected into it. + ir.SetInsertPoint(lazy_xref); + ir.CreateStore(llvm::ConstantInt::get(bool_type, 1), check_var, true); + ir.CreateRetVoid(); + return gInitFunc; } -void DeclareDataSegments(const NativeModule *cfg_module) { - for (auto &cfg_seg_entry : cfg_module->segments) { - DeclareSegment(cfg_seg_entry.second.get()); - } - - DeclareVariables(cfg_module); -} - void DefineDataSegments(const NativeModule *cfg_module) { - for (auto &cfg_seg_entry : cfg_module->segments) { - FillSegment(cfg_seg_entry.second.get()); + for (const auto &cfg_seg : cfg_module->segments) { + FillSegment(cfg_module, cfg_seg.get()); } } @@ -587,7 +667,7 @@ bool DetectAndSetInitFiniCode(const NativeModule *cfg_module) { for (const auto &cfg_func : cfg_module->ea_to_func) { for (auto &init_fini_func : init_fini_pairs) { - if (cfg_func.second->name == init_fini_func.first) { + if (cfg_func.second->name == init_fini_func.first) { init_fini_func.second = true; } } @@ -616,19 +696,19 @@ void CallInitFiniCode(const NativeModule *cfg_module) { } for (const auto &entry : cfg_module->ea_to_func) { - auto &cfg_func = entry.second; + const auto &cfg_func = entry.second; llvm::Function *callback = nullptr; llvm::Instruction *insert_point = nullptr; if (FLAGS_libc_constructor.size() && FLAGS_libc_constructor == cfg_func->name) { - callback = GetNativeToLiftedCallback(cfg_func.get()); + callback = llvm::dyn_cast(cfg_func->Pointer()); auto init_func = GetOrCreateMcSemaConstructor(); insert_point = &(init_func->front().back()); } else if (FLAGS_libc_destructor.size() && FLAGS_libc_destructor == cfg_func->name) { - callback = GetNativeToLiftedCallback(cfg_func.get()); + callback = llvm::dyn_cast(cfg_func->Pointer()); auto fini_func = GetOrCreateMcSemaDestructor(); insert_point = &(fini_func->front().front()); } diff --git a/mcsema/BC/Segment.h b/mcsema/BC/Segment.h index cf4006111..abd899b24 100644 --- a/mcsema/BC/Segment.h +++ b/mcsema/BC/Segment.h @@ -1,22 +1,21 @@ /* - * Copyright (c) 2017 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ -#ifndef MCSEMA_BC_SEGMENT_H_ -#define MCSEMA_BC_SEGMENT_H_ - +#pragma once namespace llvm { class Function; @@ -27,10 +26,8 @@ struct NativeModule; llvm::Function *GetOrCreateMcSemaInitializer(void); -void DeclareDataSegments(const NativeModule *cfg_module); +//void DeclareDataSegments(const NativeModule *cfg_module); void DefineDataSegments(const NativeModule *cfg_module); void CallInitFiniCode(const NativeModule *cfg_module); } // namespace mcsema - -#endif // MCSEMA_BC_SEGMENT_H_ diff --git a/mcsema/BC/Util.cpp b/mcsema/BC/Util.cpp index f7943f68b..72abe51ce 100644 --- a/mcsema/BC/Util.cpp +++ b/mcsema/BC/Util.cpp @@ -1,20 +1,24 @@ /* - * Copyright (c) 2017 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ +#include "mcsema/BC/Util.h" + #include +#include #include @@ -26,51 +30,205 @@ #include #include -#include "remill/Arch/Arch.h" -#include "remill/Arch/Name.h" -#include "remill/BC/Util.h" -#include "remill/BC/Version.h" -#include "remill/OS/OS.h" +#include +#include +#include +#include +#include +#include #include "mcsema/Arch/Arch.h" -#include "mcsema/BC/Util.h" + +DEFINE_bool(disable_aliases, false, "Disable using global aliases for accessing data/registers in the bitcode"); namespace mcsema { std::shared_ptr gContext = nullptr; llvm::IntegerType *gWordType = nullptr; +uint64_t gWordMask = 0; std::unique_ptr gModule = nullptr; +llvm::Constant *gZero = nullptr; llvm::Value *GetConstantInt(unsigned size, uint64_t value) { - return llvm::ConstantInt::get(llvm::Type::getIntNTy(*gContext, size), value); + return llvm::ConstantInt::get( + llvm::Type::getIntNTy(*gContext, size), value); } -// Return the type of a lifted function. -llvm::FunctionType *LiftedFunctionType(void) { - static llvm::FunctionType *func_type = nullptr; - if (!func_type) { - func_type = remill::LiftedFunctionType(gModule.get()); - } - return func_type; +// Get a lifted representation of a reference (in code) to `ea`. +llvm::Constant *LiftXrefInCode(uint64_t ea) { + return llvm::ConstantExpr::getAdd( + gZero, + llvm::ConstantInt::get(gWordType, ea & gWordMask, false)); } -// Translate `ea` into an LLVM value that is an address that points into the -// lifted segment associated with `seg`. -llvm::Constant *LiftEA(const NativeSegment *cfg_seg, uint64_t ea) { +// Get a lifted representation of a reference (in data) to `ea`. +llvm::Constant *LiftXrefInData(const NativeSegment *cfg_seg, uint64_t ea, + bool cast_to_int) { CHECK(cfg_seg != nullptr); CHECK(cfg_seg->ea <= ea); CHECK(ea < (cfg_seg->ea + cfg_seg->size)); - auto seg = gModule->getGlobalVariable(cfg_seg->lifted_name, true); - CHECK(seg != nullptr) - << "Cannot find global variable " << cfg_seg->lifted_name - << " for segment " << cfg_seg->name - << " when trying to lift EA " << std::hex << ea; + std::stringstream ss; + ss << "data_" << std::hex << ea; + auto alias_name = ss.str(); - auto offset = ea - cfg_seg->ea; - return llvm::ConstantExpr::getAdd( - llvm::ConstantExpr::getPtrToInt(seg, gWordType), - llvm::ConstantInt::get(gWordType, offset)); + llvm::Constant *ptr = nullptr; + if (auto alias = gModule->getNamedAlias(alias_name); alias) { + ptr = alias; + + } else { + auto seg_var = llvm::dyn_cast( + cfg_seg->Get()->Pointer()); + + auto seg_type = remill::GetValueType(seg_var); + llvm::DataLayout dl(gModule.get()); + + llvm::SmallVector gep_index_list; + auto i32_type = llvm::Type::getInt32Ty(*gContext); + gep_index_list.push_back(llvm::ConstantInt::get(i32_type, 0)); + const auto goal_offset = (ea - cfg_seg->ea) + cfg_seg->padding; + auto [offset, type] = remill::BuildIndexes( + dl, seg_type, 0, goal_offset, gep_index_list); + + ptr = seg_var; + if (offset) { + (void) type; + ptr = llvm::ConstantExpr::getInBoundsGetElementPtr( + seg_type, seg_var, gep_index_list); + } + + if (offset < goal_offset) { + auto i8_type = llvm::Type::getInt8Ty(*gContext); + ptr = llvm::ConstantExpr::getBitCast( + ptr, llvm::PointerType::get(i8_type, 0)); + ptr = llvm::ConstantExpr::getInBoundsGetElementPtr( + i8_type, ptr, + llvm::ConstantInt::get(i32_type, goal_offset - offset, false)); + } + + if (!FLAGS_disable_aliases && !cfg_seg->is_external) { + auto ptr_type = llvm::dyn_cast(ptr->getType()); + ptr = llvm::GlobalAlias::create( + ptr_type->getElementType(), ptr_type->getAddressSpace(), + seg_var->getLinkage(), alias_name, ptr, gModule.get()); + } + } + + if (cast_to_int) { + return llvm::ConstantExpr::getPtrToInt(ptr, gWordType); + } else { + return ptr; + } +} + +// Create a global register state pointer to pass to lifted functions. +llvm::Constant *GetStatePointer(void) { + static llvm::Constant *state_ptr = nullptr; + if (state_ptr) { + return state_ptr; + } + + auto state_type = gArch->StateStructType(); + + // State is initialized with zeroes. Each callback/entrypoint set + // appropriate value to stack pointer. This is needed because of + // thread_local + auto state_init = llvm::ConstantAggregateZero::get(state_type); + const auto state_ptr_var = new llvm::GlobalVariable( + *gModule, state_type, false, llvm::GlobalValue::ExternalLinkage, + state_init, "__mcsema_reg_state", nullptr, + llvm::GlobalValue::InitialExecTLSModel); + + state_ptr = state_ptr_var; + if (state_ptr_var->getType()->getPointerAddressSpace() != 0) { + state_ptr = llvm::ConstantExpr::getAddrSpaceCast( + state_ptr, llvm::PointerType::get(state_type, 0)); + } + + return state_ptr; +} + +// Return the address of the base of the TLS data. +llvm::Value *GetTLSBaseAddress(llvm::IRBuilder<> &ir) { + enum { + kGSAddressSpace = 256U, + kFSAddressSpace = 257U, + + // From inside of the TEB. + kWin32TLSPointerIndex = 0x2c, + kWin64TLSPointerIndex = 0x58 + }; + + if (gArch->IsAArch64()) { + +#if LLVM_VERSION(3, 7) >= LLVM_VERSION_NUMBER + LOG(ERROR) + << "LLVM 3.7 and below have no thread pointer-related " + << "intrinsics; using NULL as the base of TLS."; + return llvm::ConstantInt::get(gWordType, 0); +#else +# if LLVM_VERSION(3, 8) >= LLVM_VERSION_NUMBER + if (gArch->IsAArch64()) { + LOG(ERROR) + << "Assuming the `llvm.arm.thread.pointer` intrinsic gets us the base " + << "of thread-local storage."; + auto func = llvm::Intrinsic::getDeclaration( + gModule.get(), llvm::Intrinsic::arm_thread_pointer); + if (func) { + return ir.CreatePtrToInt(ir.CreateCall(func), gWordType); + } + } +# endif + LOG(ERROR) + << "Assuming the `thread.pointer` intrinsic gets us the base " + << "of thread-local storage."; + auto func = llvm::Intrinsic::getDeclaration( + gModule.get(), llvm::Intrinsic::thread_pointer); + return ir.CreatePtrToInt(ir.CreateCall(func), gWordType); +#endif + + // 64-bit x86. + } else if (gArch->IsAMD64()) { + llvm::ConstantInt *base = nullptr; + unsigned addr_space = 0; + if (remill::kOSWindows == gArch->os_name) { + base = llvm::ConstantInt::get(gWordType, kWin64TLSPointerIndex); + addr_space = kGSAddressSpace; + } else if (remill::kOSLinux == gArch->os_name) { + base = llvm::ConstantInt::get(gWordType, 0); + addr_space = kFSAddressSpace; + } + + if (base) { + auto tls_base_ptr = ir.CreateIntToPtr( + base, llvm::PointerType::get(gWordType, addr_space)); + return ir.CreateLoad(tls_base_ptr); + } + + // 32-bit x86. + } else if (gArch->IsX86()) { + llvm::ConstantInt *base = nullptr; + unsigned addr_space = 0; + if (remill::kOSWindows == gArch->os_name) { + base = llvm::ConstantInt::get(gWordType, kWin32TLSPointerIndex); + addr_space = kFSAddressSpace; + } else if (remill::kOSLinux == gArch->os_name) { + base = llvm::ConstantInt::get(gWordType, 0); + addr_space = kGSAddressSpace; + } + + if (base) { + auto tls_base_ptr = ir.CreateIntToPtr( + base, llvm::PointerType::get(gWordType, addr_space)); + return ir.CreateLoad(tls_base_ptr); + } + } + + LOG(FATAL) + << "Cannot generate code to find the thread base pointer for arch " + << remill::GetArchName(gArch->arch_name) << " and OS " + << remill::GetOSName(gArch->os_name); + return nullptr; } } // namespace mcsema diff --git a/mcsema/BC/Util.h b/mcsema/BC/Util.h index 2133a3558..255ba899b 100644 --- a/mcsema/BC/Util.h +++ b/mcsema/BC/Util.h @@ -1,21 +1,21 @@ /* - * Copyright (c) 2017 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ -#ifndef MCSEMA_BC_UTIL_H_ -#define MCSEMA_BC_UTIL_H_ +#pragma once #include #include @@ -43,17 +43,22 @@ struct NativeSegment; extern std::shared_ptr gContext; extern llvm::IntegerType *gWordType; extern std::unique_ptr gModule; - +extern llvm::Constant *gZero; +extern uint64_t gWordMask; llvm::Value *GetConstantInt(unsigned size, uint64_t value); -// Return the type of a lifted function. -llvm::FunctionType *LiftedFunctionType(void); +// Get a lifted representation of a reference (in code) to `ea`. +llvm::Constant *LiftXrefInCode(uint64_t ea); -// Translate `ea` into an LLVM value that is an address that points into the -// lifted segment associated with `seg`. -llvm::Constant *LiftEA(const NativeSegment *seg, uint64_t ea); +// Get a lifted representation of a reference (in data) to `ea`. +llvm::Constant *LiftXrefInData(const NativeSegment *cfg_seg, uint64_t ea, + bool cast_to_int=true); + +// Create a global register state pointer to pass to lifted functions. +llvm::Constant *GetStatePointer(void); + +// Return the address of the base of the TLS data. +llvm::Value *GetTLSBaseAddress(llvm::IRBuilder<> &ir); } // namespace mcsema - -#endif // MCSEMA_BC_UTIL_H_ diff --git a/mcsema/CFG/CFG.cpp b/mcsema/CFG/CFG.cpp index 0468c5837..056206e58 100644 --- a/mcsema/CFG/CFG.cpp +++ b/mcsema/CFG/CFG.cpp @@ -1,17 +1,18 @@ /* - * Copyright (c) 2017 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ #include @@ -19,6 +20,7 @@ #include #include +#include #include #include #include @@ -34,8 +36,13 @@ #include #include -#include "remill/Arch/Arch.h" -#include "remill/OS/OS.h" +#include +#include + +#include +#include +#include +#include #include "mcsema/Arch/Arch.h" #include "mcsema/BC/External.h" @@ -44,6 +51,13 @@ DECLARE_bool(explicit_args); +DEFINE_bool(disable_adjacent_segment_merging, false, + "Should we disable merging of adjacent segments? Adjacent segment " + "merging is performed in order to improve the reliability of cross-" + "reference lifting and comparisons, e.g. if a pointer comparison is " + "used to test if a loop should terminate, then sometimes that " + "pointer might be one element past the end of a segment."); + namespace mcsema { namespace { @@ -73,25 +87,30 @@ static std::string LiftedSegmentName(const Segment &cfg_segment) { if (cfg_segment.has_variable_name()) { auto has_name = !cfg_segment.variable_name().empty(); LOG_IF(ERROR, !has_name) - << "CFG variable segment " << cfg_segment.name() << " at " << std::hex - << cfg_segment.ea() << std::dec << " has an empty name."; + << "CFG variable segment " << cfg_segment.name() << " at " << std::hex + << cfg_segment.ea() << std::dec << " has an empty name."; if (has_name && cfg_segment.is_exported()) { ss << cfg_segment.variable_name(); } else { ss << "seg_var_" << std::hex << cfg_segment.ea() - << "_" << SaneName(cfg_segment.variable_name()); + << "_" << SaneName(cfg_segment.variable_name()) + << "_" << cfg_segment.data().size(); } } else { ss << "seg_" << std::hex << cfg_segment.ea() - << "_" << SaneName(cfg_segment.name()); + << "_" << SaneName(cfg_segment.name()) + << "_" << cfg_segment.data().size(); } return ss.str(); } static std::string LiftedVarName(const Variable &cfg_var) { std::stringstream ss; - ss << "var_" << std::hex << cfg_var.ea() << "_" << SaneName(cfg_var.name()); + ss << "data_" << std::hex << cfg_var.ea(); + if (cfg_var.has_name()) { + ss << "_" << SaneName(cfg_var.name()); + } return ss.str(); } @@ -102,25 +121,12 @@ static std::string ExternalFuncName(const ExternalFunction &cfg_func) { return ss.str(); } -static std::string LiftedStackVariableName(const StackVariable &cfg_stack) { - std::stringstream ss; - ss << "sv_" << SaneName(cfg_stack.name()); - return ss.str(); -} - // Find the segment containing the data at `ea`. // // TODO(pag): Re-implement with a call to `lower_bound` or `upper_bound`. static const NativeSegment *FindSegment(const NativeModule *module, uint64_t ea) { - for (const auto &entry : module->segments) { - const auto &seg = entry.second; - auto seg_end = seg->ea + seg->size; - if (seg->ea <= ea && ea < seg_end) { - return seg.get(); - } - } - return nullptr; + return module->TryGetSegment(ea); } // Resolve `xref` to a location. @@ -136,101 +142,16 @@ static bool ResolveReference(NativeModule *module, NativeXref *xref) { return true; } - if (!xref->target_name.empty()) { - auto var_name_it = module->name_to_extern_var.find(xref->target_name); - if (var_name_it != module->name_to_extern_var.end()) { - xref->var = reinterpret_cast( - var_name_it->second->Get()); - return true; - } - - auto func_name_it = module->name_to_extern_func.find(xref->target_name); - if (func_name_it != module->name_to_extern_func.end()) { - xref->func = reinterpret_cast( - func_name_it->second->Get()); - return true; - } - } - - if (xref->target_segment) { - return true; - } - - // Try to recover by finding a global variable. - for (const auto &entry : module->ea_to_var) { - const auto &var = entry.second; - if (var->name != xref->target_name) { - continue; - } - - const auto new_var = new NativeVariable; - const auto final_var = reinterpret_cast(var->Get()); - new_var->forward = var->Get(); - new_var->ea = xref->target_ea; - new_var->name = xref->target_name; - new_var->segment = final_var->segment; - module->ea_to_var[new_var->ea].reset(new_var); - - xref->var = reinterpret_cast(new_var->forward); - xref->target_segment = new_var->segment; - - LOG(WARNING) - << "Attempting reference fix at " << std::hex << xref->ea - << " targeting " << xref->target_name << " using variable " - << std::hex << var->ea << ", resolving to variable " - << final_var->name << " at " << std::hex << final_var->ea; - - return true; - } - - // Try to recover by finding a function with the same name. - for (const auto &entry : module->ea_to_func) { - const auto &func = entry.second; - if (func->name != xref->target_name) { - continue; - } - - const auto new_func = new NativeFunction; - new_func->forward = func->Get(); - new_func->ea = xref->target_ea; - new_func->name = xref->target_name; - module->ea_to_func[new_func->ea].reset(new_func); - - xref->func = reinterpret_cast(new_func->forward); - - LOG(WARNING) - << "Attempting reference fix at " << std::hex << xref->ea - << " targeting " << xref->target_name << " using function " - << std::hex << func->ea << ", resolving to function " - << new_func->forward->name << " at " << std::hex - << new_func->forward->ea << std::dec; - - return true; - } - if (xref->target_segment) { LOG(WARNING) << "Data cross reference at " << std::hex << xref->ea << " in segment " << xref->segment->name << " targeting " << xref->target_ea << " in segment " - << xref->target_segment->name << " has no name."; + << xref->target_segment->name + << " is not associated with a function or variable"; return true; } - if (xref->target_name.empty()) { - LOG(WARNING) - << "Data cross reference at " << std::hex << xref->ea - << " targeting " << std::hex << xref->target_ea - << " does not match any known externals and is not " - << "contained within any data segments."; - - } else { - LOG(WARNING) - << "Data cross reference at " << std::hex << xref->ea - << " targeting " << xref->target_name << " at " - << std::hex << xref->target_ea << " does not match any known " - << "externals and is not contained within any data segments."; - } return false; } @@ -240,172 +161,72 @@ static bool ResolveReference(NativeModule *module, NativeXref *xref) { // do best effort matching in here and above, so error checking is mostly // about letting us know if we should investigate something in the Python // side of things. -static void AddXref(NativeModule *module, NativeInstruction *inst, - const CodeReference &cfg_ref, uint64_t pointer_size) { - auto xref = new NativeXref; - xref->ea = inst->ea; - xref->mask = 0; - xref->width = pointer_size; - xref->segment = FindSegment(module, xref->ea); - xref->target_ea = static_cast(cfg_ref.ea()); - xref->target_segment = FindSegment(module, xref->target_ea); - - CHECK(xref->segment != nullptr) - << "Could not identify segment containing cross-reference from " - << std::hex << xref->ea << " to " << std::hex << xref->target_ea; - +static bool FillXref(NativeModule *module, NativeInstruction *inst, + const CodeReference &cfg_ref, uint64_t pointer_size, + NativeInstructionXref *xref) { if (cfg_ref.has_mask()) { xref->mask = static_cast(cfg_ref.mask()); - } - - if (cfg_ref.has_name()) { - xref->target_name = cfg_ref.name(); - } - - if (!ResolveReference(module, xref)) { - delete xref; - return; - } - - bool xref_is_external = false; - - // Does the XREF think its target is external? - if (xref->func) { - xref_is_external = xref->func->is_external; - - } else if (xref->var) { - xref_is_external = xref->var->is_external; - - // `mcsema-disass` does not recover external segments (e.g. `extern`), so - // a cross-reference that targets a NULL segment is, in practice, an - // external reference. - } else if (!xref->target_segment) { - LOG(WARNING) - << "Reference from " << std::hex << inst->ea - << " to " << xref->target_ea << std::dec - << " targets an unrecovered segment not resolved to a real symbol."; - - xref_is_external = true; - } else { - LOG(WARNING) - << "Reference from " << std::hex << inst->ea - << " to " << xref->target_ea << std::dec - << " targets the segment " << xref->target_segment->name - << " but was not resolved to a named symbol."; - xref_is_external = xref->segment->is_external || - xref->target_segment->is_external; - } - - CHECK(!xref_is_external || !xref->target_name.empty()) - << "External reference from " << std::hex << inst->ea - << " to " << xref->target_ea << std::dec << " does not have a name!"; - - // Does the CFG reference target type agree with the resolved code/data - // nature of the xref? - if (cfg_ref.target_type() == CodeReference_TargetType_CodeTarget) { - LOG_IF(WARNING, nullptr == xref->func) - << "Code cross-reference from " << std::hex << inst->ea - << " to " << std::hex << xref->target_ea << std::dec - << " is not actually a code cross-reference"; - } else { - - // NOTE(pag): This will come up a lot with the `.idata` section in PE - // binaries. We'll have things like: - // - // .idata:1400110E8 ; void __stdcall EnterCriticalSection(...) - // .idata:1400110E8 extrn EnterCriticalSection:qword - // - // And so we'll only really have this one location to represent - // both the function `EnterCriticalSection`, and the pointer to - // the function (this is a bit like the `.got.plt` section of - // ELF binaries, but they have an addition `.extern` section). - // So we'll end up with code that does something like: - // - // jmp cs:EnterCriticalSection - // - // And we'll say it's got a data AND flow reference to - // `EnterCriticalSection`. But the data reference itself looks - // like it should be a code reference, because we implement this - // type of reference as (from a mcsema-disass log): - // - // 8-byte reference at 1400110e8 to 1400110e8 (EnterCriticalSection) - // - // That is, it's self-referential. It's illogical for us to - // eventually lift the `cs:EnterCriticalSection` operand of this - // instruction as loading the bytes of the instruction itself, - // though. - LOG_IF(WARNING, nullptr != xref->func) - << "Data cross-reference from " << std::hex << inst->ea - << " to " << xref->target_ea << std::dec - << " is actually a code cross-reference"; - } - - // Does the CFG reference target location agree with the resolved - // externality of the xref? This isn't an atypical error. It can come up - // where ELF binaries will have a relocation like `stderr@GLIBC_XYZ`, and - // that will be an element in the `.bss` wherein the actual pointer to - // `stderr` will be placed. - if (cfg_ref.location() == CodeReference_Location_External) { - LOG_IF(WARNING, !xref_is_external) - << "External reference from " << std::hex << inst->ea - << " to " << xref->target_ea << std::dec << " is actually internal"; - } else { - LOG_IF(WARNING, xref_is_external) - << "Internal reference from " << std::hex << inst->ea - << " to " << xref->target_ea << std::dec << " (" << xref->target_name - << ") is actually external"; + xref->mask = 0; } + xref->target_ea = static_cast(cfg_ref.ea()); switch (cfg_ref.operand_type()) { case CodeReference_OperandType_ImmediateOperand: LOG_IF(WARNING, inst->imm != nullptr) - << "Overwriting existing immediate reference at instruction " - << std::hex << inst->ea << std::dec; + << "Overwriting existing immediate reference at instruction " + << std::hex << inst->ea << std::dec; inst->imm = xref; break; case CodeReference_OperandType_MemoryOperand: LOG_IF(WARNING, inst->mem != nullptr) - << "Overwriting existing absolute reference at instruction " - << std::hex << inst->ea << std::dec; + << "Overwriting existing absolute reference at instruction " + << std::hex << inst->ea << std::dec; inst->mem = xref; break; case CodeReference_OperandType_MemoryDisplacementOperand: LOG_IF(WARNING, inst->disp != nullptr) - << "Overwriting existing displacement reference at instruction " - << std::hex << inst->ea << std::dec; + << "Overwriting existing displacement reference at instruction " + << std::hex << inst->ea << std::dec; inst->disp = xref; break; case CodeReference_OperandType_ControlFlowOperand: LOG_IF(WARNING, inst->flow != nullptr) - << "Overwriting existing flow reference at instruction " - << std::hex << inst->ea << std::dec; + << "Overwriting existing flow reference at instruction " + << std::hex << inst->ea << std::dec; inst->flow = xref; break; case CodeReference_OperandType_OffsetTable: LOG_IF(WARNING, inst->offset_table != nullptr) - << "Overwriting existing offset table reference at instruction " - << std::hex << inst->ea << std::dec; + << "Overwriting existing offset table reference at instruction " + << std::hex << inst->ea << std::dec; inst->offset_table = xref; break; } + + return true; } } // namespace -NativeObject::NativeObject(void) - : forward(this) {} +NativeObject::NativeObject(NativeModule *module_) + : module(module_), + forward(this) {} -NativeExternalFunction::NativeExternalFunction(void) - : cc(gArch->DefaultCallingConv()) {} +NativeExternalFunction::NativeExternalFunction(NativeModule *module_) + : NativeFunction(module_), + cc(gArch->DefaultCallingConv()) {} NativeSegment::Entry::Entry( - uint64_t o_ea, uint64_t o_next_ea, NativeXref *o_xref, NativeBlob *o_blob) : - ea(o_ea), next_ea(o_next_ea), xref(o_xref), blob(o_blob) {} + uint64_t o_ea, uint64_t o_next_ea, NativeXref *o_xref, NativeBlob *o_blob) + : ea(o_ea), + next_ea(o_next_ea), + xref(o_xref), + blob(o_blob) {} void NativeObject::ForwardTo(NativeObject *dest) const { if (forward != this) { @@ -430,6 +251,28 @@ NativeObject *NativeObject::Get(void) { return forward; } +llvm::Constant *NativeObject::Pointer(void) const { + LOG(FATAL) + << "Invalid use."; + return nullptr; +} + +llvm::Constant *NativeObject::Address(void) const { + LOG(FATAL) + << "Invalid use."; + return nullptr; +} + +bool NativeFunction::IsNoReturn(void) const { + if (decl && decl->is_noreturn) { + return true; + } + if (function && function->hasFnAttribute(llvm::Attribute::NoReturn)) { + return true; + } + return false; +} + static void MergeVariables(NativeVariable *var, const NativeVariable *old_var) { var->is_exported = var->is_exported || old_var->is_exported; var->is_thread_local = var->is_thread_local || old_var->is_thread_local; @@ -438,8 +281,170 @@ static void MergeVariables(NativeVariable *var, const NativeVariable *old_var) { static void UpdateVariable(NativeVariable *var, const NativeSegment *seg) { var->is_exported = var->is_exported || seg->is_exported; var->is_thread_local = var->is_thread_local || seg->is_thread_local; + + LOG_IF(ERROR, var->is_thread_local && !seg->is_thread_local) + << "Variable " << var->name << " at " << std::hex << var->ea + << " marked as thread-local, but in non-thread-local segment " + << seg->name << " at " << seg->ea << std::dec; } +bool RecoverValueDecl(const NativeFunction *func, anvill::ValueDecl &decl, + const ValueDecl &cfg_decl) { + auto maybe_type = anvill::ParseType(*gContext, cfg_decl.type()); + if (remill::IsError(maybe_type)) { + LOG(ERROR) + << "Could not parse type in value spec of function " + << func->name << ": " << remill::GetErrorString(maybe_type); + return false; + } + + decl.type = *maybe_type; + if (cfg_decl.has_memory()) { + decl.mem_reg = gArch->RegisterByName(cfg_decl.memory().register_()); + if (!decl.mem_reg) { + LOG(ERROR) + << "Bad register name '" << cfg_decl.memory().register_() + << "' in function spec for " << func->name << " at " << std::hex + << func->ea << std::dec; + return false; + } + decl.mem_offset = cfg_decl.memory().offset(); + return true; + + } else if (cfg_decl.has_register_()) { + decl.reg = gArch->RegisterByName(cfg_decl.register_()); + if (!decl.reg) { + LOG(ERROR) + << "Bad register name '" << cfg_decl.register_() + << "' in function spec for " << func->name << " at " << std::hex + << func->ea << std::dec; + return false; + } + return true; + } else { + return false; + } +} + +bool RecoverParamDecl(const NativeFunction *func, anvill::FunctionDecl &decl, + const ValueDecl &cfg_decl) { + decl.params.emplace_back(); + auto ¶m_decl = decl.params.back(); + + if (cfg_decl.has_name()) { + param_decl.name = cfg_decl.name(); + } + + return RecoverValueDecl(func, param_decl, cfg_decl); +} + +bool RecoverRetDecl(const NativeFunction *func, anvill::FunctionDecl &decl, + const ValueDecl &cfg_decl) { + decl.returns.emplace_back(); + return RecoverValueDecl(func, decl.returns.back(), cfg_decl); +} + +// Recover a `FunctionDecl` from the CFG. +void RecoverFunctionDecl(NativeModule *module, + NativeFunction *func, + const FunctionDecl &cfg_decl, + llvm::Function *ll_func=nullptr) { + anvill::FunctionDecl decl; + decl.address = func->ea; + decl.arch = gArch.get(); + decl.is_noreturn = cfg_decl.is_noreturn(); + decl.is_variadic = cfg_decl.is_variadic(); + + if (ll_func) { + if (ll_func->doesNotReturn()) { + decl.is_noreturn = true; + } + if (ll_func->isVarArg()) { + decl.is_variadic = true; + } + } + + decl.calling_convention = static_cast( + cfg_decl.calling_convention()); + + if (!cfg_decl.has_return_stack_pointer()) { + LOG(ERROR) + << "Function spec for " << func->name << " at " << std::hex + << func->ea << std::dec << " is missing a return stack pointer"; + return; + } + + if (cfg_decl.return_stack_pointer().has_memory()) { + + decl.return_stack_pointer = gArch->RegisterByName( + cfg_decl.return_stack_pointer().memory().register_()); + + decl.return_stack_pointer_offset = + cfg_decl.return_stack_pointer().memory().offset(); + + } else if (cfg_decl.return_stack_pointer().has_register_()) { + decl.return_stack_pointer = gArch->RegisterByName( + cfg_decl.return_stack_pointer().register_()); + } else { + LOG(ERROR) + << "Function spec for " << func->name << " at " << std::hex + << func->ea << std::dec << " is missing a return stack pointer"; + return; + } + + if (!decl.return_stack_pointer) { + if (cfg_decl.return_stack_pointer().has_memory()) { + LOG(ERROR) + << "Function spec for " << func->name << " at " << std::hex + << func->ea << std::dec << " has an invalid return stack pointer name '" + << cfg_decl.return_stack_pointer().memory().register_() << "'"; + } else { + LOG(ERROR) + << "Function spec for " << func->name << " at " << std::hex + << func->ea << std::dec << " has an invalid return stack pointer name '" + << cfg_decl.return_stack_pointer().register_() << "'"; + } + return; + } + + for (const auto &cfg_ret_val : cfg_decl.return_values()) { + if (!RecoverRetDecl(func, decl, cfg_ret_val)) { + return; + } + } + + for (const auto &cfg_param_val : cfg_decl.parameters()) { + if (!RecoverParamDecl(func, decl, cfg_param_val)) { + return; + } + } + + if (!RecoverValueDecl(func, decl.return_address, cfg_decl.return_address())) { + return; + } + + // Just in case IDA is wrong. + if (decl.params.empty()) { + decl.is_variadic = true; + } + + auto maybe_func = module->DeclareFunction(decl, true); + if (remill::IsError(maybe_func)) { + LOG(ERROR) + << remill::GetErrorString(maybe_func); + return; + + } else { + func->decl = *maybe_func; + } +} + +template +struct NativeInstructionWithXrefs : public NativeInstruction { + public: + NativeInstructionXref xrefs[kNumXrefs]; +}; + // Convert the protobuf into an in-memory data structure. This does a fair // amount of checking and tries to correct errors in favor of converting // variables into functions, and internals into externals. The intuition is @@ -452,14 +457,14 @@ NativeModule *ReadProtoBuf(const std::string &file_name, std::ifstream fstream(file_name, std::ios::binary); CHECK(fstream.good()) - << "Unable to open CFG file " << file_name; + << "Unable to open CFG file " << file_name; google::protobuf::io::IstreamInputStream pstream(&fstream); google::protobuf::io::CodedInputStream cstream(&pstream); cstream.SetTotalBytesLimit(512 * 1024 * 1024, -1); Module cfg; CHECK(cfg.ParseFromCodedStream(&cstream)) - << "Unable to read module from CFG file " << file_name; + << "Unable to read module from CFG file " << file_name; LOG(INFO) << "Lifting program " << cfg.name() << " via CFG protobuf in " @@ -478,44 +483,97 @@ NativeModule *ReadProtoBuf(const std::string &file_name, // TODO(pag): Add some kind of name->var mapping so that we can // cover this. + if (!found_func->is_exported && cfg_func->is_entrypoint()) { + found_func->is_exported = true; + + // Steal the exported name. + if (cfg_func->has_name()) { + found_func->name = std::move(*(cfg_func->mutable_name())); + } + } + + // This re-declaration has a decl. + if (!found_func->decl && cfg_func->has_decl()) { + RecoverFunctionDecl(module, found_func, cfg_func->decl()); + } + LOG_IF(WARNING, found_func->name != cfg_func->name()) - << "Two or more names for function at " << std::hex - << found_func->ea << std::dec << ": '" << found_func->name - << "' and '" << cfg_func->name() << "'"; + << "Two or more names for function at " << std::hex + << found_func->ea << std::dec << ": '" << found_func->name + << "' and '" << cfg_func->name() << "'"; continue; } - const auto func = new NativeFunction; + const auto func = new NativeFunction(module); + module->functions.emplace_back(func); + func->ea = func_ea; func->lifted_name = LiftedFunctionName(*cfg_func); if (cfg_func->has_name()) { func->name = std::move(*(cfg_func->mutable_name())); - } else { - func->name = func->lifted_name; } - func->blocks.reserve(static_cast(cfg_func->blocks_size())); func->is_exported = cfg_func->is_entrypoint(); - module->ea_to_func[func->ea].reset(func); + module->ea_to_func[func->ea] = func; LOG(INFO) << "Found function " << func->name << " at " << std::hex << func->ea << std::dec; if (func->is_exported) { CHECK(!func->name.empty()) - << "Exported function at address " << std::hex << func->ea << std::dec - << " does not have a name"; + << "Exported function at address " << std::hex << func->ea << std::dec + << " does not have a name"; LOG(INFO) << "Exported function " << func->name << " at " << std::hex << func->ea << std::dec << " is implemented by " << func->lifted_name; + } - module->exported_funcs.insert(func->ea); + module->AddNameToAddress(func->name, func->ea); + + auto ll_func = gModule->getFunction(func->name); + + // Extract the function decl. + if (!func->decl && cfg_func->has_decl()) { + RecoverFunctionDecl(module, func, cfg_func->decl(), ll_func); + } + + // NOTE(pag): We don't store this in `func->function` as it may get + // optimized out, and so we just want to recall enough info + // about the function. + if (ll_func) { + + if (ll_func->hasPrivateLinkage() || ll_func->hasInternalLinkage()) { + func->is_exported = false; + } + + auto maybe_decl = anvill::FunctionDecl::Create(*ll_func, gArch); + + if (remill::IsError(maybe_decl)) { + LOG(ERROR) + << remill::GetErrorString(maybe_decl); + } else { + maybe_decl->address = func->ea; + auto maybe_decl_ptr = module->DeclareFunction(*maybe_decl, true); + if (remill::IsError(maybe_decl_ptr)) { + LOG(ERROR) + << remill::GetErrorString(maybe_decl_ptr); + } else { + LOG_IF(WARNING, func->decl != nullptr) + << "Overwriting CFG-specified function specification for " + << func->name << " at " << std::hex << func->ea << std::dec + << " with one based off of existing module function"; + func->decl = *maybe_decl_ptr; + } + } } } const bool is_windows = remill::kOSWindows == gArch->os_name; + std::unordered_map + name_to_extern_func; + // Bring in the external functions. If an internal function can take its // place, then we use it. for (auto f = 0, max_f = cfg.external_funcs_size(); f < max_f; ++f) { @@ -533,7 +591,6 @@ NativeModule *ReadProtoBuf(const std::string &file_name, if (!found_func->is_exported) { found_func->is_exported = true; found_func->name = std::move(*(cfg_extern_func->mutable_name())); - module->exported_funcs.insert(found_func->ea); LOG(INFO) << "Exported function " << found_func->name << " at " << std::hex @@ -555,24 +612,62 @@ NativeModule *ReadProtoBuf(const std::string &file_name, continue; } - auto func = new NativeExternalFunction; + const auto func = new NativeExternalFunction(module); + module->functions.emplace_back(func); + func->lifted_name = ExternalFuncName(*cfg_extern_func); func->name = std::move(*(cfg_extern_func->mutable_name())); - const auto ll_func = gModule->getFunction(func->name); func->ea = func_ea; func->is_external = true; func->is_exported = true; - func->is_explicit = FLAGS_explicit_args || nullptr != ll_func; func->is_weak = cfg_extern_func->is_weak(); func->num_args = 0; func->cc = gArch->DefaultCallingConv(); + module->AddNameToAddress(func->name, func->ea); + + // NOTE(pag): We don't store this in `func->function` as it may get + // optimized out, and so we just want to recall enough info + // about the function. + const auto ll_func = gModule->getFunction(func->name); + LOG(INFO) << "Found external function " << func->name << " at " << std::hex << func->ea << std::dec; + // Extract the function decl. This might declare the extern in the module. + if (cfg_extern_func->has_decl()) { + RecoverFunctionDecl(module, func, cfg_extern_func->decl(), ll_func); + } + + llvm::CallingConv::ID ll_func_cc = llvm::CallingConv::C; + if (ll_func) { func->num_args = static_cast(ll_func->arg_size()); + + auto maybe_decl = anvill::FunctionDecl::Create(*ll_func, gArch); + ll_func_cc = ll_func->getCallingConv(); + + if (remill::IsError(maybe_decl)) { + LOG(ERROR) + << remill::GetErrorString(maybe_decl); + + } else { + maybe_decl->address = func->ea; + auto maybe_decl_ptr = module->DeclareFunction(*maybe_decl, true); + if (remill::IsError(maybe_decl_ptr)) { + LOG(ERROR) + << remill::GetErrorString(maybe_decl_ptr); + + } else { + LOG_IF(WARNING, func->decl != nullptr) + << "Overwriting CFG-specified function specification for " + << func->name << " at " << std::hex << func->ea << std::dec + << " with one based off of existing module function"; + func->decl = *maybe_decl_ptr; + } + } + } else if (cfg_extern_func->has_argument_count()) { func->num_args = static_cast(cfg_extern_func->argument_count()); } @@ -584,38 +679,45 @@ NativeModule *ReadProtoBuf(const std::string &file_name, // came along and now we're in a bad place where the calling convention is // specified, but only in a way that is relevant to 32-bit x86, so we need // to ignore it in some places and not others. - if (gArch->IsX86()) { - switch (cfg_extern_func->cc()) { - case ExternalFunction_CallingConvention_CalleeCleanup: - func->cc = llvm::CallingConv::X86_StdCall; - break; - - case ExternalFunction_CallingConvention_FastCall: - func->cc = llvm::CallingConv::X86_FastCall; - break; - - case ExternalFunction_CallingConvention_CallerCleanup: // cdecl. - func->cc = llvm::CallingConv::C; - break; - - default: - if (is_windows) { + if (cfg_extern_func->has_cc()) { + if (gArch->IsX86()) { + switch (cfg_extern_func->cc()) { + case ExternalFunction_CallingConvention_CalleeCleanup: func->cc = llvm::CallingConv::X86_StdCall; - } - break; - } + break; - } else if (gArch->IsAMD64()) { - if (is_windows) { - func->cc = llvm::CallingConv::Win64; - } else { - func->cc = llvm::CallingConv::X86_64_SysV; + case ExternalFunction_CallingConvention_FastCall: + func->cc = llvm::CallingConv::X86_FastCall; + break; + + case ExternalFunction_CallingConvention_CallerCleanup: // cdecl. + func->cc = llvm::CallingConv::C; + break; + + default: + if (is_windows) { + func->cc = llvm::CallingConv::X86_StdCall; + } + break; + } + + } else if (gArch->IsAMD64()) { + if (is_windows) { + func->cc = llvm::CallingConv::Win64; + } else { + func->cc = llvm::CallingConv::X86_64_SysV; + } } } + // Override. + if (ll_func) { + func->cc = ll_func_cc; + } + LOG_IF(WARNING, module->ea_to_var.count(func->ea)) - << "Internal variable at " << std::hex << func->ea - << " has the same name as the external function " << func->name; + << "Internal variable at " << std::hex << func->ea + << " has the same name as the external function " << func->name; LOG(INFO) << "Found external function " << func->name << " via " @@ -624,8 +726,8 @@ NativeModule *ReadProtoBuf(const std::string &file_name, // Check to see if an external function with the same name was already // added. This is possible if there are things like thunks calling thunks, // or thin wrappers around thunks. - auto extern_func_it = module->name_to_extern_func.find(func->name); - if (extern_func_it != module->name_to_extern_func.end()) { + auto extern_func_it = name_to_extern_func.find(func->name); + if (extern_func_it != name_to_extern_func.end()) { auto dup_func = extern_func_it->second; dup_func->ForwardTo(func); @@ -636,10 +738,12 @@ NativeModule *ReadProtoBuf(const std::string &file_name, << func->ea << " is also defined at " << std::hex << dup_func->ea; } - module->name_to_extern_func[func->name] = func; - module->ea_to_func[func->ea].reset(func); + module->ea_to_func[func->ea] = func; } + std::unordered_map + name_to_extern_var; + // Bring in the external variables. for (auto v = 0, max_v = cfg.external_vars_size(); v < max_v; ++v) { const auto cfg_extern_var = cfg.mutable_external_vars(v); @@ -655,7 +759,6 @@ NativeModule *ReadProtoBuf(const std::string &file_name, if (!found_func->is_exported) { found_func->is_exported = true; found_func->name = std::move(*(cfg_extern_var->mutable_name())); - module->exported_funcs.insert(found_func->ea); LOG(INFO) << "Exported function " << found_func->name << " at " << std::hex @@ -677,23 +780,59 @@ NativeModule *ReadProtoBuf(const std::string &file_name, continue; } - auto var = new NativeExternalVariable; + const auto seg = new NativeSegment(module); + module->segments.emplace_back(seg); + + auto var = new NativeExternalVariable(module); + module->variables.emplace_back(var); + + auto seg_size = static_cast(cfg_extern_var->size()); + auto &seg_ptr = module->ea_to_seg[var_ea]; + if (seg_ptr) { + LOG(ERROR) + << "Segment '" << seg_ptr->name << "' at " << std::hex << seg_ptr->ea + << " is being redefined as '" << cfg_extern_var->name() + << "' at " << var_ea << std::dec; + + if (seg_ptr->as_extern_var) { + seg_ptr->as_extern_var->ForwardTo(var); + seg_ptr->as_extern_var = var; + } else { + seg_ptr->as_extern_var = var; + } + + seg_ptr->ForwardTo(seg); + seg_size = std::max(seg_ptr->size, seg_size); + } + + seg_ptr = seg; + seg->ea = var_ea; + seg->name = cfg_extern_var->name(); + seg->lifted_name = cfg_extern_var->name(); + seg->is_external = true; + seg->is_exported = false; + seg->is_thread_local = cfg_extern_var->is_thread_local(); + seg->is_read_only = false; + seg->size = seg_size; + seg->as_extern_var = var; + var->ea = var_ea; var->name = std::move(*(cfg_extern_var->mutable_name())); var->lifted_name = var->name; + var->segment = seg; var->is_external = true; - var->is_exported = true; + var->is_exported = false; var->is_thread_local = cfg_extern_var->is_thread_local(); var->is_weak = cfg_extern_var->is_weak(); - var->size = static_cast(cfg_extern_var->size()); + var->size = seg_size; LOG(INFO) << "Found external variable " << var->name << " at " << std::hex << var->ea << std::dec; // Look for two extern variables with the same name. - auto extern_var_it = module->name_to_extern_var.find(var->name); - if (extern_var_it != module->name_to_extern_var.end()) { + auto extern_var_it = name_to_extern_var.find(var->name); + if (extern_var_it != name_to_extern_var.end()) { auto dup_var = extern_var_it->second; MergeVariables(var, dup_var); dup_var->ForwardTo(var); @@ -705,8 +844,8 @@ NativeModule *ReadProtoBuf(const std::string &file_name, << var->ea << " is also defined at " << dup_var->ea << std::dec; } - module->ea_to_var[var->ea].reset(var); - module->name_to_extern_var[var->name] = var; + module->ea_to_var[var->ea] = var; + name_to_extern_var[var->name] = var; } // Collect variables from within the data sections. We set up the segment @@ -715,20 +854,33 @@ NativeModule *ReadProtoBuf(const std::string &file_name, for (auto s = 0, max_s = cfg.segments_size(); s < max_s; ++s) { auto cfg_segment = cfg.mutable_segments(s); - auto segment = new NativeSegment; + if (cfg_segment->has_variable_name()) { + if (name_to_extern_var.count(cfg_segment->variable_name())) { + LOG(ERROR) + << "Skipping segment '" << cfg_segment->variable_name() + << " as it's already associated with an extern var";; + continue; + } + } + + auto segment = new NativeSegment(module); + module->segments.emplace_back(segment); + segment->ea = static_cast(cfg_segment->ea()); segment->size = cfg_segment->data().size(); segment->lifted_name = LiftedSegmentName(*cfg_segment); - if (cfg_segment->has_name()) { + + if (cfg_segment->has_variable_name()) { + segment->name = std::move(*(cfg_segment->mutable_variable_name())); + + } else if (cfg_segment->has_name()) { segment->name = std::move(*(cfg_segment->mutable_name())); } segment->is_read_only = cfg_segment->read_only(); - segment->needs_initializer = true; segment->is_external = cfg_segment->is_external(); segment->is_exported = cfg_segment->is_exported(); segment->is_thread_local = cfg_segment->is_thread_local(); - segment->seg_var = nullptr; // Collect the variables. for (auto v = 0, max_v = cfg_segment->vars_size(); v < max_v; ++v) { @@ -741,9 +893,9 @@ NativeModule *ReadProtoBuf(const std::string &file_name, // cover this. LOG_IF(WARNING, found_var->name != cfg_var->name()) - << "Two or more names for variable at " << std::hex - << found_var->ea << std::dec << ": '" << found_var->name - << "' and '" << cfg_var->name() << "'"; + << "Two or more names for variable at " << std::hex + << found_var->ea << std::dec << ": '" << found_var->name + << "' and '" << cfg_var->name() << "'"; UpdateVariable(found_var, segment); @@ -759,12 +911,21 @@ NativeModule *ReadProtoBuf(const std::string &file_name, << " in segment " << segment->name; } else { - auto var = new NativeVariable; + auto var = new NativeVariable(module); + module->variables.emplace_back(var); + var->ea = var_ea; var->lifted_name = LiftedVarName(*cfg_var); - var->name = std::move(*(cfg_var->mutable_name())); + if (cfg_var->has_name()) { + var->name = std::move(*(cfg_var->mutable_name())); + } var->segment = segment; - module->ea_to_var[var->ea].reset(var); + module->ea_to_var[var->ea] = var; + + // Avoid name conflicts with things like `.bss`. + if (var->ea == segment->ea) { + segment->name = var->name; + } LOG(INFO) << "Found variable " << var->name << " at " << std::hex @@ -772,32 +933,36 @@ NativeModule *ReadProtoBuf(const std::string &file_name, } } - module->segments[segment->ea].reset(segment); - LOG(INFO) << "Found segment " << segment->name << " [" << std::hex << segment->ea << ", " << (segment->ea + segment->size) << std::dec << ")"; + + auto &seg_ptr = module->ea_to_seg[segment->ea]; + LOG_IF(WARNING, !!seg_ptr) + << "Segment '" << segment->name << "' overlaps existing segment " + << "'" << seg_ptr->name << "'"; + + seg_ptr = segment; } // Fill in the cross-reference entries for each segment. for (const auto &cfg_segment : cfg.segments()) { auto ea = static_cast(cfg_segment.ea()); - const auto &segment = module->segments[ea]; + const auto segment = const_cast(module->ea_to_seg[ea]); std::map xrefs; for (const auto &cfg_xref : cfg_segment.xrefs()) { std::unique_ptr xref(new NativeXref); xref->ea = static_cast(cfg_xref.ea()); - xref->segment = segment.get(); - xref->width = static_cast(cfg_xref.width()); + xref->segment = segment; + xref->width = static_cast(cfg_xref.width()); xref->target_ea = static_cast(cfg_xref.target_ea()); - xref->target_name = cfg_xref.target_name(); xref->target_segment = FindSegment(module, xref->target_ea); CHECK(xref->width <= pointer_size) - << "Cross reference at " << std::hex << xref->ea << " to " - << xref->target_name << " at " << std::hex << xref->target_ea - << " is too wide at " << xref->width << " bytes"; + << "Cross reference at " << std::hex << xref->ea << " to " + << std::hex << xref->target_ea << " is too wide at " + << xref->width << " bytes"; switch (cfg_xref.target_fixup_kind()) { case DataReference_TargetFixupKind_Absolute: @@ -822,7 +987,7 @@ NativeModule *ReadProtoBuf(const std::string &file_name, // Fill in the blob data entries for each segment. for (const auto &cfg_segment : cfg.segments()) { auto ea = static_cast(cfg_segment.ea()); - const auto &segment = module->segments[ea]; + const auto segment = const_cast(module->ea_to_seg[ea]); std::vector blobs; // Sentinel. @@ -831,6 +996,18 @@ NativeModule *ReadProtoBuf(const std::string &file_name, entry.ea = seg_end_ea; entry.next_ea = seg_end_ea; + anvill::ByteRange range; + range.address = ea; + range.is_writeable = !cfg_segment.read_only(); + range.is_executable = true; // TODO(pag): Fix this. + range.begin = reinterpret_cast(cfg_segment.data().data()); + range.end = &(range.begin[cfg_segment.data().size()]); + if (auto err = module->MapRange(range); remill::IsError(err)) { + LOG(FATAL) + << "Unable to map segment " << segment->name + << ": " << remill::GetErrorString(err); + } + for (const auto &xref_entry : segment->entries) { const auto &entry = xref_entry.second; @@ -841,8 +1018,6 @@ NativeModule *ReadProtoBuf(const std::string &file_name, break; } - auto pos = ea - segment->ea; - // Find the beginning of the next variable or entry. uint64_t size = 1; for (; (ea + size) < entry.ea; ++size) { @@ -851,15 +1026,54 @@ NativeModule *ReadProtoBuf(const std::string &file_name, } } - auto blob = new NativeBlob; - blob->ea = ea; - blob->data = cfg_segment.data().substr(pos, size); - blobs.push_back(NativeSegment::Entry{ea, ea + size, nullptr, blob}); + constexpr size_t kMaxBlobSize = 4; + std::unique_ptr blob; + + // We ideally want to do a kind of run-length encoding of the blob + // sections, so that we can avoid explicitly representing large + // sequences of zeroes. Our approach is to artificially split a section + // into groups of at most `kMaxBlobSize` bytes, then merge together + // adjacent blobs that are marked as `is_zero`. + auto end_ea = ea + static_cast(size); + for (auto blob_ea = ea; blob_ea < end_ea; blob_ea += kMaxBlobSize) { + const auto blob_end_ea = std::min(blob_ea + kMaxBlobSize, end_ea); + + // NOTE(pag): The `NativeSegment::Entry` takes ownership of `blob`. + if (!blob) { + blob.reset(new NativeBlob); + } + blob->ea = blob_ea; + blob->size = static_cast(blob_end_ea - blob_ea); + blob->is_zero = true; + + for (auto i = blob_ea; i < blob_end_ea; ++i) { + if (range.begin[i - range.address]) { + blob->is_zero = false; + break; + } + } + + // Merge zero blobs with zero blobs, and non-zero blobs with non-zero + // blobs. + if (!blobs.empty() && + blobs.back().next_ea == blob_ea && + blobs.back().blob && + blob->is_zero == blobs.back().blob->is_zero) { + + blobs.back().blob->size += blob->size; + blobs.back().next_ea = blob_end_ea; + + } else { + blobs.push_back(NativeSegment::Entry{ + blob_ea, blob_end_ea, nullptr, blob.release()}); + } + } + ea += size; } CHECK(ea == entry.ea) - << "Invalid partitioning of data before " << std::hex << entry.ea; + << "Invalid partitioning of data before " << std::hex << entry.ea; if (ea == seg_end_ea) { break; @@ -870,11 +1084,11 @@ NativeModule *ReadProtoBuf(const std::string &file_name, for (ea += 1; ea < entry.next_ea; ++ea) { auto var_it = module->ea_to_var.find(ea); LOG_IF(ERROR, var_it != module->ea_to_var.end()) - << "Variable " << var_it->second->name << " at " - << std::hex << var_it->second->ea - << " points into a cross reference, located at " << std::hex - << entry.xref->ea << " and targeting " << std::hex - << entry.xref->target_ea; + << "Variable " << var_it->second->name << " at " + << std::hex << var_it->second->ea + << " points into a cross reference, located at " << std::hex + << entry.xref->ea << " and targeting " << std::hex + << entry.xref->target_ea; } } @@ -890,53 +1104,43 @@ NativeModule *ReadProtoBuf(const std::string &file_name, unsigned entry_num = 0; for (const auto &entry : segment->entries) { CHECK(entry.first == ea) - << "Invalid partitioning of segment " << segment->name - << "; entry #" << std::dec << entry_num << " EA address " - << std::hex << entry.first << " does not match " - << "up with expected entry EA " << std::hex << ea; + << "Invalid partitioning of segment " << segment->name + << "; entry #" << std::dec << entry_num << " EA address " + << std::hex << entry.first << " does not match " + << "up with expected entry EA " << std::hex << ea; CHECK(entry.second.ea == ea) - << "Invalid partitioning of segment " << segment->name; + << "Invalid partitioning of segment " << segment->name; CHECK(entry.second.next_ea > entry.second.ea) - << "Invalid partitioning of segment " << segment->name; + << "Invalid partitioning of segment " << segment->name; ea = entry.second.next_ea; entry_num++; } CHECK(ea == (segment->ea + segment->size)) - << "Invalid partitioning of segment " << segment->name; + << "Invalid partitioning of segment " << segment->name; } // Add in each of the function's blocks. At this stage we have all cross- // reference information available. for (const auto &cfg_func : cfg.funcs()) { auto func = module->TryGetFunction(static_cast(cfg_func.ea())); + if (!func) { + continue; + } - // Extract the stack variables associated with the function - for (const auto &stack_var : cfg_func.stack_vars()) { - auto nat_sv = new NativeStackVariable; - - nat_sv->offset = stack_var.sp_offset(); - nat_sv->size = stack_var.size(); - nat_sv->ea = 0; - nat_sv->name = stack_var.name(); - nat_sv->lifted_name = LiftedStackVariableName(stack_var); - nat_sv->llvm_var = nullptr; - func->stack_vars.push_back(nat_sv); - - for(auto ref_ea : stack_var.ref_eas()){ - nat_sv->refs[ref_ea.inst_ea()] = ref_ea.offset(); - LOG(INFO) - << "Retrieve the referenced ea : " << std::hex - << ref_ea.inst_ea() << std::dec << " offset " << ref_ea.offset(); - } + if (auto func_byte = module->FindByte(func->ea); !func_byte.IsExecutable()) { + LOG(ERROR) + << "Could not find any executable bytes associated with function " + << std::hex << func->ea << std::dec; + continue; } // Extract the eh_frame entries associated with the function for (const auto &entry : cfg_func.eh_frame()) { - auto frame_var = new NativeExceptionFrame; + auto frame_var = new NativeExceptionFrame(module); frame_var->start_ea = entry.start_ea(); frame_var->end_ea = entry.end_ea(); @@ -945,7 +1149,11 @@ NativeModule *ReadProtoBuf(const std::string &file_name, // List all the types of the landing pad for (const auto &extern_var : entry.ttype()) { - auto var = new NativeExternalVariable; + auto var = new NativeExternalVariable(module); + module->variables.emplace_back(var); + + // TODO(pag): Initialize `var->segment`. + var->ea = static_cast(extern_var.ea()); var->name = extern_var.name(); var->is_external = true; @@ -957,64 +1165,277 @@ NativeModule *ReadProtoBuf(const std::string &file_name, frame_var->type_var[static_cast(extern_var.size())] = var; } - func->eh_frame.push_back(frame_var); + func->eh_frame.emplace_back(frame_var); } for (const auto &cfg_block : cfg_func.blocks()) { - auto block = new NativeBlock; - block->ea = static_cast(cfg_block.ea()); - block->instructions.reserve( - static_cast(cfg_block.instructions_size())); + const auto block_ea = static_cast(cfg_block.ea()); + auto &block = module->ea_to_block[block_ea]; + if (!block) { + block.reset(new NativeBlock); + block->ea = block_ea; + } + + if (cfg_block.is_referenced_by_data()) { + block->is_referenced_by_data = true; + } // Add in the addresses of the block's successors. for (auto succ_ea : cfg_block.successor_eas()) { - block->successor_eas.insert(static_cast(succ_ea)); + block->successor_eas.push_back(static_cast(succ_ea)); } + // Merge in successors. + std::sort(block->successor_eas.begin(), block->successor_eas.end()); + auto it = std::unique(block->successor_eas.begin(), block->successor_eas.end()); + block->successor_eas.erase(it, block->successor_eas.end()); + + func->blocks.push_back(block.get()); + // Add in the block's instructions. for (const auto &cfg_inst : cfg_block.instructions()) { - auto inst = new NativeInstruction; - inst->ea = static_cast(cfg_inst.ea()); - inst->lp_ea = static_cast(cfg_inst.lp_ea()); - inst->bytes = cfg_inst.bytes(); - inst->does_not_return = cfg_inst.has_local_noreturn(); - inst->imm = nullptr; - inst->flow = nullptr; - inst->mem = nullptr; - inst->disp = nullptr; - inst->offset_table = nullptr; - inst->stack_var = nullptr; - for (const auto &cfg_ref : cfg_inst.xrefs()) { - AddXref(module, inst, cfg_ref, pointer_size); + const auto inst_ea = static_cast(cfg_inst.ea()); + + // If there is no possibility of interesting metadata, then we don't + // actually need a `NativeInstruction`. + if (!cfg_inst.lp_ea() && !cfg_inst.xrefs_size()) { + continue; } - for (const auto &var : func->stack_vars) { - for (auto ref : var->refs) { - if (inst->ea == ref.first) { - inst->stack_var = var; + // Don't add it if we've already got it. + block->last_inst_ea = std::max(block->last_inst_ea, inst_ea); + + auto &inst = module->ea_to_inst[inst_ea]; + if (!inst) { + + NativeInstructionXref *xrefs = nullptr; + + switch (cfg_inst.xrefs_size()) { + case 5: { + const auto xinst = new NativeInstructionWithXrefs<5>; + inst.reset(xinst); + xrefs = &(xinst->xrefs[0]); + break; + } + case 4: { + const auto xinst = new NativeInstructionWithXrefs<4>; + inst.reset(xinst); + xrefs = &(xinst->xrefs[0]); + break; + } + case 3: { + const auto xinst = new NativeInstructionWithXrefs<3>; + inst.reset(xinst); + xrefs = &(xinst->xrefs[0]); + break; + } + case 2: { + const auto xinst = new NativeInstructionWithXrefs<2>; + inst.reset(xinst); + xrefs = &(xinst->xrefs[0]); + break; + } + case 1: { + const auto xinst = new NativeInstructionWithXrefs<1>; + inst.reset(xinst); + xrefs = &(xinst->xrefs[0]); + break; + } + case 0: { + inst.reset(new NativeInstruction); + break; + } + default: + LOG(FATAL) + << "Unsupported number of cross-references attached to " + << "instruction at " << std::hex << inst_ea << std::dec; + continue; + } + + inst->ea = inst_ea; + inst->lp_ea = static_cast(cfg_inst.lp_ea()); + + for (const auto &cfg_ref : cfg_inst.xrefs()) { + if (FillXref(module, inst.get(), cfg_ref, pointer_size, xrefs)) { + ++xrefs; } } } - - block->instructions.emplace_back(inst); } + } + } - func->blocks[block->ea].reset(block); + auto num_preserved_reg_sets = cfg.preserved_regs_size() + cfg.dead_regs_size(); + module->preserved_regs.resize(static_cast(num_preserved_reg_sets)); + auto i = 0; + for (; i < cfg.preserved_regs_size(); ++i) { + auto ®_set = module->preserved_regs[static_cast(i)]; + const auto &cfg_reg_set = cfg.preserved_regs(i); + for (const auto ®_name : cfg_reg_set.registers()) { + reg_set.reg_names.push_back(reg_name); + } + for (const auto &cfg_range : cfg_reg_set.ranges()) { + const auto ea = static_cast(cfg_range.begin_ea()); + if (cfg_range.has_end_ea()) { + const auto end_ea = static_cast(cfg_range.end_ea()); + module->ea_to_range_preserved_regs.emplace( + ea, std::make_pair(end_ea, ®_set)); + } else { + module->ea_to_inst_preserved_regs.emplace(ea, ®_set); + } + } + } + + for (auto j = 0; i < num_preserved_reg_sets; ++i, ++j) { + auto ®_set = module->preserved_regs[static_cast(i)]; + const auto &cfg_reg_set = cfg.dead_regs(j); + for (const auto ®_name : cfg_reg_set.registers()) { + reg_set.reg_names.push_back(reg_name); + } + for (const auto &cfg_range : cfg_reg_set.ranges()) { + const auto ea = static_cast(cfg_range.begin_ea()); + CHECK(!cfg_range.has_end_ea()); + module->ea_to_inst_killed_regs.emplace(ea, ®_set); + } + } + + auto prune_segments = [=] (void) { + for (auto &seg : module->segments) { + if (seg.get() != seg->Get()) { + module->unused_segments.emplace_back(std::move(seg)); + } } - // Validate the successor relationships of this block. - for (const auto &cfg_block : cfg_func.blocks()) { - for (auto succ_ea : cfg_block.successor_eas()) { - auto ea = static_cast(succ_ea); - auto succ_is_block = 0 != func->blocks.count(ea); - auto succ_is_func = module->ea_to_func.count(ea); + std::sort(module->segments.begin(), module->segments.end(), + [] (const std::unique_ptr &a, + const std::unique_ptr &b) { + return a.get() > b.get(); + }); - LOG_IF(ERROR, !succ_is_block && !succ_is_func) - << "Successor " << std::hex << ea << " of block " - << std::hex << static_cast(cfg_block.ea()) - << " in function " << static_cast(cfg_func.ea()) - << " does not exist"; + while (!module->segments.empty() && !module->segments.back()) { + module->segments.pop_back(); + } + }; + + prune_segments(); + + if (!FLAGS_disable_adjacent_segment_merging) { + + // Order the segments in increasing order of their starting address, and + // groups external segments, which may overlap internal ones due to + // external vars, together, and internal segments together, so that we + // don't miss merging opportunities. + std::sort(module->segments.begin(), module->segments.end(), + [] (const std::unique_ptr &a, + const std::unique_ptr &b) { + if (a->is_external == b->is_external) { + return a->ea < b->ea; + } else { + return a->is_external < b->is_external; + } + }); + + auto merged = false; + + for (auto i = module->segments.size(); i > 1u; ) { + auto &seg = module->segments[--i]; + auto &prev_seg = module->segments[i - 1u]; + if ((prev_seg->ea + prev_seg->size) == seg->ea && + !prev_seg->is_external && !seg->is_external) { + merged = true; + + LOG(WARNING) + << "Merging adjacent segments " << prev_seg->name << " at " + << std::hex << prev_seg->ea << " and " + << seg->name << " at " << seg->ea << std::dec; + + prev_seg->size += seg->size; + seg->size = 0; + + prev_seg->entries.insert( + std::make_move_iterator(seg->entries.begin()), + std::make_move_iterator(seg->entries.end())); + seg->entries.clear(); + + if (!seg->is_read_only) { + LOG_IF(WARNING, prev_seg->is_read_only) + << "Marking read-only segment " << prev_seg->name << " at " + << std::hex << prev_seg->ea << " as read/write due to merging" + << std::dec; + prev_seg->is_read_only = false; + } + + seg->ForwardTo(prev_seg.get()); + } + } + + if (merged) { + prune_segments(); + } + } + + // Order the segments in increasing order of size. + std::sort(module->segments.begin(), module->segments.end(), + [] (const std::unique_ptr &a, + const std::unique_ptr &b) { + return a->Get()->size < b->Get()->size; + }); + + for (auto &entry : module->ea_to_seg) { + entry.second = entry.second->Get(); + } + + for (auto &entry : module->ea_to_func) { + const auto func = const_cast(entry.second->Get()); + entry.second = func; + + if (!func->is_exported && !func->is_external) { + continue; + } + + // The ABI-specific declaration that we create from `ll_func` might + // differ in subtle ways from the actual prototype of `ll_func`. E.g. + // On 32-bit, returning an `i64` migth turn into returning `[2 x i32]` + // or returning `{i32, i32}`. + if (auto ll_func = gModule->getFunction(func->name); ll_func) { + if (ll_func->hasPrivateLinkage() || ll_func->hasInternalLinkage()) { + func->is_exported = false; + } + + if (!ll_func->hasNUsesOrMore(1)) { + LOG(INFO) + << "Erasing " << ll_func->getName().str(); + ll_func->eraseFromParent(); + } else { + LOG(ERROR) + << "Renaming existing LLVM function " << func->name + << " to avoid future name clashes with external function at " + << std::hex << func->ea << std::dec; + ll_func->setName(func->name + "__original"); + } + } + } + + for (auto &entry : module->ea_to_var) { + auto &var = const_cast(entry.second); + var = var->Get(); + var->segment = var->segment->Get(); + } + + for (auto &seg : module->segments) { + if (!seg->is_external) { + seg->padding = seg->ea & 4095u; + } + + for (auto &entry : seg->entries) { + if (const auto xref = entry.second.xref.get(); xref) { + if (xref->segment) { + xref->segment = xref->segment->Get(); + } + if (xref->target_segment) { + xref->target_segment = xref->target_segment->Get(); + } } } } @@ -1022,20 +1443,85 @@ NativeModule *ReadProtoBuf(const std::string &file_name, return module; } -NativeFunction *NativeModule::TryGetFunction(uint64_t ea) const { +const NativeSegment *NativeModule::TryGetSegment(llvm::StringRef name) const { + for (const auto &seg : segments) { + if (name == seg->lifted_name) { + return seg->Get(); + } + } + return nullptr; +} + +const NativeSegment *NativeModule::TryGetSegment(uint64_t ea) const { + for (const auto &seg_ : segments) { + const auto seg = seg_->Get(); + auto seg_end = seg->ea + seg->size; + if (seg->ea <= ea && ea < seg_end) { + return seg; + } + } + return nullptr; +} + +const NativeFunction *NativeModule::TryGetFunction(uint64_t ea) const { auto func_it = ea_to_func.find(ea); if (func_it == ea_to_func.end()) { return nullptr; } - return reinterpret_cast(func_it->second->Get()); + return func_it->second; } -NativeVariable *NativeModule::TryGetVariable(uint64_t ea) const { +const NativeVariable *NativeModule::TryGetVariable(uint64_t ea) const { auto var_it = ea_to_var.find(ea); if (var_it == ea_to_var.end()) { return nullptr; } - return reinterpret_cast(var_it->second->Get()); + return var_it->second; +} + +// Try to get the block containing `inst_ea`. +const NativeBlock *NativeModule::TryGetBlock( + uint64_t inst_ea, const NativeBlock *curr) const { + + for (uint64_t block_ea = inst_ea, i = 0u; + block_ea && i < 256u; block_ea -= 1, ++i) { + if (curr && curr->ea <= inst_ea && inst_ea <= curr->last_inst_ea) { + return curr; + } + + auto block_it = ea_to_block.find(block_ea); + if (block_it != ea_to_block.end()) { + curr = block_it->second.get(); + } else { + curr = nullptr; + } + } + + return nullptr; +} + +// Try to get the instruction at `ea`. +const NativeInstruction *NativeModule::TryGetInstruction(uint64_t ea) const { + auto inst_it = ea_to_inst.find(ea); + if (inst_it == ea_to_inst.end()) { + return nullptr; + } + return inst_it->second.get(); +} + +NativeSegment *NativeModule::TryGetSegment(uint64_t ea) { + return const_cast( + const_cast(this)->TryGetSegment(ea)); +} + +NativeFunction *NativeModule::TryGetFunction(uint64_t ea) { + return const_cast( + const_cast(this)->TryGetFunction(ea)); +} + +NativeVariable *NativeModule::TryGetVariable(uint64_t ea) { + return const_cast( + const_cast(this)->TryGetVariable(ea)); } } // namespace mcsema diff --git a/mcsema/CFG/CFG.h b/mcsema/CFG/CFG.h index 89e59034b..2aaf7c7bf 100644 --- a/mcsema/CFG/CFG.h +++ b/mcsema/CFG/CFG.h @@ -1,17 +1,18 @@ /* - * Copyright (c) 2017 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ #pragma once @@ -24,10 +25,16 @@ #include #include +#include +#include #include +#include + namespace llvm { class Constant; +class Function; +class FunctionType; class GlobalVariable; } // namespace llvm namespace mcsema { @@ -35,34 +42,43 @@ namespace mcsema { struct NativeVariable; struct NativeStackVariable; struct NativeExceptionFrame; -struct NativeFunction; - struct NativeExternalVariable; struct NativeExternalFunction; - +struct NativeFunction; +struct NativeModule; struct NativeSegment; struct NativeXref; +struct NativePreservedRegisters { + llvm::SmallVector reg_names; +}; + +// A cross reference (xref) from an instruction to something. +struct NativeInstructionXref { + public: + // Target ea of the xref. + uint64_t target_ea{0}; + + // Bitmask to apply to this xref. Zero if none. + uint64_t mask{0}; +}; + struct NativeInstruction { - uint64_t ea = 0; - uint64_t lp_ea = 0; - std::string bytes; + uint64_t ea{0}; + uint64_t lp_ea{0}; - const NativeXref *flow = nullptr; - const NativeXref *mem = nullptr; - const NativeXref *imm = nullptr; - const NativeXref *disp = nullptr; - const NativeXref *offset_table = nullptr; - - const NativeStackVariable *stack_var = nullptr; - - bool does_not_return; + const NativeInstructionXref *flow{nullptr}; + const NativeInstructionXref *mem{nullptr}; + const NativeInstructionXref *imm{nullptr}; + const NativeInstructionXref *disp{nullptr}; + const NativeInstructionXref *offset_table{nullptr}; }; struct NativeBlock { - uint64_t ea = 0; - std::vector> instructions; - std::unordered_set successor_eas; + uint64_t ea{0}; + uint64_t last_inst_ea{0}; + llvm::SmallVector successor_eas; + bool is_referenced_by_data{false}; }; // Generic object used in the binary. This includes both internally and @@ -70,100 +86,218 @@ struct NativeBlock { // have meaningful and unique effective addresses, usually pointing to // some kind of relocation section within the binary. struct NativeObject { - NativeObject(void); + explicit NativeObject(NativeModule *module_); + virtual ~NativeObject(void) = default; + + // Module containing this object. + NativeModule * const module; // Forwarding pointer to resolve duplicates and such. mutable NativeObject *forward; - uint64_t ea = 0; - std::string name; // Name in the binary. + uint64_t ea{0}; + + // Some segments don't begin on page boundaries, and so we often add + // padding bytes to the beginning of the LLVM global variable that + // represents the segment to fill its size out so that we can page-align + // the segment. This is important on fixed-width architectures like AArch64 + // because often two instructions are used to compute an address: one + // instruction for the high bits, and another for the low bits. Often, the + // instruction used for the low bits is an OR instruction. This means that + // the original low N bits of a given effective address, and the lifted low + // N bits corresponding to logically the same object, must match, else some + // bits might be "lost". If ADDs were always used then this wouldn't be + // a problem, but such is life. + uint64_t padding{0}; + + mutable std::string name; // Name in the binary. std::string lifted_name; // Name in the bitcode. - bool is_external = false; - bool is_exported = false; - bool is_thread_local = false; + // TODO(pag): Rework all these booleans into a comprehensive visibility + // enumaration that captures the various behaviours. + bool is_external{false}; + bool is_exported{false}; + bool is_thread_local{false}; void ForwardTo(NativeObject *dest) const; + + virtual llvm::Constant *Pointer(void) const; + virtual llvm::Constant *Address(void) const; + + protected: const NativeObject *Get(void) const; NativeObject *Get(void); }; // Global variable defined inside of the lifted binary. struct NativeVariable : public NativeObject { - const NativeSegment *segment = nullptr; - mutable llvm::Constant *address = nullptr; + public: + using NativeObject::NativeObject; + + virtual ~NativeVariable(void) = default; + + const NativeSegment *segment{nullptr}; + + llvm::Constant *Pointer(void) const override; + llvm::Constant *Address(void) const override; + + inline const NativeVariable *Get(void) const { + return reinterpret_cast(this->NativeObject::Get()); + } + + NativeVariable *Get(void) { + return reinterpret_cast(this->NativeObject::Get()); + } }; // Function that is defined inside the binary. struct NativeFunction : public NativeObject { - std::unordered_map> blocks; - std::vector stack_vars; - std::vector eh_frame; - mutable llvm::Function *function = nullptr; - mutable llvm::Value *stack_ptr_var = nullptr; - mutable llvm::Value *frame_ptr_var = nullptr; -}; + public: + using NativeObject::NativeObject; -struct NativeStackVariable : public NativeObject { - uint64_t size = 0; - int64_t offset = 0; - std::unordered_map refs; - mutable llvm::Value *llvm_var = nullptr; + virtual ~NativeFunction(void) = default; + + inline const NativeFunction *Get(void) const { + return reinterpret_cast(this->NativeObject::Get()); + } + + NativeFunction *Get(void) { + return reinterpret_cast(this->NativeObject::Get()); + } + + llvm::SmallVector, 2> eh_frame; + + // Defined in `Callback.cpp`. + llvm::Constant *Pointer(void) const override; + llvm::Constant *Address(void) const override; + + bool IsNoReturn(void) const; + + mutable const anvill::FunctionDecl *decl{nullptr}; + mutable llvm::Function *function{nullptr}; + mutable llvm::Function *lifted_function{nullptr}; + mutable llvm::Function *callable_lifted_function{nullptr}; + + std::vector blocks; }; struct NativeExceptionFrame : public NativeObject { - uint64_t start_ea = 0; - uint64_t end_ea = 0; - uint64_t lp_ea = 0; - uint64_t action_index = 0; - mutable llvm::Value *lp_var = nullptr; + public: + using NativeObject::NativeObject; + virtual ~NativeExceptionFrame(void) = default; + + uint64_t start_ea{0}; + uint64_t end_ea{0}; + uint64_t lp_ea{0}; + uint64_t action_index{0}; + mutable llvm::Value *lp_var{nullptr}; std::unordered_map type_var; }; // Function that is defined outside of the binary. struct NativeExternalFunction : public NativeFunction { - NativeExternalFunction(void); + public: + explicit NativeExternalFunction(NativeModule *module_); + virtual ~NativeExternalFunction(void) = default; + + inline const NativeExternalFunction *Get(void) const { + return reinterpret_cast( + this->NativeObject::Get()); + } + + NativeExternalFunction *Get(void) { + return reinterpret_cast(this->NativeObject::Get()); + } + + // Defined in `External.cpp`. + llvm::Constant *Pointer(void) const override; + + bool is_weak{false}; + unsigned num_args{0}; - bool is_explicit = false; - bool is_weak = false; - unsigned num_args = 0; llvm::CallingConv::ID cc; }; // Global variable defined outside of the lifted binary. struct NativeExternalVariable : public NativeVariable { - uint64_t size = 0; - bool is_weak; + public: + using NativeVariable::NativeVariable; + + virtual ~NativeExternalVariable(void) = default; + + inline const NativeExternalVariable *Get(void) const { + return reinterpret_cast( + this->NativeObject::Get()); + } + + NativeExternalVariable *Get(void) { + return reinterpret_cast(this->NativeObject::Get()); + } + + // Defined in `External.cpp`. + llvm::Constant *Pointer(void) const override; + llvm::Constant *Address(void) const override; + + uint64_t size{0}; + bool is_weak{false}; }; -// A cross-reference to something. +// A cross-reference (xref) from data to something. struct NativeXref { - enum FixupKind { + enum FixupKind : uint32_t { kAbsoluteFixup, kThreadLocalOffsetFixup }; - uint64_t width = 0; // In bytes. - uint64_t ea = 0; // Location of the xref within its segment. - uint64_t mask = 0; // Bitmask to apply to this xref. Zero if none. - const NativeSegment *segment = nullptr; // Segment containing the xref. + // Width (in bytes) of this cross-reference. This only makes sense for xrefs + // embedded in the data section. + uint32_t width{0}; - uint64_t target_ea = 0; - std::string target_name; - const NativeSegment *target_segment = nullptr; // Target segment of the xref, if any. + // Fixup type of this data-to-something xref. + FixupKind fixup_kind{kAbsoluteFixup}; - FixupKind fixup_kind; + // Location of the xref within its segment. + uint64_t ea{0}; - const NativeVariable *var = nullptr; - const NativeFunction *func = nullptr; + // Target ea of the xref. + uint64_t target_ea{0}; + + // Bitmask to apply to this xref. Zero if none. + uint64_t mask{0}; + + // Segment containing `ea`. + mutable const NativeSegment *segment{nullptr}; + + // Segment containin `target_ea`. + mutable const NativeSegment *target_segment{nullptr}; + + // Global variable associated with `target_ea`. + const NativeVariable *var{nullptr}; + + // Function associated with `target_ea`. + const NativeFunction *func{nullptr}; }; struct NativeBlob { - uint64_t ea = 0; - std::string data; + uint64_t ea{0}; + unsigned size{0}; + bool is_zero{false}; }; struct NativeSegment : public NativeObject { + public: + using NativeObject::NativeObject; + + virtual ~NativeSegment(void) = default; + + inline const NativeSegment *Get(void) const { + return reinterpret_cast(this->NativeObject::Get()); + } + + NativeSegment *Get(void) { + return reinterpret_cast(this->NativeObject::Get()); + } + struct Entry { Entry(void) = default; Entry(uint64_t, uint64_t, NativeXref *, NativeBlob *); @@ -174,45 +308,127 @@ struct NativeSegment : public NativeObject { std::unique_ptr blob; }; - uint64_t size = 0; - bool is_read_only = false; + // Size, in bytes, of this segment. + uint64_t size{0}; + + // Whether or not this segment is read-only. + bool is_read_only{false}; + + // The external variable associated with this segment, if any. + mutable NativeExternalVariable *as_extern_var{nullptr}; // Partition of entries, which are either cross-references, or opaque // blobs of bytes. The ordering of entries is significant. std::map entries; - mutable bool needs_initializer = true; - mutable llvm::GlobalVariable *seg_var = nullptr; + // Get or lazily create a global variable for this segment. + // + // NOTE(pag): Defined in Segment.cpp. + llvm::Constant *Pointer(void) const override; + llvm::Constant *Address(void) const override; }; -// NOTE(pag): Using an `std::map` (as opposed to an `std::unordered_map`) is -// intentional so that we can get the ordering of `NativeSegment`s -// by their `ea`s. -using SegmentMap = std::map>; +struct NativeModule : anvill::Program { -struct NativeModule { std::unordered_set exported_vars; - std::unordered_set exported_funcs; - SegmentMap segments; + // NOTE(pag): Using an `std::map` (as opposed to an `std::unordered_map`) is + // intentional so that we can get the ordering of `NativeSegment`s + // by their `ea`s. + std::map ea_to_seg; - std::unordered_map> ea_to_func; + std::vector> variables; + std::vector> functions; - std::unordered_map - name_to_extern_func; + // The lifted segments, including those invented for external variables. + // + // NOTE(pag): These are sorted by segment size (smallest first). + std::vector> segments; + std::vector> unused_segments; + + // All known basic blocks. + std::unordered_map> ea_to_block; + + // All known instructions and their cross-references. + std::unordered_map> ea_to_inst; + + // All local and global functions. + std::unordered_map ea_to_func; // Represent global and external variables. - std::unordered_map> ea_to_var; - std::unordered_map - name_to_extern_var; + std::unordered_map ea_to_var; - NativeFunction *TryGetFunction(uint64_t ea) const; - NativeVariable *TryGetVariable(uint64_t ea) const; + const NativeSegment *TryGetSegment(llvm::StringRef name) const; + const NativeSegment *TryGetSegment(uint64_t ea) const; + const NativeFunction *TryGetFunction(uint64_t ea) const; + const NativeVariable *TryGetVariable(uint64_t ea) const; - std::vector> dead_vars; + // Try to get the block containing `inst_ea`. + const NativeBlock *TryGetBlock( + uint64_t inst_ea, const NativeBlock *curr) const; + + // Try to get the instruction at `ea`. + const NativeInstruction *TryGetInstruction(uint64_t ea) const; + + NativeSegment *TryGetSegment(uint64_t ea); + NativeFunction *TryGetFunction(uint64_t ea); + NativeVariable *TryGetVariable(uint64_t ea); + + // Sets of registers that may be preserved. + std::vector preserved_regs; + + // Backup vector of instruction bytes. + std::vector> inst_bytes; + + // Maps effective addresses to sets of registers that are preserved around + // the instruction at this address. This corresponds to registers preserved + // around a function call. + std::unordered_map + ea_to_inst_preserved_regs; + + // Maps effective addresses to sets of registers that are killed just after + // the instruction at this address. + std::unordered_map + ea_to_inst_killed_regs; + + // Maps effective addresses to sets of registers that are preserved around + // the instruction at this address. This corresponds to registers preserved + // around a function call. + std::unordered_multimap> + ea_to_range_preserved_regs; + + template + void ForEachInstructionPreservedRegister(uint64_t ea, T cb) const { + auto reg_set_it = ea_to_inst_preserved_regs.find(ea); + if (reg_set_it != ea_to_inst_preserved_regs.end()) { + for (const auto ®_name : reg_set_it->second->reg_names) { + cb(reg_name); + } + } + } + + template + void ForEachInstructionKilledRegister(uint64_t ea, T cb) const { + auto reg_set_it = ea_to_inst_killed_regs.find(ea); + if (reg_set_it != ea_to_inst_killed_regs.end()) { + for (const auto ®_name : reg_set_it->second->reg_names) { + cb(reg_name); + } + } + } + + template + void ForEachRangePreservedRegister(uint64_t ea, T cb) const { + for (auto reg_set_it = ea_to_range_preserved_regs.find(ea); + (reg_set_it != ea_to_range_preserved_regs.end() && + reg_set_it->first == ea); + ++reg_set_it) { + cb(reg_set_it->second.first, *(reg_set_it->second.second)); + } + } }; NativeModule *ReadProtoBuf(const std::string &file_name, uint64_t pointer_size); -} // namespace mcsema \ No newline at end of file +} // namespace mcsema diff --git a/mcsema/CFG/CFG.proto b/mcsema/CFG/CFG.proto index 106240cd7..b6f052101 100644 --- a/mcsema/CFG/CFG.proto +++ b/mcsema/CFG/CFG.proto @@ -1,16 +1,18 @@ -// Copyright (c) 2017 Trail of Bits, Inc. +// Copyright (c) 2020 Trail of Bits, Inc. // -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. // -// http://www.apache.org/licenses/LICENSE-2.0 +// 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 Affero General Public License for more details. // -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + syntax = "proto2"; @@ -29,16 +31,25 @@ syntax = "proto2"; package mcsema; +message PreservationRange { + required int64 begin_ea = 1; + optional int64 end_ea = 2; +} + +message PreservedRegisters { + // List of registers that are preserved. + repeated string registers = 1; + + // Address of a call instruction around which the registers are preserved, + // or of function bodies. In the case of function bodies, we will have + // one range per (entry, exit) pair, i.e. if a function has N returns, + // then we'll have N ranges. + repeated PreservationRange ranges = 2; +} + // A cross-reference contained within an instruction. // Similar to reference from Segment message CodeReference { - enum TargetType { - // Examples: callq 8c0 <_ZN1AC2EPKc> - CodeTarget = 0; - // Example: lea 0x20094a(%rip),%rdi # 201049 - DataTarget = 1; - } - enum OperandType { // Example: mov $0x617400,%r8d ImmediateOperand = 0; @@ -59,32 +70,21 @@ message CodeReference { OffsetTable = 4; } - enum Location { - Internal = 0; - // Is it to external symbol? - External = 1; - } + required OperandType operand_type = 1; + required int64 ea = 2; - required TargetType target_type = 1; - required OperandType operand_type = 2; - required Location location = 3; - required int64 ea = 4; - - // For aarch64, since instruction are 32-bit and there may be the need to - // build up 64-bit address - optional int64 mask = 5; - optional string name = 6; + // For aarch64 since instruction are 32-bit and there may be the need to build + // up 64-bit address across multiple instructions using immediate/displacement operands. + optional int64 mask = 3; } // An instruction inside of a block. message Instruction { required int64 ea = 1; - required bytes bytes = 2; - repeated CodeReference xrefs = 3; - optional bool local_noreturn = 4; + repeated CodeReference xrefs = 2; // Address of the landing pad - optional uint64 lp_ea = 5; + optional uint64 lp_ea = 3; } // A basic block of instructions inside of a function. @@ -92,6 +92,45 @@ message Block { required int64 ea = 1; repeated Instruction instructions = 2; repeated int64 successor_eas = 3; + required bool is_referenced_by_data = 4; +} + +// The location of something stored in a relative position in memory. +message MemoryLocation { + required string register = 1; // Base register. + optional int64 offset = 2; // Displacement from the base register. +} + +message ValueDecl { + required string type = 1; + + // The value is either resident in memory or in a register. + optional MemoryLocation memory = 2; + optional string register = 3; + + optional string name = 4; +} + +enum CallingConvention { + C = 0; + X86_StdCall = 64; + X86_FastCall = 65; + X86_ThisCall = 70; + X86_64_SysV = 78; + Win64 = 79; + X86_VectorCall = 80; + X86_RegCall = 92; + AArch64_VectorCall = 97; +} + +message FunctionDecl { + repeated ValueDecl parameters = 1; + repeated ValueDecl return_values = 2; + required ValueDecl return_address = 3; + required ValueDecl return_stack_pointer = 4; + required bool is_variadic = 5; + required bool is_noreturn = 6; + required CallingConvention calling_convention = 7; } // A function with an implementation inside of the binary. @@ -102,8 +141,10 @@ message Function { // Can someone else link against the code and use this function? required bool is_entrypoint = 3; optional string name = 4; - repeated StackVariable stack_vars = 5; - repeated ExceptionFrame eh_frame = 6; + repeated ExceptionFrame eh_frame = 5; + + // Anvill specification of this function. + optional FunctionDecl decl = 6; } /* A function that is used or referenced within binary, but not implemented @@ -121,17 +162,22 @@ message ExternalFunction { } required string name = 1; + // Address of relocation. Other entry with ea of thunk can be added as well required int64 ea = 2; required CallingConvention cc = 3; + // Does this function return? required bool has_return = 4; required bool no_return = 5; required int32 argument_count = 6; + // Linkage information required bool is_weak = 7; - optional string signature = 8; + + // Anvill specification of this function. + optional FunctionDecl decl = 8; } // A named symbol defined outside of the binary. For example, `stderr`. @@ -174,11 +220,8 @@ message DataReference { required int32 width = 2; // Information about the target of the cross-reference. - required int64 target_ea = 4; - required string target_name = 5; - required bool target_is_code = 6; - - required TargetFixupKind target_fixup_kind = 8; + required int64 target_ea = 3; + required TargetFixupKind target_fixup_kind = 4; } /* Represents a named location within a data segment. Variables will often @@ -218,16 +261,6 @@ message ExceptionFrame { repeated ExternalVariable ttype = 7; } -// This is optional information, but leads to better lift -message StackVariable { - required string name = 1; - required uint64 size = 2; - required int64 sp_offset = 3; - optional bool has_frame = 4; - optional string reg_name = 5; - repeated Reference ref_eas = 6; -} - // Global variable from original binary message GlobalVariable { required int64 ea = 1; @@ -280,4 +313,7 @@ message Module { repeated ExternalVariable external_vars = 5; repeated GlobalVariable global_vars = 8; + + repeated PreservedRegisters preserved_regs = 9; + repeated PreservedRegisters dead_regs = 10; } diff --git a/mcsema/OS/Linux/ABI_libc.c b/mcsema/OS/Linux/ABI_libc.c deleted file mode 100644 index 71a877a53..000000000 --- a/mcsema/OS/Linux/ABI_libc.c +++ /dev/null @@ -1,5411 +0,0 @@ - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated" -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - -#include "ABI_libc.h" - // mcsema ABI library, automatically generated by cparser/make_abi-library.py - // see: https://github.com/pgoodman/cparser/ - -__attribute__((used)) -void *__mcsema_externs[] = { - // skipping because function pointer args: mcheck - // skipping because function pointer args: mcheck_pedantic - //BuiltIn(void) mcheck_check_all(); - (void *)(mcheck_check_all), - //Use(Enum(enum mcheck_status)) mprobe(Pointer(BuiltIn(void))); - (void *)(mprobe), - //BuiltIn(void) mtrace(); - (void *)(mtrace), - //BuiltIn(void) muntrace(); - (void *)(muntrace), - //BuiltIn(void) _dl_mcount_wrapper_check(Pointer(BuiltIn(void))); - (void *)(_dl_mcount_wrapper_check), - //Pointer(BuiltIn(void)) dlopen(Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int)); - (void *)(dlopen), - //BuiltIn(int) dlclose(Pointer(BuiltIn(void))); - (void *)(dlclose), - //Pointer(BuiltIn(void)) dlsym(Pointer(restrict BuiltIn(void)), Pointer(restrict Attributed(const , BuiltIn(char)))); - (void *)(dlsym), - //Pointer(BuiltIn(void)) dlmopen(Use(TypeDef(Lmid_t, BuiltIn(long))), Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int)); - (void *)(dlmopen), - //Pointer(BuiltIn(void)) dlvsym(Pointer(restrict BuiltIn(void)), Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Attributed(const , BuiltIn(char)))); - (void *)(dlvsym), - //Pointer(BuiltIn(char)) dlerror(); - (void *)(dlerror), - //BuiltIn(int) dladdr(Pointer(Attributed(const , BuiltIn(void))), Pointer(Use(TypeDef(Dl_info, Struct(struct anon_struct_0))))); - (void *)(dladdr), - //BuiltIn(int) dladdr1(Pointer(Attributed(const , BuiltIn(void))), Pointer(Use(TypeDef(Dl_info, Struct(struct anon_struct_0)))), Pointer(Pointer(BuiltIn(void))), BuiltIn(int)); - (void *)(dladdr1), - //BuiltIn(int) dlinfo(Pointer(restrict BuiltIn(void)), BuiltIn(int), Pointer(restrict BuiltIn(void))); - (void *)(dlinfo), - //BuiltIn(int) access(Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int)); - (void *)(access), - //BuiltIn(int) euidaccess(Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int)); - (void *)(euidaccess), - //BuiltIn(int) eaccess(Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int)); - (void *)(eaccess), - //BuiltIn(int) faccessat(BuiltIn(int), Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int), BuiltIn(int)); - (void *)(faccessat), - //Use(TypeDef(__off_t, BuiltIn(long))) lseek(BuiltIn(int), Use(TypeDef(__off_t, BuiltIn(long))), BuiltIn(int)); - (void *)(lseek), - //Use(TypeDef(__off64_t, BuiltIn(long))) lseek64(BuiltIn(int), Use(TypeDef(__off64_t, BuiltIn(long))), BuiltIn(int)); - (void *)(lseek64), - //BuiltIn(int) close(BuiltIn(int)); - (void *)(close), - //Use(TypeDef(ssize_t, Use(TypeDef(__ssize_t, BuiltIn(long))))) read(BuiltIn(int), Pointer(BuiltIn(void)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(read), - //Use(TypeDef(ssize_t, Use(TypeDef(__ssize_t, BuiltIn(long))))) write(BuiltIn(int), Pointer(Attributed(const , BuiltIn(void))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(write), - //Use(TypeDef(ssize_t, Use(TypeDef(__ssize_t, BuiltIn(long))))) pread(BuiltIn(int), Pointer(BuiltIn(void)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Use(TypeDef(__off_t, BuiltIn(long)))); - (void *)(pread), - //Use(TypeDef(ssize_t, Use(TypeDef(__ssize_t, BuiltIn(long))))) pwrite(BuiltIn(int), Pointer(Attributed(const , BuiltIn(void))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Use(TypeDef(__off_t, BuiltIn(long)))); - (void *)(pwrite), - //Use(TypeDef(ssize_t, Use(TypeDef(__ssize_t, BuiltIn(long))))) pread64(BuiltIn(int), Pointer(BuiltIn(void)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Use(TypeDef(__off64_t, BuiltIn(long)))); - (void *)(pread64), - //Use(TypeDef(ssize_t, Use(TypeDef(__ssize_t, BuiltIn(long))))) pwrite64(BuiltIn(int), Pointer(Attributed(const , BuiltIn(void))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Use(TypeDef(__off64_t, BuiltIn(long)))); - (void *)(pwrite64), - //BuiltIn(int) pipe(Array(BuiltIn(int))); - (void *)(pipe), - //BuiltIn(int) pipe2(Array(BuiltIn(int)), BuiltIn(int)); - (void *)(pipe2), - //Attributed(unsigned , BuiltIn(int)) alarm(Attributed(unsigned , BuiltIn(int))); - (void *)(alarm), - //Attributed(unsigned , BuiltIn(int)) sleep(Attributed(unsigned , BuiltIn(int))); - (void *)(sleep), - //Use(TypeDef(__useconds_t, Attributed(unsigned , BuiltIn(int)))) ualarm(Use(TypeDef(__useconds_t, Attributed(unsigned , BuiltIn(int)))), Use(TypeDef(__useconds_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(ualarm), - //BuiltIn(int) usleep(Use(TypeDef(__useconds_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(usleep), - //BuiltIn(int) pause(); - (void *)(pause), - //BuiltIn(int) chown(Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(__uid_t, Attributed(unsigned , BuiltIn(int)))), Use(TypeDef(__gid_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(chown), - //BuiltIn(int) fchown(BuiltIn(int), Use(TypeDef(__uid_t, Attributed(unsigned , BuiltIn(int)))), Use(TypeDef(__gid_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(fchown), - //BuiltIn(int) lchown(Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(__uid_t, Attributed(unsigned , BuiltIn(int)))), Use(TypeDef(__gid_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(lchown), - //BuiltIn(int) fchownat(BuiltIn(int), Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(__uid_t, Attributed(unsigned , BuiltIn(int)))), Use(TypeDef(__gid_t, Attributed(unsigned , BuiltIn(int)))), BuiltIn(int)); - (void *)(fchownat), - //BuiltIn(int) chdir(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(chdir), - //BuiltIn(int) fchdir(BuiltIn(int)); - (void *)(fchdir), - //Pointer(BuiltIn(char)) getcwd(Pointer(BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(getcwd), - //Pointer(BuiltIn(char)) get_current_dir_name(); - (void *)(get_current_dir_name), - //Pointer(BuiltIn(char)) getwd(Pointer(BuiltIn(char))); - (void *)(getwd), - //BuiltIn(int) dup(BuiltIn(int)); - (void *)(dup), - //BuiltIn(int) dup2(BuiltIn(int), BuiltIn(int)); - (void *)(dup2), - //BuiltIn(int) dup3(BuiltIn(int), BuiltIn(int), BuiltIn(int)); - (void *)(dup3), - //BuiltIn(int) execve(Pointer(Attributed(const , BuiltIn(char))), Array(Pointer(const BuiltIn(char))), Array(Pointer(const BuiltIn(char)))); - (void *)(execve), - //BuiltIn(int) fexecve(BuiltIn(int), Array(Pointer(const BuiltIn(char))), Array(Pointer(const BuiltIn(char)))); - (void *)(fexecve), - //BuiltIn(int) execv(Pointer(Attributed(const , BuiltIn(char))), Array(Pointer(const BuiltIn(char)))); - (void *)(execv), - // skipping because varargs function: execle - // skipping because varargs function: execl - //BuiltIn(int) execvp(Pointer(Attributed(const , BuiltIn(char))), Array(Pointer(const BuiltIn(char)))); - (void *)(execvp), - // skipping because varargs function: execlp - //BuiltIn(int) execvpe(Pointer(Attributed(const , BuiltIn(char))), Array(Pointer(const BuiltIn(char))), Array(Pointer(const BuiltIn(char)))); - (void *)(execvpe), - //BuiltIn(int) nice(BuiltIn(int)); - (void *)(nice), - //BuiltIn(void) _exit(BuiltIn(int)); - (void *)(_exit), - //BuiltIn(long) pathconf(Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int)); - (void *)(pathconf), - //BuiltIn(long) fpathconf(BuiltIn(int), BuiltIn(int)); - (void *)(fpathconf), - //BuiltIn(long) sysconf(BuiltIn(int)); - (void *)(sysconf), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) confstr(BuiltIn(int), Pointer(BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(confstr), - //Use(TypeDef(__pid_t, BuiltIn(int))) getpid(); - (void *)(getpid), - //Use(TypeDef(__pid_t, BuiltIn(int))) getppid(); - (void *)(getppid), - //Use(TypeDef(__pid_t, BuiltIn(int))) getpgrp(); - (void *)(getpgrp), - //Use(TypeDef(__pid_t, BuiltIn(int))) __getpgid(Use(TypeDef(__pid_t, BuiltIn(int)))); - (void *)(__getpgid), - //Use(TypeDef(__pid_t, BuiltIn(int))) getpgid(Use(TypeDef(__pid_t, BuiltIn(int)))); - (void *)(getpgid), - //BuiltIn(int) setpgid(Use(TypeDef(__pid_t, BuiltIn(int))), Use(TypeDef(__pid_t, BuiltIn(int)))); - (void *)(setpgid), - //BuiltIn(int) setpgrp(); - (void *)(setpgrp), - //Use(TypeDef(__pid_t, BuiltIn(int))) setsid(); - (void *)(setsid), - //Use(TypeDef(__pid_t, BuiltIn(int))) getsid(Use(TypeDef(__pid_t, BuiltIn(int)))); - (void *)(getsid), - //Use(TypeDef(__uid_t, Attributed(unsigned , BuiltIn(int)))) getuid(); - (void *)(getuid), - //Use(TypeDef(__uid_t, Attributed(unsigned , BuiltIn(int)))) geteuid(); - (void *)(geteuid), - //Use(TypeDef(__gid_t, Attributed(unsigned , BuiltIn(int)))) getgid(); - (void *)(getgid), - //Use(TypeDef(__gid_t, Attributed(unsigned , BuiltIn(int)))) getegid(); - (void *)(getegid), - //BuiltIn(int) getgroups(BuiltIn(int), Array(Use(TypeDef(__gid_t, Attributed(unsigned , BuiltIn(int)))))); - (void *)(getgroups), - //BuiltIn(int) group_member(Use(TypeDef(__gid_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(group_member), - //BuiltIn(int) setuid(Use(TypeDef(__uid_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(setuid), - //BuiltIn(int) setreuid(Use(TypeDef(__uid_t, Attributed(unsigned , BuiltIn(int)))), Use(TypeDef(__uid_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(setreuid), - //BuiltIn(int) seteuid(Use(TypeDef(__uid_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(seteuid), - //BuiltIn(int) setgid(Use(TypeDef(__gid_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(setgid), - //BuiltIn(int) setregid(Use(TypeDef(__gid_t, Attributed(unsigned , BuiltIn(int)))), Use(TypeDef(__gid_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(setregid), - //BuiltIn(int) setegid(Use(TypeDef(__gid_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(setegid), - //BuiltIn(int) getresuid(Pointer(Use(TypeDef(__uid_t, Attributed(unsigned , BuiltIn(int))))), Pointer(Use(TypeDef(__uid_t, Attributed(unsigned , BuiltIn(int))))), Pointer(Use(TypeDef(__uid_t, Attributed(unsigned , BuiltIn(int)))))); - (void *)(getresuid), - //BuiltIn(int) getresgid(Pointer(Use(TypeDef(__gid_t, Attributed(unsigned , BuiltIn(int))))), Pointer(Use(TypeDef(__gid_t, Attributed(unsigned , BuiltIn(int))))), Pointer(Use(TypeDef(__gid_t, Attributed(unsigned , BuiltIn(int)))))); - (void *)(getresgid), - //BuiltIn(int) setresuid(Use(TypeDef(__uid_t, Attributed(unsigned , BuiltIn(int)))), Use(TypeDef(__uid_t, Attributed(unsigned , BuiltIn(int)))), Use(TypeDef(__uid_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(setresuid), - //BuiltIn(int) setresgid(Use(TypeDef(__gid_t, Attributed(unsigned , BuiltIn(int)))), Use(TypeDef(__gid_t, Attributed(unsigned , BuiltIn(int)))), Use(TypeDef(__gid_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(setresgid), - //Use(TypeDef(__pid_t, BuiltIn(int))) fork(); - (void *)(fork), - //Use(TypeDef(__pid_t, BuiltIn(int))) vfork(); - (void *)(vfork), - //Pointer(BuiltIn(char)) ttyname(BuiltIn(int)); - (void *)(ttyname), - //BuiltIn(int) ttyname_r(BuiltIn(int), Pointer(BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(ttyname_r), - //BuiltIn(int) isatty(BuiltIn(int)); - (void *)(isatty), - //BuiltIn(int) ttyslot(); - (void *)(ttyslot), - //BuiltIn(int) link(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(link), - //BuiltIn(int) linkat(BuiltIn(int), Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int), Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int)); - (void *)(linkat), - //BuiltIn(int) symlink(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(symlink), - //Use(TypeDef(ssize_t, Use(TypeDef(__ssize_t, BuiltIn(long))))) readlink(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(readlink), - //BuiltIn(int) symlinkat(Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(symlinkat), - //Use(TypeDef(ssize_t, Use(TypeDef(__ssize_t, BuiltIn(long))))) readlinkat(BuiltIn(int), Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(readlinkat), - //BuiltIn(int) unlink(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(unlink), - //BuiltIn(int) unlinkat(BuiltIn(int), Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int)); - (void *)(unlinkat), - //BuiltIn(int) rmdir(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(rmdir), - //Use(TypeDef(__pid_t, BuiltIn(int))) tcgetpgrp(BuiltIn(int)); - (void *)(tcgetpgrp), - //BuiltIn(int) tcsetpgrp(BuiltIn(int), Use(TypeDef(__pid_t, BuiltIn(int)))); - (void *)(tcsetpgrp), - //Pointer(BuiltIn(char)) getlogin(); - (void *)(getlogin), - //BuiltIn(int) getlogin_r(Pointer(BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(getlogin_r), - //BuiltIn(int) setlogin(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(setlogin), - //BuiltIn(int) getopt(BuiltIn(int), Pointer(Pointer(const BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(getopt), - //BuiltIn(int) gethostname(Pointer(BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(gethostname), - //BuiltIn(int) sethostname(Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(sethostname), - //BuiltIn(int) sethostid(BuiltIn(long)); - (void *)(sethostid), - //BuiltIn(int) getdomainname(Pointer(BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(getdomainname), - //BuiltIn(int) setdomainname(Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(setdomainname), - //BuiltIn(int) vhangup(); - (void *)(vhangup), - //BuiltIn(int) revoke(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(revoke), - //BuiltIn(int) profil(Pointer(Attributed(unsigned , BuiltIn(short))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Attributed(unsigned , BuiltIn(int))); - (void *)(profil), - //BuiltIn(int) acct(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(acct), - //Pointer(BuiltIn(char)) getusershell(); - (void *)(getusershell), - //BuiltIn(void) endusershell(); - (void *)(endusershell), - //BuiltIn(void) setusershell(); - (void *)(setusershell), - //BuiltIn(int) daemon(BuiltIn(int), BuiltIn(int)); - (void *)(daemon), - //BuiltIn(int) chroot(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(chroot), - //Pointer(BuiltIn(char)) getpass(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(getpass), - //BuiltIn(int) fsync(BuiltIn(int)); - (void *)(fsync), - //BuiltIn(int) syncfs(BuiltIn(int)); - (void *)(syncfs), - //BuiltIn(long) gethostid(); - (void *)(gethostid), - //BuiltIn(void) sync(); - (void *)(sync), - //BuiltIn(int) getpagesize(); - (void *)(getpagesize), - //BuiltIn(int) getdtablesize(); - (void *)(getdtablesize), - //BuiltIn(int) truncate(Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(__off_t, BuiltIn(long)))); - (void *)(truncate), - //BuiltIn(int) truncate64(Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(__off64_t, BuiltIn(long)))); - (void *)(truncate64), - //BuiltIn(int) ftruncate(BuiltIn(int), Use(TypeDef(__off_t, BuiltIn(long)))); - (void *)(ftruncate), - //BuiltIn(int) ftruncate64(BuiltIn(int), Use(TypeDef(__off64_t, BuiltIn(long)))); - (void *)(ftruncate64), - //BuiltIn(int) brk(Pointer(BuiltIn(void))); - (void *)(brk), - //Pointer(BuiltIn(void)) sbrk(Use(TypeDef(intptr_t, Use(TypeDef(__intptr_t, BuiltIn(long)))))); - (void *)(sbrk), - // skipping because varargs function: syscall - //BuiltIn(int) lockf(BuiltIn(int), BuiltIn(int), Use(TypeDef(__off_t, BuiltIn(long)))); - (void *)(lockf), - //BuiltIn(int) lockf64(BuiltIn(int), BuiltIn(int), Use(TypeDef(__off64_t, BuiltIn(long)))); - (void *)(lockf64), - //BuiltIn(int) fdatasync(BuiltIn(int)); - (void *)(fdatasync), - //Pointer(BuiltIn(char)) crypt(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(crypt), - //BuiltIn(void) encrypt(Pointer(BuiltIn(char)), BuiltIn(int)); -// (void *)(encrypt), - //BuiltIn(void) swab(Pointer(restrict Attributed(const , BuiltIn(void))), Pointer(restrict BuiltIn(void)), Use(TypeDef(ssize_t, Use(TypeDef(__ssize_t, BuiltIn(long)))))); - (void *)(swab), - // skipping because function pointer args: _IO_cookie_init - //BuiltIn(int) __underflow(Pointer(Use(TypeDef(_IO_FILE, Use(Struct(struct _IO_FILE)))))); -// (void *)(__underflow), - //BuiltIn(int) __uflow(Pointer(Use(TypeDef(_IO_FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(__uflow), - //BuiltIn(int) __overflow(Pointer(Use(TypeDef(_IO_FILE, Use(Struct(struct _IO_FILE))))), BuiltIn(int)); - (void *)(__overflow), - //BuiltIn(int) _IO_getc(Pointer(Use(TypeDef(_IO_FILE, Use(Struct(struct _IO_FILE)))))); -// (void *)(_IO_getc), -// //BuiltIn(int) _IO_putc(BuiltIn(int), Pointer(Use(TypeDef(_IO_FILE, Use(Struct(struct _IO_FILE)))))); -// (void *)(_IO_putc), -// //BuiltIn(int) _IO_feof(Pointer(Use(TypeDef(_IO_FILE, Use(Struct(struct _IO_FILE)))))); -// (void *)(_IO_feof), -// //BuiltIn(int) _IO_ferror(Pointer(Use(TypeDef(_IO_FILE, Use(Struct(struct _IO_FILE)))))); -// (void *)(_IO_ferror), -// //BuiltIn(int) _IO_peekc_locked(Pointer(Use(TypeDef(_IO_FILE, Use(Struct(struct _IO_FILE)))))); -// (void *)(_IO_peekc_locked), -// //BuiltIn(void) _IO_flockfile(Pointer(Use(TypeDef(_IO_FILE, Use(Struct(struct _IO_FILE)))))); -// (void *)(_IO_flockfile), -// //BuiltIn(void) _IO_funlockfile(Pointer(Use(TypeDef(_IO_FILE, Use(Struct(struct _IO_FILE)))))); -// (void *)(_IO_funlockfile), -// //BuiltIn(int) _IO_ftrylockfile(Pointer(Use(TypeDef(_IO_FILE, Use(Struct(struct _IO_FILE)))))); -// (void *)(_IO_ftrylockfile), -// //BuiltIn(int) _IO_vfscanf(Pointer(restrict Use(TypeDef(_IO_FILE, Use(Struct(struct _IO_FILE))))), Pointer(restrict Attributed(const , BuiltIn(char))), Use(TypeDef(__gnuc_va_list, BuiltIn(__builtin_va_list))), Pointer(restrict BuiltIn(int))); -// (void *)(_IO_vfscanf), -// //BuiltIn(int) _IO_vfprintf(Pointer(restrict Use(TypeDef(_IO_FILE, Use(Struct(struct _IO_FILE))))), Pointer(restrict Attributed(const , BuiltIn(char))), Use(TypeDef(__gnuc_va_list, BuiltIn(__builtin_va_list)))); -// (void *)(_IO_vfprintf), -// //Use(TypeDef(__ssize_t, BuiltIn(long))) _IO_padn(Pointer(Use(TypeDef(_IO_FILE, Use(Struct(struct _IO_FILE))))), BuiltIn(int), Use(TypeDef(__ssize_t, BuiltIn(long)))); -// (void *)(_IO_padn), -// //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) _IO_sgetn(Pointer(Use(TypeDef(_IO_FILE, Use(Struct(struct _IO_FILE))))), Pointer(BuiltIn(void)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); -// (void *)(_IO_sgetn), -// //Use(TypeDef(__off64_t, BuiltIn(long))) _IO_seekoff(Pointer(Use(TypeDef(_IO_FILE, Use(Struct(struct _IO_FILE))))), Use(TypeDef(__off64_t, BuiltIn(long))), BuiltIn(int), BuiltIn(int)); -// (void *)(_IO_seekoff), -// //Use(TypeDef(__off64_t, BuiltIn(long))) _IO_seekpos(Pointer(Use(TypeDef(_IO_FILE, Use(Struct(struct _IO_FILE))))), Use(TypeDef(__off64_t, BuiltIn(long))), BuiltIn(int)); -// (void *)(_IO_seekpos), -// //BuiltIn(void) _IO_free_backup_area(Pointer(Use(TypeDef(_IO_FILE, Use(Struct(struct _IO_FILE)))))); -// (void *)(_IO_free_backup_area), - //BuiltIn(int) remove(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(remove), - //BuiltIn(int) rename(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(rename), - //BuiltIn(int) renameat(BuiltIn(int), Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(renameat), - //Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE))))) tmpfile(); - (void *)(tmpfile), - //Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE))))) tmpfile64(); - (void *)(tmpfile64), - //Pointer(BuiltIn(char)) tmpnam(Pointer(BuiltIn(char))); - (void *)(tmpnam), - //Pointer(BuiltIn(char)) tmpnam_r(Pointer(BuiltIn(char))); - (void *)(tmpnam_r), - //Pointer(BuiltIn(char)) tempnam(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(tempnam), - //BuiltIn(int) fclose(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(fclose), - //BuiltIn(int) fflush(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(fflush), - //BuiltIn(int) fflush_unlocked(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(fflush_unlocked), - //BuiltIn(int) fcloseall(); - (void *)(fcloseall), - //Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE))))) fopen(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Attributed(const , BuiltIn(char)))); - (void *)(fopen), - //Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE))))) freopen(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(freopen), - //Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE))))) fopen64(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Attributed(const , BuiltIn(char)))); - (void *)(fopen64), - //Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE))))) freopen64(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(freopen64), - //Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE))))) fdopen(BuiltIn(int), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(fdopen), - // skipping because function pointer args: fopencookie - //Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE))))) fmemopen(Pointer(BuiltIn(void)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(fmemopen), - //Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE))))) open_memstream(Pointer(Pointer(BuiltIn(char))), Pointer(Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))))); - (void *)(open_memstream), - //BuiltIn(void) setbuf(Pointer(restrict Use(TypeDef(FILE, Use(Struct(struct _IO_FILE))))), Pointer(restrict BuiltIn(char))); - (void *)(setbuf), - //BuiltIn(int) setvbuf(Pointer(restrict Use(TypeDef(FILE, Use(Struct(struct _IO_FILE))))), Pointer(restrict BuiltIn(char)), BuiltIn(int), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(setvbuf), - //BuiltIn(void) setbuffer(Pointer(restrict Use(TypeDef(FILE, Use(Struct(struct _IO_FILE))))), Pointer(restrict BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(setbuffer), - //BuiltIn(void) setlinebuf(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(setlinebuf), - // skipping because varargs function: fprintf - // skipping because varargs function: printf - // skipping because varargs function: sprintf - //BuiltIn(int) vfprintf(Pointer(restrict Use(TypeDef(FILE, Use(Struct(struct _IO_FILE))))), Pointer(restrict Attributed(const , BuiltIn(char))), Use(TypeDef(__gnuc_va_list, BuiltIn(__builtin_va_list)))); - (void *)(vfprintf), - //BuiltIn(int) vprintf(Pointer(restrict Attributed(const , BuiltIn(char))), Use(TypeDef(__gnuc_va_list, BuiltIn(__builtin_va_list)))); - (void *)(vprintf), - //BuiltIn(int) vsprintf(Pointer(restrict BuiltIn(char)), Pointer(restrict Attributed(const , BuiltIn(char))), Use(TypeDef(__gnuc_va_list, BuiltIn(__builtin_va_list)))); - (void *)(vsprintf), - // skipping because varargs function: snprintf - //BuiltIn(int) vsnprintf(Pointer(restrict BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Attributed(const , BuiltIn(char))), Use(TypeDef(__gnuc_va_list, BuiltIn(__builtin_va_list)))); - (void *)(vsnprintf), - //BuiltIn(int) vasprintf(Pointer(restrict Pointer(BuiltIn(char))), Pointer(restrict Attributed(const , BuiltIn(char))), Use(TypeDef(__gnuc_va_list, BuiltIn(__builtin_va_list)))); - (void *)(vasprintf), - // skipping because varargs function: __asprintf - // skipping because varargs function: asprintf - //BuiltIn(int) vdprintf(BuiltIn(int), Pointer(restrict Attributed(const , BuiltIn(char))), Use(TypeDef(__gnuc_va_list, BuiltIn(__builtin_va_list)))); - (void *)(vdprintf), - // skipping because varargs function: dprintf - // skipping because varargs function: fscanf - // skipping because varargs function: scanf - // skipping because varargs function: sscanf - //BuiltIn(int) vfscanf(Pointer(restrict Use(TypeDef(FILE, Use(Struct(struct _IO_FILE))))), Pointer(restrict Attributed(const , BuiltIn(char))), Use(TypeDef(__gnuc_va_list, BuiltIn(__builtin_va_list)))); - (void *)(vfscanf), - //BuiltIn(int) vscanf(Pointer(restrict Attributed(const , BuiltIn(char))), Use(TypeDef(__gnuc_va_list, BuiltIn(__builtin_va_list)))); - (void *)(vscanf), - //BuiltIn(int) vsscanf(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Attributed(const , BuiltIn(char))), Use(TypeDef(__gnuc_va_list, BuiltIn(__builtin_va_list)))); - (void *)(vsscanf), - //BuiltIn(int) fgetc(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(fgetc), - //BuiltIn(int) getc(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(getc), - //BuiltIn(int) getchar(); - (void *)(getchar), - //BuiltIn(int) getc_unlocked(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(getc_unlocked), - //BuiltIn(int) getchar_unlocked(); - (void *)(getchar_unlocked), - //BuiltIn(int) fgetc_unlocked(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(fgetc_unlocked), - //BuiltIn(int) fputc(BuiltIn(int), Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(fputc), - //BuiltIn(int) putc(BuiltIn(int), Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(putc), - //BuiltIn(int) putchar(BuiltIn(int)); - (void *)(putchar), - //BuiltIn(int) fputc_unlocked(BuiltIn(int), Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(fputc_unlocked), - //BuiltIn(int) putc_unlocked(BuiltIn(int), Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(putc_unlocked), - //BuiltIn(int) putchar_unlocked(BuiltIn(int)); - (void *)(putchar_unlocked), - //BuiltIn(int) getw(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(getw), - //BuiltIn(int) putw(BuiltIn(int), Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(putw), - (void *)(gets), - //Pointer(BuiltIn(char)) fgets(Pointer(restrict BuiltIn(char)), BuiltIn(int), Pointer(restrict Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(fgets), - //Pointer(BuiltIn(char)) fgets_unlocked(Pointer(restrict BuiltIn(char)), BuiltIn(int), Pointer(restrict Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(fgets_unlocked), - //Use(TypeDef(__ssize_t, BuiltIn(long))) __getdelim(Pointer(restrict Pointer(BuiltIn(char))), Pointer(restrict Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))), BuiltIn(int), Pointer(restrict Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(__getdelim), - //Use(TypeDef(__ssize_t, BuiltIn(long))) getdelim(Pointer(restrict Pointer(BuiltIn(char))), Pointer(restrict Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))), BuiltIn(int), Pointer(restrict Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(getdelim), - //Use(TypeDef(__ssize_t, BuiltIn(long))) getline(Pointer(restrict Pointer(BuiltIn(char))), Pointer(restrict Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))), Pointer(restrict Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(getline), - //BuiltIn(int) fputs(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(fputs), - //BuiltIn(int) puts(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(puts), - //BuiltIn(int) ungetc(BuiltIn(int), Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(ungetc), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) fread(Pointer(restrict BuiltIn(void)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(fread), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) fwrite(Pointer(restrict Attributed(const , BuiltIn(void))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(fwrite), - //BuiltIn(int) fputs_unlocked(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(fputs_unlocked), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) fread_unlocked(Pointer(restrict BuiltIn(void)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(fread_unlocked), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) fwrite_unlocked(Pointer(restrict Attributed(const , BuiltIn(void))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(fwrite_unlocked), - //BuiltIn(int) fseek(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE))))), BuiltIn(long), BuiltIn(int)); - (void *)(fseek), - //BuiltIn(long) ftell(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(ftell), - //BuiltIn(void) rewind(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(rewind), - //BuiltIn(int) fseeko(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE))))), Use(TypeDef(__off_t, BuiltIn(long))), BuiltIn(int)); - (void *)(fseeko), - //Use(TypeDef(__off_t, BuiltIn(long))) ftello(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(ftello), - //BuiltIn(int) fgetpos(Pointer(restrict Use(TypeDef(FILE, Use(Struct(struct _IO_FILE))))), Pointer(restrict Use(TypeDef(fpos_t, Use(TypeDef(_G_fpos_t, Struct(struct anon_struct_6))))))); - (void *)(fgetpos), - //BuiltIn(int) fsetpos(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE))))), Pointer(Attributed(const , Use(TypeDef(fpos_t, Use(TypeDef(_G_fpos_t, Struct(struct anon_struct_6)))))))); - (void *)(fsetpos), - //BuiltIn(int) fseeko64(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE))))), Use(TypeDef(__off64_t, BuiltIn(long))), BuiltIn(int)); - (void *)(fseeko64), - //Use(TypeDef(__off64_t, BuiltIn(long))) ftello64(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(ftello64), - //BuiltIn(int) fgetpos64(Pointer(restrict Use(TypeDef(FILE, Use(Struct(struct _IO_FILE))))), Pointer(restrict Use(TypeDef(fpos64_t, Use(TypeDef(_G_fpos64_t, Struct(struct anon_struct_7))))))); - (void *)(fgetpos64), - //BuiltIn(int) fsetpos64(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE))))), Pointer(Attributed(const , Use(TypeDef(fpos64_t, Use(TypeDef(_G_fpos64_t, Struct(struct anon_struct_7)))))))); - (void *)(fsetpos64), - //BuiltIn(void) clearerr(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(clearerr), - //BuiltIn(int) feof(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(feof), - //BuiltIn(int) ferror(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(ferror), - //BuiltIn(void) clearerr_unlocked(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(clearerr_unlocked), - //BuiltIn(int) feof_unlocked(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(feof_unlocked), - //BuiltIn(int) ferror_unlocked(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(ferror_unlocked), - //BuiltIn(void) perror(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(perror), - //BuiltIn(int) fileno(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(fileno), - //BuiltIn(int) fileno_unlocked(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(fileno_unlocked), - //Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE))))) popen(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(popen), - //BuiltIn(int) pclose(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(pclose), - //Pointer(BuiltIn(char)) ctermid(Pointer(BuiltIn(char))); - (void *)(ctermid), - //Pointer(BuiltIn(char)) cuserid(Pointer(BuiltIn(char))); - (void *)(cuserid), - // skipping because varargs function: obstack_printf - // skipping because function pointer args: obstack_vprintf - //BuiltIn(void) flockfile(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(flockfile), - //BuiltIn(int) ftrylockfile(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(ftrylockfile), - //BuiltIn(void) funlockfile(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(funlockfile), - //Pointer(Pointer(Attributed(const unsigned , BuiltIn(short)))) __ctype_b_loc(); - (void *)(__ctype_b_loc), - //Pointer(Pointer(Attributed(const , Use(TypeDef(__int32_t, Attributed(signed , BuiltIn(int))))))) __ctype_tolower_loc(); - (void *)(__ctype_tolower_loc), - //Pointer(Pointer(Attributed(const , Use(TypeDef(__int32_t, Attributed(signed , BuiltIn(int))))))) __ctype_toupper_loc(); - (void *)(__ctype_toupper_loc), - //BuiltIn(int) isalnum(BuiltIn(int)); - (void *)(isalnum), - //BuiltIn(int) isalpha(BuiltIn(int)); - (void *)(isalpha), - //BuiltIn(int) iscntrl(BuiltIn(int)); - (void *)(iscntrl), - //BuiltIn(int) isdigit(BuiltIn(int)); - (void *)(isdigit), - //BuiltIn(int) islower(BuiltIn(int)); - (void *)(islower), - //BuiltIn(int) isgraph(BuiltIn(int)); - (void *)(isgraph), - //BuiltIn(int) isprint(BuiltIn(int)); - (void *)(isprint), - //BuiltIn(int) ispunct(BuiltIn(int)); - (void *)(ispunct), - //BuiltIn(int) isspace(BuiltIn(int)); - (void *)(isspace), - //BuiltIn(int) isupper(BuiltIn(int)); - (void *)(isupper), - //BuiltIn(int) isxdigit(BuiltIn(int)); - (void *)(isxdigit), - //BuiltIn(int) tolower(BuiltIn(int)); - (void *)(tolower), - //BuiltIn(int) toupper(BuiltIn(int)); - (void *)(toupper), - //BuiltIn(int) isblank(BuiltIn(int)); - (void *)(isblank), - //BuiltIn(int) isctype(BuiltIn(int), BuiltIn(int)); - (void *)(isctype), - //BuiltIn(int) isascii(BuiltIn(int)); - (void *)(isascii), - //BuiltIn(int) toascii(BuiltIn(int)); - (void *)(toascii), - //BuiltIn(int) _toupper(BuiltIn(int)); - (void *)(_toupper), - //BuiltIn(int) _tolower(BuiltIn(int)); - (void *)(_tolower), - //BuiltIn(int) isalnum_l(BuiltIn(int), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(isalnum_l), - //BuiltIn(int) isalpha_l(BuiltIn(int), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(isalpha_l), - //BuiltIn(int) iscntrl_l(BuiltIn(int), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(iscntrl_l), - //BuiltIn(int) isdigit_l(BuiltIn(int), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(isdigit_l), - //BuiltIn(int) islower_l(BuiltIn(int), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(islower_l), - //BuiltIn(int) isgraph_l(BuiltIn(int), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(isgraph_l), - //BuiltIn(int) isprint_l(BuiltIn(int), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(isprint_l), - //BuiltIn(int) ispunct_l(BuiltIn(int), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(ispunct_l), - //BuiltIn(int) isspace_l(BuiltIn(int), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(isspace_l), - //BuiltIn(int) isupper_l(BuiltIn(int), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(isupper_l), - //BuiltIn(int) isxdigit_l(BuiltIn(int), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(isxdigit_l), - //BuiltIn(int) isblank_l(BuiltIn(int), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(isblank_l), - //BuiltIn(int) __tolower_l(BuiltIn(int), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(__tolower_l), - //BuiltIn(int) tolower_l(BuiltIn(int), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(tolower_l), - //BuiltIn(int) __toupper_l(BuiltIn(int), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(__toupper_l), - //BuiltIn(int) toupper_l(BuiltIn(int), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(toupper_l), - //BuiltIn(int) getopt(BuiltIn(int), Pointer(Pointer(const BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(getopt), - //BuiltIn(int) getopt_long(BuiltIn(int), Pointer(Pointer(const BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , Use(Struct(struct option)))), Pointer(BuiltIn(int))); - (void *)(getopt_long), - //BuiltIn(int) getopt_long_only(BuiltIn(int), Pointer(Pointer(const BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , Use(Struct(struct option)))), Pointer(BuiltIn(int))); - (void *)(getopt_long_only), - //Pointer(BuiltIn(int)) __errno_location(); - (void *)(__errno_location), - //Use(TypeDef(error_t, BuiltIn(int))) argp_parse(Pointer(restrict Attributed(const , Use(Struct(struct argp)))), BuiltIn(int), Pointer(restrict Pointer(BuiltIn(char))), Attributed(unsigned , BuiltIn(int)), Pointer(restrict BuiltIn(int)), Pointer(restrict BuiltIn(void))); - (void *)(argp_parse), - //Use(TypeDef(error_t, BuiltIn(int))) __argp_parse(Pointer(restrict Attributed(const , Use(Struct(struct argp)))), BuiltIn(int), Pointer(restrict Pointer(BuiltIn(char))), Attributed(unsigned , BuiltIn(int)), Pointer(restrict BuiltIn(int)), Pointer(restrict BuiltIn(void))); - (void *)(__argp_parse), - //BuiltIn(void) argp_help(Pointer(restrict Attributed(const , Use(Struct(struct argp)))), Pointer(restrict Use(TypeDef(FILE, Use(Struct(struct _IO_FILE))))), Attributed(unsigned , BuiltIn(int)), Pointer(restrict BuiltIn(char))); - (void *)(argp_help), - //BuiltIn(void) __argp_help(Pointer(restrict Attributed(const , Use(Struct(struct argp)))), Pointer(restrict Use(TypeDef(FILE, Use(Struct(struct _IO_FILE))))), Attributed(unsigned , BuiltIn(int)), Pointer(BuiltIn(char))); - (void *)(__argp_help), - //BuiltIn(void) argp_state_help(Pointer(restrict Attributed(const , Use(Struct(struct argp_state)))), Pointer(restrict Use(TypeDef(FILE, Use(Struct(struct _IO_FILE))))), Attributed(unsigned , BuiltIn(int))); - (void *)(argp_state_help), - //BuiltIn(void) __argp_state_help(Pointer(restrict Attributed(const , Use(Struct(struct argp_state)))), Pointer(restrict Use(TypeDef(FILE, Use(Struct(struct _IO_FILE))))), Attributed(unsigned , BuiltIn(int))); - (void *)(__argp_state_help), - //BuiltIn(void) argp_usage(Pointer(Attributed(const , Use(Struct(struct argp_state))))); - (void *)(argp_usage), - //BuiltIn(void) __argp_usage(Pointer(Attributed(const , Use(Struct(struct argp_state))))); - (void *)(__argp_usage), - // skipping because varargs function: argp_error - // skipping because varargs function: __argp_error - // skipping because varargs function: argp_failure - // skipping because varargs function: __argp_failure - //BuiltIn(int) _option_is_short(Pointer(Attributed(const , Use(Struct(struct argp_option))))); - (void *)(_option_is_short), - //BuiltIn(int) __option_is_short(Pointer(Attributed(const , Use(Struct(struct argp_option))))); - (void *)(__option_is_short), - //BuiltIn(int) _option_is_end(Pointer(Attributed(const , Use(Struct(struct argp_option))))); - (void *)(_option_is_end), - //BuiltIn(int) __option_is_end(Pointer(Attributed(const , Use(Struct(struct argp_option))))); - (void *)(__option_is_end), - //Pointer(BuiltIn(void)) _argp_input(Pointer(restrict Attributed(const , Use(Struct(struct argp)))), Pointer(restrict Attributed(const , Use(Struct(struct argp_state))))); - (void *)(_argp_input), - //Pointer(BuiltIn(void)) __argp_input(Pointer(restrict Attributed(const , Use(Struct(struct argp)))), Pointer(restrict Attributed(const , Use(Struct(struct argp_state))))); - (void *)(__argp_input), - //BuiltIn(int) select(BuiltIn(int), Pointer(restrict Use(TypeDef(fd_set, Struct(struct anon_struct_26)))), Pointer(restrict Use(TypeDef(fd_set, Struct(struct anon_struct_26)))), Pointer(restrict Use(TypeDef(fd_set, Struct(struct anon_struct_26)))), Pointer(restrict Use(Struct(struct timeval)))); - (void *)(select), - //BuiltIn(int) pselect(BuiltIn(int), Pointer(restrict Use(TypeDef(fd_set, Struct(struct anon_struct_26)))), Pointer(restrict Use(TypeDef(fd_set, Struct(struct anon_struct_26)))), Pointer(restrict Use(TypeDef(fd_set, Struct(struct anon_struct_26)))), Pointer(restrict Attributed(const , Use(Struct(struct timespec)))), Pointer(restrict Attributed(const , Use(TypeDef(__sigset_t, Struct(struct anon_struct_23)))))); - (void *)(pselect), - //Attributed(unsigned , BuiltIn(int)) gnu_dev_major(Attributed(unsigned , BuiltIn(long long))); - (void *)(gnu_dev_major), - //Attributed(unsigned , BuiltIn(int)) gnu_dev_minor(Attributed(unsigned , BuiltIn(long long))); - (void *)(gnu_dev_minor), - //Attributed(unsigned , BuiltIn(long long)) gnu_dev_makedev(Attributed(unsigned , BuiltIn(int)), Attributed(unsigned , BuiltIn(int))); - (void *)(gnu_dev_makedev), - //Use(TypeDef(ssize_t, Use(TypeDef(__ssize_t, BuiltIn(long))))) process_vm_readv(Use(TypeDef(pid_t, Use(TypeDef(__pid_t, BuiltIn(int))))), Pointer(Attributed(const , Use(Struct(struct iovec)))), Attributed(unsigned , BuiltIn(long)), Pointer(Attributed(const , Use(Struct(struct iovec)))), Attributed(unsigned , BuiltIn(long)), Attributed(unsigned , BuiltIn(long))); - (void *)(process_vm_readv), - //Use(TypeDef(ssize_t, Use(TypeDef(__ssize_t, BuiltIn(long))))) process_vm_writev(Use(TypeDef(pid_t, Use(TypeDef(__pid_t, BuiltIn(int))))), Pointer(Attributed(const , Use(Struct(struct iovec)))), Attributed(unsigned , BuiltIn(long)), Pointer(Attributed(const , Use(Struct(struct iovec)))), Attributed(unsigned , BuiltIn(long)), Attributed(unsigned , BuiltIn(long))); - (void *)(process_vm_writev), - //Use(TypeDef(ssize_t, Use(TypeDef(__ssize_t, BuiltIn(long))))) readv(BuiltIn(int), Pointer(Attributed(const , Use(Struct(struct iovec)))), BuiltIn(int)); - (void *)(readv), - //Use(TypeDef(ssize_t, Use(TypeDef(__ssize_t, BuiltIn(long))))) writev(BuiltIn(int), Pointer(Attributed(const , Use(Struct(struct iovec)))), BuiltIn(int)); - (void *)(writev), - //Use(TypeDef(ssize_t, Use(TypeDef(__ssize_t, BuiltIn(long))))) preadv(BuiltIn(int), Pointer(Attributed(const , Use(Struct(struct iovec)))), BuiltIn(int), Use(TypeDef(__off_t, BuiltIn(long)))); - (void *)(preadv), - //Use(TypeDef(ssize_t, Use(TypeDef(__ssize_t, BuiltIn(long))))) pwritev(BuiltIn(int), Pointer(Attributed(const , Use(Struct(struct iovec)))), BuiltIn(int), Use(TypeDef(__off_t, BuiltIn(long)))); - (void *)(pwritev), - //Use(TypeDef(ssize_t, Use(TypeDef(__ssize_t, BuiltIn(long))))) preadv64(BuiltIn(int), Pointer(Attributed(const , Use(Struct(struct iovec)))), BuiltIn(int), Use(TypeDef(__off64_t, BuiltIn(long)))); - (void *)(preadv64), - //Use(TypeDef(ssize_t, Use(TypeDef(__ssize_t, BuiltIn(long))))) pwritev64(BuiltIn(int), Pointer(Attributed(const , Use(Struct(struct iovec)))), BuiltIn(int), Use(TypeDef(__off64_t, BuiltIn(long)))); - (void *)(pwritev64), - //Pointer(Use(Struct(struct cmsghdr))) __cmsg_nxthdr(Pointer(Use(Struct(struct msghdr))), Pointer(Use(Struct(struct cmsghdr)))); - (void *)(__cmsg_nxthdr), - //BuiltIn(int) socket(BuiltIn(int), BuiltIn(int), BuiltIn(int)); - (void *)(socket), - //BuiltIn(int) socketpair(BuiltIn(int), BuiltIn(int), BuiltIn(int), Array(BuiltIn(int))); - (void *)(socketpair), - //BuiltIn(int) bind(BuiltIn(int), Use(TypeDef(__CONST_SOCKADDR_ARG, Attributed(__attribute__ ( ( __transparent_union__ ) ), Union(union anon_union_12)))), Use(TypeDef(socklen_t, Use(TypeDef(__socklen_t, Attributed(unsigned , BuiltIn(int))))))); - (void *)(bind), - //BuiltIn(int) getsockname(BuiltIn(int), Use(TypeDef(__SOCKADDR_ARG, Attributed(__attribute__ ( ( __transparent_union__ ) ), Union(union anon_union_11)))), Pointer(restrict Use(TypeDef(socklen_t, Use(TypeDef(__socklen_t, Attributed(unsigned , BuiltIn(int)))))))); - (void *)(getsockname), - //BuiltIn(int) connect(BuiltIn(int), Use(TypeDef(__CONST_SOCKADDR_ARG, Attributed(__attribute__ ( ( __transparent_union__ ) ), Union(union anon_union_12)))), Use(TypeDef(socklen_t, Use(TypeDef(__socklen_t, Attributed(unsigned , BuiltIn(int))))))); - (void *)(connect), - //BuiltIn(int) getpeername(BuiltIn(int), Use(TypeDef(__SOCKADDR_ARG, Attributed(__attribute__ ( ( __transparent_union__ ) ), Union(union anon_union_11)))), Pointer(restrict Use(TypeDef(socklen_t, Use(TypeDef(__socklen_t, Attributed(unsigned , BuiltIn(int)))))))); - (void *)(getpeername), - //Use(TypeDef(ssize_t, Use(TypeDef(__ssize_t, BuiltIn(long))))) send(BuiltIn(int), Pointer(Attributed(const , BuiltIn(void))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), BuiltIn(int)); - (void *)(send), - //Use(TypeDef(ssize_t, Use(TypeDef(__ssize_t, BuiltIn(long))))) recv(BuiltIn(int), Pointer(BuiltIn(void)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), BuiltIn(int)); - (void *)(recv), - //Use(TypeDef(ssize_t, Use(TypeDef(__ssize_t, BuiltIn(long))))) sendto(BuiltIn(int), Pointer(Attributed(const , BuiltIn(void))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), BuiltIn(int), Use(TypeDef(__CONST_SOCKADDR_ARG, Attributed(__attribute__ ( ( __transparent_union__ ) ), Union(union anon_union_12)))), Use(TypeDef(socklen_t, Use(TypeDef(__socklen_t, Attributed(unsigned , BuiltIn(int))))))); - (void *)(sendto), - //Use(TypeDef(ssize_t, Use(TypeDef(__ssize_t, BuiltIn(long))))) recvfrom(BuiltIn(int), Pointer(restrict BuiltIn(void)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), BuiltIn(int), Use(TypeDef(__SOCKADDR_ARG, Attributed(__attribute__ ( ( __transparent_union__ ) ), Union(union anon_union_11)))), Pointer(restrict Use(TypeDef(socklen_t, Use(TypeDef(__socklen_t, Attributed(unsigned , BuiltIn(int)))))))); - (void *)(recvfrom), - //Use(TypeDef(ssize_t, Use(TypeDef(__ssize_t, BuiltIn(long))))) sendmsg(BuiltIn(int), Pointer(Attributed(const , Use(Struct(struct msghdr)))), BuiltIn(int)); - (void *)(sendmsg), - //BuiltIn(int) sendmmsg(BuiltIn(int), Pointer(Use(Struct(struct mmsghdr))), Attributed(unsigned , BuiltIn(int)), BuiltIn(int)); - (void *)(sendmmsg), - //Use(TypeDef(ssize_t, Use(TypeDef(__ssize_t, BuiltIn(long))))) recvmsg(BuiltIn(int), Pointer(Use(Struct(struct msghdr))), BuiltIn(int)); - (void *)(recvmsg), - //BuiltIn(int) recvmmsg(BuiltIn(int), Pointer(Use(Struct(struct mmsghdr))), Attributed(unsigned , BuiltIn(int)), BuiltIn(int), Pointer(Attributed(const , Use(Struct(struct timespec))))); - (void *)(recvmmsg), - //BuiltIn(int) getsockopt(BuiltIn(int), BuiltIn(int), BuiltIn(int), Pointer(restrict BuiltIn(void)), Pointer(restrict Use(TypeDef(socklen_t, Use(TypeDef(__socklen_t, Attributed(unsigned , BuiltIn(int)))))))); - (void *)(getsockopt), - //BuiltIn(int) setsockopt(BuiltIn(int), BuiltIn(int), BuiltIn(int), Pointer(Attributed(const , BuiltIn(void))), Use(TypeDef(socklen_t, Use(TypeDef(__socklen_t, Attributed(unsigned , BuiltIn(int))))))); - (void *)(setsockopt), - //BuiltIn(int) listen(BuiltIn(int), BuiltIn(int)); - (void *)(listen), - //BuiltIn(int) accept(BuiltIn(int), Use(TypeDef(__SOCKADDR_ARG, Attributed(__attribute__ ( ( __transparent_union__ ) ), Union(union anon_union_11)))), Pointer(restrict Use(TypeDef(socklen_t, Use(TypeDef(__socklen_t, Attributed(unsigned , BuiltIn(int)))))))); - (void *)(accept), - //BuiltIn(int) accept4(BuiltIn(int), Use(TypeDef(__SOCKADDR_ARG, Attributed(__attribute__ ( ( __transparent_union__ ) ), Union(union anon_union_11)))), Pointer(restrict Use(TypeDef(socklen_t, Use(TypeDef(__socklen_t, Attributed(unsigned , BuiltIn(int))))))), BuiltIn(int)); - (void *)(accept4), - //BuiltIn(int) shutdown(BuiltIn(int), BuiltIn(int)); - (void *)(shutdown), - //BuiltIn(int) sockatmark(BuiltIn(int)); - (void *)(sockatmark), - //BuiltIn(int) isfdtype(BuiltIn(int), BuiltIn(int)); - (void *)(isfdtype), - //Use(TypeDef(uint32_t, Attributed(unsigned , BuiltIn(int)))) ntohl(Use(TypeDef(uint32_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(ntohl), - //Use(TypeDef(uint16_t, Attributed(unsigned , BuiltIn(short)))) ntohs(Use(TypeDef(uint16_t, Attributed(unsigned , BuiltIn(short))))); - (void *)(ntohs), - //Use(TypeDef(uint32_t, Attributed(unsigned , BuiltIn(int)))) htonl(Use(TypeDef(uint32_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(htonl), - //Use(TypeDef(uint16_t, Attributed(unsigned , BuiltIn(short)))) htons(Use(TypeDef(uint16_t, Attributed(unsigned , BuiltIn(short))))); - (void *)(htons), - //BuiltIn(int) bindresvport(BuiltIn(int), Pointer(Use(Struct(struct sockaddr_in)))); - (void *)(bindresvport), - //BuiltIn(int) bindresvport6(BuiltIn(int), Pointer(Use(Struct(struct sockaddr_in6)))); - (void *)(bindresvport6), - //BuiltIn(int) inet6_option_space(BuiltIn(int)); - (void *)(inet6_option_space), - //BuiltIn(int) inet6_option_init(Pointer(BuiltIn(void)), Pointer(Pointer(Use(Struct(struct cmsghdr)))), BuiltIn(int)); - (void *)(inet6_option_init), - //BuiltIn(int) inet6_option_append(Pointer(Use(Struct(struct cmsghdr))), Pointer(Attributed(const , Use(TypeDef(uint8_t, Attributed(unsigned , BuiltIn(char)))))), BuiltIn(int), BuiltIn(int)); - (void *)(inet6_option_append), - //Pointer(Use(TypeDef(uint8_t, Attributed(unsigned , BuiltIn(char))))) inet6_option_alloc(Pointer(Use(Struct(struct cmsghdr))), BuiltIn(int), BuiltIn(int), BuiltIn(int)); - (void *)(inet6_option_alloc), - //BuiltIn(int) inet6_option_next(Pointer(Attributed(const , Use(Struct(struct cmsghdr)))), Pointer(Pointer(Use(TypeDef(uint8_t, Attributed(unsigned , BuiltIn(char))))))); - (void *)(inet6_option_next), - //BuiltIn(int) inet6_option_find(Pointer(Attributed(const , Use(Struct(struct cmsghdr)))), Pointer(Pointer(Use(TypeDef(uint8_t, Attributed(unsigned , BuiltIn(char)))))), BuiltIn(int)); - (void *)(inet6_option_find), - //BuiltIn(int) inet6_opt_init(Pointer(BuiltIn(void)), Use(TypeDef(socklen_t, Use(TypeDef(__socklen_t, Attributed(unsigned , BuiltIn(int))))))); - (void *)(inet6_opt_init), - //BuiltIn(int) inet6_opt_append(Pointer(BuiltIn(void)), Use(TypeDef(socklen_t, Use(TypeDef(__socklen_t, Attributed(unsigned , BuiltIn(int)))))), BuiltIn(int), Use(TypeDef(uint8_t, Attributed(unsigned , BuiltIn(char)))), Use(TypeDef(socklen_t, Use(TypeDef(__socklen_t, Attributed(unsigned , BuiltIn(int)))))), Use(TypeDef(uint8_t, Attributed(unsigned , BuiltIn(char)))), Pointer(Pointer(BuiltIn(void)))); - (void *)(inet6_opt_append), - //BuiltIn(int) inet6_opt_finish(Pointer(BuiltIn(void)), Use(TypeDef(socklen_t, Use(TypeDef(__socklen_t, Attributed(unsigned , BuiltIn(int)))))), BuiltIn(int)); - (void *)(inet6_opt_finish), - //BuiltIn(int) inet6_opt_set_val(Pointer(BuiltIn(void)), BuiltIn(int), Pointer(BuiltIn(void)), Use(TypeDef(socklen_t, Use(TypeDef(__socklen_t, Attributed(unsigned , BuiltIn(int))))))); - (void *)(inet6_opt_set_val), - //BuiltIn(int) inet6_opt_next(Pointer(BuiltIn(void)), Use(TypeDef(socklen_t, Use(TypeDef(__socklen_t, Attributed(unsigned , BuiltIn(int)))))), BuiltIn(int), Pointer(Use(TypeDef(uint8_t, Attributed(unsigned , BuiltIn(char))))), Pointer(Use(TypeDef(socklen_t, Use(TypeDef(__socklen_t, Attributed(unsigned , BuiltIn(int))))))), Pointer(Pointer(BuiltIn(void)))); - (void *)(inet6_opt_next), - //BuiltIn(int) inet6_opt_find(Pointer(BuiltIn(void)), Use(TypeDef(socklen_t, Use(TypeDef(__socklen_t, Attributed(unsigned , BuiltIn(int)))))), BuiltIn(int), Use(TypeDef(uint8_t, Attributed(unsigned , BuiltIn(char)))), Pointer(Use(TypeDef(socklen_t, Use(TypeDef(__socklen_t, Attributed(unsigned , BuiltIn(int))))))), Pointer(Pointer(BuiltIn(void)))); - (void *)(inet6_opt_find), - //BuiltIn(int) inet6_opt_get_val(Pointer(BuiltIn(void)), BuiltIn(int), Pointer(BuiltIn(void)), Use(TypeDef(socklen_t, Use(TypeDef(__socklen_t, Attributed(unsigned , BuiltIn(int))))))); - (void *)(inet6_opt_get_val), - //Use(TypeDef(socklen_t, Use(TypeDef(__socklen_t, Attributed(unsigned , BuiltIn(int)))))) inet6_rth_space(BuiltIn(int), BuiltIn(int)); - (void *)(inet6_rth_space), - //Pointer(BuiltIn(void)) inet6_rth_init(Pointer(BuiltIn(void)), Use(TypeDef(socklen_t, Use(TypeDef(__socklen_t, Attributed(unsigned , BuiltIn(int)))))), BuiltIn(int), BuiltIn(int)); - (void *)(inet6_rth_init), - //BuiltIn(int) inet6_rth_add(Pointer(BuiltIn(void)), Pointer(Attributed(const , Use(Struct(struct in6_addr))))); - (void *)(inet6_rth_add), - //BuiltIn(int) inet6_rth_reverse(Pointer(Attributed(const , BuiltIn(void))), Pointer(BuiltIn(void))); - (void *)(inet6_rth_reverse), - //BuiltIn(int) inet6_rth_segments(Pointer(Attributed(const , BuiltIn(void)))); - (void *)(inet6_rth_segments), - //Pointer(Use(Struct(struct in6_addr))) inet6_rth_getaddr(Pointer(Attributed(const , BuiltIn(void))), BuiltIn(int)); - (void *)(inet6_rth_getaddr), - //BuiltIn(int) getipv4sourcefilter(BuiltIn(int), Use(Struct(struct in_addr)), Use(Struct(struct in_addr)), Pointer(Use(TypeDef(uint32_t, Attributed(unsigned , BuiltIn(int))))), Pointer(Use(TypeDef(uint32_t, Attributed(unsigned , BuiltIn(int))))), Pointer(Use(Struct(struct in_addr)))); - (void *)(getipv4sourcefilter), - //BuiltIn(int) setipv4sourcefilter(BuiltIn(int), Use(Struct(struct in_addr)), Use(Struct(struct in_addr)), Use(TypeDef(uint32_t, Attributed(unsigned , BuiltIn(int)))), Use(TypeDef(uint32_t, Attributed(unsigned , BuiltIn(int)))), Pointer(Attributed(const , Use(Struct(struct in_addr))))); - (void *)(setipv4sourcefilter), - //BuiltIn(int) getsourcefilter(BuiltIn(int), Use(TypeDef(uint32_t, Attributed(unsigned , BuiltIn(int)))), Pointer(Attributed(const , Use(Struct(struct sockaddr)))), Use(TypeDef(socklen_t, Use(TypeDef(__socklen_t, Attributed(unsigned , BuiltIn(int)))))), Pointer(Use(TypeDef(uint32_t, Attributed(unsigned , BuiltIn(int))))), Pointer(Use(TypeDef(uint32_t, Attributed(unsigned , BuiltIn(int))))), Pointer(Use(Struct(struct sockaddr_storage)))); - (void *)(getsourcefilter), - //BuiltIn(int) setsourcefilter(BuiltIn(int), Use(TypeDef(uint32_t, Attributed(unsigned , BuiltIn(int)))), Pointer(Attributed(const , Use(Struct(struct sockaddr)))), Use(TypeDef(socklen_t, Use(TypeDef(__socklen_t, Attributed(unsigned , BuiltIn(int)))))), Use(TypeDef(uint32_t, Attributed(unsigned , BuiltIn(int)))), Use(TypeDef(uint32_t, Attributed(unsigned , BuiltIn(int)))), Pointer(Attributed(const , Use(Struct(struct sockaddr_storage))))); - (void *)(setsourcefilter), - //Use(TypeDef(intmax_t, BuiltIn(long))) imaxabs(Use(TypeDef(intmax_t, BuiltIn(long)))); - (void *)(imaxabs), - //Use(TypeDef(imaxdiv_t, Struct(struct anon_struct_107))) imaxdiv(Use(TypeDef(intmax_t, BuiltIn(long))), Use(TypeDef(intmax_t, BuiltIn(long)))); - (void *)(imaxdiv), - //Use(TypeDef(intmax_t, BuiltIn(long))) strtoimax(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Pointer(BuiltIn(char))), BuiltIn(int)); - (void *)(strtoimax), - //Use(TypeDef(uintmax_t, Attributed(unsigned , BuiltIn(long)))) strtoumax(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Pointer(BuiltIn(char))), BuiltIn(int)); - (void *)(strtoumax), - //Use(TypeDef(intmax_t, BuiltIn(long))) wcstoimax(Pointer(restrict Attributed(const , Use(TypeDef(__gwchar_t, BuiltIn(int))))), Pointer(restrict Pointer(Use(TypeDef(__gwchar_t, BuiltIn(int))))), BuiltIn(int)); - (void *)(wcstoimax), - //Use(TypeDef(uintmax_t, Attributed(unsigned , BuiltIn(long)))) wcstoumax(Pointer(restrict Attributed(const , Use(TypeDef(__gwchar_t, BuiltIn(int))))), Pointer(restrict Pointer(Use(TypeDef(__gwchar_t, BuiltIn(int))))), BuiltIn(int)); - (void *)(wcstoumax), - //Pointer(BuiltIn(char)) ether_ntoa(Pointer(Attributed(const , Use(Struct(struct ether_addr))))); - (void *)(ether_ntoa), - //Pointer(BuiltIn(char)) ether_ntoa_r(Pointer(Attributed(const , Use(Struct(struct ether_addr)))), Pointer(BuiltIn(char))); - (void *)(ether_ntoa_r), - //Pointer(Use(Struct(struct ether_addr))) ether_aton(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(ether_aton), - //Pointer(Use(Struct(struct ether_addr))) ether_aton_r(Pointer(Attributed(const , BuiltIn(char))), Pointer(Use(Struct(struct ether_addr)))); - (void *)(ether_aton_r), - //BuiltIn(int) ether_ntohost(Pointer(BuiltIn(char)), Pointer(Attributed(const , Use(Struct(struct ether_addr))))); - (void *)(ether_ntohost), - //BuiltIn(int) ether_hostton(Pointer(Attributed(const , BuiltIn(char))), Pointer(Use(Struct(struct ether_addr)))); - (void *)(ether_hostton), - //BuiltIn(int) ether_line(Pointer(Attributed(const , BuiltIn(char))), Pointer(Use(Struct(struct ether_addr))), Pointer(BuiltIn(char))); - (void *)(ether_line), - //Pointer(BuiltIn(void)) memcpy(Pointer(restrict BuiltIn(void)), Pointer(restrict Attributed(const , BuiltIn(void))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(memcpy), - //Pointer(BuiltIn(void)) memmove(Pointer(BuiltIn(void)), Pointer(Attributed(const , BuiltIn(void))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(memmove), - //Pointer(BuiltIn(void)) memccpy(Pointer(restrict BuiltIn(void)), Pointer(restrict Attributed(const , BuiltIn(void))), BuiltIn(int), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(memccpy), - //Pointer(BuiltIn(void)) memset(Pointer(BuiltIn(void)), BuiltIn(int), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(memset), - //BuiltIn(int) memcmp(Pointer(Attributed(const , BuiltIn(void))), Pointer(Attributed(const , BuiltIn(void))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(memcmp), - //Pointer(BuiltIn(void)) memchr(Pointer(Attributed(const , BuiltIn(void))), BuiltIn(int), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); -// (void *)(memchr), - //Pointer(BuiltIn(void)) rawmemchr(Pointer(Attributed(const , BuiltIn(void))), BuiltIn(int)); - // (void *)(rawmemchr), - //Pointer(BuiltIn(void)) memrchr(Pointer(Attributed(const , BuiltIn(void))), BuiltIn(int), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); -// (void *)(memrchr), - //Pointer(BuiltIn(char)) strcpy(Pointer(restrict BuiltIn(char)), Pointer(restrict Attributed(const , BuiltIn(char)))); - (void *)(strcpy), - //Pointer(BuiltIn(char)) strncpy(Pointer(restrict BuiltIn(char)), Pointer(restrict Attributed(const , BuiltIn(char))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(strncpy), - //Pointer(BuiltIn(char)) strcat(Pointer(restrict BuiltIn(char)), Pointer(restrict Attributed(const , BuiltIn(char)))); - (void *)(strcat), - //Pointer(BuiltIn(char)) strncat(Pointer(restrict BuiltIn(char)), Pointer(restrict Attributed(const , BuiltIn(char))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(strncat), - //BuiltIn(int) strcmp(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(strcmp), - //BuiltIn(int) strncmp(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(strncmp), - //BuiltIn(int) strcoll(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(strcoll), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) strxfrm(Pointer(restrict BuiltIn(char)), Pointer(restrict Attributed(const , BuiltIn(char))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(strxfrm), - //BuiltIn(int) strcoll_l(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(strcoll_l), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) strxfrm_l(Pointer(BuiltIn(char)), Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(strxfrm_l), - //Pointer(BuiltIn(char)) strdup(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(strdup), - //Pointer(BuiltIn(char)) strndup(Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(strndup), - //Pointer(BuiltIn(char)) strchr(Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int)); -// (void *)(strchr), - //Pointer(BuiltIn(char)) strrchr(Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int)); -// (void *)(strrchr), - //Pointer(BuiltIn(char)) strchrnul(Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int)); -// (void *)(strchrnul), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) strcspn(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(strcspn), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) strspn(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(strspn), - //Pointer(BuiltIn(char)) strpbrk(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char)))); -// (void *)(strpbrk), - //Pointer(BuiltIn(char)) strstr(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char)))); -// (void *)(strstr), - //Pointer(BuiltIn(char)) strtok(Pointer(restrict BuiltIn(char)), Pointer(restrict Attributed(const , BuiltIn(char)))); - (void *)(strtok), - //Pointer(BuiltIn(char)) __strtok_r(Pointer(restrict BuiltIn(char)), Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Pointer(BuiltIn(char)))); - (void *)(__strtok_r), - //Pointer(BuiltIn(char)) strtok_r(Pointer(restrict BuiltIn(char)), Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Pointer(BuiltIn(char)))); - (void *)(strtok_r), - //Pointer(BuiltIn(char)) strcasestr(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char)))); -// (void *)(strcasestr), - //Pointer(BuiltIn(void)) memmem(Pointer(Attributed(const , BuiltIn(void))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Attributed(const , BuiltIn(void))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(memmem), - //Pointer(BuiltIn(void)) __mempcpy(Pointer(restrict BuiltIn(void)), Pointer(restrict Attributed(const , BuiltIn(void))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(__mempcpy), - //Pointer(BuiltIn(void)) mempcpy(Pointer(restrict BuiltIn(void)), Pointer(restrict Attributed(const , BuiltIn(void))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(mempcpy), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) strlen(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(strlen), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) strnlen(Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(strnlen), - //Pointer(BuiltIn(char)) strerror(BuiltIn(int)); - (void *)(strerror), - //Pointer(BuiltIn(char)) strerror_r(BuiltIn(int), Pointer(BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(strerror_r), - //Pointer(BuiltIn(char)) strerror_l(BuiltIn(int), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(strerror_l), - //BuiltIn(void) bzero(Pointer(BuiltIn(void)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(bzero), - //BuiltIn(void) bcopy(Pointer(Attributed(const , BuiltIn(void))), Pointer(BuiltIn(void)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(bcopy), - //BuiltIn(void) bzero(Pointer(BuiltIn(void)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(bzero), - //BuiltIn(int) bcmp(Pointer(Attributed(const , BuiltIn(void))), Pointer(Attributed(const , BuiltIn(void))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(bcmp), - //Pointer(BuiltIn(char)) index(Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int)); -// (void *)(index), - //Pointer(BuiltIn(char)) rindex(Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int)); -// (void *)(rindex), - //BuiltIn(int) ffs(BuiltIn(int)); - (void *)(ffs), - //BuiltIn(int) ffsl(BuiltIn(long)); - (void *)(ffsl), - //BuiltIn(int) ffsll(BuiltIn(long long)); - (void *)(ffsll), - //BuiltIn(int) strcasecmp(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(strcasecmp), - //BuiltIn(int) strncasecmp(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(strncasecmp), - //BuiltIn(int) strcasecmp_l(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(strcasecmp_l), - //BuiltIn(int) strncasecmp_l(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(strncasecmp_l), - //Pointer(BuiltIn(char)) strsep(Pointer(restrict Pointer(BuiltIn(char))), Pointer(restrict Attributed(const , BuiltIn(char)))); - (void *)(strsep), - //Pointer(BuiltIn(char)) strsignal(BuiltIn(int)); - (void *)(strsignal), - //Pointer(BuiltIn(char)) __stpcpy(Pointer(restrict BuiltIn(char)), Pointer(restrict Attributed(const , BuiltIn(char)))); - (void *)(__stpcpy), - //Pointer(BuiltIn(char)) stpcpy(Pointer(restrict BuiltIn(char)), Pointer(restrict Attributed(const , BuiltIn(char)))); - (void *)(stpcpy), - //Pointer(BuiltIn(char)) __stpncpy(Pointer(restrict BuiltIn(char)), Pointer(restrict Attributed(const , BuiltIn(char))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(__stpncpy), - //Pointer(BuiltIn(char)) stpncpy(Pointer(restrict BuiltIn(char)), Pointer(restrict Attributed(const , BuiltIn(char))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(stpncpy), - //BuiltIn(int) strverscmp(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(strverscmp), - //Pointer(BuiltIn(char)) strfry(Pointer(BuiltIn(char))); - (void *)(strfry), - //Pointer(BuiltIn(void)) memfrob(Pointer(BuiltIn(void)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(memfrob), - //Pointer(BuiltIn(char)) basename(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(basename), - //BuiltIn(int) wordexp(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Use(TypeDef(wordexp_t, Struct(struct anon_struct_156)))), BuiltIn(int)); - (void *)(wordexp), - //BuiltIn(void) wordfree(Pointer(Use(TypeDef(wordexp_t, Struct(struct anon_struct_156))))); - (void *)(wordfree), - //BuiltIn(double) acos(BuiltIn(double)); - (void *)(acos), - //BuiltIn(double) __acos(BuiltIn(double)); - (void *)(__acos), - //BuiltIn(double) asin(BuiltIn(double)); - (void *)(asin), - //BuiltIn(double) __asin(BuiltIn(double)); - (void *)(__asin), - //BuiltIn(double) atan(BuiltIn(double)); - (void *)(atan), - //BuiltIn(double) __atan(BuiltIn(double)); - (void *)(__atan), - //BuiltIn(double) atan2(BuiltIn(double), BuiltIn(double)); - (void *)(atan2), - //BuiltIn(double) __atan2(BuiltIn(double), BuiltIn(double)); - (void *)(__atan2), - //BuiltIn(double) cos(BuiltIn(double)); - (void *)(cos), - //BuiltIn(double) __cos(BuiltIn(double)); - (void *)(__cos), - //BuiltIn(double) sin(BuiltIn(double)); - (void *)(sin), - //BuiltIn(double) __sin(BuiltIn(double)); - (void *)(__sin), - //BuiltIn(double) tan(BuiltIn(double)); - (void *)(tan), - //BuiltIn(double) __tan(BuiltIn(double)); - (void *)(__tan), - //BuiltIn(double) cosh(BuiltIn(double)); - (void *)(cosh), - //BuiltIn(double) __cosh(BuiltIn(double)); - (void *)(__cosh), - //BuiltIn(double) sinh(BuiltIn(double)); - (void *)(sinh), - //BuiltIn(double) __sinh(BuiltIn(double)); - (void *)(__sinh), - //BuiltIn(double) tanh(BuiltIn(double)); - (void *)(tanh), - //BuiltIn(double) __tanh(BuiltIn(double)); - (void *)(__tanh), - //BuiltIn(void) sincos(BuiltIn(double), Pointer(BuiltIn(double)), Pointer(BuiltIn(double))); - (void *)(sincos), - //BuiltIn(void) __sincos(BuiltIn(double), Pointer(BuiltIn(double)), Pointer(BuiltIn(double))); - (void *)(__sincos), - //BuiltIn(double) acosh(BuiltIn(double)); - (void *)(acosh), - //BuiltIn(double) __acosh(BuiltIn(double)); - (void *)(__acosh), - //BuiltIn(double) asinh(BuiltIn(double)); - (void *)(asinh), - //BuiltIn(double) __asinh(BuiltIn(double)); - (void *)(__asinh), - //BuiltIn(double) atanh(BuiltIn(double)); - (void *)(atanh), - //BuiltIn(double) __atanh(BuiltIn(double)); - (void *)(__atanh), - //BuiltIn(double) exp(BuiltIn(double)); - (void *)(exp), - //BuiltIn(double) __exp(BuiltIn(double)); - (void *)(__exp), - //BuiltIn(double) frexp(BuiltIn(double), Pointer(BuiltIn(int))); - (void *)(frexp), - //BuiltIn(double) __frexp(BuiltIn(double), Pointer(BuiltIn(int))); - (void *)(__frexp), - //BuiltIn(double) ldexp(BuiltIn(double), BuiltIn(int)); - (void *)(ldexp), - //BuiltIn(double) __ldexp(BuiltIn(double), BuiltIn(int)); - (void *)(__ldexp), - //BuiltIn(double) log(BuiltIn(double)); - (void *)(log), - //BuiltIn(double) __log(BuiltIn(double)); - (void *)(__log), - //BuiltIn(double) log10(BuiltIn(double)); - (void *)(log10), - //BuiltIn(double) __log10(BuiltIn(double)); - (void *)(__log10), - //BuiltIn(double) modf(BuiltIn(double), Pointer(BuiltIn(double))); - (void *)(modf), - //BuiltIn(double) __modf(BuiltIn(double), Pointer(BuiltIn(double))); - (void *)(__modf), - //BuiltIn(double) exp10(BuiltIn(double)); - (void *)(exp10), - //BuiltIn(double) __exp10(BuiltIn(double)); - (void *)(__exp10), - //BuiltIn(double) expm1(BuiltIn(double)); - (void *)(expm1), - //BuiltIn(double) __expm1(BuiltIn(double)); - (void *)(__expm1), - //BuiltIn(double) log1p(BuiltIn(double)); - (void *)(log1p), - //BuiltIn(double) __log1p(BuiltIn(double)); - (void *)(__log1p), - //BuiltIn(double) logb(BuiltIn(double)); - (void *)(logb), - //BuiltIn(double) __logb(BuiltIn(double)); - (void *)(__logb), - //BuiltIn(double) exp2(BuiltIn(double)); - (void *)(exp2), - //BuiltIn(double) __exp2(BuiltIn(double)); - (void *)(__exp2), - //BuiltIn(double) log2(BuiltIn(double)); - (void *)(log2), - //BuiltIn(double) __log2(BuiltIn(double)); - (void *)(__log2), - //BuiltIn(double) pow(BuiltIn(double), BuiltIn(double)); - (void *)(pow), - //BuiltIn(double) __pow(BuiltIn(double), BuiltIn(double)); - (void *)(__pow), - //BuiltIn(double) sqrt(BuiltIn(double)); - (void *)(sqrt), - //BuiltIn(double) __sqrt(BuiltIn(double)); - (void *)(__sqrt), - //BuiltIn(double) hypot(BuiltIn(double), BuiltIn(double)); - (void *)(hypot), - //BuiltIn(double) __hypot(BuiltIn(double), BuiltIn(double)); - (void *)(__hypot), - //BuiltIn(double) cbrt(BuiltIn(double)); - (void *)(cbrt), - //BuiltIn(double) __cbrt(BuiltIn(double)); - (void *)(__cbrt), - //BuiltIn(double) ceil(BuiltIn(double)); - (void *)(ceil), - //BuiltIn(double) __ceil(BuiltIn(double)); - (void *)(__ceil), - //BuiltIn(double) fabs(BuiltIn(double)); - (void *)(fabs), - //BuiltIn(double) __fabs(BuiltIn(double)); - (void *)(__fabs), - //BuiltIn(double) floor(BuiltIn(double)); - (void *)(floor), - //BuiltIn(double) __floor(BuiltIn(double)); - (void *)(__floor), - //BuiltIn(double) fmod(BuiltIn(double), BuiltIn(double)); - (void *)(fmod), - //BuiltIn(double) __fmod(BuiltIn(double), BuiltIn(double)); - (void *)(__fmod), - //BuiltIn(int) __isinf(BuiltIn(double)); - (void *)(__isinf), - //BuiltIn(int) __finite(BuiltIn(double)); - (void *)(__finite), - //BuiltIn(int) isinf(BuiltIn(double)); -// (void *)(isinf), - //BuiltIn(int) finite(BuiltIn(double)); - (void *)(finite), - //BuiltIn(double) drem(BuiltIn(double), BuiltIn(double)); - (void *)(drem), - //BuiltIn(double) __drem(BuiltIn(double), BuiltIn(double)); - (void *)(__drem), - //BuiltIn(double) significand(BuiltIn(double)); - (void *)(significand), - //BuiltIn(double) __significand(BuiltIn(double)); - (void *)(__significand), - //BuiltIn(double) copysign(BuiltIn(double), BuiltIn(double)); - (void *)(copysign), - //BuiltIn(double) __copysign(BuiltIn(double), BuiltIn(double)); - (void *)(__copysign), - //BuiltIn(double) nan(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(nan), - //BuiltIn(double) __nan(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(__nan), - //BuiltIn(int) __isnan(BuiltIn(double)); - (void *)(__isnan), - //BuiltIn(int) isnan(BuiltIn(double)); -// (void *)(isnan), - //BuiltIn(double) j0(BuiltIn(double)); - (void *)(j0), - //BuiltIn(double) __j0(BuiltIn(double)); - (void *)(__j0), - //BuiltIn(double) j1(BuiltIn(double)); - (void *)(j1), - //BuiltIn(double) __j1(BuiltIn(double)); - (void *)(__j1), - //BuiltIn(double) jn(BuiltIn(int), BuiltIn(double)); - (void *)(jn), - //BuiltIn(double) __jn(BuiltIn(int), BuiltIn(double)); - (void *)(__jn), - //BuiltIn(double) y0(BuiltIn(double)); - (void *)(y0), - //BuiltIn(double) __y0(BuiltIn(double)); - (void *)(__y0), - //BuiltIn(double) y1(BuiltIn(double)); - (void *)(y1), - //BuiltIn(double) __y1(BuiltIn(double)); - (void *)(__y1), - //BuiltIn(double) yn(BuiltIn(int), BuiltIn(double)); - (void *)(yn), - //BuiltIn(double) __yn(BuiltIn(int), BuiltIn(double)); - (void *)(__yn), - //BuiltIn(double) erf(BuiltIn(double)); - (void *)(erf), - //BuiltIn(double) __erf(BuiltIn(double)); - (void *)(__erf), - //BuiltIn(double) erfc(BuiltIn(double)); - (void *)(erfc), - //BuiltIn(double) __erfc(BuiltIn(double)); - (void *)(__erfc), - //BuiltIn(double) lgamma(BuiltIn(double)); - (void *)(lgamma), - //BuiltIn(double) __lgamma(BuiltIn(double)); - (void *)(__lgamma), - //BuiltIn(double) tgamma(BuiltIn(double)); - (void *)(tgamma), - //BuiltIn(double) gamma(BuiltIn(double)); - (void *)(gamma), - //BuiltIn(double) __gamma(BuiltIn(double)); - (void *)(__gamma), - //BuiltIn(double) lgamma_r(BuiltIn(double), Pointer(BuiltIn(int))); - (void *)(lgamma_r), - //BuiltIn(double) __lgamma_r(BuiltIn(double), Pointer(BuiltIn(int))); - (void *)(__lgamma_r), - //BuiltIn(double) rint(BuiltIn(double)); - (void *)(rint), - //BuiltIn(double) __rint(BuiltIn(double)); - (void *)(__rint), - //BuiltIn(double) nextafter(BuiltIn(double), BuiltIn(double)); - (void *)(nextafter), - //BuiltIn(double) __nextafter(BuiltIn(double), BuiltIn(double)); - (void *)(__nextafter), - //BuiltIn(double) nexttoward(BuiltIn(double), BuiltIn(long double)); - (void *)(nexttoward), - //BuiltIn(double) __nexttoward(BuiltIn(double), BuiltIn(long double)); - (void *)(__nexttoward), - //BuiltIn(double) remainder(BuiltIn(double), BuiltIn(double)); - (void *)(remainder), - //BuiltIn(double) __remainder(BuiltIn(double), BuiltIn(double)); - (void *)(__remainder), - //BuiltIn(double) scalbn(BuiltIn(double), BuiltIn(int)); - (void *)(scalbn), - //BuiltIn(double) __scalbn(BuiltIn(double), BuiltIn(int)); - (void *)(__scalbn), - //BuiltIn(int) ilogb(BuiltIn(double)); - (void *)(ilogb), - //BuiltIn(int) __ilogb(BuiltIn(double)); - (void *)(__ilogb), - //BuiltIn(double) scalbln(BuiltIn(double), BuiltIn(long)); - (void *)(scalbln), - //BuiltIn(double) __scalbln(BuiltIn(double), BuiltIn(long)); - (void *)(__scalbln), - //BuiltIn(double) nearbyint(BuiltIn(double)); - (void *)(nearbyint), - //BuiltIn(double) __nearbyint(BuiltIn(double)); - (void *)(__nearbyint), - //BuiltIn(double) round(BuiltIn(double)); - (void *)(round), - //BuiltIn(double) __round(BuiltIn(double)); - (void *)(__round), - //BuiltIn(double) trunc(BuiltIn(double)); - (void *)(trunc), - //BuiltIn(double) __trunc(BuiltIn(double)); - (void *)(__trunc), - //BuiltIn(double) remquo(BuiltIn(double), BuiltIn(double), Pointer(BuiltIn(int))); - (void *)(remquo), - //BuiltIn(double) __remquo(BuiltIn(double), BuiltIn(double), Pointer(BuiltIn(int))); - (void *)(__remquo), - //BuiltIn(long) lrint(BuiltIn(double)); - (void *)(lrint), - //BuiltIn(long) __lrint(BuiltIn(double)); - (void *)(__lrint), - //BuiltIn(long long) llrint(BuiltIn(double)); - (void *)(llrint), - //BuiltIn(long long) __llrint(BuiltIn(double)); - (void *)(__llrint), - //BuiltIn(long) lround(BuiltIn(double)); - (void *)(lround), - //BuiltIn(long) __lround(BuiltIn(double)); - (void *)(__lround), - //BuiltIn(long long) llround(BuiltIn(double)); - (void *)(llround), - //BuiltIn(long long) __llround(BuiltIn(double)); - (void *)(__llround), - //BuiltIn(double) fdim(BuiltIn(double), BuiltIn(double)); - (void *)(fdim), - //BuiltIn(double) __fdim(BuiltIn(double), BuiltIn(double)); - (void *)(__fdim), - //BuiltIn(double) fmax(BuiltIn(double), BuiltIn(double)); - (void *)(fmax), - //BuiltIn(double) __fmax(BuiltIn(double), BuiltIn(double)); - (void *)(__fmax), - //BuiltIn(double) fmin(BuiltIn(double), BuiltIn(double)); - (void *)(fmin), - //BuiltIn(double) __fmin(BuiltIn(double), BuiltIn(double)); - (void *)(__fmin), - //BuiltIn(int) __fpclassify(BuiltIn(double)); - (void *)(__fpclassify), - //BuiltIn(int) __signbit(BuiltIn(double)); - (void *)(__signbit), - //BuiltIn(double) fma(BuiltIn(double), BuiltIn(double), BuiltIn(double)); - (void *)(fma), - //BuiltIn(double) __fma(BuiltIn(double), BuiltIn(double), BuiltIn(double)); - (void *)(__fma), - //BuiltIn(int) __issignaling(BuiltIn(double)); - (void *)(__issignaling), - //BuiltIn(double) scalb(BuiltIn(double), BuiltIn(double)); - (void *)(scalb), - //BuiltIn(double) __scalb(BuiltIn(double), BuiltIn(double)); - (void *)(__scalb), - //BuiltIn(float) acosf(BuiltIn(float)); - (void *)(acosf), - //BuiltIn(float) __acosf(BuiltIn(float)); - (void *)(__acosf), - //BuiltIn(float) asinf(BuiltIn(float)); - (void *)(asinf), - //BuiltIn(float) __asinf(BuiltIn(float)); - (void *)(__asinf), - //BuiltIn(float) atanf(BuiltIn(float)); - (void *)(atanf), - //BuiltIn(float) __atanf(BuiltIn(float)); - (void *)(__atanf), - //BuiltIn(float) atan2f(BuiltIn(float), BuiltIn(float)); - (void *)(atan2f), - //BuiltIn(float) __atan2f(BuiltIn(float), BuiltIn(float)); - (void *)(__atan2f), - //BuiltIn(float) cosf(BuiltIn(float)); - (void *)(cosf), - //BuiltIn(float) __cosf(BuiltIn(float)); - (void *)(__cosf), - //BuiltIn(float) sinf(BuiltIn(float)); - (void *)(sinf), - //BuiltIn(float) __sinf(BuiltIn(float)); - (void *)(__sinf), - //BuiltIn(float) tanf(BuiltIn(float)); - (void *)(tanf), - //BuiltIn(float) __tanf(BuiltIn(float)); - (void *)(__tanf), - //BuiltIn(float) coshf(BuiltIn(float)); - (void *)(coshf), - //BuiltIn(float) __coshf(BuiltIn(float)); - (void *)(__coshf), - //BuiltIn(float) sinhf(BuiltIn(float)); - (void *)(sinhf), - //BuiltIn(float) __sinhf(BuiltIn(float)); - (void *)(__sinhf), - //BuiltIn(float) tanhf(BuiltIn(float)); - (void *)(tanhf), - //BuiltIn(float) __tanhf(BuiltIn(float)); - (void *)(__tanhf), - //BuiltIn(void) sincosf(BuiltIn(float), Pointer(BuiltIn(float)), Pointer(BuiltIn(float))); - (void *)(sincosf), - //BuiltIn(void) __sincosf(BuiltIn(float), Pointer(BuiltIn(float)), Pointer(BuiltIn(float))); - (void *)(__sincosf), - //BuiltIn(float) acoshf(BuiltIn(float)); - (void *)(acoshf), - //BuiltIn(float) __acoshf(BuiltIn(float)); - (void *)(__acoshf), - //BuiltIn(float) asinhf(BuiltIn(float)); - (void *)(asinhf), - //BuiltIn(float) __asinhf(BuiltIn(float)); - (void *)(__asinhf), - //BuiltIn(float) atanhf(BuiltIn(float)); - (void *)(atanhf), - //BuiltIn(float) __atanhf(BuiltIn(float)); - (void *)(__atanhf), - //BuiltIn(float) expf(BuiltIn(float)); - (void *)(expf), - //BuiltIn(float) __expf(BuiltIn(float)); - (void *)(__expf), - //BuiltIn(float) frexpf(BuiltIn(float), Pointer(BuiltIn(int))); - (void *)(frexpf), - //BuiltIn(float) __frexpf(BuiltIn(float), Pointer(BuiltIn(int))); - (void *)(__frexpf), - //BuiltIn(float) ldexpf(BuiltIn(float), BuiltIn(int)); - (void *)(ldexpf), - //BuiltIn(float) __ldexpf(BuiltIn(float), BuiltIn(int)); - (void *)(__ldexpf), - //BuiltIn(float) logf(BuiltIn(float)); - (void *)(logf), - //BuiltIn(float) __logf(BuiltIn(float)); - (void *)(__logf), - //BuiltIn(float) log10f(BuiltIn(float)); - (void *)(log10f), - //BuiltIn(float) __log10f(BuiltIn(float)); - (void *)(__log10f), - //BuiltIn(float) modff(BuiltIn(float), Pointer(BuiltIn(float))); - (void *)(modff), - //BuiltIn(float) __modff(BuiltIn(float), Pointer(BuiltIn(float))); - (void *)(__modff), - //BuiltIn(float) exp10f(BuiltIn(float)); - (void *)(exp10f), - //BuiltIn(float) __exp10f(BuiltIn(float)); - (void *)(__exp10f), - //BuiltIn(float) expm1f(BuiltIn(float)); - (void *)(expm1f), - //BuiltIn(float) __expm1f(BuiltIn(float)); - (void *)(__expm1f), - //BuiltIn(float) log1pf(BuiltIn(float)); - (void *)(log1pf), - //BuiltIn(float) __log1pf(BuiltIn(float)); - (void *)(__log1pf), - //BuiltIn(float) logbf(BuiltIn(float)); - (void *)(logbf), - //BuiltIn(float) __logbf(BuiltIn(float)); - (void *)(__logbf), - //BuiltIn(float) exp2f(BuiltIn(float)); - (void *)(exp2f), - //BuiltIn(float) __exp2f(BuiltIn(float)); - (void *)(__exp2f), - //BuiltIn(float) log2f(BuiltIn(float)); - (void *)(log2f), - //BuiltIn(float) __log2f(BuiltIn(float)); - (void *)(__log2f), - //BuiltIn(float) powf(BuiltIn(float), BuiltIn(float)); - (void *)(powf), - //BuiltIn(float) __powf(BuiltIn(float), BuiltIn(float)); - (void *)(__powf), - //BuiltIn(float) sqrtf(BuiltIn(float)); - (void *)(sqrtf), - //BuiltIn(float) __sqrtf(BuiltIn(float)); - (void *)(__sqrtf), - //BuiltIn(float) hypotf(BuiltIn(float), BuiltIn(float)); - (void *)(hypotf), - //BuiltIn(float) __hypotf(BuiltIn(float), BuiltIn(float)); - (void *)(__hypotf), - //BuiltIn(float) cbrtf(BuiltIn(float)); - (void *)(cbrtf), - //BuiltIn(float) __cbrtf(BuiltIn(float)); - (void *)(__cbrtf), - //BuiltIn(float) ceilf(BuiltIn(float)); - (void *)(ceilf), - //BuiltIn(float) __ceilf(BuiltIn(float)); - (void *)(__ceilf), - //BuiltIn(float) fabsf(BuiltIn(float)); - (void *)(fabsf), - //BuiltIn(float) __fabsf(BuiltIn(float)); - (void *)(__fabsf), - //BuiltIn(float) floorf(BuiltIn(float)); - (void *)(floorf), - //BuiltIn(float) __floorf(BuiltIn(float)); - (void *)(__floorf), - //BuiltIn(float) fmodf(BuiltIn(float), BuiltIn(float)); - (void *)(fmodf), - //BuiltIn(float) __fmodf(BuiltIn(float), BuiltIn(float)); - (void *)(__fmodf), - //BuiltIn(int) __isinff(BuiltIn(float)); - (void *)(__isinff), - //BuiltIn(int) __finitef(BuiltIn(float)); - (void *)(__finitef), - //BuiltIn(int) isinff(BuiltIn(float)); - (void *)(isinff), - //BuiltIn(int) finitef(BuiltIn(float)); - (void *)(finitef), - //BuiltIn(float) dremf(BuiltIn(float), BuiltIn(float)); - (void *)(dremf), - //BuiltIn(float) __dremf(BuiltIn(float), BuiltIn(float)); - (void *)(__dremf), - //BuiltIn(float) significandf(BuiltIn(float)); - (void *)(significandf), - //BuiltIn(float) __significandf(BuiltIn(float)); - (void *)(__significandf), - //BuiltIn(float) copysignf(BuiltIn(float), BuiltIn(float)); - (void *)(copysignf), - //BuiltIn(float) __copysignf(BuiltIn(float), BuiltIn(float)); - (void *)(__copysignf), - //BuiltIn(float) nanf(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(nanf), - //BuiltIn(float) __nanf(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(__nanf), - //BuiltIn(int) __isnanf(BuiltIn(float)); - (void *)(__isnanf), - //BuiltIn(int) isnanf(BuiltIn(float)); - (void *)(isnanf), - //BuiltIn(float) j0f(BuiltIn(float)); - (void *)(j0f), - //BuiltIn(float) __j0f(BuiltIn(float)); - (void *)(__j0f), - //BuiltIn(float) j1f(BuiltIn(float)); - (void *)(j1f), - //BuiltIn(float) __j1f(BuiltIn(float)); - (void *)(__j1f), - //BuiltIn(float) jnf(BuiltIn(int), BuiltIn(float)); - (void *)(jnf), - //BuiltIn(float) __jnf(BuiltIn(int), BuiltIn(float)); - (void *)(__jnf), - //BuiltIn(float) y0f(BuiltIn(float)); - (void *)(y0f), - //BuiltIn(float) __y0f(BuiltIn(float)); - (void *)(__y0f), - //BuiltIn(float) y1f(BuiltIn(float)); - (void *)(y1f), - //BuiltIn(float) __y1f(BuiltIn(float)); - (void *)(__y1f), - //BuiltIn(float) ynf(BuiltIn(int), BuiltIn(float)); - (void *)(ynf), - //BuiltIn(float) __ynf(BuiltIn(int), BuiltIn(float)); - (void *)(__ynf), - //BuiltIn(float) erff(BuiltIn(float)); - (void *)(erff), - //BuiltIn(float) __erff(BuiltIn(float)); - (void *)(__erff), - //BuiltIn(float) erfcf(BuiltIn(float)); - (void *)(erfcf), - //BuiltIn(float) __erfcf(BuiltIn(float)); - (void *)(__erfcf), - //BuiltIn(float) lgammaf(BuiltIn(float)); - (void *)(lgammaf), - //BuiltIn(float) __lgammaf(BuiltIn(float)); - (void *)(__lgammaf), - //BuiltIn(float) tgammaf(BuiltIn(float)); - (void *)(tgammaf), - //BuiltIn(float) gammaf(BuiltIn(float)); - (void *)(gammaf), - //BuiltIn(float) __gammaf(BuiltIn(float)); - (void *)(__gammaf), - //BuiltIn(float) lgammaf_r(BuiltIn(float), Pointer(BuiltIn(int))); - (void *)(lgammaf_r), - //BuiltIn(float) __lgammaf_r(BuiltIn(float), Pointer(BuiltIn(int))); - (void *)(__lgammaf_r), - //BuiltIn(float) rintf(BuiltIn(float)); - (void *)(rintf), - //BuiltIn(float) __rintf(BuiltIn(float)); - (void *)(__rintf), - //BuiltIn(float) nextafterf(BuiltIn(float), BuiltIn(float)); - (void *)(nextafterf), - //BuiltIn(float) __nextafterf(BuiltIn(float), BuiltIn(float)); - (void *)(__nextafterf), - //BuiltIn(float) nexttowardf(BuiltIn(float), BuiltIn(long double)); - (void *)(nexttowardf), - //BuiltIn(float) __nexttowardf(BuiltIn(float), BuiltIn(long double)); - (void *)(__nexttowardf), - //BuiltIn(float) remainderf(BuiltIn(float), BuiltIn(float)); - (void *)(remainderf), - //BuiltIn(float) __remainderf(BuiltIn(float), BuiltIn(float)); - (void *)(__remainderf), - //BuiltIn(float) scalbnf(BuiltIn(float), BuiltIn(int)); - (void *)(scalbnf), - //BuiltIn(float) __scalbnf(BuiltIn(float), BuiltIn(int)); - (void *)(__scalbnf), - //BuiltIn(int) ilogbf(BuiltIn(float)); - (void *)(ilogbf), - //BuiltIn(int) __ilogbf(BuiltIn(float)); - (void *)(__ilogbf), - //BuiltIn(float) scalblnf(BuiltIn(float), BuiltIn(long)); - (void *)(scalblnf), - //BuiltIn(float) __scalblnf(BuiltIn(float), BuiltIn(long)); - (void *)(__scalblnf), - //BuiltIn(float) nearbyintf(BuiltIn(float)); - (void *)(nearbyintf), - //BuiltIn(float) __nearbyintf(BuiltIn(float)); - (void *)(__nearbyintf), - //BuiltIn(float) roundf(BuiltIn(float)); - (void *)(roundf), - //BuiltIn(float) __roundf(BuiltIn(float)); - (void *)(__roundf), - //BuiltIn(float) truncf(BuiltIn(float)); - (void *)(truncf), - //BuiltIn(float) __truncf(BuiltIn(float)); - (void *)(__truncf), - //BuiltIn(float) remquof(BuiltIn(float), BuiltIn(float), Pointer(BuiltIn(int))); - (void *)(remquof), - //BuiltIn(float) __remquof(BuiltIn(float), BuiltIn(float), Pointer(BuiltIn(int))); - (void *)(__remquof), - //BuiltIn(long) lrintf(BuiltIn(float)); - (void *)(lrintf), - //BuiltIn(long) __lrintf(BuiltIn(float)); - (void *)(__lrintf), - //BuiltIn(long long) llrintf(BuiltIn(float)); - (void *)(llrintf), - //BuiltIn(long long) __llrintf(BuiltIn(float)); - (void *)(__llrintf), - //BuiltIn(long) lroundf(BuiltIn(float)); - (void *)(lroundf), - //BuiltIn(long) __lroundf(BuiltIn(float)); - (void *)(__lroundf), - //BuiltIn(long long) llroundf(BuiltIn(float)); - (void *)(llroundf), - //BuiltIn(long long) __llroundf(BuiltIn(float)); - (void *)(__llroundf), - //BuiltIn(float) fdimf(BuiltIn(float), BuiltIn(float)); - (void *)(fdimf), - //BuiltIn(float) __fdimf(BuiltIn(float), BuiltIn(float)); - (void *)(__fdimf), - //BuiltIn(float) fmaxf(BuiltIn(float), BuiltIn(float)); - (void *)(fmaxf), - //BuiltIn(float) __fmaxf(BuiltIn(float), BuiltIn(float)); - (void *)(__fmaxf), - //BuiltIn(float) fminf(BuiltIn(float), BuiltIn(float)); - (void *)(fminf), - //BuiltIn(float) __fminf(BuiltIn(float), BuiltIn(float)); - (void *)(__fminf), - //BuiltIn(int) __fpclassifyf(BuiltIn(float)); - (void *)(__fpclassifyf), - //BuiltIn(int) __signbitf(BuiltIn(float)); - (void *)(__signbitf), - //BuiltIn(float) fmaf(BuiltIn(float), BuiltIn(float), BuiltIn(float)); - (void *)(fmaf), - //BuiltIn(float) __fmaf(BuiltIn(float), BuiltIn(float), BuiltIn(float)); - (void *)(__fmaf), - //BuiltIn(int) __issignalingf(BuiltIn(float)); - (void *)(__issignalingf), - //BuiltIn(float) scalbf(BuiltIn(float), BuiltIn(float)); - (void *)(scalbf), - //BuiltIn(float) __scalbf(BuiltIn(float), BuiltIn(float)); - (void *)(__scalbf), - //BuiltIn(long double) acosl(BuiltIn(long double)); - (void *)(acosl), - //BuiltIn(long double) __acosl(BuiltIn(long double)); - (void *)(__acosl), - //BuiltIn(long double) asinl(BuiltIn(long double)); - (void *)(asinl), - //BuiltIn(long double) __asinl(BuiltIn(long double)); - (void *)(__asinl), - //BuiltIn(long double) atanl(BuiltIn(long double)); - (void *)(atanl), - //BuiltIn(long double) __atanl(BuiltIn(long double)); - (void *)(__atanl), - //BuiltIn(long double) atan2l(BuiltIn(long double), BuiltIn(long double)); - (void *)(atan2l), - //BuiltIn(long double) __atan2l(BuiltIn(long double), BuiltIn(long double)); - (void *)(__atan2l), - //BuiltIn(long double) cosl(BuiltIn(long double)); - (void *)(cosl), - //BuiltIn(long double) __cosl(BuiltIn(long double)); - (void *)(__cosl), - //BuiltIn(long double) sinl(BuiltIn(long double)); - (void *)(sinl), - //BuiltIn(long double) __sinl(BuiltIn(long double)); - (void *)(__sinl), - //BuiltIn(long double) tanl(BuiltIn(long double)); - (void *)(tanl), - //BuiltIn(long double) __tanl(BuiltIn(long double)); - (void *)(__tanl), - //BuiltIn(long double) coshl(BuiltIn(long double)); - (void *)(coshl), - //BuiltIn(long double) __coshl(BuiltIn(long double)); - (void *)(__coshl), - //BuiltIn(long double) sinhl(BuiltIn(long double)); - (void *)(sinhl), - //BuiltIn(long double) __sinhl(BuiltIn(long double)); - (void *)(__sinhl), - //BuiltIn(long double) tanhl(BuiltIn(long double)); - (void *)(tanhl), - //BuiltIn(long double) __tanhl(BuiltIn(long double)); - (void *)(__tanhl), - //BuiltIn(void) sincosl(BuiltIn(long double), Pointer(BuiltIn(long double)), Pointer(BuiltIn(long double))); - (void *)(sincosl), - //BuiltIn(void) __sincosl(BuiltIn(long double), Pointer(BuiltIn(long double)), Pointer(BuiltIn(long double))); - (void *)(__sincosl), - //BuiltIn(long double) acoshl(BuiltIn(long double)); - (void *)(acoshl), - //BuiltIn(long double) __acoshl(BuiltIn(long double)); - (void *)(__acoshl), - //BuiltIn(long double) asinhl(BuiltIn(long double)); - (void *)(asinhl), - //BuiltIn(long double) __asinhl(BuiltIn(long double)); - (void *)(__asinhl), - //BuiltIn(long double) atanhl(BuiltIn(long double)); - (void *)(atanhl), - //BuiltIn(long double) __atanhl(BuiltIn(long double)); - (void *)(__atanhl), - //BuiltIn(long double) expl(BuiltIn(long double)); - (void *)(expl), - //BuiltIn(long double) __expl(BuiltIn(long double)); - (void *)(__expl), - //BuiltIn(long double) frexpl(BuiltIn(long double), Pointer(BuiltIn(int))); - (void *)(frexpl), - //BuiltIn(long double) __frexpl(BuiltIn(long double), Pointer(BuiltIn(int))); - (void *)(__frexpl), - //BuiltIn(long double) ldexpl(BuiltIn(long double), BuiltIn(int)); - (void *)(ldexpl), - //BuiltIn(long double) __ldexpl(BuiltIn(long double), BuiltIn(int)); - (void *)(__ldexpl), - //BuiltIn(long double) logl(BuiltIn(long double)); - (void *)(logl), - //BuiltIn(long double) __logl(BuiltIn(long double)); - (void *)(__logl), - //BuiltIn(long double) log10l(BuiltIn(long double)); - (void *)(log10l), - //BuiltIn(long double) __log10l(BuiltIn(long double)); - (void *)(__log10l), - //BuiltIn(long double) modfl(BuiltIn(long double), Pointer(BuiltIn(long double))); - (void *)(modfl), - //BuiltIn(long double) __modfl(BuiltIn(long double), Pointer(BuiltIn(long double))); - (void *)(__modfl), - //BuiltIn(long double) exp10l(BuiltIn(long double)); - (void *)(exp10l), - //BuiltIn(long double) __exp10l(BuiltIn(long double)); - (void *)(__exp10l), - //BuiltIn(long double) expm1l(BuiltIn(long double)); - (void *)(expm1l), - //BuiltIn(long double) __expm1l(BuiltIn(long double)); - (void *)(__expm1l), - //BuiltIn(long double) log1pl(BuiltIn(long double)); - (void *)(log1pl), - //BuiltIn(long double) __log1pl(BuiltIn(long double)); - (void *)(__log1pl), - //BuiltIn(long double) logbl(BuiltIn(long double)); - (void *)(logbl), - //BuiltIn(long double) __logbl(BuiltIn(long double)); - (void *)(__logbl), - //BuiltIn(long double) exp2l(BuiltIn(long double)); - (void *)(exp2l), - //BuiltIn(long double) __exp2l(BuiltIn(long double)); - (void *)(__exp2l), - //BuiltIn(long double) log2l(BuiltIn(long double)); - (void *)(log2l), - //BuiltIn(long double) __log2l(BuiltIn(long double)); - (void *)(__log2l), - //BuiltIn(long double) powl(BuiltIn(long double), BuiltIn(long double)); - (void *)(powl), - //BuiltIn(long double) __powl(BuiltIn(long double), BuiltIn(long double)); - (void *)(__powl), - //BuiltIn(long double) sqrtl(BuiltIn(long double)); - (void *)(sqrtl), - //BuiltIn(long double) __sqrtl(BuiltIn(long double)); - (void *)(__sqrtl), - //BuiltIn(long double) hypotl(BuiltIn(long double), BuiltIn(long double)); - (void *)(hypotl), - //BuiltIn(long double) __hypotl(BuiltIn(long double), BuiltIn(long double)); - (void *)(__hypotl), - //BuiltIn(long double) cbrtl(BuiltIn(long double)); - (void *)(cbrtl), - //BuiltIn(long double) __cbrtl(BuiltIn(long double)); - (void *)(__cbrtl), - //BuiltIn(long double) ceill(BuiltIn(long double)); - (void *)(ceill), - //BuiltIn(long double) __ceill(BuiltIn(long double)); - (void *)(__ceill), - //BuiltIn(long double) fabsl(BuiltIn(long double)); - (void *)(fabsl), - //BuiltIn(long double) __fabsl(BuiltIn(long double)); - (void *)(__fabsl), - //BuiltIn(long double) floorl(BuiltIn(long double)); - (void *)(floorl), - //BuiltIn(long double) __floorl(BuiltIn(long double)); - (void *)(__floorl), - //BuiltIn(long double) fmodl(BuiltIn(long double), BuiltIn(long double)); - (void *)(fmodl), - //BuiltIn(long double) __fmodl(BuiltIn(long double), BuiltIn(long double)); - (void *)(__fmodl), - //BuiltIn(int) __isinfl(BuiltIn(long double)); - (void *)(__isinfl), - //BuiltIn(int) __finitel(BuiltIn(long double)); - (void *)(__finitel), - //BuiltIn(int) isinfl(BuiltIn(long double)); - (void *)(isinfl), - //BuiltIn(int) finitel(BuiltIn(long double)); - (void *)(finitel), - //BuiltIn(long double) dreml(BuiltIn(long double), BuiltIn(long double)); - (void *)(dreml), - //BuiltIn(long double) __dreml(BuiltIn(long double), BuiltIn(long double)); - (void *)(__dreml), - //BuiltIn(long double) significandl(BuiltIn(long double)); - (void *)(significandl), - //BuiltIn(long double) __significandl(BuiltIn(long double)); - (void *)(__significandl), - //BuiltIn(long double) copysignl(BuiltIn(long double), BuiltIn(long double)); - (void *)(copysignl), - //BuiltIn(long double) __copysignl(BuiltIn(long double), BuiltIn(long double)); - (void *)(__copysignl), - //BuiltIn(long double) nanl(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(nanl), - //BuiltIn(long double) __nanl(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(__nanl), - //BuiltIn(int) __isnanl(BuiltIn(long double)); - (void *)(__isnanl), - //BuiltIn(int) isnanl(BuiltIn(long double)); - (void *)(isnanl), - //BuiltIn(long double) j0l(BuiltIn(long double)); - (void *)(j0l), - //BuiltIn(long double) __j0l(BuiltIn(long double)); - (void *)(__j0l), - //BuiltIn(long double) j1l(BuiltIn(long double)); - (void *)(j1l), - //BuiltIn(long double) __j1l(BuiltIn(long double)); - (void *)(__j1l), - //BuiltIn(long double) jnl(BuiltIn(int), BuiltIn(long double)); - (void *)(jnl), - //BuiltIn(long double) __jnl(BuiltIn(int), BuiltIn(long double)); - (void *)(__jnl), - //BuiltIn(long double) y0l(BuiltIn(long double)); - (void *)(y0l), - //BuiltIn(long double) __y0l(BuiltIn(long double)); - (void *)(__y0l), - //BuiltIn(long double) y1l(BuiltIn(long double)); - (void *)(y1l), - //BuiltIn(long double) __y1l(BuiltIn(long double)); - (void *)(__y1l), - //BuiltIn(long double) ynl(BuiltIn(int), BuiltIn(long double)); - (void *)(ynl), - //BuiltIn(long double) __ynl(BuiltIn(int), BuiltIn(long double)); - (void *)(__ynl), - //BuiltIn(long double) erfl(BuiltIn(long double)); - (void *)(erfl), - //BuiltIn(long double) __erfl(BuiltIn(long double)); - (void *)(__erfl), - //BuiltIn(long double) erfcl(BuiltIn(long double)); - (void *)(erfcl), - //BuiltIn(long double) __erfcl(BuiltIn(long double)); - (void *)(__erfcl), - //BuiltIn(long double) lgammal(BuiltIn(long double)); - (void *)(lgammal), - //BuiltIn(long double) __lgammal(BuiltIn(long double)); - (void *)(__lgammal), - //BuiltIn(long double) tgammal(BuiltIn(long double)); - (void *)(tgammal), - //BuiltIn(long double) gammal(BuiltIn(long double)); - (void *)(gammal), - //BuiltIn(long double) __gammal(BuiltIn(long double)); - (void *)(__gammal), - //BuiltIn(long double) lgammal_r(BuiltIn(long double), Pointer(BuiltIn(int))); - (void *)(lgammal_r), - //BuiltIn(long double) __lgammal_r(BuiltIn(long double), Pointer(BuiltIn(int))); - (void *)(__lgammal_r), - //BuiltIn(long double) rintl(BuiltIn(long double)); - (void *)(rintl), - //BuiltIn(long double) __rintl(BuiltIn(long double)); - (void *)(__rintl), - //BuiltIn(long double) nextafterl(BuiltIn(long double), BuiltIn(long double)); - (void *)(nextafterl), - //BuiltIn(long double) __nextafterl(BuiltIn(long double), BuiltIn(long double)); - (void *)(__nextafterl), - //BuiltIn(long double) nexttowardl(BuiltIn(long double), BuiltIn(long double)); - (void *)(nexttowardl), - //BuiltIn(long double) __nexttowardl(BuiltIn(long double), BuiltIn(long double)); - (void *)(__nexttowardl), - //BuiltIn(long double) remainderl(BuiltIn(long double), BuiltIn(long double)); - (void *)(remainderl), - //BuiltIn(long double) __remainderl(BuiltIn(long double), BuiltIn(long double)); - (void *)(__remainderl), - //BuiltIn(long double) scalbnl(BuiltIn(long double), BuiltIn(int)); - (void *)(scalbnl), - //BuiltIn(long double) __scalbnl(BuiltIn(long double), BuiltIn(int)); - (void *)(__scalbnl), - //BuiltIn(int) ilogbl(BuiltIn(long double)); - (void *)(ilogbl), - //BuiltIn(int) __ilogbl(BuiltIn(long double)); - (void *)(__ilogbl), - //BuiltIn(long double) scalblnl(BuiltIn(long double), BuiltIn(long)); - (void *)(scalblnl), - //BuiltIn(long double) __scalblnl(BuiltIn(long double), BuiltIn(long)); - (void *)(__scalblnl), - //BuiltIn(long double) nearbyintl(BuiltIn(long double)); - (void *)(nearbyintl), - //BuiltIn(long double) __nearbyintl(BuiltIn(long double)); - (void *)(__nearbyintl), - //BuiltIn(long double) roundl(BuiltIn(long double)); - (void *)(roundl), - //BuiltIn(long double) __roundl(BuiltIn(long double)); - (void *)(__roundl), - //BuiltIn(long double) truncl(BuiltIn(long double)); - (void *)(truncl), - //BuiltIn(long double) __truncl(BuiltIn(long double)); - (void *)(__truncl), - //BuiltIn(long double) remquol(BuiltIn(long double), BuiltIn(long double), Pointer(BuiltIn(int))); - (void *)(remquol), - //BuiltIn(long double) __remquol(BuiltIn(long double), BuiltIn(long double), Pointer(BuiltIn(int))); - (void *)(__remquol), - //BuiltIn(long) lrintl(BuiltIn(long double)); - (void *)(lrintl), - //BuiltIn(long) __lrintl(BuiltIn(long double)); - (void *)(__lrintl), - //BuiltIn(long long) llrintl(BuiltIn(long double)); - (void *)(llrintl), - //BuiltIn(long long) __llrintl(BuiltIn(long double)); - (void *)(__llrintl), - //BuiltIn(long) lroundl(BuiltIn(long double)); - (void *)(lroundl), - //BuiltIn(long) __lroundl(BuiltIn(long double)); - (void *)(__lroundl), - //BuiltIn(long long) llroundl(BuiltIn(long double)); - (void *)(llroundl), - //BuiltIn(long long) __llroundl(BuiltIn(long double)); - (void *)(__llroundl), - //BuiltIn(long double) fdiml(BuiltIn(long double), BuiltIn(long double)); - (void *)(fdiml), - //BuiltIn(long double) __fdiml(BuiltIn(long double), BuiltIn(long double)); - (void *)(__fdiml), - //BuiltIn(long double) fmaxl(BuiltIn(long double), BuiltIn(long double)); - (void *)(fmaxl), - //BuiltIn(long double) __fmaxl(BuiltIn(long double), BuiltIn(long double)); - (void *)(__fmaxl), - //BuiltIn(long double) fminl(BuiltIn(long double), BuiltIn(long double)); - (void *)(fminl), - //BuiltIn(long double) __fminl(BuiltIn(long double), BuiltIn(long double)); - (void *)(__fminl), - //BuiltIn(int) __fpclassifyl(BuiltIn(long double)); - (void *)(__fpclassifyl), - //BuiltIn(int) __signbitl(BuiltIn(long double)); - (void *)(__signbitl), - //BuiltIn(long double) fmal(BuiltIn(long double), BuiltIn(long double), BuiltIn(long double)); - (void *)(fmal), - //BuiltIn(long double) __fmal(BuiltIn(long double), BuiltIn(long double), BuiltIn(long double)); - (void *)(__fmal), - //BuiltIn(int) __issignalingl(BuiltIn(long double)); - (void *)(__issignalingl), - //BuiltIn(long double) scalbl(BuiltIn(long double), BuiltIn(long double)); - (void *)(scalbl), - //BuiltIn(long double) __scalbl(BuiltIn(long double), BuiltIn(long double)); - (void *)(__scalbl), - //BuiltIn(double _Complex) cacos(BuiltIn(double _Complex)); - (void *)(cacos), - //BuiltIn(double _Complex) __cacos(BuiltIn(double _Complex)); - (void *)(__cacos), - //BuiltIn(double _Complex) casin(BuiltIn(double _Complex)); - (void *)(casin), - //BuiltIn(double _Complex) __casin(BuiltIn(double _Complex)); - (void *)(__casin), - //BuiltIn(double _Complex) catan(BuiltIn(double _Complex)); - (void *)(catan), - //BuiltIn(double _Complex) __catan(BuiltIn(double _Complex)); - (void *)(__catan), - //BuiltIn(double _Complex) ccos(BuiltIn(double _Complex)); - (void *)(ccos), - //BuiltIn(double _Complex) __ccos(BuiltIn(double _Complex)); - (void *)(__ccos), - //BuiltIn(double _Complex) csin(BuiltIn(double _Complex)); - (void *)(csin), - //BuiltIn(double _Complex) __csin(BuiltIn(double _Complex)); - (void *)(__csin), - //BuiltIn(double _Complex) ctan(BuiltIn(double _Complex)); - (void *)(ctan), - //BuiltIn(double _Complex) __ctan(BuiltIn(double _Complex)); - (void *)(__ctan), - //BuiltIn(double _Complex) cacosh(BuiltIn(double _Complex)); - (void *)(cacosh), - //BuiltIn(double _Complex) __cacosh(BuiltIn(double _Complex)); - (void *)(__cacosh), - //BuiltIn(double _Complex) casinh(BuiltIn(double _Complex)); - (void *)(casinh), - //BuiltIn(double _Complex) __casinh(BuiltIn(double _Complex)); - (void *)(__casinh), - //BuiltIn(double _Complex) catanh(BuiltIn(double _Complex)); - (void *)(catanh), - //BuiltIn(double _Complex) __catanh(BuiltIn(double _Complex)); - (void *)(__catanh), - //BuiltIn(double _Complex) ccosh(BuiltIn(double _Complex)); - (void *)(ccosh), - //BuiltIn(double _Complex) __ccosh(BuiltIn(double _Complex)); - (void *)(__ccosh), - //BuiltIn(double _Complex) csinh(BuiltIn(double _Complex)); - (void *)(csinh), - //BuiltIn(double _Complex) __csinh(BuiltIn(double _Complex)); - (void *)(__csinh), - //BuiltIn(double _Complex) ctanh(BuiltIn(double _Complex)); - (void *)(ctanh), - //BuiltIn(double _Complex) __ctanh(BuiltIn(double _Complex)); - (void *)(__ctanh), - //BuiltIn(double _Complex) cexp(BuiltIn(double _Complex)); - (void *)(cexp), - //BuiltIn(double _Complex) __cexp(BuiltIn(double _Complex)); - (void *)(__cexp), - //BuiltIn(double _Complex) clog(BuiltIn(double _Complex)); - (void *)(clog), - //BuiltIn(double _Complex) __clog(BuiltIn(double _Complex)); - (void *)(__clog), - //BuiltIn(double _Complex) clog10(BuiltIn(double _Complex)); - (void *)(clog10), - //BuiltIn(double _Complex) __clog10(BuiltIn(double _Complex)); - (void *)(__clog10), - //BuiltIn(double _Complex) cpow(BuiltIn(double _Complex), BuiltIn(double _Complex)); - (void *)(cpow), - //BuiltIn(double _Complex) __cpow(BuiltIn(double _Complex), BuiltIn(double _Complex)); - (void *)(__cpow), - //BuiltIn(double _Complex) csqrt(BuiltIn(double _Complex)); - (void *)(csqrt), - //BuiltIn(double _Complex) __csqrt(BuiltIn(double _Complex)); - (void *)(__csqrt), - //BuiltIn(double) cabs(BuiltIn(double _Complex)); - (void *)(cabs), - //BuiltIn(double) __cabs(BuiltIn(double _Complex)); - (void *)(__cabs), - //BuiltIn(double) carg(BuiltIn(double _Complex)); - (void *)(carg), - //BuiltIn(double) __carg(BuiltIn(double _Complex)); - (void *)(__carg), - //BuiltIn(double _Complex) conj(BuiltIn(double _Complex)); - (void *)(conj), - //BuiltIn(double _Complex) __conj(BuiltIn(double _Complex)); - (void *)(__conj), - //BuiltIn(double _Complex) cproj(BuiltIn(double _Complex)); - (void *)(cproj), - //BuiltIn(double _Complex) __cproj(BuiltIn(double _Complex)); - (void *)(__cproj), - //BuiltIn(double) cimag(BuiltIn(double _Complex)); - (void *)(cimag), - //BuiltIn(double) __cimag(BuiltIn(double _Complex)); - (void *)(__cimag), - //BuiltIn(double) creal(BuiltIn(double _Complex)); - (void *)(creal), - //BuiltIn(double) __creal(BuiltIn(double _Complex)); - (void *)(__creal), - //BuiltIn(float _Complex) cacosf(BuiltIn(float _Complex)); - (void *)(cacosf), - //BuiltIn(float _Complex) __cacosf(BuiltIn(float _Complex)); - (void *)(__cacosf), - //BuiltIn(float _Complex) casinf(BuiltIn(float _Complex)); - (void *)(casinf), - //BuiltIn(float _Complex) __casinf(BuiltIn(float _Complex)); - (void *)(__casinf), - //BuiltIn(float _Complex) catanf(BuiltIn(float _Complex)); - (void *)(catanf), - //BuiltIn(float _Complex) __catanf(BuiltIn(float _Complex)); - (void *)(__catanf), - //BuiltIn(float _Complex) ccosf(BuiltIn(float _Complex)); - (void *)(ccosf), - //BuiltIn(float _Complex) __ccosf(BuiltIn(float _Complex)); - (void *)(__ccosf), - //BuiltIn(float _Complex) csinf(BuiltIn(float _Complex)); - (void *)(csinf), - //BuiltIn(float _Complex) __csinf(BuiltIn(float _Complex)); - (void *)(__csinf), - //BuiltIn(float _Complex) ctanf(BuiltIn(float _Complex)); - (void *)(ctanf), - //BuiltIn(float _Complex) __ctanf(BuiltIn(float _Complex)); - (void *)(__ctanf), - //BuiltIn(float _Complex) cacoshf(BuiltIn(float _Complex)); - (void *)(cacoshf), - //BuiltIn(float _Complex) __cacoshf(BuiltIn(float _Complex)); - (void *)(__cacoshf), - //BuiltIn(float _Complex) casinhf(BuiltIn(float _Complex)); - (void *)(casinhf), - //BuiltIn(float _Complex) __casinhf(BuiltIn(float _Complex)); - (void *)(__casinhf), - //BuiltIn(float _Complex) catanhf(BuiltIn(float _Complex)); - (void *)(catanhf), - //BuiltIn(float _Complex) __catanhf(BuiltIn(float _Complex)); - (void *)(__catanhf), - //BuiltIn(float _Complex) ccoshf(BuiltIn(float _Complex)); - (void *)(ccoshf), - //BuiltIn(float _Complex) __ccoshf(BuiltIn(float _Complex)); - (void *)(__ccoshf), - //BuiltIn(float _Complex) csinhf(BuiltIn(float _Complex)); - (void *)(csinhf), - //BuiltIn(float _Complex) __csinhf(BuiltIn(float _Complex)); - (void *)(__csinhf), - //BuiltIn(float _Complex) ctanhf(BuiltIn(float _Complex)); - (void *)(ctanhf), - //BuiltIn(float _Complex) __ctanhf(BuiltIn(float _Complex)); - (void *)(__ctanhf), - //BuiltIn(float _Complex) cexpf(BuiltIn(float _Complex)); - (void *)(cexpf), - //BuiltIn(float _Complex) __cexpf(BuiltIn(float _Complex)); - (void *)(__cexpf), - //BuiltIn(float _Complex) clogf(BuiltIn(float _Complex)); - (void *)(clogf), - //BuiltIn(float _Complex) __clogf(BuiltIn(float _Complex)); - (void *)(__clogf), - //BuiltIn(float _Complex) clog10f(BuiltIn(float _Complex)); - (void *)(clog10f), - //BuiltIn(float _Complex) __clog10f(BuiltIn(float _Complex)); - (void *)(__clog10f), - //BuiltIn(float _Complex) cpowf(BuiltIn(float _Complex), BuiltIn(float _Complex)); - (void *)(cpowf), - //BuiltIn(float _Complex) __cpowf(BuiltIn(float _Complex), BuiltIn(float _Complex)); - (void *)(__cpowf), - //BuiltIn(float _Complex) csqrtf(BuiltIn(float _Complex)); - (void *)(csqrtf), - //BuiltIn(float _Complex) __csqrtf(BuiltIn(float _Complex)); - (void *)(__csqrtf), - //BuiltIn(float) cabsf(BuiltIn(float _Complex)); - (void *)(cabsf), - //BuiltIn(float) __cabsf(BuiltIn(float _Complex)); - (void *)(__cabsf), - //BuiltIn(float) cargf(BuiltIn(float _Complex)); - (void *)(cargf), - //BuiltIn(float) __cargf(BuiltIn(float _Complex)); - (void *)(__cargf), - //BuiltIn(float _Complex) conjf(BuiltIn(float _Complex)); - (void *)(conjf), - //BuiltIn(float _Complex) __conjf(BuiltIn(float _Complex)); - (void *)(__conjf), - //BuiltIn(float _Complex) cprojf(BuiltIn(float _Complex)); - (void *)(cprojf), - //BuiltIn(float _Complex) __cprojf(BuiltIn(float _Complex)); - (void *)(__cprojf), - //BuiltIn(float) cimagf(BuiltIn(float _Complex)); - (void *)(cimagf), - //BuiltIn(float) __cimagf(BuiltIn(float _Complex)); - (void *)(__cimagf), - //BuiltIn(float) crealf(BuiltIn(float _Complex)); - (void *)(crealf), - //BuiltIn(float) __crealf(BuiltIn(float _Complex)); - (void *)(__crealf), - //BuiltIn(long double _Complex) cacosl(BuiltIn(long double _Complex)); - (void *)(cacosl), - //BuiltIn(long double _Complex) __cacosl(BuiltIn(long double _Complex)); - (void *)(__cacosl), - //BuiltIn(long double _Complex) casinl(BuiltIn(long double _Complex)); - (void *)(casinl), - //BuiltIn(long double _Complex) __casinl(BuiltIn(long double _Complex)); - (void *)(__casinl), - //BuiltIn(long double _Complex) catanl(BuiltIn(long double _Complex)); - (void *)(catanl), - //BuiltIn(long double _Complex) __catanl(BuiltIn(long double _Complex)); - (void *)(__catanl), - //BuiltIn(long double _Complex) ccosl(BuiltIn(long double _Complex)); - (void *)(ccosl), - //BuiltIn(long double _Complex) __ccosl(BuiltIn(long double _Complex)); - (void *)(__ccosl), - //BuiltIn(long double _Complex) csinl(BuiltIn(long double _Complex)); - (void *)(csinl), - //BuiltIn(long double _Complex) __csinl(BuiltIn(long double _Complex)); - (void *)(__csinl), - //BuiltIn(long double _Complex) ctanl(BuiltIn(long double _Complex)); - (void *)(ctanl), - //BuiltIn(long double _Complex) __ctanl(BuiltIn(long double _Complex)); - (void *)(__ctanl), - //BuiltIn(long double _Complex) cacoshl(BuiltIn(long double _Complex)); - (void *)(cacoshl), - //BuiltIn(long double _Complex) __cacoshl(BuiltIn(long double _Complex)); - (void *)(__cacoshl), - //BuiltIn(long double _Complex) casinhl(BuiltIn(long double _Complex)); - (void *)(casinhl), - //BuiltIn(long double _Complex) __casinhl(BuiltIn(long double _Complex)); - (void *)(__casinhl), - //BuiltIn(long double _Complex) catanhl(BuiltIn(long double _Complex)); - (void *)(catanhl), - //BuiltIn(long double _Complex) __catanhl(BuiltIn(long double _Complex)); - (void *)(__catanhl), - //BuiltIn(long double _Complex) ccoshl(BuiltIn(long double _Complex)); - (void *)(ccoshl), - //BuiltIn(long double _Complex) __ccoshl(BuiltIn(long double _Complex)); - (void *)(__ccoshl), - //BuiltIn(long double _Complex) csinhl(BuiltIn(long double _Complex)); - (void *)(csinhl), - //BuiltIn(long double _Complex) __csinhl(BuiltIn(long double _Complex)); - (void *)(__csinhl), - //BuiltIn(long double _Complex) ctanhl(BuiltIn(long double _Complex)); - (void *)(ctanhl), - //BuiltIn(long double _Complex) __ctanhl(BuiltIn(long double _Complex)); - (void *)(__ctanhl), - //BuiltIn(long double _Complex) cexpl(BuiltIn(long double _Complex)); - (void *)(cexpl), - //BuiltIn(long double _Complex) __cexpl(BuiltIn(long double _Complex)); - (void *)(__cexpl), - //BuiltIn(long double _Complex) clogl(BuiltIn(long double _Complex)); - (void *)(clogl), - //BuiltIn(long double _Complex) __clogl(BuiltIn(long double _Complex)); - (void *)(__clogl), - //BuiltIn(long double _Complex) clog10l(BuiltIn(long double _Complex)); - (void *)(clog10l), - //BuiltIn(long double _Complex) __clog10l(BuiltIn(long double _Complex)); - (void *)(__clog10l), - //BuiltIn(long double _Complex) cpowl(BuiltIn(long double _Complex), BuiltIn(long double _Complex)); - (void *)(cpowl), - //BuiltIn(long double _Complex) __cpowl(BuiltIn(long double _Complex), BuiltIn(long double _Complex)); - (void *)(__cpowl), - //BuiltIn(long double _Complex) csqrtl(BuiltIn(long double _Complex)); - (void *)(csqrtl), - //BuiltIn(long double _Complex) __csqrtl(BuiltIn(long double _Complex)); - (void *)(__csqrtl), - //BuiltIn(long double) cabsl(BuiltIn(long double _Complex)); - (void *)(cabsl), - //BuiltIn(long double) __cabsl(BuiltIn(long double _Complex)); - (void *)(__cabsl), - //BuiltIn(long double) cargl(BuiltIn(long double _Complex)); - (void *)(cargl), - //BuiltIn(long double) __cargl(BuiltIn(long double _Complex)); - (void *)(__cargl), - //BuiltIn(long double _Complex) conjl(BuiltIn(long double _Complex)); - (void *)(conjl), - //BuiltIn(long double _Complex) __conjl(BuiltIn(long double _Complex)); - (void *)(__conjl), - //BuiltIn(long double _Complex) cprojl(BuiltIn(long double _Complex)); - (void *)(cprojl), - //BuiltIn(long double _Complex) __cprojl(BuiltIn(long double _Complex)); - (void *)(__cprojl), - //BuiltIn(long double) cimagl(BuiltIn(long double _Complex)); - (void *)(cimagl), - //BuiltIn(long double) __cimagl(BuiltIn(long double _Complex)); - (void *)(__cimagl), - //BuiltIn(long double) creall(BuiltIn(long double _Complex)); - (void *)(creall), - //BuiltIn(long double) __creall(BuiltIn(long double _Complex)); - (void *)(__creall), - //Use(TypeDef(__u32, Attributed(unsigned , BuiltIn(int)))) __arch_swab32(Use(TypeDef(__u32, Attributed(unsigned , BuiltIn(int))))); - (void *)(__arch_swab32), - //Use(TypeDef(__u64, Attributed(__extension__, Attributed(unsigned , BuiltIn(long long))))) __arch_swab64(Use(TypeDef(__u64, Attributed(__extension__, Attributed(unsigned , BuiltIn(long long)))))); - (void *)(__arch_swab64), - //Use(TypeDef(__u16, Attributed(unsigned , BuiltIn(short)))) __fswab16(Use(TypeDef(__u16, Attributed(unsigned , BuiltIn(short))))); - (void *)(__fswab16), - //Use(TypeDef(__u32, Attributed(unsigned , BuiltIn(int)))) __fswab32(Use(TypeDef(__u32, Attributed(unsigned , BuiltIn(int))))); - (void *)(__fswab32), - //Use(TypeDef(__u64, Attributed(__extension__, Attributed(unsigned , BuiltIn(long long))))) __fswab64(Use(TypeDef(__u64, Attributed(__extension__, Attributed(unsigned , BuiltIn(long long)))))); - (void *)(__fswab64), - //Use(TypeDef(__u32, Attributed(unsigned , BuiltIn(int)))) __fswahw32(Use(TypeDef(__u32, Attributed(unsigned , BuiltIn(int))))); - (void *)(__fswahw32), - //Use(TypeDef(__u32, Attributed(unsigned , BuiltIn(int)))) __fswahb32(Use(TypeDef(__u32, Attributed(unsigned , BuiltIn(int))))); - (void *)(__fswahb32), - //Use(TypeDef(__u16, Attributed(unsigned , BuiltIn(short)))) __swab16p(Pointer(Attributed(const , Use(TypeDef(__u16, Attributed(unsigned , BuiltIn(short))))))); - (void *)(__swab16p), - //Use(TypeDef(__u32, Attributed(unsigned , BuiltIn(int)))) __swab32p(Pointer(Attributed(const , Use(TypeDef(__u32, Attributed(unsigned , BuiltIn(int))))))); - (void *)(__swab32p), - //Use(TypeDef(__u64, Attributed(__extension__, Attributed(unsigned , BuiltIn(long long))))) __swab64p(Pointer(Attributed(const , Use(TypeDef(__u64, Attributed(__extension__, Attributed(unsigned , BuiltIn(long long)))))))); - (void *)(__swab64p), - //Use(TypeDef(__u32, Attributed(unsigned , BuiltIn(int)))) __swahw32p(Pointer(Attributed(const , Use(TypeDef(__u32, Attributed(unsigned , BuiltIn(int))))))); - (void *)(__swahw32p), - //Use(TypeDef(__u32, Attributed(unsigned , BuiltIn(int)))) __swahb32p(Pointer(Attributed(const , Use(TypeDef(__u32, Attributed(unsigned , BuiltIn(int))))))); - (void *)(__swahb32p), - //BuiltIn(void) __swab16s(Pointer(Use(TypeDef(__u16, Attributed(unsigned , BuiltIn(short)))))); - (void *)(__swab16s), - //BuiltIn(void) __swab32s(Pointer(Use(TypeDef(__u32, Attributed(unsigned , BuiltIn(int)))))); - (void *)(__swab32s), - //BuiltIn(void) __swab64s(Pointer(Use(TypeDef(__u64, Attributed(__extension__, Attributed(unsigned , BuiltIn(long long))))))); - (void *)(__swab64s), - //BuiltIn(void) __swahw32s(Pointer(Use(TypeDef(__u32, Attributed(unsigned , BuiltIn(int)))))); - (void *)(__swahw32s), - //BuiltIn(void) __swahb32s(Pointer(Use(TypeDef(__u32, Attributed(unsigned , BuiltIn(int)))))); - (void *)(__swahb32s), - //Use(TypeDef(__le64, Use(TypeDef(__u64, Attributed(__extension__, Attributed(unsigned , BuiltIn(long long))))))) __cpu_to_le64p(Pointer(Attributed(const , Use(TypeDef(__u64, Attributed(__extension__, Attributed(unsigned , BuiltIn(long long)))))))); - (void *)(__cpu_to_le64p), - //Use(TypeDef(__u64, Attributed(__extension__, Attributed(unsigned , BuiltIn(long long))))) __le64_to_cpup(Pointer(Attributed(const , Use(TypeDef(__le64, Use(TypeDef(__u64, Attributed(__extension__, Attributed(unsigned , BuiltIn(long long)))))))))); - (void *)(__le64_to_cpup), - //Use(TypeDef(__le32, Use(TypeDef(__u32, Attributed(unsigned , BuiltIn(int)))))) __cpu_to_le32p(Pointer(Attributed(const , Use(TypeDef(__u32, Attributed(unsigned , BuiltIn(int))))))); - (void *)(__cpu_to_le32p), - //Use(TypeDef(__u32, Attributed(unsigned , BuiltIn(int)))) __le32_to_cpup(Pointer(Attributed(const , Use(TypeDef(__le32, Use(TypeDef(__u32, Attributed(unsigned , BuiltIn(int))))))))); - (void *)(__le32_to_cpup), - //Use(TypeDef(__le16, Use(TypeDef(__u16, Attributed(unsigned , BuiltIn(short)))))) __cpu_to_le16p(Pointer(Attributed(const , Use(TypeDef(__u16, Attributed(unsigned , BuiltIn(short))))))); - (void *)(__cpu_to_le16p), - //Use(TypeDef(__u16, Attributed(unsigned , BuiltIn(short)))) __le16_to_cpup(Pointer(Attributed(const , Use(TypeDef(__le16, Use(TypeDef(__u16, Attributed(unsigned , BuiltIn(short))))))))); - (void *)(__le16_to_cpup), - //Use(TypeDef(__be64, Use(TypeDef(__u64, Attributed(__extension__, Attributed(unsigned , BuiltIn(long long))))))) __cpu_to_be64p(Pointer(Attributed(const , Use(TypeDef(__u64, Attributed(__extension__, Attributed(unsigned , BuiltIn(long long)))))))); - (void *)(__cpu_to_be64p), - //Use(TypeDef(__u64, Attributed(__extension__, Attributed(unsigned , BuiltIn(long long))))) __be64_to_cpup(Pointer(Attributed(const , Use(TypeDef(__be64, Use(TypeDef(__u64, Attributed(__extension__, Attributed(unsigned , BuiltIn(long long)))))))))); - (void *)(__be64_to_cpup), - //Use(TypeDef(__be32, Use(TypeDef(__u32, Attributed(unsigned , BuiltIn(int)))))) __cpu_to_be32p(Pointer(Attributed(const , Use(TypeDef(__u32, Attributed(unsigned , BuiltIn(int))))))); - (void *)(__cpu_to_be32p), - //Use(TypeDef(__u32, Attributed(unsigned , BuiltIn(int)))) __be32_to_cpup(Pointer(Attributed(const , Use(TypeDef(__be32, Use(TypeDef(__u32, Attributed(unsigned , BuiltIn(int))))))))); - (void *)(__be32_to_cpup), - //Use(TypeDef(__be16, Use(TypeDef(__u16, Attributed(unsigned , BuiltIn(short)))))) __cpu_to_be16p(Pointer(Attributed(const , Use(TypeDef(__u16, Attributed(unsigned , BuiltIn(short))))))); - (void *)(__cpu_to_be16p), - //Use(TypeDef(__u16, Attributed(unsigned , BuiltIn(short)))) __be16_to_cpup(Pointer(Attributed(const , Use(TypeDef(__be16, Use(TypeDef(__u16, Attributed(unsigned , BuiltIn(short))))))))); - (void *)(__be16_to_cpup), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) __ctype_get_mb_cur_max(); - (void *)(__ctype_get_mb_cur_max), - //BuiltIn(double) atof(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(atof), - //BuiltIn(int) atoi(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(atoi), - //BuiltIn(long) atol(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(atol), - //BuiltIn(long long) atoll(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(atoll), - //BuiltIn(double) strtod(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Pointer(BuiltIn(char)))); - (void *)(strtod), - //BuiltIn(float) strtof(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Pointer(BuiltIn(char)))); - (void *)(strtof), - //BuiltIn(long double) strtold(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Pointer(BuiltIn(char)))); - (void *)(strtold), - //BuiltIn(long) strtol(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Pointer(BuiltIn(char))), BuiltIn(int)); - (void *)(strtol), - //Attributed(unsigned , BuiltIn(long)) strtoul(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Pointer(BuiltIn(char))), BuiltIn(int)); - (void *)(strtoul), - //BuiltIn(long long) strtoq(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Pointer(BuiltIn(char))), BuiltIn(int)); - (void *)(strtoq), - //Attributed(unsigned , BuiltIn(long long)) strtouq(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Pointer(BuiltIn(char))), BuiltIn(int)); - (void *)(strtouq), - //BuiltIn(long long) strtoll(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Pointer(BuiltIn(char))), BuiltIn(int)); - (void *)(strtoll), - //Attributed(unsigned , BuiltIn(long long)) strtoull(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Pointer(BuiltIn(char))), BuiltIn(int)); - (void *)(strtoull), - //BuiltIn(long) strtol_l(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Pointer(BuiltIn(char))), BuiltIn(int), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(strtol_l), - //Attributed(unsigned , BuiltIn(long)) strtoul_l(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Pointer(BuiltIn(char))), BuiltIn(int), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(strtoul_l), - //BuiltIn(long long) strtoll_l(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Pointer(BuiltIn(char))), BuiltIn(int), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(strtoll_l), - //Attributed(unsigned , BuiltIn(long long)) strtoull_l(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Pointer(BuiltIn(char))), BuiltIn(int), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(strtoull_l), - //BuiltIn(double) strtod_l(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Pointer(BuiltIn(char))), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(strtod_l), - //BuiltIn(float) strtof_l(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Pointer(BuiltIn(char))), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(strtof_l), - //BuiltIn(long double) strtold_l(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Pointer(BuiltIn(char))), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(strtold_l), - //Pointer(BuiltIn(char)) l64a(BuiltIn(long)); - (void *)(l64a), - //BuiltIn(long) a64l(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(a64l), - //BuiltIn(long) random(); - (void *)(random), - //BuiltIn(void) srandom(Attributed(unsigned , BuiltIn(int))); - (void *)(srandom), - //Pointer(BuiltIn(char)) initstate(Attributed(unsigned , BuiltIn(int)), Pointer(BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(initstate), - //Pointer(BuiltIn(char)) setstate(Pointer(BuiltIn(char))); - (void *)(setstate), - //BuiltIn(int) random_r(Pointer(restrict Use(Struct(struct random_data))), Pointer(restrict Use(TypeDef(int32_t, Attributed(__attribute__ ( ( __mode__ ( __SI__ ) ) ), BuiltIn(int)))))); - (void *)(random_r), - //BuiltIn(int) srandom_r(Attributed(unsigned , BuiltIn(int)), Pointer(Use(Struct(struct random_data)))); - (void *)(srandom_r), - //BuiltIn(int) initstate_r(Attributed(unsigned , BuiltIn(int)), Pointer(restrict BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Use(Struct(struct random_data)))); - (void *)(initstate_r), - //BuiltIn(int) setstate_r(Pointer(restrict BuiltIn(char)), Pointer(restrict Use(Struct(struct random_data)))); - (void *)(setstate_r), - //BuiltIn(int) rand(); - (void *)(rand), - //BuiltIn(void) srand(Attributed(unsigned , BuiltIn(int))); - (void *)(srand), - //BuiltIn(int) rand_r(Pointer(Attributed(unsigned , BuiltIn(int)))); - (void *)(rand_r), - //BuiltIn(double) drand48(); - (void *)(drand48), - //BuiltIn(double) erand48(Array(Attributed(unsigned , BuiltIn(short)))); - (void *)(erand48), - //BuiltIn(long) lrand48(); - (void *)(lrand48), - //BuiltIn(long) nrand48(Array(Attributed(unsigned , BuiltIn(short)))); - (void *)(nrand48), - //BuiltIn(long) mrand48(); - (void *)(mrand48), - //BuiltIn(long) jrand48(Array(Attributed(unsigned , BuiltIn(short)))); - (void *)(jrand48), - //BuiltIn(void) srand48(BuiltIn(long)); - (void *)(srand48), - //Pointer(Attributed(unsigned , BuiltIn(short))) seed48(Array(Attributed(unsigned , BuiltIn(short)))); - (void *)(seed48), - //BuiltIn(void) lcong48(Array(Attributed(unsigned , BuiltIn(short)))); - (void *)(lcong48), - //BuiltIn(int) drand48_r(Pointer(restrict Use(Struct(struct drand48_data))), Pointer(restrict BuiltIn(double))); - (void *)(drand48_r), - //BuiltIn(int) erand48_r(Array(Attributed(unsigned , BuiltIn(short))), Pointer(restrict Use(Struct(struct drand48_data))), Pointer(restrict BuiltIn(double))); - (void *)(erand48_r), - //BuiltIn(int) lrand48_r(Pointer(restrict Use(Struct(struct drand48_data))), Pointer(restrict BuiltIn(long))); - (void *)(lrand48_r), - //BuiltIn(int) nrand48_r(Array(Attributed(unsigned , BuiltIn(short))), Pointer(restrict Use(Struct(struct drand48_data))), Pointer(restrict BuiltIn(long))); - (void *)(nrand48_r), - //BuiltIn(int) mrand48_r(Pointer(restrict Use(Struct(struct drand48_data))), Pointer(restrict BuiltIn(long))); - (void *)(mrand48_r), - //BuiltIn(int) jrand48_r(Array(Attributed(unsigned , BuiltIn(short))), Pointer(restrict Use(Struct(struct drand48_data))), Pointer(restrict BuiltIn(long))); - (void *)(jrand48_r), - //BuiltIn(int) srand48_r(BuiltIn(long), Pointer(Use(Struct(struct drand48_data)))); - (void *)(srand48_r), - //BuiltIn(int) seed48_r(Array(Attributed(unsigned , BuiltIn(short))), Pointer(Use(Struct(struct drand48_data)))); - (void *)(seed48_r), - //BuiltIn(int) lcong48_r(Array(Attributed(unsigned , BuiltIn(short))), Pointer(Use(Struct(struct drand48_data)))); - (void *)(lcong48_r), - //Pointer(BuiltIn(void)) malloc(Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(malloc), - //Pointer(BuiltIn(void)) calloc(Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(calloc), - //Pointer(BuiltIn(void)) realloc(Pointer(BuiltIn(void)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(realloc), - //BuiltIn(void) free(Pointer(BuiltIn(void))); - (void *)(free), - //Pointer(BuiltIn(void)) alloca(Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(alloca), - //Pointer(BuiltIn(void)) valloc(Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(valloc), - //BuiltIn(int) posix_memalign(Pointer(Pointer(BuiltIn(void))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(posix_memalign), - //Pointer(BuiltIn(void)) aligned_alloc(Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(aligned_alloc), - //BuiltIn(void) abort(); - (void *)(abort), - // skipping because function pointer args: atexit - // skipping because function pointer args: at_quick_exit - // skipping because function pointer args: on_exit - //BuiltIn(void) exit(BuiltIn(int)); - (void *)(exit), - //BuiltIn(void) quick_exit(BuiltIn(int)); - (void *)(quick_exit), - //BuiltIn(void) _Exit(BuiltIn(int)); - (void *)(_Exit), - //Pointer(BuiltIn(char)) getenv(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(getenv), - //Pointer(BuiltIn(char)) secure_getenv(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(secure_getenv), - //BuiltIn(int) putenv(Pointer(BuiltIn(char))); - (void *)(putenv), - //BuiltIn(int) setenv(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int)); - (void *)(setenv), - //BuiltIn(int) unsetenv(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(unsetenv), - //BuiltIn(int) clearenv(); - (void *)(clearenv), - //Pointer(BuiltIn(char)) mktemp(Pointer(BuiltIn(char))); - (void *)(mktemp), - //BuiltIn(int) mkstemp(Pointer(BuiltIn(char))); - (void *)(mkstemp), - //BuiltIn(int) mkstemp64(Pointer(BuiltIn(char))); - (void *)(mkstemp64), - //BuiltIn(int) mkstemps(Pointer(BuiltIn(char)), BuiltIn(int)); - (void *)(mkstemps), - //BuiltIn(int) mkstemps64(Pointer(BuiltIn(char)), BuiltIn(int)); - (void *)(mkstemps64), - //Pointer(BuiltIn(char)) mkdtemp(Pointer(BuiltIn(char))); - (void *)(mkdtemp), - //BuiltIn(int) mkostemp(Pointer(BuiltIn(char)), BuiltIn(int)); - (void *)(mkostemp), - //BuiltIn(int) mkostemp64(Pointer(BuiltIn(char)), BuiltIn(int)); - (void *)(mkostemp64), - //BuiltIn(int) mkostemps(Pointer(BuiltIn(char)), BuiltIn(int), BuiltIn(int)); - (void *)(mkostemps), - //BuiltIn(int) mkostemps64(Pointer(BuiltIn(char)), BuiltIn(int), BuiltIn(int)); - (void *)(mkostemps64), - //BuiltIn(int) system(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(system), - //Pointer(BuiltIn(char)) canonicalize_file_name(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(canonicalize_file_name), - //Pointer(BuiltIn(char)) realpath(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict BuiltIn(char))); - (void *)(realpath), - // skipping because function pointer args: bsearch - // skipping because function pointer args: qsort - // skipping because function pointer args: qsort_r - //BuiltIn(int) abs(BuiltIn(int)); - (void *)(abs), - //BuiltIn(long) labs(BuiltIn(long)); - (void *)(labs), - //BuiltIn(long long) llabs(BuiltIn(long long)); - (void *)(llabs), - //Use(TypeDef(div_t, Struct(struct anon_struct_165))) div(BuiltIn(int), BuiltIn(int)); - (void *)(div), - //Use(TypeDef(ldiv_t, Struct(struct anon_struct_166))) ldiv(BuiltIn(long), BuiltIn(long)); - (void *)(ldiv), - //Use(TypeDef(lldiv_t, Attributed(__extension__, Struct(struct anon_struct_167)))) lldiv(BuiltIn(long long), BuiltIn(long long)); - (void *)(lldiv), - //Pointer(BuiltIn(char)) ecvt(BuiltIn(double), BuiltIn(int), Pointer(restrict BuiltIn(int)), Pointer(restrict BuiltIn(int))); - (void *)(ecvt), - //Pointer(BuiltIn(char)) fcvt(BuiltIn(double), BuiltIn(int), Pointer(restrict BuiltIn(int)), Pointer(restrict BuiltIn(int))); - (void *)(fcvt), - //Pointer(BuiltIn(char)) gcvt(BuiltIn(double), BuiltIn(int), Pointer(BuiltIn(char))); - (void *)(gcvt), - //Pointer(BuiltIn(char)) qecvt(BuiltIn(long double), BuiltIn(int), Pointer(restrict BuiltIn(int)), Pointer(restrict BuiltIn(int))); - (void *)(qecvt), - //Pointer(BuiltIn(char)) qfcvt(BuiltIn(long double), BuiltIn(int), Pointer(restrict BuiltIn(int)), Pointer(restrict BuiltIn(int))); - (void *)(qfcvt), - //Pointer(BuiltIn(char)) qgcvt(BuiltIn(long double), BuiltIn(int), Pointer(BuiltIn(char))); - (void *)(qgcvt), - //BuiltIn(int) ecvt_r(BuiltIn(double), BuiltIn(int), Pointer(restrict BuiltIn(int)), Pointer(restrict BuiltIn(int)), Pointer(restrict BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(ecvt_r), - //BuiltIn(int) fcvt_r(BuiltIn(double), BuiltIn(int), Pointer(restrict BuiltIn(int)), Pointer(restrict BuiltIn(int)), Pointer(restrict BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(fcvt_r), - //BuiltIn(int) qecvt_r(BuiltIn(long double), BuiltIn(int), Pointer(restrict BuiltIn(int)), Pointer(restrict BuiltIn(int)), Pointer(restrict BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(qecvt_r), - //BuiltIn(int) qfcvt_r(BuiltIn(long double), BuiltIn(int), Pointer(restrict BuiltIn(int)), Pointer(restrict BuiltIn(int)), Pointer(restrict BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(qfcvt_r), - //BuiltIn(int) mblen(Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(mblen), - //BuiltIn(int) mbtowc(Pointer(restrict Use(TypeDef(wchar_t, BuiltIn(int)))), Pointer(restrict Attributed(const , BuiltIn(char))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(mbtowc), - //BuiltIn(int) wctomb(Pointer(BuiltIn(char)), Use(TypeDef(wchar_t, BuiltIn(int)))); - (void *)(wctomb), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) mbstowcs(Pointer(restrict Use(TypeDef(wchar_t, BuiltIn(int)))), Pointer(restrict Attributed(const , BuiltIn(char))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(mbstowcs), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) wcstombs(Pointer(restrict BuiltIn(char)), Pointer(restrict Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(wcstombs), - //BuiltIn(int) rpmatch(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(rpmatch), - //BuiltIn(int) getsubopt(Pointer(restrict Pointer(BuiltIn(char))), Pointer(restrict Pointer(const BuiltIn(char))), Pointer(restrict Pointer(BuiltIn(char)))); - (void *)(getsubopt), - //BuiltIn(void) setkey(Pointer(Attributed(const , BuiltIn(char)))); -// (void *)(setkey), - //BuiltIn(int) posix_openpt(BuiltIn(int)); - (void *)(posix_openpt), - //BuiltIn(int) grantpt(BuiltIn(int)); - (void *)(grantpt), - //BuiltIn(int) unlockpt(BuiltIn(int)); - (void *)(unlockpt), - //Pointer(BuiltIn(char)) ptsname(BuiltIn(int)); - (void *)(ptsname), - //BuiltIn(int) ptsname_r(BuiltIn(int), Pointer(BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(ptsname_r), - //BuiltIn(int) getpt(); - (void *)(getpt), - //BuiltIn(int) getloadavg(Array(BuiltIn(double)), BuiltIn(int)); - (void *)(getloadavg), - //BuiltIn(int) gettimeofday(Pointer(restrict Use(Struct(struct timeval))), Use(TypeDef(__timezone_ptr_t, Pointer(restrict Use(Struct(struct timezone)))))); - (void *)(gettimeofday), - //BuiltIn(int) settimeofday(Pointer(Attributed(const , Use(Struct(struct timeval)))), Pointer(Attributed(const , Use(Struct(struct timezone))))); - (void *)(settimeofday), - //BuiltIn(int) adjtime(Pointer(Attributed(const , Use(Struct(struct timeval)))), Pointer(Use(Struct(struct timeval)))); - (void *)(adjtime), - //BuiltIn(int) getitimer(Use(TypeDef(__itimer_which_t, Use(Enum(enum __itimer_which)))), Pointer(Use(Struct(struct itimerval)))); - (void *)(getitimer), - //BuiltIn(int) setitimer(Use(TypeDef(__itimer_which_t, Use(Enum(enum __itimer_which)))), Pointer(restrict Attributed(const , Use(Struct(struct itimerval)))), Pointer(restrict Use(Struct(struct itimerval)))); - (void *)(setitimer), - //BuiltIn(int) utimes(Pointer(Attributed(const , BuiltIn(char))), Array(Attributed(const , Use(Struct(struct timeval))))); - (void *)(utimes), - //BuiltIn(int) lutimes(Pointer(Attributed(const , BuiltIn(char))), Array(Attributed(const , Use(Struct(struct timeval))))); - (void *)(lutimes), - //BuiltIn(int) futimes(BuiltIn(int), Array(Attributed(const , Use(Struct(struct timeval))))); - (void *)(futimes), - //BuiltIn(int) futimesat(BuiltIn(int), Pointer(Attributed(const , BuiltIn(char))), Array(Attributed(const , Use(Struct(struct timeval))))); - (void *)(futimesat), - // skipping because function pointer args: __sysv_signal - // skipping because function pointer args: sysv_signal - // skipping because function pointer args: signal - // skipping because function pointer args: bsd_signal - //BuiltIn(int) kill(Use(TypeDef(__pid_t, BuiltIn(int))), BuiltIn(int)); - (void *)(kill), - //BuiltIn(int) killpg(Use(TypeDef(__pid_t, BuiltIn(int))), BuiltIn(int)); - (void *)(killpg), - //BuiltIn(int) raise(BuiltIn(int)); - (void *)(raise), - // skipping because function pointer args: ssignal - //BuiltIn(int) gsignal(BuiltIn(int)); - (void *)(gsignal), - //BuiltIn(void) psignal(BuiltIn(int), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(psignal), - //BuiltIn(void) psiginfo(Pointer(Attributed(const , Use(TypeDef(siginfo_t, Struct(struct anon_struct_172))))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(psiginfo), - //BuiltIn(int) __sigpause(BuiltIn(int), BuiltIn(int)); -// (void *)(__sigpause), - //BuiltIn(int) sigpause(BuiltIn(int)); - (void *)(sigpause), - //BuiltIn(int) sigblock(BuiltIn(int)); - (void *)(sigblock), - //BuiltIn(int) sigsetmask(BuiltIn(int)); - (void *)(sigsetmask), - //BuiltIn(int) siggetmask(); - (void *)(siggetmask), - //BuiltIn(int) sigemptyset(Pointer(Use(TypeDef(sigset_t, Use(TypeDef(__sigset_t, Struct(struct anon_struct_23))))))); - (void *)(sigemptyset), - //BuiltIn(int) sigfillset(Pointer(Use(TypeDef(sigset_t, Use(TypeDef(__sigset_t, Struct(struct anon_struct_23))))))); - (void *)(sigfillset), - //BuiltIn(int) sigaddset(Pointer(Use(TypeDef(sigset_t, Use(TypeDef(__sigset_t, Struct(struct anon_struct_23)))))), BuiltIn(int)); - (void *)(sigaddset), - //BuiltIn(int) sigdelset(Pointer(Use(TypeDef(sigset_t, Use(TypeDef(__sigset_t, Struct(struct anon_struct_23)))))), BuiltIn(int)); - (void *)(sigdelset), - //BuiltIn(int) sigismember(Pointer(Attributed(const , Use(TypeDef(sigset_t, Use(TypeDef(__sigset_t, Struct(struct anon_struct_23))))))), BuiltIn(int)); - (void *)(sigismember), - //BuiltIn(int) sigisemptyset(Pointer(Attributed(const , Use(TypeDef(sigset_t, Use(TypeDef(__sigset_t, Struct(struct anon_struct_23)))))))); - (void *)(sigisemptyset), - //BuiltIn(int) sigandset(Pointer(Use(TypeDef(sigset_t, Use(TypeDef(__sigset_t, Struct(struct anon_struct_23)))))), Pointer(Attributed(const , Use(TypeDef(sigset_t, Use(TypeDef(__sigset_t, Struct(struct anon_struct_23))))))), Pointer(Attributed(const , Use(TypeDef(sigset_t, Use(TypeDef(__sigset_t, Struct(struct anon_struct_23)))))))); - (void *)(sigandset), - //BuiltIn(int) sigorset(Pointer(Use(TypeDef(sigset_t, Use(TypeDef(__sigset_t, Struct(struct anon_struct_23)))))), Pointer(Attributed(const , Use(TypeDef(sigset_t, Use(TypeDef(__sigset_t, Struct(struct anon_struct_23))))))), Pointer(Attributed(const , Use(TypeDef(sigset_t, Use(TypeDef(__sigset_t, Struct(struct anon_struct_23)))))))); - (void *)(sigorset), - //BuiltIn(int) sigprocmask(BuiltIn(int), Pointer(restrict Attributed(const , Use(TypeDef(sigset_t, Use(TypeDef(__sigset_t, Struct(struct anon_struct_23))))))), Pointer(restrict Use(TypeDef(sigset_t, Use(TypeDef(__sigset_t, Struct(struct anon_struct_23))))))); - (void *)(sigprocmask), - //BuiltIn(int) sigsuspend(Pointer(Attributed(const , Use(TypeDef(sigset_t, Use(TypeDef(__sigset_t, Struct(struct anon_struct_23)))))))); - (void *)(sigsuspend), - // skipping because function pointer args: sigaction - //BuiltIn(int) sigpending(Pointer(Use(TypeDef(sigset_t, Use(TypeDef(__sigset_t, Struct(struct anon_struct_23))))))); - (void *)(sigpending), - //BuiltIn(int) sigwait(Pointer(restrict Attributed(const , Use(TypeDef(sigset_t, Use(TypeDef(__sigset_t, Struct(struct anon_struct_23))))))), Pointer(restrict BuiltIn(int))); - (void *)(sigwait), - //BuiltIn(int) sigwaitinfo(Pointer(restrict Attributed(const , Use(TypeDef(sigset_t, Use(TypeDef(__sigset_t, Struct(struct anon_struct_23))))))), Pointer(restrict Use(TypeDef(siginfo_t, Struct(struct anon_struct_172))))); - (void *)(sigwaitinfo), - //BuiltIn(int) sigtimedwait(Pointer(restrict Attributed(const , Use(TypeDef(sigset_t, Use(TypeDef(__sigset_t, Struct(struct anon_struct_23))))))), Pointer(restrict Use(TypeDef(siginfo_t, Struct(struct anon_struct_172)))), Pointer(restrict Attributed(const , Use(Struct(struct timespec))))); - (void *)(sigtimedwait), - //BuiltIn(int) sigqueue(Use(TypeDef(__pid_t, BuiltIn(int))), BuiltIn(int), Attributed(const , Use(Union(union sigval)))); - (void *)(sigqueue), - // skipping because function pointer args: sigvec - //BuiltIn(int) sigreturn(Pointer(Use(Struct(struct sigcontext)))); - (void *)(sigreturn), - //BuiltIn(int) siginterrupt(BuiltIn(int), BuiltIn(int)); - (void *)(siginterrupt), - //BuiltIn(int) sigstack(Pointer(Use(Struct(struct sigstack))), Pointer(Use(Struct(struct sigstack)))); - (void *)(sigstack), - //BuiltIn(int) sigaltstack(Pointer(restrict Attributed(const , Use(Struct(struct sigaltstack)))), Pointer(restrict Use(Struct(struct sigaltstack)))); - (void *)(sigaltstack), - //BuiltIn(int) sighold(BuiltIn(int)); - (void *)(sighold), - //BuiltIn(int) sigrelse(BuiltIn(int)); - (void *)(sigrelse), - //BuiltIn(int) sigignore(BuiltIn(int)); - (void *)(sigignore), - // skipping because function pointer args: sigset - //BuiltIn(int) pthread_sigmask(BuiltIn(int), Pointer(restrict Attributed(const , Use(TypeDef(__sigset_t, Struct(struct anon_struct_23))))), Pointer(restrict Use(TypeDef(__sigset_t, Struct(struct anon_struct_23))))); - (void *)(pthread_sigmask), - //BuiltIn(int) pthread_kill(Use(TypeDef(pthread_t, Attributed(unsigned , BuiltIn(long)))), BuiltIn(int)); - (void *)(pthread_kill), - //BuiltIn(int) pthread_sigqueue(Use(TypeDef(pthread_t, Attributed(unsigned , BuiltIn(long)))), BuiltIn(int), Attributed(const , Use(Union(union sigval)))); - (void *)(pthread_sigqueue), - //BuiltIn(int) __libc_current_sigrtmin(); - (void *)(__libc_current_sigrtmin), - //BuiltIn(int) __libc_current_sigrtmax(); - (void *)(__libc_current_sigrtmax), - //Use(TypeDef(bool_t, BuiltIn(int))) xdr_void(); - (void *)(xdr_void), - // skipping because function pointer args: xdr_short - // skipping because function pointer args: xdr_u_short - // skipping because function pointer args: xdr_int - // skipping because function pointer args: xdr_u_int - // skipping because function pointer args: xdr_long - // skipping because function pointer args: xdr_u_long - // skipping because function pointer args: xdr_hyper - // skipping because function pointer args: xdr_u_hyper - // skipping because function pointer args: xdr_longlong_t - // skipping because function pointer args: xdr_u_longlong_t - // skipping because function pointer args: xdr_int8_t - // skipping because function pointer args: xdr_uint8_t - // skipping because function pointer args: xdr_int16_t - // skipping because function pointer args: xdr_uint16_t - // skipping because function pointer args: xdr_int32_t - // skipping because function pointer args: xdr_uint32_t - // skipping because function pointer args: xdr_int64_t - // skipping because function pointer args: xdr_uint64_t - // skipping because function pointer args: xdr_quad_t - // skipping because function pointer args: xdr_u_quad_t - // skipping because function pointer args: xdr_bool - // skipping because function pointer args: xdr_enum - // skipping because function pointer args: xdr_array - // skipping because function pointer args: xdr_bytes - // skipping because function pointer args: xdr_opaque - // skipping because function pointer args: xdr_string - // skipping because function pointer args: xdr_union - // skipping because function pointer args: xdr_char - // skipping because function pointer args: xdr_u_char - // skipping because function pointer args: xdr_vector - // skipping because function pointer args: xdr_float - // skipping because function pointer args: xdr_double - // skipping because function pointer args: xdr_reference - // skipping because function pointer args: xdr_pointer - // skipping because function pointer args: xdr_wrapstring - // skipping because function pointer args: xdr_sizeof - // skipping because function pointer args: xdr_netobj - // skipping because function pointer args: xdrmem_create - // skipping because function pointer args: xdrstdio_create - // skipping because function pointer args: xdrrec_create - // skipping because function pointer args: xdrrec_endofrecord - // skipping because function pointer args: xdrrec_skiprecord - // skipping because function pointer args: xdrrec_eof - // skipping because function pointer args: xdr_free - // skipping because function pointer args: xdr_des_block - //Pointer(Use(TypeDef(AUTH, Use(Struct(struct AUTH))))) authunix_create(Pointer(BuiltIn(char)), Use(TypeDef(__uid_t, Attributed(unsigned , BuiltIn(int)))), Use(TypeDef(__gid_t, Attributed(unsigned , BuiltIn(int)))), BuiltIn(int), Pointer(Use(TypeDef(__gid_t, Attributed(unsigned , BuiltIn(int)))))); - (void *)(authunix_create), - //Pointer(Use(TypeDef(AUTH, Use(Struct(struct AUTH))))) authunix_create_default(); - (void *)(authunix_create_default), - //Pointer(Use(TypeDef(AUTH, Use(Struct(struct AUTH))))) authnone_create(); - (void *)(authnone_create), - //Pointer(Use(TypeDef(AUTH, Use(Struct(struct AUTH))))) authdes_create(Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(u_int, Use(TypeDef(__u_int, Attributed(unsigned , BuiltIn(int)))))), Pointer(Use(Struct(struct sockaddr))), Pointer(Use(TypeDef(des_block, Use(Union(union des_block)))))); - (void *)(authdes_create), - //Pointer(Use(TypeDef(AUTH, Use(Struct(struct AUTH))))) authdes_pk_create(Pointer(Attributed(const , BuiltIn(char))), Pointer(Use(TypeDef(netobj, Use(Struct(struct netobj))))), Use(TypeDef(u_int, Use(TypeDef(__u_int, Attributed(unsigned , BuiltIn(int)))))), Pointer(Use(Struct(struct sockaddr))), Pointer(Use(TypeDef(des_block, Use(Union(union des_block)))))); - (void *)(authdes_pk_create), - //BuiltIn(int) getnetname(Pointer(BuiltIn(char))); - (void *)(getnetname), - //BuiltIn(int) host2netname(Pointer(BuiltIn(char)), Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(host2netname), - //BuiltIn(int) user2netname(Pointer(BuiltIn(char)), Attributed(const , Use(TypeDef(uid_t, Use(TypeDef(__uid_t, Attributed(unsigned , BuiltIn(int))))))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(user2netname), - //BuiltIn(int) netname2user(Pointer(Attributed(const , BuiltIn(char))), Pointer(Use(TypeDef(uid_t, Use(TypeDef(__uid_t, Attributed(unsigned , BuiltIn(int))))))), Pointer(Use(TypeDef(gid_t, Use(TypeDef(__gid_t, Attributed(unsigned , BuiltIn(int))))))), Pointer(BuiltIn(int)), Pointer(Use(TypeDef(gid_t, Use(TypeDef(__gid_t, Attributed(unsigned , BuiltIn(int)))))))); - (void *)(netname2user), - //BuiltIn(int) netname2host(Pointer(Attributed(const , BuiltIn(char))), Pointer(BuiltIn(char)), Attributed(const , BuiltIn(int))); - (void *)(netname2host), - //BuiltIn(int) key_decryptsession(Pointer(BuiltIn(char)), Pointer(Use(TypeDef(des_block, Use(Union(union des_block)))))); - (void *)(key_decryptsession), - //BuiltIn(int) key_decryptsession_pk(Pointer(BuiltIn(char)), Pointer(Use(TypeDef(netobj, Use(Struct(struct netobj))))), Pointer(Use(TypeDef(des_block, Use(Union(union des_block)))))); - (void *)(key_decryptsession_pk), - //BuiltIn(int) key_encryptsession(Pointer(BuiltIn(char)), Pointer(Use(TypeDef(des_block, Use(Union(union des_block)))))); - (void *)(key_encryptsession), - //BuiltIn(int) key_encryptsession_pk(Pointer(BuiltIn(char)), Pointer(Use(TypeDef(netobj, Use(Struct(struct netobj))))), Pointer(Use(TypeDef(des_block, Use(Union(union des_block)))))); - (void *)(key_encryptsession_pk), - //BuiltIn(int) key_gendes(Pointer(Use(TypeDef(des_block, Use(Union(union des_block)))))); - (void *)(key_gendes), - //BuiltIn(int) key_setsecret(Pointer(BuiltIn(char))); - (void *)(key_setsecret), - //BuiltIn(int) key_secretkey_is_set(); - (void *)(key_secretkey_is_set), - //BuiltIn(int) key_get_conv(Pointer(BuiltIn(char)), Pointer(Use(TypeDef(des_block, Use(Union(union des_block)))))); - (void *)(key_get_conv), - // skipping because function pointer args: xdr_opaque_auth - //Pointer(Use(TypeDef(CLIENT, Use(Struct(struct CLIENT))))) clntraw_create(Attributed(const , Use(TypeDef(u_long, Use(TypeDef(__u_long, Attributed(unsigned , BuiltIn(long))))))), Attributed(const , Use(TypeDef(u_long, Use(TypeDef(__u_long, Attributed(unsigned , BuiltIn(long)))))))); - (void *)(clntraw_create), - //Pointer(Use(TypeDef(CLIENT, Use(Struct(struct CLIENT))))) clnt_create(Pointer(Attributed(const , BuiltIn(char))), Attributed(const , Use(TypeDef(u_long, Use(TypeDef(__u_long, Attributed(unsigned , BuiltIn(long))))))), Attributed(const , Use(TypeDef(u_long, Use(TypeDef(__u_long, Attributed(unsigned , BuiltIn(long))))))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(clnt_create), - //Pointer(Use(TypeDef(CLIENT, Use(Struct(struct CLIENT))))) clnttcp_create(Pointer(Use(Struct(struct sockaddr_in))), Use(TypeDef(u_long, Use(TypeDef(__u_long, Attributed(unsigned , BuiltIn(long)))))), Use(TypeDef(u_long, Use(TypeDef(__u_long, Attributed(unsigned , BuiltIn(long)))))), Pointer(BuiltIn(int)), Use(TypeDef(u_int, Use(TypeDef(__u_int, Attributed(unsigned , BuiltIn(int)))))), Use(TypeDef(u_int, Use(TypeDef(__u_int, Attributed(unsigned , BuiltIn(int))))))); - (void *)(clnttcp_create), - //Pointer(Use(TypeDef(CLIENT, Use(Struct(struct CLIENT))))) clntudp_create(Pointer(Use(Struct(struct sockaddr_in))), Use(TypeDef(u_long, Use(TypeDef(__u_long, Attributed(unsigned , BuiltIn(long)))))), Use(TypeDef(u_long, Use(TypeDef(__u_long, Attributed(unsigned , BuiltIn(long)))))), Use(Struct(struct timeval)), Pointer(BuiltIn(int))); - (void *)(clntudp_create), - //Pointer(Use(TypeDef(CLIENT, Use(Struct(struct CLIENT))))) clntudp_bufcreate(Pointer(Use(Struct(struct sockaddr_in))), Use(TypeDef(u_long, Use(TypeDef(__u_long, Attributed(unsigned , BuiltIn(long)))))), Use(TypeDef(u_long, Use(TypeDef(__u_long, Attributed(unsigned , BuiltIn(long)))))), Use(Struct(struct timeval)), Pointer(BuiltIn(int)), Use(TypeDef(u_int, Use(TypeDef(__u_int, Attributed(unsigned , BuiltIn(int)))))), Use(TypeDef(u_int, Use(TypeDef(__u_int, Attributed(unsigned , BuiltIn(int))))))); - (void *)(clntudp_bufcreate), - //Pointer(Use(TypeDef(CLIENT, Use(Struct(struct CLIENT))))) clntunix_create(Pointer(Use(Struct(struct sockaddr_un))), Use(TypeDef(u_long, Use(TypeDef(__u_long, Attributed(unsigned , BuiltIn(long)))))), Use(TypeDef(u_long, Use(TypeDef(__u_long, Attributed(unsigned , BuiltIn(long)))))), Pointer(BuiltIn(int)), Use(TypeDef(u_int, Use(TypeDef(__u_int, Attributed(unsigned , BuiltIn(int)))))), Use(TypeDef(u_int, Use(TypeDef(__u_int, Attributed(unsigned , BuiltIn(int))))))); - (void *)(clntunix_create), - //BuiltIn(int) callrpc(Pointer(Attributed(const , BuiltIn(char))), Attributed(const , Use(TypeDef(u_long, Use(TypeDef(__u_long, Attributed(unsigned , BuiltIn(long))))))), Attributed(const , Use(TypeDef(u_long, Use(TypeDef(__u_long, Attributed(unsigned , BuiltIn(long))))))), Attributed(const , Use(TypeDef(u_long, Use(TypeDef(__u_long, Attributed(unsigned , BuiltIn(long))))))), Attributed(const , Use(TypeDef(xdrproc_t, Pointer(Function(Use(TypeDef(bool_t, BuiltIn(int))), Pointer(Use(TypeDef(XDR, Use(Struct(struct XDR))))), Pointer(BuiltIn(void))))))), Pointer(Attributed(const , BuiltIn(char))), Attributed(const , Use(TypeDef(xdrproc_t, Pointer(Function(Use(TypeDef(bool_t, BuiltIn(int))), Pointer(Use(TypeDef(XDR, Use(Struct(struct XDR))))), Pointer(BuiltIn(void))))))), Pointer(BuiltIn(char))); - (void *)(callrpc), - //BuiltIn(int) _rpc_dtablesize(); - (void *)(_rpc_dtablesize), - //BuiltIn(void) clnt_pcreateerror(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(clnt_pcreateerror), - //Pointer(BuiltIn(char)) clnt_spcreateerror(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(clnt_spcreateerror), - //BuiltIn(void) clnt_perrno(Use(Enum(enum clnt_stat))); - (void *)(clnt_perrno), - // skipping because function pointer args: clnt_perror - // skipping because function pointer args: clnt_sperror - //Pointer(BuiltIn(char)) clnt_sperrno(Use(Enum(enum clnt_stat))); - (void *)(clnt_sperrno), - //BuiltIn(int) getrpcport(Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(u_long, Use(TypeDef(__u_long, Attributed(unsigned , BuiltIn(long)))))), Use(TypeDef(u_long, Use(TypeDef(__u_long, Attributed(unsigned , BuiltIn(long)))))), Use(TypeDef(u_int, Use(TypeDef(__u_int, Attributed(unsigned , BuiltIn(int))))))); - (void *)(getrpcport), - //BuiltIn(void) get_myaddress(Pointer(Use(Struct(struct sockaddr_in)))); - (void *)(get_myaddress), - // skipping because function pointer args: xdr_callmsg - // skipping because function pointer args: xdr_callhdr - // skipping because function pointer args: xdr_replymsg - // skipping because function pointer args: _seterr_reply - // skipping because function pointer args: xdr_authunix_parms - //BuiltIn(int) authdes_getucred(Pointer(Attributed(const , Use(Struct(struct authdes_cred)))), Pointer(Use(TypeDef(uid_t, Use(TypeDef(__uid_t, Attributed(unsigned , BuiltIn(int))))))), Pointer(Use(TypeDef(gid_t, Use(TypeDef(__gid_t, Attributed(unsigned , BuiltIn(int))))))), Pointer(BuiltIn(short)), Pointer(Use(TypeDef(gid_t, Use(TypeDef(__gid_t, Attributed(unsigned , BuiltIn(int)))))))); - (void *)(authdes_getucred), - //BuiltIn(int) getpublickey(Pointer(Attributed(const , BuiltIn(char))), Pointer(BuiltIn(char))); - (void *)(getpublickey), - //BuiltIn(int) getsecretkey(Pointer(Attributed(const , BuiltIn(char))), Pointer(BuiltIn(char)), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(getsecretkey), - //BuiltIn(int) rtime(Pointer(Use(Struct(struct sockaddr_in))), Pointer(Use(Struct(struct rpc_timeval))), Pointer(Use(Struct(struct rpc_timeval)))); - (void *)(rtime), - // skipping because function pointer args: svc_register - //BuiltIn(void) svc_unregister(Use(TypeDef(rpcprog_t, Attributed(unsigned , BuiltIn(long)))), Use(TypeDef(rpcvers_t, Attributed(unsigned , BuiltIn(long))))); - (void *)(svc_unregister), - //BuiltIn(void) xprt_register(Pointer(Use(TypeDef(SVCXPRT, Use(Struct(struct SVCXPRT)))))); - (void *)(xprt_register), - //BuiltIn(void) xprt_unregister(Pointer(Use(TypeDef(SVCXPRT, Use(Struct(struct SVCXPRT)))))); - (void *)(xprt_unregister), - // skipping because function pointer args: svc_sendreply - //BuiltIn(void) svcerr_decode(Pointer(Use(TypeDef(SVCXPRT, Use(Struct(struct SVCXPRT)))))); - (void *)(svcerr_decode), - //BuiltIn(void) svcerr_weakauth(Pointer(Use(TypeDef(SVCXPRT, Use(Struct(struct SVCXPRT)))))); - (void *)(svcerr_weakauth), - //BuiltIn(void) svcerr_noproc(Pointer(Use(TypeDef(SVCXPRT, Use(Struct(struct SVCXPRT)))))); - (void *)(svcerr_noproc), - //BuiltIn(void) svcerr_progvers(Pointer(Use(TypeDef(SVCXPRT, Use(Struct(struct SVCXPRT))))), Use(TypeDef(rpcvers_t, Attributed(unsigned , BuiltIn(long)))), Use(TypeDef(rpcvers_t, Attributed(unsigned , BuiltIn(long))))); - (void *)(svcerr_progvers), - //BuiltIn(void) svcerr_auth(Pointer(Use(TypeDef(SVCXPRT, Use(Struct(struct SVCXPRT))))), Use(Enum(enum auth_stat))); - (void *)(svcerr_auth), - //BuiltIn(void) svcerr_noprog(Pointer(Use(TypeDef(SVCXPRT, Use(Struct(struct SVCXPRT)))))); - (void *)(svcerr_noprog), - //BuiltIn(void) svcerr_systemerr(Pointer(Use(TypeDef(SVCXPRT, Use(Struct(struct SVCXPRT)))))); - (void *)(svcerr_systemerr), - //BuiltIn(void) svc_getreq(BuiltIn(int)); - (void *)(svc_getreq), - //BuiltIn(void) svc_getreq_common(Attributed(const , BuiltIn(int))); - (void *)(svc_getreq_common), - //BuiltIn(void) svc_getreqset(Pointer(Use(TypeDef(fd_set, Struct(struct anon_struct_26))))); - (void *)(svc_getreqset), - //BuiltIn(void) svc_getreq_poll(Pointer(Use(Struct(struct pollfd))), Attributed(const , BuiltIn(int))); - (void *)(svc_getreq_poll), - //BuiltIn(void) svc_exit(); - (void *)(svc_exit), - //BuiltIn(void) svc_run(); - (void *)(svc_run), - //Pointer(Use(TypeDef(SVCXPRT, Use(Struct(struct SVCXPRT))))) svcraw_create(); - (void *)(svcraw_create), - //Pointer(Use(TypeDef(SVCXPRT, Use(Struct(struct SVCXPRT))))) svcudp_create(BuiltIn(int)); - (void *)(svcudp_create), - //Pointer(Use(TypeDef(SVCXPRT, Use(Struct(struct SVCXPRT))))) svcudp_bufcreate(BuiltIn(int), Use(TypeDef(u_int, Use(TypeDef(__u_int, Attributed(unsigned , BuiltIn(int)))))), Use(TypeDef(u_int, Use(TypeDef(__u_int, Attributed(unsigned , BuiltIn(int))))))); - (void *)(svcudp_bufcreate), - //Pointer(Use(TypeDef(SVCXPRT, Use(Struct(struct SVCXPRT))))) svctcp_create(BuiltIn(int), Use(TypeDef(u_int, Use(TypeDef(__u_int, Attributed(unsigned , BuiltIn(int)))))), Use(TypeDef(u_int, Use(TypeDef(__u_int, Attributed(unsigned , BuiltIn(int))))))); - (void *)(svctcp_create), - //Pointer(Use(TypeDef(SVCXPRT, Use(Struct(struct SVCXPRT))))) svcfd_create(BuiltIn(int), Use(TypeDef(u_int, Use(TypeDef(__u_int, Attributed(unsigned , BuiltIn(int)))))), Use(TypeDef(u_int, Use(TypeDef(__u_int, Attributed(unsigned , BuiltIn(int))))))); - (void *)(svcfd_create), - //Pointer(Use(TypeDef(SVCXPRT, Use(Struct(struct SVCXPRT))))) svcunix_create(BuiltIn(int), Use(TypeDef(u_int, Use(TypeDef(__u_int, Attributed(unsigned , BuiltIn(int)))))), Use(TypeDef(u_int, Use(TypeDef(__u_int, Attributed(unsigned , BuiltIn(int)))))), Pointer(BuiltIn(char))); - (void *)(svcunix_create), - // skipping because function pointer args: _authenticate - //BuiltIn(void) setrpcent(BuiltIn(int)); - (void *)(setrpcent), - //BuiltIn(void) endrpcent(); - (void *)(endrpcent), - //Pointer(Use(Struct(struct rpcent))) getrpcbyname(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(getrpcbyname), - //Pointer(Use(Struct(struct rpcent))) getrpcbynumber(BuiltIn(int)); - (void *)(getrpcbynumber), - //Pointer(Use(Struct(struct rpcent))) getrpcent(); - (void *)(getrpcent), - //BuiltIn(int) getrpcbyname_r(Pointer(Attributed(const , BuiltIn(char))), Pointer(Use(Struct(struct rpcent))), Pointer(BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Pointer(Use(Struct(struct rpcent))))); - (void *)(getrpcbyname_r), - //BuiltIn(int) getrpcbynumber_r(BuiltIn(int), Pointer(Use(Struct(struct rpcent))), Pointer(BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Pointer(Use(Struct(struct rpcent))))); - (void *)(getrpcbynumber_r), - //BuiltIn(int) getrpcent_r(Pointer(Use(Struct(struct rpcent))), Pointer(BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Pointer(Use(Struct(struct rpcent))))); - (void *)(getrpcent_r), - //Pointer(Use(TypeDef(fd_set, Struct(struct anon_struct_26)))) __rpc_thread_svc_fdset(); - (void *)(__rpc_thread_svc_fdset), - //Pointer(Use(Struct(struct rpc_createerr))) __rpc_thread_createerr(); - (void *)(__rpc_thread_createerr), - //Pointer(Pointer(Use(Struct(struct pollfd)))) __rpc_thread_svc_pollfd(); - (void *)(__rpc_thread_svc_pollfd), - //Pointer(BuiltIn(int)) __rpc_thread_svc_max_pollfd(); - (void *)(__rpc_thread_svc_max_pollfd), - // skipping because function pointer args: sprayproc_spray_1 - //Pointer(BuiltIn(void)) sprayproc_spray_1_svc(Pointer(Use(TypeDef(sprayarr, Struct(struct anon_struct_236)))), Pointer(Use(Struct(struct svc_req)))); - (void *)(sprayproc_spray_1_svc), - // skipping because function pointer args: sprayproc_get_1 - //Pointer(Use(TypeDef(spraycumul, Use(Struct(struct spraycumul))))) sprayproc_get_1_svc(Pointer(BuiltIn(void)), Pointer(Use(Struct(struct svc_req)))); - (void *)(sprayproc_get_1_svc), - // skipping because function pointer args: sprayproc_clear_1 - //Pointer(BuiltIn(void)) sprayproc_clear_1_svc(Pointer(BuiltIn(void)), Pointer(Use(Struct(struct svc_req)))); - (void *)(sprayproc_clear_1_svc), - // skipping because function pointer args: sprayprog_1_freeresult - // skipping because function pointer args: xdr_spraytimeval - // skipping because function pointer args: xdr_spraycumul - // skipping because function pointer args: xdr_sprayarr - // skipping because function pointer args: klm_test_1 - //Pointer(Use(TypeDef(klm_testrply, Use(Struct(struct klm_testrply))))) klm_test_1_svc(Pointer(Use(Struct(struct klm_testargs))), Pointer(Use(Struct(struct svc_req)))); - (void *)(klm_test_1_svc), - // skipping because function pointer args: klm_lock_1 - //Pointer(Use(TypeDef(klm_stat, Use(Struct(struct klm_stat))))) klm_lock_1_svc(Pointer(Use(Struct(struct klm_lockargs))), Pointer(Use(Struct(struct svc_req)))); - (void *)(klm_lock_1_svc), - // skipping because function pointer args: klm_cancel_1 - //Pointer(Use(TypeDef(klm_stat, Use(Struct(struct klm_stat))))) klm_cancel_1_svc(Pointer(Use(Struct(struct klm_lockargs))), Pointer(Use(Struct(struct svc_req)))); - (void *)(klm_cancel_1_svc), - // skipping because function pointer args: klm_unlock_1 - //Pointer(Use(TypeDef(klm_stat, Use(Struct(struct klm_stat))))) klm_unlock_1_svc(Pointer(Use(Struct(struct klm_unlockargs))), Pointer(Use(Struct(struct svc_req)))); - (void *)(klm_unlock_1_svc), - // skipping because function pointer args: klm_prog_1_freeresult - // skipping because function pointer args: xdr_klm_stats - // skipping because function pointer args: xdr_klm_lock - // skipping because function pointer args: xdr_klm_holder - // skipping because function pointer args: xdr_klm_stat - // skipping because function pointer args: xdr_klm_testrply - // skipping because function pointer args: xdr_klm_lockargs - // skipping because function pointer args: xdr_klm_testargs - // skipping because function pointer args: xdr_klm_unlockargs - // skipping because function pointer args: sm_stat_1 - //Pointer(Use(Struct(struct sm_stat_res))) sm_stat_1_svc(Pointer(Use(Struct(struct sm_name))), Pointer(Use(Struct(struct svc_req)))); - (void *)(sm_stat_1_svc), - // skipping because function pointer args: sm_mon_1 - //Pointer(Use(Struct(struct sm_stat_res))) sm_mon_1_svc(Pointer(Use(Struct(struct mon))), Pointer(Use(Struct(struct svc_req)))); - (void *)(sm_mon_1_svc), - // skipping because function pointer args: sm_unmon_1 - //Pointer(Use(Struct(struct sm_stat))) sm_unmon_1_svc(Pointer(Use(Struct(struct mon_id))), Pointer(Use(Struct(struct svc_req)))); - (void *)(sm_unmon_1_svc), - // skipping because function pointer args: sm_unmon_all_1 - //Pointer(Use(Struct(struct sm_stat))) sm_unmon_all_1_svc(Pointer(Use(Struct(struct my_id))), Pointer(Use(Struct(struct svc_req)))); - (void *)(sm_unmon_all_1_svc), - // skipping because function pointer args: sm_simu_crash_1 - //Pointer(BuiltIn(void)) sm_simu_crash_1_svc(Pointer(BuiltIn(void)), Pointer(Use(Struct(struct svc_req)))); - (void *)(sm_simu_crash_1_svc), - // skipping because function pointer args: sm_prog_1_freeresult - // skipping because function pointer args: xdr_sm_name - // skipping because function pointer args: xdr_my_id - // skipping because function pointer args: xdr_mon_id - // skipping because function pointer args: xdr_mon - // skipping because function pointer args: xdr_sm_stat - // skipping because function pointer args: xdr_res - // skipping because function pointer args: xdr_sm_stat_res - // skipping because function pointer args: xdr_status - // skipping because function pointer args: nlm_test_1 - //Pointer(Use(TypeDef(nlm_testres, Use(Struct(struct nlm_testres))))) nlm_test_1_svc(Pointer(Use(Struct(struct nlm_testargs))), Pointer(Use(Struct(struct svc_req)))); - (void *)(nlm_test_1_svc), - // skipping because function pointer args: nlm_lock_1 - //Pointer(Use(TypeDef(nlm_res, Use(Struct(struct nlm_res))))) nlm_lock_1_svc(Pointer(Use(Struct(struct nlm_lockargs))), Pointer(Use(Struct(struct svc_req)))); - (void *)(nlm_lock_1_svc), - // skipping because function pointer args: nlm_cancel_1 - //Pointer(Use(TypeDef(nlm_res, Use(Struct(struct nlm_res))))) nlm_cancel_1_svc(Pointer(Use(Struct(struct nlm_cancargs))), Pointer(Use(Struct(struct svc_req)))); - (void *)(nlm_cancel_1_svc), - // skipping because function pointer args: nlm_unlock_1 - //Pointer(Use(TypeDef(nlm_res, Use(Struct(struct nlm_res))))) nlm_unlock_1_svc(Pointer(Use(Struct(struct nlm_unlockargs))), Pointer(Use(Struct(struct svc_req)))); - (void *)(nlm_unlock_1_svc), - // skipping because function pointer args: nlm_granted_1 - //Pointer(Use(TypeDef(nlm_res, Use(Struct(struct nlm_res))))) nlm_granted_1_svc(Pointer(Use(Struct(struct nlm_testargs))), Pointer(Use(Struct(struct svc_req)))); - (void *)(nlm_granted_1_svc), - // skipping because function pointer args: nlm_test_msg_1 - //Pointer(BuiltIn(void)) nlm_test_msg_1_svc(Pointer(Use(Struct(struct nlm_testargs))), Pointer(Use(Struct(struct svc_req)))); - (void *)(nlm_test_msg_1_svc), - // skipping because function pointer args: nlm_lock_msg_1 - //Pointer(BuiltIn(void)) nlm_lock_msg_1_svc(Pointer(Use(Struct(struct nlm_lockargs))), Pointer(Use(Struct(struct svc_req)))); - (void *)(nlm_lock_msg_1_svc), - // skipping because function pointer args: nlm_cancel_msg_1 - //Pointer(BuiltIn(void)) nlm_cancel_msg_1_svc(Pointer(Use(Struct(struct nlm_cancargs))), Pointer(Use(Struct(struct svc_req)))); - (void *)(nlm_cancel_msg_1_svc), - // skipping because function pointer args: nlm_unlock_msg_1 - //Pointer(BuiltIn(void)) nlm_unlock_msg_1_svc(Pointer(Use(Struct(struct nlm_unlockargs))), Pointer(Use(Struct(struct svc_req)))); - (void *)(nlm_unlock_msg_1_svc), - // skipping because function pointer args: nlm_granted_msg_1 - //Pointer(BuiltIn(void)) nlm_granted_msg_1_svc(Pointer(Use(Struct(struct nlm_testargs))), Pointer(Use(Struct(struct svc_req)))); - (void *)(nlm_granted_msg_1_svc), - // skipping because function pointer args: nlm_test_res_1 - //Pointer(BuiltIn(void)) nlm_test_res_1_svc(Pointer(Use(TypeDef(nlm_testres, Use(Struct(struct nlm_testres))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(nlm_test_res_1_svc), - // skipping because function pointer args: nlm_lock_res_1 - //Pointer(BuiltIn(void)) nlm_lock_res_1_svc(Pointer(Use(TypeDef(nlm_res, Use(Struct(struct nlm_res))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(nlm_lock_res_1_svc), - // skipping because function pointer args: nlm_cancel_res_1 - //Pointer(BuiltIn(void)) nlm_cancel_res_1_svc(Pointer(Use(TypeDef(nlm_res, Use(Struct(struct nlm_res))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(nlm_cancel_res_1_svc), - // skipping because function pointer args: nlm_unlock_res_1 - //Pointer(BuiltIn(void)) nlm_unlock_res_1_svc(Pointer(Use(TypeDef(nlm_res, Use(Struct(struct nlm_res))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(nlm_unlock_res_1_svc), - // skipping because function pointer args: nlm_granted_res_1 - //Pointer(BuiltIn(void)) nlm_granted_res_1_svc(Pointer(Use(TypeDef(nlm_res, Use(Struct(struct nlm_res))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(nlm_granted_res_1_svc), - // skipping because function pointer args: nlm_prog_1_freeresult - // skipping because function pointer args: nlm_share_3 - //Pointer(Use(TypeDef(nlm_shareres, Use(Struct(struct nlm_shareres))))) nlm_share_3_svc(Pointer(Use(TypeDef(nlm_shareargs, Use(Struct(struct nlm_shareargs))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(nlm_share_3_svc), - // skipping because function pointer args: nlm_unshare_3 - //Pointer(Use(TypeDef(nlm_shareres, Use(Struct(struct nlm_shareres))))) nlm_unshare_3_svc(Pointer(Use(TypeDef(nlm_shareargs, Use(Struct(struct nlm_shareargs))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(nlm_unshare_3_svc), - // skipping because function pointer args: nlm_nm_lock_3 - //Pointer(Use(TypeDef(nlm_res, Use(Struct(struct nlm_res))))) nlm_nm_lock_3_svc(Pointer(Use(TypeDef(nlm_lockargs, Use(Struct(struct nlm_lockargs))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(nlm_nm_lock_3_svc), - // skipping because function pointer args: nlm_free_all_3 - //Pointer(BuiltIn(void)) nlm_free_all_3_svc(Pointer(Use(TypeDef(nlm_notify, Use(Struct(struct nlm_notify))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(nlm_free_all_3_svc), - // skipping because function pointer args: nlm_prog_3_freeresult - // skipping because function pointer args: xdr_nlm_stats - // skipping because function pointer args: xdr_nlm_holder - // skipping because function pointer args: xdr_nlm_testrply - // skipping because function pointer args: xdr_nlm_stat - // skipping because function pointer args: xdr_nlm_res - // skipping because function pointer args: xdr_nlm_testres - // skipping because function pointer args: xdr_nlm_lock - // skipping because function pointer args: xdr_nlm_lockargs - // skipping because function pointer args: xdr_nlm_cancargs - // skipping because function pointer args: xdr_nlm_testargs - // skipping because function pointer args: xdr_nlm_unlockargs - // skipping because function pointer args: xdr_fsh_mode - // skipping because function pointer args: xdr_fsh_access - // skipping because function pointer args: xdr_nlm_share - // skipping because function pointer args: xdr_nlm_shareargs - // skipping because function pointer args: xdr_nlm_shareres - // skipping because function pointer args: xdr_nlm_notify - //Pointer(Use(TypeDef(nis_result, Use(Struct(struct nis_result))))) nis_lookup(Use(TypeDef(const_nis_name, Pointer(Attributed(const , BuiltIn(char))))), Attributed(unsigned , BuiltIn(int))); - (void *)(nis_lookup), - //Pointer(Use(TypeDef(nis_result, Use(Struct(struct nis_result))))) nis_add(Use(TypeDef(const_nis_name, Pointer(Attributed(const , BuiltIn(char))))), Pointer(Attributed(const , Use(TypeDef(nis_object, Use(Struct(struct nis_object))))))); - (void *)(nis_add), - //Pointer(Use(TypeDef(nis_result, Use(Struct(struct nis_result))))) nis_remove(Use(TypeDef(const_nis_name, Pointer(Attributed(const , BuiltIn(char))))), Pointer(Attributed(const , Use(TypeDef(nis_object, Use(Struct(struct nis_object))))))); - (void *)(nis_remove), - //Pointer(Use(TypeDef(nis_result, Use(Struct(struct nis_result))))) nis_modify(Use(TypeDef(const_nis_name, Pointer(Attributed(const , BuiltIn(char))))), Pointer(Attributed(const , Use(TypeDef(nis_object, Use(Struct(struct nis_object))))))); - (void *)(nis_modify), - // skipping because function pointer args: nis_list - //Pointer(Use(TypeDef(nis_result, Use(Struct(struct nis_result))))) nis_add_entry(Use(TypeDef(const_nis_name, Pointer(Attributed(const , BuiltIn(char))))), Pointer(Attributed(const , Use(TypeDef(nis_object, Use(Struct(struct nis_object)))))), Attributed(unsigned , BuiltIn(int))); - (void *)(nis_add_entry), - //Pointer(Use(TypeDef(nis_result, Use(Struct(struct nis_result))))) nis_modify_entry(Use(TypeDef(const_nis_name, Pointer(Attributed(const , BuiltIn(char))))), Pointer(Attributed(const , Use(TypeDef(nis_object, Use(Struct(struct nis_object)))))), Attributed(unsigned , BuiltIn(int))); - (void *)(nis_modify_entry), - //Pointer(Use(TypeDef(nis_result, Use(Struct(struct nis_result))))) nis_remove_entry(Use(TypeDef(const_nis_name, Pointer(Attributed(const , BuiltIn(char))))), Pointer(Attributed(const , Use(TypeDef(nis_object, Use(Struct(struct nis_object)))))), Attributed(unsigned , BuiltIn(int))); - (void *)(nis_remove_entry), - //Pointer(Use(TypeDef(nis_result, Use(Struct(struct nis_result))))) nis_first_entry(Use(TypeDef(const_nis_name, Pointer(Attributed(const , BuiltIn(char)))))); - (void *)(nis_first_entry), - //Pointer(Use(TypeDef(nis_result, Use(Struct(struct nis_result))))) nis_next_entry(Use(TypeDef(const_nis_name, Pointer(Attributed(const , BuiltIn(char))))), Pointer(Attributed(const , Use(TypeDef(netobj, Use(Struct(struct netobj))))))); - (void *)(nis_next_entry), - //Use(TypeDef(nis_error, Use(Enum(enum nis_error)))) nis_mkdir(Use(TypeDef(const_nis_name, Pointer(Attributed(const , BuiltIn(char))))), Pointer(Attributed(const , Use(TypeDef(nis_server, Use(Struct(struct nis_server))))))); - (void *)(nis_mkdir), - //Use(TypeDef(nis_error, Use(Enum(enum nis_error)))) nis_rmdir(Use(TypeDef(const_nis_name, Pointer(Attributed(const , BuiltIn(char))))), Pointer(Attributed(const , Use(TypeDef(nis_server, Use(Struct(struct nis_server))))))); - (void *)(nis_rmdir), - //Use(TypeDef(nis_error, Use(Enum(enum nis_error)))) nis_servstate(Pointer(Attributed(const , Use(TypeDef(nis_server, Use(Struct(struct nis_server)))))), Pointer(Attributed(const , Use(TypeDef(nis_tag, Use(Struct(struct nis_tag)))))), BuiltIn(int), Pointer(Pointer(Use(TypeDef(nis_tag, Use(Struct(struct nis_tag))))))); - (void *)(nis_servstate), - //Use(TypeDef(nis_error, Use(Enum(enum nis_error)))) nis_stats(Pointer(Attributed(const , Use(TypeDef(nis_server, Use(Struct(struct nis_server)))))), Pointer(Attributed(const , Use(TypeDef(nis_tag, Use(Struct(struct nis_tag)))))), BuiltIn(int), Pointer(Pointer(Use(TypeDef(nis_tag, Use(Struct(struct nis_tag))))))); - (void *)(nis_stats), - //BuiltIn(void) nis_freetags(Pointer(Use(TypeDef(nis_tag, Use(Struct(struct nis_tag))))), BuiltIn(int)); - (void *)(nis_freetags), - //Pointer(Pointer(Use(TypeDef(nis_server, Use(Struct(struct nis_server)))))) nis_getservlist(Use(TypeDef(const_nis_name, Pointer(Attributed(const , BuiltIn(char)))))); - (void *)(nis_getservlist), - //BuiltIn(void) nis_freeservlist(Pointer(Pointer(Use(TypeDef(nis_server, Use(Struct(struct nis_server))))))); - (void *)(nis_freeservlist), - //Use(TypeDef(nis_name, Pointer(BuiltIn(char)))) nis_leaf_of(Use(TypeDef(const_nis_name, Pointer(Attributed(const , BuiltIn(char)))))); - (void *)(nis_leaf_of), - //Use(TypeDef(nis_name, Pointer(BuiltIn(char)))) nis_leaf_of_r(Use(TypeDef(const_nis_name, Pointer(Attributed(const , BuiltIn(char))))), Pointer(BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(nis_leaf_of_r), - //Use(TypeDef(nis_name, Pointer(BuiltIn(char)))) nis_name_of(Use(TypeDef(const_nis_name, Pointer(Attributed(const , BuiltIn(char)))))); - (void *)(nis_name_of), - //Use(TypeDef(nis_name, Pointer(BuiltIn(char)))) nis_name_of_r(Use(TypeDef(const_nis_name, Pointer(Attributed(const , BuiltIn(char))))), Pointer(BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(nis_name_of_r), - //Use(TypeDef(nis_name, Pointer(BuiltIn(char)))) nis_domain_of(Use(TypeDef(const_nis_name, Pointer(Attributed(const , BuiltIn(char)))))); - (void *)(nis_domain_of), - //Use(TypeDef(nis_name, Pointer(BuiltIn(char)))) nis_domain_of_r(Use(TypeDef(const_nis_name, Pointer(Attributed(const , BuiltIn(char))))), Pointer(BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(nis_domain_of_r), - //Pointer(Use(TypeDef(nis_name, Pointer(BuiltIn(char))))) nis_getnames(Use(TypeDef(const_nis_name, Pointer(Attributed(const , BuiltIn(char)))))); - (void *)(nis_getnames), - //BuiltIn(void) nis_freenames(Pointer(Use(TypeDef(nis_name, Pointer(BuiltIn(char)))))); - (void *)(nis_freenames), - //Use(TypeDef(name_pos, Use(Enum(enum name_pos)))) nis_dir_cmp(Use(TypeDef(const_nis_name, Pointer(Attributed(const , BuiltIn(char))))), Use(TypeDef(const_nis_name, Pointer(Attributed(const , BuiltIn(char)))))); - (void *)(nis_dir_cmp), - //Pointer(Use(TypeDef(nis_object, Use(Struct(struct nis_object))))) nis_clone_object(Pointer(Attributed(const , Use(TypeDef(nis_object, Use(Struct(struct nis_object)))))), Pointer(Use(TypeDef(nis_object, Use(Struct(struct nis_object)))))); - (void *)(nis_clone_object), - //BuiltIn(void) nis_destroy_object(Pointer(Use(TypeDef(nis_object, Use(Struct(struct nis_object)))))); - (void *)(nis_destroy_object), - //BuiltIn(void) nis_print_object(Pointer(Attributed(const , Use(TypeDef(nis_object, Use(Struct(struct nis_object))))))); - (void *)(nis_print_object), - //Use(TypeDef(nis_name, Pointer(BuiltIn(char)))) nis_local_group(); - (void *)(nis_local_group), - //Use(TypeDef(nis_name, Pointer(BuiltIn(char)))) nis_local_directory(); - (void *)(nis_local_directory), - //Use(TypeDef(nis_name, Pointer(BuiltIn(char)))) nis_local_principal(); - (void *)(nis_local_principal), - //Use(TypeDef(nis_name, Pointer(BuiltIn(char)))) nis_local_host(); - (void *)(nis_local_host), - //Pointer(Attributed(const , BuiltIn(char))) nis_sperrno(Attributed(const , Use(TypeDef(nis_error, Use(Enum(enum nis_error)))))); - (void *)(nis_sperrno), - //BuiltIn(void) nis_perror(Attributed(const , Use(TypeDef(nis_error, Use(Enum(enum nis_error))))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(nis_perror), - //BuiltIn(void) nis_lerror(Attributed(const , Use(TypeDef(nis_error, Use(Enum(enum nis_error))))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(nis_lerror), - //Pointer(BuiltIn(char)) nis_sperror(Attributed(const , Use(TypeDef(status, Use(Struct(struct status))))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(nis_sperror), - //Pointer(BuiltIn(char)) nis_sperror_r(Attributed(const , Use(TypeDef(nis_error, Use(Enum(enum nis_error))))), Pointer(Attributed(const , BuiltIn(char))), Pointer(BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(nis_sperror_r), - //Use(TypeDef(bool_t, BuiltIn(int))) nis_ismember(Use(TypeDef(const_nis_name, Pointer(Attributed(const , BuiltIn(char))))), Use(TypeDef(const_nis_name, Pointer(Attributed(const , BuiltIn(char)))))); - (void *)(nis_ismember), - //Use(TypeDef(nis_error, Use(Enum(enum nis_error)))) nis_addmember(Use(TypeDef(const_nis_name, Pointer(Attributed(const , BuiltIn(char))))), Use(TypeDef(const_nis_name, Pointer(Attributed(const , BuiltIn(char)))))); - (void *)(nis_addmember), - //Use(TypeDef(nis_error, Use(Enum(enum nis_error)))) nis_removemember(Use(TypeDef(const_nis_name, Pointer(Attributed(const , BuiltIn(char))))), Use(TypeDef(const_nis_name, Pointer(Attributed(const , BuiltIn(char)))))); - (void *)(nis_removemember), - //Use(TypeDef(nis_error, Use(Enum(enum nis_error)))) nis_creategroup(Use(TypeDef(const_nis_name, Pointer(Attributed(const , BuiltIn(char))))), Attributed(unsigned , BuiltIn(int))); - (void *)(nis_creategroup), - //Use(TypeDef(nis_error, Use(Enum(enum nis_error)))) nis_destroygroup(Use(TypeDef(const_nis_name, Pointer(Attributed(const , BuiltIn(char)))))); - (void *)(nis_destroygroup), - //BuiltIn(void) nis_print_group_entry(Use(TypeDef(const_nis_name, Pointer(Attributed(const , BuiltIn(char)))))); - (void *)(nis_print_group_entry), - //Use(TypeDef(nis_error, Use(Enum(enum nis_error)))) nis_verifygroup(Use(TypeDef(const_nis_name, Pointer(Attributed(const , BuiltIn(char)))))); - (void *)(nis_verifygroup), - //BuiltIn(void) nis_ping(Use(TypeDef(const_nis_name, Pointer(Attributed(const , BuiltIn(char))))), Use(TypeDef(uint32_t, Attributed(unsigned , BuiltIn(int)))), Pointer(Attributed(const , Use(TypeDef(nis_object, Use(Struct(struct nis_object))))))); - (void *)(nis_ping), - //Pointer(Use(TypeDef(nis_result, Use(Struct(struct nis_result))))) nis_checkpoint(Use(TypeDef(const_nis_name, Pointer(Attributed(const , BuiltIn(char)))))); - (void *)(nis_checkpoint), - //BuiltIn(void) nis_print_result(Pointer(Attributed(const , Use(TypeDef(nis_result, Use(Struct(struct nis_result))))))); - (void *)(nis_print_result), - //BuiltIn(void) nis_print_rights(Attributed(unsigned , BuiltIn(int))); - (void *)(nis_print_rights), - //BuiltIn(void) nis_print_directory(Pointer(Attributed(const , Use(TypeDef(directory_obj, Use(Struct(struct directory_obj))))))); - (void *)(nis_print_directory), - //BuiltIn(void) nis_print_group(Pointer(Attributed(const , Use(TypeDef(group_obj, Use(Struct(struct group_obj))))))); - (void *)(nis_print_group), - //BuiltIn(void) nis_print_table(Pointer(Attributed(const , Use(TypeDef(table_obj, Use(Struct(struct table_obj))))))); - (void *)(nis_print_table), - //BuiltIn(void) nis_print_link(Pointer(Attributed(const , Use(TypeDef(link_obj, Use(Struct(struct link_obj))))))); - (void *)(nis_print_link), - //BuiltIn(void) nis_print_entry(Pointer(Attributed(const , Use(TypeDef(entry_obj, Use(Struct(struct entry_obj))))))); - (void *)(nis_print_entry), - //Pointer(Use(TypeDef(directory_obj, Use(Struct(struct directory_obj))))) readColdStartFile(); - (void *)(readColdStartFile), - //Use(TypeDef(bool_t, BuiltIn(int))) writeColdStartFile(Pointer(Attributed(const , Use(TypeDef(directory_obj, Use(Struct(struct directory_obj))))))); - (void *)(writeColdStartFile), - //Pointer(Use(TypeDef(nis_object, Use(Struct(struct nis_object))))) nis_read_obj(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(nis_read_obj), - //Use(TypeDef(bool_t, BuiltIn(int))) nis_write_obj(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , Use(TypeDef(nis_object, Use(Struct(struct nis_object))))))); - (void *)(nis_write_obj), - //Pointer(Use(TypeDef(directory_obj, Use(Struct(struct directory_obj))))) nis_clone_directory(Pointer(Attributed(const , Use(TypeDef(directory_obj, Use(Struct(struct directory_obj)))))), Pointer(Use(TypeDef(directory_obj, Use(Struct(struct directory_obj)))))); - (void *)(nis_clone_directory), - //Pointer(Use(TypeDef(nis_result, Use(Struct(struct nis_result))))) nis_clone_result(Pointer(Attributed(const , Use(TypeDef(nis_result, Use(Struct(struct nis_result)))))), Pointer(Use(TypeDef(nis_result, Use(Struct(struct nis_result)))))); - (void *)(nis_clone_result), - //BuiltIn(void) nis_freeresult(Pointer(Use(TypeDef(nis_result, Use(Struct(struct nis_result)))))); - (void *)(nis_freeresult), - //BuiltIn(void) nis_free_request(Pointer(Use(TypeDef(ib_request, Use(Struct(struct ib_request)))))); - (void *)(nis_free_request), - //BuiltIn(void) nis_free_directory(Pointer(Use(TypeDef(directory_obj, Use(Struct(struct directory_obj)))))); - (void *)(nis_free_directory), - //BuiltIn(void) nis_free_object(Pointer(Use(TypeDef(nis_object, Use(Struct(struct nis_object)))))); - (void *)(nis_free_object), - //Use(TypeDef(nis_name, Pointer(BuiltIn(char)))) __nis_default_owner(Pointer(BuiltIn(char))); - (void *)(__nis_default_owner), - //Use(TypeDef(nis_name, Pointer(BuiltIn(char)))) __nis_default_group(Pointer(BuiltIn(char))); - (void *)(__nis_default_group), - //Use(TypeDef(uint32_t, Attributed(unsigned , BuiltIn(int)))) __nis_default_ttl(Pointer(BuiltIn(char))); - (void *)(__nis_default_ttl), - //Attributed(unsigned , BuiltIn(int)) __nis_default_access(Pointer(BuiltIn(char)), Attributed(unsigned , BuiltIn(int))); - (void *)(__nis_default_access), - //Pointer(Use(TypeDef(fd_result, Use(Struct(struct fd_result))))) __nis_finddirectory(Pointer(Use(TypeDef(directory_obj, Use(Struct(struct directory_obj))))), Use(TypeDef(const_nis_name, Pointer(Attributed(const , BuiltIn(char)))))); - (void *)(__nis_finddirectory), - //BuiltIn(void) __free_fdresult(Pointer(Use(TypeDef(fd_result, Use(Struct(struct fd_result)))))); - (void *)(__free_fdresult), - //BuiltIn(int) __nis_lock_cache(); - (void *)(__nis_lock_cache), - //BuiltIn(int) __nis_unlock_cache(); - (void *)(__nis_unlock_cache), - // skipping because function pointer args: nis_lookup_3 - //Pointer(Use(TypeDef(nis_result, Use(Struct(struct nis_result))))) nis_lookup_3_svc(Pointer(Use(TypeDef(ns_request, Use(Struct(struct ns_request))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(nis_lookup_3_svc), - // skipping because function pointer args: nis_add_3 - //Pointer(Use(TypeDef(nis_result, Use(Struct(struct nis_result))))) nis_add_3_svc(Pointer(Use(TypeDef(ns_request, Use(Struct(struct ns_request))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(nis_add_3_svc), - // skipping because function pointer args: nis_modify_3 - //Pointer(Use(TypeDef(nis_result, Use(Struct(struct nis_result))))) nis_modify_3_svc(Pointer(Use(TypeDef(ns_request, Use(Struct(struct ns_request))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(nis_modify_3_svc), - // skipping because function pointer args: nis_remove_3 - //Pointer(Use(TypeDef(nis_result, Use(Struct(struct nis_result))))) nis_remove_3_svc(Pointer(Use(TypeDef(ns_request, Use(Struct(struct ns_request))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(nis_remove_3_svc), - // skipping because function pointer args: nis_iblist_3 - //Pointer(Use(TypeDef(nis_result, Use(Struct(struct nis_result))))) nis_iblist_3_svc(Pointer(Use(TypeDef(ib_request, Use(Struct(struct ib_request))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(nis_iblist_3_svc), - // skipping because function pointer args: nis_ibadd_3 - //Pointer(Use(TypeDef(nis_result, Use(Struct(struct nis_result))))) nis_ibadd_3_svc(Pointer(Use(TypeDef(ib_request, Use(Struct(struct ib_request))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(nis_ibadd_3_svc), - // skipping because function pointer args: nis_ibmodify_3 - //Pointer(Use(TypeDef(nis_result, Use(Struct(struct nis_result))))) nis_ibmodify_3_svc(Pointer(Use(TypeDef(ib_request, Use(Struct(struct ib_request))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(nis_ibmodify_3_svc), - // skipping because function pointer args: nis_ibremove_3 - //Pointer(Use(TypeDef(nis_result, Use(Struct(struct nis_result))))) nis_ibremove_3_svc(Pointer(Use(TypeDef(ib_request, Use(Struct(struct ib_request))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(nis_ibremove_3_svc), - // skipping because function pointer args: nis_ibfirst_3 - //Pointer(Use(TypeDef(nis_result, Use(Struct(struct nis_result))))) nis_ibfirst_3_svc(Pointer(Use(TypeDef(ib_request, Use(Struct(struct ib_request))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(nis_ibfirst_3_svc), - // skipping because function pointer args: nis_ibnext_3 - //Pointer(Use(TypeDef(nis_result, Use(Struct(struct nis_result))))) nis_ibnext_3_svc(Pointer(Use(TypeDef(ib_request, Use(Struct(struct ib_request))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(nis_ibnext_3_svc), - // skipping because function pointer args: nis_finddirectory_3 - //Pointer(Use(TypeDef(fd_result, Use(Struct(struct fd_result))))) nis_finddirectory_3_svc(Pointer(Use(TypeDef(fd_args, Use(Struct(struct fd_args))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(nis_finddirectory_3_svc), - // skipping because function pointer args: nis_status_3 - //Pointer(Use(TypeDef(nis_taglist, Use(Struct(struct nis_taglist))))) nis_status_3_svc(Pointer(Use(TypeDef(nis_taglist, Use(Struct(struct nis_taglist))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(nis_status_3_svc), - // skipping because function pointer args: nis_dumplog_3 - //Pointer(Use(TypeDef(log_result, Use(Struct(struct log_result))))) nis_dumplog_3_svc(Pointer(Use(TypeDef(dump_args, Use(Struct(struct dump_args))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(nis_dumplog_3_svc), - // skipping because function pointer args: nis_dump_3 - //Pointer(Use(TypeDef(log_result, Use(Struct(struct log_result))))) nis_dump_3_svc(Pointer(Use(TypeDef(dump_args, Use(Struct(struct dump_args))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(nis_dump_3_svc), - // skipping because function pointer args: nis_callback_3 - //Pointer(Use(TypeDef(bool_t, BuiltIn(int)))) nis_callback_3_svc(Pointer(Use(TypeDef(netobj, Use(Struct(struct netobj))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(nis_callback_3_svc), - // skipping because function pointer args: nis_cptime_3 - //Pointer(Use(TypeDef(uint32_t, Attributed(unsigned , BuiltIn(int))))) nis_cptime_3_svc(Pointer(Use(TypeDef(nis_name, Pointer(BuiltIn(char))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(nis_cptime_3_svc), - // skipping because function pointer args: nis_checkpoint_3 - //Pointer(Use(TypeDef(cp_result, Use(Struct(struct cp_result))))) nis_checkpoint_3_svc(Pointer(Use(TypeDef(nis_name, Pointer(BuiltIn(char))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(nis_checkpoint_3_svc), - // skipping because function pointer args: nis_ping_3 - //Pointer(BuiltIn(void)) nis_ping_3_svc(Pointer(Use(TypeDef(ping_args, Use(Struct(struct ping_args))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(nis_ping_3_svc), - // skipping because function pointer args: nis_servstate_3 - //Pointer(Use(TypeDef(nis_taglist, Use(Struct(struct nis_taglist))))) nis_servstate_3_svc(Pointer(Use(TypeDef(nis_taglist, Use(Struct(struct nis_taglist))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(nis_servstate_3_svc), - // skipping because function pointer args: nis_mkdir_3 - //Pointer(Use(TypeDef(nis_error, Use(Enum(enum nis_error))))) nis_mkdir_3_svc(Pointer(Use(TypeDef(nis_name, Pointer(BuiltIn(char))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(nis_mkdir_3_svc), - // skipping because function pointer args: nis_rmdir_3 - //Pointer(Use(TypeDef(nis_error, Use(Enum(enum nis_error))))) nis_rmdir_3_svc(Pointer(Use(TypeDef(nis_name, Pointer(BuiltIn(char))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(nis_rmdir_3_svc), - // skipping because function pointer args: nis_updkeys_3 - //Pointer(Use(TypeDef(nis_error, Use(Enum(enum nis_error))))) nis_updkeys_3_svc(Pointer(Use(TypeDef(nis_name, Pointer(BuiltIn(char))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(nis_updkeys_3_svc), - // skipping because function pointer args: cbproc_receive_1 - //Pointer(Use(TypeDef(bool_t, BuiltIn(int)))) cbproc_receive_1_svc(Pointer(Use(TypeDef(cback_data, Use(Struct(struct cback_data))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(cbproc_receive_1_svc), - // skipping because function pointer args: cbproc_finish_1 - //Pointer(BuiltIn(void)) cbproc_finish_1_svc(Pointer(BuiltIn(void)), Pointer(Use(Struct(struct svc_req)))); - (void *)(cbproc_finish_1_svc), - // skipping because function pointer args: cbproc_error_1 - //Pointer(BuiltIn(void)) cbproc_error_1_svc(Pointer(Use(TypeDef(nis_error, Use(Enum(enum nis_error))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(cbproc_error_1_svc), - // skipping because function pointer args: cb_prog_1_freeresult - // skipping because function pointer args: xdr_obj_p - // skipping because function pointer args: xdr_cback_data - // skipping because function pointer args: key_set_1 - //Pointer(Use(TypeDef(keystatus, Use(Enum(enum keystatus))))) key_set_1_svc(Pointer(BuiltIn(char)), Pointer(Use(Struct(struct svc_req)))); - (void *)(key_set_1_svc), - // skipping because function pointer args: key_encrypt_1 - //Pointer(Use(TypeDef(cryptkeyres, Use(Struct(struct cryptkeyres))))) key_encrypt_1_svc(Pointer(Use(TypeDef(cryptkeyarg, Use(Struct(struct cryptkeyarg))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(key_encrypt_1_svc), - // skipping because function pointer args: key_decrypt_1 - //Pointer(Use(TypeDef(cryptkeyres, Use(Struct(struct cryptkeyres))))) key_decrypt_1_svc(Pointer(Use(TypeDef(cryptkeyarg, Use(Struct(struct cryptkeyarg))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(key_decrypt_1_svc), - // skipping because function pointer args: key_gen_1 - //Pointer(Use(TypeDef(des_block, Use(Union(union des_block))))) key_gen_1_svc(Pointer(BuiltIn(void)), Pointer(Use(Struct(struct svc_req)))); - (void *)(key_gen_1_svc), - // skipping because function pointer args: key_getcred_1 - //Pointer(Use(TypeDef(getcredres, Use(Struct(struct getcredres))))) key_getcred_1_svc(Pointer(Use(TypeDef(netnamestr, Pointer(BuiltIn(char))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(key_getcred_1_svc), - // skipping because function pointer args: key_prog_1_freeresult - // skipping because function pointer args: key_set_2 - //Pointer(Use(TypeDef(keystatus, Use(Enum(enum keystatus))))) key_set_2_svc(Pointer(BuiltIn(char)), Pointer(Use(Struct(struct svc_req)))); - (void *)(key_set_2_svc), - // skipping because function pointer args: key_encrypt_2 - //Pointer(Use(TypeDef(cryptkeyres, Use(Struct(struct cryptkeyres))))) key_encrypt_2_svc(Pointer(Use(TypeDef(cryptkeyarg, Use(Struct(struct cryptkeyarg))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(key_encrypt_2_svc), - // skipping because function pointer args: key_decrypt_2 - //Pointer(Use(TypeDef(cryptkeyres, Use(Struct(struct cryptkeyres))))) key_decrypt_2_svc(Pointer(Use(TypeDef(cryptkeyarg, Use(Struct(struct cryptkeyarg))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(key_decrypt_2_svc), - // skipping because function pointer args: key_gen_2 - //Pointer(Use(TypeDef(des_block, Use(Union(union des_block))))) key_gen_2_svc(Pointer(BuiltIn(void)), Pointer(Use(Struct(struct svc_req)))); - (void *)(key_gen_2_svc), - // skipping because function pointer args: key_getcred_2 - //Pointer(Use(TypeDef(getcredres, Use(Struct(struct getcredres))))) key_getcred_2_svc(Pointer(Use(TypeDef(netnamestr, Pointer(BuiltIn(char))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(key_getcred_2_svc), - // skipping because function pointer args: key_encrypt_pk_2 - //Pointer(Use(TypeDef(cryptkeyres, Use(Struct(struct cryptkeyres))))) key_encrypt_pk_2_svc(Pointer(Use(TypeDef(cryptkeyarg2, Use(Struct(struct cryptkeyarg2))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(key_encrypt_pk_2_svc), - // skipping because function pointer args: key_decrypt_pk_2 - //Pointer(Use(TypeDef(cryptkeyres, Use(Struct(struct cryptkeyres))))) key_decrypt_pk_2_svc(Pointer(Use(TypeDef(cryptkeyarg2, Use(Struct(struct cryptkeyarg2))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(key_decrypt_pk_2_svc), - // skipping because function pointer args: key_net_put_2 - //Pointer(Use(TypeDef(keystatus, Use(Enum(enum keystatus))))) key_net_put_2_svc(Pointer(Use(TypeDef(key_netstarg, Use(Struct(struct key_netstarg))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(key_net_put_2_svc), - // skipping because function pointer args: key_net_get_2 - //Pointer(Use(TypeDef(key_netstres, Use(Struct(struct key_netstres))))) key_net_get_2_svc(Pointer(BuiltIn(void)), Pointer(Use(Struct(struct svc_req)))); - (void *)(key_net_get_2_svc), - // skipping because function pointer args: key_get_conv_2 - //Pointer(Use(TypeDef(cryptkeyres, Use(Struct(struct cryptkeyres))))) key_get_conv_2_svc(Pointer(BuiltIn(char)), Pointer(Use(Struct(struct svc_req)))); - (void *)(key_get_conv_2_svc), - // skipping because function pointer args: key_prog_2_freeresult - // skipping because function pointer args: xdr_keystatus - // skipping because function pointer args: xdr_keybuf - // skipping because function pointer args: xdr_netnamestr - // skipping because function pointer args: xdr_cryptkeyarg - // skipping because function pointer args: xdr_cryptkeyarg2 - // skipping because function pointer args: xdr_cryptkeyres - // skipping because function pointer args: xdr_unixcred - // skipping because function pointer args: xdr_getcredres - // skipping because function pointer args: xdr_key_netstarg - // skipping because function pointer args: xdr_key_netstres - // skipping because function pointer args: xdr_utmparr - // skipping because function pointer args: xdr_utmpidlearr - // skipping because function pointer args: rusersproc_num_3 - //Pointer(BuiltIn(int)) rusersproc_num_3_svc(Pointer(BuiltIn(void)), Pointer(Use(Struct(struct svc_req)))); - (void *)(rusersproc_num_3_svc), - // skipping because function pointer args: rusersproc_names_3 - //Pointer(Use(TypeDef(utmp_array, Struct(struct anon_struct_323)))) rusersproc_names_3_svc(Pointer(BuiltIn(void)), Pointer(Use(Struct(struct svc_req)))); - (void *)(rusersproc_names_3_svc), - // skipping because function pointer args: rusersproc_allnames_3 - //Pointer(Use(TypeDef(utmp_array, Struct(struct anon_struct_323)))) rusersproc_allnames_3_svc(Pointer(BuiltIn(void)), Pointer(Use(Struct(struct svc_req)))); - (void *)(rusersproc_allnames_3_svc), - // skipping because function pointer args: rusersprog_3_freeresult - // skipping because function pointer args: xdr_rusers_utmp - // skipping because function pointer args: xdr_utmp_array - //BuiltIn(int) yp_bind(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(yp_bind), - //BuiltIn(void) yp_unbind(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(yp_unbind), - //BuiltIn(int) yp_get_default_domain(Pointer(Pointer(BuiltIn(char)))); - (void *)(yp_get_default_domain), - //BuiltIn(int) yp_match(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), Attributed(const , BuiltIn(int)), Pointer(Pointer(BuiltIn(char))), Pointer(BuiltIn(int))); - (void *)(yp_match), - //BuiltIn(int) yp_first(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), Pointer(Pointer(BuiltIn(char))), Pointer(BuiltIn(int)), Pointer(Pointer(BuiltIn(char))), Pointer(BuiltIn(int))); - (void *)(yp_first), - //BuiltIn(int) yp_next(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), Attributed(const , BuiltIn(int)), Pointer(Pointer(BuiltIn(char))), Pointer(BuiltIn(int)), Pointer(Pointer(BuiltIn(char))), Pointer(BuiltIn(int))); - (void *)(yp_next), - //BuiltIn(int) yp_master(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), Pointer(Pointer(BuiltIn(char)))); - (void *)(yp_master), - //BuiltIn(int) yp_order(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(unsigned , BuiltIn(int)))); - (void *)(yp_order), - //BuiltIn(int) yp_all(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , Use(Struct(struct ypall_callback))))); - (void *)(yp_all), - //Pointer(Attributed(const , BuiltIn(char))) yperr_string(Attributed(const , BuiltIn(int))); - (void *)(yperr_string), - //Pointer(Attributed(const , BuiltIn(char))) ypbinderr_string(Attributed(const , BuiltIn(int))); - (void *)(ypbinderr_string), - //BuiltIn(int) ypprot_err(Attributed(const , BuiltIn(int))); - (void *)(ypprot_err), - //BuiltIn(int) yp_update(Pointer(BuiltIn(char)), Pointer(BuiltIn(char)), Attributed(unsigned , BuiltIn(int)), Pointer(BuiltIn(char)), BuiltIn(int), Pointer(BuiltIn(char)), BuiltIn(int)); - (void *)(yp_update), - //BuiltIn(int) __yp_check(Pointer(Pointer(BuiltIn(char)))); - (void *)(__yp_check), - // skipping because function pointer args: rexproc_start_1 - //Pointer(Use(TypeDef(rex_result, Use(Struct(struct rex_result))))) rexproc_start_1_svc(Pointer(Use(TypeDef(rex_start, Use(Struct(struct rex_start))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(rexproc_start_1_svc), - // skipping because function pointer args: rexproc_wait_1 - //Pointer(Use(TypeDef(rex_result, Use(Struct(struct rex_result))))) rexproc_wait_1_svc(Pointer(BuiltIn(void)), Pointer(Use(Struct(struct svc_req)))); - (void *)(rexproc_wait_1_svc), - // skipping because function pointer args: rexproc_modes_1 - //Pointer(BuiltIn(void)) rexproc_modes_1_svc(Pointer(Use(TypeDef(rex_ttymode, Use(Struct(struct rex_ttymode))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(rexproc_modes_1_svc), - // skipping because function pointer args: rexproc_winch_1 - //Pointer(BuiltIn(void)) rexproc_winch_1_svc(Pointer(Use(TypeDef(rex_ttysize, Use(Struct(struct rex_ttysize))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(rexproc_winch_1_svc), - // skipping because function pointer args: rexproc_signal_1 - //Pointer(BuiltIn(void)) rexproc_signal_1_svc(Pointer(BuiltIn(int)), Pointer(Use(Struct(struct svc_req)))); - (void *)(rexproc_signal_1_svc), - // skipping because function pointer args: rexprog_1_freeresult - // skipping because function pointer args: xdr_rexstring - // skipping because function pointer args: xdr_rex_start - // skipping because function pointer args: xdr_rex_result - // skipping because function pointer args: xdr_sgttyb - // skipping because function pointer args: xdr_tchars - // skipping because function pointer args: xdr_ltchars - // skipping because function pointer args: xdr_rex_ttysize - // skipping because function pointer args: xdr_rex_ttymode - // skipping because function pointer args: mountproc_null_1 - //Pointer(BuiltIn(void)) mountproc_null_1_svc(Pointer(BuiltIn(void)), Pointer(Use(Struct(struct svc_req)))); - (void *)(mountproc_null_1_svc), - // skipping because function pointer args: mountproc_mnt_1 - //Pointer(Use(TypeDef(fhstatus, Use(Struct(struct fhstatus))))) mountproc_mnt_1_svc(Pointer(Use(TypeDef(dirpath, Pointer(BuiltIn(char))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(mountproc_mnt_1_svc), - // skipping because function pointer args: mountproc_dump_1 - //Pointer(Use(TypeDef(mountlist, Pointer(Use(Struct(struct mountbody)))))) mountproc_dump_1_svc(Pointer(BuiltIn(void)), Pointer(Use(Struct(struct svc_req)))); - (void *)(mountproc_dump_1_svc), - // skipping because function pointer args: mountproc_umnt_1 - //Pointer(BuiltIn(void)) mountproc_umnt_1_svc(Pointer(Use(TypeDef(dirpath, Pointer(BuiltIn(char))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(mountproc_umnt_1_svc), - // skipping because function pointer args: mountproc_umntall_1 - //Pointer(BuiltIn(void)) mountproc_umntall_1_svc(Pointer(BuiltIn(void)), Pointer(Use(Struct(struct svc_req)))); - (void *)(mountproc_umntall_1_svc), - // skipping because function pointer args: mountproc_export_1 - //Pointer(Use(TypeDef(exports, Pointer(Use(Struct(struct exportnode)))))) mountproc_export_1_svc(Pointer(BuiltIn(void)), Pointer(Use(Struct(struct svc_req)))); - (void *)(mountproc_export_1_svc), - // skipping because function pointer args: mountproc_exportall_1 - //Pointer(Use(TypeDef(exports, Pointer(Use(Struct(struct exportnode)))))) mountproc_exportall_1_svc(Pointer(BuiltIn(void)), Pointer(Use(Struct(struct svc_req)))); - (void *)(mountproc_exportall_1_svc), - // skipping because function pointer args: mountprog_1_freeresult - // skipping because function pointer args: xdr_fhandle - // skipping because function pointer args: xdr_fhstatus - // skipping because function pointer args: xdr_dirpath - // skipping because function pointer args: xdr_name - // skipping because function pointer args: xdr_mountlist - // skipping because function pointer args: xdr_mountbody - // skipping because function pointer args: xdr_groups - // skipping because function pointer args: xdr_groupnode - // skipping because function pointer args: xdr_exports - // skipping because function pointer args: xdr_exportnode - // skipping because function pointer args: bootparamproc_whoami_1 - //Pointer(Use(TypeDef(bp_whoami_res, Use(Struct(struct bp_whoami_res))))) bootparamproc_whoami_1_svc(Pointer(Use(TypeDef(bp_whoami_arg, Use(Struct(struct bp_whoami_arg))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(bootparamproc_whoami_1_svc), - // skipping because function pointer args: bootparamproc_getfile_1 - //Pointer(Use(TypeDef(bp_getfile_res, Use(Struct(struct bp_getfile_res))))) bootparamproc_getfile_1_svc(Pointer(Use(TypeDef(bp_getfile_arg, Use(Struct(struct bp_getfile_arg))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(bootparamproc_getfile_1_svc), - // skipping because function pointer args: bootparamprog_1_freeresult - // skipping because function pointer args: xdr_bp_machine_name_t - // skipping because function pointer args: xdr_bp_path_t - // skipping because function pointer args: xdr_bp_fileid_t - // skipping because function pointer args: xdr_ip_addr_t - // skipping because function pointer args: xdr_bp_address - // skipping because function pointer args: xdr_bp_whoami_arg - // skipping because function pointer args: xdr_bp_whoami_res - // skipping because function pointer args: xdr_bp_getfile_arg - // skipping because function pointer args: xdr_bp_getfile_res - // skipping because function pointer args: xdr_yp_buf - // skipping because function pointer args: xdr_ypupdate_args - // skipping because function pointer args: xdr_ypdelete_args - // skipping because function pointer args: ypu_change_1 - //Pointer(Use(TypeDef(u_int, Use(TypeDef(__u_int, Attributed(unsigned , BuiltIn(int))))))) ypu_change_1_svc(Pointer(Use(TypeDef(ypupdate_args, Use(Struct(struct ypupdate_args))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(ypu_change_1_svc), - // skipping because function pointer args: ypu_insert_1 - //Pointer(Use(TypeDef(u_int, Use(TypeDef(__u_int, Attributed(unsigned , BuiltIn(int))))))) ypu_insert_1_svc(Pointer(Use(TypeDef(ypupdate_args, Use(Struct(struct ypupdate_args))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(ypu_insert_1_svc), - // skipping because function pointer args: ypu_delete_1 - //Pointer(Use(TypeDef(u_int, Use(TypeDef(__u_int, Attributed(unsigned , BuiltIn(int))))))) ypu_delete_1_svc(Pointer(Use(TypeDef(ypdelete_args, Use(Struct(struct ypdelete_args))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(ypu_delete_1_svc), - // skipping because function pointer args: ypu_store_1 - //Pointer(Use(TypeDef(u_int, Use(TypeDef(__u_int, Attributed(unsigned , BuiltIn(int))))))) ypu_store_1_svc(Pointer(Use(TypeDef(ypupdate_args, Use(Struct(struct ypupdate_args))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(ypu_store_1_svc), - // skipping because function pointer args: rstatproc_stats_3 - //Pointer(Use(TypeDef(statstime, Use(Struct(struct statstime))))) rstatproc_stats_3_svc(Pointer(BuiltIn(void)), Pointer(Use(Struct(struct svc_req)))); - (void *)(rstatproc_stats_3_svc), - // skipping because function pointer args: rstatproc_havedisk_3 - //Pointer(Use(TypeDef(u_int, Use(TypeDef(__u_int, Attributed(unsigned , BuiltIn(int))))))) rstatproc_havedisk_3_svc(Pointer(BuiltIn(void)), Pointer(Use(Struct(struct svc_req)))); - (void *)(rstatproc_havedisk_3_svc), - // skipping because function pointer args: rstatprog_3_freeresult - // skipping because function pointer args: rstatproc_stats_2 - //Pointer(Use(TypeDef(statsswtch, Use(Struct(struct statsswtch))))) rstatproc_stats_2_svc(Pointer(BuiltIn(void)), Pointer(Use(Struct(struct svc_req)))); - (void *)(rstatproc_stats_2_svc), - // skipping because function pointer args: rstatproc_havedisk_2 - //Pointer(Use(TypeDef(u_int, Use(TypeDef(__u_int, Attributed(unsigned , BuiltIn(int))))))) rstatproc_havedisk_2_svc(Pointer(BuiltIn(void)), Pointer(Use(Struct(struct svc_req)))); - (void *)(rstatproc_havedisk_2_svc), - // skipping because function pointer args: rstatprog_2_freeresult - // skipping because function pointer args: rstatproc_stats_1 - //Pointer(Use(TypeDef(stats, Use(Struct(struct stats))))) rstatproc_stats_1_svc(Pointer(BuiltIn(void)), Pointer(Use(Struct(struct svc_req)))); - (void *)(rstatproc_stats_1_svc), - // skipping because function pointer args: rstatproc_havedisk_1 - //Pointer(Use(TypeDef(u_int, Use(TypeDef(__u_int, Attributed(unsigned , BuiltIn(int))))))) rstatproc_havedisk_1_svc(Pointer(BuiltIn(void)), Pointer(Use(Struct(struct svc_req)))); - (void *)(rstatproc_havedisk_1_svc), - // skipping because function pointer args: rstatprog_1_freeresult - // skipping because function pointer args: xdr_rstat_timeval - // skipping because function pointer args: xdr_statstime - // skipping because function pointer args: xdr_statsswtch - // skipping because function pointer args: xdr_stats - // skipping because function pointer args: rquotaproc_getquota_1 - //Pointer(Use(TypeDef(getquota_rslt, Use(Struct(struct getquota_rslt))))) rquotaproc_getquota_1_svc(Pointer(Use(TypeDef(getquota_args, Use(Struct(struct getquota_args))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(rquotaproc_getquota_1_svc), - // skipping because function pointer args: rquotaproc_getactivequota_1 - //Pointer(Use(TypeDef(getquota_rslt, Use(Struct(struct getquota_rslt))))) rquotaproc_getactivequota_1_svc(Pointer(Use(TypeDef(getquota_args, Use(Struct(struct getquota_args))))), Pointer(Use(Struct(struct svc_req)))); - (void *)(rquotaproc_getactivequota_1_svc), - // skipping because function pointer args: rquotaprog_1_freeresult - // skipping because function pointer args: xdr_getquota_args - // skipping because function pointer args: xdr_rquota - // skipping because function pointer args: xdr_gqr_status - // skipping because function pointer args: xdr_getquota_rslt - //BuiltIn(int) __nss_configure_lookup(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(__nss_configure_lookup), - //Pointer(BuiltIn(void)) malloc(Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(malloc), - //Pointer(BuiltIn(void)) calloc(Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(calloc), - //Pointer(BuiltIn(void)) realloc(Pointer(BuiltIn(void)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(realloc), - //BuiltIn(void) free(Pointer(BuiltIn(void))); - (void *)(free), - //Pointer(BuiltIn(void)) memalign(Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(memalign), - //Pointer(BuiltIn(void)) valloc(Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(valloc), - //Pointer(BuiltIn(void)) pvalloc(Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(pvalloc), - //Pointer(BuiltIn(void)) __default_morecore(Use(TypeDef(ptrdiff_t, BuiltIn(long)))); - (void *)(__default_morecore), - //Use(Struct(struct mallinfo)) mallinfo(); - (void *)(mallinfo), - //BuiltIn(int) mallopt(BuiltIn(int), BuiltIn(int)); - (void *)(mallopt), - //BuiltIn(int) malloc_trim(Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(malloc_trim), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) malloc_usable_size(Pointer(BuiltIn(void))); - (void *)(malloc_usable_size), - //BuiltIn(int) malloc_info(BuiltIn(int), Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(malloc_info), - //BuiltIn(void) __malloc_check_init(); -// (void *)(__malloc_check_init), - //BuiltIn(int) clock_adjtime(Use(TypeDef(__clockid_t, BuiltIn(int))), Pointer(Use(Struct(struct timex)))); - (void *)(clock_adjtime), - //Use(TypeDef(clock_t, Use(TypeDef(__clock_t, BuiltIn(long))))) clock(); - (void *)(clock), - //Use(TypeDef(time_t, Use(TypeDef(__time_t, BuiltIn(long))))) time(Pointer(Use(TypeDef(time_t, Use(TypeDef(__time_t, BuiltIn(long))))))); - (void *)(time), - //BuiltIn(double) difftime(Use(TypeDef(time_t, Use(TypeDef(__time_t, BuiltIn(long))))), Use(TypeDef(time_t, Use(TypeDef(__time_t, BuiltIn(long)))))); - (void *)(difftime), - //Use(TypeDef(time_t, Use(TypeDef(__time_t, BuiltIn(long))))) mktime(Pointer(Use(Struct(struct tm)))); - (void *)(mktime), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) strftime(Pointer(restrict BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Attributed(const , Use(Struct(struct tm))))); - (void *)(strftime), - //Pointer(BuiltIn(char)) strptime(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(Use(Struct(struct tm)))); - (void *)(strptime), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) strftime_l(Pointer(restrict BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Attributed(const , Use(Struct(struct tm)))), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(strftime_l), - //Pointer(BuiltIn(char)) strptime_l(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(Use(Struct(struct tm))), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(strptime_l), - //Pointer(Use(Struct(struct tm))) gmtime(Pointer(Attributed(const , Use(TypeDef(time_t, Use(TypeDef(__time_t, BuiltIn(long)))))))); - (void *)(gmtime), - //Pointer(Use(Struct(struct tm))) localtime(Pointer(Attributed(const , Use(TypeDef(time_t, Use(TypeDef(__time_t, BuiltIn(long)))))))); - (void *)(localtime), - //Pointer(Use(Struct(struct tm))) gmtime_r(Pointer(restrict Attributed(const , Use(TypeDef(time_t, Use(TypeDef(__time_t, BuiltIn(long))))))), Pointer(restrict Use(Struct(struct tm)))); - (void *)(gmtime_r), - //Pointer(Use(Struct(struct tm))) localtime_r(Pointer(restrict Attributed(const , Use(TypeDef(time_t, Use(TypeDef(__time_t, BuiltIn(long))))))), Pointer(restrict Use(Struct(struct tm)))); - (void *)(localtime_r), - //Pointer(BuiltIn(char)) asctime(Pointer(Attributed(const , Use(Struct(struct tm))))); - (void *)(asctime), - //Pointer(BuiltIn(char)) ctime(Pointer(Attributed(const , Use(TypeDef(time_t, Use(TypeDef(__time_t, BuiltIn(long)))))))); - (void *)(ctime), - //Pointer(BuiltIn(char)) asctime_r(Pointer(restrict Attributed(const , Use(Struct(struct tm)))), Pointer(restrict BuiltIn(char))); - (void *)(asctime_r), - //Pointer(BuiltIn(char)) ctime_r(Pointer(restrict Attributed(const , Use(TypeDef(time_t, Use(TypeDef(__time_t, BuiltIn(long))))))), Pointer(restrict BuiltIn(char))); - (void *)(ctime_r), - //BuiltIn(void) tzset(); - (void *)(tzset), - //BuiltIn(int) stime(Pointer(Attributed(const , Use(TypeDef(time_t, Use(TypeDef(__time_t, BuiltIn(long)))))))); - //(void *)(stime), - //Use(TypeDef(time_t, Use(TypeDef(__time_t, BuiltIn(long))))) timegm(Pointer(Use(Struct(struct tm)))); - (void *)(timegm), - //Use(TypeDef(time_t, Use(TypeDef(__time_t, BuiltIn(long))))) timelocal(Pointer(Use(Struct(struct tm)))); - (void *)(timelocal), - //BuiltIn(int) dysize(BuiltIn(int)); - (void *)(dysize), - //BuiltIn(int) nanosleep(Pointer(Attributed(const , Use(Struct(struct timespec)))), Pointer(Use(Struct(struct timespec)))); - (void *)(nanosleep), - //BuiltIn(int) clock_getres(Use(TypeDef(clockid_t, Use(TypeDef(__clockid_t, BuiltIn(int))))), Pointer(Use(Struct(struct timespec)))); - (void *)(clock_getres), - //BuiltIn(int) clock_gettime(Use(TypeDef(clockid_t, Use(TypeDef(__clockid_t, BuiltIn(int))))), Pointer(Use(Struct(struct timespec)))); - (void *)(clock_gettime), - //BuiltIn(int) clock_settime(Use(TypeDef(clockid_t, Use(TypeDef(__clockid_t, BuiltIn(int))))), Pointer(Attributed(const , Use(Struct(struct timespec))))); - (void *)(clock_settime), - //BuiltIn(int) clock_nanosleep(Use(TypeDef(clockid_t, Use(TypeDef(__clockid_t, BuiltIn(int))))), BuiltIn(int), Pointer(Attributed(const , Use(Struct(struct timespec)))), Pointer(Use(Struct(struct timespec)))); - (void *)(clock_nanosleep), - //BuiltIn(int) clock_getcpuclockid(Use(TypeDef(pid_t, Use(TypeDef(__pid_t, BuiltIn(int))))), Pointer(Use(TypeDef(clockid_t, Use(TypeDef(__clockid_t, BuiltIn(int))))))); - (void *)(clock_getcpuclockid), - // skipping because function pointer args: timer_create - //BuiltIn(int) timer_delete(Use(TypeDef(timer_t, Use(TypeDef(__timer_t, Pointer(BuiltIn(void))))))); - (void *)(timer_delete), - //BuiltIn(int) timer_settime(Use(TypeDef(timer_t, Use(TypeDef(__timer_t, Pointer(BuiltIn(void)))))), BuiltIn(int), Pointer(restrict Attributed(const , Use(Struct(struct itimerspec)))), Pointer(restrict Use(Struct(struct itimerspec)))); - (void *)(timer_settime), - //BuiltIn(int) timer_gettime(Use(TypeDef(timer_t, Use(TypeDef(__timer_t, Pointer(BuiltIn(void)))))), Pointer(Use(Struct(struct itimerspec)))); - (void *)(timer_gettime), - //BuiltIn(int) timer_getoverrun(Use(TypeDef(timer_t, Use(TypeDef(__timer_t, Pointer(BuiltIn(void))))))); - (void *)(timer_getoverrun), - //BuiltIn(int) timespec_get(Pointer(Use(Struct(struct timespec))), BuiltIn(int)); - (void *)(timespec_get), - //Pointer(Use(Struct(struct tm))) getdate(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(getdate), - //BuiltIn(int) getdate_r(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Use(Struct(struct tm)))); - (void *)(getdate_r), - //BuiltIn(int) timerfd_create(Use(TypeDef(clockid_t, Use(TypeDef(__clockid_t, BuiltIn(int))))), BuiltIn(int)); - (void *)(timerfd_create), - //BuiltIn(int) timerfd_settime(BuiltIn(int), BuiltIn(int), Pointer(Attributed(const , Use(Struct(struct itimerspec)))), Pointer(Use(Struct(struct itimerspec)))); - (void *)(timerfd_settime), - //BuiltIn(int) timerfd_gettime(BuiltIn(int), Pointer(Use(Struct(struct itimerspec)))); - (void *)(timerfd_gettime), - //BuiltIn(int) ftime(Pointer(Use(Struct(struct timeb)))); - (void *)(ftime), - //BuiltIn(int) uname(Pointer(Use(Struct(struct utsname)))); - (void *)(uname), - // skipping because varargs function: ioctl - //BuiltIn(int) sysinfo(Pointer(Use(Struct(struct sysinfo)))); - (void *)(sysinfo), - //BuiltIn(int) get_nprocs_conf(); - (void *)(get_nprocs_conf), - //BuiltIn(int) get_nprocs(); - (void *)(get_nprocs), - //BuiltIn(long) get_phys_pages(); - (void *)(get_phys_pages), - //BuiltIn(long) get_avphys_pages(); - (void *)(get_avphys_pages), - //BuiltIn(int) poll(Pointer(Use(Struct(struct pollfd))), Use(TypeDef(nfds_t, Attributed(unsigned , BuiltIn(long)))), BuiltIn(int)); - (void *)(poll), - //BuiltIn(int) ppoll(Pointer(Use(Struct(struct pollfd))), Use(TypeDef(nfds_t, Attributed(unsigned , BuiltIn(long)))), Pointer(Attributed(const , Use(Struct(struct timespec)))), Pointer(Attributed(const , Use(TypeDef(__sigset_t, Struct(struct anon_struct_23)))))); - (void *)(ppoll), - //Use(TypeDef(key_t, Use(TypeDef(__key_t, BuiltIn(int))))) ftok(Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int)); - (void *)(ftok), - //BuiltIn(int) msgctl(BuiltIn(int), BuiltIn(int), Pointer(Use(Struct(struct msqid_ds)))); - (void *)(msgctl), - //BuiltIn(int) msgget(Use(TypeDef(key_t, Use(TypeDef(__key_t, BuiltIn(int))))), BuiltIn(int)); - (void *)(msgget), - //Use(TypeDef(ssize_t, Use(TypeDef(__ssize_t, BuiltIn(long))))) msgrcv(BuiltIn(int), Pointer(BuiltIn(void)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), BuiltIn(long), BuiltIn(int)); - (void *)(msgrcv), - //BuiltIn(int) msgsnd(BuiltIn(int), Pointer(Attributed(const , BuiltIn(void))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), BuiltIn(int)); - (void *)(msgsnd), - //BuiltIn(int) stat(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Use(Struct(struct stat)))); - (void *)(stat), - //BuiltIn(int) fstat(BuiltIn(int), Pointer(Use(Struct(struct stat)))); - (void *)(fstat), - //BuiltIn(int) stat64(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Use(Struct(struct stat64)))); - (void *)(stat64), - //BuiltIn(int) fstat64(BuiltIn(int), Pointer(Use(Struct(struct stat64)))); - (void *)(fstat64), - //BuiltIn(int) fstatat(BuiltIn(int), Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Use(Struct(struct stat))), BuiltIn(int)); - (void *)(fstatat), - //BuiltIn(int) fstatat64(BuiltIn(int), Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Use(Struct(struct stat64))), BuiltIn(int)); - (void *)(fstatat64), - //BuiltIn(int) lstat(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Use(Struct(struct stat)))); - (void *)(lstat), - //BuiltIn(int) lstat64(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Use(Struct(struct stat64)))); - (void *)(lstat64), - //BuiltIn(int) chmod(Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(__mode_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(chmod), - //BuiltIn(int) lchmod(Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(__mode_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(lchmod), - //BuiltIn(int) fchmod(BuiltIn(int), Use(TypeDef(__mode_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(fchmod), - //BuiltIn(int) fchmodat(BuiltIn(int), Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(__mode_t, Attributed(unsigned , BuiltIn(int)))), BuiltIn(int)); - (void *)(fchmodat), - //Use(TypeDef(__mode_t, Attributed(unsigned , BuiltIn(int)))) umask(Use(TypeDef(__mode_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(umask), - //Use(TypeDef(__mode_t, Attributed(unsigned , BuiltIn(int)))) getumask(); - (void *)(getumask), - //BuiltIn(int) mkdir(Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(__mode_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(mkdir), - //BuiltIn(int) mkdirat(BuiltIn(int), Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(__mode_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(mkdirat), - //BuiltIn(int) mknod(Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(__mode_t, Attributed(unsigned , BuiltIn(int)))), Use(TypeDef(__dev_t, Attributed(unsigned , BuiltIn(long))))); - (void *)(mknod), - //BuiltIn(int) mknodat(BuiltIn(int), Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(__mode_t, Attributed(unsigned , BuiltIn(int)))), Use(TypeDef(__dev_t, Attributed(unsigned , BuiltIn(long))))); - (void *)(mknodat), - //BuiltIn(int) mkfifo(Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(__mode_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(mkfifo), - //BuiltIn(int) mkfifoat(BuiltIn(int), Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(__mode_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(mkfifoat), - //BuiltIn(int) utimensat(BuiltIn(int), Pointer(Attributed(const , BuiltIn(char))), Array(Attributed(const , Use(Struct(struct timespec)))), BuiltIn(int)); - (void *)(utimensat), - //BuiltIn(int) futimens(BuiltIn(int), Array(Attributed(const , Use(Struct(struct timespec))))); - (void *)(futimens), - //BuiltIn(int) __fxstat(BuiltIn(int), BuiltIn(int), Pointer(Use(Struct(struct stat)))); - (void *)(__fxstat), - //BuiltIn(int) __xstat(BuiltIn(int), Pointer(Attributed(const , BuiltIn(char))), Pointer(Use(Struct(struct stat)))); - (void *)(__xstat), - //BuiltIn(int) __lxstat(BuiltIn(int), Pointer(Attributed(const , BuiltIn(char))), Pointer(Use(Struct(struct stat)))); - (void *)(__lxstat), - //BuiltIn(int) __fxstatat(BuiltIn(int), BuiltIn(int), Pointer(Attributed(const , BuiltIn(char))), Pointer(Use(Struct(struct stat))), BuiltIn(int)); - (void *)(__fxstatat), - //BuiltIn(int) __fxstat64(BuiltIn(int), BuiltIn(int), Pointer(Use(Struct(struct stat64)))); - (void *)(__fxstat64), - //BuiltIn(int) __xstat64(BuiltIn(int), Pointer(Attributed(const , BuiltIn(char))), Pointer(Use(Struct(struct stat64)))); - (void *)(__xstat64), - //BuiltIn(int) __lxstat64(BuiltIn(int), Pointer(Attributed(const , BuiltIn(char))), Pointer(Use(Struct(struct stat64)))); - (void *)(__lxstat64), - //BuiltIn(int) __fxstatat64(BuiltIn(int), BuiltIn(int), Pointer(Attributed(const , BuiltIn(char))), Pointer(Use(Struct(struct stat64))), BuiltIn(int)); - (void *)(__fxstatat64), - //BuiltIn(int) __xmknod(BuiltIn(int), Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(__mode_t, Attributed(unsigned , BuiltIn(int)))), Pointer(Use(TypeDef(__dev_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(__xmknod), - //BuiltIn(int) __xmknodat(BuiltIn(int), BuiltIn(int), Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(__mode_t, Attributed(unsigned , BuiltIn(int)))), Pointer(Use(TypeDef(__dev_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(__xmknodat), - //BuiltIn(int) klogctl(BuiltIn(int), Pointer(BuiltIn(char)), BuiltIn(int)); - (void *)(klogctl), - //Use(TypeDef(speed_t, Attributed(unsigned , BuiltIn(int)))) cfgetospeed(Pointer(Attributed(const , Use(Struct(struct termios))))); - (void *)(cfgetospeed), - //Use(TypeDef(speed_t, Attributed(unsigned , BuiltIn(int)))) cfgetispeed(Pointer(Attributed(const , Use(Struct(struct termios))))); - (void *)(cfgetispeed), - //BuiltIn(int) cfsetospeed(Pointer(Use(Struct(struct termios))), Use(TypeDef(speed_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(cfsetospeed), - //BuiltIn(int) cfsetispeed(Pointer(Use(Struct(struct termios))), Use(TypeDef(speed_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(cfsetispeed), - //BuiltIn(int) cfsetspeed(Pointer(Use(Struct(struct termios))), Use(TypeDef(speed_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(cfsetspeed), - //BuiltIn(int) tcgetattr(BuiltIn(int), Pointer(Use(Struct(struct termios)))); - (void *)(tcgetattr), - //BuiltIn(int) tcsetattr(BuiltIn(int), BuiltIn(int), Pointer(Attributed(const , Use(Struct(struct termios))))); - (void *)(tcsetattr), - //BuiltIn(void) cfmakeraw(Pointer(Use(Struct(struct termios)))); - (void *)(cfmakeraw), - //BuiltIn(int) tcsendbreak(BuiltIn(int), BuiltIn(int)); - (void *)(tcsendbreak), - //BuiltIn(int) tcdrain(BuiltIn(int)); - (void *)(tcdrain), - //BuiltIn(int) tcflush(BuiltIn(int), BuiltIn(int)); - (void *)(tcflush), - //BuiltIn(int) tcflow(BuiltIn(int), BuiltIn(int)); - (void *)(tcflow), - //Use(TypeDef(__pid_t, BuiltIn(int))) tcgetsid(BuiltIn(int)); - (void *)(tcgetsid), - //Use(TypeDef(clock_t, Use(TypeDef(__clock_t, BuiltIn(long))))) times(Pointer(Use(Struct(struct tms)))); - (void *)(times), - //BuiltIn(int) eventfd(BuiltIn(int), BuiltIn(int)); - (void *)(eventfd), - //BuiltIn(int) eventfd_read(BuiltIn(int), Pointer(Use(TypeDef(eventfd_t, Use(TypeDef(uint64_t, Attributed(unsigned , BuiltIn(long)))))))); - (void *)(eventfd_read), - //BuiltIn(int) eventfd_write(BuiltIn(int), Use(TypeDef(eventfd_t, Use(TypeDef(uint64_t, Attributed(unsigned , BuiltIn(long))))))); - (void *)(eventfd_write), - //BuiltIn(int) setxattr(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(void))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), BuiltIn(int)); - (void *)(setxattr), - //BuiltIn(int) lsetxattr(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(void))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), BuiltIn(int)); - (void *)(lsetxattr), - //BuiltIn(int) fsetxattr(BuiltIn(int), Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(void))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), BuiltIn(int)); - (void *)(fsetxattr), - //Use(TypeDef(ssize_t, Use(TypeDef(__ssize_t, BuiltIn(long))))) getxattr(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), Pointer(BuiltIn(void)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(getxattr), - //Use(TypeDef(ssize_t, Use(TypeDef(__ssize_t, BuiltIn(long))))) lgetxattr(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), Pointer(BuiltIn(void)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(lgetxattr), - //Use(TypeDef(ssize_t, Use(TypeDef(__ssize_t, BuiltIn(long))))) fgetxattr(BuiltIn(int), Pointer(Attributed(const , BuiltIn(char))), Pointer(BuiltIn(void)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(fgetxattr), - //Use(TypeDef(ssize_t, Use(TypeDef(__ssize_t, BuiltIn(long))))) listxattr(Pointer(Attributed(const , BuiltIn(char))), Pointer(BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(listxattr), - //Use(TypeDef(ssize_t, Use(TypeDef(__ssize_t, BuiltIn(long))))) llistxattr(Pointer(Attributed(const , BuiltIn(char))), Pointer(BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(llistxattr), - //Use(TypeDef(ssize_t, Use(TypeDef(__ssize_t, BuiltIn(long))))) flistxattr(BuiltIn(int), Pointer(BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(flistxattr), - //BuiltIn(int) removexattr(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(removexattr), - //BuiltIn(int) lremovexattr(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(lremovexattr), - //BuiltIn(int) fremovexattr(BuiltIn(int), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(fremovexattr), - //BuiltIn(int) fanotify_init(Attributed(unsigned , BuiltIn(int)), Attributed(unsigned , BuiltIn(int))); - (void *)(fanotify_init), - //BuiltIn(int) fanotify_mark(BuiltIn(int), Attributed(unsigned , BuiltIn(int)), Use(TypeDef(uint64_t, Attributed(unsigned , BuiltIn(long)))), BuiltIn(int), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(fanotify_mark), - //BuiltIn(int) statvfs(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Use(Struct(struct statvfs)))); - (void *)(statvfs), - //BuiltIn(int) statvfs64(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Use(Struct(struct statvfs64)))); - (void *)(statvfs64), - //BuiltIn(int) fstatvfs(BuiltIn(int), Pointer(Use(Struct(struct statvfs)))); - (void *)(fstatvfs), - //BuiltIn(int) fstatvfs64(BuiltIn(int), Pointer(Use(Struct(struct statvfs64)))); - (void *)(fstatvfs64), - //BuiltIn(int) __getpagesize(); - (void *)(__getpagesize), - //BuiltIn(int) shmctl(BuiltIn(int), BuiltIn(int), Pointer(Use(Struct(struct shmid_ds)))); - (void *)(shmctl), - //BuiltIn(int) shmget(Use(TypeDef(key_t, Use(TypeDef(__key_t, BuiltIn(int))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), BuiltIn(int)); - (void *)(shmget), - //Pointer(BuiltIn(void)) shmat(BuiltIn(int), Pointer(Attributed(const , BuiltIn(void))), BuiltIn(int)); - (void *)(shmat), - //BuiltIn(int) shmdt(Pointer(Attributed(const , BuiltIn(void)))); - (void *)(shmdt), - //BuiltIn(int) prlimit(Use(TypeDef(__pid_t, BuiltIn(int))), Use(Enum(enum __rlimit_resource)), Pointer(Attributed(const , Use(Struct(struct rlimit)))), Pointer(Use(Struct(struct rlimit)))); - (void *)(prlimit), - //BuiltIn(int) prlimit64(Use(TypeDef(__pid_t, BuiltIn(int))), Use(Enum(enum __rlimit_resource)), Pointer(Attributed(const , Use(Struct(struct rlimit64)))), Pointer(Use(Struct(struct rlimit64)))); - (void *)(prlimit64), - //BuiltIn(int) getrlimit(Use(TypeDef(__rlimit_resource_t, Use(Enum(enum __rlimit_resource)))), Pointer(Use(Struct(struct rlimit)))); - (void *)(getrlimit), - //BuiltIn(int) getrlimit64(Use(TypeDef(__rlimit_resource_t, Use(Enum(enum __rlimit_resource)))), Pointer(Use(Struct(struct rlimit64)))); - (void *)(getrlimit64), - //BuiltIn(int) setrlimit(Use(TypeDef(__rlimit_resource_t, Use(Enum(enum __rlimit_resource)))), Pointer(Attributed(const , Use(Struct(struct rlimit))))); - (void *)(setrlimit), - //BuiltIn(int) setrlimit64(Use(TypeDef(__rlimit_resource_t, Use(Enum(enum __rlimit_resource)))), Pointer(Attributed(const , Use(Struct(struct rlimit64))))); - (void *)(setrlimit64), - //BuiltIn(int) getrusage(Use(TypeDef(__rusage_who_t, Use(Enum(enum __rusage_who)))), Pointer(Use(Struct(struct rusage)))); - (void *)(getrusage), - //BuiltIn(int) getpriority(Use(TypeDef(__priority_which_t, Use(Enum(enum __priority_which)))), Use(TypeDef(id_t, Use(TypeDef(__id_t, Attributed(unsigned , BuiltIn(int))))))); - (void *)(getpriority), - //BuiltIn(int) setpriority(Use(TypeDef(__priority_which_t, Use(Enum(enum __priority_which)))), Use(TypeDef(id_t, Use(TypeDef(__id_t, Attributed(unsigned , BuiltIn(int)))))), BuiltIn(int)); - (void *)(setpriority), - //BuiltIn(void) closelog(); - (void *)(closelog), - //BuiltIn(void) openlog(Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int), BuiltIn(int)); - (void *)(openlog), - //BuiltIn(int) setlogmask(BuiltIn(int)); - (void *)(setlogmask), - // skipping because varargs function: syslog - //BuiltIn(void) vsyslog(BuiltIn(int), Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(__gnuc_va_list, BuiltIn(__builtin_va_list)))); - (void *)(vsyslog), - //BuiltIn(int) epoll_create(BuiltIn(int)); - (void *)(epoll_create), - //BuiltIn(int) epoll_create1(BuiltIn(int)); - (void *)(epoll_create1), - //BuiltIn(int) epoll_ctl(BuiltIn(int), BuiltIn(int), BuiltIn(int), Pointer(Use(Struct(struct epoll_event)))); - (void *)(epoll_ctl), - //BuiltIn(int) epoll_wait(BuiltIn(int), Pointer(Use(Struct(struct epoll_event))), BuiltIn(int), BuiltIn(int)); - (void *)(epoll_wait), - //BuiltIn(int) epoll_pwait(BuiltIn(int), Pointer(Use(Struct(struct epoll_event))), BuiltIn(int), BuiltIn(int), Pointer(Attributed(const , Use(TypeDef(__sigset_t, Struct(struct anon_struct_23)))))); - (void *)(epoll_pwait), - //BuiltIn(int) quotactl(BuiltIn(int), Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int), Use(TypeDef(caddr_t, Use(TypeDef(__caddr_t, Pointer(BuiltIn(char))))))); - (void *)(quotactl), - // skipping because varargs function: ptrace -// //BuiltIn(int) isastream(BuiltIn(int)); -// (void *)(isastream), -// //BuiltIn(int) getmsg(BuiltIn(int), Pointer(restrict Use(Struct(struct strbuf))), Pointer(restrict Use(Struct(struct strbuf))), Pointer(restrict BuiltIn(int))); -// (void *)(getmsg), -// //BuiltIn(int) getpmsg(BuiltIn(int), Pointer(restrict Use(Struct(struct strbuf))), Pointer(restrict Use(Struct(struct strbuf))), Pointer(restrict BuiltIn(int)), Pointer(restrict BuiltIn(int))); -// (void *)(getpmsg), -// // skipping because varargs function: ioctl -// //BuiltIn(int) putmsg(BuiltIn(int), Pointer(Attributed(const , Use(Struct(struct strbuf)))), Pointer(Attributed(const , Use(Struct(struct strbuf)))), BuiltIn(int)); -// (void *)(putmsg), -// //BuiltIn(int) putpmsg(BuiltIn(int), Pointer(Attributed(const , Use(Struct(struct strbuf)))), Pointer(Attributed(const , Use(Struct(struct strbuf)))), BuiltIn(int), BuiltIn(int)); -// (void *)(putpmsg), - //BuiltIn(int) fattach(BuiltIn(int), Pointer(Attributed(const , BuiltIn(char)))); -// (void *)(fattach), -// //BuiltIn(int) fdetach(Pointer(Attributed(const , BuiltIn(char)))); -// (void *)(fdetach), - //BuiltIn(int) personality(Attributed(unsigned , BuiltIn(long))); - (void *)(personality), - //Pointer(Use(TypeDef(DIR, Use(Struct(struct __dirstream))))) opendir(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(opendir), - //Pointer(Use(TypeDef(DIR, Use(Struct(struct __dirstream))))) fdopendir(BuiltIn(int)); - (void *)(fdopendir), - //BuiltIn(int) closedir(Pointer(Use(TypeDef(DIR, Use(Struct(struct __dirstream)))))); - (void *)(closedir), - //Pointer(Use(Struct(struct dirent))) readdir(Pointer(Use(TypeDef(DIR, Use(Struct(struct __dirstream)))))); - (void *)(readdir), - //Pointer(Use(Struct(struct dirent64))) readdir64(Pointer(Use(TypeDef(DIR, Use(Struct(struct __dirstream)))))); - (void *)(readdir64), - //BuiltIn(int) readdir_r(Pointer(restrict Use(TypeDef(DIR, Use(Struct(struct __dirstream))))), Pointer(restrict Use(Struct(struct dirent))), Pointer(restrict Pointer(Use(Struct(struct dirent))))); - (void *)(readdir_r), - //BuiltIn(int) readdir64_r(Pointer(restrict Use(TypeDef(DIR, Use(Struct(struct __dirstream))))), Pointer(restrict Use(Struct(struct dirent64))), Pointer(restrict Pointer(Use(Struct(struct dirent64))))); - (void *)(readdir64_r), - //BuiltIn(void) rewinddir(Pointer(Use(TypeDef(DIR, Use(Struct(struct __dirstream)))))); - (void *)(rewinddir), - //BuiltIn(void) seekdir(Pointer(Use(TypeDef(DIR, Use(Struct(struct __dirstream))))), BuiltIn(long)); - (void *)(seekdir), - //BuiltIn(long) telldir(Pointer(Use(TypeDef(DIR, Use(Struct(struct __dirstream)))))); - (void *)(telldir), - //BuiltIn(int) dirfd(Pointer(Use(TypeDef(DIR, Use(Struct(struct __dirstream)))))); - (void *)(dirfd), - // skipping because function pointer args: scandir - // skipping because function pointer args: scandir64 - // skipping because function pointer args: scandirat - // skipping because function pointer args: scandirat64 - //BuiltIn(int) alphasort(Pointer(Pointer(Attributed(const , Use(Struct(struct dirent))))), Pointer(Pointer(Attributed(const , Use(Struct(struct dirent)))))); - (void *)(alphasort), - //BuiltIn(int) alphasort64(Pointer(Pointer(Attributed(const , Use(Struct(struct dirent64))))), Pointer(Pointer(Attributed(const , Use(Struct(struct dirent64)))))); - (void *)(alphasort64), - //Use(TypeDef(__ssize_t, BuiltIn(long))) getdirentries(BuiltIn(int), Pointer(restrict BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Use(TypeDef(__off_t, BuiltIn(long))))); - (void *)(getdirentries), - //Use(TypeDef(__ssize_t, BuiltIn(long))) getdirentries64(BuiltIn(int), Pointer(restrict BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Use(TypeDef(__off64_t, BuiltIn(long))))); - (void *)(getdirentries64), - //BuiltIn(int) versionsort(Pointer(Pointer(Attributed(const , Use(Struct(struct dirent))))), Pointer(Pointer(Attributed(const , Use(Struct(struct dirent)))))); - (void *)(versionsort), - //BuiltIn(int) versionsort64(Pointer(Pointer(Attributed(const , Use(Struct(struct dirent64))))), Pointer(Pointer(Attributed(const , Use(Struct(struct dirent64)))))); - (void *)(versionsort64), - //BuiltIn(int) swapon(Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int)); - (void *)(swapon), - //BuiltIn(int) swapoff(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(swapoff), - //BuiltIn(int) vtimes(Pointer(Use(Struct(struct vtimes))), Pointer(Use(Struct(struct vtimes)))); - (void *)(vtimes), - //Use(TypeDef(ssize_t, Use(TypeDef(__ssize_t, BuiltIn(long))))) readahead(BuiltIn(int), Use(TypeDef(__off64_t, BuiltIn(long))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(readahead), - //BuiltIn(int) sync_file_range(BuiltIn(int), Use(TypeDef(__off64_t, BuiltIn(long))), Use(TypeDef(__off64_t, BuiltIn(long))), Attributed(unsigned , BuiltIn(int))); - (void *)(sync_file_range), - //Use(TypeDef(ssize_t, Use(TypeDef(__ssize_t, BuiltIn(long))))) vmsplice(BuiltIn(int), Pointer(Attributed(const , Use(Struct(struct iovec)))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Attributed(unsigned , BuiltIn(int))); - (void *)(vmsplice), - //Use(TypeDef(ssize_t, Use(TypeDef(__ssize_t, BuiltIn(long))))) splice(BuiltIn(int), Pointer(Use(TypeDef(__off64_t, BuiltIn(long)))), BuiltIn(int), Pointer(Use(TypeDef(__off64_t, BuiltIn(long)))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Attributed(unsigned , BuiltIn(int))); - (void *)(splice), - //Use(TypeDef(ssize_t, Use(TypeDef(__ssize_t, BuiltIn(long))))) tee(BuiltIn(int), BuiltIn(int), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Attributed(unsigned , BuiltIn(int))); - (void *)(tee), - //BuiltIn(int) fallocate(BuiltIn(int), BuiltIn(int), Use(TypeDef(__off_t, BuiltIn(long))), Use(TypeDef(__off_t, BuiltIn(long)))); - (void *)(fallocate), - //BuiltIn(int) fallocate64(BuiltIn(int), BuiltIn(int), Use(TypeDef(__off64_t, BuiltIn(long))), Use(TypeDef(__off64_t, BuiltIn(long)))); - (void *)(fallocate64), - //BuiltIn(int) name_to_handle_at(BuiltIn(int), Pointer(Attributed(const , BuiltIn(char))), Pointer(Use(Struct(struct file_handle))), Pointer(BuiltIn(int)), BuiltIn(int)); - (void *)(name_to_handle_at), - //BuiltIn(int) open_by_handle_at(BuiltIn(int), Pointer(Use(Struct(struct file_handle))), BuiltIn(int)); - (void *)(open_by_handle_at), - // skipping because varargs function: fcntl - // skipping because varargs function: open - // skipping because varargs function: open64 - // skipping because varargs function: openat - // skipping because varargs function: openat64 - //BuiltIn(int) creat(Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(mode_t, Use(TypeDef(__mode_t, Attributed(unsigned , BuiltIn(int))))))); - (void *)(creat), - //BuiltIn(int) creat64(Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(mode_t, Use(TypeDef(__mode_t, Attributed(unsigned , BuiltIn(int))))))); - (void *)(creat64), - //BuiltIn(int) posix_fadvise(BuiltIn(int), Use(TypeDef(off_t, Use(TypeDef(__off_t, BuiltIn(long))))), Use(TypeDef(off_t, Use(TypeDef(__off_t, BuiltIn(long))))), BuiltIn(int)); - (void *)(posix_fadvise), - //BuiltIn(int) posix_fadvise64(BuiltIn(int), Use(TypeDef(off64_t, Use(TypeDef(__off64_t, BuiltIn(long))))), Use(TypeDef(off64_t, Use(TypeDef(__off64_t, BuiltIn(long))))), BuiltIn(int)); - (void *)(posix_fadvise64), - //BuiltIn(int) posix_fallocate(BuiltIn(int), Use(TypeDef(off_t, Use(TypeDef(__off_t, BuiltIn(long))))), Use(TypeDef(off_t, Use(TypeDef(__off_t, BuiltIn(long)))))); - (void *)(posix_fallocate), - //BuiltIn(int) posix_fallocate64(BuiltIn(int), Use(TypeDef(off64_t, Use(TypeDef(__off64_t, BuiltIn(long))))), Use(TypeDef(off64_t, Use(TypeDef(__off64_t, BuiltIn(long)))))); - (void *)(posix_fallocate64), - // skipping because varargs function: prctl - //BuiltIn(int) inotify_init(); - (void *)(inotify_init), - //BuiltIn(int) inotify_init1(BuiltIn(int)); - (void *)(inotify_init1), - //BuiltIn(int) inotify_add_watch(BuiltIn(int), Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(uint32_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(inotify_add_watch), - //BuiltIn(int) inotify_rm_watch(BuiltIn(int), BuiltIn(int)); - (void *)(inotify_rm_watch), - //BuiltIn(int) sprofil(Pointer(Use(Struct(struct prof))), BuiltIn(int), Pointer(Use(Struct(struct timeval))), Attributed(unsigned , BuiltIn(int))); - (void *)(sprofil), - //BuiltIn(int) acct(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(acct), - // skipping because varargs function: semctl - //BuiltIn(int) semget(Use(TypeDef(key_t, Use(TypeDef(__key_t, BuiltIn(int))))), BuiltIn(int), BuiltIn(int)); - (void *)(semget), - //BuiltIn(int) semop(BuiltIn(int), Pointer(Use(Struct(struct sembuf))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(semop), - //BuiltIn(int) semtimedop(BuiltIn(int), Pointer(Use(Struct(struct sembuf))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Attributed(const , Use(Struct(struct timespec))))); - (void *)(semtimedop), - //BuiltIn(int) ioperm(Attributed(unsigned , BuiltIn(long)), Attributed(unsigned , BuiltIn(long)), BuiltIn(int)); - (void *)(ioperm), - //BuiltIn(int) iopl(BuiltIn(int)); - (void *)(iopl), - //BuiltIn(int) signalfd(BuiltIn(int), Pointer(Attributed(const , Use(TypeDef(sigset_t, Use(TypeDef(__sigset_t, Struct(struct anon_struct_23))))))), BuiltIn(int)); - (void *)(signalfd), - //BuiltIn(int) reboot(BuiltIn(int)); - (void *)(reboot), - //BuiltIn(int) bdflush(BuiltIn(int), BuiltIn(long)); -// (void *)(bdflush), - //Attributed(unsigned , BuiltIn(long)) getauxval(Attributed(unsigned , BuiltIn(long))); - (void *)(getauxval), - //BuiltIn(int) flock(BuiltIn(int), BuiltIn(int)); - (void *)(flock), - //BuiltIn(int) sysctl(Pointer(BuiltIn(int)), BuiltIn(int), Pointer(BuiltIn(void)), Pointer(Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))), Pointer(BuiltIn(void)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(sysctl), - //Use(TypeDef(__pid_t, BuiltIn(int))) wait(Use(TypeDef(__WAIT_STATUS, Attributed(__attribute__ ( ( __transparent_union__ ) ), Union(union anon_union_22))))); - (void *)(wait), - //Use(TypeDef(__pid_t, BuiltIn(int))) waitpid(Use(TypeDef(__pid_t, BuiltIn(int))), Pointer(BuiltIn(int)), BuiltIn(int)); - (void *)(waitpid), - //BuiltIn(int) waitid(Use(TypeDef(idtype_t, Enum(enum anon_enum_24))), Use(TypeDef(__id_t, Attributed(unsigned , BuiltIn(int)))), Pointer(Use(TypeDef(siginfo_t, Struct(struct anon_struct_172)))), BuiltIn(int)); - (void *)(waitid), - //Use(TypeDef(__pid_t, BuiltIn(int))) wait3(Use(TypeDef(__WAIT_STATUS, Attributed(__attribute__ ( ( __transparent_union__ ) ), Union(union anon_union_22)))), BuiltIn(int), Pointer(Use(Struct(struct rusage)))); - (void *)(wait3), - //Use(TypeDef(__pid_t, BuiltIn(int))) wait4(Use(TypeDef(__pid_t, BuiltIn(int))), Use(TypeDef(__WAIT_STATUS, Attributed(__attribute__ ( ( __transparent_union__ ) ), Union(union anon_union_22)))), BuiltIn(int), Pointer(Use(Struct(struct rusage)))); - (void *)(wait4), - //Pointer(BuiltIn(void)) mmap(Pointer(BuiltIn(void)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), BuiltIn(int), BuiltIn(int), BuiltIn(int), Use(TypeDef(__off_t, BuiltIn(long)))); - (void *)(mmap), - //Pointer(BuiltIn(void)) mmap64(Pointer(BuiltIn(void)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), BuiltIn(int), BuiltIn(int), BuiltIn(int), Use(TypeDef(__off64_t, BuiltIn(long)))); - (void *)(mmap64), - //BuiltIn(int) munmap(Pointer(BuiltIn(void)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(munmap), - //BuiltIn(int) mprotect(Pointer(BuiltIn(void)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), BuiltIn(int)); - (void *)(mprotect), - //BuiltIn(int) msync(Pointer(BuiltIn(void)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), BuiltIn(int)); - (void *)(msync), - //BuiltIn(int) madvise(Pointer(BuiltIn(void)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), BuiltIn(int)); - (void *)(madvise), - //BuiltIn(int) posix_madvise(Pointer(BuiltIn(void)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), BuiltIn(int)); - (void *)(posix_madvise), - //BuiltIn(int) mlock(Pointer(Attributed(const , BuiltIn(void))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(mlock), - //BuiltIn(int) munlock(Pointer(Attributed(const , BuiltIn(void))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(munlock), - //BuiltIn(int) mlockall(BuiltIn(int)); - (void *)(mlockall), - //BuiltIn(int) munlockall(); - (void *)(munlockall), - //BuiltIn(int) mincore(Pointer(BuiltIn(void)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Attributed(unsigned , BuiltIn(char)))); - (void *)(mincore), - // skipping because varargs function: mremap - //BuiltIn(int) remap_file_pages(Pointer(BuiltIn(void)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), BuiltIn(int), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), BuiltIn(int)); - (void *)(remap_file_pages), - //BuiltIn(int) shm_open(Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int), Use(TypeDef(mode_t, Use(TypeDef(__mode_t, Attributed(unsigned , BuiltIn(int))))))); - (void *)(shm_open), - //BuiltIn(int) shm_unlink(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(shm_unlink), - //BuiltIn(int) mount(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), Attributed(unsigned , BuiltIn(long)), Pointer(Attributed(const , BuiltIn(void)))); - (void *)(mount), - //BuiltIn(int) umount(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(umount), - //BuiltIn(int) umount2(Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int)); - (void *)(umount2), - //Use(TypeDef(ssize_t, Use(TypeDef(__ssize_t, BuiltIn(long))))) sendfile(BuiltIn(int), BuiltIn(int), Pointer(Use(TypeDef(off_t, Use(TypeDef(__off_t, BuiltIn(long)))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(sendfile), - //Use(TypeDef(ssize_t, Use(TypeDef(__ssize_t, BuiltIn(long))))) sendfile64(BuiltIn(int), BuiltIn(int), Pointer(Use(TypeDef(__off64_t, BuiltIn(long)))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(sendfile64), - //BuiltIn(void) seqbuf_dump(); - (void *)(seqbuf_dump), - //BuiltIn(void) __monstartup(Use(TypeDef(u_long, Use(TypeDef(__u_long, Attributed(unsigned , BuiltIn(long)))))), Use(TypeDef(u_long, Use(TypeDef(__u_long, Attributed(unsigned , BuiltIn(long))))))); - (void *)(__monstartup), - //BuiltIn(void) monstartup(Use(TypeDef(u_long, Use(TypeDef(__u_long, Attributed(unsigned , BuiltIn(long)))))), Use(TypeDef(u_long, Use(TypeDef(__u_long, Attributed(unsigned , BuiltIn(long))))))); - (void *)(monstartup), - //BuiltIn(void) _mcleanup(); - (void *)(_mcleanup), - //BuiltIn(int) setfsuid(Use(TypeDef(__uid_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(setfsuid), - //BuiltIn(int) setfsgid(Use(TypeDef(__gid_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(setfsgid), - //BuiltIn(int) __adjtimex(Pointer(Use(Struct(struct timex)))); - (void *)(__adjtimex), - //BuiltIn(int) adjtimex(Pointer(Use(Struct(struct timex)))); - (void *)(adjtimex), - //BuiltIn(int) ntp_gettime(Pointer(Use(Struct(struct ntptimeval)))); - (void *)(ntp_gettime), - //BuiltIn(int) ntp_adjtime(Pointer(Use(Struct(struct timex)))); - (void *)(ntp_adjtime), - //BuiltIn(int) statfs(Pointer(Attributed(const , BuiltIn(char))), Pointer(Use(Struct(struct statfs)))); - (void *)(statfs), - //BuiltIn(int) statfs64(Pointer(Attributed(const , BuiltIn(char))), Pointer(Use(Struct(struct statfs64)))); - (void *)(statfs64), - //BuiltIn(int) fstatfs(BuiltIn(int), Pointer(Use(Struct(struct statfs)))); - (void *)(fstatfs), - //BuiltIn(int) fstatfs64(BuiltIn(int), Pointer(Use(Struct(struct statfs64)))); - (void *)(fstatfs64), - //BuiltIn(int) ioperm(Attributed(unsigned , BuiltIn(long)), Attributed(unsigned , BuiltIn(long)), BuiltIn(int)); - (void *)(ioperm), - //BuiltIn(int) iopl(BuiltIn(int)); - (void *)(iopl), - //Attributed(unsigned , BuiltIn(char)) inb(Attributed(unsigned , BuiltIn(short))); - (void *)(inb), - //Attributed(unsigned , BuiltIn(char)) inb_p(Attributed(unsigned , BuiltIn(short))); - (void *)(inb_p), - //Attributed(unsigned , BuiltIn(short)) inw(Attributed(unsigned , BuiltIn(short))); - (void *)(inw), - //Attributed(unsigned , BuiltIn(short)) inw_p(Attributed(unsigned , BuiltIn(short))); - (void *)(inw_p), - //Attributed(unsigned , BuiltIn(int)) inl(Attributed(unsigned , BuiltIn(short))); - (void *)(inl), - //Attributed(unsigned , BuiltIn(int)) inl_p(Attributed(unsigned , BuiltIn(short))); - (void *)(inl_p), - //BuiltIn(void) outb(Attributed(unsigned , BuiltIn(char)), Attributed(unsigned , BuiltIn(short))); - (void *)(outb), - //BuiltIn(void) outb_p(Attributed(unsigned , BuiltIn(char)), Attributed(unsigned , BuiltIn(short))); - (void *)(outb_p), - //BuiltIn(void) outw(Attributed(unsigned , BuiltIn(short)), Attributed(unsigned , BuiltIn(short))); - (void *)(outw), - //BuiltIn(void) outw_p(Attributed(unsigned , BuiltIn(short)), Attributed(unsigned , BuiltIn(short))); - (void *)(outw_p), - //BuiltIn(void) outl(Attributed(unsigned , BuiltIn(int)), Attributed(unsigned , BuiltIn(short))); - (void *)(outl), - //BuiltIn(void) outl_p(Attributed(unsigned , BuiltIn(int)), Attributed(unsigned , BuiltIn(short))); - (void *)(outl_p), - //BuiltIn(void) insb(Attributed(unsigned , BuiltIn(short)), Pointer(BuiltIn(void)), Attributed(unsigned , BuiltIn(long))); - (void *)(insb), - //BuiltIn(void) insw(Attributed(unsigned , BuiltIn(short)), Pointer(BuiltIn(void)), Attributed(unsigned , BuiltIn(long))); - (void *)(insw), - //BuiltIn(void) insl(Attributed(unsigned , BuiltIn(short)), Pointer(BuiltIn(void)), Attributed(unsigned , BuiltIn(long))); - (void *)(insl), - //BuiltIn(void) outsb(Attributed(unsigned , BuiltIn(short)), Pointer(Attributed(const , BuiltIn(void))), Attributed(unsigned , BuiltIn(long))); - (void *)(outsb), - //BuiltIn(void) outsw(Attributed(unsigned , BuiltIn(short)), Pointer(Attributed(const , BuiltIn(void))), Attributed(unsigned , BuiltIn(long))); - (void *)(outsw), - //BuiltIn(void) outsl(Attributed(unsigned , BuiltIn(short)), Pointer(Attributed(const , BuiltIn(void))), Attributed(unsigned , BuiltIn(long))); - (void *)(outsl), - //BuiltIn(int) ustat(Use(TypeDef(__dev_t, Attributed(unsigned , BuiltIn(long)))), Pointer(Use(Struct(struct ustat)))); -// (void *)(ustat), - //BuiltIn(int) vlimit(Use(Enum(enum __vlimit_resource)), BuiltIn(int)); - (void *)(vlimit), - //Pointer(Attributed(const , BuiltIn(char))) gnu_get_libc_release(); - (void *)(gnu_get_libc_release), - //Pointer(Attributed(const , BuiltIn(char))) gnu_get_libc_version(); - (void *)(gnu_get_libc_version), - //Pointer(BuiltIn(char)) setlocale(BuiltIn(int), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(setlocale), - //Pointer(Use(Struct(struct lconv))) localeconv(); - (void *)(localeconv), - //Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct)))) newlocale(BuiltIn(int), Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(newlocale), - //Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct)))) duplocale(Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(duplocale), - //BuiltIn(void) freelocale(Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(freelocale), - //Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct)))) uselocale(Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(uselocale), - //BuiltIn(int) utime(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , Use(Struct(struct utimbuf))))); - (void *)(utime), - //BuiltIn(int) getifaddrs(Pointer(Pointer(Use(Struct(struct ifaddrs))))); - (void *)(getifaddrs), - //BuiltIn(void) freeifaddrs(Pointer(Use(Struct(struct ifaddrs)))); - (void *)(freeifaddrs), - //BuiltIn(int) openpty(Pointer(BuiltIn(int)), Pointer(BuiltIn(int)), Pointer(BuiltIn(char)), Pointer(Attributed(const , Use(Struct(struct termios)))), Pointer(Attributed(const , Use(Struct(struct winsize))))); - (void *)(openpty), - //BuiltIn(int) forkpty(Pointer(BuiltIn(int)), Pointer(BuiltIn(char)), Pointer(Attributed(const , Use(Struct(struct termios)))), Pointer(Attributed(const , Use(Struct(struct winsize))))); - (void *)(forkpty), - //Attributed(unsigned , BuiltIn(int)) if_nametoindex(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(if_nametoindex), - //Pointer(BuiltIn(char)) if_indextoname(Attributed(unsigned , BuiltIn(int)), Pointer(BuiltIn(char))); - (void *)(if_indextoname), - //Pointer(Use(Struct(struct if_nameindex))) if_nameindex(); - (void *)(if_nameindex), - //BuiltIn(void) if_freenameindex(Pointer(Use(Struct(struct if_nameindex)))); - (void *)(if_freenameindex), - // skipping because varargs function: mq_open - //BuiltIn(int) mq_close(Use(TypeDef(mqd_t, BuiltIn(int)))); - (void *)(mq_close), - //BuiltIn(int) mq_getattr(Use(TypeDef(mqd_t, BuiltIn(int))), Pointer(Use(Struct(struct mq_attr)))); - (void *)(mq_getattr), - //BuiltIn(int) mq_setattr(Use(TypeDef(mqd_t, BuiltIn(int))), Pointer(restrict Attributed(const , Use(Struct(struct mq_attr)))), Pointer(restrict Use(Struct(struct mq_attr)))); - (void *)(mq_setattr), - //BuiltIn(int) mq_unlink(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(mq_unlink), - //BuiltIn(int) mq_notify(Use(TypeDef(mqd_t, BuiltIn(int))), Pointer(Attributed(const , Use(Struct(struct sigevent))))); - (void *)(mq_notify), - //Use(TypeDef(ssize_t, Use(TypeDef(__ssize_t, BuiltIn(long))))) mq_receive(Use(TypeDef(mqd_t, BuiltIn(int))), Pointer(BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Attributed(unsigned , BuiltIn(int)))); - (void *)(mq_receive), - //BuiltIn(int) mq_send(Use(TypeDef(mqd_t, BuiltIn(int))), Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Attributed(unsigned , BuiltIn(int))); - (void *)(mq_send), - //Use(TypeDef(ssize_t, Use(TypeDef(__ssize_t, BuiltIn(long))))) mq_timedreceive(Use(TypeDef(mqd_t, BuiltIn(int))), Pointer(restrict BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Attributed(unsigned , BuiltIn(int))), Pointer(restrict Attributed(const , Use(Struct(struct timespec))))); - (void *)(mq_timedreceive), - //BuiltIn(int) mq_timedsend(Use(TypeDef(mqd_t, BuiltIn(int))), Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Attributed(unsigned , BuiltIn(int)), Pointer(Attributed(const , Use(Struct(struct timespec))))); - (void *)(mq_timedsend), - // skipping because function pointer args: glob - // skipping because function pointer args: globfree - // skipping because function pointer args: glob64 - // skipping because function pointer args: globfree64 - //BuiltIn(int) glob_pattern_p(Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int)); - (void *)(glob_pattern_p), - //BuiltIn(int) ns_msg_getflag(Use(TypeDef(ns_msg, Struct(struct __ns_msg))), BuiltIn(int)); - (void *)(ns_msg_getflag), - //Use(TypeDef(u_int, Use(TypeDef(__u_int, Attributed(unsigned , BuiltIn(int)))))) ns_get16(Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char))))))))); - (void *)(ns_get16), - //Use(TypeDef(u_long, Use(TypeDef(__u_long, Attributed(unsigned , BuiltIn(long)))))) ns_get32(Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char))))))))); - (void *)(ns_get32), - //BuiltIn(void) ns_put16(Use(TypeDef(u_int, Use(TypeDef(__u_int, Attributed(unsigned , BuiltIn(int)))))), Pointer(Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))); - (void *)(ns_put16), - //BuiltIn(void) ns_put32(Use(TypeDef(u_long, Use(TypeDef(__u_long, Attributed(unsigned , BuiltIn(long)))))), Pointer(Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))); - (void *)(ns_put32), - //BuiltIn(int) ns_initparse(Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))), BuiltIn(int), Pointer(Use(TypeDef(ns_msg, Struct(struct __ns_msg))))); - (void *)(ns_initparse), - //BuiltIn(int) ns_skiprr(Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))), Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))), Use(TypeDef(ns_sect, Enum(enum __ns_sect))), BuiltIn(int)); - (void *)(ns_skiprr), - //BuiltIn(int) ns_parserr(Pointer(Use(TypeDef(ns_msg, Struct(struct __ns_msg)))), Use(TypeDef(ns_sect, Enum(enum __ns_sect))), BuiltIn(int), Pointer(Use(TypeDef(ns_rr, Struct(struct __ns_rr))))); - (void *)(ns_parserr), - //BuiltIn(int) ns_sprintrr(Pointer(Attributed(const , Use(TypeDef(ns_msg, Struct(struct __ns_msg))))), Pointer(Attributed(const , Use(TypeDef(ns_rr, Struct(struct __ns_rr))))), Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), Pointer(BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(ns_sprintrr), - //BuiltIn(int) ns_sprintrrf(Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(ns_class, Enum(enum __ns_class))), Use(TypeDef(ns_type, Enum(enum __ns_type))), Use(TypeDef(u_long, Use(TypeDef(__u_long, Attributed(unsigned , BuiltIn(long)))))), Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), Pointer(BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(ns_sprintrrf), - //BuiltIn(int) ns_format_ttl(Use(TypeDef(u_long, Use(TypeDef(__u_long, Attributed(unsigned , BuiltIn(long)))))), Pointer(BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(ns_format_ttl), - //BuiltIn(int) ns_parse_ttl(Pointer(Attributed(const , BuiltIn(char))), Pointer(Use(TypeDef(u_long, Use(TypeDef(__u_long, Attributed(unsigned , BuiltIn(long)))))))); - (void *)(ns_parse_ttl), - //Use(TypeDef(u_int32_t, Attributed(__attribute__ ( ( __mode__ ( __SI__ ) ) ), Attributed(unsigned , BuiltIn(int))))) ns_datetosecs(Pointer(Attributed(const , BuiltIn(char))), Pointer(BuiltIn(int))); - (void *)(ns_datetosecs), - //BuiltIn(int) ns_name_ntol(Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))), Pointer(Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char))))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(ns_name_ntol), - //BuiltIn(int) ns_name_ntop(Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))), Pointer(BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(ns_name_ntop), - //BuiltIn(int) ns_name_pton(Pointer(Attributed(const , BuiltIn(char))), Pointer(Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char))))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(ns_name_pton), - //BuiltIn(int) ns_name_unpack(Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))), Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))), Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))), Pointer(Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char))))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(ns_name_unpack), - //BuiltIn(int) ns_name_pack(Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))), Pointer(Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char))))))), BuiltIn(int), Pointer(Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char))))))))), Pointer(Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))))); - (void *)(ns_name_pack), - //BuiltIn(int) ns_name_uncompress(Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))), Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))), Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))), Pointer(BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(ns_name_uncompress), - //BuiltIn(int) ns_name_compress(Pointer(Attributed(const , BuiltIn(char))), Pointer(Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char))))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char))))))))), Pointer(Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))))); - (void *)(ns_name_compress), - //BuiltIn(int) ns_name_skip(Pointer(Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char))))))))), Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char))))))))); - (void *)(ns_name_skip), - //BuiltIn(void) ns_name_rollback(Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))), Pointer(Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char))))))))), Pointer(Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))))); - (void *)(ns_name_rollback), - //BuiltIn(int) ns_samedomain(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(ns_samedomain), - //BuiltIn(int) ns_subdomain(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(ns_subdomain), - //BuiltIn(int) ns_makecanon(Pointer(Attributed(const , BuiltIn(char))), Pointer(BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(ns_makecanon), - //BuiltIn(int) ns_samename(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(ns_samename), - //Pointer(Use(Struct(struct __res_state))) __res_state(); - (void *)(__res_state), - //BuiltIn(void) __fp_nquery(Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))), BuiltIn(int), Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(__fp_nquery), - //BuiltIn(void) __fp_query(Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))), Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(__fp_query), - //Pointer(Attributed(const , BuiltIn(char))) __hostalias(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(__hostalias), - //BuiltIn(void) __p_query(Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char))))))))); - (void *)(__p_query), - //BuiltIn(void) __res_close(); - (void *)(__res_close), - //BuiltIn(int) __res_init(); - (void *)(__res_init), - //BuiltIn(int) __res_isourserver(Pointer(Attributed(const , Use(Struct(struct sockaddr_in))))); - (void *)(__res_isourserver), - //BuiltIn(int) __res_mkquery(BuiltIn(int), Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int), BuiltIn(int), Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))), BuiltIn(int), Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))), Pointer(Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char))))))), BuiltIn(int)); - (void *)(__res_mkquery), - //BuiltIn(int) __res_query(Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int), BuiltIn(int), Pointer(Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char))))))), BuiltIn(int)); - (void *)(__res_query), - //BuiltIn(int) __res_querydomain(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int), BuiltIn(int), Pointer(Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char))))))), BuiltIn(int)); - (void *)(__res_querydomain), - //BuiltIn(int) __res_search(Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int), BuiltIn(int), Pointer(Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char))))))), BuiltIn(int)); - (void *)(__res_search), - //BuiltIn(int) __res_send(Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))), BuiltIn(int), Pointer(Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char))))))), BuiltIn(int)); - (void *)(__res_send), - //BuiltIn(int) __res_hnok(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(__res_hnok), - //BuiltIn(int) __res_ownok(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(__res_ownok), - //BuiltIn(int) __res_mailok(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(__res_mailok), - //BuiltIn(int) __res_dnok(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(__res_dnok), - //BuiltIn(int) __sym_ston(Pointer(Attributed(const , Use(Struct(struct res_sym)))), Pointer(Attributed(const , BuiltIn(char))), Pointer(BuiltIn(int))); - (void *)(__sym_ston), - //Pointer(Attributed(const , BuiltIn(char))) __sym_ntos(Pointer(Attributed(const , Use(Struct(struct res_sym)))), BuiltIn(int), Pointer(BuiltIn(int))); - (void *)(__sym_ntos), - //Pointer(Attributed(const , BuiltIn(char))) __sym_ntop(Pointer(Attributed(const , Use(Struct(struct res_sym)))), BuiltIn(int), Pointer(BuiltIn(int))); - (void *)(__sym_ntop), - //BuiltIn(int) __b64_ntop(Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(__b64_ntop), - //BuiltIn(int) __b64_pton(Pointer(Attributed(const , BuiltIn(char))), Pointer(Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char))))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(__b64_pton), - //BuiltIn(int) __loc_aton(Pointer(Attributed(const , BuiltIn(char))), Pointer(Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))); - (void *)(__loc_aton), - //Pointer(Attributed(const , BuiltIn(char))) __loc_ntoa(Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))), Pointer(BuiltIn(char))); - (void *)(__loc_ntoa), - //BuiltIn(int) __dn_skipname(Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))), Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char))))))))); - (void *)(__dn_skipname), - //BuiltIn(void) __putlong(Use(TypeDef(u_int32_t, Attributed(__attribute__ ( ( __mode__ ( __SI__ ) ) ), Attributed(unsigned , BuiltIn(int))))), Pointer(Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))); - (void *)(__putlong), - //BuiltIn(void) __putshort(Use(TypeDef(u_int16_t, Attributed(__attribute__ ( ( __mode__ ( __HI__ ) ) ), Attributed(unsigned , BuiltIn(int))))), Pointer(Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))); - (void *)(__putshort), - //Pointer(Attributed(const , BuiltIn(char))) __p_class(BuiltIn(int)); - (void *)(__p_class), - //Pointer(Attributed(const , BuiltIn(char))) __p_time(Use(TypeDef(u_int32_t, Attributed(__attribute__ ( ( __mode__ ( __SI__ ) ) ), Attributed(unsigned , BuiltIn(int)))))); - (void *)(__p_time), - //Pointer(Attributed(const , BuiltIn(char))) __p_type(BuiltIn(int)); - (void *)(__p_type), - //Pointer(Attributed(const , BuiltIn(char))) __p_rcode(BuiltIn(int)); - (void *)(__p_rcode), - //Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))) __p_cdnname(Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))), Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))), BuiltIn(int), Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(__p_cdnname), - //Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))) __p_cdname(Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))), Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))), Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(__p_cdname), - //Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))) __p_fqnname(Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))), Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))), BuiltIn(int), Pointer(BuiltIn(char)), BuiltIn(int)); - (void *)(__p_fqnname), - //Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))) __p_fqname(Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))), Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))), Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(__p_fqname), - //Pointer(Attributed(const , BuiltIn(char))) __p_option(Use(TypeDef(u_long, Use(TypeDef(__u_long, Attributed(unsigned , BuiltIn(long))))))); - (void *)(__p_option), - //BuiltIn(int) __dn_count_labels(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(__dn_count_labels), - //BuiltIn(int) __dn_comp(Pointer(Attributed(const , BuiltIn(char))), Pointer(Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char))))))), BuiltIn(int), Pointer(Pointer(Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))), Pointer(Pointer(Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char))))))))); - (void *)(__dn_comp), - //BuiltIn(int) __dn_expand(Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))), Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))), Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))), Pointer(BuiltIn(char)), BuiltIn(int)); - (void *)(__dn_expand), - //Use(TypeDef(u_int, Use(TypeDef(__u_int, Attributed(unsigned , BuiltIn(int)))))) __res_randomid(); - (void *)(__res_randomid), - //BuiltIn(int) __res_nameinquery(Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int), BuiltIn(int), Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))), Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char))))))))); - (void *)(__res_nameinquery), - //BuiltIn(int) __res_queriesmatch(Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))), Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))), Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char)))))))), Pointer(Attributed(const , Use(TypeDef(u_char, Use(TypeDef(__u_char, Attributed(unsigned , BuiltIn(char))))))))); - (void *)(__res_queriesmatch), - // skipping because function pointer args: __res_ninit - //BuiltIn(void) __fp_resstat(Attributed(const , Use(TypeDef(res_state, Pointer(Use(Struct(struct __res_state)))))), Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(__fp_resstat), - //Pointer(Attributed(const , BuiltIn(char))) __res_hostalias(Attributed(const , Use(TypeDef(res_state, Pointer(Use(Struct(struct __res_state)))))), Pointer(Attributed(const , BuiltIn(char))), Pointer(BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(__res_hostalias), - // skipping because function pointer args: __res_nquery - // skipping because function pointer args: __res_nsearch - // skipping because function pointer args: __res_nquerydomain - // skipping because function pointer args: __res_nmkquery - // skipping because function pointer args: __res_nsend - // skipping because function pointer args: __res_nclose - // skipping because function pointer args: _obstack_newchunk - // skipping because function pointer args: _obstack_begin - // skipping because function pointer args: _obstack_begin_1 - // skipping because function pointer args: _obstack_memory_used - // skipping because function pointer args: obstack_free - //BuiltIn(int) setjmp(Use(TypeDef(jmp_buf, Array(Use(Struct(struct __jmp_buf_tag)))))); - (void *)(setjmp), - //BuiltIn(int) __sigsetjmp(Array(Use(Struct(struct __jmp_buf_tag))), BuiltIn(int)); - (void *)(__sigsetjmp), - //BuiltIn(int) _setjmp(Array(Use(Struct(struct __jmp_buf_tag)))); - (void *)(_setjmp), - //BuiltIn(void) longjmp(Array(Use(Struct(struct __jmp_buf_tag))), BuiltIn(int)); - (void *)(longjmp), - //BuiltIn(void) _longjmp(Array(Use(Struct(struct __jmp_buf_tag))), BuiltIn(int)); - (void *)(_longjmp), - //BuiltIn(void) siglongjmp(Use(TypeDef(sigjmp_buf, Array(Use(Struct(struct __jmp_buf_tag))))), BuiltIn(int)); - (void *)(siglongjmp), - //Pointer(Use(Struct(struct ttyent))) getttyent(); - (void *)(getttyent), - //Pointer(Use(Struct(struct ttyent))) getttynam(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(getttynam), - //BuiltIn(int) setttyent(); - (void *)(setttyent), - //BuiltIn(int) endttyent(); - (void *)(endttyent), - //BuiltIn(int) login_tty(BuiltIn(int)); - (void *)(login_tty), - //BuiltIn(void) login(Pointer(Attributed(const , Use(Struct(struct utmp))))); - (void *)(login), - //BuiltIn(int) logout(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(logout), - //BuiltIn(void) logwtmp(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(logwtmp), - //BuiltIn(void) updwtmp(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , Use(Struct(struct utmp))))); - (void *)(updwtmp), - //BuiltIn(int) utmpname(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(utmpname), - //Pointer(Use(Struct(struct utmp))) getutent(); - (void *)(getutent), - //BuiltIn(void) setutent(); - (void *)(setutent), - //BuiltIn(void) endutent(); - (void *)(endutent), - //Pointer(Use(Struct(struct utmp))) getutid(Pointer(Attributed(const , Use(Struct(struct utmp))))); - (void *)(getutid), - //Pointer(Use(Struct(struct utmp))) getutline(Pointer(Attributed(const , Use(Struct(struct utmp))))); - (void *)(getutline), - //Pointer(Use(Struct(struct utmp))) pututline(Pointer(Attributed(const , Use(Struct(struct utmp))))); - (void *)(pututline), - //BuiltIn(int) getutent_r(Pointer(Use(Struct(struct utmp))), Pointer(Pointer(Use(Struct(struct utmp))))); - (void *)(getutent_r), - //BuiltIn(int) getutid_r(Pointer(Attributed(const , Use(Struct(struct utmp)))), Pointer(Use(Struct(struct utmp))), Pointer(Pointer(Use(Struct(struct utmp))))); - (void *)(getutid_r), - //BuiltIn(int) getutline_r(Pointer(Attributed(const , Use(Struct(struct utmp)))), Pointer(Use(Struct(struct utmp))), Pointer(Pointer(Use(Struct(struct utmp))))); - (void *)(getutline_r), - //BuiltIn(int) fnmatch(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int)); - (void *)(fnmatch), - //Use(TypeDef(in_addr_t, Use(TypeDef(uint32_t, Attributed(unsigned , BuiltIn(int)))))) inet_addr(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(inet_addr), - //Use(TypeDef(in_addr_t, Use(TypeDef(uint32_t, Attributed(unsigned , BuiltIn(int)))))) inet_lnaof(Use(Struct(struct in_addr))); - (void *)(inet_lnaof), - //Use(Struct(struct in_addr)) inet_makeaddr(Use(TypeDef(in_addr_t, Use(TypeDef(uint32_t, Attributed(unsigned , BuiltIn(int)))))), Use(TypeDef(in_addr_t, Use(TypeDef(uint32_t, Attributed(unsigned , BuiltIn(int))))))); - (void *)(inet_makeaddr), - //Use(TypeDef(in_addr_t, Use(TypeDef(uint32_t, Attributed(unsigned , BuiltIn(int)))))) inet_netof(Use(Struct(struct in_addr))); - (void *)(inet_netof), - //Use(TypeDef(in_addr_t, Use(TypeDef(uint32_t, Attributed(unsigned , BuiltIn(int)))))) inet_network(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(inet_network), - //Pointer(BuiltIn(char)) inet_ntoa(Use(Struct(struct in_addr))); - (void *)(inet_ntoa), - //BuiltIn(int) inet_pton(BuiltIn(int), Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict BuiltIn(void))); - (void *)(inet_pton), - //Pointer(Attributed(const , BuiltIn(char))) inet_ntop(BuiltIn(int), Pointer(restrict Attributed(const , BuiltIn(void))), Pointer(restrict BuiltIn(char)), Use(TypeDef(socklen_t, Use(TypeDef(__socklen_t, Attributed(unsigned , BuiltIn(int))))))); - (void *)(inet_ntop), - //BuiltIn(int) inet_aton(Pointer(Attributed(const , BuiltIn(char))), Pointer(Use(Struct(struct in_addr)))); - (void *)(inet_aton), - //Pointer(BuiltIn(char)) inet_neta(Use(TypeDef(in_addr_t, Use(TypeDef(uint32_t, Attributed(unsigned , BuiltIn(int)))))), Pointer(BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(inet_neta), - //Pointer(BuiltIn(char)) inet_net_ntop(BuiltIn(int), Pointer(Attributed(const , BuiltIn(void))), BuiltIn(int), Pointer(BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(inet_net_ntop), - //BuiltIn(int) inet_net_pton(BuiltIn(int), Pointer(Attributed(const , BuiltIn(char))), Pointer(BuiltIn(void)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(inet_net_pton), - //Attributed(unsigned , BuiltIn(int)) inet_nsap_addr(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(unsigned , BuiltIn(char))), BuiltIn(int)); - (void *)(inet_nsap_addr), - //Pointer(BuiltIn(char)) inet_nsap_ntoa(BuiltIn(int), Pointer(Attributed(const unsigned , BuiltIn(char))), Pointer(BuiltIn(char))); - (void *)(inet_nsap_ntoa), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) mbrtoc16(Pointer(restrict Use(TypeDef(char16_t, Attributed(unsigned , BuiltIn(short))))), Pointer(restrict Attributed(const , BuiltIn(char))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Use(TypeDef(mbstate_t, Use(TypeDef(__mbstate_t, Struct(struct anon_struct_5))))))); - (void *)(mbrtoc16), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) c16rtomb(Pointer(restrict BuiltIn(char)), Use(TypeDef(char16_t, Attributed(unsigned , BuiltIn(short)))), Pointer(restrict Use(TypeDef(mbstate_t, Use(TypeDef(__mbstate_t, Struct(struct anon_struct_5))))))); - (void *)(c16rtomb), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) mbrtoc32(Pointer(restrict Use(TypeDef(char32_t, Attributed(unsigned , BuiltIn(int))))), Pointer(restrict Attributed(const , BuiltIn(char))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Use(TypeDef(mbstate_t, Use(TypeDef(__mbstate_t, Struct(struct anon_struct_5))))))); - (void *)(mbrtoc32), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) c32rtomb(Pointer(restrict BuiltIn(char)), Use(TypeDef(char32_t, Attributed(unsigned , BuiltIn(int)))), Pointer(restrict Use(TypeDef(mbstate_t, Use(TypeDef(__mbstate_t, Struct(struct anon_struct_5))))))); - (void *)(c32rtomb), - //BuiltIn(void) __assert_fail(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), Attributed(unsigned , BuiltIn(int)), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(__assert_fail), - //BuiltIn(void) __assert_perror_fail(BuiltIn(int), Pointer(Attributed(const , BuiltIn(char))), Attributed(unsigned , BuiltIn(int)), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(__assert_perror_fail), - //BuiltIn(void) __assert(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int)); - (void *)(__assert), - //BuiltIn(int) fmtmsg(BuiltIn(long), Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int), Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(fmtmsg), - //BuiltIn(int) addseverity(BuiltIn(int), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(addseverity), - //Pointer(BuiltIn(char)) crypt(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(crypt), - //BuiltIn(void) setkey(Pointer(Attributed(const , BuiltIn(char)))); -// (void *)(setkey), - //BuiltIn(void) encrypt(Pointer(BuiltIn(char)), BuiltIn(int)); -// (void *)(encrypt), - //Pointer(BuiltIn(char)) crypt_r(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), Pointer(restrict Use(Struct(struct crypt_data)))); - (void *)(crypt_r), - //BuiltIn(void) setkey_r(Pointer(Attributed(const , BuiltIn(char))), Pointer(restrict Use(Struct(struct crypt_data)))); - // (void *)(setkey_r), - //BuiltIn(void) encrypt_r(Pointer(BuiltIn(char)), BuiltIn(int), Pointer(restrict Use(Struct(struct crypt_data)))); -// (void *)(encrypt_r), - //BuiltIn(int) gtty(BuiltIn(int), Pointer(Use(Struct(struct sgttyb)))); - (void *)(gtty), - //BuiltIn(int) stty(BuiltIn(int), Pointer(Attributed(const , Use(Struct(struct sgttyb))))); - (void *)(stty), - //BuiltIn(int) getcontext(Pointer(Use(TypeDef(ucontext_t, Struct(struct ucontext))))); - (void *)(getcontext), - //BuiltIn(int) setcontext(Pointer(Attributed(const , Use(TypeDef(ucontext_t, Struct(struct ucontext)))))); - (void *)(setcontext), - //BuiltIn(int) swapcontext(Pointer(restrict Use(TypeDef(ucontext_t, Struct(struct ucontext)))), Pointer(restrict Attributed(const , Use(TypeDef(ucontext_t, Struct(struct ucontext)))))); - (void *)(swapcontext), - // skipping because varargs function: makecontext - // skipping because varargs function: clone - //BuiltIn(int) unshare(BuiltIn(int)); - (void *)(unshare), - //BuiltIn(int) sched_getcpu(); - (void *)(sched_getcpu), - //BuiltIn(int) setns(BuiltIn(int), BuiltIn(int)); - (void *)(setns), - //BuiltIn(int) __sched_cpucount(Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Attributed(const , Use(TypeDef(cpu_set_t, Struct(struct anon_struct_614)))))); - (void *)(__sched_cpucount), - //Pointer(Use(TypeDef(cpu_set_t, Struct(struct anon_struct_614)))) __sched_cpualloc(Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(__sched_cpualloc), - //BuiltIn(void) __sched_cpufree(Pointer(Use(TypeDef(cpu_set_t, Struct(struct anon_struct_614))))); - (void *)(__sched_cpufree), - //BuiltIn(int) sched_setparam(Use(TypeDef(__pid_t, BuiltIn(int))), Pointer(Attributed(const , Use(Struct(struct sched_param))))); - (void *)(sched_setparam), - //BuiltIn(int) sched_getparam(Use(TypeDef(__pid_t, BuiltIn(int))), Pointer(Use(Struct(struct sched_param)))); - (void *)(sched_getparam), - //BuiltIn(int) sched_setscheduler(Use(TypeDef(__pid_t, BuiltIn(int))), BuiltIn(int), Pointer(Attributed(const , Use(Struct(struct sched_param))))); - (void *)(sched_setscheduler), - //BuiltIn(int) sched_getscheduler(Use(TypeDef(__pid_t, BuiltIn(int)))); - (void *)(sched_getscheduler), - //BuiltIn(int) sched_yield(); - (void *)(sched_yield), - //BuiltIn(int) sched_get_priority_max(BuiltIn(int)); - (void *)(sched_get_priority_max), - //BuiltIn(int) sched_get_priority_min(BuiltIn(int)); - (void *)(sched_get_priority_min), - //BuiltIn(int) sched_rr_get_interval(Use(TypeDef(__pid_t, BuiltIn(int))), Pointer(Use(Struct(struct timespec)))); - (void *)(sched_rr_get_interval), - //BuiltIn(int) sched_setaffinity(Use(TypeDef(__pid_t, BuiltIn(int))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Attributed(const , Use(TypeDef(cpu_set_t, Struct(struct anon_struct_614)))))); - (void *)(sched_setaffinity), - //BuiltIn(int) sched_getaffinity(Use(TypeDef(__pid_t, BuiltIn(int))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Use(TypeDef(cpu_set_t, Struct(struct anon_struct_614))))); - (void *)(sched_getaffinity), - //BuiltIn(int) posix_spawn(Pointer(restrict Use(TypeDef(pid_t, Use(TypeDef(__pid_t, BuiltIn(int)))))), Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Attributed(const , Use(TypeDef(posix_spawn_file_actions_t, Struct(struct anon_struct_616))))), Pointer(restrict Attributed(const , Use(TypeDef(posix_spawnattr_t, Struct(struct anon_struct_615))))), Array(Pointer(const BuiltIn(char))), Array(Pointer(const BuiltIn(char)))); - (void *)(posix_spawn), - //BuiltIn(int) posix_spawnp(Pointer(Use(TypeDef(pid_t, Use(TypeDef(__pid_t, BuiltIn(int)))))), Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , Use(TypeDef(posix_spawn_file_actions_t, Struct(struct anon_struct_616))))), Pointer(Attributed(const , Use(TypeDef(posix_spawnattr_t, Struct(struct anon_struct_615))))), Array(Pointer(const BuiltIn(char))), Array(Pointer(const BuiltIn(char)))); - (void *)(posix_spawnp), - //BuiltIn(int) posix_spawnattr_init(Pointer(Use(TypeDef(posix_spawnattr_t, Struct(struct anon_struct_615))))); - (void *)(posix_spawnattr_init), - //BuiltIn(int) posix_spawnattr_destroy(Pointer(Use(TypeDef(posix_spawnattr_t, Struct(struct anon_struct_615))))); - (void *)(posix_spawnattr_destroy), - //BuiltIn(int) posix_spawnattr_getsigdefault(Pointer(restrict Attributed(const , Use(TypeDef(posix_spawnattr_t, Struct(struct anon_struct_615))))), Pointer(restrict Use(TypeDef(sigset_t, Use(TypeDef(__sigset_t, Struct(struct anon_struct_23))))))); - (void *)(posix_spawnattr_getsigdefault), - //BuiltIn(int) posix_spawnattr_setsigdefault(Pointer(restrict Use(TypeDef(posix_spawnattr_t, Struct(struct anon_struct_615)))), Pointer(restrict Attributed(const , Use(TypeDef(sigset_t, Use(TypeDef(__sigset_t, Struct(struct anon_struct_23)))))))); - (void *)(posix_spawnattr_setsigdefault), - //BuiltIn(int) posix_spawnattr_getsigmask(Pointer(restrict Attributed(const , Use(TypeDef(posix_spawnattr_t, Struct(struct anon_struct_615))))), Pointer(restrict Use(TypeDef(sigset_t, Use(TypeDef(__sigset_t, Struct(struct anon_struct_23))))))); - (void *)(posix_spawnattr_getsigmask), - //BuiltIn(int) posix_spawnattr_setsigmask(Pointer(restrict Use(TypeDef(posix_spawnattr_t, Struct(struct anon_struct_615)))), Pointer(restrict Attributed(const , Use(TypeDef(sigset_t, Use(TypeDef(__sigset_t, Struct(struct anon_struct_23)))))))); - (void *)(posix_spawnattr_setsigmask), - //BuiltIn(int) posix_spawnattr_getflags(Pointer(restrict Attributed(const , Use(TypeDef(posix_spawnattr_t, Struct(struct anon_struct_615))))), Pointer(restrict BuiltIn(short))); - (void *)(posix_spawnattr_getflags), - //BuiltIn(int) posix_spawnattr_setflags(Pointer(Use(TypeDef(posix_spawnattr_t, Struct(struct anon_struct_615)))), BuiltIn(short)); - (void *)(posix_spawnattr_setflags), - //BuiltIn(int) posix_spawnattr_getpgroup(Pointer(restrict Attributed(const , Use(TypeDef(posix_spawnattr_t, Struct(struct anon_struct_615))))), Pointer(restrict Use(TypeDef(pid_t, Use(TypeDef(__pid_t, BuiltIn(int))))))); - (void *)(posix_spawnattr_getpgroup), - //BuiltIn(int) posix_spawnattr_setpgroup(Pointer(Use(TypeDef(posix_spawnattr_t, Struct(struct anon_struct_615)))), Use(TypeDef(pid_t, Use(TypeDef(__pid_t, BuiltIn(int)))))); - (void *)(posix_spawnattr_setpgroup), - //BuiltIn(int) posix_spawnattr_getschedpolicy(Pointer(restrict Attributed(const , Use(TypeDef(posix_spawnattr_t, Struct(struct anon_struct_615))))), Pointer(restrict BuiltIn(int))); - (void *)(posix_spawnattr_getschedpolicy), - //BuiltIn(int) posix_spawnattr_setschedpolicy(Pointer(Use(TypeDef(posix_spawnattr_t, Struct(struct anon_struct_615)))), BuiltIn(int)); - (void *)(posix_spawnattr_setschedpolicy), - //BuiltIn(int) posix_spawnattr_getschedparam(Pointer(restrict Attributed(const , Use(TypeDef(posix_spawnattr_t, Struct(struct anon_struct_615))))), Pointer(restrict Use(Struct(struct sched_param)))); - (void *)(posix_spawnattr_getschedparam), - //BuiltIn(int) posix_spawnattr_setschedparam(Pointer(restrict Use(TypeDef(posix_spawnattr_t, Struct(struct anon_struct_615)))), Pointer(restrict Attributed(const , Use(Struct(struct sched_param))))); - (void *)(posix_spawnattr_setschedparam), - //BuiltIn(int) posix_spawn_file_actions_init(Pointer(Use(TypeDef(posix_spawn_file_actions_t, Struct(struct anon_struct_616))))); - (void *)(posix_spawn_file_actions_init), - //BuiltIn(int) posix_spawn_file_actions_destroy(Pointer(Use(TypeDef(posix_spawn_file_actions_t, Struct(struct anon_struct_616))))); - (void *)(posix_spawn_file_actions_destroy), - //BuiltIn(int) posix_spawn_file_actions_addopen(Pointer(restrict Use(TypeDef(posix_spawn_file_actions_t, Struct(struct anon_struct_616)))), BuiltIn(int), Pointer(restrict Attributed(const , BuiltIn(char))), BuiltIn(int), Use(TypeDef(mode_t, Use(TypeDef(__mode_t, Attributed(unsigned , BuiltIn(int))))))); - (void *)(posix_spawn_file_actions_addopen), - //BuiltIn(int) posix_spawn_file_actions_addclose(Pointer(Use(TypeDef(posix_spawn_file_actions_t, Struct(struct anon_struct_616)))), BuiltIn(int)); - (void *)(posix_spawn_file_actions_addclose), - //BuiltIn(int) posix_spawn_file_actions_adddup2(Pointer(Use(TypeDef(posix_spawn_file_actions_t, Struct(struct anon_struct_616)))), BuiltIn(int), BuiltIn(int)); - (void *)(posix_spawn_file_actions_adddup2), - // skipping because function pointer args: pthread_create - //BuiltIn(void) pthread_exit(Pointer(BuiltIn(void))); - (void *)(pthread_exit), - //BuiltIn(int) pthread_join(Use(TypeDef(pthread_t, Attributed(unsigned , BuiltIn(long)))), Pointer(Pointer(BuiltIn(void)))); - (void *)(pthread_join), - //BuiltIn(int) pthread_tryjoin_np(Use(TypeDef(pthread_t, Attributed(unsigned , BuiltIn(long)))), Pointer(Pointer(BuiltIn(void)))); - (void *)(pthread_tryjoin_np), - //BuiltIn(int) pthread_timedjoin_np(Use(TypeDef(pthread_t, Attributed(unsigned , BuiltIn(long)))), Pointer(Pointer(BuiltIn(void))), Pointer(Attributed(const , Use(Struct(struct timespec))))); - (void *)(pthread_timedjoin_np), - //BuiltIn(int) pthread_detach(Use(TypeDef(pthread_t, Attributed(unsigned , BuiltIn(long))))); - (void *)(pthread_detach), - //Use(TypeDef(pthread_t, Attributed(unsigned , BuiltIn(long)))) pthread_self(); - (void *)(pthread_self), - //BuiltIn(int) pthread_equal(Use(TypeDef(pthread_t, Attributed(unsigned , BuiltIn(long)))), Use(TypeDef(pthread_t, Attributed(unsigned , BuiltIn(long))))); - (void *)(pthread_equal), - //BuiltIn(int) pthread_attr_init(Pointer(Use(TypeDef(pthread_attr_t, Use(Union(union pthread_attr_t)))))); - (void *)(pthread_attr_init), - //BuiltIn(int) pthread_attr_destroy(Pointer(Use(TypeDef(pthread_attr_t, Use(Union(union pthread_attr_t)))))); - (void *)(pthread_attr_destroy), - //BuiltIn(int) pthread_attr_getdetachstate(Pointer(Attributed(const , Use(TypeDef(pthread_attr_t, Use(Union(union pthread_attr_t)))))), Pointer(BuiltIn(int))); - (void *)(pthread_attr_getdetachstate), - //BuiltIn(int) pthread_attr_setdetachstate(Pointer(Use(TypeDef(pthread_attr_t, Use(Union(union pthread_attr_t))))), BuiltIn(int)); - (void *)(pthread_attr_setdetachstate), - //BuiltIn(int) pthread_attr_getguardsize(Pointer(Attributed(const , Use(TypeDef(pthread_attr_t, Use(Union(union pthread_attr_t)))))), Pointer(Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))))); - (void *)(pthread_attr_getguardsize), - //BuiltIn(int) pthread_attr_setguardsize(Pointer(Use(TypeDef(pthread_attr_t, Use(Union(union pthread_attr_t))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(pthread_attr_setguardsize), - //BuiltIn(int) pthread_attr_getschedparam(Pointer(restrict Attributed(const , Use(TypeDef(pthread_attr_t, Use(Union(union pthread_attr_t)))))), Pointer(restrict Use(Struct(struct sched_param)))); - (void *)(pthread_attr_getschedparam), - //BuiltIn(int) pthread_attr_setschedparam(Pointer(restrict Use(TypeDef(pthread_attr_t, Use(Union(union pthread_attr_t))))), Pointer(restrict Attributed(const , Use(Struct(struct sched_param))))); - (void *)(pthread_attr_setschedparam), - //BuiltIn(int) pthread_attr_getschedpolicy(Pointer(restrict Attributed(const , Use(TypeDef(pthread_attr_t, Use(Union(union pthread_attr_t)))))), Pointer(restrict BuiltIn(int))); - (void *)(pthread_attr_getschedpolicy), - //BuiltIn(int) pthread_attr_setschedpolicy(Pointer(Use(TypeDef(pthread_attr_t, Use(Union(union pthread_attr_t))))), BuiltIn(int)); - (void *)(pthread_attr_setschedpolicy), - //BuiltIn(int) pthread_attr_getinheritsched(Pointer(restrict Attributed(const , Use(TypeDef(pthread_attr_t, Use(Union(union pthread_attr_t)))))), Pointer(restrict BuiltIn(int))); - (void *)(pthread_attr_getinheritsched), - //BuiltIn(int) pthread_attr_setinheritsched(Pointer(Use(TypeDef(pthread_attr_t, Use(Union(union pthread_attr_t))))), BuiltIn(int)); - (void *)(pthread_attr_setinheritsched), - //BuiltIn(int) pthread_attr_getscope(Pointer(restrict Attributed(const , Use(TypeDef(pthread_attr_t, Use(Union(union pthread_attr_t)))))), Pointer(restrict BuiltIn(int))); - (void *)(pthread_attr_getscope), - //BuiltIn(int) pthread_attr_setscope(Pointer(Use(TypeDef(pthread_attr_t, Use(Union(union pthread_attr_t))))), BuiltIn(int)); - (void *)(pthread_attr_setscope), - //BuiltIn(int) pthread_attr_getstackaddr(Pointer(restrict Attributed(const , Use(TypeDef(pthread_attr_t, Use(Union(union pthread_attr_t)))))), Pointer(restrict Pointer(BuiltIn(void)))); - (void *)(pthread_attr_getstackaddr), - //BuiltIn(int) pthread_attr_setstackaddr(Pointer(Use(TypeDef(pthread_attr_t, Use(Union(union pthread_attr_t))))), Pointer(BuiltIn(void))); - (void *)(pthread_attr_setstackaddr), - //BuiltIn(int) pthread_attr_getstacksize(Pointer(restrict Attributed(const , Use(TypeDef(pthread_attr_t, Use(Union(union pthread_attr_t)))))), Pointer(restrict Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))))); - (void *)(pthread_attr_getstacksize), - //BuiltIn(int) pthread_attr_setstacksize(Pointer(Use(TypeDef(pthread_attr_t, Use(Union(union pthread_attr_t))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(pthread_attr_setstacksize), - //BuiltIn(int) pthread_attr_getstack(Pointer(restrict Attributed(const , Use(TypeDef(pthread_attr_t, Use(Union(union pthread_attr_t)))))), Pointer(restrict Pointer(BuiltIn(void))), Pointer(restrict Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))))); - (void *)(pthread_attr_getstack), - //BuiltIn(int) pthread_attr_setstack(Pointer(Use(TypeDef(pthread_attr_t, Use(Union(union pthread_attr_t))))), Pointer(BuiltIn(void)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(pthread_attr_setstack), - //BuiltIn(int) pthread_attr_setaffinity_np(Pointer(Use(TypeDef(pthread_attr_t, Use(Union(union pthread_attr_t))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Attributed(const , Use(TypeDef(cpu_set_t, Struct(struct anon_struct_614)))))); - (void *)(pthread_attr_setaffinity_np), - //BuiltIn(int) pthread_attr_getaffinity_np(Pointer(Attributed(const , Use(TypeDef(pthread_attr_t, Use(Union(union pthread_attr_t)))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Use(TypeDef(cpu_set_t, Struct(struct anon_struct_614))))); - (void *)(pthread_attr_getaffinity_np), - //BuiltIn(int) pthread_getattr_default_np(Pointer(Use(TypeDef(pthread_attr_t, Use(Union(union pthread_attr_t)))))); - (void *)(pthread_getattr_default_np), - //BuiltIn(int) pthread_setattr_default_np(Pointer(Attributed(const , Use(TypeDef(pthread_attr_t, Use(Union(union pthread_attr_t))))))); - (void *)(pthread_setattr_default_np), - //BuiltIn(int) pthread_getattr_np(Use(TypeDef(pthread_t, Attributed(unsigned , BuiltIn(long)))), Pointer(Use(TypeDef(pthread_attr_t, Use(Union(union pthread_attr_t)))))); - (void *)(pthread_getattr_np), - //BuiltIn(int) pthread_setschedparam(Use(TypeDef(pthread_t, Attributed(unsigned , BuiltIn(long)))), BuiltIn(int), Pointer(Attributed(const , Use(Struct(struct sched_param))))); - (void *)(pthread_setschedparam), - //BuiltIn(int) pthread_getschedparam(Use(TypeDef(pthread_t, Attributed(unsigned , BuiltIn(long)))), Pointer(restrict BuiltIn(int)), Pointer(restrict Use(Struct(struct sched_param)))); - (void *)(pthread_getschedparam), - //BuiltIn(int) pthread_setschedprio(Use(TypeDef(pthread_t, Attributed(unsigned , BuiltIn(long)))), BuiltIn(int)); - (void *)(pthread_setschedprio), - //BuiltIn(int) pthread_getname_np(Use(TypeDef(pthread_t, Attributed(unsigned , BuiltIn(long)))), Pointer(BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(pthread_getname_np), - //BuiltIn(int) pthread_setname_np(Use(TypeDef(pthread_t, Attributed(unsigned , BuiltIn(long)))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(pthread_setname_np), - //BuiltIn(int) pthread_getconcurrency(); - (void *)(pthread_getconcurrency), - //BuiltIn(int) pthread_setconcurrency(BuiltIn(int)); - (void *)(pthread_setconcurrency), - //BuiltIn(int) pthread_yield(); - (void *)(pthread_yield), - //BuiltIn(int) pthread_setaffinity_np(Use(TypeDef(pthread_t, Attributed(unsigned , BuiltIn(long)))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Attributed(const , Use(TypeDef(cpu_set_t, Struct(struct anon_struct_614)))))); - (void *)(pthread_setaffinity_np), - //BuiltIn(int) pthread_getaffinity_np(Use(TypeDef(pthread_t, Attributed(unsigned , BuiltIn(long)))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Use(TypeDef(cpu_set_t, Struct(struct anon_struct_614))))); - (void *)(pthread_getaffinity_np), - // skipping because function pointer args: pthread_once - //BuiltIn(int) pthread_setcancelstate(BuiltIn(int), Pointer(BuiltIn(int))); - (void *)(pthread_setcancelstate), - //BuiltIn(int) pthread_setcanceltype(BuiltIn(int), Pointer(BuiltIn(int))); - (void *)(pthread_setcanceltype), - //BuiltIn(int) pthread_cancel(Use(TypeDef(pthread_t, Attributed(unsigned , BuiltIn(long))))); - (void *)(pthread_cancel), - //BuiltIn(void) pthread_testcancel(); - (void *)(pthread_testcancel), - //BuiltIn(void) __pthread_register_cancel(Pointer(Use(TypeDef(__pthread_unwind_buf_t, Attributed(__attribute__ ( ( __aligned__ ) ), Struct(struct anon_struct_619)))))); - (void *)(__pthread_register_cancel), - //BuiltIn(void) __pthread_unregister_cancel(Pointer(Use(TypeDef(__pthread_unwind_buf_t, Attributed(__attribute__ ( ( __aligned__ ) ), Struct(struct anon_struct_619)))))); - (void *)(__pthread_unregister_cancel), - //BuiltIn(void) __pthread_register_cancel_defer(Pointer(Use(TypeDef(__pthread_unwind_buf_t, Attributed(__attribute__ ( ( __aligned__ ) ), Struct(struct anon_struct_619)))))); - (void *)(__pthread_register_cancel_defer), - //BuiltIn(void) __pthread_unregister_cancel_restore(Pointer(Use(TypeDef(__pthread_unwind_buf_t, Attributed(__attribute__ ( ( __aligned__ ) ), Struct(struct anon_struct_619)))))); - (void *)(__pthread_unregister_cancel_restore), - //BuiltIn(void) __pthread_unwind_next(Pointer(Use(TypeDef(__pthread_unwind_buf_t, Attributed(__attribute__ ( ( __aligned__ ) ), Struct(struct anon_struct_619)))))); - (void *)(__pthread_unwind_next), - //BuiltIn(int) __sigsetjmp(Pointer(Use(Struct(struct __jmp_buf_tag))), BuiltIn(int)); - (void *)(__sigsetjmp), - //BuiltIn(int) pthread_mutex_init(Pointer(Use(TypeDef(pthread_mutex_t, Union(union anon_union_2)))), Pointer(Attributed(const , Use(TypeDef(pthread_mutexattr_t, Union(union anon_union_3)))))); - (void *)(pthread_mutex_init), - //BuiltIn(int) pthread_mutex_destroy(Pointer(Use(TypeDef(pthread_mutex_t, Union(union anon_union_2))))); - (void *)(pthread_mutex_destroy), - //BuiltIn(int) pthread_mutex_trylock(Pointer(Use(TypeDef(pthread_mutex_t, Union(union anon_union_2))))); - (void *)(pthread_mutex_trylock), - //BuiltIn(int) pthread_mutex_lock(Pointer(Use(TypeDef(pthread_mutex_t, Union(union anon_union_2))))); - (void *)(pthread_mutex_lock), - //BuiltIn(int) pthread_mutex_timedlock(Pointer(restrict Use(TypeDef(pthread_mutex_t, Union(union anon_union_2)))), Pointer(restrict Attributed(const , Use(Struct(struct timespec))))); - (void *)(pthread_mutex_timedlock), - //BuiltIn(int) pthread_mutex_unlock(Pointer(Use(TypeDef(pthread_mutex_t, Union(union anon_union_2))))); - (void *)(pthread_mutex_unlock), - //BuiltIn(int) pthread_mutex_getprioceiling(Pointer(restrict Attributed(const , Use(TypeDef(pthread_mutex_t, Union(union anon_union_2))))), Pointer(restrict BuiltIn(int))); - (void *)(pthread_mutex_getprioceiling), - //BuiltIn(int) pthread_mutex_setprioceiling(Pointer(restrict Use(TypeDef(pthread_mutex_t, Union(union anon_union_2)))), BuiltIn(int), Pointer(restrict BuiltIn(int))); - (void *)(pthread_mutex_setprioceiling), - //BuiltIn(int) pthread_mutex_consistent(Pointer(Use(TypeDef(pthread_mutex_t, Union(union anon_union_2))))); - (void *)(pthread_mutex_consistent), - //BuiltIn(int) pthread_mutex_consistent_np(Pointer(Use(TypeDef(pthread_mutex_t, Union(union anon_union_2))))); - (void *)(pthread_mutex_consistent_np), - //BuiltIn(int) pthread_mutexattr_init(Pointer(Use(TypeDef(pthread_mutexattr_t, Union(union anon_union_3))))); - (void *)(pthread_mutexattr_init), - //BuiltIn(int) pthread_mutexattr_destroy(Pointer(Use(TypeDef(pthread_mutexattr_t, Union(union anon_union_3))))); - (void *)(pthread_mutexattr_destroy), - //BuiltIn(int) pthread_mutexattr_getpshared(Pointer(restrict Attributed(const , Use(TypeDef(pthread_mutexattr_t, Union(union anon_union_3))))), Pointer(restrict BuiltIn(int))); - (void *)(pthread_mutexattr_getpshared), - //BuiltIn(int) pthread_mutexattr_setpshared(Pointer(Use(TypeDef(pthread_mutexattr_t, Union(union anon_union_3)))), BuiltIn(int)); - (void *)(pthread_mutexattr_setpshared), - //BuiltIn(int) pthread_mutexattr_gettype(Pointer(restrict Attributed(const , Use(TypeDef(pthread_mutexattr_t, Union(union anon_union_3))))), Pointer(restrict BuiltIn(int))); - (void *)(pthread_mutexattr_gettype), - //BuiltIn(int) pthread_mutexattr_settype(Pointer(Use(TypeDef(pthread_mutexattr_t, Union(union anon_union_3)))), BuiltIn(int)); - (void *)(pthread_mutexattr_settype), - //BuiltIn(int) pthread_mutexattr_getprotocol(Pointer(restrict Attributed(const , Use(TypeDef(pthread_mutexattr_t, Union(union anon_union_3))))), Pointer(restrict BuiltIn(int))); - (void *)(pthread_mutexattr_getprotocol), - //BuiltIn(int) pthread_mutexattr_setprotocol(Pointer(Use(TypeDef(pthread_mutexattr_t, Union(union anon_union_3)))), BuiltIn(int)); - (void *)(pthread_mutexattr_setprotocol), - //BuiltIn(int) pthread_mutexattr_getprioceiling(Pointer(restrict Attributed(const , Use(TypeDef(pthread_mutexattr_t, Union(union anon_union_3))))), Pointer(restrict BuiltIn(int))); - (void *)(pthread_mutexattr_getprioceiling), - //BuiltIn(int) pthread_mutexattr_setprioceiling(Pointer(Use(TypeDef(pthread_mutexattr_t, Union(union anon_union_3)))), BuiltIn(int)); - (void *)(pthread_mutexattr_setprioceiling), - //BuiltIn(int) pthread_mutexattr_getrobust(Pointer(Attributed(const , Use(TypeDef(pthread_mutexattr_t, Union(union anon_union_3))))), Pointer(BuiltIn(int))); - (void *)(pthread_mutexattr_getrobust), - //BuiltIn(int) pthread_mutexattr_getrobust_np(Pointer(Attributed(const , Use(TypeDef(pthread_mutexattr_t, Union(union anon_union_3))))), Pointer(BuiltIn(int))); - (void *)(pthread_mutexattr_getrobust_np), - //BuiltIn(int) pthread_mutexattr_setrobust(Pointer(Use(TypeDef(pthread_mutexattr_t, Union(union anon_union_3)))), BuiltIn(int)); - (void *)(pthread_mutexattr_setrobust), - //BuiltIn(int) pthread_mutexattr_setrobust_np(Pointer(Use(TypeDef(pthread_mutexattr_t, Union(union anon_union_3)))), BuiltIn(int)); - (void *)(pthread_mutexattr_setrobust_np), - //BuiltIn(int) pthread_rwlock_init(Pointer(restrict Use(TypeDef(pthread_rwlock_t, Union(union anon_union_6)))), Pointer(restrict Attributed(const , Use(TypeDef(pthread_rwlockattr_t, Union(union anon_union_7)))))); - (void *)(pthread_rwlock_init), - //BuiltIn(int) pthread_rwlock_destroy(Pointer(Use(TypeDef(pthread_rwlock_t, Union(union anon_union_6))))); - (void *)(pthread_rwlock_destroy), - //BuiltIn(int) pthread_rwlock_rdlock(Pointer(Use(TypeDef(pthread_rwlock_t, Union(union anon_union_6))))); - (void *)(pthread_rwlock_rdlock), - //BuiltIn(int) pthread_rwlock_tryrdlock(Pointer(Use(TypeDef(pthread_rwlock_t, Union(union anon_union_6))))); - (void *)(pthread_rwlock_tryrdlock), - //BuiltIn(int) pthread_rwlock_timedrdlock(Pointer(restrict Use(TypeDef(pthread_rwlock_t, Union(union anon_union_6)))), Pointer(restrict Attributed(const , Use(Struct(struct timespec))))); - (void *)(pthread_rwlock_timedrdlock), - //BuiltIn(int) pthread_rwlock_wrlock(Pointer(Use(TypeDef(pthread_rwlock_t, Union(union anon_union_6))))); - (void *)(pthread_rwlock_wrlock), - //BuiltIn(int) pthread_rwlock_trywrlock(Pointer(Use(TypeDef(pthread_rwlock_t, Union(union anon_union_6))))); - (void *)(pthread_rwlock_trywrlock), - //BuiltIn(int) pthread_rwlock_timedwrlock(Pointer(restrict Use(TypeDef(pthread_rwlock_t, Union(union anon_union_6)))), Pointer(restrict Attributed(const , Use(Struct(struct timespec))))); - (void *)(pthread_rwlock_timedwrlock), - //BuiltIn(int) pthread_rwlock_unlock(Pointer(Use(TypeDef(pthread_rwlock_t, Union(union anon_union_6))))); - (void *)(pthread_rwlock_unlock), - //BuiltIn(int) pthread_rwlockattr_init(Pointer(Use(TypeDef(pthread_rwlockattr_t, Union(union anon_union_7))))); - (void *)(pthread_rwlockattr_init), - //BuiltIn(int) pthread_rwlockattr_destroy(Pointer(Use(TypeDef(pthread_rwlockattr_t, Union(union anon_union_7))))); - (void *)(pthread_rwlockattr_destroy), - //BuiltIn(int) pthread_rwlockattr_getpshared(Pointer(restrict Attributed(const , Use(TypeDef(pthread_rwlockattr_t, Union(union anon_union_7))))), Pointer(restrict BuiltIn(int))); - (void *)(pthread_rwlockattr_getpshared), - //BuiltIn(int) pthread_rwlockattr_setpshared(Pointer(Use(TypeDef(pthread_rwlockattr_t, Union(union anon_union_7)))), BuiltIn(int)); - (void *)(pthread_rwlockattr_setpshared), - //BuiltIn(int) pthread_rwlockattr_getkind_np(Pointer(restrict Attributed(const , Use(TypeDef(pthread_rwlockattr_t, Union(union anon_union_7))))), Pointer(restrict BuiltIn(int))); - (void *)(pthread_rwlockattr_getkind_np), - //BuiltIn(int) pthread_rwlockattr_setkind_np(Pointer(Use(TypeDef(pthread_rwlockattr_t, Union(union anon_union_7)))), BuiltIn(int)); - (void *)(pthread_rwlockattr_setkind_np), - //BuiltIn(int) pthread_cond_init(Pointer(restrict Use(TypeDef(pthread_cond_t, Union(union anon_union_4)))), Pointer(restrict Attributed(const , Use(TypeDef(pthread_condattr_t, Union(union anon_union_5)))))); - (void *)(pthread_cond_init), - //BuiltIn(int) pthread_cond_destroy(Pointer(Use(TypeDef(pthread_cond_t, Union(union anon_union_4))))); - (void *)(pthread_cond_destroy), - //BuiltIn(int) pthread_cond_signal(Pointer(Use(TypeDef(pthread_cond_t, Union(union anon_union_4))))); - (void *)(pthread_cond_signal), - //BuiltIn(int) pthread_cond_broadcast(Pointer(Use(TypeDef(pthread_cond_t, Union(union anon_union_4))))); - (void *)(pthread_cond_broadcast), - //BuiltIn(int) pthread_cond_wait(Pointer(restrict Use(TypeDef(pthread_cond_t, Union(union anon_union_4)))), Pointer(restrict Use(TypeDef(pthread_mutex_t, Union(union anon_union_2))))); - (void *)(pthread_cond_wait), - //BuiltIn(int) pthread_cond_timedwait(Pointer(restrict Use(TypeDef(pthread_cond_t, Union(union anon_union_4)))), Pointer(restrict Use(TypeDef(pthread_mutex_t, Union(union anon_union_2)))), Pointer(restrict Attributed(const , Use(Struct(struct timespec))))); - (void *)(pthread_cond_timedwait), - //BuiltIn(int) pthread_condattr_init(Pointer(Use(TypeDef(pthread_condattr_t, Union(union anon_union_5))))); - (void *)(pthread_condattr_init), - //BuiltIn(int) pthread_condattr_destroy(Pointer(Use(TypeDef(pthread_condattr_t, Union(union anon_union_5))))); - (void *)(pthread_condattr_destroy), - //BuiltIn(int) pthread_condattr_getpshared(Pointer(restrict Attributed(const , Use(TypeDef(pthread_condattr_t, Union(union anon_union_5))))), Pointer(restrict BuiltIn(int))); - (void *)(pthread_condattr_getpshared), - //BuiltIn(int) pthread_condattr_setpshared(Pointer(Use(TypeDef(pthread_condattr_t, Union(union anon_union_5)))), BuiltIn(int)); - (void *)(pthread_condattr_setpshared), - //BuiltIn(int) pthread_condattr_getclock(Pointer(restrict Attributed(const , Use(TypeDef(pthread_condattr_t, Union(union anon_union_5))))), Pointer(restrict Use(TypeDef(__clockid_t, BuiltIn(int))))); - (void *)(pthread_condattr_getclock), - //BuiltIn(int) pthread_condattr_setclock(Pointer(Use(TypeDef(pthread_condattr_t, Union(union anon_union_5)))), Use(TypeDef(__clockid_t, BuiltIn(int)))); - (void *)(pthread_condattr_setclock), - //BuiltIn(int) pthread_spin_init(Pointer(Use(TypeDef(pthread_spinlock_t, Attributed(volatile , BuiltIn(int))))), BuiltIn(int)); - (void *)(pthread_spin_init), - //BuiltIn(int) pthread_spin_destroy(Pointer(Use(TypeDef(pthread_spinlock_t, Attributed(volatile , BuiltIn(int)))))); - (void *)(pthread_spin_destroy), - //BuiltIn(int) pthread_spin_lock(Pointer(Use(TypeDef(pthread_spinlock_t, Attributed(volatile , BuiltIn(int)))))); - (void *)(pthread_spin_lock), - //BuiltIn(int) pthread_spin_trylock(Pointer(Use(TypeDef(pthread_spinlock_t, Attributed(volatile , BuiltIn(int)))))); - (void *)(pthread_spin_trylock), - //BuiltIn(int) pthread_spin_unlock(Pointer(Use(TypeDef(pthread_spinlock_t, Attributed(volatile , BuiltIn(int)))))); - (void *)(pthread_spin_unlock), - //BuiltIn(int) pthread_barrier_init(Pointer(restrict Use(TypeDef(pthread_barrier_t, Union(union anon_union_8)))), Pointer(restrict Attributed(const , Use(TypeDef(pthread_barrierattr_t, Union(union anon_union_9))))), Attributed(unsigned , BuiltIn(int))); - (void *)(pthread_barrier_init), - //BuiltIn(int) pthread_barrier_destroy(Pointer(Use(TypeDef(pthread_barrier_t, Union(union anon_union_8))))); - (void *)(pthread_barrier_destroy), - //BuiltIn(int) pthread_barrier_wait(Pointer(Use(TypeDef(pthread_barrier_t, Union(union anon_union_8))))); - (void *)(pthread_barrier_wait), - //BuiltIn(int) pthread_barrierattr_init(Pointer(Use(TypeDef(pthread_barrierattr_t, Union(union anon_union_9))))); - (void *)(pthread_barrierattr_init), - //BuiltIn(int) pthread_barrierattr_destroy(Pointer(Use(TypeDef(pthread_barrierattr_t, Union(union anon_union_9))))); - (void *)(pthread_barrierattr_destroy), - //BuiltIn(int) pthread_barrierattr_getpshared(Pointer(restrict Attributed(const , Use(TypeDef(pthread_barrierattr_t, Union(union anon_union_9))))), Pointer(restrict BuiltIn(int))); - (void *)(pthread_barrierattr_getpshared), - //BuiltIn(int) pthread_barrierattr_setpshared(Pointer(Use(TypeDef(pthread_barrierattr_t, Union(union anon_union_9)))), BuiltIn(int)); - (void *)(pthread_barrierattr_setpshared), - // skipping because function pointer args: pthread_key_create - //BuiltIn(int) pthread_key_delete(Use(TypeDef(pthread_key_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(pthread_key_delete), - //Pointer(BuiltIn(void)) pthread_getspecific(Use(TypeDef(pthread_key_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(pthread_getspecific), - //BuiltIn(int) pthread_setspecific(Use(TypeDef(pthread_key_t, Attributed(unsigned , BuiltIn(int)))), Pointer(Attributed(const , BuiltIn(void)))); - (void *)(pthread_setspecific), - //BuiltIn(int) pthread_getcpuclockid(Use(TypeDef(pthread_t, Attributed(unsigned , BuiltIn(long)))), Pointer(Use(TypeDef(__clockid_t, BuiltIn(int))))); - (void *)(pthread_getcpuclockid), - // skipping because function pointer args: pthread_atfork - //Use(TypeDef(td_err_e, Enum(enum anon_enum_169))) td_init(); - (void *)(td_init), - //Use(TypeDef(td_err_e, Enum(enum anon_enum_169))) td_log(); - (void *)(td_log), - //Pointer(Pointer(Attributed(const , BuiltIn(char)))) td_symbol_list(); - (void *)(td_symbol_list), - //Use(TypeDef(td_err_e, Enum(enum anon_enum_169))) td_ta_new(Pointer(Use(Struct(struct ps_prochandle))), Pointer(Pointer(Use(TypeDef(td_thragent_t, Use(Struct(struct td_thragent))))))); - (void *)(td_ta_new), - //Use(TypeDef(td_err_e, Enum(enum anon_enum_169))) td_ta_delete(Pointer(Use(TypeDef(td_thragent_t, Use(Struct(struct td_thragent)))))); - (void *)(td_ta_delete), - //Use(TypeDef(td_err_e, Enum(enum anon_enum_169))) td_ta_get_nthreads(Pointer(Attributed(const , Use(TypeDef(td_thragent_t, Use(Struct(struct td_thragent)))))), Pointer(BuiltIn(int))); - (void *)(td_ta_get_nthreads), - //Use(TypeDef(td_err_e, Enum(enum anon_enum_169))) td_ta_get_ph(Pointer(Attributed(const , Use(TypeDef(td_thragent_t, Use(Struct(struct td_thragent)))))), Pointer(Pointer(Use(Struct(struct ps_prochandle))))); - (void *)(td_ta_get_ph), - //Use(TypeDef(td_err_e, Enum(enum anon_enum_169))) td_ta_map_id2thr(Pointer(Attributed(const , Use(TypeDef(td_thragent_t, Use(Struct(struct td_thragent)))))), Use(TypeDef(pthread_t, Attributed(unsigned , BuiltIn(long)))), Pointer(Use(TypeDef(td_thrhandle_t, Struct(struct td_thrhandle))))); - (void *)(td_ta_map_id2thr), - //Use(TypeDef(td_err_e, Enum(enum anon_enum_169))) td_ta_map_lwp2thr(Pointer(Attributed(const , Use(TypeDef(td_thragent_t, Use(Struct(struct td_thragent)))))), Use(TypeDef(lwpid_t, Use(TypeDef(__pid_t, BuiltIn(int))))), Pointer(Use(TypeDef(td_thrhandle_t, Struct(struct td_thrhandle))))); - (void *)(td_ta_map_lwp2thr), - // skipping because function pointer args: td_ta_thr_iter - // skipping because function pointer args: td_ta_tsd_iter - //Use(TypeDef(td_err_e, Enum(enum anon_enum_169))) td_ta_event_addr(Pointer(Attributed(const , Use(TypeDef(td_thragent_t, Use(Struct(struct td_thragent)))))), Use(TypeDef(td_event_e, Enum(enum anon_enum_172))), Pointer(Use(TypeDef(td_notify_t, Struct(struct td_notify))))); - (void *)(td_ta_event_addr), - //Use(TypeDef(td_err_e, Enum(enum anon_enum_169))) td_ta_set_event(Pointer(Attributed(const , Use(TypeDef(td_thragent_t, Use(Struct(struct td_thragent)))))), Pointer(Use(TypeDef(td_thr_events_t, Struct(struct td_thr_events))))); - (void *)(td_ta_set_event), - //Use(TypeDef(td_err_e, Enum(enum anon_enum_169))) td_ta_clear_event(Pointer(Attributed(const , Use(TypeDef(td_thragent_t, Use(Struct(struct td_thragent)))))), Pointer(Use(TypeDef(td_thr_events_t, Struct(struct td_thr_events))))); - (void *)(td_ta_clear_event), - //Use(TypeDef(td_err_e, Enum(enum anon_enum_169))) td_ta_event_getmsg(Pointer(Attributed(const , Use(TypeDef(td_thragent_t, Use(Struct(struct td_thragent)))))), Pointer(Use(TypeDef(td_event_msg_t, Struct(struct td_event_msg))))); - (void *)(td_ta_event_getmsg), - //Use(TypeDef(td_err_e, Enum(enum anon_enum_169))) td_ta_setconcurrency(Pointer(Attributed(const , Use(TypeDef(td_thragent_t, Use(Struct(struct td_thragent)))))), BuiltIn(int)); - (void *)(td_ta_setconcurrency), - //Use(TypeDef(td_err_e, Enum(enum anon_enum_169))) td_ta_enable_stats(Pointer(Attributed(const , Use(TypeDef(td_thragent_t, Use(Struct(struct td_thragent)))))), BuiltIn(int)); - (void *)(td_ta_enable_stats), - //Use(TypeDef(td_err_e, Enum(enum anon_enum_169))) td_ta_reset_stats(Pointer(Attributed(const , Use(TypeDef(td_thragent_t, Use(Struct(struct td_thragent))))))); - (void *)(td_ta_reset_stats), - //Use(TypeDef(td_err_e, Enum(enum anon_enum_169))) td_ta_get_stats(Pointer(Attributed(const , Use(TypeDef(td_thragent_t, Use(Struct(struct td_thragent)))))), Pointer(Use(TypeDef(td_ta_stats_t, Struct(struct td_ta_stats))))); - (void *)(td_ta_get_stats), - //Use(TypeDef(td_err_e, Enum(enum anon_enum_169))) td_thr_validate(Pointer(Attributed(const , Use(TypeDef(td_thrhandle_t, Struct(struct td_thrhandle)))))); - (void *)(td_thr_validate), - //Use(TypeDef(td_err_e, Enum(enum anon_enum_169))) td_thr_get_info(Pointer(Attributed(const , Use(TypeDef(td_thrhandle_t, Struct(struct td_thrhandle))))), Pointer(Use(TypeDef(td_thrinfo_t, Struct(struct td_thrinfo))))); - (void *)(td_thr_get_info), - //Use(TypeDef(td_err_e, Enum(enum anon_enum_169))) td_thr_getfpregs(Pointer(Attributed(const , Use(TypeDef(td_thrhandle_t, Struct(struct td_thrhandle))))), Pointer(Use(TypeDef(prfpregset_t, Use(TypeDef(elf_fpregset_t, Use(Struct(struct user_fpregs_struct)))))))); - (void *)(td_thr_getfpregs), - //Use(TypeDef(td_err_e, Enum(enum anon_enum_169))) td_thr_getgregs(Pointer(Attributed(const , Use(TypeDef(td_thrhandle_t, Struct(struct td_thrhandle))))), Use(TypeDef(prgregset_t, Use(TypeDef(elf_gregset_t, Array(Use(TypeDef(elf_greg_t, Attributed(__extension__, Attributed(unsigned , BuiltIn(long long))))))))))); - (void *)(td_thr_getgregs), - //Use(TypeDef(td_err_e, Enum(enum anon_enum_169))) td_thr_getxregs(Pointer(Attributed(const , Use(TypeDef(td_thrhandle_t, Struct(struct td_thrhandle))))), Pointer(BuiltIn(void))); - (void *)(td_thr_getxregs), - //Use(TypeDef(td_err_e, Enum(enum anon_enum_169))) td_thr_getxregsize(Pointer(Attributed(const , Use(TypeDef(td_thrhandle_t, Struct(struct td_thrhandle))))), Pointer(BuiltIn(int))); - (void *)(td_thr_getxregsize), - //Use(TypeDef(td_err_e, Enum(enum anon_enum_169))) td_thr_setfpregs(Pointer(Attributed(const , Use(TypeDef(td_thrhandle_t, Struct(struct td_thrhandle))))), Pointer(Attributed(const , Use(TypeDef(prfpregset_t, Use(TypeDef(elf_fpregset_t, Use(Struct(struct user_fpregs_struct))))))))); - (void *)(td_thr_setfpregs), - //Use(TypeDef(td_err_e, Enum(enum anon_enum_169))) td_thr_setgregs(Pointer(Attributed(const , Use(TypeDef(td_thrhandle_t, Struct(struct td_thrhandle))))), Use(TypeDef(prgregset_t, Use(TypeDef(elf_gregset_t, Array(Use(TypeDef(elf_greg_t, Attributed(__extension__, Attributed(unsigned , BuiltIn(long long))))))))))); - (void *)(td_thr_setgregs), - //Use(TypeDef(td_err_e, Enum(enum anon_enum_169))) td_thr_setxregs(Pointer(Attributed(const , Use(TypeDef(td_thrhandle_t, Struct(struct td_thrhandle))))), Pointer(Attributed(const , BuiltIn(void)))); - (void *)(td_thr_setxregs), - //Use(TypeDef(td_err_e, Enum(enum anon_enum_169))) td_thr_tlsbase(Pointer(Attributed(const , Use(TypeDef(td_thrhandle_t, Struct(struct td_thrhandle))))), Attributed(unsigned , BuiltIn(long)), Pointer(Use(TypeDef(psaddr_t, Pointer(BuiltIn(void)))))); - (void *)(td_thr_tlsbase), - //Use(TypeDef(td_err_e, Enum(enum anon_enum_169))) td_thr_tls_get_addr(Pointer(Attributed(const , Use(TypeDef(td_thrhandle_t, Struct(struct td_thrhandle))))), Use(TypeDef(psaddr_t, Pointer(BuiltIn(void)))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Use(TypeDef(psaddr_t, Pointer(BuiltIn(void)))))); - (void *)(td_thr_tls_get_addr), - //Use(TypeDef(td_err_e, Enum(enum anon_enum_169))) td_thr_event_enable(Pointer(Attributed(const , Use(TypeDef(td_thrhandle_t, Struct(struct td_thrhandle))))), BuiltIn(int)); - (void *)(td_thr_event_enable), - //Use(TypeDef(td_err_e, Enum(enum anon_enum_169))) td_thr_set_event(Pointer(Attributed(const , Use(TypeDef(td_thrhandle_t, Struct(struct td_thrhandle))))), Pointer(Use(TypeDef(td_thr_events_t, Struct(struct td_thr_events))))); - (void *)(td_thr_set_event), - //Use(TypeDef(td_err_e, Enum(enum anon_enum_169))) td_thr_clear_event(Pointer(Attributed(const , Use(TypeDef(td_thrhandle_t, Struct(struct td_thrhandle))))), Pointer(Use(TypeDef(td_thr_events_t, Struct(struct td_thr_events))))); - (void *)(td_thr_clear_event), - //Use(TypeDef(td_err_e, Enum(enum anon_enum_169))) td_thr_event_getmsg(Pointer(Attributed(const , Use(TypeDef(td_thrhandle_t, Struct(struct td_thrhandle))))), Pointer(Use(TypeDef(td_event_msg_t, Struct(struct td_event_msg))))); - (void *)(td_thr_event_getmsg), - //Use(TypeDef(td_err_e, Enum(enum anon_enum_169))) td_thr_setprio(Pointer(Attributed(const , Use(TypeDef(td_thrhandle_t, Struct(struct td_thrhandle))))), BuiltIn(int)); - (void *)(td_thr_setprio), - //Use(TypeDef(td_err_e, Enum(enum anon_enum_169))) td_thr_setsigpending(Pointer(Attributed(const , Use(TypeDef(td_thrhandle_t, Struct(struct td_thrhandle))))), Attributed(unsigned , BuiltIn(char)), Pointer(Attributed(const , Use(TypeDef(sigset_t, Use(TypeDef(__sigset_t, Struct(struct anon_struct_23)))))))); - (void *)(td_thr_setsigpending), - //Use(TypeDef(td_err_e, Enum(enum anon_enum_169))) td_thr_sigsetmask(Pointer(Attributed(const , Use(TypeDef(td_thrhandle_t, Struct(struct td_thrhandle))))), Pointer(Attributed(const , Use(TypeDef(sigset_t, Use(TypeDef(__sigset_t, Struct(struct anon_struct_23)))))))); - (void *)(td_thr_sigsetmask), - //Use(TypeDef(td_err_e, Enum(enum anon_enum_169))) td_thr_tsd(Pointer(Attributed(const , Use(TypeDef(td_thrhandle_t, Struct(struct td_thrhandle))))), Attributed(const , Use(TypeDef(thread_key_t, Use(TypeDef(pthread_key_t, Attributed(unsigned , BuiltIn(int))))))), Pointer(Pointer(BuiltIn(void)))); - (void *)(td_thr_tsd), - //Use(TypeDef(td_err_e, Enum(enum anon_enum_169))) td_thr_dbsuspend(Pointer(Attributed(const , Use(TypeDef(td_thrhandle_t, Struct(struct td_thrhandle)))))); - (void *)(td_thr_dbsuspend), - //Use(TypeDef(td_err_e, Enum(enum anon_enum_169))) td_thr_dbresume(Pointer(Attributed(const , Use(TypeDef(td_thrhandle_t, Struct(struct td_thrhandle)))))); - (void *)(td_thr_dbresume), - // skipping because function pointer args: register_printf_specifier - // skipping because function pointer args: register_printf_function - //BuiltIn(int) register_printf_modifier(Pointer(Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int)))))); - (void *)(register_printf_modifier), - // skipping because function pointer args: register_printf_type - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) parse_printf_format(Pointer(restrict Attributed(const , BuiltIn(char))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict BuiltIn(int))); - (void *)(parse_printf_format), - //BuiltIn(int) printf_size(Pointer(restrict Use(TypeDef(FILE, Use(Struct(struct _IO_FILE))))), Pointer(Attributed(const , Use(Struct(struct printf_info)))), Pointer(restrict Pointer(const Attributed(const , BuiltIn(void))))); - (void *)(printf_size), - //BuiltIn(int) printf_size_info(Pointer(restrict Attributed(const , Use(Struct(struct printf_info)))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict BuiltIn(int))); - (void *)(printf_size_info), - // skipping because varargs function: strfmon - // skipping because varargs function: strfmon_l - //Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE))))) setmntent(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(setmntent), - //Pointer(Use(Struct(struct mntent))) getmntent(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(getmntent), - //Pointer(Use(Struct(struct mntent))) getmntent_r(Pointer(restrict Use(TypeDef(FILE, Use(Struct(struct _IO_FILE))))), Pointer(restrict Use(Struct(struct mntent))), Pointer(restrict BuiltIn(char)), BuiltIn(int)); - (void *)(getmntent_r), - //BuiltIn(int) addmntent(Pointer(restrict Use(TypeDef(FILE, Use(Struct(struct _IO_FILE))))), Pointer(restrict Attributed(const , Use(Struct(struct mntent))))); - (void *)(addmntent), - //BuiltIn(int) endmntent(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(endmntent), - //Pointer(BuiltIn(char)) hasmntopt(Pointer(Attributed(const , Use(Struct(struct mntent)))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(hasmntopt), - //Use(TypeDef(nl_catd, Pointer(BuiltIn(void)))) catopen(Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int)); - (void *)(catopen), - //Pointer(BuiltIn(char)) catgets(Use(TypeDef(nl_catd, Pointer(BuiltIn(void)))), BuiltIn(int), BuiltIn(int), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(catgets), - //BuiltIn(int) catclose(Use(TypeDef(nl_catd, Pointer(BuiltIn(void))))); - (void *)(catclose), - //Pointer(BuiltIn(char)) nl_langinfo(Use(TypeDef(nl_item, BuiltIn(int)))); - (void *)(nl_langinfo), - //Pointer(BuiltIn(char)) nl_langinfo_l(Use(TypeDef(nl_item, BuiltIn(int))), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(nl_langinfo_l), - //Use(TypeDef(reg_syntax_t, Attributed(unsigned , BuiltIn(long)))) re_set_syntax(Use(TypeDef(reg_syntax_t, Attributed(unsigned , BuiltIn(long))))); - (void *)(re_set_syntax), - //Pointer(Attributed(const , BuiltIn(char))) re_compile_pattern(Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Use(Struct(struct re_pattern_buffer)))); - (void *)(re_compile_pattern), - //BuiltIn(int) re_compile_fastmap(Pointer(Use(Struct(struct re_pattern_buffer)))); - (void *)(re_compile_fastmap), - //BuiltIn(int) re_search(Pointer(Use(Struct(struct re_pattern_buffer))), Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int), BuiltIn(int), BuiltIn(int), Pointer(Use(Struct(struct re_registers)))); - (void *)(re_search), - //BuiltIn(int) re_search_2(Pointer(Use(Struct(struct re_pattern_buffer))), Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int), Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int), BuiltIn(int), BuiltIn(int), Pointer(Use(Struct(struct re_registers))), BuiltIn(int)); - (void *)(re_search_2), - //BuiltIn(int) re_match(Pointer(Use(Struct(struct re_pattern_buffer))), Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int), BuiltIn(int), Pointer(Use(Struct(struct re_registers)))); - (void *)(re_match), - //BuiltIn(int) re_match_2(Pointer(Use(Struct(struct re_pattern_buffer))), Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int), Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int), BuiltIn(int), Pointer(Use(Struct(struct re_registers))), BuiltIn(int)); - (void *)(re_match_2), - //BuiltIn(void) re_set_registers(Pointer(Use(Struct(struct re_pattern_buffer))), Pointer(Use(Struct(struct re_registers))), Attributed(unsigned , BuiltIn(int)), Pointer(Use(TypeDef(regoff_t, BuiltIn(int)))), Pointer(Use(TypeDef(regoff_t, BuiltIn(int))))); - (void *)(re_set_registers), - //Pointer(BuiltIn(char)) re_comp(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(re_comp), - //BuiltIn(int) re_exec(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(re_exec), - //BuiltIn(int) regcomp(Pointer(restrict Use(TypeDef(regex_t, Use(Struct(struct re_pattern_buffer))))), Pointer(restrict Attributed(const , BuiltIn(char))), BuiltIn(int)); - (void *)(regcomp), - //BuiltIn(int) regexec(Pointer(restrict Attributed(const , Use(TypeDef(regex_t, Use(Struct(struct re_pattern_buffer)))))), Pointer(restrict Attributed(const , BuiltIn(char))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Array(Use(TypeDef(regmatch_t, Struct(struct anon_struct_636)))), BuiltIn(int)); - (void *)(regexec), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) regerror(BuiltIn(int), Pointer(restrict Attributed(const , Use(TypeDef(regex_t, Use(Struct(struct re_pattern_buffer)))))), Pointer(restrict BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(regerror), - //BuiltIn(void) regfree(Pointer(Use(TypeDef(regex_t, Use(Struct(struct re_pattern_buffer)))))); - (void *)(regfree), - //BuiltIn(int) sem_init(Pointer(Use(TypeDef(sem_t, Union(union anon_union_84)))), BuiltIn(int), Attributed(unsigned , BuiltIn(int))); - (void *)(sem_init), - //BuiltIn(int) sem_destroy(Pointer(Use(TypeDef(sem_t, Union(union anon_union_84))))); - (void *)(sem_destroy), - // skipping because varargs function: sem_open - //BuiltIn(int) sem_close(Pointer(Use(TypeDef(sem_t, Union(union anon_union_84))))); - (void *)(sem_close), - //BuiltIn(int) sem_unlink(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(sem_unlink), - //BuiltIn(int) sem_wait(Pointer(Use(TypeDef(sem_t, Union(union anon_union_84))))); - (void *)(sem_wait), - //BuiltIn(int) sem_timedwait(Pointer(restrict Use(TypeDef(sem_t, Union(union anon_union_84)))), Pointer(restrict Attributed(const , Use(Struct(struct timespec))))); - (void *)(sem_timedwait), - //BuiltIn(int) sem_trywait(Pointer(Use(TypeDef(sem_t, Union(union anon_union_84))))); - (void *)(sem_trywait), - //BuiltIn(int) sem_post(Pointer(Use(TypeDef(sem_t, Union(union anon_union_84))))); - (void *)(sem_post), - //BuiltIn(int) sem_getvalue(Pointer(restrict Use(TypeDef(sem_t, Union(union anon_union_84)))), Pointer(restrict BuiltIn(int))); - (void *)(sem_getvalue), - //Use(TypeDef(error_t, BuiltIn(int))) __argz_create(Array(Pointer(const BuiltIn(char))), Pointer(restrict Pointer(BuiltIn(char))), Pointer(restrict Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))))); - (void *)(__argz_create), - //Use(TypeDef(error_t, BuiltIn(int))) argz_create(Array(Pointer(const BuiltIn(char))), Pointer(restrict Pointer(BuiltIn(char))), Pointer(restrict Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))))); - (void *)(argz_create), - //Use(TypeDef(error_t, BuiltIn(int))) argz_create_sep(Pointer(restrict Attributed(const , BuiltIn(char))), BuiltIn(int), Pointer(restrict Pointer(BuiltIn(char))), Pointer(restrict Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))))); - (void *)(argz_create_sep), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) __argz_count(Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(__argz_count), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) argz_count(Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(argz_count), - //BuiltIn(void) __argz_extract(Pointer(restrict Attributed(const , BuiltIn(char))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Pointer(BuiltIn(char)))); - (void *)(__argz_extract), - //BuiltIn(void) argz_extract(Pointer(restrict Attributed(const , BuiltIn(char))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Pointer(BuiltIn(char)))); - (void *)(argz_extract), - //BuiltIn(void) __argz_stringify(Pointer(BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), BuiltIn(int)); - (void *)(__argz_stringify), - //BuiltIn(void) argz_stringify(Pointer(BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), BuiltIn(int)); - (void *)(argz_stringify), - //Use(TypeDef(error_t, BuiltIn(int))) argz_append(Pointer(restrict Pointer(BuiltIn(char))), Pointer(restrict Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))), Pointer(restrict Attributed(const , BuiltIn(char))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(argz_append), - //Use(TypeDef(error_t, BuiltIn(int))) argz_add(Pointer(restrict Pointer(BuiltIn(char))), Pointer(restrict Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))), Pointer(restrict Attributed(const , BuiltIn(char)))); - (void *)(argz_add), - //Use(TypeDef(error_t, BuiltIn(int))) argz_add_sep(Pointer(restrict Pointer(BuiltIn(char))), Pointer(restrict Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))), Pointer(restrict Attributed(const , BuiltIn(char))), BuiltIn(int)); - (void *)(argz_add_sep), - //BuiltIn(void) argz_delete(Pointer(restrict Pointer(BuiltIn(char))), Pointer(restrict Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))), Pointer(restrict BuiltIn(char))); - (void *)(argz_delete), - //Use(TypeDef(error_t, BuiltIn(int))) argz_insert(Pointer(restrict Pointer(BuiltIn(char))), Pointer(restrict Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))), Pointer(restrict BuiltIn(char)), Pointer(restrict Attributed(const , BuiltIn(char)))); - (void *)(argz_insert), - //Use(TypeDef(error_t, BuiltIn(int))) argz_replace(Pointer(restrict Pointer(BuiltIn(char))), Pointer(restrict Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))), Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Attributed(unsigned , BuiltIn(int)))); - (void *)(argz_replace), - //Pointer(BuiltIn(char)) __argz_next(Pointer(restrict Attributed(const , BuiltIn(char))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Attributed(const , BuiltIn(char)))); - (void *)(__argz_next), - //Pointer(BuiltIn(char)) argz_next(Pointer(restrict Attributed(const , BuiltIn(char))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Attributed(const , BuiltIn(char)))); - (void *)(argz_next), - //Pointer(BuiltIn(char)) gettext(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(gettext), - //Pointer(BuiltIn(char)) dgettext(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(dgettext), - //Pointer(BuiltIn(char)) __dgettext(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(__dgettext), - //Pointer(BuiltIn(char)) dcgettext(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int)); - (void *)(dcgettext), - //Pointer(BuiltIn(char)) __dcgettext(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int)); - (void *)(__dcgettext), - //Pointer(BuiltIn(char)) ngettext(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), Attributed(unsigned , BuiltIn(long))); - (void *)(ngettext), - //Pointer(BuiltIn(char)) dngettext(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), Attributed(unsigned , BuiltIn(long))); - (void *)(dngettext), - //Pointer(BuiltIn(char)) dcngettext(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), Attributed(unsigned , BuiltIn(long)), BuiltIn(int)); - (void *)(dcngettext), - //Pointer(BuiltIn(char)) textdomain(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(textdomain), - //Pointer(BuiltIn(char)) bindtextdomain(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(bindtextdomain), - //Pointer(BuiltIn(char)) bind_textdomain_codeset(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(bind_textdomain_codeset), - //BuiltIn(int) iswalnum(Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(iswalnum), - //BuiltIn(int) iswalpha(Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(iswalpha), - //BuiltIn(int) iswcntrl(Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(iswcntrl), - //BuiltIn(int) iswdigit(Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(iswdigit), - //BuiltIn(int) iswgraph(Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(iswgraph), - //BuiltIn(int) iswlower(Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(iswlower), - //BuiltIn(int) iswprint(Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(iswprint), - //BuiltIn(int) iswpunct(Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(iswpunct), - //BuiltIn(int) iswspace(Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(iswspace), - //BuiltIn(int) iswupper(Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(iswupper), - //BuiltIn(int) iswxdigit(Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(iswxdigit), - //BuiltIn(int) iswblank(Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(iswblank), - //Use(TypeDef(wctype_t, Attributed(unsigned , BuiltIn(long)))) wctype(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(wctype), - //BuiltIn(int) iswctype(Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int)))), Use(TypeDef(wctype_t, Attributed(unsigned , BuiltIn(long))))); - (void *)(iswctype), - //Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int)))) towlower(Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(towlower), - //Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int)))) towupper(Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(towupper), - //Use(TypeDef(wctrans_t, Pointer(Attributed(const , Use(TypeDef(__int32_t, Attributed(signed , BuiltIn(int)))))))) wctrans(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(wctrans), - //Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int)))) towctrans(Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int)))), Use(TypeDef(wctrans_t, Pointer(Attributed(const , Use(TypeDef(__int32_t, Attributed(signed , BuiltIn(int))))))))); - (void *)(towctrans), - //BuiltIn(int) iswalnum_l(Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int)))), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(iswalnum_l), - //BuiltIn(int) iswalpha_l(Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int)))), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(iswalpha_l), - //BuiltIn(int) iswcntrl_l(Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int)))), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(iswcntrl_l), - //BuiltIn(int) iswdigit_l(Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int)))), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(iswdigit_l), - //BuiltIn(int) iswgraph_l(Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int)))), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(iswgraph_l), - //BuiltIn(int) iswlower_l(Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int)))), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(iswlower_l), - //BuiltIn(int) iswprint_l(Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int)))), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(iswprint_l), - //BuiltIn(int) iswpunct_l(Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int)))), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(iswpunct_l), - //BuiltIn(int) iswspace_l(Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int)))), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(iswspace_l), - //BuiltIn(int) iswupper_l(Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int)))), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(iswupper_l), - //BuiltIn(int) iswxdigit_l(Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int)))), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(iswxdigit_l), - //BuiltIn(int) iswblank_l(Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int)))), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(iswblank_l), - //Use(TypeDef(wctype_t, Attributed(unsigned , BuiltIn(long)))) wctype_l(Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(wctype_l), - //BuiltIn(int) iswctype_l(Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int)))), Use(TypeDef(wctype_t, Attributed(unsigned , BuiltIn(long)))), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(iswctype_l), - //Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int)))) towlower_l(Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int)))), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(towlower_l), - //Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int)))) towupper_l(Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int)))), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(towupper_l), - //Use(TypeDef(wctrans_t, Pointer(Attributed(const , Use(TypeDef(__int32_t, Attributed(signed , BuiltIn(int)))))))) wctrans_l(Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(wctrans_l), - //Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int)))) towctrans_l(Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int)))), Use(TypeDef(wctrans_t, Pointer(Attributed(const , Use(TypeDef(__int32_t, Attributed(signed , BuiltIn(int)))))))), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(towctrans_l), - //BuiltIn(int) feclearexcept(BuiltIn(int)); - (void *)(feclearexcept), - //BuiltIn(int) fegetexceptflag(Pointer(Use(TypeDef(fexcept_t, Attributed(unsigned , BuiltIn(short))))), BuiltIn(int)); - (void *)(fegetexceptflag), - //BuiltIn(int) feraiseexcept(BuiltIn(int)); - (void *)(feraiseexcept), - //BuiltIn(int) fesetexceptflag(Pointer(Attributed(const , Use(TypeDef(fexcept_t, Attributed(unsigned , BuiltIn(short)))))), BuiltIn(int)); - (void *)(fesetexceptflag), - //BuiltIn(int) fetestexcept(BuiltIn(int)); - (void *)(fetestexcept), - //BuiltIn(int) fegetround(); - (void *)(fegetround), - //BuiltIn(int) fesetround(BuiltIn(int)); - (void *)(fesetround), - //BuiltIn(int) fegetenv(Pointer(Use(TypeDef(fenv_t, Struct(struct anon_struct_645))))); - (void *)(fegetenv), - //BuiltIn(int) feholdexcept(Pointer(Use(TypeDef(fenv_t, Struct(struct anon_struct_645))))); - (void *)(feholdexcept), - //BuiltIn(int) fesetenv(Pointer(Attributed(const , Use(TypeDef(fenv_t, Struct(struct anon_struct_645)))))); - (void *)(fesetenv), - //BuiltIn(int) feupdateenv(Pointer(Attributed(const , Use(TypeDef(fenv_t, Struct(struct anon_struct_645)))))); - (void *)(feupdateenv), - //BuiltIn(int) feenableexcept(BuiltIn(int)); - (void *)(feenableexcept), - //BuiltIn(int) fedisableexcept(BuiltIn(int)); - (void *)(fedisableexcept), - //BuiltIn(int) fegetexcept(); - (void *)(fegetexcept), - //BuiltIn(void) setpwent(); - (void *)(setpwent), - //BuiltIn(void) endpwent(); - (void *)(endpwent), - //Pointer(Use(Struct(struct passwd))) getpwent(); - (void *)(getpwent), - //Pointer(Use(Struct(struct passwd))) fgetpwent(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(fgetpwent), - //BuiltIn(int) putpwent(Pointer(restrict Attributed(const , Use(Struct(struct passwd)))), Pointer(restrict Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(putpwent), - //Pointer(Use(Struct(struct passwd))) getpwuid(Use(TypeDef(__uid_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(getpwuid), - //Pointer(Use(Struct(struct passwd))) getpwnam(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(getpwnam), - //BuiltIn(int) getpwent_r(Pointer(restrict Use(Struct(struct passwd))), Pointer(restrict BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Pointer(Use(Struct(struct passwd))))); - (void *)(getpwent_r), - //BuiltIn(int) getpwuid_r(Use(TypeDef(__uid_t, Attributed(unsigned , BuiltIn(int)))), Pointer(restrict Use(Struct(struct passwd))), Pointer(restrict BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Pointer(Use(Struct(struct passwd))))); - (void *)(getpwuid_r), - //BuiltIn(int) getpwnam_r(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Use(Struct(struct passwd))), Pointer(restrict BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Pointer(Use(Struct(struct passwd))))); - (void *)(getpwnam_r), - //BuiltIn(int) fgetpwent_r(Pointer(restrict Use(TypeDef(FILE, Use(Struct(struct _IO_FILE))))), Pointer(restrict Use(Struct(struct passwd))), Pointer(restrict BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Pointer(Use(Struct(struct passwd))))); - (void *)(fgetpwent_r), - //BuiltIn(int) getpw(Use(TypeDef(__uid_t, Attributed(unsigned , BuiltIn(int)))), Pointer(BuiltIn(char))); - (void *)(getpw), - //BuiltIn(int) backtrace(Pointer(Pointer(BuiltIn(void))), BuiltIn(int)); - (void *)(backtrace), - //Pointer(Pointer(BuiltIn(char))) backtrace_symbols(Pointer(Pointer(const BuiltIn(void))), BuiltIn(int)); - (void *)(backtrace_symbols), - //BuiltIn(void) backtrace_symbols_fd(Pointer(Pointer(const BuiltIn(void))), BuiltIn(int), BuiltIn(int)); - (void *)(backtrace_symbols_fd), - //Pointer(Use(Struct(struct fstab))) getfsent(); - (void *)(getfsent), - //Pointer(Use(Struct(struct fstab))) getfsspec(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(getfsspec), - //Pointer(Use(Struct(struct fstab))) getfsfile(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(getfsfile), - //BuiltIn(int) setfsent(); - (void *)(setfsent), - //BuiltIn(void) endfsent(); - (void *)(endfsent), -#if defined(__amd64__) || defined(_M_AMD64) - //NOTE(artem): These are only present on amd64 (yes, even the x32). The i386 equivalent is la_i86_gnu_* - //NOTE(artem): The proper way to handle this is to have per-os libc files, or to avoid architecture specific headers when generating ABI_libc.c - //Use(TypeDef(Elf64_Addr, Use(TypeDef(uint64_t, Attributed(unsigned , BuiltIn(long)))))) la_x86_64_gnu_pltenter(Pointer(Use(TypeDef(Elf64_Sym, Struct(struct anon_struct_477)))), Attributed(unsigned , BuiltIn(int)), Pointer(Use(TypeDef(uintptr_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Use(TypeDef(uintptr_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Use(TypeDef(La_x86_64_regs, Struct(struct La_x86_64_regs)))), Pointer(Attributed(unsigned , BuiltIn(int))), Pointer(Attributed(const , BuiltIn(char))), Pointer(BuiltIn(long))); - (void *)(la_x86_64_gnu_pltenter), - //Attributed(unsigned , BuiltIn(int)) la_x86_64_gnu_pltexit(Pointer(Use(TypeDef(Elf64_Sym, Struct(struct anon_struct_477)))), Attributed(unsigned , BuiltIn(int)), Pointer(Use(TypeDef(uintptr_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Use(TypeDef(uintptr_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Attributed(const , Use(TypeDef(La_x86_64_regs, Struct(struct La_x86_64_regs))))), Pointer(Use(TypeDef(La_x86_64_retval, Struct(struct La_x86_64_retval)))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(la_x86_64_gnu_pltexit), - //Use(TypeDef(Elf32_Addr, Use(TypeDef(uint32_t, Attributed(unsigned , BuiltIn(int)))))) la_x32_gnu_pltenter(Pointer(Use(TypeDef(Elf32_Sym, Struct(struct anon_struct_476)))), Attributed(unsigned , BuiltIn(int)), Pointer(Use(TypeDef(uintptr_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Use(TypeDef(uintptr_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Use(TypeDef(La_x86_64_regs, Struct(struct La_x86_64_regs)))), Pointer(Attributed(unsigned , BuiltIn(int))), Pointer(Attributed(const , BuiltIn(char))), Pointer(BuiltIn(long))); - (void *)(la_x32_gnu_pltenter), - //Attributed(unsigned , BuiltIn(int)) la_x32_gnu_pltexit(Pointer(Use(TypeDef(Elf32_Sym, Struct(struct anon_struct_476)))), Attributed(unsigned , BuiltIn(int)), Pointer(Use(TypeDef(uintptr_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Use(TypeDef(uintptr_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Attributed(const , Use(TypeDef(La_x86_64_regs, Struct(struct La_x86_64_regs))))), Pointer(Use(TypeDef(La_x86_64_retval, Struct(struct La_x86_64_retval)))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(la_x32_gnu_pltexit), -#endif - // skipping because function pointer args: dl_iterate_phdr - //Attributed(unsigned , BuiltIn(int)) la_version(Attributed(unsigned , BuiltIn(int))); - (void *)(la_version), - //BuiltIn(void) la_activity(Pointer(Use(TypeDef(uintptr_t, Attributed(unsigned , BuiltIn(long))))), Attributed(unsigned , BuiltIn(int))); - (void *)(la_activity), - //Pointer(BuiltIn(char)) la_objsearch(Pointer(Attributed(const , BuiltIn(char))), Pointer(Use(TypeDef(uintptr_t, Attributed(unsigned , BuiltIn(long))))), Attributed(unsigned , BuiltIn(int))); - (void *)(la_objsearch), - //Attributed(unsigned , BuiltIn(int)) la_objopen(Pointer(Use(Struct(struct link_map))), Use(TypeDef(Lmid_t, BuiltIn(long))), Pointer(Use(TypeDef(uintptr_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(la_objopen), - //BuiltIn(void) la_preinit(Pointer(Use(TypeDef(uintptr_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(la_preinit), - //Use(TypeDef(uintptr_t, Attributed(unsigned , BuiltIn(long)))) la_symbind32(Pointer(Use(TypeDef(Elf32_Sym, Struct(struct anon_struct_476)))), Attributed(unsigned , BuiltIn(int)), Pointer(Use(TypeDef(uintptr_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Use(TypeDef(uintptr_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Attributed(unsigned , BuiltIn(int))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(la_symbind32), - //Use(TypeDef(uintptr_t, Attributed(unsigned , BuiltIn(long)))) la_symbind64(Pointer(Use(TypeDef(Elf64_Sym, Struct(struct anon_struct_477)))), Attributed(unsigned , BuiltIn(int)), Pointer(Use(TypeDef(uintptr_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Use(TypeDef(uintptr_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Attributed(unsigned , BuiltIn(int))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(la_symbind64), - //Attributed(unsigned , BuiltIn(int)) la_objclose(Pointer(Use(TypeDef(uintptr_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(la_objclose), - // skipping because function pointer args: ftw - // skipping because function pointer args: ftw64 - // skipping because function pointer args: nftw - // skipping because function pointer args: nftw64 - //Pointer(BuiltIn(int)) __h_errno_location(); - (void *)(__h_errno_location), - //BuiltIn(void) herror(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(herror), - //Pointer(Attributed(const , BuiltIn(char))) hstrerror(BuiltIn(int)); - (void *)(hstrerror), - //BuiltIn(void) sethostent(BuiltIn(int)); - (void *)(sethostent), - //BuiltIn(void) endhostent(); - (void *)(endhostent), - //Pointer(Use(Struct(struct hostent))) gethostent(); - (void *)(gethostent), - //Pointer(Use(Struct(struct hostent))) gethostbyaddr(Pointer(Attributed(const , BuiltIn(void))), Use(TypeDef(__socklen_t, Attributed(unsigned , BuiltIn(int)))), BuiltIn(int)); - (void *)(gethostbyaddr), - //Pointer(Use(Struct(struct hostent))) gethostbyname(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(gethostbyname), - //Pointer(Use(Struct(struct hostent))) gethostbyname2(Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int)); - (void *)(gethostbyname2), - //BuiltIn(int) gethostent_r(Pointer(restrict Use(Struct(struct hostent))), Pointer(restrict BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Pointer(Use(Struct(struct hostent)))), Pointer(restrict BuiltIn(int))); - (void *)(gethostent_r), - //BuiltIn(int) gethostbyaddr_r(Pointer(restrict Attributed(const , BuiltIn(void))), Use(TypeDef(__socklen_t, Attributed(unsigned , BuiltIn(int)))), BuiltIn(int), Pointer(restrict Use(Struct(struct hostent))), Pointer(restrict BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Pointer(Use(Struct(struct hostent)))), Pointer(restrict BuiltIn(int))); - (void *)(gethostbyaddr_r), - //BuiltIn(int) gethostbyname_r(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Use(Struct(struct hostent))), Pointer(restrict BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Pointer(Use(Struct(struct hostent)))), Pointer(restrict BuiltIn(int))); - (void *)(gethostbyname_r), - //BuiltIn(int) gethostbyname2_r(Pointer(restrict Attributed(const , BuiltIn(char))), BuiltIn(int), Pointer(restrict Use(Struct(struct hostent))), Pointer(restrict BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Pointer(Use(Struct(struct hostent)))), Pointer(restrict BuiltIn(int))); - (void *)(gethostbyname2_r), - //BuiltIn(void) setnetent(BuiltIn(int)); - (void *)(setnetent), - //BuiltIn(void) endnetent(); - (void *)(endnetent), - //Pointer(Use(Struct(struct netent))) getnetent(); - (void *)(getnetent), - //Pointer(Use(Struct(struct netent))) getnetbyaddr(Use(TypeDef(uint32_t, Attributed(unsigned , BuiltIn(int)))), BuiltIn(int)); - (void *)(getnetbyaddr), - //Pointer(Use(Struct(struct netent))) getnetbyname(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(getnetbyname), - //BuiltIn(int) getnetent_r(Pointer(restrict Use(Struct(struct netent))), Pointer(restrict BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Pointer(Use(Struct(struct netent)))), Pointer(restrict BuiltIn(int))); - (void *)(getnetent_r), - //BuiltIn(int) getnetbyaddr_r(Use(TypeDef(uint32_t, Attributed(unsigned , BuiltIn(int)))), BuiltIn(int), Pointer(restrict Use(Struct(struct netent))), Pointer(restrict BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Pointer(Use(Struct(struct netent)))), Pointer(restrict BuiltIn(int))); - (void *)(getnetbyaddr_r), - //BuiltIn(int) getnetbyname_r(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Use(Struct(struct netent))), Pointer(restrict BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Pointer(Use(Struct(struct netent)))), Pointer(restrict BuiltIn(int))); - (void *)(getnetbyname_r), - //BuiltIn(void) setservent(BuiltIn(int)); - (void *)(setservent), - //BuiltIn(void) endservent(); - (void *)(endservent), - //Pointer(Use(Struct(struct servent))) getservent(); - (void *)(getservent), - //Pointer(Use(Struct(struct servent))) getservbyname(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(getservbyname), - //Pointer(Use(Struct(struct servent))) getservbyport(BuiltIn(int), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(getservbyport), - //BuiltIn(int) getservent_r(Pointer(restrict Use(Struct(struct servent))), Pointer(restrict BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Pointer(Use(Struct(struct servent))))); - (void *)(getservent_r), - //BuiltIn(int) getservbyname_r(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Use(Struct(struct servent))), Pointer(restrict BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Pointer(Use(Struct(struct servent))))); - (void *)(getservbyname_r), - //BuiltIn(int) getservbyport_r(BuiltIn(int), Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Use(Struct(struct servent))), Pointer(restrict BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Pointer(Use(Struct(struct servent))))); - (void *)(getservbyport_r), - //BuiltIn(void) setprotoent(BuiltIn(int)); - (void *)(setprotoent), - //BuiltIn(void) endprotoent(); - (void *)(endprotoent), - //Pointer(Use(Struct(struct protoent))) getprotoent(); - (void *)(getprotoent), - //Pointer(Use(Struct(struct protoent))) getprotobyname(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(getprotobyname), - //Pointer(Use(Struct(struct protoent))) getprotobynumber(BuiltIn(int)); - (void *)(getprotobynumber), - //BuiltIn(int) getprotoent_r(Pointer(restrict Use(Struct(struct protoent))), Pointer(restrict BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Pointer(Use(Struct(struct protoent))))); - (void *)(getprotoent_r), - //BuiltIn(int) getprotobyname_r(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Use(Struct(struct protoent))), Pointer(restrict BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Pointer(Use(Struct(struct protoent))))); - (void *)(getprotobyname_r), - //BuiltIn(int) getprotobynumber_r(BuiltIn(int), Pointer(restrict Use(Struct(struct protoent))), Pointer(restrict BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Pointer(Use(Struct(struct protoent))))); - (void *)(getprotobynumber_r), - //BuiltIn(int) setnetgrent(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(setnetgrent), - //BuiltIn(void) endnetgrent(); - (void *)(endnetgrent), - //BuiltIn(int) getnetgrent(Pointer(restrict Pointer(BuiltIn(char))), Pointer(restrict Pointer(BuiltIn(char))), Pointer(restrict Pointer(BuiltIn(char)))); - (void *)(getnetgrent), - //BuiltIn(int) innetgr(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(innetgr), - //BuiltIn(int) getnetgrent_r(Pointer(restrict Pointer(BuiltIn(char))), Pointer(restrict Pointer(BuiltIn(char))), Pointer(restrict Pointer(BuiltIn(char))), Pointer(restrict BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(getnetgrent_r), - //BuiltIn(int) rcmd(Pointer(restrict Pointer(BuiltIn(char))), Attributed(unsigned , BuiltIn(short)), Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict BuiltIn(int))); - (void *)(rcmd), - //BuiltIn(int) rcmd_af(Pointer(restrict Pointer(BuiltIn(char))), Attributed(unsigned , BuiltIn(short)), Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict BuiltIn(int)), Use(TypeDef(sa_family_t, Attributed(unsigned , BuiltIn(short))))); - (void *)(rcmd_af), - //BuiltIn(int) rexec(Pointer(restrict Pointer(BuiltIn(char))), BuiltIn(int), Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict BuiltIn(int))); - (void *)(rexec), - //BuiltIn(int) rexec_af(Pointer(restrict Pointer(BuiltIn(char))), BuiltIn(int), Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict BuiltIn(int)), Use(TypeDef(sa_family_t, Attributed(unsigned , BuiltIn(short))))); - (void *)(rexec_af), - //BuiltIn(int) ruserok(Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int), Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(ruserok), - //BuiltIn(int) ruserok_af(Pointer(Attributed(const , BuiltIn(char))), BuiltIn(int), Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(sa_family_t, Attributed(unsigned , BuiltIn(short))))); - (void *)(ruserok_af), - //BuiltIn(int) iruserok(Use(TypeDef(uint32_t, Attributed(unsigned , BuiltIn(int)))), BuiltIn(int), Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(iruserok), - //BuiltIn(int) iruserok_af(Pointer(Attributed(const , BuiltIn(void))), BuiltIn(int), Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(sa_family_t, Attributed(unsigned , BuiltIn(short))))); - (void *)(iruserok_af), - //BuiltIn(int) rresvport(Pointer(BuiltIn(int))); - (void *)(rresvport), - //BuiltIn(int) rresvport_af(Pointer(BuiltIn(int)), Use(TypeDef(sa_family_t, Attributed(unsigned , BuiltIn(short))))); - (void *)(rresvport_af), - //BuiltIn(int) getaddrinfo(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Attributed(const , Use(Struct(struct addrinfo)))), Pointer(restrict Pointer(Use(Struct(struct addrinfo))))); - (void *)(getaddrinfo), - //BuiltIn(void) freeaddrinfo(Pointer(Use(Struct(struct addrinfo)))); - (void *)(freeaddrinfo), - //Pointer(Attributed(const , BuiltIn(char))) gai_strerror(BuiltIn(int)); - (void *)(gai_strerror), - //BuiltIn(int) getnameinfo(Pointer(restrict Attributed(const , Use(Struct(struct sockaddr)))), Use(TypeDef(socklen_t, Use(TypeDef(__socklen_t, Attributed(unsigned , BuiltIn(int)))))), Pointer(restrict BuiltIn(char)), Use(TypeDef(socklen_t, Use(TypeDef(__socklen_t, Attributed(unsigned , BuiltIn(int)))))), Pointer(restrict BuiltIn(char)), Use(TypeDef(socklen_t, Use(TypeDef(__socklen_t, Attributed(unsigned , BuiltIn(int)))))), BuiltIn(int)); - (void *)(getnameinfo), - // skipping because function pointer args: getaddrinfo_a - //BuiltIn(int) gai_suspend(Array(Pointer(const Attributed(const , Use(Struct(struct gaicb))))), BuiltIn(int), Pointer(Attributed(const , Use(Struct(struct timespec))))); - (void *)(gai_suspend), - //BuiltIn(int) gai_error(Pointer(Use(Struct(struct gaicb)))); - (void *)(gai_error), - //BuiltIn(int) gai_cancel(Pointer(Use(Struct(struct gaicb)))); - (void *)(gai_cancel), - //Pointer(Use(TypeDef(wchar_t, BuiltIn(int)))) wcscpy(Pointer(restrict Use(TypeDef(wchar_t, BuiltIn(int)))), Pointer(restrict Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int)))))); - (void *)(wcscpy), - //Pointer(Use(TypeDef(wchar_t, BuiltIn(int)))) wcsncpy(Pointer(restrict Use(TypeDef(wchar_t, BuiltIn(int)))), Pointer(restrict Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(wcsncpy), - //Pointer(Use(TypeDef(wchar_t, BuiltIn(int)))) wcscat(Pointer(restrict Use(TypeDef(wchar_t, BuiltIn(int)))), Pointer(restrict Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int)))))); - (void *)(wcscat), - //Pointer(Use(TypeDef(wchar_t, BuiltIn(int)))) wcsncat(Pointer(restrict Use(TypeDef(wchar_t, BuiltIn(int)))), Pointer(restrict Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(wcsncat), - //BuiltIn(int) wcscmp(Pointer(Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Pointer(Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int)))))); - (void *)(wcscmp), - //BuiltIn(int) wcsncmp(Pointer(Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Pointer(Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(wcsncmp), - //BuiltIn(int) wcscasecmp(Pointer(Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Pointer(Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int)))))); - (void *)(wcscasecmp), - //BuiltIn(int) wcsncasecmp(Pointer(Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Pointer(Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(wcsncasecmp), - //BuiltIn(int) wcscasecmp_l(Pointer(Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Pointer(Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(wcscasecmp_l), - //BuiltIn(int) wcsncasecmp_l(Pointer(Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Pointer(Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(wcsncasecmp_l), - //BuiltIn(int) wcscoll(Pointer(Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Pointer(Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int)))))); - (void *)(wcscoll), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) wcsxfrm(Pointer(restrict Use(TypeDef(wchar_t, BuiltIn(int)))), Pointer(restrict Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(wcsxfrm), - //BuiltIn(int) wcscoll_l(Pointer(Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Pointer(Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(wcscoll_l), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) wcsxfrm_l(Pointer(Use(TypeDef(wchar_t, BuiltIn(int)))), Pointer(Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(wcsxfrm_l), - //Pointer(Use(TypeDef(wchar_t, BuiltIn(int)))) wcsdup(Pointer(Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int)))))); - (void *)(wcsdup), - //Pointer(Use(TypeDef(wchar_t, BuiltIn(int)))) wcschr(Pointer(Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Use(TypeDef(wchar_t, BuiltIn(int)))); - (void *)(wcschr), - //Pointer(Use(TypeDef(wchar_t, BuiltIn(int)))) wcsrchr(Pointer(Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Use(TypeDef(wchar_t, BuiltIn(int)))); - (void *)(wcsrchr), - //Pointer(Use(TypeDef(wchar_t, BuiltIn(int)))) wcschrnul(Pointer(Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Use(TypeDef(wchar_t, BuiltIn(int)))); - (void *)(wcschrnul), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) wcscspn(Pointer(Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Pointer(Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int)))))); - (void *)(wcscspn), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) wcsspn(Pointer(Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Pointer(Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int)))))); - (void *)(wcsspn), - //Pointer(Use(TypeDef(wchar_t, BuiltIn(int)))) wcspbrk(Pointer(Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Pointer(Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int)))))); - (void *)(wcspbrk), - //Pointer(Use(TypeDef(wchar_t, BuiltIn(int)))) wcsstr(Pointer(Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Pointer(Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int)))))); - (void *)(wcsstr), - //Pointer(Use(TypeDef(wchar_t, BuiltIn(int)))) wcstok(Pointer(restrict Use(TypeDef(wchar_t, BuiltIn(int)))), Pointer(restrict Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Pointer(restrict Pointer(Use(TypeDef(wchar_t, BuiltIn(int)))))); - (void *)(wcstok), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) wcslen(Pointer(Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int)))))); - (void *)(wcslen), - //Pointer(Use(TypeDef(wchar_t, BuiltIn(int)))) wcswcs(Pointer(Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Pointer(Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int)))))); - (void *)(wcswcs), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) wcsnlen(Pointer(Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(wcsnlen), - //Pointer(Use(TypeDef(wchar_t, BuiltIn(int)))) wmemchr(Pointer(Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Use(TypeDef(wchar_t, BuiltIn(int))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(wmemchr), - //BuiltIn(int) wmemcmp(Pointer(Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Pointer(Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(wmemcmp), - //Pointer(Use(TypeDef(wchar_t, BuiltIn(int)))) wmemcpy(Pointer(restrict Use(TypeDef(wchar_t, BuiltIn(int)))), Pointer(restrict Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(wmemcpy), - //Pointer(Use(TypeDef(wchar_t, BuiltIn(int)))) wmemmove(Pointer(Use(TypeDef(wchar_t, BuiltIn(int)))), Pointer(Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(wmemmove), - //Pointer(Use(TypeDef(wchar_t, BuiltIn(int)))) wmemset(Pointer(Use(TypeDef(wchar_t, BuiltIn(int)))), Use(TypeDef(wchar_t, BuiltIn(int))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(wmemset), - //Pointer(Use(TypeDef(wchar_t, BuiltIn(int)))) wmempcpy(Pointer(restrict Use(TypeDef(wchar_t, BuiltIn(int)))), Pointer(restrict Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(wmempcpy), - //Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int)))) btowc(BuiltIn(int)); - (void *)(btowc), - //BuiltIn(int) wctob(Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(wctob), - //BuiltIn(int) mbsinit(Pointer(Attributed(const , Use(TypeDef(mbstate_t, Use(TypeDef(__mbstate_t, Struct(struct anon_struct_5)))))))); - (void *)(mbsinit), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) mbrtowc(Pointer(restrict Use(TypeDef(wchar_t, BuiltIn(int)))), Pointer(restrict Attributed(const , BuiltIn(char))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Use(TypeDef(mbstate_t, Use(TypeDef(__mbstate_t, Struct(struct anon_struct_5))))))); - (void *)(mbrtowc), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) wcrtomb(Pointer(restrict BuiltIn(char)), Use(TypeDef(wchar_t, BuiltIn(int))), Pointer(restrict Use(TypeDef(mbstate_t, Use(TypeDef(__mbstate_t, Struct(struct anon_struct_5))))))); - (void *)(wcrtomb), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) __mbrlen(Pointer(restrict Attributed(const , BuiltIn(char))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Use(TypeDef(mbstate_t, Use(TypeDef(__mbstate_t, Struct(struct anon_struct_5))))))); - (void *)(__mbrlen), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) mbrlen(Pointer(restrict Attributed(const , BuiltIn(char))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Use(TypeDef(mbstate_t, Use(TypeDef(__mbstate_t, Struct(struct anon_struct_5))))))); - (void *)(mbrlen), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) mbsrtowcs(Pointer(restrict Use(TypeDef(wchar_t, BuiltIn(int)))), Pointer(restrict Pointer(Attributed(const , BuiltIn(char)))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Use(TypeDef(mbstate_t, Use(TypeDef(__mbstate_t, Struct(struct anon_struct_5))))))); - (void *)(mbsrtowcs), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) wcsrtombs(Pointer(restrict BuiltIn(char)), Pointer(restrict Pointer(Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int)))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Use(TypeDef(mbstate_t, Use(TypeDef(__mbstate_t, Struct(struct anon_struct_5))))))); - (void *)(wcsrtombs), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) mbsnrtowcs(Pointer(restrict Use(TypeDef(wchar_t, BuiltIn(int)))), Pointer(restrict Pointer(Attributed(const , BuiltIn(char)))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Use(TypeDef(mbstate_t, Use(TypeDef(__mbstate_t, Struct(struct anon_struct_5))))))); - (void *)(mbsnrtowcs), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) wcsnrtombs(Pointer(restrict BuiltIn(char)), Pointer(restrict Pointer(Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int)))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Use(TypeDef(mbstate_t, Use(TypeDef(__mbstate_t, Struct(struct anon_struct_5))))))); - (void *)(wcsnrtombs), - //BuiltIn(int) wcwidth(Use(TypeDef(wchar_t, BuiltIn(int)))); - (void *)(wcwidth), - //BuiltIn(int) wcswidth(Pointer(Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(wcswidth), - //BuiltIn(double) wcstod(Pointer(restrict Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Pointer(restrict Pointer(Use(TypeDef(wchar_t, BuiltIn(int)))))); - (void *)(wcstod), - //BuiltIn(float) wcstof(Pointer(restrict Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Pointer(restrict Pointer(Use(TypeDef(wchar_t, BuiltIn(int)))))); - (void *)(wcstof), - //BuiltIn(long double) wcstold(Pointer(restrict Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Pointer(restrict Pointer(Use(TypeDef(wchar_t, BuiltIn(int)))))); - (void *)(wcstold), - //BuiltIn(long) wcstol(Pointer(restrict Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Pointer(restrict Pointer(Use(TypeDef(wchar_t, BuiltIn(int))))), BuiltIn(int)); - (void *)(wcstol), - //Attributed(unsigned , BuiltIn(long)) wcstoul(Pointer(restrict Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Pointer(restrict Pointer(Use(TypeDef(wchar_t, BuiltIn(int))))), BuiltIn(int)); - (void *)(wcstoul), - //BuiltIn(long long) wcstoll(Pointer(restrict Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Pointer(restrict Pointer(Use(TypeDef(wchar_t, BuiltIn(int))))), BuiltIn(int)); - (void *)(wcstoll), - //Attributed(unsigned , BuiltIn(long long)) wcstoull(Pointer(restrict Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Pointer(restrict Pointer(Use(TypeDef(wchar_t, BuiltIn(int))))), BuiltIn(int)); - (void *)(wcstoull), - //BuiltIn(long long) wcstoq(Pointer(restrict Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Pointer(restrict Pointer(Use(TypeDef(wchar_t, BuiltIn(int))))), BuiltIn(int)); - (void *)(wcstoq), - //Attributed(unsigned , BuiltIn(long long)) wcstouq(Pointer(restrict Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Pointer(restrict Pointer(Use(TypeDef(wchar_t, BuiltIn(int))))), BuiltIn(int)); - (void *)(wcstouq), - //BuiltIn(long) wcstol_l(Pointer(restrict Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Pointer(restrict Pointer(Use(TypeDef(wchar_t, BuiltIn(int))))), BuiltIn(int), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(wcstol_l), - //Attributed(unsigned , BuiltIn(long)) wcstoul_l(Pointer(restrict Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Pointer(restrict Pointer(Use(TypeDef(wchar_t, BuiltIn(int))))), BuiltIn(int), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(wcstoul_l), - //BuiltIn(long long) wcstoll_l(Pointer(restrict Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Pointer(restrict Pointer(Use(TypeDef(wchar_t, BuiltIn(int))))), BuiltIn(int), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(wcstoll_l), - //Attributed(unsigned , BuiltIn(long long)) wcstoull_l(Pointer(restrict Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Pointer(restrict Pointer(Use(TypeDef(wchar_t, BuiltIn(int))))), BuiltIn(int), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(wcstoull_l), - //BuiltIn(double) wcstod_l(Pointer(restrict Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Pointer(restrict Pointer(Use(TypeDef(wchar_t, BuiltIn(int))))), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(wcstod_l), - //BuiltIn(float) wcstof_l(Pointer(restrict Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Pointer(restrict Pointer(Use(TypeDef(wchar_t, BuiltIn(int))))), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(wcstof_l), - //BuiltIn(long double) wcstold_l(Pointer(restrict Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Pointer(restrict Pointer(Use(TypeDef(wchar_t, BuiltIn(int))))), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(wcstold_l), - //Pointer(Use(TypeDef(wchar_t, BuiltIn(int)))) wcpcpy(Pointer(restrict Use(TypeDef(wchar_t, BuiltIn(int)))), Pointer(restrict Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int)))))); - (void *)(wcpcpy), - //Pointer(Use(TypeDef(wchar_t, BuiltIn(int)))) wcpncpy(Pointer(restrict Use(TypeDef(wchar_t, BuiltIn(int)))), Pointer(restrict Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(wcpncpy), - //Pointer(Use(TypeDef(__FILE, Use(Struct(struct _IO_FILE))))) open_wmemstream(Pointer(Pointer(Use(TypeDef(wchar_t, BuiltIn(int))))), Pointer(Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))))); - (void *)(open_wmemstream), - //BuiltIn(int) fwide(Pointer(Use(TypeDef(__FILE, Use(Struct(struct _IO_FILE))))), BuiltIn(int)); - (void *)(fwide), - // skipping because varargs function: fwprintf - // skipping because varargs function: wprintf - // skipping because varargs function: swprintf - //BuiltIn(int) vfwprintf(Pointer(restrict Use(TypeDef(__FILE, Use(Struct(struct _IO_FILE))))), Pointer(restrict Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Use(TypeDef(__gnuc_va_list, BuiltIn(__builtin_va_list)))); - (void *)(vfwprintf), - //BuiltIn(int) vwprintf(Pointer(restrict Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Use(TypeDef(__gnuc_va_list, BuiltIn(__builtin_va_list)))); - (void *)(vwprintf), - //BuiltIn(int) vswprintf(Pointer(restrict Use(TypeDef(wchar_t, BuiltIn(int)))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Use(TypeDef(__gnuc_va_list, BuiltIn(__builtin_va_list)))); - (void *)(vswprintf), - // skipping because varargs function: fwscanf - // skipping because varargs function: wscanf - // skipping because varargs function: swscanf - //BuiltIn(int) vfwscanf(Pointer(restrict Use(TypeDef(__FILE, Use(Struct(struct _IO_FILE))))), Pointer(restrict Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Use(TypeDef(__gnuc_va_list, BuiltIn(__builtin_va_list)))); - (void *)(vfwscanf), - //BuiltIn(int) vwscanf(Pointer(restrict Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Use(TypeDef(__gnuc_va_list, BuiltIn(__builtin_va_list)))); - (void *)(vwscanf), - //BuiltIn(int) vswscanf(Pointer(restrict Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Pointer(restrict Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Use(TypeDef(__gnuc_va_list, BuiltIn(__builtin_va_list)))); - (void *)(vswscanf), - //Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int)))) fgetwc(Pointer(Use(TypeDef(__FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(fgetwc), - //Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int)))) getwc(Pointer(Use(TypeDef(__FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(getwc), - //Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int)))) getwchar(); - (void *)(getwchar), - //Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int)))) fputwc(Use(TypeDef(wchar_t, BuiltIn(int))), Pointer(Use(TypeDef(__FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(fputwc), - //Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int)))) putwc(Use(TypeDef(wchar_t, BuiltIn(int))), Pointer(Use(TypeDef(__FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(putwc), - //Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int)))) putwchar(Use(TypeDef(wchar_t, BuiltIn(int)))); - (void *)(putwchar), - //Pointer(Use(TypeDef(wchar_t, BuiltIn(int)))) fgetws(Pointer(restrict Use(TypeDef(wchar_t, BuiltIn(int)))), BuiltIn(int), Pointer(restrict Use(TypeDef(__FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(fgetws), - //BuiltIn(int) fputws(Pointer(restrict Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Pointer(restrict Use(TypeDef(__FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(fputws), - //Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int)))) ungetwc(Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int)))), Pointer(Use(TypeDef(__FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(ungetwc), - //Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int)))) getwc_unlocked(Pointer(Use(TypeDef(__FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(getwc_unlocked), - //Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int)))) getwchar_unlocked(); - (void *)(getwchar_unlocked), - //Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int)))) fgetwc_unlocked(Pointer(Use(TypeDef(__FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(fgetwc_unlocked), - //Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int)))) fputwc_unlocked(Use(TypeDef(wchar_t, BuiltIn(int))), Pointer(Use(TypeDef(__FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(fputwc_unlocked), - //Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int)))) putwc_unlocked(Use(TypeDef(wchar_t, BuiltIn(int))), Pointer(Use(TypeDef(__FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(putwc_unlocked), - //Use(TypeDef(wint_t, Attributed(unsigned , BuiltIn(int)))) putwchar_unlocked(Use(TypeDef(wchar_t, BuiltIn(int)))); - (void *)(putwchar_unlocked), - //Pointer(Use(TypeDef(wchar_t, BuiltIn(int)))) fgetws_unlocked(Pointer(restrict Use(TypeDef(wchar_t, BuiltIn(int)))), BuiltIn(int), Pointer(restrict Use(TypeDef(__FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(fgetws_unlocked), - //BuiltIn(int) fputws_unlocked(Pointer(restrict Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Pointer(restrict Use(TypeDef(__FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(fputws_unlocked), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) wcsftime(Pointer(restrict Use(TypeDef(wchar_t, BuiltIn(int)))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Pointer(restrict Attributed(const , Use(Struct(struct tm))))); - (void *)(wcsftime), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) wcsftime_l(Pointer(restrict Use(TypeDef(wchar_t, BuiltIn(int)))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Attributed(const , Use(TypeDef(wchar_t, BuiltIn(int))))), Pointer(restrict Attributed(const , Use(Struct(struct tm)))), Use(TypeDef(__locale_t, Pointer(Struct(struct __locale_struct))))); - (void *)(wcsftime_l), - //Pointer(BuiltIn(char)) dirname(Pointer(BuiltIn(char))); - (void *)(dirname), - //Pointer(BuiltIn(char)) __xpg_basename(Pointer(BuiltIn(char))); - (void *)(__xpg_basename), - //BuiltIn(void) setsgent(); - (void *)(setsgent), - //BuiltIn(void) endsgent(); - (void *)(endsgent), - //Pointer(Use(Struct(struct sgrp))) getsgent(); - (void *)(getsgent), - //Pointer(Use(Struct(struct sgrp))) getsgnam(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(getsgnam), - //Pointer(Use(Struct(struct sgrp))) sgetsgent(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(sgetsgent), - //Pointer(Use(Struct(struct sgrp))) fgetsgent(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(fgetsgent), - //BuiltIn(int) putsgent(Pointer(Attributed(const , Use(Struct(struct sgrp)))), Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(putsgent), - //BuiltIn(int) getsgent_r(Pointer(Use(Struct(struct sgrp))), Pointer(BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Pointer(Use(Struct(struct sgrp))))); - (void *)(getsgent_r), - //BuiltIn(int) getsgnam_r(Pointer(Attributed(const , BuiltIn(char))), Pointer(Use(Struct(struct sgrp))), Pointer(BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Pointer(Use(Struct(struct sgrp))))); - (void *)(getsgnam_r), - //BuiltIn(int) sgetsgent_r(Pointer(Attributed(const , BuiltIn(char))), Pointer(Use(Struct(struct sgrp))), Pointer(BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Pointer(Use(Struct(struct sgrp))))); - (void *)(sgetsgent_r), - //BuiltIn(int) fgetsgent_r(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE))))), Pointer(Use(Struct(struct sgrp))), Pointer(BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Pointer(Use(Struct(struct sgrp))))); - (void *)(fgetsgent_r), - //BuiltIn(int) cbc_crypt(Pointer(BuiltIn(char)), Pointer(BuiltIn(char)), Attributed(unsigned , BuiltIn(int)), Attributed(unsigned , BuiltIn(int)), Pointer(BuiltIn(char))); -// (void *)(cbc_crypt), - //BuiltIn(int) ecb_crypt(Pointer(BuiltIn(char)), Pointer(BuiltIn(char)), Attributed(unsigned , BuiltIn(int)), Attributed(unsigned , BuiltIn(int))); -// (void *)(ecb_crypt), - //BuiltIn(void) des_setparity(Pointer(BuiltIn(char))); -// (void *)(des_setparity), - // skipping because function pointer args: xdr_pmap - // skipping because function pointer args: xdr_pmaplist - // skipping because function pointer args: xdr_rmtcall_args - // skipping because function pointer args: xdr_rmtcallres - //Use(TypeDef(bool_t, BuiltIn(int))) pmap_set(Attributed(const , Use(TypeDef(u_long, Use(TypeDef(__u_long, Attributed(unsigned , BuiltIn(long))))))), Attributed(const , Use(TypeDef(u_long, Use(TypeDef(__u_long, Attributed(unsigned , BuiltIn(long))))))), BuiltIn(int), Use(TypeDef(u_short, Use(TypeDef(__u_short, Attributed(unsigned , BuiltIn(short))))))); - (void *)(pmap_set), - //Use(TypeDef(bool_t, BuiltIn(int))) pmap_unset(Attributed(const , Use(TypeDef(u_long, Use(TypeDef(__u_long, Attributed(unsigned , BuiltIn(long))))))), Attributed(const , Use(TypeDef(u_long, Use(TypeDef(__u_long, Attributed(unsigned , BuiltIn(long)))))))); - (void *)(pmap_unset), - //Pointer(Use(Struct(struct pmaplist))) pmap_getmaps(Pointer(Use(Struct(struct sockaddr_in)))); - (void *)(pmap_getmaps), - // skipping because function pointer args: pmap_rmtcall - // skipping because function pointer args: clnt_broadcast - //Use(TypeDef(u_short, Use(TypeDef(__u_short, Attributed(unsigned , BuiltIn(short)))))) pmap_getport(Pointer(Use(Struct(struct sockaddr_in))), Attributed(const , Use(TypeDef(u_long, Use(TypeDef(__u_long, Attributed(unsigned , BuiltIn(long))))))), Attributed(const , Use(TypeDef(u_long, Use(TypeDef(__u_long, Attributed(unsigned , BuiltIn(long))))))), Use(TypeDef(u_int, Use(TypeDef(__u_int, Attributed(unsigned , BuiltIn(int))))))); - (void *)(pmap_getport), - //BuiltIn(void) setspent(); - (void *)(setspent), - //BuiltIn(void) endspent(); - (void *)(endspent), - //Pointer(Use(Struct(struct spwd))) getspent(); - (void *)(getspent), - //Pointer(Use(Struct(struct spwd))) getspnam(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(getspnam), - //Pointer(Use(Struct(struct spwd))) sgetspent(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(sgetspent), - //Pointer(Use(Struct(struct spwd))) fgetspent(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(fgetspent), - //BuiltIn(int) putspent(Pointer(Attributed(const , Use(Struct(struct spwd)))), Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(putspent), - //BuiltIn(int) getspent_r(Pointer(Use(Struct(struct spwd))), Pointer(BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Pointer(Use(Struct(struct spwd))))); - (void *)(getspent_r), - //BuiltIn(int) getspnam_r(Pointer(Attributed(const , BuiltIn(char))), Pointer(Use(Struct(struct spwd))), Pointer(BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Pointer(Use(Struct(struct spwd))))); - (void *)(getspnam_r), - //BuiltIn(int) sgetspent_r(Pointer(Attributed(const , BuiltIn(char))), Pointer(Use(Struct(struct spwd))), Pointer(BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Pointer(Use(Struct(struct spwd))))); - (void *)(sgetspent_r), - //BuiltIn(int) fgetspent_r(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE))))), Pointer(Use(Struct(struct spwd))), Pointer(BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Pointer(Use(Struct(struct spwd))))); - (void *)(fgetspent_r), - //BuiltIn(int) lckpwdf(); - (void *)(lckpwdf), - //BuiltIn(int) ulckpwdf(); - (void *)(ulckpwdf), - //BuiltIn(void) setutxent(); - (void *)(setutxent), - //BuiltIn(void) endutxent(); - (void *)(endutxent), - //Pointer(Use(Struct(struct utmpx))) getutxent(); - (void *)(getutxent), - //Pointer(Use(Struct(struct utmpx))) getutxid(Pointer(Attributed(const , Use(Struct(struct utmpx))))); - (void *)(getutxid), - //Pointer(Use(Struct(struct utmpx))) getutxline(Pointer(Attributed(const , Use(Struct(struct utmpx))))); - (void *)(getutxline), - //Pointer(Use(Struct(struct utmpx))) pututxline(Pointer(Attributed(const , Use(Struct(struct utmpx))))); - (void *)(pututxline), - //BuiltIn(int) utmpxname(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(utmpxname), - //BuiltIn(void) updwtmpx(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , Use(Struct(struct utmpx))))); - (void *)(updwtmpx), - //BuiltIn(void) getutmp(Pointer(Attributed(const , Use(Struct(struct utmpx)))), Pointer(Use(Struct(struct utmp)))); - (void *)(getutmp), - //BuiltIn(void) getutmpx(Pointer(Attributed(const , Use(Struct(struct utmp)))), Pointer(Use(Struct(struct utmpx)))); - (void *)(getutmpx), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) __fbufsize(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(__fbufsize), - //BuiltIn(int) __freading(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(__freading), - //BuiltIn(int) __fwriting(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(__fwriting), - //BuiltIn(int) __freadable(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(__freadable), - //BuiltIn(int) __fwritable(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(__fwritable), - //BuiltIn(int) __flbf(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(__flbf), - //BuiltIn(void) __fpurge(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(__fpurge), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) __fpending(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(__fpending), - //BuiltIn(void) _flushlbf(); - (void *)(_flushlbf), - //BuiltIn(int) __fsetlocking(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE))))), BuiltIn(int)); - (void *)(__fsetlocking), - //Use(TypeDef(iconv_t, Pointer(BuiltIn(void)))) iconv_open(Pointer(Attributed(const , BuiltIn(char))), Pointer(Attributed(const , BuiltIn(char)))); - (void *)(iconv_open), - //Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))) iconv(Use(TypeDef(iconv_t, Pointer(BuiltIn(void)))), Pointer(restrict Pointer(BuiltIn(char))), Pointer(restrict Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))), Pointer(restrict Pointer(BuiltIn(char))), Pointer(restrict Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))))); - (void *)(iconv), - //BuiltIn(int) iconv_close(Use(TypeDef(iconv_t, Pointer(BuiltIn(void))))); - (void *)(iconv_close), - // skipping because varargs function: error - // skipping because varargs function: error_at_line - //Pointer(BuiltIn(char)) envz_entry(Pointer(restrict Attributed(const , BuiltIn(char))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Attributed(const , BuiltIn(char)))); - (void *)(envz_entry), - //Pointer(BuiltIn(char)) envz_get(Pointer(restrict Attributed(const , BuiltIn(char))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Attributed(const , BuiltIn(char)))); - (void *)(envz_get), - //Use(TypeDef(error_t, BuiltIn(int))) envz_add(Pointer(restrict Pointer(BuiltIn(char))), Pointer(restrict Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))), Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Attributed(const , BuiltIn(char)))); - (void *)(envz_add), - //Use(TypeDef(error_t, BuiltIn(int))) envz_merge(Pointer(restrict Pointer(BuiltIn(char))), Pointer(restrict Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))), Pointer(restrict Attributed(const , BuiltIn(char))), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), BuiltIn(int)); - (void *)(envz_merge), - //BuiltIn(void) envz_remove(Pointer(restrict Pointer(BuiltIn(char))), Pointer(restrict Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))), Pointer(restrict Attributed(const , BuiltIn(char)))); - (void *)(envz_remove), - //BuiltIn(void) envz_strip(Pointer(restrict Pointer(BuiltIn(char))), Pointer(restrict Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))))); - (void *)(envz_strip), - //BuiltIn(void) insque(Pointer(BuiltIn(void)), Pointer(BuiltIn(void))); - (void *)(insque), - //BuiltIn(void) remque(Pointer(BuiltIn(void))); - (void *)(remque), - //Pointer(Use(TypeDef(ENTRY, Struct(struct entry)))) hsearch(Use(TypeDef(ENTRY, Struct(struct entry))), Use(TypeDef(ACTION, Enum(enum anon_enum_191)))); - (void *)(hsearch), - //BuiltIn(int) hcreate(Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long)))))); - (void *)(hcreate), - //BuiltIn(void) hdestroy(); - (void *)(hdestroy), - //BuiltIn(int) hsearch_r(Use(TypeDef(ENTRY, Struct(struct entry))), Use(TypeDef(ACTION, Enum(enum anon_enum_191))), Pointer(Pointer(Use(TypeDef(ENTRY, Struct(struct entry))))), Pointer(Use(Struct(struct hsearch_data)))); - (void *)(hsearch_r), - //BuiltIn(int) hcreate_r(Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Use(Struct(struct hsearch_data)))); - (void *)(hcreate_r), - //BuiltIn(void) hdestroy_r(Pointer(Use(Struct(struct hsearch_data)))); - (void *)(hdestroy_r), - // skipping because function pointer args: tsearch - // skipping because function pointer args: tfind - // skipping because function pointer args: tdelete - // skipping because function pointer args: twalk - // skipping because function pointer args: tdestroy - // skipping because function pointer args: lfind - // skipping because function pointer args: lsearch - //BuiltIn(void) aio_init(Pointer(Attributed(const , Use(Struct(struct aioinit))))); - (void *)(aio_init), - // skipping because function pointer args: aio_read - // skipping because function pointer args: aio_write - // skipping because function pointer args: lio_listio - //BuiltIn(int) aio_error(Pointer(Attributed(const , Use(Struct(struct aiocb))))); - (void *)(aio_error), - // skipping because function pointer args: aio_return - // skipping because function pointer args: aio_cancel - //BuiltIn(int) aio_suspend(Array(Pointer(const Attributed(const , Use(Struct(struct aiocb))))), BuiltIn(int), Pointer(restrict Attributed(const , Use(Struct(struct timespec))))); - (void *)(aio_suspend), - // skipping because function pointer args: aio_fsync - // skipping because function pointer args: aio_read64 - // skipping because function pointer args: aio_write64 - // skipping because function pointer args: lio_listio64 - //BuiltIn(int) aio_error64(Pointer(Attributed(const , Use(Struct(struct aiocb64))))); - (void *)(aio_error64), - // skipping because function pointer args: aio_return64 - // skipping because function pointer args: aio_cancel64 - //BuiltIn(int) aio_suspend64(Array(Pointer(const Attributed(const , Use(Struct(struct aiocb64))))), BuiltIn(int), Pointer(restrict Attributed(const , Use(Struct(struct timespec))))); - (void *)(aio_suspend64), - // skipping because function pointer args: aio_fsync64 - // skipping because varargs function: ulimit - //BuiltIn(void) setgrent(); - (void *)(setgrent), - //BuiltIn(void) endgrent(); - (void *)(endgrent), - //Pointer(Use(Struct(struct group))) getgrent(); - (void *)(getgrent), - //Pointer(Use(Struct(struct group))) fgetgrent(Pointer(Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(fgetgrent), - //BuiltIn(int) putgrent(Pointer(restrict Attributed(const , Use(Struct(struct group)))), Pointer(restrict Use(TypeDef(FILE, Use(Struct(struct _IO_FILE)))))); - (void *)(putgrent), - //Pointer(Use(Struct(struct group))) getgrgid(Use(TypeDef(__gid_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(getgrgid), - //Pointer(Use(Struct(struct group))) getgrnam(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(getgrnam), - //BuiltIn(int) getgrent_r(Pointer(restrict Use(Struct(struct group))), Pointer(restrict BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Pointer(Use(Struct(struct group))))); - (void *)(getgrent_r), - //BuiltIn(int) getgrgid_r(Use(TypeDef(__gid_t, Attributed(unsigned , BuiltIn(int)))), Pointer(restrict Use(Struct(struct group))), Pointer(restrict BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Pointer(Use(Struct(struct group))))); - (void *)(getgrgid_r), - //BuiltIn(int) getgrnam_r(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Use(Struct(struct group))), Pointer(restrict BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Pointer(Use(Struct(struct group))))); - (void *)(getgrnam_r), - //BuiltIn(int) fgetgrent_r(Pointer(restrict Use(TypeDef(FILE, Use(Struct(struct _IO_FILE))))), Pointer(restrict Use(Struct(struct group))), Pointer(restrict BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Pointer(Use(Struct(struct group))))); - (void *)(fgetgrent_r), - //BuiltIn(int) setgroups(Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(Attributed(const , Use(TypeDef(__gid_t, Attributed(unsigned , BuiltIn(int))))))); - (void *)(setgroups), - //BuiltIn(int) getgrouplist(Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(__gid_t, Attributed(unsigned , BuiltIn(int)))), Pointer(Use(TypeDef(__gid_t, Attributed(unsigned , BuiltIn(int))))), Pointer(BuiltIn(int))); - (void *)(getgrouplist), - //BuiltIn(int) initgroups(Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(__gid_t, Attributed(unsigned , BuiltIn(int))))); - (void *)(initgroups), - //BuiltIn(void) setaliasent(); - (void *)(setaliasent), - //BuiltIn(void) endaliasent(); - (void *)(endaliasent), - //Pointer(Use(Struct(struct aliasent))) getaliasent(); - (void *)(getaliasent), - //BuiltIn(int) getaliasent_r(Pointer(restrict Use(Struct(struct aliasent))), Pointer(restrict BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Pointer(Use(Struct(struct aliasent))))); - (void *)(getaliasent_r), - //Pointer(Use(Struct(struct aliasent))) getaliasbyname(Pointer(Attributed(const , BuiltIn(char)))); - (void *)(getaliasbyname), - //BuiltIn(int) getaliasbyname_r(Pointer(restrict Attributed(const , BuiltIn(char))), Pointer(restrict Use(Struct(struct aliasent))), Pointer(restrict BuiltIn(char)), Use(TypeDef(size_t, TypeDef(size_t, Attributed(unsigned , BuiltIn(long))))), Pointer(restrict Pointer(Use(Struct(struct aliasent))))); - (void *)(getaliasbyname_r), - // skipping because function pointer args: fts_children - // skipping because function pointer args: fts_close - // skipping because function pointer args: fts_open - // skipping because function pointer args: fts_read - // skipping because function pointer args: fts_set - // skipping because varargs function: warn - //BuiltIn(void) vwarn(Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(__gnuc_va_list, BuiltIn(__builtin_va_list)))); - (void *)(vwarn), - // skipping because varargs function: warnx - //BuiltIn(void) vwarnx(Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(__gnuc_va_list, BuiltIn(__builtin_va_list)))); - (void *)(vwarnx), - // skipping because varargs function: err - //BuiltIn(void) verr(BuiltIn(int), Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(__gnuc_va_list, BuiltIn(__builtin_va_list)))); - (void *)(verr), - // skipping because varargs function: errx - //BuiltIn(void) verrx(BuiltIn(int), Pointer(Attributed(const , BuiltIn(char))), Use(TypeDef(__gnuc_va_list, BuiltIn(__builtin_va_list)))); - (void *)(verrx), - -}; -// end of mcsema ABI library -// automatically generated by cparser/make_abi-library.py -// see: https://github.com/pgoodman/cparser/ -// Total functions: 3189 -// Total emitted in __mcsema_externs : 2790 -// Excluded variadic functions: 51 -// Excluded due to callbacks: 348 -#pragma clang diagnostic pop - diff --git a/mcsema/OS/Linux/CMakeLists.txt b/mcsema/OS/Linux/CMakeLists.txt index 2e0731caa..d8ff73d8c 100644 --- a/mcsema/OS/Linux/CMakeLists.txt +++ b/mcsema/OS/Linux/CMakeLists.txt @@ -1,61 +1,20 @@ -# Copyright (c) 2018 Trail of Bits, Inc. +# Copyright (c) 2020 Trail of Bits, Inc. # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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 Affero General Public License for more details. # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . cmake_minimum_required(VERSION 3.2) project(linux_abi) -function(add_runtime_helper target_name source_file address_bit_size) - message(" > Generating Linux ABI target: ${target_name}") +add_subdirectory(X86) - # Visual C++ requires C++14 - if(WIN32) - set(required_cpp_standard "c++14") - else() - set(required_cpp_standard "c++11") - endif() - - if(DEFINED WIN32) - set(install_folder "${CMAKE_INSTALL_PREFIX}/mcsema/${MCSEMA_LLVM_VERSION}/ABI/linux") - else() - set(install_folder "${CMAKE_INSTALL_PREFIX}/share/mcsema/${MCSEMA_LLVM_VERSION}/ABI/linux") - endif() - - if("${source_file}" MATCHES "\.c$") - set(bc_build_flags "-xc" "-m${address_bit_size}" "-std=gnu11" "-Wno-deprecated-declarations") - elseif("${source_file}" MATCHES "\.cpp$") - set(bc_build_flags "-xc++" "-m${address_bit_size}" "-std=gnu++14" "-Wno-deprecated-declarations") - else() - # assume defaults work - message(WARNING " > WARNING: Unknown file extension for ${source_file}") - set(bc_build_flags "") - endif() - - message("Build flags: ${bc_build_flags}") - add_runtime(${target_name} - SOURCES ${source_file} - ADDRESS_SIZE ${address_bit_size} - BCFLAGS ${bc_build_flags} - INCLUDEDIRECTORIES "${CMAKE_SOURCE_DIR}" - INSTALLDESTINATION "${install_folder}" - DEPENDENCIES ${ARGN} - ) -endfunction() - -add_runtime_helper(ABI_exceptions_x86 "ABI_exceptions.cpp" 32) -add_runtime_helper(ABI_libc_x86 "ABI_libc.c" 32 "ABI_libc.h") - -if(CMAKE_SIZEOF_VOID_P EQUAL 8) - add_runtime_helper(ABI_exceptions_amd64 "ABI_exceptions.cpp" 64) - add_runtime_helper(ABI_libc_amd64 "ABI_libc.c" 64 "ABI_libc.h") -endif() diff --git a/mcsema/OS/Linux/ABI_exceptions.cpp b/mcsema/OS/Linux/X86/ABI_exceptions.cpp similarity index 100% rename from mcsema/OS/Linux/ABI_exceptions.cpp rename to mcsema/OS/Linux/X86/ABI_exceptions.cpp diff --git a/mcsema/OS/Linux/ABI_libc.h b/mcsema/OS/Linux/X86/ABI_libc.pph similarity index 53% rename from mcsema/OS/Linux/ABI_libc.h rename to mcsema/OS/Linux/X86/ABI_libc.pph index ce25b7178..4ade9e82b 100644 --- a/mcsema/OS/Linux/ABI_libc.h +++ b/mcsema/OS/Linux/X86/ABI_libc.pph @@ -56,107 +56,107 @@ extern char *gets(char *s); #include //#include //#include -#include +//#include //#include #include #include -//#include <_G_config.h> -//#include +#include <_G_config.h> +#include #include #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -//#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -//#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -//#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -//#include -#include -#include -#include -#include -#include -#include -//#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include #include #include #include @@ -207,9 +207,10 @@ extern char *gets(char *s); #include #include #include -//#include +#include #include #include +#include #include #include #include @@ -253,7 +254,7 @@ extern char *gets(char *s); #include #include #include -//#include +#include #include #include #include @@ -267,7 +268,7 @@ extern char *gets(char *s); #include #include #include -//#include +#include #include #include #include @@ -292,7 +293,8 @@ extern char *gets(char *s); #include #include #include -//#include +#include #include #include #include +#include "klee_defs.h" diff --git a/mcsema/OS/Linux/X86/CMakeLists.txt b/mcsema/OS/Linux/X86/CMakeLists.txt new file mode 100644 index 000000000..a590cb6a6 --- /dev/null +++ b/mcsema/OS/Linux/X86/CMakeLists.txt @@ -0,0 +1,92 @@ +# Copyright (c) 2020 Trail of Bits, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +cmake_minimum_required(VERSION 3.2) +project(linux_abi) + +function(add_runtime_helper target_name source_file address_bit_size) + message(" > Generating Linux ABI target: ${target_name}") + + # Visual C++ requires C++14 + if(WIN32) + set(required_cpp_standard "c++14") + else() + set(required_cpp_standard "c++11") + endif() + + if(DEFINED WIN32) + set(install_folder "${CMAKE_INSTALL_PREFIX}/mcsema/${REMILL_LLVM_VERSION}/ABI/linux") + else() + set(install_folder "${CMAKE_INSTALL_PREFIX}/share/mcsema/${REMILL_LLVM_VERSION}/ABI/linux") + endif() + + if("${source_file}" MATCHES "\.c$") + set(bc_build_flags "-femit-all-decls" "-xc" "-m${address_bit_size}" "-std=gnu11" "-Wno-deprecated-declarations") + elseif("${source_file}" MATCHES "\.cpp$") + set(bc_build_flags "-femit-all-decls" "-xc++" "-m${address_bit_size}" "-std=gnu++14" "-Wno-deprecated-declarations") + else() + # assume defaults work + message(WARNING " > WARNING: Unknown file extension for ${source_file}") + set(bc_build_flags "") + endif() + + message("Build flags: ${bc_build_flags}") + add_runtime(${target_name} + SOURCES ${source_file} + ADDRESS_SIZE ${address_bit_size} + BCFLAGS ${bc_build_flags} + INCLUDEDIRECTORIES "${CMAKE_SOURCE_DIR}" + INSTALLDESTINATION "${install_folder}" + DEPENDENCIES ${ARGN} + ) +endfunction() + +add_custom_command( + OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/ABI_libc.c ${CMAKE_CURRENT_SOURCE_DIR}/ABI_libc.h + DEPENDS ${source_file} + COMMAND env TRAILOFBITS_LIBRARIES=${LIBRARY_REPOSITORY_ROOT} python3 ${CMAKE_CURRENT_SOURCE_DIR}/../generate_abi_wrapper.py + --arch "amd64" --type "c" --input ${CMAKE_CURRENT_SOURCE_DIR}/ABI_libc.pph --output ${CMAKE_CURRENT_SOURCE_DIR}/ABI_libc.c +) + +#add_custom_command( +# OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/ABI_libc_x86.c ${CMAKE_CURRENT_SOURCE_DIR}/ABI_libc.h +# DEPENDS ${source_file} +# COMMAND env TRAILOFBITS_LIBRARIES=${LIBRARY_REPOSITORY_ROOT} python3 ${CMAKE_CURRENT_SOURCE_DIR}/../generate_abi_wrapper.py +# --arch "x86" --type "c" --input ${CMAKE_CURRENT_SOURCE_DIR}/ABI_libc.pph --output ${CMAKE_CURRENT_SOURCE_DIR}/ABI_libc_x86.c +#) + +#add_custom_command( +# OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/ABI_libcpp_amd64.c +# DEPENDS ${source_file} +# COMMAND env TRAILOFBITS_LIBRARIES=${LIBRARY_REPOSITORY_ROOT} python ${CMAKE_CURRENT_SOURCE_DIR}/../generate_abi_wrapper.py +# --arch "amd64" --type "cpp" --input ${CMAKE_CURRENT_SOURCE_DIR}/ABI_libc.pph --output ${CMAKE_CURRENT_SOURCE_DIR}/ABI_libcpp_amd64.c +#) + +#add_custom_command( +# OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/ABI_libcpp_x86.c +# DEPENDS ${source_file} +# COMMAND env TRAILOFBITS_LIBRARIES=${LIBRARY_REPOSITORY_ROOT} python ${CMAKE_CURRENT_SOURCE_DIR}/../generate_abi_wrapper.py +# --arch "x86" --type "cpp" --input ${CMAKE_CURRENT_SOURCE_DIR}/ABI_libc.pph --output ${CMAKE_CURRENT_SOURCE_DIR}/ABI_libcpp_x86.c +#) + +add_runtime_helper(ABI_exceptions_x86 "ABI_exceptions.cpp" 32) +add_runtime_helper(ABI_libc_x86 "ABI_libc.c" 32 "ABI_libc.h") +#add_runtime_helper(ABI_libcpp_x86 "ABI_libcpp_x86.c" 32 "ABI_libc.h") + +if(CMAKE_SIZEOF_VOID_P EQUAL 8) + add_runtime_helper(ABI_exceptions_amd64 "ABI_exceptions.cpp" 64) + add_runtime_helper(ABI_libc_amd64 "ABI_libc.c" 64 "ABI_libc.h") +# add_runtime_helper(ABI_libcpp_amd64 "ABI_libcpp_amd64.c" 32 "ABI_libc.h") +endif() diff --git a/mcsema/OS/Linux/X86/klee_defs.h b/mcsema/OS/Linux/X86/klee_defs.h new file mode 100644 index 000000000..590fe4c6a --- /dev/null +++ b/mcsema/OS/Linux/X86/klee_defs.h @@ -0,0 +1,5 @@ +#include "stddef.h" +void klee_make_symbolic(void *addr, size_t nbytes, const char *name); +void klee_assume(uintptr_t condition); +void klee_alloc(unsigned int size); +void klee_dealloc(void *ptr); diff --git a/mcsema/OS/Linux/generate_abi_wrapper.py b/mcsema/OS/Linux/generate_abi_wrapper.py new file mode 100644 index 000000000..06e8af1e6 --- /dev/null +++ b/mcsema/OS/Linux/generate_abi_wrapper.py @@ -0,0 +1,276 @@ +# Copyright (c) 2020 Trail of Bits, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import os +import sys +import argparse +import logging +from collections import defaultdict + + +tob_path = os.environ['TRAILOFBITS_LIBRARIES'] +cc_path = tob_path + "/llvm/bin/clang" + +try: + import ccsyspath + syspath = ccsyspath.system_include_paths(cc_path) + print(syspath) +except ImportError: + syspath = list() + + +SUPPORTED_ARCH = ["x86", "amd64"] + +SUPPORTED_LIBRARY_TYPE = ["c", "cpp"] + +ARCH_NAME = "" + +ABI_LIBRARY_TYPE = "c" + +logging.basicConfig(filename="debug.log",level=logging.DEBUG) + +cc_pragma = """ + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated" +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + +""" + +cc_header = """ + // mcsema ABI library, automatically generated by generate_abi_wrapper.py + +extern char *gets(char *s); + +__attribute__((used)) +void *__mcsema_externs[] = { +""" + +FUNCDECL_LIST = defaultdict(list) + +FUNCDECL_MANGLED_NAME = defaultdict(list) + +LOCAL_HEADERS = [] + +# Check if the file exist at the given paths +def file_exist(all_dirs, file): + """ Check if file exist. + """ + for dir in all_dirs: + path = str(dir) + '/' + str(file) + if os.path.exists(path): + return True + return os.path.exists(str(file)) + +# Process the function types and remove the `__attribute__((...))` identifier +# from the function types +def process_function_types(type_string): + """ Pre-process the function types for the Funcdecl + """ + split_string = type_string.split(' ') + return ' '.join(str for str in split_string if '__attribute__' not in str) + +def get_function_pointer(type_string): + """ convert the function types to the pointer type + """ + return type_string[0:type_string.find('(')-1] + " (*)" + type_string[type_string.find('('):] + +def is_valid_type(type_string): + if "_Complex" in type_string or 'typeof' in type_string: + return False + else: + return True + +def is_blacklisted_func(func_name): + if 'operator' in func_name: + return True + return False + +def visit_func_decl(node): + """ Visit the function decl node and create a map of + function name with the mangled name + """ + try: + from clang.cindex import CursorKind, TypeKind + + except ImportError: + return + + if node.kind == CursorKind.FUNCTION_DECL: + func_name = node.spelling + mangled_name = node.mangled_name + if not is_blacklisted_func(func_name): + func_type = process_function_types(node.type.spelling) + if is_valid_type(func_type): + FUNCDECL_LIST[func_name].append([mangled_name, get_function_pointer(func_type), node.location]) + else: + FUNCDECL_LIST[func_name].append([mangled_name, 'void *', node.location]) + + for i in node.get_children(): + visit_func_decl(i) + + +def write_cc_file(hfile, outfile): + """ Generate ABI library source for the c headers; + """ + basename = os.path.splitext(hfile)[0] + + # generate the abi lib cc file + with open(outfile, "w") as s: + s.write(cc_pragma) + s.write("\n\n") + s.write("#include \"{}\"".format(hfile)) + s.write("\n\n") + s.write(cc_header) + s.write("\n") + for key in FUNCDECL_LIST.keys(): + type_values = FUNCDECL_LIST[key] + for type in type_values: + s.write(" //{}\n".format(repr(type[2]))) + s.write(" (void *)({}),\n".format(key)) + s.write("};\n") + print("Number of functions: {}".format(len(FUNCDECL_LIST))) + +def write_cxx_file(hfile, outfile): + """ Generate ABI library source for the c headers; + """ + basename = os.path.splitext(hfile)[0] + + # generate the abi lib cc file + with open(outfile, "w") as s: + s.write(cc_pragma) + s.write("\n\n") + s.write("#include \"{}\"".format(hfile)) + s.write("\n\n") + s.write(cc_header) + s.write("\n") + for key in FUNCDECL_LIST.iterkeys(): + key_values = FUNCDECL_LIST[key] + for value in key_values: + s.write(" //{} {}\n".format(repr(value[2]), value[0])) + # get the mangled name + s.write("// (void *)({}),\n".format(key)) + s.write("};\n") + print("Number of functions: {}".format(len(FUNCDECL_LIST))) + +def write_library_file(hfile, outfile): + """ Generate the library files """ + try: + import clang.cindex + cc_index = clang.cindex.Index.create() + libc_type = 'c++' if ABI_LIBRARY_TYPE == "cpp" else 'c' + if ARCH_NAME.lower() == 'amd64'.lower(): + tu = cc_index.parse(hfile, args=['-x', libc_type, '-m64']) + + elif ARCH_NAME.lower() == 'x86'.lower(): + tu = cc_index.parse(hfile, args=['-x', libc_type, '-m32']) + + else: + print("Unsupported architecture") + + visit_func_decl(tu.cursor) + + except ImportError: + libc_type = 'c++' if ABI_LIBRARY_TYPE == "cpp" else 'c' + pass + + if libc_type is 'c': + write_cc_file(hfile, outfile) + elif libc_type is 'c++': + write_cxx_file(hfile, outfile) + +def write_header_file(file, headers): + basename = os.path.splitext(file) + gen_filename = basename[0] + ".h" + print(gen_filename) + print(headers) + with open(gen_filename, "w") as s: + s.write("\n") + s.write("// {}\n".format(cc_path)) + s.write("#ifndef {}_H\n".format(os.path.basename(basename[0]).upper())) + s.write("#define {}_H\n".format(os.path.basename(basename[0]).upper())) + s.write(""" +#ifndef __has_include +# define __has_include(x) 1 +#endif + +#define _GNU_SOURCE 1 +#define _REGEX_RE_COMP +#define _BSD_SOURCE 1 + +""") + s.write("\n") + for entry in headers: + s.write("#if __has_include(<{}>)\n".format(entry)) + s.write("# include <{}>\n".format(entry)) + s.write("#endif\n") + for entry in LOCAL_HEADERS: + s.write("#if __has_include(\"{}\")\n".format(entry)) + s.write("# include \"{}\"\n".format(entry)) + s.write("#endif\n") + s.write("\n#endif\n") + s.flush() + return gen_filename + + +def parse_headers(infile, outfile): + header_files = set() + with open(infile, "rb") as f: + headers = f.readlines() + headers = [x.strip() for x in headers if x.startswith(b"#include")] + header_files = [x[x.find(b"<")+1:x.find(b">")] for x in headers if x != ""] + for entry in headers: + if len(entry.split(b"\"")) > 1: + LOCAL_HEADERS.append(entry.split(b"\"")[1]) + header_files = [x for x in header_files if file_exist(syspath, x)] + hfile = write_header_file(infile, header_files) + write_library_file(hfile, outfile) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + + parser.add_argument( + '--arch', + help='Name of the architecture.', + required=True) + + parser.add_argument( + '--type', + help='ABI Library types c/c++.', + required=True) + + parser.add_argument( + "--input", + help="The input pre-processed header file", + required=True) + + parser.add_argument( + "--output", + help="The output file generated with the script", + required=True) + + args = parser.parse_args(args=sys.argv[1:]) + + ARCH_NAME = args.arch + if ARCH_NAME not in SUPPORTED_ARCH: + logger.debug("Arch {} is not supported!".format(args.arch)) + + ABI_LIBRARY_TYPE = args.type + if ABI_LIBRARY_TYPE not in SUPPORTED_LIBRARY_TYPE: + logger.debug("Library type {} not supported!".format(args.type)) + + syspath.append(os.path.dirname(os.path.abspath(args.input))) + parse_headers(args.input, args.output) diff --git a/mcsema/Version.h.in b/mcsema/Version.h.in index 9683ec27e..522446e16 100644 --- a/mcsema/Version.h.in +++ b/mcsema/Version.h.in @@ -1,17 +1,18 @@ /* - * Copyright (c) 2017 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ #define MCSEMA_VERSION_STRING "@MCSEMA_VERSION_STRING@" diff --git a/scripts/docker-lifter-entrypoint.sh b/scripts/docker-lifter-entrypoint.sh index 647154cd6..9af50dfe2 100755 --- a/scripts/docker-lifter-entrypoint.sh +++ b/scripts/docker-lifter-entrypoint.sh @@ -1,5 +1,20 @@ #!/bin/sh +# Copyright (c) 2020 Trail of Bits, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + # Needed to process multiple arguments to docker image V="" diff --git a/scripts/lift_directory.py b/scripts/lift_directory.py index 2c403580c..79b1ae6e7 100755 --- a/scripts/lift_directory.py +++ b/scripts/lift_directory.py @@ -1,16 +1,17 @@ -# Copyright (c) 2017 Trail of Bits, Inc. +# Copyright (c) 2020 Trail of Bits, Inc. # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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 Affero General Public License for more details. # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . import argparse import multiprocessing diff --git a/scripts/lift_program.py b/scripts/lift_program.py index 1b44ab8af..b9fe3d9e8 100755 --- a/scripts/lift_program.py +++ b/scripts/lift_program.py @@ -1,17 +1,18 @@ #!/usr/bin/env python -# Copyright (c) 2017 Trail of Bits, Inc. +# Copyright (c) 2020 Trail of Bits, Inc. # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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 Affero General Public License for more details. # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . import argparse import hashlib diff --git a/scripts/travis.sh b/scripts/travis.sh index 6a27ca96a..39ddb3667 100755 --- a/scripts/travis.sh +++ b/scripts/travis.sh @@ -1,17 +1,19 @@ #!/usr/bin/env bash -# Copyright (c) 2017 Trail of Bits, Inc. +# Copyright (c) 2020 Trail of Bits, Inc. # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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 Affero General Public License for more details. # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specifi +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" SOURCE_DIR="${SCRIPT_DIR}/../" @@ -141,7 +143,11 @@ linux_initialize() { libstdc++6:i386 \ zlib1g-dev:i386 \ liblzma-dev:i386 \ - libtinfo-dev:i386 + libtinfo-dev:i386 + + # install clang and ccsyspath for ABI libraries generation + pip install clang ccsyspath + if [ $? -ne 0 ] ; then printf " x Could not install the required dependencies\n" return 1 diff --git a/tests/integration_tests/colors.py b/tests/integration_tests/colors.py index e0900a99f..9a353274e 100644 --- a/tests/integration_tests/colors.py +++ b/tests/integration_tests/colors.py @@ -1,16 +1,17 @@ -# Copyright (c) 2019 Trail of Bits, Inc. +# Copyright (c) 2020 Trail of Bits, Inc. # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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 Affero General Public License for more details. # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . class Colors: class c: diff --git a/tests/integration_tests/compile.py b/tests/integration_tests/compile.py index 4ed626dbb..0c608f6ed 100755 --- a/tests/integration_tests/compile.py +++ b/tests/integration_tests/compile.py @@ -1,18 +1,19 @@ #!/usr/bin/env python3 -# Copyright (c) 2019 Trail of Bits, Inc. +# Copyright (c) 2020 Trail of Bits, Inc. # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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 Affero General Public License for more details. # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . import argparse import os diff --git a/tests/integration_tests/get_cfg.py b/tests/integration_tests/get_cfg.py index 3da537937..360c48fd6 100755 --- a/tests/integration_tests/get_cfg.py +++ b/tests/integration_tests/get_cfg.py @@ -1,18 +1,19 @@ #!/usr/bin/env python3 -# Copyright (c) 2019 Trail of Bits, Inc. +# Copyright (c) 2020 Trail of Bits, Inc. # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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 Affero General Public License for more details. # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . import argparse import operator diff --git a/tests/integration_tests/populate.py b/tests/integration_tests/populate.py index a93d9016c..745074f85 100755 --- a/tests/integration_tests/populate.py +++ b/tests/integration_tests/populate.py @@ -1,18 +1,19 @@ #!/usr/bin/env python3 -# Copyright (c) 2019 Trail of Bits, Inc. +# Copyright (c) 2020 Trail of Bits, Inc. # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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 Affero General Public License for more details. # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . import os import shutil diff --git a/tests/integration_tests/result_data.py b/tests/integration_tests/result_data.py index 5e0e5fc6e..ce4e0d55d 100644 --- a/tests/integration_tests/result_data.py +++ b/tests/integration_tests/result_data.py @@ -1,3 +1,18 @@ +# Copyright (c) 2020 Trail of Bits, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + import json import operator import os diff --git a/tests/integration_tests/run_tests.py b/tests/integration_tests/run_tests.py index ef67a5ab4..dba80117f 100755 --- a/tests/integration_tests/run_tests.py +++ b/tests/integration_tests/run_tests.py @@ -1,18 +1,19 @@ #!/usr/bin/env python3 -# Copyright (c) 2019 Trail of Bits, Inc. +# Copyright (c) 2020 Trail of Bits, Inc. # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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 Affero General Public License for more details. # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . import argparse import difflib diff --git a/tests/integration_tests/util.py b/tests/integration_tests/util.py index b6b794270..534c22231 100644 --- a/tests/integration_tests/util.py +++ b/tests/integration_tests/util.py @@ -1,16 +1,17 @@ -# Copyright (c) 2019 Trail of Bits, Inc. +# Copyright (c) 2020 Trail of Bits, Inc. # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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 Affero General Public License for more details. # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . import os diff --git a/tests/test_suite_generator/CMakeLists.txt b/tests/test_suite_generator/CMakeLists.txt index fba63155a..a1a58e991 100644 --- a/tests/test_suite_generator/CMakeLists.txt +++ b/tests/test_suite_generator/CMakeLists.txt @@ -1,15 +1,17 @@ -# Copyright (c) 2017 Trail of Bits, Inc. +# Copyright (c) 2020 Trail of Bits, Inc. # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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 Affero General Public License for more details. # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specifi +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . # CMAKE_C_COMPILER or CMAKE_CXX_COMPILER *must* be set before project() # otherwise it causes infinite loops for some cmake versions diff --git a/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/arc4 b/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/arc4 index 2284baab7..23f18978a 100644 Binary files a/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/arc4 and b/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/arc4 differ diff --git a/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/complex_numbers b/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/complex_numbers index 813e16c84..385bb9d60 100644 Binary files a/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/complex_numbers and b/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/complex_numbers differ diff --git a/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/cpp_constructor b/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/cpp_constructor index a8a690cff..1ba90f8f3 100644 Binary files a/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/cpp_constructor and b/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/cpp_constructor differ diff --git a/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/exception_test b/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/exception_test index a39a4897d..e629fa285 100644 Binary files a/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/exception_test and b/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/exception_test differ diff --git a/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/gzip_amd64 b/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/gzip_amd64 index 3b60cf100..c56abdae3 100644 Binary files a/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/gzip_amd64 and b/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/gzip_amd64 differ diff --git a/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/hello_world b/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/hello_world index 13d5f5500..307fa79d0 100644 Binary files a/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/hello_world and b/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/hello_world differ diff --git a/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/ls_amd64 b/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/ls_amd64 index 73a69d7e2..443666645 100644 Binary files a/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/ls_amd64 and b/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/ls_amd64 differ diff --git a/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/nc_amd64 b/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/nc_amd64 index 0256c06d9..c33ec4ce9 100644 Binary files a/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/nc_amd64 and b/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/nc_amd64 differ diff --git a/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/pthread b/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/pthread index 3ee91c034..ca3225d64 100644 Binary files a/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/pthread and b/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/pthread differ diff --git a/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/pthread_worker b/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/pthread_worker index 0935637c1..c8b475d24 100644 Binary files a/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/pthread_worker and b/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/pthread_worker differ diff --git a/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/stringpool b/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/stringpool index ba6043819..8d063e953 100644 Binary files a/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/stringpool and b/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/stringpool differ diff --git a/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/switch b/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/switch index ade4c8d99..0b94c7df9 100644 Binary files a/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/switch and b/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/switch differ diff --git a/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/xz_amd64 b/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/xz_amd64 index 3f3ef52e3..6d3174fdc 100644 Binary files a/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/xz_amd64 and b/tests/test_suite_generator/generated/prebuilt_cfg/amd64/linux/cfg/xz_amd64 differ diff --git a/tests/test_suite_generator/generated/prebuilt_cfg/x86/linux/cfg/arc4 b/tests/test_suite_generator/generated/prebuilt_cfg/x86/linux/cfg/arc4 index 7c3f3c94d..bfe6b0443 100644 Binary files a/tests/test_suite_generator/generated/prebuilt_cfg/x86/linux/cfg/arc4 and b/tests/test_suite_generator/generated/prebuilt_cfg/x86/linux/cfg/arc4 differ diff --git a/tests/test_suite_generator/generated/prebuilt_cfg/x86/linux/cfg/complex_numbers b/tests/test_suite_generator/generated/prebuilt_cfg/x86/linux/cfg/complex_numbers index 1d786669e..8faf6a05e 100644 Binary files a/tests/test_suite_generator/generated/prebuilt_cfg/x86/linux/cfg/complex_numbers and b/tests/test_suite_generator/generated/prebuilt_cfg/x86/linux/cfg/complex_numbers differ diff --git a/tests/test_suite_generator/generated/prebuilt_cfg/x86/linux/cfg/cpp_constructor b/tests/test_suite_generator/generated/prebuilt_cfg/x86/linux/cfg/cpp_constructor index 12490f839..ca78e4756 100644 Binary files a/tests/test_suite_generator/generated/prebuilt_cfg/x86/linux/cfg/cpp_constructor and b/tests/test_suite_generator/generated/prebuilt_cfg/x86/linux/cfg/cpp_constructor differ diff --git a/tests/test_suite_generator/generated/prebuilt_cfg/x86/linux/cfg/exception_test b/tests/test_suite_generator/generated/prebuilt_cfg/x86/linux/cfg/exception_test index e4d803875..2cdb400ca 100644 Binary files a/tests/test_suite_generator/generated/prebuilt_cfg/x86/linux/cfg/exception_test and b/tests/test_suite_generator/generated/prebuilt_cfg/x86/linux/cfg/exception_test differ diff --git a/tests/test_suite_generator/generated/prebuilt_cfg/x86/linux/cfg/hello_world b/tests/test_suite_generator/generated/prebuilt_cfg/x86/linux/cfg/hello_world index eb9ef80f4..ffb732da8 100644 Binary files a/tests/test_suite_generator/generated/prebuilt_cfg/x86/linux/cfg/hello_world and b/tests/test_suite_generator/generated/prebuilt_cfg/x86/linux/cfg/hello_world differ diff --git a/tests/test_suite_generator/generated/prebuilt_cfg/x86/linux/cfg/pthread b/tests/test_suite_generator/generated/prebuilt_cfg/x86/linux/cfg/pthread index 721b8b6bb..aad82a5f6 100644 Binary files a/tests/test_suite_generator/generated/prebuilt_cfg/x86/linux/cfg/pthread and b/tests/test_suite_generator/generated/prebuilt_cfg/x86/linux/cfg/pthread differ diff --git a/tests/test_suite_generator/generated/prebuilt_cfg/x86/linux/cfg/pthread_worker b/tests/test_suite_generator/generated/prebuilt_cfg/x86/linux/cfg/pthread_worker index 4be3aba8a..28c71018e 100644 Binary files a/tests/test_suite_generator/generated/prebuilt_cfg/x86/linux/cfg/pthread_worker and b/tests/test_suite_generator/generated/prebuilt_cfg/x86/linux/cfg/pthread_worker differ diff --git a/tests/test_suite_generator/generated/prebuilt_cfg/x86/linux/cfg/stringpool b/tests/test_suite_generator/generated/prebuilt_cfg/x86/linux/cfg/stringpool index 50ee318dc..a78198919 100644 Binary files a/tests/test_suite_generator/generated/prebuilt_cfg/x86/linux/cfg/stringpool and b/tests/test_suite_generator/generated/prebuilt_cfg/x86/linux/cfg/stringpool differ diff --git a/tests/test_suite_generator/generated/prebuilt_cfg/x86/linux/cfg/switch b/tests/test_suite_generator/generated/prebuilt_cfg/x86/linux/cfg/switch index 855206240..15ae203f8 100644 Binary files a/tests/test_suite_generator/generated/prebuilt_cfg/x86/linux/cfg/switch and b/tests/test_suite_generator/generated/prebuilt_cfg/x86/linux/cfg/switch differ diff --git a/tests/test_suite_generator/scripts/copy_generated_cfgs.sh b/tests/test_suite_generator/scripts/copy_generated_cfgs.sh index 90794af13..e88c95c52 100755 --- a/tests/test_suite_generator/scripts/copy_generated_cfgs.sh +++ b/tests/test_suite_generator/scripts/copy_generated_cfgs.sh @@ -1,4 +1,20 @@ #!/usr/bin/env bash + +# Copyright (c) 2020 Trail of Bits, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + set -e ARCHS=("x86" "amd64") diff --git a/tests/test_suite_generator/src/linux/ls_amd64/CMakeLists.txt b/tests/test_suite_generator/src/linux/ls_amd64/CMakeLists.txt index 5190325dc..9e2dce974 100644 --- a/tests/test_suite_generator/src/linux/ls_amd64/CMakeLists.txt +++ b/tests/test_suite_generator/src/linux/ls_amd64/CMakeLists.txt @@ -15,7 +15,7 @@ project(ls_amd64) cmake_minimum_required(VERSION 3.2) set(PROJECT_CXXFLAGS -Wall -Werror) -set(PROJECT_LINKERFLAGS -lm) +set(PROJECT_LINKERFLAGS -lm -lselinux) AddBinaryTest(${PROJECT_NAME} BINARY ${PROJECT_NAME} diff --git a/tests/test_suite_generator/src/linux/nc_amd64/CMakeLists.txt b/tests/test_suite_generator/src/linux/nc_amd64/CMakeLists.txt index 8a45ca9e4..16e866334 100644 --- a/tests/test_suite_generator/src/linux/nc_amd64/CMakeLists.txt +++ b/tests/test_suite_generator/src/linux/nc_amd64/CMakeLists.txt @@ -15,7 +15,7 @@ project(nc_amd64) cmake_minimum_required(VERSION 3.2) set(PROJECT_CXXFLAGS -Wall -Werror) -set(PROJECT_LINKERFLAGS -lm -lresolv) +set(PROJECT_LINKERFLAGS -lm -lresolv -lbsd) AddBinaryTest(${PROJECT_NAME} BINARY ${PROJECT_NAME} diff --git a/tests/test_suite_generator/src/linux/xz_amd64/CMakeLists.txt b/tests/test_suite_generator/src/linux/xz_amd64/CMakeLists.txt index d6ff1cb25..26a9418ea 100644 --- a/tests/test_suite_generator/src/linux/xz_amd64/CMakeLists.txt +++ b/tests/test_suite_generator/src/linux/xz_amd64/CMakeLists.txt @@ -2,7 +2,7 @@ project(xz_amd64) cmake_minimum_required(VERSION 3.2) set(PROJECT_CXXFLAGS -Wall -Werror) -set(PROJECT_LINKERFLAGS -lm -ldl -llzma) +set(PROJECT_LINKERFLAGS -lm -ldl -llzma -lpthread) AddBinaryTest(${PROJECT_NAME} BINARY ${PROJECT_NAME} diff --git a/tests/test_suite_generator/src/start.py b/tests/test_suite_generator/src/start.py index 9e8eb8268..cf7f21a42 100755 --- a/tests/test_suite_generator/src/start.py +++ b/tests/test_suite_generator/src/start.py @@ -1,17 +1,19 @@ #!/usr/bin/env python2 -# Copyright (c) 2017 Trail of Bits, Inc. +# Copyright (c) 2020 Trail of Bits, Inc. # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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 Affero General Public License for more details. # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specifi +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . import sys import os diff --git a/tools/diff_traces.py b/tools/diff_traces.py index 5f532ec93..274fed6df 100644 --- a/tools/diff_traces.py +++ b/tools/diff_traces.py @@ -1,17 +1,19 @@ #!/usr/bin/env python -# Copyright (c) 2017 Trail of Bits, Inc. + +# Copyright (c) 2020 Trail of Bits, Inc. # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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 Affero General Public License for more details. # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . import argparse import itertools diff --git a/tools/generate_def_file.py b/tools/generate_def_file.py index 36e3dd142..d1efea1d1 100755 --- a/tools/generate_def_file.py +++ b/tools/generate_def_file.py @@ -1,17 +1,19 @@ #!/usr/bin/env python -# Copyright (c) 2017 Trail of Bits, Inc. + +# Copyright (c) 2020 Trail of Bits, Inc. # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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 Affero General Public License for more details. # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . import os.path import subprocess diff --git a/tools/mcsema_disass/__main__.py b/tools/mcsema_disass/__main__.py index 43d6f001b..a3de7c3ab 100755 --- a/tools/mcsema_disass/__main__.py +++ b/tools/mcsema_disass/__main__.py @@ -1,17 +1,19 @@ #!/usr/bin/env python -# Copyright (c) 2017 Trail of Bits, Inc. + +# Copyright (c) 2020 Trail of Bits, Inc. # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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 Affero General Public License for more details. # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . import argparse import os @@ -24,7 +26,7 @@ import traceback import textwrap -SUPPORTED_OS = ('linux', 'windows',) +SUPPORTED_OS = ('linux', 'macos', 'windows', 'solaris') SUPPORTED_ARCH = ('x86', 'x86_avx', 'x86_avx512', 'amd64', 'amd64_avx', 'amd64_avx512', 'aarch64') @@ -98,7 +100,7 @@ def main(): arg_parser.add_argument( '--entrypoint', help="The entrypoint where disassembly should begin", - required=True) + required=False) args, command_args = arg_parser.parse_known_args() @@ -149,10 +151,7 @@ def main(): ret = 1 try: if 'ida' in args.disassembler: - if 'idat' in args.disassembler: - import ida7.disass as disass - else: - import ida.disass as disass + import ida7.disass as disass ret = disass.execute(args, fixed_command_args) # in case IDA somehow says success, but no output was generated if not os.path.isfile(args.output): @@ -165,11 +164,7 @@ def main(): # remove the zero-sized file os.unlink(args.output) ret = 1 - elif 'binja' in args.disassembler or 'binaryninja' in args.disassembler: - if not _find_binary_ninja(args.disassembler): - arg_parser.error("Could not `import binaryninja`. Is it in your PYTHONPATH?") - from binja.cfg import get_cfg - ret = get_cfg(args, fixed_command_args) + elif 'dyninst' in args.disassembler: # TODO: This can almost certainly be done in cleaner way pass_args = [ diff --git a/tools/mcsema_disass/binja/__init__.py b/tools/mcsema_disass/binja/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tools/mcsema_disass/binja/cfg.py b/tools/mcsema_disass/binja/cfg.py deleted file mode 100644 index 4cc6f9fc0..000000000 --- a/tools/mcsema_disass/binja/cfg.py +++ /dev/null @@ -1,637 +0,0 @@ -# Copyright (c) 2017 Trail of Bits, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import argparse -import binaryninja as binja -from binaryninja.enums import ( - SymbolType, TypeClass, - LowLevelILOperation, RegisterValueType, - InstructionTextTokenType -) -import logging -import os -from Queue import Queue -from collections import defaultdict - -import CFG_pb2 -import util -import xrefs -import jmptable -import vars -from debug import * - -log = logging.getLogger(util.LOGNAME) - -BINJA_DIR = os.path.dirname(os.path.abspath(__file__)) -DISASS_DIR = os.path.dirname(BINJA_DIR) - -EXT_MAP = {} -EXT_DATA_MAP = {} -JMP_TABLES = [] - -CCONV_TYPES = { - 'C': CFG_pb2.ExternalFunction.CallerCleanup, - 'E': CFG_pb2.ExternalFunction.CalleeCleanup, - 'F': CFG_pb2.ExternalFunction.FastCall -} - -BINJA_CCONV_TYPES = { - 'cdecl': CFG_pb2.ExternalFunction.CallerCleanup, - 'stdcall': CFG_pb2.ExternalFunction.CalleeCleanup, - 'fastcall': CFG_pb2.ExternalFunction.FastCall -} - -RECOVERED = set() -TO_RECOVER = Queue() - -RECOVER_OPTS = { - 'stack_vars': False -} - -def queue_func(addr): - if addr not in RECOVERED: - TO_RECOVER.put(addr) - - -def func_has_return_type(func): - rtype = func.function_type.return_value.type_class - return rtype != TypeClass.VoidTypeClass - - -def recover_ext_func(bv, pb_mod, sym): - """ Recover external function information - Uses the map of predefined externals if possible - - Args: - bv (binja.BinaryView) - pb_mod (CFG_pb2.Module) - sym (binaryninja.types.Symbol) - """ - DEBUG("Recovering external function {} at {:x}".format(sym.name, sym.address)) - if sym.name in EXT_MAP: - DEBUG('Found defined external function: {} @ {:x}'.format(sym.name, sym.address)) - - args, cconv, ret, sign = EXT_MAP[sym.name] - func = bv.get_function_at(sym.address) - if func is None: - return - - pb_extfn = pb_mod.external_funcs.add() - pb_extfn.name = sym.name - pb_extfn.ea = sym.address - pb_extfn.argument_count = args - pb_extfn.cc = cconv - pb_extfn.has_return = func_has_return_type(func) - pb_extfn.no_return = ret == 'Y' - pb_extfn.is_weak = False # TODO: figure out how to decide this - - else: - WARN("External function is not part of defs file") - - func = bv.get_function_at(sym.address) - ftype = func.function_type - - pb_extfn = pb_mod.external_funcs.add() - pb_extfn.name = sym.name - pb_extfn.ea = sym.address - pb_extfn.argument_count = len(ftype.parameters) - pb_extfn.has_return = func_has_return_type(func) - pb_extfn.no_return = not ftype.can_return - pb_extfn.is_weak = False # TODO: figure out how to decide this - - # Assume cdecl if the type is unknown - cconv = ftype.calling_convention - if cconv is not None and cconv.name in BINJA_CCONV_TYPES: - pb_extfn.cc = BINJA_CCONV_TYPES[str(cconv)] - else: - pb_extfn.cc = CFG_pb2.ExternalFunction.CallerCleanup - - -def recover_ext_var(bv, pb_mod, sym): - """ Recover external variable information - - Args: - bv (binja.BinaryView) - pb_mod (CFG_pb2.Module) - sym (binja.types.Symbol) - """ - if sym.name in EXT_DATA_MAP: - DEBUG("Recovering external variable {} at {:x}".format(sym.name, sym.address)) - - pb_extvar = pb_mod.external_vars.add() - pb_extvar.name = sym.name - pb_extvar.ea = sym.address - pb_extvar.size = EXT_DATA_MAP[sym.name] - pb_extvar.is_weak = False # TODO: figure out how to decide this - pb_extvar.is_thread_local = util.is_tls_section(bv, sym.address) - else: - ERROR("Unknown external variable {} at {:x}".format(sym.name, sym.address)) - - -def recover_externals(bv, pb_mod): - """Recover info about all external symbols""" - DEBUG("Recovering externals") - DEBUG_PUSH() - for sym in bv.get_symbols(): - if sym.type == SymbolType.ImportedFunctionSymbol: - recover_ext_func(bv, pb_mod, sym) - - if sym.type == SymbolType.ImportedDataSymbol: - recover_ext_var(bv, pb_mod, sym) - DEBUG_POP() - -_BYTE_WIDTH_NAME = {4: "dword", 8: "qword"} - -def recover_section_cross_references(bv, pb_seg, real_sect, sect_start, sect_end): - """ Find references to other code/data in this section - - Args: - bv (binja.BinaryView) - pb_seg (CFG_pb2.Segment) - real_sect (binja.binaryview.Section) - sect_start (int) - sect_end (int) - """ - entry_width = util.clamp(real_sect.align, 4, bv.address_size) - read_val = {4: util.read_dword, - 8: util.read_qword}[entry_width] - - DEBUG("Recovering references in [{:x}, {:x}) of section {}".format( - sect_start, sect_end, real_sect.name)) - - DEBUG_PUSH() - for addr in xrange(sect_start, sect_end, entry_width): - xref = read_val(bv, addr) - - if not util.is_valid_addr(bv, xref): - continue - - # Skip this xref if it's a jmp table entry - if any(xref in tbl.targets for tbl in JMP_TABLES): - continue - - width_name = _BYTE_WIDTH_NAME.get(entry_width, "{}-byte".format(entry_width)) - DEBUG("Adding {} reference from {:x} to {:x}".format(width_name, addr, xref)) - - pb_ref = pb_seg.xrefs.add() - pb_ref.ea = addr - pb_ref.width = entry_width - pb_ref.target_ea = xref - pb_ref.target_name = util.find_symbol_name(bv, xref) - pb_ref.target_is_code = util.is_code(bv, xref) - - if util.is_tls_section(bv, addr): - pb_ref.target_fixup_kind = CFG_pb2.DataReference.OffsetFromThreadBase - else: - pb_ref.target_fixup_kind = CFG_pb2.DataReference.Absolute - - DEBUG_POP() - - -def recover_section_vars(bv, pb_seg, sect_start, sect_end): - """ Gather any symbols that point to data in this section - - Args:x - bv (binja.BinaryView) - pb_seg (CFG_pb2.Segment) - sect_start (int) - sect_end (int) - """ - - DEBUG("Recovering variables in [{:x}, {:x}) of section {}".format( - sect_start, sect_end, pb_seg.name)) - DEBUG_PUSH() - for sym in bv.get_symbols(): - # Ignore functions and externals - if sym.type in [SymbolType.FunctionSymbol, - SymbolType.ImportedFunctionSymbol, - SymbolType.ImportedDataSymbol, - SymbolType.ImportAddressSymbol]: - continue - - if sect_start <= sym.address < sect_end: - DEBUG("Adding variable {} at {:x}".format(sym.name, sym.address)) - pb_segvar = pb_seg.vars.add() - pb_segvar.ea = sym.address - pb_segvar.name = sym.name - - DEBUG_POP() - -def recover_sections(bv, pb_mod): - # Collect all address to split on - sec_addrs = set() - for sect in bv.sections.values(): - sec_addrs.add(sect.start) - sec_addrs.add(sect.end) - - global_starts = [gvar.ea for gvar in pb_mod.global_vars] - sec_addrs.update(global_starts) - - # Process all the split segments - sec_splits = sorted(list(sec_addrs)) - for start_addr, end_addr in zip(sec_splits[:-1], sec_splits[1:]): - real_sect = util.get_section_at(bv, start_addr) - - # Ignore any gaps - if real_sect is None: - continue - - DEBUG("Recovering [{:x}, {:x}) from segment {}".format( - start_addr, end_addr, real_sect.name)) - - pb_seg = pb_mod.segments.add() - pb_seg.name = real_sect.name - pb_seg.ea = start_addr - pb_seg.data = bv.read(start_addr, end_addr - start_addr) - pb_seg.is_external = util.is_section_external(bv, real_sect) - pb_seg.read_only = not util.is_readable(bv, start_addr) - pb_seg.is_thread_local = util.is_tls_section(bv, start_addr) - - sym = bv.get_symbol_at(start_addr) - pb_seg.is_exported = sym is not None and start_addr in global_starts - if pb_seg.is_exported and sym.name != real_sect.name: - pb_seg.variable_name = sym.name - - recover_section_vars(bv, pb_seg, start_addr, end_addr) - recover_section_cross_references(bv, pb_seg, real_sect, start_addr, end_addr) - - -def is_local_noreturn(bv, il): - """ - Args: - bv (binja.BinaryView) - il (binja.LowLevelILInstruction): - - Returns: - bool - """ - if il.operation in [LowLevelILOperation.LLIL_CALL, - LowLevelILOperation.LLIL_JUMP, - LowLevelILOperation.LLIL_GOTO]: - # Resolve the destination address - tgt_addr = None - dst = il.dest - - # GOTOs have an il index as the arg - if isinstance(dst, int): - tgt_addr = il.function[dst].address - - # Others will have an expression as the argument - elif isinstance(dst, binja.LowLevelILInstruction): - # Immediate address - if dst.operation in [LowLevelILOperation.LLIL_CONST, - LowLevelILOperation.LLIL_CONST_PTR]: - tgt_addr = dst.constant - - # Register - elif dst.operation == LowLevelILOperation.LLIL_REG: - # Attempt to resolve the register value - func = il.function.source_function - reg_val = func.get_reg_value_at(il.address, dst.src) - if reg_val.type == RegisterValueType.ConstantValue: - tgt_addr = reg_val.value - - # If a target address was recovered, check if it's in a noreturn function - if tgt_addr is not None: - tgt_func = util.get_func_containing(bv, tgt_addr) - return not tgt_func.function_type.can_return - - # Other instructions that terminate control flow - return il.operation in [LowLevelILOperation.LLIL_TRAP, - LowLevelILOperation.LLIL_BP] - - -_CFG_INST_XREF_TYPE_TO_NAME = { - CFG_pb2.CodeReference.ImmediateOperand: "imm", - CFG_pb2.CodeReference.MemoryOperand: "mem", - CFG_pb2.CodeReference.MemoryDisplacementOperand: "disp", - CFG_pb2.CodeReference.ControlFlowOperand: "flow" -} - - -def add_xref(bv, pb_inst, target, mask, optype): - xref = pb_inst.xrefs.add() - xref.ea = target - xref.operand_type = optype - - debug_mask = "" - if mask: - xref.mask = mask - debug_mask = " & {:x}".format(mask) - - sym_name = util.find_symbol_name(bv, target) - if len(sym_name) > 0: - xref.name = sym_name - - if util.is_code(bv, target): - xref.target_type = CFG_pb2.CodeReference.CodeTarget - debug_type = "code" - else: - xref.target_type = CFG_pb2.CodeReference.DataTarget - debug_type = "data" - - if util.is_external_ref(bv, target): - xref.location = CFG_pb2.CodeReference.External - debug_loc = "external" - else: - xref.location = CFG_pb2.CodeReference.Internal - debug_loc = "internal" - - # If the target happens to be a function, queue it for recovery - if bv.get_function_at(target) is not None: - queue_func(target) - - debug_op = _CFG_INST_XREF_TYPE_TO_NAME[optype] - - return "({} {} {} {:x}{} {})".format( - debug_type, debug_op, debug_loc, target, debug_mask, sym_name) - -def read_inst_bytes(bv, il): - """ Get the opcode bytes for an instruction - Args: - bv (binja.BinaryView) - il (binja.LowLevelILInstruction) - Returns: - str - """ - inst_len = bv.get_instruction_length(il.address) - return bv.read(il.address, inst_len) - - -def recover_inst(bv, func, pb_block, pb_inst, il, all_il, is_last): - """ - Args: - bv (binja.BinaryView) - pb_inst (CFG_pb2.Instruction) - il (binaryninja.lowlevelil.LowLevelILInstruction) - all_il (list): Collection of all il instructions at this address - (e.g. all instructions expanded from a cmov) - """ - pb_inst.ea = il.address - pb_inst.bytes = read_inst_bytes(bv, il) - - # Search all il instructions at the current address for xrefs - refs = set() - for il_exp in all_il: - refs.update(xrefs.get_xrefs(bv, func, il_exp)) - - debug_refs = [] - - # Add all discovered xrefs to pb_inst - for ref in refs: - debug_refs.append(add_xref(bv, pb_inst, ref.addr, ref.mask, ref.cfg_type)) - - if is_local_noreturn(bv, il): - pb_inst.local_noreturn = True - - # Add the target of a tail call as a successor - if util.is_jump_tail_call(bv, il): - tgt = il.dest.constant - pb_block.successor_eas.append(tgt) - - table = jmptable.get_jmptable(bv, il) - if table is not None: - debug_refs.append(add_xref(bv, pb_inst, table.base_addr, 0, CFG_pb2.CodeReference.MemoryDisplacementOperand)) - JMP_TABLES.append(table) - - # Add any missing successors - for tgt in table.targets: - if tgt not in pb_block.successor_eas: - pb_block.successor_eas.append(tgt) - - DEBUG("I: {:x} {}".format(il.address, " ".join(debug_refs))) - - if is_last: - if len(pb_block.successor_eas): - DEBUG(" Successors: {}".format(", ".join("{:x}".format(ea) for ea in pb_block.successor_eas))) - else: - DEBUG(" No successors") - - -def add_block(pb_func, block): - """ - Args: - pb_func (CFG_pb2.Function) - block (binaryninja.basicblock.BasicBlock) - - Returns: - CFG_pb2.Block - """ - DEBUG("BB: {:x}".format(block.start)) - pb_block = pb_func.blocks.add() - pb_block.ea = block.start - pb_block.successor_eas.extend(edge.target.start for edge in block.outgoing_edges) - return pb_block - - -def fix_tail_call_targets(bv, func): - """ - Binja will "inline" tail calls into the current function, resulting in the - same blocks appearing in multiple functions. This detects if this happened - and defines a function at the first inlined block so nothing is duplicated - - Args: - bv (binja.BinaryView) - func (binja.Function) - """ - for block in func.basic_blocks: - # This will return a list of all basic blocks starting at the same address - # The same block appearing in different functions (after inlining) - # will appear as multiple `BasicBlock`s - all_blocks = bv.get_basic_blocks_at(block.start) - - # There should only be a single block found - if len(all_blocks) > 1: - log.debug('Block 0x%x exists in multiple functions, defining a new function here', block.start) - - # Define a function here and reanalyze - # All blocks contained in this new function will not be picked up - # in the remainder of this loop after analysis - bv.add_function(block.start) - bv.update_analysis_and_wait() - - -def recover_function(bv, pb_mod, addr, is_entry=False): - func = bv.get_function_at(addr) - if func is None: - log.error('No function defined at 0x%x, skipping', addr) - return - - if func.symbol.type == SymbolType.ImportedFunctionSymbol: - # Externals are recovered later, skip this - log.warn("Skipping external function '%s' in main CFG recovery", func.symbol.name) - return - - # Initialize the protobuf for this function - DEBUG("Recovering function {} at {:x}".format(func.symbol.name, addr)) - - pb_func = pb_mod.funcs.add() - pb_func.ea = addr - pb_func.is_entrypoint = is_entry - pb_func.name = func.symbol.name - - # Recover all basic blocks - il_groups = util.collect_il_groups(func.lifted_il) - var_refs = defaultdict(list) - for block in func: - DEBUG_PUSH() - pb_block = add_block(pb_func, block) - DEBUG_PUSH() - - # Recover every instruction in the block - insts = list(block.disassembly_text) - for inst in insts: - # Skip over anything that isn't an instruction - if inst.tokens[0].type != InstructionTextTokenType.InstructionToken: - continue - il = func.get_lifted_il_at(inst.address) - all_il = il_groups[inst.address] - - pb_inst = pb_block.instructions.add() - recover_inst(bv, func, pb_block, pb_inst, il, all_il, is_last=inst==insts[-1]) - - # Find any references to stack vars in this instruction - if RECOVER_OPTS['stack_vars']: - vars.find_stack_var_refs(bv, inst, il, var_refs) - - DEBUG_POP() - DEBUG_POP() - - # Recover stack variables - if RECOVER_OPTS['stack_vars']: - vars.recover_stack_vars(pb_func, func, var_refs) - - -def recover_cfg(bv, args): - pb_mod = CFG_pb2.Module() - pb_mod.name = os.path.basename(bv.file.filename) - - # Find the chosen entrypoint in the binary - if args.entrypoint not in bv.symbols: - log.fatal('Entrypoint not found: %s', args.entrypoint) - entry_addr = bv.symbols[args.entrypoint].address - - # Recover the entrypoint func separately - log.debug('Recovering CFG') - recover_function(bv, pb_mod, entry_addr, is_entry=True) - - # Recover any discovered functions until there are none left - while not TO_RECOVER.empty(): - addr = TO_RECOVER.get() - - if addr in RECOVERED: - continue - RECOVERED.add(addr) - - recover_function(bv, pb_mod, addr) - - log.debug('Recovering Globals') - vars.recover_globals(bv, pb_mod) - - log.debug('Processing Segments') - recover_sections(bv, pb_mod) - - log.debug('Recovering Externals') - recover_externals(bv, pb_mod) - - return pb_mod - - -def parse_defs_file(bv, path): - log.debug('Parsing %s', path) - with open(path) as f: - for line in f.readlines(): - # Skip comments/empty lines - if len(line.strip()) == 0 or line[0] == '#': - continue - - if line.startswith('DATA:'): - # DATA: (name) (PTR | size) - _, dname, dsize = line.split() - if 'PTR' in dsize: - dsize = bv.address_size - EXT_DATA_MAP[dname] = int(dsize) - else: - # (name) (# args) (cconv) (ret) [(sign) | None] - fname, args, cconv, ret, sign = (line.split() + [None])[:5] - - if cconv not in CCONV_TYPES: - log.fatal('Unknown calling convention: %s', cconv) - exit(1) - - if ret not in ['Y', 'N']: - log.fatal('Unknown return type: %s', ret) - exit(1) - - EXT_MAP[fname] = (int(args), CCONV_TYPES[cconv], ret, sign) - - -def get_cfg(args, fixed_args): - # Parse any additional args - parser = argparse.ArgumentParser() - - parser.add_argument( - '--recover-stack-vars', - help='Flag to enable stack variable recovery', - default=False, - action='store_true') - - parser.add_argument( - "--std-defs", - action='append', - type=str, - default=[], - help="std_defs file: definitions and calling conventions of imported functions and data") - - extra_args = parser.parse_args(fixed_args) - - if extra_args.recover_stack_vars: - RECOVER_OPTS['stack_vars'] = True - - # Setup logger - util.init_logger(args.log_file) - - # Load the binary in binja - bv = util.load_binary(args.binary) - - # Once for good measure. - bv.add_analysis_option("linearsweep") - bv.update_analysis_and_wait() - - # Twice for good luck! - bv.add_analysis_option("linearsweep") - bv.update_analysis_and_wait() - - # Collect all paths to defs files - log.debug('Parsing definitions files') - def_paths = set(map(os.path.abspath, extra_args.std_defs)) - def_paths.add(os.path.join(DISASS_DIR, 'defs', '{}.txt'.format(args.os))) # default defs file - - # Parse all of the defs files - for fpath in def_paths: - if os.path.isfile(fpath): - parse_defs_file(bv, fpath) - else: - log.warn('%s is not a file', fpath) - - # Recover module - log.debug('Starting analysis') - pb_mod = recover_cfg(bv, args) - - # Save cfg - log.debug('Saving to file: %s', args.output) - with open(args.output, 'wb') as f: - f.write(pb_mod.SerializeToString()) - - return 0 diff --git a/tools/mcsema_disass/binja/debug.py b/tools/mcsema_disass/binja/debug.py deleted file mode 100644 index 9362184ed..000000000 --- a/tools/mcsema_disass/binja/debug.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright (c) 2017 Trail of Bits, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import logging -import util - -log = logging.getLogger(util.LOGNAME) - - -_DEBUG_PREFIX = "" - -def DEBUG_PUSH(): - global _DEBUG_PREFIX - _DEBUG_PREFIX += " " - -def DEBUG_POP(): - global _DEBUG_PREFIX - _DEBUG_PREFIX = _DEBUG_PREFIX[:-2] - -def DEBUG(s): - log.debug("{}{}".format(_DEBUG_PREFIX, str(s))) - -def WARN(s): - log.warn("{}{}".format(_DEBUG_PREFIX, str(s))) - -def ERROR(s): - log.error("{}{}".format(_DEBUG_PREFIX, str(s))) - - \ No newline at end of file diff --git a/tools/mcsema_disass/binja/jmptable.py b/tools/mcsema_disass/binja/jmptable.py deleted file mode 100644 index a67e85d54..000000000 --- a/tools/mcsema_disass/binja/jmptable.py +++ /dev/null @@ -1,144 +0,0 @@ -# Copyright (c) 2017 Trail of Bits, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import binaryninja as binja -from binaryninja.enums import ( - LowLevelILOperation, MediumLevelILOperation, RegisterValueType -) -import logging -import util -from debug import * - -log = logging.getLogger(util.LOGNAME) - - -class JMPTable(object): - """ Simple container for jump table info """ - def __init__(self, bv, rel_base, targets, rel_off=0): - self.rel_off = rel_off - self.rel_base = rel_base - - # Calculate the absolute base address - mask = (1 << bv.address_size * 8) - 1 - self.base_addr = (self.rel_base + self.rel_off) & mask - - self.targets = [t & mask for t in targets] - - - -def search_mlil_displ(il, ptr=False, _neg=False): - """ Searches for a MLIL_CONST[_PTR] as a child of an ADD or SUB - - Args: - il (binja.LowLevelILInstruction): Instruction to parse - ptr (bool): Searches for CONST_PTR instead of CONST if True - _neg (bool): Used internally to negate the final output if needed - - Returns: - int: located value - """ - # The il may be inside a MLIL_LOAD - if il.operation == MediumLevelILOperation.MLIL_LOAD: - return search_mlil_displ(il.src, ptr, _neg) - - # Continue left/right for ADD/SUB only - if il.operation in [MediumLevelILOperation.MLIL_ADD, - MediumLevelILOperation.MLIL_SUB]: - _neg = (il.operation == MediumLevelILOperation.MLIL_SUB) - return (search_mlil_displ(il.left, ptr, _neg) or - search_mlil_displ(il.right, ptr, _neg)) - - # Terminate when we find a constant - const_type = MediumLevelILOperation.MLIL_CONST_PTR if ptr else MediumLevelILOperation.MLIL_CONST - if il.operation == const_type: - return il.constant * (-1 if _neg else 1) - - # DEBUG('Reached end of expr: {}'.format(il)) - - -def get_jmptable(bv, il): - """ Gathers jump table information (if any) being referenced at the given il - - Args: - bv (binja.BinaryView) - il (binja.LowLevelILInstruction) - - Returns: - JMPTable: Jump table info if found, None otherwise - """ - # Rule out other instructions - op = il.operation - if op not in [LowLevelILOperation.LLIL_JUMP_TO, LowLevelILOperation.LLIL_JUMP]: - return None - - # Ignore any jmps that have an immediate address - if il.dest.operation in [LowLevelILOperation.LLIL_CONST, - LowLevelILOperation.LLIL_CONST_PTR]: - return None - - # Ignore any jmps that have an immediate dereference (i.e. thunks) - if il.dest.operation == LowLevelILOperation.LLIL_LOAD and \ - il.dest.src.operation in [LowLevelILOperation.LLIL_CONST, - LowLevelILOperation.LLIL_CONST_PTR]: - return None - - func = il.function.source_function - il_func = func.low_level_il - - # Gather all targets of the jump in case binja didn't lift this to LLIL_JUMP_TO - successors = [] - tgt_table = func.get_low_level_il_at(il.address).dest.possible_values - if tgt_table.type == RegisterValueType.LookupTableValue: - successors.extend(tgt_table.mapping.values()) - - # Should be able to find table info now - tbl = None - - # Jumping to a register - if il.dest.operation == LowLevelILOperation.LLIL_REG: - # This is likely a relative offset table - # Go up to MLIL and walk back a few instructions to find the values we need - mlil_func = func.medium_level_il - - # (Roughly) find the MLIL instruction at this jump - inst_idx = func.get_low_level_il_at(il.address).instr_index - mlil_idx = il_func.get_medium_level_il_instruction_index(inst_idx) - - # Find a MLIL_LOAD with the address/offset we need - while mlil_idx > 0: - mlil = mlil_func[mlil_idx] - if mlil.operation == MediumLevelILOperation.MLIL_SET_VAR and \ - mlil.src.operation == MediumLevelILOperation.MLIL_LOAD: - # Possible jump table info here, try parsing it - base = search_mlil_displ(mlil.src, ptr=True) - offset = search_mlil_displ(mlil.src) - - # If it worked return the table info - if None not in [base, offset]: - tbl = JMPTable(bv, base, successors, offset) - break - - # Keep walking back - mlil_idx -= 1 - - # Full jump expression - else: - # Parse out the base address - base = util.search_displ_base(il.dest) - if base is not None: - tbl = JMPTable(bv, base, successors) - - if tbl is not None: - DEBUG("Found jump table at {:x} with offset {:x}".format(tbl.base_addr, tbl.rel_off)) - return tbl diff --git a/tools/mcsema_disass/binja/util.py b/tools/mcsema_disass/binja/util.py deleted file mode 100644 index 24dc8c18e..000000000 --- a/tools/mcsema_disass/binja/util.py +++ /dev/null @@ -1,341 +0,0 @@ -# Copyright (c) 2017 Trail of Bits, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import binaryninja as binja -from binaryninja.enums import ( - Endianness, LowLevelILOperation, SectionSemantics -) -import inspect -import logging -import magic -import re -import struct -from collections import defaultdict - -LOGNAME = 'binja.cfg' -log = logging.getLogger(LOGNAME) - - -class StackFormatter(logging.Formatter): - def __init__(self, fmt=None, datefmt=None): - logging.Formatter.__init__(self, fmt, datefmt) - self.stack_base = len(inspect.stack()) + 7 - - def format(self, record): - record.indent = ' ' * (len(inspect.stack()) - self.stack_base) - res = logging.Formatter.format(self, record) - del record.indent - return res - - -def init_logger(log_file): - formatter = StackFormatter('[%(levelname)s] %(indent)s%(message)s') - handler = logging.FileHandler(log_file) - handler.setFormatter(formatter) - - log.addHandler(handler) - log.setLevel(logging.DEBUG) - - -ENDIAN_TO_STRUCT = { - Endianness.LittleEndian: '<', - Endianness.BigEndian: '>' -} - - -def read_dword(bv, addr): - # type: (binja.BinaryView, int) -> int - # Pad the data if fewer than 4 bytes are read - endianness = ENDIAN_TO_STRUCT[bv.endianness] - data = bv.read(addr, 4) - padded_data = '{{:\x00{}4s}}'.format(endianness).format(data) - fmt = '{}L'.format(endianness) - return struct.unpack(fmt, padded_data)[0] - - -def read_qword(bv, addr): - # type: (binja.BinaryView, int) -> int - # Pad the data if fewer than 8 bytes are read - endianness = ENDIAN_TO_STRUCT[bv.endianness] - data = bv.read(addr, 8) - padded_data = '{{:\x00{}8s}}'.format(endianness).format(data) - fmt = '{}Q'.format(endianness) - return struct.unpack(fmt, padded_data)[0] - - -def load_binary(path): - magic_type = magic.from_file(path) - if 'ELF' in magic_type: - bv_type = binja.BinaryViewType['ELF'] - elif 'PE32' in magic_type: - bv_type = binja.BinaryViewType['PE'] - elif 'Mach-O' in magic_type: - bv_type = binja.BinaryViewType['Mach-O'] - else: - bv_type = binja.BinaryViewType['Raw'] - - # Can't do anything with Raw type - log.fatal('Unknown binary type: "{}", exiting'.format(magic_type)) - exit(1) - - log.debug('Loading binary in binja...') - bv = bv_type.open(path) - bv.update_analysis_and_wait() - - # NOTE: at the moment binja will not load a binary - # that doesn't have an entry point - if len(bv) == 0: - log.error('Binary could not be loaded in binja, is it linked?') - exit(1) - - return bv - - -def find_symbol_name(bv, addr): - """Attempt to find a symbol for a given address - - Args: - bv (binja.BinaryView) - addr (int): Address the symbol should point to - - Returns: - (str): Symbol name if found, empty string otherwise - - """ - sym = bv.get_symbol_at(addr) - if sym is not None: - return sym.name - return '' - - -def get_func_containing(bv, addr): - """ Finds the function, if any, containing the given address - Args: - bv (binja.BinaryView) - addr (int) - - Returns: - binja.Function - """ - funcs = bv.get_functions_containing(addr) - return funcs[0] if funcs is not None else None - - -def get_section_at(bv, addr): - """Returns the section in the binary that contains the given address""" - if not is_valid_addr(bv, addr): - return None - - for sec in bv.sections.values(): - if sec.start <= addr < sec.end: - return sec - return None - - -def is_external_ref(bv, addr): - sym = bv.get_symbol_at(addr) - return sym is not None and 'Import' in sym.type.name - - -def is_valid_addr(bv, addr): - return bv.get_segment_at(addr) is not None - - -def is_code(bv, addr): - """Returns `True` if the given address lies in a code section""" - # This is a bit more specific than checking if a segment is executable, - # Binja will classify a section as ReadOnlyCode or ReadOnlyData, though - # both sections are still in an executable segment - sec = get_section_at(bv, addr) - return sec is not None and sec.semantics == SectionSemantics.ReadOnlyCodeSectionSemantics - - -def is_executable(bv, addr): - """Returns `True` if the given address lies in an executable segment""" - seg = bv.get_segment_at(addr) - return seg is not None and seg.executable - - -def is_readable(bv, addr): - """Returns `True` if the given address lies in a readable segment""" - seg = bv.get_segment_at(addr) - return seg is not None and seg.writable - - -def is_writeable(bv, addr): - """Returns `True` if the given address lies in a writable segment""" - seg = bv.get_segment_at(addr) - return seg is not None and seg.readable - - -def is_ELF(bv): - return bv.view_type == 'ELF' - - -def is_PE(bv): - return bv.view_type == 'PE' - - -def clamp(val, vmin, vmax): - return min(vmax, max(vmin, val)) - - -# Caching results of is_section_external -_EXT_SECTIONS = set() -_INT_SECTIONS = set() - - -def is_section_external(bv, sect): - """Returns `True` if the given section contains only external references - - Args: - bv (binja.BinaryView) - sect (binja.binaryview.Section) - """ - if sect.start in _EXT_SECTIONS: - return True - - if sect.start in _INT_SECTIONS: - return False - - if is_ELF(bv): - if re.search(r'\.(got|plt)', sect.name): - _EXT_SECTIONS.add(sect.start) - return True - - if is_PE(bv): - if '.idata' in sect.name: - _EXT_SECTIONS.add(sect.start) - return True - - _INT_SECTIONS.add(sect.start) - return False - - -def is_tls_section(bv, addr): - sect_names = (sect.name for sect in bv.get_sections_at(addr)) - return any(sect in ['.tbss', '.tdata', '.tls'] for sect in sect_names) - - -def _search_phrase_op(il, target_op): - """ Helper for finding parts of a phrase[+displacement] il """ - op = il.operation - - # Handle starting points - if op == LowLevelILOperation.LLIL_SET_REG: - return _search_phrase_op(il.src, target_op) - - if op == LowLevelILOperation.LLIL_STORE: - return _search_phrase_op(il.dest, target_op) - - # The phrase il may be inside a LLIL_LOAD - if op == LowLevelILOperation.LLIL_LOAD: - return _search_phrase_op(il.src, target_op) - - # Continue left/right at an ADD - if op == LowLevelILOperation.LLIL_ADD: - return (_search_phrase_op(il.left, target_op) or - _search_phrase_op(il.right, target_op)) - - # Continue left/right at an ADD - if op == LowLevelILOperation.LLIL_SUB: - return (_search_phrase_op(il.left, target_op) or - _search_phrase_op(il.right, target_op)) - - # Continue left/right at an ADD - if op == LowLevelILOperation.LLIL_CMP_E: - return (_search_phrase_op(il.left, target_op) or - _search_phrase_op(il.right, target_op)) - - # Terminate when constant is found - if op == target_op: - return il - - -def search_phrase_reg(il): - """ Searches for the register used in a phrase - ex: dword [ebp + 0x8] -> ebp - - Args: - il (binja.LowLevelILInstruction): Instruction to parse - - Returns: - str: register name - """ - res = _search_phrase_op(il, LowLevelILOperation.LLIL_REG) - if res is not None: - return res.src.name - - -def search_displ_base(il): - """ Searches for the base address used in a phrase[+displacement] - ex: dword [eax * 4 + 0x08040000] -> 0x08040000 - dword [ebp + 0x8] -> 0x8 - - Args: - il (binja.LowLevelILInstruction): Instruction to parse - - Returns: - int: base address - """ - res = _search_phrase_op(il, LowLevelILOperation.LLIL_CONST) - if res is not None: - # Interpret the string representation to avoid sign issues - return int(res.tokens[0].text, 16) - - -def is_jump_tail_call(bv, il): - """ Returns `True` if the given il is a jump to another function """ - return il.operation == LowLevelILOperation.LLIL_JUMP and \ - il.dest.operation == LowLevelILOperation.LLIL_CONST_PTR and \ - get_jump_tail_call_target(bv, il) is not None - - -def get_jump_tail_call_target(bv, il): - """ Get the target function of a tail-call. - - Returns: - binja.Function - """ - try: - return bv.get_function_at(il.dest.constant) - except: - return None - - -def collect_il_groups(il_func): - """ Gather all il instructions grouped by address - Some instructions (cmov, set, etc.) get expanded into multiple il - instructions when lifted, but `Function.get_lifted_il_at` will only return the first - of all the il instructions at an address. This will group all the il instructions - into a map of address to expanded instructions as follows: - - { - addr1 => [single il instruction], - addr2 => [expanded il 1, expanded il 2, ...], - ... - } - - Args: - il_func: IL function to gather all il groups from - - Returns: - dict: Map from address to all IL instructions at that address - - """ - il_map = defaultdict(list) - for blk in il_func: - for il in blk: - il_map[il.address].append(il) - return il_map diff --git a/tools/mcsema_disass/binja/vars.py b/tools/mcsema_disass/binja/vars.py deleted file mode 100644 index 2b38ff496..000000000 --- a/tools/mcsema_disass/binja/vars.py +++ /dev/null @@ -1,160 +0,0 @@ -# Copyright (c) 2017 Trail of Bits, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import binaryninja as binja -from binaryninja.enums import ( - SymbolType, TypeClass, InstructionTextTokenType, - LowLevelILOperation -) - -import logging -import util -from debug import * - -log = logging.getLogger(util.LOGNAME) - -SYM_IGNORE = [ - '__data_start', - '__dso_handle', - '__init_array_start', - '__init_array_end', - '__TMC_END__', - '__JCR_END__', - '__elf_header', - '_DYNAMIC' -] - - -def recover_globals(bv, pb_mod): - # Sort symbols by address so we can estimate size if needed - # TODO(krx): I'd prefer to find a better way to identify globals - # than going through and filtering all variable symbols in certain sections - syms = [] - for sym in bv.symbols.values(): - if isinstance(sym, list): - for dup_sym in sym: - syms.append(dup_sym) - else: - syms.append(sym) - - for i, sym in enumerate(syms): - if sym.name in SYM_IGNORE: - continue - - # Binja picks up a couple of symbols outside of named sections - sect = util.get_section_at(bv, sym.address) - if sect is None: - continue - - if sym.type == SymbolType.DataSymbol and \ - not util.is_executable(bv, sym.address) and \ - not util.is_section_external(bv, sect): - log.debug('Recovering global %s @ 0x%x', sym.name, sym.address) - pb_gvar = pb_mod.global_vars.add() - pb_gvar.ea = sym.address - pb_gvar.name = sym.name - - # Look at the variable type to determine size - data_var = bv.get_data_var_at(sym.address) - if data_var.type.type_class == TypeClass.VoidTypeClass: - # Estimate size based on the address of the next symbol - if sym is not syms[-1]: - pb_gvar.size = syms[i + 1].address - sym.address - else: - # Edge case for the last symbol - # Take end of the section as the "next symbol" instead - sec = util.get_section_at(bv, sym.address) - pb_gvar.size = sec.end - sym.address - else: - pb_gvar.size = data_var.type.width - - -def recover_stack_vars(pb_func, func, var_refs): - """ - Args: - pb_func (CFG_pb2.Function) - func (binaryninja.Function) - var_refs (dict): map of all var references in the form {var_name => [(addr, off), ...]} - """ - # Go through all variables on the stack (in order of storage) - stack_vars = sorted(func.stack_layout, key=lambda var: var.storage) - for i, svar in enumerate(stack_vars): - pb_svar = pb_func.stack_vars.add() - pb_svar.name = svar.name - pb_svar.sp_offset = svar.storage - - # Var types in binja don't account for arrays - # Estimate size based on the offset of the next variable - if svar is not stack_vars[-1]: - pb_svar.size = stack_vars[i + 1].storage - svar.storage - else: - # Edge case for the last variable, the offset is the size - pb_svar.size = svar.storage - - # Add all references to this variable - for addr, off in var_refs[svar.name]: - pb_svref = pb_svar.ref_eas.add() - pb_svref.inst_ea = addr - pb_svref.offset = off - svar.storage - - -def _sp_name(bv): - return bv.arch.stack_pointer - - -def _bp_name(bv): - # TODO(krx): this is currently specific to x86/amd64 - return 'rbp' if _sp_name(bv) == 'rsp' else 'ebp' - - -def _find_var_name(inst): - for tok in inst.tokens: - if tok.type == InstructionTextTokenType.LocalVariableToken: - return tok.text - return None - - -def _is_moving_sp(bv, il): - if il.operation == LowLevelILOperation.LLIL_SET_REG and \ - il.src.operation in [LowLevelILOperation.LLIL_ADD, LowLevelILOperation.LLIL_SUB]: - dst = il.dest.name - src = il.src.left.src.name - return dst == src == _sp_name(bv) - return False - - -def find_stack_var_refs(bv, inst, il, var_refs): - """ Attempts to find references to a stack variable in a given instruction - Args: - bv (binaryninja.BinaryView) - inst (binaryninja.DisassemblyTextLine) - il (binaryninja.LowLevelILInstruction) - var_refs (dict): map of currently known var references in the form {var_name => [(addr, off), ...]} - """ - # Ignore instructions where we just add/sub sp - if _is_moving_sp(bv, il): - return - - # Find a local var being referenced here - var_name = _find_var_name(inst) - if var_name is None: - return - - # Pull out info about the phrase in this instruction - reg = util.search_phrase_reg(il) - off = util.search_displ_base(il) or 0 - - # If this is accessing a local var, save the ref info - if reg in [_sp_name(bv), _bp_name(bv)]: - var_refs[var_name].append((il.address, off)) diff --git a/tools/mcsema_disass/binja/xrefs.py b/tools/mcsema_disass/binja/xrefs.py deleted file mode 100644 index 28d323c58..000000000 --- a/tools/mcsema_disass/binja/xrefs.py +++ /dev/null @@ -1,231 +0,0 @@ -# Copyright (c) 2017 Trail of Bits, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import binaryninja as binja -from binaryninja.enums import LowLevelILOperation -import logging - -import CFG_pb2 -import util -from debug import * - -log = logging.getLogger(util.LOGNAME) - - -class XRef(object): - IMMEDIATE = 0 - MEMORY = 1 - DISPLACEMENT = 2 - CONTROLFLOW = 3 - - TYPE_TO_CFG = { - IMMEDIATE : CFG_pb2.CodeReference.ImmediateOperand, - MEMORY : CFG_pb2.CodeReference.MemoryOperand, - DISPLACEMENT : CFG_pb2.CodeReference.MemoryDisplacementOperand, - CONTROLFLOW : CFG_pb2.CodeReference.ControlFlowOperand - } - - def __init__(self, addr, reftype, mask=0): - self.addr = addr - self.type = reftype - self.mask = mask - - @property - def cfg_type(self): - return self.TYPE_TO_CFG[self.type] - - def __repr__(self): - return ''.format(self.addr, CFG_pb2.CodeReference.OperandType.Name(self.cfg_type)) - - def __eq__(self, other): - if not isinstance(other, XRef): - return NotImplemented - return self.addr == other.addr and \ - self.type == other.type - - def __hash__(self): - return hash((self.addr, self.type)) - -_NO_XREFS = set() - -_IGNORED_XREF_OP_TYPES = (LowLevelILOperation.LLIL_JUMP, - LowLevelILOperation.LLIL_JUMP_TO, - LowLevelILOperation.LLIL_UNIMPL, - LowLevelILOperation.LLIL_UNIMPL_MEM) - - -_CONST_XREF_OP_TYPES = [LowLevelILOperation.LLIL_CONST_PTR] - -_LOAD_STORE_OP_TYPES = (LowLevelILOperation.LLIL_LOAD, - LowLevelILOperation.LLIL_STORE) - -_CONST_OR_CONST_PTR_TYPES = (binja.RegisterValueType.ConstantValue, - binja.RegisterValueType.ConstantPointerValue) - -_AARCH64_ADRP_XREFS = {} - -def _get_aarch64_partial_xref(bv, func, il, dis): - """" Figure out the final destination referenced by an ADRP+ADD instruction - combination on AArch64.""" - - if func.arch.name != 'aarch64': - return None - - if il.address in _AARCH64_ADRP_XREFS: - return _AARCH64_ADRP_XREFS[il.address] - - if not dis.startswith('adrp '): - return None - - next_address = il.address + bv.get_instruction_length(il.address) - next_dis = bv.get_disassembly(next_address) - if not next_dis.startswith('add '): - return None - - next_il = func.get_low_level_il_at(next_address) - value = next_il.get_reg_value_after(next_il.dest) - - if value.type not in _CONST_OR_CONST_PTR_TYPES: - return None - - _AARCH64_ADRP_XREFS[il.address] = XRef(value.value, XRef.DISPLACEMENT, mask=-4096L) - _AARCH64_ADRP_XREFS[next_address] = XRef(value.value, XRef.IMMEDIATE, mask=4095) - - return _AARCH64_ADRP_XREFS[il.address] - - -def get_xrefs(bv, func, il): - global _LAST_UNUSED_REFS - - refs = set() - dis = bv.get_disassembly(il.address) - - # TODO(pag): This is an ugly hack for the ADRP instruction on AArch64. - ref = _get_aarch64_partial_xref(bv, func, il, dis) - if ref is not None: - refs.add(ref) - else: - reftype = XRef.IMMEDIATE - - # PC-relative displacement for AArch64's `adr` instruction. - if func.arch.name == 'aarch64' and dis.startswith('adr '): - reftype = XRef.DISPLACEMENT - - _fill_xrefs_internal(bv, il, refs, reftype) - - # TODO(pag): Another ugly hack to deal with a specific flavor of jump - # table that McSema doesn't handle very well. The specific form - # is: - # - # .text:00000000004009AC ADRP X1, #asc_400E5C@PAGE ; "\b" - # .text:00000000004009B0 ADD X1, X1, #asc_400E5C@PAGEOFF ; "\b" - # .text:00000000004009B4 LDR W0, [X1,W0,UXTW#2] - # .text:00000000004009B8 ADR X1, loc_4009C4 <-- point to a block - # .text:00000000004009BC ADD X0, X1, W0,SXTW#2 - # .text:00000000004009C0 BR X0 - # - # We don't have good ways of referencing basic blocks, so if we - # left the reference from `4009B8` to `4009C4`, then that would - # be computed in terms of the location in memory of the copied - # `.text` segment in the lifted binary. - # - # We could handle this via a jump-offset table with offset of - # `4009B8`, but we don't yet support this variant of jump table - # in jmptable.py. - if dis.startswith('adr ') and len(refs): - ref = refs.pop() - if util.is_code(bv, ref.addr) and not bv.get_function_at(ref.addr): - DEBUG("WARNING: Omitting reference to non-function code address {:x}".format(ref.addr)) - else: - refs.add(ref) # Add it back in. - - return refs - - -def _fill_xrefs_internal(bv, il, refs, reftype=XRef.IMMEDIATE, parent=None): - """ Recursively gather xrefs in an IL instruction - - Args: - bv (binja.BinaryView) - il (binja.LowLevelILInstruction) - reftype (int) - parent (binja.LowLevelILInstruction) - - Returns: - set[XRef] - """ - global _NO_XREFS, _IGNORED_XREF_OP_TYPES, _CONST_XREF_OF_TYPES - global _LOAD_STORE_OP_TYPES - - if not isinstance(il, binja.LowLevelILInstruction): - return _NO_XREFS - - # Update reftype using il information - op = il.operation - - # Detect a tail call target - # This is the only instance where a LLIL_JUMP is considered - if util.is_jump_tail_call(bv, il): - target = util.get_jump_tail_call_target(bv, il) - DEBUG('Tail call from {:x} to {:x}'.format(il.address, target.start)) - return _fill_xrefs_internal(bv, il.dest, refs, XRef.CONTROLFLOW, il) - - # Some instruction types are ignored - if op in _IGNORED_XREF_OP_TYPES: - return _NO_XREFS - - elif op == LowLevelILOperation.LLIL_CALL: - # Any xref in here will be a control flow target - reftype = XRef.CONTROLFLOW - - elif op in _LOAD_STORE_OP_TYPES: - - # Choose the correct operand to look at - mem_il = il.src if op == LowLevelILOperation.LLIL_LOAD else il.dest - - # Loading from memory - # Check if we're using a displacement in this - if mem_il.operation in _CONST_XREF_OP_TYPES: - # No displacement - reftype = XRef.MEMORY - else: - reftype = XRef.DISPLACEMENT - - # In a load/store, only the operand that references memory gets the new reftype - # The other operand(s) start at the default (immediate) again - _fill_xrefs_internal(bv, mem_il, refs, reftype, il) - for oper in il.operands: - if oper != mem_il: - _fill_xrefs_internal(bv, oper, refs) - - elif op in _CONST_XREF_OP_TYPES: - # Hit a value, if this is a reference we can save the xref - if util.is_valid_addr(bv, il.constant): - # A displacement might be incorrectly classified as an immediate at this point - if reftype == XRef.IMMEDIATE and parent is not None: - # There's some other expression including this value - # look at the disassembly to figure out if this is actually a displacement - dis = bv.get_disassembly(il.address) - if '[' in dis and ']' in dis: - # Fix the reftype depending on how this value is used - if parent.operation == LowLevelILOperation.LLIL_SET_REG: - reftype = XRef.MEMORY - else: - reftype = XRef.DISPLACEMENT - - refs.add(XRef(il.constant, reftype)) - - # Continue searching operands for xrefs - for oper in il.operands: - _fill_xrefs_internal(bv, oper, refs, reftype, il) diff --git a/tools/mcsema_disass/defs/linux.txt b/tools/mcsema_disass/defs/linux.txt index e26c9c681..e0b1e0bd2 100644 --- a/tools/mcsema_disass/defs/linux.txt +++ b/tools/mcsema_disass/defs/linux.txt @@ -36,6 +36,7 @@ DATA: _end PTR __assert_fail 4 C Y +__assert_c99 3 C Y __cxa_atexit 5 C N __cxa_guard_acquire 5 C N __cxa_guard_release 5 C N @@ -1569,7 +1570,7 @@ ass_add_font 4 C N ass_alloc_event 1 C N ass_alloc_style 1 C N ass_clear_fonts 1 C N -__assert 3 C N +__assert 3 C Y __assert_perror_fail 4 C Y ass_flush_events 1 C N ass_fonts_update 1 C N @@ -2382,7 +2383,6 @@ bfd_set_section_size 3 C N bfd_set_start_address 2 C N bfd_set_symtab 3 C N bfd_simple_get_relocated_section_contents 4 C N -bfd_sparclinux_size_dynamic_sections 2 C N bfd_sprintf_vma 3 C N bfd_stat 2 C N bfd_sunos_get_needed_list 2 C N @@ -20190,7 +20190,6 @@ print_insn_s390 2 C N print_insn_sh 2 C N print_insn_sh64 2 C N print_insn_sh64x_media 2 C N -print_insn_sparc 2 C N print_insn_spu 2 C N print_insn_tic30 2 C N print_insn_tic4x 2 C N diff --git a/tools/mcsema_disass/dyninst/CFGWriter.cpp b/tools/mcsema_disass/dyninst/CFGWriter.cpp index ba1dbc412..cfab2f8c7 100644 --- a/tools/mcsema_disass/dyninst/CFGWriter.cpp +++ b/tools/mcsema_disass/dyninst/CFGWriter.cpp @@ -1,17 +1,18 @@ /* - * Copyright (c) 2018 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ #include "CFGWriter.h" @@ -190,8 +191,8 @@ void ResolveOffsetTable(const std::set &successors, auto cfg_inst = cfg_block->mutable_instructions( cfg_block->instructions_size() - 1); if (!cfg_inst->xrefs_size()) { - AddCodeXref(cfg_inst, CodeReference::DataTarget, CodeReference::OffsetTable, - CodeReference::Internal, table_ea.value()); + AddCodeXref(cfg_inst, CodeReference::OffsetTable, + table_ea.value()); } } @@ -282,8 +283,6 @@ CFGWriter::CFGWriter(mcsema::Module &m, } } - GetNoReturns(); - // Calculate where can magic section start without // potentialy overwriting part of the binary //TODO(lukas): Move out @@ -359,50 +358,9 @@ void CFGWriter::Write() { } } - WriteLocalVariables(); module.set_name(FLAGS_binary); } -// TODO(lukas): Need to get all xrefs for local variable -void CFGWriter::WriteLocalVariables() { - // We need to get SymtabAPI version of functions - std::vector funcs; - symtab.getAllFunctions(funcs); - for (auto func : funcs) { - auto cfg_func = ctx.func_map.find(func->getOffset()); - if (cfg_func == ctx.func_map.end()) { - continue; - } - - std::vector locals; - func->getLocalVariables(locals); - - // getParams resets the vector passed to it - std::vector params; - func->getParams(params); - for (auto a : params) { - locals.push_back(a); - } - - for (auto local : locals) { - auto cfg_var = cfg_func->second->add_stack_vars(); - cfg_var->set_name(local->getName()); - cfg_var->set_size(local->getType()->getSize()); - auto location_list = local->getLocationLists(); - - LOG(INFO) - << std::hex << "Found local variable with name " << local->getName() - << " with size: " << local->getType()->getSize(); - - for (auto &location : location_list) { - cfg_var->set_sp_offset(location.frameOffset); - LOG(INFO) << std::hex << "\tat sp_offset: 0x" << location.frameOffset; - } - - } - } -} - void CFGWriter::WriteExternalVariables() { std::vector symbols; symbols = section_m.GetExternalRelocs( @@ -682,7 +640,6 @@ void CFGWriter::WriteInstruction(InstructionAPI::Instruction *instruction, instBytes += (int)instruction->rawByte(offset); } - cfg_instruction->set_bytes(instBytes); cfg_instruction->set_ea(addr); std::vector operands; @@ -779,18 +736,6 @@ void CFGWriter::CheckDisplacement(Dyninst::InstructionAPI::Expression *expr, } } -void CFGWriter::GetNoReturns() { - for (auto f : code_object.funcs()) { - if (f->retstatus() == ParseAPI::NORETURN) { - no_ret_funcs.insert(f->name()); - } - } -} - -bool CFGWriter::IsNoReturn(const std::string &name) { - return no_ret_funcs.find(name) != no_ret_funcs.end(); -} - //TODO(lukas): This is hacky void CFGWriter::HandleCallInstruction(InstructionAPI::Instruction *instruction, @@ -826,9 +771,6 @@ void CFGWriter::HandleCallInstruction(InstructionAPI::Instruction *instruction, } } - if (IsNoReturn(cfg_instruction->mutable_xrefs(0)->name())) { - cfg_instruction->set_local_noreturn(true); - } } Address CFGWriter::immediateNonCall(InstructionAPI::Immediate* imm, @@ -839,9 +781,7 @@ Address CFGWriter::immediateNonCall(InstructionAPI::Immediate* imm, if (!ctx.HandleCodeXref({addr, a, cfg_instruction}, section_m, false)) { if (section_m.IsCode(a)) { AddCodeXref(cfg_instruction, - CodeReference::DataTarget, CodeReference::ImmediateOperand, - CodeReference::Internal, a); LOG(INFO) << std::hex @@ -951,7 +891,6 @@ void CFGWriter::HandleNonCallInstruction( // in CrossXref if (ctx.HandleCodeXref({0, *a, cfg_instruction}, section_m)) { auto cfg_xref = GetLastXref(cfg_instruction); - cfg_xref->set_target_type(CodeReference::CodeTarget); cfg_xref->set_operand_type(CodeReference::ControlFlowOperand); } direct_values[i] = *a; diff --git a/tools/mcsema_disass/dyninst/CFGWriter.h b/tools/mcsema_disass/dyninst/CFGWriter.h index 4b03cad4e..39272d7b6 100644 --- a/tools/mcsema_disass/dyninst/CFGWriter.h +++ b/tools/mcsema_disass/dyninst/CFGWriter.h @@ -1,17 +1,18 @@ /* - * Copyright (c) 2018 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ #pragma once @@ -55,7 +56,6 @@ private: void WriteGlobalVariables(); void SweepStubs(); void WriteInternalFunctions(); - void WriteLocalVariables(); void WriteFunctionBlocks(Dyninst::ParseAPI::Function *func, mcsema::Function *cfg_internal_func); @@ -97,9 +97,6 @@ private: bool HandleXref(mcsema::Instruction *, Dyninst::Address, bool force=true); - bool IsNoReturn(const std::string& str); - void GetNoReturns(); - void CheckDisplacement(Dyninst::InstructionAPI::Expression *, mcsema::Instruction *); bool IsExternal(Dyninst::Address addr) const; @@ -113,8 +110,6 @@ private: ExternalFunctionManager ext_funcs_m; SectionManager section_m; - std::unordered_set no_ret_funcs; - std::map> code_xrefs_to_resolve; std::map> inst_xrefs_to_resolve; diff --git a/tools/mcsema_disass/dyninst/CMakeLists.txt b/tools/mcsema_disass/dyninst/CMakeLists.txt index 3506f2428..e3e39be66 100644 --- a/tools/mcsema_disass/dyninst/CMakeLists.txt +++ b/tools/mcsema_disass/dyninst/CMakeLists.txt @@ -1,16 +1,17 @@ -# Copyright (c) 2018 Trail of Bits, Inc. +# Copyright (c) 2020 Trail of Bits, Inc. # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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 Affero General Public License for more details. # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . if (NOT UNIX) message (ERROR "The Dyninst frontend currently does not support this OS") diff --git a/tools/mcsema_disass/dyninst/ExternalFunctionManager.cpp b/tools/mcsema_disass/dyninst/ExternalFunctionManager.cpp index efca53639..4e6fcfac6 100644 --- a/tools/mcsema_disass/dyninst/ExternalFunctionManager.cpp +++ b/tools/mcsema_disass/dyninst/ExternalFunctionManager.cpp @@ -1,17 +1,18 @@ /* - * Copyright (c) 2018 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ #include "ExternalFunctionManager.h" diff --git a/tools/mcsema_disass/dyninst/ExternalFunctionManager.h b/tools/mcsema_disass/dyninst/ExternalFunctionManager.h index 0635a290f..ee62862d7 100644 --- a/tools/mcsema_disass/dyninst/ExternalFunctionManager.h +++ b/tools/mcsema_disass/dyninst/ExternalFunctionManager.h @@ -1,17 +1,18 @@ /* - * Copyright (c) 2018 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ #pragma once diff --git a/tools/mcsema_disass/dyninst/MagicSection.cpp b/tools/mcsema_disass/dyninst/MagicSection.cpp index 58fabd58d..1b4dc2223 100644 --- a/tools/mcsema_disass/dyninst/MagicSection.cpp +++ b/tools/mcsema_disass/dyninst/MagicSection.cpp @@ -1,17 +1,18 @@ /* - * Copyright (c) 2018 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ #include "MagicSection.h" diff --git a/tools/mcsema_disass/dyninst/MagicSection.h b/tools/mcsema_disass/dyninst/MagicSection.h index 098021bbf..7e24764a8 100644 --- a/tools/mcsema_disass/dyninst/MagicSection.h +++ b/tools/mcsema_disass/dyninst/MagicSection.h @@ -1,17 +1,18 @@ /* - * Copyright (c) 2018 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ #pragma once diff --git a/tools/mcsema_disass/dyninst/Maybe.h b/tools/mcsema_disass/dyninst/Maybe.h index 1f428b711..94985633b 100644 --- a/tools/mcsema_disass/dyninst/Maybe.h +++ b/tools/mcsema_disass/dyninst/Maybe.h @@ -1,17 +1,18 @@ /* - * Copyright (c) 2019 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ #pragma once diff --git a/tools/mcsema_disass/dyninst/OffsetTable.cpp b/tools/mcsema_disass/dyninst/OffsetTable.cpp index e92247564..107bcb9c3 100644 --- a/tools/mcsema_disass/dyninst/OffsetTable.cpp +++ b/tools/mcsema_disass/dyninst/OffsetTable.cpp @@ -1,17 +1,18 @@ /* - * Copyright (c) 2018 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ #include diff --git a/tools/mcsema_disass/dyninst/OffsetTable.h b/tools/mcsema_disass/dyninst/OffsetTable.h index af728def7..08d638272 100644 --- a/tools/mcsema_disass/dyninst/OffsetTable.h +++ b/tools/mcsema_disass/dyninst/OffsetTable.h @@ -1,17 +1,18 @@ /* - * Copyright (c) 2018 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ #pragma once diff --git a/tools/mcsema_disass/dyninst/SectionManager.cpp b/tools/mcsema_disass/dyninst/SectionManager.cpp index c188bec42..5e7a564e8 100644 --- a/tools/mcsema_disass/dyninst/SectionManager.cpp +++ b/tools/mcsema_disass/dyninst/SectionManager.cpp @@ -1,17 +1,18 @@ /* - * Copyright (c) 2018 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ #include "SectionManager.h" diff --git a/tools/mcsema_disass/dyninst/SectionManager.h b/tools/mcsema_disass/dyninst/SectionManager.h index f947aa165..588e0c22a 100644 --- a/tools/mcsema_disass/dyninst/SectionManager.h +++ b/tools/mcsema_disass/dyninst/SectionManager.h @@ -1,17 +1,18 @@ /* - * Copyright (c) 2018 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ #pragma once diff --git a/tools/mcsema_disass/dyninst/SectionParser.cpp b/tools/mcsema_disass/dyninst/SectionParser.cpp index e6db81655..d9d561590 100644 --- a/tools/mcsema_disass/dyninst/SectionParser.cpp +++ b/tools/mcsema_disass/dyninst/SectionParser.cpp @@ -1,17 +1,18 @@ /* - * Copyright (c) 2018 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ #include "SectionParser.h" diff --git a/tools/mcsema_disass/dyninst/SectionParser.h b/tools/mcsema_disass/dyninst/SectionParser.h index faebf4690..4340eb9df 100644 --- a/tools/mcsema_disass/dyninst/SectionParser.h +++ b/tools/mcsema_disass/dyninst/SectionParser.h @@ -1,17 +1,18 @@ /* - * Copyright (c) 2018 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ #pragma once diff --git a/tools/mcsema_disass/dyninst/Util.cpp b/tools/mcsema_disass/dyninst/Util.cpp index 726722d01..d0f8ed1c4 100644 --- a/tools/mcsema_disass/dyninst/Util.cpp +++ b/tools/mcsema_disass/dyninst/Util.cpp @@ -1,34 +1,28 @@ /* - * Copyright (c) 2018 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ #include "Util.h" mcsema::CodeReference *AddCodeXref(mcsema::Instruction * instruction, - mcsema::CodeReference::TargetType tarTy, mcsema::CodeReference_OperandType opTy, - mcsema::CodeReference_Location location, - Dyninst::Address addr, - const std::string &name) { + Dyninst::Address addr) { auto xref = instruction->add_xrefs(); - xref->set_target_type(tarTy); xref->set_operand_type(opTy); - xref->set_location(location); xref->set_ea(addr); - if (!name.empty()) - xref->set_name(name); return xref; } diff --git a/tools/mcsema_disass/dyninst/Util.h b/tools/mcsema_disass/dyninst/Util.h index ff8614343..6a7d59eb0 100644 --- a/tools/mcsema_disass/dyninst/Util.h +++ b/tools/mcsema_disass/dyninst/Util.h @@ -1,17 +1,18 @@ /* - * Copyright (c) 2018 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ #pragma once @@ -39,11 +40,8 @@ auto *GetLastXref(T *cfg) { mcsema::CodeReference *AddCodeXref( mcsema::Instruction * instruction, - mcsema::CodeReference::TargetType tarTy, mcsema::CodeReference_OperandType opTy, - mcsema::CodeReference_Location location, - Dyninst::Address addr, - const std::string &name=""); + Dyninst::Address addr); template struct CrossXref { @@ -61,15 +59,12 @@ struct CrossXref { } mcsema::DataReference *WriteDataXref( - bool is_code=false, uint64_t width=8) const { LOG(INFO) << "\tFound xref targeting " << std::hex << target_ea; auto cfg_xref = segment->add_xrefs(); cfg_xref->set_ea(ea); cfg_xref->set_width(width); cfg_xref->set_target_ea(target_ea); - cfg_xref->set_target_name(target_name); - cfg_xref->set_target_is_code(is_code); // TODO(lukas): This will almost certainly cause problems once cfg_xref->set_target_fixup_kind(mcsema::DataReference::Absolute); return cfg_xref; @@ -102,7 +97,7 @@ struct DisassContext { bool is_code=false, uint64_t width=8) { width = std::min(width, 8ul); - auto cfg_xref = xref.WriteDataXref(is_code, width); + auto cfg_xref = xref.WriteDataXref(width); data_xrefs.insert({xref.ea, cfg_xref}); return cfg_xref; } @@ -142,22 +137,16 @@ struct DisassContext { bool WriteFact(const CrossXref &xref, mcsema::Function *fact) { AddCodeXref(xref.segment, - mcsema::CodeReference::DataTarget, mcsema::CodeReference::ControlFlowOperand, - mcsema::CodeReference::Internal, - fact->ea(), - fact->name()); + fact->ea()); return true; } bool WriteFact(const CrossXref &xref, mcsema::GlobalVariable *fact) { AddCodeXref(xref.segment, - mcsema::CodeReference::DataTarget, mcsema::CodeReference::MemoryOperand, - mcsema::CodeReference::Internal, - fact->ea(), - fact->name()); + fact->ea()); return true; } @@ -165,22 +154,16 @@ struct DisassContext { mcsema::ExternalFunction *fact) { // Mapping to magic_section AddCodeXref(xref.segment, - mcsema::CodeReference::DataTarget, mcsema::CodeReference::ControlFlowOperand, - mcsema::CodeReference::External, - magic_section.GetAllocated(xref.target_ea), - fact->name()); + magic_section.GetAllocated(xref.target_ea)); return true; } bool WriteFact(const CrossXref &xref, mcsema::Variable *fact) { AddCodeXref(xref.segment, - mcsema::CodeReference::DataTarget, mcsema::CodeReference::MemoryOperand, - mcsema::CodeReference::Internal, - fact->ea(), - fact->name()); + fact->ea()); return true; } @@ -191,11 +174,8 @@ struct DisassContext { addr = fact->ea(); } AddCodeXref(xref.segment, - mcsema::CodeReference::DataTarget, mcsema::CodeReference::MemoryOperand, - mcsema::CodeReference::External, - addr, - fact->name()); + addr); return true; } @@ -203,9 +183,7 @@ struct DisassContext { bool WriteFact(const CrossXref &xref, mcsema::DataReference *fact) { AddCodeXref(xref.segment, - mcsema::CodeReference::DataTarget, mcsema::CodeReference::MemoryOperand, - mcsema::CodeReference::Internal, fact->ea()); return true; } @@ -244,9 +222,7 @@ struct DisassContext { if (section_m.IsInRegions({".data", ".rodata", ".bss"}, xref.target_ea)) { AddCodeXref(xref.segment, - mcsema::CodeReference::DataTarget, mcsema::CodeReference::MemoryOperand, - mcsema::CodeReference::Internal, xref.target_ea); return true; } @@ -255,9 +231,7 @@ struct DisassContext { for (auto a : segment_eas) { if (a == xref.target_ea) { AddCodeXref(xref.segment, - mcsema::CodeReference::DataTarget, mcsema::CodeReference::MemoryOperand, - mcsema::CodeReference::Internal, xref.target_ea); return true; } @@ -267,9 +241,7 @@ struct DisassContext { LOG(INFO) << "Could not regonize xref anywhere target_ea 0x" << std::hex << xref.target_ea << " forcing it"; AddCodeXref(xref.segment, - mcsema::CodeReference::DataTarget, mcsema::CodeReference::MemoryOperand, - mcsema::CodeReference::Internal, xref.target_ea); return true; } diff --git a/tools/mcsema_disass/dyninst/main.cpp b/tools/mcsema_disass/dyninst/main.cpp index 2ea035e93..a17a381f7 100644 --- a/tools/mcsema_disass/dyninst/main.cpp +++ b/tools/mcsema_disass/dyninst/main.cpp @@ -1,17 +1,18 @@ /* - * Copyright (c) 2018 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ #include "CFGWriter.h" @@ -41,8 +42,6 @@ DEFINE_string(output, "", "Path to output file"); DEFINE_string(binary, "", "Path to binary to be disassembled"); DEFINE_string(entrypoint, "main", "Name of entrypoint function"); DEFINE_bool(pie_mode, false, "Need to be true for pie binaries"); -DEFINE_string(arch, "", "NOT IMPLEMENTED YET"); -DEFINE_string(os, "", "NOT IMPLEMENTED YET"); using namespace Dyninst; diff --git a/tools/mcsema_disass/ida/__init__.py b/tools/mcsema_disass/ida/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tools/mcsema_disass/ida/arm_util.py b/tools/mcsema_disass/ida/arm_util.py deleted file mode 100644 index 15413d0d8..000000000 --- a/tools/mcsema_disass/ida/arm_util.py +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright (c) 2017 Trail of Bits, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import collections -import idaapi -import idautils -import idc - -# Maps instruction EAs to a pair of decoded inst, and the bytes of the inst. -PREFIX_ITYPES = tuple() - -PERSONALITY_NORMAL = 0 -PERSONALITY_DIRECT_JUMP = 1 -PERSONALITY_INDIRECT_JUMP = 2 -PERSONALITY_DIRECT_CALL = 3 -PERSONALITY_INDIRECT_CALL = 4 -PERSONALITY_RETURN = 5 -PERSONALITY_SYSTEM_CALL = 6 -PERSONALITY_SYSTEM_RETURN = 7 -PERSONALITY_CONDITIONAL_BRANCH = 8 -PERSONALITY_TERMINATOR = 9 - -PERSONALITIES = collections.defaultdict(int) -PERSONALITIES.update({ - idaapi.ARM_bl: PERSONALITY_DIRECT_CALL, - idaapi.ARM_blr: PERSONALITY_INDIRECT_CALL, - - idaapi.ARM_ret: PERSONALITY_RETURN, - - idaapi.ARM_b: PERSONALITY_DIRECT_JUMP, - idaapi.ARM_br: PERSONALITY_INDIRECT_JUMP, - - idaapi.ARM_svc: PERSONALITY_SYSTEM_CALL, - idaapi.ARM_hvc: PERSONALITY_SYSTEM_CALL, - idaapi.ARM_smc: PERSONALITY_SYSTEM_CALL, - - idaapi.ARM_hlt: PERSONALITY_TERMINATOR, - - idaapi.ARM_cbnz: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.ARM_cbz: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.ARM_tbnz: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.ARM_tbz: PERSONALITY_CONDITIONAL_BRANCH, -}) - -def fixup_personality(inst, p): - """For things like b.le, IDA will give us the `ARM_b` opcode, and we need - to figure out if it's actually conditional. This is stored in the `segpref` - field, and `0xe` is the unconditional version.""" - if inst.itype == idaapi.ARM_b: - if 0 <= inst.segpref <= 0xf and inst.segpref != 0xe: - return PERSONALITY_CONDITIONAL_BRANCH - return p diff --git a/tools/mcsema_disass/ida/binja_var_recovery/__init__.py b/tools/mcsema_disass/ida/binja_var_recovery/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tools/mcsema_disass/ida/binja_var_recovery/il_analysis.py b/tools/mcsema_disass/ida/binja_var_recovery/il_analysis.py deleted file mode 100644 index d4ee04463..000000000 --- a/tools/mcsema_disass/ida/binja_var_recovery/il_analysis.py +++ /dev/null @@ -1,477 +0,0 @@ -# Copyright (c) 2018 Trail of Bits, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import re -import io -import collections -import struct -from binaryninja import * -from binja_var_recovery.util import * - -LOPS = LowLevelILOperation -MOPS = MediumLevelILOperation - -VariableSet = set() - -class Value(object): - def __init__(self, bv, addr, base = None): - self.bv = bv - self.address = addr - self._has_xrefs = has_xrefs(bv, addr) - self._base = base if base else addr - - @property - def base_address(self): - return self._base - - @property - def size(self): - if self.address > self._base: - return self.address - self._base - else: - return self._base - self.address - - def __str__(self): - return "<{:x} - {:x}>".format(self.address, self._base) - - def __repr__(self): - return "<{:x} - {:x}>".format(self.address, self._base) - - def __sub__(self, other): - if self._has_xrefs: - return Value(self.bv, self.address - other.address, self._base) - else: - return Value(self.bv, self.address - other.address, other._base) - - def __add__(self, other): - if self._has_xrefs: - return Value(self.bv, self.address + other.address, self._base) - else: - return Value(self.bv, self.address + other.address, other._base) - - def __lshift__(self, other): - if isinstance(other, Value): - return Value(self.bv, self.address << other.address, self._base) - else: - return self - - def __rshift__(self, other): - if isinstance(other, Value): - return Value(self.bv, self.address >> other.address, self._base) - else: - return self - - def __hash__(self): - return hash(self.__repr__()) - - def __eq__(self, other): - if isinstance(self, Value): - return (self.__repr__() == other.__repr__()) - else: - return False - - def __ne__(self, other): - return not self.__eq__(self) - -class SymbolicValue(Value): - def __init__(self, bv, sym_value, offset=0): - super(SymbolicValue, self).__init__(bv, 0) - self.sym_value = sym_value - self.offset = offset - - @property - def base_address(self): - return 0 - - @property - def size(self): - return 0 - - def __str__(self): - return "<{}, {}>".format(self.sym_value, self.offset) - - def __repr__(self): - return "<{} {}>".format(self.sym_value, self.offset) - - def __add__(self, other): - if isinstance(other, Value): - return SymbolicValue(self.bv, self.sym_value, self.offset + other.address) - else: - return SymbolicValue(self.bv, self.sym_value + " + " + other.sym_value, other.offset) - - def __sub__(self, other): - if isinstance(other, Value): - return SymbolicValue(self.bv, self.sym_value, self.offset - other.address) - else: - return SymbolicValue(self.bv, self.sym_value + " - " + other.sym_value, other.offset) - - def __lshift__(self, other): - if isinstance(other, Value): - return SymbolicValue(self.bv, self.sym_value + " << " + "{}".format(hex(other.address)), self.offset) - else: - return self - - def __rshift__(self, other): - if isinstance(other, Value): - return SymbolicValue(self.bv, self.sym_value + " >> " + "{}".format(hex(other.address)), self.offset) - else: - return self - - def __hash__(self): - return hash(self.__repr__()) - - def __eq__(self, other): - if isinstance(self, SymbolicValue): - return (self.__repr__() == other.__repr__()) - else: - return False - - def __ne__(self, other): - return not self.__eq__(self) - -def is_subset(s1, s2): - for item in s2: - if item not in s1: - return False - return True - -def is_long(bv, addr): - return isinstance(addr, long) - -def is_values(bv, obj): - return isinstance(obj, Values) - -def is_sym_values(bv, obj): - return isinstance(obj, SymbolicValue) - -def is_mlil(bv, insn): - return isinstance(insn, MediumLevelILInstruction) - -def is_llil(bv, insn): - return isinstance(insn, LowLevelILInstruction) - -def is_reg_ssa(bv, reg): - return isinstance(reg, SSARegister) - -def is_call(bv, insn): - if is_llil(bv, insn): - return insn.operation == LOPS.LLIL_CALL or \ - insn.operation == LOPS.LLIL_CALL_STACK_ADJUST or \ - insn.operation == LOPS.LLIL_CALL_SSA - return False - -def is_load(bv, insn): - return insn.operation == LOPS.LLIL_LOAD_SSA or \ - insn.operation == LOPS.LLIL_LOAD - -def is_store(bv, insn): - return insn.operation == LOPS.LLIL_STORE_SSA or \ - insn.operation == LOPS.LLIL_STORE - -def is_constant(bv, insn): - """ Check if the operand is constant""" - if is_mlil(bv, insn): - return insn.operation == MOPS.MLIL_CONST or \ - insn.operation == MOPS.MLIL_CONST_PTR - elif is_llil(bv, insn): - return insn.operation == LOPS.LLIL_CONST or \ - insn.operation == LOPS.LLIL_CONST_PTR - -def ssa_reg_name(ssa_reg): - return "{}#{}".format(ssa_reg.reg, ssa_reg.version) - -def global_reg_name(func, ssa_reg): - return "{}_{}".format(func.name, ssa_reg_name(ssa_reg)) - -def get_constant(bv, insn): - """ Get the constant value of the operand """ - return insn.constant - -def is_register(bv, insn): - if is_mlil(bv, insn): - return insn.operation == MOPS.MLIL_REG or \ - insn.operation == MOPS.MLIL_REG_SSA - elif is_llil(bv, insn): - return insn.operation == LOPS.LLIL_REG or \ - insn.operation == LOPS.LLIL_REG_SSA - -def is_address(bv, insn): - if insn.operation == LowLevelILOperation.LLIL_SET_REG or \ - insn.operation == LowLevelILOperation.LLIL_SET_REG_SSA: - return is_constant(bv, insn.src) - return False - -def call_target(bv, insn): - if is_llil(bv, insn) and is_constant(bv, insn.dest): - return insn.dest.constant - else: - return None - -def call_params(bv, insn): - if is_llil(bv, insn): - for op in insn.operands: - if op.operation == LOPS.LLIL_CALL_PARAM: - return op.src - return None - -def get_call_params(bv, insn): - for pparam in call_params(bv, insn): - yield pparam - -def get_call_output(bv, insn): - if is_llil(bv, insn): - for op in insn.operands: - if op.operation == LOPS.LLIL_CALL_OUTPUT_SSA: - for reg in op.dest: - yield reg - -def is_stack_op(bv, expr): - for opnd in expr.operands: - if isinstance(opnd, SSARegister): - if repr(opnd.reg) in ["rsp", "rbp"]: - return True - - if is_llil(bv, opnd) and is_register(bv, opnd): - reg_name = repr(opnd.src.reg) - if reg_name in ["rsp", "rbp"]: - return True - return False - -def is_arith_op(bv, insn): - postfix = insn.postfix_operands - DEBUG("insn {} ->postfix {}".format(insn, postfix)) - -def get_exec_sections(bv): - for k in bv.sections: - v = bv.sections[k] - if bv.is_offset_executable(v.start): - yield v - -def dw(bv, addr, end): - if end - addr < 4: - return None - return struct.unpack(' 0: - return insn.ssa_memory_version - elif "mem#0" in str(insn): - return 0 - elif is_llil(bv, insn): - if "mem#" in str(insn): - return 1 - -def get_address(bv, insn): - for token in insn.tokens: - if token.type == InstructionTextTokenType.PossibleAddressToken: - return token.value - -def has_memory_xrefs(bv, addr): - if addr in VariableSet: - return True - - if not is_data_variable_section(bv, addr): - return False - - # if there is any reference to data section return false - # Not handling such cases - for ref in bv.get_data_refs(addr): - return False - - dv_refs = list() - dv_func_set = set() - dv = bv.get_data_var_at(addr) - prev_dv = bv.get_previous_data_var_before(addr) - - for ref in bv.get_code_refs(addr): - dv_func_set.add(ref.function.start) - llil = ref.function.get_low_level_il_at(ref.address) - if llil: - DEBUG("VariableAnalysis: {:x} - {:x} {}".format(addr, ref.address, llil.ssa_form)) - dv_refs.append(llil.ssa_form) - - for ins in dv_refs: - if get_memory_version(bv, ins) is None: - return False - - if is_call(bv, ins): - return False - - if get_address(bv, ins) != addr: - return False - - prev_dv_refs = list() - prev_dv_func_set = set() - if prev_dv != None: - for ref in bv.get_code_refs(prev_dv): - prev_dv_func_set.add(ref.function.start) - llil = ref.function.get_low_level_il_at(ref.address) - prev_dv_refs.append(llil) - - for ins in prev_dv_refs: - if ins and (is_call(bv, ins) or is_address(bv, ins)): - return False - - if is_subset(prev_dv_func_set, dv_func_set): - return False - - VariableSet.add(addr) - return True - -def has_address_xrefs(bv, insn, addr): - if addr in VariableSet: - return True - - if not is_data_variable_section(bv, addr): - return False - - # if there is any reference to data section return True - # Assuming this will be the start address of the synbol - for ref in bv.get_data_refs(addr): - VariableSet.add(addr) - return True - - dv_refs = list() - dv_func_set = set() - dv = bv.get_data_var_at(addr) - prev_dv = bv.get_previous_data_var_before(addr) - - for ref in bv.get_code_refs(addr): - dv_func_set.add(ref.function.start) - llil = ref.function.get_low_level_il_at(ref.address) - if llil: - DEBUG("AddressAnalysis: {:x} - {:x} {}".format(addr, ref.address, llil.ssa_form)) - dv_refs.append(llil.ssa_form) - - prev_dv_refs = list() - prev_dv_func_set = set() - if prev_dv != None: - for ref in bv.get_code_refs(prev_dv): - prev_dv_func_set.add(ref.function.start) - llil = ref.function.get_low_level_il_at(ref.address) - prev_dv_refs.append(llil) - - if is_subset(prev_dv_func_set, dv_func_set): - return False - - for ins in dv_refs: - if is_address(bv, ins) and \ - get_address(bv, ins) == addr: - VariableSet.add(addr) - return True - - return False \ No newline at end of file diff --git a/tools/mcsema_disass/ida/binja_var_recovery/il_function.py b/tools/mcsema_disass/ida/binja_var_recovery/il_function.py deleted file mode 100644 index fb00522e9..000000000 --- a/tools/mcsema_disass/ida/binja_var_recovery/il_function.py +++ /dev/null @@ -1,257 +0,0 @@ -# Copyright (c) 2018 Trail of Bits, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import pprint -import collections -from Queue import Queue -from binaryninja import * -from binja_var_recovery.util import * -from binja_var_recovery.il_variable import * -from binja_var_recovery.il_instructions import * - -RECOVERED = set() -TO_RECOVER = Queue() - -def queue_func(addr): - if addr not in RECOVERED: - TO_RECOVER.put(addr) - return True - else: - return False - -class Function(object): - """ The function objects - """ - def __init__(self, bv, func): - self.bv = bv - self.func = func - self.start_addr = func.start - self.params = list() - self.ssa_variables = collections.defaultdict(set) - self.num_params = 0 - self.return_set = set([SymbolicValue(self.bv, "Return {}".format(hex(func.start)), 0)]) - self.regs = collections.defaultdict(set) - - def get_return_set(self): - return self.return_set - - def update_register(self, reg_name, value): - if reg_name is None: - return - try: - if isinstance(value, set): - self.regs[reg_name].update(value) - else: - self.regs[reg_name].add(value) - except KeyError: - pass - - def add_ssa_variables(self, var_name, value, insn): - if var_name in self.ssa_variables.keys(): - variable = self.ssa_variables[var_name] - variable["value"].append(value) - else: - variable = dict(value=list(), insn_def=insn) - variable["value"].append(value) - self.ssa_variables[var_name] = variable - - def set_params_count(self): - """ Set the number of function parameters - """ - if self.func is None: - return - - for ref in self.bv.get_code_refs(self.start_addr): - ref_function = ref.function - insn_il = ref_function.get_low_level_il_at(ref.address).medium_level_il - insn_il_ssa = insn_il.ssa_form if insn_il is not None else None - if (insn_il_ssa is None or not hasattr(insn_il_ssa, "params")): - continue - if isinstance(insn_il_ssa.params, MediumLevelILInstruction): - continue - self.num_params = len(insn_il_ssa.params) if len(insn_il_ssa.params) > self.num_params else self.num_params - - def collect_parameters(self): - def global_varname(bv, func, ssa_var): - return "{}_{}#{}".format(func.name, ssa_var.reg.name, ssa_var.version) - - DEBUG_PUSH() - self.params = [set() for i in range(self.num_params)] - for ref in self.bv.get_code_refs(self.start_addr): - ref_function = ref.function - insn_il = ref_function.get_low_level_il_at(ref.address) - if not is_call(self.bv, insn_il): - continue - - DEBUG("Function referred : {} {}".format(ref_function, insn_il.ssa_form)) - for pparam in get_call_params(self.bv, insn_il.ssa_form): - ssa_reg = pparam.src - var_handler = SSARegister(self.bv, ssa_reg, ref_function) - ssa_values = var_handler.backward_analysis(insn_il) - DEBUG("{} -> {}".format(global_varname(self.bv, ref_function, ssa_reg), ssa_values)) - SSAVariableSet[global_varname(self.bv, ref_function, ssa_reg)].update(ssa_values) - target = call_target(self.bv, insn_il) - if isinstance(target, long): - func = self.bv.get_function_at(target) - if func: - variable_name = "{}_{}#0".format(func.name, ssa_reg.reg.name) - SSAVariableSet[variable_name].update(ssa_values) - DEBUG("{} -> {}".format(variable_name, ssa_values)) - DEBUG_POP() - - def collect_returnset(self): - index = 0 - size = len(self.func.low_level_il.ssa_form) - DEBUG_PUSH() - while index < size: - insn = self.func.low_level_il.ssa_form[index] - if not is_executable(self.bv, insn.address): - index += 1 - continue - - if insn.operation == LowLevelILOperation.LLIL_RET: - llil_insn = ILInstruction(self.bv, self.func, insn) - operation_name = "{}".format(insn.operation.name.lower()) - if hasattr(llil_insn, operation_name): - self.return_set = getattr(llil_insn, operation_name)(insn) - DEBUG("Function returnset {} {}".format(self.return_set, insn.operation.name)) - index += 1 - DEBUG_POP() - pass - - def get_param_register(self, reg_name): - try: - index = PARAM_REGISTERS[reg_name.lower()] - return self.params[index] - except KeyError: - return set() - except IndexError: - return set() - - def get_entry_register(self, register): - if register is None: - return - - try: - value_set = self.regs[register] - return value_set - except KeyError: - return set() - except IndexError: - return set() - - def print_parameters(self): - size = len(self.params) - for index in range(size): - try: - DEBUG("{} : {}".format(PARAM_REGISTERS_INDEX[index], pprint.pformat(self.params[index]))) - except KeyError: - pass - - def recover_mlil(self): - """ It creates the instruction objects and process them for the variable - analysis. - """ - index = 0 - DEBUG("{:x} {}".format(self.func.start, self.func.name)) - size = len(self.func.medium_level_il.ssa_form) - - DEBUG_PUSH() - while index < size: - insn = self.func.medium_level_il.ssa_form[index] - DEBUG("{} : {:x} {} operation {} ".format(index+1, insn.address, insn, insn.operation.name)) - if not is_executable(self.bv, insn.address): - index += 1 - continue - - DEBUG_PUSH() - mlil_insn = ILInstruction(self.bv, self.func, insn) - operation_name = "{}".format(insn.operation.name.lower()) - if hasattr(mlil_insn, operation_name): - getattr(mlil_insn, operation_name)(insn) - else: - DEBUG("Instruction operation {} is not supported!".format(operation_name)) - DEBUG_POP() - - if insn.operation == MediumLevelILOperation.MLIL_CALL_SSA: - dest = insn.dest - if dest.operation == MediumLevelILOperation.MLIL_CONST_PTR: - called_function = self.bv.get_function_at(dest.constant) - if called_function is not None: - queue_func(called_function.start) - index += 1 - DEBUG_POP() - - def recover_llil(self): - index = 0 - DEBUG("{:x} {}".format(self.func.start, self.func.name)) - size = len(self.func.low_level_il.ssa_form) - - DEBUG_PUSH() - while index < size: - insn = self.func.low_level_il.ssa_form[index] - DEBUG("{} : {:x} {} operation {} ".format(index+1, insn.address, insn, insn.operation.name)) - if not is_executable(self.bv, insn.address): - index += 1 - continue - - DEBUG_PUSH() - llil_insn = ILInstruction(self.bv, self.func, insn) - operation_name = "{}".format(insn.operation.name.lower()) - if hasattr(llil_insn, operation_name): - getattr(llil_insn, operation_name)(insn) - else: - DEBUG("Instruction operation {} is not supported!".format(operation_name)) - DEBUG_POP() - - if is_call(self.bv, insn): - target = call_target(self.bv, insn) - if target is not None: - queue_func(target) - index += 1 - DEBUG_POP() - -def recover_function(bv, addr, is_entry=False): - """ Process the function and collect the function which should be visited next - """ - func = bv.get_function_at(addr) - if func is None: - return - - if func.symbol.type == SymbolType.ImportedFunctionSymbol: - DEBUG("Skipping external function '{}'".format(func.symbol.name)) - return - - DEBUG("Recovering function {} at {:x}".format(func.symbol.name, addr)) - - if func.start not in FUNCTION_OBJECTS.keys(): - return None - - f_handle = FUNCTION_OBJECTS[func.start] - - f_handle.collect_parameters() - f_handle.collect_returnset() - f_handle.recover_llil() - -def create_function(bv, func): - if func.symbol.type == SymbolType.ImportedFunctionSymbol: - return - - DEBUG("Processing... {:x} {}".format(func.start, func.name)) - f_handler = Function(bv, func) - if f_handler is None: - return - - FUNCTION_OBJECTS[func.start] = f_handler - f_handler.set_params_count() diff --git a/tools/mcsema_disass/ida/binja_var_recovery/il_instructions.py b/tools/mcsema_disass/ida/binja_var_recovery/il_instructions.py deleted file mode 100644 index 52469519b..000000000 --- a/tools/mcsema_disass/ida/binja_var_recovery/il_instructions.py +++ /dev/null @@ -1,382 +0,0 @@ -# Copyright (c) 2018 Trail of Bits, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import pprint -import collections -from binaryninja import * -from binja_var_recovery.util import * -from binja_var_recovery.il_analysis import * -from binja_var_recovery.il_variable import * -from binja_var_recovery.il_function import * - -def get_opd_1(expr): - return expr.src - -def get_opd_2(expr): - return expr.dest, expr.src - -class ILInstruction(object): - def __init__(self, bv, func, insn_il): - self.insn = insn_il - self.address = insn_il.address - self.bv = bv - self.function = func - self.f_handler = FUNCTION_OBJECTS[func.start] - self.ssa_variables = collections.defaultdict(set) - - def get_ssa_var_values(self, ssa_var): - if isinstance(ssa_var, binja.SSAVariable): - value_set = set() - p_value = self.function.medium_level_il.get_ssa_var_value(ssa_var) - if p_value.type in [ binja.RegisterValueType.ConstantValue, - binja.RegisterValueType.ConstantPointerValue ]: - value_set.add(p_value.value) - - elif p_value.type == binja.RegisterValueType.EntryValue: - values = self.f_handler.get_param_register(p_value.reg) - value_set.update(values) - else: - values = self.backward_analysis(ssa_var) - value_set.update(values) - return value_set - else: - return None - - def get_ssa_var_possible_values(self, ssa_var): - value_set = set() - if isinstance(ssa_var, binja.SSAVariable): - p_value = self.insn.get_ssa_var_possible_values(ssa_var) - if p_value.type == binja.RegisterValueType.EntryValue: - value_set = self.func_obj.get_entry_register(p_value.reg) - elif p_value.type != binja.RegisterValueType.UndeterminedValue: - pass - else: - values = self.backward_analysis(ssa_var) - value_set.update(values) - return value_set - - def evaluate_expression(self, expr): - expr_value_set = set() - if expr is None: - return - operation_name = "{}".format(expr.operation.name.lower()) - if hasattr(self, operation_name): - ssa_values = getattr(self, operation_name)(expr) - else: - DEBUG("Instruction operation {} is not supported!".format(operation_name)) - ssa_values = set() - - if ssa_values: - expr_value_set.update(ssa_values) - return expr_value_set - - def forward_analysis(self, ssa_var): - # Collect all the alias ssa variables associated - indices = set() - vars_uses = self.function.medium_level_il.get_ssa_var_uses(ssa_var) - for index in vars_uses: - insn = self.function.medium_level_il[index].ssa_form - if insn is None: - continue - - if insn.operation == binja.MediumLevelILOperation.MLIL_SET_VAR_SSA or \ - insn.operation == binja.MediumLevelILOperation.MLIL_SET_VAR_SSA_FIELD or \ - insn.operation == binja.MediumLevelILOperation.MLIL_VAR_PHI : - indices.add(index) - vars_written = insn.vars_written - for ssa_var in vars_written: - indices.update(self.forward_analysis(ssa_var)) - - return sorted(indices) - - def get_ssa_reg_values(self, ssa_reg): - ssa_reg_name = global_reg_name(self.function, ssa_reg) - if ssa_reg_name in SSAVariableSet.keys(): - ssa_values = SSAVariableSet[ssa_reg_name] - #DEBUG("get_ssa_reg_values {} -> {}".format(ssa_reg_name, ssa_values)) - return ssa_values - else: - var_handler = SSARegister(self.bv, ssa_reg, self.function) - ssa_values = var_handler.backward_analysis(self.insn) - #DEBUG("get_ssa_reg_values {} -> {}".format(ssa_reg_name, ssa_values)) - return ssa_values - - def get_memory_version(self, insn): - version = insn.ssa_memory_version - if version > 0: - return version - elif "mem#0" in str(insn): - return 0 - else: - return None - - def get_variable_addr(self, expr): - if expr is None: - return None - - for token in expr.tokens: - if token.type == binja.InstructionTextTokenType.PossibleAddressToken: - if is_data_variable(self.bv, token.value): - return token.value - return None - -# Low Level IL analysis to determine the possible values of the variables - def _unarry_op(self, expr): - """ Handle the unarry operand; if the operand is const, check if - it has the xrefs or not - """ - src_vset = set() - if is_constant(self.bv, expr): - value = get_constant(self.bv, expr) - src_vset.add(Value(self.bv, value)) - else: - src_vset = self.evaluate_expression(expr) - return src_vset - - def llil_const(self, expr): - value = get_constant(self.bv, expr) - return set([Value(self.bv, value)]) - - def llil_const_ptr(self, expr): - value = get_constant(self.bv, expr) - return set([Value(self.bv, value)]) - - def llil_reg_ssa(self, expr): - ssa_reg = expr.src - ssa_values = self.get_ssa_reg_values(ssa_reg) - return ssa_values - - def llil_reg_ssa_partial(self, expr): - ssa_full_reg = expr.full_reg - ssa_values = self.get_ssa_reg_values(ssa_full_reg) - return ssa_values - - def llil_set_reg_ssa(self, expr): - idest, isrc = get_opd_2(expr) - name = global_reg_name(self.function, expr.dest) - ssa_values = set() - - if name in SSAVariableSet.keys(): - return SSAVariableSet[name] - - if is_constant(self.bv, isrc): - value = get_constant(self.bv, isrc) - ssa_values.add(Value(self.bv, value)) - if has_xrefs(self.bv, value) and \ - has_address_xrefs(self.bv, expr, value): - ADDRESS_REFS[value] = 0 - else: - ssa_values = self.evaluate_expression(isrc) - - SSAVariableSet[name] = ssa_values - DEBUG("{} -> {}".format(name, ssa_values)) - return ssa_values - - def llil_goto(self, expr): - pass - - def llil_sx(self, expr): - return self._unarry_op(expr.src) - - def llil_zx(self, expr): - return self._unarry_op(expr.src) - - def llil_jump(self, expr): - idest = expr.dest - ssa_values = self.evaluate_expression(idest) - - def llil_lsl(self, expr): - expr_vset = set() - lvset = set() - rvset = set() - - # Handle left operand - ileft = expr.left - if is_constant(self.bv, ileft): - value = get_constant(self.bv, ileft) - if has_xrefs(self.bv, value) and \ - has_address_xrefs(self.bv, expr, value): - lvset.add(Values(value, value)) - ADDRESS_REFS[value] = 0 - else: - lvset.add(value) - else: - lvset = self.evaluate_expression(expr.left) - - iright = expr.right - if is_constant(self.bv, iright): - value = get_constant(self.bv, iright) - if has_xrefs(self.bv, value) and \ - has_address_xrefs(self.bv, expr, value): - rvset.add(Values(value, value)) - ADDRESS_REFS[value] = 0 - else: - rvset.add(value) - else: - rvset = self.evaluate_expression(expr.right) - - DEBUG("llil_lsl expr_vset {}".format(expr_vset)) - return expr_vset - - def llil_sub(self, expr): - lvset = set() - rvset = set() - - lvset = self.evaluate_expression(expr.left) - if is_constant(self.bv, expr.right): - iright = expr.right - rvset.add(Value(self.bv, iright.constant)) - else: - rvset = self.evaluate_expression(expr.right) - - ssa_values = set([l - r for l in lvset for r in rvset]) - DEBUG("llil_sub {}".format(ssa_values)) - return ssa_values - - def llil_add(self, expr): - lvset = set() - rvset = set() - - if is_constant(self.bv, expr.left): - ileft = expr.left - value = get_constant(self.bv, ileft) - lvset.add(Value(self.bv, value)) - if has_xrefs(self.bv, value) and \ - has_address_xrefs(self.bv, expr, value): - ADDRESS_REFS[ileft.constant] = 0 - else: - lvset = self.evaluate_expression(expr.left) - - if is_constant(self.bv, expr.right): - iright = expr.right - value = get_constant(self.bv, iright) - rvset.add(Value(self.bv, value)) - if has_xrefs(self.bv, value) and \ - has_address_xrefs(self.bv, expr, value): - ADDRESS_REFS[iright.constant] = 0 - else: - rvset = self.evaluate_expression(expr.right) - - ssa_values = set([l + r for l in lvset for r in rvset]) - DEBUG("llil_add {}".format(ssa_values)) - return ssa_values - - def llil_store_ssa(self, expr): - DEBUG("llil_store_ssa {}".format(expr)) - idest, isrc = get_opd_2(expr) - - sz = isrc.size - if is_constant(self.bv, idest): - dest_memory = get_constant(self.bv, idest) - dest_memset = set([Value(self.bv, dest_memory)]) - if has_xrefs(self.bv, dest_memory) and \ - has_memory_xrefs(self.bv, dest_memory): - MEMORY_REFS[dest_memory] = sz - else: - dest_memset = self.evaluate_expression(idest) - - for item in dest_memset: - if isinstance(item, Value): - set_variables(self.bv, item.base_address, item.size + sz) - - DEBUG("llil_store_ssa {}".format(dest_memset)) - - def llil_load_ssa(self, expr): - DEBUG("llil_load_ssa {}".format(expr)) - isrc = get_opd_1(expr) - - sz = isrc.size - if is_constant(self.bv, isrc): - src_memory = get_constant(self.bv, isrc) - src_memset = set([Value(self.bv, src_memory)]) - if has_xrefs(self.bv, src_memory) and \ - has_memory_xrefs(self.bv, src_memory): - MEMORY_REFS[src_memory] = sz - else: - src_memset = self.evaluate_expression(isrc) - - for item in src_memset: - if isinstance(item, Value): - set_variables(self.bv, item.base_address, item.size + sz) - - ssa_values = set([SymbolicValue(self.bv, "memory load {}".format(src_memset))]) - return ssa_values - - def llil_cmp_e(self, expr): - lvset = self.evaluate_expression(expr.left) - rvset = self.evaluate_expression(expr.right) - DEBUG("llil_cmp_e {} left {}, right {}".format(expr, lvset, rvset)) - - def llil_cmp_ne(self, expr): - lvset = self.evaluate_expression(expr.left) - rvset = self.evaluate_expression(expr.right) - DEBUG("llil_cmp_ne {} left {}, right {}".format(expr, lvset, rvset)) - - def llil_if(self, expr): - cond = self.evaluate_expression(expr.condition) - DEBUG("llil_if {} -> {}".format(expr.condition, cond)) - - ssa_variable_set = set() - def llil_reg_phi(self, expr): - idest, isrc = get_opd_2(expr) - reg_name = global_reg_name(self.function, idest) - if reg_name in SSAVariableSet.keys(): - return SSAVariableSet[reg_name] - - ssa_values = set() - for ssa_reg in isrc: - if str(ssa_reg) not in SSARegister.ssa_variable_set: - ILInstruction.ssa_variable_set.add(str(ssa_reg)) - reg_handler = SSARegister(self.bv, ssa_reg, self.function) - ssa_values.update(reg_handler.backward_analysis(self.insn)) - ILInstruction.ssa_variable_set.remove(str(ssa_reg)) - - SSAVariableSet[reg_name] = ssa_values - DEBUG("llil_reg_phi ssa values {} -> {}".format(reg_name, ssa_values)) - return ssa_values - - def llil_call_ssa(self, expr): - DEBUG("Analyze low level IL llil_call_ssa") - call_parameters = call_params(self.bv, expr) - if call_parameters != None: - for param in call_parameters: - ssa_values = self.get_ssa_reg_values(param.src) - DEBUG("param {} -> {}".format(param.src, ssa_values)) - - target = call_target(self.bv, expr) - try: - sym_value = FUNCTION_OBJECTS[target].get_return_set() - except KeyError: - sym_value = set([SymbolicValue(self.bv, "Return {}".format(hex(target) if isinstance(target, long) else target), 0)]) - for out in get_call_output(self.bv, expr): - SSAVariableSet[global_reg_name(self.function, out)].update(sym_value) - - def llil_tailcall_ssa(self, expr): - DEBUG("Analyze low level IL llil_tailcall_ssa") - call_parameters = call_params(self.bv, expr) - if call_parameters != None: - for param in call_parameters: - ssa_values = self.get_ssa_reg_values(param.src) - DEBUG("param {} -> {}".format(param.src, ssa_values)) - - def llil_ret(self, expr): - ssa_values = self.evaluate_expression(expr.dest) - DEBUG("llil_ret ssa values {} {}".format(expr.dest, ssa_values)) - return ssa_values - - def llil_noret(self, expr): - DEBUG("llil_noret not supported for the analysis") - - def llil_unimpl_mem(self, expr): - DEBUG("llil_unimpl_mem not supported for the analysis") diff --git a/tools/mcsema_disass/ida/binja_var_recovery/il_variable.py b/tools/mcsema_disass/ida/binja_var_recovery/il_variable.py deleted file mode 100644 index a0261f31d..000000000 --- a/tools/mcsema_disass/ida/binja_var_recovery/il_variable.py +++ /dev/null @@ -1,210 +0,0 @@ -# Copyright (c) 2018 Trail of Bits, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import pprint -import collections -import binaryninja as bn -from binja_var_recovery.util import * -from binja_var_recovery.il_analysis import * - -FUNCTION_OBJECTS = collections.defaultdict() - -VARIABLE_ALIAS_SET = collections.defaultdict(set) - -SSAVariableSet = collections.defaultdict(set) - -class ILVisitor(object): - """ Class functions to visit low-level IL""" - def __init__(self): - super(ILVisitor, self).__init__() - - def visit(self, expr): - method_name = 'visit_{}'.format(expr.operation.name.lower()) - if hasattr(self, method_name): - value = getattr(self, method_name)(expr) - else: - DEBUG("Warning! method `{}` not found.".format(method_name)) - value = set() - return value - -""" SSA variable class provides support for backward analysis and - get the value set for the ssa variables -""" -class SSARegister(ILVisitor): - def __init__(self, bv, reg, func=None): - super(SSARegister, self).__init__() - self.bv = bv - self.reg = reg - self.function = func - self.func_start = func.start - self.visited = set() - self.to_visit = list() - self.insn = None - - @property - def version(self): - return self.reg.version - - @property - def name(self): - return "{}#{}".format(self.reg.reg.name, self.reg.version) - - @property - def global_name(self): - return "{}_{}#{}".format(self.function.name, self.reg.reg.name, self.reg.version) - - @staticmethod - def version(self, ssa_reg): - return ssa_reg.version - - @staticmethod - def name(self, ssa_reg): - return "{}#{}".format(ssa_reg.reg.name, self.version(self, ssa_reg)) - - @staticmethod - def global_name(self, ssa_reg): - return "{}_{}#{}".format(self.function.name, ssa_reg.reg.name, self.version(self, ssa_reg)) - - def backward_analysis(self, insn): - var_def = self.function.low_level_il.ssa_form.get_ssa_reg_definition(self.reg) - if var_def: - self.to_visit.append(var_def) - ssa_values = set() - - if len(self.to_visit): - self.insn = insn - while self.to_visit: - idx = self.to_visit.pop() - if idx is not None: - ssa_values.update(self.visit(self.function.low_level_il.ssa_form[idx])) - else: - ssa_values = set([SymbolicValue(self.bv, self.global_name(self, self.reg))]) - - return ssa_values - - def visit_llil_const(self, expr): - value = get_constant(self.bv, expr) - return set([Value(self.bv, value)]) - - def visit_llil_const_ptr(self, expr): - value = get_constant(self.bv, expr) - return set([Value(self.bv, value)]) - - def visit_llil_reg_ssa(self, expr): - #DEBUG("visit_llil_reg_ssa {}".format(expr)) - if self.version(self, expr.src) == 0: - return set([SymbolicValue(self.bv, self.global_name(self, expr.src))]) - - if self.global_name(self, expr.src) in SSAVariableSet.keys(): - return SSAVariableSet[self.global_name(self, expr.src)] - - reg_handler = SSARegister(self.bv, expr.src, self.function) - ssa_values = reg_handler.backward_analysis(self.insn) - return ssa_values - - def visit_llil_reg_ssa_partial(self, expr): - full_reg = expr.full_reg - full_reg_name = self.global_name(self, full_reg) - if full_reg_name in SSAVariableSet.keys(): - return SSAVariableSet[full_reg_name] - - reg_handler = SSARegister(self.bv, full_reg, self.function) - ssa_values = reg_handler.backward_analysis(self.insn) - return ssa_values - - def visit_llil_set_reg_ssa(self, expr): - #DEBUG("visit_llil_set_reg_ssa {}".format(expr)) - ssa_reg = expr.dest - ssa_reg_name = self.global_name(self, ssa_reg) - if ssa_reg_name in SSAVariableSet.keys(): - return SSAVariableSet[ssa_reg_name] - - ssa_values = self.visit(expr.src) - SSAVariableSet[ssa_reg_name] = ssa_values - return ssa_values - - def visit_llil_set_reg_ssa_partial(self, expr): - #DEBUG("visit_llil_set_reg_ssa_partial {}".format(expr)) - ssa_values = self.visit(expr.src) - return ssa_values - - def visit_llil_zx(self, expr): - isrc = expr.src - return self.visit(isrc) - - def visit_llil_sx(self, expr): - isrc = expr.src - return self.visit(isrc) - - def visit_llil_lsl(self, expr): - ssa_values_left = self.visit(expr.left) - ssa_values_right = self.visit(expr.right) - ssa_values = set([l << r for l in ssa_values_left for r in ssa_values_right]) - DEBUG("visit_llil_lsl values {} ".format(ssa_values)) - return ssa_values - - def visit_llil_lsr(self, expr): - ssa_values_left = self.visit(expr.left) - ssa_values_right = self.visit(expr.right) - ssa_values = set([l >> r for l in ssa_values_left for r in ssa_values_right]) - DEBUG("visit_llil_lsr values {} ".format(ssa_values)) - return ssa_values - - def visit_llil_load_ssa(self, expr): - DEBUG("visit_llil_load_ssa {}".format(expr)) - isrc = expr.src - memory = self.visit(isrc) - return set([SymbolicValue(self.bv, "memory load ({})".format(memory))]) - - def visit_llil_add(self, expr): - """ Resolve the SSA variable used in the addition expression - """ - left = self.visit(expr.left) - right = self.visit(expr.right) - values = set([l + r for l in left for r in right]) - DEBUG("visit_llil_add values {} ".format(values)) - return values - - def visit_llil_sub(self, expr): - """ Resolve the SSA variable used in the addition expression - """ - left = self.visit(expr.left) - right = self.visit(expr.right) - values = set([l - r for l in left for r in right]) - DEBUG("visit_llil_sub values {} ".format(values)) - return values - - ssa_variable_set = set() - def visit_llil_reg_phi(self, expr): - values_set = set() - for ssa_reg in expr.src: - if str(ssa_reg) not in SSARegister.ssa_variable_set: - SSARegister.ssa_variable_set.add(str(ssa_reg)) - reg_handler = SSARegister(self.bv, ssa_reg, self.function) - values_set.update(reg_handler.backward_analysis(self.insn)) - SSARegister.ssa_variable_set.remove(str(ssa_reg)) - return values_set - - def visit_llil_call_ssa(self, expr): - def global_varname(bv, func, ssa_var): - return "{}_{}#{}".format(func.name, ssa_var.reg.name, ssa_var.version) - - target = call_target(self.bv, expr) - try: - sym_value = FUNCTION_OBJECTS[target].get_return_set() - except KeyError: - sym_value = set([SymbolicValue(self.bv, "Return {}".format(hex(target) if isinstance(target, long) else target), 0)]) - for out in get_call_output(self.bv, expr): - SSAVariableSet[global_reg_name(self.function, out)].update(sym_value) - return sym_value \ No newline at end of file diff --git a/tools/mcsema_disass/ida/binja_var_recovery/util.py b/tools/mcsema_disass/ida/binja_var_recovery/util.py deleted file mode 100644 index 8e693b13e..000000000 --- a/tools/mcsema_disass/ida/binja_var_recovery/util.py +++ /dev/null @@ -1,213 +0,0 @@ -# Copyright (c) 2018 Trail of Bits, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import re -import io -import collections -import struct - -try: - from elftools.elf.elffile import ELFFile - from elftools.elf.sections import SymbolTableSection -except ImportError: - print "Install pyelf tools" - -_DEBUG_FILE = None -_DEBUG_PREFIX = "" - -def INIT_DEBUG_FILE(file): - global _DEBUG_FILE - _DEBUG_FILE = file - -def DEBUG_PUSH(): - global _DEBUG_PREFIX - _DEBUG_PREFIX += " " - -def DEBUG_POP(): - global _DEBUG_PREFIX - _DEBUG_PREFIX = _DEBUG_PREFIX[:-2] - -def DEBUG(s): - global _DEBUG_FILE - if _DEBUG_FILE: - _DEBUG_FILE.write("{}{}\n".format(_DEBUG_PREFIX, str(s))) - -dynamic_symbols = collections.defaultdict() - -MEMORY_REFS = collections.defaultdict() - -ADDRESS_REFS = collections.defaultdict() - -EXPORTED_REFS = collections.defaultdict() - -VARIABLE_SET_REFS = collections.defaultdict() - -def set_comments(bv, addr, str): - functions = bv.get_functions_containing(addr) - if functions is None: - return - - for func in functions: - old_str = func.get_comment_at(addr) - new_str = old_str + " ; " + str - func.set_comment_at(addr, new_str) - -def convert_signed32(num): - num = num & 0xFFFFFFFF - return (num ^ 0x80000000) - 0x80000000 - -def is_valid_addr(bv, addr): - return bv.get_segment_at(addr) is not None - -def is_invalid_addr(bv, addr): - return bv.get_segment_at(addr) is None - -def get_section_at(bv, addr): - if is_invalid_addr(bv, addr): - return None - - for sec in bv.sections.values(): - if sec.start <= addr < sec.end: - return sec - return None - -def is_executable(bv, addr): - seg = bv.get_segment_at(addr) - return seg is not None and seg.executable - -def is_readable(bv, addr): - seg = bv.get_segment_at(addr) - return seg is not None and seg.writable - -def is_writeable(bv, addr): - seg = bv.get_segment_at(addr) - return seg is not None and seg.readable - -def is_ELF(bv): - return bv.view_type == 'ELF' - -def is_PE(bv): - return bv.view_type == 'PE' - -def is_data_variable_section(bv, addr): - seg = bv.get_segment_at(addr) - if seg == None: - return False - - sect = get_section_at(bv, addr) - if sect is not None and is_ELF(bv): - if re.search(r'\.(init|fini|got|plt)', sect.name): - return False - - return (seg.executable == False) - -def is_data_variable(bv, addr): - seg = bv.get_segment_at(addr) - if seg == None: - return False - - sect = get_section_at(bv, addr) - if sect is not None and is_ELF(bv): - if re.search(r'\.(init|fini|got|plt)', sect.name): - return False - - if is_dynamic_range_lookup(bv, addr): - return False - - return (seg.executable == False) - -# Caching results of is_section_external -_EXT_SECTIONS = set() -_INT_SECTIONS = set() - -def is_section_external(bv, sect): - if sect.start in _EXT_SECTIONS: - return True - - if sect.start in _INT_SECTIONS: - return False - - if is_ELF(bv): - if re.search(r'\.(got|plt)', sect.name): - _EXT_SECTIONS.add(sect.start) - return True - - _INT_SECTIONS.add(sect.start) - return False - -def is_dynamic_range_lookup(bv, addr): - for sym in sorted(dynamic_symbols.keys()): - if sym <= addr < sym + dynamic_symbols[sym]: - return True - return False - -def process_binary(bv, binfile): - with open(binfile, 'rb') as f: - elffile = ELFFile(f) - symbol_tables = [s for s in elffile.iter_sections() if isinstance(s, SymbolTableSection)] - - for section in symbol_tables: - if not isinstance(section, SymbolTableSection): - continue - - if section['sh_entsize'] == 0: - continue - - for nsym, symbol in enumerate(section.iter_symbols()): - sym_addr = symbol['st_value'] - sym_size = symbol['st_size'] - if is_data_variable_section(bv, sym_addr): - dynamic_symbols[sym_addr] = sym_size - -def set_variables(bv, addr, size): - if not is_data_variable(bv, addr): - return - try: - curr_size = VARIABLE_SET_REFS[addr] - if size > curr_size: - VARIABLE_SET_REFS[addr] = size - except KeyError: - VARIABLE_SET_REFS[addr] = size - -def print_variables(bv): - g_variables = collections.defaultdict() - for key in VARIABLE_SET_REFS.keys(): - size = VARIABLE_SET_REFS[key] - g_variables[key] = size - - DEBUG("Variables set") - for addr in g_variables.keys(): - DEBUG("{:x} -> {:x}".format(addr, g_variables[addr])) - -def get_dynamic_symbol(bv): - sym_table = sorted(dynamic_symbols.keys()) - for sym in sym_table: - size = dynamic_symbols[sym] - yield (sym, size) - yield (sym +size, 0) - -def get_memory_refs(bv): - memory_refs = sorted(MEMORY_REFS.keys()) - for ref in memory_refs: - size = MEMORY_REFS[ref] - if is_dynamic_range_lookup(bv, ref): - continue - yield (ref, size) - -def get_address_refs(bv): - xrefs = sorted(ADDRESS_REFS.keys()) - for ref in xrefs: - if is_dynamic_range_lookup(bv, ref): - continue - yield (ref, 0) diff --git a/tools/mcsema_disass/ida/collect_variable.py b/tools/mcsema_disass/ida/collect_variable.py deleted file mode 100644 index e202ed691..000000000 --- a/tools/mcsema_disass/ida/collect_variable.py +++ /dev/null @@ -1,695 +0,0 @@ -#!/usr/bin/env python - -# Copyright (c) 2017 Trail of Bits, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import idautils -import idaapi -import idc -import sys -import os -import argparse -import struct -import traceback -import collections -import itertools -import pprint - -# Bring in utility libraries. -from util import * -from table import * -from flow import * -from refs import * -from segment import * - -OPND_WRITE_FLAGS = { - 0: idaapi.CF_CHG1, - 1: idaapi.CF_CHG2, - 2: idaapi.CF_CHG3, - 3: idaapi.CF_CHG4, - 4: idaapi.CF_CHG5, - 5: idaapi.CF_CHG6, -} - -OPND_READ_FLAGS = { - 0: idaapi.CF_USE1, - 1: idaapi.CF_USE2, - 2: idaapi.CF_USE3, - 3: idaapi.CF_USE4, - 4: idaapi.CF_USE5, - 5: idaapi.CF_USE6, -} - -OPND_DTYPE_STR = { - 0:'dt_byte', - 1:'dt_word', - 2:'dt_dword', - 3:'dt_float', - 4:'dt_double', - 5:'dt_tbyte', - 6:'dt_packreal', - 7:'dt_qword', - 8:'dt_byte16', - 9:'dt_code', - 10:'dt_void', - 11:'dt_fword', - 12:'dt_bitfild', - 13:'dt_string', - 14:'dt_unicode', - 15:'dt_3byte', - 16:'dt_ldbl', - 17:'dt_byte32', - 18:'dt_byte64' -} - -OPND_DTYPE_TO_SIZE = { - idaapi.dt_byte: 1, - idaapi.dt_word: 2, - idaapi.dt_dword: 4, - idaapi.dt_float: 4, - idaapi.dt_double: 8, - idaapi.dt_qword: 8, - idaapi.dt_byte16: 16, - idaapi.dt_fword: 6, - idaapi.dt_3byte: 3, - idaapi.dt_byte32: 32, - idaapi.dt_byte64: 64, -} - -def get_native_size(): - info = idaapi.get_inf_structure() - if info.is_64bit(): - return 8 - elif info.is_32bit(): - return 4 - else: - return 2 - -def get_register_name(reg_id, size=None): - if size is None: - size = get_native_size() - return idaapi.get_reg_name(reg_id, size) - -def get_register_info(reg_name): - ri = idaapi.reg_info_t() - success = idaapi.parse_reg_name(reg_name, ri) - return ri - -class Operand(object): - def __init__(self, opnd, ea, insn, write, read): - self._operand = opnd - self._ea = ea - self._read = read - self._write= write - self._insn = insn - self._type = opnd.type - self._index_id = None - self._base_id = None - self._displ = None - self._scale = None - - if self._type in (idaapi.o_displ, idaapi.o_phrase): - specflag1 = self.op_t.specflag1 - specflag2 = self.op_t.specflag2 - scale = 1 << ((specflag2 & 0xC0) >> 6) - offset = self.op_t.addr - - if specflag1 == 0: - index_ = None - base_ = self.op_t.reg - elif specflag1 == 1: - index_ = (specflag2 & 0x38) >> 3 - base_ = (specflag2 & 0x07) >> 0 - - if self.op_t.reg == 0xC: - base_ += 8 - # HACK: Check if the index register is there in the operand - # It will fix the issue if `rsi` is getting used as index register - if (index_ & 4) and get_register_name(index_) not in idc.GetOpnd(self._ea, opnd.n): - index_ += 8 - - if (index_ == base_ == idautils.procregs.sp.reg) and (scale == 1): - index_ = None - - self._scale = scale - self._index_id = index_ - self._base_id = base_ - self._displ = offset - - def _get_datatype_size(self, dtype): - return OPND_DTYPE_TO_SIZE.get(dtype,0) - - def _get_datatypestr_from_dtyp(self, dt_dtyp): - return OPND_DTYPE_STR.get(dt_dtyp,"") - - @property - def op_t(self): - return self._operand - - @property - def value(self): - return idc.GetOperandValue(self._ea, self.index) - - @property - def size(self): - return self._get_datatype_size(self._operand.dtyp) - - @property - def text(self): - return idc.GetOpnd(self._ea, self.index) - - @property - def dtype(self): - return self._get_datatypestr_from_dtyp(self._operand.dtyp) - - @property - def index(self): - return self._operand.n - - @property - def type(self): - return self._type - - @property - def is_read(self): - return self._read - - @property - def is_write(self): - return self._write - - @property - def is_void(self): - return self._type == idaapi.o_void - - @property - def is_reg(self): - return self._type == idaapi.o_reg - - @property - def is_mem(self): - return self._type == idaapi.o_mem - - @property - def is_phrase(self): - return self._type == idaapi.o_phrase - - @property - def is_displ(self): - return self._type == idaapi.o_displ - - @property - def is_imm(self): - return self._type == idaapi.o_imm - - @property - def is_far(self): - return self._type == idaapi.o_far - - @property - def is_near(self): - return self._type == idaapi.o_near - - @property - def is_special(self): - return self._type >= idaapi.o_idpspec0 - - @property - def has_phrase(self): - return self._type in (idaapi.o_phrase, idaapi.o_displ) - - @property - def reg_id(self): - """ID of the register used in the operand.""" - return self._operand.reg - - @property - def reg(self): - """Name of the register used in the operand.""" - if self.has_phrase: - size = get_native_size() - return get_register_name(self.reg_id, size) - - if self.is_reg: - return get_register_name(self.reg_id, self.size) - - @property - def regs(self): - if self.has_phrase: - return set(reg for reg in (self.base, self.index) if reg) - elif self.is_reg: - return {get_register_name(self.reg_id, self.size)} - else: - return set() - - @property - def base_reg(self): - if self._base_id is None: - return None - return get_register_name(self._base_id) - - @property - def index_reg(self): - if self._index_id is None: - return None - return get_register_name(self._index_id) - - @property - def scale(self): - return self._scale - - @property - def displ(self): - return self._displ - - -class Instruction(object): - ''' - Instruction objects - ''' - def __init__(self, ea): - self._ea = ea - self._insn, _ = decode_instruction(ea) - self._operands = self._make_operands() - - def _is_operand_write_to(self, index): - return (self.feature & OPND_WRITE_FLAGS[index]) - - def _is_operand_read_from(self, index): - return (self.feature & OPND_READ_FLAGS[index]) - - def _make_operands(self): - operands = [] - for index, opnd in enumerate(self._insn.Operands): - if opnd.type == idaapi.o_void: - break - operands.append(Operand(opnd, - self._ea, - insn=self._insn, - write=self._is_operand_write_to(index), - read=self._is_operand_read_from(index))) - - return operands - - @property - def feature(self): - return self._insn.get_canon_feature() - - @property - def opearnds(self): - return self._operands - - @property - def mnemonic(self): - return self._insn.get_canon_mnem() - - -def _signed_from_unsigned64(val): - if val & 0x8000000000000000: - return -0x10000000000000000 + val - return val - -def _signed_from_unsigned32(val): - if val & 0x80000000: - return -0x100000000 + val - return val - -def _mark_function_args_ms64(referers, dereferences, func_var_data): - for reg in ["rcx", "rdx", "r8", "r9"]: - _mark_func_arg(reg, referers, dereferences, func_var_data) - -def _mark_function_args_sysv64(referers, dereferences, func_var_data): - for reg in ["rdi", "rsi", "rdx", "rcx", "r8", "r9"]: - _mark_func_arg(reg, referers, dereferences, func_var_data) - -def _mark_function_args_x86(referers, dereferences, func_var_data): - pass #TODO. urgh. - -def _translate_reg_32(reg): - return reg - -def _translate_reg_64(reg): - return {"edi":"rdi", - "esi":"rsi", - "eax":"rax", - "ebx":"rbx", - "ecx":"rcx", - "edx":"rdx", - "ebp":"rbp", - "esp":"rsp"}.get(reg, reg) - -if idaapi.get_inf_structure().is_64bit(): - _signed_from_unsigned = _signed_from_unsigned64 - _base_ptr = "rbp" - _stack_ptr = "rsp" - _trashed_regs = ["rax", "rcx", "rdx", "rsi", "rdi", "r8", "r9", "r10", "r11"] - _mark_args = _mark_function_args_sysv64 - _translate_reg = _translate_reg_64 -elif idaapi.get_inf_structure().is_32bit(): - _signed_from_unsigned = _signed_from_unsigned32 - _base_ptr = "ebp" - _stack_ptr = "esp" - _trashed_regs = ["eax", "ecx", "edx"] - _mark_args = _mark_function_args_x86 - _translate_reg = _translate_reg_32 - -_base_ptr_format = "[{}+".format(_base_ptr) -_stack_ptr_format = "[{}+".format(_stack_ptr) - -def floor_key(d, key): - L1 = list(k for k in d if k <= key) - if len(L1): - return max(L1) - -def _get_flags_from_bits(flag): - ''' - Translates the flag field in structures (and elsewhere?) into a human readable - string that is compatible with pasting into IDA or something. - Returns an empty string if supplied with -1. - ''' - if -1 == flag: - return "" - - cls = { - 'MASK':1536, - 1536:'FF_CODE', - 1024:'FF_DATA', - 512:'FF_TAIL', - 0:'FF_UNK', - } - - comm = { - 'MASK':1046528, - 2048:'FF_COMM', - 4096:'FF_REF', - 8192:'FF_LINE', - 16384:'FF_NAME', - 32768:'FF_LABL', - 65536:'FF_FLOW', - 524288:'FF_VAR', - 49152:'FF_ANYNAME', - } - - _0type = { - 'MASK':15728640, - 1048576:'FF_0NUMH', - 2097152:'FF_0NUMD', - 3145728:'FF_0CHAR', - 4194304:'FF_0SEG', - 5242880:'FF_0OFF', - 6291456:'FF_0NUMB', - 7340032:'FF_0NUMO', - 8388608:'FF_0ENUM', - 9437184:'FF_0FOP', - 10485760:'FF_0STRO', - 11534336:'FF_0STK', - } - _1type = { - 'MASK':251658240, - 16777216:'FF_1NUMH', - 33554432:'FF_1NUMD', - 50331648:'FF_1CHAR', - 67108864:'FF_1SEG', - 83886080:'FF_1OFF', - 100663296:'FF_1NUMB', - 117440512:'FF_1NUMO', - 134217728:'FF_1ENUM', - 150994944:'FF_1FOP', - 167772160:'FF_1STRO', - 184549376:'FF_1STK', - } - datatype = { - 'MASK':4026531840, - 0:'FF_BYTE', - 268435456:'FF_WORD', - 536870912:'FF_DWRD', - 805306368:'FF_QWRD', - 1073741824:'FF_TBYT', - 1342177280:'FF_ASCI', - 1610612736:'FF_STRU', - 1879048192:'FF_OWRD', - 2147483648:'FF_FLOAT', - 2415919104:'FF_DOUBLE', - 2684354560:'FF_PACKREAL', - 2952790016:'FF_ALIGN', - } - - flags = set() - flags.add(cls[cls['MASK']&flag]) - - for category in [comm, _0type, _1type, datatype]: - #the ida docs define, for example, a FF_0VOID = 0 constant in with the rest - # of the 0type constants, but I _think_ that just means - # the field is unused, rather than being specific data - val = category.get(category['MASK']&flag, None) - if val: - flags.add(val) - return flags - -def _process_instruction(inst_ea, func_variable): - insn = Instruction(inst_ea) - for opnd in insn.opearnds: - if opnd.has_phrase: - base_ = _translate_reg(opnd.base_reg) if opnd.base_reg else None - index_ = _translate_reg(opnd.index_reg) if opnd.index_reg else None - offset = _signed_from_unsigned(idc.GetOperandValue(inst_ea, opnd.index)) - if len(func_variable["stack_vars"].keys()) == 0: - return - - if opnd.is_write: - target_on_stack = base_ if base_ == _stack_ptr or base_ == _base_ptr else None - if target_on_stack == _base_ptr: - start_ = floor_key(func_variable["stack_vars"].keys(), offset) - if start_: - end_ = start_ + func_variable["stack_vars"][start_]["size"] - if offset in range(start_, end_): - var_offset = offset - start_ - func_variable["stack_vars"][start_]["writes"].append({"ea" :inst_ea, "offset" :var_offset}) - func_variable["stack_vars"][start_]["safe"] = True - else: - for key in func_variable["stack_vars"].keys(): - if func_variable["stack_vars"][key]["name"] in opnd.text: - func_variable["stack_vars"][key]["safe"] = False - func_variable["stack_vars"].pop(key, None) - break - - elif opnd.is_read: - read_on_stack = base_ if base_ == _stack_ptr or base_ == _base_ptr else None - if read_on_stack == _base_ptr: - start_ = floor_key(func_variable["stack_vars"].keys(), offset) - if start_: - end_ = start_ + func_variable["stack_vars"][start_]["size"] - if offset in range(start_, end_): - var_offset = offset - start_ - func_variable["stack_vars"][start_]["reads"].append({"ea" :inst_ea, "offset" :var_offset}) - func_variable["stack_vars"][start_]["safe"] = True - else: - for key in func_variable["stack_vars"].keys(): - if func_variable["stack_vars"][key]["name"] in opnd.text: - func_variable["stack_vars"][key]["safe"] = False - func_variable["stack_vars"].pop(key, None) - break - else: - read_on_stack = base_ if base_ == _stack_ptr or base_ == _base_ptr else None - if read_on_stack: - start_ = floor_key(func_variable["stack_vars"].keys(), offset) - if start_: - end_ = start_ + func_variable["stack_vars"][start_]["size"] - if offset in range(start_, end_): - var_offset = offset - start_ - func_variable["stack_vars"][start_]["flags"].add("LOCAL_REFERER") - func_variable["stack_vars"][start_]["referent"].append({"ea" :inst_ea, "offset" :var_offset}) - - elif opnd.is_reg and opnd.is_read: - if insn.mnemonic in ["push"]: - continue - - # The register operand such as `add %rax %rbp` will not have the offset value - # It is set as 0 since we are looking to replace %rbp with %frame = ... - offset = 0 #_signed_from_unsigned(idc.GetOperandValue(inst_ea, opnd.index)) - if len(func_variable["stack_vars"].keys()) == 0: - return - - for reg in opnd.regs: - if _translate_reg(reg) == _base_ptr: - start_ = floor_key(func_variable["stack_vars"].keys(), offset) - if start_: - end_ = start_ + func_variable["stack_vars"][start_]["size"] - if offset in range(start_, end_+1): - var_offset = offset - start_ - func_variable["stack_vars"][start_]["reads"].append({"ea" :inst_ea, "offset" : var_offset}) - func_variable["stack_vars"][start_]["safe"] = True - -def _process_basic_block(f_ea, block_ea, func_variable): - inst_eas, succ_eas = analyse_block(f_ea, block_ea, True) - for inst_ea in inst_eas: - _process_instruction(inst_ea, func_variable) - -_FUNC_UNSAFE_LIST = set() - -def build_stack_variable(func_ea): - stack_vars = dict() - - frame = idc.GetFrame(func_ea) - if not frame: - return stack_vars - - f_name = get_symbol_name(func_ea) - #grab the offset of the stored frame pointer, so that - #we can correlate offsets correctly in referent code - # e.g., EBP+(-0x4) will match up to the -0x4 offset - delta = idc.GetMemberOffset(frame, " s") - if delta == -1: - delta = 0 - - if f_name not in _FUNC_UNSAFE_LIST: - offset = idc.GetFirstMember(frame) - while -1 != _signed_from_unsigned(offset): - member_name = idc.GetMemberName(frame, offset) - if member_name is None: - offset = idc.GetStrucNextOff(frame, offset) - continue - if (member_name == " r" or member_name == " s"): - offset = idc.GetStrucNextOff(frame, offset) - continue - - member_size = idc.GetMemberSize(frame, offset) - if offset >= delta: - offset = idc.GetStrucNextOff(frame, offset) - continue - - member_flag = idc.GetMemberFlag(frame, offset) - flag_str = _get_flags_from_bits(member_flag) - member_offset = offset-delta - stack_vars[member_offset] = {"name": member_name, - "size": member_size, - "flags": flag_str, - "writes": list(), - "referent": list(), - "reads": list(), - "safe": False } - - offset = idc.GetStrucNextOff(frame, offset) - else: - offset = idc.GetFirstMember(frame) - frame_size = idc.GetFunctionAttr(func_ea, idc.FUNCATTR_FRSIZE) - flag_str = "" - member_offset = _signed_from_unsigned(offset) - delta - stack_vars[member_offset] = {"name": f_name, - "size": frame_size, - "flags": flag_str, - "writes": list(), - "referent": list(), - "reads": list(), - "safe": False } - - return stack_vars - -def is_instruction_unsafe(inst_ea, func_ea): - """ Returns `True` if the instruction reads from the base ptr and loads - the value to the other registers. - """ - _uses_bp = False - insn = Instruction(inst_ea) - - # Special case check for function prologue which prepares - # the function for stack and register uses - # push rbp - # mov rbp, rsp - # ... - if insn.mnemonic in ["push"]: - return False - - for opnd in insn.opearnds: - if opnd.is_read and opnd.is_reg: - for reg in opnd.regs: - if _translate_reg(reg) == _base_ptr: - _uses_bp = True - - return _uses_bp - -def is_function_unsafe(func_ea, blockset): - """ Returns `True` if the function uses bp and it might access the stack variable - indirectly using the base pointer. - """ - if not (idc.GetFunctionFlags(func_ea) & idc.FUNC_FRAME): - return False - - for block_ea in blockset: - inst_eas, succ_eas = analyse_block(func_ea, block_ea, True) - for inst_ea in inst_eas: - if is_instruction_unsafe(inst_ea, func_ea): - return True - return False - -def collect_function_vars(func_ea, blockset): - DEBUG_PUSH() - if is_function_unsafe(func_ea, blockset): - _FUNC_UNSAFE_LIST.add(get_symbol_name(func_ea)) - - # Check for the variadic function type; Add the variadic function - # to the list of unsafe functions - func_type = idc.GetType(func_ea) - if (func_type is not None) and ("(" in func_type): - args = func_type[ func_type.index('(')+1: func_type.rindex(')') ] - args_list = [ x.strip() for x in args.split(',')] - if "..." in args_list: - _FUNC_UNSAFE_LIST.add(get_symbol_name(func_ea)) - - stack_vars = build_stack_variable(func_ea) - processed_blocks = set() - while len(blockset) > 0: - block_ea = blockset.pop() - if block_ea in processed_blocks: - DEBUG("ERROR: Attempting to add same block twice: {0:x}".format(block_ea)) - continue - - processed_blocks.add(block_ea) - _process_basic_block(func_ea, block_ea, {"stack_vars": stack_vars}) - - DEBUG_POP() - return stack_vars - -def recover_variables(F, func_ea, blockset): - """ Recover the stack variables from the function. It also collect - the instructions referring to the stack variables. - """ - # Checks for the stack frame; return if it is None - if not is_code_by_flags(func_ea) or \ - not idc.GetFrame(func_ea): - return - - functions = list() - f_name = get_symbol_name(func_ea) - f_ea = idc.GetFunctionAttr(func_ea, idc.FUNCATTR_START) - f_vars = collect_function_vars(func_ea, blockset) - functions.append({"ea":f_ea, "name":f_name, "stackArgs":f_vars}) - - for offset in f_vars.keys(): - if f_vars[offset]["safe"] is False: - continue - - var = F.stack_vars.add() - var.sp_offset = offset - var.name = f_vars[offset]["name"] - var.size = f_vars[offset]["size"] - for i in f_vars[offset]["writes"]: - r = var.ref_eas.add() - r.inst_ea = i["ea"] - r.offset = i["offset"] - - for i in f_vars[offset]["reads"]: - r = var.ref_eas.add() - r.inst_ea = i["ea"] - r.offset = i["offset"] diff --git a/tools/mcsema_disass/ida/disass.py b/tools/mcsema_disass/ida/disass.py deleted file mode 100644 index 05b98f4ef..000000000 --- a/tools/mcsema_disass/ida/disass.py +++ /dev/null @@ -1,81 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2017 Trail of Bits, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import argparse -import collections -import itertools -import os -import subprocess -import sys -import traceback - -try: - from shlex import quote -except: - from pipes import quote - -def execute(args, command_args): - """Execute IDA Pro as a subprocess, passing this file in as a batch-mode - script for IDA to run. This forwards along arguments passed to `mcsema-disass` - down into the IDA script. `command_args` contains unparsed arguments passed - to `mcsema-disass`. This script may handle extra arguments.""" - - ida_disass_path = os.path.abspath(__file__) - ida_dir = os.path.dirname(ida_disass_path) - ida_get_cfg_path = os.path.join(ida_dir, "get_cfg.py") - - env = {} - env["IDALOG"] = os.devnull - env["TVHEADLESS"] = "1" - env["HOME"] = os.path.expanduser('~') - env["IDA_PATH"] = os.path.dirname(args.disassembler) - env["PYTHONPATH"] = os.path.dirname(ida_dir) - if "SystemRoot" in os.environ: - env["SystemRoot"] = os.environ["SystemRoot"] - - script_cmd = [] - script_cmd.append(ida_get_cfg_path) - script_cmd.append("--output") - script_cmd.append(args.output) - script_cmd.append("--log_file") - script_cmd.append(args.log_file) - script_cmd.append("--arch") - script_cmd.append(args.arch) - script_cmd.append("--os") - script_cmd.append(args.os) - script_cmd.append("--entrypoint") - script_cmd.append(args.entrypoint) - script_cmd.extend(command_args) # Extra, script-specific arguments. - - cmd = [] - cmd.append(quote(args.disassembler)) # Path to IDA. - cmd.append("-B") # Batch mode. - cmd.append("-S\"{}\"".format(" ".join(script_cmd))) - cmd.append(quote(args.binary)) - - try: - with open(os.devnull, "w") as devnull: - return subprocess.check_call( - " ".join(cmd), - env=env, - stdin=None, - stdout=devnull, # Necessary. - stderr=sys.stderr, # For enabling `--log_file /dev/stderr`. - shell=True, # Necessary. - cwd=os.path.dirname(__file__)) - - except: - sys.stderr.write(traceback.format_exc()) - return 1 diff --git a/tools/mcsema_disass/ida/exception.py b/tools/mcsema_disass/ida/exception.py deleted file mode 100644 index ea88b9476..000000000 --- a/tools/mcsema_disass/ida/exception.py +++ /dev/null @@ -1,553 +0,0 @@ -#!/usr/bin/env python - -# Copyright (c) 2017 Trail of Bits, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import idautils -import idaapi -import idc -import sys -import os -import argparse -import struct -import traceback -import collections -import itertools -import pprint - -from collections import namedtuple -# Bring in utility libraries. -from util import * - -frame_entry = namedtuple('frame_entry', ['cs_start', 'cs_end', 'cs_lp', 'cs_action', 'action_list']) -_FUNC_UNWIND_FRAME_EAS = set() - -_EXCEPTION_BLOCKS_EAS = dict() - -DW_EH_PE_ptr = 0x00 -DW_EH_PE_uleb128 = 0x01 -DW_EH_PE_udata2 = 0x02 -DW_EH_PE_udata4 = 0x03 -DW_EH_PE_udata8 = 0x04 -DW_EH_PE_signed = 0x08 -DW_EH_PE_sleb128 = 0x09 -DW_EH_PE_sdata2 = 0x0A -DW_EH_PE_sdata4 = 0x0B -DW_EH_PE_sdata8 = 0x0C - -DW_EH_PE_absptr = 0x00 -DW_EH_PE_pcrel = 0x10 -DW_EH_PE_textrel = 0x20 -DW_EH_PE_datarel = 0x30 -DW_EH_PE_funcrel = 0x40 -DW_EH_PE_aligned = 0x50 -DW_EH_PE_indirect = 0x80 -DW_EH_PE_omit = 0xFF - -class EHBlocks(object): - def __init__(self, start_ea, end_ea): - self.start_ea = start_ea - self.end_ea = end_ea - -def make_array(ea, size): - if ea != idc.BADADDR and ea != 0: - flags = idc.GetFlags(ea) - if not idc.isByte(flags) or idc.ItemSize(ea) != 1: - idc.MakeUnknown(ea, 1, idc.DOUNK_SIMPLE) - idc.MakeByte(ea) - idc.MakeArray(ea, size) - -def read_string(ea): - s = idc.GetString(ea, -1, idc.ASCSTR_C) - if s: - slen = len(s)+1 - idc.MakeUnknown(ea, slen, idc.DOUNK_SIMPLE) - idaapi.make_ascii_string(ea, slen, idc.ASCSTR_C) - return s, ea + slen - else: - return s, ea - -def read_uleb128(ea): - return read_leb128(ea, False) - -def read_sleb128(ea): - return read_leb128(ea, True) - -def enc_size(enc): - """ Read encoding size - """ - fmt = enc & 0x0F - if fmt == DW_EH_PE_ptr: - return get_address_size_in_bytes() - elif fmt in [DW_EH_PE_sdata2, DW_EH_PE_udata2]: - return 2 - elif fmt in [DW_EH_PE_sdata4, DW_EH_PE_udata4]: - return 4 - elif fmt in [DW_EH_PE_sdata8, DW_EH_PE_udata8]: - return 8 - elif fmt != DW_EH_PE_omit: - DEBUG("Encoding {0:x} is not of fixed size".format(enc)) - return 0 - -def read_enc_value(ea, enc): - """ Read encoded value - """ - if enc == DW_EH_PE_omit: - DEBUG("Error in read_enc_val {0:x}".format(ea)) - return idc.BADADDR, idc.BADADDR - - start = ea - fmt, mod = enc&0x0F, enc&0x70 - - if fmt == DW_EH_PE_ptr: - val = read_pointer(ea) - ea += get_address_size_in_bytes() - - elif fmt in [DW_EH_PE_uleb128, DW_EH_PE_sleb128]: - val, ea = read_leb128(ea, fmt == DW_EH_PE_sleb128) - if ea - start > 1: - make_array(start, ea - start) - - elif fmt in [DW_EH_PE_sdata2, DW_EH_PE_udata2]: - val = read_word(ea) - ea += 2 - if fmt == DW_EH_PE_sdata2: - val = sign_extend(val, 16) - - elif fmt in [DW_EH_PE_sdata4, DW_EH_PE_udata4]: - val = read_dword(ea) - ea += 4 - if fmt == DW_EH_PE_sdata4: - val = sign_extend(val, 32) - - elif fmt in [DW_EH_PE_sdata8, DW_EH_PE_udata8]: - val = read_qword(ea) - ea += 8 - if f == DW_EH_PE_sdata8: - val = sign_extend(val, 64) - - else: - DEBUG("{0:x}: don't know how to handle {1:x}".format(start, enc)) - return idc.BADADDR, idc.BADADDR - - if mod == DW_EH_PE_pcrel: - if val != 0: - val += start - val &= (1<<(get_address_size_in_bits())) - 1 - - elif mod != DW_EH_PE_absptr: - DEBUG("{0:x}: don't know how to handle {1:x}".format(start, enc)) - return BADADDR, BADADDR - - if (enc & DW_EH_PE_indirect) and val != 0: - if not idc.isLoaded(val): - DEBUG("{0:x}: dereference invalid pointer {1:x}".format(start, val)) - return idc.BADADDR, idc.BADADDR - val = read_pointer(val) - - return val, ea - -def _create_frame_entry(start = None, end = None, lp = None, action = None, act_list = None): - return frame_entry(start, end, lp, action, act_list) - -def format_lsda_actions(action_tbl, act_ea, type_addr, type_enc, act_id): - """ Recover the exception actions and type info - """ - action_list = [] - if action_tbl == idc.BADADDR: - return - - DEBUG("start action ea : {:x}".format(act_ea)) - while True: - ar_filter,ea2 = read_enc_value(act_ea, DW_EH_PE_sleb128) - ar_disp, ea3 = read_enc_value(ea2, DW_EH_PE_sleb128) - - if ar_filter > 0: - type_slot = type_addr - ar_filter * enc_size(type_enc) - type_ea, eatmp = read_enc_value(type_slot, type_enc) - DEBUG("catch type typeinfo = {:x} {} {}".format(type_ea, get_symbol_name(type_ea), ar_filter)) - action_list.append((ar_disp, ar_filter, type_ea)) - - #DEBUG(" format_lsda_actions ea {:x}: ar_disp[{}]: {} ({:x})".format(act_ea, act_id, ar_disp, ar_filter)) - if ar_disp == 0: - break - - act_ea = ea2 + ar_disp - - return action_list - -def create_block_entries(start_ea, heads): - index = 0 - block_set = set() - for entry in heads: - if entry == 0: - continue - - if index < len(heads) - 1: - ea = heads[index] - while heads[index] <= ea < heads[index + 1]: - inst, _ = decode_instruction(ea) - if not inst: - break - block = EHBlocks(ea, ea + inst.size) - ea = ea + inst.size - block_set.add(block) - index = index + 1 - - _EXCEPTION_BLOCKS_EAS[start_ea] = block_set - -def format_lsda(lsda_ptr, start_ea, range = None, sjlj = False): - """ Recover the language specific data area - """ - lsda_entries = list() - heads = set() - lpstart_enc, ea = read_byte(lsda_ptr), lsda_ptr + 1 - if lpstart_enc != DW_EH_PE_omit: - lpstart, next_ea = read_enc_value(ea, lpstart_enc) - ea = next_ea - else: - lpstart = start_ea - - # get the type encoding and type address associated with the exception handling blocks - type_enc, ea = read_byte(ea), ea + 1 - type_addr = idc.BADADDR - - if type_enc != DW_EH_PE_omit: - type_off, next_ea = read_enc_value(ea, DW_EH_PE_uleb128) - type_addr = next_ea + type_off - ea = next_ea - - cs_enc, next_ea = read_byte(ea), ea + 1 - ea = next_ea - cs_len, next_ea = read_enc_value(ea, DW_EH_PE_uleb128) - action_tbl = next_ea + cs_len - ea = next_ea - - i = 0 - actions = [] - action_list = [] - while ea < action_tbl: - if sjlj: - cs_lp, next_ea = read_enc_val(ea, DW_EH_PE_uleb128, True) - act_ea = next_ea - cs_action, next_ea = read_enc_value(next_ea, DW_EH_PE_uleb128) - DEBUG("ea {:x}: cs_lp[{}] = {}".format(ea, i, cs_lp)) - ea = next_ea - else: - cs_start, next_ea = read_enc_value(ea, cs_enc) - cs_start += lpstart - DEBUG("ea {:x}: cs_start[{}] = {:x} ({})".format(ea, i, cs_start, get_symbol_name(start_ea))) - ea = next_ea - heads.add(cs_start) - - cs_len, next_ea = read_enc_value(ea, cs_enc & 0x0F) - cs_end = cs_start + cs_len - DEBUG("ea {:x}: cs_len[{:x}] = {} (end = {:x})".format(ea, i, cs_len, cs_start + cs_len)) - ea = next_ea - heads.add(cs_end) - - cs_lp, next_ea = read_enc_value(ea, cs_enc) - cs_lp = cs_lp + lpstart if cs_lp != 0 else cs_lp - act_ea = next_ea - DEBUG("ea {:x}: cs_lp[{}] = {:x}".format(ea, i, cs_lp)) - ea = next_ea - heads.add(cs_lp) - - cs_action, next_ea = read_enc_value(ea, DW_EH_PE_uleb128) - ea = next_ea - - if cs_action != 0: - actions.append(cs_action) - - DEBUG_PUSH() - DEBUG("Landing pad for {0:x}..{1:x}".format(cs_start, cs_start + cs_len)) - DEBUG_POP() - - if cs_action != 0: - action_offset = action_tbl + cs_action - 1 - action_list = format_lsda_actions(action_tbl, action_offset, type_addr, type_enc, cs_action) - - lsda_entries.append(_create_frame_entry(cs_start, cs_start + cs_len, cs_lp, cs_action, action_list)) - - DEBUG("ea {:x}: cs_action[{}] = {}".format(act_ea, i, cs_action)) - i += 1 - - create_block_entries(start_ea, sorted(heads)) - FUNC_LSDA_ENTRIES[start_ea] = lsda_entries - -class AugmentationData: - def __init__(self): - self.aug_present = False - self.lsda_encoding = DW_EH_PE_omit - self.personality_ptr = None - self.fde_encoding = DW_EH_PE_absptr - -class EHRecord: - def __init__(self): - self.type = "" - self.version = None - self.data = None - self.aug_string = "" - self.code_align = None - self.data_align = None - self.retn_reg = None - -_AUGM_PARAM = dict() - -def format_entries(ea): - """ Check the types of entries CIE/FDE recover them - """ - start_ea = ea - size, ea = read_dword(ea), ea + 4 - if size == 0: - return idc.BADADDR - - end_ea = ea + size - entry = EHRecord() - - cie_id, ea = read_dword(ea), ea + 4 - is_cie = cie_id == 0 - entry.type = ["FDE", "CIE"][is_cie] - #DEBUG("ea {0:x}: type {1} size {2}".format(start_ea, entry.type, size)) - - if is_cie: - entry.version, ea = read_byte(ea), ea + 1 - entry.aug_string, ea = read_string(ea) - if entry.aug_string is None: - return end_ea - - entry.code_align, ea = read_uleb128(ea) - entry.data_align, ea = read_uleb128(ea) - if entry.version == 1: - entry.retn_reg, ea = read_byte(ea), ea + 1 - else: - entry.retn_reg, ea = read_uleb128(ea) - - aug_data = AugmentationData() - - if entry.aug_string[0:1]=='z': - aug_len, ea = read_uleb128(ea) - aug_data.aug_present = True - - for s in entry.aug_string[1:]: - if s == 'L': - aug_data.lsda_encoding, ea = read_byte(ea), ea + 1 - elif s == 'P': - enc, ea = read_byte(ea), ea + 1 - aug_data.personality_ptr, ea2 = read_enc_value(ea, enc) - #DEBUG("ea {0:x}: personality function {1:x}".format(ea, aug_data.personality_ptr)) - ea = ea2 - elif s == 'R': - aug_data.fde_encoding, ea = read_byte(ea), ea + 1 - else: - #DEBUG("ea {0:x}: unhandled string char {1}".format(ea, s)) - return idc.BADADDR - - _AUGM_PARAM[start_ea] = aug_data - - else: - base_ea = ea - 4 - cie_ea = base_ea - cie_id - if cie_ea in _AUGM_PARAM: - aug_data = _AUGM_PARAM[cie_ea] - else: - return idc.BADADDR - - pc_begin, ea2 = read_enc_value(ea, aug_data.fde_encoding) - #DEBUG("ea {0:x}: CIE pointer".format(base_ea)) - #DEBUG("ea {0:x}: PC begin={1:x}".format(ea, pc_begin)) - - ea = ea2 - range_len, ea2 = read_enc_value(ea, aug_data.fde_encoding & 0x0F) - #DEBUG("ea {:x}: PC range = {:x} (PC end={:x})".format(ea, range_len, range_len + pc_begin)) - - if range_len: - _FUNC_UNWIND_FRAME_EAS.add((pc_begin, range_len)) - - ea = ea2 - if aug_data.aug_present: - aug_len, ea = read_uleb128(ea) - if aug_data.lsda_encoding != DW_EH_PE_omit: - lsda_ptr, ea2 = read_enc_value(ea, aug_data.lsda_encoding) - #DEBUG("ea {0:x}: LSDA pointer {1:x}".format(ea, lsda_ptr)) - DEBUG_PUSH() - if lsda_ptr: - format_lsda(lsda_ptr, pc_begin, range_len, False) - DEBUG_POP() - - return end_ea - -def recover_frame_entries(seg_ea): - if seg_ea == idc.BADADDR: - return - - DEBUG("Recover entries from section : {}".format(idc.SegName(seg_ea))) - ea = idc.SegStart(seg_ea) - end_ea = idc.SegEnd(seg_ea) - while ea != idc.BADADDR and ea < end_ea: - ea = format_entries(ea) - -def recover_exception_table(): - """ Recover the CIE and FDE entries from the segment .eh_frame - """ - seg_eas = [ea for ea in idautils.Segments() if not is_invalid_ea(ea)] - - for seg_ea in seg_eas: - seg_name = idc.SegName(seg_ea) - if seg_name in [".eh_frame", "__eh_frame"]: - recover_frame_entries(seg_ea) - break - - recover_rtti() - -def recover_exception_entries(F, func_ea): - has_unwind_frame = func_ea in FUNC_LSDA_ENTRIES.keys() - if has_unwind_frame: - lsda_entries = FUNC_LSDA_ENTRIES[func_ea] - - for entry in lsda_entries: - EH = F.eh_frame.add() - EH.func_ea = func_ea - EH.start_ea = entry.cs_start - EH.end_ea = entry.cs_end - EH.lp_ea = entry.cs_lp - EH.action = entry.cs_action != 0 - - for ar_disp, ar_filter, type_ea in entry.action_list: - AC = EH.ttype.add() - AC.ea = type_ea - AC.name = get_symbol_name(type_ea) - AC.size = ar_filter - AC.is_weak = False - AC.is_thread_local = False - -def fix_function_bounds(min_ea, max_ea): - for func_ea, range in _FUNC_UNWIND_FRAME_EAS: - if func_ea == min_ea: - return func_ea, func_ea + range - return min_ea, max_ea - -def get_exception_landingpad(F, insn_ea): - has_lp = F.ea in FUNC_LSDA_ENTRIES.keys() - if has_lp: - lsda_entries = FUNC_LSDA_ENTRIES[F.ea] - for entry in lsda_entries: - if insn_ea >= entry.cs_start and insn_ea < entry.cs_end: - return entry.cs_lp - return 0 - -def get_exception_chunks(sub_ea): - has_block = sub_ea in _EXCEPTION_BLOCKS_EAS.keys() - if has_block: - block_set = _EXCEPTION_BLOCKS_EAS[sub_ea] - for block in block_set: - yield block.start_ea, block.end_ea - - -""" Recover the RTTI information which can't be detected by IDA 6.9 -""" - -typeinfo_names = [ - "_ZTVSt9type_info", - "_ZTVN10__cxxabiv117__class_type_infoE", - "_ZTVN10__cxxabiv120__si_class_type_infoE", - "_ZTVN10__cxxabiv121__vmi_class_type_infoE", -] - -EXTERNAL_NAMES = ("@@GLIBCXX_", "@@CXXABI_") - -def get_stripped_name(name): - for en in EXTERNAL_NAMES: - if en in name: - name = name[:name.find(en)] - return name - -def _create_reference_object(name, ea, offset): - return dict(name=name, addr=ea, offset=offset) - -def get_alternative_symbol_name(ea): - comment = idc.GetCommentEx(ea, 0) or "" - for comment_line in comment.split("\n"): - comment_line = comment_line.replace(";", "").strip() - if not comment_line: - continue - mstr = comment_line.split("'") - if 3 <= len(mstr): - return mstr[1] + "'" + mstr[2] - return None - -def convert_to_bytes(value): - is64 = get_address_size_in_bytes() == 8 - if is64: - sv = struct.pack(" ea else 0 - RTTI_REFERENCE_TABLE[x] = _create_reference_object(name, ea, offset) - ea3 = get_si_type_info(x) - -def recover_rtti(): - for index, ordinal, ea, name in idautils.Entries(): - if get_stripped_name(name) in typeinfo_names: - get_typeinfo_refs(name, ea) diff --git a/tools/mcsema_disass/ida/flow.py b/tools/mcsema_disass/ida/flow.py deleted file mode 100644 index de5ffd284..000000000 --- a/tools/mcsema_disass/ida/flow.py +++ /dev/null @@ -1,343 +0,0 @@ -# Copyright (c) 2017 Trail of Bits, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from table import * -from exception import * -from refs import * - -# Addresses of the first instruction in a function. -_FUNC_HEAD_EAS = set() - -# Addresses of the first instruction in a block. -_BLOCK_HEAD_EAS = set() - -# Set of initially discovered block entrypoint addresses for each function -# as discovered by IDA's initial auto-analysis. -_DEFAULT_BLOCK_HEAD_EAS = {} - -# Addresses of instructions that terminate a basic block. -_TERMINATOR_EAS = set() - -# Instruction bytes that are used for alignment. In this case, an x86 NOP. -_ALIGNMENT_BYTES = set([0x90]) - -# Maps subroutine addresses to sets of block that are not targeted by any -# flows. We use this as an opportunistic way of handling jump tables that -# IDA does not understand. They are not handled directly as jump tables, -# rather they get handled as code cross-references. -_MISSING_FLOWS = collections.defaultdict(set) - -# Mark an address as being the beginning of a function. -def try_mark_as_function(address): - global _FUNC_HEAD_EAS, _BLOCK_HEAD_EAS - - _FUNC_HEAD_EAS.add(address) - _BLOCK_HEAD_EAS.add(address) - - if not idaapi.add_func(address, idc.BADADDR): - return False - - idaapi.autoWait() - return True - -def find_linear_terminator(ea, max_num=256): - """Find the terminating instruction of a basic block, without actually - associating the instructions with the block. This scans linearly until - we find something that is definitely a basic block terminator. This does - not consider the case of intermediate blocks.""" - global _BLOCK_HEAD_EAS, _TERMINATOR_EAS - - prev_term = None - term_ea = ea - for i in xrange(max_num): - term_inst, inst_bytes = decode_instruction(ea) - if not term_inst: - # TODO(pag): Log that we couldn't decode. - term_inst = prev_term - break - - term_ea = ea - prev_term = term_inst - if ea in _TERMINATOR_EAS or instruction_ends_block(term_inst): - break - - ea += len(inst_bytes) - - # The next instruction was already processed as part of some other scan. - if ea in _BLOCK_HEAD_EAS: - break - - if term_inst: - _TERMINATOR_EAS.add(term_ea) - - return term_inst, inst_bytes - -def get_direct_branch_target(arg): - """Tries to 'force' get the target of a direct or conditional branch. - IDA can't always get code refs for flows from an instruction that appears - inside another instruction (and so even seen by IDA in the first place).""" - if not isinstance(arg, (int, long)): - branch_inst_ea = arg.ea - else: - branch_inst_ea = arg - try: - branch_flows = tuple(idautils.CodeRefsFrom(branch_inst_ea, False)) - return branch_flows[0] - except: - decoded_inst, _ = decode_instruction(branch_inst_ea) - target_ea = decoded_inst.Op1.addr - #log.warning("Determined target of {:08x} to be {:08x}".format( - # branch_inst_ea, target_ea)) - return target_ea - -def is_noreturn_inst(arg): - """Returns `True` if the instruction `arg`, or at `arg`, will terminate - control flow.""" - inst = arg - if isinstance(arg, (int, long)): - inst, _ = decode_instruction(arg) - - if is_direct_function_call(inst) or is_direct_jump(inst): - called_ea = get_direct_branch_target(inst.ea) - return is_noreturn_function(called_ea) - - return inst.itype in (idaapi.NN_int3, idaapi.NN_icebp, idaapi.NN_hlt) - -def get_static_successors(sub_ea, inst, binary_is_pie): - """Returns the statically known successors of an instruction.""" - - branch_flows = tuple(idautils.CodeRefsFrom(inst.ea, False)) - next_ea = inst.ea + inst.size - # Direct function call. The successor will be the fall-through instruction - # unless the target of the function call looks like a `noreturn` function. - if is_direct_function_call(inst): - if not is_noreturn_function(get_direct_branch_target(inst.ea)): - yield next_ea # Not recognised as a `noreturn` function. - - if is_function_call(inst): # Indirect function call, system call. - yield next_ea - - elif is_conditional_jump(inst): - yield next_ea - yield get_direct_branch_target(inst.ea) - - elif is_direct_jump(inst): - yield get_direct_branch_target(inst.ea) - - elif is_indirect_jump(inst): - table = get_jump_table(inst, binary_is_pie) - target_eas = set(idautils.CodeRefsFrom(inst.ea, True)) - if table: - for target_ea in table.entries.values(): - target_eas.add(target_ea) - - # Opportunistically add more flows to this instruction if it seems like - # there are any blocks in the function with no predecessors. - if not len(target_eas) and sub_ea in _MISSING_FLOWS: - missing_flows = _MISSING_FLOWS[sub_ea] - for target_ea in missing_flows: - if not has_flow_to_code(target_ea): - DEBUG("Assuming that jump at {:x} targets block {:x} with missing flow.") - idc.AddCodeXref(inst.ea, target_ea, idc.XREF_USER | idc.fl_JN) - target_eas.add(target_ea) - - for target_ea in target_eas: - yield target_ea - - elif not is_control_flow(inst): - if not is_noreturn_inst(inst): - yield next_ea - -_BAD_BLOCK = (tuple(), set()) - -def analyse_block(func_ea, ea, binary_is_pie=False): - """Find the instructions of a basic block.""" - global _BLOCK_HEAD_EAS, _TERMINATOR_EAS, _FUNC_HEAD_EAS - - if not is_code(ea): - DEBUG("ERROR: Block at {:x} in function {:x} is not code".format(ea, func_ea)) - return _BAD_BLOCK - - inst_eas = [] - insts = [] - seen = set() - - next_ea = ea - while is_code(next_ea) and next_ea not in seen: - seen.add(next_ea) - inst, _ = decode_instruction(next_ea) - if not inst: - break - - inst_eas.append(next_ea) - insts.append(inst) - - if next_ea in _TERMINATOR_EAS or instruction_ends_block(inst): - break - - next_ea = inst.ea + inst.size - if next_ea in _BLOCK_HEAD_EAS: - break - - successors = [] - if inst_eas: - _TERMINATOR_EAS.add(inst_eas[-1]) - successors = get_static_successors(func_ea, insts[-1], binary_is_pie) - successors = [succ for succ in successors if is_code(succ)] - - return (inst_eas, set(successors)) - -def find_default_block_heads(sub_ea): - """Pre-process a function by finding all the recognized block head EAs - before we dig deeper into individual blocks.""" - global _BLOCK_HEAD_EAS, _FUNC_HEAD_EAS, _DEFAULT_BLOCK_HEAD_EAS - global _ALIGNMENT_BYTES - - if sub_ea in _DEFAULT_BLOCK_HEAD_EAS: - return _DEFAULT_BLOCK_HEAD_EAS[sub_ea] - - _FUNC_HEAD_EAS.add(sub_ea) - heads = set([sub_ea]) - - seg_start, seg_end = idc.SegStart(sub_ea), idc.SegEnd(sub_ea) - min_ea, max_ea = get_function_bounds(sub_ea) - - DEBUG("Default block heads for function {:x} with loose bounds [{:x}, {:x})".format( - sub_ea, min_ea, max_ea)) - - f = idaapi.get_func(sub_ea) - if f: - for b in idaapi.FlowChart(f): - if min_ea <= b.startEA < max_ea: - _BLOCK_HEAD_EAS.add(b.startEA) - heads.add(b.startEA) - DEBUG(" block [{:x}, {:x})".format(b.startEA, b.endEA)) - - for chunk_start_ea, chunk_end_ea in idautils.Chunks(sub_ea): - _BLOCK_HEAD_EAS.add(chunk_start_ea) - heads.add(chunk_start_ea) - DEBUG(" chunk [{:x}, {:x})".format(chunk_start_ea, chunk_end_ea)) - - for eh_start_ea, eh_end_ea in get_exception_chunks(sub_ea): - _BLOCK_HEAD_EAS.update([eh_start_ea, eh_end_ea]) - heads.update([eh_start_ea, eh_end_ea]) - DEBUG(" exception chunks [{:x}, {:x})".format(eh_start_ea, eh_end_ea)) - - # Look for possibly good jump table target candidates. We will use this - # information in `get_static_successors` when we come across an indirect - # jump with no known targets (i.e. not a jump table). In that case, we - # assert that the untargeted code (if still not targeted) are candidate - # targets for the instruction. - if max_ea: - ea = sub_ea - while min_ea <= ea < max_ea and ea != idc.BADADDR: - if ea not in _BLOCK_HEAD_EAS \ - and 16 < idaapi.get_alignment(ea) \ - and read_byte(ea) not in _ALIGNMENT_BYTES \ - and not has_flow_to_code(ea): - if is_data_reference(ea): - DEBUG(" {:x} in function {:x} looks like an embedded jump table entry".format( - ea, sub_ea)) - else: - DEBUG(" block {:x} of function {:x} is not targeted by any flows!".format( - ea, sub_ea)) - - _MISSING_FLOWS[sub_ea].add(ea) - ea = idc.NextHead(ea, max_ea) - - - _DEFAULT_BLOCK_HEAD_EAS[sub_ea] = heads - - return heads - -_FUNCTION_BLOCK_HEAD_EAS = {} - -def analyse_subroutine(sub_ea, binary_is_pie): - """Goes through the basic blocks of an identified function. Returns a set - of basic block heads in the function, as well as block terminator - instructions.""" - global _BLOCK_HEAD_EAS, _FUNC_HEAD_EAS, _FUNCTION_BLOCK_HEAD_EAS - - if sub_ea in _FUNCTION_BLOCK_HEAD_EAS: - return _FUNCTION_BLOCK_HEAD_EAS[sub_ea] - - sub_name = get_symbol_name(sub_ea, allow_dummy=True) - DEBUG("Analysing subroutine {} at {:x}".format(sub_name, sub_ea)) - block_head_eas = find_default_block_heads(sub_ea) - term_insts = set() - - # Iteratively scan for block heads. This will do linear sweeps looking for - # block terminators. These linear sweeps do not consider flows incoming - # flows from existing blocks that logically split a block into two. - found_block_eas = set() - seen_blocks = set() - while len(block_head_eas): - block_head_ea = block_head_eas.pop() - if block_head_ea in seen_blocks: - continue - - was_seen_before = block_head_ea in _BLOCK_HEAD_EAS - is_func_entry = block_head_ea in _FUNC_HEAD_EAS - - seen_blocks.add(block_head_ea) - - # The exception handling blocks are not identified as code with tight checks - if not is_code(block_head_ea): #is_code_by_flags(block_head_ea): - DEBUG(" Block head at {:08x} is not code.".format(block_head_ea)) - found_block_eas.discard(block_head_ea) - continue - - found_block_eas.add(block_head_ea) - _BLOCK_HEAD_EAS.add(block_head_ea) - - # Try to make sure that analysis will terminate if we accidentally - # walk through a noreturn call. - if block_head_ea != sub_ea and is_func_entry: - found_block_eas.remove(block_head_ea) - continue - - #log.debug("Found block head at {:08x}".format(block_head_ea)) - term_inst, inst_bytes = find_linear_terminator(block_head_ea) - if not term_inst: - DEBUG(" Block at {:x} has no terminator!".format(block_head_ea)) - found_block_eas.remove(block_head_ea) - continue - - elif term_inst.ea != sub_ea and term_inst.ea in _FUNC_HEAD_EAS: - found_block_eas.remove(block_head_ea) - continue - - term_insts.add(term_inst) - - # Check the instruction next to term_instr for recovery, if it has missing flow - # IDA heuristics misses the landing pad and exception blocks in some cases; Linear - # scan identifies the missing blocks and recover them - next_ea = term_inst.ea + len(inst_bytes) - if next_ea not in _FUNC_HEAD_EAS and next_ea not in _BLOCK_HEAD_EAS: - block_head_eas.add(next_ea) - - #log.debug("Linear terminator of {:08x} is {:08x}".format( - # block_head_ea, term_inst.ea)) - - for succ_ea in get_static_successors(sub_ea, term_inst, binary_is_pie): - if succ_ea not in _FUNC_HEAD_EAS or succ_ea == sub_ea: - block_head_eas.add(succ_ea) - - DEBUG("Subroutine {} at {:x} has {} blocks".format( - sub_name, sub_ea, len(found_block_eas))) - - # Analyse the blocks - ret = found_block_eas, term_insts - _FUNCTION_BLOCK_HEAD_EAS[sub_ea] = ret - return ret diff --git a/tools/mcsema_disass/ida/get_cfg.py b/tools/mcsema_disass/ida/get_cfg.py deleted file mode 100755 index e12cbc704..000000000 --- a/tools/mcsema_disass/ida/get_cfg.py +++ /dev/null @@ -1,1655 +0,0 @@ -#!/usr/bin/env python - -# Copyright (c) 2017 Trail of Bits, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import idautils -import idaapi -import idc -import sys -import os -import argparse -import struct -import traceback -import collections -import itertools -import pprint - -# Bring in utility libraries. -from util import * -from table import * -from flow import * -from refs import * -from segment import * -from collect_variable import * -from exception import * - -#hack for IDAPython to see google protobuf lib -if os.path.isdir('/usr/lib/python2.7/dist-packages'): - sys.path.append('/usr/lib/python2.7/dist-packages') - -if os.path.isdir('/usr/local/lib/python2.7/dist-packages'): - sys.path.append('/usr/local/lib/python2.7/dist-packages') - -tools_disass_ida_dir = os.path.dirname(__file__) -tools_disass_dir = os.path.dirname(tools_disass_ida_dir) - -# Note: The bootstrap file will copy CFG_pb2.py into this dir!! -import CFG_pb2 - -EXTERNAL_FUNCS_TO_RECOVER = {} -EXTERNAL_VARS_TO_RECOVER = {} - -RECOVERED_EAS = set() -ACCESSED_VIA_JMP = set() - -TO_RECOVER = { - "stack_var" : False, -} - -RECOVER_EHTABLE = False - -PERSONALITY_FUNCTIONS = [ - "__gxx_personality_v0", - "__gnat_personality_v0" - ] - -# Map of external functions names to a tuple containing information like the -# number of arguments and calling convention of the function. -EMAP = {} - -# Map of external variable names to their sizes, in bytes. -EMAP_DATA = {} - -# `True` if we are getting the CFG of a position independent executable. This -# affects heuristics like trying to turn immediate operands in instructions -# into references into the data. -PIE_MODE = False - -# Name of the operating system that runs the program being lifted. E.g. if -# we're lifting an ELF then this will typically be `linux`. -OS_NAME = "" - -# Set of substrings that can be found inside of symbol names that are usually -# signs that the symbol is external. For example, `stderr@@GLIBC_2.2.5` is -# really the external `stderr`, so we want to be able to chop out the `@@...` -# part to resolve the "true" name. There are a lot of `@@` variants in PE files, -# e.g. `@@QEAU_..`, `@@AEAV..`, though these are likely for name mangling. -EXTERNAL_NAMES = ("@@GLIBC_", "@@GLIBCXX_", "@@CXXABI_", "@@GCC_") - -_NOT_ELF_BEGIN_EAS = (0xffffffffL, 0xffffffffffffffffL) - -# Returns `True` if this is an ELF binary (as opposed to an ELF object file). -def is_linked_ELF_program(): - global _NOT_ELF_BEGIN_EAS - return IS_ELF and idc.BeginEA() not in _NOT_ELF_BEGIN_EAS - -def is_ELF_got_pointer(ea): - """Returns `True` if this is a pointer to a pointer stored in the - `.got` section of an ELF binary. For example, `__gmon_start___ptr` is - a pointer in the `.got` that will be fixed up to contain the address of - the external function `__gmon_start__`. We don't want to treat - `__gmon_start___ptr` as external because it is really a sort of local - variable that will will resolve with a data cross-reference.""" - seg_name = idc.SegName(ea).lower() - if ".got" not in seg_name: - return False - - name = get_symbol_name(ea) - target_ea = get_reference_target(ea) - target_name = get_true_external_name(get_symbol_name(target_ea)) - - if target_name not in name: - return False - - return is_referenced_by(target_ea, ea) - -def is_ELF_got_pointer_to_external(ea): - """Similar to `is_ELF_got_pointer`, but requires that the eventual target - of the pointer is an external.""" - if not is_ELF_got_pointer(ea): - return False - - target_ea = get_reference_target(ea) - return is_external_segment(target_ea) - -_FIXED_EXTERNAL_NAMES = {} - -def demangled_name(name): - """Tries to demangle a functin name.""" - try: - dname = idc.Demangle(name, idc.GetLongPrm(INF_SHORT_DN)) - if dname and len(dname) and "::" not in dname: - dname = dname.split("(")[0] - dname = dname.split(" ")[-1] - if re.match(r"^[a-zA-Z0-9_]+$", dname): - return dname - return name - except: - return name - -def get_true_external_name(fn, demangle=True): - """Tries to get the 'true' name of `fn`. This removes things like - ELF-versioning from symbols.""" - if not fn: - return "" - - orig_fn = fn - if fn in _FIXED_EXTERNAL_NAMES: - return _FIXED_EXTERNAL_NAMES[orig_fn] - - if fn in EMAP: - return fn - - if fn in EMAP_DATA: - return fn - - # Try to demangle the name, but don't do it if looks like there's a C++ - # namespace. - if demangle: - fn = demangled_name(fn) - - # TODO(pag): Is this a macOS or Windows thing? - if not is_linked_ELF_program() and fn[0] == '_': - return fn[1:] - - if fn.endswith("_0"): - newfn = fn[:-2] - if newfn in EMAP: - return newfn - - # Go and strip off things like the `@@GLIBC_*` symbol suffixes. - for en in EXTERNAL_NAMES: - if en in fn: - fn = fn[:fn.find(en)] - break - - if orig_fn != fn: - DEBUG("True name of {} is {}".format(orig_fn, fn)) - - _FIXED_EXTERNAL_NAMES[orig_fn] = fn - return fn - -# Set of symbols that IDA identifies as being "weak" symbols. In ELF binaries, -# a weak symbol is kind of an optional linking thing. For example, the -# `__gmon_start__` function is referenced as a weak symbol. This function is -# used for gcov-based profiling. If gcov is available, then this symbol will -# be resolved to a real function, but if not, it will be NULL and programs -# will detect it as such. An example use of a weak symbol in C would be: -# -# extern void __gmon_start__(void) __attribute__((weak)); -# ... -# if (__gmon_start__) { -# __gmon_start__(); -# } -WEAK_SYMS = set() - -# Used to track thunks that are actually implemented. For example, in a static -# binary, you might have a bunch of calls to `strcpy` in the `.plt` section -# that go through the `.plt.got` to call the implementation of `strcpy` compiled -# into the binary. -INTERNALLY_DEFINED_EXTERNALS = {} # Name external to EA of internal. -INTERNAL_THUNK_EAS = {} # EA of thunk to EA of implementation. - -def parse_os_defs_file(df): - """Parse the file containing external function and variable - specifications.""" - global OS_NAME, WEAK_SYMS, EMAP, EMAP_DATA - global _FIXED_EXTERNAL_NAMES, INTERNALLY_DEFINED_EXTERNALS - - is_linux = OS_NAME == "linux" - for l in df.readlines(): - #skip comments / empty lines - l = l.strip() - if not l or l[0] == "#": - continue - - if l.startswith('DATA:'): - # process as data - (marker, symname, dsize) = l.split() - if 'PTR' in dsize: - dsize = get_address_size_in_bytes() - - EMAP_DATA[symname] = int(dsize) - - else: - fname = args = conv = ret = sign = None - line_args = l.split() - - if len(line_args) == 4: - (fname, args, conv, ret) = line_args - elif len(line_args) == 5: - (fname, args, conv, ret, sign) = line_args - - if conv == "C": - realconv = CFG_pb2.ExternalFunction.CallerCleanup - elif conv == "E": - realconv = CFG_pb2.ExternalFunction.CalleeCleanup - elif conv == "F": - realconv = CFG_pb2.ExternalFunction.FastCall - else: - DEBUG("ERROR: Unknown calling convention: {}".format(l)) - continue - - if ret not in "YN": - DEBUG("ERROR: Unknown return type {} in {}".format(ret, l)) - continue - - ea = idc.LocByName(fname) - - if not is_invalid_ea(ea): - if not is_external_segment(ea) and not is_thunk(ea): - DEBUG("Not treating {} as external, it is defined at {:x}".format( - fname, ea)) - INTERNALLY_DEFINED_EXTERNALS[fname] = ea - continue - - # Misidentified and external. This comes up often in PE binaries, for - # example, we will have the following: - # - # .idata:01400110E8 ; void __stdcall EnterCriticalSection(...) - # .idata:01400110E8 extrn EnterCriticalSection:qword - # - # Really, we want to try this as code. - flags = idc.GetFlags(ea) - if not idc.isCode(flags) and not idaapi.is_weak_name(ea): - seg_name = idc.SegName(ea).lower() - if ".idata" in seg_name: - EXTERNAL_FUNCS_TO_RECOVER[ea] = fname - - # Refer to issue #308 - else: - DEBUG("WARNING: External {} at {:x} from definitions file may not be a function".format( - fname, ea)) - - EMAP[fname] = (int(args), realconv, ret, sign) - if ret == 'Y': - noreturn_external_function(fname, int(args), realconv, ret, sign) - - # Sometimes there will be things like `__imp___gmon_start__` which - # is really the implementation of `__gmon_start__`, where that is - # a weak symbol. - if is_linux: - imp_name = "__imp_{}".format(fname) - - if idc.LocByName(imp_name): - _FIXED_EXTERNAL_NAMES[imp_name] = fname - WEAK_SYMS.add(fname) - WEAK_SYMS.add(imp_name) - - df.close() - -def is_external_reference(ea): - """Returns `True` if `ea` references external data.""" - return is_external_segment(ea) \ - or ea in EXTERNAL_VARS_TO_RECOVER \ - or ea in EXTERNAL_FUNCS_TO_RECOVER - -def get_function_name(ea): - """Return name of a function, as IDA sees it. This includes allowing - dummy names, e.g. `sub_abc123`.""" - return get_symbol_name(ea, ea, allow_dummy=True) - -def undecorate_external_name(fn): - # Don't mangle symbols for fully linked ELFs... yet - in_a_map = fn in EMAP or fn in EMAP_DATA - if not is_linked_ELF_program(): - if fn.startswith("__imp_"): - fn = fn[6:] - - if fn.endswith("_0"): - fn = fn[:-2] - - # name could have been modified by the above tests - in_a_map = fn in EMAP or fn in EMAP_DATA - - if fn.startswith("_") and not in_a_map: - fn = fn[1:] - - if fn.startswith("@") and not in_a_map: - fn = fn[1:] - - if IS_ELF and '@' in fn: - fn = fn[:fn.find('@')] - - fixfn = get_true_external_name(fn) - return fixfn - -_ELF_THUNKS = {} -_NOT_ELF_THUNKS = set() -_INVALID_THUNK = (False, idc.BADADDR, "") -_INVALID_THUNK_ADDR = (False, idc.BADADDR) - -def is_ELF_thunk_by_structure(ea): - """Try to manually identify an ELF thunk by its structure.""" - global _INVALID_THUNK_ADDR - - if ".plt" not in idc.SegName(ea).lower(): - return _INVALID_THUNK_ADDR - - # Scan through looking for a branch, either direct or indirect. - inst = None - for i in range(4): # 1 is good enough for x86, 4 for aarch64. - inst, _ = decode_instruction(ea) - if not inst: - return _INVALID_THUNK_ADDR - # elif is_direct_jump(inst): - # ea = get_direct_branch_target(inst) - # inst = None - elif is_indirect_jump(inst) or is_direct_jump(inst): - ea = inst.ea - break - else: - ea = inst.ea + inst.size - inst = None - - if not inst: - return _INVALID_THUNK_ADDR - - target_ea = get_reference_target(inst.ea) - if ".got.plt" == idc.SegName(target_ea).lower(): - target_ea = get_reference_target(target_ea) - - # For AArch64, the thunk structure is something like: - # .plt:000400470 .atoi - # .plt:000400470 ADRP X16, #off_411000@PAGE - # .plt:000400474 LDR X17, [X16,#off_411000@PAGEOFF] - # .plt:000400478 ADD X16, X16, #off_411000@PAGEOFF - # .plt:00040047C BR X17 ; atoi - # - # With: - # - # extern:000411070 ; int atoi(const char *nptr) - # extern:000411070 IMPORT atoi - - - # For x86, the thunk structure is something like: - # - # .plt:00041F10 _qsort proc near - # .plt:00041F10 jmp cs:off_31F388 - # .plt:00041F10 _qsort endp - # - # With: - # - # .got.plt:0031F388 off_31F388 dq offset qsort - # - # With - # extern:0031F388 ; void qsort(void *base, ...) - # extern:0031F388 extrn qsort:near - - if is_invalid_ea(target_ea): - return _INVALID_THUNK_ADDR - - return True, target_ea - -def is_thunk_by_flags(ea): - """Try to identify a thunk based off of the IDA flags. This isn't actually - specific to ELFs. - - IDA seems to have a kind of thunk-propagation. So if one thunk calls - another thunk, then the former thing is treated as a thunk. The former - thing will not actually follow the 'structured' form matched above, so - we'll try to recursively match to the 'final' referenced thunk.""" - global _INVALID_THUNK_ADDR - - if not is_thunk(ea): - return _INVALID_THUNK_ADDR - - ea_name = get_function_name(ea) - inst, _ = decode_instruction(ea) - if not inst: - DEBUG("WARNING: {} at {:x} is a thunk with no code??".format(ea_name, ea)) - return _INVALID_THUNK_ADDR - - # Recursively find thunk-to-thunks. - if is_direct_jump(inst) or is_direct_function_call(inst): - targ_ea = get_direct_branch_target(inst) - targ_is_thunk = is_thunk(targ_ea) - if targ_is_thunk: - targ_thunk_name = get_symbol_name(ea, targ_ea) - DEBUG("Found thunk-to-thunk {:x} -> {:x}: {} to {}".format( - ea, targ_ea, ea_name, targ_thunk_name)) - return True, targ_ea - - DEBUG("ERROR? targ_ea={:x} is not thunk".format(targ_ea)) - - if not is_external_reference(ea): - return _INVALID_THUNK_ADDR - - return True, targ_ea - -def try_get_thunk_name(ea): - """Try to figure out if a function is actually a thunk, i.e. a function - that represents a 'local' definition for an external function. Thunks work - by having the local function jump through a function pointer that is - resolved at runtime.""" - global _ELF_THUNKS, _NOT_ELF_THUNKS, _INVALID_THUNK - - if ea in _ELF_THUNKS: - return _ELF_THUNKS[ea] - - if ea in _NOT_ELF_THUNKS: - _NOT_ELF_THUNKS.add(ea) - return _INVALID_THUNK - - # Try two approaches to detecting whether or not - # something is a thunk. - is_thunk = False - target_ea = idc.BADADDR - if IS_ELF: - is_thunk, target_ea = is_ELF_thunk_by_structure(ea) - - if not is_thunk: - is_thunk, target_ea = is_thunk_by_flags(ea) - - if not is_thunk: - _NOT_ELF_THUNKS.add(ea) - return _INVALID_THUNK - - else: - name = get_function_name(target_ea) - name = undecorate_external_name(name) - name = get_true_external_name(name) - ret = (is_thunk, target_ea, name) - _ELF_THUNKS[ea] = ret - return ret - -def is_start_of_function(ea): - """Returns `True` if `ea` is the start of a function.""" - if not is_code(ea): - return False - - name = idc.GetTrueName(ea) or idc.GetFunctionName(ea) - return ea == idc.LocByName(name) - -_REFERENCE_OPERAND_TYPE = { - Reference.IMMEDIATE: CFG_pb2.CodeReference.ImmediateOperand, - Reference.DISPLACEMENT: CFG_pb2.CodeReference.MemoryDisplacementOperand, - Reference.MEMORY: CFG_pb2.CodeReference.MemoryOperand, - Reference.CODE: CFG_pb2.CodeReference.ControlFlowOperand, -} - -def reference_target_type(ref): - """Sometimes code references into the GOT would be treated as data - references. We fall back onto our external maps as an oracle for - what the type should really be. This has happened with `pcre_free` - references from Apache.""" - if ref.ea in EXTERNAL_VARS_TO_RECOVER: - return CFG_pb2.CodeReference.DataTarget - - # TODO(pag): - #elif ref.ea in EXTERNAL_FUNCS_TO_RECOVER: - # return CFG_pb2.CodeReference.CodeTarget - - elif is_code(ref.ea): - return CFG_pb2.CodeReference.CodeTarget - else: - return CFG_pb2.CodeReference.DataTarget - -def reference_operand_type(ref): - global _REFERENCE_OPERAND_TYPE - return _REFERENCE_OPERAND_TYPE[ref.type] - -def reference_location(ref): - if ref.ea in EXTERNAL_VARS_TO_RECOVER: - return CFG_pb2.CodeReference.External - elif ref.ea in EXTERNAL_FUNCS_TO_RECOVER: - return CFG_pb2.CodeReference.External - elif is_external_segment_by_flags(ref.ea): - DEBUG("WARNING: Reference to {:x} is in an external segment, but is not an external var or function".format(ref.ea)) - return CFG_pb2.CodeReference.External - else: - return CFG_pb2.CodeReference.Internal - -def referenced_name(ref): - if ref.ea in EXTERNAL_VARS_TO_RECOVER: - return EXTERNAL_VARS_TO_RECOVER[ref.ea] - elif ref.ea in EXTERNAL_FUNCS_TO_RECOVER: - return EXTERNAL_FUNCS_TO_RECOVER[ref.ea] - else: - return get_true_external_name(ref.symbol) - -_TARGET_NAME = { - CFG_pb2.CodeReference.CodeTarget: "code", - CFG_pb2.CodeReference.DataTarget: "data", -} - -_OPERAND_NAME = { - CFG_pb2.CodeReference.ImmediateOperand: "imm", - CFG_pb2.CodeReference.MemoryDisplacementOperand: "disp", - CFG_pb2.CodeReference.MemoryOperand: "mem", - CFG_pb2.CodeReference.ControlFlowOperand: "flow", -} - -_LOCATION_NAME = { - CFG_pb2.CodeReference.External: "external", - CFG_pb2.CodeReference.Internal: "internal", -} - -def format_instruction_reference(ref): - """Returns a string representation of a cross reference contained - in an instruction.""" - mask_begin = "" - mask_end = "" - if ref.mask: - mask_begin = "(" - mask_end = " & {:x})".format(ref.mask) - - return "({} {} {} {}{:x}{} {})".format( - _TARGET_NAME[ref.target_type], - _OPERAND_NAME[ref.operand_type], - _LOCATION_NAME[ref.location], - mask_begin, - ref.ea, - mask_end, - ref.HasField('name') and ref.name or "") - -def recover_instruction_references(I, inst, addr, refs): - """Add the memory/code reference information from this instruction - into the CFG format. The LLVM side of things needs to be able to - match instruction operands to references to internal/external - code/data. - - The `get_instruction_references` gives us an accurate picture of the - references as they are, but in practice we want a higher-level perspective - that resolves things like thunks to their true external representations. - - Note: References are a kind of gotcha that need special explaining. We kind - of 'devirtualize' references. An example of this is: - - extern:00000000002010A8 extrn stderr@@GLIBC_2_2_5 - - extern:00000000002010D8 ; struct _IO_FILE *stderr - extern:00000000002010D8 extrn stderr - | ; DATA XREF: .got:stderr_ptr - `-------------------------------. - | - .got:0000000000200FF0 stderr_ptr dq offset stderr - | ; DATA XREF: main+12 - `-------------------------------. - | - .text:0000000000000932 mov rax, cs:stderr_ptr - .text:0000000000000939 mov rdi, [rax] ; stream - ... - .text:0000000000000949 call _fprintf - - So above we see that the `mov` instruction is dereferencing `stderr_ptr`, - and from there it's getting the address of `stderr`. Then it dereferences - that, which is the value of `stderr, getting us the address of the `FILE *`. - That is passed at the first argument to `fprintf`. - - Now, what we see in the `mcseam-disass` log is a bit different. - - Variable at 200ff0 is the external stderr - Variable at 2010a8 is the external stderr - Variable at 2010d8 is the external stderr - ... - I: 932 (data mem external 200ff0 stderr) - - So even though the `mov` instruction uses `stderr_ptr` and an extra level - of indirection, we devirtualize that to `stderr`. But, how could this work? - It seems like it's removing a layer of indirection. The answer is on the - LLVM side of things. - - On the LLVM side, `stderr` is a global variable: - - @stderr = external global %struct._IO_FILE*, align 8 - - And the corresponding call is: - - %4 = load %struct._IO_FILE*, %struct._IO_FILE** @stderr, align 8 - %5 = call i32 (...) @fprintf(%struct._IO_FILE* %4, i8* ...) - - So now we see that by declaring the global variable `stderr` on the LLVM - side, we regain this extra level of indirection because all global variables - are really pointers to their type (i.e. `%struct._IO_FILE**`), thus we - preserve the intent of the original assembly. - """ - DEBUG_PUSH() - debug_info = ["I: {:x}".format(addr)] - for ref in refs: - if not ref.is_valid(): - DEBUG("POSSIBLE ERROR: Invalid reference {} at instruction {:x}".format( - str(ref), inst.ea)) - continue - - # Redirect the thunk target to the internal target. - if ref.ea in INTERNAL_THUNK_EAS: - ref.ea = INTERNAL_THUNK_EAS[ref.ea] - ref.symbol = get_symbol_name(ref.ea) - - if Reference.CODE == ref.type: - is_thunk, thunk_target_ea, thunk_name = try_get_thunk_name(ref.ea) - if is_thunk: - ref.ea = thunk_target_ea - ref.symbol = thunk_name - - target_type = reference_target_type(ref) - location = reference_location(ref) - - addrs = set() - R = I.xrefs.add() - R.ea = ref.ea - if ref.mask: - R.mask = ref.mask - - R.operand_type = reference_operand_type(ref) - R.target_type = target_type - R.location = location - name = referenced_name(ref) - if name: - R.name = name.format('utf-8') - - debug_info.append(format_instruction_reference(R)) - - DEBUG_POP() - DEBUG(" ".join(debug_info)) - -def recover_instruction_offset_table(I, table): - """Recovers an offset table as a kind of reference.""" - DEBUG("Offset-based jump table") - R = I.xrefs.add() - R.ea = table.offset - R.operand_type = CFG_pb2.CodeReference.OffsetTable - R.target_type = CFG_pb2.CodeReference.DataTarget - R.location = CFG_pb2.CodeReference.Internal - name = get_symbol_name(table.offset * table.offset_mult, allow_dummy=False) - if name: - R.name = name.format('utf-8') - -def try_recovery_external_flow(I, inst, refs): - """We have somehting like: - - jmp cs:EnterCriticalSection - - Where `EnterCriticalSection` is in the `.idata` section and is filled in at - load time to contain the real address of the external - `EnterCriticalSection`.""" - if not (is_indirect_jump(inst) or is_indirect_function_call(inst)) or \ - not refs or len(refs) > 1: - return - - ref = refs[0] - if ref.type == Reference.CODE or ref.ea not in EXTERNAL_FUNCS_TO_RECOVER: - return - - R = I.xrefs.add() - R.ea = ref.ea - R.name = EXTERNAL_FUNCS_TO_RECOVER[ref.ea].format('utf-8') - R.operand_type = CFG_pb2.CodeReference.ControlFlowOperand - R.target_type = CFG_pb2.CodeReference.CodeTarget - R.location = CFG_pb2.CodeReference.External - - if is_indirect_jump(inst): - DEBUG("Tail-calls external {}".format(R.name)) - else: - DEBUG("Calls external {}".format(R.name)) - -def recover_instruction(M, B, ea): - """Recover an instruction, adding it to its parent block in the CFG.""" - inst, inst_bytes = decode_instruction(ea) - - I = B.instructions.add() - I.ea = ea # May not be `inst.ea` because of prefix coalescing. - I.bytes = inst_bytes - - refs = get_instruction_references(inst, PIE_MODE) - recover_instruction_references(I, inst, ea, refs) - - if is_noreturn_inst(inst): - I.local_noreturn = True - - - DEBUG_PUSH() - table = get_jump_table(inst, PIE_MODE) - if table and table.offset and \ - not is_invalid_ea(table.offset * table.offset_mult): - recover_instruction_offset_table(I, table) - - if not table: - try_recovery_external_flow(I, inst, refs) - - DEBUG_POP() - - return I - -def recover_basic_block(M, F, block_ea): - """Add in a basic block to a specific function in the CFG.""" - if is_external_segment_by_flags(block_ea): - DEBUG("BB: {:x} in func {:x} is an external".format(block_ea, F.ea)) - return - - inst_eas, succ_eas = analyse_block(F.ea, block_ea, PIE_MODE) - - DEBUG("BB: {:x} in func {:x} with {} insts".format( - block_ea, F.ea, len(inst_eas))) - - B = F.blocks.add() - B.ea = block_ea - - DEBUG_PUSH() - I = None - for inst_ea in inst_eas: - I = recover_instruction(M, B, inst_ea) - # Get the landing pad associated with the instructions; - # 0 if no landing pad associated - if RECOVER_EHTABLE is True and I: - I.lp_ea = get_exception_landingpad(F, inst_ea) - - DEBUG_PUSH() - if I and I.local_noreturn: - DEBUG("Does not return") - - elif len(succ_eas) > 0: - B.successor_eas.extend(succ_eas) - DEBUG("Successors: {}".format(", ".join("{0:x}".format(i) for i in succ_eas))) - else: - DEBUG("No successors") - - DEBUG_POP() - DEBUG_POP() - -def analyze_jump_table_targets(inst, new_eas, new_func_eas): - """Function recovery is an iterative process. Sometimes we'll find things - in the entries of the jump table that we need to go mark as code to be - added into the CFG.""" - table = get_jump_table(inst, PIE_MODE) - if not table: - return - - for entry_addr, entry_target in table.entries.items(): - if is_start_of_function(entry_target): - DEBUG(" Jump table {:x} entry at {:x} references function at {:x}".format( - table.table_ea, entry_addr, entry_target)) - new_func_eas.add(entry_target) - else: - DEBUG(" Jump table {:x} entry at {:x} references block at {:x}".format( - table.table_ea, entry_addr, entry_target)) - new_eas.add(entry_target) - -_RECOVERED_FUNCS = set() - -def recover_function(M, func_ea, new_func_eas, entrypoints): - """Decode a function and store it, all of its basic blocks, and all of - their instructions into the CFG file.""" - global _RECOVERED_FUNCS - if func_ea in _RECOVERED_FUNCS: - return - - _RECOVERED_FUNCS.add(func_ea) - - if not is_start_of_function(func_ea): - DEBUG("{:x} is not a function! Not recovering.".format(func_ea)) - return - - F = M.funcs.add() - F.ea = func_ea - F.is_entrypoint = (func_ea in entrypoints) - name = get_symbol_name(func_ea) - if name: - DEBUG("Recovering {} at {:x}".format(name, func_ea)) - F.name = name.format('utf-8') - else: - DEBUG("Recovering {:x}".format(func_ea)) - - DEBUG_PUSH() - # Update the protobuf with the recovered eh_frame entries - if RECOVER_EHTABLE is True: - recover_exception_entries(F, func_ea) - blockset, term_insts = analyse_subroutine(func_ea, PIE_MODE) - - for term_inst in term_insts: - if get_jump_table(term_inst, PIE_MODE): - DEBUG("Terminator inst {:x} in func {:x} is a jump table".format( - term_inst.ea, func_ea)) - analyze_jump_table_targets(term_inst, blockset, new_func_eas) - - processed_blocks = set() - while len(blockset) > 0: - block_ea = blockset.pop() - if block_ea in processed_blocks: - DEBUG("ERROR: Attempting to add same block twice: {0:x}".format(block_ea)) - continue - - processed_blocks.add(block_ea) - recover_basic_block(M, F, block_ea) - - if TO_RECOVER["stack_var"]: - recover_variables(F, func_ea, processed_blocks) - - DEBUG_POP() - -def find_default_function_heads(): - """Loop through every function, to discover the heads of all blocks that - IDA recognizes. This will populate some global sets in `flow.py` that - will help distinguish block heads.""" - func_heads = set() - for seg_ea in idautils.Segments(): - seg_type = idc.GetSegmentAttr(seg_ea, idc.SEGATTR_TYPE) - if seg_type != idc.SEG_CODE: - continue - - for func_ea in idautils.Functions(seg_ea, idc.SegEnd(seg_ea)): - if is_code_by_flags(func_ea): - func_heads.add(func_ea) - - return func_heads - -def recover_region_variables(M, S, seg_ea, seg_end_ea, exported_vars): - """Look for named locations pointing into the data of this segment, and - add them to the protobuf.""" - is_code_seg = is_code(seg_ea) - - for ea, name in idautils.Names(): - if ea < seg_ea or ea >= seg_end_ea: - continue - - if is_external_segment_by_flags(ea) or ea in EXTERNAL_VARS_TO_RECOVER: - continue - - if is_code_seg and is_code_by_flags(ea): - continue - - # Only add named internal variables if they are referenced or exported. - if is_referenced(ea) or ea in exported_vars: - DEBUG("Variable {} at {:x}".format(name, ea)) - V = S.vars.add() - V.ea = ea - V.name = name.format('utf-8') - -def recover_region_cross_references(M, S, seg_ea, seg_end_ea): - """Goes through the segment and identifies fixups that need to be - handled by the LLVM side of things.""" - - # Go through and look for the fixups. We start at `seg_ea - 1` because we - # always try to find the *next* fixup/heads, and if there's one right at - # the beginning of the segment then we don't want to jump to the second one. - global PIE_MODE - - max_xref_width = get_address_size_in_bytes() - min_xref_width = PIE_MODE and max_xref_width or 4 - - is_code_seg = is_code(seg_ea) - seg_name = idc.SegName(seg_ea) - has_func_pointers = segment_contains_external_function_pointers(seg_ea) - - ea, next_ea = seg_ea, seg_ea - while next_ea < seg_end_ea: - ea = next_ea - - # The item size is 1 in some of the cases where it refer to the external data. The - # references in such cases get ignored. Assign the address size if there is reference - # to the external data. - item_size = idc.ItemSize(ea) - xref_width = min(max(item_size, 4), max_xref_width) - next_ea = min(ea + xref_width, - # idc.GetNextFixupEA(ea), - idc.NextHead(ea, seg_end_ea)) - - # This data is a copy of shared data. - if is_runtime_external_data_reference(ea): - continue - - # We don't want to fill the jump table bytes with their actual - # code cross-references. This is because we can't get the address - # of a basic block. Our goal is thus to preserve the original values, - # and implement the switch in terms of those original values on the - # LLVM side of things. - if is_jump_table_entry(ea): - continue - - # Skip over instructions. - if is_code_seg: - flags = idc.GetFlags(ea) - if idc.isCode(flags): - next_ea = idc.NextHead(ea, seg_end_ea) - continue - - target_ea = get_reference_target(ea) - - # Handle entries in the `.got.plt` and `.idata` segments. In ELF binaries, - # this looks like: - # - # .got.plt:000000000032E058 off_32E058 dq offset getenv - # - # In PE binaries, this looks like: - # - # .idata:00000001400110D8 ; DWORD __stdcall GetLastError() - # .idata:00000001400110D8 extrn GetLastError:qword - if is_invalid_ea(target_ea): - if has_func_pointers and ea in EXTERNAL_FUNCS_TO_RECOVER: - target_ea = ea - - # Note: it's possible that `ea == target_ea`. This happens with - # external references to things like `stderr`, where there's - # an internal slot, whose value is filled in at runtime. - if is_invalid_ea(target_ea): - continue - - elif (ea % 4) != 0: - DEBUG("WARNING: Unaligned reference at {:x} to {:x}".format(ea, target_ea)) - continue - - elif item_size < min_xref_width: - DEBUG("WARNING: Ingorning {}-byte item that looks like at reference from {:x} to {:x}; it needs to be at least {} bytes".format( - item_size, ea, target_ea, min_xref_width)) - continue - - # Probably some really small number. - elif not idc.GetFlags(target_ea): - DEBUG("WARNING: No information about target {:x} from {:x}".format( - target_ea, ea)) - continue - - else: - X = S.xrefs.add() - X.ea = ea - X.width = xref_width - X.target_ea = target_ea - X.target_name = get_symbol_name(target_ea) - X.target_is_code = is_code(target_ea) or \ - target_ea in EXTERNAL_FUNCS_TO_RECOVER - - if is_external_segment(X.target_ea): - X.target_name = get_true_external_name(X.target_name) - - # A cross-reference to some TLS data. Because each thread has its own - # instance of the data, this reference ends up actually being an offset - # from a thread base pointer. In x86, this tends to be the base of one of - # the segment registers, e.g. `fs` or `gs`. On the McSema side, we fill in - # this xref lazily by computing the offset. - if is_tls(target_ea): - X.target_fixup_kind = CFG_pb2.DataReference.OffsetFromThreadBase - DEBUG("{}-byte TLS offset at {:x} to {:x} ({})".format( - X.width, ea, target_ea, X.target_name)) - - # A cross-reference to a 'single' thing, where the fixup that we create - # will be an absolute address to the targeted variable/function. - else: - X.target_fixup_kind = CFG_pb2.DataReference.Absolute - DEBUG("{}-byte reference at {:x} to {:x} ({})".format( - X.width, ea, target_ea, X.target_name)) - - try_identify_as_external_function(target_ea, X.target_name) - - -def recover_region(M, region_name, region_ea, region_end_ea, exported_vars): - """Recover the data and cross-references from a segment. The data of a - segment is stored verbatim within the protobuf, and accompanied by a - series of variable and cross-reference entries.""" - - seg_name = idc.SegName(region_ea) - - DEBUG("Recovering region {} [{:x}, {:x}) in segment {}".format( - region_name, region_ea, region_end_ea, seg_name)) - - seg = idaapi.getseg(region_ea) - - # An item spans two regions. This may mean that there's a reference into - # the middle of an item. This happens with strings. - item_size = idc.ItemSize(region_end_ea - 1) - if 1 < item_size: - DEBUG(" ERROR: Segment should probably include {} more bytes".format( - item_size - 1)) - - S = M.segments.add() - S.ea = region_ea - S.data = read_bytes_slowly(region_ea, region_end_ea) - S.read_only = (seg.perm & idaapi.SEGPERM_WRITE) == 0 - S.is_external = is_external_segment_by_flags(region_ea) - S.is_thread_local = is_tls_segment(region_ea) - S.name = seg_name.format('utf-8') - S.is_exported = region_ea in exported_vars - - if region_name != seg_name: - S.variable_name = region_name.format('utf-8') - - DEBUG_PUSH() - recover_region_cross_references(M, S, region_ea, region_end_ea) - recover_region_variables(M, S, region_ea, region_end_ea, exported_vars) - DEBUG_POP() - -def recover_regions(M, exported_vars, global_vars=[]): - """Recover all non-external segments into the CFG module. This will also - recover global variables, specified in terms of a list of - `(name, begin_ea, end_ea)` tuples, as their own segments.""" - - seg_names = {} - - # Collect the segment bounds to lift. - seg_parts = collections.defaultdict(set) - for seg_ea in idautils.Segments(): - seg_name = idc.SegName(seg_ea) - seg_names[seg_ea] = seg_name - - if (not is_external_segment_by_flags(seg_ea) or \ - segment_contains_external_function_pointers(seg_ea)) and \ - not (is_constructor_segment(seg_ea) or is_destructor_segment(seg_ea)): - seg_parts[seg_ea].add(seg_ea) - seg_parts[seg_ea].add(idc.SegEnd(seg_ea)) - - # Fix for an important feature - static storage allocation of the objects in C++, where - # the constructor gets invoked before the main and it typically calls the 'init/__libc_csu_init' function. - # - # The function iterate over the array conatined in .init_array initializing the global constructor/destructor - # function pointers using the symbol `off_201D70` and `off_201D80` as the array bounds as shown below. These - # symbols falls in section `.init_array` and `.fini_array` correspondingly. - # - # .init_array:0000000000201D70 ; ELF Initialization Function Table - # .init_array:0000000000201D70 ; =========================================================================== - # .init_array:0000000000201D70 ; Segment type: Pure data - # .init_array:0000000000201D70 _init_array segment para public 'DATA' use64 - # .init_array:0000000000201D70 assume cs:_init_array - # .init_array:0000000000201D70 ;org 201D70h - # .init_array:0000000000201D70 off_201D70 dq offset sub_C40 - # .init_array:0000000000201D70 - # .init_array:0000000000201D78 dq offset sub_10E5 - # .init_array:0000000000201D78 _init_array ends - # - # .fini_array:0000000000201D80 ; ELF Termination Function Table - # .fini_array:0000000000201D80 ; =========================================================================== - # .fini_array:0000000000201D80 ; Segment type: Pure data - # .fini_array:0000000000201D80 _fini_array segment para public 'DATA' use64 - # .fini_array:0000000000201D80 assume cs:_fini_array - # .fini_array:0000000000201D80 ;org 201D80h - # .fini_array:0000000000201D80 off_201D80 dq offset sub_C00 - # .fini_array:0000000000201D80 _fini_array ends - # - # .text:0000000000001160 ; void init(void) - # .text:0000000000001160 push r15 - # .text:0000000000001162 mov r15d, edi - # .text:0000000000001165 push r14 - # .text:0000000000001167 mov r14, rsi - # .text:000000000000116A push r13 - # .text:000000000000116C mov r13, rdx - # .text:000000000000116F push r12 - # .text:0000000000001171 lea r12, off_201D70 - # .text:0000000000001178 push rbp - # .text:0000000000001179 lea rbp, off_201D80 - # .text:0000000000001180 push rbx - # .text:0000000000001181 sub rbp, r12 - # .text:0000000000001184 xor ebx, ebx - # .text:0000000000001186 sar rbp, 3 - # .text:000000000000118A sub rsp, 8 - # .text:000000000000118E call _init_proc - # ... - # Extracting these sections as different LLVM GlobalVariable will not guarantee the adjacency placement in - # recompiled binary. Hence it should be lifted as one LLVM GlobalVariable if they are adjacent. - - if is_constructor_segment(seg_ea): - seg_parts[seg_ea].add(seg_ea) - end_ea = idc.SegEnd(seg_ea) - if is_destructor_segment(end_ea): - seg_parts[seg_ea].add(idc.SegEnd(end_ea)) - DEBUG("WARNING: Global constructor and destructor sections are adjacent!") - else: - seg_parts[seg_ea].add(end_ea) - fini_ea = get_destructor_segment() - if fini_ea: - seg_parts[fini_ea].add(fini_ea) - seg_parts[fini_ea].add(idc.SegEnd(fini_ea)) - - # Treat analysis-identified global variables as segment begin/end points. - for var_name, begin_ea, end_ea in global_vars: - if is_invalid_ea(begin_ea) or is_invalid_ea(end_ea): - DEBUG("ERROR: Variable {} at [{:x}, {:x}) is not valid.".format( - var_name, begin_ea, end_ea)) - continue - - if is_external_segment_by_flags(begin_ea): - DEBUG("ERROR: Variable {} at [{:x}, {:x}) is in an external segment.".format( - var_name, begin_ea, end_ea)) - continue - - seg_ea = idc.SegStart(begin_ea) - seg_name = idc.SegName(seg_ea) - - DEBUG("Splitting segment {} from {:x} to {:x} for global variable {}".format( - seg_name, begin_ea, end_ea, var_name)) - - seg_parts[seg_ea].add(begin_ea) - seg_names[begin_ea] = var_name - - if end_ea <= idc.SegEnd(seg_ea): - seg_parts[seg_ea].add(end_ea) - - # Treat exported variables as segment begin/end points. - for var_ea in exported_vars: - seg_ea = idc.SegStart(var_ea) - seg_name = idc.SegName(seg_ea) - var_name = get_symbol_name(var_ea) - seg_parts[seg_ea].add(var_ea) - seg_names[var_ea] = var_name - DEBUG("Splitting segment {} at {:x} for exported variable {}".format( - seg_name, var_ea, var_name)) - - for seg_ea, eas in seg_parts.items(): - parts = list(sorted(list(eas))) - seg_name = idc.SegName(seg_ea) - for begin_ea, end_ea in zip(parts[:-1], parts[1:]): - region_name = seg_name - if begin_ea in seg_names: - region_name = seg_names[begin_ea] - recover_region(M, region_name, begin_ea, end_ea, exported_vars) - -def recover_external_functions(M): - """Recover the named external functions (e.g. `printf`) that are referenced - within this binary.""" - global EXTERNAL_FUNCS_TO_RECOVER, WEAK_SYMS, EMAP - - for ea, name in EXTERNAL_FUNCS_TO_RECOVER.items(): - DEBUG("Recovering extern function {} at {:x}".format(name, ea)) - args, conv, ret, sign = EMAP[name] - E = M.external_funcs.add() - E.name = name.format('utf-8') - E.ea = ea - E.argument_count = args - E.cc = conv - E.is_weak = idaapi.is_weak_name(ea) or (name in WEAK_SYMS) - E.no_return = ret == 'Y' - - # TODO(pag): This should probably reflect whether or not the function - # actually returns something, rather than simply does not - # return (e.g. `abort`). - E.has_return = ret == 'N' - -def recover_external_variables(M): - """Reover the named external variables (e.g. `stdout`) that are referenced - within this binary.""" - global EXTERNAL_VARS_TO_RECOVER, WEAK_SYMS - - for ea, name in EXTERNAL_VARS_TO_RECOVER.items(): - EV = M.external_vars.add() - EV.ea = ea - EV.name = name.format('utf-8') - EV.is_weak = idaapi.is_weak_name(ea) or (name in WEAK_SYMS) - EV.is_thread_local = is_tls(ea) - if name in EMAP_DATA: - EV.size = EMAP_DATA[name] - else: - EV.size = idc.ItemSize(ea) - if EV.is_thread_local: - DEBUG("Recovering extern TLS variable {} at {:x}".format(name, ea)) - else: - DEBUG("Recovering extern variable {} at {:x}".format(name, ea)) - -def recover_external_symbols(M): - recover_external_functions(M) - recover_external_variables(M) - -def try_identify_as_external_function(ea, name=None): - """Try to identify a function as being an external function.""" - global EXTERNAL_FUNCS_TO_RECOVER, EMAP - - if ea in EXTERNAL_FUNCS_TO_RECOVER: - return True - - if ea in INTERNAL_THUNK_EAS: - return False - - # First, check if it's a thunk. Some thunks are not location in exported - # sections. Sometimes there are thunk-to-thunks, where there's a function - # whose only instruction is a direct jump to the real thunk. - is_thunk, thunk_target_ea, thunk_name = try_get_thunk_name(ea) - - if is_thunk: - name = thunk_name - - elif is_external_segment(ea): - name = get_true_external_name(get_function_name(ea)) - - elif not name: - return False - - # We've got a thunk with an implementation already done. - if name in INTERNALLY_DEFINED_EXTERNALS: - impl_ea = INTERNALLY_DEFINED_EXTERNALS[name] - INTERNAL_THUNK_EAS[ea] = impl_ea - return False - - if name not in EMAP: - return False - - DEBUG("Function at {:x} is the external function {}".format(ea, name)) - EXTERNAL_FUNCS_TO_RECOVER[ea] = name - return True - -def identify_thunks(func_eas): - DEBUG("Looking for thunks") - DEBUG_PUSH() - for func_ea in func_eas: - is_thunk, thunk_target_ea, name = try_get_thunk_name(func_ea) - if is_thunk: - DEBUG("Found thunk for {} targeting {:x} at {:x}".format( - name, thunk_target_ea, func_ea)) - DEBUG_POP() - -def identify_external_symbols(): - """Try to identify external functions and variables.""" - global _FIXED_EXTERNAL_NAMES - - DEBUG("Looking for external symbols") - DEBUG_PUSH() - - for ea, name in idautils.Names(): - if try_identify_as_external_function(ea) or is_code(ea): - continue - - elif is_ELF_got_pointer(ea): - target_ea = get_reference_target(ea) - target_name = get_true_external_name(get_symbol_name(target_ea)) - - # Detect missing references. - if is_external_segment(target_ea): - if target_name not in EMAP_DATA and target_name not in EMAP: - DEBUG("ERROR: Missing external reference information for {} referenced at {:x}".format( - target_name, ea)) - - target_flags = idc.GetFlags(target_ea) - - # The missing reference looks like code, so add it to the EMAP with - # 16 arguments (probably enough, eh?), and assume it uses the cdecl - # calling convention. - # - # NOTE(pag): We use `idc.isCode` and not `is_code` because the latter - # operates at the segment granularity, and `target_ea` will - # likely point into the `extern` section. Individual - # entries in the extern section can have - if idc.isCode(target_flags): - DEBUG("WARNING: Adding external {} at {:x} as an external code reference".format( - target_name, ea)) - EMAP[target_name] = (16, CFG_pb2.ExternalFunction.CallerCleanup, "N", None) - - imp_name = "__imp_{}".format(target_name) - if idc.LocByName(imp_name): - _FIXED_EXTERNAL_NAMES[imp_name] = target_name - WEAK_SYMS.add(target_name) - WEAK_SYMS.add(imp_name) - - # The - else: - DEBUG("WARNING: Adding external {} at {:x} as an external data reference".format( - target_name, ea)) - EMAP_DATA[target_name] = 8 # TODO(pag): Made up, based on max pointer size. - - elif target_name in EMAP_DATA: - EXTERNAL_VARS_TO_RECOVER[target_ea] = target_name - elif target_name in EMAP: - EXTERNAL_FUNCS_TO_RECOVER[target_ea] = target_name - - # Corner case, there is an external reference in the `.got` section - # into internal data. This was observed in one binary where - # `fec_scheme_str_ptr` was an entry in the `.got`, but pointed into the - # `.data` section. - else: - DEBUG("External-looking reference from {} at {:x} to {} at {:x} is actually internal".format( - name, ea, target_name, target_ea)) - - if ea in EXTERNAL_VARS_TO_RECOVER: - del EXTERNAL_VARS_TO_RECOVER[ea] - - if ea in EXTERNAL_FUNCS_TO_RECOVER: - del EXTERNAL_FUNCS_TO_RECOVER[ea] - - if ea in _FIXED_EXTERNAL_NAMES: - del _FIXED_EXTERNAL_NAMES[ea] - - if target_name in EMAP_DATA: - del EMAP_DATA[target_name] - - if target_name in EMAP: - del EMAP[target_name] - - elif is_external_segment_by_flags(ea) or is_runtime_external_data_reference(ea): - # idc.Demangle (...) gives incorrect name for the external data objects - # only de-mangle the name of the external functions - extern_name = get_true_external_name(name, demangle=is_code(ea)) - - if extern_name in EMAP_DATA: - DEBUG("Variable at {:x} is the external {}".format(ea, extern_name)) - set_symbol_name(ea, extern_name) - EXTERNAL_VARS_TO_RECOVER[ea] = extern_name - - elif extern_name in EMAP: - DEBUG("Function at {:x} is the external {}".format(ea, extern_name)) - set_symbol_name(ea, extern_name) - EXTERNAL_FUNCS_TO_RECOVER[ea] = extern_name - - else: - # IDA sometimes does this dumb thing where it will actually have a bunch - # of names for the same address, and it will choose the wrong one. This - # tends to happen with the `.bss` section, and can be reproduced by a C - # file with only one global variable `FILE *fp = stdout;`. Some versions - # of IDA will treat the local copy of `stdout` as being the symbol - # `__bss_start`. - comment = idc.GetCommentEx(ea, 0) or "" - for comment_line in comment.split("\n"): - comment_line = comment_line.replace(";", "").strip() - found_name = get_true_external_name(comment_line, demangle=is_code(ea)) - if found_name in EMAP_DATA: - extern_name = found_name - break - - if extern_name not in PERSONALITY_FUNCTIONS: - DEBUG("WARNING: Adding variable {} at {:x} as external".format( - extern_name, ea)) - - set_symbol_name(ea, extern_name) # Rename it. - EXTERNAL_VARS_TO_RECOVER[ea] = extern_name - _FIXED_EXTERNAL_NAMES[ea] = extern_name - - DEBUG_POP() - -def identify_program_entrypoints(func_eas): - """Identify all entrypoints into the program. This is pretty much any - externally visible function.""" - DEBUG("Looking for entrypoints") - DEBUG_PUSH() - - exclude = set(["_start", "__libc_csu_fini", "__libc_csu_init", "main", - "__data_start", "__dso_handle", "_IO_stdin_used", - "_dl_relocate_static_pie"]) - - exported_funcs = set() - exported_vars = set() - - for index, ordinal, ea, name in idautils.Entries(): - assert ea != idc.BADADDR - if not is_external_segment(ea): - sym_name = get_symbol_name(ea, allow_dummy=False) - if not sym_name: - DEBUG("WEIRD: Forcing entrypoint {:x} name to be {}".format(ea, name)) - set_symbol_name(ea, name) - - if is_code(ea): - func_eas.add(ea) - if name not in exclude: - exported_funcs.add(ea) - else: - # If there is reference to the external vtable in the segment, add it - # as the exported variables. This is required to preserve the typeinfo - # of the user-define exception type variables. The lazy initilization - # of the vtable screw up the associated types. - # It checks for the following vtable variables: - # __ZTVSt9type_info, - # __ZTVN10__cxxabiv117__class_type_infoE, - # __ZTVN10__cxxabiv120__si_class_type_infoE, - # __ZTVN10__cxxabiv121__vmi_class_type_infoE - if name not in exclude and \ - not is_runtime_external_data_reference(ea) or \ - is_external_vtable_reference(ea): - exported_vars.add(ea) - - DEBUG_POP() - return exported_funcs, exported_vars - -def find_main_in_ELF_file(): - """Tries to automatically find the `main` function if we haven't found it - yet. IDA recognizes the pattern of `_start` calling `__libc_start_main` in - ELF binaries, where one of the parameters is the `main` function. IDA will - helpfully comment it as such.""" - - start_ea = idc.LocByName("_start") - if is_invalid_ea(start_ea): - start_ea = idc.LocByName("start") - if is_invalid_ea(start_ea): - return idc.BADADDR - - for begin_ea, end_ea in idautils.Chunks(start_ea): - for inst_ea in Heads(begin_ea, end_ea): - comment = idc.GetCommentEx(inst_ea, 0) - if comment and "main" in comment: - for main_ea in xrefs_from(inst_ea): - if not is_code(main_ea): - continue - - # Sometimes the `main` function isn't identified as code. This comes - # up when there are some alignment bytes in front of `main`. - try_mark_as_code(main_ea) - if is_code_by_flags(main_ea): - try_mark_as_function(main_ea) - - main = idaapi.get_func(main_ea) - if not main: - continue - - if main and main.startEA == main_ea: - set_symbol_name(main_ea, "main") - DEBUG("Found main at {:x}".format(main_ea)) - return main_ea - - return idc.BADADDR - -def recover_module(entrypoint, gvar_infile = None): - global EMAP - global EXTERNAL_FUNCS_TO_RECOVER - global INTERNAL_THUNK_EAS - - M = CFG_pb2.Module() - M.name = idc.GetInputFile().format('utf-8') - DEBUG("Recovering module {}".format(M.name)) - - entry_ea = idc.LocByName(args.entrypoint) - - # If the entrypoint is `main`, then we'll try to find `main` via another - # means. - if is_invalid_ea(entry_ea): - if "main" == args.entrypoint and IS_ELF: - entry_ea = find_main_in_ELF_file() - - if RECOVER_EHTABLE: - recover_exception_table() - - process_segments(PIE_MODE) - - func_eas = find_default_function_heads() - - recovered_fns = 0 - - identify_thunks(func_eas) - identify_external_symbols() - - exported_funcs, exported_vars = identify_program_entrypoints(func_eas) - - if is_invalid_ea(entry_ea): - DEBUG("ERROR: Could not find entrypoint {}".format(args.entrypoint)) - else: - func_eas.add(entry_ea) - exported_funcs.add(entry_ea) - - # Process and recover functions. - while len(func_eas) > 0: - func_ea = func_eas.pop() - if func_ea in RECOVERED_EAS or func_ea in EXTERNAL_FUNCS_TO_RECOVER: - continue - - RECOVERED_EAS.add(func_ea) - - if try_identify_as_external_function(func_ea): - DEBUG("ERROR: External function {:x} not previously identified".format(func_ea)) - continue - - if not is_code_by_flags(func_ea): - DEBUG("ERROR: Function EA not code: {:x}".format(func_ea)) - continue - - if is_external_segment_by_flags(func_ea): - continue - - recover_function(M, func_ea, func_eas, exported_funcs) - recovered_fns += 1 - - if recovered_fns == 0: - DEBUG("COULD NOT RECOVER ANY FUNCTIONS") - return - - global_vars = [] # TODO(akshay): Pass in relevant info. - - DEBUG("Global Variable {}".format(gvar_infile)) - if gvar_infile is not None: - GM = CFG_pb2.Module() - GM.ParseFromString(gvar_infile.read()) - count = 0 - for gvar in GM.global_vars: - global_vars.append([gvar.name, gvar.ea, gvar.ea + gvar.size]) - - recover_regions(M, exported_vars, global_vars) - recover_external_symbols(M) - - DEBUG("Recovered {0} functions.".format(recovered_fns)) - return M - -if __name__ == "__main__": - - parser = argparse.ArgumentParser() - - parser.add_argument( - "--log_file", - type=argparse.FileType('w'), - default=sys.stderr, - help="Log to a specific file. Default is stderr.") - - parser.add_argument( - '--arch', - help='Name of the architecture. Valid names are x86, amd64.', - required=True) - - parser.add_argument( - '--os', - help='Name of the operating system. Valid names are linux, windows.', - required=True) - - parser.add_argument( - "--output", - type=argparse.FileType('wb'), - default=None, - help="The output control flow graph recovered from this file", - required=True) - - parser.add_argument( - "--std-defs", - action='append', - type=str, - default=[], - help="std_defs file: definitions and calling conventions of imported functions and data") - - parser.add_argument( - "--syms", - type=argparse.FileType('r'), - default=None, - help="File containing
pairs of symbols to pre-define.") - - parser.add_argument( - "--pie-mode", - action="store_true", - default=False, - help="Assume all immediate values are constants (useful for ELFs built with -fPIE") - - parser.add_argument( - '--entrypoint', - help="The entrypoint where disassembly should begin", - required=True) - - parser.add_argument( - '--recover-global-vars', - type=argparse.FileType('r'), - default=None, - help="File containing the global variables to be lifted") - - parser.add_argument( - '--recover-stack-vars', - action="store_true", - default=False, - help="Flag to enable stack variable recovery") - - parser.add_argument( - '--recover-exception', - action="store_true", - default=False, - help="Flag to enable the exception handler recovery") - - args = parser.parse_args(args=idc.ARGV[1:]) - - if args.log_file != os.devnull: - INIT_DEBUG_FILE(args.log_file) - DEBUG("Debugging is enabled.") - - addr_size = {"x86": 32, "amd64": 64, "aarch64": 64}.get(args.arch, 0) - if addr_size != get_address_size_in_bits(): - DEBUG("Arch {} address size does not match IDA's available bitness {}! Did you mean to use idal64?".format( - args.arch, get_address_size_in_bits())) - idc.ChangeConfig("ABANDON_DATABASE=YES") - idc.Exit(-1) - - if args.pie_mode: - DEBUG("Using PIE mode.") - PIE_MODE = True - - if args.recover_stack_vars: - TO_RECOVER["stack_var"] = True - - if args.recover_exception: - RECOVER_EHTABLE = True - - EMAP = {} - EMAP_DATA = {} - - # Try to find the defs file or this OS - OS_NAME = args.os - os_defs_file = os.path.join(tools_disass_dir, "defs", "{}.txt".format(args.os)) - if os.path.isfile(os_defs_file): - args.std_defs.insert(0, os_defs_file) - - # Load in all defs files, include custom ones. - for defsfile in args.std_defs: - with open(defsfile, "r") as df: - DEBUG("Loading Standard Definitions file: {0}".format(defsfile)) - parse_os_defs_file(df) - - # Turn off "automatically make offset" heuristic, and set some - # other sane defaults. - idc.SetShortPrm(idc.INF_START_AF, 0xdfff) - idc.SetShortPrm(idc.INF_AF2, 0xfffd) - - # Ensure that IDA is done processing - DEBUG("Using Batch mode.") - idaapi.autoWait() - - DEBUG("Starting analysis") - try: - # Pre-define a bunch of symbol names and their addresses. Useful when reading - # a core dump. - if args.syms: - for line in args.syms: - name, ea_str = line.strip().split(" ") - ea = int(ea_str, base=16) - if not is_internal_code(ea): - try_mark_as_code(ea) - if is_code(ea): - try_mark_as_function(ea) - set_symbol_name(ea, name) - idaapi.autoWait() - - M = recover_module(args.entrypoint, args.recover_global_vars) - - DEBUG("Saving to: {0}".format(args.output.name)) - args.output.write(M.SerializeToString()) - args.output.close() - - except: - DEBUG(traceback.format_exc()) - - DEBUG("Done analysis!") - idc.ChangeConfig("ABANDON_DATABASE=YES") - idc.Exit(0) diff --git a/tools/mcsema_disass/ida/refs.py b/tools/mcsema_disass/ida/refs.py deleted file mode 100644 index 695beacd6..000000000 --- a/tools/mcsema_disass/ida/refs.py +++ /dev/null @@ -1,521 +0,0 @@ -# Copyright (c) 2017 Trail of Bits, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from util import * - -class Reference(object): - __slots__ = ('offset', 'ea', 'symbol', 'type', 'mask') - - INVALID = 0 - IMMEDIATE = 1 - DISPLACEMENT = 2 - MEMORY = 3 - CODE = 4 - - TYPE_TO_STR = { - INVALID: "(null)", - IMMEDIATE: "imm", - DISPLACEMENT: "disp", - MEMORY: "mem", - CODE: "code", - } - - def __init__(self, ea, offset, mask=0): - self.offset = offset - self.ea = ea - self.symbol = "" - self.type = self.INVALID - self.mask = mask - - def __str__(self): - mask_str = "" - if self.mask: - mask_str = " & {:x}".format(self.mask) - return "({} {} {}{})".format( - is_code(self.ea) and "code" or "data", - self.TYPE_TO_STR[self.type], - self.symbol or "0x{:x}".format(self.ea), - mask_str) - - def is_valid(self): - return self.type != self.INVALID - -# Try to determine if `ea` points at a field within a structure. This is a -# heuristic for determining whether or not an immediate `ea` should actually -# be treated as a reference. The intuition is that if it points into a logical -# location, then we should treat it as a reference. -def _is_address_of_struct_field(ea): - prev_head_ea = idc.PrevHead(ea) - - if is_invalid_ea(prev_head_ea): - return False - - prev_item_size = idc.ItemSize(prev_head_ea) - if ea >= (prev_head_ea + prev_item_size): - return False - - # Try to get a type for the last item head. - flags = idaapi.getFlags(ea) - ti = idaapi.opinfo_t() - oi = idaapi.get_opinfo(ea, 0, flags, ti) - if not oi: - return False - - # Get the size of the struct, and keep going if the suze of the previous - # item is a multiple of the struct's size (e.g. one struct or an array - # of that struct). - struct_size = idc.GetStrucSize(oi.tid) - if not struct_size or 0 != (prev_item_size % struct_size): - return False - - # Figure out the offset of `ea` within its structure, which may belong to - # an array of structures, and then check if that offset is associated with - # a named field. - arr_index = int((ea - prev_head_ea) / struct_size) - struct_begin_ea = (arr_index & struct_size) + prev_head_ea - off_in_struct = ea - struct_begin_ea - if not idc.GetMemberName(oi.tid, off_in_struct): - return False - - field_begin_ea = struct_begin_ea + off_in_struct - if field_begin_ea != ea: - return False - - field_size = idc.GetMemberSize(oi.tid, off_in_struct) - if not field_size: - return False - - return True - -_MAKE_ARRAY_ENTRY = { - 4: idc.MakeDword, - 8: idc.MakeQword -} - -# Try to create an array at `ea`, that extends into something that also looks -# like an array down the line. The idea is that sometimes there are arrays, -# but prefixes of those arrays are missed by IDA (curiously, idaq will sometimes -# correctly get these, but idal64 won't). If we find an immediate that looks -# like it could point at an array entry, then we want to treat it as a -# reference. To do that, we may need to make an array. -# -# TODO(pag): For now, we will assume that items must be at least 4 or 8 bytes -# i.e. pointer or offset sized entries. -# -# TODO(pag): Should we check that all the entries agree in terms of zero-ness? -# i.e. if the next entry is zero, then everything up to it should be -# zero, and if the next entry is non-zero, then everything up to it -# should be non-zero. -def _try_create_array(ea, max_num_entries=8): - global _MAKE_ARRAY_ENTRY - - seg_end_ea = idc.SegEnd(ea) - next_head_ea = idc.NextHead(ea, seg_end_ea) - if is_invalid_ea(next_head_ea): - return False - - item_size = idc.ItemSize(next_head_ea) - diff = next_head_ea - ea - - if item_size not in (4, 8) \ - or 0 != (diff % item_size) \ - or max_num_entries < (diff / item_size): - return False - - next_next_head_ea = idc.NextHead(next_head_ea, seg_end_ea) - if is_invalid_ea(next_head_ea): - return False - - if (next_next_head_ea - next_head_ea) != item_size: - return False - - for entry_ea in xrange(ea, next_head_ea, item_size): - _MAKE_ARRAY_ENTRY[item_size](entry_ea) - - return True - -# Return `True` if `ea` is nearby to other heads. -def _nearest_head(ea, bounds): - seg_ea = idc.SegStart(ea) - seg_end_ea = idc.SegEnd(ea) - next_head_ea = idc.NextHead(ea, seg_end_ea) - if not is_invalid_ea(next_head_ea) and bounds >= (next_head_ea - ea): - return next_head_ea - - prev_head_ea = idc.PrevHead(ea, seg_ea) - if not is_invalid_ea(prev_head_ea) and bounds >= (ea - prev_head_ea): - return prev_head_ea - - return idc.BADADDR - -_POSSIBLE_REFS = set() -_REFS = {} -_HAS_NO_REFS = set() -_NO_REFS = tuple() -_ENABLE_CACHING = False -_BAD_ARM_REF_OFF = (idc.BADADDR, 0) -_NOT_A_REF = set() - -# Remove a reference from `from_ea` to `to_ea`. -def remove_instruction_reference(from_ea, to_ea): - global _REFS, _NOT_A_REF - - _NOT_A_REF.add((from_ea, to_ea)) - - try: - idaapi.del_dref(from_ea, to_ea) - idaapi.del_cref(from_ea, to_ea, False) - idaapi.del_cref(from_ea, to_ea, True) - except: - pass - - if not _ENABLE_CACHING or from_ea not in _REFS: - return - - new_refs = [] - found = False - for old_ref in _REFS[from_ea]: - if old_ref.ea != to_ea: - new_refs.append(old_ref) - else: - found = True - - if found: - _REFS[from_ea] = tuple(new_refs) - -def _get_arm_ref_candidate(mask, op_val, op_str, all_refs): - global _BAD_ARM_REF_OFF - - try: - op_name = op_str.split("@")[0][1:] # `#asc_400E5C@PAGE` -> `asc_400E5C`. - ref_ea = idc.LocByName(op_name) - if (ref_ea & mask) == op_val: - return ref_ea, mask - except: - pass - - # NOTE(pag): We deal with candidates because it's possible that this - # instruction will have multiple references. In the case of - # `@PAGE`-based offsets, it's problematic when the wrong base - # is matched, because it really throws off the C++ side of things - # because the arrangement of the lifted data being on the same - # page is not guaranteed. - - candidates = set() - for ref_ea in all_refs: - if (ref_ea & mask) == op_val: - candidates.add(ref_ea) - return ref_ea, mask - - if len(candidates): - for candidate_ea in candidates: - if candidate_ea == op_val: - return candidate_ea, mask - - return candidates.pop(), mask - - return _BAD_ARM_REF_OFF - -# Try to handle `@PAGE` and `@PAGEOFF` references, resolving them to their -# 'intended' address. -# -# TODO(pag): There must be a better way than just string searching :-/ -def _try_get_arm_ref_addr(inst, op, op_val, all_refs): - global _BAD_ARM_REF_OFF - - if op.type not in (idc.o_imm, idc.o_displ): - # This is a reference type that the other ref tracking code - # can handle, return defaults - return op_val, 0 - - op_str = idc.GetOpnd(inst.ea, op.n) - - if '@PAGEOFF' in op_str: - return _get_arm_ref_candidate(4095, op_val, op_str, all_refs) - - elif '@PAGE' in op_str: - return _get_arm_ref_candidate(-4096L, op_val, op_str, all_refs) - - elif not is_invalid_ea(op_val) and inst.get_canon_mnem().lower() == "adr": - return op_val, 0 - - return _BAD_ARM_REF_OFF - -# Returns `True` if `ea` looks like it points into the middle of an instruction. -def _is_ea_into_bad_code(ea, binary_is_pie): - if not is_code(ea): - return False - - import flow # Circular dependency! - term_inst, _ = flow.find_linear_terminator(ea) - if not term_inst: - return True - - succs = list(flow.get_static_successors(idc.BADADDR, term_inst, binary_is_pie)) - if not succs: - return True - - for succ_ea in succs: - if is_invalid_ea(succ_ea): - return True - - return False - -# Try to recognize an operand as a reference candidate when a target fixup -# is not available. -def _get_ref_candidate(inst, op, all_refs, binary_is_pie): - global _POSSIBLE_REFS, _ENABLE_CACHING - - ref = None - addr_val = idc.BADADDR - mask = 0 - is_memop = idc.o_mem == op.type - - if idc.o_imm == op.type: - addr_val = op.value - elif op.type in (idc.o_displ, idc.o_mem, idc.o_near): - addr_val = op.addr - else: - return None - - # TODO(artem): We should have a class that has ref heuristics and put ARM - # related refs in the ARM class, and X86 in the x86 class that - # will avoid these awkward `if IS_ARM` and the comments about - # x86 / amd64 stuff. - if IS_ARM: - old_addr_val = addr_val - addr_val, mask = _try_get_arm_ref_addr(inst, op, addr_val, all_refs) - - info = idaapi.refinfo_t() - has_ref_info = idaapi.get_refinfo(inst.ea, op.n, info) == 1 - - if is_invalid_ea(addr_val): - - # The `addr_val` that we get might actually be a value that is relative to - # a base address. For example, in IDA we might see: - # - # mov eax, ds:rva off_1400022FC[r9+r8*4] - # - # And we'd get `addr_val` as `0x22FC`, which isn't a valid EA. Here we - # detect this and fixup the `addr_val` to include the relative base - # of `0x140000000`. - if has_ref_info and info.is_rvaoff(): - addr_val += info.base - if is_invalid_ea(addr_val): - return None - else: - return None - - # The address is a direct memory reference. - if addr_val not in all_refs and is_memop: - all_refs.add(addr_val) - - if addr_val not in all_refs and is_head(addr_val): - all_refs.add(addr_val) - - # Some other instruction/data references this thing. Let's assume it's - # a real thing within this particular instruction. - if addr_val not in all_refs and is_referenced(addr_val): - DEBUG("WARNING: Adding reference from {:x} to {:x}, which is referenced by other stuff".format( - inst.ea, addr_val)) - all_refs.add(addr_val) - - # Curiously, sometimes `idaq` will recognize references that `idal64` will - # not. It's possible that this is due to configuration options. This happened - # in SQLite 3, where the `sqlite3_config` function references a field inside - # of the `sqlite3Config` global structure variable. - if addr_val not in all_refs and _is_address_of_struct_field(addr_val): - DEBUG("WARNING: Adding reference from {:x} to {:x}, which is a struct field".format( - inst.ea, addr_val)) - all_refs.add(addr_val) - - # Same as above, `idal64` can miss things that `idaq` gets. - if addr_val not in all_refs: - nearest_head_ea = _nearest_head(addr_val, 128) - if not is_invalid_ea(nearest_head_ea) and not _is_ea_into_bad_code(nearest_head_ea, binary_is_pie): - DEBUG("WARNING: Adding reference from {:x} to {:x}, which is near other heads".format( - inst.ea, addr_val)) - all_refs.add(addr_val) - - # # Same as above, `idal64` can miss things that `idaq` gets. - # if addr_val not in all_refs and _try_create_array(addr_val): - # all_refs.add(addr_val) - - # The idea here is that if we have seen a possible ref show up more than once, - # then lets assume it's actually a real reference. This sometimes happens - # with strings, especially in SQLite3. - if addr_val not in all_refs and addr_val in _POSSIBLE_REFS: - all_refs.add(addr_val) - DEBUG("WARNING: Adding reference from {:x} to {:x}, which appeared other times".format( - inst.ea, addr_val)) - - if addr_val not in all_refs: - DEBUG("POSSIBLE ERROR: Not adding reference from {:x} to {:x}; candidates were {}; operand type is {}, has ref info is {}".format( - inst.ea, addr_val, " ".join("{:x}".format(r) for r in all_refs), op.type, has_ref_info)) - _POSSIBLE_REFS.add(addr_val) - return None - - ref = Reference(addr_val, op.offb, mask=mask) - - # Make sure we add in a reference to the (possibly new) head, addressed - # by `addr_val`. - make_head(addr_val) - - # WTF(pag): This silently kills IDA. - # idc.add_dref(inst.ea, addr_val, idc.XREF_USER) - - return ref - -def memop_is_actually_displacement(inst): - """IDA will unhelpfully decode something like `jmp ds:off_48A5F0[rax*8]` - and tell us that this is an `o_mem` rather than an `o_displ`. We really want - to recognize it as an `o_displ` because the memory reference is a displacement - and not an absolute address.""" - asm = idc.GetDisasm(inst.ea) - return "[" in asm and "]" in asm - -# Return the set of all references from `ea` to anything. -def get_all_references_from(ea): - return set(xrefs_from(ea)) - -# This is a real hack. It can take a few tries to really find references, so -# we'll only enable reference caching after we do some processing of segments. -# Hopefully after such processing, we will have discovered item heads that IDA -# hadn't previously identified. Curiosly, `idaq` will sometimes recognize -# references or item heads that `idal64` does not. -def enable_reference_caching(): - global _ENABLE_CACHING - _ENABLE_CACHING = True - -# Get a list of references from an instruction. -def get_instruction_references(arg, binary_is_pie=False): - global _ENABLE_CACHING, _NOT_A_REF - - inst = arg - if isinstance(arg, (int, long)): - inst, _ = decode_instruction(arg) - - if not inst: - return _NO_REFS - - if _ENABLE_CACHING: - if inst.ea in _HAS_NO_REFS: - return _NO_REFS - - if inst.ea in _REFS: - return _REFS[inst.ea] - - offset_to_ref = {} - all_refs = get_all_references_from(inst.ea) - for ea in xrange(inst.ea, inst.ea + inst.size): - targ_ea = idc.GetFixupTgtOff(ea) - if not is_invalid_ea(targ_ea): - all_refs.add(targ_ea) - ref = Reference(targ_ea, ea - inst.ea) - offset_to_ref[ref.offset] = ref - - refs = [] - for i, op in enumerate(inst.Operands): - if not op.type: - continue - - op_ea = inst.ea + op.offb - ref = None - if op.offb in offset_to_ref: - ref = offset_to_ref[op.offb] - - if not ref or is_invalid_ea(ref.ea): - ref = _get_ref_candidate(inst, op, all_refs, binary_is_pie) - - if not ref or is_invalid_ea(ref.ea): - continue - - # Immediate constant, may be the absolute address of a data reference. - if idc.o_imm == op.type: - seg_begin = idaapi.getseg(ref.ea) - seg_end = idaapi.getseg(ref.ea + idc.ItemSize(ref.ea) - 1) - - # If the immediate constant is not within a segment, or crosses - # two segments then don't treat it as a reference. - if not seg_begin or not seg_end or seg_begin.startEA != seg_end.startEA: - idaapi.del_dref(op_ea, op.value) - idaapi.del_cref(op_ea, op.value, False) - continue - - # If this is a PIE-mode, 64-bit binary, then most likely the immediate - # operand is not a data ref. - if seg_begin.use64() and binary_is_pie: - idaapi.del_dref(op_ea, op.value) - idaapi.del_cref(op_ea, op.value, False) - continue - - # In the special case of "ADR" and "ADRP" instructions for aarch64 - # IDA infers the absolute immediate value to assign as op_type, rather - # than characterizing it as a displacement from PC - if idc.GetMnem(inst.ea) in ["ADRP", "ADR"]: - ref.type = Reference.DISPLACEMENT - else: - ref.type = Reference.IMMEDIATE - - ref.symbol = get_symbol_name(op_ea, ref.ea) - - # Displacement within a memory operand, excluding PC-relative - # displacements when those are memory references. - # - # Note: ref.ea may not be op.addr, this happens on AArch64 with - # @PAGE and @PAGEOFF memory operands. - elif idc.o_displ == op.type: - ref.type = Reference.DISPLACEMENT - ref.symbol = get_symbol_name(op_ea, ref.ea) - - # Absolute memory reference, and PC-relative memory reference. These - # are references that IDA can recognize statically. - elif idc.o_mem == op.type: - assert ref.ea == op.addr - if memop_is_actually_displacement(inst): - ref.type = Reference.DISPLACEMENT - else: - ref.type = Reference.MEMORY - ref.symbol = get_symbol_name(op_ea, ref.ea) - - # Code reference. - elif idc.o_near == op.type: - assert ref.ea == op.addr - ref.type = Reference.CODE - ref.symbol = get_symbol_name(op_ea, ref.ea) - - # TODO(pag): Not sure what to do with this yet. - elif idc.o_far == op.type: - DEBUG("ERROR inst={:x}\ntarget={:x}\nsym={}".format( - inst.ea, ref.ea, get_symbol_name(op_ea, ref.ea))) - assert False - - # Note: idc.o_phrase is ignored because it doesn't have a displacement, - # and so can't reference a specific symbol. - - if (inst.ea, ref.ea) not in _NOT_A_REF: - refs.append(ref) - - for ref in refs: - assert not is_invalid_ea(ref.ea) - - if len(refs): - refs = tuple(refs) - if _ENABLE_CACHING: - _REFS[inst.ea] = refs - return refs - else: - if _ENABLE_CACHING: - _HAS_NO_REFS.add(inst.ea) - return _NO_REFS diff --git a/tools/mcsema_disass/ida/segment.py b/tools/mcsema_disass/ida/segment.py deleted file mode 100644 index 4db540ddf..000000000 --- a/tools/mcsema_disass/ida/segment.py +++ /dev/null @@ -1,375 +0,0 @@ -# Copyright (c) 2017 Trail of Bits, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from flow import * -from table import * - - -def is_sane_reference_target(ea): - """Returns `True` if `target_ea` looks like the address of some code/data.""" - if is_invalid_ea(ea): - return False - - flags = idc.GetFlags(ea) - if idaapi.isAlign(flags): - return False - - if idc.isHead(flags): - return True - - if has_string_type(ea): - return True - - if idc.isTail(flags): - head_ea = idc.PrevHead(ea) - if has_string_type(head_ea): - return True - - # TODO(pag): Check if it points at a logical element in an array, or at a - # field of a struct. - - if idc.isCode(flags): - return is_block_or_instruction_head(ea) - - if is_referenced(ea): - return True - - # NOTE(pag): We test `idc.isCode` above; this check looks to see if the - # segment itself is a code segment. This check happens after - # `is_referenced`, because we may have something like a vtable - # embedded in a code segment. - if is_code(ea): - return False - - - #item_size = idc.ItemSize(ea) - - #DEBUG("!!! target_ea = {:x} item_size = {}".format(ea, item_size)) - #return 1 != item_size - #NOTE(artem): Above lines commented out since they caused problems - # and we cannot determine what they fixed. If this code has problems - # again, consider a solution that handles both cases properly - return True - -def is_read_only_segment(ea): - seg_ea = idc.SegStart(ea) - seg = idaapi.getseg(seg_ea) - - if not seg: - return False - - return (seg.perm & idaapi.SEGPERM_WRITE) == 0 - -_NOT_STRING_TYPE_EAS = set() - -# TODO(pag): Why does the following get treated as a string with type `48326`? -# -# ; struct _EXCEPTION_POINTERS ExceptionInfo -# ExceptionInfo _EXCEPTION_POINTERS -def has_string_type(ea): - global _NOT_STRING_TYPE_EAS - if ea in _NOT_STRING_TYPE_EAS: - return False - - if not is_read_only_segment(ea): - return False - - str_type = idc.GetStringType(ea) - return (str_type is not None) and str_type != -1 - -def next_reasonable_head(ea, max_ea): - """Returns the next 'reasonable' head, skipping over alignments. One heuristic - for matching strings is to see if there's an unmatched string between two - matched ones. If the next logical head is a string, but the actual head is - an alignment, then we really want to find the head of the string. - - TODO(pag): Investigate using `idc.NextNotTail(ea)`.""" - while ea < max_ea: - ea = idc.NextHead(ea, max_ea) - flags = idc.GetFlags(ea) - if not idaapi.isAlign(flags): - return ea - - return idc.BADADDR - -def find_missing_strings_in_segment(seg_ea, seg_end_ea): - """Try to find and mark missing strings in this segment.""" - global _NOT_STRING_TYPE_EAS - end_ea = idc.SegEnd(seg_ea) - ea, next_ea = seg_ea, seg_ea - last_was_string = False - - while next_ea < end_ea: - next_head_ea = next_reasonable_head(next_ea, seg_end_ea) - ea, next_ea = next_ea, next_head_ea - item_size = idc.ItemSize(ea) - if is_jump_table_entry(ea): - DEBUG("Found jump table at {:x}, jumping to {:x}".format(ea, next_ea)) - continue - - next_is_string = has_string_type(next_head_ea) - - as_str = idc.GetString(ea, -1, -1) - if has_string_type(ea): - if as_str is not None and len(as_str): - next_ea = ea + item_size - last_was_string = True - DEBUG("Found string {} of length {} at {:x}, jumping to {:x}".format( - repr(as_str), item_size, ea, next_ea)) - make_head(ea) - continue - else: - _NOT_STRING_TYPE_EAS.add(ea) - - # If we find a zero, then assume it's possibly padding between strings, and - # so don't change the state of `last_was_string`. - if 0 == read_byte(ea): - next_ea = ea + 1 - continue - - if as_str is None or not len(as_str): - last_was_string = False - continue - - # A bit aggressive, but lets try to make it into a string. - if last_was_string and 1 < len(as_str) and (ea not in RTTI_REFERENCE_TABLE.keys()): - old_item_size = idc.ItemSize(ea) - if 1 != idc.MakeStr(ea, idc.BADADDR): - last_was_string = False - continue - - item_size = idc.ItemSize(ea) - next_ea = ea + item_size - last_was_string = True - - if 1 != old_item_size or not is_referenced(ea): - DEBUG("WARNING: Made {:x} into a string of length {}".format(ea, item_size)) - continue - - # Clear the `last_was_string` flag - last_was_string = False - - # # Look for one string squashed between another. Compilers tend to place - # # all strings together, and sometimes IDA misses some of the intermediate - # # ones when they aren't directly referenced. - # if last_was_string and next_is_string: - # max_str_len = (next_head_ea - ea) - # if 1 != idc.MakeStr(ea, idc.BADADDR): - # last_was_string = False - # continue - - # item_size = idc.ItemSize(ea) - # DEBUG("Inferred string {} of length {} at {:x} to {:x}".format( - # repr(as_str), item_size, ea, next_head_ea)) - # make_head(ea) - # next_ea = ea + item_size - # last_was_string = True - -def remaining_item_size(ea): - flags = idc.GetFlags(ea) - size = idc.ItemSize(ea) - if idc.isHead(flags): - return size - - head_ea = idc.PrevHead(ea, max(0, ea - size)) - if is_invalid_ea(head_ea): - return 0 - assert (head_ea + size) >= ea - return (head_ea + size) - ea - -def find_missing_xrefs_in_segment(seg_ea, seg_end_ea, binary_is_pie): - """Look for cross-refernces that were missed by IDA. This function assumes - a natural alignments for pointers (i.e. 4- or 8-byte alignment).""" - - seg_ea = (seg_ea + 3) & ~3 # Align to a 4-byte boundary. - - try_qwords = get_address_size_in_bits() == 64 - try_dwords = True - if try_qwords and binary_is_pie: - try_dwords = False - - pointer_size = try_qwords and 8 or 4 - ea, next_ea = idc.BADADDR, seg_ea - - missing_refs = [] - - while next_ea < seg_end_ea: - ea, next_ea = next_ea, idc.BADADDR - if is_invalid_ea(ea): - break - - flags = idc.GetFlags(ea) - - # Jump over strings. - if has_string_type(ea): - item_size = max(1, remaining_item_size(ea)) # Guarantee forward progress. - next_ea = ea + item_size - DEBUG("Found string at {:x}, jumping to {:x}".format(ea, next_ea)) - continue - - if (ea % 4) != 0: - next_ea = (ea + 3) & ~3 - DEBUG("Aligning from {:x} to {:x}".format(ea, next_ea)) - assert ea < next_ea - continue - - fixup_ea = idc.GetFixupTgtOff(ea) - if binary_is_pie and not is_sane_reference_target(fixup_ea): - # This {d|q}word was not a fixup, try the next one - next_ea = ea + pointer_size - continue - - qword_data, dword_data = 0, 0 - - # Try to read it as an 8-byte pointer. - if try_qwords and (ea + 8) <= seg_end_ea: - target_ea = qword_data = read_qword(ea) - if is_sane_reference_target(target_ea): - DEBUG("Adding qword reference from {:x} to {:x}".format(ea, target_ea)) - make_xref(ea, target_ea, idc.MakeQword, 8) - next_ea = ea + 8 - continue - - # Try to read it as a 4-byte pointer. - if try_dwords and (ea + 4) <= seg_end_ea: - target_ea = dword_data = read_dword(ea) - if is_sane_reference_target(target_ea): - DEBUG("Adding dword reference from {:x} to {:x}".format(ea, target_ea)) - make_xref(ea, target_ea, idc.MakeDword, 4) - next_ea = ea + 4 - continue - - # We've got a reference from here; it might actually be that we're inside - # of a larger thing (e.g. an array, or struct) and so this reference target - # doesn't belong to `ea`, but really a nearby `ea`. Let's go and remove it. - target_ea = get_reference_target(ea) - if not is_invalid_ea(target_ea) and 0 != (qword_data | dword_data): - DEBUG("WARNING: Removing likely in-object reference from nearby {:x} to {:x}".format( - ea, target_ea)) - idaapi.do_unknown_range(ea, 4, idc.DOUNK_EXPAND) - - next_ea = ea + 4 - - DEBUG("Stopping scan at {:x}".format(ea)) - -def _next_code_or_jt_ea(ea): - """Scan forward looking for the next non-data effective address.""" - seg_end_ea = idc.SegEnd(ea) - while ea <= seg_end_ea: - flags = idc.GetFlags(ea) - if idc.isCode(flags): - break - if is_jump_table_entry(ea): - break - ea += 1 - return ea - -def find_missing_xrefs_in_code_segment(seg_ea, seg_end_ea, binary_is_pie): - """Looks for data cross-references in a code segment.""" - ea, next_ea = seg_ea, seg_ea - while next_ea < seg_end_ea: - ea = next_ea - - if is_jump_table_entry(ea): - next_ea = ea + 1 - continue - - # This manifests in AArch64 as something like: - # - # .text:00400488 LDR X0, =main - # .text:0040048C LDR X3, =__libc_csu_init - # .text:00400490 LDR X4, =__libc_csu_fini - # .text:00400494 BL .__libc_start_main - # .text:00400498 BL .abort - # .text:00400498 ; End of function _start - # .text:00400498 - # .text:00400498 ; ---------------------------------------------------- - # .text:0040049C ALIGN 0x20 - # .text:004004A0 off_4004A0 DCQ main - # .text:004004A8 off_4004A8 DCQ __libc_csu_init - # .text:004004B0 off_4004B0 DCQ __libc_csu_fini - # - # Where the `LDR` references a nearby slot in the `.text` segment wherein - # there is a reference to the real function. - # - # In x86, we see this behavior with embedded exception tables. This comes - # up a bunch in Windows binaries. - flags = idc.GetFlags(ea) - if idc.isData(flags): - next_ea = _next_code_or_jt_ea(ea + 1) - find_missing_xrefs_in_segment(ea, next_ea, binary_is_pie) - continue - - else: - next_ea = idc.NextHead(ea) - continue - - DEBUG_POP() - -def decode_segment_instructions(seg_ea, binary_is_pie): - """Tries to find all jump tables ahead of time. A side-effect of this is to - create a decoded instruction and jump table cache. The other side-effect is - that the decoding of jump tables will *remove* some cross-references.""" - seg_end_ea = idc.SegEnd(seg_ea) - for head_ea in idautils.Heads(seg_ea, seg_end_ea): - inst, _ = decode_instruction(head_ea) - get_instruction_references(inst, binary_is_pie) - table = get_jump_table(inst, binary_is_pie) - - for funcea in idautils.Functions(seg_ea, seg_end_ea): - find_default_block_heads(funcea) - -def process_segments(binary_is_pie): - """Pre-process a segment and try to fill in as many cross-references - as is possible.""" - - seg_eas = [ea for ea in idautils.Segments() if not is_invalid_ea(ea)] - - # Go through through the data segments and look for strings, and through the - # code segments and look for instructions. One result is that we should find - # and identify jump tables, which we need to do so that we don't incorrectly - # categorize some things as strings. - for seg_ea in seg_eas: - seg_name = idc.SegName(seg_ea) - seg_end_ea = idc.SegEnd(seg_ea) - if is_code(seg_ea): - DEBUG("Looking for instructions in segment {}".format(seg_name)) - DEBUG_PUSH() - decode_segment_instructions(seg_ea, binary_is_pie) - DEBUG_POP() - else: - DEBUG("Looking for strings in segment {} [{:x}, {:x})".format( - seg_name, seg_ea, seg_end_ea)) - DEBUG_PUSH() - find_missing_strings_in_segment(seg_ea, seg_end_ea) - DEBUG_POP() - - # Now go through through the data segments and find missing cross-references. - for seg_ea in seg_eas: - seg_name = idc.SegName(seg_ea) - seg_end_ea = idc.SegEnd(seg_ea) - DEBUG("Looking for cross-references in segment {} [{:x}, {:x})".format( - seg_name, seg_ea, seg_end_ea)) - - DEBUG_PUSH() - if is_code(seg_ea): - find_missing_xrefs_in_code_segment(seg_ea, seg_end_ea, binary_is_pie) - else: - find_missing_xrefs_in_segment(seg_ea, seg_end_ea, binary_is_pie) - DEBUG_POP() - - # Okay, hopefully by this point we've been able to introduce more information - # so that IDA can better find references. We'll enable caching of instruction - # references from now on so that we don't need to repeat too much work. - enable_reference_caching() diff --git a/tools/mcsema_disass/ida/table.py b/tools/mcsema_disass/ida/table.py deleted file mode 100644 index 4bd845dc8..000000000 --- a/tools/mcsema_disass/ida/table.py +++ /dev/null @@ -1,529 +0,0 @@ -# Copyright (c) 2017 Trail of Bits, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from refs import * - -_FIRST_JUMP_TABLE_ENTRY = {} -_JUMP_TABLE_ENTRY = {} - -class JumpTable(object): - """Represents generic info known about a particular jump table.""" - - def __init__(self, builder, entries): - global _FIRST_JUMP_TABLE_ENTRY, _JUMP_TABLE_ENTRY - self.inst_ea = builder.jump_ea - self.table_ea = builder.table_ea - self.offset = builder.offset - self.offset_mult = builder.offset_mult - self.entry_size = builder.entry_size - self.entry_mult = builder.entry_mult - self.entries = entries - - max_ea = self.table_ea - data_flags = (4 == self.entry_size) and idc.FF_DWRD or idc.FF_QWRD - - # Update IDA's understanding of the flow of control out of the jump - # instruction, as well as references to/from the table. - for entry_ea, target_ea in entries.items(): - idc.AddCodeXref(self.inst_ea, target_ea, idc.XREF_USER | idc.fl_JN) - max_ea = max(max_ea, entry_ea + self.entry_size) - - # Make sure each entry is seen as referenced. - for entry_ea, target_ea in entries.items(): - idc.add_dref(self.inst_ea, entry_ea, idc.dr_I) - - # Make sure that the contents of the table are no longer considered - # code (only affects `is_code`). This is only meaningful if the table - # itself is embedded in a code segment. - for ea_into_table in xrange(self.table_ea, max_ea): - mark_as_not_code(ea_into_table) - _FIRST_JUMP_TABLE_ENTRY[ea_into_table] = self.table_ea - - _JUMP_TABLE_ENTRY[self.table_ea] = self - idaapi.autoWait() - -class JumpTableBuilder(object): - _READERS = { - 4: read_dword, - 8: read_qword - } - - def __init__(self, inst, binary_is_pie): - self.entry_size = 0 - self.entry_mult = 1 - self.table_ea = idc.BADADDR - self.offset = 0 - self.offset_mult = 1 - self.jump_ea = inst.ea - self.inst = inst - self.binary_is_pie = binary_is_pie - self.candidate_target_eas = [] - - def read_entry(self, entry_ea): - data = (self._READERS[self.entry_size])(entry_ea) - data &= ((1 << (self.entry_size * 8)) - 1) - data += self.offset * self.offset_mult - data &= 0xFFFFFFFFFFFFFFFF - if 4 == self.entry_size and (self.offset & 0xFFFFFFFF) == self.offset: - data &= 0xFFFFFFFF - - return data - -def get_default_jump_table_entries(builder): - """Return the 'default' jump table entries, based on IDA's ability to - recognize a jump table. If IDA doesn't recognize the table, then we - say that there are 0 entries, but we also return what we have inferred - to be the first entry.""" - si = idaapi.get_switch_info_ex(builder.jump_ea) - if si: - next_addr = builder.table_ea - for i in xrange(si.get_jtable_size()): - target_ea = builder.read_entry(next_addr) - builder.candidate_target_eas.append(target_ea) - next_addr += builder.entry_size - else: - builder.candidate_target_eas.append(builder.read_entry(builder.table_ea)) - -def get_num_jump_table_entries(builder): - """Try to get the number of entries in a jump table. This will use some - base set of entries.""" - curr_num_targets = len(builder.candidate_target_eas) - - DEBUG("Checking if jump table at {:x} has more than {} entries".format( - builder.table_ea, curr_num_targets)) - - # Use the bounds of the function containing the jump instruction as our - # initial bounds for candidate jump table targets. - min_ea, max_ea = get_function_bounds(builder.jump_ea) - orig_min_ea, orig_max_ea = min_ea, max_ea - - # Treat the current set of targets as candidates, even if the source of - # those targets is IDA. We will assume that jump table entries point within - # a given function, or within nearby functions that IDA believes to be - # different (but hopefully are logically the same). So we will get bounds - # on the range of possible targets based on the function(s) containing the - # candidates, and use that as a scanning heuristic to find missing entries. - last_target_func = None - for i, curr_target in enumerate(builder.candidate_target_eas): - is_sane_target = is_block_or_instruction_head(curr_target) - if not is_sane_target: - DEBUG(" ERROR jump table {:x} entry candidate {} target {:x} is not sane!".format( - builder.table_ea, i, curr_target)) - continue - - targ_min_ea, targ_max_ea = get_function_bounds(curr_target) - if targ_min_ea >= max_ea or targ_max_ea <= min_ea: - DEBUG(" ERROR jump table {:x} entry candidate {} target {:x} inferred bounds are not sane".format( - builder.table_ea, i, curr_target)) - continue - - min_ea = min(min_ea, targ_min_ea) - max_ea = max(max_ea, targ_max_ea) - - if not max_ea: - return curr_num_targets - - # The candidate entries gave us a wider bound - if orig_min_ea != min_ea or orig_max_ea != max_ea: - assert (orig_max_ea - orig_min_ea) < (max_ea - min_ea) - DEBUG("Old table {:x} target bounds were [{:x}, {:x})".format( - builder.table_ea, orig_min_ea, orig_max_ea)) - - DEBUG("Jump table {:x} targets can be in the range [{:x}, {:x})".format( - builder.table_ea, min_ea, max_ea)) - - # The candidate targets have given us some rough bounds on the function, - # now lets go and check all the targets - max_i = max(curr_num_targets, 1024) - entry_addr = builder.table_ea - table_seg_ea = idc.SegStart(builder.table_ea) - for i in xrange(max_i): - - # Make sure we don't read across a segment (e.g. if the jump table is the - # last thing in our current segment). - try: - if table_seg_ea != idc.SegStart(entry_addr): - break - except: - break - - entry_data = builder.read_entry(entry_addr) - next_entry_addr = entry_addr + (builder.entry_size * builder.entry_mult) - - # We will have already checked, or assumed, the sanity of the first - # `curr_num_targets` entries of the table. - if i < curr_num_targets: - entry_addr = next_entry_addr - continue - - DEBUG(" Checking possible jump table {:x} entry {} at {:x} going to {:x}".format( - builder.table_ea, i, entry_addr, entry_data)) - - if not is_block_or_instruction_head(entry_data): - DEBUG(" Not an entry, the target {:x} isn't sane.".format(entry_data)) - break - - elif min_ea > entry_data or entry_data >= max_ea: - DEBUG(" Not an entry, the target {:x} is out of range.".format(entry_data)) - break - - # We will assume that any reference to the data in here means - # that we've gone and found the end of a table. - # - # TODO(pag): Handle more fine-grained refs, i.e. ones where there's - # a reference into the Nth byte of what could be the - # next address. - elif len(list(idautils.DataRefsTo(entry_addr))): - DEBUG(" Ignoring entry {:x} is referenced by data.".format(entry_data)) - break - elif len(list(idautils.CodeRefsTo(entry_addr, 0))): - DEBUG(" Ignoring entry {:x} is referenced by code (0).".format(entry_data)) - break - elif len(list(idautils.CodeRefsTo(entry_addr, 1))): - DEBUG(" Ignoring entry {:x} is referenced by code (1).".format(entry_data)) - break - - entry_addr = next_entry_addr - - if i != curr_num_targets: - DEBUG("Jump table at {:x} actually has {} entries".format( - builder.table_ea, i)) - - return i - -def try_get_simple_jump_table_reader(builder): - """Try to create a jump table entry reader by looking for address-sized - code pointers in the memory pointed to by `table_ea`. - - This uses heuristics like assuming certain alignments of table entries, - and that the entry targets must be code.""" - if 0 != (builder.table_ea % 4): - return False # Doesn't meet minimum alignment requirements. - - min_ea, max_ea = get_function_bounds(builder.jump_ea) - - sizes = [4] - if 64 == get_address_size_in_bits(): - sizes.insert(0, 8) - - # Try the offset table based approach first, as it's likely to be more - # constrained. - for offset in (builder.table_ea, builder.table_ea, builder.offset): - for offset_mult in (1, -1): - for entry_mult in (1, -1): - for size in sizes: - builder.offset = offset - builder.offset_mult = offset_mult - builder.entry_size = size - builder.entry_mult = entry_mult - - target_ea = builder.read_entry(builder.table_ea) - - if min_ea > target_ea or max_ea <= target_ea: - continue - - if not is_block_or_instruction_head(target_ea): - continue - - # Read the second entry from the table as a way of verifying our - # guesses on things like the offset multiplier and entry multiplier. - next_entry_addr = builder.table_ea + \ - (builder.entry_size * builder.entry_mult) - - target_ea = builder.read_entry(next_entry_addr) - if min_ea <= target_ea < max_ea and \ - is_block_or_instruction_head(target_ea): - return True - - return False - -def try_convert_table_offset_to_ea(offset): - """Try to convert a jump table offset into a valid ea, but only if it is - near the base of an existing segment. See Issue #321.""" - next_seg = idaapi.get_next_seg(offset) - if not next_seg: - return False - - next_seg_ea = next_seg.startEA - if 0x1000 > (next_seg_ea - offset): - return False - - seg_name = idc.SegName(next_seg_ea) - next_seg_end_ea = idc.SegEnd(next_seg_ea) - new_seg_ea = offset & ~0xFFF - res = idaapi.set_segm_start(next_seg_ea, new_seg_ea, idc.SEGMOD_KEEP) - if not res: - DEBUG("ERROR: Could not resize {} from [{:x},{:x}) to [{:x},{:x})".format( - seg_name, next_seg_ea, next_seg_end_ea, new_seg_ea, next_seg_end_ea)) - return False - else: - DEBUG("WARNING: Resized {} from [{:x},{:x}) to [{:x},{:x})".format( - seg_name, next_seg_ea, next_seg_end_ea, new_seg_ea, next_seg_end_ea)) - return True - -def get_ida_jump_table_reader(builder, si): - """Try to trust IDA's ability to recognize a jump table and its entries, - and return an appropriate jump table entry reader.""" - - builder.table_ea = si.jumps - DEBUG("IDA inferred jump table base: {:x}".format(builder.table_ea)) - - builder.entry_size = si.get_jtable_element_size() - - if (si.flags & idaapi.SWI_JMP_INV) == idaapi.SWI_JMP_INV: - builder.entry_mult = -1 - - DEBUG("IDA inferred jump table entry size: {}".format(builder.entry_size)) - - # Check if this is an offset based jump table, and if so, create an - # appropriate wrapper that uses the displacement from the table base - # address to find the actual jump target. - if (si.flags & idaapi.SWI_ELBASE) == idaapi.SWI_ELBASE: - builder.offset = si.elbase - - # Figure out if we need to subtract the offset instead of add it. - if (si.flags2 & idaapi.SWI2_SUBTRACT) == idaapi.SWI2_SUBTRACT: - builder.offset_mult = -1 - - DEBUG("IDA inferred jump table offset: {:x}".format(builder.offset)) - - # NOTE(pag): Converting this base to a real address is likely not correct, - # hence commenting it out. The jump table in question had - # entries like: - # - # dd offset msetTab00 - 140000000h; jump table for switch statement - # - # And then the code would add back in the `0x140000000`. The - # way we lift jump tables is to `switch` on the original EAs, - # because we can get the address of lifted LLVM basic blocks, - # so we need to make sure that the lifted computation and the - # original computation produce the same EAs for the jump targets, - # and converting the offset to be valid would be incorrect. - # - # # See Issue #321. The offset ea may end up being nearby the beginning of - # # the `.text` segment, e.g. `0x1400000000` is the offset, but the `.text` - # # begins at `0x1400001000`. - # if is_invalid_ea(builder.offset): - # DEBUG("WARNING: Table offset {:x} is not a valid address".format( - # builder.offset)) - # try_convert_table_offset_to_ea(builder.offset) - - - return True - -def get_manual_jump_table_reader(builder): - """Scan backwards looking for something that looks like a jump table, - even if it's not explicitly referenced in the current instruction. - This handles the case where we see something like a `mov` or an `lea` - of the table base address that happens before the actual `jmp`.""" - ret = False - next_inst_ea = builder.jump_ea - found_ref_eas = set() - for i in xrange(5): - inst_ea = next_inst_ea - next_inst_ea = idc.PrevHead(inst_ea) - if inst_ea == idc.BADADDR: - break - - elif builder.jump_ea != inst_ea and is_control_flow(inst_ea): - break - - refs = get_instruction_references(inst_ea, builder.binary_is_pie) - if not len(refs): - continue - - found_ref_eas.add((inst_ea, refs[0].ea)) - - builder.table_ea = refs[0].ea - builder.offset = 0 - - # Don't treat things like thunks to be tables. - if is_thunk(builder.table_ea) or is_external_segment(builder.table_ea): - builder.table_ea = idc.BADADDR - continue - - if try_get_simple_jump_table_reader(builder): - ret = True - break - - if ret: - DEBUG("Reader inferred jump table base: {:x}".format(builder.table_ea)) - if builder.offset: - DEBUG("Reader inferred jump table offset: {:x}".format(builder.offset)) - return ret - - if len(found_ref_eas) < 2: - return ret - - # We're going to try to recognize a jump table of the form: - # - # .text:00000000004009AC ADRP X1, #asc_400E5C@PAGE ; "\b" - # .text:00000000004009B0 ADD X1, X1, #asc_400E5C@PAGEOFF ; "\b" - # .text:00000000004009B4 LDR W0, [X1,W0,UXTW#2] - # .text:00000000004009B8 ADR X1, loc_4009C4 - # .text:00000000004009BC ADD X0, X1, W0,SXTW#2 - # .text:00000000004009C0 BR X0 - # - # Where it's a table of offsets (`asc_400E5C`), and the base offset is - # the basic block `loc_4009C4`. - min_ea, max_ea = get_function_bounds(builder.jump_ea) - - inst_block_ea = idc.BADADDR - block_ea = idc.BADADDR - - for inst_ea, ref_ea in found_ref_eas: - if is_code_by_flags(ref_ea) and min_ea <= ref_ea < max_ea: - inst_block_ea = inst_ea - block_ea = ref_ea - break - - if idc.BADADDR == block_ea: - return ret - - found_ref_eas.remove((inst_block_ea, block_ea)) - - # The idea here is that we want to trick the jump table reader into thinking - # that the offset of the jump table is a basic block. - for inst_ea, ref_ea in found_ref_eas: - builder.table_ea = ref_ea - builder.offset = block_ea - ret = try_get_simple_jump_table_reader(builder) - if ret: - break - - if ret: - DEBUG("Reader inferred jump table base: {:x}".format(builder.table_ea)) - if builder.offset == block_ea: - DEBUG("Reader inferred jump table offset is the block {:x}".format( - builder.offset)) - - # McSema-lifted bitcode doesn't really have a good way of getting the - # address of a basic block, and even so, we don't really want that either. - # The way our jump table lifting works is to preserve the original - # addresses and computation, and `switch` based on that, so we need to - # make sure that the original basic block address shows up in the lifted - # bitcode. - - DEBUG("WARNING: Removing reference from {:x} to block {:x}".format( - inst_block_ea, block_ea)) - remove_instruction_reference(inst_block_ea, block_ea) - - # NOTE(pag): For now we disable this jump table detection, even if it seems - # like we find the table. This is because we don't yet have a good - # way of dealing with the `ADD X0, X1, W0,SXTW#2`, which scales - # the read table entry out by shifting it left by two. Besides - # that, the following code actually works reasonably well. To - # account for this, on the C++ side, we augment jump table - # `switch`es to target blocks that are not referenced by the - # successor lists of any other blocks. - # - # It is also pretty important to make sure that we remove the - # instruction reference. If/when we have good support for this - # kind of jump table, then the above call to - # `remove_instruction_reference` has to be removed so that the - # various things that the C++ side of things does to handle offset- - # based jump tables works. - return False - -def get_jump_table_reader(builder): - """Returns the size of a jump table entry, as well as a reader function - that can extract entries.""" - si = idaapi.get_switch_info_ex(builder.jump_ea) - if si: - return get_ida_jump_table_reader(builder, si) - - # IDA can be a bit ignorant at recognizing jump tables. This came up - # in sqlite3 where IDA decided that `jmp ds:off_48A5F0[rax*8]` wasn't - # a table-based jump. It's possible that this was because IDA - # incorrectly recognized the memory operand as being an `o_mem` as - # opposed to being an `o_disp`. `get_instruction_references` correctly - # resolves this difference, so we'll also try to use it to pick up - # where IDA leaves off. - else: - return get_manual_jump_table_reader(builder) - -_JMP_THROUGH_TABLE_INFO = {} -_NOT_A_JMP_THROUGH_TABLE = set() - -def get_jump_table(inst, binary_is_pie=False): - """Returns an instance of JumpTable, or None depending on whether or not - a jump table was discovered.""" - global _JMP_THROUGH_TABLE_INFO, _NOT_A_JMP_THROUGH_TABLE - global _INVALID_JMP_TABLE - - if not inst or not is_indirect_jump(inst): - return None # Don't cache. - - if inst.ea in _JMP_THROUGH_TABLE_INFO: - return _JMP_THROUGH_TABLE_INFO[inst.ea] - - elif inst.ea in _NOT_A_JMP_THROUGH_TABLE: - return None - - elif is_external_segment(inst.ea): - _NOT_A_JMP_THROUGH_TABLE.add(inst.ea) - return None - - builder = JumpTableBuilder(inst, binary_is_pie) - - if not get_jump_table_reader(builder): - _NOT_A_JMP_THROUGH_TABLE.add(builder.jump_ea) - return None - - DEBUG("Jump table candidate at {:x} referenced by instruction {:x}".format( - builder.table_ea, builder.jump_ea)) - - get_default_jump_table_entries(builder) - - # Try to fix-up the number of entries. - num_entries = get_num_jump_table_entries(builder) - - # Treat zero- or one-entry 'tables' as not actually being tables. - if num_entries <= 1: - DEBUG("Ignoring jump table {:x} with 1 >= {} entries referenced by {:x}".format( - builder.table_ea, num_entries, builder.jump_ea)) - _NOT_A_JMP_THROUGH_TABLE.add(builder.jump_ea) - return None - - DEBUG("Jump table {:x} entries:".format(builder.table_ea)) - - # We've got a more accurate number of table entries, so go and actually - # read them to fill in our `JumpTable` data structure. - entries = {} - raw_entries = {} - entry_addr = builder.table_ea - for i in xrange(num_entries): - entry_data = builder.read_entry(entry_addr) - entries[entry_addr] = entry_data - DEBUG(" {:x} => {:x}".format(entry_addr, entry_data)) - entry_addr += builder.entry_size * builder.entry_mult - - table = JumpTable(builder, entries) - _JMP_THROUGH_TABLE_INFO[builder.jump_ea] = table - - return table - -def is_jump_table_entry(ea): - """Returns `True` if `ea` falls somewhere inside of the bytes of a jump - table.""" - global _FIRST_JUMP_TABLE_ENTRY - return ea in _FIRST_JUMP_TABLE_ENTRY - -def get_jump_table_from_entry(entry_ea): - """Returns a `JumpTable` """ - global _FIRST_JUMP_TABLE_ENTRY, _JUMP_TABLE_ENTRY - if entry_ea not in _FIRST_JUMP_TABLE_ENTRY: - return None - table_ea = _FIRST_JUMP_TABLE_ENTRY[entry_ea] - return _JUMP_TABLE_ENTRY[table_ea] diff --git a/tools/mcsema_disass/ida/util.py b/tools/mcsema_disass/ida/util.py deleted file mode 100644 index 01c095d98..000000000 --- a/tools/mcsema_disass/ida/util.py +++ /dev/null @@ -1,807 +0,0 @@ -# Copyright (c) 2017 Trail of Bits, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import collections -import idaapi -import idautils -import idc -import itertools -import struct -import inspect - -_DEBUG_FILE = None -_DEBUG_PREFIX = "" -_INFO = idaapi.get_inf_structure() - -# Map of the external functions names which does not return to a tuple containing information -# like the number of agruments and calling convention of the function. -_NORETURN_EXTERNAL_FUNC = {} - -RTTI_REFERENCE_TABLE = collections.defaultdict() - -FUNC_LSDA_ENTRIES = collections.defaultdict() - -IS_ARM = "ARM" in _INFO.procName - -# True if we are running on an ELF file. -IS_ELF = (idaapi.f_ELF == _INFO.filetype) or \ - (idc.GetLongPrm(idc.INF_FILETYPE) == idc.FT_ELF) - -# True if this is a Windows PE file. -IS_PE = idaapi.f_PE == _INFO.filetype - -if IS_ARM: - from arm_util import * -else: - from x86_util import * - -def INIT_DEBUG_FILE(file): - global _DEBUG_FILE - _DEBUG_FILE = file - -def DEBUG_PUSH(): - global _DEBUG_PREFIX - _DEBUG_PREFIX += " " - -def DEBUG_POP(): - global _DEBUG_PREFIX - _DEBUG_PREFIX = _DEBUG_PREFIX[:-2] - -def DEBUG(s): - global _DEBUG_FILE - if _DEBUG_FILE: - _DEBUG_FILE.write("{}{}\n".format(_DEBUG_PREFIX, str(s))) - -# Python 2.7's xrange doesn't work with `long`s. -def xrange(begin, end=None, step=1): - if end: - return iter(itertools.count(begin, step).next, end) - else: - return iter(itertools.count().next, begin) - -_NOT_INST_EAS = set() - -# sign extension to the given bits -def sign_extend(x, b): - m = 1 << (b - 1) - x = x & ((1 << b) - 1) - return (x ^ m) - m - -# Returns `True` if `ea` belongs to some code segment. -# -# TODO(pag): This functon is extra aggressive, in that it doesn't strictly -# trust the `idc.isCode`. I have observed cases where data in -# `.bss` is treated as code and I am not sure why. Perhaps adding -# a reference to the data did this. -# -# I think it has something to do with ELF thunks, e.g. entries in -# the `.plt` section. When I made this function stricter, -# `mcsema-lift` would report issues where it needed to add tail-calls -# to externals. -def is_code(ea): - if is_invalid_ea(ea): - return False - - seg_ea = idc.SegStart(ea) - seg_type = idc.GetSegmentAttr(seg_ea, idc.SEGATTR_TYPE) - return seg_type == idc.SEG_CODE - -# A stricter form of `is_code`, where we also check whether IDA thinks something -# is code. IDA is able to identify some things like embedded exception tables -# in the code section as not truly being code. -def is_code_by_flags(ea): - if not is_code(ea): - return False - - flags = idc.GetFlags(ea) - return idc.isCode(flags) - -def is_read_only_segment(ea): - mask_perms = idaapi.SEGPERM_WRITE | idaapi.SEGPERM_READ - perms = idc.GetSegmentAttr(ea, idc.SEGATTR_PERM) - return idaapi.SEGPERM_READ == (perms & mask_perms) - -def is_tls_segment(ea): - try: - seg_name = idc.SegName(ea) - return seg_name in (".tbss", ".tdata", ".tls") - except: - return False - -# Returns `True` if `ea` looks like a thread-local thing. -def is_tls(ea): - if is_invalid_ea(ea): - return False - - if is_tls_segment(ea): - return True - - # Something references `ea`, and that something is commented as being a - # `TLS-reference`. This comes up if you have an thread-local extern variable - # declared/used in a binary, and defined in a shared lib. There will be an - # offset variable. - for source_ea in _drefs_to(ea): - comment = idc.GetCommentEx(source_ea, 0) - if isinstance(comment, str) and "TLS-reference" in comment: - return True - - return False - -# Mark an address as containing code. -def try_mark_as_code(ea): - if is_code(ea) and not is_code_by_flags(ea): - idc.MakeCode(ea) - idaapi.autoWait() - return True - return False - -def mark_as_not_code(ea): - global _NOT_INST_EAS - _NOT_INST_EAS.add(ea) - -def read_bytes_slowly(start, end): - bytestr = [] - for i in xrange(start, end): - if idc.hasValue(idc.GetFlags(i)): - bt = idc.Byte(i) - bytestr.append(chr(bt)) - else: - bytestr.append("\x00") - return "".join(bytestr) - -def read_byte(ea): - byte = read_bytes_slowly(ea, ea + 1) - byte = ord(byte) - return byte - -def read_word(ea): - bytestr = read_bytes_slowly(ea, ea + 2) - word = struct.unpack(" 64: - DEBUG("Bad leb128 encoding at {0:x}".format(ea - shift/7)) - return idc.BADADDR - - if signed and (byte & 0x40): - val -= (1< addr_size - -def _xref_generator(ea, get_first, get_next): - target_ea = get_first(ea) - while not is_invalid_ea(target_ea): - yield target_ea - target_ea = get_next(ea, target_ea) - -def drefs_from(ea, only_one=False, check_fixup=True): - seen = False - has_one = only_one - fixup_ea = idc.BADADDR - if check_fixup: - fixup_ea = idc.GetFixupTgtOff(ea) - if not is_invalid_ea(fixup_ea) and not is_code(fixup_ea): - seen = only_one - has_one = True - yield fixup_ea - - if has_one and _stop_looking_for_xrefs(ea): - return - - for target_ea in _xref_generator(ea, idaapi.get_first_dref_from, idaapi.get_next_dref_from): - if target_ea != fixup_ea and not is_invalid_ea(target_ea): - seen = only_one - yield target_ea - if seen: - return - - if not seen and ea in _DREFS_FROM: - for target_ea in _DREFS_FROM[ea]: - yield target_ea - seen = only_one - if seen: - return - -def crefs_from(ea, only_one=False, check_fixup=True): - flags = idc.GetFlags(ea) - if not idc.isCode(flags): - return - - fixup_ea = idc.BADADDR - seen = False - has_one = only_one - if check_fixup: - fixup_ea = idc.GetFixupTgtOff(ea) - if not is_invalid_ea(fixup_ea) and is_code(fixup_ea): - seen = only_one - has_one = True - yield fixup_ea - - if has_one and _stop_looking_for_xrefs(ea): - return - - for target_ea in _xref_generator(ea, idaapi.get_first_cref_from, idaapi.get_next_cref_from): - if target_ea != fixup_ea and not is_invalid_ea(target_ea): - seen = only_one - yield target_ea - if seen: - return - - if not seen and ea in _CREFS_FROM: - for target_ea in _CREFS_FROM[ea]: - seen = only_one - yield target_ea - if seen: - return - -def xrefs_from(ea, only_one=False): - fixup_ea = idc.GetFixupTgtOff(ea) - seen = False - has_one = only_one - if not is_invalid_ea(fixup_ea): - seen = only_one - has_one = True - yield fixup_ea - - if has_one and _stop_looking_for_xrefs(ea): - return - - for target_ea in drefs_from(ea, only_one, check_fixup=False): - if target_ea != fixup_ea: - seen = only_one - yield target_ea - if seen: - return - - for target_ea in crefs_from(ea, only_one, check_fixup=False): - if target_ea != fixup_ea: - seen = only_one - yield target_ea - if seen: - return - -def _drefs_to(ea): - for source_ea in _xref_generator(ea, idaapi.get_first_dref_to, idaapi.get_next_dref_to): - yield source_ea - -def _crefs_to(ea): - for source_ea in _xref_generator(ea, idaapi.get_first_cref_to, idaapi.get_next_cref_to): - yield source_ea - -def _xrefs_to(ea): - for source_ea in _drefs_to(ea): - yield source_ea - - for source_ea in _crefs_to(ea): - yield source_ea - -def _reference_checker(ea, dref_finder=_IGNORE_DREF, cref_finder=_IGNORE_CREF): - """Looks for references to/from `ea`, and does some sanity checks on what - IDA returns.""" - for ref_ea in dref_finder(ea): - return True - - for ref_ea in cref_finder(ea): - return True - - return False - -def remove_all_refs(ea): - """Remove all references to something.""" - assert False - dref_eas = list(drefs_from(ea)) - cref_eas = list(crefs_from(ea)) - - for ref_ea in dref_eas: - idaapi.del_dref(ea, ref_ea) - - for ref_ea in cref_eas: - idaapi.del_cref(ea, ref_ea, False) - idaapi.del_cref(ea, ref_ea, True) - -def is_thunk(ea): - """Returns true if some address is a known to IDA to be a thunk.""" - flags = idc.GetFunctionFlags(ea) - return 0 < flags and 0 != (flags & idaapi.FUNC_THUNK) - -def is_referenced(ea): - """Returns `True` if the data at `ea` is referenced by something else.""" - return _reference_checker(ea, _drefs_to, _crefs_to) - -def is_referenced_by(ea, by_ea): - for ref_ea in _drefs_to(ea): - if ref_ea == by_ea: - return True - - for ref_ea in _crefs_to(ea): - if ref_ea == by_ea: - return True - - return False - -def is_runtime_external_data_reference(ea): - """This can happen in ELF binaries, where you'll have somehting like - `stdout@@GLIBC_2.2.5` in the `.bss` section, where at runtime the - linker will fill in the slot with a pointer to the real `stdout`. - - IDA discovers this type of reference, but it has no real way to - cross-reference it to anything, because the target address will - only exist at runtime.""" - comment = idc.GetCommentEx(ea, 0) - if comment and "Copy of shared data" in comment: - return True - else: - return False - -def is_external_vtable_reference(ea): - """ It checks the references of external vtable in the .bss section, where - it is referred as the `Copy of shared data`. There is no way to resolve - the cross references for these vtable as the target address will only - appear during runtime. - - It is introduced to avoid lazy initilization of runtime typeinfo variables - which gets referred by the user-defined exception types. - """ - if not is_runtime_external_data_reference(ea): - return False - - comment = idc.GetCommentEx(ea, 0) - if comment and "Alternative name is '`vtable" in comment: - return True - else: - return - -def is_reference(ea): - """Returns `True` if the `ea` references something else.""" - if is_invalid_ea(ea): - return False - - for target in xrefs_from(ea): - return True - - return is_runtime_external_data_reference(ea) - -def is_data_reference(ea): - """Returns `True` if the `ea` references something else.""" - if is_invalid_ea(ea): - return False - - for target_ea in drefs_from(ea): - return True - - return is_runtime_external_data_reference(ea) - -def has_flow_to_code(ea): - """Returns `True` if there are any control flows to the instruction at - `ea`.""" - return _reference_checker(ea, cref_finder=idautils.CodeRefsTo) - -def get_reference_target(ea): - for ref_ea in xrefs_from(ea, True): - return ref_ea - - # This is kind of funny, but it works with how we understand external - # variable references from the CFG production and LLVM side. Really, - # we need a unique location for every reference (internal and external). - # For external references, the location itself is not super important, it's - # used for identification in the LLVM side of things. - # - # When creating cross-references, we need that ability to identify the - # "target" of the cross-reference, and again, that can be anything so long - # as other parts of the code agree on the target. - if is_runtime_external_data_reference(ea): - return ea - - return idc.BADADDR - -def is_head(ea): - return idc.isHead(idc.GetFlags(ea)) - -# Make the data at `ea` into a head. -def make_head(ea): - flags = idc.GetFlags(ea) - if not idc.isHead(flags): - idc.SetFlags(ea, flags | idc.FF_DATA) - idaapi.autoWait() - return is_head(ea) - return True diff --git a/tools/mcsema_disass/ida/var_recovery.py b/tools/mcsema_disass/ida/var_recovery.py deleted file mode 100755 index ab2d3e56d..000000000 --- a/tools/mcsema_disass/ida/var_recovery.py +++ /dev/null @@ -1,500 +0,0 @@ -#!/usr/bin/env python - -import os -import sys -import argparse -import pprint - -from collections import defaultdict, OrderedDict -from collections import namedtuple -from enum import Enum - -try: - from elftools.elf.elffile import ELFFile - from elftools.common.py3compat import itervalues - from elftools.dwarf.descriptions import (describe_DWARF_expr, set_global_machine_arch, describe_CFI_instructions) - from elftools.dwarf.descriptions import describe_attr_value, describe_reg_name - from elftools.dwarf.locationlists import LocationEntry - from elftools.common.py3compat import maxint, bytes2str, byte2int, int2byte - from elftools.dwarf.callframe import instruction_name, CIE, FDE, ZERO -except ImportError: - print "Install pyelf tools" - -import CFG_pb2 - -DWARF_OPERATIONS = defaultdict(lambda: (lambda *args: None)) -SYMBOL_BLACKLIST = defaultdict(lambda: (lambda *args: None)) - -BINARY_FILE = "" - -Type = namedtuple('Type', ['name', 'size', 'type_offset', 'tag']) - -GLOBAL_VARIABLES = OrderedDict() - -TYPES_MAP = OrderedDict() - -EH_FRAMES = OrderedDict() - -BASE_TYPES = [ - 'DW_TAG_base_type', - 'DW_TAG_structure_type', - 'DW_TAG_union_type', - 'DW_TAG_enumeration_type', -] - -INDIRECT_TYPES = [ - 'DW_TAG_typedef', - 'DW_TAG_const_type', - 'DW_TAG_volatile_type', - 'DW_TAG_restrict_type', - 'DW_TAG_subroutine_type', -] - -POINTER_TYPES = { - 'DW_TAG_pointer_type' : '*', -} - -ARRAY_TYPES = { - 'DW_TAG_array_type', -} - -TYPE_ENUM = { - 'DW_TAG_unknown_type': 0, - 'DW_TAG_base_type': 1, - 'DW_TAG_structure_type' : 2, - 'DW_TAG_union_type': 3, - 'DW_TAG_pointer_type': 4, - 'DW_TAG_array_type': 5, -} - -_DEBUG = False -_DEBUG_FILE = None -_DEBUG_PREFIX = "" - -def DEBUG_INIT(file, flag): - global _DEBUG - global _DEBUG_FILE - _DEBUG = flag - _DEBUG_FILE = file - -def DEBUG_PUSH(): - global _DEBUG_PREFIX - _DEBUG_PREFIX += " " - -def DEBUG_POP(): - global _DEBUG_PREFIX - _DEBUG_PREFIX = _DEBUG_PREFIX[:-2] - -def DEBUG(s): - if _DEBUG: - _DEBUG_FILE.write("{}{}\n".format(_DEBUG_PREFIX, str(s))) - -''' - DIE attributes utilities -''' -def get_name(die): - if 'DW_AT_name' in die.attributes: - return die.attributes['DW_AT_name'].value - else: - return 'UNKNOWN' - -def get_size(die): - if 'DW_AT_byte_size' in die.attributes: - return die.attributes['DW_AT_byte_size'].value - else: - return -1 - -def get_location(die): - if 'DW_AT_location' in die.attributes: - return die.attributes['DW_AT_location'].value - else: - return None - -def get_types(die): - if 'DW_AT_type' in die.attributes: - offset = die.attributes['DW_AT_type'].value + die.cu.cu_offset - if offset in TYPES_MAP: - return (TYPES_MAP[offset], TYPES_MAP[offset].size, TYPES_MAP[offset].type_offset) - - return (Type(None, None, None, None), -1, -1) - -def _create_variable_entry(name, offset): - return dict(name=name, offset=offset, type=Type(None, None, None, None), size=0, addr=0, is_global=False) - -def process_types(dwarf, typemap): - def process_direct_types(die): - if die.tag in BASE_TYPES: - name = get_name(die) - size = get_size(die) - if die.offset not in typemap : - typemap[die.offset] = Type(name=name, size=size, type_offset=die.offset, tag=TYPE_ENUM.get(die.tag)) - DEBUG("<{0:x}> {1}".format(die.offset, typemap.get(die.offset))) - - def process_pointer_types(die): - if die.tag in POINTER_TYPES: - if 'DW_AT_type' in die.attributes: - offset = die.attributes['DW_AT_type'].value + die.cu.cu_offset - indirect = POINTER_TYPES[die.tag] - name = (typemap[offset].name if offset in typemap else 'UNKNOWN') + indirect - type_offset = typemap[offset].type_offset if offset in typemap else -1 - else: - name = 'void*' - type_offset = 0 - if die.offset not in typemap: - typemap[die.offset] = Type(name=name, size=die.cu['address_size'], type_offset=type_offset, tag=TYPE_ENUM.get(die.tag)) - DEBUG("<{0:x}> {1}".format(die.offset, typemap.get(die.offset))) - - def process_indirect_types(die): - if die.tag in INDIRECT_TYPES: - if 'DW_AT_type' in die.attributes: - offset = die.attributes['DW_AT_type'].value + die.cu.cu_offset - if offset in typemap: - size = typemap[offset].size - name = typemap[offset].name - type_offset = typemap[offset].type_offset - tag = typemap[offset].tag if offset in typemap else 0 - if die.offset not in typemap: - typemap[die.offset] = Type(name=name, size=size, type_offset=type_offset, tag=tag) - else: - tag = 0 - type_offset = 0 - name = get_name(die) - if die.offset not in typemap: - typemap[die.offset] = Type(name=name, size=-1, type_offset=type_offset, tag=tag) - DEBUG("<{0:x}> {1}".format(die.offset, typemap.get(die.offset))) - - def process_array_types(die): - if die.tag in ARRAY_TYPES: - if 'DW_AT_type' in die.attributes: - offset = die.attributes['DW_AT_type'].value + die.cu.cu_offset - if offset in typemap: - name = typemap[offset].name if offset in typemap else 'UNKNOWN' - type_offset = typemap[offset].type_offset if offset in typemap else 0 - size = typemap[offset].size if offset in typemap else 0 - # get sub range to get the array size - for child_die in die.iter_children(): - if child_die.tag == 'DW_TAG_subrange_type': - if 'DW_AT_upper_bound' in child_die.attributes: - index = child_die.attributes['DW_AT_upper_bound'].value - if type(index) is int: - index = index +1 - size = size*index - break - typemap[die.offset] = Type(name=name, size=size, type_offset=type_offset, tag=TYPE_ENUM.get(die.tag)) - DEBUG("<{0:x}> {1}".format(die.offset, typemap.get(die.offset))) - - build_typemap(dwarf, process_direct_types) - build_typemap(dwarf, process_indirect_types) - build_typemap(dwarf, process_pointer_types) - build_typemap(dwarf, process_array_types) - build_typemap(dwarf, process_indirect_types) - build_typemap(dwarf, process_array_types) - -def _process_dies(die, fn): - fn(die) - for child in die.iter_children(): - _process_dies(child, fn) - -def build_typemap(dwarf, fn): - for CU in dwarf.iter_CUs(): - top = CU.get_top_DIE() - _process_dies(top, fn) - -def _process_frames_info(dwarf, cfi_entries, eh_frames): - for entry in cfi_entries: - if isinstance(entry, CIE): - pass - elif isinstance(entry, FDE): - pc = entry['initial_location'] - if pc not in eh_frames: - eh_frames[pc] = entry - else: - continue - -def process_frames(dwarf, eh_frames): - if dwarf.has_EH_CFI(): - _process_frames_info(dwarf, dwarf.EH_CFI_entries(), eh_frames) - -def _create_global_var_entry(memory_ref, var_name): - return dict(addrs=set(), size=-1, name=var_name, type=None, safe=True) - -VARIABLE_STAT = {"type1": 0, "type2": 0} - -def address_lookup(g_ref, global_var_array): - for value, gvar in GLOBAL_VARIABLES.iteritems(): - if ((gvar['type'].tag == 1) or (gvar['type'].tag == 4)): - if gvar['addr'] == g_ref.address: - address = gvar['addr'] - size = gvar['size'] - if address not in global_var_array: - global_var_array[address] = _create_global_var_entry(address, g_ref.var.name) - global_var_array[address]['size'] = size - global_var_array[address]['type'] = g_ref.var.ida_type - for ref in g_ref.var.ref_eas: - global_var_array[address]['addrs'].add((ref.inst_addr, ref.offset)) - VARIABLE_STAT["type1"] = VARIABLE_STAT["type1"] + 1 - return None - elif (gvar['type'].tag == 5) or (gvar['type'].tag == 2): - base_address = gvar['addr'] - size = gvar['size'] - name = "recovered_global_{:0x}".format(base_address) - if g_ref.address in xrange(base_address, base_address + size): - if base_address not in global_var_array: - global_var_array[base_address] = _create_global_var_entry(base_address, name) - global_var_array[base_address]['size'] = size - global_var_array[base_address]['type'] = g_ref.var.ida_type - offset = g_ref.address - base_address - for ref in g_ref.var.ref_eas: - global_var_array[base_address]['addrs'].add((ref.inst_addr, offset)) - VARIABLE_STAT["type2"] = VARIABLE_STAT["type2"] + 1 - return None - return None - - -def _print_die(die, section_offset): - DEBUG("Processing DIE: {}".format(str(die))) - for attr in itervalues(die.attributes): - if attr.name == 'DW_AT_name' : - variable_name = attr.value - name = attr.name - if isinstance(name, int): - name = 'Unknown AT value: %x' % name - DEBUG(' <%x> %-18s: %s' % (attr.offset, name, describe_attr_value(attr, die, section_offset))) - -def _process_variable_tag(die, section_offset, M, global_var_data): - if die.tag != 'DW_TAG_variable': - return - name = get_name(die) - if 'DW_AT_location' in die.attributes: - attr = die.attributes['DW_AT_location'] - if attr.form not in ('DW_FORM_data4', 'DW_FORM_data8', 'DW_FORM_sec_offset'): - loc_expr = "{}".format(describe_DWARF_expr(attr.value, die.cu.structs)).split(':') - if loc_expr[0][1:] == 'DW_OP_addr': - memory_ref = int(loc_expr[1][:-1][1:], 16) - if memory_ref not in global_var_data: - global_var_data[memory_ref] = _create_variable_entry(name, die.offset) - global_var_data[memory_ref]['is_global'] = True - global_var_data[memory_ref]['addr'] = memory_ref - (type, size, offset) = get_types(die) - global_var_data[memory_ref]['type'] = type - global_var_data[memory_ref]['size'] = size - DEBUG("{}".format(pprint.pformat(global_var_data[memory_ref]))) # DEBUG_ENABLE - -def _full_reg_name(regnum): - regname = describe_reg_name(regnum, None, False) - if regname: - return 'r%s (%s)' % (regnum, regname) - else: - return 'r%s' % regnum - -""" - Process subprogram tag and recover the local variables -""" -def _process_subprogram_tag(die, section_offset, M, global_var_data): - if die.tag != 'DW_TAG_subprogram': - return - - F = M.funcs.add() - F.ea = 0 - F.name = get_name(die) - F.is_entrypoint = 0 - has_frame = False - frame_regname = "" - - if 'DW_AT_frame_base' in die.attributes: - frame_attr = die.attributes['DW_AT_frame_base'] - has_frame = True - loc_expr = "{}".format(describe_DWARF_expr(frame_attr.value, die.cu.structs)).split(' ') - if loc_expr[0][1:][:-1] == "DW_OP_call_frame_cfa": - lowpc_attr = die.attributes['DW_AT_low_pc'] - #DEBUG("loc_expr {0} {1:x}".format(loc_expr, lowpc_attr.value)) - frame = EH_FRAMES[lowpc_attr.value] if lowpc_attr.value in EH_FRAMES else None - if frame: - DEBUG("{0:x}, {1}".format(frame['initial_location'], frame)) - for instr in frame.instructions: - name = instruction_name(instr.opcode) - if name == 'DW_CFA_def_cfa_register': - frame_regname = describe_reg_name(instr.args[0], None, False) - - for child in die.iter_children(): - if child.tag != 'DW_TAG_variable': - continue - - stackvar = F.stack_vars.add() - stackvar.name = get_name(child) - stackvar.sp_offset = 0 - stackvar.has_frame = has_frame - stackvar.reg_name = frame_regname - (type, size, offset) = get_types(child) - stackvar.size = size if size > 0 else 0 - - if 'DW_AT_location' in child.attributes: - attr = child.attributes['DW_AT_location'] - if attr.form not in ('DW_FORM_data4', 'DW_FORM_data8', 'DW_FORM_sec_offset'): - loc_expr = "{}".format(describe_DWARF_expr(attr.value, child.cu.structs)).split(' ') - if loc_expr[0][1:][:-1] == 'DW_OP_fbreg': - offset = int(loc_expr[1][:-1]) - stackvar.sp_offset = offset - -DWARF_OPERATIONS = { - #'DW_TAG_compile_unit': _process_compile_unit_tag, - 'DW_TAG_variable' : _process_variable_tag, - 'DW_TAG_subprogram' : _process_subprogram_tag, -} - -class CUnit(object): - def __init__(self, die, cu_len, cu_offset, global_offset = 0): - self._die = die - self._length = cu_len - self._offset = cu_offset - self._section_offset = global_offset - self._global_variable = dict() - - def _process_child(self, child_die, M, global_var_data): - for child in child_die.iter_children(): - func_ = DWARF_OPERATIONS.get(child.tag) - if func_: - func_(child, self._section_offset, M, global_var_data) - continue - self._process_child(child, M, global_var_data) - - def decode_control_unit(self, M, global_var_data): - for child in self._die.iter_children(): - func_ = DWARF_OPERATIONS.get(child.tag) - if func_: - func_(child, self._section_offset, M, global_var_data) - continue - self._process_child(child, M, global_var_data) - - -def process_dwarf_info(in_file, out_file): - ''' - Main function processing the dwarf informations from debug sections - ''' - DEBUG('Processing file: {0}'.format(in_file)) - - with open(in_file, 'rb') as f: - f_elf = ELFFile(f) - if not f_elf.has_dwarf_info(): - DEBUG("{0} has no debug informations!".format(file)) - return False - - M = CFG_pb2.Module() - M.name = "GlobalVariable".format('utf-8') - - set_global_machine_arch(f_elf.get_machine_arch()) - dwarf_info = f_elf.get_dwarf_info() - process_types(dwarf_info, TYPES_MAP) - process_frames(dwarf_info, EH_FRAMES) - section_offset = dwarf_info.debug_info_sec.global_offset - - # Iterate through all the compile units - for CU in dwarf_info.iter_CUs(): - DEBUG('Found a compile unit at offset {0}, length {1}'.format(CU.cu_offset, CU['unit_length'])) - top_DIE = CU.get_top_DIE() - c_unit = CUnit(top_DIE, CU['unit_length'], CU.cu_offset, section_offset) - c_unit.decode_control_unit(M, GLOBAL_VARIABLES) - - for key, value in GLOBAL_VARIABLES.iteritems(): - if value["size"] > 0: - gvar = M.global_vars.add() - gvar.name = value["name"] - gvar.ea = value["addr"] - gvar.size = value["size"] - else: - DEBUG("Look for {}".format(pprint.pformat(value))) - - #for func in M.funcs: - # DEBUG("Function name {}".format(func.name)) - # for sv in func.stackvars: - # DEBUG_PUSH() - # DEBUG("{} : {}, ".format(sv.name, sv.sp_offset)) - # DEBUG_POP() - - - with open(out_file, "w") as outf: - outf.write(M.SerializeToString()) - - DEBUG("Global Vars\n") - DEBUG('Number of Global Vars: {0}'.format(len(GLOBAL_VARIABLES))) - DEBUG("{}".format(pprint.pformat(GLOBAL_VARIABLES))) - DEBUG("End Global Vars\n") - -def is_global_variable_reference(global_var, address): - for key in sorted(global_var.iterkeys()): - entry = global_var[key] - start = key - end = start + entry['size'] - if (start <= address) and (end > address): - return True - return False - -def add_global_variable_entry(M, ds): - for g in M.global_vars: - start = g.address - end = start + g.var.size - if (ds.base_address >= start) and (ds.base_address < end): - symbol = g.symbols.add() - symbol.base_address = ds.base_address - symbol.symbol_name = ds.symbol_name - symbol.symbol_size = ds.symbol_size - -def updateCFG(in_file, out_file): - global_var_array = dict() - - M = CFG_pb2.Module() - with open(in_file, 'rb') as inf: - M.ParseFromString(inf.read()) - GV = list(M.global_vars) - DEBUG('Number of Global Variables recovered from dwarf: {0}'.format(len(GLOBAL_VARIABLES))) - for g in GV: - gvar = address_lookup(g, global_var_array) - if gvar is None: - DEBUG("Global Vars {} {}".format(str(g.var.name), hex(g.address))) - M.global_vars.remove(g) - - for key in sorted(global_var_array.iterkeys()): - entry = global_var_array[key] - var = M.global_vars.add() - var.address = key - var.var.name = entry['name'] - var.var.size = entry['size'] - var.var.ida_type = entry['type'] - for i in entry["addrs"]: - r = var.var.ref_eas.add() - r.inst_addr = i[0] - r.offset = i[1] - - for data in M.internal_data: - for ds in data.symbols: - symbol = ds.symbol_name.split("_") - if (symbol[0] == 'data') and (is_global_variable_reference(global_var_array, long(symbol[1], 16)) is True): - ds.symbol_name = "recovered_global_{0:x}".format(long(symbol[1], 16)) - add_global_variable_entry(M, ds) - - with open(out_file, "w") as outf: - outf.write(M.SerializeToString()) - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument("--log_file", type=argparse.FileType('w'), - default=sys.stderr, - help='Name of the log file. Default is stderr.') - - parser.add_argument('--out', - help='Name of the output proto buffer file.', - required=True) - - parser.add_argument('--binary', - help='Name of the binary image.', - required=True) - - args = parser.parse_args(sys.argv[1:]) - - if args.log_file: - DEBUG_INIT(args.log_file, True) - DEBUG("Debugging is enabled.") - - BINARY_FILE = args.binary - process_dwarf_info(args.binary, args.out) - \ No newline at end of file diff --git a/tools/mcsema_disass/ida/variable_analysis_binja.py b/tools/mcsema_disass/ida/variable_analysis_binja.py deleted file mode 100644 index bfd87af25..000000000 --- a/tools/mcsema_disass/ida/variable_analysis_binja.py +++ /dev/null @@ -1,172 +0,0 @@ -#!/usr/bin/env python - -# Copyright (c) 2018 Trail of Bits, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import sys -import collections -import argparse -import pprint -from binaryninja import * -import mcsema_disass.ida.CFG_pb2 -from binja_var_recovery.util import * -from binja_var_recovery.il_function import * - -def is_exported_symbol(bv, sym): - if sym.type == SymbolType.DataSymbol and \ - is_data_variable(bv, sym.address): - return True - return False - -def get_symbols(bv): - for syms in bv.symbols.values(): - if isinstance(syms, Symbol): - yield (syms) - else: - for entry in syms: - yield (entry) - -def identify_exported_symbols(bv): - syms = sorted(get_symbols(bv), key=lambda s: s.address) - for i, sym in enumerate(syms): - sect = get_section_at(bv, sym.address) - if sect is None: - continue - - if is_exported_symbol(bv, sym) and \ - not is_section_external(bv, sect): - EXPORTED_REFS[sym.address] = sym.address - -# main function -def main(args): - """ Function which recover the variables from the medium-level IL instructions; - 1) Get the data variables and populate the list with possible sizes and references; The data variables - recovered may not be having the correct size which should get fixed at later point - """ - bv = BinaryViewType.get_view_of_file(args.binary) - bv.add_analysis_option("linearsweep") - bv.update_analysis_and_wait() - process_binary(bv, args.binary) - - DEBUG("Analysis file {} loaded...".format(args.binary)) - DEBUG("Number of functions {}".format(len(bv.functions))) - - entry_symbol = bv.get_symbols_by_name(args.entrypoint)[0] - DEBUG("Entry points {:x} {} {} ".format(entry_symbol.address, entry_symbol.name, len(bv.functions))) - - # recover the exported symbols from the binary - identify_exported_symbols(bv) - - # Create function objects and collect its references - for func in bv.functions: - create_function(bv, func) - - entry_addr = entry_symbol.address - recover_function(bv, entry_addr, is_entry=True) - - # Recover any discovered functions until there are none left - while not TO_RECOVER.empty(): - addr = TO_RECOVER.get() - if addr not in RECOVERED: - RECOVERED.add(addr) - DEBUG("STAT -> Recovering {} out of {} functions...".format(len(RECOVERED), len(bv.functions))) - recover_function(bv, addr) - - if TO_RECOVER.empty() and (len(bv.functions) > 0): - for func in bv.functions: - if func.start not in RECOVERED: - queue_func(func.start) - break - - DEBUG("Number of functions {} {}".format(len(bv.functions), TO_RECOVER.qsize())) - updateCFG(bv, args.out) - print_variables(bv) - -def get_variable_size(bv, next_var, var): - sec = get_section_at(bv, var) - if sec is None: - return 0 - if sec.end > next_var: - return next_var - var - else: - return sec.end - var - -def generate_variable_list(bv): - g_variables = collections.defaultdict() - for ref, size in get_dynamic_symbol(bv): - g_variables[ref] = size - - for ref, size in get_memory_refs(bv): - DEBUG("Memory ref : {:x} size {:x}".format(ref, size)) - g_variables[ref] = size - - for ref, size in get_address_refs(bv): - DEBUG("Address ref : {:x} size 0".format(ref)) - g_variables[ref] = size - - variable_list = sorted(g_variables.iterkeys()) - for index, addr in enumerate(variable_list): - try: - size = get_variable_size(bv, variable_list[index+1], addr) - except IndexError: - sec = get_section_at(bv, addr) - if sec is None: - continue - size = get_variable_size(bv, sec.end, addr) - g_variables[addr] = size - - DEBUG("Number of global symbols {}".format(len(g_variables))) - return g_variables - -def updateCFG(bv, outfile): - """ Update the CFG file with the recovered global variables - """ - M = mcsema_disass.ida.CFG_pb2.Module() - M.name = "GlobalVariables".format('utf-8') - - g_variables = generate_variable_list(bv) - for key in sorted(g_variables.iterkeys()): - var = M.global_vars.add() - var.ea = key - var.name = "global_var_{:x}".format(key) - var.size = g_variables[key] - - with open(outfile, "w") as outf: - outf.write(M.SerializeToString()) - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument("--log_file", type=argparse.FileType('w'), - default=sys.stderr, - help='Name of the log file. Default is stderr.') - - parser.add_argument('--out', - help='Name of the output proto buffer file.', - required=True) - - parser.add_argument('--binary', - help='Name of the binary image.', - required=True) - - parser.add_argument('--entrypoint', - help='Name of the entry point function.', - required=True) - - args = parser.parse_args(sys.argv[1:]) - - if args.log_file: - INIT_DEBUG_FILE(args.log_file) - DEBUG("Debugging is enabled.") - - main(args) diff --git a/tools/mcsema_disass/ida/x86_util.py b/tools/mcsema_disass/ida/x86_util.py deleted file mode 100644 index 82c2be6ab..000000000 --- a/tools/mcsema_disass/ida/x86_util.py +++ /dev/null @@ -1,123 +0,0 @@ -# Copyright (c) 2017 Trail of Bits, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import collections -import idaapi -import idautils -import idc - -# Maps instruction EAs to a pair of decoded inst, and the bytes of the inst. -PREFIX_ITYPES = (idaapi.NN_lock, idaapi.NN_rep, - idaapi.NN_repe, idaapi.NN_repne) - -PERSONALITY_NORMAL = 0 -PERSONALITY_DIRECT_JUMP = 1 -PERSONALITY_INDIRECT_JUMP = 2 -PERSONALITY_DIRECT_CALL = 3 -PERSONALITY_INDIRECT_CALL = 4 -PERSONALITY_RETURN = 5 -PERSONALITY_SYSTEM_CALL = 6 -PERSONALITY_SYSTEM_RETURN = 7 -PERSONALITY_CONDITIONAL_BRANCH = 8 -PERSONALITY_TERMINATOR = 9 - -PERSONALITIES = collections.defaultdict(int) -PERSONALITIES.update({ - idaapi.NN_call: PERSONALITY_DIRECT_CALL, - idaapi.NN_callfi: PERSONALITY_INDIRECT_CALL, - idaapi.NN_callni: PERSONALITY_INDIRECT_CALL, - - idaapi.NN_retf: PERSONALITY_RETURN, - idaapi.NN_retfd: PERSONALITY_RETURN, - idaapi.NN_retfq: PERSONALITY_RETURN, - idaapi.NN_retfw: PERSONALITY_RETURN, - idaapi.NN_retn: PERSONALITY_RETURN, - idaapi.NN_retnd: PERSONALITY_RETURN, - idaapi.NN_retnq: PERSONALITY_RETURN, - idaapi.NN_retnw: PERSONALITY_RETURN, - - idaapi.NN_jmp: PERSONALITY_DIRECT_JUMP, - idaapi.NN_jmpshort: PERSONALITY_DIRECT_JUMP, - idaapi.NN_jmpfi: PERSONALITY_INDIRECT_JUMP, - idaapi.NN_jmpni: PERSONALITY_INDIRECT_JUMP, - - idaapi.NN_int: PERSONALITY_SYSTEM_CALL, - idaapi.NN_into: PERSONALITY_SYSTEM_CALL, - idaapi.NN_int3: PERSONALITY_SYSTEM_CALL, - idaapi.NN_bound: PERSONALITY_SYSTEM_CALL, - idaapi.NN_syscall: PERSONALITY_SYSTEM_CALL, - idaapi.NN_sysenter: PERSONALITY_SYSTEM_CALL, - - idaapi.NN_iretw: PERSONALITY_SYSTEM_RETURN, - idaapi.NN_iret: PERSONALITY_SYSTEM_RETURN, - idaapi.NN_iretd: PERSONALITY_SYSTEM_RETURN, - idaapi.NN_iretq: PERSONALITY_SYSTEM_RETURN, - idaapi.NN_sysret: PERSONALITY_SYSTEM_RETURN, - idaapi.NN_sysexit: PERSONALITY_SYSTEM_RETURN, - - idaapi.NN_hlt: PERSONALITY_TERMINATOR, - idaapi.NN_ud2: PERSONALITY_TERMINATOR, - idaapi.NN_icebp: PERSONALITY_TERMINATOR, - - idaapi.NN_ja: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_jae: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_jb: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_jbe: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_jc: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_jcxz: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_je: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_jecxz: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_jg: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_jge: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_jl: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_jle: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_jna: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_jnae: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_jnb: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_jnbe: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_jnc: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_jne: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_jng: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_jnge: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_jnl: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_jnle: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_jno: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_jnp: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_jns: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_jnz: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_jo: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_jp: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_jpe: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_jpo: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_jrcxz: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_js: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_jz: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_xbegin: PERSONALITY_CONDITIONAL_BRANCH, - - idaapi.NN_loopw: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_loop: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_loopd: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_loopq: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_loopwe: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_loope: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_loopde: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_loopqe: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_loopwne: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_loopne: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_loopdne: PERSONALITY_CONDITIONAL_BRANCH, - idaapi.NN_loopqne: PERSONALITY_CONDITIONAL_BRANCH, -}) - -def fixup_personality(inst, p): - return p diff --git a/tools/mcsema_disass/ida7/CFG_pb2.py b/tools/mcsema_disass/ida7/CFG_pb2.py index 4f14ed1c1..d06ed16ba 100644 --- a/tools/mcsema_disass/ida7/CFG_pb2.py +++ b/tools/mcsema_disass/ida7/CFG_pb2.py @@ -3,6 +3,7 @@ import sys _b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) +from google.protobuf.internal import enum_type_wrapper from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message from google.protobuf import reflection as _reflection @@ -18,33 +19,71 @@ _sym_db = _symbol_database.Default() DESCRIPTOR = _descriptor.FileDescriptor( name='CFG.proto', package='mcsema', - serialized_pb=_b('\n\tCFG.proto\x12\x06mcsema\"\xaf\x03\n\rCodeReference\x12\x35\n\x0btarget_type\x18\x01 \x02(\x0e\x32 .mcsema.CodeReference.TargetType\x12\x37\n\x0coperand_type\x18\x02 \x02(\x0e\x32!.mcsema.CodeReference.OperandType\x12\x30\n\x08location\x18\x03 \x02(\x0e\x32\x1e.mcsema.CodeReference.Location\x12\n\n\x02\x65\x61\x18\x04 \x02(\x03\x12\x0c\n\x04mask\x18\x05 \x01(\x03\x12\x0c\n\x04name\x18\x06 \x01(\t\",\n\nTargetType\x12\x0e\n\nCodeTarget\x10\x00\x12\x0e\n\nDataTarget\x10\x01\"~\n\x0bOperandType\x12\x14\n\x10ImmediateOperand\x10\x00\x12\x11\n\rMemoryOperand\x10\x01\x12\x1d\n\x19MemoryDisplacementOperand\x10\x02\x12\x16\n\x12\x43ontrolFlowOperand\x10\x03\x12\x0f\n\x0bOffsetTable\x10\x04\"&\n\x08Location\x12\x0c\n\x08Internal\x10\x00\x12\x0c\n\x08\x45xternal\x10\x01\"u\n\x0bInstruction\x12\n\n\x02\x65\x61\x18\x01 \x02(\x03\x12\r\n\x05\x62ytes\x18\x02 \x02(\x0c\x12$\n\x05xrefs\x18\x03 \x03(\x0b\x32\x15.mcsema.CodeReference\x12\x16\n\x0elocal_noreturn\x18\x04 \x01(\x08\x12\r\n\x05lp_ea\x18\x05 \x01(\x04\"U\n\x05\x42lock\x12\n\n\x02\x65\x61\x18\x01 \x02(\x03\x12)\n\x0cinstructions\x18\x02 \x03(\x0b\x32\x13.mcsema.Instruction\x12\x15\n\rsuccessor_eas\x18\x03 \x03(\x03\"\xaf\x01\n\x08\x46unction\x12\n\n\x02\x65\x61\x18\x01 \x02(\x03\x12\x1d\n\x06\x62locks\x18\x02 \x03(\x0b\x32\r.mcsema.Block\x12\x15\n\ris_entrypoint\x18\x03 \x02(\x08\x12\x0c\n\x04name\x18\x04 \x01(\t\x12)\n\nstack_vars\x18\x05 \x03(\x0b\x32\x15.mcsema.StackVariable\x12(\n\x08\x65h_frame\x18\x06 \x03(\x0b\x32\x16.mcsema.ExceptionFrame\"\x90\x02\n\x10\x45xternalFunction\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\n\n\x02\x65\x61\x18\x02 \x02(\x03\x12\x36\n\x02\x63\x63\x18\x03 \x02(\x0e\x32*.mcsema.ExternalFunction.CallingConvention\x12\x12\n\nhas_return\x18\x04 \x02(\x08\x12\x11\n\tno_return\x18\x05 \x02(\x08\x12\x16\n\x0e\x61rgument_count\x18\x06 \x02(\x05\x12\x0f\n\x07is_weak\x18\x07 \x02(\x08\x12\x11\n\tsignature\x18\x08 \x01(\t\"G\n\x11\x43\x61llingConvention\x12\x11\n\rCallerCleanup\x10\x00\x12\x11\n\rCalleeCleanup\x10\x01\x12\x0c\n\x08\x46\x61stCall\x10\x02\"d\n\x10\x45xternalVariable\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\n\n\x02\x65\x61\x18\x02 \x02(\x03\x12\x0c\n\x04size\x18\x03 \x02(\x05\x12\x0f\n\x07is_weak\x18\x04 \x02(\x08\x12\x17\n\x0fis_thread_local\x18\x05 \x02(\x08\"\xe7\x01\n\rDataReference\x12\n\n\x02\x65\x61\x18\x01 \x02(\x03\x12\r\n\x05width\x18\x02 \x02(\x05\x12\x11\n\ttarget_ea\x18\x04 \x02(\x03\x12\x13\n\x0btarget_name\x18\x05 \x02(\t\x12\x16\n\x0etarget_is_code\x18\x06 \x02(\x08\x12@\n\x11target_fixup_kind\x18\x08 \x02(\x0e\x32%.mcsema.DataReference.TargetFixupKind\"9\n\x0fTargetFixupKind\x12\x0c\n\x08\x41\x62solute\x10\x00\x12\x18\n\x14OffsetFromThreadBase\x10\x01\"$\n\x08Variable\x12\n\n\x02\x65\x61\x18\x01 \x02(\x03\x12\x0c\n\x04name\x18\x02 \x02(\t\",\n\tReference\x12\x0f\n\x07inst_ea\x18\x01 \x02(\x04\x12\x0e\n\x06offset\x18\x02 \x02(\x03\"\xcc\x01\n\x0e\x45xceptionFrame\x12\x0f\n\x07\x66unc_ea\x18\x01 \x02(\x04\x12\x10\n\x08start_ea\x18\x03 \x02(\x04\x12\x0e\n\x06\x65nd_ea\x18\x04 \x02(\x04\x12\r\n\x05lp_ea\x18\x05 \x02(\x04\x12-\n\x06\x61\x63tion\x18\x06 \x02(\x0e\x32\x1d.mcsema.ExceptionFrame.Action\x12\'\n\x05ttype\x18\x07 \x03(\x0b\x32\x18.mcsema.ExternalVariable\" \n\x06\x41\x63tion\x12\x0b\n\x07\x43leanup\x10\x00\x12\t\n\x05\x43\x61tch\x10\x01\"\x87\x01\n\rStackVariable\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\x0c\n\x04size\x18\x02 \x02(\x04\x12\x11\n\tsp_offset\x18\x03 \x02(\x03\x12\x11\n\thas_frame\x18\x04 \x01(\x08\x12\x10\n\x08reg_name\x18\x05 \x01(\t\x12\"\n\x07ref_eas\x18\x06 \x03(\x0b\x32\x11.mcsema.Reference\"8\n\x0eGlobalVariable\x12\n\n\x02\x65\x61\x18\x01 \x02(\x03\x12\x0c\n\x04name\x18\x02 \x02(\t\x12\x0c\n\x04size\x18\x03 \x02(\x03\"\xe4\x01\n\x07Segment\x12\n\n\x02\x65\x61\x18\x01 \x02(\x03\x12\x0c\n\x04\x64\x61ta\x18\x02 \x02(\x0c\x12\x11\n\tread_only\x18\x03 \x02(\x08\x12\x13\n\x0bis_external\x18\x04 \x02(\x08\x12\x0c\n\x04name\x18\x05 \x02(\t\x12\x15\n\rvariable_name\x18\x06 \x01(\t\x12\x13\n\x0bis_exported\x18\x07 \x02(\x08\x12\x17\n\x0fis_thread_local\x18\x08 \x02(\x08\x12$\n\x05xrefs\x18\t \x03(\x0b\x32\x15.mcsema.DataReference\x12\x1e\n\x04vars\x18\n \x03(\x0b\x32\x10.mcsema.Variable\"\xea\x01\n\x06Module\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\x1f\n\x05\x66uncs\x18\x02 \x03(\x0b\x32\x10.mcsema.Function\x12!\n\x08segments\x18\x03 \x03(\x0b\x32\x0f.mcsema.Segment\x12\x30\n\x0e\x65xternal_funcs\x18\x04 \x03(\x0b\x32\x18.mcsema.ExternalFunction\x12/\n\rexternal_vars\x18\x05 \x03(\x0b\x32\x18.mcsema.ExternalVariable\x12+\n\x0bglobal_vars\x18\x08 \x03(\x0b\x32\x16.mcsema.GlobalVariable') + serialized_pb=_b('\n\tCFG.proto\x12\x06mcsema\"5\n\x11PreservationRange\x12\x10\n\x08\x62\x65gin_ea\x18\x01 \x02(\x03\x12\x0e\n\x06\x65nd_ea\x18\x02 \x01(\x03\"R\n\x12PreservedRegisters\x12\x11\n\tregisters\x18\x01 \x03(\t\x12)\n\x06ranges\x18\x02 \x03(\x0b\x32\x19.mcsema.PreservationRange\"\xe2\x01\n\rCodeReference\x12\x37\n\x0coperand_type\x18\x01 \x02(\x0e\x32!.mcsema.CodeReference.OperandType\x12\n\n\x02\x65\x61\x18\x02 \x02(\x03\x12\x0c\n\x04mask\x18\x03 \x01(\x03\"~\n\x0bOperandType\x12\x14\n\x10ImmediateOperand\x10\x00\x12\x11\n\rMemoryOperand\x10\x01\x12\x1d\n\x19MemoryDisplacementOperand\x10\x02\x12\x16\n\x12\x43ontrolFlowOperand\x10\x03\x12\x0f\n\x0bOffsetTable\x10\x04\"N\n\x0bInstruction\x12\n\n\x02\x65\x61\x18\x01 \x02(\x03\x12$\n\x05xrefs\x18\x02 \x03(\x0b\x32\x15.mcsema.CodeReference\x12\r\n\x05lp_ea\x18\x03 \x01(\x04\"t\n\x05\x42lock\x12\n\n\x02\x65\x61\x18\x01 \x02(\x03\x12)\n\x0cinstructions\x18\x02 \x03(\x0b\x32\x13.mcsema.Instruction\x12\x15\n\rsuccessor_eas\x18\x03 \x03(\x03\x12\x1d\n\x15is_referenced_by_data\x18\x04 \x02(\x08\"2\n\x0eMemoryLocation\x12\x10\n\x08register\x18\x01 \x02(\t\x12\x0e\n\x06offset\x18\x02 \x01(\x03\"a\n\tValueDecl\x12\x0c\n\x04type\x18\x01 \x02(\t\x12&\n\x06memory\x18\x02 \x01(\x0b\x32\x16.mcsema.MemoryLocation\x12\x10\n\x08register\x18\x03 \x01(\t\x12\x0c\n\x04name\x18\x04 \x01(\t\"\x9c\x02\n\x0c\x46unctionDecl\x12%\n\nparameters\x18\x01 \x03(\x0b\x32\x11.mcsema.ValueDecl\x12(\n\rreturn_values\x18\x02 \x03(\x0b\x32\x11.mcsema.ValueDecl\x12)\n\x0ereturn_address\x18\x03 \x02(\x0b\x32\x11.mcsema.ValueDecl\x12/\n\x14return_stack_pointer\x18\x04 \x02(\x0b\x32\x11.mcsema.ValueDecl\x12\x13\n\x0bis_variadic\x18\x05 \x02(\x08\x12\x13\n\x0bis_noreturn\x18\x06 \x02(\x08\x12\x35\n\x12\x63\x61lling_convention\x18\x07 \x02(\x0e\x32\x19.mcsema.CallingConvention\"\xa8\x01\n\x08\x46unction\x12\n\n\x02\x65\x61\x18\x01 \x02(\x03\x12\x1d\n\x06\x62locks\x18\x02 \x03(\x0b\x32\r.mcsema.Block\x12\x15\n\ris_entrypoint\x18\x03 \x02(\x08\x12\x0c\n\x04name\x18\x04 \x01(\t\x12(\n\x08\x65h_frame\x18\x05 \x03(\x0b\x32\x16.mcsema.ExceptionFrame\x12\"\n\x04\x64\x65\x63l\x18\x06 \x01(\x0b\x32\x14.mcsema.FunctionDecl\"\xa1\x02\n\x10\x45xternalFunction\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\n\n\x02\x65\x61\x18\x02 \x02(\x03\x12\x36\n\x02\x63\x63\x18\x03 \x02(\x0e\x32*.mcsema.ExternalFunction.CallingConvention\x12\x12\n\nhas_return\x18\x04 \x02(\x08\x12\x11\n\tno_return\x18\x05 \x02(\x08\x12\x16\n\x0e\x61rgument_count\x18\x06 \x02(\x05\x12\x0f\n\x07is_weak\x18\x07 \x02(\x08\x12\"\n\x04\x64\x65\x63l\x18\x08 \x01(\x0b\x32\x14.mcsema.FunctionDecl\"G\n\x11\x43\x61llingConvention\x12\x11\n\rCallerCleanup\x10\x00\x12\x11\n\rCalleeCleanup\x10\x01\x12\x0c\n\x08\x46\x61stCall\x10\x02\"d\n\x10\x45xternalVariable\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\n\n\x02\x65\x61\x18\x02 \x02(\x03\x12\x0c\n\x04size\x18\x03 \x02(\x05\x12\x0f\n\x07is_weak\x18\x04 \x02(\x08\x12\x17\n\x0fis_thread_local\x18\x05 \x02(\x08\"\xba\x01\n\rDataReference\x12\n\n\x02\x65\x61\x18\x01 \x02(\x03\x12\r\n\x05width\x18\x02 \x02(\x05\x12\x11\n\ttarget_ea\x18\x03 \x02(\x03\x12@\n\x11target_fixup_kind\x18\x04 \x02(\x0e\x32%.mcsema.DataReference.TargetFixupKind\"9\n\x0fTargetFixupKind\x12\x0c\n\x08\x41\x62solute\x10\x00\x12\x18\n\x14OffsetFromThreadBase\x10\x01\"$\n\x08Variable\x12\n\n\x02\x65\x61\x18\x01 \x02(\x03\x12\x0c\n\x04name\x18\x02 \x02(\t\",\n\tReference\x12\x0f\n\x07inst_ea\x18\x01 \x02(\x04\x12\x0e\n\x06offset\x18\x02 \x02(\x03\"\xcc\x01\n\x0e\x45xceptionFrame\x12\x0f\n\x07\x66unc_ea\x18\x01 \x02(\x04\x12\x10\n\x08start_ea\x18\x03 \x02(\x04\x12\x0e\n\x06\x65nd_ea\x18\x04 \x02(\x04\x12\r\n\x05lp_ea\x18\x05 \x02(\x04\x12-\n\x06\x61\x63tion\x18\x06 \x02(\x0e\x32\x1d.mcsema.ExceptionFrame.Action\x12\'\n\x05ttype\x18\x07 \x03(\x0b\x32\x18.mcsema.ExternalVariable\" \n\x06\x41\x63tion\x12\x0b\n\x07\x43leanup\x10\x00\x12\t\n\x05\x43\x61tch\x10\x01\"8\n\x0eGlobalVariable\x12\n\n\x02\x65\x61\x18\x01 \x02(\x03\x12\x0c\n\x04name\x18\x02 \x02(\t\x12\x0c\n\x04size\x18\x03 \x02(\x03\"\xe4\x01\n\x07Segment\x12\n\n\x02\x65\x61\x18\x01 \x02(\x03\x12\x0c\n\x04\x64\x61ta\x18\x02 \x02(\x0c\x12\x11\n\tread_only\x18\x03 \x02(\x08\x12\x13\n\x0bis_external\x18\x04 \x02(\x08\x12\x0c\n\x04name\x18\x05 \x02(\t\x12\x15\n\rvariable_name\x18\x06 \x01(\t\x12\x13\n\x0bis_exported\x18\x07 \x02(\x08\x12\x17\n\x0fis_thread_local\x18\x08 \x02(\x08\x12$\n\x05xrefs\x18\t \x03(\x0b\x32\x15.mcsema.DataReference\x12\x1e\n\x04vars\x18\n \x03(\x0b\x32\x10.mcsema.Variable\"\xcd\x02\n\x06Module\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\x1f\n\x05\x66uncs\x18\x02 \x03(\x0b\x32\x10.mcsema.Function\x12!\n\x08segments\x18\x03 \x03(\x0b\x32\x0f.mcsema.Segment\x12\x30\n\x0e\x65xternal_funcs\x18\x04 \x03(\x0b\x32\x18.mcsema.ExternalFunction\x12/\n\rexternal_vars\x18\x05 \x03(\x0b\x32\x18.mcsema.ExternalVariable\x12+\n\x0bglobal_vars\x18\x08 \x03(\x0b\x32\x16.mcsema.GlobalVariable\x12\x32\n\x0epreserved_regs\x18\t \x03(\x0b\x32\x1a.mcsema.PreservedRegisters\x12-\n\tdead_regs\x18\n \x03(\x0b\x32\x1a.mcsema.PreservedRegisters*\xa8\x01\n\x11\x43\x61llingConvention\x12\x05\n\x01\x43\x10\x00\x12\x0f\n\x0bX86_StdCall\x10@\x12\x10\n\x0cX86_FastCall\x10\x41\x12\x10\n\x0cX86_ThisCall\x10\x46\x12\x0f\n\x0bX86_64_SysV\x10N\x12\t\n\x05Win64\x10O\x12\x12\n\x0eX86_VectorCall\x10P\x12\x0f\n\x0bX86_RegCall\x10\\\x12\x16\n\x12\x41\x41rch64_VectorCall\x10\x61') ) _sym_db.RegisterFileDescriptor(DESCRIPTOR) - - -_CODEREFERENCE_TARGETTYPE = _descriptor.EnumDescriptor( - name='TargetType', - full_name='mcsema.CodeReference.TargetType', +_CALLINGCONVENTION = _descriptor.EnumDescriptor( + name='CallingConvention', + full_name='mcsema.CallingConvention', filename=None, file=DESCRIPTOR, values=[ _descriptor.EnumValueDescriptor( - name='CodeTarget', index=0, number=0, + name='C', index=0, number=0, options=None, type=None), _descriptor.EnumValueDescriptor( - name='DataTarget', index=1, number=1, + name='X86_StdCall', index=1, number=64, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='X86_FastCall', index=2, number=65, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='X86_ThisCall', index=3, number=70, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='X86_64_SysV', index=4, number=78, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='Win64', index=5, number=79, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='X86_VectorCall', index=6, number=80, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='X86_RegCall', index=7, number=92, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='AArch64_VectorCall', index=8, number=97, options=None, type=None), ], containing_type=None, options=None, - serialized_start=241, - serialized_end=285, + serialized_start=2696, + serialized_end=2864, ) -_sym_db.RegisterEnumDescriptor(_CODEREFERENCE_TARGETTYPE) +_sym_db.RegisterEnumDescriptor(_CALLINGCONVENTION) + +CallingConvention = enum_type_wrapper.EnumTypeWrapper(_CALLINGCONVENTION) +C = 0 +X86_StdCall = 64 +X86_FastCall = 65 +X86_ThisCall = 70 +X86_64_SysV = 78 +Win64 = 79 +X86_VectorCall = 80 +X86_RegCall = 92 +AArch64_VectorCall = 97 + _CODEREFERENCE_OPERANDTYPE = _descriptor.EnumDescriptor( name='OperandType', @@ -75,33 +114,11 @@ _CODEREFERENCE_OPERANDTYPE = _descriptor.EnumDescriptor( ], containing_type=None, options=None, - serialized_start=287, - serialized_end=413, + serialized_start=261, + serialized_end=387, ) _sym_db.RegisterEnumDescriptor(_CODEREFERENCE_OPERANDTYPE) -_CODEREFERENCE_LOCATION = _descriptor.EnumDescriptor( - name='Location', - full_name='mcsema.CodeReference.Location', - filename=None, - file=DESCRIPTOR, - values=[ - _descriptor.EnumValueDescriptor( - name='Internal', index=0, number=0, - options=None, - type=None), - _descriptor.EnumValueDescriptor( - name='External', index=1, number=1, - options=None, - type=None), - ], - containing_type=None, - options=None, - serialized_start=415, - serialized_end=453, -) -_sym_db.RegisterEnumDescriptor(_CODEREFERENCE_LOCATION) - _EXTERNALFUNCTION_CALLINGCONVENTION = _descriptor.EnumDescriptor( name='CallingConvention', full_name='mcsema.ExternalFunction.CallingConvention', @@ -123,8 +140,8 @@ _EXTERNALFUNCTION_CALLINGCONVENTION = _descriptor.EnumDescriptor( ], containing_type=None, options=None, - serialized_start=1041, - serialized_end=1112, + serialized_start=1415, + serialized_end=1486, ) _sym_db.RegisterEnumDescriptor(_EXTERNALFUNCTION_CALLINGCONVENTION) @@ -145,8 +162,8 @@ _DATAREFERENCE_TARGETFIXUPKIND = _descriptor.EnumDescriptor( ], containing_type=None, options=None, - serialized_start=1391, - serialized_end=1448, + serialized_start=1720, + serialized_end=1777, ) _sym_db.RegisterEnumDescriptor(_DATAREFERENCE_TARGETFIXUPKIND) @@ -167,12 +184,86 @@ _EXCEPTIONFRAME_ACTION = _descriptor.EnumDescriptor( ], containing_type=None, options=None, - serialized_start=1707, - serialized_end=1739, + serialized_start=2036, + serialized_end=2068, ) _sym_db.RegisterEnumDescriptor(_EXCEPTIONFRAME_ACTION) +_PRESERVATIONRANGE = _descriptor.Descriptor( + name='PreservationRange', + full_name='mcsema.PreservationRange', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='begin_ea', full_name='mcsema.PreservationRange.begin_ea', index=0, + number=1, type=3, cpp_type=2, label=2, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='end_ea', full_name='mcsema.PreservationRange.end_ea', index=1, + number=2, type=3, cpp_type=2, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + extension_ranges=[], + oneofs=[ + ], + serialized_start=21, + serialized_end=74, +) + + +_PRESERVEDREGISTERS = _descriptor.Descriptor( + name='PreservedRegisters', + full_name='mcsema.PreservedRegisters', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='registers', full_name='mcsema.PreservedRegisters.registers', index=0, + number=1, type=9, cpp_type=9, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='ranges', full_name='mcsema.PreservedRegisters.ranges', index=1, + number=2, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + extension_ranges=[], + oneofs=[ + ], + serialized_start=76, + serialized_end=158, +) + + _CODEREFERENCE = _descriptor.Descriptor( name='CodeReference', full_name='mcsema.CodeReference', @@ -181,63 +272,40 @@ _CODEREFERENCE = _descriptor.Descriptor( containing_type=None, fields=[ _descriptor.FieldDescriptor( - name='target_type', full_name='mcsema.CodeReference.target_type', index=0, + name='operand_type', full_name='mcsema.CodeReference.operand_type', index=0, number=1, type=14, cpp_type=8, label=2, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( - name='operand_type', full_name='mcsema.CodeReference.operand_type', index=1, - number=2, type=14, cpp_type=8, label=2, + name='ea', full_name='mcsema.CodeReference.ea', index=1, + number=2, type=3, cpp_type=2, label=2, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( - name='location', full_name='mcsema.CodeReference.location', index=2, - number=3, type=14, cpp_type=8, label=2, + name='mask', full_name='mcsema.CodeReference.mask', index=2, + number=3, type=3, cpp_type=2, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), - _descriptor.FieldDescriptor( - name='ea', full_name='mcsema.CodeReference.ea', index=3, - number=4, type=3, cpp_type=2, label=2, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - _descriptor.FieldDescriptor( - name='mask', full_name='mcsema.CodeReference.mask', index=4, - number=5, type=3, cpp_type=2, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - _descriptor.FieldDescriptor( - name='name', full_name='mcsema.CodeReference.name', index=5, - number=6, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), ], extensions=[ ], nested_types=[], enum_types=[ - _CODEREFERENCE_TARGETTYPE, _CODEREFERENCE_OPERANDTYPE, - _CODEREFERENCE_LOCATION, ], options=None, is_extendable=False, extension_ranges=[], oneofs=[ ], - serialized_start=22, - serialized_end=453, + serialized_start=161, + serialized_end=387, ) @@ -256,29 +324,15 @@ _INSTRUCTION = _descriptor.Descriptor( is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( - name='bytes', full_name='mcsema.Instruction.bytes', index=1, - number=2, type=12, cpp_type=9, label=2, - has_default_value=False, default_value=_b(""), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - _descriptor.FieldDescriptor( - name='xrefs', full_name='mcsema.Instruction.xrefs', index=2, - number=3, type=11, cpp_type=10, label=3, + name='xrefs', full_name='mcsema.Instruction.xrefs', index=1, + number=2, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( - name='local_noreturn', full_name='mcsema.Instruction.local_noreturn', index=3, - number=4, type=8, cpp_type=7, label=1, - has_default_value=False, default_value=False, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - _descriptor.FieldDescriptor( - name='lp_ea', full_name='mcsema.Instruction.lp_ea', index=4, - number=5, type=4, cpp_type=4, label=1, + name='lp_ea', full_name='mcsema.Instruction.lp_ea', index=2, + number=3, type=4, cpp_type=4, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, @@ -294,8 +348,8 @@ _INSTRUCTION = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=455, - serialized_end=572, + serialized_start=389, + serialized_end=467, ) @@ -327,6 +381,13 @@ _BLOCK = _descriptor.Descriptor( message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), + _descriptor.FieldDescriptor( + name='is_referenced_by_data', full_name='mcsema.Block.is_referenced_by_data', index=3, + number=4, type=8, cpp_type=7, label=2, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), ], extensions=[ ], @@ -338,8 +399,168 @@ _BLOCK = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=574, - serialized_end=659, + serialized_start=469, + serialized_end=585, +) + + +_MEMORYLOCATION = _descriptor.Descriptor( + name='MemoryLocation', + full_name='mcsema.MemoryLocation', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='register', full_name='mcsema.MemoryLocation.register', index=0, + number=1, type=9, cpp_type=9, label=2, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='offset', full_name='mcsema.MemoryLocation.offset', index=1, + number=2, type=3, cpp_type=2, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + extension_ranges=[], + oneofs=[ + ], + serialized_start=587, + serialized_end=637, +) + + +_VALUEDECL = _descriptor.Descriptor( + name='ValueDecl', + full_name='mcsema.ValueDecl', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='type', full_name='mcsema.ValueDecl.type', index=0, + number=1, type=9, cpp_type=9, label=2, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='memory', full_name='mcsema.ValueDecl.memory', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='register', full_name='mcsema.ValueDecl.register', index=2, + number=3, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='name', full_name='mcsema.ValueDecl.name', index=3, + number=4, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + extension_ranges=[], + oneofs=[ + ], + serialized_start=639, + serialized_end=736, +) + + +_FUNCTIONDECL = _descriptor.Descriptor( + name='FunctionDecl', + full_name='mcsema.FunctionDecl', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='parameters', full_name='mcsema.FunctionDecl.parameters', index=0, + number=1, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='return_values', full_name='mcsema.FunctionDecl.return_values', index=1, + number=2, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='return_address', full_name='mcsema.FunctionDecl.return_address', index=2, + number=3, type=11, cpp_type=10, label=2, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='return_stack_pointer', full_name='mcsema.FunctionDecl.return_stack_pointer', index=3, + number=4, type=11, cpp_type=10, label=2, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='is_variadic', full_name='mcsema.FunctionDecl.is_variadic', index=4, + number=5, type=8, cpp_type=7, label=2, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='is_noreturn', full_name='mcsema.FunctionDecl.is_noreturn', index=5, + number=6, type=8, cpp_type=7, label=2, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='calling_convention', full_name='mcsema.FunctionDecl.calling_convention', index=6, + number=7, type=14, cpp_type=8, label=2, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + extension_ranges=[], + oneofs=[ + ], + serialized_start=739, + serialized_end=1023, ) @@ -379,16 +600,16 @@ _FUNCTION = _descriptor.Descriptor( is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( - name='stack_vars', full_name='mcsema.Function.stack_vars', index=4, + name='eh_frame', full_name='mcsema.Function.eh_frame', index=4, number=5, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( - name='eh_frame', full_name='mcsema.Function.eh_frame', index=5, - number=6, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], + name='decl', full_name='mcsema.Function.decl', index=5, + number=6, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), @@ -403,8 +624,8 @@ _FUNCTION = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=662, - serialized_end=837, + serialized_start=1026, + serialized_end=1194, ) @@ -465,9 +686,9 @@ _EXTERNALFUNCTION = _descriptor.Descriptor( is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( - name='signature', full_name='mcsema.ExternalFunction.signature', index=7, - number=8, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + name='decl', full_name='mcsema.ExternalFunction.decl', index=7, + number=8, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), @@ -483,8 +704,8 @@ _EXTERNALFUNCTION = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=840, - serialized_end=1112, + serialized_start=1197, + serialized_end=1486, ) @@ -541,8 +762,8 @@ _EXTERNALVARIABLE = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1114, - serialized_end=1214, + serialized_start=1488, + serialized_end=1588, ) @@ -569,28 +790,14 @@ _DATAREFERENCE = _descriptor.Descriptor( options=None), _descriptor.FieldDescriptor( name='target_ea', full_name='mcsema.DataReference.target_ea', index=2, - number=4, type=3, cpp_type=2, label=2, + number=3, type=3, cpp_type=2, label=2, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( - name='target_name', full_name='mcsema.DataReference.target_name', index=3, - number=5, type=9, cpp_type=9, label=2, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - _descriptor.FieldDescriptor( - name='target_is_code', full_name='mcsema.DataReference.target_is_code', index=4, - number=6, type=8, cpp_type=7, label=2, - has_default_value=False, default_value=False, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - _descriptor.FieldDescriptor( - name='target_fixup_kind', full_name='mcsema.DataReference.target_fixup_kind', index=5, - number=8, type=14, cpp_type=8, label=2, + name='target_fixup_kind', full_name='mcsema.DataReference.target_fixup_kind', index=3, + number=4, type=14, cpp_type=8, label=2, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, @@ -607,8 +814,8 @@ _DATAREFERENCE = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1217, - serialized_end=1448, + serialized_start=1591, + serialized_end=1777, ) @@ -644,8 +851,8 @@ _VARIABLE = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1450, - serialized_end=1486, + serialized_start=1779, + serialized_end=1815, ) @@ -681,8 +888,8 @@ _REFERENCE = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1488, - serialized_end=1532, + serialized_start=1817, + serialized_end=1861, ) @@ -747,73 +954,8 @@ _EXCEPTIONFRAME = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1535, - serialized_end=1739, -) - - -_STACKVARIABLE = _descriptor.Descriptor( - name='StackVariable', - full_name='mcsema.StackVariable', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='name', full_name='mcsema.StackVariable.name', index=0, - number=1, type=9, cpp_type=9, label=2, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - _descriptor.FieldDescriptor( - name='size', full_name='mcsema.StackVariable.size', index=1, - number=2, type=4, cpp_type=4, label=2, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - _descriptor.FieldDescriptor( - name='sp_offset', full_name='mcsema.StackVariable.sp_offset', index=2, - number=3, type=3, cpp_type=2, label=2, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - _descriptor.FieldDescriptor( - name='has_frame', full_name='mcsema.StackVariable.has_frame', index=3, - number=4, type=8, cpp_type=7, label=1, - has_default_value=False, default_value=False, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - _descriptor.FieldDescriptor( - name='reg_name', full_name='mcsema.StackVariable.reg_name', index=4, - number=5, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - _descriptor.FieldDescriptor( - name='ref_eas', full_name='mcsema.StackVariable.ref_eas', index=5, - number=6, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=None, - is_extendable=False, - extension_ranges=[], - oneofs=[ - ], - serialized_start=1742, - serialized_end=1877, + serialized_start=1864, + serialized_end=2068, ) @@ -856,8 +998,8 @@ _GLOBALVARIABLE = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1879, - serialized_end=1935, + serialized_start=2070, + serialized_end=2126, ) @@ -949,8 +1091,8 @@ _SEGMENT = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1938, - serialized_end=2166, + serialized_start=2129, + serialized_end=2357, ) @@ -1003,6 +1145,20 @@ _MODULE = _descriptor.Descriptor( message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), + _descriptor.FieldDescriptor( + name='preserved_regs', full_name='mcsema.Module.preserved_regs', index=6, + number=9, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='dead_regs', full_name='mcsema.Module.dead_regs', index=7, + number=10, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), ], extensions=[ ], @@ -1014,29 +1170,32 @@ _MODULE = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=2169, - serialized_end=2403, + serialized_start=2360, + serialized_end=2693, ) -_CODEREFERENCE.fields_by_name['target_type'].enum_type = _CODEREFERENCE_TARGETTYPE +_PRESERVEDREGISTERS.fields_by_name['ranges'].message_type = _PRESERVATIONRANGE _CODEREFERENCE.fields_by_name['operand_type'].enum_type = _CODEREFERENCE_OPERANDTYPE -_CODEREFERENCE.fields_by_name['location'].enum_type = _CODEREFERENCE_LOCATION -_CODEREFERENCE_TARGETTYPE.containing_type = _CODEREFERENCE _CODEREFERENCE_OPERANDTYPE.containing_type = _CODEREFERENCE -_CODEREFERENCE_LOCATION.containing_type = _CODEREFERENCE _INSTRUCTION.fields_by_name['xrefs'].message_type = _CODEREFERENCE _BLOCK.fields_by_name['instructions'].message_type = _INSTRUCTION +_VALUEDECL.fields_by_name['memory'].message_type = _MEMORYLOCATION +_FUNCTIONDECL.fields_by_name['parameters'].message_type = _VALUEDECL +_FUNCTIONDECL.fields_by_name['return_values'].message_type = _VALUEDECL +_FUNCTIONDECL.fields_by_name['return_address'].message_type = _VALUEDECL +_FUNCTIONDECL.fields_by_name['return_stack_pointer'].message_type = _VALUEDECL +_FUNCTIONDECL.fields_by_name['calling_convention'].enum_type = _CALLINGCONVENTION _FUNCTION.fields_by_name['blocks'].message_type = _BLOCK -_FUNCTION.fields_by_name['stack_vars'].message_type = _STACKVARIABLE _FUNCTION.fields_by_name['eh_frame'].message_type = _EXCEPTIONFRAME +_FUNCTION.fields_by_name['decl'].message_type = _FUNCTIONDECL _EXTERNALFUNCTION.fields_by_name['cc'].enum_type = _EXTERNALFUNCTION_CALLINGCONVENTION +_EXTERNALFUNCTION.fields_by_name['decl'].message_type = _FUNCTIONDECL _EXTERNALFUNCTION_CALLINGCONVENTION.containing_type = _EXTERNALFUNCTION _DATAREFERENCE.fields_by_name['target_fixup_kind'].enum_type = _DATAREFERENCE_TARGETFIXUPKIND _DATAREFERENCE_TARGETFIXUPKIND.containing_type = _DATAREFERENCE _EXCEPTIONFRAME.fields_by_name['action'].enum_type = _EXCEPTIONFRAME_ACTION _EXCEPTIONFRAME.fields_by_name['ttype'].message_type = _EXTERNALVARIABLE _EXCEPTIONFRAME_ACTION.containing_type = _EXCEPTIONFRAME -_STACKVARIABLE.fields_by_name['ref_eas'].message_type = _REFERENCE _SEGMENT.fields_by_name['xrefs'].message_type = _DATAREFERENCE _SEGMENT.fields_by_name['vars'].message_type = _VARIABLE _MODULE.fields_by_name['funcs'].message_type = _FUNCTION @@ -1044,9 +1203,16 @@ _MODULE.fields_by_name['segments'].message_type = _SEGMENT _MODULE.fields_by_name['external_funcs'].message_type = _EXTERNALFUNCTION _MODULE.fields_by_name['external_vars'].message_type = _EXTERNALVARIABLE _MODULE.fields_by_name['global_vars'].message_type = _GLOBALVARIABLE +_MODULE.fields_by_name['preserved_regs'].message_type = _PRESERVEDREGISTERS +_MODULE.fields_by_name['dead_regs'].message_type = _PRESERVEDREGISTERS +DESCRIPTOR.message_types_by_name['PreservationRange'] = _PRESERVATIONRANGE +DESCRIPTOR.message_types_by_name['PreservedRegisters'] = _PRESERVEDREGISTERS DESCRIPTOR.message_types_by_name['CodeReference'] = _CODEREFERENCE DESCRIPTOR.message_types_by_name['Instruction'] = _INSTRUCTION DESCRIPTOR.message_types_by_name['Block'] = _BLOCK +DESCRIPTOR.message_types_by_name['MemoryLocation'] = _MEMORYLOCATION +DESCRIPTOR.message_types_by_name['ValueDecl'] = _VALUEDECL +DESCRIPTOR.message_types_by_name['FunctionDecl'] = _FUNCTIONDECL DESCRIPTOR.message_types_by_name['Function'] = _FUNCTION DESCRIPTOR.message_types_by_name['ExternalFunction'] = _EXTERNALFUNCTION DESCRIPTOR.message_types_by_name['ExternalVariable'] = _EXTERNALVARIABLE @@ -1054,10 +1220,24 @@ DESCRIPTOR.message_types_by_name['DataReference'] = _DATAREFERENCE DESCRIPTOR.message_types_by_name['Variable'] = _VARIABLE DESCRIPTOR.message_types_by_name['Reference'] = _REFERENCE DESCRIPTOR.message_types_by_name['ExceptionFrame'] = _EXCEPTIONFRAME -DESCRIPTOR.message_types_by_name['StackVariable'] = _STACKVARIABLE DESCRIPTOR.message_types_by_name['GlobalVariable'] = _GLOBALVARIABLE DESCRIPTOR.message_types_by_name['Segment'] = _SEGMENT DESCRIPTOR.message_types_by_name['Module'] = _MODULE +DESCRIPTOR.enum_types_by_name['CallingConvention'] = _CALLINGCONVENTION + +PreservationRange = _reflection.GeneratedProtocolMessageType('PreservationRange', (_message.Message,), dict( + DESCRIPTOR = _PRESERVATIONRANGE, + __module__ = 'CFG_pb2' + # @@protoc_insertion_point(class_scope:mcsema.PreservationRange) + )) +_sym_db.RegisterMessage(PreservationRange) + +PreservedRegisters = _reflection.GeneratedProtocolMessageType('PreservedRegisters', (_message.Message,), dict( + DESCRIPTOR = _PRESERVEDREGISTERS, + __module__ = 'CFG_pb2' + # @@protoc_insertion_point(class_scope:mcsema.PreservedRegisters) + )) +_sym_db.RegisterMessage(PreservedRegisters) CodeReference = _reflection.GeneratedProtocolMessageType('CodeReference', (_message.Message,), dict( DESCRIPTOR = _CODEREFERENCE, @@ -1080,6 +1260,27 @@ Block = _reflection.GeneratedProtocolMessageType('Block', (_message.Message,), d )) _sym_db.RegisterMessage(Block) +MemoryLocation = _reflection.GeneratedProtocolMessageType('MemoryLocation', (_message.Message,), dict( + DESCRIPTOR = _MEMORYLOCATION, + __module__ = 'CFG_pb2' + # @@protoc_insertion_point(class_scope:mcsema.MemoryLocation) + )) +_sym_db.RegisterMessage(MemoryLocation) + +ValueDecl = _reflection.GeneratedProtocolMessageType('ValueDecl', (_message.Message,), dict( + DESCRIPTOR = _VALUEDECL, + __module__ = 'CFG_pb2' + # @@protoc_insertion_point(class_scope:mcsema.ValueDecl) + )) +_sym_db.RegisterMessage(ValueDecl) + +FunctionDecl = _reflection.GeneratedProtocolMessageType('FunctionDecl', (_message.Message,), dict( + DESCRIPTOR = _FUNCTIONDECL, + __module__ = 'CFG_pb2' + # @@protoc_insertion_point(class_scope:mcsema.FunctionDecl) + )) +_sym_db.RegisterMessage(FunctionDecl) + Function = _reflection.GeneratedProtocolMessageType('Function', (_message.Message,), dict( DESCRIPTOR = _FUNCTION, __module__ = 'CFG_pb2' @@ -1129,13 +1330,6 @@ ExceptionFrame = _reflection.GeneratedProtocolMessageType('ExceptionFrame', (_me )) _sym_db.RegisterMessage(ExceptionFrame) -StackVariable = _reflection.GeneratedProtocolMessageType('StackVariable', (_message.Message,), dict( - DESCRIPTOR = _STACKVARIABLE, - __module__ = 'CFG_pb2' - # @@protoc_insertion_point(class_scope:mcsema.StackVariable) - )) -_sym_db.RegisterMessage(StackVariable) - GlobalVariable = _reflection.GeneratedProtocolMessageType('GlobalVariable', (_message.Message,), dict( DESCRIPTOR = _GLOBALVARIABLE, __module__ = 'CFG_pb2' diff --git a/tools/mcsema_disass/ida7/anvill_compat.py b/tools/mcsema_disass/ida7/anvill_compat.py new file mode 100644 index 000000000..7cefa10f8 --- /dev/null +++ b/tools/mcsema_disass/ida7/anvill_compat.py @@ -0,0 +1,55 @@ +# Copyright (c) 2020 Trail of Bits, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +class InvalidFunctionException(Exception): + pass + +class CompatAnvillMemory(object): + def map_byte(self, ea, val, can_write, can_exec): + pass + +class CompatAnvillProgram(object): + def __init__(self): + self._memory = CompatAnvillMemory() + + def get_function(self, ea): + return None + + def get_variable(self, ea): + return None + + def add_symbol(self, ea, name): + pass + + def add_variable_declaration(self, *args, **kargs): + return False + + def add_variable_definition(self, *args, **kargs): + return False + + def add_function_definition(self, *args, **kargs): + return False + + def add_function_declaration(self, *args, **kargs): + return False + + def try_add_referenced_entity(self, *args, **kargs): + return False + + def memory(self): + return self._memory + +def get_program(*args, **kargs): + return CompatAnvillProgram() diff --git a/tools/mcsema_disass/ida7/arm_util.py b/tools/mcsema_disass/ida7/arm_util.py index 15413d0d8..fa74a8b8d 100644 --- a/tools/mcsema_disass/ida7/arm_util.py +++ b/tools/mcsema_disass/ida7/arm_util.py @@ -1,16 +1,17 @@ -# Copyright (c) 2017 Trail of Bits, Inc. +# Copyright (c) 2020 Trail of Bits, Inc. # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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 Affero General Public License for more details. # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . import collections import idaapi @@ -61,3 +62,117 @@ def fixup_personality(inst, p): if 0 <= inst.segpref <= 0xf and inst.segpref != 0xe: return PERSONALITY_CONDITIONAL_BRANCH return p + +def has_delayed_slot(inst): + return False + +def fixup_delayed_instr_size(inst): + return 4 # All isntructions are four bytes. + +def fixup_instr_as_nop(inst): + return False + +def fixup_function_return_address(inst, next_ea): + return next_ea + + +_INVALID_THUNK_ADDR = (False, idc.BADADDR) + +def is_ELF_thunk_by_structure(ea): + """Try to manually identify an ELF thunk by its structure.""" + from util import * + global _INVALID_THUNK_ADDR + inst = None + + for i in range(4): # 1 is good enough for x86, 4 for aarch64. + inst, _ = decode_instruction(ea) + if not inst: + break + # elif is_direct_jump(inst): + # ea = get_direct_branch_target(inst) + # inst = None + if is_indirect_jump(inst) or is_direct_jump(inst): + target_ea = get_reference_target(inst.ea) + if not is_invalid_ea(target_ea): + seg_name = idc.get_segm_name(target_ea).lower() + if ".got" in seg_name or ".plt" in seg_name: + target_ea = get_reference_target(target_ea) + seg_name = idc.get_segm_name(target_ea).lower() + + if "extern" == seg_name: + return True, target_ea + + ea = inst.ea + inst.size + + return _INVALID_THUNK_ADDR + +_ARM_REF_CANDIDATES = set() + +def _get_arm_ref_candidate(mask, op_val, op_str, all_refs): + global _BAD_ARM_REF_OFF, _ARM_REF_CANDIDATES + + try: + op_name = op_str.split("@")[0][1:] # `#asc_400E5C@PAGE` -> `asc_400E5C`. + ref_ea = idc.get_name_ea_simple(op_name) + if (ref_ea & mask) == op_val: + return ref_ea, mask, 0 + except: + pass + + # NOTE(pag): We deal with candidates because it's possible that this + # instruction will have multiple references. In the case of + # `@PAGE`-based offsets, it's problematic when the wrong base + # is matched, because it really throws off the C++ side of things + # because the arrangement of the lifted data being on the same + # page is not guaranteed. + _ARM_REF_CANDIDATES.clear() + for ref_ea in all_refs: + if (ref_ea & mask) == op_val: + _ARM_REF_CANDIDATES.add(ref_ea) + return ref_ea, mask, 0 + + if len(_ARM_REF_CANDIDATES): + for candidate_ea in _ARM_REF_CANDIDATES: + if candidate_ea == op_val: + return candidate_ea, mask, 0 + + return _ARM_REF_CANDIDATES.pop(), mask, 0 + + return _BAD_ARM_REF_OFF + +# Try to handle `@PAGE` and `@PAGEOFF` references, resolving them to their +# 'intended' address. +# +# TODO(pag): There must be a better way than just string searching :-/ +def try_get_ref_addr(inst, op, op_val, all_refs, _NOT_A_REF): + global _BAD_ARM_REF_OFF + + from util import * + + if op.type not in (idc.o_imm, idc.o_displ): + # This is a reference type that the other ref tracking code + # can handle, return defaults + return op_val, 0, 0 + + op_str = idc.print_operand(inst.ea, op.n) + + if '@PAGEOFF' in op_str: + return _get_arm_ref_candidate(4095, op_val, op_str, all_refs) + + elif '@PAGE' in op_str: + return _get_arm_ref_candidate(-4096L, op_val, op_str, all_refs) + + elif not is_invalid_ea(op_val) and inst.get_canon_mnem().lower() == "adr": + return op_val, 0, 0 + + return _BAD_ARM_REF_OFF + + +def recover_preserved_regs(M, F, inst, xrefs, preserved_reg_sets): + return False + +def recover_deferred_preserved_regs(M): + return + +def recover_function_spec_from_arch(E): + return diff --git a/tools/mcsema_disass/ida7/collect_variable.py b/tools/mcsema_disass/ida7/collect_variable.py index 1d0c8e4f1..a8c3954f9 100644 --- a/tools/mcsema_disass/ida7/collect_variable.py +++ b/tools/mcsema_disass/ida7/collect_variable.py @@ -1,18 +1,19 @@ #!/usr/bin/env python -# Copyright (c) 2017 Trail of Bits, Inc. +# Copyright (c) 2020 Trail of Bits, Inc. # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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 Affero General Public License for more details. # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . import idautils import idaapi @@ -157,7 +158,7 @@ class Operand(object): @property def value(self): - return idc.GetOperandValue(self._ea, self.index) + return idc.get_operand_value(self._ea, self.index) @property def size(self): @@ -165,7 +166,7 @@ class Operand(object): @property def text(self): - return idc.GetOpnd(self._ea, self.index) + return idc.print_operand(self._ea, self.index) @property def dtype(self): @@ -462,7 +463,7 @@ def _process_instruction(inst_ea, func_variable): if opnd.has_phrase: base_ = _translate_reg(opnd.base_reg) if opnd.base_reg else None index_ = _translate_reg(opnd.index_reg) if opnd.index_reg else None - offset = _signed_from_unsigned(idc.GetOperandValue(inst_ea, opnd.index)) + offset = _signed_from_unsigned(idc.get_operand_value(inst_ea, opnd.index)) if len(func_variable["stack_vars"].keys()) == 0: return @@ -548,7 +549,7 @@ def build_stack_variable(func_ea): #grab the offset of the stored frame pointer, so that #we can correlate offsets correctly in referent code # e.g., EBP+(-0x4) will match up to the -0x4 offset - delta = idc.GetMemberOffset(frame, " s") + delta = idc.get_member_offset(frame, " s") if delta == -1: delta = 0 @@ -563,12 +564,12 @@ def build_stack_variable(func_ea): offset = idc.get_next_offset(frame, offset) continue - member_size = idc.GetMemberSize(frame, offset) + member_size = idc.get_member_size(frame, offset) if offset >= delta: offset = idc.get_next_offset(frame, offset) continue - member_flag = idc.GetMemberFlag(frame, offset) + member_flag = idc.get_member_flag(frame, offset) flag_str = _get_flags_from_bits(member_flag) member_offset = offset-delta stack_vars[member_offset] = {"name": member_name, @@ -622,7 +623,7 @@ def is_function_unsafe(func_ea, blockset): """ Returns `True` if the function uses bp and it might access the stack variable indirectly using the base pointer. """ - if not (idc.GetFunctionFlags(func_ea) & idc.FUNC_FRAME): + if not (idc.get_func_attr(func_ea, idc.FUNCATTR_FLAGS) & idc.FUNC_FRAME): return False for block_ea in blockset: @@ -639,7 +640,7 @@ def collect_function_vars(func_ea, blockset): # Check for the variadic function type; Add the variadic function # to the list of unsafe functions - func_type = idc.GetType(func_ea) + func_type = idc.get_type(func_ea) if (func_type is not None) and ("(" in func_type): args = func_type[ func_type.index('(')+1: func_type.rindex(')') ] args_list = [ x.strip() for x in args.split(',')] diff --git a/tools/mcsema_disass/ida7/disass.py b/tools/mcsema_disass/ida7/disass.py index 05b98f4ef..c8cc12baa 100644 --- a/tools/mcsema_disass/ida7/disass.py +++ b/tools/mcsema_disass/ida7/disass.py @@ -55,8 +55,9 @@ def execute(args, command_args): script_cmd.append(args.arch) script_cmd.append("--os") script_cmd.append(args.os) - script_cmd.append("--entrypoint") - script_cmd.append(args.entrypoint) + if args.entrypoint is not None and len(args.entrypoint): + script_cmd.append("--entrypoint") + script_cmd.append(args.entrypoint) script_cmd.extend(command_args) # Extra, script-specific arguments. cmd = [] diff --git a/tools/mcsema_disass/ida7/exception.py b/tools/mcsema_disass/ida7/exception.py index 6871106f3..08193d6d7 100644 --- a/tools/mcsema_disass/ida7/exception.py +++ b/tools/mcsema_disass/ida7/exception.py @@ -1,18 +1,19 @@ #!/usr/bin/env python -# Copyright (c) 2017 Trail of Bits, Inc. +# Copyright (c) 2020 Trail of Bits, Inc. # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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 Affero General Public License for more details. # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . import idautils import idaapi @@ -26,6 +27,8 @@ import collections import itertools import pprint +import ida_bytes + from collections import namedtuple # Bring in utility libraries. from util import * @@ -65,8 +68,8 @@ def make_array(ea, size): flags = idc.get_full_flags(ea) if not idc.isByte(flags) or idc.get_item_size(ea) != 1: idc.del_items(ea, idc.DOUNK_SIMPLE, 1) - idc.MakeByte(ea) - idc.MakeArray(ea, size) + ida_bytes.create_data(ea, ida_bytes.FF_BYTE, 1, ida_idaapi.BADADDR) + idc.make_array(ea, size) def read_string(ea): s = idc.get_strlit_contents(ea, -1, idc.ASCSTR_C) diff --git a/tools/mcsema_disass/ida7/flow.py b/tools/mcsema_disass/ida7/flow.py index 15f0ceef5..a478eeaec 100644 --- a/tools/mcsema_disass/ida7/flow.py +++ b/tools/mcsema_disass/ida7/flow.py @@ -1,16 +1,17 @@ -# Copyright (c) 2017 Trail of Bits, Inc. +# Copyright (c) 2020 Trail of Bits, Inc. # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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 Affero General Public License for more details. # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . from table import * from exception import * @@ -75,7 +76,9 @@ def find_linear_terminator(ea, max_num=256): ea += len(inst_bytes) # The next instruction was already processed as part of some other scan. - if ea in _BLOCK_HEAD_EAS: + if ea in _BLOCK_HEAD_EAS or \ + has_our_dref_to(ea) or \ + is_jump_table_target(ea): break if term_inst: @@ -97,8 +100,10 @@ def get_direct_branch_target(arg): except: decoded_inst, _ = decode_instruction(branch_inst_ea) target_ea = decoded_inst.Op1.addr - #log.warning("Determined target of {:08x} to be {:08x}".format( - # branch_inst_ea, target_ea)) + if not target_ea: + for i, op in enumerate(decoded_inst.ops): + if op.addr != 0: + target_ea = op.addr return target_ea def is_noreturn_inst(arg): @@ -112,36 +117,52 @@ def is_noreturn_inst(arg): called_ea = get_direct_branch_target(inst.ea) return is_noreturn_function(called_ea) - return inst.itype in (idaapi.NN_int3, idaapi.NN_icebp, idaapi.NN_hlt) + return is_terminator(inst) -def get_static_successors(sub_ea, inst, binary_is_pie): +def get_static_successors(sub_ea, term_inst, delayed_inst, binary_is_pie): """Returns the statically known successors of an instruction.""" - branch_flows = tuple(idautils.CodeRefsFrom(inst.ea, False)) - next_ea = inst.ea + inst.size + # delayed_inst will be term_inst if there is no delay slot + # + # NOTE(pag): It is possible that there is an apparently single instruction + # block containing a synthetic instruction that is actually two underlying + # instructions, and so we want to use `term_inst.size` (8 in this case) to find `next_ea` + # if `term_inst` and `delayed_inst` match. + global _FUNC_HEAD_EAS + + next_ea = term_inst.ea + term_inst.size + if term_inst.ea != delayed_inst.ea: + next_ea = delayed_inst.ea + fixup_delayed_instr_size(delayed_inst) + # Direct function call. The successor will be the fall-through instruction # unless the target of the function call looks like a `noreturn` function. - if is_direct_function_call(inst): - if not is_noreturn_function(get_direct_branch_target(inst.ea)): - yield next_ea # Not recognised as a `noreturn` function. + if is_direct_function_call(term_inst): + if not is_noreturn_function(get_direct_branch_target(term_inst.ea)): + yield fixup_function_return_address(term_inst, next_ea) # Not recognised as a `noreturn` function. - if is_function_call(inst): # Indirect function call, system call. + if is_function_call(term_inst): # Indirect function call, system call. + yield fixup_function_return_address(term_inst, next_ea) + + elif is_conditional_jump(term_inst): yield next_ea + yield get_direct_branch_target(term_inst.ea) - elif is_conditional_jump(inst): - yield next_ea - yield get_direct_branch_target(inst.ea) + elif is_direct_jump(term_inst): + yield get_direct_branch_target(term_inst.ea) - elif is_direct_jump(inst): - yield get_direct_branch_target(inst.ea) + elif is_indirect_jump(term_inst): + table = get_jump_table(term_inst, binary_is_pie) + target_eas = set(idautils.CodeRefsFrom(term_inst.ea, True)) + + # Over the course of execution, `idautils.CodeRefsFrom` might change to + # include delayed instructions. + if delayed_inst.ea in target_eas: + target_eas.remove(delayed_inst.ea) - elif is_indirect_jump(inst): - table = get_jump_table(inst, binary_is_pie) - target_eas = set(idautils.CodeRefsFrom(inst.ea, True)) if table: for target_ea in table.entries.values(): target_eas.add(target_ea) - + # Opportunistically add more flows to this instruction if it seems like # there are any blocks in the function with no predecessors. if not len(target_eas) and sub_ea in _MISSING_FLOWS: @@ -149,14 +170,22 @@ def get_static_successors(sub_ea, inst, binary_is_pie): for target_ea in missing_flows: if not has_flow_to_code(target_ea): DEBUG("Assuming that jump at {:x} targets block {:x} with missing flow.") - idc.add_cref(inst.ea, target_ea, idc.XREF_USER | idc.fl_JN) + idc.add_cref(term_inst.ea, target_ea, idc.XREF_USER | idc.fl_JN) target_eas.add(target_ea) - for target_ea in target_eas: - yield target_ea + # If the jump table is not recovered add the next_ea as + # the successor eas and throw a warning to look into later + if len(target_eas) == 0: + DEBUG("WARNING: No table entries for indirect jump at {:x}; Adding next_ea {:x} as successor." \ + .format(term_inst.ea, next_ea)) + yield next_ea + else: + for target_ea in target_eas: + yield target_ea - elif not is_control_flow(inst): - if not is_noreturn_inst(inst): + elif not is_control_flow(term_inst): + if not is_noreturn_inst(term_inst) \ + and next_ea not in _FUNC_HEAD_EAS: yield next_ea _BAD_BLOCK = (tuple(), set()) @@ -187,14 +216,19 @@ def analyse_block(func_ea, ea, binary_is_pie=False): break next_ea = inst.ea + inst.size - if next_ea in _BLOCK_HEAD_EAS: + if next_ea in _BLOCK_HEAD_EAS or \ + has_our_dref_to(next_ea) or \ + is_jump_table_target(next_ea): break successors = [] if inst_eas: + delayed_inst, delayed_ea = get_delayed_instruction(insts[-1]) + successors = get_static_successors(func_ea, insts[-1], delayed_inst, binary_is_pie) _TERMINATOR_EAS.add(inst_eas[-1]) - successors = get_static_successors(func_ea, insts[-1], binary_is_pie) successors = [succ for succ in successors if is_code(succ)] + if delayed_ea not in inst_eas: + inst_eas.append(delayed_ea) return (inst_eas, set(successors)) @@ -210,7 +244,6 @@ def find_default_block_heads(sub_ea): _FUNC_HEAD_EAS.add(sub_ea) heads = set([sub_ea]) - seg_start, seg_end = idc.get_segm_start(sub_ea), idc.get_segm_end(sub_ea) min_ea, max_ea = get_function_bounds(sub_ea) DEBUG("Default block heads for function {:x} with loose bounds [{:x}, {:x})".format( @@ -242,10 +275,11 @@ def find_default_block_heads(sub_ea): if max_ea: ea = sub_ea while min_ea <= ea < max_ea and ea != idc.BADADDR: - if ea not in _BLOCK_HEAD_EAS \ - and 16 < idaapi.get_alignment(ea) \ - and read_byte(ea) not in _ALIGNMENT_BYTES \ - and not has_flow_to_code(ea): + if ea not in _BLOCK_HEAD_EAS and \ + 16 < idaapi.get_alignment(ea) and \ + read_byte(ea) not in _ALIGNMENT_BYTES and \ + not has_flow_to_code(ea): + if is_data_reference(ea): DEBUG(" {:x} in function {:x} looks like an embedded jump table entry".format( ea, sub_ea)) @@ -323,14 +357,15 @@ def analyse_subroutine(sub_ea, binary_is_pie): # Check the instruction next to term_instr for recovery, if it has missing flow # IDA heuristics misses the landing pad and exception blocks in some cases; Linear # scan identifies the missing blocks and recover them - next_ea = term_inst.ea + len(inst_bytes) + delayed_inst, delayed_ea = get_delayed_instruction(term_inst) + next_ea = delayed_inst.ea + delayed_inst.size if next_ea not in _FUNC_HEAD_EAS and next_ea not in _BLOCK_HEAD_EAS: block_head_eas.add(next_ea) - #log.debug("Linear terminator of {:08x} is {:08x}".format( + #DEBUG("Linear terminator of {:08x} is {:08x}".format( # block_head_ea, term_inst.ea)) - for succ_ea in get_static_successors(sub_ea, term_inst, binary_is_pie): + for succ_ea in get_static_successors(sub_ea, term_inst, delayed_inst, binary_is_pie): if succ_ea not in _FUNC_HEAD_EAS or succ_ea == sub_ea: block_head_eas.add(succ_ea) diff --git a/tools/mcsema_disass/ida7/get_cfg.py b/tools/mcsema_disass/ida7/get_cfg.py index b3fa2108a..fe1a8ecb4 100644 --- a/tools/mcsema_disass/ida7/get_cfg.py +++ b/tools/mcsema_disass/ida7/get_cfg.py @@ -1,18 +1,19 @@ #!/usr/bin/env python -# Copyright (c) 2017 Trail of Bits, Inc. +# Copyright (c) 2020 Trail of Bits, Inc. # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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 Affero General Public License for more details. # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . import idautils import idaapi @@ -35,12 +36,21 @@ from segment import * from collect_variable import * from exception import * -#hack for IDAPython to see google protobuf lib -if os.path.isdir('/usr/lib/python2.7/dist-packages'): - sys.path.append('/usr/lib/python2.7/dist-packages') +# Bring in Anvill +try: + import anvill +except: + import anvill_compat as anvill -if os.path.isdir('/usr/local/lib/python2.7/dist-packages'): - sys.path.append('/usr/local/lib/python2.7/dist-packages') +ANVILL_PROGRAM = None + +#hack for IDAPython to see google protobuf lib +_VERSION_NUM = "{}.{}".format(sys.version_info[0], sys.version_info[1]) +if os.path.isdir('/usr/lib/python{}/dist-packages'.format(_VERSION_NUM)): + sys.path.append('/usr/lib/python{}/dist-packages'.format(_VERSION_NUM)) + +if os.path.isdir('/usr/local/lib/python{}/dist-packages'.format(_VERSION_NUM)): + sys.path.append('/usr/local/lib/python{}/dist-packages'.format(_VERSION_NUM)) tools_disass_ida_dir = os.path.dirname(__file__) tools_disass_dir = os.path.dirname(tools_disass_ida_dir) @@ -72,6 +82,10 @@ EMAP = {} # Map of external variable names to their sizes, in bytes. EMAP_DATA = {} +# Map of the functions which are forced to be extern and does not require to +# be recovered. +FORCED_EXTERNAL_EMAP = {} + # `True` if we are getting the CFG of a position independent executable. This # affects heuristics like trying to turn immediate operands in instructions # into references into the data. @@ -129,7 +143,7 @@ _FIXED_EXTERNAL_NAMES = {} def demangled_name(name): """Tries to demangle a functin name.""" try: - dname = idc.Demangle(name, idc.GetLongPrm(INF_SHORT_DN)) + dname = idc.demangle_name(name, idc.get_inf_attr(INF_SHORT_DN)) if dname and len(dname) and "::" not in dname: dname = dname.split("(")[0] dname = dname.split(" ")[-1] @@ -290,6 +304,44 @@ def parse_os_defs_file(df): df.close() +def parse_fextern_defs_file(df): + """Parse the file containing forced external function which + does not need to be recovered. + """ + global FORCED_EXTERNAL_EMAP + + for l in df.readlines(): + #skip comments / empty lines + l = l.strip() + if not l or l[0] == "#": + continue + + fname = args = conv = ret = None + line_args = l.split() + + if len(line_args) == 4: + (fname, args, conv, ret) = line_args + + if conv == "C": + realconv = CFG_pb2.ExternalFunction.CallerCleanup + elif conv == "E": + realconv = CFG_pb2.ExternalFunction.CalleeCleanup + elif conv == "F": + realconv = CFG_pb2.ExternalFunction.FastCall + else: + DEBUG("ERROR: Unknown calling convention for forced extern : {}".format(l)) + continue + + if ret not in "YN": + DEBUG("ERROR: Unknown return type {} in {}".format(ret, l)) + continue + + ea = idc.get_name_ea_simple(fname) + + FORCED_EXTERNAL_EMAP[fname] = (int(args), realconv, ret, None) + + df.close() + def is_external_reference(ea): """Returns `True` if `ea` references external data.""" return is_external_segment(ea) \ @@ -331,67 +383,7 @@ _NOT_ELF_THUNKS = set() _INVALID_THUNK = (False, idc.BADADDR, "") _INVALID_THUNK_ADDR = (False, idc.BADADDR) -def is_ELF_thunk_by_structure(ea): - """Try to manually identify an ELF thunk by its structure.""" - global _INVALID_THUNK_ADDR - - if ".plt" not in idc.get_segm_name(ea).lower(): - return _INVALID_THUNK_ADDR - - # Scan through looking for a branch, either direct or indirect. - inst = None - for i in range(4): # 1 is good enough for x86, 4 for aarch64. - inst, _ = decode_instruction(ea) - if not inst: - return _INVALID_THUNK_ADDR - # elif is_direct_jump(inst): - # ea = get_direct_branch_target(inst) - # inst = None - elif is_indirect_jump(inst) or is_direct_jump(inst): - ea = inst.ea - break - else: - ea = inst.ea + inst.size - inst = None - - if not inst: - return _INVALID_THUNK_ADDR - - target_ea = get_reference_target(inst.ea) - if ".got.plt" == idc.get_segm_name(target_ea).lower(): - target_ea = get_reference_target(target_ea) - - # For AArch64, the thunk structure is something like: - # .plt:000400470 .atoi - # .plt:000400470 ADRP X16, #off_411000@PAGE - # .plt:000400474 LDR X17, [X16,#off_411000@PAGEOFF] - # .plt:000400478 ADD X16, X16, #off_411000@PAGEOFF - # .plt:00040047C BR X17 ; atoi - # - # With: - # - # extern:000411070 ; int atoi(const char *nptr) - # extern:000411070 IMPORT atoi - - - # For x86, the thunk structure is something like: - # - # .plt:00041F10 _qsort proc near - # .plt:00041F10 jmp cs:off_31F388 - # .plt:00041F10 _qsort endp - # - # With: - # - # .got.plt:0031F388 off_31F388 dq offset qsort - # - # With - # extern:0031F388 ; void qsort(void *base, ...) - # extern:0031F388 extrn qsort:near - - if is_invalid_ea(target_ea): - return _INVALID_THUNK_ADDR - - return True, target_ea +# NOTE(pag): `is_ELF_thunk_by_structure` is arch-specific. def is_thunk_by_flags(ea): """Try to identify a thunk based off of the IDA flags. This isn't actually @@ -461,6 +453,11 @@ def try_get_thunk_name(ea): name = get_function_name(target_ea) name = undecorate_external_name(name) name = get_true_external_name(name) + # if the elf thunk name is not in external table + if name not in EMAP: + DEBUG("WARNING: Adding {} as external function".format(name)) + EMAP[name] = (16, CFG_pb2.ExternalFunction.CallerCleanup, "N", None) + ret = (is_thunk, target_ea, name) _ELF_THUNKS[ea] = ret return ret @@ -482,38 +479,10 @@ _REFERENCE_OPERAND_TYPE = { Reference.CODE: CFG_pb2.CodeReference.ControlFlowOperand, } -def reference_target_type(ref): - """Sometimes code references into the GOT would be treated as data - references. We fall back onto our external maps as an oracle for - what the type should really be. This has happened with `pcre_free` - references from Apache.""" - if ref.ea in EXTERNAL_VARS_TO_RECOVER: - return CFG_pb2.CodeReference.DataTarget - - # TODO(pag): - #elif ref.ea in EXTERNAL_FUNCS_TO_RECOVER: - # return CFG_pb2.CodeReference.CodeTarget - - elif is_code(ref.ea): - return CFG_pb2.CodeReference.CodeTarget - else: - return CFG_pb2.CodeReference.DataTarget - def reference_operand_type(ref): global _REFERENCE_OPERAND_TYPE return _REFERENCE_OPERAND_TYPE[ref.type] -def reference_location(ref): - if ref.ea in EXTERNAL_VARS_TO_RECOVER: - return CFG_pb2.CodeReference.External - elif ref.ea in EXTERNAL_FUNCS_TO_RECOVER: - return CFG_pb2.CodeReference.External - elif is_external_segment_by_flags(ref.ea): - DEBUG("WARNING: Reference to {:x} is in an external segment, but is not an external var or function".format(ref.ea)) - return CFG_pb2.CodeReference.External - else: - return CFG_pb2.CodeReference.Internal - def referenced_name(ref): if ref.ea in EXTERNAL_VARS_TO_RECOVER: return EXTERNAL_VARS_TO_RECOVER[ref.ea] @@ -522,11 +491,6 @@ def referenced_name(ref): else: return get_true_external_name(ref.symbol) -_TARGET_NAME = { - CFG_pb2.CodeReference.CodeTarget: "code", - CFG_pb2.CodeReference.DataTarget: "data", -} - _OPERAND_NAME = { CFG_pb2.CodeReference.ImmediateOperand: "imm", CFG_pb2.CodeReference.MemoryDisplacementOperand: "disp", @@ -534,11 +498,6 @@ _OPERAND_NAME = { CFG_pb2.CodeReference.ControlFlowOperand: "flow", } -_LOCATION_NAME = { - CFG_pb2.CodeReference.External: "external", - CFG_pb2.CodeReference.Internal: "internal", -} - def format_instruction_reference(ref): """Returns a string representation of a cross reference contained in an instruction.""" @@ -548,14 +507,11 @@ def format_instruction_reference(ref): mask_begin = "(" mask_end = " & {:x})".format(ref.mask) - return "({} {} {} {}{:x}{} {})".format( - _TARGET_NAME[ref.target_type], + return "({} {}{:x}{})".format( _OPERAND_NAME[ref.operand_type], - _LOCATION_NAME[ref.location], mask_begin, ref.ea, - mask_end, - ref.HasField('name') and ref.name or "") + mask_end) def recover_instruction_references(I, inst, addr, refs): """Add the memory/code reference information from this instruction @@ -637,21 +593,14 @@ def recover_instruction_references(I, inst, addr, refs): ref.ea = thunk_target_ea ref.symbol = thunk_name - target_type = reference_target_type(ref) - location = reference_location(ref) - - addrs = set() R = I.xrefs.add() R.ea = ref.ea if ref.mask: R.mask = ref.mask + if ref.imm_val: + R.ea = ref.imm_val R.operand_type = reference_operand_type(ref) - R.target_type = target_type - R.location = location - name = referenced_name(ref) - if name: - R.name = name.format('utf-8') debug_info.append(format_instruction_reference(R)) @@ -664,11 +613,6 @@ def recover_instruction_offset_table(I, table): R = I.xrefs.add() R.ea = table.offset R.operand_type = CFG_pb2.CodeReference.OffsetTable - R.target_type = CFG_pb2.CodeReference.DataTarget - R.location = CFG_pb2.CodeReference.Internal - name = get_symbol_name(table.offset * table.offset_mult, allow_dummy=False) - if name: - R.name = name.format('utf-8') def try_recovery_external_flow(I, inst, refs): """We have somehting like: @@ -688,30 +632,28 @@ def try_recovery_external_flow(I, inst, refs): R = I.xrefs.add() R.ea = ref.ea - R.name = EXTERNAL_FUNCS_TO_RECOVER[ref.ea].format('utf-8') R.operand_type = CFG_pb2.CodeReference.ControlFlowOperand - R.target_type = CFG_pb2.CodeReference.CodeTarget - R.location = CFG_pb2.CodeReference.External if is_indirect_jump(inst): DEBUG("Tail-calls external {}".format(R.name)) else: DEBUG("Calls external {}".format(R.name)) -def recover_instruction(M, B, ea): +# Groups preserved register sets that save/restore the same set of registers. +_REG_SETS = {} + +def recover_instruction(M, F, B, ea): """Recover an instruction, adding it to its parent block in the CFG.""" + global _REG_SETS + inst, inst_bytes = decode_instruction(ea) I = B.instructions.add() I.ea = ea # May not be `inst.ea` because of prefix coalescing. - I.bytes = inst_bytes - - refs = get_instruction_references(inst, PIE_MODE) - recover_instruction_references(I, inst, ea, refs) - - if is_noreturn_inst(inst): - I.local_noreturn = True + xrefs = get_instruction_references(inst, PIE_MODE) + recover_instruction_references(I, inst, ea, xrefs) + regs_saved = recover_preserved_regs(M, F, inst, xrefs, _REG_SETS) DEBUG_PUSH() table = get_jump_table(inst, PIE_MODE) @@ -720,7 +662,10 @@ def recover_instruction(M, B, ea): recover_instruction_offset_table(I, table) if not table: - try_recovery_external_flow(I, inst, refs) + try_recovery_external_flow(I, inst, xrefs) + + if regs_saved and len(regs_saved): + DEBUG("Added save record: {}".format(regs_saved)) DEBUG_POP() @@ -741,19 +686,25 @@ def recover_basic_block(M, F, block_ea): B.ea = block_ea DEBUG_PUSH() + + B.is_referenced_by_data = False + if is_jump_table_target(block_ea) or \ + idaapi.get_first_dref_to(block_ea) != idc.BADADDR or \ + has_our_dref_to(block_ea): + DEBUG("Referenced by data") + B.is_referenced_by_data = True + I = None for inst_ea in inst_eas: - I = recover_instruction(M, B, inst_ea) + I = recover_instruction(M, F, B, inst_ea) # Get the landing pad associated with the instructions; # 0 if no landing pad associated if RECOVER_EHTABLE is True and I: I.lp_ea = get_exception_landingpad(F, inst_ea) DEBUG_PUSH() - if I and I.local_noreturn: - DEBUG("Does not return") - - elif len(succ_eas) > 0: + + if len(succ_eas) > 0: B.successor_eas.extend(succ_eas) DEBUG("Successors: {}".format(", ".join("{0:x}".format(i) for i in succ_eas))) else: @@ -771,23 +722,91 @@ def analyze_jump_table_targets(inst, new_eas, new_func_eas): return for entry_addr, entry_target in table.entries.items(): + new_eas.add(entry_target) if is_start_of_function(entry_target): DEBUG(" Jump table {:x} entry at {:x} references function at {:x}".format( table.table_ea, entry_addr, entry_target)) - new_func_eas.add(entry_target) + new_func_eas.append(entry_target) else: DEBUG(" Jump table {:x} entry at {:x} references block at {:x}".format( table.table_ea, entry_addr, entry_target)) - new_eas.add(entry_target) + +def recover_value_spec(V, spec): + """Recovers an Anvill value specification into the CFG proto format.""" + V.type = spec["type"] + + if "name" in spec and len(spec["name"]): + V.name = spec["name"] + + if "register" in spec: + V.register = spec["register"] + elif "memory" in spec: + mem_spec = spec["memory"] + V.memory.register = mem_spec["register"] + if mem_spec["offset"]: + V.memory.offset = mem_spec["offset"] + +def recover_function_spec(F, spec): + """Recovers most of an Anvill function specification into the CFG proto format.""" + D = F.decl + + if "is_noreturn" in spec: + D.is_noreturn = spec["is_noreturn"] + else: + D.is_noreturn = False + + if "is_variadic" in spec: + D.is_variadic = spec["is_variadic"] + else: + D.is_variadic = False + + if "parameters" in spec: + for param in spec["parameters"]: + P = D.parameters.add() + recover_value_spec(P, param) + + if "return_values" in spec: + for ret_val in spec["return_values"]: + V = D.return_values.add() + recover_value_spec(V, ret_val) + + if "calling_convention" in spec: + D.calling_convention = spec["calling_convention"] + else: + D.calling_convention = 0 + + recover_value_spec(D.return_address, spec["return_address"]) + recover_value_spec(D.return_stack_pointer, spec["return_stack_pointer"]) + +def try_get_anvill_func(func_ea, is_thunk, thunk_target_ea): + """Try to get the Anvill Function object for the function associated with + `func_ea`, and if it's a thunk, then `thunk_target_ea`.""" + + if is_thunk: + try: + if ANVILL_PROGRAM.add_function_declaration(thunk_target_ea): + return ANVILL_PROGRAM.get_function(thunk_target_ea) + except Exception as e: + pass + + try: + if ANVILL_PROGRAM.add_function_declaration(func_ea): + return ANVILL_PROGRAM.get_function(func_ea) + except: + pass + + return None _RECOVERED_FUNCS = set() -def recover_function(M, func_ea, new_func_eas, entrypoints): +def recover_function(M, func_ea, new_func_eas, entrypoints, prev_F, processed_blocks): """Decode a function and store it, all of its basic blocks, and all of their instructions into the CFG file.""" global _RECOVERED_FUNCS + global ANVILL_PROGRAM + global EXTERNAL_FUNCS_TO_RECOVER if func_ea in _RECOVERED_FUNCS: - return + return prev_F _RECOVERED_FUNCS.add(func_ea) @@ -795,33 +814,49 @@ def recover_function(M, func_ea, new_func_eas, entrypoints): # as the start of the function. if not is_start_of_function(func_ea): # and func_ea not in entrypoints: DEBUG("{:x} is not a function! Not recovering.".format(func_ea)) - return + return prev_F + # Double check to see if it looks like a thunk, and if so, we'll just + # re-direct to that. + is_thunk, thunk_target_ea, name = try_get_thunk_name(func_ea) + if is_thunk and name and is_external_segment(thunk_target_ea): + EXTERNAL_FUNCS_TO_RECOVER[func_ea] = name + DEBUG("Deferring recovery of thunk {:x}, resolved to external {}".format( + func_ea, name)) + return prev_F + + name = get_symbol_name(func_ea) + processed_blocks.clear() F = M.funcs.add() F.ea = func_ea F.is_entrypoint = (func_ea in entrypoints) - name = get_symbol_name(func_ea) - if name: - DEBUG("Recovering {} at {:x}".format(name, func_ea)) - F.name = name.format('utf-8') - else: + + if not name: DEBUG("Recovering {:x}".format(func_ea)) + else: + F.name = name.format('utf-8') + DEBUG("Recovering {} at {:x}".format(F.name, func_ea)) + + # Try to get the Anvill representation of this function. + anvill_func = try_get_anvill_func(func_ea, is_thunk, thunk_target_ea) + if anvill_func: + recover_function_spec(F, anvill_func.proto()) DEBUG_PUSH() + # Update the protobuf with the recovered eh_frame entries if RECOVER_EHTABLE is True: recover_exception_entries(F, func_ea) - blockset, term_insts = analyse_subroutine(func_ea, PIE_MODE) + block_eas, term_insts = analyse_subroutine(func_ea, PIE_MODE) for term_inst in term_insts: if get_jump_table(term_inst, PIE_MODE): DEBUG("Terminator inst {:x} in func {:x} is a jump table".format( term_inst.ea, func_ea)) - analyze_jump_table_targets(term_inst, blockset, new_func_eas) + analyze_jump_table_targets(term_inst, block_eas, new_func_eas) - processed_blocks = set() - while len(blockset) > 0: - block_ea = blockset.pop() + while len(block_eas) > 0: + block_ea = block_eas.pop() if block_ea in processed_blocks: DEBUG("ERROR: Attempting to add same block twice: {0:x}".format(block_ea)) continue @@ -829,16 +864,14 @@ def recover_function(M, func_ea, new_func_eas, entrypoints): processed_blocks.add(block_ea) recover_basic_block(M, F, block_ea) - if TO_RECOVER["stack_var"]: - recover_variables(F, func_ea, processed_blocks) - DEBUG_POP() + return F def find_default_function_heads(): """Loop through every function, to discover the heads of all blocks that IDA recognizes. This will populate some global sets in `flow.py` that will help distinguish block heads.""" - func_heads = set() + func_eas = [] for seg_ea in idautils.Segments(): seg_type = idc.get_segm_attr(seg_ea, idc.SEGATTR_TYPE) if seg_type != idc.SEG_CODE: @@ -846,9 +879,9 @@ def find_default_function_heads(): for func_ea in idautils.Functions(seg_ea, idc.get_segm_end(seg_ea)): if is_code_by_flags(func_ea): - func_heads.add(func_ea) + func_eas.append(func_ea) - return func_heads + return func_eas def recover_region_variables(M, S, seg_ea, seg_end_ea, exported_vars): """Look for named locations pointing into the data of this segment, and @@ -910,8 +943,8 @@ def recover_region_cross_references(M, S, seg_ea, seg_end_ea): # of a basic block. Our goal is thus to preserve the original values, # and implement the switch in terms of those original values on the # LLVM side of things. - if is_jump_table_entry(ea): - continue + #if is_jump_table_entry(ea): + # continue # Skip over instructions. if is_code_seg: @@ -961,12 +994,10 @@ def recover_region_cross_references(M, S, seg_ea, seg_end_ea): X.ea = ea X.width = xref_width X.target_ea = target_ea - X.target_name = get_symbol_name(target_ea) - X.target_is_code = is_code(target_ea) or \ - target_ea in EXTERNAL_FUNCS_TO_RECOVER + target_name = get_symbol_name(target_ea) if is_external_segment(X.target_ea): - X.target_name = get_true_external_name(X.target_name) + target_name = get_true_external_name(target_name) # A cross-reference to some TLS data. Because each thread has its own # instance of the data, this reference ends up actually being an offset @@ -976,16 +1007,16 @@ def recover_region_cross_references(M, S, seg_ea, seg_end_ea): if is_tls(target_ea): X.target_fixup_kind = CFG_pb2.DataReference.OffsetFromThreadBase DEBUG("{}-byte TLS offset at {:x} to {:x} ({})".format( - X.width, ea, target_ea, X.target_name)) + X.width, ea, target_ea, target_name)) # A cross-reference to a 'single' thing, where the fixup that we create # will be an absolute address to the targeted variable/function. else: X.target_fixup_kind = CFG_pb2.DataReference.Absolute DEBUG("{}-byte reference at {:x} to {:x} ({})".format( - X.width, ea, target_ea, X.target_name)) + X.width, ea, target_ea, target_name)) - try_identify_as_external_function(target_ea, X.target_name) + try_identify_as_external_function(target_ea, target_name) def recover_region(M, region_name, region_ea, region_end_ea, exported_vars): @@ -1143,8 +1174,10 @@ def recover_regions(M, exported_vars, global_vars=[]): seg_name = idc.get_segm_name(seg_ea) for begin_ea, end_ea in zip(parts[:-1], parts[1:]): region_name = seg_name - if begin_ea in seg_names: + if begin_ea in seg_names and \ + not is_runtime_external_data_reference(begin_ea): region_name = seg_names[begin_ea] + recover_region(M, region_name, begin_ea, end_ea, exported_vars) def recover_external_functions(M): @@ -1153,6 +1186,19 @@ def recover_external_functions(M): global EXTERNAL_FUNCS_TO_RECOVER, WEAK_SYMS, EMAP for ea, name in EXTERNAL_FUNCS_TO_RECOVER.items(): + + # Try to fix up the name. Sometimes the thunks have names like `_setlocale`, + # whereas the external will have the proper `setlocate` name. + is_thunk, thunk_target_ea, thunk_name = try_get_thunk_name(ea) + if is_thunk and thunk_name: + name = thunk_name + + if name not in EMAP and not try_infer_func_for_emap(name, ea): + DEBUG("ERROR: Not recovering external function {} at {:x}; info not in EMAP".format(name, ea)) + return + + anvill_func = try_get_anvill_func(ea, False, ea) + DEBUG("Recovering extern function {} at {:x}".format(name, ea)) args, conv, ret, sign = EMAP[name] E = M.external_funcs.add() @@ -1164,10 +1210,15 @@ def recover_external_functions(M): E.no_return = ret == 'Y' # TODO(pag): This should probably reflect whether or not the function - # actually returns something, rather than simply does not - # return (e.g. `abort`). + # actually returns something, rather than simply does not + # return (e.g. `abort`). E.has_return = ret == 'N' + if anvill_func: + recover_function_spec(E, anvill_func.proto()) + else: + recover_function_spec_from_arch(E) + def recover_external_variables(M): """Reover the named external variables (e.g. `stdout`) that are referenced within this binary.""" @@ -1192,6 +1243,14 @@ def recover_external_symbols(M): recover_external_functions(M) recover_external_variables(M) +def is_forced_external(ea): + name = get_function_name(ea) + return (name in FORCED_EXTERNAL_EMAP) + +def add_fextern_to_emap(name, ea): + if name in FORCED_EXTERNAL_EMAP: + EMAP[name] = FORCED_EXTERNAL_EMAP[name] + def try_identify_as_external_function(ea, name=None): """Try to identify a function as being an external function.""" global EXTERNAL_FUNCS_TO_RECOVER, EMAP @@ -1213,6 +1272,10 @@ def try_identify_as_external_function(ea, name=None): elif is_external_segment(ea): name = get_true_external_name(get_function_name(ea)) + elif is_forced_external(ea): + name = get_function_name(ea) + add_fextern_to_emap(name, ea) + elif not name: return False @@ -1222,13 +1285,75 @@ def try_identify_as_external_function(ea, name=None): INTERNAL_THUNK_EAS[ea] = impl_ea return False + # If we don't have info about this function from our std defs file, then + # try to figure it out from IDA's internal info. if name not in EMAP: - return False + if not try_infer_func_for_emap(name, ea): + return False + + # args, conv, ret, sign DEBUG("Function at {:x} is the external function {}".format(ea, name)) EXTERNAL_FUNCS_TO_RECOVER[ea] = name return True +def try_infer_func_for_emap(name, ea): + """Tries to infer function information to add to the EMAP, which stores + our external info. This uses IDA's internal type info.""" + global _FIXED_EXTERNAL_NAMES + global WEAK_SYMS + + is_thunk, thunk_target_ea, thunk_name = try_get_thunk_name(ea) + if not is_thunk: + return False + + type_info = idaapi.tinfo_t() + if not idaapi.get_tinfo2(ea, type_info): + if thunk_target_ea != ea: + ea = thunk_target_ea + type_info = idaapi.tinfo_t() + if not idaapi.get_tinfo2(ea, type_info): + return False + else: + return False + + func_data = idaapi.func_type_data_t() + if not type_info.get_func_details(func_data): + return False + + num_args = func_data.size() + is_noreturn = 'N' + if is_noreturn_function(ea): + is_noreturn = 'Y' + + conv = CFG_pb2.ExternalFunction.CallerCleanup + if func_data.cc & idaapi.CM_CC_STDCALL: + conv = CFG_pb2.ExternalFunction.CalleeCleanup + elif func_data.cc & idaapi.CM_CC_FASTCALL: + conv = CFG_pb2.ExternalFunction.FastCall + + EMAP[name] = (num_args, conv, is_noreturn, None) + + imp_name = "__imp_{}".format(name) + if idc.get_name_ea_simple(imp_name): + _FIXED_EXTERNAL_NAMES[imp_name] = name + WEAK_SYMS.add(name) + WEAK_SYMS.add(imp_name) + + return True + +def force_add_func_to_emap(target_name, ea): + """Forcefully adds a function to the EMAP.""" + DEBUG("WARNING: Adding external {} at {:x} as an external code reference".format( + target_name, ea)) + EMAP[target_name] = (16, CFG_pb2.ExternalFunction.CallerCleanup, "N", None) + + imp_name = "__imp_{}".format(target_name) + if idc.get_name_ea_simple(imp_name): + _FIXED_EXTERNAL_NAMES[imp_name] = target_name + WEAK_SYMS.add(target_name) + WEAK_SYMS.add(imp_name) + def identify_thunks(func_eas): DEBUG("Looking for thunks") DEBUG_PUSH() @@ -1271,15 +1396,8 @@ def identify_external_symbols(): # likely point into the `extern` section. Individual # entries in the extern section can have if idc.is_code(target_flags): - DEBUG("WARNING: Adding external {} at {:x} as an external code reference".format( - target_name, ea)) - EMAP[target_name] = (16, CFG_pb2.ExternalFunction.CallerCleanup, "N", None) - - imp_name = "__imp_{}".format(target_name) - if idc.get_name_ea_simple(imp_name): - _FIXED_EXTERNAL_NAMES[imp_name] = target_name - WEAK_SYMS.add(target_name) - WEAK_SYMS.add(imp_name) + if not try_infer_func_for_emap(target_name, ea): + force_add_func_to_emap(target_name, ea) # The else: @@ -1337,7 +1455,7 @@ def identify_external_symbols(): # file with only one global variable `FILE *fp = stdout;`. Some versions # of IDA will treat the local copy of `stdout` as being the symbol # `__bss_start`. - comment = idc.GetCommentEx(ea, 0) or "" + comment = ida_bytes.get_cmt(ea, 0) or "" for comment_line in comment.split("\n"): comment_line = comment_line.replace(";", "").strip() found_name = get_true_external_name(comment_line, demangle=is_code(ea)) @@ -1363,7 +1481,7 @@ def identify_program_entrypoints(func_eas): exclude = set(["_start", "__libc_csu_fini", "__libc_csu_init", "main", "__data_start", "__dso_handle", "_IO_stdin_used", - "_dl_relocate_static_pie"]) + "_dl_relocate_static_pie", "__DTOR_END__"]) exported_funcs = set() exported_vars = set() @@ -1377,7 +1495,7 @@ def identify_program_entrypoints(func_eas): set_symbol_name(ea, name) if is_code(ea): - func_eas.add(ea) + func_eas.append(ea) if name not in exclude: exported_funcs.add(ea) else: @@ -1411,8 +1529,8 @@ def find_main_in_ELF_file(): return idc.BADADDR for begin_ea, end_ea in idautils.Chunks(start_ea): - for inst_ea in Heads(begin_ea, end_ea): - comment = idc.GetCommentEx(inst_ea, 0) + for inst_ea in idautils.Heads(begin_ea, end_ea): + comment = ida_bytes.get_cmt(inst_ea, 0) if comment and "main" in comment: for main_ea in xrefs_from(inst_ea): if not is_code(main_ea): @@ -1443,13 +1561,15 @@ def recover_module(entrypoint, gvar_infile = None): M = CFG_pb2.Module() M.name = idc.get_root_filename().format('utf-8') DEBUG("Recovering module {}".format(M.name)) - - entry_ea = idc.get_name_ea_simple(args.entrypoint) - # If the entrypoint is `main`, then we'll try to find `main` via another - # means. - if is_invalid_ea(entry_ea): - if "main" == args.entrypoint and IS_ELF: - entry_ea = find_main_in_ELF_file() + + entry_ea = idc.BADADDR + if args.entrypoint: + entry_ea = idc.get_name_ea_simple(args.entrypoint) + # If the entrypoint is `main`, then we'll try to find `main` via another + # means. + if is_invalid_ea(entry_ea): + if "main" == args.entrypoint and IS_ELF: + entry_ea = find_main_in_ELF_file() if RECOVER_EHTABLE: recover_exception_table() @@ -1466,13 +1586,19 @@ def recover_module(entrypoint, gvar_infile = None): exported_funcs, exported_vars = identify_program_entrypoints(func_eas) if is_invalid_ea(entry_ea): - DEBUG("ERROR: Could not find entrypoint {}".format(args.entrypoint)) + if args.entrypoint: + DEBUG("ERROR: Could not find entrypoint {}".format(args.entrypoint)) else: - func_eas.add(entry_ea) + func_eas.append(entry_ea) exported_funcs.add(entry_ea) + prev_F = None + processed_blocks = set() + + func_eas.sort(reverse=True) + # Process and recover functions. - while len(func_eas) > 0: + while len(func_eas): func_ea = func_eas.pop() if func_ea in RECOVERED_EAS or func_ea in EXTERNAL_FUNCS_TO_RECOVER: continue @@ -1490,9 +1616,11 @@ def recover_module(entrypoint, gvar_infile = None): if is_external_segment_by_flags(func_ea): continue - recover_function(M, func_ea, func_eas, exported_funcs) + prev_F = recover_function(M, func_ea, func_eas, exported_funcs, prev_F, processed_blocks) recovered_fns += 1 + recover_deferred_preserved_regs(M) + if recovered_fns == 0: DEBUG("COULD NOT RECOVER ANY FUNCTIONS") return @@ -1562,7 +1690,7 @@ if __name__ == "__main__": parser.add_argument( '--entrypoint', help="The entrypoint where disassembly should begin", - required=True) + required=False) parser.add_argument( '--recover-global-vars', @@ -1582,6 +1710,12 @@ if __name__ == "__main__": default=False, help="Flag to enable the exception handler recovery") + parser.add_argument( + '--forced-extern-defs', + help='List of functions which are forced to be extern and dont need to be recovered', + default=None, + required=False) + args = parser.parse_args(args=idc.ARGV[1:]) if args.log_file != os.devnull: @@ -1600,7 +1734,7 @@ if __name__ == "__main__": PIE_MODE = True if args.recover_stack_vars: - TO_RECOVER["stack_var"] = True + DEBUG("Stack variable recovery is deprecated") if args.recover_exception: RECOVER_EHTABLE = True @@ -1620,6 +1754,13 @@ if __name__ == "__main__": DEBUG("Loading Standard Definitions file: {0}".format(defsfile)) parse_os_defs_file(df) + if args.forced_extern_defs: + defsfile_list = args.forced_extern_defs.split(',') + for defsfile in defsfile_list: + extern_defsfile = os.path.abspath(defsfile) + with open(extern_defsfile, 'r') as df: + parse_fextern_defs_file(df) + # Turn off "automatically make offset" heuristic, and set some # other sane defaults. idc.set_inf_attr(idc.INF_AF, 0xdfff) @@ -1629,6 +1770,8 @@ if __name__ == "__main__": DEBUG("Using Batch mode.") idaapi.auto_wait() + ANVILL_PROGRAM = anvill.get_program() + DEBUG("Starting analysis") try: # Pre-define a bunch of symbol names and their addresses. Useful when reading diff --git a/tools/mcsema_disass/ida7/refs.py b/tools/mcsema_disass/ida7/refs.py index 1d8594253..6b7528ab4 100644 --- a/tools/mcsema_disass/ida7/refs.py +++ b/tools/mcsema_disass/ida7/refs.py @@ -1,23 +1,24 @@ -# Copyright (c) 2017 Trail of Bits, Inc. +# Copyright (c) 2020 Trail of Bits, Inc. # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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 Affero General Public License for more details. # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . import ida_bytes import ida_nalt from util import * class Reference(object): - __slots__ = ('offset', 'ea', 'symbol', 'type', 'mask') + __slots__ = ('offset', 'ea', 'symbol', 'type', 'mask', 'imm_val') INVALID = 0 IMMEDIATE = 1 @@ -33,12 +34,13 @@ class Reference(object): CODE: "code", } - def __init__(self, ea, offset, mask=0): + def __init__(self, ea, offset, mask=0, imm_val=0): self.offset = offset self.ea = ea self.symbol = "" self.type = self.INVALID self.mask = mask + self.imm_val = imm_val def __str__(self): mask_str = "" @@ -53,6 +55,10 @@ class Reference(object): def is_valid(self): return self.type != self.INVALID +# Sort flow references first; in arch utils, when looking up preserved +# registers, we need easy access to flow targets, if any. +_REF_SORT_KEY = lambda r: -r.type + # Try to determine if `ea` points at a field within a structure. This is a # heuristic for determining whether or not an immediate `ea` should actually # be treated as a reference. The intuition is that if it points into a logical @@ -94,7 +100,7 @@ def _is_address_of_struct_field(ea): if field_begin_ea != ea: return False - field_size = idc.GetMemberSize(oi.tid, off_in_struct) + field_size = idc.get_member_size(oi.tid, off_in_struct) if not field_size: return False @@ -199,64 +205,6 @@ def remove_instruction_reference(from_ea, to_ea): if found: _REFS[from_ea] = tuple(new_refs) -def _get_arm_ref_candidate(mask, op_val, op_str, all_refs): - global _BAD_ARM_REF_OFF - - try: - op_name = op_str.split("@")[0][1:] # `#asc_400E5C@PAGE` -> `asc_400E5C`. - ref_ea = idc.get_name_ea_simple(op_name) - if (ref_ea & mask) == op_val: - return ref_ea, mask - except: - pass - - # NOTE(pag): We deal with candidates because it's possible that this - # instruction will have multiple references. In the case of - # `@PAGE`-based offsets, it's problematic when the wrong base - # is matched, because it really throws off the C++ side of things - # because the arrangement of the lifted data being on the same - # page is not guaranteed. - - candidates = set() - for ref_ea in all_refs: - if (ref_ea & mask) == op_val: - candidates.add(ref_ea) - return ref_ea, mask - - if len(candidates): - for candidate_ea in candidates: - if candidate_ea == op_val: - return candidate_ea, mask - - return candidates.pop(), mask - - return _BAD_ARM_REF_OFF - -# Try to handle `@PAGE` and `@PAGEOFF` references, resolving them to their -# 'intended' address. -# -# TODO(pag): There must be a better way than just string searching :-/ -def _try_get_arm_ref_addr(inst, op, op_val, all_refs): - global _BAD_ARM_REF_OFF - - if op.type not in (idc.o_imm, idc.o_displ): - # This is a reference type that the other ref tracking code - # can handle, return defaults - return op_val, 0 - - op_str = idc.GetOpnd(inst.ea, op.n) - - if '@PAGEOFF' in op_str: - return _get_arm_ref_candidate(4095, op_val, op_str, all_refs) - - elif '@PAGE' in op_str: - return _get_arm_ref_candidate(-4096L, op_val, op_str, all_refs) - - elif not is_invalid_ea(op_val) and inst.get_canon_mnem().lower() == "adr": - return op_val, 0 - - return _BAD_ARM_REF_OFF - # Returns `True` if `ea` looks like it points into the middle of an instruction. def _is_ea_into_bad_code(ea, binary_is_pie): if not is_code(ea): @@ -267,7 +215,8 @@ def _is_ea_into_bad_code(ea, binary_is_pie): if not term_inst: return True - succs = list(flow.get_static_successors(idc.BADADDR, term_inst, binary_is_pie)) + delayed_inst, delayed_ea = get_delayed_instruction(term_inst) + succs = list(flow.get_static_successors(idc.BADADDR, term_inst, delayed_inst, binary_is_pie)) if not succs: return True @@ -277,14 +226,37 @@ def _is_ea_into_bad_code(ea, binary_is_pie): return False +# Returns `True` if a number looks more like a magic constant that would +# appear in a program. +def _looks_like_constant(val): + # In decimal, a number with only a single non-zero digit. + if len("{}".format(val).replace("0", "")) == 1: + return True + + # This looks more like a bitmask, or just some value without much going on + # in it. + bin_rep = "{:b}".format(val) + if min(bin_rep.count('1'), bin_rep.count('0')) <= 2: + return True + + hex_rep = "{:x}".format(val) + + # Looks like it's probably a bitmask or negative value meant for sign-exension. + if len(hex_rep) in (4, 8, 16) and hex_rep.startswith('ff'): + return True + + # TODO(pag): Look for yyyymmdd, ddmmyyyy, etc.? + return False + # Try to recognize an operand as a reference candidate when a target fixup # is not available. def _get_ref_candidate(inst, op, all_refs, binary_is_pie): - global _POSSIBLE_REFS, _ENABLE_CACHING + global _POSSIBLE_REFS, _ENABLE_CACHING, _NOT_A_REF ref = None addr_val = idc.BADADDR mask = 0 + imm_val = 0 is_memop = idc.o_mem == op.type if idc.o_imm == op.type: @@ -294,13 +266,8 @@ def _get_ref_candidate(inst, op, all_refs, binary_is_pie): else: return None - # TODO(artem): We should have a class that has ref heuristics and put ARM - # related refs in the ARM class, and X86 in the x86 class that - # will avoid these awkward `if IS_ARM` and the comments about - # x86 / amd64 stuff. - if IS_ARM: - old_addr_val = addr_val - addr_val, mask = _try_get_arm_ref_addr(inst, op, addr_val, all_refs) + old_addr_val = addr_val + addr_val, mask, imm_val = try_get_ref_addr(inst, op, addr_val, all_refs, _NOT_A_REF) info = idaapi.refinfo_t() has_ref_info = ida_nalt.get_refinfo(info, inst.ea, op.n) == 1 @@ -349,7 +316,9 @@ def _get_ref_candidate(inst, op, all_refs, binary_is_pie): # Same as above, `idal64` can miss things that `idaq` gets. if addr_val not in all_refs: nearest_head_ea = _nearest_head(addr_val, 128) - if not is_invalid_ea(nearest_head_ea) and not _is_ea_into_bad_code(nearest_head_ea, binary_is_pie): + if not is_invalid_ea(nearest_head_ea) and \ + not _is_ea_into_bad_code(nearest_head_ea, binary_is_pie) and \ + not _looks_like_constant(addr_val): DEBUG("WARNING: Adding reference from {:x} to {:x}, which is near other heads".format( inst.ea, addr_val)) all_refs.add(addr_val) @@ -372,7 +341,7 @@ def _get_ref_candidate(inst, op, all_refs, binary_is_pie): _POSSIBLE_REFS.add(addr_val) return None - ref = Reference(addr_val, op.offb, mask=mask) + ref = Reference(addr_val, op.offb, mask=mask, imm_val=imm_val) # Make sure we add in a reference to the (possibly new) head, addressed # by `addr_val`. @@ -388,7 +357,7 @@ def memop_is_actually_displacement(inst): and tell us that this is an `o_mem` rather than an `o_displ`. We really want to recognize it as an `o_displ` because the memory reference is a displacement and not an absolute address.""" - asm = idc.GetDisasm(inst.ea) + asm = disassemble(inst.ea) return "[" in asm and "]" in asm # Return the set of all references from `ea` to anything. @@ -424,7 +393,7 @@ def get_instruction_references(arg, binary_is_pie=False): if inst.ea in _REFS: return _REFS[inst.ea] - offset_to_ref = {} + # offset_to_ref = {} all_refs = get_all_references_from(inst.ea) del _FIXUPS[:] @@ -443,8 +412,8 @@ def get_instruction_references(arg, binary_is_pie=False): op_ea = inst.ea + op.offb ref = None - if op.offb in offset_to_ref: - ref = offset_to_ref[op.offb] + # if op.offb in offset_to_ref: + # ref = offset_to_ref[op.offb] if not ref or is_invalid_ea(ref.ea): ref = _get_ref_candidate(inst, op, all_refs, binary_is_pie) @@ -502,7 +471,10 @@ def get_instruction_references(arg, binary_is_pie=False): # Code reference. elif idc.o_near == op.type: - assert ref.ea == op.addr + # assert ref.ea == op.addr + if ref.ea != op.addr: + DEBUG("ERROR inst={:x} ref.ea={:x} op.addr={:x}".format(inst.ea, ref.ea, op.addr)) + ref.type = Reference.CODE ref.symbol = get_symbol_name(op_ea, ref.ea) @@ -522,14 +494,13 @@ def get_instruction_references(arg, binary_is_pie=False): # go and prefer the instruction-operand focused approach, and fall back on # fixup targets when available. for offset, targ_ea in _FIXUPS: - if offset not in offset_to_ref and (inst.ea, targ_ea) not in _NOT_A_REF: + # if offset not in offset_to_ref and (inst.ea, targ_ea) not in _NOT_A_REF: + if (inst.ea, targ_ea) not in _NOT_A_REF: refs.append(Reference(targ_ea, offset)) - for ref in refs: - assert not is_invalid_ea(ref.ea) - if len(refs): - refs = tuple(refs) + refs.sort(key=_REF_SORT_KEY) + refs = tuple(r for r in refs if not is_invalid_ea(r.ea)) if _ENABLE_CACHING: _REFS[inst.ea] = refs return refs diff --git a/tools/mcsema_disass/ida7/segment.py b/tools/mcsema_disass/ida7/segment.py index 6b7de5c71..87ded082e 100644 --- a/tools/mcsema_disass/ida7/segment.py +++ b/tools/mcsema_disass/ida7/segment.py @@ -1,16 +1,17 @@ -# Copyright (c) 2017 Trail of Bits, Inc. +# Copyright (c) 2020 Trail of Bits, Inc. # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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 Affero General Public License for more details. # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . from flow import * from table import * @@ -55,8 +56,16 @@ def is_sane_reference_target(ea): #item_size = idc.get_item_size(ea) + # If the byte has value but no other flag is set + # This is possibly not a true reference target + if not IS_ARM: + if (flags == idc.FF_IVL) \ + or (flags == idc.FF_UNK) \ + or (flags == 0xfff00300): + return False + #DEBUG("!!! target_ea = {:x} item_size = {}".format(ea, item_size)) - #return 1 != item_size + #return 1 != item_size #NOTE(artem): Above lines commented out since they caused problems # and we cannot determine what they fixed. If this code has problems # again, consider a solution that handles both cases properly @@ -94,7 +103,7 @@ def next_reasonable_head(ea, max_ea): matched ones. If the next logical head is a string, but the actual head is an alignment, then we really want to find the head of the string. - TODO(pag): Investigate using `idc.NextNotTail(ea)`.""" + TODO(pag): Investigate using `ida_bytes.next_not_tail(ea)`.""" while ea < max_ea: ea = idc.next_head(ea, max_ea) flags = idc.get_full_flags(ea) @@ -195,13 +204,28 @@ def remaining_item_size(ea): assert (head_ea + size) >= ea return (head_ea + size) - ea + +_POPCOUNT_TABLE8 = [0] * 2**8 +for index in xrange(len(_POPCOUNT_TABLE8)): + _POPCOUNT_TABLE8[index] = (index & 1) + _POPCOUNT_TABLE8[index >> 1] + +def _popcount(v): + v = struct.unpack("=Q", struct.pack("=Q", v))[0] + count = 0 + while v: + count += _POPCOUNT_TABLE8[v & 0xff] + v = v >> 8 + return count + def find_missing_xrefs_in_segment(seg_ea, seg_end_ea, binary_is_pie): """Look for cross-refernces that were missed by IDA. This function assumes a natural alignments for pointers (i.e. 4- or 8-byte alignment).""" + addr_size_bits = get_address_size_in_bits() + seg_ea = (seg_ea + 3) & ~3 # Align to a 4-byte boundary. - try_qwords = get_address_size_in_bits() == 64 + try_qwords = addr_size_bits == 64 try_dwords = True if try_qwords and binary_is_pie: try_dwords = False @@ -211,6 +235,8 @@ def find_missing_xrefs_in_segment(seg_ea, seg_end_ea, binary_is_pie): missing_refs = [] + maybe_jump_table_entries = [] + while next_ea < seg_end_ea: ea, next_ea = next_ea, idc.BADADDR if is_invalid_ea(ea): @@ -239,11 +265,20 @@ def find_missing_xrefs_in_segment(seg_ea, seg_end_ea, binary_is_pie): qword_data, dword_data = 0, 0 + # Minimum number of set bits for something to be considered an address. + MIN_NUM_SET_BITS = 1 + # Try to read it as an 8-byte pointer. if try_qwords and (ea + 8) <= seg_end_ea: target_ea = qword_data = read_qword(ea) if is_sane_reference_target(target_ea): - if make_xref(ea, target_ea, idc.FF_QWORD, 8): + if MIN_NUM_SET_BITS >= _popcount(target_ea): + DEBUG("Ignoring possible qword reference from {:x} to {:x}: not enough set bits".format( + ea, target_ea)) + + elif make_dref(ea, target_ea, ida_bytes.FF_QWORD, 8): + if is_block_or_instruction_head(target_ea): + maybe_jump_table_entries.append((ea, 8)) DEBUG("Adding qword reference from {:x} to {:x}".format(ea, target_ea)) next_ea = ea + 8 continue @@ -252,7 +287,7 @@ def find_missing_xrefs_in_segment(seg_ea, seg_end_ea, binary_is_pie): if try_dwords and (ea + 4) <= seg_end_ea: target_ea = dword_data = read_dword(ea) if is_sane_reference_target(target_ea): - if make_xref(ea, target_ea, idc.FF_DWORD, 4): + if make_dref(ea, target_ea, idc.FF_DWORD, 4): DEBUG("Adding dword reference from {:x} to {:x}".format(ea, target_ea)) next_ea = ea + 4 continue @@ -270,6 +305,23 @@ def find_missing_xrefs_in_segment(seg_ea, seg_end_ea, binary_is_pie): DEBUG("Stopping scan at {:x}".format(ea)) + # Look for missed jump tables. + for (entry_ea, entry_size) in maybe_jump_table_entries: + if is_jump_table_entry(entry_ea): + continue + inst_ea = None + for maybe_inst_ea in xrefs_to(entry_ea): + if is_block_or_instruction_head(maybe_inst_ea): + inst_ea = maybe_inst_ea + break + if not inst_ea: + continue + + DEBUG("Investigating possibly missed jump table at {:x} referenced by {:x}".format( + entry_ea, inst_ea)) + try_create_jump_table(inst_ea, entry_ea, entry_size, binary_is_pie) + + def _next_code_or_jt_ea(ea): """Scan forward looking for the next non-data effective address.""" seg_end_ea = idc.get_segm_end(ea) diff --git a/tools/mcsema_disass/ida7/table.py b/tools/mcsema_disass/ida7/table.py index 308ec2cd8..8d709ef66 100644 --- a/tools/mcsema_disass/ida7/table.py +++ b/tools/mcsema_disass/ida7/table.py @@ -1,21 +1,26 @@ -# Copyright (c) 2017 Trail of Bits, Inc. +# Copyright (c) 2020 Trail of Bits, Inc. # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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 Affero General Public License for more details. # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . from refs import * +import struct + _FIRST_JUMP_TABLE_ENTRY = {} _JUMP_TABLE_ENTRY = {} +_IS_JUMP_TABLE_ENTRY = set() +_FUDGE_FACTOR = 256 class JumpTable(object): """Represents generic info known about a particular jump table.""" @@ -39,9 +44,15 @@ class JumpTable(object): idc.add_cref(self.inst_ea, target_ea, idc.XREF_USER | idc.fl_JN) max_ea = max(max_ea, entry_ea + self.entry_size) + entry_type = ida_bytes.FF_QWORD + if self.entry_size == 4: + entry_type = ida_bytes.FF_DWORD + # Make sure each entry is seen as referenced. for entry_ea, target_ea in entries.items(): - idc.add_dref(self.inst_ea, entry_ea, idc.dr_I) + idc.create_data(entry_ea, entry_type, self.entry_size, idaapi.BADADDR) + idc.add_dref(entry_ea, target_ea, idc.XREF_USER|idc.dr_I) + idc.add_dref(self.inst_ea, entry_ea, idc.XREF_USER|idc.dr_I) # Make sure that the contents of the table are no longer considered # code (only affects `is_code`). This is only meaningful if the table @@ -49,10 +60,13 @@ class JumpTable(object): for ea_into_table in xrange(self.table_ea, max_ea): mark_as_not_code(ea_into_table) _FIRST_JUMP_TABLE_ENTRY[ea_into_table] = self.table_ea + _IS_JUMP_TABLE_ENTRY.add(ea_into_table) _JUMP_TABLE_ENTRY[self.table_ea] = self idaapi.auto_wait() +_IS_TARGETED_BY_JUMP_TABLE = set() + class JumpTableBuilder(object): _READERS = { 4: read_dword, @@ -60,6 +74,8 @@ class JumpTableBuilder(object): } def __init__(self, inst, binary_is_pie): + import util + self.entry_size = 0 self.entry_mult = 1 self.table_ea = idc.BADADDR @@ -77,9 +93,20 @@ class JumpTableBuilder(object): data &= 0xFFFFFFFFFFFFFFFF if 4 == self.entry_size and (self.offset & 0xFFFFFFFF) == self.offset: data &= 0xFFFFFFFF - return data +def _check_entry_target_ea(target_ea, min_ea, max_ea): + global _FUDGE_FACTOR + min_ea = max(0, min_ea - _FUDGE_FACTOR) + max_ea += _FUDGE_FACTOR + if min_ea > target_ea or max_ea <= target_ea: + return False + + if not is_block_or_instruction_head(target_ea): + return False + + return True + def get_default_jump_table_entries(builder): """Return the 'default' jump table entries, based on IDA's ability to recognize a jump table. If IDA doesn't recognize the table, then we @@ -98,6 +125,8 @@ def get_default_jump_table_entries(builder): def get_num_jump_table_entries(builder): """Try to get the number of entries in a jump table. This will use some base set of entries.""" + global _IS_TARGETED_BY_JUMP_TABLE + curr_num_targets = len(builder.candidate_target_eas) DEBUG("Checking if jump table at {:x} has more than {} entries".format( @@ -121,6 +150,8 @@ def get_num_jump_table_entries(builder): DEBUG(" ERROR jump table {:x} entry candidate {} target {:x} is not sane!".format( builder.table_ea, i, curr_target)) continue + + _IS_TARGETED_BY_JUMP_TABLE.add(curr_target) targ_min_ea, targ_max_ea = get_function_bounds(curr_target) if targ_min_ea >= max_ea or targ_max_ea <= min_ea: @@ -148,6 +179,12 @@ def get_num_jump_table_entries(builder): max_i = max(curr_num_targets, 2048) entry_addr = builder.table_ea table_seg_ea = idc.get_segm_start(builder.table_ea) + stop_at = max_i + + entry_type = ida_bytes.FF_QWORD + if builder.entry_size == 4: + entry_type = ida_bytes.FF_DWORD + for i in xrange(max_i): # Make sure we don't read across a segment (e.g. if the jump table is the @@ -158,6 +195,9 @@ def get_num_jump_table_entries(builder): except: break + #if entry_addr in _FIRST_JUMP_TABLE_ENTRY: + # DEBUG(" Entry at {:x} is already part of another jump table".format(entry_addr)) + entry_data = builder.read_entry(entry_addr) next_entry_addr = entry_addr + (builder.entry_size * builder.entry_mult) @@ -174,9 +214,18 @@ def get_num_jump_table_entries(builder): DEBUG(" Not an entry, the target {:x} isn't sane.".format(entry_data)) break - elif min_ea > entry_data or entry_data >= max_ea: - DEBUG(" Not an entry, the target {:x} is out of range.".format(entry_data)) - break + elif not _check_entry_target_ea(entry_data, min_ea, max_ea): + DEBUG(" Not an entry, the target {:x} is out of range [{:x}, {:x})".format( + entry_data, min_ea, max_ea)) + stop_at = min(stop_at, i) + + if entry_data != get_reference_target(entry_addr): + idc.create_data(entry_addr, entry_type, builder.entry_size, idaapi.BADADDR) + idc.add_dref(entry_addr, entry_data, idc.XREF_USER|idc.dr_I) + + _IS_TARGETED_BY_JUMP_TABLE.add(entry_data) + for entry_addr_sub_ea in xrange(entry_addr, entry_addr + builder.entry_size): + _IS_JUMP_TABLE_ENTRY.add(entry_addr_sub_ea) # We will assume that any reference to the data in here means # that we've gone and found the end of a table. @@ -195,8 +244,15 @@ def get_num_jump_table_entries(builder): DEBUG(" Ignoring entry {:x} is referenced by code (1).".format(entry_data)) break + # Widen the bounds if the fudge factor came into play. + min_ea = min(min_ea, entry_data) + max_ea = max(max_ea, entry_data) + if stop_at < i < max_i: + stop_at = max_i + entry_addr = next_entry_addr + i = min(i, stop_at) if i != curr_num_targets: DEBUG("Jump table at {:x} actually has {} != {} entries".format( builder.table_ea, i, curr_num_targets)) @@ -231,21 +287,16 @@ def try_get_simple_jump_table_reader(builder): target_ea = builder.read_entry(builder.table_ea) - if min_ea > target_ea or max_ea <= target_ea: - continue - - if not is_block_or_instruction_head(target_ea): - continue - # Read the second entry from the table as a way of verifying our # guesses on things like the offset multiplier and entry multiplier. next_entry_addr = builder.table_ea + \ (builder.entry_size * builder.entry_mult) - target_ea = builder.read_entry(next_entry_addr) - if min_ea <= target_ea < max_ea and \ - is_block_or_instruction_head(target_ea): - return True + if _check_entry_target_ea(target_ea, min_ea, max_ea): + target_ea = builder.read_entry(next_entry_addr) + # Additional check is added to avoid target_ea becoming valid if the data at next_entry_addr is 0 + if (target_ea != builder.offset) and _check_entry_target_ea(target_ea, min_ea, max_ea): + return True return False @@ -333,35 +384,62 @@ def get_manual_jump_table_reader(builder): even if it's not explicitly referenced in the current instruction. This handles the case where we see something like a `mov` or an `lea` of the table base address that happens before the actual `jmp`.""" + if not is_invalid_ea(builder.table_ea): + if try_get_simple_jump_table_reader(builder): + return True + + inst_ea = builder.jump_ea + block_eas = list() + block_eas.append(inst_ea) + for i in xrange(8): + prev_head_ea = idc.prev_head(inst_ea) + + for xref_ea in crefs_to(inst_ea): + if prev_head_ea != xref_ea: + inst, _ = decode_instruction(xref_ea) + if has_delayed_slot(inst): + block_eas.append(inst.ea + inst.size) + else: + block_eas.append(xref_ea) + + inst_ea = prev_head_ea + ret = False next_inst_ea = builder.jump_ea found_ref_eas = set() - for i in xrange(5): - inst_ea = next_inst_ea - next_inst_ea = idc.prev_head(inst_ea) - if inst_ea == idc.BADADDR: - break - elif builder.jump_ea != inst_ea and is_control_flow(inst_ea): - break + for block_ea in block_eas: + next_inst_ea = block_ea + for i in xrange(10): + inst_ea = next_inst_ea + next_inst_ea = idc.prev_head(inst_ea) + if inst_ea == idc.BADADDR: + break - refs = get_instruction_references(inst_ea, builder.binary_is_pie) - if not len(refs): - continue + elif is_noreturn_external_function(inst_ea): + break - found_ref_eas.add((inst_ea, refs[0].ea)) + elif builder.jump_ea != inst_ea and is_control_flow(inst_ea): + continue - builder.table_ea = refs[0].ea - builder.offset = 0 + refs = get_instruction_references(inst_ea, builder.binary_is_pie) + if not len(refs): + continue - # Don't treat things like thunks to be tables. - if is_thunk(builder.table_ea) or is_external_segment(builder.table_ea): - builder.table_ea = idc.BADADDR - continue + found_ref_eas.add((inst_ea, refs[0].ea)) - if try_get_simple_jump_table_reader(builder): - ret = True - break + builder.table_ea = refs[0].ea + builder.offset = 0 + builder.offset_mult = 1 + + # Don't treat things like thunks to be tables. + if is_thunk(builder.table_ea) or is_external_segment(builder.table_ea): + builder.table_ea = idc.BADADDR + continue + + if try_get_simple_jump_table_reader(builder): + ret = True + break if ret: DEBUG("Reader inferred jump table base: {:x}".format(builder.table_ea)) @@ -442,12 +520,52 @@ def get_manual_jump_table_reader(builder): # based jump tables works. return False +def get_dref_jump_table_reader(builder): + """Try to get a jump table by looking at any of the blocks that might be + referenced by data.""" + func = idaapi.get_func(builder.jump_ea) + if not func: + return False + + min_entry_ea = idc.BADADDR + max_entry_ea = 0 + + import flow + + best_entry_ea = 0 + best_num_entries = 0 + + for block_ea in flow.find_default_block_heads(func.start_ea): + for entry_ea in drefs_to(block_ea): + builder.table_ea = entry_ea + builder.offset = 0 + builder.offset_mult = 1 + del builder.candidate_target_eas[:] + if try_get_simple_jump_table_reader(builder): + if len(builder.candidate_target_eas) > best_num_entries: + best_entry_ea = entry_ea + + if best_num_entries: + builder.table_ea = entry_ea + builder.offset = 0 + builder.offset_mult = 1 + del builder.candidate_target_eas[:] + return try_get_simple_jump_table_reader(builder) + + return False + + def get_jump_table_reader(builder): """Returns the size of a jump table entry, as well as a reader function that can extract entries.""" si = ida_nalt.get_switch_info(builder.jump_ea) if si: - return get_ida_jump_table_reader(builder, si) + if get_ida_jump_table_reader(builder, si): + return True + else: + builder.offset = 0 + builder.offset_mult = 1 + del builder.candidate_target_eas[:] # IDA can be a bit ignorant at recognizing jump tables. This came up # in sqlite3 where IDA decided that `jmp ds:off_48A5F0[rax*8]` wasn't @@ -456,18 +574,58 @@ def get_jump_table_reader(builder): # opposed to being an `o_disp`. `get_instruction_references` correctly # resolves this difference, so we'll also try to use it to pick up # where IDA leaves off. - else: - return get_manual_jump_table_reader(builder) + if get_manual_jump_table_reader(builder): + return True + + return False + #return get_dref_jump_table_reader(builder) _JMP_THROUGH_TABLE_INFO = {} _TABLE_INFO = {} _NOT_A_JMP_THROUGH_TABLE = set() +def _handle_new_builder(builder): + """Try to finalize a new jump table builder and get the final jump + table.""" + global _NOT_A_JMP_THROUGH_TABLE, _IS_TARGETED_BY_JUMP_TABLE + + get_default_jump_table_entries(builder) + + # Try to fix-up the number of entries. + num_entries = get_num_jump_table_entries(builder) + + # Treat zero- or one-entry 'tables' as not actually being tables. + if num_entries <= 1: + DEBUG("Ignoring jump table {:x} with 1 >= {} entries referenced by {:x}".format( + builder.table_ea, num_entries, builder.jump_ea)) + _NOT_A_JMP_THROUGH_TABLE.add(builder.jump_ea) + return None + + DEBUG("Jump table {:x} entries:".format(builder.table_ea)) + + # We've got a more accurate number of table entries, so go and actually + # read them to fill in our `JumpTable` data structure. + entries = {} + raw_entries = {} + entry_addr = builder.table_ea + for i in xrange(num_entries): + entry_data = builder.read_entry(entry_addr) + entries[entry_addr] = entry_data + _IS_TARGETED_BY_JUMP_TABLE.add(entry_data) + DEBUG(" {:x} => {:x}".format(entry_addr, entry_data)) + entry_addr += builder.entry_size * builder.entry_mult + + table = JumpTable(builder, entries) + _JMP_THROUGH_TABLE_INFO[builder.jump_ea] = table + _TABLE_INFO[builder.table_ea] = table + + return table + def get_jump_table(inst, binary_is_pie=False): """Returns an instance of JumpTable, or None depending on whether or not a jump table was discovered.""" global _JMP_THROUGH_TABLE_INFO, _NOT_A_JMP_THROUGH_TABLE, _TABLE_INFO - global _INVALID_JMP_TABLE + global _INVALID_JMP_TABLE, _IS_TARGETED_BY_JUMP_TABLE if not inst or not is_indirect_jump(inst): return None # Don't cache. @@ -497,42 +655,18 @@ def get_jump_table(inst, binary_is_pie=False): _JMP_THROUGH_TABLE_INFO[builder.jump_ea] = table return table - get_default_jump_table_entries(builder) - - # Try to fix-up the number of entries. - num_entries = get_num_jump_table_entries(builder) - - # Treat zero- or one-entry 'tables' as not actually being tables. - if num_entries <= 1: - DEBUG("Ignoring jump table {:x} with 1 >= {} entries referenced by {:x}".format( - builder.table_ea, num_entries, builder.jump_ea)) - _NOT_A_JMP_THROUGH_TABLE.add(builder.jump_ea) - return None - - DEBUG("Jump table {:x} entries:".format(builder.table_ea)) - - # We've got a more accurate number of table entries, so go and actually - # read them to fill in our `JumpTable` data structure. - entries = {} - raw_entries = {} - entry_addr = builder.table_ea - for i in xrange(num_entries): - entry_data = builder.read_entry(entry_addr) - entries[entry_addr] = entry_data - DEBUG(" {:x} => {:x}".format(entry_addr, entry_data)) - entry_addr += builder.entry_size * builder.entry_mult - - table = JumpTable(builder, entries) - _JMP_THROUGH_TABLE_INFO[builder.jump_ea] = table - _TABLE_INFO[builder.table_ea] = table - - return table + return _handle_new_builder(builder) def is_jump_table_entry(ea): """Returns `True` if `ea` falls somewhere inside of the bytes of a jump table.""" - global _FIRST_JUMP_TABLE_ENTRY - return ea in _FIRST_JUMP_TABLE_ENTRY + global _IS_JUMP_TABLE_ENTRY + return ea in _IS_JUMP_TABLE_ENTRY + +def is_jump_table_target(ea): + """Returns `True` if `ea` is targeted by some jump table.""" + global _IS_TARGETED_BY_JUMP_TABLE + return ea in _IS_TARGETED_BY_JUMP_TABLE def get_jump_table_from_entry(entry_ea): """Returns a `JumpTable` """ @@ -541,3 +675,60 @@ def get_jump_table_from_entry(entry_ea): return None table_ea = _FIRST_JUMP_TABLE_ENTRY[entry_ea] return _JUMP_TABLE_ENTRY[table_ea] + +def _find_jumps_near(inst_ea): + """Try to find an indirect jump instruction near `inst_ea`.""" + min_ea, max_ea = get_function_bounds(inst_ea) + candidates = [] + DEBUG("Looking for indirect jumps in range [{:x}, {:x})".format(min_ea, max_ea)) + while min_ea < max_ea: + if is_indirect_jump(min_ea): + DEBUG(" Found indirect jump at {:x}".format(min_ea)) + candidates.append(min_ea) + min_ea = idc.next_head(min_ea+1) + return candidates + +def try_create_jump_table(inst_ea, entry_ea, entry_size, binary_is_pie=False): + """Try to create a jump table, beginning at `entry_ea`, and referenced by + `inst_ea` (which may or may not be a jump instruction).""" + DEBUG_PUSH() + + if entry_ea in _TABLE_INFO: + table = _TABLE_INFO[entry_ea] + DEBUG("Instruction at {:x} references jump table {:x} because of entry at {:x}".format( + inst_ea, table.table_ea, entry_ea)) + DEBUG_POP() + return + + if not is_indirect_jump(inst_ea): + jump_eas = _find_jumps_near(inst_ea) + else: + jump_eas = [inst_ea] + + for jump_ea in jump_eas: + if jump_ea in _JMP_THROUGH_TABLE_INFO: + continue # Already have a jump table for this. + + # elif entry_ea in _TABLE_INFO: + # table = _TABLE_INFO[entry_ea] + # DEBUG("Jump table candidate at {:x} referenced by instruction {:x} because of entry {:x}".format( + # table.table_ea, jump_ea, entry_ea)) + # _JMP_THROUGH_TABLE_INFO[jump_ea] = table + # continue + + inst, _ = decode_instruction(jump_ea) + builder = JumpTableBuilder(inst, binary_is_pie) + builder.table_ea = entry_ea + builder.entry_size = entry_size + + if not try_get_simple_jump_table_reader(builder): + continue + + DEBUG("Jump table candidate at {:x} referenced by instruction {:x}".format( + builder.table_ea, builder.jump_ea)) + + _handle_new_builder(builder) + break + + DEBUG_POP() + diff --git a/tools/mcsema_disass/ida7/util.py b/tools/mcsema_disass/ida7/util.py index 4c084bf00..6fc38e114 100644 --- a/tools/mcsema_disass/ida7/util.py +++ b/tools/mcsema_disass/ida7/util.py @@ -1,16 +1,17 @@ -# Copyright (c) 2017 Trail of Bits, Inc. +# Copyright (c) 2020 Trail of Bits, Inc. # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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 Affero General Public License for more details. # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . import collections import idaapi @@ -131,8 +132,8 @@ def is_tls(ea): # `TLS-reference`. This comes up if you have an thread-local extern variable # declared/used in a binary, and defined in a shared lib. There will be an # offset variable. - for source_ea in _drefs_to(ea): - comment = idc.GetCommentEx(source_ea, 0) + for source_ea in drefs_to(ea): + comment = ida_bytes.get_cmt(source_ea, 0) if isinstance(comment, str) and "TLS-reference" in comment: return True @@ -141,7 +142,7 @@ def is_tls(ea): # Mark an address as containing code. def try_mark_as_code(ea): if is_code(ea) and not is_code_by_flags(ea): - idc.MakeCode(ea) + idc.create_insn(ea) idaapi.auto_wait() return True return False @@ -165,19 +166,25 @@ def read_byte(ea): byte = ord(byte) return byte +IS_BIG_ENDIAN = False + +_UNPACK_FORMAT_WORD = IS_BIG_ENDIAN and ">H" or "L" or "Q" or ". + import os import sys import argparse @@ -339,7 +354,7 @@ def _process_subprogram_tag(die, section_offset, M, global_var_data): DWARF_OPERATIONS = { #'DW_TAG_compile_unit': _process_compile_unit_tag, 'DW_TAG_variable' : _process_variable_tag, - 'DW_TAG_subprogram' : _process_subprogram_tag, + #'DW_TAG_subprogram' : _process_subprogram_tag, } class CUnit(object): @@ -497,4 +512,4 @@ if __name__ == '__main__': BINARY_FILE = args.binary process_dwarf_info(args.binary, args.out) - \ No newline at end of file + diff --git a/tools/mcsema_disass/ida7/x86_util.py b/tools/mcsema_disass/ida7/x86_util.py index 82c2be6ab..d0c8fe703 100644 --- a/tools/mcsema_disass/ida7/x86_util.py +++ b/tools/mcsema_disass/ida7/x86_util.py @@ -1,16 +1,17 @@ -# Copyright (c) 2017 Trail of Bits, Inc. +# Copyright (c) 2020 Trail of Bits, Inc. # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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 Affero General Public License for more details. # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . import collections import idaapi @@ -121,3 +122,127 @@ PERSONALITIES.update({ def fixup_personality(inst, p): return p + +def has_delayed_slot(inst): + return False + +def fixup_delayed_instr_size(inst): + return inst.size + +def fixup_instr_as_nop(inst): + return False + +def fixup_function_return_address(inst, next_ea): + return next_ea + +_INVALID_THUNK_ADDR = (False, idc.BADADDR) + +def is_ELF_thunk_by_structure(ea): + """Try to manually identify an ELF thunk by its structure.""" + from util import * + global _INVALID_THUNK_ADDR + + seg_name = idc.get_segm_name(ea).lower() + if ".plt" not in seg_name: + return _INVALID_THUNK_ADDR + + inst, _ = decode_instruction(ea) + if not inst or not (is_indirect_jump(inst) or is_direct_jump(inst)): + return _INVALID_THUNK_ADDR + + target_ea = get_reference_target(inst.ea) + if is_invalid_ea(target_ea): + return _INVALID_THUNK_ADDR + + seg_name = idc.get_segm_name(target_ea).lower() + if ".got" in seg_name or ".plt" in seg_name: + target_ea = get_reference_target(target_ea) + seg_name = idc.get_segm_name(target_ea).lower() + + if "extern" == seg_name: + return True, target_ea + + return _INVALID_THUNK_ADDR + +def try_get_ref_addr(inst, op, op_val, all_refs, _NOT_A_REF): + return op_val, 0, 0 + +def recover_preserved_regs(M, F, inst, xrefs, preserved_reg_sets): + return False + +def recover_deferred_preserved_regs(M): + return + +if idaapi.get_inf_structure().is_64bit(): + def return_values(): + return { + "register": "RAX", + "type": "L" + } + + def return_address(): + return { + "memory": { + "register": "RSP", + "offset": 0 + }, + "type": "L" + } + + def return_stack_pointer(): + return { + "register": "RSP", + "offset": 8, + "type": "L" + } + +elif idaapi.get_inf_structure().is_32bit(): + def return_values(): + return { + "register": "EAX", + "type": "I" + } + + def return_address(): + return { + "memory": { + "register": "ESP", + "offset": 0 + }, + "type": "I" + } + + def return_stack_pointer(): + return { + "register": "ESP", + "offset": 4, + "type": "I" + } + +def recover_value_spec(V, spec): + """Recovers the default value specification.""" + V.type = spec["type"] + + if "name" in spec and len(spec["name"]): + V.name = spec["name"] + + if "register" in spec: + V.register = spec["register"] + elif "memory" in spec: + mem_spec = spec["memory"] + V.memory.register = mem_spec["register"] + if mem_spec["offset"]: + V.memory.offset = mem_spec["offset"] + +def recover_function_spec_from_arch(E): + """ recover the basic information about the function spec""" + D = E.decl + if E.argument_count >= 8: + D.is_noreturn = E.no_return + D.is_variadic = (E.argument_count >= 8) + D.calling_convention = 0 + if D.is_noreturn == False: + V = D.return_values.add() + recover_value_spec(V, return_values()) + recover_value_spec(D.return_address, return_address()) + recover_value_spec(D.return_stack_pointer, return_stack_pointer()) diff --git a/tools/mcsema_lift/Lift.cpp b/tools/mcsema_lift/Lift.cpp index 7deed589f..fc92d2bbf 100644 --- a/tools/mcsema_lift/Lift.cpp +++ b/tools/mcsema_lift/Lift.cpp @@ -1,19 +1,22 @@ /* - * Copyright (c) 2017 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ +#include "mcsema/BC/Lift.h" + #include #include @@ -27,6 +30,7 @@ #include #include #include +#include #include #include @@ -34,7 +38,6 @@ #include #include "mcsema/Arch/Arch.h" -#include "mcsema/BC/Lift.h" #include "mcsema/BC/Util.h" #ifndef LLVM_VERSION_STRING @@ -56,6 +59,10 @@ DEFINE_string(cfg, "", "Path to the CFG file containing code to lift."); DEFINE_string(output, "", "Output bitcode file name."); +DEFINE_string(log, "", "Output log filename for lifter."); + +DEFINE_int32(loglevel, 2, "Minimum log level for GLOG" ); + // Using ',' as it will work well enough on Windows and Linux // Other suggestions were ':', which is a path character on Windows // and ';', which is an end of statement escape on Linux shells @@ -65,11 +72,10 @@ DEFINE_string(abi_libraries, "", "Path to one or more bitcode files that contain DECLARE_bool(version); -DECLARE_bool(disable_optimizer); DECLARE_bool(keep_memops); DECLARE_bool(explicit_args); DECLARE_string(pc_annotation); -DECLARE_uint64(explicit_args_count); +DECLARE_uint32(explicit_args_count); DEFINE_bool(list_supported, false, "List instructions that can be lifted."); @@ -123,7 +129,7 @@ struct ABILibsLoader { llvm::Module &module; llvm::LLVMContext &ctx; - Options opts; + const Options &opts; static constexpr const char * g_var_kind = "mcsema.abi.libraries"; @@ -151,13 +157,6 @@ struct ABILibsLoader { return true; } - // We simply cannot handle va_args properly yet. (Issue #599) - if (func.isVarArg() && !opts.explicit_args) { - LOG(WARNING) << "Skipped " << func.getName().str() - << ": va_args. (See Issue #599)"; - return true; - } - // There are some problems related to native <-> lifted synchronization // without explicit args and function ptrs (entrypoint behaviour) if (!FLAGS_explicit_args) { @@ -176,8 +175,8 @@ struct ABILibsLoader { } void Load(const std::string &path) { - LOG(INFO) << "Loading ABI Library: " << path; - LoadLibraryIntoModule(path); + LOG(INFO) << "Loading ABI Library: " << path; + LoadLibraryIntoModule(path); } void Load(const std::vector &files) { @@ -186,10 +185,9 @@ struct ABILibsLoader { } } - // Note(lukas): Not sure, which util file this belongs to + // NOTE(lukas): Not sure, which util file this belongs to bool HasFunctionPtrArg(const llvm::Function &func) { for (auto &arg : func.args()) { - auto ptr = llvm::dyn_cast(arg.getType()); if(!ptr || !ptr->getElementType()->isFunctionTy()) { return true; @@ -200,7 +198,8 @@ struct ABILibsLoader { // Copy function into module with `name` as it's name (useful if there are aliases) - void Copy(llvm::Function &func, llvm::FunctionType *fn_t, const std::string &name) { + void Copy(llvm::Function &func, llvm::FunctionType *fn_t, + const std::string &name) { auto dest_func = llvm::Function::Create(fn_t, func.getLinkage(), name, &module); @@ -211,9 +210,10 @@ struct ABILibsLoader { remill::Annotate(dest_func); } - bool ShouldCopy(llvm::Function &func, const std::string &name) { - return !mcsema::gModule->getFunction(name) && !IsBlacklisted(func) && name != "main"; + return !mcsema::gModule->getFunction(name) && + !IsBlacklisted(func) && + (name != "main" && name != "_main" && name != "DllMain"); } // If function is variadic, mcsema uses generic prototype in form @@ -231,7 +231,6 @@ struct ABILibsLoader { args.push_back( llvm::Type::getInt64Ty( ctx ) ); return llvm::FunctionType::get(ret_type, args, false); - } void CloneFunction(llvm::Function &func, const std::string &name="") { @@ -250,7 +249,8 @@ struct ABILibsLoader { std::unique_ptr LoadABILib(const std::string &path, const C &search_paths) { - std::unique_ptr abi_lib(remill::LoadModuleFromFile(&ctx, path, true)); + std::unique_ptr abi_lib( + remill::LoadModuleFromFile(&ctx, path, true)); if (abi_lib) { return abi_lib; } @@ -297,7 +297,8 @@ struct ABILibsLoader { // Declare the global variables from the library in McSema's target module. for (auto &var : abi_lib->globals()) { auto var_name = var.getName(); - if (var_name.startswith("__mcsema") || var_name.startswith("__remill")) { + if (var_name.startswith("__mcsema") || + var_name.startswith("__remill")) { continue; } @@ -309,7 +310,6 @@ struct ABILibsLoader { continue; } - auto dest_var = new llvm::GlobalVariable( module, var.getType()->getElementType(), var.isConstant(), var.getLinkage(), nullptr, @@ -321,40 +321,299 @@ struct ABILibsLoader { dest_var->setMetadata(g_var_kind, node); } } - - void RemoveUnused() { - UnloadLibraryFromModule(module); - } - - // Remove unused functions and globals brought in from the library. - void UnloadLibraryFromModule(llvm::Module &module) { - - auto copied_funcs = remill::GetFunctionsByOrigin< - std::vector,remill::AbiLibraries>(module); - for (auto func : copied_funcs) { - if (!func->hasNUsesOrMore(1)) - func->eraseFromParent(); - } - - for (auto &var : module.globals()) { - auto md = var.getMetadata(g_var_kind); - if (!md) { - continue; - } - - if (var.hasName() && var.getName().startswith("llvm.global")) { - continue; - } - - if (!var.hasNUsesOrMore(1)) { - var.eraseFromParent(); - } - } - } - - }; +static void FiniBaselineDecls(void) { + if (auto gmon_start = mcsema::gModule->getFunction("__gmon_start__"); + gmon_start && gmon_start->isDeclaration()) { + gmon_start->setLinkage(llvm::GlobalValue::WeakAnyLinkage); + llvm::ReturnInst::Create( + *mcsema::gContext, + llvm::BasicBlock::Create(*mcsema::gContext, "", gmon_start)); + } + + for (auto &func : *mcsema::gModule) { + if (func.isDeclaration() && func.hasLocalLinkage()) { + func.setLinkage(llvm::GlobalValue::ExternalWeakLinkage); + } + } +} + +static void InitBaselineDecls(void) { + auto &context = *mcsema::gContext; + auto module = mcsema::gModule.get(); + + auto i8_type = llvm::Type::getInt8Ty(context); + auto i32_type = llvm::Type::getInt32Ty(context); + auto void_type = llvm::Type::getVoidTy(context); + auto argv_type = llvm::PointerType::get(llvm::PointerType::get(i8_type, 0), 0); + llvm::Type *param_types_3[3]; + param_types_3[0] = i32_type; + param_types_3[1] = argv_type; + param_types_3[2] = argv_type; // envp. + + const auto main_func_type = llvm::FunctionType::get( + i32_type, param_types_3, false); + + auto main_func = llvm::Function::Create( + main_func_type, + llvm::GlobalValue::ExternalLinkage, + "main", + module); + + llvm::Function::Create( + main_func_type, + llvm::GlobalValue::InternalLinkage, + "__libc_init", + module); + + llvm::Function::Create( + main_func_type, + llvm::GlobalValue::InternalLinkage, + "__libc_first", + module); + + llvm::Function::Create( + llvm::FunctionType::get(void_type, false), + llvm::GlobalValue::InternalLinkage, + "_start", + module); + + llvm::Function::Create( + llvm::FunctionType::get(void_type, false), + llvm::GlobalValue::InternalLinkage, + "__libc_csu_init", + module); + + llvm::Function::Create( + llvm::FunctionType::get(void_type, false), + llvm::GlobalValue::InternalLinkage, + "__libc_csu_fini", + module); + + llvm::Function::Create( + llvm::FunctionType::get(void_type, false), + llvm::GlobalValue::InternalLinkage, + "init", + module); + + llvm::Function::Create( + llvm::FunctionType::get(void_type, false), + llvm::GlobalValue::InternalLinkage, + "fini", + module); + + llvm::Function::Create( + llvm::FunctionType::get(void_type, false), + llvm::GlobalValue::InternalLinkage, + "frame_dummy", + module); + + llvm::Function::Create( + llvm::FunctionType::get(void_type, false), + llvm::GlobalValue::InternalLinkage, + "call_frame_dummy", + module); + + llvm::Function::Create( + llvm::FunctionType::get(void_type, false), + llvm::GlobalValue::InternalLinkage, + "__do_global_dtors", + module); + + llvm::Function::Create( + llvm::FunctionType::get(void_type, false), + llvm::GlobalValue::InternalLinkage, + "__do_global_dtors_aux", + module); + + llvm::Function::Create( + llvm::FunctionType::get(void_type, false), + llvm::GlobalValue::InternalLinkage, + "call___do_global_dtors_aux", + module); + + llvm::Function::Create( + llvm::FunctionType::get(void_type, false), + llvm::GlobalValue::InternalLinkage, + "__do_global_ctors", + module); + + llvm::Function::Create( + llvm::FunctionType::get(void_type, false), + llvm::GlobalValue::InternalLinkage, + "__do_global_ctors_1", + module); + + llvm::Function::Create( + llvm::FunctionType::get(void_type, false), + llvm::GlobalValue::InternalLinkage, + "__do_global_ctors_aux", + module); + + llvm::Function::Create( + llvm::FunctionType::get(void_type, false), + llvm::GlobalValue::InternalLinkage, + "call___do_global_ctors_aux", + module); + + llvm::Function::Create( + llvm::FunctionType::get(void_type, false), + llvm::GlobalValue::ExternalWeakLinkage, + "__gmon_start__", + module); + + auto init_func = llvm::Function::Create( + llvm::FunctionType::get(void_type, false), + llvm::GlobalValue::InternalLinkage, + "_init_proc", + module); + + llvm::Function::Create( + llvm::FunctionType::get(void_type, false), + llvm::GlobalValue::InternalLinkage, + ".init_proc", + module); + + auto term_func = llvm::Function::Create( + llvm::FunctionType::get(void_type, false), + llvm::GlobalValue::InternalLinkage, + "_term_proc", + module); + + llvm::Function::Create( + llvm::FunctionType::get(void_type, false), + llvm::GlobalValue::InternalLinkage, + ".term_proc", + module); + + llvm::Type *param_types_7[7]; + param_types_7[0] = main_func->getType(); + param_types_7[1] = i32_type; + param_types_7[2] = argv_type; + param_types_7[3] = init_func->getType(); + param_types_7[4] = term_func->getType(); + param_types_7[5] = term_func->getType(); + param_types_7[6] = llvm::PointerType::get(i32_type, 0); // Stack end. + + llvm::Function::Create( + llvm::FunctionType::get(void_type, param_types_7, false), + llvm::GlobalValue::ExternalLinkage, + "__uClibc_main", + module); + + llvm::Type *param_types_8[8]; + param_types_8[0] = main_func->getType(); + param_types_8[1] = i32_type; + param_types_8[2] = argv_type; + param_types_8[3] = llvm::PointerType::get(i8_type, 0); // ELF auxv. + param_types_8[4] = main_func->getType(); + param_types_8[5] = term_func->getType(); + param_types_8[6] = term_func->getType(); + param_types_8[7] = llvm::PointerType::get(i32_type, 0); // Stack end. + + llvm::Function::Create( + llvm::FunctionType::get(void_type, param_types_8, false), + llvm::GlobalValue::ExternalLinkage, + "__libc_start_main", + module); + + auto abort_func = llvm::Function::Create( + llvm::FunctionType::get(void_type, false), + llvm::GlobalValue::ExternalLinkage, + "abort", + module); + abort_func->addFnAttr(llvm::Attribute::NoReturn); + + llvm::Type *param_types_1[1]; + param_types_1[0] = i32_type; + auto exit_func = llvm::Function::Create( + llvm::FunctionType::get(void_type, param_types_1, false), + llvm::GlobalValue::ExternalLinkage, + "exit", + module); + exit_func->addFnAttr(llvm::Attribute::NoReturn); + + exit_func = llvm::Function::Create( + llvm::FunctionType::get(void_type, param_types_1, false), + llvm::GlobalValue::ExternalLinkage, + "_Exit", + module); + exit_func->addFnAttr(llvm::Attribute::NoReturn); + + param_types_1[0] = llvm::PointerType::get(i8_type, 0); + llvm::Function::Create( + llvm::FunctionType::get(void_type, param_types_1, false), + llvm::GlobalValue::ExternalWeakLinkage, + "_Jv_RegisterClasses", + module); + + llvm::Function::Create( + llvm::FunctionType::get(void_type, param_types_1, false), + llvm::GlobalValue::ExternalWeakLinkage, + "__deregister_frame_info_bases", + module); + + llvm::Function::Create( + llvm::FunctionType::get(void_type, param_types_1, false), + llvm::GlobalValue::ExternalWeakLinkage, + "__deregister_frame_info", + module); + + param_types_1[0] = llvm::PointerType::get(i8_type, 0); + llvm::Function::Create( + llvm::FunctionType::get(i32_type, param_types_1, true), + llvm::GlobalValue::ExternalLinkage, + "printf", + module); + + llvm::Type *param_types_2[2]; + param_types_2[0] = llvm::PointerType::get(i8_type, 0); + param_types_2[1] = i32_type; + + auto longjmp_func = llvm::Function::Create( + llvm::FunctionType::get(void_type, param_types_2, false), + llvm::GlobalValue::ExternalLinkage, + "longjmp", + module); + longjmp_func->addFnAttr(llvm::Attribute::NoReturn); + + longjmp_func = llvm::Function::Create( + llvm::FunctionType::get(void_type, param_types_2, false), + llvm::GlobalValue::ExternalLinkage, + "siglongjmp", + module); + longjmp_func->addFnAttr(llvm::Attribute::NoReturn); + + param_types_2[1] = param_types_2[0]; + llvm::Function::Create( + llvm::FunctionType::get(void_type, param_types_1, false), + llvm::GlobalValue::ExternalWeakLinkage, + "__register_frame_info", + module); + + llvm::Type *param_types_4[4]; + param_types_4[0] = llvm::PointerType::get(i8_type, 0); + param_types_4[1] = param_types_4[0]; + param_types_4[2] = param_types_4[0]; + param_types_4[3] = param_types_4[0]; + llvm::Function::Create( + llvm::FunctionType::get(void_type, param_types_1, false), + llvm::GlobalValue::ExternalWeakLinkage, + "__register_frame_info_bases", + module); + + param_types_4[1] = param_types_4[0]; + param_types_4[2] = i32_type; + param_types_4[3] = param_types_4[0]; + auto assert_func = llvm::Function::Create( + llvm::FunctionType::get(void_type, param_types_4, false), + llvm::GlobalValue::ExternalLinkage, + "__assert_fail", + module); + assert_func->addFnAttr(llvm::Attribute::NoReturn); +} + } // namespace int main(int argc, char *argv[]) { @@ -377,11 +636,11 @@ int main(int argc, char *argv[]) { // This option injects a function call before every lifted instruction. // This function is implemented in the McSema runtime and it prints the // values of the general purpose registers to `stderr`. - << " [--add_reg_tracer] \\" << std::endl + << " [--add_state_tracer] \\" << std::endl + << " [--add_func_state_tracer] \\" << std::endl + << " [--add_pc_tracer] \\" << std::endl - // This option tells McSema not to optimize the bitcode. This is useful - // for debugging, especially in conjunction with `--add_breakpoints`. - << " [--disable_optimizer] \\" << std::endl + << " [--trace_reg_values=reg1[,reg2[,...]]] \\" << std::endl // This option tells McSema not to lower Remill's memory access intrinsic // functions into LLVM `load` and `store` instructions. @@ -433,7 +692,7 @@ int main(int argc, char *argv[]) { << " [--legacy_mode] \\" << std::endl // Print a list of the instructions that can be lifted. - << " [--list-supported]" << std::endl + << " [--list_supported]" << std::endl // Assign the personality function for exception handling ABIs. It is // `__gxx_personality_v0` for libstdc++ and `__gnat_personality_v0` for ADA ABIs. @@ -441,12 +700,31 @@ int main(int argc, char *argv[]) { // Print the version and exit. << " [--version]" << std::endl + + // Log file name for the lifter. + << " [--log]" << std::endl + + << " [--loglevel]" << std::endl << std::endl; - google::InitGoogleLogging(argv[0]); + const char * const llvm_argv[] = { + "-memdep-block-scan-limit=500", + nullptr + }; + + llvm::cl::ParseCommandLineOptions(1, llvm_argv); + google::SetUsageMessage(ss.str()); google::ParseCommandLineFlags(&argc, &argv, true); + if (FLAGS_log.empty()){ + google::InitGoogleLogging(argv[0]); + } else { + google::InitGoogleLogging(FLAGS_log.c_str()); + } + + FLAGS_minloglevel = FLAGS_loglevel; + if (FLAGS_version) { PrintVersion(); return EXIT_SUCCESS; @@ -484,14 +762,17 @@ int main(int argc, char *argv[]) { LOG_IF(WARNING, !FLAGS_pc_annotation.empty()) << "Changing --pc_annotation to mcsema_real_eip in legacy mode."; FLAGS_pc_annotation = "mcsema_real_eip"; - - LOG_IF(WARNING, FLAGS_disable_optimizer) - << "Re-enabling the optimizer in legacy mode."; - FLAGS_disable_optimizer = false; } - mcsema::gModule = remill::LoadTargetSemantics(*mcsema::gContext); - mcsema::gArch->PrepareModule(mcsema::gModule.get()); + mcsema::gModule = remill::LoadArchSemantics(mcsema::gArch); + + InitBaselineDecls(); + + const auto zero_var = new llvm::GlobalVariable( + *mcsema::gModule, llvm::Type::getInt8Ty(*mcsema::gContext), + true, llvm::GlobalValue::ExternalLinkage, + nullptr, "__anvill_pc"); + mcsema::gZero = llvm::ConstantExpr::getPtrToInt(zero_var, mcsema::gWordType); // Load in a special library before CFG processing. This affects the // renaming of exported functions. @@ -508,10 +789,14 @@ int main(int argc, char *argv[]) { << "Unable to lift CFG from " << FLAGS_cfg << " into module " << FLAGS_output; - abi_loader.RemoveUnused(); + FiniBaselineDecls(); remill::StoreModuleToFile(mcsema::gModule.get(), FLAGS_output); + // Don't waste time reclaiming their memory. + mcsema::gModule.release(); + (void) new std::shared_ptr(mcsema::gContext); + google::ShutDownCommandLineFlags(); google::ShutdownGoogleLogging(); diff --git a/tools/regtrace/Trace.cpp b/tools/regtrace/Trace.cpp index fbc463714..acef04413 100644 --- a/tools/regtrace/Trace.cpp +++ b/tools/regtrace/Trace.cpp @@ -1,17 +1,18 @@ /* - * Copyright (c) 2017 Trail of Bits, Inc. + * Copyright (c) 2020 Trail of Bits, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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 Affero General Public License for more details. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ #include "pin.H" diff --git a/tools/regtrace/build.sh b/tools/regtrace/build.sh index d1386c5ed..109f716ea 100755 --- a/tools/regtrace/build.sh +++ b/tools/regtrace/build.sh @@ -1,17 +1,19 @@ #!/usr/bin/env bash -# Copyright (c) 2017 Trail of Bits, Inc. + +# Copyright (c) 2020 Trail of Bits, Inc. # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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 Affero General Public License for more details. # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" diff --git a/tools/setup.py b/tools/setup.py index bf8a459d0..8192522af 100755 --- a/tools/setup.py +++ b/tools/setup.py @@ -1,18 +1,19 @@ #!/usr/bin/env python -# Copyright (c) 2017 Trail of Bits, Inc. +# Copyright (c) 2020 Trail of Bits, Inc. # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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 Affero General Public License for more details. # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . import os os.chdir(os.path.dirname(os.path.abspath(__file__))) @@ -26,7 +27,7 @@ setup(name="mcsema-disass", author="Trail of Bits", author_email="mcsema@trailofbits.com", license='Apache 2.0', - packages=['mcsema_disass', 'mcsema_disass.ida', 'mcsema_disass.ida7', 'mcsema_disass.defs', 'mcsema_disass.binja'], + packages=['mcsema_disass', 'mcsema_disass.ida7', 'mcsema_disass.defs'], install_requires=['protobuf==3.2.0', 'python-magic'], package_data={ "mcsema_disass.defs": ["linux.txt", "windows.txt"]}, diff --git a/tools/setup_launcher.sh b/tools/setup_launcher.sh index 1cda20ac1..48b311480 100755 --- a/tools/setup_launcher.sh +++ b/tools/setup_launcher.sh @@ -1,5 +1,20 @@ #!/usr/bin/env bash +# Copyright (c) 2020 Trail of Bits, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + main() { if [ $# -ne 1 ] ; then printf "Pass the install folder to the script!\n"