如何从 Rust 程序的 LLVM IR 代码中找到用于测试的函数指针?

How do I find the function pointers for tests from the LLVM IR code of a Rust program?

我们正在开发 mutation testing system based on LLVM。该系统支持使用 GoogleTest 的 C++ 项目,我正在尝试支持 Rust。为此,我们需要完成以下步骤:

  1. 将语言编译成LLVM IR。 Rust 支持这个。
  2. 在 LLVM IR 中找到测试。
  3. 运行 测试由测试 ("testees") 执行的代码。

挑战在于通过 LLVM IR 找到单元测试方法 API。

考虑 the following example。它有 4 个测试和一个 testee 函数:

pub fn sum(a: i32, b: i32) -> i32 {
    return a + b;
}

pub fn just_print() {
    println!("I am just_print() function. I just say hello!");
}

#[test]
fn rusttest_foo_sum1() {
    assert!(sum(3, 4) == 7);
}

#[test]
fn rusttest_foo_sum2() {
    assert!(sum(4, 5) == 9);
}

#[test]
fn rusttest_foo_sum3() {
    assert!(sum(5, 6) == 11);
}

#[test]
fn rusttest_foo_sum4() {
    assert!(sum(5, 6) == 11);
}

这是编译这段 Rust 代码时产生的the slightly prettified LLVM IR

探索 LLVM IR 一段时间后,可以注意到 Rust/Cargo 运行 通过函数 main 进行测试,该函数调用给定数组的 test_main_static 函数的描述。每个描述都是一对测试函数名和测试函数指针。 See the @ref.e at line 47.

我们的挑战是通过解析这个复杂的结构布局来收集指向这些测试的函数指针,以便稍后我们可以通过 LLVM JIT 运行 通过给它我们积累的函数指针来 运行 这些函数。

我们将采用的明显的蛮力方法是 运行 通过此结构布局并仔细解析结构并找到测试函数的正确偏移量。这种方法似乎无法跨不同版本的 Rust 或 LLVM IR 移植,将来可能会发生变化。

除了默认的手动解析偏移量之外,找到测试函数指针的最简单同时可靠的方法是什么?

这个问题也cross-posted to the Rust forums

made it work 通过使用我在问题中概述的 brute-force 方法。使用 LLVM C++ API,我们:

  • 找到指向 test_main_static
  • 的指针
  • test_main_static
  • 中找到对 @ref.e 的引用
  • 枚举@ref.e结构并找到测试函数指针

该方法似乎可行,但我们仍然担心它可能无法跨 Rust/LLVM 的不同版本移植。我们接下来的步骤之一是对 rustc --test 生成的 LLVM IR 进行完整性检查。另一个步骤是在真实代码库上尝试这个 RustTestFinder 看看我们是否有任何问题。

我仍然会感谢 rustc --test 提供的任何有关 LLVM IR 的信息,这些信息可以使事情变得更简单。