如何在运行时通过llvm或clang获得所有全局变量的地址和大小



我正在分析c/c++项目的内存错误跟踪(越界读/写)。我想在运行时创建所有全局变量地址的列表,即它们的边界。是否有任何解决方法与LLVM(例如一些LLVM模块通过)我可以想出,这样在运行时,我能够找到所有全局变量及其相应的大小?

下面的c伪代码描述了期望的结果。
// Example of file.cc
int i;
int a[3] = {0, 1, 2};
char *s = "Simple string";
SOME_LIST_TYPE global_list;
void track_global_vars() {
for (GLOBAL_VAR gv: GLOBAL_VAR gvs) {
LIST_ITEM *li = (LIST_ITEM*) malloc(sizeof(LIST_ITEM));
li->start = gv.getAddress();
li->end   = li->start + gv.getSize();
global_list.add(li);
}
}
int main(int argc, char *argv[]) {
track_global_vars();
// AT this point I would like to have:
// global_list -> [i_start, i_end] -> [a_start, a_end] -> [s_start, s_end] -> ...
// normal program execution
return 0;
}

有什么建议或解决方法吗?

LLVM传递AddressSanitizer已经检测到越界的内存访问,包括全局变量和堆栈和堆。您可以将-fsanitizer=address传递给clang来使用它。它甚至在相同的标志下被移植到GCC。您可以将它与UBSan(未定义行为清理器)结合使用,作为-fsanitize=address,undefined来捕获更多错误,同样可以在clang和gcc上使用。

如果出于某种原因你不想要ASan,你想继续构建一个反映全局变量大小和地址的系统,你可以在Cextern SOME_LIST_TYPE global_list;中声明一个全局变量,并有一个LLVM通道来填充数据。给定一个llvm::Module *M,你可以用for (auto GV : M->globals()) {(氧)扫描所有全局变量,你可以建立一个常数"GEP"它遍历全局类型的一个元素以获得指向结束的指针。请参阅GEP faq。作为LLVM API的提示,请注意,大多数这些指令,Add, Mul, GEP,以两种形式存在,llvm::Instruction的子类和llvm::ConstantExpr的子类。你需要第二个形式,如果你想让它成为常量数据,你可以初始化你的数组。

使用auto *the_array_to_fill = M->getNamedGlobal("global_list");获取global_list作为llvm::GlobalVariable,然后调用the_array_to_fill->setInitializer(...)设置其数据。您需要以您想要的类型和布局来准备数据,可能是一个具有两个成员(begin和end)的结构体的数组,或者是一个全部开始然后全部结束的数组,任何适合您的方法。LLVM教程介绍了如何创建LLVM IR,您需要使用它来构建初始化全局变量的类型和(常量!)值。

您可能还想要the_array_to_fill->setLinkage(llvm::GlobalValue::AppendingLinkage);,以便在链接时将所有翻译单元的所有全局变量组合到一个数组中,而不是"多个定义"。错误或使用弱链接并且只获得其中一个而丢弃其余的。

最新更新