From 28a34ccdbf589b4f4dbe869e2240c38f033e3258 Mon Sep 17 00:00:00 2001 From: Fabian Schiebel Date: Fri, 4 Apr 2025 19:33:06 +0200 Subject: [PATCH 01/20] Update llvm-hello-world + add examples for load-llvm-ir and build-type-hierarchy with phasar --- .../how-to/00-load-llvm-ir/CMakeLists.txt | 10 + examples/how-to/00-load-llvm-ir/README.md | 24 + examples/how-to/00-load-llvm-ir/main.cpp | 54 + .../01-build-type-hierarchy/CMakeLists.txt | 10 + .../how-to/01-build-type-hierarchy/README.md | 24 + .../how-to/01-build-type-hierarchy/main.cpp | 47 + .../how-to/02-build-call-graph/CMakeLists.txt | 1 + .../03-create-alias-info/CMakeLists.txt | 1 + .../04-run-ifds-analysis/CMakeLists.txt | 1 + .../how-to/05-run-ide-analysis/CMakeLists.txt | 1 + .../07-write-ide-analysis/CMakeLists.txt | 1 + .../08-write-ifds-analysis/CMakeLists.txt | 1 + examples/how-to/CMakeLists.txt | 11 + examples/how-to/README.md | 13 + examples/llvm-hello-world/CMakeLists.txt | 13 + examples/llvm-hello-world/README.md | 30 + examples/llvm-hello-world/README.txt | 12 - examples/llvm-hello-world/main.cpp | 4 - .../llvm-hello-world/target/CMakeLists.txt | 12 + examples/llvm-hello-world/target/branching.ll | 116 +- .../llvm-hello-world/target/branching2.ll | 122 +- examples/llvm-hello-world/target/call.ll | 66 +- examples/llvm-hello-world/target/call2.ll | 170 ++- .../target/class_hierarchy.cpp | 33 + .../target/class_hierarchy.ll | 596 ++++++++++ examples/llvm-hello-world/target/exception.ll | 1012 +++++++++++++++-- examples/llvm-hello-world/target/functions.ll | 157 ++- .../llvm-hello-world/target/functions2.ll | 433 ++++--- .../target/llvm_intrinsic_functions.ll | 170 ++- .../target/llvm_intrinsic_functions2.ll | 435 ++++++- examples/llvm-hello-world/target/loop.ll | 136 ++- examples/llvm-hello-world/target/loop2.ll | 99 +- examples/llvm-hello-world/target/pointers.ll | 101 +- examples/llvm-hello-world/target/pointers2.ll | 363 +++++- examples/llvm-hello-world/target/simple.ll | 72 +- examples/llvm-hello-world/target/simple2.ll | 120 +- examples/llvm-hello-world/target/struct.ll | 91 +- examples/llvm-hello-world/target/struct2.ll | 146 ++- examples/llvm-hello-world/target/struct3.ll | 223 ++-- 39 files changed, 4024 insertions(+), 907 deletions(-) create mode 100644 examples/how-to/00-load-llvm-ir/CMakeLists.txt create mode 100644 examples/how-to/00-load-llvm-ir/README.md create mode 100644 examples/how-to/00-load-llvm-ir/main.cpp create mode 100644 examples/how-to/01-build-type-hierarchy/CMakeLists.txt create mode 100644 examples/how-to/01-build-type-hierarchy/README.md create mode 100644 examples/how-to/01-build-type-hierarchy/main.cpp create mode 100644 examples/how-to/02-build-call-graph/CMakeLists.txt create mode 100644 examples/how-to/03-create-alias-info/CMakeLists.txt create mode 100644 examples/how-to/04-run-ifds-analysis/CMakeLists.txt create mode 100644 examples/how-to/05-run-ide-analysis/CMakeLists.txt create mode 100644 examples/how-to/07-write-ide-analysis/CMakeLists.txt create mode 100644 examples/how-to/08-write-ifds-analysis/CMakeLists.txt create mode 100644 examples/how-to/CMakeLists.txt create mode 100644 examples/how-to/README.md create mode 100644 examples/llvm-hello-world/CMakeLists.txt create mode 100644 examples/llvm-hello-world/README.md delete mode 100644 examples/llvm-hello-world/README.txt create mode 100644 examples/llvm-hello-world/target/CMakeLists.txt create mode 100644 examples/llvm-hello-world/target/class_hierarchy.cpp create mode 100644 examples/llvm-hello-world/target/class_hierarchy.ll diff --git a/examples/how-to/00-load-llvm-ir/CMakeLists.txt b/examples/how-to/00-load-llvm-ir/CMakeLists.txt new file mode 100644 index 0000000000..be859cacb0 --- /dev/null +++ b/examples/how-to/00-load-llvm-ir/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 3.14...3.28) + +project(load-llvm-ir) + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +find_package(phasar REQUIRED CONFIG) + +add_executable(load-llvm-ir main.cpp) +target_link_libraries(load-llvm-ir PRIVATE phasar::phasar) diff --git a/examples/how-to/00-load-llvm-ir/README.md b/examples/how-to/00-load-llvm-ir/README.md new file mode 100644 index 0000000000..92b8588fd3 --- /dev/null +++ b/examples/how-to/00-load-llvm-ir/README.md @@ -0,0 +1,24 @@ +# Load LLVM IR + +Shows, how you can use PhASAR to load and manage a LLVM IR module. + +## Build + +This example program can be built using cmake. +It assumes, that you have installed PhASAR on your system. If you did not install PhASAR to a default location, you can specify `-Dphasar_ROOT=your/path/to/phasar` replacing "your/path/to/phasar" by the actual path where you have installed PhASAR. + +```bash +# Invoked from the 00-load-llvm-ir root folder: +$ mkdir -p build && cd build +$ cmake .. +$ cmake --build . +``` + +## Test + +You can test the example program on the target program from [llvm-hello-world/target](../../llvm-hello-world/target/). + +```bash +# Invoked from the 00-load-llvm-ir/build folder: +./load-llvm-ir ../../../llvm-hello-world/target/simple.ll +``` diff --git a/examples/how-to/00-load-llvm-ir/main.cpp b/examples/how-to/00-load-llvm-ir/main.cpp new file mode 100644 index 0000000000..14823201c6 --- /dev/null +++ b/examples/how-to/00-load-llvm-ir/main.cpp @@ -0,0 +1,54 @@ +#include "phasar/PhasarLLVM/DB.h" +#include "phasar/PhasarLLVM/Passes.h" +#include "phasar/PhasarLLVM/Utils.h" + +#include "llvm/IR/InstIterator.h" + +static void printIRStats(psr::LLVMProjectIRDB &IRDB); + +int main(int Argc, char *Argv[]) { + if (Argc < 2) { + llvm::errs() << "USAGE: load-llvm-ir \n"; + return 1; + } + + // The LLVMProjectIRDB loads and manages an LLVM-IR module. + // You can load both .ll (human readable) and .bc (smaller, faster load-times) + // files. + // If you already have an llvm::Module*, you can also pass it here. + psr::LLVMProjectIRDB IRDB(Argv[1]); + if (!IRDB) { + // If phasar yould not load the IR, we should exit. + // Phasar has already printed an error message to the terminal. + return 1; + } + + // ======== + // Now, you can work with the module + + printIRStats(IRDB); + + // Inspect the module (see also llvm-hello-world) + + auto *F = IRDB.getFunctionDefinition("main"); + if (!F) { + llvm::errs() << "error: could not find function 'main'\n"; + return 1; + } + + llvm::outs() << "--------------- Instructions of 'main' ---------------\n"; + + for (const auto &Inst : llvm::instructions(F)) { + // Phasar annotates all instructions with IRDB-wide unique integer Ids: + auto InstId = IRDB.getInstructionId(&Inst); + + llvm::outs() << '#' << InstId << ": " << psr::llvmIRToString(&Inst) << '\n'; + + // TODO: Analyze instruction 'Inst' here. + } +} + +static void printIRStats(psr::LLVMProjectIRDB &IRDB) { + psr::GeneralStatisticsAnalysis Stats; + llvm::outs() << Stats.runOnModule(*IRDB.getModule()) << '\n'; +} diff --git a/examples/how-to/01-build-type-hierarchy/CMakeLists.txt b/examples/how-to/01-build-type-hierarchy/CMakeLists.txt new file mode 100644 index 0000000000..bb41ee47c7 --- /dev/null +++ b/examples/how-to/01-build-type-hierarchy/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 3.14...3.28) + +project(build-type-hierarchy) + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +find_package(phasar REQUIRED CONFIG) + +add_executable(build-type-hierarchy main.cpp) +target_link_libraries(build-type-hierarchy PRIVATE phasar::phasar) diff --git a/examples/how-to/01-build-type-hierarchy/README.md b/examples/how-to/01-build-type-hierarchy/README.md new file mode 100644 index 0000000000..44f855140b --- /dev/null +++ b/examples/how-to/01-build-type-hierarchy/README.md @@ -0,0 +1,24 @@ +# Build Type Hierarchy + +Shows, how you can use PhASAR to build and use a type hierarchy from a LLVM IR module. + +## Build + +This example program can be built using cmake. +It assumes, that you have installed PhASAR on your system. If you did not install PhASAR to a default location, you can specify `-Dphasar_ROOT=your/path/to/phasar` replacing "your/path/to/phasar" by the actual path where you have installed PhASAR. + +```bash +# Invoked from the 01-build-type-hierarchy root folder: +$ mkdir -p build && cd build +$ cmake .. +$ cmake --build . +``` + +## Test + +You can test the example program on the target program from [llvm-hello-world/target](../../llvm-hello-world/target/). + +```bash +# Invoked from the 01-build-type-hierarchy/build folder: +./build-type-hierarchy ../../../llvm-hello-world/target/class_hierarchy.ll +``` diff --git a/examples/how-to/01-build-type-hierarchy/main.cpp b/examples/how-to/01-build-type-hierarchy/main.cpp new file mode 100644 index 0000000000..776ba0e4e0 --- /dev/null +++ b/examples/how-to/01-build-type-hierarchy/main.cpp @@ -0,0 +1,47 @@ +#include "phasar/PhasarLLVM/DB.h" +#include "phasar/PhasarLLVM/TypeHierarchy.h" + +#include + +int main(int Argc, char *Argv[]) { + if (Argc < 2) { + llvm::errs() << "USAGE: build-type-hierarchy \n"; + return 1; + } + + // Load the IR + psr::LLVMProjectIRDB IRDB(Argv[1]); + if (!IRDB) { + return 1; + } + + // Build the type hierarchy. + // Note that this DIBasedTypeHierarchy requires debug information (DI) to be + // embedded into the LLVM IR. You can achieve this by passing -g to clang. + psr::DIBasedTypeHierarchy TH(IRDB); + + for (const auto *ClassTy : TH.getAllTypes()) { + llvm::outs() << "Found class type " << ClassTy->getName() << " (" + << TH.getTypeName(ClassTy) << ")\n"; + llvm::outs() << "> demangled name: " + << llvm::demangle(TH.getTypeName(ClassTy).str()) << '\n'; + } + llvm::outs() << '\n'; + + // Try to find class 'A' + const auto *ClassA = TH.getType("_ZTS1A"); + + // If TH does not find, it returns nullptr. + + if (ClassA != nullptr) { + // Get the (transitive) sub-types of ClassA + for (const auto *ClassTy : TH.subTypesOf(ClassA)) { + llvm::outs() << "Class " << ClassTy->getName() + << " is a (transitive) sub-type of A\n"; + + // You can also check, whether a type is a (transitive) sub-type of + // another type: + assert(TH.isSubType(ClassA, ClassTy)); + } + } +} diff --git a/examples/how-to/02-build-call-graph/CMakeLists.txt b/examples/how-to/02-build-call-graph/CMakeLists.txt new file mode 100644 index 0000000000..e762377581 --- /dev/null +++ b/examples/how-to/02-build-call-graph/CMakeLists.txt @@ -0,0 +1 @@ +cmake_minimum_required(VERSION 3.14...3.28) diff --git a/examples/how-to/03-create-alias-info/CMakeLists.txt b/examples/how-to/03-create-alias-info/CMakeLists.txt new file mode 100644 index 0000000000..e762377581 --- /dev/null +++ b/examples/how-to/03-create-alias-info/CMakeLists.txt @@ -0,0 +1 @@ +cmake_minimum_required(VERSION 3.14...3.28) diff --git a/examples/how-to/04-run-ifds-analysis/CMakeLists.txt b/examples/how-to/04-run-ifds-analysis/CMakeLists.txt new file mode 100644 index 0000000000..e762377581 --- /dev/null +++ b/examples/how-to/04-run-ifds-analysis/CMakeLists.txt @@ -0,0 +1 @@ +cmake_minimum_required(VERSION 3.14...3.28) diff --git a/examples/how-to/05-run-ide-analysis/CMakeLists.txt b/examples/how-to/05-run-ide-analysis/CMakeLists.txt new file mode 100644 index 0000000000..e762377581 --- /dev/null +++ b/examples/how-to/05-run-ide-analysis/CMakeLists.txt @@ -0,0 +1 @@ +cmake_minimum_required(VERSION 3.14...3.28) diff --git a/examples/how-to/07-write-ide-analysis/CMakeLists.txt b/examples/how-to/07-write-ide-analysis/CMakeLists.txt new file mode 100644 index 0000000000..e762377581 --- /dev/null +++ b/examples/how-to/07-write-ide-analysis/CMakeLists.txt @@ -0,0 +1 @@ +cmake_minimum_required(VERSION 3.14...3.28) diff --git a/examples/how-to/08-write-ifds-analysis/CMakeLists.txt b/examples/how-to/08-write-ifds-analysis/CMakeLists.txt new file mode 100644 index 0000000000..e762377581 --- /dev/null +++ b/examples/how-to/08-write-ifds-analysis/CMakeLists.txt @@ -0,0 +1 @@ +cmake_minimum_required(VERSION 3.14...3.28) diff --git a/examples/how-to/CMakeLists.txt b/examples/how-to/CMakeLists.txt new file mode 100644 index 0000000000..0e0ce7af2e --- /dev/null +++ b/examples/how-to/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.14...3.28) + +project(phasar-how-tos) + +file(GLOB children RELATIVE ${CMAKE_CURRENT_LIST_DIR} ${CMAKE_CURRENT_LIST_DIR}/*) + +foreach(child ${children}) + if(IS_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/${child}) + add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/${child}) + endif() +endforeach() diff --git a/examples/how-to/README.md b/examples/how-to/README.md new file mode 100644 index 0000000000..ded969e59b --- /dev/null +++ b/examples/how-to/README.md @@ -0,0 +1,13 @@ +# How To ... + +This folder contains various examples on how to use certain features of PhASAR. + +Currently supporting: +- Working with the IR +- Build a type-hierarchy +- Build a call-graph +- Create alias-information +- Run an IFDS analysis +- Run an IDE analysis +- Write an IFDS analysis +- Write an IDE analysis diff --git a/examples/llvm-hello-world/CMakeLists.txt b/examples/llvm-hello-world/CMakeLists.txt new file mode 100644 index 0000000000..8ed9e80124 --- /dev/null +++ b/examples/llvm-hello-world/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 3.14...3.28) + +project(llvm-hello-world) + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +find_package(LLVM 15 REQUIRED CONFIG) + +add_executable(main main.cpp) +target_link_libraries(main PRIVATE LLVMCore LLVMIRReader) +target_include_directories(main PRIVATE ${LLVM_INCLUDE_DIRS}) + +add_subdirectory(target) diff --git a/examples/llvm-hello-world/README.md b/examples/llvm-hello-world/README.md new file mode 100644 index 0000000000..23a1eb7854 --- /dev/null +++ b/examples/llvm-hello-world/README.md @@ -0,0 +1,30 @@ +# LLVM Hello World + +The "Hello, World!" program can be compiled using: + +```bash +$ make +``` + +However, we recommend using cmake: + +```bash +$ mkdir -p build && cd build +$ cmake .. +$ cmake --build . +``` + +"Hello, World!" reads a LLVM IR file (.ll or .bc) specified by the first +command-line argument. It then looks for the main function, iterates all of its +instructions and prints them to the command-line using an LLVM output stream. +Have a look at the comments within the source code in main.cpp. + +Example use: + +```bash +# Invoked from the llvm-hello-world root folder if compiled with make: +./main ./target/simple.ll + +# Invoked from the llvm-hello-world/build folder if compiled with cmake: +./main ./target/simple_cpp_dbg.ll +``` diff --git a/examples/llvm-hello-world/README.txt b/examples/llvm-hello-world/README.txt deleted file mode 100644 index 51b3fcedf6..0000000000 --- a/examples/llvm-hello-world/README.txt +++ /dev/null @@ -1,12 +0,0 @@ -The "Hello, World!" program can be compiled using: - - $ make - -The auto-generated files can be removed using: - - $ make clean - -"Hello, World!" reads a LLVM IR file (.ll or .bc) specified by the first -command-line argument. It then looks for the main function, iterates all of its -instructions and prints them to the command-line using an LLVM output stream. -Have a look at the comments within the source code in main.cpp. diff --git a/examples/llvm-hello-world/main.cpp b/examples/llvm-hello-world/main.cpp index 3cb439b218..ce435a7de2 100644 --- a/examples/llvm-hello-world/main.cpp +++ b/examples/llvm-hello-world/main.cpp @@ -2,18 +2,14 @@ #include "llvm/IR/Function.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" -#include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IR/Verifier.h" #include "llvm/IRReader/IRReader.h" -#include "llvm/Support/ManagedStatic.h" -#include "llvm/Support/SMLoc.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" #include -#include int main(int argc, char **argv) { if (argc != 2) { diff --git a/examples/llvm-hello-world/target/CMakeLists.txt b/examples/llvm-hello-world/target/CMakeLists.txt new file mode 100644 index 0000000000..f8f25bef38 --- /dev/null +++ b/examples/llvm-hello-world/target/CMakeLists.txt @@ -0,0 +1,12 @@ +add_custom_target(LLFileGeneration ALL) + +# Use phasar's capabilities to automate the LLVM-IR file generation + +include(../../../cmake/phasar_macros.cmake) +set(PHASAR_LLVM_VERSION 15) + +file(GLOB target_files RELATIVE ${CMAKE_CURRENT_LIST_DIR} *.cpp) + +foreach(target_file ${target_files}) + generate_ll_file(FILE ${target_file} DEBUG) +endforeach() diff --git a/examples/llvm-hello-world/target/branching.ll b/examples/llvm-hello-world/target/branching.ll index cc4c36efa6..098eee04f0 100644 --- a/examples/llvm-hello-world/target/branching.ll +++ b/examples/llvm-hello-world/target/branching.ll @@ -1,43 +1,89 @@ ; ModuleID = 'branching.cpp' source_filename = "branching.cpp" -target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" -; Function Attrs: noinline norecurse nounwind optnone uwtable -define i32 @main(i32, i8**) #0 { - %3 = alloca i32, align 4 - %4 = alloca i32, align 4 - %5 = alloca i8**, align 8 - %6 = alloca i32, align 4 - %7 = alloca i32, align 4 - store i32 0, i32* %3, align 4 - store i32 %0, i32* %4, align 4 - store i8** %1, i8*** %5, align 8 - store i32 10, i32* %6, align 4 - %8 = load i32, i32* %4, align 4 - %9 = sub nsw i32 %8, 1 - %10 = icmp ne i32 %9, 0 - br i1 %10, label %11, label %12 - -;