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