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