Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 106 additions & 0 deletions CFFunctionInstrumentation/parse_found_funcs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@

from argparse import ArgumentParser
from utils import demangle_function_name

def unique_funcs(funcs_per_module):
unique_functions = set()
for module, funcs in funcs_per_module.items():
unique_functions.update(funcs)
return unique_functions


def parse_called_funcs(filename):
print(f'Parsing {filename}')

funcs_per_module = {}
# open the file and read the lines
try:
with open(filename, 'r') as f:
for line in f:
splitline = line.strip().split(' ')
if not len(splitline) == 4:
continue
func = splitline[0]
module = splitline[3]
if module not in funcs_per_module:
funcs_per_module[module] = []
funcs_per_module[module].append(func)
except FileNotFoundError:
print(f'File {filename} not found')
return []

return funcs_per_module

def get_unique_funcs(filename):
funcs_per_module = parse_called_funcs(filename)
return unique_funcs(funcs_per_module)

def get_stored_funcs_dict(filename):
file = open(filename, "r")
funcs_per_module = eval(file.read())

return funcs_per_module

def print_stats(funcs_per_module):

unique_functions = unique_funcs(funcs_per_module)

print(f'Found {len(funcs_per_module)} modules')

print(f'Found {len(unique_functions)} unique functions')

def build_folder_hierarchy(modules):
hierarchy = {}
for module in modules:
module = module.removeprefix('/home/webmiche/questions/llvm-project/')
parts = module.split('/')
current = hierarchy
for part in parts:
if part not in current:
current[part] = {}
current = current[part]
return hierarchy

def print_hierarchy(hierarchy):
for outer_most, inner in hierarchy.items():
print(outer_most)
for inner_most, inner_inner in inner.items():
print(f' {inner_most}')
for inner_inner_most in inner_inner:
print(f' {inner_inner_most}')
for inner_inner_inner in inner_inner[inner_inner_most]:
print(f' {inner_inner_inner}')
for inner_inner_inner_inner in inner_inner[inner_inner_most][inner_inner_inner]:
print(f' {inner_inner_inner_inner}')
print()
print()
print()



if __name__ == '__main__':
# pass the filename as an argument
parser = ArgumentParser()
parser.add_argument('filename')
args = parser.parse_args()
filename = args.filename
funcs_per_module = get_stored_funcs_dict(filename)


hierarchy = build_folder_hierarchy(funcs_per_module.keys())

print_hierarchy(hierarchy)

# add up all the functions in the TableGen folder
functions_in_tablegen = {}
for module, funcs in funcs_per_module.items():
if module.startswith('/home/webmiche/questions/llvm-project/llvm/utils/TableGen'):
functions_in_tablegen[module] = funcs

unique_functions = unique_funcs(functions_in_tablegen)
total_functions = len(unique_functions)


print_stats(funcs_per_module)

print(f'Functions in TableGen: {total_functions}')
5 changes: 1 addition & 4 deletions CFFunctionInstrumentation/parse_trace.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@

from collections import Counter
from subprocess import run, PIPE
from utils import demangle_function_name

def parse_trace(trace_string) -> dict:

Expand Down Expand Up @@ -30,10 +31,6 @@ def parse_file(file_path) -> dict:
trace_string = f.read()
return parse_trace(trace_string)

def demangle_function_name(function_name):
cmd = f"llvm-cxxfilt {function_name}"
result = run(cmd, shell=True, stdout=PIPE)
return result.stdout.decode('utf-8').strip()

def single_valued_functions(trace_dict):
result = {}
Expand Down
6 changes: 6 additions & 0 deletions CFFunctionInstrumentation/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from subprocess import run, PIPE

def demangle_function_name(function_name):
cmd = f"llvm-cxxfilt {function_name}"
result = run(cmd, shell=True, stdout=PIPE)
return result.stdout.decode('utf-8').strip()
Binary file added funcs_per_module.zip
Binary file not shown.
Binary file added instrumented_per_module.zip
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "llvm/IR/PassManager.h"
#include "llvm/Support/Debug.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include <fstream>

