├── doc ├── CMakeLists.txt ├── images │ ├── loom.ai │ ├── loom.png │ ├── loom-small.png │ ├── instr-callout.pdf │ └── instr-inline.pdf ├── dtrace │ ├── usdt.graffle │ ├── usdt_loom.png │ └── usdt_orginal.png ├── api │ ├── llvm │ │ ├── Type.java │ │ ├── Value.java │ │ ├── CallInst.java │ │ ├── Instruction.java │ │ ├── LoadInst.java │ │ ├── StructType.java │ │ ├── Module.java │ │ ├── StoreInst.java │ │ ├── GetElementPtrInst.java │ │ ├── BasicBlock.java │ │ ├── ModulePass.java │ │ └── Function.java │ ├── graph │ └── loom.java ├── doxygen │ ├── CMakeLists.txt │ ├── footer.html │ ├── loom-dox.css │ ├── header.html │ └── Doxyfile.in └── loom-overview.adoc ├── test ├── regression │ ├── missing-phi.ll.policy │ ├── non-dominating-inst.ll.policy │ ├── sccp-block-fold.ll.policy │ ├── sccp-block-fold.ll │ ├── non-dominating-inst.ll │ └── missing-phi.ll ├── instrument-everything-and-run.ll.policy ├── instrument-everything.ll.policy ├── load-plugin.ll ├── CMakeLists.txt ├── ktrace-kernel.c ├── ktrace-userspace.c ├── static.c ├── ktrace-userspace-libnv-run.c ├── ktrace-userspace-libnv.c ├── indirect-fields.c ├── wildcard-function-instrumentation.c ├── function-instrumentation.c ├── function-instrumentation-libxo.c ├── call-instrumentation.c ├── function-instrumentation-with-file-scope.c ├── call-instrumentation-inline-noblocks.c ├── call-instrumentation-libxo.c ├── call-instrumentation-inline.c ├── lit.cfg ├── test_support.py ├── field-instrumentation.c ├── wildcard-field-instrumentation.c ├── instrument-everything-and-run.ll └── instrument-everything.ll ├── publications ├── llvm-dev-mtg-2019 │ └── Loom_Weaving_Instrumentation_for_Program_Analysis-Brian_Kidney.pdf └── Readme.md ├── examples └── socket_replacement.policy ├── .gitmodules ├── scripts ├── xtools.sh ├── loom-fbsdmake └── plot-tracelen ├── src ├── CMakeLists.txt ├── Strings.hh ├── Strings.cc ├── DagTransform.hh ├── Metadata.hh ├── IRUtils.cc ├── IRUtils.hh ├── Transform.hh ├── DTraceLogger.hh ├── NVSerializer.hh ├── KTraceLogger.hh ├── Policy.cc ├── Serializer.cc ├── Instrumentation.cc ├── KTraceLogger.cc ├── DagTransform.cc ├── Transform.cc ├── Instrumentation.hh ├── PolicyFile.hh ├── DTraceLogger.cc ├── Serializer.hh ├── DebugInfo.hh ├── DebugInfo.cc ├── Instrumenter.hh ├── Logger.hh ├── Policy.hh └── InstrStrategy.hh ├── CMakeLists.txt ├── LICENSE.txt └── README.md /doc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(doxygen) 2 | -------------------------------------------------------------------------------- /doc/images/loom.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cadets/loom/HEAD/doc/images/loom.ai -------------------------------------------------------------------------------- /doc/images/loom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cadets/loom/HEAD/doc/images/loom.png -------------------------------------------------------------------------------- /doc/dtrace/usdt.graffle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cadets/loom/HEAD/doc/dtrace/usdt.graffle -------------------------------------------------------------------------------- /doc/dtrace/usdt_loom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cadets/loom/HEAD/doc/dtrace/usdt_loom.png -------------------------------------------------------------------------------- /doc/images/loom-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cadets/loom/HEAD/doc/images/loom-small.png -------------------------------------------------------------------------------- /test/regression/missing-phi.ll.policy: -------------------------------------------------------------------------------- 1 | strategy: inline 2 | logging: xo 3 | everything: true 4 | -------------------------------------------------------------------------------- /doc/dtrace/usdt_orginal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cadets/loom/HEAD/doc/dtrace/usdt_orginal.png -------------------------------------------------------------------------------- /doc/images/instr-callout.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cadets/loom/HEAD/doc/images/instr-callout.pdf -------------------------------------------------------------------------------- /doc/images/instr-inline.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cadets/loom/HEAD/doc/images/instr-inline.pdf -------------------------------------------------------------------------------- /test/instrument-everything-and-run.ll.policy: -------------------------------------------------------------------------------- 1 | strategy: inline 2 | logging: xo 3 | everything: true 4 | -------------------------------------------------------------------------------- /test/regression/non-dominating-inst.ll.policy: -------------------------------------------------------------------------------- 1 | strategy: inline 2 | logging: xo 3 | everything: true 4 | -------------------------------------------------------------------------------- /test/regression/sccp-block-fold.ll.policy: -------------------------------------------------------------------------------- 1 | strategy: inline 2 | logging: xo 3 | everything: true 4 | -------------------------------------------------------------------------------- /doc/api/llvm/Type.java: -------------------------------------------------------------------------------- 1 | package llvm; 2 | 3 | /** 4 | * @opt nodefillcolor #cccccc 5 | */ 6 | public class Type {} 7 | -------------------------------------------------------------------------------- /test/instrument-everything.ll.policy: -------------------------------------------------------------------------------- 1 | strategy: inline 2 | logging: xo 3 | block_structure: true 4 | everything: true 5 | -------------------------------------------------------------------------------- /doc/api/llvm/Value.java: -------------------------------------------------------------------------------- 1 | package llvm; 2 | 3 | /** 4 | * @opt nodefillcolor #cccccc 5 | */ 6 | public class Value 7 | { 8 | } 9 | -------------------------------------------------------------------------------- /doc/api/llvm/CallInst.java: -------------------------------------------------------------------------------- 1 | package llvm; 2 | 3 | /** 4 | * @opt nodefillcolor #cccccc 5 | */ 6 | public class CallInst extends Instruction 7 | { 8 | } 9 | -------------------------------------------------------------------------------- /doc/api/llvm/Instruction.java: -------------------------------------------------------------------------------- 1 | package llvm; 2 | 3 | /** 4 | * @opt nodefillcolor #cccccc 5 | */ 6 | public class Instruction extends Value 7 | { 8 | } 9 | -------------------------------------------------------------------------------- /doc/api/llvm/LoadInst.java: -------------------------------------------------------------------------------- 1 | package llvm; 2 | 3 | /** 4 | * @opt nodefillcolor #cccccc 5 | */ 6 | public class LoadInst extends Instruction 7 | { 8 | } 9 | -------------------------------------------------------------------------------- /doc/api/llvm/StructType.java: -------------------------------------------------------------------------------- 1 | package llvm; 2 | 3 | /** 4 | * @opt nodefillcolor #cccccc 5 | */ 6 | public class StructType extends Type 7 | { 8 | } 9 | -------------------------------------------------------------------------------- /doc/api/llvm/Module.java: -------------------------------------------------------------------------------- 1 | package llvm; 2 | 3 | /** 4 | * @navassoc "" - "*" Function 5 | * @opt nodefillcolor #cccccc 6 | */ 7 | public class Module {} 8 | -------------------------------------------------------------------------------- /doc/api/llvm/StoreInst.java: -------------------------------------------------------------------------------- 1 | package llvm; 2 | 3 | /** 4 | * @opt nodefillcolor #cccccc 5 | */ 6 | public class StoreInst extends Instruction 7 | { 8 | } 9 | -------------------------------------------------------------------------------- /doc/api/llvm/GetElementPtrInst.java: -------------------------------------------------------------------------------- 1 | package llvm; 2 | 3 | /** 4 | * @opt nodefillcolor #cccccc 5 | */ 6 | public class GetElementPtrInst extends Instruction 7 | { 8 | } 9 | -------------------------------------------------------------------------------- /doc/api/llvm/BasicBlock.java: -------------------------------------------------------------------------------- 1 | package llvm; 2 | 3 | /** 4 | * @opt nodefillcolor #cccccc 5 | * @navassoc "" - "*" Instruction 6 | */ 7 | public class BasicBlock 8 | { 9 | } 10 | -------------------------------------------------------------------------------- /doc/api/llvm/ModulePass.java: -------------------------------------------------------------------------------- 1 | package llvm; 2 | 3 | /** 4 | * @opt nodefillcolor #cccccc 5 | */ 6 | public class ModulePass 7 | { 8 | public abstract boolean runOnModule(llvm.Module Mod); 9 | } 10 | -------------------------------------------------------------------------------- /publications/llvm-dev-mtg-2019/Loom_Weaving_Instrumentation_for_Program_Analysis-Brian_Kidney.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cadets/loom/HEAD/publications/llvm-dev-mtg-2019/Loom_Weaving_Instrumentation_for_Program_Analysis-Brian_Kidney.pdf -------------------------------------------------------------------------------- /examples/socket_replacement.policy: -------------------------------------------------------------------------------- 1 | strategy: callout 2 | hook_prefix: __test_hook 3 | logging: printf 4 | 5 | dag_replacements: 6 | - name: socket 7 | replacement: socket_paired 8 | followed-by: 9 | - name: connect 10 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "doc/doxygen-bootstrapped"] 2 | path = doc/doxygen/doxygen-bootstrapped 3 | url = https://github.com/Velron/doxygen-bootstrapped 4 | [submodule "web"] 5 | path = web 6 | url = git@github.com:cadets/loom 7 | branch = gh-pages 8 | -------------------------------------------------------------------------------- /publications/Readme.md: -------------------------------------------------------------------------------- 1 | # Publications 2 | 3 | ## LLVM Developers Meeting, October 2019 4 | 5 | * Loom: Weaving Instrumentation for Program Analysis 6 | * [Poster](llvm-dev-mtg-2019/Loom_Weaving_Instrumentation_for_Program_Analysis.pdf) 7 | * [Lightning Talk](https://www.youtube.com/watch?v=T8qGbze3apo) 8 | -------------------------------------------------------------------------------- /doc/api/llvm/Function.java: -------------------------------------------------------------------------------- 1 | package llvm; 2 | 3 | /** 4 | * @navassoc "" - "*" BasicBlock 5 | * @opt nodefillcolor #cccccc 6 | * @depend - - Function.ArgumentListType 7 | */ 8 | public class Function 9 | { 10 | /** 11 | * @opt nodefillcolor #cccccc 12 | */ 13 | public class ArgumentListType 14 | { 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /scripts/xtools.sh: -------------------------------------------------------------------------------- 1 | check_tool() 2 | { 3 | prefix=$1 4 | varname=$2 5 | tool=$3 6 | 7 | if ! [ -e "${prefix}/bin/${tool}" ] 8 | then 9 | echo "bin/${tool} does not exist in prefix ${prefix}" 10 | exit 1 11 | fi 12 | 13 | if ! [ -x "${prefix}/bin/${tool}" ] 14 | then 15 | echo "${prefix}/bin/${tool} is not executable" 16 | exit 1 17 | fi 18 | 19 | export X${varname}=${prefix}/bin/${tool} 20 | } 21 | -------------------------------------------------------------------------------- /doc/api/graph: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | : ${umlgraph:="/usr/local/share/java/classes/UmlGraph.jar"} 4 | : ${tools:="/usr/local/openjdk8/lib/tools.jar"} 5 | : ${format:="png"} 6 | 7 | classpath="-classpath ${umlgraph}:${tools}" 8 | 9 | find . -name '*.java' \ 10 | | xargs \ 11 | java ${classpath} \ 12 | org.umlgraph.doclet.UmlGraph \ 13 | -private \ 14 | -attributes -operations -types -visibility \ 15 | -output - \ 16 | | dot -T${format} -o loom.${format} 17 | -------------------------------------------------------------------------------- /doc/doxygen/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | find_package(Doxygen) 2 | 3 | if(DOXYGEN_FOUND) 4 | set(DOX_BOOTSTRAP ${CMAKE_CURRENT_SOURCE_DIR}/doxygen-bootstrapped) 5 | set(DOX_THEME ${CMAKE_CURRENT_SOURCE_DIR}) 6 | 7 | configure_file(Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY) 8 | add_custom_target(doc 9 | ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile 10 | DEPENDS Doxyfile.in 11 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 12 | COMMENT "Generating API documentation with Doxygen" VERBATIM 13 | ) 14 | endif(DOXYGEN_FOUND) 15 | -------------------------------------------------------------------------------- /test/load-plugin.ll: -------------------------------------------------------------------------------- 1 | ; \file load-plugin.ll 2 | ; Ensure that LLVM 'opt' can load the LOOM plugin. 3 | ; 4 | ; RUN: %loom -S %s -o %t.ll 5 | 6 | ; ModuleID = 'hello.c' 7 | target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" 8 | target triple = "x86_64-unknown-freebsd11.0" 9 | 10 | ; Function Attrs: nounwind uwtable 11 | define i32 @main() #0 { 12 | entry: 13 | ret i32 0 14 | } 15 | 16 | attributes #0 = { nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } 17 | -------------------------------------------------------------------------------- /test/regression/sccp-block-fold.ll: -------------------------------------------------------------------------------- 1 | ; \file sccp-block-fold.ll 2 | ; \brief Regression test for constant propagation of degenerate block branches, 3 | ; leading to "Didn't fold away reference to block!" in 4 | ; llvm::runIPSCCP at lib/Transforms/Scalar/SCCP.cpp:1867. 5 | ; 6 | ; This test was derived from bsdgrep.full.bc using LLVM's bugpoint. 7 | ; 8 | ; Commands for llvm-lit: 9 | ; RUN: %loom -O2 -S %s -loom-file %s.policy -o %t.instr.ll 10 | 11 | target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" 12 | target triple = "x86_64-unknown-freebsd11.0" 13 | 14 | define void @fastcmp() { 15 | entry: 16 | br i1 undef, label %a, label %b 17 | 18 | a: 19 | %0 = load i8*, i8** undef, align 8 20 | br label %b 21 | 22 | b: 23 | ret void 24 | } 25 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(LLVM_LIT ${LLVM_BINARY_DIR}/llvm-lit) 2 | 3 | set(SHOW_TEST_STATS true CACHE BOOL "Show statistics after running tests") 4 | if (SHOW_TEST_STATS) 5 | message(STATUS "Will show statistics after each test run") 6 | set(LIT_OPTIONS "-sv") 7 | else () 8 | message(STATUS "Will run successful tests quietly") 9 | set(LIT_OPTIONS "-qv") 10 | endif () 11 | 12 | 13 | add_custom_target(check 14 | COMMAND 15 | ${LLVM_LIT} ${LIT_OPTIONS} ${CMAKE_CURRENT_SOURCE_DIR} 16 | --param=build_dir=${CMAKE_BINARY_DIR} 17 | --param=source_dir=${CMAKE_SOURCE_DIR} 18 | --param=output_dir=${CMAKE_CURRENT_BINARY_DIR} 19 | --xunit-xml-output=loom.xml 20 | 21 | BYPRODUCTS loom.xml 22 | COMMENT "Running unit tests" 23 | ) 24 | 25 | add_dependencies(check LLVMLoom) 26 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(FILES 2 | DebugInfo 3 | DTraceLogger 4 | Instrumentation 5 | Instrumenter 6 | InstrStrategy 7 | IRUtils 8 | KTraceLogger 9 | Logger 10 | NVSerializer 11 | Policy 12 | PolicyFile 13 | Serializer 14 | Strings 15 | Transform 16 | DagTransform 17 | ) 18 | 19 | foreach(base IN LISTS FILES) 20 | list(APPEND HEADERS ${base}.hh) 21 | list(APPEND SOURCES ${base}.cc) 22 | endforeach(base) 23 | 24 | list(APPEND SOURCES OptPass.cc) 25 | list(APPEND HEADERS Metadata.hh) 26 | 27 | file(COPY ${HEADERS} DESTINATION ${CMAKE_BINARY_DIR}/include/loom) 28 | install(FILES ${HEADERS} COMPONENT "development" DESTINATION "include/loom") 29 | 30 | add_llvm_library(LLVMLoom MODULE BUILDTREE_ONLY ${SOURCES}) 31 | install(TARGETS LLVMLoom COMPONENT "runtime" DESTINATION "lib") 32 | -------------------------------------------------------------------------------- /doc/doxygen/footer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /test/ktrace-kernel.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file ktrace-kernel.c 3 | * \brief Tests kernel-mode ktrace instrumentation. 4 | * 5 | * Commands for llvm-lit: 6 | * RUN: %cpp -DPOLICY_FILE %s > %t.yaml 7 | * RUN: %cpp %cflags %s > %t.c 8 | * RUN: %clang %cflags -S -emit-llvm %cflags %t.c -o %t.ll 9 | * RUN: %loom -S %t.ll -loom-file %t.yaml -o %t.instr.ll 10 | * RUN: %filecheck -input-file %t.instr.ll %s 11 | */ 12 | 13 | #if defined (POLICY_FILE) 14 | 15 | hook_prefix: __ktrace_test 16 | 17 | ktrace: kernel 18 | 19 | block_structure: true 20 | 21 | functions: 22 | - name: foo 23 | caller: [ entry ] 24 | 25 | #else 26 | 27 | #include 28 | 29 | // CHECK: define{{.*}} [[FOO_TYPE:i[0-9]+]] @foo(i32{{.*}}, float{{.*}}, double{{.*}}) 30 | int foo(int x, float y, double z) 31 | { 32 | return x; 33 | } 34 | 35 | // CHECK: define{{.*}} void @__ktrace_test_call_foo 36 | // CHECK-NEXT: preamble: 37 | // CHECK: call void @ktrstruct 38 | 39 | int 40 | main(int argc, char *argv[]) 41 | { 42 | foo(1, 2, 3); 43 | 44 | return 0; 45 | } 46 | 47 | #endif /* !POLICY_FILE */ 48 | -------------------------------------------------------------------------------- /test/ktrace-userspace.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file ktrace-userspace.c 3 | * \brief Tests userspace ktrace instrumentation. 4 | * 5 | * Commands for llvm-lit: 6 | * RUN: %cpp -DPOLICY_FILE %s > %t.yaml 7 | * RUN: %cpp %cflags %s > %t.c 8 | * RUN: %clang %cflags -S -emit-llvm %cflags %t.c -o %t.ll 9 | * RUN: %loom -S %t.ll -loom-file %t.yaml -o %t.instr.ll 10 | * RUN: %filecheck -input-file %t.instr.ll %s 11 | */ 12 | 13 | #if defined (POLICY_FILE) 14 | 15 | hook_prefix: __ktrace_test 16 | 17 | ktrace: utrace 18 | 19 | block_structure: true 20 | 21 | functions: 22 | - name: foo 23 | caller: [ entry ] 24 | 25 | #else 26 | 27 | #include 28 | 29 | // CHECK: define{{.*}} [[FOO_TYPE:i[0-9]+]] @foo(i32{{.*}}, float{{.*}}, double{{.*}}) 30 | int foo(int x, float y, double z) 31 | { 32 | return x; 33 | } 34 | 35 | // CHECK: define{{.*}} void @__ktrace_test_call_foo 36 | // CHECK-NEXT: preamble: 37 | // CHECK: call i32 @utrace 38 | 39 | int 40 | main(int argc, char *argv[]) 41 | { 42 | foo(1, 2, 3); 43 | 44 | return 0; 45 | } 46 | 47 | #endif /* !POLICY_FILE */ 48 | -------------------------------------------------------------------------------- /test/regression/non-dominating-inst.ll: -------------------------------------------------------------------------------- 1 | ; \file non-dominating-inst.ll 2 | ; \brief Regression test for Phi node handling, leading to 3 | ; "Instruction does not dominate all uses" error. 4 | ; 5 | ; This test was derived from bsdgrep.full.bc using LLVM's bugpoint. 6 | ; 7 | ; Commands for llvm-lit: 8 | ; RUN: %loom -S %s -loom-file %s.policy -o %t.instr.ll 9 | 10 | target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" 11 | target triple = "x86_64-unknown-freebsd11.0" 12 | 13 | define void @fastcmp() { 14 | entry: 15 | br i1 undef, label %cond.true, label %cond.false 16 | 17 | cond.true: ; preds = %entry 18 | %0 = load i8*, i8** undef, align 8 19 | br label %cond.end 20 | 21 | cond.false: ; preds = %entry 22 | br label %cond.end 23 | 24 | cond.end: ; preds = %cond.false, %cond.true 25 | %cond = phi i8* [ %0, %cond.true ], [ undef, %cond.false ] 26 | br label %for.cond 27 | 28 | for.cond: ; preds = %for.cond, %cond.end 29 | br label %for.cond 30 | } 31 | -------------------------------------------------------------------------------- /test/static.c: -------------------------------------------------------------------------------- 1 | /*! 2 | * \file static-functions.c 3 | * \brief Tests instrumentation of static functions. 4 | * 5 | * Commands for llvm-lit: 6 | * RUN: %cpp -DPOLICY_FILE %s > %t.yaml 7 | * RUN: %cpp %cflags %s > %t.c 8 | * RUN: %clang -S -emit-llvm %cflags %t.c -o %t.ll 9 | * RUN: %loom -S %t.ll -loom-file %t.yaml -o %t.instr.ll 10 | * RUN: %filecheck -input-file %t.instr.ll %s 11 | */ 12 | 13 | #if defined (POLICY_FILE) 14 | 15 | hook_prefix: __test_hook 16 | 17 | block_structure: true 18 | 19 | functions: 20 | - name: foo 21 | callee: [ entry, exit ] 22 | caller: [ entry, exit ] 23 | 24 | #else 25 | 26 | static void foo(); 27 | 28 | 29 | int 30 | main(int argc, char *argv[]) 31 | { 32 | // CHECK: define{{.*}} i{{[0-9]+}} @main 33 | 34 | // CHECK: call void @[[PREFIX:__test_hook]]_call_foo 35 | foo(); 36 | // CHECK: call void @[[PREFIX]]_return_foo 37 | 38 | return 0; 39 | } 40 | 41 | static void 42 | foo() 43 | { 44 | /* 45 | * CHECK: define internal void @foo() 46 | * CHECK: call void @[[PREFIX]]_enter_foo 47 | * CHECK: call void @[[PREFIX]]_leave_foo 48 | */ 49 | } 50 | #endif /* !POLICY_FILE */ 51 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.3) 2 | 3 | project(LOOM) 4 | 5 | find_package(LLVM REQUIRED CONFIG) 6 | list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") 7 | 8 | # Based on http://stackoverflow.com/questions/27863706: 9 | # 10 | # AddLLVM expects LLVM{LIBRARY,RUNTIME}_OUTPUT_INTDIR to be set in order 11 | # to build successfully out of the LLVM tree on non-Mac platforms. 12 | set(LLVM_RUNTIME_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/bin) 13 | set(LLVM_LIBRARY_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib) 14 | 15 | include(HandleLLVMOptions) 16 | include(AddLLVM) 17 | 18 | add_definitions(${LLVM_DEFINITIONS}) 19 | include_directories(${LLVM_INCLUDE_DIRS}) 20 | link_directories(${LLVM_LIBRARY_DIRS}) 21 | 22 | # Where to find LLVM binaries (e.g., llvm-lit). 23 | set(LLVM_BINARY_DIR ${LLVM_DIR}/../../../bin) 24 | 25 | # Always use C++11. 26 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14") 27 | 28 | # Enable warnings, i.e., suppress LLVM's insertion of `-w`. 29 | set(LLVM_ENABLE_WARNINGS TRUE) 30 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") 31 | 32 | add_subdirectory(doc) 33 | add_subdirectory(src) 34 | add_subdirectory(test) 35 | -------------------------------------------------------------------------------- /doc/doxygen/loom-dox.css: -------------------------------------------------------------------------------- 1 | html, body, table, table.directory, div, p, dl 2 | { 3 | font-family: "Avenir Book", "Helvetica", sans-serif; 4 | } 5 | 6 | html, body, div, p, dl 7 | { 8 | font-size: 100%; 9 | line-height: 120%; 10 | } 11 | 12 | table, table.directory 13 | { 14 | font-size: 80%; 15 | } 16 | 17 | h1, .h1, h2, h3, h4, h5, h6, .navbar-brand 18 | { 19 | font-family: "Avenir Black", "Roboto", "Helvetica", sans-serif; 20 | font-weight: bold; 21 | } 22 | 23 | div.fragment 24 | { 25 | background-color: #edf2f9; 26 | border-color: #7392cb; 27 | } 28 | 29 | div.line 30 | { 31 | font-size: 80%; 32 | } 33 | 34 | .navbar-brand 35 | { 36 | font-size: 110%; 37 | } 38 | 39 | .navbar-default 40 | { 41 | background-color: #7392cb; 42 | border-color: #7392cb; 43 | } 44 | 45 | .navbar-default .navbar-brand 46 | { 47 | color: #ddd; 48 | } 49 | 50 | .navbar-default .navbar-nav > li > a 51 | { 52 | color: #eee; 53 | } 54 | 55 | .navbar-default .navbar-nav > li > a:focus, 56 | .navbar-default .navbar-nav > li > a:hover 57 | { 58 | color: #fff; 59 | } 60 | 61 | .table tr td.memItemLeft, 62 | .table tr td.memItemRight 63 | { 64 | padding: 0 0 0 8px; 65 | } 66 | 67 | .table tr td.mdescLeft, 68 | .table tr td.mdescRight 69 | { 70 | padding-left: 1em; 71 | padding-bottom: 0.5em; 72 | } 73 | -------------------------------------------------------------------------------- /test/ktrace-userspace-libnv-run.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file ktrace-userspace-libnv-run.c 3 | * \brief Actually run utrace instrumentation with libnv serialization. 4 | * 5 | * FreeBSD <11 doesn't provide the libnv we're looking for in base or ports: 6 | * XFAIL: darwin, freebsd9, freebsd10, linux 7 | * 8 | * Commands for llvm-lit: 9 | * RUN: %cpp -DPOLICY_FILE %s > %t.yaml 10 | * RUN: %cpp %cflags %s > %t.c 11 | * RUN: %clang -target x86_64-unknown-freebsd %cflags -S -emit-llvm %cflags %t.c -o %t.ll 12 | * RUN: %loom -S %t.ll -loom-file %t.yaml -loom-nv-debug -o %t.instr.ll 13 | * RUN: %clang -lnv %t.instr.ll -o %t.instr 14 | * RUN: %t.instr 2> %t.instr.out 15 | * RUN: %filecheck -input-file %t.instr.out %s 16 | */ 17 | 18 | #if defined (POLICY_FILE) 19 | 20 | hook_prefix: __ktrace_test 21 | 22 | ktrace: utrace 23 | 24 | serialization: nv 25 | 26 | block_structure: true 27 | 28 | functions: 29 | - name: foo 30 | caller: [ exit ] 31 | 32 | #else 33 | 34 | #include 35 | 36 | int foo(int x, float y, double z) 37 | { 38 | return x; 39 | } 40 | 41 | // CHECK: name (STRING): [__ktrace_test_return_foo] 42 | // CHECK-NEXT: description (STRING): [return foo:] 43 | // CHECK-NEXT: values (NVLIST): 44 | // CHECK-NEXT: (NUMBER): {{.*}} (1) (0x1) 45 | // CHECK-NEXT: (NUMBER): {{.*}} (1) (0x1) 46 | 47 | int 48 | main(int argc, char *argv[]) 49 | { 50 | foo(1, 2, 3); 51 | 52 | return 0; 53 | } 54 | 55 | #endif /* !POLICY_FILE */ 56 | -------------------------------------------------------------------------------- /test/regression/missing-phi.ll: -------------------------------------------------------------------------------- 1 | ; \file missing-phi.ll 2 | ; \brief Regression test for error that manifested as 3 | ; "PHINode should have one entry for each predecessor" 4 | ; 5 | ; This test was derived from bsdgrep.full.bc using LLVM's bugpoint. 6 | ; 7 | ; TODO: set block_structure to true 8 | ; 9 | ; Commands for llvm-lit: 10 | ; RUN: %loom -O2 -S %s -loom-file %s.policy -o %t.instr.ll 11 | 12 | ; ModuleID = 'bugpoint-reduced-simplified.bc' 13 | source_filename = "bugpoint-output-2c605a7.bc" 14 | target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" 15 | target triple = "x86_64-unknown-freebsd11.0" 16 | 17 | define void @tre_match_fast() { 18 | entry: 19 | %shift = alloca i32, align 4 20 | %j = alloca i64, align 8 21 | br label %do.body 22 | 23 | do.body: 24 | br i1 undef, label %if.then220, label %if.end405 25 | 26 | if.then220: 27 | store i32 1, i32* %shift, align 4 28 | br label %do.cond 29 | 30 | if.end405: 31 | %tobool430 = trunc i8 undef to i1 32 | br i1 %tobool430, label %if.end462, label %if.end405 33 | 34 | if.end462: 35 | %0 = load i32, i32* %shift, align 4 36 | store i32 %0, i32* %shift, align 4 37 | %sub584 = sub nsw i64 undef, undef 38 | store i64 %sub584, i64* %j, align 8 39 | br label %do.cond 40 | 41 | do.cond: 42 | %1 = load i64, i64* %j, align 8 43 | br label %do.body 44 | } 45 | 46 | ; Function Attrs: noreturn nounwind 47 | declare void @llvm.trap() #0 48 | 49 | attributes #0 = { noreturn nounwind } 50 | -------------------------------------------------------------------------------- /test/ktrace-userspace-libnv.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file ktrace-userspace-libnv.c 3 | * \brief Tests userspace ktrace instrumentation with libnv serialization. 4 | * 5 | * Commands for llvm-lit: 6 | * RUN: %cpp -DPOLICY_FILE %s > %t.yaml 7 | * RUN: %cpp %cflags %s > %t.c 8 | * RUN: %clang -target x86_64-unknown-freebsd %cflags -S -emit-llvm %cflags %t.c -o %t.ll 9 | * RUN: %loom -S %t.ll -loom-file %t.yaml -loom-nv-debug -o %t.instr.ll 10 | * RUN: %filecheck -input-file %t.instr.ll %s 11 | */ 12 | 13 | #if defined (POLICY_FILE) 14 | 15 | hook_prefix: __ktrace_test 16 | 17 | ktrace: utrace 18 | 19 | serialization: nv 20 | 21 | block_structure: true 22 | 23 | functions: 24 | - name: foo 25 | caller: [ exit ] 26 | 27 | #else 28 | 29 | #include 30 | 31 | // CHECK: define{{.*}} [[FOO_TYPE:i[0-9]+]] @foo(i32{{.*}}, float{{.*}}, double{{.*}}) 32 | int foo(int x, float y, double z) 33 | { 34 | return x; 35 | } 36 | 37 | // CHECK: define{{.*}} void @__ktrace_test_return_foo 38 | // CHECK-NEXT: preamble: 39 | // CHECK: [[LIST:%.*]] = call %nvlist_t* @nvlist_create 40 | // CHECK: [[BUFFER:%.*]] = call i8* @nvlist_pack(%nvlist_t* [[LIST]], i64* [[LENPTR:%.*]]) 41 | // CHECK-DAG: [[LEN:%.*]] = load i64, i64* [[LENPTR]] 42 | // CHECK-DAG: call void @nvlist_destroy(%nvlist_t* [[LIST]]) 43 | // CHECK: call i32 @utrace(i8* [[BUFFER]], i64 [[LEN]]) 44 | 45 | int 46 | main(int argc, char *argv[]) 47 | { 48 | foo(1, 2, 3); 49 | 50 | return 0; 51 | } 52 | 53 | #endif /* !POLICY_FILE */ 54 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Unless specified otherwise, the contents of this directory are distributed 2 | according to the following terms. 3 | 4 | Copyright (c) 2011-2015 Jonathan Anderson 5 | Copyright (c) 2011-2014 Robert N. M. Watson 6 | Copyright (c) 2013-2014 David Chisnall 7 | Copyright (c) 2013-2014 Khilan Gudka 8 | Copyright (c) 2011 Anil Madhavapeddy 9 | Copyright (c) 2011 Steven Murdoch 10 | All rights reserved. 11 | 12 | The development of this software was sponsored by: 13 | - DARPA CRASH (AFRL FA8750-10-C-0237) 14 | - DARPA Transparent Computing (AFRL FA8650-15-C-7558) 15 | - NSERC Discovery (RGPIN/06048-2015) 16 | 17 | Redistribution and use in source and binary forms, with or without 18 | modification, are permitted provided that the following conditions 19 | are met: 20 | 1. Redistributions of source code must retain the above copyright 21 | notice, this list of conditions and the following disclaimer. 22 | 2. Redistributions in binary form must reproduce the above copyright 23 | notice, this list of conditions and the following disclaimer in the 24 | documentation and/or other materials provided with the distribution. 25 | 26 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 27 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 | ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 30 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 | SUCH DAMAGE. 37 | -------------------------------------------------------------------------------- /src/Strings.hh: -------------------------------------------------------------------------------- 1 | //! @file Strings.hh Declaration of string manipulation functions. 2 | /* 3 | * Copyright (c) 2015 Jonathan Anderson 4 | * All rights reserved. 5 | * 6 | * This software was developed at Memorial University under the 7 | * NSERC Discovery program (RGPIN-2015-06048). 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 | * SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef LOOM_STRINGS_H 32 | #define LOOM_STRINGS_H 33 | 34 | #include 35 | #include 36 | 37 | namespace loom { 38 | 39 | std::string Join(const std::vector &, 40 | const std::string &delim = ","); 41 | 42 | } // namespace loom 43 | 44 | #endif /* LOOM_STRINGS_H */ 45 | -------------------------------------------------------------------------------- /test/indirect-fields.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Commands for llvm-lit: 3 | * RUN: %cpp -DPOLICY_FILE %s > %t.yaml 4 | * RUN: %cpp %cflags %s > %t.c 5 | * RUN: %clang %cflags -S -emit-llvm %cflags %t.c -o %t.ll 6 | * RUN: %loom -S %t.ll -loom-file %t.yaml -o %t.instr.ll 7 | * RUN: %filecheck -input-file %t.instr.ll %s 8 | * RUN: %llc -filetype=obj %t.instr.ll -o %t.instr.o 9 | * RUN: %clang %ldflags %t.instr.o -o %t.instr 10 | * RUN: %t.instr > %t.output 11 | * RUN: %filecheck -input-file %t.output %s -check-prefix CHECK-OUTPUT 12 | */ 13 | 14 | #if defined (POLICY_FILE) 15 | 16 | hook_prefix: TEST 17 | 18 | logging: printf 19 | 20 | block_structure: true 21 | 22 | structures: 23 | - name: foo 24 | fields: 25 | - name: f_int 26 | operations: [ read, write ] 27 | 28 | #else 29 | 30 | struct foo { 31 | int f_int; 32 | int f_int2; 33 | }; 34 | 35 | struct bar { 36 | int b_int; 37 | double b_double; 38 | struct foo b_foo; 39 | }; 40 | 41 | 42 | int 43 | main(int argc, char *argv[]) 44 | { 45 | struct bar bars[] = { 46 | { .b_foo = { .f_int = 99 } }, 47 | { .b_foo = { .f_int = 42 } }, 48 | }; 49 | 50 | // CHECK: [[F_INT_PTR:%.+]] = getelementptr inbounds %struct.foo, [[FOO:%.*]], i32 0, i32 0 51 | // CHECK: [[F_INT_PTR:%.+]] = getelementptr inbounds %struct.foo, [[FOO:%.*]], i32 0, i32 0 52 | // CHECK: [[F_INT_PTR:%.+]] = getelementptr inbounds %struct.foo, [[FOO:%.*]], i32 0, i32 0 53 | // CHECK: [[F_INT_NOW:%[0-9]+]] = load [[INT:i[0-9]+]], [[INT]]* [[F_INT_PTR]] 54 | // CHECK: call void @[[PREFIX:TEST]]_load_struct_foo_field_f_int([[FOO]], [[INT]] [[F_INT_NOW]] 55 | // CHECK: [[INC:%.+]] = add {{.*}}[[INT]] [[F_INT_NOW]], 1 56 | // CHECK: call void @[[PREFIX]]_store_struct_foo_field_f_int([[FOO]], [[INT]] [[INC]]) 57 | 58 | // CHECK-OUTPUT: foo.f_int load: [[FOO:0x.*]] 42 59 | // CHECK-OUTPUT: foo.f_int store: [[FOO]] 43 60 | int offset = 1; 61 | (bars + offset)->b_foo.f_int++; 62 | 63 | return 0; 64 | } 65 | 66 | #endif /* !POLICY_FILE */ 67 | 68 | -------------------------------------------------------------------------------- /src/Strings.cc: -------------------------------------------------------------------------------- 1 | //! @file Strings.cc Definition of string manipulation functions. 2 | /* 3 | * Copyright (c) 2015 Jonathan Anderson 4 | * All rights reserved. 5 | * 6 | * This software was developed at Memorial University under the 7 | * NSERC Discovery program (RGPIN-2015-06048). 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 | * SUCH DAMAGE. 29 | */ 30 | 31 | #include "Strings.hh" 32 | 33 | #include 34 | #include 35 | #include 36 | 37 | using namespace std; 38 | 39 | string loom::Join(const vector &Components, const string &Delimiter) { 40 | ostringstream Stream; 41 | ostream_iterator Iterator(Stream, Delimiter.c_str()); 42 | 43 | std::copy(Components.begin(), Components.end() - 1, Iterator); 44 | Stream << Components.back(); 45 | 46 | return Stream.str(); 47 | } 48 | -------------------------------------------------------------------------------- /src/DagTransform.hh: -------------------------------------------------------------------------------- 1 | //! @file DTraceLogger.hh Declaration of @refDagTransform. 2 | /* 3 | * Copyright (c) 2021 Brian Kidney 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 | * SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef DAG_TRANSFORM_H_ 29 | #define DAG_TRANSFORM_H_ 30 | 31 | #include 32 | #include 33 | 34 | namespace llvm { 35 | class BasicBlock; 36 | class Value; 37 | class Instruction; 38 | class StoreInst; 39 | class StringRef; 40 | } // namespace llvm 41 | 42 | 43 | namespace loom { 44 | 45 | bool findAllUsers(llvm::Instruction *Call, std::queue dagTail, std::vector& toDelete); 46 | bool findStoreCalls(llvm::StoreInst *Store, std::queue dagTail, std::vector& toDelete); 47 | 48 | } // namespace loom 49 | 50 | #endif // !DAG_TRANSFORM_H_ 51 | -------------------------------------------------------------------------------- /src/Metadata.hh: -------------------------------------------------------------------------------- 1 | //! @file Metadata.hh Declaration of policy metadata. 2 | /* 3 | * Copyright (c) 2018 Brian Kidney 4 | * All rights reserved. 5 | * 6 | * This software was developed by BAE Systems, the University of Cambridge 7 | * Computer Laboratory, and Memorial University under DARPA/AFRL contract 8 | * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing 9 | * (TC) research program. 10 | * 11 | * Redistribution and use in source and binary forms, with or without 12 | * modification, are permitted provided that the following conditions 13 | * are met: 14 | * 1. Redistributions of source code must retain the above copyright 15 | * notice, this list of conditions and the following disclaimer. 16 | * 2. Redistributions in binary form must reproduce the above copyright 17 | * notice, this list of conditions and the following disclaimer in the 18 | * documentation and/or other materials provided with the distribution. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 | * SUCH DAMAGE. 31 | */ 32 | 33 | #ifndef LOOM_METADATA_H 34 | #define LOOM_METADATA_H 35 | 36 | 37 | namespace loom { 38 | 39 | //! Metadata to be recorded with the instrumentation 40 | typedef struct Metadata { 41 | Metadata(std::string n = "", int i = 0) { 42 | Name = n; 43 | Id = i; 44 | } 45 | 46 | bool isValid() { 47 | if (Name.empty() and Id == 0) { 48 | return false; 49 | } 50 | return true; 51 | } 52 | 53 | std::string Name; 54 | unsigned int Id; 55 | } Metadata; 56 | 57 | 58 | } // namespace loom 59 | 60 | #endif /* LOOM_METADATA_H */ 61 | -------------------------------------------------------------------------------- /src/IRUtils.cc: -------------------------------------------------------------------------------- 1 | //! @file IRUtils.cc Definition of LLVM IR utility functions. 2 | /* 3 | * Copyright (c) 2016 Jonathan Anderson 4 | * All rights reserved. 5 | * 6 | * This software was developed by BAE Systems, the University of Cambridge 7 | * Computer Laboratory, and Memorial University under DARPA/AFRL contract 8 | * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing 9 | * (TC) research program. 10 | * 11 | * Redistribution and use in source and binary forms, with or without 12 | * modification, are permitted provided that the following conditions 13 | * are met: 14 | * 1. Redistributions of source code must retain the above copyright 15 | * notice, this list of conditions and the following disclaimer. 16 | * 2. Redistributions in binary form must reproduce the above copyright 17 | * notice, this list of conditions and the following disclaimer in the 18 | * documentation and/or other materials provided with the distribution. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 | * SUCH DAMAGE. 31 | */ 32 | 33 | #include "IRUtils.hh" 34 | 35 | #include "llvm/IR/Function.h" 36 | #include "llvm/IR/Module.h" 37 | 38 | #include 39 | 40 | using namespace llvm; 41 | using namespace loom; 42 | using std::vector; 43 | 44 | BasicBlock *loom::FindBlock(StringRef Name, Function &Fn) { 45 | for (auto &B : Fn) 46 | if (B.getName() == Name) 47 | return &B; 48 | 49 | return NULL; 50 | } 51 | 52 | ParamVec loom::GetParameters(Function *Fn) { 53 | ParamVec Parameters; 54 | for (auto &Arg : Fn->args()) { 55 | Parameters.emplace_back(Arg.getName(), Arg.getType()); 56 | } 57 | return Parameters; 58 | } 59 | -------------------------------------------------------------------------------- /src/IRUtils.hh: -------------------------------------------------------------------------------- 1 | //! @file IRUtils.hh Declarations of LLVM IR utility functions. 2 | /* 3 | * Copyright (c) 2016 Jonathan Anderson 4 | * All rights reserved. 5 | * 6 | * This software was developed by BAE Systems, the University of Cambridge 7 | * Computer Laboratory, and Memorial University under DARPA/AFRL contract 8 | * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing 9 | * (TC) research program. 10 | * 11 | * Redistribution and use in source and binary forms, with or without 12 | * modification, are permitted provided that the following conditions 13 | * are met: 14 | * 1. Redistributions of source code must retain the above copyright 15 | * notice, this list of conditions and the following disclaimer. 16 | * 2. Redistributions in binary form must reproduce the above copyright 17 | * notice, this list of conditions and the following disclaimer in the 18 | * documentation and/or other materials provided with the distribution. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 | * SUCH DAMAGE. 31 | */ 32 | 33 | #ifndef LOOM_IRUTILS_H 34 | #define LOOM_IRUTILS_H 35 | 36 | #include 37 | #include 38 | 39 | #include 40 | 41 | namespace loom { 42 | 43 | /// Information about a (named) parameter to a function. 44 | typedef std::pair Parameter; 45 | 46 | /// An ordered collection of Parameter objects. 47 | typedef std::vector ParamVec; 48 | 49 | /// Find a named BasicBlock within a function. 50 | llvm::BasicBlock *FindBlock(llvm::StringRef Name, llvm::Function &); 51 | 52 | /// Retrieve a function's parameter names and types. 53 | ParamVec GetParameters(llvm::Function *); 54 | 55 | } // namespace loom 56 | 57 | #endif // LOOM_IRUTILS_H 58 | -------------------------------------------------------------------------------- /test/wildcard-function-instrumentation.c: -------------------------------------------------------------------------------- 1 | /* 2 | * \file function-instrumentation.c 3 | * \brief Tests callee-context function instrumentation. 4 | * 5 | * Commands for llvm-lit: 6 | * RUN: %cpp -DPOLICY_FILE %s > %t.yaml 7 | * RUN: %cpp %cflags %s > %t.c 8 | * RUN: %clang %cflags -S -emit-llvm %cflags %t.c -o %t.ll 9 | * RUN: %loom -S %t.ll -loom-file %t.yaml -o %t.instr.ll 10 | * RUN: %filecheck -input-file %t.instr.ll %s 11 | * RUN: %llc -filetype=obj %t.instr.ll -o %t.instr.o 12 | * RUN: %clang %ldflags %t.instr.o -o %t.instr 13 | * RUN: %t.instr > %t.output 14 | * RUN: %filecheck -input-file %t.output %s -check-prefix CHECK-OUTPUT 15 | */ 16 | 17 | #if defined (POLICY_FILE) 18 | 19 | hook_prefix: __test_hook 20 | 21 | logging: printf 22 | 23 | block_structure: true 24 | 25 | functions: 26 | - name: "[a-zA-Z0-9_]+" 27 | callee: [ entry, exit ] 28 | 29 | #else 30 | 31 | #include 32 | 33 | // CHECK: define{{.*}} [[FOO_TYPE:.*]] @foo([[INT:i[0-9]+]]{{.*}}, float{{.*}}, double{{.*}}) 34 | int foo(int x, float y, double z) 35 | { 36 | // CHECK: call void @[[PREFIX:__test_hook]]_enter_foo([[FOO_ARGS:.*]]) 37 | printf("foo(%d, %g, %g)\n", x, y, z); 38 | return x; 39 | // CHECK: call void @[[PREFIX]]_leave_foo([[FOO_TYPE]] [[RETVAL:.*]], [[FOO_ARGS]]) 40 | // CHECK-NEXT: ret [[FOO_TYPE]] [[RETVAL]] 41 | } 42 | 43 | // CHECK: define{{.*}} [[BAR_TYPE:.*]] @bar([[INT]]{{.*}}, i8*{{.*}}) 44 | float bar(unsigned int i, const char *s) 45 | { 46 | // CHECK: call void @[[PREFIX]]_enter_bar([[INT]] {{%.*}}, i8* {{%.*}}) 47 | printf("bar(%d, \"%s\")\n", i, s); 48 | // CHECK: call void @[[PREFIX]]_leave_bar 49 | return i; 50 | } 51 | 52 | // CHECK: define{{.*}} double @baz() 53 | double baz(void) 54 | { 55 | // CHECK: call void @[[PREFIX]]_enter_baz 56 | printf("baz()\n"); 57 | // CHECK: call void @[[PREFIX]]_leave_baz 58 | return 0; 59 | } 60 | 61 | int 62 | main(int argc, char *argv[]) 63 | { 64 | printf("Hello, world!\n"); 65 | 66 | printf("First, we will call foo():\n"); 67 | foo(1, 2, 3); 68 | // CHECK-OUTPUT: enter foo: 1 2{{.*}} 3{{.*}} 69 | // CHECK-OUTPUT: foo(1, 2, 3) 70 | // CHECK-OUTPUT: leave foo: 1 1 2{{.*}} 3{{.*}} 71 | 72 | printf("Then bar():\n"); 73 | bar(4, "5"); 74 | // CHECK-OUTPUT: enter bar: 4 0x{{[0-9a-z]+}} 75 | // CHECK-OUTPUT: bar(4, "5") 76 | // CHECK-OUTPUT: leave bar 77 | 78 | printf("And finally baz():\n"); 79 | baz(); 80 | // CHECK-OUTPUT: enter baz 81 | // CHECK-OUTPUT: baz 82 | // CHECK-OUTPUT: leave baz 83 | 84 | 85 | return 0; 86 | } 87 | 88 | #endif /* !POLICY_FILE */ 89 | -------------------------------------------------------------------------------- /src/Transform.hh: -------------------------------------------------------------------------------- 1 | //! @file Transform.hh Declaration of logging transforms. 2 | /* 3 | * Copyright (c) 2019 Brian Kidney 4 | * All rights reserved. 5 | * 6 | * This software was developed by BAE Systems, the University of Cambridge 7 | * Computer Laboratory, and Memorial University under DARPA/AFRL contract 8 | * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing 9 | * (TC) research program. 10 | * 11 | * Redistribution and use in source and binary forms, with or without 12 | * modification, are permitted provided that the following conditions 13 | * are met: 14 | * 1. Redistributions of source code must retain the above copyright 15 | * notice, this list of conditions and the following disclaimer. 16 | * 2. Redistributions in binary form must reproduce the above copyright 17 | * notice, this list of conditions and the following disclaimer in the 18 | * documentation and/or other materials provided with the distribution. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 | * SUCH DAMAGE. 31 | */ 32 | 33 | #ifndef LOOM_TRANSFORM_H 34 | #define LOOM_TRANSFORM_H 35 | 36 | 37 | namespace loom { 38 | 39 | //! Transforms to be applied during the instrumentation 40 | class Transform { 41 | 42 | public: 43 | Transform(std::string fn = "", int i = 0) { 44 | Arg = i; 45 | Fn = fn; 46 | } 47 | 48 | bool isValid() { 49 | if (Fn.empty() and Arg == 0) { 50 | return false; 51 | } 52 | return true; 53 | } 54 | 55 | unsigned int Arg; 56 | std::string Fn; 57 | 58 | llvm::Value* CreateTransform(llvm::Instruction*, llvm::Module&, llvm::Value*); 59 | 60 | private: 61 | llvm::Value* CreateUUIDTransform(llvm::Instruction*, llvm::Module&, llvm::Value*); 62 | 63 | }; 64 | 65 | 66 | 67 | } // namespace loom 68 | 69 | #endif /* LOOM_TRANSFORMS_H */ 70 | -------------------------------------------------------------------------------- /scripts/loom-fbsdmake: -------------------------------------------------------------------------------- 1 | #!/bin/sh -x 2 | 3 | . `dirname $0`/xtools.sh 4 | 5 | # 6 | # Find the LLVM tools whose versions match those expected by Loom: 7 | # 8 | # - in an explicit LLVM_PREFIX environment variable 9 | # - relative to the `opt` tool in the current PATH 10 | # 11 | if [ "${LLVM_PREFIX}" = "" ] 12 | then 13 | llvm_link=`which llvm-link` 14 | if [ -e "${llvm_link}" ] 15 | then 16 | LLVM_PREFIX=`dirname ${llvm_link} | xargs dirname` 17 | else 18 | echo "LLVM_PREFIX not set and no llvm-link in PATH" 19 | exit 1 20 | fi 21 | fi 22 | 23 | 24 | check_tool ${LLVM_PREFIX} CC clang 25 | check_tool ${LLVM_PREFIX} CXX clang++ 26 | check_tool ${LLVM_PREFIX} LLC llc 27 | check_tool ${LLVM_PREFIX} LLVM_LINK llvm-link 28 | check_tool ${LLVM_PREFIX} OPT opt 29 | 30 | 31 | # 32 | # Find the Loom library: 33 | # 34 | # - as explicitly specified with LOOM_LIB 35 | # - within LLVM_PREFIX 36 | # 37 | 38 | libname=LLVMLoom.so 39 | 40 | if [ "${LOOM_LIB}" = "" ] 41 | then 42 | LOOM_LIB="${LLVM_PREFIX}/lib/${libname}" 43 | 44 | if ! [ -e "${LOOM_LIB}" ] 45 | then 46 | echo "LOOM_LIB not specified, no ${libname} in LLVM_PREFIX" 47 | exit 1 48 | fi 49 | fi 50 | 51 | export LOOM_FILE="loom.policy" 52 | 53 | export LLVM_INSTR_DEPS="${LOOM_FILE}" 54 | export LLVM_INSTR_FLAGS="-load ${LOOM_LIB} -loom -loom-file ${LOOM_FILE} \ 55 | ${LLVM_INSTR_FLAGS}" 56 | export LLVM_INSTR_LDADD="-lxo" 57 | 58 | # If building on FreeBSD 10, /usr/bin/ld doesn't support the 59 | # --no-fatal-warnings option, so we need to suppress its use. 60 | if [ `uname -U` -lt 1100000 ] 61 | then 62 | export LD_NO_FATAL_WARNS= 63 | fi 64 | 65 | # Default to the LOOM kernel config, but allow this to be overridden. 66 | : ${KERNCONF:="LOOM"} 67 | export KERNCONF 68 | 69 | # Use instrumentation in the kernel config phase. 70 | export CONFIGARGS="-i" 71 | 72 | # Set up an instrumentation policy for the kernel. 73 | KERNEL_OBJDIR="`make -V .OBJDIR`/sys/${KERNCONF}" 74 | mkdir -p ${KERNEL_OBJDIR} 75 | 76 | if [ -e "${KERNEL_INSTR_POLICY}" ] 77 | then 78 | cp ${KERNEL_INSTR_POLICY} ${KERNEL_OBJDIR}/loom.policy 79 | else 80 | echo "No KERNEL_INSTR_POLICY specified, defaulting to" \ 81 | "no kernel instrumentation" 82 | 83 | echo << EOF >> ${KERNEL_OBJDIR}/${LOOM_FILE} 84 | # Auto-generated kernel instrumentation configuration 85 | 86 | strategy: inline 87 | logging: none 88 | EOF 89 | 90 | fi 91 | 92 | # Disable -Werror in both buildworld (NO_WERROR) and buildkernel (WERROR). 93 | # This is currently necessary due to warnings generated by development 94 | # versions of Clang (v3.9). 95 | export NO_WERROR= 96 | export WERROR= 97 | 98 | make $* 99 | -------------------------------------------------------------------------------- /test/function-instrumentation.c: -------------------------------------------------------------------------------- 1 | /* 2 | * \file function-instrumentation.c 3 | * \brief Tests callee-context function instrumentation. 4 | * 5 | * Commands for llvm-lit: 6 | * RUN: %cpp -DPOLICY_FILE %s > %t.yaml 7 | * RUN: %cpp %cflags %s > %t.c 8 | * RUN: %clang %cflags -S -emit-llvm %cflags %t.c -o %t.ll 9 | * RUN: %loom -S %t.ll -loom-file %t.yaml -o %t.instr.ll 10 | * RUN: %filecheck -input-file %t.instr.ll %s 11 | * RUN: %llc -filetype=obj %t.instr.ll -o %t.instr.o 12 | * RUN: %clang %ldflags %t.instr.o -o %t.instr 13 | * RUN: %t.instr > %t.output 14 | * RUN: %filecheck -input-file %t.output %s -check-prefix CHECK-OUTPUT 15 | */ 16 | 17 | #if defined (POLICY_FILE) 18 | 19 | hook_prefix: __test_hook 20 | 21 | logging: printf 22 | 23 | block_structure: true 24 | 25 | functions: 26 | - name: foo 27 | callee: [ entry, exit ] 28 | 29 | - name: bar 30 | callee: [ entry ] 31 | 32 | - name: baz 33 | callee: [ exit ] 34 | 35 | #else 36 | 37 | #include 38 | 39 | // CHECK: define{{.*}} [[FOO_TYPE:.*]] @foo([[INT:i[0-9]+]]{{.*}}, float{{.*}}, double{{.*}}) 40 | int foo(int x, float y, double z) 41 | { 42 | // CHECK: call void @[[PREFIX:__test_hook]]_enter_foo([[FOO_ARGS:.*]]) 43 | printf("foo(%d, %g, %g)\n", x, y, z); 44 | return x; 45 | // CHECK: call void @[[PREFIX]]_leave_foo([[FOO_TYPE]] [[RETVAL:.*]], [[FOO_ARGS]]) 46 | // CHECK-NEXT: ret [[FOO_TYPE]] [[RETVAL]] 47 | } 48 | 49 | // CHECK: define{{.*}} [[BAR_TYPE:.*]] @bar([[INT]]{{.*}}, i8*{{.*}}) 50 | float bar(unsigned int i, const char *s) 51 | { 52 | // CHECK: call void @[[PREFIX]]_enter_bar([[INT]] {{%.*}}, i8* {{%.*}}) 53 | printf("bar(%d, \"%s\")\n", i, s); 54 | // CHECK-NOT: call void @[[PREFIX]]_leave_bar 55 | return i; 56 | } 57 | 58 | // CHECK: define{{.*}} double @baz() 59 | double baz(void) 60 | { 61 | // CHECK-NOT: call void @[[PREFIX]]_enter_baz 62 | printf("baz()\n"); 63 | // CHECK: call void @[[PREFIX]]_leave_baz 64 | return 0; 65 | } 66 | 67 | int 68 | main(int argc, char *argv[]) 69 | { 70 | printf("Hello, world!\n"); 71 | 72 | printf("First, we will call foo():\n"); 73 | foo(1, 2, 3); 74 | // CHECK-OUTPUT: enter foo: 1 2{{.*}} 3{{.*}} 75 | // CHECK-OUTPUT: foo(1, 2, 3) 76 | // CHECK-OUTPUT: leave foo: 1 1 2{{.*}} 3{{.*}} 77 | 78 | printf("Then bar():\n"); 79 | bar(4, "5"); 80 | // CHECK-OUTPUT: enter bar: 4 0x{{[0-9a-z]+}} 81 | // CHECK-OUTPUT: bar(4, "5") 82 | // CHECK-OUTPUT-NOT: leave bar 83 | 84 | printf("And finally baz():\n"); 85 | baz(); 86 | // CHECK-OUTPUT-NOT: enter baz 87 | // CHECK-OUTPUT: baz 88 | // CHECK-OUTPUT: leave baz 89 | 90 | 91 | return 0; 92 | } 93 | 94 | #endif /* !POLICY_FILE */ 95 | -------------------------------------------------------------------------------- /test/function-instrumentation-libxo.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file function-instrumentation-libxo.c 3 | * \brief Tests callee-context function instrumentation using libxo. 4 | * 5 | * Commands for llvm-lit: 6 | * RUN: %cpp -DPOLICY_FILE %s > %t.yaml 7 | * RUN: %cpp %cflags %s > %t.c 8 | * RUN: %clang %cflags -S -emit-llvm %cflags %t.c -o %t.ll 9 | * RUN: %loom -S %t.ll -loom-file %t.yaml -o %t.instr.ll 10 | * RUN: %filecheck -input-file %t.instr.ll %s 11 | * RUN: %llc -filetype=obj %t.instr.ll -o %t.instr.o 12 | * RUN: %clang %ldflags %t.instr.o -o %t.instr 13 | * RUN: %t.instr > %t.output 14 | * RUN: %filecheck -input-file %t.output %s -check-prefix CHECK-OUTPUT 15 | */ 16 | 17 | #if defined (POLICY_FILE) 18 | 19 | hook_prefix: __test_hook 20 | 21 | logging: xo 22 | 23 | block_structure: true 24 | 25 | functions: 26 | - name: foo 27 | callee: [ entry, exit ] 28 | 29 | - name: bar 30 | callee: [ entry ] 31 | 32 | - name: baz 33 | 34 | #else 35 | 36 | #include 37 | #include 38 | 39 | #include 40 | 41 | // CHECK: define{{.*}} [[FOO_TYPE:.*]] @foo([[INT:i[0-9]+]]{{.*}}, float{{.*}}, double{{.*}}) 42 | int foo(int x, float y, double z) 43 | { 44 | // CHECK: call void @[[PREFIX:__test_hook]]_enter_foo([[FOO_ARGS:.*]]) 45 | printf("foo(%d, %g, %g)\n", x, y, z); 46 | return x; 47 | // CHECK: call void @[[PREFIX]]_leave_foo([[FOO_TYPE]] [[RETVAL:.*]], [[FOO_ARGS]]) 48 | // CHECK-NEXT: ret [[FOO_TYPE]] [[RETVAL]] 49 | } 50 | 51 | // CHECK: define{{.*}} [[BAR_TYPE:.*]] @bar([[INT]]{{.*}}, i8*{{.*}}) 52 | float bar(unsigned int i, const char *s) 53 | { 54 | // CHECK: call void @[[PREFIX]]_enter_bar([[INT]] {{%.*}}, i8* {{%.*}}) 55 | printf("bar(%d, \"%s\")\n", i, s); 56 | // CHECK-NOT: call void @[[PREFIX]]_leave_bar 57 | return i; 58 | } 59 | 60 | // CHECK: define{{.*}} double @baz() 61 | double baz(void) 62 | { 63 | // CHECK-NOT: call void @[[PREFIX]]_enter_baz 64 | printf("baz()\n"); 65 | // CHECK-NOT: call void @[[PREFIX]]_leave_baz 66 | return 0; 67 | } 68 | 69 | int 70 | main(int argc, char *argv[]) 71 | { 72 | atexit(xo_finish_atexit); 73 | 74 | printf("Hello, world!\n"); 75 | 76 | printf("First, we will call foo():\n"); 77 | foo(1, 2, 3); 78 | // CHECK-OUTPUT: enter foo: 1 2{{(.0+)?}} 3{{(.0+)?}} 79 | // CHECK-OUTPUT: leave foo: 1 1 2{{(.0+)?}} 3{{(.0+)?}} 80 | 81 | printf("Then bar():\n"); 82 | bar(4, "5"); 83 | // CHECK-OUTPUT: enter bar: 4 0x{{[0-9a-z]+}} 84 | // CHECK-OUTPUT-NOT: leave bar 85 | 86 | printf("And finally baz():\n"); 87 | baz(); 88 | // CHECK-OUTPUT-NOT: enter baz 89 | // CHECK-OUTPUT-NOT: leave baz 90 | 91 | 92 | return 0; 93 | } 94 | 95 | #endif /* !POLICY_FILE */ 96 | -------------------------------------------------------------------------------- /doc/doxygen/header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | $projectname: $title 15 | $title 16 | 17 | 18 | $treeview 19 | $search 20 | $mathjax 21 | 22 | $extrastylesheet 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 42 |
43 |
44 |
45 |
46 |
47 |
48 | 49 | -------------------------------------------------------------------------------- /src/DTraceLogger.hh: -------------------------------------------------------------------------------- 1 | //! @file DTraceLogger.hh Declaration of @ref DTraceLogger. 2 | /* 3 | * Copyright (c) 2017 Brian Kidney 4 | * All rights reserved. 5 | * 6 | * This software was developed by BAE Systems, the University of Cambridge 7 | * Computer Laboratory, and Memorial University under DARPA/AFRL contract 8 | * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing 9 | * (TC) research program. 10 | * 11 | * Redistribution and use in source and binary forms, with or without 12 | * modification, are permitted provided that the following conditions 13 | * are met: 14 | * 1. Redistributions of source code must retain the above copyright 15 | * notice, this list of conditions and the following disclaimer. 16 | * 2. Redistributions in binary form must reproduce the above copyright 17 | * notice, this list of conditions and the following disclaimer in the 18 | * documentation and/or other materials provided with the distribution. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 | * SUCH DAMAGE. 31 | */ 32 | 33 | #ifndef DTRACE_LOGGER_H_ 34 | #define DTRACE_LOGGER_H_ 35 | 36 | #include "Logger.hh" 37 | 38 | namespace loom { 39 | 40 | class Serializer; 41 | 42 | /** 43 | * A logging technique that writes values to the DTrace framework using 44 | * Userland Statically Defined Traces (USDT). libusdt is used to create probes 45 | * at runtime. 46 | */ 47 | class DTraceLogger : public loom::Logger { 48 | public: 49 | DTraceLogger(llvm::Module& Mod); 50 | 51 | 52 | virtual llvm::Value* Log(llvm::Instruction *I, llvm::ArrayRef Values, 53 | llvm::StringRef Name, llvm::StringRef Descrip, 54 | Metadata Metadata, std::vector Transforms, 55 | bool /* SuppressUniqueness */) override; 56 | private: 57 | llvm::Value* ConvertValueToPtr(llvm::IRBuilder<>&, llvm::LLVMContext&, llvm::Value*, llvm::Type*); 58 | 59 | }; 60 | 61 | } // namespace loom 62 | 63 | #endif // !DTRACE_LOGGER_H_ 64 | -------------------------------------------------------------------------------- /src/NVSerializer.hh: -------------------------------------------------------------------------------- 1 | //! @file NVSerializer.hh Declaration of @ref loom::NVSerializer. 2 | /* 3 | * Copyright (c) 2016 Jonathan Anderson 4 | * All rights reserved. 5 | * 6 | * This software was developed by BAE Systems, the University of Cambridge 7 | * Computer Laboratory, and Memorial University under DARPA/AFRL contract 8 | * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing 9 | * (TC) research program. 10 | * 11 | * Redistribution and use in source and binary forms, with or without 12 | * modification, are permitted provided that the following conditions 13 | * are met: 14 | * 1. Redistributions of source code must retain the above copyright 15 | * notice, this list of conditions and the following disclaimer. 16 | * 2. Redistributions in binary form must reproduce the above copyright 17 | * notice, this list of conditions and the following disclaimer in the 18 | * documentation and/or other materials provided with the distribution. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 | * SUCH DAMAGE. 31 | */ 32 | 33 | #ifndef NV_SERIALIZER_H_ 34 | #define NV_SERIALIZER_H_ 35 | 36 | #include "Serializer.hh" 37 | 38 | #include 39 | 40 | namespace { 41 | class LibNV; 42 | } 43 | 44 | namespace loom { 45 | 46 | //! A Serializer that uses libnv to aggregate values. 47 | class NVSerializer : public Serializer { 48 | public: 49 | //! Construct a libnv-based @ref Serializer. 50 | NVSerializer(llvm::Module &); 51 | 52 | virtual llvm::StringRef SchemeName() const override { return "nvlist"; } 53 | 54 | virtual BufferInfo Serialize(llvm::StringRef Name, llvm::StringRef Descrip, 55 | llvm::ArrayRef, 56 | llvm::IRBuilder<> &) override; 57 | 58 | virtual llvm::Instruction *Cleanup(BufferInfo &, 59 | llvm::IRBuilder<> &) override; 60 | 61 | private: 62 | const std::unique_ptr NV; 63 | }; 64 | 65 | } // namespace loom 66 | 67 | #endif // !SERIALIZER_H_ 68 | -------------------------------------------------------------------------------- /test/call-instrumentation.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file call-instrumentation.c 3 | * \brief Tests caller-context function instrumentation. 4 | * 5 | * Commands for llvm-lit: 6 | * RUN: %cpp -DPOLICY_FILE %s > %t.yaml 7 | * RUN: %cpp %cflags %s > %t.c 8 | * RUN: %clang %cflags -S -emit-llvm %cflags %t.c -o %t.ll 9 | * RUN: %loom -S %t.ll -loom-file %t.yaml -o %t.instr.ll 10 | * RUN: %filecheck -input-file %t.instr.ll %s 11 | * RUN: %llc -filetype=obj %t.instr.ll -o %t.instr.o 12 | * RUN: %clang %ldflags %t.instr.o -o %t.instr 13 | * RUN: %t.instr > %t.output 14 | * RUN: %filecheck -input-file %t.output %s -check-prefix CHECK-OUTPUT 15 | */ 16 | 17 | #if defined (POLICY_FILE) 18 | 19 | hook_prefix: __test_hook 20 | 21 | logging: printf 22 | 23 | block_structure: true 24 | 25 | functions: 26 | - name: foo 27 | caller: [ entry, exit ] 28 | 29 | - name: bar 30 | caller: [ entry ] 31 | callee: [ exit ] 32 | 33 | - name: baz 34 | callee: [ entry, exit ] 35 | 36 | #else 37 | 38 | #include 39 | 40 | // CHECK: define{{.*}} [[FOO_TYPE:.*]] @foo(i32{{.*}}, float{{.*}}, double{{.*}}) 41 | int foo(int x, float y, double z) 42 | { 43 | printf("foo(%d, %f, %f\n", x, y, z); 44 | return x; 45 | } 46 | 47 | // CHECK: define{{.*}} [[BAR_TYPE:.*]] @bar(i32{{.*}}, i8*{{.*}}) 48 | void bar(unsigned int i, const char *s) 49 | { 50 | printf("bar(%d, \"%s\")\n", i, s); 51 | } 52 | 53 | // CHECK: define{{.*}} double @baz() 54 | double baz(void) 55 | { 56 | printf("baz()\n"); 57 | return 0; 58 | } 59 | 60 | int 61 | main(int argc, char *argv[]) 62 | { 63 | printf("Hello, world!\n"); 64 | 65 | printf("First, we will call foo():\n"); 66 | 67 | // We should instrument foo's call and return: 68 | // CHECK: call void @[[PREFIX:__test_hook]]_call_foo([[FOO_ARGS:.*]]) 69 | // CHECK: [[FOO_RET:.*]] = call [[FOO_TYPE]] @foo([[FOO_ARGS]]) 70 | // CHECK-OUTPUT: call foo: 1 2{{.*}} 3{{.*}} 71 | foo(1, 2, 3); 72 | // CHECK-OUTPUT: return foo: 1 1 2{{.*}} 3{{.*}} 73 | // CHECK: call void @[[PREFIX]]_return_foo([[FOO_TYPE]][[FOO_RET]], [[FOO_ARGS]]) 74 | 75 | printf("Then bar():\n"); 76 | 77 | // We should instrument bar's call but not return: 78 | // CHECK: call void @[[PREFIX]]_call_bar([[BAR_ARGS:.*]]) 79 | // CHECK: call [[BAR_TYPE]] @bar([[BAR_ARGS]]) 80 | // CHECK-OUTPUT: call bar: 4 0x{{[0-9a-z]+}} 81 | bar(4, "5"); 82 | // CHECK-OUTPUT-NOT: return bar 83 | // CHECK-NOT: call void @[[PREFIX]]_return_bar 84 | 85 | printf("And finally baz():\n"); 86 | 87 | // We should not instrument the call to baz: 88 | // CHECK-NOT: call {{.*}}_call_baz 89 | // CHECK-OUTPUT-NOT: call baz 90 | baz(); 91 | // CHECK-OUTPUT-NOT: return baz 92 | // CHECK-NOT: call {{.*}}_return_baz 93 | 94 | return 0; 95 | } 96 | 97 | #endif /* !POLICY_FILE */ 98 | -------------------------------------------------------------------------------- /test/function-instrumentation-with-file-scope.c: -------------------------------------------------------------------------------- 1 | /* 2 | * \file function-instrumentation.c 3 | * \brief Tests callee-context function instrumentation. 4 | * 5 | * Commands for llvm-lit: 6 | * RUN: %cpp -DPOLICY_FILE %s > %t.yaml 7 | * RUN: %cpp %cflags %s > %t.c 8 | * RUN: %clang %cflags -S -emit-llvm %cflags %t.c -o %t.ll 9 | * RUN: %loom -S %t.ll -loom-file %t.yaml -o %t.instr.ll 10 | * RUN: %filecheck -input-file %t.instr.ll %s 11 | * RUN: %llc -filetype=obj %t.instr.ll -o %t.instr.o 12 | * RUN: %clang %ldflags %t.instr.o -o %t.instr 13 | * RUN: %t.instr > %t.output 14 | * RUN: %filecheck -input-file %t.output %s -check-prefix CHECK-OUTPUT 15 | */ 16 | 17 | #if defined (POLICY_FILE) 18 | 19 | hook_prefix: __test_hook 20 | 21 | logging: printf 22 | 23 | block_structure: true 24 | 25 | functions: 26 | - name: foo 27 | within-file: function-instrumentation-with-file-scope.c 28 | callee: [ entry, exit ] 29 | 30 | - name: bar 31 | within-file: function.c 32 | callee: [ entry ] 33 | 34 | - name: baz 35 | callee: [ exit ] 36 | 37 | #else 38 | 39 | #include 40 | 41 | // CHECK: define{{.*}} [[FOO_TYPE:.*]] @foo([[INT:i[0-9]+]]{{.*}}, float{{.*}}, double{{.*}}) 42 | int foo(int x, float y, double z) 43 | { 44 | // CHECK: call void @[[PREFIX:__test_hook]]_enter_foo([[FOO_ARGS:.*]]) 45 | printf("foo(%d, %g, %g)\n", x, y, z); 46 | return x; 47 | // CHECK: call void @[[PREFIX]]_leave_foo([[FOO_TYPE]] [[RETVAL:.*]], [[FOO_ARGS]]) 48 | // CHECK-NEXT: ret [[FOO_TYPE]] [[RETVAL]] 49 | } 50 | 51 | // CHECK: define{{.*}} [[BAR_TYPE:.*]] @bar([[INT]]{{.*}}, i8*{{.*}}) 52 | float bar(unsigned int i, const char *s) 53 | { 54 | // CHECK-NOT: call void @[[PREFIX]]_enter_bar([[INT]] {{%.*}}, i8* {{%.*}}) 55 | printf("bar(%d, \"%s\")\n", i, s); 56 | // CHECK-NOT: call void @[[PREFIX]]_leave_bar 57 | return i; 58 | } 59 | 60 | // CHECK: define{{.*}} double @baz() 61 | double baz(void) 62 | { 63 | // CHECK-NOT: call void @[[PREFIX]]_enter_baz 64 | printf("baz()\n"); 65 | // CHECK: call void @[[PREFIX]]_leave_baz 66 | return 0; 67 | } 68 | 69 | int 70 | main(int argc, char *argv[]) 71 | { 72 | printf("Hello, world!\n"); 73 | 74 | printf("First, we will call foo():\n"); 75 | foo(1, 2, 3); 76 | // CHECK-OUTPUT: enter foo: 1 2{{.*}} 3{{.*}} 77 | // CHECK-OUTPUT: foo(1, 2, 3) 78 | // CHECK-OUTPUT: leave foo: 1 1 2{{.*}} 3{{.*}} 79 | 80 | printf("Then bar():\n"); 81 | bar(4, "5"); 82 | // CHECK-OUTPUT-NOT: enter bar: 4 0x{{[0-9a-z]+}} 83 | // CHECK-OUTPUT: bar(4, "5") 84 | // CHECK-OUTPUT-NOT: leave bar 85 | 86 | printf("And finally baz():\n"); 87 | baz(); 88 | // CHECK-OUTPUT-NOT: enter baz 89 | // CHECK-OUTPUT: baz 90 | // CHECK-OUTPUT: leave baz 91 | 92 | 93 | return 0; 94 | } 95 | 96 | #endif /* !POLICY_FILE */ 97 | -------------------------------------------------------------------------------- /test/call-instrumentation-inline-noblocks.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file call-instrumentation-inline.c 3 | * \brief Tests caller-context function instrumentation using InlineStrategy. 4 | * 5 | * Commands for llvm-lit: 6 | * RUN: %cpp -DPOLICY_FILE %s > %t.yaml 7 | * RUN: %cpp %cflags %s > %t.c 8 | * RUN: %clang %cflags -S -emit-llvm %cflags %t.c -o %t.ll 9 | * RUN: %loom -S %t.ll -loom-file %t.yaml -o %t.instr.ll 10 | * RUN: %filecheck -input-file %t.instr.ll %s 11 | * RUN: %llc -filetype=obj %t.instr.ll -o %t.instr.o 12 | * RUN: %clang %ldflags %t.instr.o -o %t.instr 13 | * RUN: %t.instr > %t.output 14 | * RUN: %filecheck -input-file %t.output %s -check-prefix CHECK-OUTPUT 15 | */ 16 | 17 | #if defined (POLICY_FILE) 18 | 19 | strategy: inline 20 | 21 | logging: printf 22 | 23 | hook_prefix: __test_hook 24 | 25 | functions: 26 | - name: foo 27 | caller: [ entry, exit ] 28 | 29 | - name: bar 30 | caller: [ entry ] 31 | callee: [ exit ] 32 | 33 | - name: baz 34 | callee: [ entry, exit ] 35 | 36 | #else 37 | 38 | #include 39 | 40 | // CHECK: define{{.*}} [[FOO_TYPE:i[0-9]+]] @foo(i32{{.*}}, float{{.*}}, double{{.*}}) 41 | int foo(int x, float y, double z) 42 | { 43 | printf("foo(%d, %f, %f\n", x, y, z); 44 | return x; 45 | } 46 | 47 | // CHECK: define{{.*}} [[BAR_TYPE:.*]] @bar(i32{{.*}}, i8*{{.*}}) 48 | float bar(unsigned int i, const char *s) 49 | { 50 | printf("bar(%d, \"%s\")\n", i, s); 51 | return i; 52 | } 53 | 54 | // CHECK: define{{.*}} double @baz() 55 | double baz(void) 56 | { 57 | printf("baz()\n"); 58 | return 0; 59 | } 60 | 61 | // CHECK: define{{.*}} i32 @main 62 | int 63 | main(int argc, char *argv[]) 64 | { 65 | // CHECK: call [[PRINTF:i32 .* @printf]](i8* getelementptr 66 | printf("Hello, world!\n"); 67 | 68 | // CHECK: call [[PRINTF]](i8* getelementptr 69 | printf("First, we will call foo():\n"); 70 | 71 | // We should instrument foo's call and return: 72 | 73 | // CHECK: call [[PRINTF]](i8* getelementptr {{[^)]+}}), [[FOO_INSTR_ARGS:.*]]) 74 | // CHECK: [[FOO_RET:%.*]] = call [[FOO_TYPE]] @foo(i32 1, float 2.{{[^,]+}}, double 3.{{[^)]+}}) 75 | foo(1, 2, 3); 76 | // CHECK-OUTPUT: call foo: 1 2{{.*}} 3{{.*}} 77 | 78 | // CHECK: call [[PRINTF]](i8* getelementptr {{[^)]+}}), [[FOO_TYPE]] [[FOO_RET]], [[FOO_INSTR_ARGS]]) 79 | // CHECK-OUTPUT: return foo: 1 1 2{{.*}} 3{{.*}} 80 | 81 | printf("Then bar():\n"); 82 | 83 | // We should instrument bar's call but not return: 84 | // CHECK-OUTPUT: call bar: 4 0x{{[0-9a-z]+}} 85 | bar(4, "5"); 86 | // CHECK-OUTPUT-NOT: return bar 87 | 88 | printf("And finally baz():\n"); 89 | 90 | // We should not instrument the call to baz: 91 | // CHECK-OUTPUT-NOT: call baz 92 | baz(); 93 | // CHECK-OUTPUT-NOT: return baz 94 | 95 | return 0; 96 | } 97 | 98 | #endif /* !POLICY_FILE */ 99 | -------------------------------------------------------------------------------- /src/KTraceLogger.hh: -------------------------------------------------------------------------------- 1 | //! @file KTraceLogger.hh Declaration of @ref loom::KTraceLogger. 2 | /* 3 | * Copyright (c) 2016 Jonathan Anderson 4 | * All rights reserved. 5 | * 6 | * This software was developed by BAE Systems, the University of Cambridge 7 | * Computer Laboratory, and Memorial University under DARPA/AFRL contract 8 | * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing 9 | * (TC) research program. 10 | * 11 | * Redistribution and use in source and binary forms, with or without 12 | * modification, are permitted provided that the following conditions 13 | * are met: 14 | * 1. Redistributions of source code must retain the above copyright 15 | * notice, this list of conditions and the following disclaimer. 16 | * 2. Redistributions in binary form must reproduce the above copyright 17 | * notice, this list of conditions and the following disclaimer in the 18 | * documentation and/or other materials provided with the distribution. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 | * SUCH DAMAGE. 31 | */ 32 | 33 | #ifndef KTRACE_LOGGER_H_ 34 | #define KTRACE_LOGGER_H_ 35 | 36 | #include "Logger.hh" 37 | 38 | namespace loom { 39 | 40 | class Serializer; 41 | 42 | /** 43 | * A logging technique that serializes values with libnv and writes them 44 | * to the BSD `ktrace` framework. If we're instrumenting kernel code, we 45 | * submit the record directly to `ktrace` ourselves. If we're instrumenting 46 | * userspace code, we submit it via the `utrace` system call. 47 | */ 48 | class KTraceLogger : public loom::Logger { 49 | public: 50 | KTraceLogger(llvm::Module &Mod, std::unique_ptr, bool KernelMode); 51 | 52 | virtual llvm::Value *Log(llvm::Instruction *, llvm::ArrayRef, 53 | llvm::StringRef Name, llvm::StringRef Descrip, 54 | loom::Metadata Md, std::vector Transforms, 55 | bool SuppressUniqueness) override; 56 | 57 | private: 58 | const std::unique_ptr Serial; 59 | const bool KernelMode; 60 | }; 61 | 62 | } // namespace loom 63 | 64 | #endif // !KTRACE_LOGGER_H_ 65 | -------------------------------------------------------------------------------- /test/call-instrumentation-libxo.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file call-instrumentation-libxo.c 3 | * \brief Tests caller-context function instrumentation using libxo. 4 | * 5 | * Commands for llvm-lit: 6 | * RUN: %cpp -DPOLICY_FILE %s > %t.yaml 7 | * RUN: %cpp %cflags %s > %t.c 8 | * RUN: %clang %cflags -S -emit-llvm %cflags %t.c -o %t.ll 9 | * RUN: %loom -S %t.ll -loom-file %t.yaml -o %t.instr.ll 10 | * RUN: %filecheck -input-file %t.instr.ll %s 11 | * RUN: %llc -filetype=obj %t.instr.ll -o %t.instr.o 12 | * RUN: %clang %ldflags %t.instr.o -o %t.instr 13 | * RUN: %t.instr > %t.output 14 | * RUN: %filecheck -input-file %t.output %s -check-prefix CHECK-OUTPUT 15 | */ 16 | 17 | #if defined (POLICY_FILE) 18 | 19 | hook_prefix: __test_hook 20 | 21 | logging: xo 22 | 23 | block_structure: true 24 | 25 | functions: 26 | - name: foo 27 | caller: [ entry, exit ] 28 | 29 | - name: bar 30 | caller: [ entry ] 31 | callee: [ exit ] 32 | 33 | - name: baz 34 | callee: [ entry, exit ] 35 | 36 | #else 37 | 38 | #include 39 | #include 40 | 41 | #include 42 | 43 | // CHECK: define{{.*}} [[FOO_TYPE:.*]] @foo(i32{{.*}}, float{{.*}}, double{{.*}}) 44 | int foo(int x, float y, double z) 45 | { 46 | printf("foo(%d, %f, %f\n", x, y, z); 47 | return x; 48 | } 49 | 50 | // CHECK: define{{.*}} [[BAR_TYPE:.*]] @bar(i32{{.*}}, i8*{{.*}}) 51 | float bar(unsigned int i, const char *s) 52 | { 53 | printf("bar(%d, \"%s\")\n", i, s); 54 | return i; 55 | } 56 | 57 | // CHECK: define{{.*}} double @baz() 58 | double baz(void) 59 | { 60 | printf("baz()\n"); 61 | return 0; 62 | } 63 | 64 | int 65 | main(int argc, char *argv[]) 66 | { 67 | atexit(xo_finish_atexit); 68 | 69 | printf("Hello, world!\n"); 70 | 71 | printf("First, we will call foo():\n"); 72 | 73 | // We should instrument foo's call and return: 74 | // CHECK: call void @[[PREFIX:__test_hook]]_call_foo([[FOO_ARGS:.*]]) 75 | // CHECK: [[FOO_RET:.*]] = call [[FOO_TYPE]] @foo([[FOO_ARGS]]) 76 | // CHECK-OUTPUT: call foo: 1 2{{(.0+)?}} 3{{(.0+)?}} 77 | foo(1, 2, 3); 78 | // CHECK-OUTPUT: return foo: 1 1 2{{(.0+)?}} 3{{(.0+)?}} 79 | // CHECK: call void @[[PREFIX]]_return_foo([[FOO_TYPE]][[FOO_RET]], [[FOO_ARGS]]) 80 | 81 | printf("Then bar():\n"); 82 | 83 | // We should instrument bar's call but not return: 84 | // CHECK: call void @[[PREFIX]]_call_bar([[BAR_ARGS:.*]]) 85 | // CHECK: call [[BAR_TYPE]] @bar([[BAR_ARGS]]) 86 | // CHECK-OUTPUT: call bar: 4 0x{{[0-9a-z]+}} 87 | bar(4, "5"); 88 | // CHECK-OUTPUT-NOT: return bar 89 | // CHECK-NOT: call void @[[PREFIX]]_return_bar 90 | 91 | printf("And finally baz():\n"); 92 | 93 | // We should not instrument the call to baz: 94 | // CHECK-NOT: call {{.*}}_call_baz 95 | // CHECK-OUTPUT-NOT: call baz 96 | baz(); 97 | // CHECK-OUTPUT-NOT: return baz 98 | // CHECK-NOT: call {{.*}}_return_baz 99 | 100 | return 0; 101 | } 102 | 103 | #endif /* !POLICY_FILE */ 104 | -------------------------------------------------------------------------------- /src/Policy.cc: -------------------------------------------------------------------------------- 1 | //! @file Policy.cc Definition of @ref loom::Policy. 2 | /* 3 | * Copyright (c) 2016-2017 Jonathan Anderson 4 | * All rights reserved. 5 | * 6 | * This software was developed by BAE Systems, the University of Cambridge 7 | * Computer Laboratory, and Memorial University under DARPA/AFRL contract 8 | * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing 9 | * (TC) research program. 10 | * 11 | * Redistribution and use in source and binary forms, with or without 12 | * modification, are permitted provided that the following conditions 13 | * are met: 14 | * 1. Redistributions of source code must retain the above copyright 15 | * notice, this list of conditions and the following disclaimer. 16 | * 2. Redistributions in binary form must reproduce the above copyright 17 | * notice, this list of conditions and the following disclaimer in the 18 | * documentation and/or other materials provided with the distribution. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 | * SUCH DAMAGE. 31 | */ 32 | 33 | #include "DTraceLogger.hh" 34 | #include "Policy.hh" 35 | #include "KTraceLogger.hh" 36 | 37 | using namespace llvm; 38 | using namespace loom; 39 | using std::unique_ptr; 40 | 41 | Policy::~Policy() {} 42 | 43 | std::vector> Policy::Loggers(Module &Mod) const { 44 | std::vector> Loggers; 45 | 46 | auto SimpleLogType = this->Logging(); 47 | 48 | if (SimpleLogType != SimpleLogger::LogType::None) { 49 | Loggers.push_back(SimpleLogger::Create(Mod, SimpleLogType)); 50 | } 51 | 52 | unique_ptr Serial = this->Serialization(Mod); 53 | 54 | switch (this->KTrace()) { 55 | case Policy::KTraceTarget::Kernel: 56 | Loggers.emplace_back(new KTraceLogger(Mod, std::move(Serial), true)); 57 | break; 58 | 59 | case Policy::KTraceTarget::Userspace: 60 | Loggers.emplace_back(new KTraceLogger(Mod, std::move(Serial), false)); 61 | break; 62 | 63 | case Policy::KTraceTarget::None: 64 | break; 65 | } 66 | 67 | switch (this->DTrace()) { 68 | case Policy::DTraceTarget::Userspace: 69 | Loggers.emplace_back(new DTraceLogger(Mod)); 70 | break; 71 | 72 | case Policy::DTraceTarget::None: 73 | break; 74 | } 75 | 76 | return Loggers; 77 | } 78 | -------------------------------------------------------------------------------- /src/Serializer.cc: -------------------------------------------------------------------------------- 1 | //! @file Serializer.cc Definition of @ref loom::Serializer. 2 | /* 3 | * Copyright (c) 2016-2017 Jonathan Anderson 4 | * All rights reserved. 5 | * 6 | * This software was developed by BAE Systems, the University of Cambridge 7 | * Computer Laboratory, and Memorial University under DARPA/AFRL contract 8 | * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing 9 | * (TC) research program. 10 | * 11 | * Redistribution and use in source and binary forms, with or without 12 | * modification, are permitted provided that the following conditions 13 | * are met: 14 | * 1. Redistributions of source code must retain the above copyright 15 | * notice, this list of conditions and the following disclaimer. 16 | * 2. Redistributions in binary form must reproduce the above copyright 17 | * notice, this list of conditions and the following disclaimer in the 18 | * documentation and/or other materials provided with the distribution. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 | * SUCH DAMAGE. 31 | */ 32 | 33 | #include "Serializer.hh" 34 | 35 | using namespace llvm; 36 | using namespace loom; 37 | 38 | std::unique_ptr Serializer::None() { 39 | return std::unique_ptr(); 40 | } 41 | 42 | Serializer::Serializer(llvm::LLVMContext &Ctx) 43 | : Ctx(Ctx), Byte(IntegerType::get(Ctx, 8)), 44 | BytePtr(PointerType::getUnqual(Byte)), SizeT(IntegerType::get(Ctx, 64)) {} 45 | 46 | Serializer::~Serializer() {} 47 | 48 | Serializer::BufferInfo NullSerializer::Serialize(StringRef /* Name */, 49 | StringRef /* Description */, 50 | ArrayRef V, 51 | IRBuilder<> &B) { 52 | 53 | // As a "null" operation, simply copy zero bytes from nullptr. 54 | Value *NullPtr = ConstantPointerNull::get(BytePtr); 55 | ConstantInt *Zero = ConstantInt::get(SizeT, 0); 56 | 57 | return {NullPtr, Zero}; 58 | } 59 | 60 | Value *NullSerializer::Cleanup(BufferInfo &, IRBuilder<> &B) { 61 | // No cleanup is required, as no memory has been allocated. 62 | return Nop(B); 63 | } 64 | 65 | Value *NullSerializer::Nop(IRBuilder<> &B) { 66 | auto *False = ConstantInt::getFalse(Ctx); 67 | return B.CreateXor(False, False); 68 | } 69 | -------------------------------------------------------------------------------- /src/Instrumentation.cc: -------------------------------------------------------------------------------- 1 | //! @file Instrumentation.cc Definition of @ref loom::Instrumentation. 2 | /* 3 | * Copyright (c) 2013,2015-2016 Jonathan Anderson 4 | * Copyright (c) 2016 Cem Kilic 5 | * All rights reserved. 6 | * 7 | * This software was developed by SRI International and the University of 8 | * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) 9 | * ("CTSRD"), as part of the DARPA CRASH research programme, by BAE Systems, 10 | * the University of Cambridge Computer Laboratory, and Memorial University 11 | * under DARPA/AFRL contract FA8650-15-C-7558 ("CADETS"), as part of the 12 | * DARPA Transparent Computing (TC) research program, and at Memorial University 13 | * under the NSERC Discovery program (RGPIN-2015-06048). 14 | * 15 | * Redistribution and use in source and binary forms, with or without 16 | * modification, are permitted provided that the following conditions 17 | * are met: 18 | * 1. Redistributions of source code must retain the above copyright 19 | * notice, this list of conditions and the following disclaimer. 20 | * 2. Redistributions in binary form must reproduce the above copyright 21 | * notice, this list of conditions and the following disclaimer in the 22 | * documentation and/or other materials provided with the distribution. 23 | * 24 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 25 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 | * SUCH DAMAGE. 35 | */ 36 | 37 | #include "Instrumentation.hh" 38 | 39 | #include 40 | #include 41 | 42 | using namespace llvm; 43 | using namespace loom; 44 | 45 | using std::string; 46 | using std::unique_ptr; 47 | using std::vector; 48 | 49 | Instrumentation::Instrumentation(SmallVector Values, 50 | BasicBlock *Preamble, BasicBlock *EndBlock, 51 | Instruction *Begin, Instruction *End) 52 | : InstrValues(std::move(Values)), Preamble(Preamble), EndBlock(EndBlock), 53 | PreambleEnd(Begin), End(End) { 54 | assert(not Preamble->empty()); 55 | assert(not EndBlock->empty()); 56 | } 57 | 58 | Instrumentation::Instrumentation(SmallVector Values, 59 | Instruction *Begin, Instruction *End) 60 | : InstrValues(std::move(Values)), Preamble(nullptr), EndBlock(nullptr), 61 | PreambleEnd(Begin), End(End) {} 62 | 63 | -------------------------------------------------------------------------------- /test/call-instrumentation-inline.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file call-instrumentation-inline.c 3 | * \brief Tests caller-context function instrumentation using InlineStrategy. 4 | * 5 | * Commands for llvm-lit: 6 | * RUN: %cpp -DPOLICY_FILE %s > %t.yaml 7 | * RUN: %cpp %cflags %s > %t.c 8 | * RUN: %clang %cflags -S -emit-llvm %cflags %t.c -o %t.ll 9 | * RUN: %loom -S %t.ll -loom-file %t.yaml -o %t.instr.ll 10 | * RUN: %filecheck -input-file %t.instr.ll %s 11 | * RUN: %llc -filetype=obj %t.instr.ll -o %t.instr.o 12 | * RUN: %clang %ldflags %t.instr.o -o %t.instr 13 | * RUN: %t.instr > %t.output 14 | * RUN: %filecheck -input-file %t.output %s -check-prefix CHECK-OUTPUT 15 | */ 16 | 17 | #if defined (POLICY_FILE) 18 | 19 | strategy: inline 20 | 21 | logging: printf 22 | 23 | hook_prefix: __test_hook 24 | 25 | block_structure: true 26 | 27 | functions: 28 | - name: foo 29 | caller: [ entry, exit ] 30 | 31 | - name: bar 32 | caller: [ entry ] 33 | callee: [ exit ] 34 | 35 | - name: baz 36 | callee: [ entry, exit ] 37 | 38 | #else 39 | 40 | #include 41 | 42 | // CHECK: define{{.*}} [[FOO_TYPE:i[0-9]+]] @foo(i32{{.*}}, float{{.*}}, double{{.*}}) 43 | int foo(int x, float y, double z) 44 | { 45 | printf("foo(%d, %f, %f\n", x, y, z); 46 | return x; 47 | } 48 | 49 | // CHECK: define{{.*}} [[BAR_TYPE:.*]] @bar(i32{{.*}}, i8*{{.*}}) 50 | float bar(unsigned int i, const char *s) 51 | { 52 | printf("bar(%d, \"%s\")\n", i, s); 53 | return i; 54 | } 55 | 56 | // CHECK: define{{.*}} double @baz() 57 | double baz(void) 58 | { 59 | printf("baz()\n"); 60 | return 0; 61 | } 62 | 63 | int 64 | main(int argc, char *argv[]) 65 | { 66 | printf("Hello, world!\n"); 67 | 68 | printf("First, we will call foo():\n"); 69 | 70 | // We should instrument foo's call and return: 71 | 72 | // CHECK: "[[PREFIX:__test_hook]]_call_foo:preamble": 73 | // CHECK-NEXT: call [[PRINTF:i32 .* @printf]](i8* getelementptr {{[^)]+}}), [[FOO_INSTR_ARGS:.*]]) 74 | // CHECK-OUTPUT: call foo: 1 2{{.*}} 3{{.*}} 75 | // CHECK-NEXT: br label %"[[PREFIX]]_call_foo:end" 76 | 77 | // CHECK: "[[PREFIX]]_call_foo:end": 78 | // CHECK-NEXT: br label %[[TARGET:.*]] 79 | 80 | // CHECK: [[TARGET]]: 81 | // CHECK-NEXT: [[FOO_RET:%.*]] = call [[FOO_TYPE]] @foo(i32 1, float 2.{{[^,]+}}, double 3.{{[^)]+}}) 82 | foo(1, 2, 3); 83 | 84 | // CHECK: "[[PREFIX]]_return_foo:preamble": 85 | // CHECK-NEXT: call [[PRINTF]](i8* getelementptr {{[^)]+}}), [[FOO_TYPE]] [[FOO_RET]], [[FOO_INSTR_ARGS]]) 86 | // CHECK-OUTPUT: return foo: 1 1 2{{.*}} 3{{.*}} 87 | // CHECK-NEXT: br label %"[[PREFIX]]_return_foo:end" 88 | 89 | // CHECK: "[[PREFIX]]_return_foo:end": 90 | // CHECK-NEXT: br label 91 | 92 | printf("Then bar():\n"); 93 | 94 | // We should instrument bar's call but not return: 95 | // CHECK-OUTPUT: call bar: 4 0x{{[0-9a-z]+}} 96 | bar(4, "5"); 97 | // CHECK-OUTPUT-NOT: return bar 98 | 99 | printf("And finally baz():\n"); 100 | 101 | // We should not instrument the call to baz: 102 | // CHECK-OUTPUT-NOT: call baz 103 | baz(); 104 | // CHECK-OUTPUT-NOT: return baz 105 | 106 | return 0; 107 | } 108 | 109 | #endif /* !POLICY_FILE */ 110 | -------------------------------------------------------------------------------- /scripts/plot-tracelen: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright (c) 2016 Jonathan Anderson 4 | # All rights reserved. 5 | # 6 | # This software was developed by BAE Systems, the University of Cambridge 7 | # Computer Laboratory, and Memorial University under DARPA/AFRL contract 8 | # FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing 9 | # (TC) research program. 10 | # 11 | # Redistribution and use in source and binary forms, with or without 12 | # modification, are permitted provided that the following conditions 13 | # are met: 14 | # 1. Redistributions of source code must retain the above copyright 15 | # notice, this list of conditions and the following disclaimer. 16 | # 2. Redistributions in binary form must reproduce the above copyright 17 | # notice, this list of conditions and the following disclaimer in the 18 | # documentation and/or other materials provided with the distribution. 19 | # 20 | # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 | # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 | # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 | # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 | # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 | # SUCH DAMAGE. 31 | 32 | import argparse 33 | import os.path 34 | 35 | 36 | args = argparse.ArgumentParser('plot trace file sizes vs input files') 37 | args.add_argument('--bytes', help='Input sizes in bytes', action='store_true') 38 | args.add_argument('tool', help='Name of the tool that processed the inputs') 39 | args.add_argument('filename', nargs='+') 40 | 41 | args = args.parse_args() 42 | 43 | def size(name): 44 | if base[-1].isalpha(): 45 | return int(base[:-1]) * { 46 | 'k': 1024, 47 | 'M': 1024 ** 2, 48 | 'G': 1024 ** 3, 49 | }[base[-1]] 50 | 51 | else: 52 | return int(base) 53 | 54 | 55 | filenames = args.filename 56 | inputs, outputs = [], [] 57 | 58 | for name in filenames: 59 | (base, ext) = os.path.splitext(name) 60 | 61 | if ext == '.trace': 62 | outputs.append(os.path.getsize(name)) 63 | else: 64 | inputs.append(size(base)) 65 | 66 | print('Read %d input and %d output sizes' % (len(inputs), len(outputs))) 67 | 68 | 69 | # If we were only given trace files, infer the input sizes from the trace 70 | # files' names. 71 | if len(inputs) == 0: 72 | for name in filenames: 73 | (base, _) = os.path.splitext(name) 74 | inputs.append(size(base)) 75 | 76 | 77 | import matplotlib.pyplot as plt 78 | import numpy 79 | 80 | from matplotlib.ticker import EngFormatter 81 | 82 | 83 | fig, ax = plt.subplots() 84 | 85 | plt.title('Trace sizes: %s' % args.tool) 86 | plt.xscale('log') 87 | plt.xlabel('Input size') 88 | plt.yscale('log') 89 | plt.ylabel('Trace size') 90 | 91 | fmt = EngFormatter(unit = ('B' if args.bytes else ''), places = 0) 92 | ax.xaxis.set_major_formatter(fmt) 93 | ax.yaxis.set_major_formatter(fmt) 94 | 95 | ax.plot(inputs, outputs, '-o') 96 | 97 | plt.show() 98 | -------------------------------------------------------------------------------- /src/KTraceLogger.cc: -------------------------------------------------------------------------------- 1 | //! @file KTraceLogger.cc Definition of @ref loom::KTraceLogger. 2 | /* 3 | * Copyright (c) 2016 Jonathan Anderson 4 | * All rights reserved. 5 | * 6 | * This software was developed by BAE Systems, the University of Cambridge 7 | * Computer Laboratory, and Memorial University under DARPA/AFRL contract 8 | * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing 9 | * (TC) research program. 10 | * 11 | * Redistribution and use in source and binary forms, with or without 12 | * modification, are permitted provided that the following conditions 13 | * are met: 14 | * 1. Redistributions of source code must retain the above copyright 15 | * notice, this list of conditions and the following disclaimer. 16 | * 2. Redistributions in binary form must reproduce the above copyright 17 | * notice, this list of conditions and the following disclaimer in the 18 | * documentation and/or other materials provided with the distribution. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 | * SUCH DAMAGE. 31 | */ 32 | 33 | #include "KTraceLogger.hh" 34 | #include "Serializer.hh" 35 | 36 | #include 37 | 38 | using namespace loom; 39 | using namespace llvm; 40 | using std::vector; 41 | 42 | KTraceLogger::KTraceLogger(Module &Mod, std::unique_ptr S, bool K) 43 | : Logger(Mod), Serial(std::move(S)), KernelMode(K) { 44 | assert(Serial && "no Serializer passed into KTraceLogger"); 45 | } 46 | 47 | Value *KTraceLogger::Log(Instruction *I, ArrayRef Values, 48 | StringRef Name, StringRef Descrip, loom::Metadata Md, 49 | std::vector Transforms, bool /* SuppressUniqueness */) { 50 | 51 | IRBuilder<> B(I); 52 | 53 | // Get pointer to serialized data buffer: 54 | Serializer::BufferInfo Buffer = Serial->Serialize(Name, Descrip, Values, B); 55 | 56 | LLVMContext &Ctx = Mod.getContext(); 57 | 58 | if (!KernelMode) { 59 | // Send record to `utrace`: 60 | Type *params[] = { 61 | PointerType::getUnqual(IntegerType::get(Ctx, sizeof(uint8_t) * CHAR_BIT)), 62 | IntegerType::get(Ctx, sizeof(size_t) * CHAR_BIT), 63 | }; 64 | auto *FT = FunctionType::get(IntegerType::get(Ctx, sizeof(int) * CHAR_BIT), params, false); 65 | 66 | FunctionCallee F = Mod.getOrInsertFunction("utrace", FT); 67 | 68 | B.CreateCall(F, {Buffer.first, Buffer.second}); 69 | 70 | } else { 71 | // Send record to `ktrstruct`: 72 | Type *params[] = { 73 | PointerType::getUnqual(IntegerType::get(Ctx, sizeof(char) * CHAR_BIT)), 74 | PointerType::getUnqual(IntegerType::get(Ctx, sizeof(uint8_t) * CHAR_BIT)), // void* 75 | IntegerType::get(Ctx, sizeof(size_t) * CHAR_BIT), 76 | }; 77 | auto *FT = FunctionType::get(Type::getVoidTy(Ctx), params, false); 78 | FunctionCallee F = Mod.getOrInsertFunction("ktrstruct", FT); 79 | Value *Name = B.CreateGlobalStringPtr(Serial->SchemeName(), "scheme"); 80 | 81 | B.CreateCall(F, {Name, Buffer.first, Buffer.second}); 82 | } 83 | 84 | return Serial->Cleanup(Buffer, B); 85 | } 86 | -------------------------------------------------------------------------------- /test/lit.cfg: -------------------------------------------------------------------------------- 1 | # vim:syntax=python 2 | 3 | import os 4 | import platform 5 | import subprocess 6 | import sys 7 | 8 | import lit 9 | 10 | 11 | # 12 | # Basic information about this test suite. 13 | # 14 | config.name = 'LOOM' 15 | config.suffixes = [ '.c', '.cpp', '.ll' ] 16 | config.excludes = [ 'Inputs' ] 17 | config.test_format = lit.formats.ShTest() 18 | 19 | # Unbelievably, llvm-lit can't figure out its own default target triple, 20 | # so we need to execute an LLVM tool and parse its output (!) 21 | try: 22 | llc_version = subprocess.check_output([ 'llc', '--version' ]) 23 | triple_lines = [ t for t in llc_version.decode().split('\n') if 'target' in t ] 24 | config.target_triple = triple_lines[0].split()[-1] 25 | except OSError as e: 26 | sys.stderr.write("Failed to execute 'llc --version': %s\n" % e) 27 | 28 | import errno 29 | if e.errno == errno.ENOENT: 30 | sys.stderr.write("Is llc in your PATH?") 31 | 32 | sys.exit(1) 33 | 34 | # 35 | # Useful environment variables. 36 | # 37 | # This variables are optional when LOOM is installed to a standard location; 38 | # if not, failure to set these variables will cause tests to fail building. 39 | # 40 | extra_cflags = [ '-g' ] # always build tests with debug symbols 41 | extra_cxxflags = [ '-g' ] 42 | libdirs = [ ] 43 | extra_libs = [ 'xo' ] 44 | 45 | if platform.system() == 'FreeBSD': 46 | extra_libs += [ 'util' ] 47 | 48 | 49 | if 'output_dir' in lit_config.params: 50 | config.test_exec_root = lit_config.params['output_dir'] 51 | 52 | 53 | # 54 | # Find the 'test_support' module (which may not be in the current PYTHONPATH). 55 | # 56 | loom_src = os.getenv('LOOM_SOURCE_DIR') 57 | if not loom_src: 58 | if not 'source_dir' in lit_config.params: 59 | raise Exception('Unable to find LOOM source directory.' 60 | + ' Set LOOM_SOURCE_DIR or pass' 61 | + ' --param=source_dir=path/to/src to lit') 62 | 63 | loom_src = lit_config.params['source_dir'] 64 | 65 | sys.path.append(os.curdir) 66 | if loom_src: sys.path.append(os.path.join(loom_src, 'test')) 67 | 68 | try: 69 | import test_support as test 70 | 71 | except ImportError as e: 72 | print("Unable to find 'test_support' module in:\n[") 73 | for p in sys.path: 74 | print(" %s" % p) 75 | print("]") 76 | sys.exit(1) 77 | 78 | 79 | # 80 | # Find LLVM tools (e.g. FileCheck). 81 | # 82 | llvm_obj_root = test.llvm_config['obj-root'] 83 | llvm_tools = os.path.join(llvm_obj_root, b'bin') 84 | 85 | 86 | # 87 | # Find instrumentation library. 88 | # 89 | loom_build = os.getenv('LOOM_BUILD_DIR') 90 | if not loom_build: 91 | if not 'build_dir' in lit_config.params: 92 | raise Exception('Unable to find LOOM build directory;' + 93 | ' set LOOM_BUILD_DIR or pass --build_dir to lit') 94 | 95 | loom_build = lit_config.params['build_dir'] 96 | 97 | lib = test.find_library(test.libname('LLVMLoom', loadable_module = True), 98 | [ os.path.join(loom_build, 'lib') ]) 99 | 100 | 101 | # 102 | # Set variables that we can access from lit RUN lines. 103 | # 104 | config.substitutions += [ 105 | # Tools: 106 | ('%cpp', test.which([ 'clang-cpp', 'clang-cpp38', 'cpp' ])), 107 | ('%clang', test.which([ 'clang', 'clang38' ])), 108 | ('%clang', test.which([ 'clang', 'clang38' ])), 109 | ('%llc', test.which([ 'llc', 'llc38' ])), 110 | ('%filecheck', test.which([ 'FileCheck', 'FileCheck38' ])), 111 | ('%loom', '%s -load %s -loom' % (test.which([ 'opt', 'opt38', ]), lib)), 112 | 113 | # Flags: 114 | ('%cflags', test.cflags([ '%p/Inputs' ], extra = extra_cflags)), 115 | ('%cxxflags', test.cflags([ '%p/Inputs' ], extra = extra_cxxflags)), 116 | ('%ldflags', test.ldflags(libdirs, extra_libs)), 117 | ('%cpp_out', test.cpp_out()), 118 | ] 119 | 120 | 121 | 122 | 123 | config.environment['PATH'] = os.pathsep.join([ 124 | llvm_tools.decode(), 125 | config.environment['PATH'] 126 | ]) 127 | -------------------------------------------------------------------------------- /src/DagTransform.cc: -------------------------------------------------------------------------------- 1 | //! @file DagTransform.cc Definition of @ref DagTransform. 2 | /* 3 | * Copyright (c) 2021 Brian Kidney 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 | * SUCH DAMAGE. 26 | */ 27 | 28 | #include "DagTransform.hh" 29 | 30 | #include "llvm/Pass.h" 31 | #include "llvm/IR/Function.h" 32 | #include "llvm/Support/raw_ostream.h" 33 | #include "llvm/IR/LegacyPassManager.h" 34 | #include "llvm/Transforms/IPO/PassManagerBuilder.h" 35 | #include "llvm/IR/IRBuilder.h" 36 | #include "llvm/Transforms/Utils/BasicBlockUtils.h" 37 | #include "llvm/IR/Module.h" 38 | #include 39 | 40 | using namespace loom; 41 | using namespace llvm; 42 | using std::vector; 43 | using std::queue; 44 | 45 | 46 | bool loom::findAllUsers(Instruction *Call, 47 | std::queue dagTail, 48 | std::vector& toDelete) { 49 | 50 | 51 | bool isDagComplete = false; 52 | if (dagTail.empty()) { 53 | isDagComplete = true; 54 | } 55 | 56 | for (User *U: Call->users()) 57 | { 58 | if (Instruction *Inst = dyn_cast(U)) { 59 | toDelete.push_back(Inst); 60 | errs() << "Users deleting: " << *Inst << "\n"; 61 | if (CallInst *Call = dyn_cast(Inst)) { 62 | Function *Target = Call->getCalledFunction(); 63 | if (Target->getName() == dagTail.front()) { 64 | errs() << "Users popping: " << *Target << "\n"; 65 | dagTail.pop(); 66 | } 67 | } 68 | isDagComplete |= findAllUsers(Inst, dagTail, toDelete); 69 | if (StoreInst *Store = dyn_cast(Inst)) { 70 | isDagComplete |= findStoreCalls(Store, dagTail, toDelete); 71 | } 72 | 73 | } 74 | } 75 | return isDagComplete; 76 | } 77 | 78 | bool loom::findStoreCalls(StoreInst *Store, 79 | std::queue dagTail, 80 | std::vector& toDelete) { 81 | 82 | bool isDagComplete = false; 83 | 84 | for (User* U : Store->getPointerOperand()->users()) { 85 | if (Instruction *Inst = dyn_cast(U)) { 86 | errs() << "Store: " << *Inst << "\n"; 87 | for (User *User: Inst->users()) { 88 | if (CallInst *Call = dyn_cast(User)) { 89 | errs() << "Store user: " << *Call << "\n"; 90 | Function *Target = Call->getCalledFunction(); 91 | if (Target->getName() == dagTail.front()) { 92 | errs() << "Store deleting " << *Call << "\n"; 93 | errs() << "Store popping " << *Target << "\n"; 94 | dagTail.pop(); 95 | toDelete.push_back(Call); 96 | isDagComplete |= findAllUsers(Call, dagTail, toDelete); 97 | } 98 | } 99 | } 100 | } 101 | } 102 | 103 | return isDagComplete; 104 | } 105 | -------------------------------------------------------------------------------- /src/Transform.cc: -------------------------------------------------------------------------------- 1 | //! @file Transforms.cc Defines transforms that can be applied to IR Data. 2 | /* 3 | * Copyright (c) 2017 Brian Kidney 4 | * All rights reserved. 5 | * 6 | * This software was developed by BAE Systems, the University of Cambridge 7 | * Computer Laboratory, and Memorial University under DARPA/AFRL contract 8 | * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing 9 | * (TC) research program. 10 | * 11 | * Redistribution and use in source and binary forms, with or without 12 | * modification, are permitted provided that the following conditions 13 | * are met: 14 | * 1. Redistributions of source code must retain the above copyright 15 | * notice, this list of conditions and the following disclaimer. 16 | * 2. Redistributions in binary form must reproduce the above copyright 17 | * notice, this list of conditions and the following disclaimer in the 18 | * documentation and/or other materials provided with the distribution. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 | * SUCH DAMAGE. 31 | */ 32 | 33 | #include "DTraceLogger.hh" 34 | 35 | #include 36 | 37 | #include 38 | #include 39 | #include 40 | 41 | using namespace loom; 42 | using namespace llvm; 43 | using std::vector; 44 | 45 | 46 | Value* Transform::CreateTransform(Instruction* I, Module& Mod, Value* V) { 47 | 48 | Value* call = V; 49 | 50 | if (this->Fn == "GetUUID") { 51 | call = CreateUUIDTransform(I, Mod, V); 52 | } else { 53 | errs() << "Warning: Dtrace Logger requires the use of Metadata to function properly."; 54 | call = nullptr; 55 | } 56 | 57 | return call; 58 | } 59 | 60 | /* Length of a node address (an IEEE 802 address). */ 61 | /* #define _UUID_NODE_LEN 6 */ 62 | /* struct uuid { */ 63 | /* uint32_t time_low; */ 64 | /* uint16_t time_mid; */ 65 | /* uint16_t time_hi_and_version; */ 66 | /* uint8_t clock_seq_hi_and_reserved; */ 67 | /* uint8_t clock_seq_low; */ 68 | /* uint8_t node[_UUID_NODE_LEN]; */ 69 | /* } */ 70 | 71 | /* int fgetuuid(int, struct uuid *); */ 72 | 73 | Value* Transform::CreateUUIDTransform(Instruction* I, Module& Mod, Value* V) { 74 | 75 | IRBuilder<> B(I); 76 | 77 | LLVMContext &Ctx = Mod.getContext(); 78 | Type* fd_t = IntegerType::get(Ctx, sizeof(int) * CHAR_BIT); 79 | Type* uuid_t = StructType::get( IntegerType::get(Ctx, sizeof(uint32_t) * CHAR_BIT), 80 | IntegerType::get(Ctx, sizeof(uint16_t) * CHAR_BIT), 81 | IntegerType::get(Ctx, sizeof(uint16_t) * CHAR_BIT), 82 | IntegerType::get(Ctx, sizeof(uint8_t) * CHAR_BIT), 83 | IntegerType::get(Ctx, sizeof(uint8_t) * CHAR_BIT), 84 | ArrayType::get(IntegerType::get(Ctx, sizeof(uint8_t) * CHAR_BIT), 6)); 85 | 86 | 87 | Value* args[2]; 88 | args[0] = V; 89 | args[1] = B.CreateAlloca(uuid_t); 90 | ArrayRef argsRef(args, 2); 91 | 92 | std::vector params; 93 | params.push_back(fd_t); 94 | params.push_back(args[1]->getType()); 95 | 96 | auto *FT = FunctionType::get( IntegerType::get(Ctx, sizeof(int) * CHAR_BIT), params, false); 97 | 98 | FunctionCallee F = Mod.getOrInsertFunction("fgetuuid", FT); 99 | 100 | 101 | B.CreateCall(F, argsRef); 102 | 103 | return argsRef.data()[1]; 104 | 105 | } 106 | 107 | -------------------------------------------------------------------------------- /src/Instrumentation.hh: -------------------------------------------------------------------------------- 1 | //! @file Instrumentation.hh Declaration of @ref loom::Instrumentation. 2 | /* 3 | * Copyright (c) 2012-2013,2015-2016 Jonathan Anderson 4 | * Copyright (c) 2016 Cem Kilic 5 | * All rights reserved. 6 | * 7 | * This software was developed by SRI International and the University of 8 | * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) 9 | * ("CTSRD"), as part of the DARPA CRASH research programme, by BAE Systems, 10 | * the University of Cambridge Computer Laboratory, and Memorial University 11 | * under DARPA/AFRL contract FA8650-15-C-7558 ("CADETS"), as part of the 12 | * DARPA Transparent Computing (TC) research program, and at Memorial University 13 | * under the NSERC Discovery program (RGPIN-2015-06048). 14 | * 15 | * Redistribution and use in source and binary forms, with or without 16 | * modification, are permitted provided that the following conditions 17 | * are met: 18 | * 1. Redistributions of source code must retain the above copyright 19 | * notice, this list of conditions and the following disclaimer. 20 | * 2. Redistributions in binary form must reproduce the above copyright 21 | * notice, this list of conditions and the following disclaimer in the 22 | * documentation and/or other materials provided with the distribution. 23 | * 24 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 25 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 | * SUCH DAMAGE. 35 | */ 36 | 37 | #ifndef LOOM_INSTRUMENTATION_FN_H 38 | #define LOOM_INSTRUMENTATION_FN_H 39 | 40 | #include "IRUtils.hh" 41 | #include "InstrStrategy.hh" 42 | #include "PolicyFile.hh" 43 | 44 | #include 45 | #include 46 | #include 47 | #include 48 | 49 | namespace llvm { 50 | class Instruction; 51 | class LLVMContext; 52 | class Module; 53 | } // namespace llvm 54 | 55 | namespace loom { 56 | 57 | /** 58 | * Instrumentation code (which could be a function or inline instructions) 59 | * that receives program events such as "called foo(42,97)" and takes 60 | * policy-defined actions (e.g., logs events or updates counters). 61 | */ 62 | class Instrumentation { 63 | public: 64 | /** 65 | * Construct some instrumentation that puts all actions into BasicBlocks 66 | * injected between the specified preamble and end blocks. 67 | */ 68 | Instrumentation(llvm::SmallVector Values, 69 | llvm::BasicBlock *Preamble, llvm::BasicBlock *EndBlock, 70 | llvm::Instruction *PreambleEnd, llvm::Instruction *End); 71 | 72 | /** 73 | * Construct some instrumentation that directly injects actions as inline 74 | * instructions rather than using BasicBlocks. 75 | */ 76 | Instrumentation(llvm::SmallVector Values, 77 | llvm::Instruction *PreambleEnd, llvm::Instruction *End); 78 | 79 | //! Retrieve the values passed into the instrumentation. 80 | llvm::ArrayRef Values() { return InstrValues; } 81 | 82 | private: 83 | llvm::SmallVector InstrValues; //!< Instrumented values 84 | llvm::BasicBlock *Preamble; //!< Cross-instrumentation logging, etc. 85 | llvm::BasicBlock *EndBlock; //!< End of the instrumentation block chain. 86 | llvm::Instruction *PreambleEnd; //!< Terminator of the preamble. 87 | llvm::Instruction *End; //!< Final instruction in the instrumentation. 88 | }; 89 | 90 | } // namespace loom 91 | 92 | #endif /* !LOOM_INSTRUMENTATION_FN_H */ 93 | -------------------------------------------------------------------------------- /test/test_support.py: -------------------------------------------------------------------------------- 1 | import glob 2 | import platform 3 | import os 4 | import subprocess 5 | import sys 6 | 7 | # 8 | # Standard places to find include files and libraries. 9 | # 10 | # Excluded from CFLAGS, LDFLAGS, etc. 11 | # 12 | if platform.system() == 'FreeBSD': 13 | std_incdirs = [ '/usr/include' ] 14 | std_libdirs = [ '/lib', '/usr/lib' ] 15 | else: 16 | std_incdirs = [ '/usr/include', '/usr/local/include' ] 17 | std_libdirs = [ '/lib', '/usr/lib', '/usr/local/lib' ] 18 | 19 | 20 | # 21 | # Location of LLVM binaries (directory containing the executing llvm-lit) 22 | # 23 | llvm_bindir = os.path.dirname(sys.argv[0]) 24 | default_path = llvm_bindir + os.pathsep + os.environ.get('PATH') 25 | 26 | 27 | def cflags(dirs, defines = [], extra = []): 28 | dirs += [ '/usr/local/include' ] 29 | return ' '.join([ 30 | ' '.join([ '-I %s' % d for d in dirs if d not in std_incdirs ]), 31 | ' '.join([ '-D %s' % d for d in defines ]), 32 | ' '.join(extra) 33 | ]) 34 | 35 | def ldflags(dirs, libs, extras = []): 36 | dirs += [ '/usr/local/lib' ] 37 | return ' '.join([ 38 | ' '.join([ '-L %s' % d for d in dirs if d not in std_libdirs ]), 39 | ' '.join([ '-l %s' % l for l in libs ]) 40 | ] + extras) 41 | 42 | def cpp_out(): 43 | """ How do we specify the output file from our platform's cpp? """ 44 | cpp_version = run_command('cpp', [ '--version' ]).decode().split('\n')[0] 45 | 46 | # Clang usage: 'cpp in -o out'; GCC usage: 'cpp in out' 47 | if 'clang version 3.3' in cpp_version: return '-o' 48 | else: return '' 49 | 50 | 51 | def find_containing_dir(filename, paths, notfound_msg): 52 | """ Find the first directory that contains a file. """ 53 | 54 | for d in paths: 55 | if len(glob.glob(os.path.join(d, filename))) > 0: 56 | return d 57 | 58 | sys.stderr.write("No '%s' in %s\n" % (filename, paths)) 59 | if notfound_msg: sys.stderr.write('%s\n' % notfound_msg) 60 | sys.stderr.flush() 61 | sys.exit(1) 62 | 63 | 64 | def find_include_dir(filename, paths = [], notfound_msg = ""): 65 | return find_containing_dir(filename, std_incdirs + paths, notfound_msg) 66 | 67 | def find_libdir(filename, paths = [], notfound_msg = ""): 68 | return find_containing_dir(filename, std_libdirs + paths, notfound_msg) 69 | 70 | def find_library(filename, paths = [], notfound_msg = ""): 71 | d = find_containing_dir(filename, std_libdirs + paths, notfound_msg) 72 | return os.path.join(d, filename) 73 | 74 | def libname(name, loadable_module = False): 75 | """ Translate a library name to a filename (e.g., foo -> libfoo.so). """ 76 | system = platform.system() 77 | 78 | # Loadable modules don't get a 'lib' prefix on any platform. 79 | if system != 'Windows': 80 | name = name if loadable_module else 'lib' + name 81 | 82 | # Platform-specific suffixes: 83 | if system == 'Darwin': 84 | name += '.dylib' 85 | 86 | elif system == 'Windows': 87 | name += '.dll' 88 | 89 | else: 90 | name += '.so' 91 | 92 | return name 93 | 94 | def run_command(command, args = []): 95 | """ Run a command line and return the output from stdout. """ 96 | 97 | argv = [ command ] + args 98 | try: cmd = subprocess.Popen(argv, stdout = subprocess.PIPE) 99 | except OSError as why: 100 | sys.stderr.write('Unable to run %s: %s\n' % (command, why)) 101 | sys.stderr.flush() 102 | sys.exit(1) 103 | 104 | cmd.wait() 105 | return cmd.stdout.read() 106 | 107 | def which(commands, paths = default_path): 108 | """ 109 | Do something similar to which(2): find the full path of a command 110 | (one of 'commands') contained in the $PATH environment variable. 111 | """ 112 | 113 | for command in commands: 114 | for path in paths.split(os.pathsep): 115 | full = os.path.join(path, command) 116 | if os.path.exists(full): 117 | return full 118 | 119 | raise ValueError('No command from %s in path %s' % (commands, paths)) 120 | 121 | 122 | 123 | class Config: 124 | def __init__(self, command): 125 | self.command = command 126 | 127 | def __getitem__(self, name): 128 | return run_command(self.command, [ '--' + name ]).strip() 129 | 130 | llvm_config = Config(which([ 'llvm-config33', 'llvm-config' ])) 131 | -------------------------------------------------------------------------------- /doc/loom-overview.adoc: -------------------------------------------------------------------------------- 1 | = Loom: LLVM instrumentation library 2 | 3 | Loom is a general purpose library for adding instrumentation to software. Loom does not require you to have access to the original source code, working instead on code compiled to the LLVM intermediate representation (IR) bytecode. Loom weaves in static instrumentation into this bytecode, allowing you to expose internal values to instrumentation frameworks. Loom ships with multiple supported frameworks, but it can also be expanded to use the instrumentation framework of your choosing. 4 | 5 | == How Loom Works 6 | 7 | // Include a diagram in this section of the instrumentation process 8 | 9 | In order to use Loom a you needs access to the application of interest compiled to LLVM IR. Some system make use of "Fat Binaries", or binaries that contain both a machine code compiled version of the application and a version compiled to LLVM IR. On those system, the provided intermediate representation can be used. Otherwise, you need to compile the IR themselves using the LLVM tool chain to allow for Loom to be used. 10 | 11 | Working from LLVM IR means that the end user does not need to add instrumentation the application in the source code. Instead, the require probes are defined in a Loom policy file. This allows you to specify the parameters for instrumentation in an easy to use YAML syntax. Without touching the source code of the application, you can specify functions and variables to be trace, logging formats and instrumentation framework to be used. 12 | 13 | The policy file also specifies the code to be instrumented. Currently, Loom supports the instrumentation of functions (on entry and return), structures and structure fields and global variable. Additional functionality is under development. For the latest list, check https://github.com/cadets/loom. 14 | 15 | Loom uses an LLVM Optimization (Opt) pass to instrument the IR code. When run with the IR code and policy file as inputs, the Loom Opt pass outputs an augmented version of application IR with the specified instrumentation woven throughout. This IR is then compiled to the final machine code to be run on the desired architecture. Once running, the new version of the application will output tracing data as each instrumentation port is reached. 16 | 17 | == Why Loom? 18 | 19 | Loom is designed to be a general purpose library, allowing you to instrument your application without imposing requirements on source code or architecture. We provide outputs to multiple instrumentation frameworks and are continuing development to add more. But you are not just limited to we provide, Loom is design to be extended to suit you needs. 20 | 21 | === Separation of code and instrumentation 22 | 23 | Loom's use of a policy file to define what you want to instrument allows you to keep your codebase clean of instrumentation. This allows you to avoid the overhead of unnecessary instrumentation is production code, or the added complexity of defining code to be enabled only during debug builds. It allow allow you flexibility and ease when you need to change instrumentation requirements as your application evolves. 24 | 25 | === Architecture Independent 26 | 27 | Because Loom works with LLVM architecture independent intermediate representation, instrumentation is added before final compilation. In practice, this means that the application can be instrumented once, and then compiled to many architectures for testing. 28 | 29 | === Support for Multiple Frameworks 30 | 31 | Currently, Loom supports three instrumentation outputs. For tracing tasks that do not require the complexity of using an instrumentation framework, there is a simple logger that outputs data as text. There are two supported formats for this data, simple text and structured data (e.g. json). 32 | 33 | Loom also supports two external logging frameworks, dtrace(1)* and FreeBSD's ktrace(1). When either of these loggers are used Loom makes function calls to pass the data into the framework itself, bypassing the use of log files. 34 | 35 | * Currently dtrace(1) requires the use of new system call to make use of this functionality. 36 | 37 | === Designed for Extensibility 38 | 39 | If the instrumentation frameworks provided do not meet your needs it can be extended to support others. Loom is an open source library designed with extensibility in mind. Adding new instrumentation frameworks can be done by extending one of the existing loggers and making small changes to the policy file parser. 40 | -------------------------------------------------------------------------------- /src/PolicyFile.hh: -------------------------------------------------------------------------------- 1 | //! @file PolicyFile.hh Declaration of @ref loom::PolicyFile. 2 | /* 3 | * Copyright (c) 2015-2016 Jonathan Anderson 4 | * Copyright (c) 2018 Brian Kidney 5 | * All rights reserved. 6 | * 7 | * This software was developed at Memorial University under the 8 | * NSERC Discovery program (RGPIN-2015-06048). 9 | * 10 | * Copyright (c) 2018 Stephen Lee 11 | * All rights reserved. 12 | * 13 | * This software was developed by SRI International, Purdue University, 14 | * University of Wisconsin and University of Georgia under DARPA/AFRL 15 | * contract FA8650-15-C-7562 ("TRACE"), as part of the DARPA Transparent 16 | * Computing (TC) research program. 17 | * 18 | * Redistribution and use in source and binary forms, with or without 19 | * modification, are permitted provided that the following conditions 20 | * are met: 21 | * 1. Redistributions of source code must retain the above copyright 22 | * notice, this list of conditions and the following disclaimer. 23 | * 2. Redistributions in binary form must reproduce the above copyright 24 | * notice, this list of conditions and the following disclaimer in the 25 | * documentation and/or other materials provided with the distribution. 26 | * 27 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 28 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 31 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 | * SUCH DAMAGE. 38 | */ 39 | 40 | #ifndef LOOM_POLICY_FILE_H 41 | #define LOOM_POLICY_FILE_H 42 | 43 | #include "Policy.hh" 44 | 45 | #include 46 | 47 | namespace loom { 48 | 49 | class PolicyFile : public Policy { 50 | public: 51 | /// A structure that contains policy data parsed from a file. 52 | struct PolicyFileData; 53 | 54 | virtual ~PolicyFile(); 55 | 56 | /// Open a policy file. 57 | static llvm::ErrorOr> Open(std::string Filename); 58 | 59 | InstrStrategy::Kind Strategy() const override; 60 | 61 | SimpleLogger::LogType Logging() const override; 62 | 63 | KTraceTarget KTrace() const override; 64 | 65 | DTraceTarget DTrace() const override; 66 | 67 | std::unique_ptr Serialization(llvm::Module &) const override; 68 | 69 | bool UseBlockStructure() const override; 70 | 71 | bool InstrumentAll() const override; 72 | 73 | bool InstrumentPointerInsts() const override; 74 | 75 | Policy::Directions CallHooks(const llvm::Function &) const override; 76 | 77 | std::string ReplaceCall(const llvm::Function &) const override; 78 | 79 | std::string ReplaceDAG(const llvm::Function &Fn) const override; 80 | 81 | std::queue DAGTail(const llvm::Function &Fn) const override; 82 | 83 | Policy::Directions FnHooks(const llvm::Function &) const override; 84 | 85 | Metadata InstrMetadata(const llvm::Function &Fn) const override; 86 | 87 | std::vector InstrTransforms(const llvm::Function &Fn) const override; 88 | 89 | bool StructTypeMatters(const llvm::StructType &) const override; 90 | 91 | bool FieldReadHook(const llvm::StructType &, llvm::StringRef) const override; 92 | 93 | bool FieldWriteHook(const llvm::StructType &, llvm::StringRef) const override; 94 | 95 | bool GlobalValueMatters(const llvm::Value &) const override; 96 | 97 | bool GlobalReadHook(const llvm::Value &) const override; 98 | 99 | bool GlobalWriteHook(const llvm::Value &) const override; 100 | 101 | std::string InstrName(const std::vector &) const override; 102 | 103 | private: 104 | PolicyFile(const PolicyFileData &); 105 | 106 | bool MatchName(std::string instrName, llvm::StringRef name) const; 107 | 108 | std::unique_ptr Policy; 109 | }; 110 | 111 | } // namespace loom 112 | 113 | #endif /* LOOM_POLICY_FILE_H */ 114 | -------------------------------------------------------------------------------- /src/DTraceLogger.cc: -------------------------------------------------------------------------------- 1 | //! @file DTraceLogger.cc Definition of @ref DTraceLogger. 2 | /* 3 | * Copyright (c) 2017 Brian Kidney 4 | * All rights reserved. 5 | * 6 | * This software was developed by BAE Systems, the University of Cambridge 7 | * Computer Laboratory, and Memorial University under DARPA/AFRL contract 8 | * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing 9 | * (TC) research program. 10 | * 11 | * Redistribution and use in source and binary forms, with or without 12 | * modification, are permitted provided that the following conditions 13 | * are met: 14 | * 1. Redistributions of source code must retain the above copyright 15 | * notice, this list of conditions and the following disclaimer. 16 | * 2. Redistributions in binary form must reproduce the above copyright 17 | * notice, this list of conditions and the following disclaimer in the 18 | * documentation and/or other materials provided with the distribution. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 | * SUCH DAMAGE. 31 | */ 32 | 33 | #include "DTraceLogger.hh" 34 | 35 | #include 36 | 37 | #include 38 | #include 39 | #include 40 | 41 | using namespace loom; 42 | using namespace llvm; 43 | using std::vector; 44 | 45 | DTraceLogger::DTraceLogger(llvm::Module& Mod) 46 | : Logger(Mod){ }; 47 | 48 | Value* DTraceLogger::ConvertValueToPtr(IRBuilder<>& B, LLVMContext& Ctx, Value* V, Type* param_t) 49 | { 50 | Type *T = V->getType(); 51 | if (T->isPointerTy()) { 52 | return B.CreatePtrToInt(V, param_t); 53 | } else if (T->isIntegerTy()) { 54 | return B.CreateSExt(V, param_t); 55 | } else if (T->isDoubleTy()) { 56 | return B.CreateBitCast(V, IntegerType::get(Ctx, sizeof(int64_t) * CHAR_BIT)); 57 | } else if (T->isFloatTy()) { 58 | auto *BC = B.CreateBitCast(V, IntegerType::get(Ctx, sizeof(int32_t) * CHAR_BIT)); 59 | return B.CreateSExt(BC, param_t); 60 | } 61 | return ConstantInt::get(param_t, 0); 62 | } 63 | 64 | 65 | 66 | Value* DTraceLogger::Log(Instruction *I, ArrayRef Values, 67 | StringRef Name, StringRef Descrip, 68 | Metadata Metadata, std::vector Transforms, 69 | bool /* SuppressUniqueness */) { 70 | 71 | if (not Metadata.isValid()) 72 | errs() << "Warning: Dtrace Logger requires the use of Metadata to function properly."; 73 | 74 | IRBuilder<> B(I); 75 | 76 | LLVMContext &Ctx = Mod.getContext(); 77 | Type* id_t = IntegerType::get(Ctx, sizeof(unsigned int) * CHAR_BIT); 78 | Type* param_t = IntegerType::get(Ctx, sizeof(uintptr_t) * CHAR_BIT); 79 | 80 | size_t n_args = std::min(Values.size(), 5ul); 81 | 82 | std::vector params; 83 | for (unsigned int i = 0; i < n_args + 1; i++) { 84 | params.push_back(param_t); 85 | } 86 | 87 | auto *FT = FunctionType::get( IntegerType::get(Ctx, sizeof(int) * CHAR_BIT), params, false); 88 | 89 | FunctionCallee F = Mod.getOrInsertFunction("dt_probe", FT); 90 | 91 | 92 | Value* args[6]; 93 | args[0] = B.CreateSExt(ConstantInt::get(id_t, Metadata.Id), param_t);; 94 | for (unsigned int i = 0; i < n_args; i++) 95 | { 96 | Value *ptr; 97 | 98 | Transform Tf; 99 | for (auto t: Transforms) { 100 | if (t.Arg == i) 101 | Tf = t; 102 | break; 103 | } 104 | 105 | if (Tf.isValid()) { 106 | ptr = ConvertValueToPtr(B, Ctx, Tf.CreateTransform(I, Mod, Values[i]), param_t); 107 | } else { 108 | ptr = ConvertValueToPtr(B, Ctx, Values[i], param_t); 109 | } 110 | 111 | args[i + 1] = ptr; 112 | } 113 | 114 | ArrayRef argsRef(args, n_args + 1); 115 | 116 | return B.CreateCall(F, argsRef); 117 | 118 | } 119 | 120 | -------------------------------------------------------------------------------- /src/Serializer.hh: -------------------------------------------------------------------------------- 1 | //! @file Serializer.hh Declaration of @ref loom::Serializer. 2 | /* 3 | * Copyright (c) 2016-2017 Jonathan Anderson 4 | * All rights reserved. 5 | * 6 | * This software was developed by BAE Systems, the University of Cambridge 7 | * Computer Laboratory, and Memorial University under DARPA/AFRL contract 8 | * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing 9 | * (TC) research program. 10 | * 11 | * Redistribution and use in source and binary forms, with or without 12 | * modification, are permitted provided that the following conditions 13 | * are met: 14 | * 1. Redistributions of source code must retain the above copyright 15 | * notice, this list of conditions and the following disclaimer. 16 | * 2. Redistributions in binary form must reproduce the above copyright 17 | * notice, this list of conditions and the following disclaimer in the 18 | * documentation and/or other materials provided with the distribution. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 | * SUCH DAMAGE. 31 | */ 32 | 33 | #ifndef SERIALIZER_H_ 34 | #define SERIALIZER_H_ 35 | 36 | #include 37 | #include 38 | 39 | namespace loom { 40 | 41 | //! A tool that can transform a set of values into a serialized representation. 42 | class Serializer { 43 | public: 44 | virtual ~Serializer(); 45 | 46 | //! A buffer can be described using a pointer and a length. 47 | typedef std::pair BufferInfo; 48 | 49 | //! Create an empty Serializer unique_ptr. 50 | static std::unique_ptr None(); 51 | 52 | //! A unique name that identifies the serialization scheme (e.g., `nvlist`). 53 | virtual llvm::StringRef SchemeName() const = 0; 54 | 55 | /** 56 | * Generate the code to serialize a set of values, returning details of the 57 | * resulting buffer (pointer and length). 58 | * 59 | * @param Name Machine-readable instrumentation name. 60 | * @param Descrip Human-readable short description (may be ignored). 61 | * @param Values Values actually being serialized 62 | * @param B IRBuilder positioned within instrumentation code 63 | */ 64 | virtual BufferInfo Serialize(llvm::StringRef Name, llvm::StringRef Descrip, 65 | llvm::ArrayRef Values, 66 | llvm::IRBuilder<> &B) = 0; 67 | 68 | /** 69 | * Clean up a serialized data buffer using Serializer-specific cleanup code 70 | * (e.g., `free()` or `nvlist_destroy`). 71 | */ 72 | virtual llvm::Value *Cleanup(BufferInfo &, llvm::IRBuilder<> &) = 0; 73 | 74 | protected: 75 | //! Base constructor for subclasses. 76 | Serializer(llvm::LLVMContext &); 77 | 78 | llvm::LLVMContext &Ctx; //!< store of LLVM types 79 | llvm::IntegerType *Byte; //!< `char` / `uint8_t` 80 | llvm::PointerType *BytePtr; //!< `char*` / `uint8_t*` 81 | llvm::IntegerType *SizeT; //!< `size_t` 82 | }; 83 | 84 | //! A Serializer that doesn't serialize anything. 85 | class NullSerializer : public Serializer { 86 | public: 87 | //! Construct a null serializer. 88 | NullSerializer(llvm::LLVMContext &Ctx) : Serializer(Ctx) {} 89 | 90 | virtual llvm::StringRef SchemeName() const override { return "null"; } 91 | 92 | virtual BufferInfo Serialize(llvm::StringRef Name, llvm::StringRef Descrip, 93 | llvm::ArrayRef, 94 | llvm::IRBuilder<> &) override; 95 | 96 | virtual llvm::Value *Cleanup(BufferInfo &, llvm::IRBuilder<> &) override; 97 | 98 | private: 99 | llvm::Value *Nop(llvm::IRBuilder<> &); 100 | }; 101 | 102 | } // namespace loom 103 | 104 | #endif // !SERIALIZER_H_ 105 | -------------------------------------------------------------------------------- /test/field-instrumentation.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file field-instrumentation.c 3 | * \brief Tests instrumentation of structure field accesses. 4 | * 5 | * Commands for llvm-lit: 6 | * RUN: %cpp -DPOLICY_FILE %s > %t.yaml 7 | * RUN: %cpp %cflags %s > %t.c 8 | * RUN: %clang %cflags -S -emit-llvm %cflags %t.c -o %t.ll 9 | * RUN: %loom -S %t.ll -loom-file %t.yaml -o %t.instr.ll 10 | * RUN: %filecheck -input-file %t.instr.ll %s 11 | * RUN: %llc -filetype=obj %t.instr.ll -o %t.instr.o 12 | * RUN: %clang %ldflags %t.instr.o -o %t.instr 13 | * RUN: %t.instr > %t.output 14 | * RUN: %filecheck -input-file %t.output %s -check-prefix CHECK-OUTPUT 15 | */ 16 | 17 | #if defined (POLICY_FILE) 18 | 19 | hook_prefix: __test_hook 20 | 21 | logging: printf 22 | 23 | block_structure: true 24 | 25 | structures: 26 | - name: foo 27 | fields: 28 | - name: f_int 29 | operations: [ read, write ] 30 | - name: f_float 31 | operations: [ read, write ] 32 | - name: f_double 33 | operations: [ read, write ] 34 | - name: f_string 35 | operations: [ read, write ] 36 | 37 | - name: bar 38 | fields: 39 | - name: b_fooptr 40 | operations: [ read, write ] 41 | 42 | #else 43 | 44 | #include 45 | 46 | struct foo { 47 | int f_int; 48 | float f_float; 49 | double f_double; 50 | const char * f_string; 51 | int f_ignored; 52 | }; 53 | 54 | struct bar { 55 | // TODO: struct foo b_foo; 56 | struct foo *b_fooptr; 57 | }; 58 | 59 | 60 | int 61 | main(int argc, char *argv[]) 62 | { 63 | struct foo f = { 64 | .f_int = 42, 65 | .f_float = 3, 66 | .f_double = 3.1415926, 67 | .f_string = "Pi is exactly equal to 3!", 68 | }; 69 | 70 | struct bar b = { 71 | //.b_foo = f, 72 | 73 | // CHECK: call void @[[PREFIX:__test_hook]]_store_struct_bar_field_b_fooptr([[BAR:.*]], [[FOO:.*]]) 74 | // CHECK-OUTPUT: bar.b_fooptr store: [[BAR:.*]] [[FOO:.*]] 75 | .b_fooptr = &f, 76 | }; 77 | 78 | // CHECK: [[F_INT_PTR:%.+]] = getelementptr {{.*}}%struct.foo, [[FOO]] 79 | // CHECK: [[F_INT_NOW:%[0-9]+]] = load [[INT:i[0-9]+]], [[INT]]* [[F_INT_PTR]] 80 | // CHECK: call void @[[PREFIX]]_load_struct_foo_field_f_int([[FOO]], [[INT]] [[F_INT_NOW]] 81 | // CHECK: [[INC:%.+]] = add {{.*}}[[INT]] [[F_INT_NOW]], 1 82 | // CHECK: call void @[[PREFIX]]_store_struct_foo_field_f_int([[FOO]], [[INT]] [[INC]]) 83 | // CHECK-OUTPUT: foo.f_int load: [[FOO]] 42 84 | // CHECK-OUTPUT: foo.f_int store: [[FOO]] 43 85 | f.f_int++; 86 | 87 | // CHECK: [[F_FLOAT_PTR:%.+]] = getelementptr {{.*}}%struct.foo, [[FOO]] 88 | // CHECK: [[F_FLOAT_NOW:%[0-9]+]] = load float, float* [[F_FLOAT_PTR]] 89 | // CHECK: call void @[[PREFIX]]_load_struct_foo_field_f_float([[FOO]], float [[F_FLOAT_NOW]] 90 | // CHECK: [[SUB:%.+]] = fsub {{.*}}float [[F_FLOAT_NOW]], 1 91 | // CHECK: call void @[[PREFIX]]_store_struct_foo_field_f_float([[FOO]], float [[SUB]]) 92 | // CHECK-OUTPUT: foo.f_float load: [[FOO]] 3 93 | // CHECK-OUTPUT: foo.f_float store: [[FOO]] 2 94 | f.f_float -= 1; 95 | 96 | // CHECK: [[F_DOUBLE_PTR:%.+]] = getelementptr {{.*}}%struct.foo, [[FOO]] 97 | // CHECK: call void @[[PREFIX]]_store_struct_foo_field_f_double([[FOO]], double -1 98 | // CHECK: store double -1{{.*}}, double* [[F_DOUBLE_PTR]] 99 | // CHECK-OUTPUT: foo.f_double store: [[FOO]] -1 100 | f.f_double = -1; 101 | 102 | // CHECK: [[F_IGNORED_PTR:%.+]] = getelementptr {{.*}}%struct.foo, [[FOO]] 103 | // CHECK-NOT: call void @[[PREFIX]]_store_{{.*}}([[FOO]], i32 99 104 | // CHECK: store i32 99, i32* [[F_IGNORED_PTR]] 105 | f.f_ignored = 99; 106 | 107 | // CHECK: [[MESSAGE_PTR:%.+]] = getelementptr {{.*}}%struct.foo, [[FOO]] 108 | // CHECK: [[MESSAGE:%.+]] = load i8*, i8** [[MESSAGE_PTR]] 109 | // CHECK: call void @[[PREFIX]]_load_struct_foo_field_f_string([[FOO]], i8* [[MESSAGE]]) 110 | // CHECK-OUTPUT: foo.f_string load: [[FOO]] 0x{{[0-9a-z]+}} 111 | // CHECK-OUTPUT: message: '{{.*}}' 112 | const char *message = f.f_string; 113 | printf("message: '%s'\n", message); 114 | 115 | //TODO: b.b_foo.f_int = 0; 116 | 117 | // CHECK: [[FOOPTR_PTR:%.+]] = getelementptr {{.*}}%struct.bar, [[BAR]] 118 | // CHECK: [[FOOPTR_VAL:%.+]] = load %struct.foo*, %struct.foo** [[FOOPTR_PTR]] 119 | // CHECK: call void @[[PREFIX]]_load_struct_bar_field_b_fooptr([[BAR]], %struct.foo* [[FOOPTR_VAL]]) 120 | // CHECK-OUTPUT: bar.b_fooptr load: [[BAR]] [[FOO]] 121 | 122 | // CHECK: call void @[[PREFIX]]_store_struct_foo_field_f_int(%struct.foo* [[FOOPTR_VAL]], [[INT]] 123) 123 | // CHECK-OUTPUT: foo.f_int store: [[FOO]] 123 124 | b.b_fooptr->f_int = 123; 125 | 126 | return 0; 127 | } 128 | 129 | #endif /* !POLICY_FILE */ 130 | -------------------------------------------------------------------------------- /test/wildcard-field-instrumentation.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file field-instrumentation.c 3 | * \brief Tests instrumentation of structure field accesses. 4 | * 5 | * Commands for llvm-lit: 6 | * RUN: %cpp -DPOLICY_FILE %s > %t.yaml 7 | * RUN: %cpp %cflags %s > %t.c 8 | * RUN: %clang %cflags -S -emit-llvm %cflags %t.c -o %t.ll 9 | * RUN: %loom -S %t.ll -loom-file %t.yaml -o %t.instr.ll 10 | * RUN: %filecheck -input-file %t.instr.ll %s 11 | * RUN: %llc -filetype=obj %t.instr.ll -o %t.instr.o 12 | * RUN: %clang %ldflags %t.instr.o -o %t.instr 13 | * RUN: %t.instr > %t.output 14 | * RUN: %filecheck -input-file %t.output %s -check-prefix CHECK-OUTPUT 15 | */ 16 | 17 | #if defined (POLICY_FILE) 18 | 19 | hook_prefix: __test_hook 20 | 21 | logging: printf 22 | 23 | block_structure: true 24 | 25 | structures: 26 | - name: f.* 27 | fields: 28 | - name: f_int 29 | operations: [ read, write ] 30 | - name: f_f.* 31 | operations: [ read, write ] 32 | - name: f_d.* 33 | operations: [ read, write ] 34 | - name: f_string 35 | operations: [ read, write ] 36 | 37 | - name: bar 38 | fields: 39 | - name: b_foo.* 40 | operations: [ read, write ] 41 | 42 | #else 43 | 44 | #include 45 | 46 | struct foo { 47 | int f_int; 48 | float f_float; 49 | double f_double; 50 | const char * f_string; 51 | int f_ignored; 52 | }; 53 | 54 | struct bar { 55 | // TODO: struct foo b_foo; 56 | struct foo *b_fooptr; 57 | }; 58 | 59 | 60 | int 61 | main(int argc, char *argv[]) 62 | { 63 | struct foo f = { 64 | .f_int = 42, 65 | .f_float = 3, 66 | .f_double = 3.1415926, 67 | .f_string = "Pi is exactly equal to 3!", 68 | }; 69 | 70 | struct bar b = { 71 | //.b_foo = f, 72 | 73 | // CHECK: call void @[[PREFIX:__test_hook]]_store_struct_bar_field_b_fooptr([[BAR:.*]], [[FOO:.*]]) 74 | // CHECK-OUTPUT: bar.b_fooptr store: [[BAR:.*]] [[FOO:.*]] 75 | .b_fooptr = &f, 76 | }; 77 | 78 | // CHECK: [[F_INT_PTR:%.+]] = getelementptr {{.*}}%struct.foo, [[FOO]] 79 | // CHECK: [[F_INT_NOW:%[0-9]+]] = load [[INT:i[0-9]+]], [[INT]]* [[F_INT_PTR]] 80 | // CHECK: call void @[[PREFIX]]_load_struct_foo_field_f_int([[FOO]], [[INT]] [[F_INT_NOW]] 81 | // CHECK: [[INC:%.+]] = add {{.*}}[[INT]] [[F_INT_NOW]], 1 82 | // CHECK: call void @[[PREFIX]]_store_struct_foo_field_f_int([[FOO]], [[INT]] [[INC]]) 83 | // CHECK-OUTPUT: foo.f_int load: [[FOO]] 42 84 | // CHECK-OUTPUT: foo.f_int store: [[FOO]] 43 85 | f.f_int++; 86 | 87 | // CHECK: [[F_FLOAT_PTR:%.+]] = getelementptr {{.*}}%struct.foo, [[FOO]] 88 | // CHECK: [[F_FLOAT_NOW:%[0-9]+]] = load float, float* [[F_FLOAT_PTR]] 89 | // CHECK: call void @[[PREFIX]]_load_struct_foo_field_f_float([[FOO]], float [[F_FLOAT_NOW]] 90 | // CHECK: [[SUB:%.+]] = fsub {{.*}}float [[F_FLOAT_NOW]], 1 91 | // CHECK: call void @[[PREFIX]]_store_struct_foo_field_f_float([[FOO]], float [[SUB]]) 92 | // CHECK-OUTPUT: foo.f_float load: [[FOO]] 3 93 | // CHECK-OUTPUT: foo.f_float store: [[FOO]] 2 94 | f.f_float -= 1; 95 | 96 | // CHECK: [[F_DOUBLE_PTR:%.+]] = getelementptr {{.*}}%struct.foo, [[FOO]] 97 | // CHECK: call void @[[PREFIX]]_store_struct_foo_field_f_double([[FOO]], double -1 98 | // CHECK: store double -1{{.*}}, double* [[F_DOUBLE_PTR]] 99 | // CHECK-OUTPUT: foo.f_double store: [[FOO]] -1 100 | f.f_double = -1; 101 | 102 | // CHECK: [[F_IGNORED_PTR:%.+]] = getelementptr {{.*}}%struct.foo, [[FOO]] 103 | // CHECK-NOT: call void @[[PREFIX]]_store_{{.*}}([[FOO]], i32 99 104 | // CHECK: store i32 99, i32* [[F_IGNORED_PTR]] 105 | f.f_ignored = 99; 106 | 107 | // CHECK: [[MESSAGE_PTR:%.+]] = getelementptr {{.*}}%struct.foo, [[FOO]] 108 | // CHECK: [[MESSAGE:%.+]] = load i8*, i8** [[MESSAGE_PTR]] 109 | // CHECK: call void @[[PREFIX]]_load_struct_foo_field_f_string([[FOO]], i8* [[MESSAGE]]) 110 | // CHECK-OUTPUT: foo.f_string load: [[FOO]] 0x{{[0-9a-z]+}} 111 | // CHECK-OUTPUT: message: '{{.*}}' 112 | const char *message = f.f_string; 113 | printf("message: '%s'\n", message); 114 | 115 | //TODO: b.b_foo.f_int = 0; 116 | 117 | // CHECK: [[FOOPTR_PTR:%.+]] = getelementptr {{.*}}%struct.bar, [[BAR]] 118 | // CHECK: [[FOOPTR_VAL:%.+]] = load %struct.foo*, %struct.foo** [[FOOPTR_PTR]] 119 | // CHECK: call void @[[PREFIX]]_load_struct_bar_field_b_fooptr([[BAR]], %struct.foo* [[FOOPTR_VAL]]) 120 | // CHECK-OUTPUT: bar.b_fooptr load: [[BAR]] [[FOO]] 121 | 122 | // CHECK: call void @[[PREFIX]]_store_struct_foo_field_f_int(%struct.foo* [[FOOPTR_VAL]], [[INT]] 123) 123 | // CHECK-OUTPUT: foo.f_int store: [[FOO]] 123 124 | b.b_fooptr->f_int = 123; 125 | 126 | return 0; 127 | } 128 | 129 | #endif /* !POLICY_FILE */ 130 | -------------------------------------------------------------------------------- /doc/api/loom.java: -------------------------------------------------------------------------------- 1 | /** 2 | * @opt edgefontname "Avenir" 3 | * @opt edgefontsize 10 4 | * 5 | * @opt nodefontname "Avenir" 6 | * @opt nodefontsize 12 7 | * 8 | * @opt nodefillcolor "#ddddff" 9 | * @hidden 10 | */ 11 | class UMLOptions{} 12 | 13 | 14 | /** @navassoc "" - "" llvm.Module */ 15 | class DebugInfo 16 | { 17 | } 18 | 19 | /** 20 | * @navassoc "" - "" InstrStrategy 21 | * @navassoc "" - "*" Instrumentation 22 | * @navassoc "" - "" llvm.Module 23 | */ 24 | class Instrumenter 25 | { 26 | public boolean Instrument(llvm.Instruction I) {} 27 | public boolean Instrument(llvm.CallInst Call) {} 28 | public boolean Instrument(llvm.Function F) {} 29 | public boolean Instrument(llvm.GetElementPtrInst GEP, llvm.LoadInst L) {} 30 | public boolean Instrument(llvm.GetElementPtrInst GEP, llvm.StoreInst S) {} 31 | } 32 | 33 | /** 34 | * @depend - - Instrumentation 35 | * @depend - - Logger 36 | */ 37 | class InstrStrategy 38 | { 39 | public enum Kind {} 40 | public void AddLogger(Logger Log) {} 41 | 42 | public Instrumentation Instrument(llvm.Instruction I, llvm.Value[] Values) {} 43 | 44 | private boolean UseBlockStructure; 45 | } 46 | 47 | /** 48 | * @navassoc "" - "Preamble,EndBlock" llvm.BasicBlock 49 | * @navassoc "" - "PreambleEnd,End" llvm.Instruction 50 | */ 51 | class Instrumentation 52 | { 53 | private llvm.Value[] InstrValues; 54 | } 55 | 56 | /** 57 | * @navassoc "" - "" Serializer 58 | */ 59 | class KTraceLogger extends Logger 60 | { 61 | public llvm.Value Log(llvm.Instruction I, llvm.Value[] Values, 62 | String Name, String Description, 63 | boolean SuppressUniqueness); 64 | 65 | } 66 | 67 | class LibxoLogger extends SimpleLogger 68 | { 69 | public llvm.Value CreateFormatString(Parameter[] Params) {} 70 | } 71 | 72 | /** 73 | * @depend - - llvm.Function.ArgumentListType 74 | * @navassoc "" - "" llvm.Module 75 | */ 76 | class Logger 77 | { 78 | public abstract llvm.Value Log(llvm.Instruction I, llvm.Value[] Values, 79 | String Name, String Description, 80 | boolean SuppressUniqueness); 81 | 82 | public llvm.Value Log(llvm.Instruction I, 83 | llvm.Function.ArgumentListType Args, 84 | String Name, String Description, 85 | boolean SuppressUniqueness) 86 | { 87 | } 88 | } 89 | 90 | /** 91 | * @depend - - Serializer.BufferInfo 92 | */ 93 | class NVSerializer extends Serializer 94 | { 95 | public BufferInfo Serialize(llvm.Value[] Values) {} 96 | public llvm.Value Cleanup(BufferInfo Buffer) {} 97 | } 98 | 99 | class NullSerializer extends Serializer 100 | { 101 | public BufferInfo Serialize(llvm.Value[] Values) {} 102 | public llvm.Value Cleanup(BufferInfo Buffer) {} 103 | } 104 | 105 | /** 106 | * @navassoc "" - "" PolicyFile 107 | * @depend - - InstrStrategy 108 | * @depend - - Instrumenter 109 | */ 110 | class OptPass extends llvm.ModulePass 111 | { 112 | public boolean runOnModule(llvm.Module Mod) {} 113 | } 114 | 115 | /** 116 | * @navassoc "" - "" llvm.Type 117 | */ 118 | class Parameter 119 | { 120 | String Name; 121 | } 122 | 123 | /** 124 | * @depend - - Logger 125 | */ 126 | interface Policy 127 | { 128 | public InstrStrategy.Kind Strategy(); 129 | public Logger[] Loggers(llvm.Module Mod); 130 | public SimpleLogger.LogType Logging(); 131 | 132 | public enum KTraceTarget { Kernel, Userspace, None } 133 | 134 | public KTraceTarget KTrace(); 135 | 136 | public Serializer Serialization(llvm.Module Mod); 137 | 138 | public boolean UseBlockStructure(); 139 | 140 | public boolean InstrumentAll(); 141 | 142 | public enum Direction { In, Out }; 143 | 144 | public Direction[] CallHooks(llvm.Function F); 145 | public Direction[] FnHooks(llvm.Function F); 146 | 147 | public boolean StructTypeMatters(llvm.StructType S); 148 | 149 | public boolean 150 | FieldReadHook(llvm.StructType T, String Field); 151 | 152 | public boolean 153 | FieldWriteHook(llvm.StructType T, String Field); 154 | 155 | public String InstrName(String[] Components); 156 | } 157 | 158 | class PolicyFile implements Policy 159 | { 160 | public InstrStrategy.Kind Strategy() {} 161 | public Logger[] Loggers(llvm.Module Mod) {} 162 | public SimpleLogger.LogType Logging() {} 163 | public KTraceTarget KTrace() {} 164 | public Serializer Serialization(llvm.Module Mod) {} 165 | public boolean UseBlockStructure() {} 166 | public boolean InstrumentAll() {} 167 | public Direction[] CallHooks(llvm.Function F) {} 168 | public Direction[] FnHooks(llvm.Function F) {} 169 | public boolean StructTypeMatters(llvm.StructType S) {} 170 | public boolean 171 | FieldReadHook(llvm.StructType T, String Field) {} 172 | public boolean 173 | FieldWriteHook(llvm.StructType T, String Field) {} 174 | public String InstrName(String[] Components) {} 175 | } 176 | 177 | class PrintfLogger extends SimpleLogger 178 | { 179 | public llvm.Value CreateFormatString(Parameter[] Params) {} 180 | } 181 | 182 | /** 183 | * @depend - - Parameter 184 | */ 185 | class SimpleLogger extends Logger 186 | { 187 | public enum LogType {} 188 | 189 | protected abstract llvm.Value CreateFormatString(Parameter[] Params); 190 | protected llvm.Value CreateFormatString(llvm.Value[] Values) {} 191 | 192 | protected llvm.Value[] Adapt(llvm.Value[] Values) {} 193 | } 194 | 195 | class Serializer 196 | { 197 | public class BufferInfo 198 | { 199 | llvm.Value Pointer; 200 | llvm.Value Length; 201 | } 202 | 203 | public abstract BufferInfo Serialize(llvm.Value[] Values); 204 | public abstract llvm.Value Cleanup(BufferInfo Buffer); 205 | } 206 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Loom: LLVM instrumentation library 2 | 3 | 5 | 6 | Loom is a general-purpose library for adding instrumentation to software in the LLVM intermediate representation (IR) format. It is currently capable of generating static instrumentation points that expose values (e.g., function parameters and return values) to software-defined instrumentation functions. 7 | 8 | Loom is part of the [CADETS](https://www.cl.cam.ac.uk/research/security/cadets) (Causal, Adaptive, Distributed, and Efficient Tracing System) project as part of DARPA's [Transparent Computing](http://www.darpa.mil/program/transparent-computing) program. 9 | 10 | ## Get it 11 | 12 | Loom itself is entirely contained within this GitHub repository, but it requires that you build [LLVM](http://llvm.org) from source. In order to run Loom's test suite, you must also build a matching version of [Clang](http://clang.llvm.org). 13 | 14 | ```sh 15 | $ git clone https://github.com/cadets/llvm -b cadets llvm 16 | $ git clone https://github.com/cadets/clang -b cadets llvm/tools/clang 17 | $ git clone https://github.com/cadets/loom loom 18 | ``` 19 | 20 | 21 | ## Build it 22 | 23 | ### Building Clang/LLVM 24 | 25 | First, build LLVM using [CMake](https://cmake.org) and [Ninja](https://ninja-build.org). The directions below assume a `Release` build, but a `Debug` build is also possible. 26 | 27 | ```sh 28 | $ mkdir llvm/Release 29 | $ cd llvm/Release 30 | $ cmake -G Ninja -D CMAKE_BUILD_TYPE=Release .. 31 | $ ninja 32 | [go get some coffee] 33 | ``` 34 | 35 | ### Building LOOM 36 | 37 | 1. Set your PATH to include the version of LLVM you just built: 38 | ```sh 39 | $ export PATH=/path/to/LLVM/Release/bin:$PATH 40 | ``` 41 | or: 42 | ```csh 43 | $ setenv PATH /path/to/LLVM/Release/bin:$PATH 44 | ``` 45 | 46 | 2. Configure Loom build: 47 | ```sh 48 | $ cd /path/to/Loom 49 | $ mkdir Release 50 | $ cd Release 51 | $ cmake -G Ninja -D CMAKE_BUILD_TYPE=Release .. 52 | ``` 53 | 54 | 3. Build Loom: 55 | ```sh 56 | $ ninja 57 | ``` 58 | 59 | 4. (optional) run test suite: 60 | 61 | a. Install [libxo](https://github.com/Juniper/libxo), which is used by 62 | Loom to emit structured output: 63 | ```sh 64 | $ pkg install libxo # or whatever your package manager command is 65 | ``` 66 | b. Run the Loom test suite: 67 | ```sh 68 | $ ninja check 69 | ``` 70 | 71 | 72 | ## Use it 73 | 74 | ### `opt` pass 75 | 76 | Loom is structured as a set of libraries for LLVM instrumentation, 77 | but can be run most straightforwardly as an LLVM 78 | [opt](http://llvm.org/docs/CommandGuide/opt.html) pass. 79 | This requires creating an instrumentation policy file such as: 80 | ```yaml 81 | # 82 | # There are two instrumentation strategies: 83 | # * callout: call an instrumentation function like __loom_called_foo 84 | # * inline inject instrumentation inline with instrumented events 85 | # 86 | strategy: callout 87 | 88 | # 89 | # When using callout instrumentation, the generated instrumentation functions 90 | # are named __loom_{event-specific-name} by default. This configuration value 91 | # allows the `__loom` prefix to be overridden. 92 | # 93 | hook_prefix: __test_hook 94 | 95 | # 96 | # Loom can automatically log events and their immediate values (e.g., when 97 | # logging a call to foo(1, 2, 3.1415), emit "foo", 1, 2 and 3.1415) without 98 | # any processing. Strategies include: 99 | # 100 | # * none do not use the simple logger 101 | # * printf just print the event using printf() 102 | # * xo use libxo to emit a structured representation (e.g., json) 103 | # 104 | logging: printf 105 | 106 | # 107 | # Loom can report events via FreeBSD's ktrace(1) mechanism, either from 108 | # the kernel ("kernel") or from userspace via the utrace(2) system call. 109 | # 110 | ktrace: utrace 111 | 112 | # 113 | # Loom currently serializes event information for, e.g., ktrace reporting 114 | # using libnv. Support for other serialization schemes can be added. 115 | # 116 | serialization: nv 117 | 118 | # 119 | # Specify how/when functions should be instrumented. 120 | # 121 | # Functions can be instrumented on the caller side (before/after the call) 122 | # or the callee side (function prelude / return sites). This configuration 123 | # value should be a list of entries, each specifying: 124 | # 125 | # * `name`: the name of the function being instrumented (language-mangled) 126 | # * `caller`: (optional) list of directions to instrument calls (entry/exit) 127 | # * `callee`: (optional) list of directions to instrument functions 128 | # 129 | functions: 130 | - name: foo 131 | caller: [ entry, exit ] 132 | 133 | - name: bar 134 | caller: [ entry ] 135 | callee: [ exit ] 136 | 137 | # 138 | # Specify how/when structure fields should be instrumented. 139 | # 140 | # We can instrument both reads and writes to structure fields. 141 | # These fields must currently be identified by number rather than name. 142 | # The `structures` config value is a list of entries containing: 143 | # 144 | # * `name`: the structure name 145 | # * `fields`: a list of structure field descriptions: 146 | # * `name`: field name 147 | # * `operations`: list of operations to instrument (`read` or `write`) 148 | # 149 | structures: 150 | - name: baz 151 | fields: 152 | - name: refcount 153 | operations: [ read, write ] 154 | ``` 155 | 156 | and then running `opt`: 157 | 158 | ```sh 159 | $ opt -load /path/to/LLVMLoom.so -loom -loom-file /path/to/instr.policy 160 | ``` 161 | 162 | Loom's `opt` pass has options that can be seen in the help/usage output: 163 | 164 | ```sh 165 | $ opt -load /path/to/LLVMLoom.so -help | grep loom 166 | ``` 167 | 168 | 169 | ### Instrumenting FreeBSD 170 | 171 | To build FreeBSD with Loom, you need to clone our IR-augmented version of FreeBSD. Then, you can use our `loom-fbsdmake` script as a drop-in wrapper around `make`: 172 | 173 | ```sh 174 | $ git clone https://github.com/cadets/freebsd -b cadets freebsd-cadets 175 | $ cd freebsd-cadets 176 | $ export LLVM_PREFIX=/path/to/LLVM/Release 177 | $ export LOOM_LIB=/path/to/Loom/Release/lib/LLVMLoom.so 178 | $ /path/to/Loom/scripts/loom-fbsdmake buildworld buildkernel 179 | $ /path/to/Loom/scripts/loom-fbsdmake buildenv # etc. 180 | ``` 181 | -------------------------------------------------------------------------------- /test/instrument-everything-and-run.ll: -------------------------------------------------------------------------------- 1 | ; \file instrument-everything.ll 2 | ; \brief Tests generic instrumentation of all instructions 3 | ; 4 | ; Since we're building something with a FreeBSD target triple, this will 5 | ; only work on FreeBSD: 6 | ; REQUIRES: freebsd 7 | ; 8 | ; Commands for llvm-lit: 9 | ; RUN: %loom -S %s -loom-file %s.policy -o %t.instr.ll 10 | ; RUN: %llc -filetype=obj %t.instr.ll -o %t.instr.o 11 | ; RUN: %clang %ldflags %t.instr.o -o %t.instr 12 | ; RUN: %t.instr > %t.output 13 | ; RUN: %filecheck -input-file %t.output %s 14 | 15 | ; ModuleID = 'tmp.c' 16 | source_filename = "tmp.c" 17 | target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" 18 | target triple = "x86_64-unknown-freebsd12.0" 19 | 20 | @.str = private unnamed_addr constant [15 x i8] c"Hello, world!\0A\00", align 1 21 | @.str.1 = private unnamed_addr constant [23 x i8] c"The value of x is: %f\0A\00", align 1 22 | 23 | ; Function Attrs: nounwind uwtable 24 | define i32 @main(i32 %argc, i8** %argv) #0 !dbg !6 { 25 | entry: 26 | %retval = alloca i32, align 4 27 | ; CHECK: [[INSTR:instrumentation:instruction]]:0x{{[0-f]+}} [[ALLOCA:[0-9]+]] [[RETVAL:0x[0-f]+]] 28 | 29 | %argc.addr = alloca i32, align 4 30 | ; CHECK: [[INSTR]]:0x{{[0-f]+}} [[ALLOCA]] [[ARGC_ADDR:0x[0-f]+]] 31 | 32 | %argv.addr = alloca i8**, align 8 33 | ; CHECK: [[INSTR]]:0x{{[0-f]+}} [[ALLOCA]] [[ARGV_ADDR:0x[0-f]+]] 34 | 35 | %x = alloca double, align 8 36 | ; CHECK: [[INSTR]]:0x{{[0-f]+}} [[ALLOCA]] [[XPTR:0x[0-f]+]] 37 | 38 | store i32 0, i32* %retval, align 4 39 | ; CHECK: [[INSTR]]:0x{{[0-f]+}} [[STORE:[0-9]+]] 0 [[RETVAL]] 40 | 41 | store i32 %argc, i32* %argc.addr, align 4 42 | ; CHECK: [[INSTR]]:0x{{[0-f]+}} [[STORE]] {{[0-9]+}} [[ARGC_ADDR]] 43 | 44 | call void @llvm.dbg.declare(metadata i32* %argc.addr, metadata !13, metadata !14), !dbg !15 45 | 46 | store i8** %argv, i8*** %argv.addr, align 8 47 | ; CHECK: [[INSTR]]:0x{{[0-f]+}} [[STORE]] {{0x[0-f]+}} [[ARGV_ADDR]] 48 | 49 | call void @llvm.dbg.declare(metadata i8*** %argv.addr, metadata !16, metadata !14), !dbg !17 50 | 51 | %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.str, i32 0, i32 0)), !dbg !18 52 | ; CHECK: [[INSTR]]:0x{{[0-f]+}} [[CALL:[0-9]+]] [[LEN:14]] "Hello, world! 53 | 54 | call void @llvm.dbg.declare(metadata double* %x, metadata !19, metadata !14), !dbg !21 55 | 56 | store double 0x402ABCEF97BFC839, double* %x, align 8, !dbg !21 57 | ; CHECK: [[INSTR]]:0x{{[0-f]+}} [[STORE]] [[X:[0-9.]+]] [[XPTR:0x[0-f]+]] 58 | 59 | 60 | ; Note: Unnamed values like this one can be renumbered arbitrarily once we 61 | ; introduce instrumentation (which can itself include unnamed values), 62 | ; so we can't check for a literal %0. Instead, we need to check for 63 | ; consistency between the value name and what we pass to 64 | ; instrumentation. 65 | 66 | %0 = load double, double* %x, align 8, !dbg !22 67 | ; CHECK: [[INSTR]]:0x{{[0-f]+}} [[LOAD:[0-9]+]] [[X]] [[XPTR]] 68 | 69 | %call1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([23 x i8], [23 x i8]* @.str.1, i32 0, i32 0), double %0), !dbg !23 70 | ; CHECK: [[INSTR]]:0x{{[0-f]+}} [[CALL:[0-9]+]] {{[0-9]+}} "The value of x is: 71 | 72 | br label %foo 73 | 74 | foo: 75 | %call2 = call i32 @xo_finish(), !dbg !24 76 | 77 | ret i32 0, !dbg !25 78 | } 79 | 80 | ; Function Attrs: nounwind readnone 81 | declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 82 | 83 | declare i32 @printf(i8*, ...) #2 84 | 85 | declare i32 @xo_finish() #2 86 | 87 | attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } 88 | attributes #1 = { nounwind readnone } 89 | attributes #2 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } 90 | 91 | !llvm.dbg.cu = !{!0} 92 | !llvm.module.flags = !{!3, !4} 93 | !llvm.ident = !{!5} 94 | 95 | !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 4.0.0 (http://llvm.org/git/clang.git 3f7a1d0a6dedbbff7cdd804e31063c9c33a837ec) (http://llvm.org/git/llvm.git 20014804ba63d479300bb5c136856d11fbc1bdae)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) 96 | !1 = !DIFile(filename: "tmp.c", directory: "/usr/home/jon/CADETS/local/loom/Debug") 97 | !2 = !{} 98 | !3 = !{i32 2, !"Dwarf Version", i32 2} 99 | !4 = !{i32 2, !"Debug Info Version", i32 3} 100 | !5 = !{!"clang version 4.0.0 (http://llvm.org/git/clang.git 3f7a1d0a6dedbbff7cdd804e31063c9c33a837ec) (http://llvm.org/git/llvm.git 20014804ba63d479300bb5c136856d11fbc1bdae)"} 101 | !6 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 5, type: !7, isLocal: false, isDefinition: true, scopeLine: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2) 102 | !7 = !DISubroutineType(types: !8) 103 | !8 = !{!9, !9, !10} 104 | !9 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) 105 | !10 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !11, size: 64, align: 64) 106 | !11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64, align: 64) 107 | !12 = !DIBasicType(name: "char", size: 8, align: 8, encoding: DW_ATE_signed_char) 108 | !13 = !DILocalVariable(name: "argc", arg: 1, scope: !6, file: !1, line: 5, type: !9) 109 | !14 = !DIExpression() 110 | !15 = !DILocation(line: 5, column: 14, scope: !6) 111 | !16 = !DILocalVariable(name: "argv", arg: 2, scope: !6, file: !1, line: 5, type: !10) 112 | !17 = !DILocation(line: 5, column: 26, scope: !6) 113 | !18 = !DILocation(line: 7, column: 2, scope: !6) 114 | !19 = !DILocalVariable(name: "x", scope: !6, file: !1, line: 9, type: !20) 115 | !20 = !DIBasicType(name: "double", size: 64, align: 64, encoding: DW_ATE_float) 116 | !21 = !DILocation(line: 9, column: 9, scope: !6) 117 | !22 = !DILocation(line: 10, column: 36, scope: !6) 118 | !23 = !DILocation(line: 10, column: 2, scope: !6) 119 | !24 = !DILocation(line: 12, column: 2, scope: !6) 120 | !25 = !DILocation(line: 14, column: 2, scope: !6) 121 | -------------------------------------------------------------------------------- /test/instrument-everything.ll: -------------------------------------------------------------------------------- 1 | ; \file instrument-everything.ll 2 | ; \brief Tests generic instrumentation of all instructions 3 | ; 4 | ; Commands for llvm-lit: 5 | ; RUN: %loom -S %s -loom-file %s.policy -o %t.instr.ll 6 | ; RUN: %filecheck -input-file %t.instr.ll %s 7 | ; RUN: %llc -filetype=obj %t.instr.ll -o %t.instr.o 8 | 9 | ; ModuleID = 'tmp.c' 10 | source_filename = "tmp.c" 11 | target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" 12 | target triple = "x86_64-unknown-freebsd12.0" 13 | 14 | @.str = private unnamed_addr constant [15 x i8] c"Hello, world!\0A\00", align 1 15 | @.str.1 = private unnamed_addr constant [23 x i8] c"The value of x is: %f\0A\00", align 1 16 | 17 | ; Function Attrs: nounwind uwtable 18 | define i32 @main(i32 %argc, i8** %argv) #0 !dbg !6 { 19 | entry: 20 | ; CHECK: %retval = alloca i32, align 4 21 | %retval = alloca i32, align 4 22 | ; CHECK: xo_emit({{.*}} %retval 23 | 24 | ; CHECK: %argc.addr = alloca i32, align 4 25 | %argc.addr = alloca i32, align 4 26 | ; CHECK: xo_emit({{.*}} %argc.addr 27 | 28 | ; CHECK: %argv.addr = alloca i8**, align 8 29 | %argv.addr = alloca i8**, align 8 30 | ; CHECK: xo_emit({{.*}} %argv.addr 31 | 32 | ; CHECK: %x = alloca double, align 8 33 | %x = alloca double, align 8 34 | ; CHECK: xo_emit({{.*}} %x 35 | 36 | ; CHECK: store i32 0, i32* %retval, align 4 37 | store i32 0, i32* %retval, align 4 38 | ; CHECK: xo_emit({{.*}}i32* %retval 39 | 40 | ; CHECK: store i32 %argc, i32* %argc.addr, align 4 41 | store i32 %argc, i32* %argc.addr, align 4 42 | ; CHECK: xo_emit({{.*}}i32* %argc.addr 43 | 44 | call void @llvm.dbg.declare(metadata i32* %argc.addr, metadata !13, metadata !14), !dbg !15 45 | 46 | ; CHECK: store i8** %argv, i8*** %argv.addr, align 8 47 | store i8** %argv, i8*** %argv.addr, align 8 48 | ; CHECK: xo_emit({{.*}}i8*** %argv.addr 49 | 50 | call void @llvm.dbg.declare(metadata i8*** %argv.addr, metadata !16, metadata !14), !dbg !17 51 | 52 | ; CHECK: %call = call i32 (i8*, ...) @printf 53 | %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.str, i32 0, i32 0)), !dbg !18 54 | ; CHECK: xo_emit({{.*}} %call 55 | 56 | call void @llvm.dbg.declare(metadata double* %x, metadata !19, metadata !14), !dbg !21 57 | 58 | ; CHECK: store double 0x402ABCEF97BFC839, double* %x, align 8, !dbg !20 59 | store double 0x402ABCEF97BFC839, double* %x, align 8, !dbg !21 60 | ; CHECK: xo_emit({{.*}}double* %x 61 | 62 | 63 | ; Note: Unnamed values like this one can be renumbered arbitrarily once we 64 | ; introduce instrumentation (which can itself include unnamed values), 65 | ; so we can't check for a literal %0. Instead, we need to check for 66 | ; consistency between the value name and what we pass to 67 | ; instrumentation. 68 | 69 | ; CHECK: %[[ZERO:[0-9]+]] = load double, double* %x, align 8, !dbg !21 70 | %0 = load double, double* %x, align 8, !dbg !22 71 | ; CHECK: xo_emit({{.*}} %[[ZERO]] 72 | 73 | ; CHECK: %call1 = call i32 (i8*, ...) @printf 74 | %call1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([23 x i8], [23 x i8]* @.str.1, i32 0, i32 0), double %0), !dbg !23 75 | ; CHECK: xo_emit({{.*}} %call1 76 | 77 | ; CHECK: xo_emit({{.*}}, i32 [[BRANCH:2]]) 78 | ; CHECK: br label %foo 79 | br label %foo 80 | 81 | foo: 82 | %call2 = call i32 @xo_finish(), !dbg !24 83 | 84 | ret i32 0, !dbg !25 85 | } 86 | 87 | ; Function Attrs: nounwind readnone 88 | declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 89 | 90 | declare i32 @printf(i8*, ...) #2 91 | 92 | declare i32 @xo_finish() #2 93 | 94 | attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } 95 | attributes #1 = { nounwind readnone } 96 | attributes #2 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } 97 | 98 | !llvm.dbg.cu = !{!0} 99 | !llvm.module.flags = !{!3, !4} 100 | !llvm.ident = !{!5} 101 | 102 | !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 4.0.0 (http://llvm.org/git/clang.git 3f7a1d0a6dedbbff7cdd804e31063c9c33a837ec) (http://llvm.org/git/llvm.git 20014804ba63d479300bb5c136856d11fbc1bdae)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) 103 | !1 = !DIFile(filename: "tmp.c", directory: "/usr/home/jon/CADETS/local/loom/Debug") 104 | !2 = !{} 105 | !3 = !{i32 2, !"Dwarf Version", i32 2} 106 | !4 = !{i32 2, !"Debug Info Version", i32 3} 107 | !5 = !{!"clang version 4.0.0 (http://llvm.org/git/clang.git 3f7a1d0a6dedbbff7cdd804e31063c9c33a837ec) (http://llvm.org/git/llvm.git 20014804ba63d479300bb5c136856d11fbc1bdae)"} 108 | !6 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 5, type: !7, isLocal: false, isDefinition: true, scopeLine: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !2) 109 | !7 = !DISubroutineType(types: !8) 110 | !8 = !{!9, !9, !10} 111 | !9 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) 112 | !10 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !11, size: 64, align: 64) 113 | !11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64, align: 64) 114 | !12 = !DIBasicType(name: "char", size: 8, align: 8, encoding: DW_ATE_signed_char) 115 | !13 = !DILocalVariable(name: "argc", arg: 1, scope: !6, file: !1, line: 5, type: !9) 116 | !14 = !DIExpression() 117 | !15 = !DILocation(line: 5, column: 14, scope: !6) 118 | !16 = !DILocalVariable(name: "argv", arg: 2, scope: !6, file: !1, line: 5, type: !10) 119 | !17 = !DILocation(line: 5, column: 26, scope: !6) 120 | !18 = !DILocation(line: 7, column: 2, scope: !6) 121 | !19 = !DILocalVariable(name: "x", scope: !6, file: !1, line: 9, type: !20) 122 | !20 = !DIBasicType(name: "double", size: 64, align: 64, encoding: DW_ATE_float) 123 | !21 = !DILocation(line: 9, column: 9, scope: !6) 124 | !22 = !DILocation(line: 10, column: 36, scope: !6) 125 | !23 = !DILocation(line: 10, column: 2, scope: !6) 126 | !24 = !DILocation(line: 12, column: 2, scope: !6) 127 | !25 = !DILocation(line: 14, column: 2, scope: !6) 128 | -------------------------------------------------------------------------------- /src/DebugInfo.hh: -------------------------------------------------------------------------------- 1 | //! @file DebugInfo.hh Declaration of DebugInfo class. 2 | /* 3 | * Copyright (c) 2016 Jonathan Anderson 4 | * All rights reserved. 5 | * 6 | * This software was developed by BAE Systems, the University of Cambridge 7 | * Computer Laboratory, and Memorial University under DARPA/AFRL contract 8 | * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing 9 | * (TC) research program. 10 | * 11 | * Copyright (c) 2018 Stephen Lee 12 | * All rights reserved. 13 | * 14 | * This software was developed by SRI International, Purdue University, 15 | * University of Wisconsin and University of Georgia under DARPA/AFRL 16 | * contract FA8650-15-C-7562 ("TRACE"), as part of the DARPA Transparent 17 | * Computing (TC) research program. 18 | * 19 | * Redistribution and use in source and binary forms, with or without 20 | * modification, are permitted provided that the following conditions 21 | * are met: 22 | * 1. Redistributions of source code must retain the above copyright 23 | * notice, this list of conditions and the following disclaimer. 24 | * 2. Redistributions in binary form must reproduce the above copyright 25 | * notice, this list of conditions and the following disclaimer in the 26 | * documentation and/or other materials provided with the distribution. 27 | * 28 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 29 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 32 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 | * SUCH DAMAGE. 39 | */ 40 | 41 | #ifndef LOOM_DEBUG_INFO_H 42 | #define LOOM_DEBUG_INFO_H 43 | 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | 51 | namespace llvm { 52 | class GetElementPtrInst; 53 | } 54 | 55 | namespace loom { 56 | 57 | /// Class for finding LLVM debug information within a Module. 58 | class DebugInfo { 59 | public: 60 | /// A single LLVM metadata node, with an integer metadata "kind". 61 | typedef std::pair DebugNode; 62 | 63 | /// A vector of metadata nodes associated with a Value. 64 | template 65 | using DebugVec = llvm::SmallVector; 66 | 67 | DebugInfo(llvm::Module &); 68 | 69 | bool ModuleHasFullDebugInfo() const; 70 | 71 | /// Find the name of a field being looked up by a GetElementPtrInst. 72 | std::string FieldName(llvm::GetElementPtrInst *); 73 | 74 | template 75 | const DebugType *Get(llvm::NamedMDNode *Node) const { 76 | for (auto *MD : Node->operands()) { 77 | if (auto *DebugInfo = llvm::dyn_cast(MD)) { 78 | return DebugInfo; 79 | } 80 | } 81 | 82 | return nullptr; 83 | } 84 | 85 | template 86 | const DebugType *Get(llvm::Value *V) const { 87 | if (auto *I = llvm::dyn_cast(V)) { 88 | llvm::SmallVector Debug; 89 | I->getAllMetadata(Debug); 90 | 91 | for (auto i : Debug) { 92 | if (auto *DebugInfo = llvm::dyn_cast(i.second)) { 93 | return DebugInfo; 94 | } 95 | } 96 | } 97 | 98 | auto i = DbgDecls.find(V); 99 | if (i != DbgDecls.end()) { 100 | for (auto *MD : i->second) { 101 | if (auto *DebugInfo = llvm::dyn_cast(MD)) { 102 | return DebugInfo; 103 | } 104 | } 105 | } 106 | 107 | /* auto j = DbgValues.find(V); 108 | if (j != DbgValues.end()) { 109 | for (auto *MD : j->second) { 110 | if (auto *DebugInfo = llvm::dyn_cast(MD)) { 111 | return DebugInfo; 112 | } 113 | } 114 | } // */ 115 | 116 | return nullptr; 117 | } 118 | 119 | const llvm::DIVariable *GetGlobalDIVariable(llvm::GlobalVariable *G) { 120 | // llvm::errs() << "In Get< GlobalVariable\n"; 121 | // DebugNode is defined above 122 | llvm::SmallVector Debug; 123 | G->getAllMetadata(Debug); 124 | 125 | llvm::DIVariable *result = nullptr; 126 | 127 | for (auto i : Debug) { 128 | if (auto *DebugInfo = llvm::dyn_cast(i.second)) { 129 | // llvm::errs() << "Returning from Get<\n"; 130 | result = DebugInfo; 131 | break; 132 | } 133 | 134 | if (auto *DebugInfo = 135 | llvm::dyn_cast(i.second)) { 136 | result = DebugInfo->getVariable(); 137 | } 138 | } 139 | 140 | return result; 141 | } 142 | 143 | private: 144 | /** 145 | * Trace from a GetElementPtrInst representing a structure field lookup 146 | * back to a variable that has a DIVariable debug metadata node. 147 | * 148 | * The result is a DIVariable for the variable with debug information and 149 | * a vector that of GEP offsets, representing how we got to a variable from 150 | * the GEP of interest. Together, these can be used to work forwards again 151 | * from the DIVariable to a field name in the current GEP. 152 | * 153 | * @param[in] GEP the structure field lookup to trace 154 | * @param[out] Offsets the vector to fill with GEP offsets 155 | * 156 | * @returns debug metadata for the variable we found 157 | */ 158 | const llvm::DIVariable *Trace(llvm::GetElementPtrInst *GEP, 159 | llvm::SmallVectorImpl &Offsets); 160 | 161 | llvm::Module &Mod; 162 | llvm::Function *DbgDeclare; 163 | llvm::Function *DbgValue; 164 | 165 | /// Kinds of metadata that are used in this module. 166 | llvm::SmallVector MetadataKinds; 167 | 168 | /// Declarations of metadata, i.e., metadata from `@llvm.db.declare()` calls. 169 | llvm::ValueMap> 170 | DbgDecls; 171 | /// Declarations of metadata, i.e., metadata from `@llvm.db.value()` calls. 172 | llvm::ValueMap> 173 | DbgValues; 174 | }; 175 | 176 | } // namespace loom 177 | 178 | #endif // LOOM_DEBUG_INFO_H 179 | -------------------------------------------------------------------------------- /src/DebugInfo.cc: -------------------------------------------------------------------------------- 1 | //! @file DebugInfo.cc Definition of DebugInfo class. 2 | /* 3 | * Copyright (c) 2016 Jonathan Anderson 4 | * All rights reserved. 5 | * 6 | * This software was developed by BAE Systems, the University of Cambridge 7 | * Computer Laboratory, and Memorial University under DARPA/AFRL contract 8 | * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing 9 | * (TC) research program. 10 | * 11 | * Copyright (c) 2018 Stephen Lee 12 | * All rights reserved. 13 | * 14 | * This software was developed by SRI International, Purdue University, 15 | * University of Wisconsin and University of Georgia under DARPA/AFRL 16 | * contract FA8650-15-C-7562 ("TRACE"), as part of the DARPA Transparent 17 | * Computing (TC) research program. 18 | * 19 | * Redistribution and use in source and binary forms, with or without 20 | * modification, are permitted provided that the following conditions 21 | * are met: 22 | * 1. Redistributions of source code must retain the above copyright 23 | * notice, this list of conditions and the following disclaimer. 24 | * 2. Redistributions in binary form must reproduce the above copyright 25 | * notice, this list of conditions and the following disclaimer in the 26 | * documentation and/or other materials provided with the distribution. 27 | * 28 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 29 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 32 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 | * SUCH DAMAGE. 39 | */ 40 | 41 | #include "DebugInfo.hh" 42 | 43 | #include 44 | #include 45 | #include 46 | #include 47 | 48 | using namespace llvm; 49 | using namespace loom; 50 | 51 | DebugInfo::DebugInfo(llvm::Module &M) 52 | : Mod(M), DbgDeclare(Mod.getFunction("llvm.dbg.declare")), 53 | DbgValue(Mod.getFunction("llvm.dbg.value")) { 54 | Mod.getMDKindNames(MetadataKinds); 55 | 56 | if (DbgDeclare) { 57 | // Examine all calls to @llvm.dbg.declare() to find metadata: 58 | for (auto &Use : DbgDeclare->uses()) { 59 | auto *Dbg = dyn_cast(Use.getUser()); 60 | assert(Dbg && "call to llvm.dbg.declare must be a DbgDeclareInst"); 61 | DbgDecls[Dbg->getAddress()].push_back(Dbg->getVariable()); 62 | } 63 | } 64 | 65 | if (DbgValue) { 66 | // Examine all calls to @llvm.dbg.value() to find metadata: 67 | for (auto &Use : DbgValue->uses()) { 68 | auto *Dbg = dyn_cast(Use.getUser()); 69 | assert(Dbg && "call to llvm.dbg.value must be a DbgValueInst"); 70 | } 71 | } 72 | } 73 | 74 | bool DebugInfo::ModuleHasFullDebugInfo() const { 75 | if (not DbgDeclare) 76 | return false; 77 | 78 | auto *ModuleMetadata = Mod.getNamedMetadata("llvm.dbg.cu"); 79 | if (not ModuleMetadata) 80 | return false; 81 | 82 | if (auto *DI = Get(ModuleMetadata)) { 83 | constexpr auto FullDebug = DICompileUnit::DebugEmissionKind::FullDebug; 84 | 85 | return DI->getEmissionKind() == FullDebug and not DI->isOptimized(); 86 | } 87 | 88 | return false; 89 | } 90 | 91 | std::string DebugInfo::FieldName(GetElementPtrInst *GEP) { 92 | // Trace back to a variable with debug metadata. 93 | SmallVector GEPOffsets; 94 | const DIVariable *Var = Trace(GEP, GEPOffsets); 95 | if (Var == nullptr) { 96 | errs() << "WARNING: unable to trace GEP "; 97 | GEP->print(errs(), true); 98 | errs() << " back to a variable\n"; 99 | 100 | return ""; 101 | } 102 | 103 | const DIType *T = dyn_cast(Var->getType()); 104 | assert(T && "DIVariable::getType() should return a DIType"); 105 | 106 | do { 107 | switch (T->getTag()) { 108 | case dwarf::DW_TAG_array_type: { 109 | auto *CT = dyn_cast(T); 110 | T = dyn_cast(CT->getBaseType()); 111 | break; 112 | } 113 | 114 | case dwarf::DW_TAG_pointer_type: { 115 | auto *DT = dyn_cast(T); 116 | T = dyn_cast(DT->getBaseType()); 117 | break; 118 | } 119 | 120 | case dwarf::DW_TAG_structure_type: { 121 | assert(not GEPOffsets.empty()); 122 | 123 | size_t Index = GEPOffsets.back(); 124 | GEPOffsets.pop_back(); 125 | 126 | auto *CT = dyn_cast(T); 127 | auto *Member = dyn_cast(CT->getElements()[Index]); 128 | 129 | if (GEPOffsets.empty()) { 130 | return Member->getName().str(); 131 | } else { 132 | T = dyn_cast(Member->getBaseType()); 133 | } 134 | 135 | break; 136 | } 137 | 138 | case dwarf::DW_TAG_typedef: { 139 | auto *DT = dyn_cast(T); 140 | T = dyn_cast(DT->getBaseType()); 141 | break; 142 | } 143 | 144 | default: 145 | errs() << "ERROR: unhandled debug info tag: " << T->getTag() << "\n"; 146 | T->print(errs(), GEP->getModule()); 147 | errs() << " tag\n"; 148 | 149 | return ""; 150 | } 151 | 152 | } while (T); 153 | 154 | return ""; 155 | } 156 | 157 | const DIVariable *DebugInfo::Trace(GetElementPtrInst *GEP, 158 | SmallVectorImpl &Offsets) { 159 | 160 | // Walk backwards from GEP to source until we find a variable with 161 | // debug metadata (or die trying, having reached the end of the GEP chain). 162 | do { 163 | // If GEP'ing the address of a structure field, track which field 164 | // index we are working with. 165 | if (isa(GEP->getSourceElementType()) and 166 | GEP->getNumIndices() == 2) { 167 | 168 | Value *Index = GEP->idx_begin()[1]; 169 | 170 | auto *ConstIdx = dyn_cast(Index); 171 | assert(ConstIdx && "struct field indexing must be static"); 172 | Offsets.push_back(ConstIdx->getLimitedValue()); 173 | } 174 | 175 | Value *Ptr = GEP->getPointerOperand()->stripPointerCasts(); 176 | if (auto *Var = Get(Ptr)) { 177 | return Var; 178 | } 179 | 180 | if (auto *Load = dyn_cast(Ptr)) { 181 | while (Load != nullptr) { 182 | Ptr = Load->getPointerOperand(); 183 | Load = dyn_cast(Ptr); 184 | } 185 | } 186 | 187 | if (auto *G = llvm::dyn_cast(Ptr)) { 188 | if (auto *Var = GetGlobalDIVariable(G)) { 189 | return Var; 190 | } 191 | } 192 | 193 | GEP = dyn_cast(Ptr); 194 | } while (GEP != nullptr); 195 | 196 | return nullptr; 197 | } 198 | -------------------------------------------------------------------------------- /src/Instrumenter.hh: -------------------------------------------------------------------------------- 1 | //! @file Instrumenter.hh Declaration of @ref loom::Instrumenter. 2 | /* 3 | * Copyright (c) 2016 Jonathan Anderson 4 | * Copyright (c) 2018 Brian Kidney 5 | * All rights reserved. 6 | * 7 | * This software was developed by BAE Systems, the University of Cambridge 8 | * Computer Laboratory, and Memorial University under DARPA/AFRL contract 9 | * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing 10 | * (TC) research program. 11 | * 12 | * Copyright (c) 2018 Stephen Lee 13 | * All rights reserved. 14 | * 15 | * This software was developed by SRI International, Purdue University, 16 | * University of Wisconsin and University of Georgia under DARPA/AFRL 17 | * contract FA8650-15-C-7562 ("TRACE"), as part of the DARPA Transparent 18 | * Computing (TC) research program. 19 | * 20 | * Redistribution and use in source and binary forms, with or without 21 | * modification, are permitted provided that the following conditions 22 | * are met: 23 | * 1. Redistributions of source code must retain the above copyright 24 | * notice, this list of conditions and the following disclaimer. 25 | * 2. Redistributions in binary form must reproduce the above copyright 26 | * notice, this list of conditions and the following disclaimer in the 27 | * documentation and/or other materials provided with the distribution. 28 | * 29 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 30 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 31 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 32 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 33 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 34 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 35 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 36 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 37 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 38 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 39 | * SUCH DAMAGE. 40 | */ 41 | 42 | #ifndef LOOM_INSTRUMENTER_H_ 43 | #define LOOM_INSTRUMENTER_H_ 44 | 45 | #include "Instrumentation.hh" 46 | #include "Policy.hh" 47 | 48 | #include 49 | 50 | namespace loom { 51 | 52 | class InstrStrategy; 53 | 54 | /// An object used for instrumenting code within a single LLVM module. 55 | class Instrumenter { 56 | public: 57 | /** 58 | * A @ref NameFn takes an ordered collection of name components (e.g., 59 | * `"call"`, `"fn"`, `"foo"`) and converts it into a name that can 60 | * be used for instrumentation (e.g., `"__tesla_call_fn_foo"`). 61 | */ 62 | typedef std::function &)> NameFn; 63 | 64 | /** 65 | * Create a new Instrumenter instance. 66 | * 67 | * @param NF a function that can be called to name instrumentation 68 | * (e.g., ["call","foo"] => "__loom_hook_call_foo") 69 | */ 70 | static std::unique_ptr Create(llvm::Module &, NameFn NF, 71 | std::unique_ptr); 72 | 73 | /// Instrument an instruction generically: instruction name and values. 74 | bool Instrument(llvm::Instruction *, Metadata = Metadata(), std::vector = std::vector()); 75 | 76 | /// Instrument an instruction generically with better info: instruction type 77 | /// and values. 78 | bool InstrumentPtrInsts(llvm::Instruction *, const llvm::DIVariable *, 79 | Metadata = Metadata(), std::vector = std::vector()); 80 | 81 | /// Instrument a function call in the call and/or return direction. 82 | bool Instrument(llvm::CallInst *, const Policy::Directions &, 83 | Metadata = Metadata(), std::vector = std::vector()); 84 | 85 | /// Instrument a function call (caller-side), either calling or returning. 86 | bool Instrument(llvm::CallInst *Call, Policy::Direction, 87 | Metadata = Metadata(), std::vector = std::vector()); 88 | 89 | /// Instrument a function entry and/or exit. 90 | bool Instrument(llvm::Function &, const Policy::Directions &, 91 | Metadata = Metadata(), std::vector = std::vector()); 92 | 93 | /// Instrument a function entry or exit. 94 | bool Instrument(llvm::Function &, Policy::Direction, 95 | Metadata = Metadata(), std::vector = std::vector()); 96 | 97 | /// Instrument a read from a structure field. 98 | bool Instrument(llvm::GetElementPtrInst *, llvm::LoadInst *, 99 | llvm::StringRef FieldName, Metadata = Metadata(), std::vector = std::vector()); 100 | 101 | /// Instrument a write to a structure field. 102 | bool Instrument(llvm::GetElementPtrInst *, llvm::StoreInst *, 103 | llvm::StringRef FieldName, Metadata = Metadata(), std::vector = std::vector()); 104 | 105 | /// Add initialization required by Loggers 106 | bool InitializeLoggers(llvm::Function &); 107 | 108 | //! Where parameters can be added to a function's parameter list. 109 | enum class ParamPosition { Beginning, End }; 110 | 111 | /** 112 | * Adapt a function call to use a function with an extended API. 113 | * 114 | * This is helpful for converting code that uses an existing API to use 115 | * an extended version of the same function with additional metadata. 116 | * This is an alternative to run-time linker tricks such as LD_PRELOAD. 117 | * 118 | * This method can only be used to extend function calls by adding additional 119 | * arguments at the beginning or the end of the parameter list: all of the 120 | * original arguments will still be passed and the return value will not 121 | * be modified. 122 | * 123 | * @param Call the original function call: will be replaced with a 124 | * call to the new, extended function 125 | * @param NewName the name of the new, extended function 126 | * @param NewArgs the arguments to be added to the call 127 | * @param Position where the new parameters should be added 128 | */ 129 | llvm::CallInst *Extend(llvm::CallInst *Call, llvm::StringRef NewName, 130 | llvm::ArrayRef NewArgs, 131 | ParamPosition Position = ParamPosition::End); 132 | 133 | bool ReplaceCall(llvm::CallInst *Call, llvm::StringRef NewCall); 134 | bool DeleteInst(llvm::Instruction *Inst); 135 | 136 | llvm::Module &getModule() { return Mod; } 137 | 138 | private: 139 | Instrumenter(llvm::Module &, NameFn NF, std::unique_ptr); 140 | 141 | Instrumentation &GetOrCreateInstr(llvm::StringRef Name, 142 | llvm::StringRef FormatStringPrefix, 143 | const ParamVec &); 144 | 145 | uint32_t FieldNumber(llvm::GetElementPtrInst *); 146 | 147 | llvm::Module &Mod; 148 | std::unique_ptr Strategy; 149 | llvm::StringMap> Instr; 150 | NameFn Name; 151 | }; 152 | 153 | } // namespace loom 154 | 155 | #endif // LOOM_INSTRUMENTER_H_ 156 | -------------------------------------------------------------------------------- /src/Logger.hh: -------------------------------------------------------------------------------- 1 | //! @file Logger.hh Declaration of @ref loom::Logger. 2 | /* 3 | * Copyright (c) 2016-2017 Jonathan Anderson 4 | * All rights reserved. 5 | * 6 | * This software was developed by BAE Systems, the University of Cambridge 7 | * Computer Laboratory, and Memorial University under DARPA/AFRL contract 8 | * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing 9 | * (TC) research program. 10 | * 11 | * Redistribution and use in source and binary forms, with or without 12 | * modification, are permitted provided that the following conditions 13 | * are met: 14 | * 1. Redistributions of source code must retain the above copyright 15 | * notice, this list of conditions and the following disclaimer. 16 | * 2. Redistributions in binary form must reproduce the above copyright 17 | * notice, this list of conditions and the following disclaimer in the 18 | * documentation and/or other materials provided with the distribution. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 | * SUCH DAMAGE. 31 | */ 32 | 33 | #ifndef LOOM_LOGGER_H 34 | #define LOOM_LOGGER_H 35 | 36 | #include "IRUtils.hh" 37 | #include "Metadata.hh" 38 | #include "Transform.hh" 39 | 40 | #include 41 | 42 | #include 43 | 44 | namespace llvm { 45 | class Function; 46 | class FunctionType; 47 | class Module; 48 | class Value; 49 | } // namespace llvm 50 | 51 | namespace loom { 52 | 53 | /// Something that can be used to log events, e.g., `printf` or `libxo`. 54 | class Logger { 55 | public: 56 | virtual ~Logger(); 57 | 58 | /** 59 | * Create code to log a set of values using the underlying mechanism. 60 | * 61 | * @param I Insertion point for the logging code 62 | * @param Values Values to log 63 | * @param Name Machine-readable name of the logged event 64 | * (may not be used by all Logger types) 65 | * @param Description Short, human-readable event description 66 | * (may not be used by all Logger types) 67 | * @param SuppressUniqueness Suppress uniqueness among format strings 68 | * to the extent possible (e.g., for libxo, which allows 69 | * values' names to be specified as well as types). 70 | * 71 | * @returns the last instruction (if any) in the generated instrumentation 72 | */ 73 | virtual llvm::Value *Log(llvm::Instruction *I, 74 | llvm::ArrayRef Values, 75 | llvm::StringRef Name, llvm::StringRef Description, 76 | Metadata Metadata, std::vector Transforms, 77 | bool SuppressUniqueness) = 0; 78 | 79 | virtual bool HasInitialization(); 80 | 81 | virtual llvm::Value *Initialize(llvm::Function &Main); 82 | 83 | protected: 84 | Logger(llvm::Module &Mod) : Mod(Mod) {} 85 | 86 | //! The module being instrumented: where to find functions like xo_emit(). 87 | llvm::Module &Mod; 88 | }; 89 | 90 | /// A logging technique that requires a single call to a printf-like function 91 | class SimpleLogger : public Logger { 92 | public: 93 | /// Types of simple loggers. 94 | enum class LogType { 95 | 96 | /// The libc printf() function, but treating all u8 pointers as char* 97 | UnsafePrintf, 98 | 99 | /// The libc printf() function 100 | Printf, 101 | 102 | /// Juniper's libxo, which generates text or structured output 103 | Libxo, 104 | 105 | /// Do not log anything 106 | None, 107 | }; 108 | 109 | /// Create a new Logger of the specified type (`printf`, `libxo`, etc.). 110 | static std::unique_ptr Create(llvm::Module &, 111 | LogType Log = LogType::Printf); 112 | 113 | virtual llvm::Value *Log(llvm::Instruction *I, 114 | llvm::ArrayRef Values, 115 | llvm::StringRef Name, llvm::StringRef Description, 116 | Metadata Metadata, std::vector Transforms, 117 | bool SuppressUniqueness) override; 118 | 119 | /// Log a set of values, with optional prefix and suffix text. 120 | llvm::CallInst *Call(llvm::IRBuilder<> &, llvm::StringRef FormatStringPrefix, 121 | llvm::ArrayRef Values, 122 | llvm::StringRef Suffix, Metadata Metadata, 123 | std::vector Transforms, 124 | bool SuppressUniqueness = false); 125 | 126 | protected: 127 | SimpleLogger(llvm::Module &Mod) : Logger(Mod) {} 128 | 129 | /// Get (or create) declaration for the logging function. 130 | llvm::Function *GetFunction(); 131 | 132 | /// Get the name of the logging function. 133 | virtual llvm::StringRef FunctionName() const = 0; 134 | 135 | /// Get the type of the logging function, often `int (const char*, ...)`. 136 | virtual llvm::FunctionType *GetType(); 137 | 138 | /// Create a format string that we can pass to the logging function. 139 | virtual llvm::Value * 140 | CreateFormatString(llvm::IRBuilder<> &, llvm::StringRef Prefix, 141 | llvm::ArrayRef, llvm::StringRef Suffix, 142 | Metadata Metadata, bool SuppressUniqueness) = 0; 143 | 144 | /** 145 | * Adapt a set of values into a form that can be logged. 146 | * 147 | * Before values can be passed to a logging function, they may need to be 148 | * adapted to a suitable form. For example, `float` values may need to be 149 | * extended into `double` values or aggregates (e.g., `struct` values) 150 | * may need to be expanded into their constituent parts. Some logging schemes 151 | * may require that all values be bundled into an aggregate type, e.g., a 152 | * structured key-value list. 153 | * 154 | * This function adapts values as necessary and returns a vector of 155 | * possibly-adapted values. In the best case, nothing requires adaptation, 156 | * the IRBuilder is not used and the original values are returned. 157 | * In the worse case, everything requires adaptation and all of the values in 158 | * the returned vector will be new, derived from the originals using the 159 | * supplied IRBuilder. 160 | * 161 | * @returns a vector of possibly-adapted values 162 | */ 163 | virtual std::vector Adapt(llvm::ArrayRef, 164 | llvm::IRBuilder<> &); 165 | 166 | //! A cache of already-generated format strings. 167 | llvm::StringMap FormatStrings; 168 | }; 169 | 170 | } // namespace loom 171 | 172 | #endif // !LOOM_LOGGER_H 173 | -------------------------------------------------------------------------------- /src/Policy.hh: -------------------------------------------------------------------------------- 1 | //! @file Policy.hh Definition of @ref loom::Policy. 2 | /* 3 | * Copyright (c) 2015-2017 Jonathan Anderson 4 | * All rights reserved. 5 | * 6 | * This software was developed by BAE Systems, the University of Cambridge 7 | * Computer Laboratory, and Memorial University under DARPA/AFRL contract 8 | * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing 9 | * (TC) research program. 10 | * 11 | * Copyright (c) 2018 Stephen Lee 12 | * All rights reserved. 13 | * 14 | * This software was developed by SRI International, Purdue University, 15 | * University of Wisconsin and University of Georgia under DARPA/AFRL 16 | * contract FA8650-15-C-7562 ("TRACE"), as part of the DARPA Transparent 17 | * Computing (TC) research program. 18 | * 19 | * Redistribution and use in source and binary forms, with or without 20 | * modification, are permitted provided that the following conditions 21 | * are met: 22 | * 1. Redistributions of source code must retain the above copyright 23 | * notice, this list of conditions and the following disclaimer. 24 | * 2. Redistributions in binary form must reproduce the above copyright 25 | * notice, this list of conditions and the following disclaimer in the 26 | * documentation and/or other materials provided with the distribution. 27 | * 28 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 29 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 32 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 | * SUCH DAMAGE. 39 | */ 40 | 41 | #ifndef LOOM_POLICY_H 42 | #define LOOM_POLICY_H 43 | 44 | #include "InstrStrategy.hh" 45 | #include "Serializer.hh" 46 | #include "Metadata.hh" 47 | #include "Transform.hh" 48 | 49 | #include 50 | #include 51 | #include 52 | 53 | namespace llvm { 54 | class Function; 55 | class StructType; 56 | } // namespace llvm 57 | 58 | namespace loom { 59 | 60 | /** 61 | * An instrumentation policy tells us what things to instrument and in 62 | * which direction (e.g., call vs return). 63 | */ 64 | 65 | class Policy { 66 | public: 67 | virtual ~Policy(); 68 | 69 | /** 70 | * The instrumentation strategy that should be employed by this pass. 71 | * 72 | * This is currently a pass-level decision, but in the future we may want to 73 | * employ different strategies for different types of instrumentation within 74 | * a single module. 75 | */ 76 | virtual InstrStrategy::Kind Strategy() const = 0; 77 | 78 | //! Create all loggers required by the policy. 79 | virtual std::vector> Loggers(llvm::Module &) const; 80 | 81 | //! Simple (non-serializing) logging. 82 | virtual SimpleLogger::LogType Logging() const = 0; 83 | 84 | //! Ways that we can use KTrace (or not). 85 | enum class KTraceTarget { Kernel, Userspace, None }; 86 | 87 | //! Should we use ktrace logging? 88 | virtual KTraceTarget KTrace() const = 0; 89 | 90 | //! Ways that we can use DTrace (or not). 91 | enum class DTraceTarget { Userspace, None }; 92 | 93 | //! Should we use ktrace logging? 94 | virtual DTraceTarget DTrace() const = 0; 95 | 96 | 97 | //! How should we serialize data? 98 | virtual std::unique_ptr Serialization(llvm::Module &) const = 0; 99 | 100 | /** 101 | * Create instrumentation within BasicBlocks, making the structure of the 102 | * instrumentation clearer but more complex. 103 | */ 104 | virtual bool UseBlockStructure() const = 0; 105 | 106 | //! Special case: instrument every single function. 107 | virtual bool InstrumentAll() const = 0; 108 | 109 | //! Special case: instrument all load, store, and GEP instructions. 110 | virtual bool InstrumentPointerInsts() const = 0; 111 | 112 | //! A direction that we can instrument: on the way in or on the way out. 113 | enum class Direction { In, Out }; 114 | 115 | //! A set of directions that we might like to instrument something on. 116 | typedef std::vector Directions; 117 | 118 | //! In which directions should calls to a function be instrumented? 119 | virtual Directions CallHooks(const llvm::Function &) const = 0; 120 | 121 | //! Should a call be replaced? 122 | virtual std::string ReplaceCall(const llvm::Function &) const = 0; 123 | 124 | virtual std::string ReplaceDAG(const llvm::Function &Fn) const = 0; 125 | 126 | virtual std::queue DAGTail(const llvm::Function &Fn) const = 0; 127 | 128 | //! In which directions (preamble/return) should a function be instrumented? 129 | virtual Directions FnHooks(const llvm::Function &) const = 0; 130 | 131 | //! Return any metadata defined for an instruction 132 | virtual Metadata InstrMetadata(const llvm::Function &Fn) const = 0; 133 | 134 | //! Return any transforms defined for an instruction 135 | virtual std::vector InstrTransforms(const llvm::Function &Fn) const = 0; 136 | 137 | /** 138 | * A structure type is relevant in some way to instrumentation. 139 | * 140 | * Since the process of iterating over debug metadata can be expensive, 141 | * this method allows a policy to express which structure types are to be 142 | * instrumented in any way. 143 | */ 144 | virtual bool StructTypeMatters(const llvm::StructType &) const = 0; 145 | 146 | /** 147 | * Should a read from a structure field be instrumented? 148 | * 149 | * @param T the type of the structure being read from 150 | * @param Field the field being read from within the structure 151 | */ 152 | virtual bool FieldReadHook(const llvm::StructType &T, 153 | llvm::StringRef Field) const = 0; 154 | 155 | /** 156 | * Should a write to a structure field be instrumented? 157 | * 158 | * @param T the type of the structure being written to 159 | * @param Field the field being written to within the structure 160 | */ 161 | virtual bool FieldWriteHook(const llvm::StructType &T, 162 | llvm::StringRef Field) const = 0; 163 | 164 | /** 165 | * A global value is relevant in some way to instrumentation. 166 | * 167 | * Since the process of iterating over debug metadata can be expensive, 168 | * this method allows a policy to express which global values are to be 169 | * instrumented in any way. 170 | */ 171 | virtual bool GlobalValueMatters(const llvm::Value &) const = 0; 172 | 173 | /** 174 | * Should a read from a global variable be instrumented? 175 | * 176 | * @param V the value of the global being read from 177 | */ 178 | virtual bool GlobalReadHook(const llvm::Value &V) const = 0; 179 | 180 | /** 181 | * Should a write to a gloabl variable be instrumented? 182 | * 183 | * @param V the value of the global being written to 184 | */ 185 | virtual bool GlobalWriteHook(const llvm::Value &V) const = 0; 186 | 187 | //! Name an instrumentation function for a particular event type. 188 | virtual std::string 189 | InstrName(const std::vector &Components) const = 0; 190 | }; 191 | 192 | } // namespace loom 193 | 194 | #endif /* LOOM_POLICY_H */ 195 | -------------------------------------------------------------------------------- /src/InstrStrategy.hh: -------------------------------------------------------------------------------- 1 | //! @file InstrStrategy.hh Declaration of @ref loom::InstrStrategy. 2 | /* 3 | * Copyright (c) 2016-2017 Jonathan Anderson 4 | * All rights reserved. 5 | * 6 | * This software was developed by BAE Systems, the University of Cambridge 7 | * Computer Laboratory, and Memorial University under DARPA/AFRL contract 8 | * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing 9 | * (TC) research program, as well as at Memorial University under the 10 | * NSERC Discovery program (RGPIN-2015-06048). 11 | * 12 | * Redistribution and use in source and binary forms, with or without 13 | * modification, are permitted provided that the following conditions 14 | * are met: 15 | * 1. Redistributions of source code must retain the above copyright 16 | * notice, this list of conditions and the following disclaimer. 17 | * 2. Redistributions in binary form must reproduce the above copyright 18 | * notice, this list of conditions and the following disclaimer in the 19 | * documentation and/or other materials provided with the distribution. 20 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 | * SUCH DAMAGE. 32 | */ 33 | 34 | #ifndef LOOM_INSTR_STRATEGY_H 35 | #define LOOM_INSTR_STRATEGY_H 36 | 37 | #include 38 | 39 | #include 40 | #include 41 | 42 | #include "IRUtils.hh" 43 | #include "Logger.hh" 44 | 45 | namespace llvm { 46 | class Instruction; 47 | } 48 | 49 | namespace loom { 50 | 51 | class Instrumentation; 52 | 53 | //! An instrumentation strategy (inline, callout, etc.). 54 | class InstrStrategy { 55 | public: 56 | enum class Kind { 57 | Callout, //!< Call out to a user-defined instrumentation function. 58 | Inline, //!< Add instrumentation inline with the instrumented code. 59 | }; 60 | 61 | virtual ~InstrStrategy(); 62 | 63 | /** 64 | * Create a new instrumentation strategy (callout, inline, etc.). 65 | * 66 | * @param K Which instrumentation approach to take. 67 | * @param UseBlocks Use BasicBlock-based internal structure for 68 | * instrumentation in order to expose the control flow 69 | * among [potentially] different instrumentation actions 70 | * very explicit. This is the old behaviour from TESLA. 71 | * The alternative (if UseBlocks is false) is to generate 72 | * a stream of instructions. 73 | */ 74 | static std::unique_ptr Create(Kind K, bool UseBlocks); 75 | 76 | //! Add another @ref Logger to the instrumentation we generate. 77 | void AddLogger(std::unique_ptr); 78 | 79 | /** 80 | * Instrument a particular instruction, returning an @ref Instrumentation 81 | * object that can be used to create actions. 82 | * 83 | * @param I The instruction to instrument. 84 | * @param Name The name of the instrumentation to create/find. 85 | * This name will be incorporated in the name of the 86 | * instrumentation function or inline BasicBlock(s), 87 | * so it should be unique to the desired instrumentation 88 | * (e.g., `"__loom_returnfrom_foo"`). 89 | * @param Description A human-readable short description of the 90 | * instrumentation for logging, etc., e.g., `"call foo"`. 91 | * @param Params Static description (names and types) of the values 92 | * that will be passed to the instrumentation. 93 | * @param Values Dynamic values to pass to the instrumentation. 94 | * Must agree in number and type with @b Params and 95 | * @b VarArgs, but may be named differently (e.g., when 96 | * instrumenting function calls, the parameters and 97 | * arguments may have different names). 98 | * @param Metadata Additional metadata about the instrumented function. 99 | * @param VarArgs The instrumentation should accept varargs after the 100 | * explicitly-defined @b Params. 101 | * @param AfterInst If true, apply the instrumentation *after* the 102 | * instruction rather than, as by default, before it. 103 | * @param SuppressUniqueness Suppress, to the extent possible, uniqueness 104 | * among constants (e.g., format strings) generated in 105 | * support of instrumentation instances. For example, 106 | * libxo format strings can be generated with names for 107 | * each argument: this flag suppresses such detail. 108 | * This may be necessary when generating great quantities 109 | * of instrumentation (e.g., using `everything`). 110 | * 111 | * Example of simple Function Boundary Tracing (where the @b Params and 112 | * @b Values come from the same place, the target function's parameters): 113 | * 114 | * ```cpp 115 | * Function *Target = // the function you want to instrument 116 | * vector Params = // get from Target->getArgumentList() 117 | * vector Values = // get from Target->getArgumentList() 118 | * Instruction *Start = &Target->getBasicBlockList().front().front(); 119 | * 120 | * Strategy->Instrument(Start, "__foo_hook_fn_" + Target->getName(), 121 | * "calling " + Target->getName(), Params, Values, 122 | * Target->isVarArg()); 123 | * ``` 124 | */ 125 | virtual Instrumentation 126 | Instrument(llvm::Instruction *I, llvm::StringRef Name, 127 | llvm::StringRef Description, llvm::ArrayRef Params, 128 | llvm::ArrayRef Values, 129 | Metadata Md, std::vector Tf, bool VarArgs = false, 130 | bool AfterInst = false, bool SuppressUniqueness = false) = 0; 131 | 132 | bool Initialize(llvm::Function &main); 133 | 134 | protected: 135 | InstrStrategy(bool UseBlocks) : UseBlockStructure(UseBlocks) {} 136 | 137 | /** 138 | * Add code to instrumentation preamble that will log the instrumented values 139 | * via all of our Logger objects. 140 | * 141 | * @returns the last instruction of the added logging code (or I if none) 142 | */ 143 | llvm::Value *AddLogging(llvm::Instruction *I, llvm::ArrayRef, 144 | llvm::StringRef Name, llvm::StringRef Description, 145 | Metadata Md, std::vector Tf, bool SuppressUniqueness); 146 | 147 | /** 148 | * Use an explicit structure of premable/instrumentation/end BasicBlocks 149 | * when creating instrumentation. 150 | */ 151 | const bool UseBlockStructure; 152 | 153 | private: 154 | std::vector> Loggers; 155 | }; 156 | 157 | } // namespace loom 158 | 159 | #endif 160 | -------------------------------------------------------------------------------- /doc/doxygen/Doxyfile.in: -------------------------------------------------------------------------------- 1 | PROJECT_NAME = "Loom" 2 | PROJECT_NUMBER = 3 | PROJECT_BRIEF = "Static instrumentation library for LLVM" 4 | PROJECT_LOGO = @CMAKE_SOURCE_DIR@/doc/images/loom.png 5 | OUTPUT_DIRECTORY = @CMAKE_CURRENT_BUILD_DIR@ 6 | 7 | OUTPUT_LANGUAGE = @DOXYGEN_LANGUAGE@ 8 | 9 | INTERNAL_DOCS = NO 10 | HIDE_UNDOC_CLASSES = YES 11 | 12 | BRIEF_MEMBER_DESC = YES 13 | REPEAT_BRIEF = YES 14 | 15 | ALWAYS_DETAILED_SEC = NO 16 | 17 | # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all 18 | # inherited members of a class in the documentation of that class as if those 19 | # members were ordinary class members. Constructors, destructors and assignment 20 | # operators of the base classes will not be shown. 21 | # The default value is: NO. 22 | 23 | INLINE_INHERITED_MEMB = YES 24 | 25 | # If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path 26 | # before files name in the file list and in the header files. If set to NO the 27 | # shortest path that makes the file name unique will be used 28 | # The default value is: YES. 29 | 30 | FULL_PATH_NAMES = YES 31 | 32 | HIDE_SCOPE_NAMES = NO 33 | 34 | JAVADOC_AUTOBRIEF = YES 35 | QT_AUTOBRIEF = YES 36 | 37 | INHERIT_DOCS = YES 38 | 39 | SEPARATE_MEMBER_PAGES = NO 40 | 41 | TAB_SIZE = 4 42 | 43 | ALIASES += "license=@par License:\n" 44 | 45 | MARKDOWN_SUPPORT = YES 46 | AUTOLINK_SUPPORT = YES 47 | 48 | BUILTIN_STL_SUPPORT = YES 49 | CPP_CLI_SUPPORT = NO 50 | 51 | DISTRIBUTE_GROUP_DOC = NO 52 | 53 | SUBGROUPING = YES 54 | 55 | #--------------------------------------------------------------------------- 56 | # Build related configuration options 57 | #--------------------------------------------------------------------------- 58 | 59 | EXTRACT_ALL = NO 60 | EXTRACT_ANON_NSPACES = NO 61 | EXTRACT_PRIVATE = NO 62 | EXTRACT_PACKAGE = NO 63 | EXTRACT_STATIC = NO 64 | 65 | SORT_MEMBERS_CTORS_1ST = YES 66 | STRICT_PROTO_MATCHING = NO 67 | 68 | GENERATE_TODOLIST = YES 69 | GENERATE_TESTLIST = YES 70 | GENERATE_BUGLIST = YES 71 | GENERATE_DEPRECATEDLIST= YES 72 | 73 | LAYOUT_FILE = 74 | 75 | 76 | #--------------------------------------------------------------------------- 77 | # Configuration options related to warning and progress messages 78 | #--------------------------------------------------------------------------- 79 | 80 | QUIET = YES 81 | WARNINGS = NO 82 | WARN_IF_UNDOCUMENTED = NO 83 | WARN_IF_DOC_ERROR = YES 84 | WARN_NO_PARAMDOC = NO 85 | 86 | #--------------------------------------------------------------------------- 87 | # Configuration options related to the input files 88 | #--------------------------------------------------------------------------- 89 | 90 | INPUT = @CMAKE_SOURCE_DIR@/README.md @CMAKE_SOURCE_DIR@/include @CMAKE_SOURCE_DIR@/src 91 | STRIP_FROM_PATH = @CMAKE_SOURCE_DIR@ 92 | RECURSIVE = YES 93 | 94 | EXAMPLE_PATH = 95 | EXAMPLE_PATTERNS = 96 | 97 | USE_MDFILE_AS_MAINPAGE = README.md 98 | 99 | 100 | #--------------------------------------------------------------------------- 101 | # Configuration options related to source browsing 102 | #--------------------------------------------------------------------------- 103 | 104 | SOURCE_BROWSER = YES 105 | 106 | # Setting the INLINE_SOURCES tag to YES will include the body of functions, 107 | # classes and enums directly into the documentation. 108 | # The default value is: NO. 109 | 110 | INLINE_SOURCES = NO 111 | STRIP_CODE_COMMENTS = YES 112 | 113 | REFERENCED_BY_RELATION = YES 114 | REFERENCES_RELATION = YES 115 | REFERENCES_LINK_SOURCE = YES 116 | 117 | VERBATIM_HEADERS = YES 118 | 119 | 120 | #--------------------------------------------------------------------------- 121 | # Configuration options related to the HTML output 122 | #--------------------------------------------------------------------------- 123 | 124 | GENERATE_HTML = YES 125 | HTML_OUTPUT = html 126 | 127 | HTML_HEADER = @DOX_THEME@/header.html 128 | HTML_FOOTER = @DOX_THEME@/footer.html 129 | HTML_STYLESHEET = 130 | HTML_EXTRA_STYLESHEET = @DOX_BOOTSTRAP@/customdoxygen.css 131 | 132 | HTML_EXTRA_FILES = @DOX_BOOTSTRAP@/doxy-boot.js @DOX_THEME@/loom-dox.css 133 | 134 | HTML_COLORSTYLE_HUE = 218 135 | HTML_COLORSTYLE_SAT = 43 136 | HTML_COLORSTYLE_GAMMA = 80 137 | 138 | HTML_TIMESTAMP = NO 139 | HTML_DYNAMIC_SECTIONS = YES 140 | 141 | GENERATE_DOCSET = NO 142 | GENERATE_QHP = NO 143 | GENERATE_ECLIPSEHELP = NO 144 | 145 | GENERATE_TREEVIEW = NO 146 | TREEVIEW_WIDTH = 250 147 | 148 | USE_MATHJAX = NO 149 | MATHJAX_FORMAT = HTML-CSS 150 | MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest 151 | MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols 152 | MATHJAX_CODEFILE = 153 | 154 | SEARCHENGINE = YES 155 | 156 | 157 | GENERATE_LATEX = NO 158 | GENERATE_RTF = NO 159 | GENERATE_XML = NO 160 | GENERATE_AUTOGEN_DEF = NO 161 | GENERATE_PERLMOD = NO 162 | 163 | 164 | #--------------------------------------------------------------------------- 165 | # Configuration options related to the man page output 166 | #--------------------------------------------------------------------------- 167 | 168 | GENERATE_MAN = YES 169 | MAN_OUTPUT = man 170 | MAN_EXTENSION = .3 171 | MAN_SUBDIR = 172 | MAN_LINKS = YES 173 | 174 | 175 | 176 | #--------------------------------------------------------------------------- 177 | # Configuration options related to the DOCBOOK output 178 | #--------------------------------------------------------------------------- 179 | 180 | GENERATE_DOCBOOK = YES 181 | DOCBOOK_OUTPUT = docbook 182 | 183 | 184 | 185 | #--------------------------------------------------------------------------- 186 | # Configuration options related to the preprocessor 187 | #--------------------------------------------------------------------------- 188 | 189 | ENABLE_PREPROCESSING = YES 190 | MACRO_EXPANSION = NO 191 | EXPAND_ONLY_PREDEF = NO 192 | SEARCH_INCLUDES = YES 193 | INCLUDE_PATH = 194 | INCLUDE_FILE_PATTERNS = 195 | PREDEFINED = 196 | EXPAND_AS_DEFINED = 197 | SKIP_FUNCTION_MACROS = YES 198 | 199 | 200 | 201 | #--------------------------------------------------------------------------- 202 | # Configuration options related to the dot tool 203 | #--------------------------------------------------------------------------- 204 | 205 | CLASS_DIAGRAMS = YES 206 | HIDE_UNDOC_RELATIONS = YES 207 | HAVE_DOT = YES 208 | DOT_NUM_THREADS = 0 209 | DOT_FONTNAME = Avenir-Book 210 | 211 | DOT_FONTSIZE = 11 212 | DOT_FONTPATH = 213 | CLASS_GRAPH = YES 214 | COLLABORATION_GRAPH = NO 215 | GROUP_GRAPHS = YES 216 | 217 | UML_LOOK = YES 218 | UML_LIMIT_NUM_FIELDS = 4 219 | 220 | TEMPLATE_RELATIONS = YES 221 | INCLUDE_GRAPH = YES 222 | INCLUDED_BY_GRAPH = YES 223 | 224 | CALL_GRAPH = YES 225 | CALLER_GRAPH = YES 226 | 227 | GRAPHICAL_HIERARCHY = YES 228 | 229 | DIRECTORY_GRAPH = YES 230 | 231 | DOT_IMAGE_FORMAT = svg 232 | INTERACTIVE_SVG = YES 233 | 234 | MAX_DOT_GRAPH_DEPTH = 0 235 | 236 | DOT_TRANSPARENT = YES 237 | 238 | DOT_MULTI_TARGETS = NO 239 | 240 | GENERATE_LEGEND = YES 241 | 242 | DOT_CLEANUP = YES 243 | --------------------------------------------------------------------------------