1 //===-- SymbolFileDWARFTests.cpp --------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "gtest/gtest.h" 10 11 #include "llvm/ADT/STLExtras.h" 12 #include "llvm/DebugInfo/PDB/PDBSymbolData.h" 13 #include "llvm/DebugInfo/PDB/PDBSymbolExe.h" 14 #include "llvm/Support/FileSystem.h" 15 #include "llvm/Support/Path.h" 16 17 #include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h" 18 #include "Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h" 19 #include "Plugins/SymbolFile/DWARF/DWARFDataExtractor.h" 20 #include "Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h" 21 #include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h" 22 #include "Plugins/SymbolFile/PDB/SymbolFilePDB.h" 23 #include "TestingSupport/TestUtilities.h" 24 #include "lldb/Core/Address.h" 25 #include "lldb/Core/Module.h" 26 #include "lldb/Core/ModuleSpec.h" 27 #include "lldb/Host/FileSystem.h" 28 #include "lldb/Host/HostInfo.h" 29 #include "lldb/Symbol/ClangASTContext.h" 30 #include "lldb/Symbol/CompileUnit.h" 31 #include "lldb/Symbol/LineTable.h" 32 #include "lldb/Utility/ArchSpec.h" 33 #include "lldb/Utility/DataEncoder.h" 34 #include "lldb/Utility/FileSpec.h" 35 #include "lldb/Utility/StreamString.h" 36 37 38 39 using namespace lldb; 40 using namespace lldb_private; 41 42 class SymbolFileDWARFTests : public testing::Test { 43 public: 44 void SetUp() override { 45 // Initialize and TearDown the plugin every time, so we get a brand new 46 // AST every time so that modifications to the AST from each test don't 47 // leak into the next test. 48 FileSystem::Initialize(); 49 HostInfo::Initialize(); 50 ObjectFilePECOFF::Initialize(); 51 SymbolFileDWARF::Initialize(); 52 ClangASTContext::Initialize(); 53 SymbolFilePDB::Initialize(); 54 55 m_dwarf_test_exe = GetInputFilePath("test-dwarf.exe"); 56 } 57 58 void TearDown() override { 59 SymbolFilePDB::Terminate(); 60 ClangASTContext::Initialize(); 61 SymbolFileDWARF::Terminate(); 62 ObjectFilePECOFF::Terminate(); 63 HostInfo::Terminate(); 64 FileSystem::Terminate(); 65 } 66 67 protected: 68 std::string m_dwarf_test_exe; 69 }; 70 71 TEST_F(SymbolFileDWARFTests, TestAbilitiesForDWARF) { 72 // Test that when we have Dwarf debug info, SymbolFileDWARF is used. 73 FileSpec fspec(m_dwarf_test_exe); 74 ArchSpec aspec("i686-pc-windows"); 75 lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec); 76 77 SymbolFile *symfile = module->GetSymbolFile(); 78 ASSERT_NE(nullptr, symfile); 79 EXPECT_EQ(symfile->GetPluginName(), SymbolFileDWARF::GetPluginNameStatic()); 80 81 uint32_t expected_abilities = SymbolFile::kAllAbilities; 82 EXPECT_EQ(expected_abilities, symfile->CalculateAbilities()); 83 } 84 85 TEST_F(SymbolFileDWARFTests, TestAbbrevOrder1Start1) { 86 // Test that if we have a .debug_abbrev that contains ordered abbreviation 87 // codes that start at 1, that we get O(1) access. 88 89 const auto byte_order = eByteOrderLittle; 90 const uint8_t addr_size = 4; 91 StreamString encoder(Stream::eBinary, addr_size, byte_order); 92 encoder.PutULEB128(1); // Abbrev code 1 93 encoder.PutULEB128(DW_TAG_compile_unit); 94 encoder.PutHex8(DW_CHILDREN_yes); 95 encoder.PutULEB128(DW_AT_name); 96 encoder.PutULEB128(DW_FORM_strp); 97 encoder.PutULEB128(0); 98 encoder.PutULEB128(0); 99 100 encoder.PutULEB128(2); // Abbrev code 2 101 encoder.PutULEB128(DW_TAG_subprogram); 102 encoder.PutHex8(DW_CHILDREN_no); 103 encoder.PutULEB128(DW_AT_name); 104 encoder.PutULEB128(DW_FORM_strp); 105 encoder.PutULEB128(0); 106 encoder.PutULEB128(0); 107 108 encoder.PutULEB128(0); // Abbrev code 0 (termination) 109 110 DWARFDataExtractor data; 111 data.SetData(encoder.GetData(), encoder.GetSize(), byte_order); 112 DWARFAbbreviationDeclarationSet abbrev_set; 113 lldb::offset_t data_offset = 0; 114 llvm::Error error = abbrev_set.extract(data, &data_offset); 115 EXPECT_FALSE(bool(error)); 116 // Make sure we have O(1) access to each abbreviation by making sure the 117 // index offset is 1 and not UINT32_MAX 118 EXPECT_EQ(abbrev_set.GetIndexOffset(), 1u); 119 120 auto abbrev1 = abbrev_set.GetAbbreviationDeclaration(1); 121 EXPECT_EQ(abbrev1->Tag(), DW_TAG_compile_unit); 122 EXPECT_TRUE(abbrev1->HasChildren()); 123 EXPECT_EQ(abbrev1->NumAttributes(), 1u); 124 auto abbrev2 = abbrev_set.GetAbbreviationDeclaration(2); 125 EXPECT_EQ(abbrev2->Tag(), DW_TAG_subprogram); 126 EXPECT_FALSE(abbrev2->HasChildren()); 127 EXPECT_EQ(abbrev2->NumAttributes(), 1u); 128 } 129 130 TEST_F(SymbolFileDWARFTests, TestAbbrevOrder1Start5) { 131 // Test that if we have a .debug_abbrev that contains ordered abbreviation 132 // codes that start at 5, that we get O(1) access. 133 134 const auto byte_order = eByteOrderLittle; 135 const uint8_t addr_size = 4; 136 StreamString encoder(Stream::eBinary, addr_size, byte_order); 137 encoder.PutULEB128(5); // Abbrev code 5 138 encoder.PutULEB128(DW_TAG_compile_unit); 139 encoder.PutHex8(DW_CHILDREN_yes); 140 encoder.PutULEB128(DW_AT_name); 141 encoder.PutULEB128(DW_FORM_strp); 142 encoder.PutULEB128(0); 143 encoder.PutULEB128(0); 144 145 encoder.PutULEB128(6); // Abbrev code 6 146 encoder.PutULEB128(DW_TAG_subprogram); 147 encoder.PutHex8(DW_CHILDREN_no); 148 encoder.PutULEB128(DW_AT_name); 149 encoder.PutULEB128(DW_FORM_strp); 150 encoder.PutULEB128(0); 151 encoder.PutULEB128(0); 152 153 encoder.PutULEB128(0); // Abbrev code 0 (termination) 154 155 DWARFDataExtractor data; 156 data.SetData(encoder.GetData(), encoder.GetSize(), byte_order); 157 DWARFAbbreviationDeclarationSet abbrev_set; 158 lldb::offset_t data_offset = 0; 159 llvm::Error error = abbrev_set.extract(data, &data_offset); 160 EXPECT_FALSE(bool(error)); 161 // Make sure we have O(1) access to each abbreviation by making sure the 162 // index offset is 5 and not UINT32_MAX 163 EXPECT_EQ(abbrev_set.GetIndexOffset(), 5u); 164 165 auto abbrev1 = abbrev_set.GetAbbreviationDeclaration(5); 166 EXPECT_EQ(abbrev1->Tag(), DW_TAG_compile_unit); 167 EXPECT_TRUE(abbrev1->HasChildren()); 168 EXPECT_EQ(abbrev1->NumAttributes(), 1u); 169 auto abbrev2 = abbrev_set.GetAbbreviationDeclaration(6); 170 EXPECT_EQ(abbrev2->Tag(), DW_TAG_subprogram); 171 EXPECT_FALSE(abbrev2->HasChildren()); 172 EXPECT_EQ(abbrev2->NumAttributes(), 1u); 173 } 174 175 TEST_F(SymbolFileDWARFTests, TestAbbrevOutOfOrder) { 176 // Test that if we have a .debug_abbrev that contains unordered abbreviation 177 // codes, that we can access the information correctly. 178 179 const auto byte_order = eByteOrderLittle; 180 const uint8_t addr_size = 4; 181 StreamString encoder(Stream::eBinary, addr_size, byte_order); 182 encoder.PutULEB128(2); // Abbrev code 2 183 encoder.PutULEB128(DW_TAG_compile_unit); 184 encoder.PutHex8(DW_CHILDREN_yes); 185 encoder.PutULEB128(DW_AT_name); 186 encoder.PutULEB128(DW_FORM_strp); 187 encoder.PutULEB128(0); 188 encoder.PutULEB128(0); 189 190 encoder.PutULEB128(1); // Abbrev code 1 191 encoder.PutULEB128(DW_TAG_subprogram); 192 encoder.PutHex8(DW_CHILDREN_no); 193 encoder.PutULEB128(DW_AT_name); 194 encoder.PutULEB128(DW_FORM_strp); 195 encoder.PutULEB128(0); 196 encoder.PutULEB128(0); 197 198 encoder.PutULEB128(0); // Abbrev code 0 (termination) 199 200 DWARFDataExtractor data; 201 data.SetData(encoder.GetData(), encoder.GetSize(), byte_order); 202 DWARFAbbreviationDeclarationSet abbrev_set; 203 lldb::offset_t data_offset = 0; 204 llvm::Error error = abbrev_set.extract(data, &data_offset); 205 EXPECT_FALSE(bool(error)); 206 // Make sure we don't have O(1) access to each abbreviation by making sure 207 // the index offset is UINT32_MAX 208 EXPECT_EQ(abbrev_set.GetIndexOffset(), UINT32_MAX); 209 210 auto abbrev1 = abbrev_set.GetAbbreviationDeclaration(2); 211 EXPECT_EQ(abbrev1->Tag(), DW_TAG_compile_unit); 212 EXPECT_TRUE(abbrev1->HasChildren()); 213 EXPECT_EQ(abbrev1->NumAttributes(), 1u); 214 auto abbrev2 = abbrev_set.GetAbbreviationDeclaration(1); 215 EXPECT_EQ(abbrev2->Tag(), DW_TAG_subprogram); 216 EXPECT_FALSE(abbrev2->HasChildren()); 217 EXPECT_EQ(abbrev2->NumAttributes(), 1u); 218 } 219 220 TEST_F(SymbolFileDWARFTests, TestAbbrevInvalidNULLTag) { 221 // Test that we detect when an abbreviation has a NULL tag and that we get 222 // an error when decoding. 223 224 const auto byte_order = eByteOrderLittle; 225 const uint8_t addr_size = 4; 226 StreamString encoder(Stream::eBinary, addr_size, byte_order); 227 encoder.PutULEB128(1); // Abbrev code 1 228 encoder.PutULEB128(0); // Invalid NULL tag here! 229 encoder.PutHex8(DW_CHILDREN_no); 230 encoder.PutULEB128(0); 231 encoder.PutULEB128(0); 232 233 encoder.PutULEB128(0); // Abbrev code 0 (termination) 234 235 DWARFDataExtractor data; 236 data.SetData(encoder.GetData(), encoder.GetSize(), byte_order); 237 DWARFAbbreviationDeclarationSet abbrev_set; 238 lldb::offset_t data_offset = 0; 239 llvm::Error error = abbrev_set.extract(data, &data_offset); 240 // Verify we get an error 241 EXPECT_TRUE(bool(error)); 242 EXPECT_EQ("abbrev decl requires non-null tag.", 243 llvm::toString(std::move(error))); 244 245 } 246 247 TEST_F(SymbolFileDWARFTests, TestAbbrevNullAttrValidForm) { 248 // Test that we detect when an abbreviation has a NULL attribute and a non 249 // NULL form and that we get an error when decoding. 250 251 const auto byte_order = eByteOrderLittle; 252 const uint8_t addr_size = 4; 253 StreamString encoder(Stream::eBinary, addr_size, byte_order); 254 encoder.PutULEB128(1); // Abbrev code 1 255 encoder.PutULEB128(DW_TAG_compile_unit); 256 encoder.PutHex8(DW_CHILDREN_no); 257 encoder.PutULEB128(0); // Invalid NULL DW_AT 258 encoder.PutULEB128(DW_FORM_strp); // With a valid form 259 encoder.PutULEB128(0); 260 encoder.PutULEB128(0); 261 262 encoder.PutULEB128(0); // Abbrev code 0 (termination) 263 264 DWARFDataExtractor data; 265 data.SetData(encoder.GetData(), encoder.GetSize(), byte_order); 266 DWARFAbbreviationDeclarationSet abbrev_set; 267 lldb::offset_t data_offset = 0; 268 llvm::Error error = abbrev_set.extract(data, &data_offset); 269 // Verify we get an error 270 EXPECT_TRUE(bool(error)); 271 EXPECT_EQ("malformed abbreviation declaration attribute", 272 llvm::toString(std::move(error))); 273 274 } 275 276 TEST_F(SymbolFileDWARFTests, TestAbbrevValidAttrNullForm) { 277 // Test that we detect when an abbreviation has a valid attribute and a 278 // NULL form and that we get an error when decoding. 279 280 const auto byte_order = eByteOrderLittle; 281 const uint8_t addr_size = 4; 282 StreamString encoder(Stream::eBinary, addr_size, byte_order); 283 encoder.PutULEB128(1); // Abbrev code 1 284 encoder.PutULEB128(DW_TAG_compile_unit); 285 encoder.PutHex8(DW_CHILDREN_no); 286 encoder.PutULEB128(DW_AT_name); // Valid attribute 287 encoder.PutULEB128(0); // NULL form 288 encoder.PutULEB128(0); 289 encoder.PutULEB128(0); 290 291 encoder.PutULEB128(0); // Abbrev code 0 (termination) 292 293 DWARFDataExtractor data; 294 data.SetData(encoder.GetData(), encoder.GetSize(), byte_order); 295 DWARFAbbreviationDeclarationSet abbrev_set; 296 lldb::offset_t data_offset = 0; 297 llvm::Error error = abbrev_set.extract(data, &data_offset); 298 // Verify we get an error 299 EXPECT_TRUE(bool(error)); 300 EXPECT_EQ("malformed abbreviation declaration attribute", 301 llvm::toString(std::move(error))); 302 } 303 304 TEST_F(SymbolFileDWARFTests, TestAbbrevMissingTerminator) { 305 // Test that we detect when an abbreviation has a valid attribute and a 306 // form, but is missing the NULL attribute and form that terminates an 307 // abbreviation 308 309 const auto byte_order = eByteOrderLittle; 310 const uint8_t addr_size = 4; 311 StreamString encoder(Stream::eBinary, addr_size, byte_order); 312 encoder.PutULEB128(1); // Abbrev code 1 313 encoder.PutULEB128(DW_TAG_compile_unit); 314 encoder.PutHex8(DW_CHILDREN_no); 315 encoder.PutULEB128(DW_AT_name); 316 encoder.PutULEB128(DW_FORM_strp); 317 // Don't add the NULL DW_AT and NULL DW_FORM terminator 318 319 DWARFDataExtractor data; 320 data.SetData(encoder.GetData(), encoder.GetSize(), byte_order); 321 DWARFAbbreviationDeclarationSet abbrev_set; 322 lldb::offset_t data_offset = 0; 323 llvm::Error error = abbrev_set.extract(data, &data_offset); 324 // Verify we get an error 325 EXPECT_TRUE(bool(error)); 326 EXPECT_EQ("abbreviation declaration attribute list not terminated with a " 327 "null entry", llvm::toString(std::move(error))); 328 } 329