291 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "gtest/gtest.h"10 11#include "llvm/ADT/STLExtras.h"12#include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h"13#include "llvm/DebugInfo/PDB/PDBSymbolData.h"14#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"15#include "llvm/Support/FileSystem.h"16#include "llvm/Support/Path.h"17 18#include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h"19#include "Plugins/SymbolFile/DWARF/DWARFDataExtractor.h"20#include "Plugins/SymbolFile/DWARF/DWARFDebugAranges.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 38using namespace lldb;39using namespace lldb_private;40using namespace lldb_private::plugin::dwarf;41using namespace llvm::dwarf;42using llvm::DWARFDebugArangeSet;43 44class SymbolFileDWARFTests : public testing::Test {45 SubsystemRAII<FileSystem, HostInfo, ObjectFilePECOFF, SymbolFileDWARF,46 TypeSystemClang, SymbolFilePDB>47 subsystems;48 49public:50 void SetUp() override {51 m_dwarf_test_exe = GetInputFilePath("test-dwarf.exe");52 }53 54protected:55 std::string m_dwarf_test_exe;56};57 58TEST_F(SymbolFileDWARFTests, TestAbilitiesForDWARF) {59 // Test that when we have Dwarf debug info, SymbolFileDWARF is used.60 FileSpec fspec(m_dwarf_test_exe);61 ArchSpec aspec("i686-pc-windows");62 lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);63 64 SymbolFile *symfile = module->GetSymbolFile();65 ASSERT_NE(nullptr, symfile);66 EXPECT_EQ(symfile->GetPluginName(), SymbolFileDWARF::GetPluginNameStatic());67 68 uint32_t expected_abilities = SymbolFile::kAllAbilities;69 EXPECT_EQ(expected_abilities, symfile->CalculateAbilities());70}71 72TEST_F(SymbolFileDWARFTests, ParseArangesNonzeroSegmentSize) {73 // This `.debug_aranges` table header is a valid 32bit big-endian section74 // according to the DWARFv5 spec:6.2.1, but contains segment selectors which75 // are not supported by lldb, and should be gracefully rejected76 const unsigned char binary_data[] = {77 0, 0, 0, 41, // unit_length (length field not including this field itself)78 0, 2, // DWARF version number (half)79 0, 0, 0, 0, // offset into the .debug_info_table (ignored for the purposes80 // of this test81 4, // address size82 1, // segment size83 // alignment for the first tuple which "begins at an offset that is a84 // multiple of the size of a single tuple". Tuples are nine bytes in this85 // example.86 0, 0, 0, 0, 0, 0,87 // BEGIN TUPLES88 1, 0, 0, 0, 4, 0, 0, 0,89 1, // a 1byte object starting at address 4 in segment 190 0, 0, 0, 0, 4, 0, 0, 0,91 1, // a 1byte object starting at address 4 in segment 092 // END TUPLES93 0, 0, 0, 0, 0, 0, 0, 0, 0 // terminator94 };95 llvm::DWARFDataExtractor data(llvm::ArrayRef<unsigned char>(binary_data),96 /*isLittleEndian=*/false, /*AddrSize=*/4);97 98 DWARFDebugArangeSet debug_aranges;99 offset_t off = 0;100 llvm::Error error = debug_aranges.extract(data, &off);101 EXPECT_TRUE(bool(error));102 EXPECT_EQ("non-zero segment selector size in address range table at offset "103 "0x0 is not supported",104 llvm::toString(std::move(error)));105 EXPECT_EQ(off, 12U); // Parser should read no further than the segment size106}107 108TEST_F(SymbolFileDWARFTests, ParseArangesWithMultipleTerminators) {109 // This .debug_aranges set has multiple terminator entries which appear in110 // binaries produced by popular linux compilers and linker combinations. We111 // must be able to parse all the way through the data for each112 // DWARFDebugArangeSet. Previously the DWARFDebugArangeSet::extract()113 // function would stop parsing as soon as we ran into a terminator even114 // though the length field stated that there was more data that follows. This115 // would cause the next DWARFDebugArangeSet to be parsed immediately116 // following the first terminator and it would attempt to decode the117 // DWARFDebugArangeSet header using the remaining segment + address pairs118 // from the remaining bytes.119 unsigned char binary_data[] = {120 0, 0, 0, 0, // unit_length that will be set correctly after this121 0, 2, // DWARF version number (uint16_t)122 0, 0, 0, 255, // CU offset123 4, // address size124 0, // segment size125 0, 0, 0, 0, // alignment for the first tuple126 // BEGIN TUPLES127 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // premature terminator128 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, // [0x1000-0x1100)129 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // premature terminator130 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10, // [0x2000-0x2010)131 // END TUPLES132 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // terminator133 };134 // Set the big endian length correctly.135 const offset_t binary_data_size = sizeof(binary_data);136 binary_data[3] = (uint8_t)binary_data_size - 4;137 DWARFDataExtractor data;138 data.SetData(static_cast<const void *>(binary_data), sizeof binary_data,139 lldb::ByteOrder::eByteOrderBig);140 DWARFDebugAranges debug_aranges;141 debug_aranges.extract(data);142 // Parser should read all terminators to the end of the length specified.143 ASSERT_EQ(debug_aranges.GetNumRanges(), 2U);144 EXPECT_EQ(debug_aranges.FindAddress(0x0fff), DW_INVALID_OFFSET);145 EXPECT_EQ(debug_aranges.FindAddress(0x1000), 255u);146 EXPECT_EQ(debug_aranges.FindAddress(0x1100 - 1), 255u);147 EXPECT_EQ(debug_aranges.FindAddress(0x1100), DW_INVALID_OFFSET);148 EXPECT_EQ(debug_aranges.FindAddress(0x1fff), DW_INVALID_OFFSET);149 EXPECT_EQ(debug_aranges.FindAddress(0x2000), 255u);150 EXPECT_EQ(debug_aranges.FindAddress(0x2010 - 1), 255u);151 EXPECT_EQ(debug_aranges.FindAddress(0x2010), DW_INVALID_OFFSET);152}153 154TEST_F(SymbolFileDWARFTests, ParseArangesIgnoreEmpty) {155 // This .debug_aranges set has some address ranges which have zero length156 // and we ensure that these are ignored by our DWARFDebugArangeSet parser157 // and not included in the descriptors that are returned.158 unsigned char binary_data[] = {159 0, 0, 0, 0, // unit_length that will be set correctly after this160 0, 2, // DWARF version number (uint16_t)161 0, 0, 0, 255, // CU offset162 4, // address size163 0, // segment size164 0, 0, 0, 0, // alignment for the first tuple165 // BEGIN TUPLES166 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, // [0x1000-0x1100)167 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, // [0x1100-0x1100)168 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10, // [0x2000-0x2010)169 0x00, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, // [0x2010-0x2010)170 // END TUPLES171 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // terminator172 };173 // Set the big endian length correctly.174 const offset_t binary_data_size = sizeof(binary_data);175 binary_data[3] = (uint8_t)binary_data_size - 4;176 DWARFDataExtractor data;177 data.SetData(static_cast<const void *>(binary_data), sizeof binary_data,178 lldb::ByteOrder::eByteOrderBig);179 DWARFDebugAranges debug_aranges;180 debug_aranges.extract(data);181 // Parser should read all terminators to the end of the length specified.182 // Previously the DWARFDebugArangeSet would stop at the first terminator183 // entry and leave the offset in the middle of the current184 // DWARFDebugArangeSet data, and that would cause the next extracted185 // DWARFDebugArangeSet to fail.186 ASSERT_EQ(debug_aranges.GetNumRanges(), 2U);187 EXPECT_EQ(debug_aranges.FindAddress(0x0fff), DW_INVALID_OFFSET);188 EXPECT_EQ(debug_aranges.FindAddress(0x1000), 255u);189 EXPECT_EQ(debug_aranges.FindAddress(0x1100 - 1), 255u);190 EXPECT_EQ(debug_aranges.FindAddress(0x1100), DW_INVALID_OFFSET);191 EXPECT_EQ(debug_aranges.FindAddress(0x1fff), DW_INVALID_OFFSET);192 EXPECT_EQ(debug_aranges.FindAddress(0x2000), 255u);193 EXPECT_EQ(debug_aranges.FindAddress(0x2010 - 1), 255u);194 EXPECT_EQ(debug_aranges.FindAddress(0x2010), DW_INVALID_OFFSET);195}196 197TEST_F(SymbolFileDWARFTests, ParseAranges) {198 // Test we can successfully parse a DWARFDebugAranges. The initial error199 // checking code had a bug where it would always return an empty address200 // ranges for everything in .debug_aranges and no error.201 unsigned char binary_data[] = {202 0, 0, 0, 0, // unit_length that will be set correctly after this203 2, 0, // DWARF version number204 255, 0, 0, 0, // offset into the .debug_info_table205 8, // address size206 0, // segment size207 0, 0, 0, 0, // pad bytes208 // BEGIN TUPLES209 // First tuple: [0x1000-0x1100)210 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Address 0x1000211 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Size 0x0100212 // Second tuple: [0x2000-0x2100)213 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Address 0x2000214 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Size 0x0100215 // Terminating tuple216 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Terminator217 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Terminator218 };219 // Set the little endian length correctly.220 binary_data[0] = sizeof(binary_data) - 4;221 DWARFDataExtractor data;222 data.SetData(static_cast<const void *>(binary_data), sizeof binary_data,223 lldb::ByteOrder::eByteOrderLittle);224 DWARFDebugAranges debug_aranges;225 debug_aranges.extract(data);226 EXPECT_EQ(debug_aranges.GetNumRanges(), 2u);227 EXPECT_EQ(debug_aranges.FindAddress(0x0fff), DW_INVALID_OFFSET);228 EXPECT_EQ(debug_aranges.FindAddress(0x1000), 255u);229 EXPECT_EQ(debug_aranges.FindAddress(0x1100 - 1), 255u);230 EXPECT_EQ(debug_aranges.FindAddress(0x1100), DW_INVALID_OFFSET);231 EXPECT_EQ(debug_aranges.FindAddress(0x1fff), DW_INVALID_OFFSET);232 EXPECT_EQ(debug_aranges.FindAddress(0x2000), 255u);233 EXPECT_EQ(debug_aranges.FindAddress(0x2100 - 1), 255u);234 EXPECT_EQ(debug_aranges.FindAddress(0x2100), DW_INVALID_OFFSET);235}236 237TEST_F(SymbolFileDWARFTests, ParseArangesSkipErrors) {238 // Test we can successfully parse a DWARFDebugAranges that contains some239 // valid DWARFDebugArangeSet objects and some with errors as long as their240 // length is set correctly. This helps LLDB ensure that it can parse newer241 // .debug_aranges version that LLDB currently doesn't support, or ignore242 // errors in individual DWARFDebugArangeSet objects as long as the length243 // is set correctly.244 const unsigned char binary_data[] = {245 // This DWARFDebugArangeSet is well formed and has a single address range246 // for [0x1000-0x1100) with a CU offset of 0x00000000.247 0, 0, 0, 28, // unit_length that will be set correctly after this248 0, 2, // DWARF version number (uint16_t)249 0, 0, 0, 0, // CU offset = 0x00000000250 4, // address size251 0, // segment size252 0, 0, 0, 0, // alignment for the first tuple253 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, // [0x1000-0x1100)254 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // terminator255 // This DWARFDebugArangeSet has the correct length, but an invalid256 // version. We need to be able to skip this correctly and ignore it.257 0, 0, 0, 20, // unit_length that will be set correctly after this258 0, 44, // invalid DWARF version number (uint16_t)259 0, 0, 1, 0, // CU offset = 0x00000100260 4, // address size261 0, // segment size262 0, 0, 0, 0, // alignment for the first tuple263 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // terminator264 // This DWARFDebugArangeSet is well formed and has a single address range265 // for [0x2000-0x2100) with a CU offset of 0x00000000.266 0, 0, 0, 28, // unit_length that will be set correctly after this267 0, 2, // DWARF version number (uint16_t)268 0, 0, 2, 0, // CU offset = 0x00000200269 4, // address size270 0, // segment size271 0, 0, 0, 0, // alignment for the first tuple272 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, // [0x2000-0x2100)273 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // terminator274 };275 276 DWARFDataExtractor data;277 data.SetData(static_cast<const void *>(binary_data), sizeof binary_data,278 lldb::ByteOrder::eByteOrderBig);279 DWARFDebugAranges debug_aranges;280 debug_aranges.extract(data);281 EXPECT_EQ(debug_aranges.GetNumRanges(), 2u);282 EXPECT_EQ(debug_aranges.FindAddress(0x0fff), DW_INVALID_OFFSET);283 EXPECT_EQ(debug_aranges.FindAddress(0x1000), 0u);284 EXPECT_EQ(debug_aranges.FindAddress(0x1100 - 1), 0u);285 EXPECT_EQ(debug_aranges.FindAddress(0x1100), DW_INVALID_OFFSET);286 EXPECT_EQ(debug_aranges.FindAddress(0x1fff), DW_INVALID_OFFSET);287 EXPECT_EQ(debug_aranges.FindAddress(0x2000), 0x200u);288 EXPECT_EQ(debug_aranges.FindAddress(0x2100 - 1), 0x200u);289 EXPECT_EQ(debug_aranges.FindAddress(0x2100), DW_INVALID_OFFSET);290}291