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