diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 476b50b6..cf63d8ff 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -9,7 +9,7 @@ jobs: build: strategy: matrix: - os: [ubuntu-latest, windows-latest] + os: [ubuntu-latest, windows-latest, macos-latest] ida_sdk: [74, 77, 80, 81, 82, 83, 84] include: - ida_sdk: 74 @@ -30,6 +30,12 @@ jobs: ext: so - os: windows-latest ext: dll + - os: macos-latest + ext: dylib + exclude: + # We exclude these because ARM libraries were not available in 7.4 and the latest macos runner on GitHub are Mx machines + - os: macos-latest + ida_sdk: 74 runs-on: ${{ matrix.os }} steps: @@ -48,12 +54,12 @@ jobs: with: cmake-version: 'latest' - - name: Install Ninja (Linux only) - if: ${{ matrix.os == 'ubuntu-latest' }} - uses: seanmiddleditch/gha-setup-ninja@master + - name: Install Ninja (Linux / MacOS) + if: ${{ matrix.os == 'ubuntu-latest' || matrix.os == 'macos-latest' }} + uses: seanmiddleditch/gha-setup-ninja@v4 - - name: Fetch IDA SDKs (Linux) - if: ${{ matrix.os == 'ubuntu-latest' && steps.cache-sdk.outputs.cache-hit != 'true' }} + - name: Fetch IDA SDKs (Linux / MacOS) + if: ${{ (matrix.os == 'ubuntu-latest' || matrix.os == 'macos-latest') && steps.cache-sdk.outputs.cache-hit != 'true' }} run: | cd scripts ./fetch_sdk.sh @@ -75,6 +81,24 @@ jobs: [ -f third_party/$IDA_SDK_VERSION/include/regex.h ] && mv third_party/$IDA_SDK_VERSION/include/regex.h third_party/$IDA_SDK_VERSION/include/regex.bak cmake -B $CMAKE_BUILD_DIR -S $GITHUB_WORKSPACE -G Ninja -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DIdaSdk_ROOT_DIR=${GITHUB_WORKSPACE}/third_party/$IDA_SDK_VERSION + # We need to differentiate MacOS build from Linux because we want to use a specific compiler on MacOS + - name: Prepare build environment (MacOS) + if: ${{ matrix.os == 'macos-latest' }} + env: + IDA_SDK_VERSION: idasdk${{ matrix.ida_sdk }} + IDA_SDK_PASSWORD: ${{ secrets[matrix.sdk_password] }} + CMAKE_BUILD_DIR: build${{ matrix.ida_sdk }} + run: | + [ ! -d third_party/$IDA_SDK_VERSION ] && unzip -d third_party -P $IDA_SDK_PASSWORD third_party/$IDA_SDK_VERSION.zip + [ -f third_party/$IDA_SDK_VERSION/include/regex.h ] && mv third_party/$IDA_SDK_VERSION/include/regex.h third_party/$IDA_SDK_VERSION/include/regex.bak + cmake -B $CMAKE_BUILD_DIR \ + -S $GITHUB_WORKSPACE \ + -G Ninja \ + -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ + -DIdaSdk_ROOT_DIR=${GITHUB_WORKSPACE}/third_party/$IDA_SDK_VERSION \ + -DCMAKE_C_COMPILER=$(brew --prefix llvm@15)/bin/clang \ + -DCMAKE_CXX_COMPILER=$(brew --prefix llvm@15)/bin/clang++ + - name: Prepare build environment (Windows) if: ${{ matrix.os == 'windows-latest' }} env: @@ -96,16 +120,26 @@ jobs: - name: Rename Plugin shell: bash - run: - mv build${{ matrix.ida_sdk }}/quokka-install/quokka_* ${{ matrix.ida_sdk }}-quokka_plugin0064.${{ matrix.ext }} + run: | + mv build${{ matrix.ida_sdk }}/quokka-install/quokka_plugin64.${{ matrix.ext }} ${{ matrix.ida_sdk }}-quokka_plugin0064.${{ matrix.ext }} + mv build${{ matrix.ida_sdk }}/quokka-install/quokka_plugin.${{ matrix.ext }} ${{ matrix.ida_sdk }}-quokka_plugin0032.${{ matrix.ext }} - - name: Upload Artifacts - uses: actions/upload-artifact@v4 + # We need one action per file + # See https://github.com/actions/upload-artifact/issues/331 + - name: Upload Artifacts (64) + uses: actions/upload-artifact@v4.3.1 with: name: idaplugin-${{ matrix.os }}-${{ matrix.ida_sdk }} path: ${{ matrix.ida_sdk }}-quokka_plugin0064.${{ matrix.ext }} if-no-files-found: error + - name: Upload Artifacts (32) + uses: actions/upload-artifact@v4.3.1 + with: + name: idaplugin-${{ matrix.os }}-${{ matrix.ida_sdk }}-32 + path: ${{ matrix.ida_sdk }}-quokka_plugin0032.${{ matrix.ext }} + if-no-files-found: error + upload: name: Upload artifacts for Release needs: [build] @@ -114,18 +148,25 @@ jobs: strategy: matrix: - os: [ubuntu-latest, windows-latest] + os: [ubuntu-latest, windows-latest, macos-latest] ida_sdk: [74, 77, 80, 81, 82, 83, 84] + bitness: ['', '-32'] include: - os: windows-latest ext: dll - os: ubuntu-latest ext: so + - os: macos-latest + ext: dylib + exclude: + - os: macos-latest + ida_sdk: 74 + steps: - name: Download Artefact uses: actions/download-artifact@v4 with: - name: idaplugin-${{ matrix.os }}-${{ matrix.ida_sdk }} + name: idaplugin-${{ matrix.os }}-${{ matrix.ida_sdk }}${{ matrix.bitness }} - name: Release uses: softprops/action-gh-release@v2.2.1 diff --git a/CMakeLists.txt b/CMakeLists.txt index fce274fa..5a17ac0b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,6 +8,8 @@ if (CCACHE_PROGRAM) set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}") endif () +set(CMAKE_OSX_DEPLOYMENT_TARGET "11.0" CACHE STRING "Targeting MacOS Version" FORCE) + project(quokka DESCRIPTION "Quokka: A Fast and Accurate Binary Exporter" VERSION 0.5.8 @@ -16,7 +18,7 @@ project(quokka list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) include(FetchContent) -include(CMakePrintHelpers) +include(CheckLinkerFlag) include(GoogleTest) if (PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR) @@ -41,6 +43,28 @@ option(NO_BUILD "Don't build plugin" OFF) option(NO_DEPRECATED "Don't use deprecated functions from IDA SDK" OFF) option(ENABLE_SANITIZER "Enable address sanitizer" OFF) +if (UNIX) + if(APPLE) + add_compile_options( + -gfull + -Wno-nullability-completeness + ) + + # Originates from google/binexport + # https://github.com/google/binexport/blob/85c89a4ab96febcccc4cdc01ca5fc6c005e9a2cf/cmake/CompileOptions.cmake#L71-L74 + check_linker_flag(CXX "LINKER:-ld_classic" _ld_classic_supported) + if(_ld_classic_supported) + add_link_options(LINKER:-ld_classic) + endif() + + add_link_options( + -dead_strip + ) + else() + endif() +elseif(WIN32) +endif() + if (NOT NO_BUILD) if (ENABLE_SANITIZER) @@ -61,22 +85,16 @@ if (NOT NO_BUILD) FetchContent_Declare( protobuf GIT_REPOSITORY https://github.com/protocolbuffers/protobuf.git + SOURCE_SUBDIR cmake GIT_TAG v3.11.4 ) - - FetchContent_GetProperties(protobuf) - if (NOT protobuf_POPULATED) - FetchContent_Populate(protobuf) - - set(protobuf_BUILD_TESTS OFF CACHE BOOL "" FORCE) - set(protobuf_BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE) - set(protobuf_WITH_ZLIB_DEFAULT OFF CACHE BOOL "" FORCE) - set(protobuf_USE_STATIC_LIBS ON CACHE BOOL "" FORCE) - set(protobuf_MSVC_STATIC_RUNTIME OFF CACHE BOOL "" FORCE) - # Top level doesn't contain the CMakeLists.txt, it is in the "cmake" subdirectory - add_subdirectory(${protobuf_SOURCE_DIR}/cmake - ${protobuf_BINARY_DIR}) - endif () + set(protobuf_BUILD_TESTS OFF CACHE INTERNAL "") + set(protobuf_BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE) + set(protobuf_BUILD_EXPORT OFF) + set(protobuf_WITH_ZLIB_DEFAULT OFF CACHE BOOL "" FORCE) + set(protobuf_USE_STATIC_LIBS ON CACHE BOOL "" FORCE) + set(protobuf_MSVC_STATIC_RUNTIME OFF CACHE BOOL "" FORCE) + FetchContent_MakeAvailable(protobuf) # Find protoc set(_PROTOBUF_PROTOC $) diff --git a/ci/build.dockerfile b/ci/build.dockerfile index 4eef75f7..e40cb294 100644 --- a/ci/build.dockerfile +++ b/ci/build.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/library/debian:stable-slim +FROM --platform=linux/amd64 docker.io/library/debian:stable-slim RUN apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get install --yes --no-install-recommends \ diff --git a/cmake/FindIdaSdk.cmake b/cmake/FindIdaSdk.cmake index 4d3d9d7e..73214df0 100644 --- a/cmake/FindIdaSdk.cmake +++ b/cmake/FindIdaSdk.cmake @@ -1,10 +1,10 @@ -# Copyright 2011-2019 Google LLC. All Rights Reserved. +# Copyright 2011-2024 Google LLC # # 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 +# https://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, @@ -12,13 +12,14 @@ # See the License for the specific language governing permissions and # limitations under the License. +# THIS FILE ORIGINATES FROM google/binexport AND CAN BE FOUND +# https://raw.githubusercontent.com/google/binexport/11e8e699f43830c7cb3c391740bdbcc0f6514142/cmake/FindIdaSdk.cmake + + # FindIdaSdk # ---------- # -# This module is derived from FindIdaSdk.cmake from BinExport -# https://github.com/google/binexport/blob/main/cmake/FindIdaSdk.cmake -# -# Locates and configures the IDA Pro SDK. Only support version 7.0 or higher. +# Locates and configures the IDA Pro SDK. Supports version 7.0 or higher. # # Use this module by invoking find_package with the form: # @@ -31,130 +32,397 @@ # IdaSdk_INCLUDE_DIRS - Include directories for the IDA Pro SDK. # IdaSdk_PLATFORM - IDA SDK platform, one of __LINUX__, __NT__ or # __MAC__. -# IDA_ROOT_DIR - IDA Binary -# IdaSdk_LIB - Windows: path to ida.lib for 64-bit address sizes -# IdaSdk_LIB32 - Windows: full path to a suitable ida.lib for 32-bit -# address aware IDA. # # This module reads hints about search locations from variables: # -# IdaSdk_ROOT_DIR - SDK root dir -# Ida_BIN_DIR - IDA binary root dir +# IdaSdk_ROOT_DIR - Preferred installation prefix +# +# Example (this assumes Windows): +# +# find_package(IdaSdk REQUIRED) +# +# # Builds targets plugin.dll and plugin64.dll +# add_ida_plugin(plugin myplugin.cc) +# # Builds target plugin64.dll +# add_ida_plugin(plugin NOEA32 myplugin.cc) +# # Builds target plugin.dll +# add_ida_plugin(plugin NOEA64 myplugin.cc) +# +# Builds targets ldr.dll and ldr64.dll +# add_ida_loader(ldr myloader.cc) +# +# For platform-agnostic build files, the variables _so, and _so64 are +# available (and map to .dll, .so, .dylib as necessary): +# +# add_ida_plugin(plugin myplugin.cc) +# target_link_libraries(plugin${_so} ssl) +# target_link_libraries(plugin${_so64} ssl) +# +# To avoid the duplication above, these functions, which mimic the built-in +# ones, are also defined: +# +# add_ida_library( NOEA64|NOEA64 ...) <=> add_libary() +# ida_target_link_libraries(...) <=> target_link_libraries() +# ida_target_include_directories(...) <=> target_include_directories() +# set_ida_target_properties(...) <=> set_target_properties() +# ida_install(...) <=> install() include(CMakeParseArguments) include(FindPackageHandleStandardArgs) find_path(IdaSdk_DIR NAMES include/pro.h - HINTS ${IdaSdk_ROOT_DIR} ENV IDASDK_ROOT - PATHS ${CMAKE_CURRENT_LIST_DIR}/../third_party/idasdk - DOC "Location of the IDA SDK" - NO_DEFAULT_PATH) -set(IdaSdk_INCLUDE_DIRS ${IdaSdk_DIR}/include) -set(IdaSdk_MODULE_DIRS ${IdaSdk_DIR}/module) - -find_package_handle_standard_args( - IdaSdk FOUND_VAR IdaSdk_FOUND - REQUIRED_VARS IdaSdk_DIR - IdaSdk_INCLUDE_DIRS - FAIL_MESSAGE "IDA SDK not found, try setting IdaSdk_ROOT_DIR") - -find_path(IDA_ROOT_DIR - NAMES appico.png appico64.png - PATHS /opt/ida/ - HINTS ${Ida_BIN_DIR} ENV IDA_BIN - DOC "Location of IDA root dir") - -if (NOT IDA_ROOT_DIR) - message(STATUS "Did not find IDA binary. Try to set Ida_BIN_DIR or env variable IDA_BIN") -else () - message(STATUS "Found IDA binary in ${IDA_ROOT_DIR}") -endif () - -if (UNIX) - set(IdaLib ${IdaSdk_DIR}/lib/x64_linux_gcc_64/libida64.so) - if (APPLE) - set(IdaSdk_PLATFORM __MAC__) - else () - set(IdaSdk_PLATFORM __LINUX__) - endif () -elseif (WIN32) - set(IdaSdk_PLATFORM __NT__) - find_library(IdaSdk_LIB ida - PATHS ${IdaSdk_DIR}/lib - PATH_SUFFIXES x64_win_vc_64 - # IDA SDK 8.2 and later - x64_win_vc_64_teams - x64_win_vc_64_pro - x64_win_vc_64_home - NO_DEFAULT_PATH + HINTS "${IdaSdk_ROOT_DIR}" ENV IDASDK_ROOT + PATHS "${CMAKE_CURRENT_LIST_DIR}/../third_party/idasdk" + PATH_SUFFIXES idasdk + DOC "Location of the IDA SDK" + NO_DEFAULT_PATH) +set(IdaSdk_INCLUDE_DIRS "${IdaSdk_DIR}/include") + +find_package_handle_standard_args(IdaSdk + FOUND_VAR IdaSdk_FOUND + REQUIRED_VARS IdaSdk_DIR + IdaSdk_INCLUDE_DIRS + FAIL_MESSAGE "IDA SDK not found, try setting IdaSdk_ROOT_DIR" +) + +# Define some platform specific variables for later use. +set(_so "${CMAKE_SHARED_LIBRARY_SUFFIX}") +set(_so64 "64${CMAKE_SHARED_LIBRARY_SUFFIX}") # An additional "64" +# _plx, _plx64, _llx, _llx64 are kept to stay compatible with older +# CMakeLists.txt files. +set(_plx "${CMAKE_SHARED_LIBRARY_SUFFIX}") +set(_plx64 "64${CMAKE_SHARED_LIBRARY_SUFFIX}") # An additional "64" +set(_llx "${CMAKE_SHARED_LIBRARY_SUFFIX}") +set(_llx64 "64${CMAKE_SHARED_LIBRARY_SUFFIX}") # An additional "64" + +function(_ida_get_libpath_suffixes var basename) + # IDA SDK 8.3 introduced lib path suffixes per edition + foreach(_suffix IN ITEMS "" "_teams" "_pro" "_home") + list(APPEND _suffixes "${basename}${_suffix}") + endforeach() + set("${var}" "${_suffixes}" PARENT_SCOPE) +endfunction() + +if(APPLE) + set(IdaSdk_PLATFORM __MAC__) + + # Not using find_library(), as static-lib search might be enforced in + # calling project. + _ida_get_libpath_suffixes(_ida64_x64_suffixes "x64_mac_clang_64") + find_path(IdaSdk_LIBPATH64_X64 libida64.dylib + PATHS "${IdaSdk_DIR}/lib" PATH_SUFFIXES ${_ida64_x64_suffixes} + NO_DEFAULT_PATH REQUIRED + ) + _ida_get_libpath_suffixes(_ida64_arm64_suffixes "arm64_mac_clang_64") + find_path(IdaSdk_LIBPATH64_ARM64 libida64.dylib + PATHS "${IdaSdk_DIR}/lib" PATH_SUFFIXES ${_ida64_arm64_suffixes} + NO_DEFAULT_PATH REQUIRED + ) + if(NOT TARGET ida64_universal) + set(_ida64_universal_lib + "${CMAKE_CURRENT_BINARY_DIR}/libida64_universal.dylib" + CACHE INTERNAL "" ) - find_library(IdaSdk_LIB32 ida - PATHS ${IdaSdk_DIR}/lib - PATH_SUFFIXES x64_win_vc_32 - # IDA SDK 8.2 and later - x64_win_vc_32_teams - x64_win_vc_32_pro - x64_win_vc_32_home - NO_DEFAULT_PATH + # Create a new "universal" library to allow the linker to select the + # correct one per architecture. Ideally, Hex Rays would just compile + # libida64.dylib as a universal bundle. + add_custom_target(ida64_universal + DEPENDS "${IdaSdk_LIBPATH64_ARM64}/libida64.dylib" + "${IdaSdk_LIBPATH64_X64}/libida64.dylib" + BYPRODUCTS "${_ida64_universal_lib}" + COMMAND lipo -create "${IdaSdk_LIBPATH64_ARM64}/libida64.dylib" + "${IdaSdk_LIBPATH64_X64}/libida64.dylib" + -output "${_ida64_universal_lib}" ) - if(NOT IdaSdk_LIB OR NOT IdaSdk_LIB32) - message(FATAL_ERROR "Missing ida.lib from SDK lib dir") - endif() - set(IdaLib ${IdaSdk_LIB}) -else () - message(FATAL_ERROR "Unsupported system type: ${CMAKE_SYSTEM_NAME}") -endif () - -function(ida_common_target_settings t) - # Add the necessary __IDP__ define and allow to use "dangerous" and standard - # file functions. - target_compile_definitions(${t} PUBLIC - ${IdaSdk_PLATFORM} __X64__ __IDP__ USE_DANGEROUS_FUNCTIONS - USE_STANDARD_FILE_FUNCTIONS __EA64__) - - target_include_directories(${t} PUBLIC ${IdaSdk_INCLUDE_DIRS}) + endif() + add_library(ida64 SHARED IMPORTED) + add_dependencies(ida64 ida64_universal) + set_target_properties(ida64 PROPERTIES + IMPORTED_LOCATION "${_ida64_universal_lib}" + ) + + _ida_get_libpath_suffixes(_ida32_x64_suffixes "x64_mac_clang_32") + find_path(IdaSdk_LIBPATH32_X64 libida.dylib + PATHS "${IdaSdk_DIR}/lib" PATH_SUFFIXES ${_ida32_x64_suffixes} + NO_DEFAULT_PATH REQUIRED + ) + _ida_get_libpath_suffixes(_ida32_arm64_suffixes "arm64_mac_clang_32") + find_path(IdaSdk_LIBPATH32_ARM64 libida.dylib + PATHS "${IdaSdk_DIR}/lib" PATH_SUFFIXES ${_ida32_arm64_suffixes} + NO_DEFAULT_PATH REQUIRED + ) + if(NOT TARGET ida32_universal) + set(_ida32_universal_lib + "${CMAKE_CURRENT_BINARY_DIR}/libida32_universal.dylib" + CACHE INTERNAL "" + ) + add_custom_target(ida32_universal + DEPENDS "${IdaSdk_LIBPATH32_ARM64}/libida.dylib" + "${IdaSdk_LIBPATH32_X64}/libida.dylib" + BYPRODUCTS "${_ida32_universal_lib}" + COMMAND lipo -create "${IdaSdk_LIBPATH32_ARM64}/libida.dylib" + "${IdaSdk_LIBPATH32_X64}/libida.dylib" + -output "${_ida32_universal_lib}" + ) + endif() + add_library(ida32 SHARED IMPORTED) + add_dependencies(ida32 ida32_universal) + set_target_properties(ida32 PROPERTIES + IMPORTED_LOCATION "${_ida32_universal_lib}" + ) +elseif(UNIX) + set(IdaSdk_PLATFORM __LINUX__) + + _ida_get_libpath_suffixes(_ida64_suffixes "x64_linux_gcc_64") + find_path(IdaSdk_LIBPATH64 libida64.so + PATHS "${IdaSdk_DIR}/lib" PATH_SUFFIXES ${_ida64_suffixes} + NO_DEFAULT_PATH REQUIRED + ) + add_library(ida64 SHARED IMPORTED) + set_target_properties(ida64 PROPERTIES + IMPORTED_LOCATION "${IdaSdk_LIBPATH64}/libida64.so" + ) + + _ida_get_libpath_suffixes(_ida32_suffixes "x64_linux_gcc_32") + find_path(IdaSdk_LIBPATH32 libida.so + PATHS "${IdaSdk_DIR}/lib" PATH_SUFFIXES ${_ida32_suffixes} + NO_DEFAULT_PATH REQUIRED + ) + add_library(ida32 SHARED IMPORTED) + set_target_properties(ida32 PROPERTIES + IMPORTED_LOCATION "${IdaSdk_LIBPATH32}/libida.so" + ) +elseif(WIN32) + set(IdaSdk_PLATFORM __NT__) + + _ida_get_libpath_suffixes(_ida64_suffixes "x64_win_vc_64") + find_library(IdaSdk_LIB64 ida + PATHS "${IdaSdk_DIR}/lib" PATH_SUFFIXES ${_ida64_suffixes} + NO_DEFAULT_PATH REQUIRED + ) + add_library(ida64 SHARED IMPORTED) + set_target_properties(ida64 PROPERTIES IMPORTED_LOCATION "${IdaSdk_LIB64}") + set_target_properties(ida64 PROPERTIES IMPORTED_IMPLIB "${IdaSdk_LIB64}") + + _ida_get_libpath_suffixes(_ida32_suffixes "x64_win_vc_32") + find_library(IdaSdk_LIB32 ida + PATHS "${IdaSdk_DIR}/lib" PATH_SUFFIXES ${_ida32_suffixes} + NO_DEFAULT_PATH REQUIRED + ) + add_library(ida32 SHARED IMPORTED) + set_target_properties(ida32 PROPERTIES IMPORTED_LOCATION "${IdaSdk_LIB32}") + set_target_properties(ida32 PROPERTIES IMPORTED_IMPLIB "${IdaSdk_LIB32}") +else() + message(FATAL_ERROR "Unsupported system type: ${CMAKE_SYSTEM_NAME}") +endif() + +function(_ida_common_target_settings t ea64) + if(ea64) # Support for 64-bit addresses. + target_compile_definitions(${t} PUBLIC __EA64__) + endif() + # Add the necessary __IDP__ define and allow to use "dangerous" and standard + # file functions. + target_compile_definitions(${t} PUBLIC ${IdaSdk_PLATFORM} + __X64__ + __IDP__ + USE_DANGEROUS_FUNCTIONS + USE_STANDARD_FILE_FUNCTIONS) + target_include_directories(${t} PUBLIC "${IdaSdk_INCLUDE_DIRS}") endfunction() -function(_ida_plugin name link_script) # ARGN contains sources - # Define a module with the specified sources. - add_library(${name} MODULE ${ARGN}) - ida_common_target_settings(${name}) - - # Rename the plugin to have the proper naming scheme for IDA - set_target_properties(${name} PROPERTIES - PREFIX "" - OUTPUT_NAME ${name}${PROJECT_VERSION_MAJOR}${PROJECT_VERSION_MINOR}64) - - if (UNIX) - if (APPLE) - target_link_libraries(${name} - -Wl,-flat_namespace - -Wl,-undefined,warning - -Wl,-exported_symbol,_PLUGIN) - else () - # Always use the linker script needed for IDA. - target_link_libraries(${name} - -Wl,--version-script ${IdaSdk_DIR}/${link_script}) - endif () - - # For qrefcnt_obj_t in ida.hpp - # TODO(cblichmann): This belongs in an interface library instead. - target_compile_options(${name} PUBLIC -Wno-non-virtual-dtor) - elseif (WIN32) - target_link_libraries(${name} ${IdaSdk_LIB}) - endif () +macro(_ida_check_bitness) + if(opt_NOEA32 AND opt_NOEA64) + message(FATAL_ERROR "NOEA32 and NOEA64 cannot be used at the same time") + endif() +endmacro() + +function(_ida_library name ea64) + if(ea64) + set(t ${name}_ea64) + else() + set(t ${name}_ea32) + endif() + + # Define the actual library. + add_library(${t} ${ARGN}) + _ida_common_target_settings(${t} ${ea64}) +endfunction() + +function(_ida_plugin name ea64 link_script) # ARGN contains sources + if(ea64) + set(t ${name}${_so64}) + else() + set(t ${name}${_so}) + endif() + + # Define a module with the specified sources. + add_library(${t} MODULE ${ARGN}) + _ida_common_target_settings(${t} ${ea64}) + + set_target_properties(${t} PROPERTIES PREFIX "" SUFFIX "") + if(ea64) + target_link_libraries(${t} ida64) + else() + target_link_libraries(${t} ida32) + endif() + if(UNIX) + if(APPLE) + target_link_libraries(${t} + -Wl,-flat_namespace + -Wl,-exported_symbol,_PLUGIN + ) + else() + # Always use the linker script needed for IDA. + target_link_libraries(${t} + -Wl,--version-script "${IdaSdk_DIR}/${link_script}") + endif() + + # For qrefcnt_obj_t in ida.hpp + # TODO(cblichmann): This belongs in an interface library instead. + target_compile_options(${t} PUBLIC + -Wno-non-virtual-dtor + -Wno-varargs + ) + endif() endfunction() function(add_ida_library name) - # Define the actual library. - add_library(${name} ${ARGN}) - ida_common_target_settings(${name}) + cmake_parse_arguments(PARSE_ARGV 1 opt "NOEA32;NOEA64" "" "") + _ida_check_bitness(opt_NOEA32 opt_NOEA64) + + if(NOT DEFINED(opt_NOEA32)) + _ida_library(${name} FALSE ${opt_UNPARSED_ARGUMENTS}) + endif() + if(NOT DEFINED(opt_NOEA64)) + _ida_library(${name} TRUE ${opt_UNPARSED_ARGUMENTS}) + endif() +endfunction() + +function(ida_add_dependencies name) + add_dependencies(ida32 ida32_universal) + + cmake_parse_arguments(PARSE_ARGV 1 opt "NOEA32;NOEA64" "" "") + _ida_check_bitness(opt_NOEA32 opt_NOEA64) + + foreach(target ${name}${_so} ${name}${_so64} + {name}_ea32 ${name}_ea64) + + if(TARGET ${target}) + add_dependencies(${target} ${ARGN}) + set(added TRUE) + endif() + endforeach() + + if (NOT added) + message(FATAL_ERROR "No such target: ${name}") + endif() endfunction() function(add_ida_plugin name) - _ida_plugin(${name} plugins/exports.def ${ARGN}) + cmake_parse_arguments(PARSE_ARGV 1 opt "NOEA32;NOEA64" "" "") + _ida_check_bitness(opt_NOEA32 opt_NOEA64) + + if(NOT opt_NOEA32) + _ida_plugin(${name} FALSE plugins/exports.def ${opt_UNPARSED_ARGUMENTS}) + endif() + if(NOT opt_NOEA64) + _ida_plugin(${name} TRUE plugins/exports.def ${opt_UNPARSED_ARGUMENTS}) + endif() endfunction() function(add_ida_loader name) - _ida_plugin(${name} ldr/exports.def ${ARGN}) + cmake_parse_arguments(PARSE_ARGV 1 opt "NOEA32;NOEA64" "" "") + _ida_check_bitness(opt_NOEA32 opt_NOEA64) + + if(NOT opt_NOEA32) + _ida_plugin(${name} FALSE ldr/exports.def ${opt_UNPARSED_ARGUMENTS}) + endif() + if(NOT opt_NOEA64) + _ida_plugin(${name} TRUE ldr/exports.def ${opt_UNPARSED_ARGUMENTS}) + endif() endfunction() + +function(ida_target_link_libraries name) + foreach(item IN LISTS ARGN) + if(TARGET ${item}_ea32 OR TARGET ${item}_ea64) + if(TARGET ${item}_ea32) + list(APPEND args32 ${item}_ea32) + endif() + if(TARGET ${item}_ea64) + list(APPEND args64 ${item}_ea64) + endif() + else() + list(APPEND args ${item}) + endif() + endforeach() + foreach(target ${name}${_so} ${name}_ea32) + if(TARGET ${target}) + target_link_libraries(${target} ${args32} ${args}) + set(added TRUE) + endif() + endforeach() + foreach(target ${name}${_so64} ${name}_ea64) + if(TARGET ${target}) + target_link_libraries(${target} ${args64} ${args}) + set(added TRUE) + endif() + endforeach() + if (NOT added) + message(FATAL_ERROR "No such target: ${name}") + endif() +endfunction() + +function(ida_target_include_directories name) + foreach(target ${name}${_so} ${name}${_so64} + ${name}_ea32 ${name}_ea64) + if(TARGET ${target}) + target_include_directories(${target} ${ARGN}) + set(added TRUE) + endif() + endforeach() + if (NOT added) + message(FATAL_ERROR "No such target: ${name}") + endif() +endfunction() + +function(set_ida_target_properties name) + foreach(target ${name}${_so} ${name}${_so64} + ${name}_ea32 ${name}_ea64) + if(TARGET ${target}) + set_target_properties(${target} ${ARGN}) + set(added TRUE) + endif() + endforeach() + if (NOT added) + message(FATAL_ERROR "No such target: ${name}") + endif() +endfunction() + +function(ida_target_sources name) + foreach(target ${name}${_so} ${name}${_so64} + ${name}_ea32 ${name}_ea64) + if(TARGET ${target}) + target_sources(${target} ${ARGN}) + set(added TRUE) + endif() + endforeach() + if (NOT added) + message(FATAL_ERROR "No such target: ${name}") + endif() +endfunction() + +function(ida_install) + foreach(item IN LISTS ARGN) + if(TARGET ${item}${_so} OR TARGET ${item}${_so64}) + if(TARGET ${item}${_so}) + list(APPEND args ${item}${_so}) + endif() + if(TARGET ${item}${_so64}) + list(APPEND args ${item}${_so64}) + endif() + else() + list(APPEND args ${item}) + endif() + endforeach() + install(${args}) +endfunction() \ No newline at end of file diff --git a/proto/CMakeLists.txt b/proto/CMakeLists.txt index efe8ea71..22fe4817 100644 --- a/proto/CMakeLists.txt +++ b/proto/CMakeLists.txt @@ -1,18 +1,15 @@ include_guard() -get_filename_component(hw_proto "quokka.proto" ABSOLUTE) +set(PROTO_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}") -protobuf_generate_python(PROTO_PY "${hw_proto}") -protobuf_generate_cpp(PROTO_SRC PROTO_HDRS "${hw_proto}") +add_library(quokka_proto OBJECT "${CMAKE_CURRENT_LIST_DIR}/quokka.proto") -add_custom_target(quokka_python ALL - DEPENDS "${PROTO_PY}") +protobuf_generate( + TARGET quokka_proto + LANGUAGE cpp) -add_custom_target(quokka_proto - DEPENDS ${PROTO_SRC} ${PROTO_HDRS}) +target_link_libraries(quokka_proto PUBLIC protobuf::libprotobuf) -set_target_properties(quokka_proto PROPERTIES - GENERATED_FILES "${PROTO_SRC};${PROTO_HDRS}") - -set_target_properties(quokka_python PROPERTIES - GENERATED_FILES ${PROTO_PY}) \ No newline at end of file +protobuf_generate( + TARGET quokka_proto + LANGUAGE python) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6aa10949..2704e2e6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -14,7 +14,7 @@ if (NO_DEPRECATED) add_compile_definitions(NO_OBSOLETE_FUNCS) endif () -add_library(quokka_shared STATIC +add_ida_library(quokka_shared STATIC "Block.cpp" "Comment.cpp" "Data.cpp" @@ -26,21 +26,16 @@ add_library(quokka_shared STATIC "Reference.cpp" "Segment.cpp" "Util.cpp" - "Writer.cpp" - "${quokka_BINARY_DIR}/proto/quokka.pb.cc") + "Writer.cpp") -protobuf_set_generated(quokka_proto) +ida_target_include_directories(quokka_shared + PRIVATE "${quokka_SOURCE_DIR}/include" + "${quokka_BINARY_DIR}/proto" +) -add_dependencies(quokka_shared quokka_proto) - -target_include_directories(quokka_shared PRIVATE - "${quokka_SOURCE_DIR}/include" - "${quokka_BINARY_DIR}/proto") - -ida_common_target_settings(quokka_shared) - -target_link_libraries(quokka_shared PUBLIC +ida_target_link_libraries(quokka_shared PUBLIC quokka_version + quokka_proto protobuf::libprotobuf absl::strings absl::str_format @@ -51,44 +46,33 @@ target_link_libraries(quokka_shared PUBLIC add_ida_plugin(quokka_plugin "Quokka.cpp") -target_include_directories(quokka_plugin - PUBLIC "${quokka_SOURCE_DIR}/include" - "${quokka_BINARY_DIR}/proto") - -set_target_properties(quokka_plugin - PROPERTIES POSITION_INDEPENDENT_CODE ON) - -if (NOT ${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC) - target_link_libraries( - quokka_plugin - quokka_shared - absl::strings - absl::str_format - stdc++fs - protobuf::libprotobuf - ) -else () - target_link_libraries( - quokka_plugin - quokka_shared - absl::strings - absl::str_format - protobuf::libprotobuf - ) -endif () +ida_target_include_directories(quokka_plugin + PRIVATE "${quokka_SOURCE_DIR}/include" + "${quokka_BINARY_DIR}/proto" +) +set_ida_target_properties(quokka_plugin + PROPERTIES POSITION_INDEPENDENT_CODE ON) + +ida_target_link_libraries( + quokka_plugin + quokka_shared + absl::strings + absl::str_format + protobuf::libprotobuf +) -install(TARGETS quokka_plugin +ida_install(TARGETS quokka_plugin LIBRARY DESTINATION $ENV{HOME}/.idapro/plugins) if (IDA_ROOT_DIR) - install(TARGETS quokka_plugin + ida_install(TARGETS quokka_plugin LIBRARY DESTINATION ${IDA_ROOT_DIR}/plugins) endif () -install(TARGETS quokka_plugin +ida_install(TARGETS quokka_plugin ARCHIVE DESTINATION quokka-install RUNTIME DESTINATION quokka-install LIBRARY DESTINATION quokka-install) \ No newline at end of file