From da7caae8023f4e43757a3afe8251816865a82c8f Mon Sep 17 00:00:00 2001 From: AkshayK Date: Mon, 26 Aug 2024 17:19:23 -0400 Subject: [PATCH 01/12] test: Refactor decompilation script testing framework and use lit runner. --- scripts/ghidra/README.md | 34 +---------- scripts/ghidra/decompile-headless-test.sh | 18 ------ scripts/ghidra/decompile-headless.sh | 17 +++--- scripts/ghidra/test/CMakeLists.txt | 32 ---------- scripts/ghidra/test/run-test.sh | 19 ------ scripts/ghidra/test/src/argc.c | 8 --- scripts/ghidra/test/src/argc.function | 1 - scripts/ghidra/test/src/array.function | 1 - scripts/ghidra/test/src/concat.function | 1 - scripts/ghidra/test/src/fib.c | 14 ----- scripts/ghidra/test/src/fib.function | 1 - scripts/ghidra/test/src/fread.function | 1 - scripts/ghidra/test/src/fwrite.function | 1 - scripts/ghidra/test/src/insert.function | 1 - scripts/ghidra/test/src/list.function | 1 - scripts/ghidra/test/src/matrix.function | 1 - scripts/ghidra/test/src/prime.function | 1 - scripts/ghidra/test/src/queue.function | 1 - scripts/ghidra/test/src/reverse.function | 1 - scripts/ghidra/test/src/sort.function | 1 - scripts/ghidra/test/src/struct.c | 15 ----- scripts/ghidra/test/src/struct.function | 1 - scripts/ghidra/test/src/structb.c | 19 ------ scripts/ghidra/test/src/structb.function | 1 - scripts/ghidra/test/src/sub.c | 7 --- scripts/ghidra/test/src/sub.function | 1 - scripts/ghidra/test/src/union.c | 19 ------ scripts/ghidra/test/src/union.function | 1 - test/CMakeLists.txt | 33 +++++++++-- test/ghidra.cpp | 8 --- test/ghidra/argc.c | 14 +++++ .../ghidra/test/src => test/ghidra}/array.c | 7 +++ .../ghidra/test/src => test/ghidra}/concat.c | 8 ++- test/ghidra/fib.c | 20 +++++++ .../ghidra/test/src => test/ghidra}/fread.c | 8 ++- .../ghidra/test/src => test/ghidra}/fwrite.c | 8 ++- .../ghidra/test/src => test/ghidra}/insert.c | 8 ++- .../ghidra/test/src => test/ghidra}/list.c | 8 ++- .../ghidra/test/src => test/ghidra}/matrix.c | 9 ++- .../ghidra/test/src => test/ghidra}/prime.c | 8 ++- .../ghidra/test/src => test/ghidra}/queue.c | 8 ++- .../ghidra/test/src => test/ghidra}/reverse.c | 10 +++- .../ghidra/test/src => test/ghidra}/sort.c | 6 ++ test/ghidra/struct.c | 21 +++++++ test/ghidra/structb.c | 26 ++++++++ test/ghidra/sub.c | 13 ++++ test/ghidra/test.c | 13 ++++ test/ghidra/union.c | 25 ++++++++ test/lit.cfg.py | 59 +++++++++++++++++++ test/lit.site.cfg.py.in | 40 +++++++++++++ 50 files changed, 347 insertions(+), 232 deletions(-) delete mode 100644 scripts/ghidra/decompile-headless-test.sh delete mode 100644 scripts/ghidra/test/CMakeLists.txt delete mode 100755 scripts/ghidra/test/run-test.sh delete mode 100644 scripts/ghidra/test/src/argc.c delete mode 100644 scripts/ghidra/test/src/argc.function delete mode 100644 scripts/ghidra/test/src/array.function delete mode 100644 scripts/ghidra/test/src/concat.function delete mode 100644 scripts/ghidra/test/src/fib.c delete mode 100644 scripts/ghidra/test/src/fib.function delete mode 100644 scripts/ghidra/test/src/fread.function delete mode 100644 scripts/ghidra/test/src/fwrite.function delete mode 100644 scripts/ghidra/test/src/insert.function delete mode 100644 scripts/ghidra/test/src/list.function delete mode 100644 scripts/ghidra/test/src/matrix.function delete mode 100644 scripts/ghidra/test/src/prime.function delete mode 100644 scripts/ghidra/test/src/queue.function delete mode 100644 scripts/ghidra/test/src/reverse.function delete mode 100644 scripts/ghidra/test/src/sort.function delete mode 100644 scripts/ghidra/test/src/struct.c delete mode 100644 scripts/ghidra/test/src/struct.function delete mode 100644 scripts/ghidra/test/src/structb.c delete mode 100644 scripts/ghidra/test/src/structb.function delete mode 100644 scripts/ghidra/test/src/sub.c delete mode 100644 scripts/ghidra/test/src/sub.function delete mode 100644 scripts/ghidra/test/src/union.c delete mode 100644 scripts/ghidra/test/src/union.function delete mode 100644 test/ghidra.cpp create mode 100644 test/ghidra/argc.c rename {scripts/ghidra/test/src => test/ghidra}/array.c (54%) rename {scripts/ghidra/test/src => test/ghidra}/concat.c (50%) create mode 100644 test/ghidra/fib.c rename {scripts/ghidra/test/src => test/ghidra}/fread.c (50%) rename {scripts/ghidra/test/src => test/ghidra}/fwrite.c (58%) rename {scripts/ghidra/test/src => test/ghidra}/insert.c (60%) rename {scripts/ghidra/test/src => test/ghidra}/list.c (74%) rename {scripts/ghidra/test/src => test/ghidra}/matrix.c (73%) rename {scripts/ghidra/test/src => test/ghidra}/prime.c (52%) rename {scripts/ghidra/test/src => test/ghidra}/queue.c (78%) rename {scripts/ghidra/test/src => test/ghidra}/reverse.c (57%) rename {scripts/ghidra/test/src => test/ghidra}/sort.c (63%) create mode 100644 test/ghidra/struct.c create mode 100644 test/ghidra/structb.c create mode 100644 test/ghidra/sub.c create mode 100644 test/ghidra/test.c create mode 100644 test/ghidra/union.c create mode 100644 test/lit.cfg.py create mode 100644 test/lit.site.cfg.py.in diff --git a/scripts/ghidra/README.md b/scripts/ghidra/README.md index 0007a64..88d67af 100644 --- a/scripts/ghidra/README.md +++ b/scripts/ghidra/README.md @@ -1,10 +1,6 @@ -# Decompilation and Testing Framework +# Decompilation Framework -The directory includes a decompilation script that runs Ghidra in headless mode -to extract pcode for specific functions from binary files. It also features a -testing framework that compiles the source files, generates the corresponding -pcode for the specified function, and validates the output using the FileCheck -verifier. +The directory includes a decompilation script that runs Ghidra in headless mode to extract pcode for specific functions from binary files. We support two decompilation modes: @@ -16,12 +12,8 @@ We support two decompilation modes: Before running the scripts, make sure you have the following installed: - **Docker**: The scripts use a Docker container to run Ghidra in headless mode. -- **FileCheck**: The `FileCheck` tool is installed and available in your PATH. It is typically part of LLVM suite. - -## Usage - -### Run Headless Decompilation Script +## Running Headless Decompilation Script To decompile and extract pcode for a specific function from a binary file, use the `decompile-headless.sh` script. This script extracts the pcode for the @@ -30,26 +22,6 @@ in the output directory. ```bash ./decompile-headless.sh ``` -### Testing the Output - -#### Using Test Script - -You can run all the tests using `decompile-headless-test.sh` script: - -``` -./decompile-headless-test.sh -``` - -#### Testing with CMake - -Alternatively, you can use CMake to configure, build, and run the tests. - -``` -cmake -B /path/to/build -S /path/to/test -cmake --build /path/to/build -ctest --test-dir /path/to/build -``` - ## Running Patchestry via Ghidra GUI 1. Ensure Patchestry is available via PATH: diff --git a/scripts/ghidra/decompile-headless-test.sh b/scripts/ghidra/decompile-headless-test.sh deleted file mode 100644 index 329c91d..0000000 --- a/scripts/ghidra/decompile-headless-test.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2024, Trail of Bits, Inc. -# All rights reserved. -# -# This source code is licensed in accordance with the terms specified in -# the LICENSE file found in the root directory of this source tree. -# -SCRIPTS_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) -CMAKE_ARGS= - -if [[ ! -d "${SCRIPTS_DIR}/test" ]]; then - echo "No tests found!!!" && exit 1 -fi - -cmake ${CMAKE_ARGS} -B ${SCRIPTS_DIR}/build -S ${SCRIPTS_DIR}/test -cmake --build ${SCRIPTS_DIR}/build -ctest --output-on-failure --test-dir ${SCRIPTS_DIR}/build diff --git a/scripts/ghidra/decompile-headless.sh b/scripts/ghidra/decompile-headless.sh index c91c7a4..a64777d 100755 --- a/scripts/ghidra/decompile-headless.sh +++ b/scripts/ghidra/decompile-headless.sh @@ -16,7 +16,6 @@ fi INPUT_PATH=$1 FUNCTION_NAME=$2 OUTPUT_PATH=$3 -TMP_OUTPUT_PATH="/tmp/patchestry.out.json" # Create docker container and run the decompilation docker build \ @@ -29,15 +28,15 @@ if [ $? -ne 0 ]; then exit 1 fi -# Make sure $TMP_OUTPUT_PATH exists so that it gets properly mounted -touch $TMP_OUTPUT_PATH +# Make sure $OUTPUT_PATH exists and is empty so that it can be +# mounted to the container +if [ ! -f $OUTPUT_PATH ]; then + touch $OUTPUT_PATH +fi +truncate -s 0 $OUTPUT_PATH docker run --rm \ -v $INPUT_PATH:/input \ - -v $TMP_OUTPUT_PATH:/output \ + -v $OUTPUT_PATH:/output \ trailofbits/patchestry-decompilation:latest \ - /input $FUNCTION_NAME /output - -if [ $(dirname $TMP_OUTPUT_PATH) != $OUTPUT_PATH ]; then - mv $TMP_OUTPUT_PATH $OUTPUT_PATH -fi + /input $FUNCTION_NAME /output \ No newline at end of file diff --git a/scripts/ghidra/test/CMakeLists.txt b/scripts/ghidra/test/CMakeLists.txt deleted file mode 100644 index b5b6867..0000000 --- a/scripts/ghidra/test/CMakeLists.txt +++ /dev/null @@ -1,32 +0,0 @@ -cmake_minimum_required(VERSION 3.25) - -include(CTest) - -SET(CMAKE_BUILD_TYPE Debug) -SET(CMAKE_CXX_FLAGS_DEBUG "-g") - -file(GLOB_RECURSE SOURCES "${CMAKE_SOURCE_DIR}/src/*.c") - -function(get_function_name filename function) - file(READ "${filename}" content) - string(FIND "${file_content}" "\n" newline) - - # Extract the first line - if(newline GREATER -1) - string(SUBSTRING "${content}" 0 "${newline}" first_line) - else() - set(first_line "${content}") - endif() - set(${function} "${first_line}" PARENT_SCOPE) -endfunction() - -# Iterate over each source file and compile them -foreach(SOURCE_FILE ${SOURCES}) - get_filename_component(BINARY_NAME ${SOURCE_FILE} NAME_WE) - add_executable(${BINARY_NAME} ${SOURCE_FILE}) - - get_function_name("${CMAKE_SOURCE_DIR}/src/${BINARY_NAME}.function" FUNCTION) - add_test(NAME ${BINARY_NAME}Test - COMMAND ${CMAKE_SOURCE_DIR}/run-test.sh ${CMAKE_CURRENT_BINARY_DIR}/${BINARY_NAME} ${FUNCTION} ${SOURCE_FILE} - ) -endforeach() diff --git a/scripts/ghidra/test/run-test.sh b/scripts/ghidra/test/run-test.sh deleted file mode 100755 index 9add14e..0000000 --- a/scripts/ghidra/test/run-test.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2024, Trail of Bits, Inc. -# All rights reserved. -# -# This source code is licensed in accordance with the terms specified in -# the LICENSE file found in the root directory of this source tree. -# -set -e -SCRIPTS_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) - -INPUT_FILE=$1 -FUNCTION=$2 -PATTERN_FILE=$3 -tmpdir=/tmp - -# It expects decompile-headless.sh will be in its parent directory. -${SCRIPTS_DIR}/../decompile-headless.sh ${INPUT_FILE} ${FUNCTION} ${tmpdir} -FileCheck ${PATTERN_FILE} --input-file ${tmpdir}/patchestry.out.json || exit 1 diff --git a/scripts/ghidra/test/src/argc.c b/scripts/ghidra/test/src/argc.c deleted file mode 100644 index 6a86094..0000000 --- a/scripts/ghidra/test/src/argc.c +++ /dev/null @@ -1,8 +0,0 @@ -// CHECK: {{...}} -int argc(int argc, char **argv) { - return argc; -} -int main(int a, char **argv) -{ - return argc(a, argv); -} diff --git a/scripts/ghidra/test/src/argc.function b/scripts/ghidra/test/src/argc.function deleted file mode 100644 index ba2906d..0000000 --- a/scripts/ghidra/test/src/argc.function +++ /dev/null @@ -1 +0,0 @@ -main diff --git a/scripts/ghidra/test/src/array.function b/scripts/ghidra/test/src/array.function deleted file mode 100644 index ba2906d..0000000 --- a/scripts/ghidra/test/src/array.function +++ /dev/null @@ -1 +0,0 @@ -main diff --git a/scripts/ghidra/test/src/concat.function b/scripts/ghidra/test/src/concat.function deleted file mode 100644 index c5e327f..0000000 --- a/scripts/ghidra/test/src/concat.function +++ /dev/null @@ -1 +0,0 @@ -string_concat diff --git a/scripts/ghidra/test/src/fib.c b/scripts/ghidra/test/src/fib.c deleted file mode 100644 index 47a041e..0000000 --- a/scripts/ghidra/test/src/fib.c +++ /dev/null @@ -1,14 +0,0 @@ -#include - -// CHECK: {{...}} -int fibonacci(int n) { - if (n <= 1) return n; - return fibonacci(n - 1) + fibonacci(n - 2); -} - -int main() { - int n = 10; - printf("%d: %d\n", n, fibonacci(n)); - return 0; -} - diff --git a/scripts/ghidra/test/src/fib.function b/scripts/ghidra/test/src/fib.function deleted file mode 100644 index 45c7e66..0000000 --- a/scripts/ghidra/test/src/fib.function +++ /dev/null @@ -1 +0,0 @@ -fibonacci diff --git a/scripts/ghidra/test/src/fread.function b/scripts/ghidra/test/src/fread.function deleted file mode 100644 index ba2906d..0000000 --- a/scripts/ghidra/test/src/fread.function +++ /dev/null @@ -1 +0,0 @@ -main diff --git a/scripts/ghidra/test/src/fwrite.function b/scripts/ghidra/test/src/fwrite.function deleted file mode 100644 index a57c15b..0000000 --- a/scripts/ghidra/test/src/fwrite.function +++ /dev/null @@ -1 +0,0 @@ -write_file diff --git a/scripts/ghidra/test/src/insert.function b/scripts/ghidra/test/src/insert.function deleted file mode 100644 index 73c6240..0000000 --- a/scripts/ghidra/test/src/insert.function +++ /dev/null @@ -1 +0,0 @@ -insert_substring diff --git a/scripts/ghidra/test/src/list.function b/scripts/ghidra/test/src/list.function deleted file mode 100644 index 138405c..0000000 --- a/scripts/ghidra/test/src/list.function +++ /dev/null @@ -1 +0,0 @@ -print_list diff --git a/scripts/ghidra/test/src/matrix.function b/scripts/ghidra/test/src/matrix.function deleted file mode 100644 index 0e2e4c8..0000000 --- a/scripts/ghidra/test/src/matrix.function +++ /dev/null @@ -1 +0,0 @@ -multiply_matrices diff --git a/scripts/ghidra/test/src/prime.function b/scripts/ghidra/test/src/prime.function deleted file mode 100644 index ce30acd..0000000 --- a/scripts/ghidra/test/src/prime.function +++ /dev/null @@ -1 +0,0 @@ -is_prime diff --git a/scripts/ghidra/test/src/queue.function b/scripts/ghidra/test/src/queue.function deleted file mode 100644 index 07ae589..0000000 --- a/scripts/ghidra/test/src/queue.function +++ /dev/null @@ -1 +0,0 @@ -dequeue diff --git a/scripts/ghidra/test/src/reverse.function b/scripts/ghidra/test/src/reverse.function deleted file mode 100644 index f569804..0000000 --- a/scripts/ghidra/test/src/reverse.function +++ /dev/null @@ -1 +0,0 @@ -reverse_string diff --git a/scripts/ghidra/test/src/sort.function b/scripts/ghidra/test/src/sort.function deleted file mode 100644 index ba2906d..0000000 --- a/scripts/ghidra/test/src/sort.function +++ /dev/null @@ -1 +0,0 @@ -main diff --git a/scripts/ghidra/test/src/struct.c b/scripts/ghidra/test/src/struct.c deleted file mode 100644 index 6f3c6ed..0000000 --- a/scripts/ghidra/test/src/struct.c +++ /dev/null @@ -1,15 +0,0 @@ -//CHECK: {{...}} -struct data -{ - int a; - int b; - int c; - int d; - int e; -}; - -int main(int argc, char **argv) -{ - struct data d = { 0, 1, 2, 3, 4 }; - return d.a + d.b + d.c + d.d + d.e; -} diff --git a/scripts/ghidra/test/src/struct.function b/scripts/ghidra/test/src/struct.function deleted file mode 100644 index ba2906d..0000000 --- a/scripts/ghidra/test/src/struct.function +++ /dev/null @@ -1 +0,0 @@ -main diff --git a/scripts/ghidra/test/src/structb.c b/scripts/ghidra/test/src/structb.c deleted file mode 100644 index 9a5039f..0000000 --- a/scripts/ghidra/test/src/structb.c +++ /dev/null @@ -1,19 +0,0 @@ -#include - -typedef struct { - char name[50]; - int age; -} Person; - -// CHECK: {{...}} -int main(void) { - Person p; - snprintf(p.name, sizeof(p.name), "John"); - p.age = 30; - - printf("Name: %s\n", p.name); - printf("Age: %d\n", p.age); - - return 0; -} - diff --git a/scripts/ghidra/test/src/structb.function b/scripts/ghidra/test/src/structb.function deleted file mode 100644 index ba2906d..0000000 --- a/scripts/ghidra/test/src/structb.function +++ /dev/null @@ -1 +0,0 @@ -main diff --git a/scripts/ghidra/test/src/sub.c b/scripts/ghidra/test/src/sub.c deleted file mode 100644 index 0c45bd5..0000000 --- a/scripts/ghidra/test/src/sub.c +++ /dev/null @@ -1,7 +0,0 @@ -// CHECK: {{...}} -int main() -{ - int x; - x = 4; - return x - 4; -} diff --git a/scripts/ghidra/test/src/sub.function b/scripts/ghidra/test/src/sub.function deleted file mode 100644 index ba2906d..0000000 --- a/scripts/ghidra/test/src/sub.function +++ /dev/null @@ -1 +0,0 @@ -main diff --git a/scripts/ghidra/test/src/union.c b/scripts/ghidra/test/src/union.c deleted file mode 100644 index 0198e11..0000000 --- a/scripts/ghidra/test/src/union.c +++ /dev/null @@ -1,19 +0,0 @@ -// CHECK: {{...}} -struct access -{ - int l; - int h; -}; - -union data -{ - unsigned long long b; - struct access s; -}; - -int main(int argc, char **argv) -{ - union data d; - d.b = 0xffffffff00000000 + argc; - return d.s.l; -} diff --git a/scripts/ghidra/test/src/union.function b/scripts/ghidra/test/src/union.function deleted file mode 100644 index ba2906d..0000000 --- a/scripts/ghidra/test/src/union.function +++ /dev/null @@ -1 +0,0 @@ -main diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 0a592d7..27e4a97 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,10 +1,31 @@ +# Copyright (c) 2024, Trail of Bits, Inc. All rights reserved. This source code +# is licensed in accordance with the terms specified in the LICENSE file found +# in the root directory of this source tree. + +cmake_minimum_required(VERSION 3.25) + include(CTest) -add_executable(patchestry_test ghidra.cpp) -target_link_libraries(patchestry_test - PRIVATE - patchestry_ghidra - patchestry_settings +# Configure the lit site configuration file +configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in + ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg.py + MAIN_CONFIG + ${CMAKE_CURRENT_SOURCE_DIR}/lit.cfg.py +) + +# Define test dependencies +set(TEST_DEPS + FileCheck +) + +# Add a lit test suite named "PatchestryTest" +add_lit_testsuite(PatchestryTest "Running Patchestry tests" + ${CMAKE_CURRENT_SOURCE_DIR}/ghidra + DEPENDS ${TEST_DEPS} ) -add_test(NAME patchestry_test COMMAND patchestry_test) +# Add a CTest test that runs the lit test suite +add_test(NAME lit + COMMAND lit -v "${CMAKE_CURRENT_BINARY_DIR}/ghidra" + --param BUILD_TYPE=$) \ No newline at end of file diff --git a/test/ghidra.cpp b/test/ghidra.cpp deleted file mode 100644 index 0024fa6..0000000 --- a/test/ghidra.cpp +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright (c) 2024, Trail of Bits, Inc. - * All rights reserved. - * - * This source code is licensed in accordance with the terms specified in - * the LICENSE file found in the root directory of this source tree. - */ -auto main() -> int { return 0; } diff --git a/test/ghidra/argc.c b/test/ghidra/argc.c new file mode 100644 index 0000000..af3ae6f --- /dev/null +++ b/test/ghidra/argc.c @@ -0,0 +1,14 @@ +// UNSUPPORTED: system-windows +// RUN: %cc %s -o %t +// RUN %t; if [ "$(uname)" = "Linux" ]; then %decompile-headless %t argc %t1 fi +// RUN %t; if [ "$(uname)" = "Darwin" ]; then %decompile-headless %t _argc %t1 fi +// RUN %t1; %file-check %s --input-file %t1 +// CHECK: {{...}} + +int argc(int argc, char **argv) { + return argc; +} +int main(int a, char **argv) +{ + return argc(a, argv); +} diff --git a/scripts/ghidra/test/src/array.c b/test/ghidra/array.c similarity index 54% rename from scripts/ghidra/test/src/array.c rename to test/ghidra/array.c index 0867e34..f24cd09 100644 --- a/scripts/ghidra/test/src/array.c +++ b/test/ghidra/array.c @@ -1,3 +1,10 @@ +// UNSUPPORTED: system-windows +// RUN: %cc %s -o %t +// RUN %t; if [ "$(uname)" = "Linux" ]; then %decompile-headless %t main %t1 fi +// RUN %t; if [ "$(uname)" = "Darwin" ]; then %decompile-headless %t _main %t1 fi +// RUN %t1; %file-check %s --input-file %t1 +// CHECK: {{...}} + #include #include diff --git a/scripts/ghidra/test/src/concat.c b/test/ghidra/concat.c similarity index 50% rename from scripts/ghidra/test/src/concat.c rename to test/ghidra/concat.c index 0b35029..dea1e2f 100644 --- a/scripts/ghidra/test/src/concat.c +++ b/test/ghidra/concat.c @@ -1,7 +1,13 @@ +// UNSUPPORTED: system-windows +// RUN: %cc %s -o %t +// RUN %t; if [ "$(uname)" = "Linux" ]; then %decompile-headless %t string_concat %t1 fi +// RUN %t; if [ "$(uname)" = "Darwin" ]; then %decompile-headless %t _string_concat %t1 fi +// RUN %t1; %file-check %s --input-file %t1 +// CHECK: {{...}} + #include #include -// CHECK: {{...}} char* string_concat(char* dest, const char* src) { strcat(dest, src); return dest; diff --git a/test/ghidra/fib.c b/test/ghidra/fib.c new file mode 100644 index 0000000..790df13 --- /dev/null +++ b/test/ghidra/fib.c @@ -0,0 +1,20 @@ +// UNSUPPORTED: system-windows +// RUN: %cc %s -o %t +// RUN %t; if [ "$(uname)" = "Linux" ]; then %decompile-headless %t fibonacci %t1 fi +// RUN %t; if [ "$(uname)" = "Darwin" ]; then %decompile-headless %t _fibonacci %t1 fi +// RUN %t1; %file-check %s --input-file %t1 +// CHECK: {{...}} + +#include + +int fibonacci(int n) { + if (n <= 1) return n; + return fibonacci(n - 1) + fibonacci(n - 2); +} + +int main() { + int n = 10; + printf("%d: %d\n", n, fibonacci(n)); + return 0; +} + diff --git a/scripts/ghidra/test/src/fread.c b/test/ghidra/fread.c similarity index 50% rename from scripts/ghidra/test/src/fread.c rename to test/ghidra/fread.c index 8fcea7b..2fcadcc 100644 --- a/scripts/ghidra/test/src/fread.c +++ b/test/ghidra/fread.c @@ -1,6 +1,12 @@ +// UNSUPPORTED: system-windows +// RUN: %cc %s -o %t +// RUN %t; if [ "$(uname)" = "Linux" ]; then %decompile-headless %t main %t1 fi +// RUN %t; if [ "$(uname)" = "Darwin" ]; then %decompile-headless %t _main %t1 fi +// RUN %t1; %file-check %s --input-file %t1 +// CHECK: {{...}} + #include -//CHECK: {{...}} int main(void) { FILE *file = fopen("example.txt", "r"); if (!file) { diff --git a/scripts/ghidra/test/src/fwrite.c b/test/ghidra/fwrite.c similarity index 58% rename from scripts/ghidra/test/src/fwrite.c rename to test/ghidra/fwrite.c index c2c6261..6e20f67 100644 --- a/scripts/ghidra/test/src/fwrite.c +++ b/test/ghidra/fwrite.c @@ -1,6 +1,12 @@ +// UNSUPPORTED: system-windows +// RUN: %cc %s -o %t +// RUN %t; if [ "$(uname)" = "Linux" ]; then %decompile-headless %t write_file %t1 fi +// RUN %t; if [ "$(uname)" = "Darwin" ]; then %decompile-headless %t _write_file %t1 fi +// RUN %t1; %file-check %s --input-file %t1 +// CHECK: {{...}} + #include -// CHECK: {{...}} void write_file(const char* filename, const char* content) { FILE* file = fopen(filename, "w"); if (file == NULL) { diff --git a/scripts/ghidra/test/src/insert.c b/test/ghidra/insert.c similarity index 60% rename from scripts/ghidra/test/src/insert.c rename to test/ghidra/insert.c index eb506f1..70d96dc 100644 --- a/scripts/ghidra/test/src/insert.c +++ b/test/ghidra/insert.c @@ -1,7 +1,13 @@ +// UNSUPPORTED: system-windows +// RUN: %cc %s -o %t +// RUN %t; if [ "$(uname)" = "Linux" ]; then %decompile-headless %t insert_substring %t1 fi +// RUN %t; if [ "$(uname)" = "Darwin" ]; then %decompile-headless %t _insert_substring %t1 fi +// RUN %t1; %file-check %s --input-file %t1 +// CHECK: {{...}} + #include #include -// CHECK: {{...}} void insert_substring(char *str, char *sub, int pos) { char temp[100]; strncpy(temp, str, pos); diff --git a/scripts/ghidra/test/src/list.c b/test/ghidra/list.c similarity index 74% rename from scripts/ghidra/test/src/list.c rename to test/ghidra/list.c index 4b0a1bd..c3b750c 100644 --- a/scripts/ghidra/test/src/list.c +++ b/test/ghidra/list.c @@ -1,3 +1,10 @@ +// UNSUPPORTED: system-windows +// RUN: %cc %s -o %t +// RUN %t; if [ "$(uname)" = "Linux" ]; then %decompile-headless %t print_list %t1 fi +// RUN %t; if [ "$(uname)" = "Darwin" ]; then %decompile-headless %t _print_list %t1 fi +// RUN %t1; %file-check %s --input-file %t1 +// CHECK: {{...}} + #include #include @@ -6,7 +13,6 @@ typedef struct Node { struct Node *next; } Node; -// CHECK: {{...}} void print_list(Node *head) { Node *current = head; while (current) { diff --git a/scripts/ghidra/test/src/matrix.c b/test/ghidra/matrix.c similarity index 73% rename from scripts/ghidra/test/src/matrix.c rename to test/ghidra/matrix.c index 3e377c3..a46be76 100644 --- a/scripts/ghidra/test/src/matrix.c +++ b/test/ghidra/matrix.c @@ -1,7 +1,14 @@ +// UNSUPPORTED: system-windows +// RUN: %cc %s -o %t +// RUN %t; if [ "$(uname)" = "Linux" ]; then %decompile-headless %t multiply_matrices %t1 fi +// RUN %t; if [ "$(uname)" = "Darwin" ]; then %decompile-headless %t _multiply_matrices %t1 fi +// RUN %t1; %file-check %s --input-file %t1 +// CHECK: {{...}} + #include #define SIZE 3 -// CHECK: {{...}} + void multiply_matrices(int a[SIZE][SIZE], int b[SIZE][SIZE], int result[SIZE][SIZE]) { for (int i = 0; i < SIZE; ++i) { for (int j = 0; j < SIZE; ++j) { diff --git a/scripts/ghidra/test/src/prime.c b/test/ghidra/prime.c similarity index 52% rename from scripts/ghidra/test/src/prime.c rename to test/ghidra/prime.c index c9a2de3..e49e53a 100644 --- a/scripts/ghidra/test/src/prime.c +++ b/test/ghidra/prime.c @@ -1,7 +1,13 @@ +// UNSUPPORTED: system-windows +// RUN: %cc %s -o %t +// RUN %t; if [ "$(uname)" = "Linux" ]; then %decompile-headless %t is_prime %t1 fi +// RUN %t; if [ "$(uname)" = "Darwin" ]; then %decompile-headless %t _is_prime %t1 fi +// RUN %t1; %file-check %s --input-file %t1 +// CHECK: {{...}} + #include #include -// CHECK: {{...}} bool is_prime(int n) { if (n <= 1) return false; for (int i = 2; i < n; i++) { diff --git a/scripts/ghidra/test/src/queue.c b/test/ghidra/queue.c similarity index 78% rename from scripts/ghidra/test/src/queue.c rename to test/ghidra/queue.c index 76bebc1..f2e3a26 100644 --- a/scripts/ghidra/test/src/queue.c +++ b/test/ghidra/queue.c @@ -1,3 +1,10 @@ +// UNSUPPORTED: system-windows +// RUN: %cc %s -o %t +// RUN %t; if [ "$(uname)" = "Linux" ]; then %decompile-headless %t dequeue %t1 fi +// RUN %t; if [ "$(uname)" = "Darwin" ]; then %decompile-headless %t _dequeue %t1 fi +// RUN %t1; %file-check %s --input-file %t1 +// CHECK: {{...}} + #include #include @@ -32,7 +39,6 @@ void enqueue(Queue *q, int value) { q->count++; } -//CHECK: {{...}} int dequeue(Queue *q) { if (is_empty(q)) { printf("Queue is empty\n"); diff --git a/scripts/ghidra/test/src/reverse.c b/test/ghidra/reverse.c similarity index 57% rename from scripts/ghidra/test/src/reverse.c rename to test/ghidra/reverse.c index 60e833e..0cda695 100644 --- a/scripts/ghidra/test/src/reverse.c +++ b/test/ghidra/reverse.c @@ -1,7 +1,13 @@ +// UNSUPPORTED: system-windows +// RUN: %cc %s -o %t +// RUN %t; if [ "$(uname)" = "Linux" ]; then %decompile-headless %t reverse_string %t1 fi +// RUN %t; if [ "$(uname)" = "Darwin" ]; then %decompile-headless %t _reverse_string %t1 fi +// RUN %t1; %file-check %s --input-file %t1 +// CHECK: {{...}} + #include #include -// CHECK: {{...}} void reverse_string(char *str) { int len = strlen(str); for (int i = 0; i < len / 2; ++i) { @@ -16,4 +22,4 @@ int main(void) { reverse_string(str); printf("Reversed: %s\n", str); return 0; -} +} \ No newline at end of file diff --git a/scripts/ghidra/test/src/sort.c b/test/ghidra/sort.c similarity index 63% rename from scripts/ghidra/test/src/sort.c rename to test/ghidra/sort.c index d6756d5..6c6932e 100644 --- a/scripts/ghidra/test/src/sort.c +++ b/test/ghidra/sort.c @@ -1,4 +1,10 @@ +// UNSUPPORTED: system-windows +// RUN: %cc %s -o %t +// RUN %t; if [ "$(uname)" = "Linux" ]; then %decompile-headless %t main %t1 fi +// RUN %t; if [ "$(uname)" = "Darwin" ]; then %decompile-headless %t _main %t1 fi +// RUN %t1; %file-check %s --input-file %t1 // CHECK: {{...}} + #include int main() diff --git a/test/ghidra/struct.c b/test/ghidra/struct.c new file mode 100644 index 0000000..8099a64 --- /dev/null +++ b/test/ghidra/struct.c @@ -0,0 +1,21 @@ +// UNSUPPORTED: system-windows +// RUN: %cc %s -o %t +// RUN %t; if [ "$(uname)" = "Linux" ]; then %decompile-headless %t main %t1 fi +// RUN %t; if [ "$(uname)" = "Darwin" ]; then %decompile-headless %t _main %t1 fi +// RUN %t1; %file-check %s --input-file %t1 +// CHECK: {{...}} + +struct data +{ + int a; + int b; + int c; + int d; + int e; +}; + +int main(int argc, char **argv) +{ + struct data d = { 0, 1, 2, 3, 4 }; + return d.a + d.b + d.c + d.d + d.e; +} diff --git a/test/ghidra/structb.c b/test/ghidra/structb.c new file mode 100644 index 0000000..acf6618 --- /dev/null +++ b/test/ghidra/structb.c @@ -0,0 +1,26 @@ +// UNSUPPORTED: system-windows +// RUN: %cc %s -o %t +// RUN %t; if [ "$(uname)" = "Linux" ]; then %decompile-headless %t main %t1 fi +// RUN %t; if [ "$(uname)" = "Darwin" ]; then %decompile-headless %t _main %t1 fi +// RUN %t1; %file-check %s --input-file %t1 +// CHECK: {{...}} + +#include + +typedef struct { + char name[50]; + int age; +} Person; + +// CHECK: {{...}} +int main(void) { + Person p; + snprintf(p.name, sizeof(p.name), "John"); + p.age = 30; + + printf("Name: %s\n", p.name); + printf("Age: %d\n", p.age); + + return 0; +} + diff --git a/test/ghidra/sub.c b/test/ghidra/sub.c new file mode 100644 index 0000000..cc0ac42 --- /dev/null +++ b/test/ghidra/sub.c @@ -0,0 +1,13 @@ +// UNSUPPORTED: system-windows +// RUN: %cc %s -o %t +// RUN %t; if [ "$(uname)" = "Linux" ]; then %decompile-headless %t main %t1 fi +// RUN %t; if [ "$(uname)" = "Darwin" ]; then %decompile-headless %t _main %t1 fi +// RUN %t1; %file-check %s --input-file %t1 +// CHECK: {{...}} + +int main() +{ + int x; + x = 4; + return x - 4; +} diff --git a/test/ghidra/test.c b/test/ghidra/test.c new file mode 100644 index 0000000..6ed32bb --- /dev/null +++ b/test/ghidra/test.c @@ -0,0 +1,13 @@ +// UNSUPPORTED: system-windows +// RUN: %cc %s -o %t +// RUN %t; if [ "$(uname)" = "Linux" ]; then %decompile-headless %t main %t1 fi +// RUN %t; if [ "$(uname)" = "Darwin" ]; then %decompile-headless %t _main %t1 fi +// RUN %t1; %file-check %s --input-file %t1 +// CHECK: {{...}} + +#include + +int main() { + printf("Test passed\n"); + return 0; +} diff --git a/test/ghidra/union.c b/test/ghidra/union.c new file mode 100644 index 0000000..24e03ac --- /dev/null +++ b/test/ghidra/union.c @@ -0,0 +1,25 @@ +// UNSUPPORTED: system-windows +// RUN: %cc %s -o %t +// RUN %t; if [ "$(uname)" = "Linux" ]; then %decompile-headless %t main %t1 fi +// RUN %t; if [ "$(uname)" = "Darwin" ]; then %decompile-headless %t _main %t1 fi +// RUN %t1; %file-check %s --input-file %t1 +// CHECK: {{...}} + +struct access +{ + int l; + int h; +}; + +union data +{ + unsigned long long b; + struct access s; +}; + +int main(int argc, char **argv) +{ + union data d; + d.b = 0xffffffff00000000 + argc; + return d.s.l; +} diff --git a/test/lit.cfg.py b/test/lit.cfg.py new file mode 100644 index 0000000..366f4c2 --- /dev/null +++ b/test/lit.cfg.py @@ -0,0 +1,59 @@ + +import os +import platform +import re +import subprocess +import tempfile + +import lit.formats +import lit.util + +from lit.llvm import llvm_config +from lit.llvm.subst import ToolSubst +from lit.llvm.subst import FindTool + +# Configuration name +config.name = 'PatchestryTest' + +# Set the test format to ShTest (shell-based tests) +config.test_format = lit.formats.ShTest() + +# Define file suffixes for test files +config.suffixes = ['.c', '.cpp'] + +# Set the root directory where tests should be executed +config.test_exec_root = os.path.join(config.patchestry_obj_root, 'test') + +# Set the root directory for test source files +config.test_source_root = os.path.join(config.patchestry_src_root, 'test') + +# Set the directory for Ghidra scripts +config.patchestry_script_dir = os.path.join(config.patchestry_src_root, 'scripts', 'ghidra') + +# Add the Ghidra scripts directory to the substitutions list +config.substitutions.append(('%PATH%', config.patchestry_script_dir)) + +# Define tool substitutions +tools = [ + ToolSubst('%decompile-headless', command='decompile-headless.sh'), + ToolSubst('%file-check', command=FindTool('FileCheck')), + ToolSubst('%cc', command=FindTool('clang')), + ToolSubst('%cxx', command=FindTool('clang++')), + ToolSubst('%host_cc', command=config.host_cc), + ToolSubst('%host_cxx', command=config.host_cxx) +] + +# Process tool substitutions +for tool in tools: + if tool.command == 'decompile-headless.sh': + # Set the full path for the decompile-headless.sh script + path = [config.patchestry_script_dir] + tool.command = os.path.join(*path, tool.command) + # Add tool substitutions to LLVM config + llvm_config.add_tool_substitutions([tool]) + +# Add test directory to substitutions +config.substitutions.append(('%test_dir', os.path.join(config.test_source_root, 'ghidra'))) + +# Add PATH to substitutions +config.substitutions.append(('%PATH%', config.environment['PATH'])) \ No newline at end of file diff --git a/test/lit.site.cfg.py.in b/test/lit.site.cfg.py.in new file mode 100644 index 0000000..edb57fd --- /dev/null +++ b/test/lit.site.cfg.py.in @@ -0,0 +1,40 @@ +@LIT_SITE_CFG_IN_HEADER@ + +import sys + +config.host_triple = "@LLVM_HOST_TRIPLE@" +config.target_triple = "@TARGET_TRIPLE@" +config.llvm_src_root = "@LLVM_SOURCE_DIR@" +config.llvm_obj_root = "@LLVM_BINARY_DIR@" +config.llvm_tools_dir = "@LLVM_TOOLS_DIR@" +config.llvm_lib_dir = "@LLVM_LIBS_DIR@" +config.llvm_shlib_dir = "@SHLIBDIR@" +config.llvm_shlib_ext = "@SHLIBEXT@" +config.llvm_exe_ext = "@EXEEXT@" +config.lit_tools_dir = "@LLVM_LIT_TOOLS_DIR@" +config.python_executable = "@PYTHON_EXECUTABLE@" +config.gold_executable = "@GOLD_EXECUTABLE@" +config.ld64_executable = "@LD64_EXECUTABLE@" +config.enable_shared = @ENABLE_SHARED@ +config.enable_assertions = @ENABLE_ASSERTIONS@ +config.targets_to_build = "@TARGETS_TO_BUILD@" +config.native_target = "@LLVM_NATIVE_ARCH@" +config.llvm_bindings = "@LLVM_BINDINGS@".split(' ') +config.host_os = "@HOST_OS@" +config.host_cc = "@HOST_CC@" +config.host_cxx = "@HOST_CXX@" +config.enable_libcxx = "@LLVM_ENABLE_LIBCXX@" +# Note: ldflags can contain double-quoted paths, so must use single quotes here. +config.host_ldflags = '@HOST_LDFLAGS@' +config.llvm_use_sanitizer = "@LLVM_USE_SANITIZER@" +config.llvm_host_triple = '@LLVM_HOST_TRIPLE@' +config.host_arch = "@HOST_ARCH@" +config.patchestry_src_root = "@CMAKE_SOURCE_DIR@" +config.patchestry_obj_root = "@CMAKE_BINARY_DIR@" + + +import lit.llvm +lit.llvm.initialize(lit_config, config) + +# Let the main config do the real work. +lit_config.load_config(config, "@CMAKE_SOURCE_DIR@/test/lit.cfg.py") \ No newline at end of file From 3760ea27fffc69bcacd112c423de949980e6a497 Mon Sep 17 00:00:00 2001 From: AkshayK Date: Thu, 29 Aug 2024 09:19:35 -0400 Subject: [PATCH 02/12] test: Update lit config to wrap decompiler-headless tool. --- test/CMakeLists.txt | 11 +++++------ test/ghidra/argc.c | 5 +---- test/ghidra/array.c | 5 +---- test/ghidra/concat.c | 5 +---- test/ghidra/fib.c | 5 +---- test/ghidra/fread.c | 5 +---- test/ghidra/fwrite.c | 5 +---- test/ghidra/insert.c | 5 +---- test/ghidra/list.c | 5 +---- test/ghidra/matrix.c | 5 +---- test/ghidra/prime.c | 5 +---- test/ghidra/queue.c | 5 +---- test/ghidra/reverse.c | 5 +---- test/ghidra/sort.c | 5 +---- test/ghidra/struct.c | 5 +---- test/ghidra/structb.c | 6 +----- test/ghidra/sub.c | 5 +---- test/ghidra/test.c | 5 +---- test/ghidra/union.c | 5 +---- test/lit.cfg.py | 35 +++++++++++++++++++++++++++-------- 20 files changed, 50 insertions(+), 87 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 27e4a97..57d4de7 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -6,6 +6,11 @@ cmake_minimum_required(VERSION 3.25) include(CTest) +find_package(Python REQUIRED COMPONENTS Interpreter) +if (Python_Interpreter_FOUND) + set(PYTHON_EXECUTABLE ${Python_EXECUTABLE}) +endif() + # Configure the lit site configuration file configure_lit_site_cfg( ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in @@ -14,15 +19,9 @@ configure_lit_site_cfg( ${CMAKE_CURRENT_SOURCE_DIR}/lit.cfg.py ) -# Define test dependencies -set(TEST_DEPS - FileCheck -) - # Add a lit test suite named "PatchestryTest" add_lit_testsuite(PatchestryTest "Running Patchestry tests" ${CMAKE_CURRENT_SOURCE_DIR}/ghidra - DEPENDS ${TEST_DEPS} ) # Add a CTest test that runs the lit test suite diff --git a/test/ghidra/argc.c b/test/ghidra/argc.c index af3ae6f..fad3fdc 100644 --- a/test/ghidra/argc.c +++ b/test/ghidra/argc.c @@ -1,8 +1,5 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t -// RUN %t; if [ "$(uname)" = "Linux" ]; then %decompile-headless %t argc %t1 fi -// RUN %t; if [ "$(uname)" = "Darwin" ]; then %decompile-headless %t _argc %t1 fi -// RUN %t1; %file-check %s --input-file %t1 +// RUN: %cc %s -o %t && %decompile-headless %t argc %t1 && %file-check -vv %s --input-file %t1 // CHECK: {{...}} int argc(int argc, char **argv) { diff --git a/test/ghidra/array.c b/test/ghidra/array.c index f24cd09..48bb33d 100644 --- a/test/ghidra/array.c +++ b/test/ghidra/array.c @@ -1,8 +1,5 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t -// RUN %t; if [ "$(uname)" = "Linux" ]; then %decompile-headless %t main %t1 fi -// RUN %t; if [ "$(uname)" = "Darwin" ]; then %decompile-headless %t _main %t1 fi -// RUN %t1; %file-check %s --input-file %t1 +// RUN: %cc %s -o %t && %decompile-headless %t main %t1 && %file-check %s --input-file %t1 // CHECK: {{...}} #include diff --git a/test/ghidra/concat.c b/test/ghidra/concat.c index dea1e2f..6e6afaf 100644 --- a/test/ghidra/concat.c +++ b/test/ghidra/concat.c @@ -1,8 +1,5 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t -// RUN %t; if [ "$(uname)" = "Linux" ]; then %decompile-headless %t string_concat %t1 fi -// RUN %t; if [ "$(uname)" = "Darwin" ]; then %decompile-headless %t _string_concat %t1 fi -// RUN %t1; %file-check %s --input-file %t1 +// RUN: %cc %s -o %t && %decompile-headless %t string_concat %t1 && %file-check %s --input-file %t1 // CHECK: {{...}} #include diff --git a/test/ghidra/fib.c b/test/ghidra/fib.c index 790df13..391186d 100644 --- a/test/ghidra/fib.c +++ b/test/ghidra/fib.c @@ -1,8 +1,5 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t -// RUN %t; if [ "$(uname)" = "Linux" ]; then %decompile-headless %t fibonacci %t1 fi -// RUN %t; if [ "$(uname)" = "Darwin" ]; then %decompile-headless %t _fibonacci %t1 fi -// RUN %t1; %file-check %s --input-file %t1 +// RUN: %cc %s -o %t && %decompile-headless %t fibonacci %t1 && %file-check %s --input-file %t1 // CHECK: {{...}} #include diff --git a/test/ghidra/fread.c b/test/ghidra/fread.c index 2fcadcc..cfd5bfb 100644 --- a/test/ghidra/fread.c +++ b/test/ghidra/fread.c @@ -1,8 +1,5 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t -// RUN %t; if [ "$(uname)" = "Linux" ]; then %decompile-headless %t main %t1 fi -// RUN %t; if [ "$(uname)" = "Darwin" ]; then %decompile-headless %t _main %t1 fi -// RUN %t1; %file-check %s --input-file %t1 +// RUN: %cc %s -o %t && %decompile-headless %t main %t1 && %file-check %s --input-file %t1 // CHECK: {{...}} #include diff --git a/test/ghidra/fwrite.c b/test/ghidra/fwrite.c index 6e20f67..73db3fc 100644 --- a/test/ghidra/fwrite.c +++ b/test/ghidra/fwrite.c @@ -1,8 +1,5 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t -// RUN %t; if [ "$(uname)" = "Linux" ]; then %decompile-headless %t write_file %t1 fi -// RUN %t; if [ "$(uname)" = "Darwin" ]; then %decompile-headless %t _write_file %t1 fi -// RUN %t1; %file-check %s --input-file %t1 +// RUN: %cc %s -o %t && %decompile-headless %t write_file %t1 && %file-check %s --input-file %t1 // CHECK: {{...}} #include diff --git a/test/ghidra/insert.c b/test/ghidra/insert.c index 70d96dc..ac81243 100644 --- a/test/ghidra/insert.c +++ b/test/ghidra/insert.c @@ -1,8 +1,5 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t -// RUN %t; if [ "$(uname)" = "Linux" ]; then %decompile-headless %t insert_substring %t1 fi -// RUN %t; if [ "$(uname)" = "Darwin" ]; then %decompile-headless %t _insert_substring %t1 fi -// RUN %t1; %file-check %s --input-file %t1 +// RUN: %cc %s -o %t && %decompile-headless %t insert_substring %t1 && %file-check %s --input-file %t1 // CHECK: {{...}} #include diff --git a/test/ghidra/list.c b/test/ghidra/list.c index c3b750c..a1f5175 100644 --- a/test/ghidra/list.c +++ b/test/ghidra/list.c @@ -1,8 +1,5 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t -// RUN %t; if [ "$(uname)" = "Linux" ]; then %decompile-headless %t print_list %t1 fi -// RUN %t; if [ "$(uname)" = "Darwin" ]; then %decompile-headless %t _print_list %t1 fi -// RUN %t1; %file-check %s --input-file %t1 +// RUN: %cc %s -o %t && %decompile-headless %t print_list %t1 && %file-check %s --input-file %t1 // CHECK: {{...}} #include diff --git a/test/ghidra/matrix.c b/test/ghidra/matrix.c index a46be76..51a408e 100644 --- a/test/ghidra/matrix.c +++ b/test/ghidra/matrix.c @@ -1,8 +1,5 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t -// RUN %t; if [ "$(uname)" = "Linux" ]; then %decompile-headless %t multiply_matrices %t1 fi -// RUN %t; if [ "$(uname)" = "Darwin" ]; then %decompile-headless %t _multiply_matrices %t1 fi -// RUN %t1; %file-check %s --input-file %t1 +// RUN: %cc %s -o %t && %decompile-headless %t multiply_matrices %t1 && %file-check %s --input-file %t1 // CHECK: {{...}} #include diff --git a/test/ghidra/prime.c b/test/ghidra/prime.c index e49e53a..ee28315 100644 --- a/test/ghidra/prime.c +++ b/test/ghidra/prime.c @@ -1,8 +1,5 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t -// RUN %t; if [ "$(uname)" = "Linux" ]; then %decompile-headless %t is_prime %t1 fi -// RUN %t; if [ "$(uname)" = "Darwin" ]; then %decompile-headless %t _is_prime %t1 fi -// RUN %t1; %file-check %s --input-file %t1 +// RUN: %cc %s -o %t && %decompile-headless %t is_prime %t1 && %file-check %s --input-file %t1 // CHECK: {{...}} #include diff --git a/test/ghidra/queue.c b/test/ghidra/queue.c index f2e3a26..0c2ad3e 100644 --- a/test/ghidra/queue.c +++ b/test/ghidra/queue.c @@ -1,8 +1,5 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t -// RUN %t; if [ "$(uname)" = "Linux" ]; then %decompile-headless %t dequeue %t1 fi -// RUN %t; if [ "$(uname)" = "Darwin" ]; then %decompile-headless %t _dequeue %t1 fi -// RUN %t1; %file-check %s --input-file %t1 +// RUN: %cc %s -o %t && %decompile-headless %t dequeue %t1 && %file-check %s --input-file %t1 // CHECK: {{...}} #include diff --git a/test/ghidra/reverse.c b/test/ghidra/reverse.c index 0cda695..4c3b273 100644 --- a/test/ghidra/reverse.c +++ b/test/ghidra/reverse.c @@ -1,8 +1,5 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t -// RUN %t; if [ "$(uname)" = "Linux" ]; then %decompile-headless %t reverse_string %t1 fi -// RUN %t; if [ "$(uname)" = "Darwin" ]; then %decompile-headless %t _reverse_string %t1 fi -// RUN %t1; %file-check %s --input-file %t1 +// RUN: %cc %s -o %t && %decompile-headless %t reverse_string %t1 && %file-check %s --input-file %t1 // CHECK: {{...}} #include diff --git a/test/ghidra/sort.c b/test/ghidra/sort.c index 6c6932e..aa3c759 100644 --- a/test/ghidra/sort.c +++ b/test/ghidra/sort.c @@ -1,8 +1,5 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t -// RUN %t; if [ "$(uname)" = "Linux" ]; then %decompile-headless %t main %t1 fi -// RUN %t; if [ "$(uname)" = "Darwin" ]; then %decompile-headless %t _main %t1 fi -// RUN %t1; %file-check %s --input-file %t1 +// RUN: %cc %s -o %t && %decompile-headless %t main %t1 && %file-check %s --input-file %t1 // CHECK: {{...}} #include diff --git a/test/ghidra/struct.c b/test/ghidra/struct.c index 8099a64..87cce94 100644 --- a/test/ghidra/struct.c +++ b/test/ghidra/struct.c @@ -1,8 +1,5 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t -// RUN %t; if [ "$(uname)" = "Linux" ]; then %decompile-headless %t main %t1 fi -// RUN %t; if [ "$(uname)" = "Darwin" ]; then %decompile-headless %t _main %t1 fi -// RUN %t1; %file-check %s --input-file %t1 +// RUN: %cc %s -o %t && %decompile-headless %t main %t1 && %file-check %s --input-file %t1 // CHECK: {{...}} struct data diff --git a/test/ghidra/structb.c b/test/ghidra/structb.c index acf6618..e59b657 100644 --- a/test/ghidra/structb.c +++ b/test/ghidra/structb.c @@ -1,8 +1,5 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t -// RUN %t; if [ "$(uname)" = "Linux" ]; then %decompile-headless %t main %t1 fi -// RUN %t; if [ "$(uname)" = "Darwin" ]; then %decompile-headless %t _main %t1 fi -// RUN %t1; %file-check %s --input-file %t1 +// RUN: %cc -ggdb %s -o %t && %decompile-headless %t main %t1 && %file-check %s --input-file %t1 // CHECK: {{...}} #include @@ -12,7 +9,6 @@ typedef struct { int age; } Person; -// CHECK: {{...}} int main(void) { Person p; snprintf(p.name, sizeof(p.name), "John"); diff --git a/test/ghidra/sub.c b/test/ghidra/sub.c index cc0ac42..0d32259 100644 --- a/test/ghidra/sub.c +++ b/test/ghidra/sub.c @@ -1,8 +1,5 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t -// RUN %t; if [ "$(uname)" = "Linux" ]; then %decompile-headless %t main %t1 fi -// RUN %t; if [ "$(uname)" = "Darwin" ]; then %decompile-headless %t _main %t1 fi -// RUN %t1; %file-check %s --input-file %t1 +// RUN: %cc %s -o %t && %decompile-headless %t main %t1 && %file-check %s --input-file %t1 // CHECK: {{...}} int main() diff --git a/test/ghidra/test.c b/test/ghidra/test.c index 6ed32bb..9955de1 100644 --- a/test/ghidra/test.c +++ b/test/ghidra/test.c @@ -1,8 +1,5 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t -// RUN %t; if [ "$(uname)" = "Linux" ]; then %decompile-headless %t main %t1 fi -// RUN %t; if [ "$(uname)" = "Darwin" ]; then %decompile-headless %t _main %t1 fi -// RUN %t1; %file-check %s --input-file %t1 +// RUN: %cc %s -o %t && %decompile-headless %t main %t1 && %file-check %s --input-file %t1 // CHECK: {{...}} #include diff --git a/test/ghidra/union.c b/test/ghidra/union.c index 24e03ac..b89187a 100644 --- a/test/ghidra/union.c +++ b/test/ghidra/union.c @@ -1,8 +1,5 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t -// RUN %t; if [ "$(uname)" = "Linux" ]; then %decompile-headless %t main %t1 fi -// RUN %t; if [ "$(uname)" = "Darwin" ]; then %decompile-headless %t _main %t1 fi -// RUN %t1; %file-check %s --input-file %t1 +// RUN: %cc %s -o %t && %decompile-headless %t main %t1 && %file-check %s --input-file %t1 // CHECK: {{...}} struct access diff --git a/test/lit.cfg.py b/test/lit.cfg.py index 366f4c2..763ebc4 100644 --- a/test/lit.cfg.py +++ b/test/lit.cfg.py @@ -12,11 +12,21 @@ from lit.llvm.subst import ToolSubst from lit.llvm.subst import FindTool +# Prefix for function name +if platform.system() == "Darwin": + config.function_prefix = "_" +else: + config.function_prefix = "" + +config.debug = True + # Configuration name config.name = 'PatchestryTest' # Set the test format to ShTest (shell-based tests) -config.test_format = lit.formats.ShTest() +config.test_format = lit.formats.ShTest(not llvm_config.use_lit_shell) + +config.python_executable = config.python_executable if config.python_executable else sys.executable # Define file suffixes for test files config.suffixes = ['.c', '.cpp'] @@ -33,9 +43,10 @@ # Add the Ghidra scripts directory to the substitutions list config.substitutions.append(('%PATH%', config.patchestry_script_dir)) +config.decompiler_headless_tool = os.path.join(config.patchestry_script_dir, 'decompile-headless.sh') + # Define tool substitutions tools = [ - ToolSubst('%decompile-headless', command='decompile-headless.sh'), ToolSubst('%file-check', command=FindTool('FileCheck')), ToolSubst('%cc', command=FindTool('clang')), ToolSubst('%cxx', command=FindTool('clang++')), @@ -45,15 +56,23 @@ # Process tool substitutions for tool in tools: - if tool.command == 'decompile-headless.sh': - # Set the full path for the decompile-headless.sh script - path = [config.patchestry_script_dir] - tool.command = os.path.join(*path, tool.command) - # Add tool substitutions to LLVM config llvm_config.add_tool_substitutions([tool]) # Add test directory to substitutions config.substitutions.append(('%test_dir', os.path.join(config.test_source_root, 'ghidra'))) # Add PATH to substitutions -config.substitutions.append(('%PATH%', config.environment['PATH'])) \ No newline at end of file +config.substitutions.append(('%PATH%', config.environment['PATH'])) + +config.substitutions.append( + ('%decompile-headless', + f"'{config.python_executable}' -c '" + f"import subprocess;" + f"import sys;" + f"args = sys.argv[1:4];" + f"print(args);" + f"args[1] = \"{config.function_prefix}\" + args[1]; " + f"result = subprocess.run([\"{config.decompiler_headless_tool}\"] + args, capture_output=True, text=True); " + f"print(result.stdout + result.stderr); " + f"sys.exit(result.returncode)' ") +) \ No newline at end of file From 59b5361325c793b5d42c646d7a427af55dd85397 Mon Sep 17 00:00:00 2001 From: AkshayK Date: Thu, 29 Aug 2024 10:25:48 -0400 Subject: [PATCH 03/12] test: Update unit tests to recover function not main. --- test/ghidra/array.c | 10 +++++++--- test/ghidra/fread.c | 7 +++++-- test/ghidra/sort.c | 8 ++++++-- test/ghidra/struct.c | 9 +++++++-- test/ghidra/structb.c | 7 +++++-- test/ghidra/sub.c | 11 +++++++++-- test/ghidra/test.c | 8 ++++++-- test/ghidra/union.c | 8 ++++++-- 8 files changed, 51 insertions(+), 17 deletions(-) diff --git a/test/ghidra/array.c b/test/ghidra/array.c index 48bb33d..721f772 100644 --- a/test/ghidra/array.c +++ b/test/ghidra/array.c @@ -1,12 +1,11 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t && %decompile-headless %t main %t1 && %file-check %s --input-file %t1 +// RUN: %cc %s -o %t && %decompile-headless %t array %t1 && %file-check %s --input-file %t1 // CHECK: {{...}} #include #include -// CHECK: {{...}} -int main(void) { +int array(int argc, char **argv) { int size = 5; int *array = malloc(size * sizeof(int)); @@ -23,3 +22,8 @@ int main(void) { return 0; } +int main(int a, char **argv) +{ + return array(a, argv); +} + diff --git a/test/ghidra/fread.c b/test/ghidra/fread.c index cfd5bfb..e4acfee 100644 --- a/test/ghidra/fread.c +++ b/test/ghidra/fread.c @@ -1,10 +1,10 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t && %decompile-headless %t main %t1 && %file-check %s --input-file %t1 +// RUN: %cc %s -o %t && %decompile-headless %t fread_test %t1 && %file-check %s --input-file %t1 // CHECK: {{...}} #include -int main(void) { +int fread_test(void) { FILE *file = fopen("example.txt", "r"); if (!file) { perror("Error opening file"); @@ -20,3 +20,6 @@ int main(void) { return 0; } +int main(void) { + return fread_test(); +} \ No newline at end of file diff --git a/test/ghidra/sort.c b/test/ghidra/sort.c index aa3c759..be7c6c4 100644 --- a/test/ghidra/sort.c +++ b/test/ghidra/sort.c @@ -1,10 +1,10 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t && %decompile-headless %t main %t1 && %file-check %s --input-file %t1 +// RUN: %cc %s -o %t && %decompile-headless %t sort_test %t1 && %file-check %s --input-file %t1 // CHECK: {{...}} #include -int main() +int sort_test() { int array[100], n, c, d, swap; scanf("%d", &n); @@ -26,3 +26,7 @@ int main() return 0; } + +int main(void) { + return sort_test(); +} diff --git a/test/ghidra/struct.c b/test/ghidra/struct.c index 87cce94..46fd913 100644 --- a/test/ghidra/struct.c +++ b/test/ghidra/struct.c @@ -1,5 +1,5 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t && %decompile-headless %t main %t1 && %file-check %s --input-file %t1 +// RUN: %cc %s -o %t && %decompile-headless %t struct_test %t1 && %file-check %s --input-file %t1 // CHECK: {{...}} struct data @@ -11,8 +11,13 @@ struct data int e; }; -int main(int argc, char **argv) +int struct_test(int argc, char **argv) { struct data d = { 0, 1, 2, 3, 4 }; return d.a + d.b + d.c + d.d + d.e; } + +int main(int argc, char **argv) { + return struct_test(argc, argv); + +} \ No newline at end of file diff --git a/test/ghidra/structb.c b/test/ghidra/structb.c index e59b657..6a16b9a 100644 --- a/test/ghidra/structb.c +++ b/test/ghidra/structb.c @@ -1,5 +1,5 @@ // UNSUPPORTED: system-windows -// RUN: %cc -ggdb %s -o %t && %decompile-headless %t main %t1 && %file-check %s --input-file %t1 +// RUN: %cc %s -o %t && %decompile-headless %t structb %t1 && %file-check %s --input-file %t1 // CHECK: {{...}} #include @@ -9,7 +9,7 @@ typedef struct { int age; } Person; -int main(void) { +int structb(void) { Person p; snprintf(p.name, sizeof(p.name), "John"); p.age = 30; @@ -20,3 +20,6 @@ int main(void) { return 0; } +int main(void) { + return structb(); +} diff --git a/test/ghidra/sub.c b/test/ghidra/sub.c index 0d32259..fad7c72 100644 --- a/test/ghidra/sub.c +++ b/test/ghidra/sub.c @@ -1,10 +1,17 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t && %decompile-headless %t main %t1 && %file-check %s --input-file %t1 +// RUN: %cc %s -o %t && %decompile-headless %t sub %t1 && %file-check %s --input-file %t1 // CHECK: {{...}} -int main() +#include + +int sub() { int x; x = 4; return x - 4; } + +int main(void) { + printf("sub: %d\n", sub()); + return 0; +} diff --git a/test/ghidra/test.c b/test/ghidra/test.c index 9955de1..e174b31 100644 --- a/test/ghidra/test.c +++ b/test/ghidra/test.c @@ -1,10 +1,14 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t && %decompile-headless %t main %t1 && %file-check %s --input-file %t1 +// RUN: %cc %s -o %t && %decompile-headless %t test %t1 && %file-check %s --input-file %t1 // CHECK: {{...}} #include -int main() { +int test() { printf("Test passed\n"); return 0; } + +int main(void) { + return test(); +} \ No newline at end of file diff --git a/test/ghidra/union.c b/test/ghidra/union.c index b89187a..93bcdfc 100644 --- a/test/ghidra/union.c +++ b/test/ghidra/union.c @@ -1,5 +1,5 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t && %decompile-headless %t main %t1 && %file-check %s --input-file %t1 +// RUN: %cc %s -o %t && %decompile-headless %t union_test %t1 && %file-check %s --input-file %t1 // CHECK: {{...}} struct access @@ -14,9 +14,13 @@ union data struct access s; }; -int main(int argc, char **argv) +int union_test(int argc, char **argv) { union data d; d.b = 0xffffffff00000000 + argc; return d.s.l; } + +int main(int argc, char **argv) { + return union_test(argc, argv); +} \ No newline at end of file From 131e480aba675def2dd35a102c17d4d25858a5a4 Mon Sep 17 00:00:00 2001 From: AkshayK Date: Thu, 29 Aug 2024 23:27:05 -0400 Subject: [PATCH 04/12] test: Refactor ci and run test as different job. --- .devcontainer/Dockerfile | 7 ++++ .devcontainer/devcontainer.json | 15 +++++-- .github/workflows/ci.yml | 58 +++++++++++++++++++++++++++- scripts/ghidra/decompile-headless.sh | 2 +- 4 files changed, 75 insertions(+), 7 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 8acf8d3..1ce54de 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -25,9 +25,16 @@ RUN apt-get update && \ apt-get clean --yes && \ rm -rf /var/lib/apt/lists/* +# Install Docker +RUN curl -fsSL https://get.docker.com -o get-docker.sh \ + && sh get-docker.sh \ + && rm get-docker.sh + RUN apt-get -y purge llvm-14 clang-14 RUN pip3 install lit codespell jinja2 Pygments COPY ./install-llvm.sh /tmp/ RUN chmod +x /tmp/install-llvm.sh && /tmp/install-llvm.sh ${LLVM_VERSION} all + +RUN groupadd docker || true && usermod -aG docker root \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index f6bf695..a076ec2 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -4,8 +4,10 @@ "name": "C++", // to run local build of devcontainer "build": { "dockerfile": "./Dockerfile" }, - "runArgs": ["--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined"], - + "runArgs": ["--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined", "--privileged"], + "mounts": [ + "source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind" + ], // Configure tool-specific properties. "customizations": { // Configure properties specific to VS Code. @@ -18,10 +20,15 @@ } }, - "remoteUser": "vscode", + "remoteUser": "root", "features": { "git": "os-provided", - "python": "os-provided" + "python": "os-provided", + "ghcr.io/devcontainers/features/docker-in-docker:2": { + "version": "latest", + "moby": true, + "dockerDashComposeVersion": "v2" + } }, "containerEnv": { "CMAKE_PREFIX_PATH": "/usr/lib/llvm-18/lib/cmake/mlir/;/usr/lib/llvm-18/lib/cmake/clang/", diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7ac45b3..d4e885a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -54,5 +54,59 @@ jobs: - name: Build ${{ matrix.build-type }} with sanitizers set ${{ matrix.sanitizers }} run: cmake --build --preset ci --config ${{ matrix.build-type }} -j $(nproc) - - name: Test ${{ matrix.build-type }} with sanitizers set ${{ matrix.sanitizers }} - run: ctest --preset ci --build-config ${{ matrix.build-type }} + #- name: Test ${{ matrix.build-type }} with sanitizers set ${{ matrix.sanitizers }} + # run: | + # cmake --preset ci + # ctest --preset ci --build-config ${{ matrix.build-type }} + test: + needs: build + strategy: + matrix: + llvm-version: [18] + image-version: [22.04] + build-type: [Release, Debug] + sanitizers: [ON, OFF] + runs-on: ubuntu-${{ matrix.image-version }} + env: + CMAKE_PREFIX_PATH: "/usr/lib/llvm-${{ matrix.llvm-version }}/lib/cmake/mlir/;/usr/lib/llvm-${{ matrix.llvm-version }}/lib/cmake/clang/" + LLVM_EXTERNAL_LIT: "/usr/local/bin/lit" + ENABLE_SANITIZER_UNDEFINED_BEHAVIOR: ${{ matrix.sanitizers }} + ENABLE_SANITIZER_ADDRESS: ${{ matrix.sanitizers }} + + steps: + - name: Clone the Patchestry repository + uses: actions/checkout@v4 + with: + submodules: true + fetch-depth: 1 + + - name: Install CTest dependencies + run: | + sudo apt-get update + sudo apt-get install -y \ + software-properties-common \ + ninja-build python3-pip \ + ccache cmake lld lcov \ + doxygen libzstd-dev + + curl -fsSL https://get.docker.com -o get-docker.sh \ + && sh get-docker.sh \ + && rm get-docker.sh + + sudo apt-get -y purge llvm-14 clang-14 + pip3 install lit codespell jinja2 Pygments + + curl -fsSL https://apt.llvm.org/llvm.sh -o llvm.sh && \ + chmod +x llvm.sh && \ + sudo ./llvm.sh ${{ matrix.llvm-version }} all && \ + rm llvm.sh + + sudo apt-get install libmlir-${{ matrix.llvm-version }}-dev mlir-${{ matrix.llvm-version }}-tools + sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++-${{ matrix.llvm-version }} 60 + sudo update-alternatives --install /usr/bin/cc cc /usr/bin/clang-${{ matrix.llvm-version }} 60 + sudo ln -s /usr/bin/FileCheck-${{ matrix.llvm-version }} /usr/bin/FileCheck + + - name: Run CTest + run: | + cmake --preset ci + ctest --preset ci --build-config ${{ matrix.build-type }} \ No newline at end of file diff --git a/scripts/ghidra/decompile-headless.sh b/scripts/ghidra/decompile-headless.sh index a64777d..c2602d9 100755 --- a/scripts/ghidra/decompile-headless.sh +++ b/scripts/ghidra/decompile-headless.sh @@ -39,4 +39,4 @@ docker run --rm \ -v $INPUT_PATH:/input \ -v $OUTPUT_PATH:/output \ trailofbits/patchestry-decompilation:latest \ - /input $FUNCTION_NAME /output \ No newline at end of file + /input $FUNCTION_NAME /output From 5141f38e8c695c013f244b597f3c162e1113923f Mon Sep 17 00:00:00 2001 From: xlauko Date: Wed, 4 Sep 2024 10:50:20 +0000 Subject: [PATCH 05/12] gh: Use docker-in-docker service. --- .devcontainer/Dockerfile | 28 +++++++++------- .github/workflows/ci.yml | 71 ++++++++-------------------------------- test/lit.cfg.py | 31 +++++++++--------- 3 files changed, 46 insertions(+), 84 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 1ce54de..c506c92 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -11,30 +11,36 @@ ARG LLVM_VERSION # CMake reinstall choices: none, 3.21.5, 3.22.2, or versions from https://cmake.org/download/ ARG REINSTALL_CMAKE_VERSION_FROM_SOURCE="3.29.2" -# Optionally install the cmake for vcpkg +# Optionally install CMake for vcpkg COPY ./reinstall-cmake.sh /tmp/ RUN if [ "${REINSTALL_CMAKE_VERSION_FROM_SOURCE}" != "none" ]; then \ - chmod +x /tmp/reinstall-cmake.sh && /tmp/reinstall-cmake.sh ${REINSTALL_CMAKE_VERSION_FROM_SOURCE}; \ - fi \ - && rm -f /tmp/reinstall-cmake.sh + chmod +x /tmp/reinstall-cmake.sh && \ + /tmp/reinstall-cmake.sh ${REINSTALL_CMAKE_VERSION_FROM_SOURCE}; \ + fi && \ + rm -f /tmp/reinstall-cmake.sh COPY ./dependencies.txt /tmp/ RUN apt-get update && \ export DEBIAN_FRONTEND=noninteractive && \ - xargs -a /tmp/dependencies.txt apt-get -y install --no-install-recommends && \ - apt-get clean --yes && \ + xargs -a /tmp/dependencies.txt apt-get install -y --no-install-recommends && \ + apt-get clean && \ rm -rf /var/lib/apt/lists/* # Install Docker -RUN curl -fsSL https://get.docker.com -o get-docker.sh \ - && sh get-docker.sh \ - && rm get-docker.sh +RUN curl -fsSL https://get.docker.com -o get-docker.sh && \ + sh get-docker.sh && \ + rm get-docker.sh +# Remove old versions of LLVM and Clang RUN apt-get -y purge llvm-14 clang-14 +# Install Python packages RUN pip3 install lit codespell jinja2 Pygments COPY ./install-llvm.sh /tmp/ -RUN chmod +x /tmp/install-llvm.sh && /tmp/install-llvm.sh ${LLVM_VERSION} all +RUN chmod +x /tmp/install-llvm.sh && \ + /tmp/install-llvm.sh ${LLVM_VERSION} all -RUN groupadd docker || true && usermod -aG docker root \ No newline at end of file +# Add docker group and add root to it +RUN groupadd docker || true && \ + usermod -aG docker root diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d4e885a..2b0eb43 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,11 +35,18 @@ jobs: image: ghcr.io/lifting-bits/patchestry-ubuntu-${{ matrix.image-version }}-llvm-${{ matrix.llvm-version }}-dev:latest + services: + docker: + image: docker:20.10-dind + options: --privileged + ports: + - 2375:2375 + env: - CMAKE_PREFIX_PATH: "/usr/lib/llvm-${{ matrix.llvm-version }}/lib/cmake/mlir/;/usr/lib/llvm-${{ matrix.llvm-version }}/lib/cmake/clang/" - LLVM_EXTERNAL_LIT: "/usr/local/bin/lit" - ENABLE_SANITIZER_UNDEFINED_BEHAVIOR: ${{ matrix.sanitizers }} - ENABLE_SANITIZER_ADDRESS: ${{ matrix.sanitizers }} + CMAKE_PREFIX_PATH: "/usr/lib/llvm-${{ matrix.llvm-version }}/lib/cmake/mlir/;/usr/lib/llvm-${{ matrix.llvm-version }}/lib/cmake/clang/" + LLVM_EXTERNAL_LIT: "/usr/local/bin/lit" + ENABLE_SANITIZER_UNDEFINED_BEHAVIOR: ${{ matrix.sanitizers }} + ENABLE_SANITIZER_ADDRESS: ${{ matrix.sanitizers }} steps: - name: Clone the Patchestry repository @@ -54,59 +61,7 @@ jobs: - name: Build ${{ matrix.build-type }} with sanitizers set ${{ matrix.sanitizers }} run: cmake --build --preset ci --config ${{ matrix.build-type }} -j $(nproc) - #- name: Test ${{ matrix.build-type }} with sanitizers set ${{ matrix.sanitizers }} - # run: | - # cmake --preset ci - # ctest --preset ci --build-config ${{ matrix.build-type }} - test: - needs: build - strategy: - matrix: - llvm-version: [18] - image-version: [22.04] - build-type: [Release, Debug] - sanitizers: [ON, OFF] - runs-on: ubuntu-${{ matrix.image-version }} - env: - CMAKE_PREFIX_PATH: "/usr/lib/llvm-${{ matrix.llvm-version }}/lib/cmake/mlir/;/usr/lib/llvm-${{ matrix.llvm-version }}/lib/cmake/clang/" - LLVM_EXTERNAL_LIT: "/usr/local/bin/lit" - ENABLE_SANITIZER_UNDEFINED_BEHAVIOR: ${{ matrix.sanitizers }} - ENABLE_SANITIZER_ADDRESS: ${{ matrix.sanitizers }} - - steps: - - name: Clone the Patchestry repository - uses: actions/checkout@v4 - with: - submodules: true - fetch-depth: 1 - - - name: Install CTest dependencies - run: | - sudo apt-get update - sudo apt-get install -y \ - software-properties-common \ - ninja-build python3-pip \ - ccache cmake lld lcov \ - doxygen libzstd-dev - - curl -fsSL https://get.docker.com -o get-docker.sh \ - && sh get-docker.sh \ - && rm get-docker.sh - - sudo apt-get -y purge llvm-14 clang-14 - pip3 install lit codespell jinja2 Pygments - - curl -fsSL https://apt.llvm.org/llvm.sh -o llvm.sh && \ - chmod +x llvm.sh && \ - sudo ./llvm.sh ${{ matrix.llvm-version }} all && \ - rm llvm.sh - - sudo apt-get install libmlir-${{ matrix.llvm-version }}-dev mlir-${{ matrix.llvm-version }}-tools - sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++-${{ matrix.llvm-version }} 60 - sudo update-alternatives --install /usr/bin/cc cc /usr/bin/clang-${{ matrix.llvm-version }} 60 - sudo ln -s /usr/bin/FileCheck-${{ matrix.llvm-version }} /usr/bin/FileCheck - - - name: Run CTest + - name: Test ${{ matrix.build-type }} with sanitizers set ${{ matrix.sanitizers }} run: | cmake --preset ci - ctest --preset ci --build-config ${{ matrix.build-type }} \ No newline at end of file + ctest --preset ci --build-config ${{ matrix.build-type }} diff --git a/test/lit.cfg.py b/test/lit.cfg.py index 763ebc4..5ddbeda 100644 --- a/test/lit.cfg.py +++ b/test/lit.cfg.py @@ -51,28 +51,29 @@ ToolSubst('%cc', command=FindTool('clang')), ToolSubst('%cxx', command=FindTool('clang++')), ToolSubst('%host_cc', command=config.host_cc), - ToolSubst('%host_cxx', command=config.host_cxx) + ToolSubst('%host_cxx', command=config.host_cxx), + ToolSubst('%decompile-headless', command=config.decompiler_headless_tool) ] # Process tool substitutions for tool in tools: llvm_config.add_tool_substitutions([tool]) -# Add test directory to substitutions -config.substitutions.append(('%test_dir', os.path.join(config.test_source_root, 'ghidra'))) +# # Add test directory to substitutions +# config.substitutions.append(('%test_dir', os.path.join(config.test_source_root, 'ghidra'))) # Add PATH to substitutions config.substitutions.append(('%PATH%', config.environment['PATH'])) -config.substitutions.append( - ('%decompile-headless', - f"'{config.python_executable}' -c '" - f"import subprocess;" - f"import sys;" - f"args = sys.argv[1:4];" - f"print(args);" - f"args[1] = \"{config.function_prefix}\" + args[1]; " - f"result = subprocess.run([\"{config.decompiler_headless_tool}\"] + args, capture_output=True, text=True); " - f"print(result.stdout + result.stderr); " - f"sys.exit(result.returncode)' ") -) \ No newline at end of file +# config.substitutions.append( +# ('%decompile-headless', config.decompiler_headless_tool +# f"'{config.python_executable}' -c '" +# f"import subprocess;" +# f"import sys;" +# f"args = sys.argv[1:4];" +# f"print(args);" +# f"args[1] = \"{config.function_prefix}\" + args[1]; " +# f"result = subprocess.run([\"{config.decompiler_headless_tool}\"] + args, capture_output=True, text=True); " +# f"print(result.stdout + result.stderr); " +# f"sys.exit(result.returncode)' ") +# ) From 597d3496d2c9ffd96069dba9de4e375f844c051e Mon Sep 17 00:00:00 2001 From: xlauko Date: Thu, 5 Sep 2024 10:59:36 +0200 Subject: [PATCH 06/12] scripts: Rename DecompileHeadless. --- ...DecompileHeadless.Dockerfile => decompile-headless.dockerfile} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename scripts/ghidra/{DecompileHeadless.Dockerfile => decompile-headless.dockerfile} (100%) diff --git a/scripts/ghidra/DecompileHeadless.Dockerfile b/scripts/ghidra/decompile-headless.dockerfile similarity index 100% rename from scripts/ghidra/DecompileHeadless.Dockerfile rename to scripts/ghidra/decompile-headless.dockerfile From 6fe89a8ebb297e12615e4dbecfdeb7080bdf072c Mon Sep 17 00:00:00 2001 From: xlauko Date: Thu, 5 Sep 2024 11:00:45 +0200 Subject: [PATCH 07/12] treewide: Make cmake prebuild decompile headless docker for tests. --- scripts/ghidra/README.md | 9 +++++---- scripts/ghidra/build-headless-docker.sh | 21 +++++++++++++++++++++ scripts/ghidra/decompile-headless.sh | 11 ----------- test/CMakeLists.txt | 20 +++++++++++--------- 4 files changed, 37 insertions(+), 24 deletions(-) create mode 100644 scripts/ghidra/build-headless-docker.sh diff --git a/scripts/ghidra/README.md b/scripts/ghidra/README.md index 88d67af..7c041c5 100644 --- a/scripts/ghidra/README.md +++ b/scripts/ghidra/README.md @@ -13,14 +13,15 @@ Before running the scripts, make sure you have the following installed: - **Docker**: The scripts use a Docker container to run Ghidra in headless mode. +To perform headless decompilation, you need to build a Docker container (`decompile-headless.dockerfile`) configured to run Ghidra in headless mode. You can do this by running the `build-headless-docker.sh` script. + ## Running Headless Decompilation Script To decompile and extract pcode for a specific function from a binary file, use the `decompile-headless.sh` script. This script extracts the pcode for the -specified function and writes the output to a file named `patchestry.out.json` -in the output directory. +specified function and writes the json output to a file named ``. -```bash ./decompile-headless.sh ``` +```sh ./decompile-headless.sh ``` ## Running Patchestry via Ghidra GUI @@ -38,4 +39,4 @@ in the output directory. 4. Run `PatchestryScript.java`. -**Note:** Ghidra scripts must be installed. See the [build](build.md) section for details. \ No newline at end of file +**Note:** Ghidra scripts must be installed. See the [build](build.md) section for details. diff --git a/scripts/ghidra/build-headless-docker.sh b/scripts/ghidra/build-headless-docker.sh new file mode 100644 index 0000000..4ca580f --- /dev/null +++ b/scripts/ghidra/build-headless-docker.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +# Get the directory of the current script +SCRIPTS_DIR="$(dirname "$(realpath "${BASH_SOURCE[0]}")")" + +# Print the script directory (for debugging purposes, can be removed) +echo "Using SCRIPTS_DIR: $SCRIPTS_DIR" + +# Build the Docker image +docker build \ + -t trailofbits/patchestry-decompilation:latest \ + -f "${SCRIPTS_DIR}/decompile-headless.dockerfile" \ + "${SCRIPTS_DIR}" + +# Check if the Docker build was successful +if [ $? -eq 0 ]; then + echo "Docker image built successfully." +else + echo "Error: Docker build failed." + exit 1 +fi diff --git a/scripts/ghidra/decompile-headless.sh b/scripts/ghidra/decompile-headless.sh index c2602d9..6f06e6d 100755 --- a/scripts/ghidra/decompile-headless.sh +++ b/scripts/ghidra/decompile-headless.sh @@ -17,17 +17,6 @@ INPUT_PATH=$1 FUNCTION_NAME=$2 OUTPUT_PATH=$3 -# Create docker container and run the decompilation -docker build \ - -t trailofbits/patchestry-decompilation:latest \ - -f ${SCRIPTS_DIR}/DecompileHeadless.Dockerfile \ - ${SCRIPTS_DIR} - -if [ $? -ne 0 ]; then - echo "Docker build failed" - exit 1 -fi - # Make sure $OUTPUT_PATH exists and is empty so that it can be # mounted to the container if [ ! -f $OUTPUT_PATH ]; then diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 57d4de7..5105c0f 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -6,12 +6,12 @@ cmake_minimum_required(VERSION 3.25) include(CTest) -find_package(Python REQUIRED COMPONENTS Interpreter) -if (Python_Interpreter_FOUND) - set(PYTHON_EXECUTABLE ${Python_EXECUTABLE}) -endif() +add_custom_target(decompile_headless_docker + COMMAND sh ./scripts/ghidra/build-headless-docker.sh + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + COMMENT "Building decompile-headless docker image..." +) -# Configure the lit site configuration file configure_lit_site_cfg( ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg.py @@ -19,12 +19,14 @@ configure_lit_site_cfg( ${CMAKE_CURRENT_SOURCE_DIR}/lit.cfg.py ) -# Add a lit test suite named "PatchestryTest" -add_lit_testsuite(PatchestryTest "Running Patchestry tests" +add_lit_testsuite(headless-ghidra + "Running headless Ghidra decompilation tests" ${CMAKE_CURRENT_SOURCE_DIR}/ghidra + DEPENDS + decompile_headless_docker ) -# Add a CTest test that runs the lit test suite add_test(NAME lit COMMAND lit -v "${CMAKE_CURRENT_BINARY_DIR}/ghidra" - --param BUILD_TYPE=$) \ No newline at end of file + --param BUILD_TYPE=$ +) From 93b89c3f2a57f595d264a6a66136fe3710a9bdfe Mon Sep 17 00:00:00 2001 From: xlauko Date: Thu, 5 Sep 2024 13:06:25 +0200 Subject: [PATCH 08/12] treewide: Refactor headless container tooling and scripts. --- .github/workflows/ci.yml | 1 + scripts/ghidra/.dockerignore | 2 - scripts/ghidra/PatchestryScript.java | 10 +- scripts/ghidra/build-headless-docker.sh | 4 - .../{decompile.sh => decompile-entrypoint.sh} | 11 -- scripts/ghidra/decompile-headless.dockerfile | 28 +--- scripts/ghidra/decompile-headless.sh | 131 +++++++++++++++--- test/CMakeLists.txt | 8 -- 8 files changed, 125 insertions(+), 70 deletions(-) delete mode 100644 scripts/ghidra/.dockerignore rename scripts/ghidra/{decompile.sh => decompile-entrypoint.sh} (70%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2b0eb43..6aa3c58 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -63,5 +63,6 @@ jobs: - name: Test ${{ matrix.build-type }} with sanitizers set ${{ matrix.sanitizers }} run: | + bash ./scripts/ghidra/build-headless-docker.sh cmake --preset ci ctest --preset ci --build-config ${{ matrix.build-type }} diff --git a/scripts/ghidra/.dockerignore b/scripts/ghidra/.dockerignore deleted file mode 100644 index 5511b20..0000000 --- a/scripts/ghidra/.dockerignore +++ /dev/null @@ -1,2 +0,0 @@ -.ghidra -ghidra_scripts diff --git a/scripts/ghidra/PatchestryScript.java b/scripts/ghidra/PatchestryScript.java index 936a498..5f9f889 100644 --- a/scripts/ghidra/PatchestryScript.java +++ b/scripts/ghidra/PatchestryScript.java @@ -114,7 +114,7 @@ private void serializeToFile(Path file, Function function) throws Exception { println("Serializing function: " + function.getName() + " @ " + function.getEntryPoint()); serializer.serialize(function).close(); } - + private void runHeadless() throws Exception { final var args = getScriptArgs(); if (args.length != 2) { @@ -123,10 +123,10 @@ private void runHeadless() throws Exception { println("\tOUTPUT_FILE"); return; } - + final var functionName = args[0]; final var outputPath = args[1]; - + final var functions = getGlobalFunctions(functionName); if (functions.isEmpty()) { println("Function not found: " + functionName); @@ -144,12 +144,12 @@ private void runGUI() throws Exception { final var curFunction = getFunctionContaining(currentAddress); final var functionName = curFunction.getName(); final var jsonPath = Files.createTempFile(functionName + '.', ".patchestry.json"); - + serializeToFile(jsonPath, curFunction); final var mlirPath = Files.createTempFile(functionName + '.', ".patchestry.out"); final var binaryPath = "patchestry"; - + final var cmd = new ArrayList(); cmd.add(binaryPath); cmd.add(jsonPath.toString()); diff --git a/scripts/ghidra/build-headless-docker.sh b/scripts/ghidra/build-headless-docker.sh index 4ca580f..bde3f6a 100644 --- a/scripts/ghidra/build-headless-docker.sh +++ b/scripts/ghidra/build-headless-docker.sh @@ -1,18 +1,14 @@ #!/bin/bash -# Get the directory of the current script SCRIPTS_DIR="$(dirname "$(realpath "${BASH_SOURCE[0]}")")" -# Print the script directory (for debugging purposes, can be removed) echo "Using SCRIPTS_DIR: $SCRIPTS_DIR" -# Build the Docker image docker build \ -t trailofbits/patchestry-decompilation:latest \ -f "${SCRIPTS_DIR}/decompile-headless.dockerfile" \ "${SCRIPTS_DIR}" -# Check if the Docker build was successful if [ $? -eq 0 ]; then echo "Docker image built successfully." else diff --git a/scripts/ghidra/decompile.sh b/scripts/ghidra/decompile-entrypoint.sh similarity index 70% rename from scripts/ghidra/decompile.sh rename to scripts/ghidra/decompile-entrypoint.sh index e40c5d3..7bf13a7 100644 --- a/scripts/ghidra/decompile.sh +++ b/scripts/ghidra/decompile-entrypoint.sh @@ -7,8 +7,6 @@ # the LICENSE file found in the root directory of this source tree. # -set -x - if [ "$#" -lt 3 ]; then echo "Usage: $0 " exit 1 @@ -18,14 +16,6 @@ INPUT_PATH=$1 FUNCTION_NAME=$2 OUTPUT_PATH=$3 -# Running with non-root user may cause permission issue on ubuntu -# because binded directory will have root permission. -# This is a hacky fix to avoid the issue. It can be avoided -# by switching to using docker volume. -if [ ! -w ${OUTPUT_PATH} ]; then - sudo chown ${USER}:${USER} ${OUTPUT_PATH} -fi - # Create a new Ghidra project and import the file ${GHIDRA_HEADLESS} ${GHIDRA_PROJECTS} patchestry-decompilation \ -readOnly -deleteProject \ @@ -34,7 +24,6 @@ ${GHIDRA_HEADLESS} ${GHIDRA_PROJECTS} patchestry-decompilation \ $FUNCTION_NAME \ $OUTPUT_PATH - # Check if the decompile script was successful if [ $? -ne 0 ]; then echo "Decompilation failed" diff --git a/scripts/ghidra/decompile-headless.dockerfile b/scripts/ghidra/decompile-headless.dockerfile index aa40490..e1b80fb 100644 --- a/scripts/ghidra/decompile-headless.dockerfile +++ b/scripts/ghidra/decompile-headless.dockerfile @@ -2,14 +2,12 @@ FROM eclipse-temurin:17 AS base FROM base AS build -# Set environment variables for Ghidra ENV GHIDRA_VERSION=11.1.2 ENV GHIDRA_RELEASE_TAG=20240709 ENV GHIDRA_PACKAGE=ghidra_${GHIDRA_VERSION}_PUBLIC_${GHIDRA_RELEASE_TAG} ENV GHIDRA_SHA256=219ec130b901645779948feeb7cc86f131dd2da6c36284cf538c3a7f3d44b588 ENV GHIDRA_REPOSITORY=https://github.com/NationalSecurityAgency/ghidra -# Update and install necessary packages RUN apt-get update && apt-get install -y \ wget \ ca-certificates \ @@ -17,7 +15,6 @@ RUN apt-get update && apt-get install -y \ --no-install-recommends && \ apt-get clean && rm -rf /var/lib/apt/lists/* /var/cache/apt/archives -# Download and verify Ghidra package RUN wget --progress=bar:force -O /tmp/ghidra.zip ${GHIDRA_REPOSITORY}/releases/download/Ghidra_${GHIDRA_VERSION}_build/${GHIDRA_PACKAGE}.zip && \ echo "${GHIDRA_SHA256} /tmp/ghidra.zip" | sha256sum -c - @@ -27,7 +24,6 @@ RUN unzip /tmp/ghidra.zip -d /tmp && \ chmod +x /ghidra/ghidraRun && \ rm -rf /var/tmp/* /tmp/* /ghidra/docs /ghidra/Extensions/Eclipse /ghidra/licenses -# Clean up RUN apt-get purge -y --auto-remove wget ca-certificates unzip && \ apt-get clean @@ -46,36 +42,20 @@ RUN adduser --shell /sbin/nologin --disabled-login --gecos "" user && \ adduser user sudo && \ echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers -# Switch to the newly created user USER user -# Set working directory for the user WORKDIR /home/user/ -# Copy Ghidra from the build stage -COPY --from=build /ghidra ghidra - -# Create projects and scripts directory -RUN mkdir ghidra_projects ghidra_scripts +RUN mkdir -p /home/user/ghidra_projects /home/user/ghidra_scripts -# Copy the Java and script files into the appropriate directories +COPY --from=build /ghidra ghidra COPY PatchestryScript.java ghidra_scripts/ -COPY decompile.sh decompile.sh - -# Make the decompile script executable -USER root -RUN chmod +x decompile.sh -USER user - -# Copy the .dockerignore file (if necessary) -COPY .dockerignore .dockerignore +COPY --chown=user:user --chmod=755 decompile-entrypoint.sh . -# Set environment variable for Ghidra home directory ENV GHIDRA_HOME=/home/user/ghidra ENV GHIDRA_SCRIPTS=/home/user/ghidra_scripts ENV GHIDRA_PROJECTS=/home/user/ghidra_projects ENV GHIDRA_HEADLESS=${GHIDRA_HOME}/support/analyzeHeadless ENV USER=user -# Set the entrypoint -ENTRYPOINT ["/home/user/decompile.sh"] +ENTRYPOINT ["/home/user/decompile-entrypoint.sh"] diff --git a/scripts/ghidra/decompile-headless.sh b/scripts/ghidra/decompile-headless.sh index 6f06e6d..1561ef1 100755 --- a/scripts/ghidra/decompile-headless.sh +++ b/scripts/ghidra/decompile-headless.sh @@ -6,26 +6,125 @@ # This source code is licensed in accordance with the terms specified in # the LICENSE file found in the root directory of this source tree. # -SCRIPTS_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) -if [ "$#" -lt 3 ]; then - echo "Usage: $0 " +show_help() { + echo "Usage: $0 [OPTIONS]" + echo + echo "Options:" + echo " -h, --help Show this help message and exit" + echo " -i, --input Path to the input file" + echo " -f, --function Name of the function to decompile" + echo " -o, --output Path to the output file where results will be saved" + echo " -v, --verbose Enable verbose output" + echo " -t, --interactive Start Docker container in interactive mode" + echo +} + +INPUT_PATH="" +FUNCTION_NAME="" +OUTPUT_PATH="" +VERBOSE=false +INTERACTIVE=false + +while [[ $# -gt 0 ]]; do + case "$1" in + -h|--help) + show_help + exit 0 + ;; + -i|--input) + INPUT_PATH="$2" + shift 2 + ;; + -f|--function) + FUNCTION_NAME="$2" + shift 2 + ;; + -o|--output) + OUTPUT_PATH="$2" + shift 2 + ;; + -v|--verbose) + VERBOSE=true + shift + ;; + -t|--interactive) + INTERACTIVE=true + shift + ;; + *) + echo "Unknown option: $1" + show_help + exit 1 + ;; + esac +done + +if [ -z "$INPUT_PATH" ]; then + echo "Error: Missing required option: -i, --input " + exit 1 +fi + +if [ -z "$FUNCTION_NAME" ]; then + echo "Error: Missing required option: -f, --function " exit 1 fi -INPUT_PATH=$1 -FUNCTION_NAME=$2 -OUTPUT_PATH=$3 +if [ -z "$OUTPUT_PATH" ]; then + echo "Error: Missing required option: -o, --output " + exit 1 +fi + +if [ "$VERBOSE" = true ]; then + echo "Input file: $INPUT_PATH" + echo "Function name: $FUNCTION_NAME" + echo "Output file: $OUTPUT_PATH" +fi + +if [ ! -e "$OUTPUT_PATH" ]; then + if [ "$VERBOSE" = true ]; then + echo "Creating output file: $OUTPUT_PATH" + fi + touch "$OUTPUT_PATH" +fi + +if [ "$VERBOSE" = true ]; then + echo "Running Docker container..." +fi + +absolute_path() { + if [[ "$1" = /* ]]; then + echo "$1" + else + echo "$(pwd)/$1" + fi +} + +INPUT_ABS_PATH=$(absolute_path "$INPUT_PATH") +OUTPUT_ABS_PATH=$(absolute_path "$OUTPUT_PATH") + +RUN="docker run --rm \ + -v \"$INPUT_ABS_PATH:/input.o\" \ + -v \"$OUTPUT_ABS_PATH:/output.json\" \ + trailofbits/patchestry-decompilation:latest" + +if file "$INPUT_PATH" | grep -q "Mach-O"; then + FUNCTION_NAME="_$FUNCTION_NAME" +fi + +if [ "$INTERACTIVE" = true ]; then + RUN=$(echo "$RUN" | sed 's/docker run --rm/docker run -it --rm --entrypoint \/bin\/bash/') +else + RUN="$RUN /input.o \"$FUNCTION_NAME\" /output.json" +fi + +if [ "$VERBOSE" = true ]; then + echo "Running Docker container with the following command:" + echo "$RUN" +fi -# Make sure $OUTPUT_PATH exists and is empty so that it can be -# mounted to the container -if [ ! -f $OUTPUT_PATH ]; then - touch $OUTPUT_PATH +if [ "$VERBOSE" = true ]; then + echo "Starting Docker container..." fi -truncate -s 0 $OUTPUT_PATH -docker run --rm \ - -v $INPUT_PATH:/input \ - -v $OUTPUT_PATH:/output \ - trailofbits/patchestry-decompilation:latest \ - /input $FUNCTION_NAME /output +eval "$RUN" diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 5105c0f..240345e 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -6,12 +6,6 @@ cmake_minimum_required(VERSION 3.25) include(CTest) -add_custom_target(decompile_headless_docker - COMMAND sh ./scripts/ghidra/build-headless-docker.sh - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - COMMENT "Building decompile-headless docker image..." -) - configure_lit_site_cfg( ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg.py @@ -22,8 +16,6 @@ configure_lit_site_cfg( add_lit_testsuite(headless-ghidra "Running headless Ghidra decompilation tests" ${CMAKE_CURRENT_SOURCE_DIR}/ghidra - DEPENDS - decompile_headless_docker ) add_test(NAME lit From 7b7a9b4396377b35a59e68fc719b5eb0e650b79e Mon Sep 17 00:00:00 2001 From: xlauko Date: Thu, 5 Sep 2024 15:05:57 +0200 Subject: [PATCH 09/12] test: Update ghidra test run commands. --- test/ghidra/argc.c | 11 ++++++----- test/ghidra/array.c | 7 ++++--- test/ghidra/concat.c | 7 ++++--- test/ghidra/fib.c | 7 ++++--- test/ghidra/fread.c | 8 +++++--- test/ghidra/fwrite.c | 7 ++++--- test/ghidra/insert.c | 7 ++++--- test/ghidra/list.c | 7 ++++--- test/ghidra/matrix.c | 6 ++++-- test/ghidra/prime.c | 7 ++++--- test/ghidra/queue.c | 7 +++++-- test/ghidra/reverse.c | 8 +++++--- test/ghidra/sort.c | 14 ++++++++------ test/ghidra/struct.c | 8 +++++--- test/ghidra/structb.c | 7 +++++-- test/ghidra/sub.c | 8 +++++--- test/ghidra/test.c | 8 +++++--- test/ghidra/union.c | 8 +++++--- 18 files changed, 86 insertions(+), 56 deletions(-) diff --git a/test/ghidra/argc.c b/test/ghidra/argc.c index fad3fdc..9560a73 100644 --- a/test/ghidra/argc.c +++ b/test/ghidra/argc.c @@ -1,10 +1,11 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t && %decompile-headless %t argc %t1 && %file-check -vv %s --input-file %t1 -// CHECK: {{...}} +// RUN: %cc %s -o %t.o +// RUN: %decompile-headless --input %t.o --function argc --output %t +// RUN: %file-check -vv %s --input-file %t +// CHECK: "name":"{{_?argc}}" + +int argc(int argc, char **argv) { return argc; } -int argc(int argc, char **argv) { - return argc; -} int main(int a, char **argv) { return argc(a, argv); diff --git a/test/ghidra/array.c b/test/ghidra/array.c index 721f772..4517bd5 100644 --- a/test/ghidra/array.c +++ b/test/ghidra/array.c @@ -1,6 +1,8 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t && %decompile-headless %t array %t1 && %file-check %s --input-file %t1 -// CHECK: {{...}} +// RUN: %cc %s -o %t.o +// RUN: %decompile-headless --input %t.o --function array --output %t +// RUN: %file-check -vv %s --input-file %t +// CHECK: "name":"{{_?array}}" #include #include @@ -26,4 +28,3 @@ int main(int a, char **argv) { return array(a, argv); } - diff --git a/test/ghidra/concat.c b/test/ghidra/concat.c index 6e6afaf..aa1faa8 100644 --- a/test/ghidra/concat.c +++ b/test/ghidra/concat.c @@ -1,6 +1,8 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t && %decompile-headless %t string_concat %t1 && %file-check %s --input-file %t1 -// CHECK: {{...}} +// RUN: %cc %s -o %t.o +// RUN: %decompile-headless --input %t.o --function string_concat --output %t +// RUN: %file-check -vv %s --input-file %t +// CHECK: "name":"{{_?string_concat}}" #include #include @@ -16,4 +18,3 @@ int main() { printf("%s\n", string_concat(dest, src)); return 0; } - diff --git a/test/ghidra/fib.c b/test/ghidra/fib.c index 391186d..94558b8 100644 --- a/test/ghidra/fib.c +++ b/test/ghidra/fib.c @@ -1,6 +1,8 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t && %decompile-headless %t fibonacci %t1 && %file-check %s --input-file %t1 -// CHECK: {{...}} +// RUN: %cc %s -o %t.o +// RUN: %decompile-headless --input %t.o --function fibonacci --output %t +// RUN: %file-check -vv %s --input-file %t +// CHECK: "name":"{{_?fibonacci}}" #include @@ -14,4 +16,3 @@ int main() { printf("%d: %d\n", n, fibonacci(n)); return 0; } - diff --git a/test/ghidra/fread.c b/test/ghidra/fread.c index e4acfee..ec7426b 100644 --- a/test/ghidra/fread.c +++ b/test/ghidra/fread.c @@ -1,6 +1,8 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t && %decompile-headless %t fread_test %t1 && %file-check %s --input-file %t1 -// CHECK: {{...}} +// RUN: %cc %s -o %t.o +// RUN: %decompile-headless --input %t.o --function fread_test --output %t +// RUN: %file-check -vv %s --input-file %t +// CHECK: "name":"{{_?fread_test}}" #include @@ -22,4 +24,4 @@ int fread_test(void) { int main(void) { return fread_test(); -} \ No newline at end of file +} diff --git a/test/ghidra/fwrite.c b/test/ghidra/fwrite.c index 73db3fc..1797137 100644 --- a/test/ghidra/fwrite.c +++ b/test/ghidra/fwrite.c @@ -1,6 +1,8 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t && %decompile-headless %t write_file %t1 && %file-check %s --input-file %t1 -// CHECK: {{...}} +// RUN: %cc %s -o %t.o +// RUN: %decompile-headless --input %t.o --function write_file --output %t +// RUN: %file-check -vv %s --input-file %t +// CHECK: "name":"{{_?write_file}}" #include @@ -19,4 +21,3 @@ int main() { write_file(filename, content); return 0; } - diff --git a/test/ghidra/insert.c b/test/ghidra/insert.c index ac81243..0ac4a9a 100644 --- a/test/ghidra/insert.c +++ b/test/ghidra/insert.c @@ -1,6 +1,8 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t && %decompile-headless %t insert_substring %t1 && %file-check %s --input-file %t1 -// CHECK: {{...}} +// RUN: %cc %s -o %t.o +// RUN: %decompile-headless --input %t.o --function insert_substring --output %t +// RUN: %file-check -vv %s --input-file %t +// CHECK: "name":"{{_?insert_substring}}" #include #include @@ -21,4 +23,3 @@ int main() { printf("After insertion: %s\n", str); return 0; } - diff --git a/test/ghidra/list.c b/test/ghidra/list.c index a1f5175..e31e51b 100644 --- a/test/ghidra/list.c +++ b/test/ghidra/list.c @@ -1,6 +1,8 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t && %decompile-headless %t print_list %t1 && %file-check %s --input-file %t1 -// CHECK: {{...}} +// RUN: %cc %s -o %t.o +// RUN: %decompile-headless --input %t.o --function print_list --output %t +// RUN: %file-check -vv %s --input-file %t +// CHECK: "name":"{{_?print_list}}" #include #include @@ -41,4 +43,3 @@ int main(void) { return 0; } - diff --git a/test/ghidra/matrix.c b/test/ghidra/matrix.c index 51a408e..02ae431 100644 --- a/test/ghidra/matrix.c +++ b/test/ghidra/matrix.c @@ -1,6 +1,8 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t && %decompile-headless %t multiply_matrices %t1 && %file-check %s --input-file %t1 -// CHECK: {{...}} +// RUN: %cc %s -o %t.o +// RUN: %decompile-headless --input %t.o --function multiply_matrices --output %t +// RUN: %file-check -vv %s --input-file %t +// CHECK: "name":"{{_?multiply_matrices}}" #include diff --git a/test/ghidra/prime.c b/test/ghidra/prime.c index ee28315..6f32eb2 100644 --- a/test/ghidra/prime.c +++ b/test/ghidra/prime.c @@ -1,6 +1,8 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t && %decompile-headless %t is_prime %t1 && %file-check %s --input-file %t1 -// CHECK: {{...}} +// RUN: %cc %s -o %t.o +// RUN: %decompile-headless --input %t.o --function is_prime --output %t +// RUN: %file-check -vv %s --input-file %t +// CHECK: "name":"{{_?is_prime}}" #include #include @@ -18,4 +20,3 @@ int main() { printf("is prime: %d\n", is_prime(n)); return 0; } - diff --git a/test/ghidra/queue.c b/test/ghidra/queue.c index 0c2ad3e..4230815 100644 --- a/test/ghidra/queue.c +++ b/test/ghidra/queue.c @@ -1,6 +1,9 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t && %decompile-headless %t dequeue %t1 && %file-check %s --input-file %t1 -// CHECK: {{...}} +// RUN: %cc %s -o %t.o +// RUN: %decompile-headless --input %t.o --function dequeue --output %t +// RUN: %file-check -vv %s --input-file %t +// CHECK: "name":"{{_?dequeue}}" + #include #include diff --git a/test/ghidra/reverse.c b/test/ghidra/reverse.c index 4c3b273..6033cd0 100644 --- a/test/ghidra/reverse.c +++ b/test/ghidra/reverse.c @@ -1,6 +1,8 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t && %decompile-headless %t reverse_string %t1 && %file-check %s --input-file %t1 -// CHECK: {{...}} +// RUN: %cc %s -o %t.o +// RUN: %decompile-headless --input %t.o --function reverse_string --output %t +// RUN: %file-check -vv %s --input-file %t +// CHECK: "name":"{{_?reverse_string}}" #include #include @@ -19,4 +21,4 @@ int main(void) { reverse_string(str); printf("Reversed: %s\n", str); return 0; -} \ No newline at end of file +} diff --git a/test/ghidra/sort.c b/test/ghidra/sort.c index be7c6c4..b3373f6 100644 --- a/test/ghidra/sort.c +++ b/test/ghidra/sort.c @@ -1,16 +1,18 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t && %decompile-headless %t sort_test %t1 && %file-check %s --input-file %t1 -// CHECK: {{...}} +// RUN: %cc %s -o %t.o +// RUN: %decompile-headless --input %t.o --function sort_test --output %t +// RUN: %file-check -vv %s --input-file %t +// CHECK: "name":"{{_?sort_test}}" #include - + int sort_test() { int array[100], n, c, d, swap; scanf("%d", &n); for (c = 0; c < n; c++) scanf("%d", &array[c]); - + for (c = 0 ; c < n - 1; c++) { for (d = 0 ; d < n - c - 1; d++) { if (array[d] > array[d+1]) { @@ -20,10 +22,10 @@ int sort_test() } } } - + for (c = 0; c < n; c++) printf("%d\n", array[c]); - + return 0; } diff --git a/test/ghidra/struct.c b/test/ghidra/struct.c index 46fd913..e19e394 100644 --- a/test/ghidra/struct.c +++ b/test/ghidra/struct.c @@ -1,6 +1,8 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t && %decompile-headless %t struct_test %t1 && %file-check %s --input-file %t1 -// CHECK: {{...}} +// RUN: %cc %s -o %t.o +// RUN: %decompile-headless --input %t.o --function struct_test --output %t +// RUN: %file-check -vv %s --input-file %t +// CHECK: "name":"{{_?struct_test}}" struct data { @@ -20,4 +22,4 @@ int struct_test(int argc, char **argv) int main(int argc, char **argv) { return struct_test(argc, argv); -} \ No newline at end of file +} diff --git a/test/ghidra/structb.c b/test/ghidra/structb.c index 6a16b9a..31da470 100644 --- a/test/ghidra/structb.c +++ b/test/ghidra/structb.c @@ -1,6 +1,9 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t && %decompile-headless %t structb %t1 && %file-check %s --input-file %t1 -// CHECK: {{...}} +// RUN: %cc %s -o %t.o +// RUN: %decompile-headless --input %t.o --function structb --output %t +// RUN: %file-check -vv %s --input-file %t +// CHECK: "name":"{{_?structb}}" + #include diff --git a/test/ghidra/sub.c b/test/ghidra/sub.c index fad7c72..47d2f6f 100644 --- a/test/ghidra/sub.c +++ b/test/ghidra/sub.c @@ -1,12 +1,14 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t && %decompile-headless %t sub %t1 && %file-check %s --input-file %t1 -// CHECK: {{...}} +// RUN: %cc %s -o %t.o +// RUN: %decompile-headless --input %t.o --function sub --output %t +// RUN: %file-check -vv %s --input-file %t +// CHECK: "name":"{{_?sub}}" #include int sub() { - int x; + int x; x = 4; return x - 4; } diff --git a/test/ghidra/test.c b/test/ghidra/test.c index e174b31..7f82776 100644 --- a/test/ghidra/test.c +++ b/test/ghidra/test.c @@ -1,6 +1,8 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t && %decompile-headless %t test %t1 && %file-check %s --input-file %t1 -// CHECK: {{...}} +// RUN: %cc %s -o %t.o +// RUN: %decompile-headless --input %t.o --function test --output %t +// RUN: %file-check -vv %s --input-file %t +// CHECK: "name":"{{_?test}}" #include @@ -11,4 +13,4 @@ int test() { int main(void) { return test(); -} \ No newline at end of file +} diff --git a/test/ghidra/union.c b/test/ghidra/union.c index 93bcdfc..aafbad4 100644 --- a/test/ghidra/union.c +++ b/test/ghidra/union.c @@ -1,6 +1,8 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t && %decompile-headless %t union_test %t1 && %file-check %s --input-file %t1 -// CHECK: {{...}} +// RUN: %cc %s -o %t.o +// RUN: %decompile-headless --input %t.o --function union_test --output %t +// RUN: %file-check -vv %s --input-file %t +// CHECK: "name":"{{_?union_test}}" struct access { @@ -23,4 +25,4 @@ int union_test(int argc, char **argv) int main(int argc, char **argv) { return union_test(argc, argv); -} \ No newline at end of file +} From 3f3aa1c25b897cee471ed87e81d267478989ec85 Mon Sep 17 00:00:00 2001 From: xlauko Date: Thu, 5 Sep 2024 17:32:29 +0200 Subject: [PATCH 10/12] devcontainer: Add `file` to dependencies. --- .devcontainer/dependencies.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/dependencies.txt b/.devcontainer/dependencies.txt index 01c1598..0f613ec 100644 --- a/.devcontainer/dependencies.txt +++ b/.devcontainer/dependencies.txt @@ -1 +1 @@ -software-properties-common ninja-build python3-pip ccache cmake lld lcov doxygen libzstd-dev +software-properties-common ninja-build python3-pip ccache cmake lld lcov doxygen libzstd-dev file From f391d302933dd01a6a97ace4bd8fed3f6a1f7c7f Mon Sep 17 00:00:00 2001 From: xlauko Date: Fri, 6 Sep 2024 12:40:49 +0200 Subject: [PATCH 11/12] test: Add debug info to ghidra tests. --- test/ghidra/argc.c | 2 +- test/ghidra/array.c | 2 +- test/ghidra/concat.c | 2 +- test/ghidra/fib.c | 2 +- test/ghidra/fread.c | 2 +- test/ghidra/fwrite.c | 2 +- test/ghidra/insert.c | 2 +- test/ghidra/list.c | 2 +- test/ghidra/matrix.c | 2 +- test/ghidra/prime.c | 2 +- test/ghidra/queue.c | 2 +- test/ghidra/reverse.c | 2 +- test/ghidra/sort.c | 2 +- test/ghidra/struct.c | 2 +- test/ghidra/structb.c | 2 +- test/ghidra/sub.c | 2 +- test/ghidra/test.c | 2 +- test/ghidra/union.c | 2 +- 18 files changed, 18 insertions(+), 18 deletions(-) diff --git a/test/ghidra/argc.c b/test/ghidra/argc.c index 9560a73..7ff3561 100644 --- a/test/ghidra/argc.c +++ b/test/ghidra/argc.c @@ -1,5 +1,5 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t.o +// RUN: %cc %s -g -o %t.o // RUN: %decompile-headless --input %t.o --function argc --output %t // RUN: %file-check -vv %s --input-file %t // CHECK: "name":"{{_?argc}}" diff --git a/test/ghidra/array.c b/test/ghidra/array.c index 4517bd5..b89cdd5 100644 --- a/test/ghidra/array.c +++ b/test/ghidra/array.c @@ -1,5 +1,5 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t.o +// RUN: %cc %s -g -o %t.o // RUN: %decompile-headless --input %t.o --function array --output %t // RUN: %file-check -vv %s --input-file %t // CHECK: "name":"{{_?array}}" diff --git a/test/ghidra/concat.c b/test/ghidra/concat.c index aa1faa8..11538d5 100644 --- a/test/ghidra/concat.c +++ b/test/ghidra/concat.c @@ -1,5 +1,5 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t.o +// RUN: %cc %s -g -o %t.o // RUN: %decompile-headless --input %t.o --function string_concat --output %t // RUN: %file-check -vv %s --input-file %t // CHECK: "name":"{{_?string_concat}}" diff --git a/test/ghidra/fib.c b/test/ghidra/fib.c index 94558b8..29a47b9 100644 --- a/test/ghidra/fib.c +++ b/test/ghidra/fib.c @@ -1,5 +1,5 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t.o +// RUN: %cc %s -g -o %t.o // RUN: %decompile-headless --input %t.o --function fibonacci --output %t // RUN: %file-check -vv %s --input-file %t // CHECK: "name":"{{_?fibonacci}}" diff --git a/test/ghidra/fread.c b/test/ghidra/fread.c index ec7426b..9588669 100644 --- a/test/ghidra/fread.c +++ b/test/ghidra/fread.c @@ -1,5 +1,5 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t.o +// RUN: %cc %s -g -o %t.o // RUN: %decompile-headless --input %t.o --function fread_test --output %t // RUN: %file-check -vv %s --input-file %t // CHECK: "name":"{{_?fread_test}}" diff --git a/test/ghidra/fwrite.c b/test/ghidra/fwrite.c index 1797137..c0e2311 100644 --- a/test/ghidra/fwrite.c +++ b/test/ghidra/fwrite.c @@ -1,5 +1,5 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t.o +// RUN: %cc %s -g -o %t.o // RUN: %decompile-headless --input %t.o --function write_file --output %t // RUN: %file-check -vv %s --input-file %t // CHECK: "name":"{{_?write_file}}" diff --git a/test/ghidra/insert.c b/test/ghidra/insert.c index 0ac4a9a..d3a0d7f 100644 --- a/test/ghidra/insert.c +++ b/test/ghidra/insert.c @@ -1,5 +1,5 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t.o +// RUN: %cc %s -g -o %t.o // RUN: %decompile-headless --input %t.o --function insert_substring --output %t // RUN: %file-check -vv %s --input-file %t // CHECK: "name":"{{_?insert_substring}}" diff --git a/test/ghidra/list.c b/test/ghidra/list.c index e31e51b..e377736 100644 --- a/test/ghidra/list.c +++ b/test/ghidra/list.c @@ -1,5 +1,5 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t.o +// RUN: %cc %s -g -o %t.o // RUN: %decompile-headless --input %t.o --function print_list --output %t // RUN: %file-check -vv %s --input-file %t // CHECK: "name":"{{_?print_list}}" diff --git a/test/ghidra/matrix.c b/test/ghidra/matrix.c index 02ae431..b85f040 100644 --- a/test/ghidra/matrix.c +++ b/test/ghidra/matrix.c @@ -1,5 +1,5 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t.o +// RUN: %cc %s -g -o %t.o // RUN: %decompile-headless --input %t.o --function multiply_matrices --output %t // RUN: %file-check -vv %s --input-file %t // CHECK: "name":"{{_?multiply_matrices}}" diff --git a/test/ghidra/prime.c b/test/ghidra/prime.c index 6f32eb2..7d858ad 100644 --- a/test/ghidra/prime.c +++ b/test/ghidra/prime.c @@ -1,5 +1,5 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t.o +// RUN: %cc %s -g -o %t.o // RUN: %decompile-headless --input %t.o --function is_prime --output %t // RUN: %file-check -vv %s --input-file %t // CHECK: "name":"{{_?is_prime}}" diff --git a/test/ghidra/queue.c b/test/ghidra/queue.c index 4230815..8ab345f 100644 --- a/test/ghidra/queue.c +++ b/test/ghidra/queue.c @@ -1,5 +1,5 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t.o +// RUN: %cc %s -g -o %t.o // RUN: %decompile-headless --input %t.o --function dequeue --output %t // RUN: %file-check -vv %s --input-file %t // CHECK: "name":"{{_?dequeue}}" diff --git a/test/ghidra/reverse.c b/test/ghidra/reverse.c index 6033cd0..7d9ba8f 100644 --- a/test/ghidra/reverse.c +++ b/test/ghidra/reverse.c @@ -1,5 +1,5 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t.o +// RUN: %cc %s -g -o %t.o // RUN: %decompile-headless --input %t.o --function reverse_string --output %t // RUN: %file-check -vv %s --input-file %t // CHECK: "name":"{{_?reverse_string}}" diff --git a/test/ghidra/sort.c b/test/ghidra/sort.c index b3373f6..f6817e8 100644 --- a/test/ghidra/sort.c +++ b/test/ghidra/sort.c @@ -1,5 +1,5 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t.o +// RUN: %cc %s -g -o %t.o // RUN: %decompile-headless --input %t.o --function sort_test --output %t // RUN: %file-check -vv %s --input-file %t // CHECK: "name":"{{_?sort_test}}" diff --git a/test/ghidra/struct.c b/test/ghidra/struct.c index e19e394..8baf2f1 100644 --- a/test/ghidra/struct.c +++ b/test/ghidra/struct.c @@ -1,5 +1,5 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t.o +// RUN: %cc %s -g -o %t.o // RUN: %decompile-headless --input %t.o --function struct_test --output %t // RUN: %file-check -vv %s --input-file %t // CHECK: "name":"{{_?struct_test}}" diff --git a/test/ghidra/structb.c b/test/ghidra/structb.c index 31da470..58eee06 100644 --- a/test/ghidra/structb.c +++ b/test/ghidra/structb.c @@ -1,5 +1,5 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t.o +// RUN: %cc %s -g -o %t.o // RUN: %decompile-headless --input %t.o --function structb --output %t // RUN: %file-check -vv %s --input-file %t // CHECK: "name":"{{_?structb}}" diff --git a/test/ghidra/sub.c b/test/ghidra/sub.c index 47d2f6f..029965e 100644 --- a/test/ghidra/sub.c +++ b/test/ghidra/sub.c @@ -1,5 +1,5 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t.o +// RUN: %cc %s -g -o %t.o // RUN: %decompile-headless --input %t.o --function sub --output %t // RUN: %file-check -vv %s --input-file %t // CHECK: "name":"{{_?sub}}" diff --git a/test/ghidra/test.c b/test/ghidra/test.c index 7f82776..bbbd13a 100644 --- a/test/ghidra/test.c +++ b/test/ghidra/test.c @@ -1,5 +1,5 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t.o +// RUN: %cc %s -g -o %t.o // RUN: %decompile-headless --input %t.o --function test --output %t // RUN: %file-check -vv %s --input-file %t // CHECK: "name":"{{_?test}}" diff --git a/test/ghidra/union.c b/test/ghidra/union.c index aafbad4..0ec3be6 100644 --- a/test/ghidra/union.c +++ b/test/ghidra/union.c @@ -1,5 +1,5 @@ // UNSUPPORTED: system-windows -// RUN: %cc %s -o %t.o +// RUN: %cc %s -g -o %t.o // RUN: %decompile-headless --input %t.o --function union_test --output %t // RUN: %file-check -vv %s --input-file %t // CHECK: "name":"{{_?union_test}}" From 8233f0c908c4c7612528c27e61c139a8f0d579f9 Mon Sep 17 00:00:00 2001 From: xlauko Date: Thu, 5 Sep 2024 15:46:51 +0200 Subject: [PATCH 12/12] treewide: Integrate CI with new decompilation scripts. --- .github/workflows/ci.yml | 7 +- scripts/ghidra/README.md | 2 +- scripts/ghidra/decompile-entrypoint.sh | 17 ++ scripts/ghidra/decompile-headless.sh | 221 +++++++++++++------------ test/ghidra/argc.c | 2 +- test/ghidra/array.c | 2 +- test/ghidra/concat.c | 2 +- test/ghidra/fib.c | 2 +- test/ghidra/fread.c | 2 +- test/ghidra/fwrite.c | 2 +- test/ghidra/insert.c | 2 +- test/ghidra/list.c | 2 +- test/ghidra/matrix.c | 2 +- test/ghidra/prime.c | 2 +- test/ghidra/queue.c | 2 +- test/ghidra/reverse.c | 2 +- test/ghidra/sort.c | 2 +- test/ghidra/struct.c | 2 +- test/ghidra/structb.c | 2 +- test/ghidra/sub.c | 2 +- test/ghidra/test.c | 2 +- test/ghidra/union.c | 2 +- test/lit.cfg.py | 25 +-- 23 files changed, 156 insertions(+), 152 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6aa3c58..fd3df62 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -61,8 +61,9 @@ jobs: - name: Build ${{ matrix.build-type }} with sanitizers set ${{ matrix.sanitizers }} run: cmake --build --preset ci --config ${{ matrix.build-type }} -j $(nproc) + - name: Build the headless docker image + run: bash ./scripts/ghidra/build-headless-docker.sh + - name: Test ${{ matrix.build-type }} with sanitizers set ${{ matrix.sanitizers }} run: | - bash ./scripts/ghidra/build-headless-docker.sh - cmake --preset ci - ctest --preset ci --build-config ${{ matrix.build-type }} + lit ./builds/ci/test -v -DCI_OUTPUT_FOLDER=${{ github.workspace }}/builds/ci/test/ghidra/Output diff --git a/scripts/ghidra/README.md b/scripts/ghidra/README.md index 7c041c5..0738428 100644 --- a/scripts/ghidra/README.md +++ b/scripts/ghidra/README.md @@ -21,7 +21,7 @@ To decompile and extract pcode for a specific function from a binary file, use the `decompile-headless.sh` script. This script extracts the pcode for the specified function and writes the json output to a file named ``. -```sh ./decompile-headless.sh ``` +```sh ./decompile-headless.sh --input --function --output ``` ## Running Patchestry via Ghidra GUI diff --git a/scripts/ghidra/decompile-entrypoint.sh b/scripts/ghidra/decompile-entrypoint.sh index 7bf13a7..ad92b9f 100644 --- a/scripts/ghidra/decompile-entrypoint.sh +++ b/scripts/ghidra/decompile-entrypoint.sh @@ -13,8 +13,25 @@ if [ "$#" -lt 3 ]; then fi INPUT_PATH=$1 +if [ ! -f $INPUT_PATH ]; then + echo "Input file does not exist" + exit 1 +fi + FUNCTION_NAME=$2 OUTPUT_PATH=$3 +if [ ! -f $OUTPUT_PATH ]; then + echo "Output file does not exist" + exit 1 +fi + +if [ ! -w "$OUTPUT_PATH" ]; then + sudo chmod 777 "$OUTPUT_PATH" 2>/dev/null + if [ $? -ne 0 ]; then + echo "Error: Failed to change permissions on output file '$OUTPUT_PATH'." + exit 1 + fi +fi # Create a new Ghidra project and import the file ${GHIDRA_HEADLESS} ${GHIDRA_PROJECTS} patchestry-decompilation \ diff --git a/scripts/ghidra/decompile-headless.sh b/scripts/ghidra/decompile-headless.sh index 1561ef1..df5320d 100755 --- a/scripts/ghidra/decompile-headless.sh +++ b/scripts/ghidra/decompile-headless.sh @@ -8,123 +8,132 @@ # show_help() { - echo "Usage: $0 [OPTIONS]" - echo - echo "Options:" - echo " -h, --help Show this help message and exit" - echo " -i, --input Path to the input file" - echo " -f, --function Name of the function to decompile" - echo " -o, --output Path to the output file where results will be saved" - echo " -v, --verbose Enable verbose output" - echo " -t, --interactive Start Docker container in interactive mode" - echo + cat <" - exit 1 -fi - -if [ -z "$FUNCTION_NAME" ]; then - echo "Error: Missing required option: -f, --function " - exit 1 -fi - -if [ -z "$OUTPUT_PATH" ]; then - echo "Error: Missing required option: -o, --output " - exit 1 -fi - -if [ "$VERBOSE" = true ]; then - echo "Input file: $INPUT_PATH" - echo "Function name: $FUNCTION_NAME" - echo "Output file: $OUTPUT_PATH" -fi - -if [ ! -e "$OUTPUT_PATH" ]; then - if [ "$VERBOSE" = true ]; then - echo "Creating output file: $OUTPUT_PATH" +parse_args() { + while [[ $# -gt 0 ]]; do + case "$1" in + -h|--help) + show_help + exit 0 + ;; + -i|--input) + INPUT_PATH="$2" + shift 2 + ;; + -f|--function) + FUNCTION_NAME="$2" + shift 2 + ;; + -o|--output) + OUTPUT_PATH="$2" + shift 2 + ;; + -v|--verbose) + VERBOSE=true + shift + ;; + -t|--interactive) + INTERACTIVE=true + shift + ;; + -c|--ci) + CI_OUTPUT_FOLDER="$2" + shift 2 + ;; + *) + echo "Unknown option: $1" + show_help + exit 1 + ;; + esac + done +} + +validate_args() { + if [ -z "$INPUT_PATH" ]; then + echo "Error: Missing required option: -i, --input " + exit 1 fi - touch "$OUTPUT_PATH" -fi -if [ "$VERBOSE" = true ]; then - echo "Running Docker container..." -fi + if [ -z "$FUNCTION_NAME" ]; then + echo "Error: Missing required option: -f, --function " + exit 1 + fi -absolute_path() { - if [[ "$1" = /* ]]; then - echo "$1" - else - echo "$(pwd)/$1" + if [ -z "$OUTPUT_PATH" ]; then + echo "Error: Missing required option: -o, --output " + exit 1 fi } -INPUT_ABS_PATH=$(absolute_path "$INPUT_PATH") -OUTPUT_ABS_PATH=$(absolute_path "$OUTPUT_PATH") +prepare_paths() { + INPUT_PATH=$(realpath "$INPUT_PATH") + OUTPUT_PATH=$(realpath "$OUTPUT_PATH") -RUN="docker run --rm \ - -v \"$INPUT_ABS_PATH:/input.o\" \ - -v \"$OUTPUT_ABS_PATH:/output.json\" \ - trailofbits/patchestry-decompilation:latest" + if [ ! -e "$INPUT_PATH" ]; then + echo "Error: Input file does not exist: $INPUT_PATH" + exit 1 + fi -if file "$INPUT_PATH" | grep -q "Mach-O"; then - FUNCTION_NAME="_$FUNCTION_NAME" -fi + if [ ! -e "$OUTPUT_PATH" ]; then + if [ "$VERBOSE" = true ]; then + echo "Creating output file: $OUTPUT_PATH" + fi + touch "$OUTPUT_PATH" + fi +} -if [ "$INTERACTIVE" = true ]; then - RUN=$(echo "$RUN" | sed 's/docker run --rm/docker run -it --rm --entrypoint \/bin\/bash/') -else - RUN="$RUN /input.o \"$FUNCTION_NAME\" /output.json" -fi +build_docker_command() { + if [ -n "$CI_OUTPUT_FOLDER" ]; then + INPUT_PATH=$(basename "$INPUT_PATH") + OUTPUT_PATH=$(basename "$OUTPUT_PATH") + RUN="docker run --rm \ + -v $CI_OUTPUT_FOLDER:/mnt/output:rw \ + trailofbits/patchestry-decompilation:latest \ + /mnt/output/$INPUT_PATH \"$FUNCTION_NAME\" /mnt/output/$OUTPUT_PATH" + else + RUN="docker run --rm \ + -v \"$INPUT_PATH:/input.o\" \ + -v \"$OUTPUT_PATH:/output.json\" \ + trailofbits/patchestry-decompilation:latest" + + if file "$INPUT_PATH" | grep -q "Mach-O"; then + FUNCTION_NAME="_$FUNCTION_NAME" + fi + + if [ "$INTERACTIVE" = true ]; then + RUN="${RUN} --entrypoint /bin/bash" + else + RUN="${RUN} /input.o \"$FUNCTION_NAME\" /output.json" + fi + fi +} -if [ "$VERBOSE" = true ]; then - echo "Running Docker container with the following command:" - echo "$RUN" -fi +main() { + parse_args "$@" + validate_args + prepare_paths + build_docker_command -if [ "$VERBOSE" = true ]; then - echo "Starting Docker container..." -fi + if [ "$VERBOSE" = true ]; then + echo "Running Docker container with the following command:" + echo "$RUN" + fi + + eval "$RUN" +} -eval "$RUN" +main "$@" diff --git a/test/ghidra/argc.c b/test/ghidra/argc.c index 7ff3561..9078a63 100644 --- a/test/ghidra/argc.c +++ b/test/ghidra/argc.c @@ -1,6 +1,6 @@ // UNSUPPORTED: system-windows // RUN: %cc %s -g -o %t.o -// RUN: %decompile-headless --input %t.o --function argc --output %t +// RUN: %decompile-headless --input %t.o --function argc --output %t %ci_output_folder // RUN: %file-check -vv %s --input-file %t // CHECK: "name":"{{_?argc}}" diff --git a/test/ghidra/array.c b/test/ghidra/array.c index b89cdd5..15b2ca2 100644 --- a/test/ghidra/array.c +++ b/test/ghidra/array.c @@ -1,6 +1,6 @@ // UNSUPPORTED: system-windows // RUN: %cc %s -g -o %t.o -// RUN: %decompile-headless --input %t.o --function array --output %t +// RUN: %decompile-headless --input %t.o --function array --output %t %ci_output_folder // RUN: %file-check -vv %s --input-file %t // CHECK: "name":"{{_?array}}" diff --git a/test/ghidra/concat.c b/test/ghidra/concat.c index 11538d5..d5d3de0 100644 --- a/test/ghidra/concat.c +++ b/test/ghidra/concat.c @@ -1,6 +1,6 @@ // UNSUPPORTED: system-windows // RUN: %cc %s -g -o %t.o -// RUN: %decompile-headless --input %t.o --function string_concat --output %t +// RUN: %decompile-headless --input %t.o --function string_concat --output %t %ci_output_folder // RUN: %file-check -vv %s --input-file %t // CHECK: "name":"{{_?string_concat}}" diff --git a/test/ghidra/fib.c b/test/ghidra/fib.c index 29a47b9..5431d64 100644 --- a/test/ghidra/fib.c +++ b/test/ghidra/fib.c @@ -1,6 +1,6 @@ // UNSUPPORTED: system-windows // RUN: %cc %s -g -o %t.o -// RUN: %decompile-headless --input %t.o --function fibonacci --output %t +// RUN: %decompile-headless --input %t.o --function fibonacci --output %t %ci_output_folder // RUN: %file-check -vv %s --input-file %t // CHECK: "name":"{{_?fibonacci}}" diff --git a/test/ghidra/fread.c b/test/ghidra/fread.c index 9588669..82d2f7a 100644 --- a/test/ghidra/fread.c +++ b/test/ghidra/fread.c @@ -1,6 +1,6 @@ // UNSUPPORTED: system-windows // RUN: %cc %s -g -o %t.o -// RUN: %decompile-headless --input %t.o --function fread_test --output %t +// RUN: %decompile-headless --input %t.o --function fread_test --output %t %ci_output_folder // RUN: %file-check -vv %s --input-file %t // CHECK: "name":"{{_?fread_test}}" diff --git a/test/ghidra/fwrite.c b/test/ghidra/fwrite.c index c0e2311..d08706f 100644 --- a/test/ghidra/fwrite.c +++ b/test/ghidra/fwrite.c @@ -1,6 +1,6 @@ // UNSUPPORTED: system-windows // RUN: %cc %s -g -o %t.o -// RUN: %decompile-headless --input %t.o --function write_file --output %t +// RUN: %decompile-headless --input %t.o --function write_file --output %t %ci_output_folder // RUN: %file-check -vv %s --input-file %t // CHECK: "name":"{{_?write_file}}" diff --git a/test/ghidra/insert.c b/test/ghidra/insert.c index d3a0d7f..606c676 100644 --- a/test/ghidra/insert.c +++ b/test/ghidra/insert.c @@ -1,6 +1,6 @@ // UNSUPPORTED: system-windows // RUN: %cc %s -g -o %t.o -// RUN: %decompile-headless --input %t.o --function insert_substring --output %t +// RUN: %decompile-headless --input %t.o --function insert_substring --output %t %ci_output_folder // RUN: %file-check -vv %s --input-file %t // CHECK: "name":"{{_?insert_substring}}" diff --git a/test/ghidra/list.c b/test/ghidra/list.c index e377736..2a12bd4 100644 --- a/test/ghidra/list.c +++ b/test/ghidra/list.c @@ -1,6 +1,6 @@ // UNSUPPORTED: system-windows // RUN: %cc %s -g -o %t.o -// RUN: %decompile-headless --input %t.o --function print_list --output %t +// RUN: %decompile-headless --input %t.o --function print_list --output %t %ci_output_folder // RUN: %file-check -vv %s --input-file %t // CHECK: "name":"{{_?print_list}}" diff --git a/test/ghidra/matrix.c b/test/ghidra/matrix.c index b85f040..2c959d5 100644 --- a/test/ghidra/matrix.c +++ b/test/ghidra/matrix.c @@ -1,6 +1,6 @@ // UNSUPPORTED: system-windows // RUN: %cc %s -g -o %t.o -// RUN: %decompile-headless --input %t.o --function multiply_matrices --output %t +// RUN: %decompile-headless --input %t.o --function multiply_matrices --output %t %ci_output_folder // RUN: %file-check -vv %s --input-file %t // CHECK: "name":"{{_?multiply_matrices}}" diff --git a/test/ghidra/prime.c b/test/ghidra/prime.c index 7d858ad..b2d7653 100644 --- a/test/ghidra/prime.c +++ b/test/ghidra/prime.c @@ -1,6 +1,6 @@ // UNSUPPORTED: system-windows // RUN: %cc %s -g -o %t.o -// RUN: %decompile-headless --input %t.o --function is_prime --output %t +// RUN: %decompile-headless --input %t.o --function is_prime --output %t %ci_output_folder // RUN: %file-check -vv %s --input-file %t // CHECK: "name":"{{_?is_prime}}" diff --git a/test/ghidra/queue.c b/test/ghidra/queue.c index 8ab345f..cea9fe2 100644 --- a/test/ghidra/queue.c +++ b/test/ghidra/queue.c @@ -1,6 +1,6 @@ // UNSUPPORTED: system-windows // RUN: %cc %s -g -o %t.o -// RUN: %decompile-headless --input %t.o --function dequeue --output %t +// RUN: %decompile-headless --input %t.o --function dequeue --output %t %ci_output_folder // RUN: %file-check -vv %s --input-file %t // CHECK: "name":"{{_?dequeue}}" diff --git a/test/ghidra/reverse.c b/test/ghidra/reverse.c index 7d9ba8f..d456a50 100644 --- a/test/ghidra/reverse.c +++ b/test/ghidra/reverse.c @@ -1,6 +1,6 @@ // UNSUPPORTED: system-windows // RUN: %cc %s -g -o %t.o -// RUN: %decompile-headless --input %t.o --function reverse_string --output %t +// RUN: %decompile-headless --input %t.o --function reverse_string --output %t %ci_output_folder // RUN: %file-check -vv %s --input-file %t // CHECK: "name":"{{_?reverse_string}}" diff --git a/test/ghidra/sort.c b/test/ghidra/sort.c index f6817e8..9fcc353 100644 --- a/test/ghidra/sort.c +++ b/test/ghidra/sort.c @@ -1,6 +1,6 @@ // UNSUPPORTED: system-windows // RUN: %cc %s -g -o %t.o -// RUN: %decompile-headless --input %t.o --function sort_test --output %t +// RUN: %decompile-headless --input %t.o --function sort_test --output %t %ci_output_folder // RUN: %file-check -vv %s --input-file %t // CHECK: "name":"{{_?sort_test}}" diff --git a/test/ghidra/struct.c b/test/ghidra/struct.c index 8baf2f1..0061378 100644 --- a/test/ghidra/struct.c +++ b/test/ghidra/struct.c @@ -1,6 +1,6 @@ // UNSUPPORTED: system-windows // RUN: %cc %s -g -o %t.o -// RUN: %decompile-headless --input %t.o --function struct_test --output %t +// RUN: %decompile-headless --input %t.o --function struct_test --output %t %ci_output_folder // RUN: %file-check -vv %s --input-file %t // CHECK: "name":"{{_?struct_test}}" diff --git a/test/ghidra/structb.c b/test/ghidra/structb.c index 58eee06..fb7fd4d 100644 --- a/test/ghidra/structb.c +++ b/test/ghidra/structb.c @@ -1,6 +1,6 @@ // UNSUPPORTED: system-windows // RUN: %cc %s -g -o %t.o -// RUN: %decompile-headless --input %t.o --function structb --output %t +// RUN: %decompile-headless --input %t.o --function structb --output %t %ci_output_folder // RUN: %file-check -vv %s --input-file %t // CHECK: "name":"{{_?structb}}" diff --git a/test/ghidra/sub.c b/test/ghidra/sub.c index 029965e..fac4430 100644 --- a/test/ghidra/sub.c +++ b/test/ghidra/sub.c @@ -1,6 +1,6 @@ // UNSUPPORTED: system-windows // RUN: %cc %s -g -o %t.o -// RUN: %decompile-headless --input %t.o --function sub --output %t +// RUN: %decompile-headless --input %t.o --function sub --output %t %ci_output_folder // RUN: %file-check -vv %s --input-file %t // CHECK: "name":"{{_?sub}}" diff --git a/test/ghidra/test.c b/test/ghidra/test.c index bbbd13a..9b3219f 100644 --- a/test/ghidra/test.c +++ b/test/ghidra/test.c @@ -1,6 +1,6 @@ // UNSUPPORTED: system-windows // RUN: %cc %s -g -o %t.o -// RUN: %decompile-headless --input %t.o --function test --output %t +// RUN: %decompile-headless --input %t.o --function test --output %t %ci_output_folder // RUN: %file-check -vv %s --input-file %t // CHECK: "name":"{{_?test}}" diff --git a/test/ghidra/union.c b/test/ghidra/union.c index 0ec3be6..2dc40b8 100644 --- a/test/ghidra/union.c +++ b/test/ghidra/union.c @@ -1,6 +1,6 @@ // UNSUPPORTED: system-windows // RUN: %cc %s -g -o %t.o -// RUN: %decompile-headless --input %t.o --function union_test --output %t +// RUN: %decompile-headless --input %t.o --function union_test --output %t %ci_output_folder // RUN: %file-check -vv %s --input-file %t // CHECK: "name":"{{_?union_test}}" diff --git a/test/lit.cfg.py b/test/lit.cfg.py index 5ddbeda..789f357 100644 --- a/test/lit.cfg.py +++ b/test/lit.cfg.py @@ -12,14 +12,6 @@ from lit.llvm.subst import ToolSubst from lit.llvm.subst import FindTool -# Prefix for function name -if platform.system() == "Darwin": - config.function_prefix = "_" -else: - config.function_prefix = "" - -config.debug = True - # Configuration name config.name = 'PatchestryTest' @@ -59,21 +51,6 @@ for tool in tools: llvm_config.add_tool_substitutions([tool]) -# # Add test directory to substitutions -# config.substitutions.append(('%test_dir', os.path.join(config.test_source_root, 'ghidra'))) - # Add PATH to substitutions config.substitutions.append(('%PATH%', config.environment['PATH'])) - -# config.substitutions.append( -# ('%decompile-headless', config.decompiler_headless_tool -# f"'{config.python_executable}' -c '" -# f"import subprocess;" -# f"import sys;" -# f"args = sys.argv[1:4];" -# f"print(args);" -# f"args[1] = \"{config.function_prefix}\" + args[1]; " -# f"result = subprocess.run([\"{config.decompiler_headless_tool}\"] + args, capture_output=True, text=True); " -# f"print(result.stdout + result.stderr); " -# f"sys.exit(result.returncode)' ") -# ) +config.substitutions.append(('%ci_output_folder', f"--ci {llvm_config.lit_config.params.get('CI_OUTPUT_FOLDER', '')}"))