diff --git a/.github/workflows/vcpkg_ci.yml b/.github/workflows/vcpkg_ci.yml new file mode 100644 index 000000000..6a157c8e1 --- /dev/null +++ b/.github/workflows/vcpkg_ci.yml @@ -0,0 +1,89 @@ +name: VCPKG Continuous Integration +on: + push: + branches: + - master + pull_request: + schedule: + # run CI every day even if no PRs/merges occur + - cron: '0 6 * * *' + +jobs: + build_linux: + strategy: + fail-fast: false + matrix: + image: + - { name: 'ubuntu', tag: '18.04' } + - { name: 'ubuntu', tag: '20.04' } + llvm: [ + '9', + '10', + '11' + ] + + runs-on: ubuntu-20.04 + container: + image: docker.pkg.github.com/trailofbits/cxx-common/vcpkg-builder-${{ matrix.image.name }}:${{ matrix.image.tag }} + credentials: + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + steps: + - uses: actions/checkout@v2 + - name: Install utility tools + shell: bash + run: | + # TODO some of these should probably live in the Docker build image + apt-get update + apt-get install -y pixz xz-utils make + + - name: Build with build script + shell: bash + run: ./scripts/build.sh --llvm-version ${{ matrix.llvm }} + - name: Run tests + shell: bash + working-directory: remill-build + run: | + cmake --build . --target install -- -j "$(nproc)" + cmake --build . --target test_dependencies -- -j "$(nproc)" + env CTEST_OUTPUT_ON_FAILURE=1 cmake --build . --target test -- -j "$(nproc)" + - name: Smoketests with installed executable + shell: bash + run: | + remill-lift-${{ matrix.llvm }} --arch amd64 --ir_out /dev/stdout --bytes c704ba01000000 + remill-lift-${{ matrix.llvm }} --arch aarch64 --ir_out /dev/stdout --address 0x400544 --bytes FD7BBFA90000009000601891FD030091B7FFFF97E0031F2AFD7BC1A8C0035FD6 + + build_mac: + strategy: + fail-fast: false + matrix: + os: [ + 'macos-10.15', + 'macos-11.0' + ] + llvm: [ + '9', + '10', + '11' + ] + + runs-on: ${{ matrix.os }} + + steps: + - uses: actions/checkout@v2 + - name: Build with build script + shell: bash + run: ./scripts/build.sh --llvm-version ${{ matrix.llvm }} + - name: Run tests + shell: bash + working-directory: remill-build + run: | + cmake --build . --target install -- -j "$(sysctl -n hw.logicalcpu)" + cmake --build . --target test_dependencies -- -j "$(sysctl -n hw.logicalcpu)" + env CTEST_OUTPUT_ON_FAILURE=1 cmake --build . --target test -- -j "$(sysctl -n hw.logicalcpu)" + - name: Smoketests with installed executable + shell: bash + run: | + remill-lift-${{ matrix.llvm }} --arch amd64 --ir_out /dev/stdout --bytes c704ba01000000 + remill-lift-${{ matrix.llvm }} --arch aarch64 --ir_out /dev/stdout --address 0x400544 --bytes FD7BBFA90000009000601891FD030091B7FFFF97E0031F2AFD7BC1A8C0035FD6 diff --git a/.gitignore b/.gitignore index 2838a539b..e331c6e90 100644 --- a/.gitignore +++ b/.gitignore @@ -27,7 +27,6 @@ cmake-build-release compile_commands.json bin/* -lib/* third_party/* build/* diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e6b4f18f..7d122adb5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,13 +12,16 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Fix behavior of CMAKE_CXX_STANDARD when targeting macOS. -if (POLICY CMP0025) - cmake_policy(SET CMP0025 NEW) -endif () +if (NOT DEFINED ENV{TRAILOFBITS_LIBRARIES}) + message(STATUS "Using new vcpkg build system") + include(CMakeLists_vcpkg.txt) + return() +endif() project(remill) -cmake_minimum_required(VERSION 3.2) +cmake_minimum_required(VERSION 3.14) + +include(GNUInstallDirs) include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/settings.cmake") include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/utils.cmake") diff --git a/CMakeLists_vcpkg.txt b/CMakeLists_vcpkg.txt new file mode 100644 index 000000000..fbf7b6194 --- /dev/null +++ b/CMakeLists_vcpkg.txt @@ -0,0 +1,335 @@ +# 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. + +include(cmake/vcpkg_helper.cmake) + +project(remill) +cmake_minimum_required(VERSION 3.14) +include(GNUInstallDirs) + +include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/settings.cmake") +include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/utils_vcpkg.cmake") +include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/ccache.cmake") +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules") +include(CTest) + +configureCcache() +FindAndSelectClangCompiler() + +enable_language(C CXX ASM) + +set(REMILL_SOURCE_DIR "${PROJECT_SOURCE_DIR}") + +set(REMILL_INSTALL_LIB_DIR "${CMAKE_INSTALL_LIBDIR}" CACHE PATH "Directory in which remill libraries will be installed") +set(REMILL_INSTALL_BIN_DIR "${CMAKE_INSTALL_BINDIR}" CACHE PATH "Directory in which remill binaries will be installed") +set(REMILL_INSTALL_INCLUDE_DIR "${CMAKE_INSTALL_INCLUDEDIR}/remill" CACHE PATH "Directory in which remill headers will be installed") +set(REMILL_INSTALL_SHARE_DIR "${CMAKE_INSTALL_DATADIR}" CACHE PATH "Directory in which remill cmake files will be installed") + +# +# libraries +# + +# LLVM +find_package(LLVM CONFIG REQUIRED) +message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") +message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") + +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) + +add_library(thirdparty_llvm INTERFACE) +target_include_directories(thirdparty_llvm SYSTEM INTERFACE + ${LLVM_INCLUDE_DIRS} +) +target_compile_definitions(thirdparty_llvm INTERFACE + ${LLVM_DEFINITIONS} +) +include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/BCCompiler.cmake") + +# Go find only the static libraries of LLVM, and link against those. +foreach(LLVM_LIB IN LISTS LLVM_AVAILABLE_LIBS) + get_target_property(LLVM_LIB_TYPE ${LLVM_LIB} TYPE) + if(LLVM_LIB_TYPE STREQUAL "STATIC_LIBRARY") + list(APPEND LLVM_LIBRARIES "${LLVM_LIB}") + endif() +endforeach() + +# These are out-of-order in `LLVM_AVAILABLE_LIBS` and should always be last. +list(REMOVE_ITEM LLVM_LIBRARIES LLVMMC LLVMCore LLVMSupport) +list(APPEND LLVM_LIBRARIES LLVMMC LLVMCore LLVMSupport) + +target_link_libraries(thirdparty_llvm INTERFACE + ${LLVM_LIBRARIES} +) + +# Microsoft Z3 with LLVM. Not exactly used in remill, but LLVM doesn't link +# against it correctly +# NOTE: If changing this, also replicate in remillConfig file +if (LLVM_WITH_Z3) + find_package(Z3 CONFIG REQUIRED 4.7.1) + get_target_property(LLVMSupport_LIBS LLVMSupport INTERFACE_LINK_LIBRARIES) + list(REMOVE_ITEM LLVMSupport_LIBS Z3) + list(APPEND LLVMSupport_LIBS z3::libz3) + set_target_properties(LLVMSupport PROPERTIES + INTERFACE_LINK_LIBRARIES "${LLVMSupport_LIBS}") +endif() + +message(STATUS "LLVM Libraries: ${LLVM_LIBRARIES}") + +# Intel XED +find_package(XED CONFIG REQUIRED) +add_library(thirdparty_xed INTERFACE) +target_link_libraries(thirdparty_xed INTERFACE + XED::XED +) + +# Google glog module +find_package(glog CONFIG REQUIRED) +add_library(thirdparty_glog INTERFACE) +target_link_libraries(thirdparty_glog INTERFACE + glog::glog +) + +# Google gflags +find_package(gflags CONFIG REQUIRED) +add_library(thirdparty_gflags INTERFACE) +target_link_libraries(thirdparty_gflags INTERFACE + gflags +) + +# Windows SDK +add_library(thirdparty_win32 INTERFACE) +if(DEFINED WIN32) + target_link_libraries(thirdparty_win32 INTERFACE + "Kernel32.lib" + ) +endif() + + +# For Linux builds, group LLVM libraries into a single group +# that avoids frustrating library ordering issues. +if(UNIX AND NOT APPLE) + set(LINKER_START_GROUP "-Wl,--start-group") + set(LINKER_END_GROUP "-Wl,--end-group") +else() + set(LINKER_START_GROUP "") + set(LINKER_END_GROUP "") +endif() + +# +# Configuration options for semantics +# +option(REMILL_BARRIER_AS_NOP "Remove compiler barriers (inline assembly) in semantics" OFF) + +# +# target settings +# + +set(REMILL_LLVM_VERSION "${LLVM_MAJOR_VERSION}") +message("Remill llvm version: ${REMILL_LLVM_VERSION}") +math(EXPR REMILL_LLVM_VERSION_NUMBER "${LLVM_MAJOR_VERSION} * 100 + ${LLVM_MINOR_VERSION}") + +set(REMILL_INSTALL_SEMANTICS_DIR "${CMAKE_INSTALL_PREFIX}/${REMILL_INSTALL_SHARE_DIR}/remill/${REMILL_LLVM_VERSION}/semantics" CACHE PATH "Directory into which semantics are installed") + +set(REMILL_BUILD_SEMANTICS_DIR_X86 "${CMAKE_CURRENT_BINARY_DIR}/lib/Arch/X86/Runtime") +set(REMILL_BUILD_SEMANTICS_DIR_AARCH64 "${CMAKE_CURRENT_BINARY_DIR}/lib/Arch/AArch64/Runtime") +set(REMILL_BUILD_SEMANTICS_DIR_SPARC32 "${CMAKE_CURRENT_BINARY_DIR}/lib/Arch/SPARC32/Runtime") +set(REMILL_BUILD_SEMANTICS_DIR_SPARC64 "${CMAKE_CURRENT_BINARY_DIR}/lib/Arch/SPARC64/Runtime") + +# add everything as public. +set(REMILL_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include") +set(REMILL_LIB_DIR "${CMAKE_CURRENT_SOURCE_DIR}/lib") + +add_library(remill_settings INTERFACE) + +target_include_directories(remill_settings INTERFACE + $ + $) + +if(WIN32) + # warnings and compiler settings + target_compile_options(remill_settings INTERFACE + /MD /nologo /W3 /EHsc /wd4141 /wd4146 /wd4180 /wd4244 + /wd4258 /wd4267 /wd4291 /wd4345 /wd4351 /wd4355 /wd4456 + /wd4457 /wd4458 /wd4459 /wd4503 /wd4624 /wd4722 /wd4800 + /wd4100 /wd4127 /wd4512 /wd4505 /wd4610 /wd4510 /wd4702 + /wd4245 /wd4706 /wd4310 /wd4701 /wd4703 /wd4389 /wd4611 + /wd4805 /wd4204 /wd4577 /wd4091 /wd4592 /wd4324 + ) + + target_compile_definitions(remill_settings INTERFACE + _CRT_SECURE_NO_DEPRECATE + _CRT_SECURE_NO_WARNINGS + _CRT_NONSTDC_NO_DEPRECATE + _CRT_NONSTDC_NO_WARNINGS + _SCL_SECURE_NO_DEPRECATE + _SCL_SECURE_NO_WARNINGS + GOOGLE_PROTOBUF_NO_RTTI + ) + +else() + # warnings and compiler settings + target_compile_options(remill_settings INTERFACE + -Wall -Wextra -Wno-unused-parameter -Wno-c++98-compat + -Wno-unreachable-code-return -Wno-nested-anon-types + -Wno-extended-offsetof + -Wno-variadic-macros -Wno-return-type-c-linkage + -Wno-c99-extensions -Wno-ignored-attributes -Wno-unused-local-typedef + -Wno-unknown-pragmas -Wno-unknown-warning-option -fPIC + -fno-omit-frame-pointer -fvisibility-inlines-hidden + -fno-asynchronous-unwind-tables + ) + + # Clang-specific warnings/error options + if("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang") + target_compile_options(remill_settings INTERFACE + -Wgnu-alignof-expression -Wno-gnu-anonymous-struct -Wno-gnu-designator + -Wno-gnu-zero-variadic-macro-arguments -Wno-gnu-statement-expression + -fno-aligned-allocation + ) + endif() + + # debug symbols + if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") + target_compile_options(remill_settings INTERFACE + -gdwarf-2 -g3 + ) + endif() + + # optimization flags and definitions + if(CMAKE_BUILD_TYPE STREQUAL "Debug") + target_compile_options(remill_settings INTERFACE + -O0 + ) + target_compile_definitions(remill_settings INTERFACE + "DEBUG" + ) + else() + target_compile_options(remill_settings INTERFACE + -O2 + ) + target_compile_definitions(remill_settings INTERFACE + "NDEBUG" + ) + endif() +endif() + +target_compile_definitions(remill_settings INTERFACE + "REMILL_INSTALL_SEMANTICS_DIR=\"${REMILL_INSTALL_SEMANTICS_DIR}\"" + "REMILL_BUILD_SEMANTICS_DIR_X86=\"${REMILL_BUILD_SEMANTICS_DIR_X86}\"" + "REMILL_BUILD_SEMANTICS_DIR_AARCH64=\"${REMILL_BUILD_SEMANTICS_DIR_AARCH64}\"" + "REMILL_BUILD_SEMANTICS_DIR_SPARC32=\"${REMILL_BUILD_SEMANTICS_DIR_SPARC32}\"" + "REMILL_BUILD_SEMANTICS_DIR_SPARC64=\"${REMILL_BUILD_SEMANTICS_DIR_SPARC64}\"" +) + +set(THIRDPARTY_LIBRARY_LIST thirdparty_llvm thirdparty_xed thirdparty_glog thirdparty_gflags) +target_link_libraries(remill_settings INTERFACE + ${THIRDPARTY_LIBRARY_LIST} +) +install(TARGETS remill_settings ${THIRDPARTY_LIBRARY_LIST} + EXPORT remillTargets) + +add_subdirectory(lib/Arch) +add_subdirectory(lib/BC) +add_subdirectory(lib/OS) +add_subdirectory(lib/Version) + +add_library(remill INTERFACE) +target_link_libraries(remill INTERFACE + ${LINKER_START_GROUP} + ${THIRDPARTY_LIBRARY_LIST} + remill_bc + remill_os + remill_arch + remill_version + ${LINKER_END_GROUP} +) +install(TARGETS remill EXPORT remillTargets) + +# +# Also install clang, libllvm and llvm-link +# + +set(INSTALLED_CLANG_NAME "remill-clang-${REMILL_LLVM_VERSION}${CMAKE_EXECUTABLE_SUFFIX}") +set(INSTALLED_LLVMLINK_NAME "remill-llvm-link-${REMILL_LLVM_VERSION}${CMAKE_EXECUTABLE_SUFFIX}") + +InstallExternalTarget("ext_clang" "${CLANG_PATH}" "BIN" "${INSTALLED_CLANG_NAME}") + +InstallExternalTarget("ext_llvmlink" "${LLVMLINK_PATH}" "BIN" "${INSTALLED_LLVMLINK_NAME}") + +GetTargetTree(THIRDPARTY_LIBRARIES ${THIRDPARTY_LIBRARY_LIST}) +GetPublicIncludeFolders(THIRDPARTY_INCLUDE_DIRECTORIES ${THIRDPARTY_LIBRARIES}) +foreach(THIRDPARTY_LIB IN LISTS THIRDPARTY_LIBRARIES) + string(SUBSTRING "${THIRDPARTY_LIB}" 0 1 THIRDPARTY_LIB_PREFIX) + if(TARGET ${THIRDPARTY_LIB}) + get_target_property(THIRDPARTY_LIB_TYPE ${THIRDPARTY_LIB} TYPE) + if(THIRDPARTY_LIB_TYPE STREQUAL "STATIC_LIBRARY" OR THIRDPARTY_LIB_TYPE STREQUAL "SHARED_LIBRARY") + list(APPEND THIRDPARTY_LIBRARY_FILES "$${}") + endif() + elseif("${THIRDPARTY_LIB_PREFIX}" STREQUAL "$${}") + # E.g. $ + else() + list(APPEND THIRDPARTY_LIBRARY_FILES "${THIRDPARTY_LIB}") + endif() +endforeach() + +list(REMOVE_DUPLICATES THIRDPARTY_LIBRARY_FILES) + +# First do the basic substitutions. +configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/remillConfig_vcpkg.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/remillConfig.cmake" + @ONLY +) + +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/remillConfig.cmake" + "${CMAKE_CURRENT_LIST_DIR}/cmake/vcpkg_helper.cmake" + DESTINATION "${REMILL_INSTALL_LIB_DIR}/cmake/remill" +) + +install(DIRECTORY "${REMILL_INCLUDE_DIR}/remill/" + DESTINATION "${REMILL_INSTALL_INCLUDE_DIR}" +) + +# +# additional targets +# + +add_custom_target(semantics) + +# tools +add_subdirectory(bin) + +install(EXPORT remillTargets + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/remill") + +# tests +message("compiler ID ${CMAKE_C_COMPILER_ID}") +if ("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang") + find_package(Threads REQUIRED) + add_custom_target(test_dependencies) + + if(NOT "${PLATFORM_NAME}" STREQUAL "windows") + if("${CMAKE_HOST_SYSTEM_PROCESSOR}" STREQUAL "AMD64" OR "${CMAKE_HOST_SYSTEM_PROCESSOR}" STREQUAL "x86_64") + message(STATUS "X86 tests enabled") + add_subdirectory(tests/X86) + endif() + endif() + + if("${CMAKE_HOST_SYSTEM_PROCESSOR}" STREQUAL "aarch64" AND "${PLATFORM_NAME}" STREQUAL "linux") + message(STATUS "aarch64 tests enabled") + add_subdirectory(tests/AArch64) + endif() +endif() diff --git a/Dockerfile b/Dockerfile index ba018b78c..6b395e72e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -ARG LLVM_VERSION=800 +ARG LLVM_VERSION=1000 ARG ARCH=amd64 ARG UBUNTU_VERSION=18.04 ARG DISTRO_BASE=ubuntu${UBUNTU_VERSION} diff --git a/README.md b/README.md index c8724ca2a..501b380a4 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ Most of Remill's dependencies can be provided by the [cxx-common](https://github | Name | Version | | ---- | ------- | | [Git](https://git-scm.com/) | Latest | -| [CMake](https://cmake.org/) | 3.2+ | +| [CMake](https://cmake.org/) | 3.14+ | | [Google Flags](https://github.com/google/glog) | Latest | | [Google Log](https://github.com/google/glog) | Latest | | [Google Test](https://github.com/google/googletest) | Latest | @@ -51,7 +51,7 @@ Most of Remill's dependencies can be provided by the [cxx-common](https://github ### Docker Build -Remill now comes with a Dockerfile for easier testing. This Dockerfile references the [cxx-common](https://github.com/trailofbits/cxx-common) container to have all pre-requisite libraries available. +Remill now comes with a Dockerfile for easier testing. This Dockerfile references the [cxx-common](https://github.com/trailofbits/cxx-common) container to have all pre-requisite libraries available. The Dockerfile allows for quick builds of multiple supported LLVM, architecture, and Linux configurations. diff --git a/cmake/BCCompiler.cmake b/cmake/BCCompiler.cmake index 54766a35a..28e8ae827 100644 --- a/cmake/BCCompiler.cmake +++ b/cmake/BCCompiler.cmake @@ -64,7 +64,7 @@ else() # llvm-link path find_program(LLVMLINK_PATH NAMES "${LLVMLINK_EXECUTABLE_NAME}" - PATHS "/usr/bin" "/usr/local/bin" "${LLVM_INSTALL_PREFIX}/bin" "${LLVM_TOOLS_BINARY_DIR}" "C:/Program Files/LLVM/bin" "C:/Program Files (x86)/LLVM/bin" + PATHS "${LLVM_INSTALL_PREFIX}/bin" "${LLVM_TOOLS_BINARY_DIR}" "/usr/bin" "/usr/local/bin" "C:/Program Files/LLVM/bin" "C:/Program Files (x86)/LLVM/bin" ) endif() diff --git a/cmake/remillConfig_vcpkg.cmake.in b/cmake/remillConfig_vcpkg.cmake.in new file mode 100644 index 000000000..bff71bd52 --- /dev/null +++ b/cmake/remillConfig_vcpkg.cmake.in @@ -0,0 +1,63 @@ +# 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 +# +# 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. + +@PACKAGE_INIT@ + +foreach(_comp ${remill_FIND_COMPONENTS}) + if (NOT "VCPKG_DEPS" STREQUAL _comp) + set(remill_FOUND False) + set(remill_NOT_FOUND_MESSAGE "Unsupported component: ${_comp}. Only VCPKG_DEPS") + endif() + + if ("VCPKG_DEPS" STREQUAL _comp) + set(remill_setup_vcpkg True) + if(NOT "x@VCPKG_ROOT@x" STREQUAL "xx" AND NOT USE_SYSTEM_DEPENDENCIES) + if (EXISTS "@VCPKG_ROOT@") + set(VCPKG_ROOT "@VCPKG_ROOT@" + CACHE PATH "Location of dependency libraries" + ) + include(${CMAKE_CURRENT_LIST_DIR}/vcpkg_helper.cmake) + message(STATUS "Found VCPKG_ROOT: ${VCPKG_ROOT}") + set(vcpkgdeps_FOUND) + endif() + endif() + endif() +endforeach() + +if(NOT remill_setup_vcpkg AND NOT TARGET remill) + set(LLVM_MAJOR_VERSION @LLVM_MAJOR_VERSION@) + set(LLVM_MINOR_VERSION @LLVM_MINOR_VERSION@) + set(REMILL_LLVM_VERSION "@LLVM_MAJOR_VERSION@.@LLVM_MINOR_VERSION@") + + # External libs + include(CMakeFindDependencyMacro) + find_dependency(XED) + find_dependency(glog) + find_dependency(LLVM) + # NOTE: If changing this, also replicate in CMakeLists.txt + if (LLVM_WITH_Z3) + find_dependency(Z3) + get_target_property(LLVMSupport_LIBS LLVMSupport INTERFACE_LINK_LIBRARIES) + list(REMOVE_ITEM LLVMSupport_LIBS Z3) + list(APPEND LLVMSupport_LIBS z3::libz3) + set_target_properties(LLVMSupport PROPERTIES + INTERFACE_LINK_LIBRARIES "${LLVMSupport_LIBS}") + endif() + + # Exported Targets + include("${CMAKE_CURRENT_LIST_DIR}/remillTargets.cmake") + +endif() + +set(remill_setup_vcpkg False) diff --git a/cmake/utils_vcpkg.cmake b/cmake/utils_vcpkg.cmake new file mode 100644 index 000000000..3b42912fb --- /dev/null +++ b/cmake/utils_vcpkg.cmake @@ -0,0 +1,227 @@ +cmake_minimum_required(VERSION 3.2) + +function(FindAndSelectClangCompiler) + if(DEFINED ENV{LLVM_INSTALL_PREFIX}) + set(LLVM_INSTALL_PREFIX $ENV{LLVM_INSTALL_PREFIX} PARENT_SCOPE) + endif() + + if(DEFINED LLVM_INSTALL_PREFIX) + list(APPEND FINDPACKAGE_LLVM_HINTS "${LLVM_INSTALL_PREFIX}/lib/cmake/llvm/") + list(APPEND FINDPACKAGE_LLVM_HINTS "${LLVM_INSTALL_PREFIX}/share/llvm/cmake/") + set(FINDPACKAGE_LLVM_HINTS ${FINDPACKAGE_LLVM_HINTS} PARENT_SCOPE) + + message(STATUS "Using LLVM_INSTALL_PREFIX hints for find_package(LLVM): ${FINDPACKAGE_LLVM_HINTS}") + endif() + + if(DEFINED WIN32) + set(executable_extension ".exe") + else() + set(executable_extension "") + endif() + + # it is important to avoid re-defining these variables if they have been already + # set or you risk ending up in a configure loop! + if(NOT DEFINED CMAKE_C_COMPILER) + if(DEFINED LLVM_INSTALL_PREFIX) + set(CMAKE_C_COMPILER "${LLVM_INSTALL_PREFIX}/bin/clang${executable_extension}" + CACHE PATH "Path to clang binary." FORCE) + else() + set(CMAKE_C_COMPILER "clang" PARENT_SCOPE) + endif() + endif() + + if(NOT DEFINED CMAKE_CXX_COMPILER) + if(DEFINED LLVM_INSTALL_PREFIX) + set(CMAKE_CXX_COMPILER "${LLVM_INSTALL_PREFIX}/bin/clang++${executable_extension}" + CACHE PATH "Path to clang++ binary." FORCE) + else() + set(CMAKE_CXX_COMPILER "clang++${executable_extension}" PARENT_SCOPE) + endif() + endif() + + if(NOT DEFINED CMAKE_ASM_COMPILER) + if(DEFINED LLVM_INSTALL_PREFIX) + set(CMAKE_ASM_COMPILER "${LLVM_INSTALL_PREFIX}/bin/clang++${executable_extension}" + CACHE PATH "Path to assembler (aka clang) binary." FORCE) + else() + set(CMAKE_ASM_COMPILER ${CMAKE_CXX_COMPILER} PARENT_SCOPE) + endif() + endif() + + if(NOT DEFINED CMAKE_LLVM_LINK) + if(DEFINED LLVM_INSTALL_PREFIX) + set(CMAKE_LLVM_LINK "${LLVM_INSTALL_PREFIX}/bin/llvm-link${executable_extension}" + CACHE PATH "Path to llvm-link binary." FORCE) + else() + set(CMAKE_LLVM_LINK "llvm-link${executable_extension}" PARENT_SCOPE) + endif() + endif() +endfunction() + +function(GetTargetTree output_variable) + if(${ARGC} LESS 1) + message(FATAL_ERROR "Usage: GetTargetTree output_var target1 target2 ...") + endif() + + foreach(target ${ARGN}) + list(APPEND queue "${target}") + endforeach() + + while(true) + # Update the queue + unset(new_queue) + + foreach(target ${queue}) + list(APPEND visited_dependencies "${target}") + + if (NOT TARGET "${target}") + continue() + endif() + + # Always reset to empty value + set(target_link_libs "target_link_libs-NOTFOUND") + set(target_interface_link_libs "target_interface_link_libs-NOTFOUND") + + # Skip utility targets + get_target_property(target_type "${target}" TYPE) + if("${target_type}" STREQUAL "UTILITY") + continue() + endif() + + # Collect the results + unset(new_queue_candidates) + + # We can only get LINK_LIBRARIES from normal targets + if(NOT "${target_type}" STREQUAL "INTERFACE_LIBRARY") + get_target_property(target_link_libs "${target}" LINK_LIBRARIES) + if(NOT "${target_link_libs}" STREQUAL "target_link_libs-NOTFOUND") + list(APPEND new_queue_candidates ${target_link_libs}) + endif() + endif() + + # INTERFACE_LINK_LIBRARIES are potentially always present + get_target_property(target_interface_link_libs "${target}" INTERFACE_LINK_LIBRARIES) + if(NOT "${target_interface_link_libs}" STREQUAL "target_interface_link_libs-NOTFOUND") + list(APPEND new_queue_candidates ${target_interface_link_libs}) + endif() + + # Try to find the actual file + if ("${target_type}" STREQUAL "UNKNOWN_LIBRARY" OR + "${target_type}" STREQUAL "STATIC_LIBRARY" OR + "${target_type}" STREQUAL "SHARED_LIBRARY" OR + "${target_type}" STREQUAL "IMPORTED_LIBRARY") + get_target_property(target_imported_loc "${target}" IMPORTED_LOCATION) + if(NOT "${target_imported_loc}" STREQUAL "target_imported_loc-NOTFOUND") + list(APPEND new_queue_candidates "${target_imported_loc}") + endif() + endif() + + foreach(queue_candidate ${new_queue_candidates}) + list(FIND visited_dependencies "${queue_candidate}" visited) + if(visited EQUAL -1) + list(APPEND new_queue "${queue_candidate}") + endif() + endforeach() + endforeach() + + list(LENGTH new_queue new_queue_size) + if(${new_queue_size} EQUAL 0) + break() + endif() + + set(queue ${new_queue}) + endwhile() + + list(REVERSE visited_dependencies) + list(REMOVE_DUPLICATES visited_dependencies) + list(REVERSE visited_dependencies) + set("${output_variable}" ${visited_dependencies} PARENT_SCOPE) +endfunction() + +function(GetPublicIncludeFolders output_variable) + if(${ARGC} LESS 1) + message(FATAL_ERROR "Usage: GetPublicIncludeFolders output_var target1 target2 ...") + endif() + + foreach(target ${ARGN}) + if (NOT TARGET "${target}") + continue() + endif() + + get_target_property(include_dir_list "${target}" INTERFACE_INCLUDE_DIRECTORIES) + if(NOT "${include_dir_list}" STREQUAL "include_dir_list-NOTFOUND") + list(APPEND collected_include_dirs "${include_dir_list}") + endif() + endforeach() + + list(REMOVE_DUPLICATES collected_include_dirs) + set("${output_variable}" ${collected_include_dirs} PARENT_SCOPE) +endfunction() + +function(InstallExternalTarget target_name target_path install_type installed_file_name) + # Get the optional rpath parameter + set(additional_arguments ${ARGN}) + list(LENGTH additional_arguments additional_argument_count) + + if("${additional_argument_count}" EQUAL 0) + elseif("${additional_argument_count}" EQUAL 1) + list(GET additional_arguments 0 rpath) + else() + message(FATAL_ERROR "InstallExternalTarget: Invalid argument count") + endif() + + # We need to locate the patchelf executable to fix the rpath; search for it + # only once, and then export the variable with PARENT_SCOPE so that we can + # re-use it in the next calls + if(NOT "${rpath}" STREQUAL "") + if("${PATCHELF_LOCATION}" STREQUAL "") + find_program("program_location" "patchelf") + if("${program_location}" STREQUAL "program_location-NOTFOUND") + message(FATAL_ERROR "InstallExternalTarget: Failed to locate the patchelf executable") + endif() + + # We need to set it both in local and in parent scope + set("PATCHELF_LOCATION" "${program_location}" PARENT_SCOPE) + set("PATCHELF_LOCATION" "${program_location}") + endif() + endif() + + # Make sure the parameters are correct + if(NOT EXISTS "${target_path}") + message(FATAL_ERROR "InstallExternalTarget: The following path does not exists: ${target_path}") + endif() + + if("${target_name}") + message(FATAL_ERROR "InstallExternalTarget: The following target already exists: ${target_name}") + endif() + + if("${install_type}" STREQUAL "") + message(FATAL_ERROR "InstallExternalTarget: Invalid install type specified") + endif() + + # Generate the target + set("output_file_path" "${CMAKE_CURRENT_BINARY_DIR}/${installed_file_name}") + + if(NOT "${rpath}" STREQUAL "") + set(CHRPATH_COMMAND ${PATCHELF_LOCATION} --set-rpath ${rpath} ${output_file_path}) + else() + set(CHRPATH_COMMAND ${CMAKE_COMMAND} -E echo 'No rpath patch needed for ${target_name}') + endif() + + add_custom_command( + OUTPUT "${output_file_path}" + + COMMAND "${CMAKE_COMMAND}" -E copy ${target_path} ${output_file_path} + COMMAND ${CHRPATH_COMMAND} + ) + + add_custom_target("${target_name}" ALL DEPENDS "${output_file_path}") + + install(FILES "${output_file_path}" + TYPE ${install_type} + PERMISSIONS OWNER_READ OWNER_EXECUTE + GROUP_READ GROUP_EXECUTE + WORLD_READ WORLD_EXECUTE + ) +endfunction() + diff --git a/cmake/vcpkg_helper.cmake b/cmake/vcpkg_helper.cmake new file mode 100644 index 000000000..765c91538 --- /dev/null +++ b/cmake/vcpkg_helper.cmake @@ -0,0 +1,43 @@ +set(USE_SYSTEM_DEPENDENCIES OFF CACHE BOOL "Use system dependencies instead of trying to find vcpkg") + +if (NOT USE_SYSTEM_DEPENDENCIES) + set(VCPKG_ROOT "" CACHE FILEPATH "Root directory to use for vcpkg-managed dependencies") + if (VCPKG_ROOT) + if (NOT EXISTS "${VCPKG_ROOT}") + message(FATAL_ERROR "VCPKG_ROOT directory does not exist: '${VCPKG_ROOT}'") + endif() + + set(VCPKG_ROOT_INSTALL_DIR "${VCPKG_ROOT}/installed") + if (NOT EXISTS "${VCPKG_ROOT_INSTALL_DIR}") + message(FATAL_ERROR "VCPKG_ROOT installation directory does not exist: '${VCPKG_ROOT_INSTALL_DIR}'") + endif() + + set(CMAKE_TOOLCHAIN_FILE "${VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" CACHE FILEPATH "" FORCE) + else() + message(FATAL_ERROR "Please define a path to VCPKG_ROOT. See https://github.com/trailofbits/cxx-common for more details. Or if you don't want to use vcpkg dependencies, add '-DUSE_SYSTEM_DEPENDENCIES=ON'") + endif() + + # Set default triplet to Release VCPKG build unless we can't find it + if (NOT DEFINED VCPKG_TARGET_TRIPLET) + if (APPLE) + set(_project_vcpkg_triplet "x64-osx-rel") + elseif(UNIX) + set(_project_vcpkg_triplet "x64-linux-rel") + else() + message(FATAL_ERROR "Could not detect default release triplet") + endif() + + if (NOT EXISTS "${VCPKG_ROOT_INSTALL_DIR}/${_project_vcpkg_triplet}") + message(STATUS "Could not find installed project-default triplet '${_project_vcpkg_triplet}' using vcpkg-default for your system") + else() + set(VCPKG_TARGET_TRIPLET "${_project_vcpkg_triplet}" CACHE STRING "") + message(STATUS "Setting default vcpkg triplet to release-only libraries: ${VCPKG_TARGET_TRIPLET}") + endif() + endif() + + if (DEFINED VCPKG_TARGET_TRIPLET AND NOT EXISTS "${VCPKG_ROOT_INSTALL_DIR}/${VCPKG_TARGET_TRIPLET}") + message(FATAL_ERROR "Could not find vcpkg triplet (${VCPKG_TARGET_TRIPLET}) installation libraries '${VCPKG_ROOT_INSTALL_DIR}/${VCPKG_TARGET_TRIPLET}'.") + endif() + + message(STATUS "Using vcpkg installation directory at '${VCPKG_ROOT_INSTALL_DIR}/${VCPKG_TARGET_TRIPLET}'") +endif() diff --git a/lib/Arch/AArch64/CMakeLists.txt b/lib/Arch/AArch64/CMakeLists.txt index 2928e6aef..ec2766814 100644 --- a/lib/Arch/AArch64/CMakeLists.txt +++ b/lib/Arch/AArch64/CMakeLists.txt @@ -20,11 +20,11 @@ add_library(remill_arch_aarch64 STATIC "${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/Runtime.h" "${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/State.h" "${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/Types.h" - + "${REMILL_INCLUDE_DIR}/remill/Arch/AArch64/Runtime/Operators.h" "${REMILL_INCLUDE_DIR}/remill/Arch/AArch64/Runtime/State.h" "${REMILL_INCLUDE_DIR}/remill/Arch/AArch64/Runtime/Types.h" - + Arch.cpp Decode.cpp Decode.h @@ -41,6 +41,5 @@ target_link_libraries(remill_arch_aarch64 LINK_PUBLIC install( TARGETS remill_arch_aarch64 - ARCHIVE DESTINATION "${REMILL_INSTALL_LIB_DIR}" - PUBLIC_HEADER DESTINATION "${REMILL_INSTALL_INCLUDE_DIR}" + EXPORT remillTargets ) diff --git a/lib/Arch/CMakeLists.txt b/lib/Arch/CMakeLists.txt index 25363ad0b..224e835af 100644 --- a/lib/Arch/CMakeLists.txt +++ b/lib/Arch/CMakeLists.txt @@ -16,7 +16,7 @@ add_library(remill_arch STATIC "${REMILL_INCLUDE_DIR}/remill/Arch/Arch.h" "${REMILL_INCLUDE_DIR}/remill/Arch/Instruction.h" "${REMILL_INCLUDE_DIR}/remill/Arch/Name.h" - + Arch.cpp Instruction.cpp Name.cpp @@ -30,15 +30,13 @@ add_subdirectory(X86) set_property(TARGET remill_arch PROPERTY POSITION_INDEPENDENT_CODE ON) target_link_libraries(remill_arch LINK_PUBLIC - remill_settings remill_arch_aarch64 remill_arch_sparc32 remill_arch_sparc64 remill_arch_x86 + LINK_PRIVATE + remill_settings ) -install( - TARGETS remill_arch - ARCHIVE DESTINATION "${REMILL_INSTALL_LIB_DIR}" - PUBLIC_HEADER DESTINATION "${REMILL_INSTALL_INCLUDE_DIR}" -) +install(TARGETS remill_arch + EXPORT remillTargets) diff --git a/lib/Arch/SPARC32/CMakeLists.txt b/lib/Arch/SPARC32/CMakeLists.txt index 87fdec86e..4929f4577 100644 --- a/lib/Arch/SPARC32/CMakeLists.txt +++ b/lib/Arch/SPARC32/CMakeLists.txt @@ -23,7 +23,7 @@ add_library(remill_arch_sparc32 STATIC "${REMILL_INCLUDE_DIR}/remill/Arch/SPARC32/Runtime/State.h" "${REMILL_INCLUDE_DIR}/remill/Arch/SPARC32/Runtime/Types.h" - + Arch.cpp Decode.h Extract.cpp @@ -39,6 +39,5 @@ target_link_libraries(remill_arch_sparc32 LINK_PUBLIC install( TARGETS remill_arch_sparc32 - ARCHIVE DESTINATION "${REMILL_INSTALL_LIB_DIR}" - PUBLIC_HEADER DESTINATION "${REMILL_INSTALL_INCLUDE_DIR}" -) \ No newline at end of file + EXPORT remillTargets +) diff --git a/lib/Arch/SPARC64/CMakeLists.txt b/lib/Arch/SPARC64/CMakeLists.txt index df502d9b7..5f559511a 100644 --- a/lib/Arch/SPARC64/CMakeLists.txt +++ b/lib/Arch/SPARC64/CMakeLists.txt @@ -20,12 +20,12 @@ add_library(remill_arch_sparc64 STATIC "${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/Runtime.h" "${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/State.h" "${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/Types.h" - + "${REMILL_INCLUDE_DIR}/remill/Arch/SPARC64/Runtime/State.h" "${REMILL_INCLUDE_DIR}/remill/Arch/SPARC64/Runtime/Types.h" - + "${REMILL_LIB_DIR}/Arch/SPARC32/Decode.h" - + Arch.cpp Decode.h Extract.cpp @@ -41,6 +41,5 @@ target_link_libraries(remill_arch_sparc64 LINK_PUBLIC install( TARGETS remill_arch_sparc64 - ARCHIVE DESTINATION "${REMILL_INSTALL_LIB_DIR}" - PUBLIC_HEADER DESTINATION "${REMILL_INSTALL_INCLUDE_DIR}" + EXPORT remillTargets ) diff --git a/lib/Arch/X86/CMakeLists.txt b/lib/Arch/X86/CMakeLists.txt index 1fbf3b2f6..85c8de8c7 100644 --- a/lib/Arch/X86/CMakeLists.txt +++ b/lib/Arch/X86/CMakeLists.txt @@ -20,11 +20,11 @@ add_library(remill_arch_x86 STATIC "${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/Runtime.h" "${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/State.h" "${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/Types.h" - + "${REMILL_INCLUDE_DIR}/remill/Arch/X86/Runtime/Operators.h" "${REMILL_INCLUDE_DIR}/remill/Arch/X86/Runtime/State.h" "${REMILL_INCLUDE_DIR}/remill/Arch/X86/Runtime/Types.h" - + Arch.cpp XED.h ) @@ -37,8 +37,5 @@ target_link_libraries(remill_arch_x86 LINK_PUBLIC remill_settings ) -install( - TARGETS remill_arch_x86 - ARCHIVE DESTINATION "${REMILL_INSTALL_LIB_DIR}" - PUBLIC_HEADER DESTINATION "${REMILL_INSTALL_INCLUDE_DIR}" -) \ No newline at end of file +install(TARGETS remill_arch_x86 + EXPORT remillTargets) diff --git a/lib/Arch/X86/Runtime/CMakeLists.txt b/lib/Arch/X86/Runtime/CMakeLists.txt index ea52f03fc..a389601fc 100644 --- a/lib/Arch/X86/Runtime/CMakeLists.txt +++ b/lib/Arch/X86/Runtime/CMakeLists.txt @@ -18,7 +18,7 @@ project(x86_runtime) set(X86RUNTIME_SOURCEFILES Instructions.cpp BasicBlock.cpp - + "${REMILL_LIB_DIR}/Arch/Runtime/Intrinsics.cpp" ) @@ -55,7 +55,7 @@ function(add_runtime_helper target_name address_bit_size enable_avx enable_avx51 "${REMILL_INCLUDE_DIR}/remill/Arch/X86/Runtime/Operators.h" "${REMILL_INCLUDE_DIR}/remill/Arch/X86/Runtime/State.h" "${REMILL_INCLUDE_DIR}/remill/Arch/X86/Runtime/Types.h" - + "${REMILL_LIB_DIR}/Arch/X86/Semantics/CONVERT.cpp" "${REMILL_LIB_DIR}/Arch/X86/Semantics/POP.cpp" "${REMILL_LIB_DIR}/Arch/X86/Semantics/BITBYTE.cpp" diff --git a/lib/BC/CMakeLists.txt b/lib/BC/CMakeLists.txt index 5fc02fa54..8b5a42fa0 100644 --- a/lib/BC/CMakeLists.txt +++ b/lib/BC/CMakeLists.txt @@ -23,7 +23,7 @@ add_library(remill_bc STATIC "${REMILL_INCLUDE_DIR}/remill/BC/TraceLifter.h" "${REMILL_INCLUDE_DIR}/remill/BC/Util.h" "${REMILL_INCLUDE_DIR}/remill/BC/Version.h" - + ABI.cpp Annotate.cpp DeadStoreEliminator.cpp @@ -37,12 +37,11 @@ add_library(remill_bc STATIC set_property(TARGET remill_bc PROPERTY POSITION_INDEPENDENT_CODE ON) -target_link_libraries(remill_bc LINK_PUBLIC +target_link_libraries(remill_bc LINK_PRIVATE remill_settings ) install( TARGETS remill_bc - ARCHIVE DESTINATION "${REMILL_INSTALL_LIB_DIR}" - PUBLIC_HEADER DESTINATION "${REMILL_INSTALL_INCLUDE_DIR}" -) \ No newline at end of file + EXPORT remillTargets +) diff --git a/lib/OS/CMakeLists.txt b/lib/OS/CMakeLists.txt index 9c3c7983f..376765916 100644 --- a/lib/OS/CMakeLists.txt +++ b/lib/OS/CMakeLists.txt @@ -15,7 +15,7 @@ add_library(remill_os STATIC "${REMILL_INCLUDE_DIR}/remill/OS/FileSystem.h" "${REMILL_INCLUDE_DIR}/remill/OS/OS.h" - + Compat.cpp FileSystem.cpp OS.cpp @@ -23,12 +23,11 @@ add_library(remill_os STATIC set_property(TARGET remill_os PROPERTY POSITION_INDEPENDENT_CODE ON) -target_link_libraries(remill_os LINK_PUBLIC +target_link_libraries(remill_os LINK_PRIVATE remill_settings ) install( TARGETS remill_os - ARCHIVE DESTINATION "${REMILL_INSTALL_LIB_DIR}" - PUBLIC_HEADER DESTINATION "${REMILL_INSTALL_INCLUDE_DIR}" -) \ No newline at end of file + EXPORT remillTargets +) diff --git a/lib/Version/CMakeLists.txt b/lib/Version/CMakeLists.txt index 2339cf25d..2c2ee1a9b 100644 --- a/lib/Version/CMakeLists.txt +++ b/lib/Version/CMakeLists.txt @@ -2,20 +2,25 @@ # By Andrew Hardin # Released under the MIT License. # https://raw.githubusercontent.com/andrew-hardin/cmake-git-version-tracking/master/LICENSE -# +# # Define the two required variables before including # the source code for watching a git repository. set(PRE_CONFIGURE_FILE "Version.cpp.in") set(POST_CONFIGURE_FILE "${CMAKE_CURRENT_BINARY_DIR}/Version.cpp") include("${CMAKE_SOURCE_DIR}/cmake/git_watcher.cmake") +set(Version_PUBLIC_H + "${PROJECT_SOURCE_DIR}/include/remill/Version/Version.h" +) # Create a library out of the compiled post-configure file. -add_library(remill_version STATIC ${POST_CONFIGURE_FILE}) -target_include_directories(remill_version PUBLIC "${REMILL_INCLUDE_DIR}") +add_library(remill_version STATIC + ${POST_CONFIGURE_FILE} + ${Version_PUBLIC_H} + ) +target_link_libraries(remill_version LINK_PRIVATE remill_settings) add_dependencies(remill_version check_git_${PROJECT_NAME}) install( TARGETS remill_version - ARCHIVE DESTINATION "${REMILL_INSTALL_LIB_DIR}" - PUBLIC_HEADER DESTINATION "${REMILL_INSTALL_INCLUDE_DIR}" -) \ No newline at end of file + EXPORT remillTargets +) diff --git a/scripts/build.sh b/scripts/build.sh index 1c24ffe7c..039120f6d 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -19,10 +19,11 @@ SCRIPTS_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) SRC_DIR=$( cd "$( dirname "${SCRIPTS_DIR}" )" && pwd ) +DOWNLOAD_DIR="$( cd "$( dirname "${SRC_DIR}" )" && pwd )/lifting-bits-downloads" CURR_DIR=$( pwd ) BUILD_DIR="${CURR_DIR}/remill-build" INSTALL_DIR=/usr/local -LLVM_VERSION=llvm900 +LLVM_VERSION=llvm-9 OS_VERSION= ARCH_VERSION= BUILD_FLAGS= @@ -37,31 +38,30 @@ function GetUbuntuOSVersion case "${DISTRIB_CODENAME}" in groovy) echo "[!] Ubuntu 20.10 is not supported; using libraries for Ubuntu 20.04 instead" - OS_VERSION=ubuntu20.04 + OS_VERSION=ubuntu-20.04 return 0 ;; focal) - OS_VERSION=ubuntu20.04 + OS_VERSION=ubuntu-20.04 return 0 ;; - eoam) echo "[!] Ubuntu 19.10 is not supported; using libraries for Ubuntu 18.04 instead" - OS_VERSION=ubuntu18.04 + OS_VERSION=ubuntu-18.04 return 0 ;; disco) echo "[!] Ubuntu 19.04 is not supported; using libraries for Ubuntu 18.04 instead" - OS_VERSION=ubuntu18.04 + OS_VERSION=ubuntu-18.04 return 0 ;; cosmic) echo "[!] Ubuntu 18.10 is not supported; using libraries for Ubuntu 18.04 instead" - OS_VERSION=ubuntu18.04 + OS_VERSION=ubuntu-18.04 return 0 ;; bionic) - OS_VERSION=ubuntu18.04 + OS_VERSION=ubuntu-18.04 return 0 ;; *) @@ -74,7 +74,8 @@ function GetUbuntuOSVersion # Figure out the architecture of the current machine. function GetArchVersion { - local version=$( uname -m ) + local version + version="$( uname -m )" case "${version}" in x86_64) @@ -96,12 +97,15 @@ function GetArchVersion esac } -function DownloadCxxCommon +function DownloadVcpkgLibraries { local GITHUB_LIBS="${LIBRARY_VERSION}.tar.xz" local URL="https://github.com/trailofbits/cxx-common/releases/latest/download/${GITHUB_LIBS}" - echo "Fetching: ${URL}" + mkdir -p "${DOWNLOAD_DIR}" + pushd "${DOWNLOAD_DIR}" || return 1 + + echo "Fetching: ${URL} and placing in ${DOWNLOAD_DIR}" if ! curl -LO "${URL}"; then return 1 fi @@ -111,11 +115,17 @@ function DownloadCxxCommon TAR_OPTIONS="" fi - tar -xJf "${GITHUB_LIBS}" ${TAR_OPTIONS} + # NOTE: export-raw is the directory that vcpkg used for exporting raw file tree + # we want to rename it + ( + set -x + tar -xJf "${GITHUB_LIBS}" ${TAR_OPTIONS} + ) || return $? rm "${GITHUB_LIBS}" + popd || return 1 # Make sure modification times are not in the future. - find "${BUILD_DIR}/libraries" -type f -exec touch {} \; + find "${DOWNLOAD_DIR}/${LIBRARY_VERSION}" -type f -exec touch {} \; return 0 } @@ -132,12 +142,12 @@ function GetOSVersion ;; *arch*) - OS_VERSION=ubuntu18.04 + OS_VERSION=ubuntu-18.04 return 0 ;; - + [Kk]ali) - OS_VERSION=ubuntu18.04 + OS_VERSION=ubuntu-18.04 return 0; ;; @@ -156,17 +166,26 @@ function DownloadLibraries if [[ "${OSTYPE}" = "darwin"* ]]; then # Compute an isysroot from the SDK root dir. - local sdk_root="${SDKROOT}" - if [[ "x${sdk_root}x" = "xx" ]]; then - sdk_root=$(xcrun -sdk macosx --show-sdk-path) - fi - - BUILD_FLAGS="${BUILD_FLAGS} -DCMAKE_OSX_SYSROOT=${sdk_root}" - OS_VERSION=macos + #local sdk_root="${SDKROOT}" + #if [[ "x${sdk_root}x" = "xx" ]]; then + # sdk_root=$(xcrun -sdk macosx --show-sdk-path) + #fi + + #BUILD_FLAGS="${BUILD_FLAGS} -DCMAKE_OSX_SYSROOT=${sdk_root}" + # Min version supported + OS_VERSION="macos-10.15" + XCODE_VERSION="12.1.0" if [[ "$(sw_vers -productVersion)" == "10.15"* ]]; then echo "Found MacOS Catalina" + OS_VERSION="macos-10.15" + XCODE_VERSION="12.1.0" + elif [[ "$(sw_vers -productVersion)" == "11.0"* ]]; then + echo "Found MacOS Big Sur" + OS_VERSION="macos-11.0" + XCODE_VERSION="12.2.0" else echo "WARNING: ****Likely unsupported MacOS Version****" + echo "WARNING: ****Using ${OS_VERSION}****" fi # Linux packages @@ -183,18 +202,19 @@ function DownloadLibraries return 1 fi - if [[ "${OS_VERSION}" == "macos" ]]; then - # Only support catalina build, for now - LIBRARY_VERSION="libraries-catalina-macos" + if [[ "${OS_VERSION}" == "macos-"* ]]; then + # TODO Figure out Xcode compatibility + LIBRARY_VERSION="vcpkg_${OS_VERSION}_${LLVM_VERSION}_xcode-${XCODE_VERSION}_${ARCH_VERSION}" else - LIBRARY_VERSION="libraries-${LLVM_VERSION}-${OS_VERSION}-${ARCH_VERSION}" + # TODO Arch version + LIBRARY_VERSION="vcpkg_${OS_VERSION}_${LLVM_VERSION}_${ARCH_VERSION}" fi echo "[-] Library version is ${LIBRARY_VERSION}" - if [[ ! -d "${BUILD_DIR}/libraries" ]]; then - if ! DownloadCxxCommon; then - echo "[x] Unable to download cxx-common build ${LIBRARY_VERSION}." + if [[ ! -d "${DOWNLOAD_DIR}/${LIBRARY_VERSION}" ]]; then + if ! DownloadVcpkgLibraries; then + echo "[x] Unable to download vcpkg libraries build ${LIBRARY_VERSION}." return 1 fi fi @@ -205,19 +225,17 @@ function DownloadLibraries # Configure the build. function Configure { - # Tell the remill CMakeLists.txt where the extracted libraries are. - export TRAILOFBITS_LIBRARIES="${BUILD_DIR}/libraries" - export PATH="${TRAILOFBITS_LIBRARIES}/cmake/bin:${TRAILOFBITS_LIBRARIES}/llvm/bin:${PATH}" - # Configure the remill build, specifying that it should use the pre-built # Clang compiler binaries. - "${TRAILOFBITS_LIBRARIES}/cmake/bin/cmake" \ - -DCMAKE_INSTALL_PREFIX="${INSTALL_DIR}" \ - -DCMAKE_BC_COMPILER="${TRAILOFBITS_LIBRARIES}/llvm/bin/clang++" \ - -DCMAKE_BC_LINKER="${TRAILOFBITS_LIBRARIES}/llvm/bin/llvm-link" \ - -DCMAKE_VERBOSE_MAKEFILE=True \ - ${BUILD_FLAGS} \ - "${SRC_DIR}" + ( + set -x + cmake \ + -DCMAKE_INSTALL_PREFIX="${INSTALL_DIR}" \ + -DCMAKE_VERBOSE_MAKEFILE=True \ + -DVCPKG_ROOT="${DOWNLOAD_DIR}/${LIBRARY_VERSION}" \ + ${BUILD_FLAGS} \ + "${SRC_DIR}" + ) || exit $? return $? } @@ -230,7 +248,12 @@ function Build else NPROC=$( nproc ) fi - make -j"${NPROC}" + + ( + set -x + cmake --build . -- -j"${NPROC}" + ) || return $? + return $? } @@ -239,16 +262,16 @@ function Build function GetLLVMVersion { case ${1} in - 9.0) - LLVM_VERSION=llvm900 + 9) + LLVM_VERSION=llvm-9 return 0 ;; - 10.0) - LLVM_VERSION=llvm1000 + 10) + LLVM_VERSION=llvm-10 return 0 ;; - 11.0) - LLVM_VERSION=llvm1100 + 11) + LLVM_VERSION=llvm-11 return 0 ;; *) @@ -260,6 +283,20 @@ function GetLLVMVersion return 1 } +function Help +{ + echo "Beginner build script to get started" + echo "" + echo "Options:" + echo " --prefix Change the default (${INSTALL_DIR}) installation prefix." + echo " --llvm-version Change the default (9) LLVM version." + echo " --build-dir Change the default (${BUILD_DIR}) build directory." + echo " --debug Build with Debug symbols." + echo " --extra-cmake-args Extra CMake arguments to build with." + echo " --dyinst-frontend Build McSema with dyninst frontend as well." + echo " -h --help Print help." +} + function main { while [[ $# -gt 0 ]] ; do @@ -267,6 +304,16 @@ function main case $key in + -h) + Help + exit 0 + ;; + + --help) + Help + exit 0 + ;; + # Change the default installation prefix. --prefix) INSTALL_DIR=$(python3 -c "import os; import sys; sys.stdout.write(os.path.abspath('${2}'))") @@ -290,6 +337,13 @@ function main shift # past argument ;; + # Change the default download directory. + --download-dir) + DOWNLOAD_DIR=$(python3 -c "import os; import sys; sys.stdout.write(os.path.abspath('${2}'))") + echo "[+] New download directory is ${BUILD_DIR}" + shift # past argument + ;; + # Make the build type to be a debug build. --debug) BUILD_FLAGS="${BUILD_FLAGS} -DCMAKE_BUILD_TYPE=Debug" @@ -333,6 +387,7 @@ function main if ! (DownloadLibraries && Configure && Build); then echo "[x] Build aborted." + exit 1 fi return $? diff --git a/scripts/travis.sh b/scripts/travis.sh index 5747c5acd..da49949b5 100755 --- a/scripts/travis.sh +++ b/scripts/travis.sh @@ -77,7 +77,7 @@ osx_initialize() { printf " > The macOS SDK is located at ${SDKROOT}\n" # Mainly for realpath - brew install coreutils + brew install coreutils cmake if [ $? -ne 0 ] ; then printf " x Could not install the required dependencies\n" return 1 @@ -210,7 +210,11 @@ common_build() { printf " i ${CCACHE_DIR}\n" export TRAILOFBITS_LIBRARIES=`GetRealPath libraries` - export PATH="${TRAILOFBITS_LIBRARIES}/llvm/bin:${TRAILOFBITS_LIBRARIES}/cmake/bin:${TRAILOFBITS_LIBRARIES}/protobuf/bin:${PATH}" + export PATH="${TRAILOFBITS_LIBRARIES}/llvm/bin:${TRAILOFBITS_LIBRARIES}/protobuf/bin:${PATH}" + # Use brew-installed cmake instead of outdated version here + if [[ "${platform_name}" != "osx" ]] ; then + export PATH="${TRAILOFBITS_LIBRARIES}/cmake/bin:${PATH}" + fi export CC="${TRAILOFBITS_LIBRARIES}/llvm/bin/clang" export CXX="${TRAILOFBITS_LIBRARIES}/llvm/bin/clang++" diff --git a/tests/X86/CMakeLists.txt b/tests/X86/CMakeLists.txt index ad5ef5437..2c344bfdc 100644 --- a/tests/X86/CMakeLists.txt +++ b/tests/X86/CMakeLists.txt @@ -41,8 +41,12 @@ function(COMPILE_X86_TESTS name address_size has_avx has_avx512) set_target_properties(lift-${name}-tests PROPERTIES OBJECT_DEPENDS "${X86_TEST_FILES}") - target_link_libraries(lift-${name}-tests PUBLIC remill ${gtest_LIBRARIES}) - target_include_directories(lift-${name}-tests PUBLIC ${gtest_INCLUDE_DIRS}) + if (DEFINED ENV{TRAILOFBITS_LIBRARIES}) + target_link_libraries(lift-${name}-tests PUBLIC remill ${gtest_LIBRARIES}) + target_include_directories(lift-${name}-tests PUBLIC ${gtest_INCLUDE_DIRS}) + else() + target_link_libraries(lift-${name}-tests PRIVATE remill GTest::gtest) + endif() target_compile_definitions(lift-${name}-tests PUBLIC ${PROJECT_DEFINITIONS}) add_custom_command( @@ -60,8 +64,12 @@ function(COMPILE_X86_TESTS name address_size has_avx has_avx512) add_executable(run-${name}-tests EXCLUDE_FROM_ALL Run.cpp Tests.S tests_${name}.S) set_target_properties(run-${name}-tests PROPERTIES OBJECT_DEPENDS "${X86_TEST_FILES}") - target_link_libraries(run-${name}-tests PUBLIC remill ${gtest_LIBRARIES}) - target_include_directories(run-${name}-tests PUBLIC ${gtest_INCLUDE_DIRS}) + if (DEFINED ENV{TRAILOFBITS_LIBRARIES}) + target_link_libraries(run-${name}-tests PUBLIC remill ${gtest_LIBRARIES}) + target_include_directories(run-${name}-tests PUBLIC ${gtest_INCLUDE_DIRS}) + else() + target_link_libraries(run-${name}-tests PUBLIC remill GTest::gtest) + endif() target_compile_definitions(run-${name}-tests PUBLIC ${PROJECT_DEFINITIONS}) target_compile_options(run-${name}-tests @@ -73,7 +81,12 @@ function(COMPILE_X86_TESTS name address_size has_avx has_avx512) add_dependencies(test_dependencies "run-${name}-tests") endfunction() -find_package(gtest REQUIRED) +if (DEFINED ENV{TRAILOFBITS_LIBRARIES}) + find_package(gtest REQUIRED) +else() + find_package(GTest CONFIG REQUIRED) +endif() + enable_testing() if (NOT APPLE) diff --git a/vcpkg.README.md b/vcpkg.README.md new file mode 100644 index 000000000..8f0b8b9af --- /dev/null +++ b/vcpkg.README.md @@ -0,0 +1,89 @@ +# Remill [![Slack Chat](http://empireslacking.herokuapp.com/badge.svg)](https://empireslacking.herokuapp.com/) + +

