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