IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> LLVM ASAN【源码分析】(二)——调试分析 -> 正文阅读

[C++知识库]LLVM ASAN【源码分析】(二)——调试分析

LLVM ASAN【源码分析】(一)——简单分析》中通过已有资料简单分析了下ASAN结构。

由于看源码有点懵,进行Clang-ASAN源码调试

下面使用gdb调试分析ASAN源码。

gdb调试分析ASAN源码

Legacy ASAN不再使用,关注使用New PassManager的ASAN。Clang父进程创建子进程完成编译任务。

ASAN初始化时栈信息(子进程视角)

断点下在AddressSanitizerPass::AddressSanitizerPass(),栈信息如下(可以看到调用过程):

(gdb) set args -g -std=c++11 -fsanitize=address,fuzzer /home/leone/文档/libfuzzer-workshop/lessons/04/first_fuzzer.cc -o /home/leone/文档/libfuzzer-workshop/lessons/04/first_fuzzer
(gdb) set follow-fork-mode child
(gdb) b AddressSanitizerPass::AddressSanitizerPass
(gdb) r
(gdb) info stack
#0  llvm::AddressSanitizerPass::AddressSanitizerPass (this=0x7fffffff8650, CompileKernel=false, Recover=false, UseAfterScope=true, 
    UseAfterReturn=llvm::AsanDetectStackUseAfterReturnMode::Runtime)
    at /home/leone/文档/llvm-project/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp:1219
#1  0x000055555ecc7518 in operator() (__closure=0x7fffffff8700, Mask=..., CompileKernel=false)
    at /home/leone/文档/llvm-project/clang/lib/CodeGen/BackendUtil.cpp:1162
#2  0x000055555ecc785c in operator() (__closure=0x5555641c2f70, MPM=..., Level=...)
    at /home/leone/文档/llvm-project/clang/lib/CodeGen/BackendUtil.cpp:1166
#3  0x000055555ecce189 in std::__invoke_impl<void, addSanitizers(const llvm::Triple&, const clang::CodeGenOptions&, const clang::LangOptions&, llvm::PassBuilder&)::<lambda(llvm::ModulePassManager&, llvm::OptimizationLevel)>&, llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module> >&, llvm::OptimizationLevel>(std::__invoke_other, struct {...} &) (__f=...) at /usr/include/c++/10/bits/invoke.h:60
#4  0x000055555eccce28 in std::__invoke_r<void, addSanitizers(const llvm::Triple&, const clang::CodeGenOptions&, const clang::LangOptions&, llvm::PassBuilder&)::<lambda(llvm::ModulePassManager&, llvm::OptimizationLevel)>&, llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module> >&, llvm::OptimizationLevel>(struct {...} &) (__fn=...) at /usr/include/c++/10/bits/invoke.h:153
#5  0x000055555eccbbe3 in std::_Function_handler<void(llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module> >&, llvm::OptimizationLevel), addSanitizers(const llvm::Triple&, const clang::CodeGenOptions&, const clang::LangOptions&, llvm::PassBuilder&)::<lambda(llvm::ModulePassManager&, llvm::OptimizationLevel)> >::_M_invoke(const std::_Any_data &, llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module> > &, llvm::OptimizationLevel &&) (__functor=..., __args#0=..., __args#1=...) at /usr/include/c++/10/bits/std_function.h:291
#6  0x000055555fd9ff59 in std::function<void (llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>&, llvm::OptimizationLevel)>::operator()(llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>&, llvm::OptimizationLevel) const (this=0x7fffffff98e0, 
    __args#0=..., __args#1=...) at /usr/include/c++/10/bits/std_function.h:622
#7  0x000055555fd4f634 in llvm::PassBuilder::buildO0DefaultPipeline (this=0x7fffffff9650, Level=..., LTOPreLink=false)
    at /home/leone/文档/llvm-project/llvm/lib/Passes/PassBuilder.cpp:1993
#8  0x000055555ecc9568 in (anonymous namespace)::EmitAssemblyHelper::EmitAssemblyWithNewPassManager (this=0x7fffffff9dd0, 
    Action=clang::Backend_EmitObj, OS=std::unique_ptr<llvm::raw_pwrite_stream> = {...})
    at /home/leone/文档/llvm-project/clang/lib/CodeGen/BackendUtil.cpp:1408
#9  0x000055555eccafc7 in clang::EmitBackendOutput (Diags=..., HeaderOpts=..., CGOpts=..., TOpts=..., LOpts=..., TDesc=..., 
    M=0x555563e880f0, Action=clang::Backend_EmitObj, OS=std::unique_ptr<llvm::raw_pwrite_stream> = {...})
    at /home/leone/文档/llvm-project/clang/lib/CodeGen/BackendUtil.cpp:1658