+ +

+ +Remill is a static binary translator that translates machine code instructions into [LLVM bitcode](http://llvm.org/docs/LangRef.html). It translates AArch64 (64-bit ARMv8), SPARC32 (SPARCv8), SPARC64 (SPARCv9), x86 and amd64 machine code (including AVX and AVX512) into LLVM bitcode. AArch32 (32-bit ARMv8 / ARMv7) support is underway. + +Remill focuses on accurately lifting instructions. It is meant to be used as a library for other tools, e.g. [McSema](https://github.com/lifting-bits/mcsema). + +## Build Status + +[![Build Status](https://img.shields.io/github/workflow/status/lifting-bits/remill/CI/master)](https://github.com/lifting-bits/remill/actions?query=workflow%3ACI) + +## Additional Documentation + + - [How to contribute](docs/CONTRIBUTING.md) + - [How to implement the semantics of an instruction](docs/ADD_AN_INSTRUCTION.md) + - [How instructions are lifted](docs/LIFE_OF_AN_INSTRUCTION.md) + - [The design and architecture of Remill](docs/DESIGN.md) + +## Getting Help + +If you are experiencing undocumented problems with Remill then ask for help in the `#binary-lifting` channel of the [Empire Hacking Slack](https://empireslacking.herokuapp.com/). + +## Supported Platforms + +Remill is supported on Linux platforms and has been tested on Ubuntu 14.04, 16.04, and 18.04. Remill also works on macOS, and has experimental support for Windows. + +Remill's Linux version can also be built via Docker for quicker testing. + +## Dependencies + +Most of Remill's dependencies can be provided by the [cxx-common](https://github.com/trailofbits/cxx-common) repository. Trail of Bits hosts downloadable, pre-built versions of cxx-common, which makes it substantially easier to get up and running with Remill. Nonetheless, the following table represents most of Remill's dependencies. + +| Name | Version | +| ---- | ------- | +| [Git](https://git-scm.com/) | Latest | +| [CMake](https://cmake.org/) | 3.2+ | +| [Google Flags](https://github.com/google/glog) | Latest | +| [Google Log](https://github.com/google/glog) | Latest | +| [Google Test](https://github.com/google/googletest) | Latest | +| [LLVM](http://llvm.org/) | 3.5+ | +| [Clang](http://clang.llvm.org/) | 3.5+ | +| [Intel XED](https://software.intel.com/en-us/articles/xed-x86-encoder-decoder-software-library) | Latest | +| [Python](https://www.python.org/) | 2.7 | +| Unzip | Latest | +| [ccache](https://ccache.dev/) | Latest | + +## Getting and Building the Code + +### Vcpkg Quickstart + +If you are running Ubuntu or Mac, you will be able to use pre-compiled libraries instead of building everything yourself. + +First, clone the repository. This will clone the code into the `remill` directory. + +```shell +git clone https://github.com/lifting-bits/remill.git +``` + +Next, we build Remill. This script will create another directory, `remill-build`, in the current working directory. All remaining dependencies needed by Remill will be downloaded from what was built in our CI into the `remill-build` directory. The build script will use whatever compiler is found by CMake. + +```bash +./remill/scripts/build.sh +``` + +To run the tests you must have built Remill with `clang`: + +```bash +cmake --build . --target test_dependencies +env CTEST_OUTPUT_ON_FAILURE=1 cmake --build build --target test +``` + +To see more options for the build script, use `--help`, open an issue, or join Slack. + +### Docker Build + +Ensure remill works: +```shell +# Decode some AMD64 instructions to LLVM +docker run --rm -it remill:llvm800-ubuntu18.04-amd64 \ + --arch amd64 --ir_out /dev/stdout --bytes c704ba01000000 + +# Decode some AArch64 instructions to LLVM +docker run --rm -it remill:llvm800-ubuntu18.04-amd64 \ + --arch aarch64 --address 0x400544 --ir_out /dev/stdout \ + --bytes FD7BBFA90000009000601891FD030091B7FFFF97E0031F2AFD7BC1A8C0035FD6 +```