├── .gitignore ├── CMakeLists.txt ├── ExtractBB ├── CMakeLists.txt └── Extract.cpp ├── README.md └── images ├── example.png └── example_extractinst.png /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | build/ 3 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.4.3) 2 | project(LLVMExtractBB) 3 | 4 | find_package(LLVM REQUIRED CONFIG) 5 | list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") 6 | include(AddLLVM) 7 | 8 | add_definitions(${LLVM_DEFINITIONS}) 9 | include_directories(${LLVM_INCLUDE_DIRS}) 10 | 11 | add_subdirectory(ExtractBB) 12 | -------------------------------------------------------------------------------- /ExtractBB/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # This is a work-around for an LLVM bug in the llvm-8-dev package that will 2 | # cause a segmentation fault during llvm_shutdown(). There is an issue with 3 | # LLVM's implementation of ManagedStatic that will cause our plugin to be 4 | # unloaded before our pass is cleaned up. This will result in a call through a 5 | # dangling pointer to our unloaded library. Note that this issue only manifests 6 | # when using RegisterStandardPasses with an out-of-tree build. 7 | # 8 | # This issue is mentioned in a few places: 9 | # http://lists.llvm.org/pipermail/llvm-dev/2017-September/117566.html 10 | # https://github.com/sampsyo/llvm-pass-skeleton/issues/7 11 | # https://bugs.llvm.org/show_bug.cgi?id=34573 12 | # https://bugs.llvm.org/show_bug.cgi?id=39321 https://reviews.llvm.org/D33515 13 | set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,-znodelete") 14 | 15 | add_llvm_library(LLVMExtractBB MODULE 16 | Extract.cpp) 17 | 18 | add_llvm_library(LLVMExtractInst MODULE 19 | Extract.cpp) 20 | target_compile_definitions(LLVMExtractInst PRIVATE "-DSPLIT_BASICBLOCKS") 21 | -------------------------------------------------------------------------------- /ExtractBB/Extract.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @brief Module pass to extract instructions into functions. 3 | * 4 | * This pass will individually process each function, extracting instructions 5 | * into new functions. Edges between instructions and basic blocks will be 6 | * converted into calls. As a side-effect of this, loops will be translated 7 | * into recursive calls. 8 | * 9 | * At the moment, the only supported Terminator instructions for BasicBlocks 10 | * are returns and branches. The following terminators are not implemented: 11 | * - switch statements 12 | * - indirect branches 13 | * - exceptions/cleanup 14 | * 15 | * TODO: 16 | * - Propagate local variables down to the lowest level to hinder function 17 | * start detection. 18 | */ 19 | 20 | #include "llvm/ADT/SmallPtrSet.h" 21 | #include "llvm/ADT/Statistic.h" 22 | #include "llvm/IR/CFG.h" 23 | #include "llvm/IR/Function.h" 24 | #include "llvm/IR/Instructions.h" 25 | #include "llvm/IR/IRBuilder.h" 26 | #include "llvm/IR/LegacyPassManager.h" 27 | #include "llvm/IR/Module.h" 28 | #include "llvm/Pass.h" 29 | #include "llvm/Support/Debug.h" 30 | #include "llvm/Support/raw_ostream.h" 31 | #include "llvm/Transforms/IPO/PassManagerBuilder.h" 32 | 33 | #include 34 | #include 35 | 36 | #define DEBUG_TYPE "extractbb" 37 | 38 | STATISTIC(NumBlocksExtracted, "Number of basic blocks extracted"); 39 | 40 | using namespace llvm; 41 | 42 | namespace { 43 | 44 | /** 45 | * @brief Structure used to represent the current state of a BasicBlock that 46 | * is being extracted. 47 | * @member BB BasicBlock that's being extracted. 48 | * @member Func Extracted function. This is only valid after all parameters 49 | * have been calculated. 50 | * @member params A map of values that will become input parameters for the 51 | * extracted function. Each parameter maps to a list of Uses in the 52 | * extracted function. 53 | * @member phis A map of incoming PHINodes for this basic block. Each PHINode 54 | * will become an additional parameter. They need to be tracked 55 | * separately from params because they need special handling and will 56 | * be removed once we're done processing all BasicBlocks. 57 | */ 58 | struct BBContext { 59 | BasicBlock *BB; 60 | Function *Func; 61 | std::map> params; 62 | std::map> phis; 63 | }; 64 | 65 | typedef std::map> BBMap; 66 | 67 | 68 | #if defined(SPLIT_BASICBLOCKS) 69 | /** 70 | * @brief Split a BasicBlock after the first insertion point. 71 | * @param BB BasicBlock to split. 72 | */ 73 | void splitBasicBlock(BasicBlock &BB) { 74 | auto it = BB.getFirstInsertionPt(); 75 | if (it == BB.end() || std::next(it) == BB.end()) { 76 | return; 77 | } 78 | BB.splitBasicBlock(std::next(it)); 79 | } 80 | #endif // SPLIT_BASICBLOCKS 81 | 82 | 83 | /** 84 | * @brief Create a BBContext object. Populate params with Values used in the 85 | * given basic block. 86 | * 87 | * Get the values used by instructions in this basic block. These values will 88 | * become the input parameters to an extracted function. This function will 89 | * also verify that all output values are only used within the current 90 | * BasicBlock. 91 | * 92 | * @return A BBContext with a partially initialized set of params. 93 | */ 94 | std::unique_ptr createBBContext(BasicBlock &BB) { 95 | std::unique_ptr ctx(new BBContext()); 96 | ctx->BB = &BB; 97 | ctx->Func = nullptr; 98 | 99 | LLVM_DEBUG(dbgs() << " Basic block (name=" << BB.getName() << ") has " 100 | << BB.size() << " instructions.\n"); 101 | for (Instruction &I : BB) { 102 | LLVM_DEBUG(dbgs() << " inst: " << I << "\n"); 103 | 104 | // PHINodes need special handling. In this case, we have two input 105 | // values, but only need one parameter. Add the PHI to the context with 106 | // no uses (it will be erased later). We also have to iterate through 107 | // the PHINode Users in the current block to properly replace it's 108 | // Uses. 109 | if (PHINode *phi = dyn_cast(&I)) { 110 | ctx->phis[phi] = std::move(SmallVector()); 111 | continue; 112 | } 113 | 114 | for (Use &U : I.operands()) { 115 | Value *value = U.get(); 116 | 117 | // globals and constants don't need to become parameters. 118 | // llvm GlobalValue subclasses llvm::Constant. 119 | if (isa(value)) { 120 | continue; 121 | } 122 | 123 | // Uses of Values that aren't Instructions or Arguments 124 | // (BasicBlocks by a BranchInst, Functions by a CallInst), don't 125 | // require a parameter. 126 | if (!isa(value) && !isa(value)) { 127 | continue; 128 | } 129 | 130 | // Unless it's PHINode, Values from the current BasicBlock don't 131 | // need to become parameters. 132 | if (auto *VI = dyn_cast(value)) { 133 | if (!isa(value) && VI->getParent() == &BB) { 134 | continue; 135 | } 136 | } 137 | 138 | LLVM_DEBUG(dbgs() << " "); 139 | LLVM_DEBUG(value->dump()); 140 | 141 | // PHINode in the current BasicBlock is tracked separately 142 | if (PHINode *phi = dyn_cast(value)) { 143 | if (phi->getParent() == &BB) { 144 | ctx->phis[phi].push_back(&U); 145 | continue; 146 | } 147 | } 148 | 149 | // normal parameter - add it to the param list 150 | if (ctx->params.count(value) == 0) { 151 | ctx->params[value] = std::move(SmallVector()); 152 | } 153 | ctx->params[value].push_back(&U); 154 | } 155 | } 156 | 157 | return ctx; 158 | } 159 | 160 | 161 | /** 162 | * @brief Perform a recursive postorder traversal of the CFG in order to 163 | * determine parameters for each extracted basic block function. 164 | * 165 | * Since we're doing a postorder traversal in a graph that may have loops, 166 | * there's no way to have a complete answer if a loop is detected (since the 167 | * already seen successor hasn't been populated yet). To fix this, the 168 | * traversal must be performed until this function returns false. 169 | * 170 | * @param BB Current BasicBlock to process. 171 | * @param bbMap Map of all BasicBlocks to their contexts. The goal of the 172 | * traversal is to fully populate this map. 173 | * @param seenBB A set of all BasicBlocks seen so far during this recursive 174 | * iteration. This variable is used to detect loops in the CFG and 175 | * prevent infinite recursion. 176 | * @return true if any modifications were made to the bbMap. This function 177 | * should be repeatedly called while true is returned in order to 178 | * properly handle loops in the CFG. 179 | */ 180 | bool visitBasicBlock(BasicBlock &BB, 181 | BBMap &bbMap, 182 | SmallPtrSet &seenBB) { 183 | // base case 1: BB terminator is a function terminator 184 | if (isa(BB.getTerminator())) { 185 | bool retval = false; 186 | if (bbMap.count(&BB) == 0) { 187 | bbMap[&BB] = createBBContext(BB); 188 | retval = true; 189 | } 190 | 191 | seenBB.erase(&BB); 192 | return retval; 193 | } 194 | 195 | // base case 2: loop detected 196 | if (seenBB.count(&BB) > 0) { 197 | return false; 198 | } 199 | 200 | // recursive case: recurse to get params of children, then populate current 201 | // block. 202 | bool retval = false; 203 | seenBB.insert(&BB); 204 | if (bbMap.count(&BB) == 0) { 205 | bbMap[&BB] = createBBContext(BB); 206 | retval = true; 207 | } 208 | BBContext &ctx = *bbMap[&BB]; 209 | 210 | for (succ_iterator si = succ_begin(&BB), se = succ_end(&BB); si != se; si++) { 211 | // recurse to populate bbMap[succBB] 212 | if (visitBasicBlock(**si, bbMap, seenBB)) { 213 | retval = true; 214 | } 215 | 216 | // add succ params to this function's params if they aren't produced in 217 | // this BasicBlock. succ params won't have any Uses associated with 218 | // them since there is no CallInst yet. 219 | BBContext *succCtx = bbMap[*si].get(); 220 | for (auto &it : succCtx->params) { 221 | Value *value = it.first; 222 | if (Instruction *I = dyn_cast(value)) { 223 | if (I->getParent() == &BB) { 224 | continue; 225 | } 226 | } 227 | 228 | if (ctx.params.count(value) == 0) { 229 | ctx.params[value] = std::move(SmallVector()); 230 | retval = true; 231 | } 232 | } 233 | 234 | // if the succ has PHINodes that depend on a Value produced by one of 235 | // our parent BasicBlocks, that Value needs to become a parameter. 236 | for (auto &it : succCtx->phis) { 237 | PHINode *phi = it.first; 238 | Value *value = phi->getIncomingValueForBlock(&BB); 239 | if (Instruction *I = dyn_cast(value)) { 240 | if (I->getParent() == &BB) { 241 | continue; 242 | } 243 | } 244 | 245 | if (ctx.params.count(value) == 0) { 246 | ctx.params[value] = std::move(SmallVector()); 247 | retval = true; 248 | } 249 | } 250 | } 251 | 252 | seenBB.erase(&BB); 253 | return retval; 254 | } 255 | 256 | 257 | /** 258 | * @brief Extract a basic block into a function. 259 | * @param M Module to insert the function into. 260 | * @param ctx Context object containing information about the BasicBlock to 261 | * extract. 262 | */ 263 | void extractBasicBlock(Module &M, BBContext &ctx) { 264 | // create the function 265 | SmallVector argsTy; 266 | for (auto &it : ctx.params) { 267 | Value *value = it.first; 268 | argsTy.push_back(value->getType()); 269 | } 270 | for (auto &it : ctx.phis) { 271 | PHINode *phi = it.first; 272 | argsTy.push_back(phi->getType()); 273 | } 274 | 275 | Type *retTy = ctx.BB->getParent()->getReturnType(); 276 | FunctionType *funcTy = FunctionType::get(retTy, argsTy, false); 277 | Twine funcName = ctx.BB->getParent()->getName() + "_extracted_" + ctx.BB->getName(); 278 | ctx.Func = Function::Create(funcTy, GlobalValue::InternalLinkage, funcName, &M); 279 | 280 | // move the basic block to the new function 281 | ctx.BB->removeFromParent(); 282 | ctx.BB->insertInto(ctx.Func); 283 | } 284 | 285 | 286 | /** 287 | * @brief Helper function to create a CallInst to an extracted BasicBlock. 288 | * @param BB Original BasicBlock that is being modified. 289 | * @param builder IRBuilder that should be used to insert instructions. 290 | * @param ctx Context for the current extracted function. This can be nullptr 291 | * if the current function is not an extracted BasicBlock. 292 | * @param targetCtx Context representing the extracted BasicBlock that should 293 | * be used as the call target. 294 | */ 295 | CallInst * createCallInst(BasicBlock &BB, IRBuilder<> &builder, BBContext *ctx, 296 | BBContext &targetCtx) { 297 | // build argument array for the call from the child 298 | SmallVector args; 299 | for (auto &it : targetCtx.params) { 300 | Value *value = it.first; 301 | args.push_back(value); 302 | } 303 | for (auto &it : targetCtx.phis) { 304 | PHINode *phi = it.first; 305 | Value *arg = phi->getIncomingValueForBlock(&BB); 306 | args.push_back(arg); 307 | } 308 | 309 | CallInst *callInst = builder.CreateCall(targetCtx.Func, args); 310 | 311 | // if this BasicBlock was extracted, add the new uses to the list 312 | // of uses for the arguments so it can be properly replaced later. 313 | if (ctx != nullptr) { 314 | for (Use &U : callInst->arg_operands()) { 315 | Value *value = U.get(); 316 | if (ctx->params.count(value) > 0) { 317 | ctx->params[value].push_back(&U); 318 | } 319 | else if (PHINode *phi = dyn_cast(value)) { 320 | if (ctx->phis.count(phi) > 0) { 321 | ctx->phis[phi].push_back(&U); 322 | } 323 | } 324 | } 325 | } 326 | 327 | return callInst; 328 | } 329 | 330 | 331 | /** 332 | * @brief Fixup the terminator instruction for a BasicBlock. Since successor 333 | * BasicBlocks are extracted to functions, we need to translate branches 334 | * to calls. 335 | * 336 | * This function currently handles three cases: 337 | * - ReturnInst or UnreachableInst: The terminator is a terminator for the 338 | * original function. No action required. 339 | * - Unconditional Branch: Replace the branch with a call to the branch target 340 | * and a return. 341 | * - Conditional Branch: Create two new BasicBlocks to replace the branch 342 | * successors. For each block, insert a call to the original successor and 343 | * branch to a new return block, that will return the result of the call. 344 | * 345 | * Switch statements, indirect branches, and exception-related terminators are 346 | * not currently supported. 347 | * 348 | * @param BB The BasicBlock to fixup. 349 | * @param ctx Context for the current BasicBlock and corresponding extracted 350 | * function. This can be nullptr if the current BasicBlock has not been 351 | * extracted. 352 | * @param bbMap A map of all extracted BasicBlocks to their contexts. 353 | */ 354 | void fixupTerminator(BasicBlock &BB, BBContext *ctx, BBMap &bbMap) 355 | { 356 | Instruction *term = BB.getTerminator(); 357 | if (isa(term) || isa(term)) { 358 | return; 359 | } 360 | 361 | if (BranchInst *branch = dyn_cast(term)) { 362 | if (branch->isUnconditional()) { 363 | // handle single target branch 364 | BasicBlock *succ = branch->getSuccessor(0); 365 | 366 | IRBuilder<> builder(term); 367 | CallInst *callInst = createCallInst(BB, builder, ctx, *bbMap[succ]); 368 | if (callInst->getCalledFunction()->getReturnType()->isVoidTy()) { 369 | builder.CreateRetVoid(); 370 | } 371 | else { 372 | builder.CreateRet(callInst); 373 | } 374 | term->eraseFromParent(); 375 | return; 376 | } 377 | else { 378 | // handle multi target branch 379 | BasicBlock *succ0 = branch->getSuccessor(0); 380 | BasicBlock *succ1 = branch->getSuccessor(1); 381 | BasicBlock *bb0 = BasicBlock::Create(BB.getContext(), "call_" + succ0->getName(), 382 | BB.getParent()); 383 | BasicBlock *bb1 = BasicBlock::Create(BB.getContext(), "call_" + succ1->getName(), 384 | BB.getParent()); 385 | BasicBlock *bb2 = BasicBlock::Create(BB.getContext(), "retblock", BB.getParent()); 386 | 387 | branch->setSuccessor(0, bb0); 388 | branch->setSuccessor(1, bb1); 389 | 390 | IRBuilder <> builder(bb0); 391 | CallInst *callInst0 = createCallInst(BB, builder, ctx, *bbMap[succ0]); 392 | builder.CreateBr(bb2); 393 | 394 | builder.SetInsertPoint(bb1); 395 | CallInst *callInst1 = createCallInst(BB, builder, ctx, *bbMap[succ1]); 396 | builder.CreateBr(bb2); 397 | 398 | builder.SetInsertPoint(bb2); 399 | Type *retTy = callInst0->getCalledFunction()->getReturnType(); 400 | if (retTy->isVoidTy()) { 401 | builder.CreateRetVoid(); 402 | } 403 | else { 404 | PHINode *phi = builder.CreatePHI(retTy, 2); 405 | phi->addIncoming(callInst0, bb0); 406 | phi->addIncoming(callInst1, bb1); 407 | builder.CreateRet(phi); 408 | } 409 | 410 | return; 411 | } 412 | } 413 | 414 | // SwitchInst, IndirectBrInst, InvokeInst, ResumeInst, CatchSwitchInst, 415 | // CatchReturnInst, and CleanupReturnInst are not implemented. 416 | errs() << "Unsupported terminator: '" << *term << "'\n"; 417 | exit(1); 418 | } 419 | 420 | 421 | /** 422 | * @brief Replace Uses of Values with arguments. At this point, BasicBlocks 423 | * still reference Values that were created outside of the current 424 | * function. 425 | * @param ctx Context for the current extracted BasicBlock. 426 | */ 427 | void fixupArgumentUses(BBContext &ctx) { 428 | auto ai = ctx.Func->arg_begin(); 429 | for (auto &it : ctx.params) { 430 | Value *value = it.first; 431 | Argument &arg = *ai; 432 | arg.setName(value->getName()); 433 | for (Use *U : it.second) { 434 | U->set(&arg); 435 | } 436 | ai++; 437 | } 438 | for (auto &it : ctx.phis) { 439 | PHINode *phi = it.first; 440 | Argument &arg = *ai; 441 | arg.setName(phi->getName()); 442 | for (Use *U : it.second) { 443 | U->set(&arg); 444 | } 445 | ai++; 446 | } 447 | } 448 | 449 | 450 | /** 451 | * @brief Remove PHINodes that were replaced with parameters. 452 | * @param ctx Context for the current extracted BasicBlock. 453 | */ 454 | void removePhis(BBContext &ctx) { 455 | for (auto &it : ctx.phis) { 456 | PHINode *phi = it.first; 457 | phi->eraseFromParent(); 458 | } 459 | } 460 | 461 | 462 | /** 463 | * @brief Extract basic blocks from a function. 464 | * @param M Module to insert extracted functions into. 465 | * @param Func Function to extract BasicBlocks from. 466 | */ 467 | void extractBasicBlocks(Module &M, Function &Func) { 468 | LLVM_DEBUG(dbgs() << "extractBasicBlocks("); 469 | LLVM_DEBUG(dbgs().write_escaped(Func.getName()) << ")\n"); 470 | 471 | // add a dummy BasicBlock as the function entry block that only branches 472 | // to the true entry block. this will ensure we have a single BasicBlock 473 | // that will be the root node for the postorder traversal. 474 | BasicBlock &startBB = Func.getEntryBlock(); 475 | BasicBlock *entryBB = BasicBlock::Create(Func.getContext(), "entry", &Func, &startBB); 476 | IRBuilder<> builder(entryBB); 477 | builder.CreateBr(&startBB); 478 | 479 | #if defined(SPLIT_BASICBLOCKS) 480 | // Pass 1: Split BasicBlocks into blocks with a single Instruction 481 | for (BasicBlock &BB : Func) { 482 | splitBasicBlock(BB); 483 | } 484 | #endif // SPLIT_BASICBLOCKS 485 | 486 | // Pass 2: Recursive postorder traversal of the CFG to determine 487 | // parameters needed for each extracted BasicBlock. Multiple iterations 488 | // may be required to handle loops. 489 | BBMap bbMap; 490 | SmallPtrSet seenBB; 491 | while (visitBasicBlock(startBB, bbMap, seenBB)) { 492 | ; 493 | } 494 | 495 | // Pass 3: Extract BasicBlocks into new functions 496 | for (auto &pair : bbMap) { 497 | extractBasicBlock(M, *pair.second); 498 | } 499 | 500 | // Pass 4: Fixup BasicBlock transitions by converting branches to calls 501 | fixupTerminator(*entryBB, nullptr, bbMap); 502 | for (auto &pair : bbMap) { 503 | fixupTerminator(*pair.second->BB, pair.second.get(), bbMap); 504 | fixupArgumentUses(*pair.second); 505 | } 506 | 507 | 508 | // Pass 5: Remove PHINodes that were replaced with parameters 509 | for (auto &pair : bbMap) { 510 | removePhis(*pair.second); 511 | } 512 | 513 | NumBlocksExtracted += bbMap.size(); 514 | } 515 | 516 | 517 | struct ExtractBB : public ModulePass { 518 | static char ID; 519 | 520 | ExtractBB() : ModulePass(ID) {} 521 | 522 | bool runOnModule(Module &M) override { 523 | // build the list of functions to extract before extracting them, as 524 | // we will be adding extracted functions to the module as we go. 525 | SmallVector functions; 526 | for (Function &Func : M) { 527 | // only extract BasicBlocks if the function contains at least one 528 | // BasicBlock. external functions will have 0 BasicBlocks. 529 | if (!Func.empty()) { 530 | functions.push_back(&Func); 531 | } 532 | } 533 | 534 | for (Function *Func : functions) { 535 | extractBasicBlocks(M, *Func); 536 | } 537 | 538 | return false; 539 | } 540 | }; 541 | 542 | static void addExtractBBPass(const PassManagerBuilder &Builder, legacy::PassManagerBase &PM) { 543 | PM.add(new ExtractBB()); 544 | } 545 | 546 | } // namespace 547 | 548 | 549 | char ExtractBB::ID = 0; 550 | static RegisterPass X("extractbb", "Extract Basic Blocks", false, false); 551 | 552 | // automatically register pass when loaded by clang 553 | static RegisterStandardPasses RegisterExtractBBO0(PassManagerBuilder::EP_EnabledOnOptLevel0, 554 | addExtractBBPass); 555 | static RegisterStandardPasses RegisterExtractBBOx(PassManagerBuilder::EP_OptimizerLast, 556 | addExtractBBPass); 557 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LLVM Obfuscation Pass via Extracted Basic Blocks 2 | 3 | Obfuscate a target program by converting all branches between basic blocks to 4 | call instructions. 5 | 6 | 7 | ## Description 8 | 9 | This project provides two LLVM passes that can be used to obfuscate a target 10 | program by modifying the program's control flow and call graph. The control 11 | flow for individual functions will be obfuscated by converting transitions 12 | between basic blocks from traditional branch instructions to calls. This has 13 | the effect of making a function's control flow logic interprocedural, which is 14 | often poorly handled by traditional reverse engineering tools. 15 | 16 | Each optimization pass is implemented as an LLVM plugin. The `LLVMExtractBB.so` 17 | plugin will convert basic block transitions to calls. The `LLVMExtractInst.so` 18 | plugin will split basic blocks into individual instructions before modifying 19 | any transitions. This causes a significant increase in the number of resulting 20 | functions. 21 | 22 | When compiled with clang-8, IDA identifies 29 total functions in this short 23 | test program (including imports). 24 | 25 | ![Test program with normal control flow](./images/example.png) 26 | 27 | When compiled with LLVMExtractInst enabled, IDA identifies 105 total functions. 28 | Most functions have a similar CFG (a singular basic block or four basic blocks 29 | in a diamond pattern). 30 | 31 | ![Test program with obfuscated control flow](./images/example_extractinst.png) 32 | 33 | Note that loops in a function will be transformed into recursive function calls 34 | as a side effect of this pass. As such, infinite or high repitition loops may 35 | result in stack exhaustion. 36 | 37 | 38 | ## Build Instructions 39 | 40 | This project can be built as an out-of-tree module, or directly within the LLVM 41 | source tree. 42 | 43 | ### Out of Tree Build 44 | 45 | 1. Install build dependencies. 46 | 47 | ``` 48 | apt install cmake clang-8 llvm-8.0-dev 49 | ``` 50 | 51 | 1. Compile the plugins with cmake. 52 | 53 | ``` 54 | mkdir build && cd build 55 | cmake .. 56 | make -j2 57 | ``` 58 | 59 | ### In Tree Build 60 | 61 | 1. Create a symlink or copy the `ExtractBB` directory to 62 | `/lib/Transforms`. 63 | 64 | 1. Add `add_subdirectory(ExtractBB)` to 65 | `/lib/Transforms/CMakeLists.txt`. 66 | 67 | 1. Build LLVM as described in the LLVM documentation. 68 | 69 | 70 | ## Usage 71 | 72 | Either plugin can be loaded directly from clang, or invoked manually with the 73 | `opt` tool. If loaded by clang, the plugin's pass will automatically run 74 | regardless of the optimization level. If loaded by `opt`, you must specify an 75 | additional flag to enable the pass. 76 | 77 | To compile using clang: 78 | 79 | clang-8 -Xclang -load -Xclang ./LLVMExtract(BB|Inst).so file.c 80 | 81 | To compile using `opt`: 82 | 83 | clang-8 -c -emit-llvm file.c 84 | opt-8 -load ./LLVMExtract(BB|Inst).so -extractbb file.bc > file_opt.bc 85 | clang-8 file_opt.bc 86 | 87 | ### Debugging the Plugin 88 | 89 | To debug or view statistics generated by this plugin, the following additional 90 | options can be passed to `opt`. 91 | 92 | Print debug output from all passes: 93 | 94 | opt-8 -debug -load ./LLVMExtract(BB|Inst).so -extractbb file.bc > file_opt.bc 95 | 96 | Print debug output from only this plugin's pass: 97 | 98 | opt-8 -debug-only=extractbb -load ./LLVMExtract(BB|Inst).so -extractbb file.bc > file_opt.bc 99 | 100 | Print duration of all passes: 101 | 102 | opt-8 --time-passes -load ./LLVMExtract(BB|Inst).so -extractbb file.bc > file_opt.bc 103 | 104 | Print the pass structure: 105 | 106 | opt-8 --debug-pass=Structure -load ./LLVMExtract(BB|Inst).so -extractbb file.bc > file_opt.bc 107 | 108 | Debug the pass itself: 109 | 110 | gdb opt-8 111 | run -load ./LLVMExtract(BB|Inst).so -extractbb file.bc > file_opt.bc 112 | -------------------------------------------------------------------------------- /images/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shareef12/ExtractBB/8cc4ddf2502353450e88f435b252e39d4bc31c8d/images/example.png -------------------------------------------------------------------------------- /images/example_extractinst.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shareef12/ExtractBB/8cc4ddf2502353450e88f435b252e39d4bc31c8d/images/example_extractinst.png --------------------------------------------------------------------------------