[llvm] [llvm-debuginfo-analyzer] Common handling of unsigned attribute values. (PR #116027)

Carlos Alberto Enciso via llvm-commits llvm-commits at lists.llvm.org
Sun Nov 24 22:36:39 PST 2024


https://github.com/CarlosAlbertoEnciso updated https://github.com/llvm/llvm-project/pull/116027

>From 9fb77c9862f1eaaa728a967917147f3e03f9c23e Mon Sep 17 00:00:00 2001
From: Carlos Alberto Enciso <Carlos.Enciso at sony.com>
Date: Wed, 13 Nov 2024 11:10:01 +0000
Subject: [PATCH 1/2] [llvm-debuginfo-analyzer] Common handling of unsigned
 attribute values.

- In the DWARF reader, for those attributes that can have an
  unsigned value, allow for the following cases:
  * Is an implicit constant
  * Is an optional value
---
 .../LogicalView/Readers/LVDWARFReader.cpp     | 26 +++++++++++--------
 ...warf-incorrect-lexical-scope-variable.test |  4 +--
 2 files changed, 17 insertions(+), 13 deletions(-)

diff --git a/llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp b/llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp
index ce1d5619e1fa80..b9ba3357002cab 100644
--- a/llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp
@@ -254,15 +254,18 @@ void LVDWARFReader::processOneAttribute(const DWARFDie &Die,
   // We are processing .debug_info section, implicit_const attribute
   // values are not really stored here, but in .debug_abbrev section.
   auto GetAsUnsignedConstant = [&]() -> int64_t {
-    return AttrSpec.isImplicitConst() ? AttrSpec.getImplicitConstValue()
-                                      : *FormValue.getAsUnsignedConstant();
+    if (AttrSpec.isImplicitConst())
+      return AttrSpec.getImplicitConstValue();
+    if (std::optional<uint64_t> Val = FormValue.getAsUnsignedConstant())
+      return *Val;
+    return 0;
   };
 
   auto GetFlag = [](const DWARFFormValue &FormValue) -> bool {
     return FormValue.isFormClass(DWARFFormValue::FC_Flag);
   };
 
-  auto GetBoundValue = [](const DWARFFormValue &FormValue) -> int64_t {
+  auto GetBoundValue = [&AttrSpec](const DWARFFormValue &FormValue) -> int64_t {
     switch (FormValue.getForm()) {
     case dwarf::DW_FORM_ref_addr:
     case dwarf::DW_FORM_ref1:
@@ -283,6 +286,8 @@ void LVDWARFReader::processOneAttribute(const DWARFDie &Die,
       return *FormValue.getAsUnsignedConstant();
     case dwarf::DW_FORM_sdata:
       return *FormValue.getAsSignedConstant();
+    case dwarf::DW_FORM_implicit_const:
+      return AttrSpec.getImplicitConstValue();
     default:
       return 0;
     }
@@ -295,13 +300,13 @@ void LVDWARFReader::processOneAttribute(const DWARFDie &Die,
 
   switch (AttrSpec.Attr) {
   case dwarf::DW_AT_accessibility:
-    CurrentElement->setAccessibilityCode(*FormValue.getAsUnsignedConstant());
+    CurrentElement->setAccessibilityCode(GetAsUnsignedConstant());
     break;
   case dwarf::DW_AT_artificial:
     CurrentElement->setIsArtificial();
     break;
   case dwarf::DW_AT_bit_size:
-    CurrentElement->setBitSize(*FormValue.getAsUnsignedConstant());
+    CurrentElement->setBitSize(GetAsUnsignedConstant());
     break;
   case dwarf::DW_AT_call_file:
     CurrentElement->setCallFilenameIndex(IncrementFileIndex
@@ -333,13 +338,12 @@ void LVDWARFReader::processOneAttribute(const DWARFDie &Die,
         Stream << hexString(Value, 2);
         CurrentElement->setValue(Stream.str());
       } else
-        CurrentElement->setValue(
-            hexString(*FormValue.getAsUnsignedConstant(), 2));
+        CurrentElement->setValue(hexString(GetAsUnsignedConstant(), 2));
     } else
       CurrentElement->setValue(dwarf::toStringRef(FormValue));
     break;
   case dwarf::DW_AT_count:
-    CurrentElement->setCount(*FormValue.getAsUnsignedConstant());
+    CurrentElement->setCount(GetAsUnsignedConstant());
     break;
   case dwarf::DW_AT_decl_line:
     CurrentElement->setLineNumber(GetAsUnsignedConstant());
@@ -358,10 +362,10 @@ void LVDWARFReader::processOneAttribute(const DWARFDie &Die,
       CurrentElement->setIsExternal();
     break;
   case dwarf::DW_AT_GNU_discriminator:
-    CurrentElement->setDiscriminator(*FormValue.getAsUnsignedConstant());
+    CurrentElement->setDiscriminator(GetAsUnsignedConstant());
     break;
   case dwarf::DW_AT_inline:
-    CurrentElement->setInlineCode(*FormValue.getAsUnsignedConstant());
+    CurrentElement->setInlineCode(GetAsUnsignedConstant());
     break;
   case dwarf::DW_AT_lower_bound:
     CurrentElement->setLowerBound(GetBoundValue(FormValue));
@@ -381,7 +385,7 @@ void LVDWARFReader::processOneAttribute(const DWARFDie &Die,
     CurrentElement->setUpperBound(GetBoundValue(FormValue));
     break;
   case dwarf::DW_AT_virtuality:
-    CurrentElement->setVirtualityCode(*FormValue.getAsUnsignedConstant());
+    CurrentElement->setVirtualityCode(GetAsUnsignedConstant());
     break;
 
   case dwarf::DW_AT_abstract_origin:
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/05-dwarf-incorrect-lexical-scope-variable.test b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/05-dwarf-incorrect-lexical-scope-variable.test
index e1ac7588f1d8c4..3c3c5dcbda520b 100644
--- a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/05-dwarf-incorrect-lexical-scope-variable.test
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/05-dwarf-incorrect-lexical-scope-variable.test
@@ -43,14 +43,14 @@
 ; ONE-EMPTY:
 ; ONE-NEXT: [001]             {CompileUnit} 'pr-43860.cpp'
 ; ONE-NEXT: [002]               {Producer} 'clang version 15.0.0 {{.*}}'
-; ONE-NEXT: [002]     2         {Function} extern not_inlined 'InlineFunction' -> 'int'
+; ONE-NEXT: [002]     2         {Function} extern inlined 'InlineFunction' -> 'int'
 ; ONE-NEXT: [003]                 {Block}
 ; ONE-NEXT: [004]     5             {Variable} 'Var_2' -> 'int'
 ; ONE-NEXT: [003]     2           {Parameter} 'Param' -> 'int'
 ; ONE-NEXT: [003]     3           {Variable} 'Var_1' -> 'int'
 ; ONE-NEXT: [002]    11         {Function} extern not_inlined 'test' -> 'int'
 ; ONE-NEXT: [003]    12           {Variable} 'A' -> 'int'
-; ONE-NEXT: [003]    13           {InlinedFunction} not_inlined 'InlineFunction' -> 'int'
+; ONE-NEXT: [003]    13           {InlinedFunction} inlined 'InlineFunction' -> 'int'
 ; ONE-NEXT: [004]                   {Block}
 ; ONE-NEXT: [005]                     {Variable} 'Var_2' -> 'int'
 ; ONE-NEXT: [004]                   {Parameter} 'Param' -> 'int'

>From cdf1783e84988ad5420120dde80643281203461e Mon Sep 17 00:00:00 2001
From: Carlos Alberto Enciso <Carlos.Enciso at sony.com>
Date: Mon, 25 Nov 2024 06:27:32 +0000
Subject: [PATCH 2/2] [llvm-debuginfo-analyzer] Common handling of unsigned
 attribute values.

- In the DWARF reader, for those attributes that can have an
  unsigned value, allow for the following cases:
  * Is an implicit constant
  * Is an optional value
- The testing is done by creating a file with generated DWARF,
  using 'DwarfGenerator' (generate DWARF debug info for unit tests).
---
 .../DebugInfo/LogicalView/CMakeLists.txt      |   5 +
 .../LogicalView/DWARFGeneratedTest.cpp        | 370 ++++++++++++++++++
 2 files changed, 375 insertions(+)
 create mode 100644 llvm/unittests/DebugInfo/LogicalView/DWARFGeneratedTest.cpp

diff --git a/llvm/unittests/DebugInfo/LogicalView/CMakeLists.txt b/llvm/unittests/DebugInfo/LogicalView/CMakeLists.txt
index 1116edb212b057..cb38f5301279b0 100644
--- a/llvm/unittests/DebugInfo/LogicalView/CMakeLists.txt
+++ b/llvm/unittests/DebugInfo/LogicalView/CMakeLists.txt
@@ -1,7 +1,9 @@
 set(LLVM_LINK_COMPONENTS
+  ${LLVM_TARGETS_TO_BUILD}
   AllTargetsDescs
   AllTargetsDisassemblers
   AllTargetsInfos
+  AsmPrinter
   DebugInfoLogicalView
   MC
   MCDisassembler
@@ -9,9 +11,12 @@ set(LLVM_LINK_COMPONENTS
   )
 
 add_llvm_unittest_with_input_files(DebugInfoLogicalViewTests
+  ../DWARF/DwarfGenerator.cpp
+  ../DWARF/DwarfUtils.cpp
   CodeViewReaderTest.cpp
   CommandLineOptionsTest.cpp
   CompareElementsTest.cpp
+  DWARFGeneratedTest.cpp
   DWARFReaderTest.cpp
   SelectElementsTest.cpp
   LocationRangesTest.cpp
diff --git a/llvm/unittests/DebugInfo/LogicalView/DWARFGeneratedTest.cpp b/llvm/unittests/DebugInfo/LogicalView/DWARFGeneratedTest.cpp
new file mode 100644
index 00000000000000..b51df0993a135e
--- /dev/null
+++ b/llvm/unittests/DebugInfo/LogicalView/DWARFGeneratedTest.cpp
@@ -0,0 +1,370 @@
+//===- llvm/unittest/DebugInfo/LogicalView/DWARFGeneratedTest.cpp ---------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "../DWARF/DwarfGenerator.h"
+#include "../DWARF/DwarfUtils.h"
+#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVLine.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVReader.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVScope.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVType.h"
+#include "llvm/DebugInfo/LogicalView/LVReaderHandler.h"
+#include "llvm/MC/TargetRegistry.h"
+#include "llvm/Support/COM.h"
+#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/ScopedPrinter.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/ToolOutputFile.h"
+#include "llvm/Testing/Support/Error.h"
+#include "llvm/Testing/Support/SupportHelpers.h"
+
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::logicalview;
+using namespace llvm::dwarf;
+using namespace llvm::dwarf::utils;
+
+namespace {
+
+// Helper function to get the first compile unit.
+LVScopeCompileUnit *getFirstCompileUnit(LVScopeRoot *Root) {
+  EXPECT_NE(Root, nullptr);
+  const LVScopes *CompileUnits = Root->getScopes();
+  EXPECT_NE(CompileUnits, nullptr);
+  EXPECT_EQ(CompileUnits->size(), 1u);
+
+  LVScopes::const_iterator Iter = CompileUnits->begin();
+  EXPECT_NE(Iter, nullptr);
+  LVScopeCompileUnit *CompileUnit = static_cast<LVScopeCompileUnit *>(*Iter);
+  EXPECT_NE(CompileUnit, nullptr);
+  return CompileUnit;
+}
+
+// Helper function to create a reader.
+std::unique_ptr<LVReader> createReader(LVReaderHandler &ReaderHandler,
+                                       SmallString<128> &InputsDir,
+                                       StringRef Filename) {
+  SmallString<128> ObjectName(InputsDir);
+  llvm::sys::path::append(ObjectName, Filename);
+
+  Expected<std::unique_ptr<LVReader>> ReaderOrErr =
+      ReaderHandler.createReader(std::string(ObjectName));
+  EXPECT_THAT_EXPECTED(ReaderOrErr, Succeeded());
+  std::unique_ptr<LVReader> Reader = std::move(*ReaderOrErr);
+  EXPECT_NE(Reader, nullptr);
+  return Reader;
+}
+
+// Create a file with generated DWARF.
+void generateDebugInfo(StringRef Path, Triple &Triple) {
+  uint16_t Version = 5;
+  auto ExpectedDG = dwarfgen::Generator::create(Triple, Version);
+  ASSERT_THAT_EXPECTED(ExpectedDG, Succeeded());
+  dwarfgen::Generator *DG = ExpectedDG.get().get();
+  dwarfgen::CompileUnit &CU = DG->addCompileUnit();
+
+  dwarfgen::DIE CUDie = CU.getUnitDIE();
+  CUDie.addAttribute(DW_AT_name, DW_FORM_strp, "test.cpp");
+  CUDie.addAttribute(DW_AT_language, DW_FORM_data2, DW_LANG_C_plus_plus);
+  CUDie.addAttribute(DW_AT_producer, DW_FORM_strp, "dwarfgen::Generator");
+
+  dwarfgen::DIE ScopeValueDie = CUDie.addChild(DW_TAG_inlined_subroutine);
+  ScopeValueDie.addAttribute(DW_AT_accessibility, DW_FORM_data1, 1);
+  ScopeValueDie.addAttribute(DW_AT_inline, DW_FORM_data4, 2);
+  ScopeValueDie.addAttribute(DW_AT_virtuality, DW_FORM_data4, 3);
+  ScopeValueDie.addAttribute(DW_AT_call_file, DW_FORM_data4, 4);
+  ScopeValueDie.addAttribute(DW_AT_call_line, DW_FORM_data4, 5);
+  ScopeValueDie.addAttribute(DW_AT_decl_file, DW_FORM_data4, 6);
+  ScopeValueDie.addAttribute(DW_AT_decl_line, DW_FORM_data4, 7);
+  ScopeValueDie.addAttribute(DW_AT_GNU_discriminator, DW_FORM_data4, 8);
+
+  dwarfgen::DIE ScopeNoValueDie = CUDie.addChild(DW_TAG_inlined_subroutine);
+  ScopeNoValueDie.addAttribute(DW_AT_accessibility, DW_FORM_sdata, 1);
+  ScopeNoValueDie.addAttribute(DW_AT_inline, DW_FORM_sdata, 2);
+  ScopeNoValueDie.addAttribute(DW_AT_virtuality, DW_FORM_sdata, 3);
+  ScopeNoValueDie.addAttribute(DW_AT_call_file, DW_FORM_sdata, 4);
+  ScopeNoValueDie.addAttribute(DW_AT_call_line, DW_FORM_sdata, 5);
+  ScopeNoValueDie.addAttribute(DW_AT_decl_file, DW_FORM_sdata, 6);
+  ScopeNoValueDie.addAttribute(DW_AT_decl_line, DW_FORM_sdata, 7);
+  ScopeNoValueDie.addAttribute(DW_AT_GNU_discriminator, DW_FORM_sdata, 8);
+
+  dwarfgen::DIE ScopeImplicitDie = CUDie.addChild(DW_TAG_inlined_subroutine);
+  ScopeImplicitDie.addAttribute(DW_AT_accessibility, DW_FORM_implicit_const, 1);
+  ScopeImplicitDie.addAttribute(DW_AT_inline, DW_FORM_implicit_const, 2);
+  ScopeImplicitDie.addAttribute(DW_AT_virtuality, DW_FORM_implicit_const, 3);
+  ScopeImplicitDie.addAttribute(DW_AT_call_file, DW_FORM_implicit_const, 4);
+  ScopeImplicitDie.addAttribute(DW_AT_call_line, DW_FORM_implicit_const, 5);
+  ScopeImplicitDie.addAttribute(DW_AT_decl_file, DW_FORM_implicit_const, 6);
+  ScopeImplicitDie.addAttribute(DW_AT_decl_line, DW_FORM_implicit_const, 7);
+  ScopeImplicitDie.addAttribute(DW_AT_GNU_discriminator, DW_FORM_implicit_const,
+                                8);
+
+  dwarfgen::DIE SymbolValueDie = CUDie.addChild(DW_TAG_variable);
+  SymbolValueDie.addAttribute(DW_AT_bit_size, DW_FORM_data1, 1);
+
+  dwarfgen::DIE SymbolNoValueDie = CUDie.addChild(DW_TAG_variable);
+  SymbolNoValueDie.addAttribute(DW_AT_bit_size, DW_FORM_sdata, 1);
+
+  dwarfgen::DIE SymbolImplicitDie = CUDie.addChild(DW_TAG_variable);
+  SymbolImplicitDie.addAttribute(DW_AT_bit_size, DW_FORM_implicit_const, 1);
+
+  dwarfgen::DIE TypeValueCountDie = CUDie.addChild(DW_TAG_subrange_type);
+  TypeValueCountDie.addAttribute(DW_AT_count, DW_FORM_data4, 1);
+
+  dwarfgen::DIE TypeNoValueCountDie = CUDie.addChild(DW_TAG_subrange_type);
+  TypeNoValueCountDie.addAttribute(DW_AT_count, DW_FORM_sdata, 1);
+
+  dwarfgen::DIE TypeImplicitCountDie = CUDie.addChild(DW_TAG_subrange_type);
+  TypeImplicitCountDie.addAttribute(DW_AT_count, DW_FORM_implicit_const, 1);
+
+  dwarfgen::DIE TypeValueRangeDie = CUDie.addChild(DW_TAG_subrange_type);
+  TypeValueRangeDie.addAttribute(DW_AT_lower_bound, DW_FORM_data4, 1);
+  TypeValueRangeDie.addAttribute(DW_AT_upper_bound, DW_FORM_data4, 2);
+
+  dwarfgen::DIE TypeNoValueRangeDie = CUDie.addChild(DW_TAG_subrange_type);
+  TypeNoValueRangeDie.addAttribute(DW_AT_lower_bound, DW_FORM_addr, 3);
+  TypeNoValueRangeDie.addAttribute(DW_AT_upper_bound, DW_FORM_addr, 4);
+
+  dwarfgen::DIE TypeImplicitRangeDie = CUDie.addChild(DW_TAG_subrange_type);
+  TypeImplicitRangeDie.addAttribute(DW_AT_lower_bound, DW_FORM_implicit_const,
+                                    5);
+  TypeImplicitRangeDie.addAttribute(DW_AT_upper_bound, DW_FORM_implicit_const,
+                                    6);
+
+  // Generate the DWARF.
+  StringRef FileBytes = DG->generate();
+  MemoryBufferRef FileBuffer(FileBytes, "dwarf");
+  auto Obj = object::ObjectFile::createObjectFile(FileBuffer);
+  EXPECT_TRUE((bool)Obj);
+  std::unique_ptr<DWARFContext> DwarfContext = DWARFContext::create(**Obj);
+
+  // Verify the number of compile units is correct.
+  uint32_t NumCUs = DwarfContext->getNumCompileUnits();
+  EXPECT_EQ(NumCUs, 1u);
+  DWARFCompileUnit *U = cast<DWARFCompileUnit>(DwarfContext->getUnitAtIndex(0));
+  auto DieDG = U->getUnitDIE(false);
+  EXPECT_TRUE(DieDG.isValid());
+
+  // Verify the siblings correct order.
+  //   ScopeValue
+  //   ScopeNoValue
+  //   ScopeImplicit
+  auto ScopeValueDieDG = DieDG.getFirstChild();
+  EXPECT_TRUE(ScopeValueDieDG.isValid());
+  EXPECT_EQ(ScopeValueDieDG.getTag(), DW_TAG_inlined_subroutine);
+  auto ScopeNoValueDieDG = ScopeValueDieDG.getSibling();
+  EXPECT_TRUE(ScopeNoValueDieDG.isValid());
+  EXPECT_EQ(ScopeNoValueDieDG.getTag(), DW_TAG_inlined_subroutine);
+  auto ScopeImplicitDieDG = ScopeNoValueDieDG.getSibling();
+  EXPECT_TRUE(ScopeImplicitDieDG.isValid());
+  EXPECT_EQ(ScopeImplicitDieDG.getTag(), DW_TAG_inlined_subroutine);
+
+  // Verify the siblings correct order.
+  //   SymbolValue
+  //   SymbolNoValue
+  //   SymbolImplicitValue
+  auto SymbolValueDieDG = ScopeImplicitDieDG.getSibling();
+  EXPECT_TRUE(SymbolValueDieDG.isValid());
+  EXPECT_EQ(SymbolValueDieDG.getTag(), DW_TAG_variable);
+  auto SymbolNoValueDieDG = SymbolValueDieDG.getSibling();
+  EXPECT_TRUE(SymbolNoValueDieDG.isValid());
+  EXPECT_EQ(SymbolNoValueDieDG.getTag(), DW_TAG_variable);
+  auto SymbolImplicitDieDG = SymbolNoValueDieDG.getSibling();
+  EXPECT_TRUE(SymbolImplicitDieDG.isValid());
+  EXPECT_EQ(SymbolImplicitDieDG.getTag(), DW_TAG_variable);
+
+  // Verify the siblings correct order.
+  //   TypeValueCount
+  //   TypeNoValueCount
+  //   TypeImplicitValueCount
+  auto TypeValueCountDieDG = SymbolImplicitDieDG.getSibling();
+  EXPECT_TRUE(TypeValueCountDieDG.isValid());
+  EXPECT_EQ(TypeValueCountDieDG.getTag(), DW_TAG_subrange_type);
+  auto TypeNoValueCountDieDG = TypeValueCountDieDG.getSibling();
+  EXPECT_TRUE(TypeNoValueCountDieDG.isValid());
+  EXPECT_EQ(TypeNoValueCountDieDG.getTag(), DW_TAG_subrange_type);
+  auto TypeImplicitCountDieDG = TypeNoValueCountDieDG.getSibling();
+  EXPECT_TRUE(TypeImplicitCountDieDG.isValid());
+  EXPECT_EQ(TypeImplicitCountDieDG.getTag(), DW_TAG_subrange_type);
+
+  // Verify the siblings correct order.
+  //   TypeValueRange
+  //   TypeNoValueRange
+  //   TypeImplicitValueRange
+  auto TypeValueRangeDieDG = TypeImplicitCountDieDG.getSibling();
+  EXPECT_TRUE(TypeValueRangeDieDG.isValid());
+  EXPECT_EQ(TypeValueRangeDieDG.getTag(), DW_TAG_subrange_type);
+  auto TypeNoValueRangeDieDG = TypeValueRangeDieDG.getSibling();
+  EXPECT_TRUE(TypeNoValueRangeDieDG.isValid());
+  EXPECT_EQ(TypeNoValueRangeDieDG.getTag(), DW_TAG_subrange_type);
+  auto TypeImplicitRangeDieDG = TypeNoValueRangeDieDG.getSibling();
+  EXPECT_TRUE(TypeImplicitRangeDieDG.isValid());
+  EXPECT_EQ(TypeImplicitRangeDieDG.getTag(), DW_TAG_subrange_type);
+
+  // Save the generated DWARF file to disk.
+  EXPECT_TRUE(DG->saveFile(Path));
+}
+
+// Check the logical elements basic properties.
+void checkElementAttributes(LVReader *Reader) {
+  LVScopeRoot *Root = Reader->getScopesRoot();
+  EXPECT_NE(Root, nullptr);
+  LVScopeCompileUnit *CompileUnit = getFirstCompileUnit(Root);
+
+  const LVScopes *Scopes = CompileUnit->getScopes();
+  ASSERT_NE(Scopes, nullptr);
+  ASSERT_EQ(Scopes->size(), 3u);
+
+  // Check values.
+  LVScopes::const_iterator ScopeIter = Scopes->begin();
+  EXPECT_NE(ScopeIter, nullptr);
+  LVScope *Scope = static_cast<LVScope *>(*ScopeIter);
+  EXPECT_NE(Scope, nullptr);
+  EXPECT_EQ(Scope->getAccessibilityCode(), 1); // Element
+  EXPECT_EQ(Scope->getInlineCode(), 2);        // Element
+  EXPECT_EQ(Scope->getVirtualityCode(), 3);    // Element
+  EXPECT_EQ(Scope->getCallFilenameIndex(), 5); // ScopeFunctionInlined
+  EXPECT_EQ(Scope->getCallLineNumber(), 5);    // ScopeFunctionInlined
+  EXPECT_EQ(Scope->getFilenameIndex(), 7);     // Element
+  EXPECT_EQ(Scope->getLineNumber(), 7);        // Element
+  EXPECT_EQ(Scope->getDiscriminator(), 8);     // ScopeFunctionInlined
+
+  // Check no-values.
+  EXPECT_NE(++ScopeIter, nullptr);
+  Scope = static_cast<LVScope *>(*ScopeIter);
+  EXPECT_NE(Scope, nullptr);
+  EXPECT_EQ(Scope->getAccessibilityCode(), 0); // Element
+  EXPECT_EQ(Scope->getInlineCode(), 0);        // Element
+  EXPECT_EQ(Scope->getVirtualityCode(), 0);    // Element
+  EXPECT_EQ(Scope->getCallFilenameIndex(), 1); // ScopeFunctionInlined
+  EXPECT_EQ(Scope->getCallLineNumber(), 0);    // ScopeFunctionInlined
+  EXPECT_EQ(Scope->getFilenameIndex(), 1);     // Element
+  EXPECT_EQ(Scope->getLineNumber(), 0);        // Element
+  EXPECT_EQ(Scope->getDiscriminator(), 0);     // ScopeFunctionInlined
+
+  // Check implicit values.
+  EXPECT_NE(++ScopeIter, nullptr);
+  Scope = static_cast<LVScope *>(*ScopeIter);
+  EXPECT_NE(Scope, nullptr);
+  EXPECT_EQ(Scope->getAccessibilityCode(), 1); // Element
+  EXPECT_EQ(Scope->getInlineCode(), 2);        // Element
+  EXPECT_EQ(Scope->getVirtualityCode(), 3);    // Element
+  EXPECT_EQ(Scope->getCallFilenameIndex(), 5); // ScopeFunctionInlined
+  EXPECT_EQ(Scope->getCallLineNumber(), 5);    // ScopeFunctionInlined
+  EXPECT_EQ(Scope->getFilenameIndex(), 7);     // Element
+  EXPECT_EQ(Scope->getLineNumber(), 7);        // Element
+  EXPECT_EQ(Scope->getDiscriminator(), 8);     // ScopeFunctionInlined
+
+  const LVSymbols *Symbols = CompileUnit->getSymbols();
+  ASSERT_NE(Symbols, nullptr);
+  ASSERT_EQ(Symbols->size(), 3u);
+
+  // Check values.
+  LVSymbols::const_iterator SymbolIter = Symbols->begin();
+  EXPECT_NE(SymbolIter, nullptr);
+  LVSymbol *Symbol = static_cast<LVSymbol *>(*SymbolIter);
+  EXPECT_NE(Symbol, nullptr);
+  EXPECT_EQ(Symbol->getBitSize(), 1); // Symbol
+
+  // Check no-values.
+  EXPECT_NE(++SymbolIter, nullptr);
+  Symbol = static_cast<LVSymbol *>(*SymbolIter);
+  EXPECT_NE(Symbol, nullptr);
+  EXPECT_EQ(Symbol->getBitSize(), 0); // Symbol
+
+  // Check implicit values.
+  EXPECT_NE(++SymbolIter, nullptr);
+  Symbol = static_cast<LVSymbol *>(*SymbolIter);
+  EXPECT_NE(Symbol, nullptr);
+  EXPECT_EQ(Symbol->getBitSize(), 1); // Symbol
+
+  const LVTypes *Types = CompileUnit->getTypes();
+  ASSERT_NE(Types, nullptr);
+  ASSERT_EQ(Types->size(), 6u);
+
+  // Check values.
+  LVTypes::const_iterator TypeIter = Types->begin();
+  EXPECT_NE(TypeIter, nullptr);
+  LVType *Type = static_cast<LVType *>(*TypeIter);
+  EXPECT_NE(Type, nullptr);
+  EXPECT_EQ(Type->getCount(), 1); // Type
+
+  // Check no-values.
+  EXPECT_NE(++TypeIter, nullptr);
+  Type = static_cast<LVType *>(*TypeIter);
+  EXPECT_NE(Type, nullptr);
+  EXPECT_EQ(Type->getCount(), 0); // Type
+
+  // Check implicit values.
+  EXPECT_NE(++TypeIter, nullptr);
+  Type = static_cast<LVType *>(*TypeIter);
+  EXPECT_NE(Type, nullptr);
+  EXPECT_EQ(Type->getCount(), 1); // Type
+
+  // Check values.
+  EXPECT_NE(++TypeIter, nullptr);
+  Type = static_cast<LVType *>(*TypeIter);
+  EXPECT_NE(Type, nullptr);
+  EXPECT_EQ(Type->getLowerBound(), 1); // Type
+  EXPECT_EQ(Type->getUpperBound(), 2); // Type
+
+  // Check no-values.
+  EXPECT_NE(++TypeIter, nullptr);
+  Type = static_cast<LVType *>(*TypeIter);
+  EXPECT_NE(Type, nullptr);
+  EXPECT_EQ(Type->getLowerBound(), 0); // Type
+  EXPECT_EQ(Type->getUpperBound(), 0); // Type
+
+  // Check implicit values.
+  EXPECT_NE(++TypeIter, nullptr);
+  Type = static_cast<LVType *>(*TypeIter);
+  EXPECT_NE(Type, nullptr);
+  EXPECT_EQ(Type->getLowerBound(), 5); // Type
+  EXPECT_EQ(Type->getUpperBound(), 6); // Type
+}
+
+TEST(LogicalViewTest, ElementAttributes) {
+  // Initialize targets and assembly printers/parsers.
+  llvm::InitializeAllTargetInfos();
+  llvm::InitializeAllTargetMCs();
+  InitializeAllDisassemblers();
+
+  llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::MultiThreaded);
+
+  Triple Triple(Triple::normalize("x86_64-pc-linux-gnu"));
+  if (!isConfigurationSupported(Triple))
+    GTEST_SKIP();
+
+  unittest::TempDir TestDirectory("dwarf-test", /*Unique=*/true);
+  llvm::SmallString<128> DirName(TestDirectory.path());
+  StringRef Filename("test.o");
+  llvm::SmallString<128> Path(TestDirectory.path(Filename));
+  generateDebugInfo(Path, Triple);
+
+  // Reader options.
+  LVOptions ReaderOptions;
+  ReaderOptions.setPrintScopes();
+  ReaderOptions.setPrintSymbols();
+  ReaderOptions.setPrintTypes();
+  ReaderOptions.resolveDependencies();
+
+  std::vector<std::string> Objects;
+  ScopedPrinter W(outs());
+  LVReaderHandler ReaderHandler(Objects, W, ReaderOptions);
+
+  // Check logical elements properties.
+  std::unique_ptr<LVReader> Reader =
+      createReader(ReaderHandler, DirName, Filename);
+
+  checkElementAttributes(Reader.get());
+}
+
+} // namespace



More information about the llvm-commits mailing list