diff --git a/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp index 8bbaf93db0caa..f187b1a57bd45 100644 --- a/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp +++ b/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp @@ -330,13 +330,16 @@ void LVScope::addMissingElements(LVScope *Reference) { Symbol->setIsOptimized(); Symbol->setReference(Reference); - // The symbol can be a constant, parameter or variable. + // The symbol can be a constant, parameter, variable or unspecified + // parameters (i.e. `...`). if (Reference->getIsConstant()) Symbol->setIsConstant(); else if (Reference->getIsParameter()) Symbol->setIsParameter(); else if (Reference->getIsVariable()) Symbol->setIsVariable(); + else if (Reference->getIsUnspecified()) + Symbol->setIsUnspecified(); else llvm_unreachable("Invalid symbol kind."); } diff --git a/llvm/lib/DebugInfo/LogicalView/Readers/LVBinaryReader.cpp b/llvm/lib/DebugInfo/LogicalView/Readers/LVBinaryReader.cpp index ad14baa0c9269..c1ebe0dda4a16 100644 --- a/llvm/lib/DebugInfo/LogicalView/Readers/LVBinaryReader.cpp +++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVBinaryReader.cpp @@ -433,6 +433,15 @@ Error LVBinaryReader::createInstructions(LVScope *Scope, ArrayRef Bytes = arrayRefFromStringRef(*SectionContentsOrErr); uint64_t Offset = Address - SectionAddress; + if (Offset > Bytes.size()) { + LLVM_DEBUG({ + dbgs() << "offset (" << hexValue(Offset) << ") is beyond section size (" + << hexValue(Bytes.size()) << "); malformed input?\n"; + }); + return createStringError( + errc::bad_address, + "Failed to parse instructions; offset beyond section size"); + } uint8_t const *Begin = Bytes.data() + Offset; uint8_t const *End = Bytes.data() + Offset + Size; diff --git a/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp b/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp index c062c15481da9..03bf394631c99 100644 --- a/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp +++ b/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp @@ -30,6 +30,9 @@ extern const char *TestMainArgv0; namespace { const char *DwarfClang = "test-dwarf-clang.o"; +// Two compile units: one declares `extern int foo_printf(const char *, ...);` +// and another one that defines the function. +const char *DwarfClangUnspecParams = "test-dwarf-clang-unspec-params.elf"; const char *DwarfGcc = "test-dwarf-gcc.o"; // Helper function to get the first compile unit. @@ -37,7 +40,7 @@ LVScopeCompileUnit *getFirstCompileUnit(LVScopeRoot *Root) { EXPECT_NE(Root, nullptr); const LVScopes *CompileUnits = Root->getScopes(); EXPECT_NE(CompileUnits, nullptr); - EXPECT_EQ(CompileUnits->size(), 1u); + EXPECT_GT(CompileUnits->size(), 0u); LVScopes::const_iterator Iter = CompileUnits->begin(); EXPECT_NE(Iter, nullptr); @@ -124,6 +127,36 @@ void checkElementProperties(LVReader *Reader) { ASSERT_EQ(Lines->size(), 0x12u); } +// Check proper handling of DW_AT_unspecified_parameters in +// LVScope::addMissingElements(). +void checkUnspecifiedParameters(LVReader *Reader) { + LVScopeRoot *Root = Reader->getScopesRoot(); + LVScopeCompileUnit *CompileUnit = getFirstCompileUnit(Root); + + EXPECT_EQ(Root->getFileFormatName(), "elf64-x86-64"); + EXPECT_EQ(Root->getName(), DwarfClangUnspecParams); + + const LVPublicNames &PublicNames = CompileUnit->getPublicNames(); + ASSERT_EQ(PublicNames.size(), 1u); + + LVPublicNames::const_iterator IterNames = PublicNames.cbegin(); + LVScope *Function = (*IterNames).first; + EXPECT_EQ(Function->getName(), "foo_printf"); + const LVElements *Elements = Function->getChildren(); + ASSERT_NE(Elements, nullptr); + // foo_printf is a variadic function whose prototype is + // `int foo_printf(const char *, ...)`, where the '...' is represented by a + // DW_TAG_unspecified_parameters, i.e. we expect to find at least one child + // for which getIsUnspecified() returns true. + EXPECT_EQ(std::any_of( + Elements->begin(), Elements->end(), + [](const LVElement *elt) { + return elt->getIsSymbol() && + static_cast(elt)->getIsUnspecified(); + }), + true); +} + // Check the logical elements selection. void checkElementSelection(LVReader *Reader) { LVScopeRoot *Root = Reader->getScopesRoot(); @@ -253,6 +286,7 @@ void elementProperties(SmallString<128> &InputsDir) { ReaderOptions.setAttributePublics(); ReaderOptions.setAttributeRange(); ReaderOptions.setAttributeLocation(); + ReaderOptions.setAttributeInserted(); ReaderOptions.setPrintAll(); ReaderOptions.resolveDependencies(); @@ -264,6 +298,9 @@ void elementProperties(SmallString<128> &InputsDir) { std::unique_ptr Reader = createReader(ReaderHandler, InputsDir, DwarfClang); checkElementProperties(Reader.get()); + + Reader = createReader(ReaderHandler, InputsDir, DwarfClangUnspecParams); + checkUnspecifiedParameters(Reader.get()); } // Logical elements selection. diff --git a/llvm/unittests/DebugInfo/LogicalView/Inputs/test-dwarf-clang-unspec-params.elf b/llvm/unittests/DebugInfo/LogicalView/Inputs/test-dwarf-clang-unspec-params.elf new file mode 100755 index 0000000000000..67c6e71fbf7b9 Binary files /dev/null and b/llvm/unittests/DebugInfo/LogicalView/Inputs/test-dwarf-clang-unspec-params.elf differ