如何在LLVM中获取原始源代码和行号?

如何在LLVM中获取原始源代码和行号?,llvm,Llvm,我从LLVM源代码树的Hello.cpp修改了以下代码。代码当前打印函数、指令和操作数 我还想打印所访问的函数、指令和变量的源文件名和行号。有人能告诉我怎么做吗 $ cat Hello.cpp /* vim: set noexpandtab tabstop=2: */ #include "llvm/ADT/Statistic.h" #include "llvm/IR/Function.h" #include "llvm/IR/InstIterator.h" #include "llvm/Pass

我从LLVM源代码树的Hello.cpp修改了以下代码。代码当前打印函数、指令和操作数

我还想打印所访问的函数、指令和变量的源文件名和行号。有人能告诉我怎么做吗

$ cat Hello.cpp
/* vim: set noexpandtab tabstop=2: */
#include "llvm/ADT/Statistic.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/Pass.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;

#define DEBUG_TYPE "hello"

STATISTIC(HelloCounter, "Counts number of functions greeted");

namespace {
  // Hello - The first implementation, without getAnalysisUsage.
  struct Hello : public FunctionPass {
    static char ID; // Pass identification, replacement for typeid
    Hello() : FunctionPass(ID) {}

    bool runOnFunction(Function &F) override {
      ++HelloCounter;
      errs() << "Hello: ";
      errs().write_escaped(F.getName()) << '\n';

      for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) {
        errs() << "I:" << *I << "\n";
        for (Use &U : I->operands()) {
          Value *v = U.get();
          errs() << "v:" << *v << "\n";
        }
      }
      return false;
    }
  };
}

char Hello::ID = 0;
static RegisterPass<Hello> X("hello", "Hello World Pass");

$ ./main.sh ;./opt.sh 
Hello: main
I:  %1 = alloca i32, align 4
v:i32 1
I:  store i32 0, i32* %1, align 4
v:i32 0
v:  %1 = alloca i32, align 4
I:  call void (...) bitcast (void ()* @f to void (...)*)()
v:void (...)* bitcast (void ()* @f to void (...)*)
I:  ret i32 0
v:i32 0
Hello: f
I:  %1 = load i32, i32* @U, align 4
v:@U = common dso_local global i32 0, align 4
I:  %2 = add nsw i32 %1, 1
v:  %1 = load i32, i32* @U, align 4
v:i32 1
I:  store i32 %2, i32* @U, align 4
v:  %2 = add nsw i32 %1, 1
v:@U = common dso_local global i32 0, align 4
I:  ret void


==> main.sh <==
#!/usr/bin/env bash
# vim: set noexpandtab tabstop=2:

compile=(
    c++
    -I"$HOME"/opt/llvm/include
    -std=c++11 -Wall -pedantic
    -g -fPIC
    -fno-rtti
    -o Hello.cpp.o -c Hello.cpp
)
"${compile[@]}"
link=(
    c++
    -Wl,-flat_namespace -Wl,-undefined -Wl,suppress
    -o x.so
    Hello.cpp.o
)
"${link[@]}"

==> opt.sh <==
#!/usr/bin/env bash
# vim: set noexpandtab tabstop=2:

cmd=(
    ~/opt/llvm/bin/opt
    -load x.so
    -hello
)
"${cmd[@]}" < hello.bc > /dev/null

==> hello.c <==
/* vim: set noexpandtab tabstop=2: */
#include <stdio.h>

int U;

void f();

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

==> f.c <==
/* vim: set noexpandtab tabstop=2: */
#include <stdio.h>

extern int U;

void f() {
    ++U;
}
$cat Hello.cpp
/*vim:设置noexpandtab tabstop=2:*/
#包括“llvm/ADT/Statistic.h”
#包括“llvm/IR/Function.h”
#包括“llvm/IR/InstIterator.h”
#包括“llvm/Pass.h”
#包括“llvm/Support/raw_ostream.h”
使用名称空间llvm;
#定义调试类型“hello”
统计(HelloCounter,“统计函数的数量”);
名称空间{
//Hello-第一个实现,没有getAnalysisUsage。
struct Hello:public FunctionPass{
静态字符ID;//传递标识,替换typeid
Hello():FunctionPass(ID){}
bool runOnFunction(功能和F)覆盖{
++HelloCounter;

errs()您需要将这些值强制转换为
指令
,然后可以通过
DebugLoc
类访问调试信息:

Value *v = U.get();
Instruction *instruction = dyn_cast<Instruction>(v);
const llvm::DebugLoc &debugInfo = instruction->getDebugLoc();

std::string directory = debugInfo->getDirectory();
std::string filePath = debugInfo->getFilename();
int line = debugInfo->getLine();
int column = debugInfo->getColumn();
Value*v=U.get();
指令*指令=动态转换(v);
const llvm::DebugLoc&debugInfo=指令->getDebugLoc();
std::string directory=debugInfo->getDirectory();
std::string filePath=debugInfo->getFilename();
int line=debugInfo->getLine();
int column=debugInfo->getColumn();
UPD:确保包含所需的头文件:

#include <llvm/IR/DebugLoc.h>
#include <llvm/IR/DebugInfoMetadata.h>
#包括
#包括

请注意,只有在启用调试信息的情况下编译源文件时,这才可能。这些信息看起来像文件末尾的许多行,如
!39186=!DILocation(行:481,作用域:!39143)
(以及其他一些DIfoobar),以及一些IR指令上的一些标记,如
!dbg!39186
。您需要从开始。我遇到了以下错误。您知道怎么回事吗?
Hello.cpp:32:39:错误:成员访问不完整的类型“llvm::DILocation”std::string directory=debugInfo->getDirectory()/Users/pengy/opt/llvm/include/llvm/IR/Metadata.def:83:42:注意:转发声明'llvm::DILocation'
@user1424739您需要包含标题文件包含这些类的定义:我将更新答案。我遇到了分段错误。您能帮助尝试编码并查看有什么问题?
I:%1=alloca i32,对齐4堆栈转储:……14 opt 0x000000010f41d201 llvm::legacy::PassManager::run(llvm::Module&)+33 15 opt 0x000000010c80c234 main+28116 16 libdyld.dylib 0x00007fff569f0015 start+1./opt.sh:第12行:80208分段错误:11“${cmd[@]}“…
指令可能没有调试信息。调用
debugInfo->getDirectory()
相当于
debugInfo.get()->getDirectory()
,其中
返回指向
DILocation
的指针,在本例中可能是空指针。添加更多错误处理。不确定如何执行。我尝试了此操作。但它仍然会产生分段错误。请尝试该程序,看看有什么问题吗?谢谢。
auto di=debugInfo.get();if(di==null){errs()getFilename();int line=di->getLine();int column=di->getColumn();errs()