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