#10 0x000055555f3a30e5 in clang::BackendConsumer::HandleTranslationUnit (this=0x555563e205e0, C=...)
    at /home/leone/文档/llvm-project/clang/lib/CodeGen/CodeGenAction.cpp:334
#11 0x00005555617e5f48 in clang::ParseAST (S=..., PrintStats=false, SkipFunctionBodies=false)
    at /home/leone/文档/llvm-project/clang/lib/Parse/ParseAST.cpp:171
#12 0x000055555f1e8d05 in clang::ASTFrontendAction::ExecuteAction (this=0x555563e5fb00)
    at /home/leone/文档/llvm-project/clang/lib/Frontend/FrontendAction.cpp:1058
#13 0x000055555f39f9b4 in clang::CodeGenAction::ExecuteAction (this=0x555563e5fb00)
    at /home/leone/文档/llvm-project/clang/lib/CodeGen/CodeGenAction.cpp:1044
#14 0x000055555f1e85c6 in clang::FrontendAction::Execute (this=0x555563e5fb00)
    at /home/leone/文档/llvm-project/clang/lib/Frontend/FrontendAction.cpp:951
#15 0x000055555f1205ac in clang::CompilerInstance::ExecuteAction (this=0x555563e57060, Act=...)
    at /home/leone/文档/llvm-project/clang/lib/Frontend/CompilerInstance.cpp:974
#16 0x000055555f38d456 in clang::ExecuteCompilerInvocation (Clang=0x555563e57060)
    at /home/leone/文档/llvm-project/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp:278
#17 0x000055555c355fe9 in cc1_main (Argv=..., Argv0=0x7fffffffd7ad "/opt/llvm/bin/clang-14", 
    MainAddr=0x55555c3488ea <GetExecutablePath[abi:cxx11](char const*, bool)>)
    at /home/leone/文档/llvm-project/clang/tools/driver/cc1_main.cpp:246
#18 0x000055555c34a206 in ExecuteCC1Tool (ArgV=...) at /home/leone/文档/llvm-project/clang/tools/driver/driver.cpp:338
#19 0x000055555c34a8d6 in main (Argc=83, Argv=0x7fffffffd138) at /home/leone/文档/llvm-project/clang/tools/driver/driver.cpp:409

从Clang父进程Main函数开始

线程刚启动时,记录栈底地址。作为LLVM工具执行一次性初始化。检查标准文件描述符。配置支持目标架构。设置命令行分词器。设置诊断功能。待Clang Driver解析完命令行后,ExecuteCompilation() Fork子进程执行具体编译任务。

// clang/tools/driver/driver.cpp
int main(...) {
	...
	if (C && !C->containsError()) {
		...
		Res = TheDriver.ExecuteCompilation(*C, FailingCommands);
		...
	}
	...
}

进入Clang子进程Main函数

子进程带着解析后的具体命令,完成配置后使用cc1执行具体编译任务。(代码如下)

// clang/tools/driver/driver.cpp
int main(...) {
	...
	if (FirstArg != Args.end() && StringRef(*FirstArg).startswith("-cc1")) {
		...
		return ExecuteCC1Tool(Args);
	}
	...
}

检查参数包含-cc1选项(Clang Driver分析命令行后加上的选项),调用cc1_main()

// clang/tools/driver/driver.cpp
static int ExecuteCC1Tool(SmallVectorImpl<const char *> &ArgV) {
  ...
  if (Tool == "-cc1")
    return cc1_main(makeArrayRef(ArgV).slice(1), ArgV[0], GetExecutablePathVP);
  ...
}

创建Clang实例并配置调用功能、前端选项和诊断功能,然后执行前端动作。

// clang/tools/driver/cc1_main.cpp
int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
	...
	// Execute the frontend actions.
	{
    	llvm::TimeTraceScope TimeScope("ExecuteCompiler");
    	Success = ExecuteCompilerInvocation(Clang.get());
    }
	...
}

解析前端选项,加载所需插件,基于Clang实例创建并执行前端动作。

// clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
/// ExecuteCompilerInvocation - Execute the given actions described by the
/// compiler invocation object in the given compiler instance.
///
/// \return - True on success.
bool ExecuteCompilerInvocation(CompilerInstance *Clang) {
	...
	// Create and execute the frontend action.
	std::unique_ptr<FrontendAction> Act(CreateFrontendAction(*Clang));
	if (!Act) return false;
	bool Success = Clang->ExecuteAction(*Act);
	...
}

配置前端动作,读取源文件并准备处理。

