<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      使用 SVF 分析某個開源項目

      因為一些學習任務需要在本地使用 SVF 構建某個項目的 CallGraph,中間遇到一點問題

      wLLVM

      參考 https://blog.csdn.net/weixin_47778392/article/details/141107768

      SVF 編譯時終端 exited with code 1

      需要更新 CMake 版本,嘗試更新 CMake:參考 https://blog.csdn.net/qq_42176274/article/details/144149612

      使用 SVF 分析一個簡單 demo

      寫一個包含直接調用和間接調用的 c 語言 demo:

      #include <stdio.h>
      
      void foo() {
          printf("foo\n");
      }
      
      void bar() {
          printf("bar\n");
      }
      
      int main() {
          void (*fp)() = bar;
          fp();           // 間接調用
          foo();          // 直接調用
          return 0;
      }
      

      獲取 bitcode,編譯時注意關閉 optnone

      clang -O0 -g -emit-llvm -c demo.c -o demo.bc -Xclang -disable-O0-optnone
      

      編譯復雜項目的時候用 wllvm 導出 bitcode,以 httpd 為例:

      CC=wllvm CFLAGS="-O0 -g -save-temps=obj -fno-discard-value-names -w -Xclang -disable-O0-optnone" ./configure
      make
      extract-bc -l llvm-link httpd
      

      使用 Anderson 指針分析構造 callgraph: wpa -ander -dump-callgraph demo.bc

      callgraph_initial.dot

      digraph "Call Graph" {
      	label="Call Graph";
      
      	Node0x55d3e7dd2620 [shape=record,shape=box,label="{CallGraphNode ID: 0 \{fun: foo\}|{<s0>1}}"];
      	Node0x55d3e7dd2620:s0 -> Node0x55d3e7da6830[color=black];
      	Node0x55d3e7da4ab0 [shape=record,shape=box,label="{CallGraphNode ID: 1 \{fun: bar\}|{<s0>2}}"];
      	Node0x55d3e7da4ab0:s0 -> Node0x55d3e7da6830[color=black];
      	Node0x55d3e7da4bf0 [shape=record,shape=box,label="{CallGraphNode ID: 2 \{fun: main\}|{<s0>3}}"];
      	Node0x55d3e7da4bf0:s0 -> Node0x55d3e7dd2620[color=black];
      	Node0x55d3e7da6830 [shape=record,shape=Mrecord,label="{CallGraphNode ID: 3 \{fun: printf\}}"];
      	Node0x55d3e7da6970 [shape=record,shape=Mrecord,label="{CallGraphNode ID: 4 \{fun: llvm.dbg.declare\}}"];
      }
      

      callgraph_final.dot

      digraph "Call Graph" {
      	label="Call Graph";
      
      	Node0x55d3e7dd2620 [shape=record,shape=box,label="{CallGraphNode ID: 0 \{fun: foo\}|{<s0>1}}"];
      	Node0x55d3e7dd2620:s0 -> Node0x55d3e7da6830[color=black];
      	Node0x55d3e7da4ab0 [shape=record,shape=box,label="{CallGraphNode ID: 1 \{fun: bar\}|{<s0>2}}"];
      	Node0x55d3e7da4ab0:s0 -> Node0x55d3e7da6830[color=black];
      	Node0x55d3e7da4bf0 [shape=record,shape=box,label="{CallGraphNode ID: 2 \{fun: main\}|{<s0>3|<s1>4}}"];
      	Node0x55d3e7da4bf0:s0 -> Node0x55d3e7dd2620[color=black];
      	Node0x55d3e7da4bf0:s1 -> Node0x55d3e7da4ab0[color=red];
      	Node0x55d3e7da6830 [shape=record,shape=Mrecord,label="{CallGraphNode ID: 3 \{fun: printf\}}"];
      	Node0x55d3e7da6970 [shape=record,shape=Mrecord,label="{CallGraphNode ID: 4 \{fun: llvm.dbg.declare\}}"];
      }
      

      容易觀察到,通過指針分析,(通過函數指針的)間接調用被識別出來添加到 callgraph 里面了。接下來可以通過寫一個簡單的 llvm pass 從 bitcode 里面分析哪些是間接調用,從而分析 SVF 給出的 callgraph 中函數指針有沒有被分析出來(或者說被分析認為是哪些函數)

      寫一個 IndirectCallPass

      對于一個 CallBase,如果 getCalledFunction() == nullptr,可以認為它是一個間接調用。

      
      #include "llvm/IR/PassManager.h"
      #include "llvm/IR/Function.h"
      #include "llvm/IR/Instructions.h"
      #include "llvm/Support/raw_ostream.h"
      #include "llvm/Passes/PassPlugin.h"
      #include "llvm/Passes/PassBuilder.h"
      #include <fstream>
      
      using namespace llvm;
      
      namespace {
      struct IndirectCallPass : public PassInfoMixin<IndirectCallPass> {
        PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM) {
          static std::ofstream outfile("indirect_calls.jsonl", std::ios::app);
          unsigned callsite_idx = 0;
          for (auto &BB : F) {
            for (auto &I : BB) {
              if (auto *callInst = dyn_cast<CallBase>(&I)) {
                auto *calledFunc = callInst->getCalledFunction();
                if (calledFunc && calledFunc->isIntrinsic()){
                  continue;
                }
                if (!callInst->getCalledFunction()) {
                  outfile << F.getName().str() << "," << callsite_idx << "\n";
                }
                callsite_idx++;
              }
            }
          }
          return PreservedAnalyses::all();
        }
      };
      } // namespace
      
      // 注冊Pass(供opt工具使用)
      llvm::PassPluginLibraryInfo getIndirectCallPassPluginInfo() {
        return {LLVM_PLUGIN_API_VERSION, "find-indirect-calls", LLVM_VERSION_STRING,
                [](PassBuilder &PB) {
                  PB.registerPipelineParsingCallback(
                      [](StringRef Name, FunctionPassManager &FPM,
                         ArrayRef<PassBuilder::PipelineElement>) {
                        if (Name == "find-indirect-calls") {
                          FPM.addPass(IndirectCallPass());
                          return true;
                        }
                        return false;
                      });
                }};
      }
      
      extern "C" LLVM_ATTRIBUTE_WEAK ::llvm::PassPluginLibraryInfo llvmGetPassPluginInfo() {
        return getIndirectCallPassPluginInfo();
      }
      

      通過 opt 工具使用這個 pass:

      opt -load-pass-plugin=./IndirectCallPass.so -passes="find-indirect-calls" ./httpd.bc
      

      對于通過 SVF 的 Anderson 導出的 callgraph,它不能精確到調用點位置信息,只能得到“某些函數調用了哪些函數”這樣的信息。導出的 ICFG 也暫時只包含分析前的結果。所以最好還是把 SVF 作為一個 library 導入并使用。

      === SVF 關于 callgraph 和間接調用的部分源碼分析

      觀察 SVF 的 CallGraph.h 文件:

      • class CallGraphEdge:從函數 A 到函數 B 的多個調用會被合并成一個調用邊,每個邊有一組直接調用和一組間接調用 CallInstSet indirectcalls,每個調用邊有一個 CallSiteID csId(這個設計有點奇怪),有方法 getIndirectCalls()

      • class CallGraph:在多個指針分析中會被使用,每個調用圖有一個成員 CallEdgeMap indirectCallMap 維護某個圖上節點 CallICFGNode 到間接調用的函數的映射,有方法 hasIndCSCalleesgetIndCSCallees 判別和獲取間接調用的函數信息,getIndCallSitesInvokingCallee 獲取間接調用對應的調用點

      感覺內容暫時夠用,可以先在官方提供的 SVF-example 上試驗一下,獲取所有的間接調用的 callsite 及其指針分析后結果(指向哪些函數)

      === 在項目中使用 SVF,并且獲取間接調用可能指向的函數

      對于上面的 demo.c,可以在 SVF-example 里面寫:

        CallGraph::CallEdgeMap &indCallMap = callgraph->getIndCallMap();
        std::ofstream outfile("indirect_calls");
        for (CallGraph::CallEdgeMap::iterator it = indCallMap.begin(), eit = indCallMap.end(); it != eit; ++it) {
          const CallICFGNode *cs = it->first;
          const CallGraph::FunctionSet &callees = it->second;
          for (const FunObjVar *callee : callees) {
              std::string calleeName = callee ? callee->getName() : "<unknown>";
              outfile << cs->getSourceLoc() << " : " << calleeName << std::endl;
          }
        }
        outfile.close();
      

      輸出結果應當形如:

      CallICFGNode: { "ln": 25, "cl": 5, "fl": "demo.c" } : baz
      ...
      

      改進了一下 demo,用一個 array 來放函數指針,發現 anderson 給出的結果不夠精確。

      使用 SVF-example 分析一下 httpd 項目,得到結果:

      ...
      CallICFGNode: { "ln": 301, "cl": 34, "fl": "config.c" } : merge_core_dir_configs
      ...
      

      去看源代碼,發現這里確實對應一個函數指針:

      conf_vector[i] = (*df)(p, base_vector[i], new_vector[i]);
      

      使用前面的 llvm pass 跑一下所有間接調用發生的位置,觀察 anderson 的推理結果(是否有忽略的函數指針):

      config.c,85,977
      config.c,88,963
      config.c,93,1014
      config.c,98,945
      config.c,102,996
      config.c,160,960
      config.c,165,928
      config.c,169,870
      ...
      

      發現 llvm pass 識別出了一些特殊形式的東西,比如對于宏定義:

      AP_IMPLEMENT_HOOK_RUN_ALL(int, header_parser,
                                (request_rec *r), (r), OK, DECLINED)
      

      這個宏定義會被展開成一個包含間接調用的函數,anderson 靜態分析沒有實際做這個分析,暫時不知道是因為宏的問題還是 array 的問題。

      ===

      posted @ 2025-07-15 19:23  sysss  閱讀(33)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 精品久久一线二线三线区| 在线免费不卡视频| 久久精品亚洲中文字幕无码网站 | 色护士极品影院| 国产一区二区三区十八禁| 福利一区二区在线观看| 野外做受又硬又粗又大视频√| 人妻有码av中文字幕久久琪| 动漫av网站免费观看| 上司人妻互换中文字幕| 国产一精品一av一免费爽爽| 久热久热免费在线观视频| 久久99精品久久久久久| 调兵山市| 黄色不卡视频一区二区三区| 欧美变态另类zozo| 中国女人熟毛茸茸A毛片| 免费观看的av在线播放| 人妻无码vs中文字幕久久av爆 | 久久亚洲国产欧洲精品一| 国精产品999国精产| 国产在线国偷精品免费看| 成午夜福利人试看120秒| 亚洲国产五月综合网| 国产精品 欧美激情 在线播放| 精品国产免费一区二区三区香蕉| 久久狠狠一本精品综合网| 超碰人人超碰人人| 亚洲精品www久久久久久| 欧洲熟妇色自偷自拍另类| 亚洲狠狠婷婷综合久久久| 内射囯产旡码丰满少妇| 在线精品国产中文字幕| 铁岭县| 亚洲综合中文字幕第一页| 重口SM一区二区三区视频| 口爆少妇在线视频免费观看| 国产在线观看黄| 免费看黄色片| 亚洲性日韩精品一区二区三区 | 九九热精品视频在线免费|