Skip to content

Commit

Permalink
Locating target instruction by file:line
Browse files Browse the repository at this point in the history
  • Loading branch information
examon committed Nov 1, 2018
1 parent d5d8eaf commit d49137a
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 18 deletions.
80 changes: 67 additions & 13 deletions apex/apex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::pair<Function *, std::vector<Function *>>> call_graph;
std::vector<Function *> 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);
Expand All @@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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<Instruction *> 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.
Expand Down Expand Up @@ -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<CallInst>(I)) {
Expand All @@ -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 "
Expand Down
21 changes: 19 additions & 2 deletions apex/apex.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <vector>

#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"
Expand All @@ -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<std::string> PROTECTED_FCNS = {"lib_test", "lib_exit", "exit",
"printf", "llvm.dbg.declare"};

/// Command line arguments for opt.
cl::opt<std::string> ARG_SOURCE_FCN("source",
/*
cl::opt<std::string> source_function("source",
cl::desc("Specify source function."),
cl::value_desc("function name"));
cl::opt<std::string> ARG_TARGET_FCN("target",
cl::opt<std::string> target_function("target",
cl::desc("Specify target function."),
cl::value_desc("function name"));
*/

cl::opt<std::string> 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<std::string> 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 {
Expand Down Expand Up @@ -137,6 +151,9 @@ class APEXPass : public ModulePass {
std::vector<LLVMNode *> &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<Function *> &path);
void moduleInsertExitAfterTarget(Module &M,
Expand Down
9 changes: 6 additions & 3 deletions build_and_run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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

Expand Down

0 comments on commit d49137a

Please sign in to comment.