1

我正在使用 clang 开发 libtooling。我开发了一个工具来查找全局变量以及这些全局变量的引用位置。

现在,我想获取使用这些全局变量的函数名称。

这是示例代码

int Var;

int display()
{
  Var = 10;
return Var;
}

int main()
{
  display();
return 0;
}

在这里,我想Var在 Function 中引用该全局变量display

如何使用 LibTooling clang 获取此输出?请让我知道是否有任何解决方案。

4

1 回答 1

0

有可能与libTooling. 如果您已经找到DeclRefExpr引用全局变量的节点,则可以将 AST 向上传递给它们的FunctionDecl父节点。

另一方面,走上 AST 需要 Clang 构建从节点到其父节点的映射(这对于大型翻译单元来说可能相当昂贵)。在这里,我整理了一个简短的解决方案,它只找到引用全局变量的函数并打印它们的名称:

class GlobalVariableFinder final
    : public RecursiveASTVisitor<GlobalVariableFinder> {
public:
  static bool find(FunctionDecl *CandidateFunction) {
    GlobalVariableFinder ActualFinder;
    ActualFinder.TraverseDecl(CandidateFunction);
    return ActualFinder.Found;
  }

  bool VisitDeclRefExpr(DeclRefExpr *SymbolUse) {
    // we are interested only in variables
    if (auto *Declaration = dyn_cast<VarDecl>(SymbolUse->getDecl())) {
      Found = Declaration->hasGlobalStorage();
      // if we found one global variable use, there is no need in traversing
      // this function any further
      if (Found) return false;
    }
    return true;
  }
private:
  bool Found = false;
};

class VisitingASTConsumer final
    : public ASTConsumer,
      public RecursiveASTVisitor<VisitingASTConsumer> {
public:
  void HandleTranslationUnit(ASTContext &C) {
    this->TraverseTranslationUnitDecl(Context->getTranslationUnitDecl());
  }

  bool VisitFunctionDecl(FunctionDecl *CandidateFunction) {
    if (GlobalVariableFinder::find(CandidateFunction)) {
      llvm::errs() << CandidateFunction->getQualifiedNameAsString() << "\n";
    }
    return true;
  }
};

如果要存储全局变量引用,则可能需要修改GlobalVariableFinder类以包含其他逻辑。

以下解决方案在此代码片段上产生以下输出:

int Var;

int display()
{
  Var = 10;
  return Var;
}

int foo() {
  return Var;
}

int bar() {
  return foo();
}

int main()
{
  display();
  return 0;
}
display
foo

您会注意到它仅包含在语法上使用全局变量的函数。如果您希望算法也能找到bar,您需要构建目标程序的调用图,并通过图的反向边(即我们的示例中的fromfoo到)传播有关全局变量的信息。bar

我希望这些信息对你有用。与 Clang 一起愉快地黑客攻击!

于 2019-11-02T13:05:26.557 回答