├── Makefile ├── README └── memcpy-find.cc /Makefile: -------------------------------------------------------------------------------- 1 | UNAME_S:=$(shell uname -s) 2 | ifeq ($(UNAME_S),Darwin) 3 | PATH:=/usr/local/opt/llvm/bin:$(PATH) 4 | endif 5 | # llvm-config -cxxflags gives the flags that llvm was built 6 | # with instead of flags needed to build against llvm 7 | CXX=clang++ 8 | CXXFLAGS=`llvm-config --cxxflags` -g -std=c++14 9 | LDLIBS=`llvm-config --libs core irreader object bitreader` -lcurses -lLLVMDemangle 10 | LDFLAGS=`llvm-config --ldflags` 11 | 12 | .PHONY: all clean 13 | 14 | all: memcpy-find 15 | 16 | clean: 17 | rm -f memcpy-find 18 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | To use pass the name of a llvm ir file as the first argument. 2 | 3 | In rust you can get these by adding --emit=llvm-ir to rust command line. 4 | They show up in target/release/deps/*.ll 5 | 6 | This can usually be done with `RUSTFLAGS='-g --emit=llvm-ir' cargo build --release` 7 | This will generate .ll files for all dependencies as well. I've run into issues with 8 | that not working: https://github.com/rust-lang/rust/issues/56290. If you run into this 9 | you can also do `RUSTFLAGS='-g' cargo build --release -v` and get the command line and 10 | just append `--emit=llvm-ir` 11 | 12 | The bitcode files should work too, but have not been tested. 13 | 14 | You can demangle the names using rustfilt. (cargo install rustfilt) 15 | -------------------------------------------------------------------------------- /memcpy-find.cc: -------------------------------------------------------------------------------- 1 | 2 | #include "llvm/IR/Constants.h" 3 | #include "llvm/IR/DebugInfoMetadata.h" 4 | #include "llvm/IR/InstIterator.h" 5 | #include "llvm/IR/Instructions.h" 6 | #include "llvm/IR/LLVMContext.h" 7 | #include "llvm/IR/Module.h" 8 | #include "llvm/Support/ErrorOr.h" 9 | #include "llvm/Support/MemoryBuffer.h" 10 | #include "llvm/Support/Debug.h" 11 | #include "llvm/IRReader/IRReader.h" 12 | #include "llvm/Support/SourceMgr.h" 13 | 14 | #include "llvm/Support/raw_ostream.h" 15 | #include "llvm/Bitcode/BitcodeReader.h" 16 | #include 17 | 18 | 19 | using namespace llvm; 20 | using namespace std; 21 | 22 | void print_all(vector> &memcpys) { 23 | for (auto& i : memcpys) { 24 | auto callInst = get<0>(i); 25 | auto size = get<1>(i); 26 | auto function = get<2>(i); 27 | cout << "memcpy" << " of " << size << " in " << function->getName().data() << " @ " << std::endl; 28 | MDNode* metadata = callInst->getMetadata("dbg"); 29 | if (!metadata) { 30 | cout << " no debug info" << endl; 31 | continue; 32 | } 33 | DILocation *debugLocation = dyn_cast(metadata); 34 | while (debugLocation) { 35 | DILocalScope *scope = debugLocation->getScope(); 36 | cout << " "; 37 | if (scope) { 38 | DISubprogram *subprogram = scope->getSubprogram(); 39 | if (subprogram) { 40 | const char* name = subprogram->getName().data(); 41 | cout << name << " "; 42 | } 43 | } 44 | 45 | cout << debugLocation->getFilename().data() << ":" << debugLocation->getLine() << std::endl; 46 | debugLocation = debugLocation->getInlinedAt(); 47 | } 48 | } 49 | } 50 | 51 | void print_summary(vector> &memcpys) { 52 | for (auto& i : memcpys) { 53 | auto callInst = get<0>(i); 54 | auto size = get<1>(i); 55 | auto function = get<2>(i); 56 | cout << "memcpy" << " of " << size << std::endl; 57 | } 58 | } 59 | 60 | int main(int argc, char **argv) { 61 | LLVMContext context; 62 | SMDiagnostic Err; 63 | 64 | const char *fileName; 65 | if (argc > 1) { 66 | fileName = argv[1]; 67 | } else { 68 | printf("missing ir filename\n"); 69 | abort(); 70 | } 71 | bool summary = false; 72 | 73 | if (argc > 2) { 74 | if (std::string(argv[2]) == "summary") { 75 | summary = true; 76 | } 77 | } 78 | 79 | Expected > m = parseIRFile(fileName, Err, context); 80 | if (!m) { 81 | errs() << toString(m.takeError()) << "\n"; 82 | } 83 | vector> memcpys; 84 | { 85 | auto &functionList = m->get()->getFunctionList(); 86 | for (auto &function : functionList) { 87 | //printf("%s\n", function.getName().data()); 88 | for (auto &bb : function) { 89 | for (auto &instruction : bb) { 90 | //printf(" %s\n", instruction.getOpcodeName()); 91 | CallInst *callInst = dyn_cast(&instruction); 92 | 93 | if (callInst == nullptr) { 94 | continue; 95 | } 96 | //printf("have call\n"); 97 | 98 | Function *calledFunction = callInst->getCalledFunction(); 99 | 100 | if (calledFunction == nullptr) { 101 | //printf("no calledFunction\n"); 102 | continue; 103 | } 104 | 105 | StringRef cfName = calledFunction->getName(); 106 | if (cfName.find("llvm.memcpy") != std::string::npos) { 107 | auto size_operand = callInst->getOperand(2); 108 | auto size_constant = dyn_cast(size_operand); 109 | if (!size_constant) { 110 | //printf("not constant\n"); 111 | continue; 112 | } 113 | 114 | auto size = size_constant->getValue().getLimitedValue(); 115 | memcpys.push_back({callInst, size, &function}); 116 | } 117 | } 118 | } 119 | } 120 | } 121 | 122 | std::sort(memcpys.begin(), memcpys.end(), [](auto& x, auto &y) { 123 | if (get<1>(y) == get<1>(x)) { 124 | return get<2>(x) > get<2>(y); 125 | } else { 126 | return get<1>(x) > get<1>(y); 127 | } 128 | }); 129 | 130 | if (summary) { 131 | print_summary(memcpys); 132 | } else { 133 | print_all(memcpys); 134 | } 135 | } 136 | --------------------------------------------------------------------------------