Home | History | Annotate | Download | only in DebugIR
      1 //===- DebugIR.cpp - Unit tests for the DebugIR pass ----------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // The tests in this file verify the DebugIR pass that generates debug metadata
     11 // for LLVM IR.
     12 //
     13 //===----------------------------------------------------------------------===//
     14 
     15 #include "llvm/ADT/Triple.h"
     16 #include "llvm/Config/config.h"
     17 #include "llvm/DebugInfo.h"
     18 #include "llvm/DIBuilder.h"
     19 #include "llvm/IR/Module.h"
     20 #include "llvm/Support/Host.h"
     21 #include "llvm/Support/FileSystem.h"
     22 #include "llvm/Support/Path.h"
     23 #include "llvm/Transforms/Instrumentation.h"
     24 
     25 #include "../lib/Transforms/Instrumentation/DebugIR.h"
     26 
     27 // These tests do not depend on MCJIT, but we use the TrivialModuleBuilder
     28 // helper class to construct some trivial Modules.
     29 #include "../unittests/ExecutionEngine/MCJIT/MCJITTestBase.h"
     30 
     31 #include <string>
     32 
     33 #include "gtest/gtest.h"
     34 
     35 #if defined(LLVM_ON_WIN32)
     36 #include <direct.h>
     37 #define getcwd_impl _getcwd
     38 #elif defined (HAVE_GETCWD)
     39 #include <unistd.h>
     40 #define getcwd_impl getcwd
     41 #endif // LLVM_ON_WIN32
     42 
     43 using namespace llvm;
     44 using namespace std;
     45 
     46 namespace {
     47 
     48 /// Insert a mock CUDescriptor with the specified producer
     49 void insertCUDescriptor(Module *M, StringRef File, StringRef Dir,
     50                         StringRef Producer) {
     51   DIBuilder B(*M);
     52   B.createCompileUnit(dwarf::DW_LANG_C99, File, Dir, Producer, false, "", 0);
     53   B.finalize();
     54 }
     55 
     56 /// Attempts to remove file at Path and returns true if it existed, or false if
     57 /// it did not.
     58 bool removeIfExists(StringRef Path) {
     59   bool existed = false;
     60   sys::fs::remove(Path, existed);
     61   return existed;
     62 }
     63 
     64 char * current_dir() {
     65 #if defined(LLVM_ON_WIN32) || defined(HAVE_GETCWD)
     66   // calling getcwd (or _getcwd() on windows) with a null buffer makes it
     67   // allocate a sufficiently sized buffer to store the current working dir.
     68   return getcwd_impl(0, 0);
     69 #else
     70   return 0;
     71 #endif
     72 }
     73 
     74 class TestDebugIR : public ::testing::Test, public TrivialModuleBuilder {
     75 protected:
     76   TestDebugIR()
     77       : TrivialModuleBuilder(sys::getProcessTriple())
     78       , cwd(current_dir()) {}
     79 
     80   ~TestDebugIR() { free(cwd); }
     81 
     82   /// Returns a concatenated path string consisting of Dir and Filename
     83   string getPath(const string &Dir, const string &Filename) {
     84     SmallVector<char, 8> Path;
     85     sys::path::append(Path, Dir, Filename);
     86     Path.resize(Dir.size() + Filename.size() + 2);
     87     Path[Dir.size() + Filename.size() + 1] = '\0';
     88     return string(Path.data());
     89   }
     90 
     91   LLVMContext Context;
     92   char *cwd;
     93   OwningPtr<Module> M;
     94   OwningPtr<DebugIR> D;
     95 };
     96 
     97 // Test empty named Module that is not supposed to be output to disk.
     98 TEST_F(TestDebugIR, EmptyNamedModuleNoWrite) {
     99   string Dir = "MadeUpDirectory";
    100   string File = "empty_module.ll";
    101   string Path(getPath(Dir, File));
    102 
    103   M.reset(createEmptyModule(Path));
    104 
    105   // constructing DebugIR with no args should not result in any file generated.
    106   D.reset(static_cast<DebugIR *>(llvm::createDebugIRPass()));
    107   D->runOnModule(*M);
    108 
    109   // verify DebugIR did not generate a file
    110   ASSERT_FALSE(removeIfExists(Path)) << "Unexpected file " << Path;
    111 }
    112 
    113 // Test a non-empty unnamed module that is output to an autogenerated file name.
    114 TEST_F(TestDebugIR, NonEmptyUnnamedModuleWriteToAutogeneratedFile) {
    115   M.reset(createEmptyModule());
    116   insertAddFunction(M.get());
    117   D.reset(static_cast<DebugIR *>(llvm::createDebugIRPass(true, true)));
    118 
    119   string Path;
    120   D->runOnModule(*M, Path);
    121 
    122   // verify DebugIR generated a file, and clean it up
    123   ASSERT_TRUE(removeIfExists(Path)) << "Missing expected file at " << Path;
    124 }
    125 
    126 // Test not specifying a name in the module -- DebugIR should generate a name
    127 // and write the file contents.
    128 TEST_F(TestDebugIR, EmptyModuleWriteAnonymousFile) {
    129   M.reset(createEmptyModule());
    130   D.reset(static_cast<DebugIR *>(llvm::createDebugIRPass(false, false)));
    131 
    132   string Path;
    133   D->runOnModule(*M, Path);
    134 
    135   // verify DebugIR generated a file and clean it up
    136   ASSERT_TRUE(removeIfExists(Path)) << "Missing expected file at " << Path;
    137 }
    138 
    139 #ifdef HAVE_GETCWD // These tests require get_current_dir_name()
    140 
    141 // Test empty named Module that is to be output to path specified at Module
    142 // construction.
    143 TEST_F(TestDebugIR, EmptyNamedModuleWriteFile) {
    144   string Filename("NamedFile1");
    145   string ExpectedPath(getPath(cwd, Filename));
    146 
    147   M.reset(createEmptyModule(ExpectedPath));
    148   D.reset(static_cast<DebugIR *>(llvm::createDebugIRPass(true, true)));
    149 
    150   string Path;
    151   D->runOnModule(*M, Path);
    152 
    153   // verify DebugIR was able to correctly parse the file name from module ID
    154   ASSERT_EQ(ExpectedPath, Path);
    155 
    156   // verify DebugIR generated a file, and clean it up
    157   ASSERT_TRUE(removeIfExists(Path)) << "Missing expected file at " << Path;
    158 }
    159 
    160 // Test an empty unnamed module generates an output file whose path is specified
    161 // at DebugIR construction.
    162 TEST_F(TestDebugIR, EmptyUnnamedModuleWriteNamedFile) {
    163   string Filename("NamedFile2");
    164 
    165   M.reset(createEmptyModule());
    166   D.reset(static_cast<DebugIR *>(llvm::createDebugIRPass(
    167       false, false, StringRef(cwd), StringRef(Filename))));
    168   string Path;
    169   D->runOnModule(*M, Path);
    170 
    171   string ExpectedPath(getPath(cwd, Filename));
    172   ASSERT_EQ(ExpectedPath, Path);
    173 
    174   // verify DebugIR generated a file, and clean it up
    175   ASSERT_TRUE(removeIfExists(Path)) << "Missing expected file at " << Path;
    176 }
    177 
    178 // Test an empty named module generates an output file at the path specified
    179 // during DebugIR construction.
    180 TEST_F(TestDebugIR, EmptyNamedModuleWriteNamedFile) {
    181   string Filename("NamedFile3");
    182 
    183   string UnexpectedPath(getPath(cwd, "UnexpectedFilename"));
    184   M.reset(createEmptyModule(UnexpectedPath));
    185 
    186   D.reset(static_cast<DebugIR *>(llvm::createDebugIRPass(
    187       false, false, StringRef(cwd), StringRef(Filename))));
    188   string Path;
    189   D->runOnModule(*M, Path);
    190 
    191   string ExpectedPath(getPath(cwd, Filename));
    192   ASSERT_EQ(ExpectedPath, Path);
    193 
    194   // verify DebugIR generated a file, and clean it up
    195   ASSERT_TRUE(removeIfExists(Path)) << "Missing expected file at " << Path;
    196 
    197   // verify DebugIR did not generate a file at the path specified at Module
    198   // construction.
    199   ASSERT_FALSE(removeIfExists(UnexpectedPath)) << "Unexpected file " << Path;
    200 }
    201 
    202 // Test a non-empty named module that is not supposed to be output to disk
    203 TEST_F(TestDebugIR, NonEmptyNamedModuleNoWrite) {
    204   string Filename("NamedFile4");
    205   string ExpectedPath(getPath(cwd, Filename));
    206 
    207   M.reset(createEmptyModule(ExpectedPath));
    208   insertAddFunction(M.get());
    209 
    210   D.reset(static_cast<DebugIR *>(llvm::createDebugIRPass()));
    211 
    212   string Path;
    213   D->runOnModule(*M, Path);
    214   ASSERT_EQ(ExpectedPath, Path);
    215 
    216   // verify DebugIR did not generate a file
    217   ASSERT_FALSE(removeIfExists(Path)) << "Unexpected file " << Path;
    218 }
    219 
    220 // Test a non-empty named module that is output to disk.
    221 TEST_F(TestDebugIR, NonEmptyNamedModuleWriteFile) {
    222   string Filename("NamedFile5");
    223   string ExpectedPath(getPath(cwd, Filename));
    224 
    225   M.reset(createEmptyModule(ExpectedPath));
    226   insertAddFunction(M.get());
    227 
    228   D.reset(static_cast<DebugIR *>(llvm::createDebugIRPass(true, true)));
    229 
    230   string Path;
    231   D->runOnModule(*M, Path);
    232   ASSERT_EQ(ExpectedPath, Path);
    233 
    234   // verify DebugIR generated a file, and clean it up
    235   ASSERT_TRUE(removeIfExists(Path)) << "Missing expected file at " << Path;
    236 }
    237 
    238 // Test a non-empty unnamed module is output to a path specified at DebugIR
    239 // construction.
    240 TEST_F(TestDebugIR, NonEmptyUnnamedModuleWriteToNamedFile) {
    241   string Filename("NamedFile6");
    242 
    243   M.reset(createEmptyModule());
    244   insertAddFunction(M.get());
    245 
    246   D.reset(static_cast<DebugIR *>(
    247       llvm::createDebugIRPass(true, true, cwd, Filename)));
    248   string Path;
    249   D->runOnModule(*M, Path);
    250 
    251   string ExpectedPath(getPath(cwd, Filename));
    252   ASSERT_EQ(ExpectedPath, Path);
    253 
    254   // verify DebugIR generated a file, and clean it up
    255   ASSERT_TRUE(removeIfExists(Path)) << "Missing expected file at " << Path;
    256 }
    257 
    258 // Test that information inside existing debug metadata is retained
    259 TEST_F(TestDebugIR, ExistingMetadataRetained) {
    260   string Filename("NamedFile7");
    261   string ExpectedPath(getPath(cwd, Filename));
    262 
    263   M.reset(createEmptyModule(ExpectedPath));
    264   insertAddFunction(M.get());
    265 
    266   StringRef Producer("TestProducer");
    267   insertCUDescriptor(M.get(), Filename, cwd, Producer);
    268 
    269   DebugInfoFinder Finder;
    270   Finder.processModule(*M);
    271   ASSERT_EQ((unsigned)1, Finder.compile_unit_count());
    272   D.reset(static_cast<DebugIR *>(llvm::createDebugIRPass()));
    273 
    274   string Path;
    275   D->runOnModule(*M, Path);
    276   ASSERT_EQ(ExpectedPath, Path);
    277 
    278   // verify DebugIR did not generate a file
    279   ASSERT_FALSE(removeIfExists(Path)) << "Unexpected file " << Path;
    280 
    281   DICompileUnit CU(*Finder.compile_unit_begin());
    282 
    283   // Verify original CU information is retained
    284   ASSERT_EQ(Filename, CU.getFilename());
    285   ASSERT_EQ(cwd, CU.getDirectory());
    286   ASSERT_EQ(Producer, CU.getProducer());
    287 }
    288 
    289 #endif // HAVE_GETCWD
    290 
    291 #ifdef GTEST_HAS_DEATH_TEST
    292 
    293 // Test a non-empty unnamed module that is not supposed to be output to disk
    294 // NOTE: this test is expected to die with LLVM_ERROR, and such depends on
    295 // google test's "death test" mode.
    296 TEST_F(TestDebugIR, NonEmptyUnnamedModuleNoWrite) {
    297   M.reset(createEmptyModule(StringRef()));
    298   insertAddFunction(M.get());
    299   D.reset(static_cast<DebugIR *>(llvm::createDebugIRPass()));
    300 
    301   // No name in module or on DebugIR construction ==> DebugIR should assert
    302   EXPECT_DEATH(D->runOnModule(*M),
    303                "DebugIR unable to determine file name in input.");
    304 }
    305 
    306 #endif // GTEST_HAS_DEATH_TEST
    307 }
    308