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

时间:2017-02-11 15:37:31

标签: rust llvm llvm-ir

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

  1. 将语言编译为LLVM IR。 Rust支持这一点。
  2. 在LLVM IR中查找测试。
  3. 运行测试由测试执行的代码("被测者")。
  4. 挑战在于通过LLVM IR API找到单元测试方法。

    考虑the following example。它有4个测试和一个测试人员功能:

    main

    这是编译此Rust代码时生成的the slightly prettified LLVM IR

    在探索了LLVM IR一段时间之后,人们可以注意到Rust / Cargo通过调用test_main_static函数的函数public class Utilities { static boolean availability; static FirebaseDatabase fireDb = FirebaseDatabase.getInstance(); static DatabaseReference dbRef1; private static boolean checkAvailability(String ID) { /**check in firebase if the generated ID exists. if it exists return false, else return true**/ final String id = ID; availability = true; dbRef1 = fireDb.getReference("xdsdads"); dbRef1.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { try { if (dataSnapshot.hasChild(id) || dataSnapshot.hasChild("Room:" + id)) { Log.d("key", "Key exists!"); availability = false; } else { availability = true; } } catch (Exception e) { Log.d("Error", "error getting key" + e.toString()); } } @Override public void onCancelled(DatabaseError databaseError) { } }); Log.d("Availability","" + availability); return availability; } public static String generateID() { /**generates ID **/ String ID = ""; Random random = new Random(); for (int i = 0; i < 8; i++) { if (i < 4) { ID = ID + giveAlphabet(random.nextInt(26)); } else { ID = ID + random.nextInt(9); } } Log.d("ID",ID); if (checkAvailability(ID)) { return ID; } else { return generateID(); } } public static String giveAlphabet(int i) { /**returns an alphabet from A-Z**/ String[] alphabet = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}; String output = ""; try { if (i >= 0 && i < 26) { output = alphabet[i]; } else { throw new Exception("Value not between 0-26 cannot generate Alphabet"); } } catch (Exception e) { Log.d("Exception at Beacon", e.toString()); } return output; } 运行测试,该函数给出了描述数组。每个描述都是一对测试函数名称和测试函数指针。 See the @ref.e at line 47

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

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

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

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

1 个答案:

答案 0 :(得分:1)

made it work使用我在问题中概述的蛮力方法。使用LLVM C ++ API,我们:

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

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

我仍然感谢rustc --test生成的有关LLVM IR的任何信息,这些信息可以使事情变得更加直截了当。