namespace llvm {

Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Analysis/CFFunctionAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ PreservedAnalyses CFFunctionAnalysisStorePass::run(Module &M,
}

for (auto &F : CalledFunctions) {
out << F.str() << "\n";
out << F.str() << " called from " << M.getName().str() << "\n";
}

out.close();
Expand Down
79 changes: 76 additions & 3 deletions llvm/lib/Transforms/Utils/CFFunctionInstrumentation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,30 @@ CFFunctionInstrumentationPass::run(Module &M, ModuleAnalysisManager &AM) {
continue;
}

// print the function name and the module name to traced_functions.txt
std::ofstream out;
out.open("traced_functions.txt", std::ios::app);

if (!out) {
errs() << "Error: cannot open file traced_functions.txt \n";
return PreservedAnalyses::none();
}
out << F.getName().str() << " instrumented in " << M.getName().str()
<< "\n";
out.close();

std::string outputString = F.getName().str() + " %lld\n";
StringRef funcFormatStr = StringRef(outputString);
std::string fileName = "function_trace.txt";
StringRef funcFileName = StringRef(fileName);
// for all return instructions, print the return value to a file with the
// name of the function

auto GV = new GlobalVariable(
M, Type::getInt32Ty(M.getContext()), true,
GlobalValue::LinkageTypes::PrivateLinkage,
ConstantInt::get(IntegerType::getInt32Ty(M.getContext()), 0),
"init" + F.getName());
// store already handled blocks
std::set<BasicBlock *> HandledBlocks;
for (auto &BB : F) {
Expand All @@ -46,7 +63,7 @@ CFFunctionInstrumentationPass::run(Module &M, ModuleAnalysisManager &AM) {
// Do NOT reinstrument the inserted blocks
if (BB.getName() == "return" || BB.getName() == "print" ||
BB.getName() == "open") {
HandledBlocks.insert(&BB);
HandledBlocks.insert(&BB);
continue;
}
if (auto *RI = dyn_cast<ReturnInst>(BB.getTerminator())) {
Expand Down Expand Up @@ -76,10 +93,44 @@ CFFunctionInstrumentationPass::run(Module &M, ModuleAnalysisManager &AM) {
// split at return
BasicBlock *ReturnBB = BB.splitBasicBlock(RI, "return", false);

BasicBlock *CheckBB =
BasicBlock::Create(M.getContext(), "access_check", &F);
BasicBlock *Check2BB =
BasicBlock::Create(M.getContext(), "no_init_check", &F);
BasicBlock *AccessBB =
BasicBlock::Create(M.getContext(), "access", &F);
BasicBlock *UpdateGVBB =
BasicBlock::Create(M.getContext(), "update", &F);
BasicBlock *NoAccessBB =
BasicBlock::Create(M.getContext(), "no_access", &F);

BasicBlock *PrintBB = BasicBlock::Create(M.getContext(), "print", &F);

LLVM_DEBUG(dbgs() << "Created BBs\n");

IRBuilder<> CheckBuilder(CheckBB);

Value *GV_value = CheckBuilder.CreateLoad(
IntegerType::getInt32Ty(M.getContext()), GV);

// check if GV is 0 (not yet accessed) or -1 (no access) or 1 (access)
Value *CmpGV = CheckBuilder.CreateICmpEQ(
GV_value,
ConstantInt::get(IntegerType::getInt32Ty(M.getContext()), 1));

CheckBuilder.CreateCondBr(CmpGV, PrintBB, Check2BB);

LLVM_DEBUG(dbgs() << "Created check BB\n");

IRBuilder<> Check2Builder(Check2BB);
Value *CmpGV2 = Check2Builder.CreateICmpEQ(
GV_value,
ConstantInt::get(IntegerType::getInt32Ty(M.getContext()), -1));

Check2Builder.CreateCondBr(CmpGV2, ReturnBB, AccessBB);

LLVM_DEBUG(dbgs() << "Created check2 BB\n");

IRBuilder<> AccessBuilder(AccessBB);
// insert call to access function with filename and 0
Value *status = AccessBuilder.CreateCall(
Expand All @@ -88,7 +139,25 @@ CFFunctionInstrumentationPass::run(Module &M, ModuleAnalysisManager &AM) {
Value *Cmp = AccessBuilder.CreateICmpEQ(
status,
ConstantInt::get(IntegerType::getInt32Ty(M.getContext()), 0));
AccessBuilder.CreateCondBr(Cmp, PrintBB, ReturnBB);
AccessBuilder.CreateCondBr(Cmp, UpdateGVBB, NoAccessBB);

LLVM_DEBUG(dbgs() << "Created access BB\n");

IRBuilder<> NoAccessBuilder(NoAccessBB);
NoAccessBuilder.CreateStore(
ConstantInt::get(IntegerType::getInt32Ty(M.getContext()), -1),
GV);
NoAccessBuilder.CreateBr(ReturnBB);

LLVM_DEBUG(dbgs() << "Created no access BB\n");

IRBuilder<> UpdateGVBuilder(UpdateGVBB);
UpdateGVBuilder.CreateStore(
ConstantInt::get(IntegerType::getInt32Ty(M.getContext()), 1), GV);

UpdateGVBuilder.CreateBr(PrintBB);

LLVM_DEBUG(dbgs() << "Created update BB\n");

IRBuilder<> PrintBuilder(PrintBB);
FunctionCallee PrintFunc = M.getOrInsertFunction(
Expand Down Expand Up @@ -119,14 +188,18 @@ CFFunctionInstrumentationPass::run(Module &M, ModuleAnalysisManager &AM) {
PrintBuilder.CreateCall(CloseFunc, write_fptr);
PrintBuilder.CreateBr(ReturnBB);

BB.getTerminator()->setSuccessor(0, AccessBB);
BB.getTerminator()->setSuccessor(0, CheckBB);

// place new BBs in the correct order
ReturnBB->moveAfter(PrintBB);

HandledBlocks.insert(AccessBB);
HandledBlocks.insert(PrintBB);
HandledBlocks.insert(ReturnBB);
HandledBlocks.insert(CheckBB);
HandledBlocks.insert(Check2BB);
HandledBlocks.insert(UpdateGVBB);
HandledBlocks.insert(NoAccessBB);
}
}
HandledBlocks.insert(&BB);
Expand Down
Loading