brintos

brintos / llvm-project-archived public Read only

0
0
Text · 14.9 KiB · fb728c8 Raw
420 lines · cpp
1//===- llvm/unittest/DebugInfo/LogicalView/DWARFReaderTest.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 "llvm/DebugInfo/LogicalView/Core/LVCompare.h"10#include "llvm/DebugInfo/LogicalView/Core/LVLine.h"11#include "llvm/DebugInfo/LogicalView/Core/LVScope.h"12#include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h"13#include "llvm/DebugInfo/LogicalView/Core/LVType.h"14#include "llvm/DebugInfo/LogicalView/LVReaderHandler.h"15#include "llvm/MC/TargetRegistry.h"16#include "llvm/Support/COM.h"17#include "llvm/Support/InitLLVM.h"18#include "llvm/Support/ScopedPrinter.h"19#include "llvm/Support/TargetSelect.h"20#include "llvm/Support/ToolOutputFile.h"21#include "llvm/Testing/Support/Error.h"22 23#include "gtest/gtest.h"24 25using namespace llvm;26using namespace llvm::logicalview;27 28extern const char *TestMainArgv0;29 30namespace {31 32const char *DwarfClang = "test-dwarf-clang.o";33// Two compile units: one declares `extern int foo_printf(const char *, ...);`34// and another one that defines the function.35const char *DwarfClangUnspecParams = "test-dwarf-clang-unspec-params.elf";36const char *DwarfClangModule = "test-dwarf-clang-module.o";37const char *DwarfGcc = "test-dwarf-gcc.o";38 39// Helper function to get the first compile unit.40LVScopeCompileUnit *getFirstCompileUnit(LVScopeRoot *Root) {41  EXPECT_NE(Root, nullptr);42  const LVScopes *CompileUnits = Root->getScopes();43  EXPECT_NE(CompileUnits, nullptr);44  EXPECT_GT(CompileUnits->size(), 0u);45 46  LVScopes::const_iterator Iter = CompileUnits->begin();47  EXPECT_NE(Iter, nullptr);48  LVScopeCompileUnit *CompileUnit = static_cast<LVScopeCompileUnit *>(*Iter);49  EXPECT_NE(CompileUnit, nullptr);50  return CompileUnit;51}52 53// Helper function to create a reader.54std::unique_ptr<LVReader> createReader(LVReaderHandler &ReaderHandler,55                                       SmallString<128> &InputsDir,56                                       StringRef Filename) {57  SmallString<128> ObjectName(InputsDir);58  llvm::sys::path::append(ObjectName, Filename);59 60  Expected<std::unique_ptr<LVReader>> ReaderOrErr =61      ReaderHandler.createReader(std::string(ObjectName));62  EXPECT_THAT_EXPECTED(ReaderOrErr, Succeeded());63  std::unique_ptr<LVReader> Reader = std::move(*ReaderOrErr);64  EXPECT_NE(Reader, nullptr);65  return Reader;66}67 68// Check the logical elements basic properties.69void checkElementProperties(LVReader *Reader) {70  LVScopeRoot *Root = Reader->getScopesRoot();71  LVScopeCompileUnit *CompileUnit = getFirstCompileUnit(Root);72 73  EXPECT_EQ(Root->getFileFormatName(), "elf64-x86-64");74  EXPECT_EQ(Root->getName(), DwarfClang);75 76  EXPECT_EQ(CompileUnit->getBaseAddress(), 0u);77  EXPECT_TRUE(CompileUnit->getProducer().starts_with("clang"));78  EXPECT_EQ(CompileUnit->getName(), "test.cpp");79  LVSourceLanguage Language = CompileUnit->getSourceLanguage();80  EXPECT_TRUE(Language.isValid());81  EXPECT_EQ(Language, LVSourceLanguage::DW_LANG_C_plus_plus_14);82  EXPECT_EQ(Language.getName(), "DW_LANG_C_plus_plus_14");83 84  EXPECT_EQ(CompileUnit->lineCount(), 1u);85  EXPECT_EQ(CompileUnit->scopeCount(), 1u);86  EXPECT_EQ(CompileUnit->symbolCount(), 0u);87  EXPECT_EQ(CompileUnit->typeCount(), 7u);88  EXPECT_EQ(CompileUnit->rangeCount(), 1u);89 90  const LVLocations *Ranges = CompileUnit->getRanges();91  ASSERT_NE(Ranges, nullptr);92  ASSERT_EQ(Ranges->size(), 1u);93  LVLocations::const_iterator IterLocation = Ranges->begin();94  LVLocation *Location = (*IterLocation);95  EXPECT_STREQ(Location->getIntervalInfo().c_str(),96               "{Range} Lines 2:9 [0x0000000000:0x000000003a]");97 98  LVRange RangeList;99  CompileUnit->getRanges(RangeList);100 101  const LVRangeEntries &RangeEntries = RangeList.getEntries();102  ASSERT_EQ(RangeEntries.size(), 2u);103  LVRangeEntries::const_iterator IterRanges = RangeEntries.cbegin();104  LVRangeEntry RangeEntry = *IterRanges;105  EXPECT_EQ(RangeEntry.lower(), 0u);106  EXPECT_EQ(RangeEntry.upper(), 0x3au);107  EXPECT_EQ(RangeEntry.scope()->getLineNumber(), 0u);108  EXPECT_EQ(RangeEntry.scope()->getName(), "test.cpp");109  EXPECT_EQ(RangeEntry.scope()->getOffset(), 0x0bu);110 111  ++IterRanges;112  RangeEntry = *IterRanges;113  EXPECT_EQ(RangeEntry.lower(), 0x1cu);114  EXPECT_EQ(RangeEntry.upper(), 0x2fu);115  EXPECT_EQ(RangeEntry.scope()->getLineNumber(), 0u);116  EXPECT_EQ(RangeEntry.scope()->getName(), "foo::?");117  EXPECT_EQ(RangeEntry.scope()->getOffset(), 0x71u);118 119  const LVPublicNames &PublicNames = CompileUnit->getPublicNames();120  ASSERT_EQ(PublicNames.size(), 1u);121  LVPublicNames::const_iterator IterNames = PublicNames.cbegin();122  LVScope *Function = (*IterNames).first;123  EXPECT_EQ(Function->getName(), "foo");124  EXPECT_EQ(Function->getLineNumber(), 2u);125  LVNameInfo NameInfo = (*IterNames).second;126  EXPECT_EQ(NameInfo.first, 0u);127  EXPECT_EQ(NameInfo.second, 0x3au);128 129  // Lines (debug and assembler) for 'foo'.130  const LVLines *Lines = Function->getLines();131  ASSERT_NE(Lines, nullptr);132  ASSERT_EQ(Lines->size(), 19u);133 134  // Check size of types in CompileUnit.135  const LVTypes *Types = CompileUnit->getTypes();136  ASSERT_NE(Types, nullptr);137  EXPECT_EQ(Types->size(), 7u);138 139  const auto BoolType = llvm::find_if(140      *Types, [](const LVElement *elt) { return elt->getName() == "bool"; });141  ASSERT_NE(BoolType, Types->end());142  const auto IntType = llvm::find_if(143      *Types, [](const LVElement *elt) { return elt->getName() == "int"; });144  ASSERT_NE(IntType, Types->end());145  EXPECT_EQ(static_cast<LVType *>(*BoolType)->getBitSize(), 8u);146  EXPECT_EQ(static_cast<LVType *>(*BoolType)->getStorageSizeInBytes(), 1u);147  EXPECT_EQ(static_cast<LVType *>(*IntType)->getBitSize(), 32u);148  EXPECT_EQ(static_cast<LVType *>(*IntType)->getStorageSizeInBytes(), 4u);149}150 151// Check proper handling of DW_AT_unspecified_parameters in152// LVScope::addMissingElements().153void checkUnspecifiedParameters(LVReader *Reader) {154  LVScopeRoot *Root = Reader->getScopesRoot();155  LVScopeCompileUnit *CompileUnit = getFirstCompileUnit(Root);156 157  EXPECT_EQ(Root->getFileFormatName(), "elf64-x86-64");158  EXPECT_EQ(Root->getName(), DwarfClangUnspecParams);159 160  const LVPublicNames &PublicNames = CompileUnit->getPublicNames();161  ASSERT_EQ(PublicNames.size(), 1u);162 163  LVPublicNames::const_iterator IterNames = PublicNames.cbegin();164  LVScope *Function = (*IterNames).first;165  EXPECT_EQ(Function->getName(), "foo_printf");166  const LVElementsView Elements = Function->getChildren();167  // foo_printf is a variadic function whose prototype is168  // `int foo_printf(const char *, ...)`, where the '...' is represented by a169  // DW_TAG_unspecified_parameters, i.e. we expect to find at least one child170  // for which getIsUnspecified() returns true.171  EXPECT_TRUE(llvm::any_of(Elements, [](const LVElement *elt) {172    return elt->getIsSymbol() &&173           static_cast<const LVSymbol *>(elt)->getIsUnspecified();174  }));175}176 177// Check the basic properties on parsed DW_TAG_module.178void checkScopeModule(LVReader *Reader) {179  LVScopeRoot *Root = Reader->getScopesRoot();180  LVScopeCompileUnit *CompileUnit = getFirstCompileUnit(Root);181 182  EXPECT_EQ(Root->getFileFormatName(), "Mach-O 64-bit x86-64");183  EXPECT_EQ(Root->getName(), DwarfClangModule);184 185  LVElement *FirstChild = *(CompileUnit->getChildren().begin());186  ASSERT_NE(FirstChild, nullptr);187  EXPECT_EQ(FirstChild->getIsScope(), 1);188  LVScopeModule *Module = static_cast<LVScopeModule *>(FirstChild);189  EXPECT_EQ(Module->getIsModule(), 1);190  EXPECT_EQ(Module->getName(), "DebugModule");191}192 193// Check the logical elements selection.194void checkElementSelection(LVReader *Reader) {195  LVScopeRoot *Root = Reader->getScopesRoot();196  LVScopeCompileUnit *CompileUnit = getFirstCompileUnit(Root);197 198  // Get the matched elements.199  LVElements MatchedElements = CompileUnit->getMatchedElements();200  std::map<LVOffset, LVElement *> MapElements;201  for (LVElement *Element : MatchedElements)202    MapElements[Element->getOffset()] = Element;203  ASSERT_EQ(MapElements.size(), 0xeu);204 205  LVElement *Element = MapElements[0x000000004b]; // 'foo'206  ASSERT_NE(Element, nullptr);207  EXPECT_NE(Element->getName().find("foo"), StringRef::npos);208  EXPECT_EQ(Element->getIsScope(), 1);209 210  Element = MapElements[0x00000000c0]; // 'CONSTANT'211  ASSERT_NE(Element, nullptr);212  EXPECT_NE(Element->getName().find("CONSTANT"), StringRef::npos);213  EXPECT_EQ(Element->getIsSymbol(), 1);214 215  Element = MapElements[0x000000002d]; // 'INTPTR'216  ASSERT_NE(Element, nullptr);217  EXPECT_NE(Element->getName().find("INTPTR"), StringRef::npos);218  EXPECT_EQ(Element->getIsType(), 1);219 220  Element = MapElements[0x00000000af]; // 'INTEGER'221  ASSERT_NE(Element, nullptr);222  EXPECT_NE(Element->getName().find("INTEGER"), StringRef::npos);223  EXPECT_EQ(Element->getIsType(), 1);224 225  Element = MapElements[0x000000000f]; // 'movl	%edx, %eax'226  ASSERT_NE(Element, nullptr);227  EXPECT_NE(Element->getName().find("movl"), StringRef::npos);228  EXPECT_EQ(Element->getIsLine(), 1);229 230  // Get the parents for the matched elements.231  LVScopes MatchedScopes = CompileUnit->getMatchedScopes();232  std::set<LVOffset> SetScopes;233  for (LVScope *Scope : MatchedScopes)234    SetScopes.insert(Scope->getOffset());235  std::set<LVOffset>::iterator Iter;236  ASSERT_EQ(SetScopes.size(), 3u);237 238  Iter = SetScopes.find(0x000000000b); // CompileUnit <- 'foo'239  EXPECT_NE(Iter, SetScopes.end());240  Iter = SetScopes.find(0x000000009e); // Function <- 'movl	%edx, %eax'241  EXPECT_NE(Iter, SetScopes.end());242  Iter = SetScopes.find(0x000000009e); // LexicalScope <- 'INTEGER'243  EXPECT_NE(Iter, SetScopes.end());244}245 246// Check the logical elements comparison.247void checkElementComparison(LVReader *Reference, LVReader *Target) {248  LVCompare Compare(nulls());249  Error Err = Compare.execute(Reference, Target);250  ASSERT_THAT_ERROR(std::move(Err), Succeeded());251 252  // Get comparison table.253  LVPassTable PassTable = Compare.getPassTable();254  ASSERT_EQ(PassTable.size(), 4u);255 256  LVReader *Reader;257  LVElement *Element;258  LVComparePass Pass;259 260  // Reference: Missing Variable 'CONSTANT'261  std::tie(Reader, Element, Pass) = PassTable[0];262  ASSERT_NE(Reader, nullptr);263  ASSERT_NE(Element, nullptr);264  EXPECT_EQ(Reader, Reference);265  EXPECT_EQ(Element->getLevel(), 4u);266  EXPECT_EQ(Element->getLineNumber(), 5u);267  EXPECT_EQ(Element->getName(), "CONSTANT");268  EXPECT_EQ(Pass, LVComparePass::Missing);269 270  // Reference: Missing TypeDefinition 'INTEGER'271  std::tie(Reader, Element, Pass) = PassTable[1];272  ASSERT_NE(Reader, nullptr);273  ASSERT_NE(Element, nullptr);274  EXPECT_EQ(Reader, Reference);275  EXPECT_EQ(Element->getLevel(), 3u);276  EXPECT_EQ(Element->getLineNumber(), 4u);277  EXPECT_EQ(Element->getName(), "INTEGER");278  EXPECT_EQ(Pass, LVComparePass::Missing);279 280  // Target: Added Variable 'CONSTANT'281  std::tie(Reader, Element, Pass) = PassTable[2];282  ASSERT_NE(Reader, nullptr);283  ASSERT_NE(Element, nullptr);284  EXPECT_EQ(Reader, Target);285  EXPECT_EQ(Element->getLevel(), 4u);286  EXPECT_EQ(Element->getLineNumber(), 5u);287  EXPECT_EQ(Element->getName(), "CONSTANT");288  EXPECT_EQ(Pass, LVComparePass::Added);289 290  // Target: Added TypeDefinition 'INTEGER'291  std::tie(Reader, Element, Pass) = PassTable[3];292  ASSERT_NE(Reader, nullptr);293  ASSERT_NE(Element, nullptr);294  EXPECT_EQ(Reader, Target);295  EXPECT_EQ(Element->getLevel(), 4u);296  EXPECT_EQ(Element->getLineNumber(), 4u);297  EXPECT_EQ(Element->getName(), "INTEGER");298  EXPECT_EQ(Pass, LVComparePass::Added);299}300 301// Logical elements properties.302void elementProperties(SmallString<128> &InputsDir) {303  // Reader options.304  LVOptions ReaderOptions;305  ReaderOptions.setAttributeOffset();306  ReaderOptions.setAttributeFormat();307  ReaderOptions.setAttributeFilename();308  ReaderOptions.setAttributeProducer();309  ReaderOptions.setAttributePublics();310  ReaderOptions.setAttributeRange();311  ReaderOptions.setAttributeLanguage();312  ReaderOptions.setAttributeLocation();313  ReaderOptions.setAttributeInserted();314  ReaderOptions.setAttributeSize();315  ReaderOptions.setPrintAll();316  ReaderOptions.resolveDependencies();317 318  std::vector<std::string> Objects;319  ScopedPrinter W(outs());320  LVReaderHandler ReaderHandler(Objects, W, ReaderOptions);321 322  // Check logical elements properties.323  std::unique_ptr<LVReader> Reader =324      createReader(ReaderHandler, InputsDir, DwarfClang);325  checkElementProperties(Reader.get());326 327  Reader = createReader(ReaderHandler, InputsDir, DwarfClangUnspecParams);328  checkUnspecifiedParameters(Reader.get());329 330  Reader = createReader(ReaderHandler, InputsDir, DwarfClangModule);331  checkScopeModule(Reader.get());332}333 334// Logical elements selection.335void elementSelection(SmallString<128> &InputsDir) {336  // Reader options.337  LVOptions ReaderOptions;338  ReaderOptions.setAttributeOffset();339  ReaderOptions.setPrintAll();340 341  ReaderOptions.setSelectIgnoreCase();342  ReaderOptions.setSelectUseRegex();343 344  ReaderOptions.setReportList(); // Matched elements.345  ReaderOptions.setReportView(); // Parents for matched elements.346 347  // Add patterns.348  ReaderOptions.Select.Generic.insert("foo");349  ReaderOptions.Select.Generic.insert("movl[ \t]?%");350  ReaderOptions.Select.Generic.insert("INT[a-z]*");351  ReaderOptions.Select.Generic.insert("CONSTANT");352 353  ReaderOptions.resolveDependencies();354 355  std::vector<std::string> Objects;356  ScopedPrinter W(outs());357  LVReaderHandler ReaderHandler(Objects, W, ReaderOptions);358 359  // Check logical elements selection.360  std::unique_ptr<LVReader> Reader =361      createReader(ReaderHandler, InputsDir, DwarfGcc);362  checkElementSelection(Reader.get());363}364 365// Compare logical elements.366void compareElements(SmallString<128> &InputsDir) {367  // Reader options.368  LVOptions ReaderOptions;369  ReaderOptions.setAttributeOffset();370  ReaderOptions.setPrintLines();371  ReaderOptions.setPrintSymbols();372  ReaderOptions.setPrintTypes();373  ReaderOptions.setCompareLines();374  ReaderOptions.setCompareSymbols();375  ReaderOptions.setCompareTypes();376 377  ReaderOptions.resolveDependencies();378 379  std::vector<std::string> Objects;380  ScopedPrinter W(outs());381  LVReaderHandler ReaderHandler(Objects, W, ReaderOptions);382 383  // Check logical comparison.384  std::unique_ptr<LVReader> Reference =385      createReader(ReaderHandler, InputsDir, DwarfClang);386  std::unique_ptr<LVReader> Target =387      createReader(ReaderHandler, InputsDir, DwarfGcc);388  checkElementComparison(Reference.get(), Target.get());389}390 391TEST(LogicalViewTest, DWARFReader) {392  // Initialize targets and assembly printers/parsers.393  llvm::InitializeAllTargetInfos();394  llvm::InitializeAllTargetMCs();395  InitializeAllDisassemblers();396 397  llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::MultiThreaded);398 399  // This test requires a x86-registered-target.400  Triple TT;401  TT.setArch(Triple::x86_64);402  TT.setVendor(Triple::UnknownVendor);403  TT.setOS(Triple::UnknownOS);404 405  std::string TargetLookupError;406  if (!TargetRegistry::lookupTarget(TT, TargetLookupError))407    GTEST_SKIP();408 409  SmallString<128> InputsDir = unittest::getInputFileDirectory(TestMainArgv0);410 411  // Logical elements general properties and selection.412  elementProperties(InputsDir);413  elementSelection(InputsDir);414 415  // Compare logical elements.416  compareElements(InputsDir);417}418 419} // namespace420