From d49137a3613e616cb08477529db42799bd880fc5 Mon Sep 17 00:00:00 2001 From: Tomas Meszaros Date: Thu, 1 Nov 2018 07:54:49 +0100 Subject: [PATCH] Locating target instruction by file:line --- apex/apex.cpp | 80 ++++++++++++++++++++++++++++++++++++++++-------- apex/apex.h | 21 +++++++++++-- build_and_run.sh | 9 ++++-- 3 files changed, 92 insertions(+), 18 deletions(-) diff --git a/apex/apex.cpp b/apex/apex.cpp index 5c14e6b..ba5d70f 100644 --- a/apex/apex.cpp +++ b/apex/apex.cpp @@ -11,13 +11,22 @@ /// Running on each module. bool APEXPass::runOnModule(Module &M) { - logPrintUnderline("\nInitial Module Dump:"); - logDumpModule(M); + // logPrintUnderline("\nInitial Module Dump:"); + // logDumpModule(M); APEXDependencyGraph apex_dg; LLVMDependenceGraph dg; std::vector>> call_graph; std::vector path; + std::string source_function = "main"; // TODO: Figure out entry automaticall? + std::string target_function = ""; // This is going to be initialized later. + + logPrintUnderline("Parsing command line arguments:"); + moduleParseCmdLineArgsOrDie(); + + logPrintUnderline("Locating target instructions:"); + // TODO: Store target instruction. + target_function = moduleFindTargetFunctionOrDie(M, ARG_FILE, ARG_LINE); // Initialize dg. This runs analysis and computes dependencies. dgInit(M, dg); @@ -33,20 +42,20 @@ bool APEXPass::runOnModule(Module &M) { // apexDgPrintGraph(apex_dg); // Create call graph from module. - createCallGraph(M, ARG_SOURCE_FCN, call_graph); + createCallGraph(M, source_function, call_graph); // printCallGraph(call_graph); // Find path from @source to @target in the @callgraph. Save it to @path. - findPath(call_graph, ARG_SOURCE_FCN, ARG_TARGET_FCN, path); - printPath(path, ARG_SOURCE_FCN, ARG_TARGET_FCN); + findPath(call_graph, source_function, target_function, path); + printPath(path, source_function, target_function); // Put exit call before selected @target function call. - // moduleInsertExitAfterTarget(M, path, ARG_TARGET_FCN); + // moduleInsertExitAfterTarget(M, path, target_function); // Resolve data dependencies for functions in @path. // TODO: @y should be added to deps when target=@n // updatePathAddDependencies(path, apex_dg); - // printPath(path, ARG_SOURCE_FCN, ARG_TARGET_FCN); + // printPath(path, source_function, target_function); logPrintUnderline("Dependency resolver: START"); // Investigate each function in @path. @@ -121,11 +130,12 @@ bool APEXPass::runOnModule(Module &M) { logPrint(""); } } + // TODO: one iteration of dep resolving is done logPrint("\n---\n"); } - printPath(path, ARG_SOURCE_FCN, ARG_TARGET_FCN); + printPath(path, source_function, target_function); // Remove all functions (along with dependencies) that are not in the @path. // Excluding functions in @PROTECTED_FCNS. @@ -1041,6 +1051,50 @@ void APEXPass::updatePathAddDependencies( // Module utilities // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +/// Parses command line arguments +/// +/// Dies if arguments are missing or are in from format. +void APEXPass::moduleParseCmdLineArgsOrDie(void) { + // TODO: Add handling in case of missing/wrong values. + logPrint("file = " + ARG_FILE); + logPrint("line = " + ARG_LINE); +} + +/// Tries to find instruction that is located at @file and @line. +/// Extract parent function of this instruction and returns global id of this +/// function. +/// +/// Dies if unable to find instruction. +std::string APEXPass::moduleFindTargetFunctionOrDie(Module &M, + const std::string &file, + const std::string &line) { + std::vector target_instructions; + for (auto &F : M) { + for (auto &BB : F) { + for (auto &I : BB) { + if (DILocation *loc = I.getDebugLoc()) { + std::string line = std::to_string(loc->getLine()); + std::string file = loc->getFilename(); + // std::string dir = loc->getDirectory(); + if (file == ARG_FILE && line == ARG_LINE) { + // Found instruction that matches ARG_FILE+ARG_LINE + target_instructions.push_back(&I); + } + } + } + } + } + if (true == target_instructions.empty()) { + logPrint("ERROR: Could not locate target instructions!"); + exit(FATAL_ERROR); + } + logPrint("Instructions at: file = " + ARG_FILE + ", line = " + ARG_LINE); + for (Instruction *I : target_instructions) { + I->dump(); + } + return target_instructions.back()->getFunction()->getGlobalIdentifier(); +} + /// Goes over all functions in module. If there is some function in module /// that is not in the @path, put it for removal along it all its dependencies. /// Note: Functions that are in @PROTECTED_FCNS, will NOT be removed. @@ -1200,12 +1254,12 @@ void APEXPass::moduleInsertExitAfterTarget(Module &M, logPrint("- chosen caller id: " + chosen_caller->getGlobalIdentifier()); } - logPrint("\nFinding chosen call instruction to @" + ARG_TARGET_FCN + - " inside @" + chosen_caller->getGlobalIdentifier() + ":"); + logPrint("\nFinding chosen call instruction to target function inside @" + + chosen_caller->getGlobalIdentifier() + ":"); Instruction *chosen_instruction = nullptr; { - // Now that we have function that should call @ARG_TARGET_FCN, we search - // inside for call instruction to @ARG_TARGET_FCN. + // Now that we have function that should call @target_function, we search + // inside for call instruction to @target_function. for (auto &BB : *chosen_caller) { for (auto &&I : BB) { if (isa(I)) { @@ -1221,7 +1275,7 @@ void APEXPass::moduleInsertExitAfterTarget(Module &M, logPrint("ERROR: Could not find chosen instruction."); exit(-1); } - logPrint("- call instruction to @" + ARG_TARGET_FCN + " found"); + logPrint("- call instruction to target function found"); } logPrint("\nSearching for insertion point (that is, instruction after chosen " diff --git a/apex/apex.h b/apex/apex.h index dab9863..f80855b 100644 --- a/apex/apex.h +++ b/apex/apex.h @@ -14,6 +14,7 @@ #include #include "llvm/ADT/APInt.h" +#include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/InstIterator.h" #include "llvm/IR/LLVMContext.h" @@ -31,18 +32,31 @@ using namespace llvm; using namespace dg; +/// Error code when we want to crash APEXPass. +int FATAL_ERROR = -1; + /// Protected functions IDs. These will not be removed by APEXPass. std::vector PROTECTED_FCNS = {"lib_test", "lib_exit", "exit", "printf", "llvm.dbg.declare"}; /// Command line arguments for opt. -cl::opt ARG_SOURCE_FCN("source", +/* +cl::opt source_function("source", cl::desc("Specify source function."), cl::value_desc("function name")); -cl::opt ARG_TARGET_FCN("target", +cl::opt target_function("target", cl::desc("Specify target function."), cl::value_desc("function name")); +*/ + +cl::opt ARG_FILE( + "file", cl::desc("Filename in relative path from to the launching script."), + cl::value_desc("file name (e.g. code/main.c)")); + +cl::opt ARG_LINE("line", + cl::desc("Number representing line in the file."), + cl::value_desc("Source code line number.")); /// Node is usually line instruction of IR. Sometimes whole function. struct APEXDependencyNode { @@ -137,6 +151,9 @@ class APEXPass : public ModulePass { std::vector &rev_data_dependencies); // Module utilities. + void moduleParseCmdLineArgsOrDie(void); + std::string moduleFindTargetFunctionOrDie(Module &M, const std::string &file, + const std::string &line); void moduleRemoveFunctionsNotInPath(Module &M, APEXDependencyGraph &apex_dg, std::vector &path); void moduleInsertExitAfterTarget(Module &M, diff --git a/build_and_run.sh b/build_and_run.sh index bc84926..a628c07 100755 --- a/build_and_run.sh +++ b/build_and_run.sh @@ -13,8 +13,11 @@ # TODO: This should be part of user input and not hardcoded. INPUT_SOURCE="test_dependencies_minimal.c" -SOURCE_FCN="main" -TARGET_FCN="y" +#SOURCE_FCN="main" +#TARGET_FCN="n" +FILE="c-code/test_dependencies_minimal.c" +LINE=29 + INPUT_LIB="lib.c" # Generated bytecodes during all stages of processing. @@ -83,7 +86,7 @@ echo "========= Running APEXPass." #opt -o build/${BYTECODE_FROM_INPUT_BASIC_OPTS} ${BASIC_OPTS} build/${BYTECODE_FROM_INPUT} > /dev/null # run APEXPass without additional opts -opt -o build/${BYTECODE_FROM_APEX} -load build/apex/libAPEXPass.so -apex -source=${SOURCE_FCN} -target=${TARGET_FCN} < build/${BYTECODE_FROM_LINKED_INPUT_LIB} > /dev/null +opt -o build/${BYTECODE_FROM_APEX} -load build/apex/libAPEXPass.so -apex -file=${FILE} -line=${LINE} < build/${BYTECODE_FROM_LINKED_INPUT_LIB} > /dev/null # run APEXPass with ${BASIC_OPTS} #opt -o build/${BYTECODE_FROM_APEX} -load build/apex/libAPEXPass.so -apex ${BASIC_OPTS} -source=${SOURCE_FCN} -target=${TARGET_FCN} < build/${BYTECODE_FROM_LINKED_INPUT_LIB} > /dev/null