// clang/lib/Frontend/CompilerInstance.cpp
// High-Level Operations
/// ExecuteAction - Execute the provided action against the compiler's
/// CompilerInvocation object.
///
/// This function makes the following assumptions:
///
///  - The invocation options should be initialized. This function does not
///    handle the '-help' or '-version' options, clients should handle those
///    directly.
///
///  - The diagnostics engine should have already been created by the client.
///
///  - No other CompilerInstance state should have been initialized (this is
///    an unchecked error).
///
///  - Clients should have initialized any LLVM target features that may be
///    required.
///
///  - Clients should eventually call llvm_shutdown() upon the completion of
///    this routine to ensure that any managed objects are properly destroyed.
///
/// Note that this routine may write output to 'stderr'.
///
/// \param Act - The action to execute.
/// \return - True on success.
//
// FIXME: Eliminate the llvm_shutdown requirement, that should either be part
// of the context or else not CompilerInstance specific.
bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
  ...
  for (const FrontendInputFile &FIF : getFrontendOpts().Inputs) {
    ...
    if (Act.BeginSourceFile(*this, FIF)) {
      if (llvm::Error Err = Act.Execute()) {
        consumeError(std::move(Err)); // FIXME this drops errors on the floor.
      }
      Act.EndSourceFile();
    }
  }
  ...
}

执行后端CodeGen动作。

// clang/lib/Frontend/FrontendAction.cpp
/// Set the source manager's main input file, and run the action.
llvm::Error FrontendAction::Execute() {
  ...
  ExecuteAction(); //函数为虚函数,当前指向clang::CodeGenAction::ExecuteAction,类继承关系为class CodeGenAction : public ASTFrontendAction : public FrontendAction
  ...
}

当前文件所用语言不是IR,让ASTFrontendAction执行动作

// clang/lib/CodeGen/CodeGenAction.cpp
void CodeGenAction::ExecuteAction() {
  if (getCurrentFileKind().getLanguage() != Language::LLVM_IR) {
    this->ASTFrontendAction::ExecuteAction();
    return;
  }
  ...
}

获取编译器实例并创建Sema结构体以分析抽象语法树。

// clang/lib/Frontend/FrontendAction.cpp
/// Implement the ExecuteAction interface by running Sema(ntic) on
/// the already-initialized AST consumer.
///
/// This will also take care of instantiating a code completion consumer if
/// the user requested it and the action supports it.
void ASTFrontendAction::ExecuteAction() {
  ...
  ParseAST(CI.getSema(), CI.getFrontendOpts().ShowStats,
           CI.getFrontendOpts().SkipFunctionBodies);
}

AST分析中收集状态,配置语法结构体和分析器结构体。ASTConsumer处理顶级声明的词法分析,使用AST上下文处理转译单元(再次进入后端)。

// clang/lib/Parse/ParseAST.cpp
/// Parse the main file known to the preprocessor, producing an
/// abstract syntax tree.
void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) {
	...
	Consumer->HandleTranslationUnit(S.getASTContext());
	...
}	

AST分析、IR生成及模块链接后,发射后端输出。

// clang/lib/CodeGen/CodeGenAction.cpp
// clang::BackendConsumer::HandleTranslationUnit
// 继承关系 class BackendConsumer : public ASTConsumer
/// HandleTranslationUnit - This method is called when the ASTs for entire
/// translation unit have been parsed.
void HandleTranslationUnit(ASTContext &C) override {
	...
	EmitBackendOutput(...);
	...
}

构建汇编帮助工具实例,根据代码生成选项,使用新的PassManager发射二进制。

// clang/lib/CodeGen/BackendUtil.cpp
void clang::EmitBackendOutput(...) {
	...
	if (!CGOpts.LegacyPassManager)
    	AsmHelper.EmitAssemblyWithNewPassManager(Action, std::move(OS));
   	...
}

根据目标机器配置,各种选项结构体配置,构造PassBuilder,加载Pass插件并使用PassBuilder对其注册回调,注册几个Pass(Alias Analyses Manager、Target Library Analysis、Module Analyses、CGSCC Analyses、Function Analyses、Loop Analyses)

// clang/lib/CodeGen/BackendUtil.cpp
/// A clean version of `EmitAssembly` that uses the new pass manager.
///
/// Not all features are currently supported in this system, but where
/// necessary it falls back to the legacy pass manager to at least provide
/// basic functionality.
///
/// This API is planned to have its functionality finished and then to replace
/// `EmitAssembly` at some point in the future when the default switches.
void EmitAssemblyHelper::EmitAssemblyWithNewPassManager(
    BackendAction Action, std::unique_ptr<raw_pwrite_stream> OS) {
    ...
    if (!CodeGenOpts.DisableLLVMPasses) {
    	...
    	
   	}
   	...
}

未完待续。。。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-07 11:49:05  更:2021-08-07 11:49:36 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/26 4:53:39-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计