有關LLVM(https://github.com/yejinlei/about-compiler)
一、Clang
clang分三個實體概念:
- clang驅動:利用現有OS、編譯環境以及參數選項來驅動整個編譯過程的工具。
- clang編譯器:利用clang前端組件及庫打造的編譯器,其入口為cc1_main; 參數為clang -cc1 或者 -Xclang;
- clang前端組件及庫:包括Support、Basic、Diagnostics、Preprocessor、Lexer、Sema、CodeGen等;
二、clang前端組件及庫
三、clang編譯器架構
3.1 編譯器選項(clang -cc1 -help,CC1Options.td中定義)
選項 說明 FrontendAction子類 ASTConsumer子類 備註
- -init-only | | InitOnlyAction | | 只做前端初始化
- -Eonly | 預處理 | PreprocessOnlyAction | | 只做預處理,不輸出
- -E | 預處理 | PrintPreprocessedAction | | 子選項還包括-P、-C、-dM、-dD具體查看PreprocessorOutputOptions類
- -dump-tokens | 列印token | DumpTokensAction | | 輸出tokens
- -dump-raw-tokens | 列印tokens | DumpRawTokensAction | | 輸出原始tokens,包括空格符
- -rewrite-test | 測試宏定義處理 | RewriteTestAction | | 類似-rewrite-macros,僅測試用
- -emit-html | 生成高亮的代碼網頁 | HTMLPrintAction | HTMLPrinter |
- -print-decl-contexts | 列印聲明 | DeclContextPrintAction | DeclContextPrinter |
- -ast-list | 列印ast節點 | ASTDeclListAction | ASTDeclNodeLister | clang -S -D_WIN32 -Xclang -ast-list hello.c
- -ast-dump | 列印ast詳細信息 | ASTDumpAction | ASTPrinter |
- -ast-view | 生成ast dot | ASTViewAction | ASTViewer |
- -analyze | 運行靜態分析引擎 | AnalysisAction | AnalysisConsumer | clang -cc1 -analyzer-checker-help顯示所有checkers;,具體請看《clang靜態分析器》
- -emit-llvm | 生成.ll IR彙編文件 | EmitLLVMAction | BackendConsumer | clang -S -D_WIN32 -Xclang -emit-llvm hello.c -o hello.ll
- -emit-llvm-bc | 生成.bc IR二進位文件 | EmitBCAction | BackendConsumer | clang -S -D_WIN32 -Xclang -emit-llvm-bc hello.c -o hello.bc
備註:
1. FrontendAction及其子類主要是前端功能的集合,不同的子類包含的功能不同;2. ASTConsumer及其子類主要是後端功能的集合,不同的子類包含的功能不同;3. 編譯器選項表格中基本上按功能從小到大排列;3.2 clang架構圖
3.3 clang流程分析
備註:
通過clang編譯器選項,來選擇創建不同的FrontendAction,具體在createFrontendBaseAction函數中,創建不同的FrontendAction對象
- FrontendAction::CreateASTConsumer用於創建不同ASTConsumer對象,因此需實現該函數;
- FrontendAction::ExecuteAction用於銜接後端,例如ASTFrontendAction::ExecuteAction調用ParseAST解析語法樹並傳遞給後端,而DumpRawTokensAction只列印tokens;
- 需要抽象語法樹的後端,需要調用ParseAST函數;
3.4 clang靜態分析器
按功能區分的選項(clang -cc1 -analyzer-checker-help,Checkers.td中定義)選項 | 說明 | 備註 -analyzer-checker=debug | |
Clang Static Analyzer就是利用不同的checker來檢測源碼不同類型的bug的。
靜態分析器會默認使用6類checkers(default checker):
- Core Checkers:提供一些一般性的檢查,比如是否被0除、是否使用空指針和使用未初始化參數等。
- C++ Checkers:提供C++檢查。
- Dead Code Checkers:檢查沒有使用的代碼。
- OS X Checkers:檢查Objective-C和Apples SDKs的使用情況。
- Security Checkers:檢查不安全API的使用和基於CERT Secure Coding Standards的檢查。
- Unix Checkers:檢查Unix和POSIX API的使用情況。
主要流程
- CheckerManager
- CheckerContext上下文
- addTransition方法,改變狀態
- generateSink
- ProgramPoint程序關鍵點(等同checker類成員函數、回調函數)
- [check::PreStmt] - 在statement xxx發生之前調用這個checker
- [check::PostStmt] - 在statement xxx發生之後調用這個checker
- [check::PreCall] - 在函數調用之前調用這個checker
- [check::EndFunction] - 在函數結束時調用這個checker
- [check::BranchCondition] - 在分支出現時調用這個checker
- [check::DeadSymbols] - 當參數超出生命周期時調用這個checker
- checker的回調函數要麼修改程序狀態,要麼報告bug
7. ProgramState表示程序所在狀態
- Clang Static Analyzer就像其他靜態分析工具一樣,並不會執行源代碼,而是象徵性的執行代碼(symbolic excution),並且會執行代碼中的每一個分支(Path Sensitive)。
- 在「執行」過程中,Analyzer會實時的根據運行情況追蹤和改變程序狀態(Program State)。
- 註冊狀態宏:REGISTERTRAITWITHPROGRAMSTATE、REGISTERMAPWITHPROGRAMSTATE、REGISTERSETWITHPROGRAMSTATE、REGISTERLISTWITHPROGRAMSTATE
- CheckerContext類包含了一些操作狀態的函數,例如獲取狀態getState(),更改狀態addTransition(State)、產生sink節點generateSink(),上報BUG EmitReport(BUG)
- 節點類ExplodedNode、BUG類BugReport、狀態類ProgramState
8. 如何編寫Checker
兩種編寫Checker方式:一、一種直接編譯進clang編譯器中;二、生成共享庫,由clang編譯器動態載入
方式一
- 在lib/StaticAnalyzer/Checkers目錄下,創建xxxxChecker.cpp
- xxxxChecker.cpp編寫Checke子類和註冊函數: using namespace clang; using namespace ento;
- }
namespace { class NewChecker: public Checker< check::PreStmt<CallExpr> > { public: void checkPreStmt(const CallExpr *CE, CheckerContext &Ctx) const {} }}void ento::registerxxxx(CheckerManager &mgr) { mgr.registerChecker<xxxx>();
- clang/lib/StaticAnalyzer/Checkers/Checkers.td註冊Checker歸屬關係,例如alpha.core.yyyy
let ParentPackage = CoreAlpha in {...def xxxxChecker : Checker<"yyyy">, //注意yyyy,任意名字 HelpText<"Checker功能表述">, DescFile<"xxxxChecker.cpp">;...} // end "alpha.core"
方式二
- 具體參考「SampleAnalyzerPlugin」例子
四、clang驅動
4.1 驅動選項(clang -help,Options.td定義)
- -cc1,clang編譯器
- -###,列印clang driver Parse階段命令行參數,參考:[Driver Design & Internals](Driver Design & Internals)
- -ccc-print-phases,列印clang driver Pipeline階段信息
- -ccc-print-bindings,列印clang driver Bind階段各工具鏈及輸入輸出文件
- -E,預處理
- -S,預處理~彙編
- -c,預處理~生成obj
- -fcolor-diagnostics,診斷色彩
- -driver-mode=cl,等同於clang-cl,兼容VC
- -emit-llvm,生成.ll中間語言文件
- -fpack-struct=1 or n,壓縮
- -Wunused-variable,未初始化4.2 驅動流程分析
推薦閱讀:
※llvm memcpy的本質?
※LLVM每日談之七 Clang
※LLVM國內的開發者需要Social一下嗎?
※[Debug] Clang / LLVM 關於continue語句的二三事