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 "../lib/Transforms/Instrumentation/DebugIR.h"
     17 #include "llvm/Config/config.h"
     18 #include "llvm/IR/DIBuilder.h"
     19 #include "llvm/IR/DebugInfo.h"
     20 #include "llvm/IR/Module.h"
     21 #include "llvm/Support/Errc.h"
     22 #include "llvm/Support/FileSystem.h"
     23 #include "llvm/Support/Host.h"
     24 #include "llvm/Support/Path.h"
     25 #include "llvm/Transforms/Instrumentation.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   // This is an approximation, on error we don't know in general if the file
     60   // existed or not.
     61   std::error_code EC = sys::fs::remove(Path, false);
     62   return EC != llvm::errc::no_such_file_or_directory;
     63 }
     64 
     65 char * current_dir() {
     66 #if defined(LLVM_ON_WIN32) || defined(HAVE_GETCWD)
     67   // calling getcwd (or _getcwd() on windows) with a null buffer makes it
     68   // allocate a sufficiently sized buffer to store the current working dir.
     69   return getcwd_impl(nullptr, 0);
     70 #else
     71   return 0;
     72 #endif
     73 }
     74 
     75 class TestDebugIR : public ::testing::Test, public TrivialModuleBuilder {
     76 protected:
     77   TestDebugIR()
     78       : TrivialModuleBuilder(sys::getProcessTriple())
     79       , cwd(current_dir()) {}
     80 
     81   ~TestDebugIR() { free(cwd); }
     82 
     83   /// Returns a concatenated path string consisting of Dir and Filename
     84   string getPath(const string &Dir, const string &Filename) {
     85     SmallVector<char, 8> Path;
     86     sys::path::append(Path, Dir, Filename);
     87     Path.resize(Dir.size() + Filename.size() + 2);
     88     Path[Dir.size() + Filename.size() + 1] = '\0';
     89     return string(Path.data());
     90   }
     91 
     92   LLVMContext Context;
     93   char *cwd;
     94   std::unique_ptr<Module> M;
     95   std::unique_ptr<DebugIR> D;
     96 };
     97 
     98 // Test empty named Module that is not supposed to be output to disk.
     99 TEST_F(TestDebugIR, EmptyNamedModuleNoWrite) {
    100   string Dir = "MadeUpDirectory";
    101   string File = "empty_module.ll";
    102   string Path(getPath(Dir, File));
    103 
    104   M.reset(createEmptyModule(Path));
    105 
    106   // constructing DebugIR with no args should not result in any file generated.
    107   D.reset(static_cast<DebugIR *>(llvm::createDebugIRPass()));
    108   D->runOnModule(*M);
    109 
    110   // verify DebugIR did not generate a file
    111   ASSERT_FALSE(removeIfExists(Path)) << "Unexpected file " << Path;
    112 }
    113 
    114 // Test a non-empty unnamed module that is output to an autogenerated file name.
    115 TEST_F(TestDebugIR, NonEmptyUnnamedModuleWriteToAutogeneratedFile) {
    116   M.reset(createEmptyModule());
    117   insertAddFunction(M.get());
    118   D.reset(static_cast<DebugIR *>(llvm::createDebugIRPass(true, true)));
    119 
    120   string Path;
    121   D->runOnModule(*M, Path);
    122 
    123   // verify DebugIR generated a file, and clean it up
    124   ASSERT_TRUE(removeIfExists(Path)) << "Missing expected file at " << Path;
    125 }
    126 
    127 // Test not specifying a name in the module -- DebugIR should generate a name
    128 // and write the file contents.
    129 TEST_F(TestDebugIR, EmptyModuleWriteAnonymousFile) {
    130   M.reset(createEmptyModule());
    131   D.reset(static_cast<DebugIR *>(llvm::createDebugIRPass(false, false)));
    132 
    133   string Path;
    134   D->runOnModule(*M, Path);
    135 
    136   // verify DebugIR generated a file and clean it up
    137   ASSERT_TRUE(removeIfExists(Path)) << "Missing expected file at " << Path;
    138 }
    139 
    140 #ifdef HAVE_GETCWD // These tests require get_current_dir_name()
    141 
    142 // Test empty named Module that is to be output to path specified at Module
    143 // construction.
    144 TEST_F(TestDebugIR, EmptyNamedModuleWriteFile) {
    145   string Filename("NamedFile1");
    146   string ExpectedPath(getPath(cwd, Filename));
    147 
    148   M.reset(createEmptyModule(ExpectedPath));
    149   D.reset(static_cast<DebugIR *>(llvm::createDebugIRPass(true, true)));
    150 
    151   string Path;
    152   D->runOnModule(*M, Path);
    153 
    154   // verify DebugIR was able to correctly parse the file name from module ID
    155   ASSERT_EQ(ExpectedPath, Path);
    156 
    157   // verify DebugIR generated a file, and clean it up
    158   ASSERT_TRUE(removeIfExists(Path)) << "Missing expected file at " << Path;
    159 }
    160 
    161 // Test an empty unnamed module generates an output file whose path is specified
    162 // at DebugIR construction.
    163 TEST_F(TestDebugIR, EmptyUnnamedModuleWriteNamedFile) {
    164   string Filename("NamedFile2");
    165 
    166   M.reset(createEmptyModule());
    167   D.reset(static_cast<DebugIR *>(llvm::createDebugIRPass(
    168       false, false, StringRef(cwd), StringRef(Filename))));
    169   string Path;
    170   D->runOnModule(*M, Path);
    171 
    172   string ExpectedPath(getPath(cwd, Filename));
    173   ASSERT_EQ(ExpectedPath, Path);
    174 
    175   // verify DebugIR generated a file, and clean it up
    176   ASSERT_TRUE(removeIfExists(Path)) << "Missing expected file at " << Path;
    177 }
    178 
    179 // Test an empty named module generates an output file at the path specified
    180 // during DebugIR construction.
    181 TEST_F(TestDebugIR, EmptyNamedModuleWriteNamedFile) {
    182   string Filename("NamedFile3");
    183 
    184   string UnexpectedPath(getPath(cwd, "UnexpectedFilename"));
    185   M.reset(createEmptyModule(UnexpectedPath));
    186 
    187   D.reset(static_cast<DebugIR *>(llvm::createDebugIRPass(
    188       false, false, StringRef(cwd), StringRef(Filename))));
    189   string Path;
    190   D->runOnModule(*M, Path);
    191 
    192   string ExpectedPath(getPath(cwd, Filename));
    193   ASSERT_EQ(ExpectedPath, Path);
    194 
    195   // verify DebugIR generated a file, and clean it up
    196   ASSERT_TRUE(removeIfExists(Path)) << "Missing expected file at " << Path;
    197 
    198   // verify DebugIR did not generate a file at the path specified at Module
    199   // construction.
    200   ASSERT_FALSE(removeIfExists(UnexpectedPath)) << "Unexpected file " << Path;
    201 }
    202 
    203 // Test a non-empty named module that is not supposed to be output to disk
    204 TEST_F(TestDebugIR, NonEmptyNamedModuleNoWrite) {
    205   string Filename("NamedFile4");
    206   string ExpectedPath(getPath(cwd, Filename));
    207 
    208   M.reset(createEmptyModule(ExpectedPath));
    209   insertAddFunction(M.get());
    210 
    211   D.reset(static_cast<DebugIR *>(llvm::createDebugIRPass()));
    212 
    213   string Path;
    214   D->runOnModule(*M, Path);
    215   ASSERT_EQ(ExpectedPath, Path);
    216 
    217   // verify DebugIR did not generate a file
    218   ASSERT_FALSE(removeIfExists(Path)) << "Unexpected file " << Path;
    219 }
    220 
    221 // Test a non-empty named module that is output to disk.
    222 TEST_F(TestDebugIR, NonEmptyNamedModuleWriteFile) {
    223   string Filename("NamedFile5");
    224   string ExpectedPath(getPath(cwd, Filename));
    225 
    226   M.reset(createEmptyModule(ExpectedPath));
    227   insertAddFunction(M.get());
    228 
    229   D.reset(static_cast<DebugIR *>(llvm::createDebugIRPass(true, true)));
    230 
    231   string Path;
    232   D->runOnModule(*M, Path);
    233   ASSERT_EQ(ExpectedPath, Path);
    234 
    235   // verify DebugIR generated a file, and clean it up
    236   ASSERT_TRUE(removeIfExists(Path)) << "Missing expected file at " << Path;
    237 }
    238 
    239 // Test a non-empty unnamed module is output to a path specified at DebugIR
    240 // construction.
    241 TEST_F(TestDebugIR, NonEmptyUnnamedModuleWriteToNamedFile) {
    242   string Filename("NamedFile6");
    243 
    244   M.reset(createEmptyModule());
    245   insertAddFunction(M.get());
    246 
    247   D.reset(static_cast<DebugIR *>(
    248       llvm::createDebugIRPass(true, true, cwd, Filename)));
    249   string Path;
    250   D->runOnModule(*M, Path);
    251 
    252   string ExpectedPath(getPath(cwd, Filename));
    253   ASSERT_EQ(ExpectedPath, Path);
    254 
    255   // verify DebugIR generated a file, and clean it up
    256   ASSERT_TRUE(removeIfExists(Path)) << "Missing expected file at " << Path;
    257 }
    258 
    259 // Test that information inside existing debug metadata is retained
    260 TEST_F(TestDebugIR, ExistingMetadataRetained) {
    261   string Filename("NamedFile7");
    262   string ExpectedPath(getPath(cwd, Filename));
    263 
    264   M.reset(createEmptyModule(ExpectedPath));
    265   insertAddFunction(M.get());
    266 
    267   StringRef Producer("TestProducer");
    268   insertCUDescriptor(M.get(), Filename, cwd, Producer);
    269 
    270   DebugInfoFinder Finder;
    271   Finder.processModule(*M);
    272   ASSERT_EQ((unsigned)1, Finder.compile_unit_count());
    273   D.reset(static_cast<DebugIR *>(llvm::createDebugIRPass()));
    274 
    275   string Path;
    276   D->runOnModule(*M, Path);
    277   ASSERT_EQ(ExpectedPath, Path);
    278 
    279   // verify DebugIR did not generate a file
    280   ASSERT_FALSE(removeIfExists(Path)) << "Unexpected file " << Path;
    281 
    282   DICompileUnit CU(*Finder.compile_units().begin());
    283 
    284   // Verify original CU information is retained
    285   ASSERT_EQ(Filename, CU.getFilename());
    286   ASSERT_EQ(cwd, CU.getDirectory());
    287   ASSERT_EQ(Producer, CU.getProducer());
    288 }
    289 
    290 #endif // HAVE_GETCWD
    291 
    292 #ifdef GTEST_HAS_DEATH_TEST
    293 
    294 // Test a non-empty unnamed module that is not supposed to be output to disk
    295 // NOTE: this test is expected to die with LLVM_ERROR, and such depends on
    296 // google test's "death test" mode.
    297 TEST_F(TestDebugIR, NonEmptyUnnamedModuleNoWrite) {
    298   M.reset(createEmptyModule(StringRef()));
    299   insertAddFunction(M.get());
    300   D.reset(static_cast<DebugIR *>(llvm::createDebugIRPass()));
    301 
    302   // No name in module or on DebugIR construction ==> DebugIR should assert
    303   EXPECT_DEATH(D->runOnModule(*M),
    304                "DebugIR unable to determine file name in input.");
    305 }
    306 
    307 #endif // GTEST_HAS_DEATH_TEST
    308 }
    309