| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| //===-- LVReaderHandler.h ---------------------------------------*- C++ -*-===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This class implements the Reader handler. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_DEBUGINFO_LOGICALVIEW_READERS_LVREADERHANDLER_H | ||
| #define LLVM_DEBUGINFO_LOGICALVIEW_READERS_LVREADERHANDLER_H | ||
|
|
||
| #include "llvm/ADT/PointerUnion.h" | ||
| #include "llvm/DebugInfo/LogicalView/Core/LVReader.h" | ||
| #include "llvm/DebugInfo/PDB/Native/PDBFile.h" | ||
| #include "llvm/Object/Archive.h" | ||
| #include "llvm/Object/MachOUniversal.h" | ||
| #include "llvm/Object/ObjectFile.h" | ||
| #include "llvm/Support/MemoryBuffer.h" | ||
| #include "llvm/Support/ScopedPrinter.h" | ||
| #include <string> | ||
| #include <vector> | ||
|
|
||
| namespace llvm { | ||
| namespace logicalview { | ||
|
|
||
| using LVReaders = std::vector<LVReader *>; | ||
| using ArgVector = std::vector<std::string>; | ||
| using PdbOrObj = PointerUnion<object::ObjectFile *, pdb::PDBFile *>; | ||
|
|
||
| // This class performs the following tasks: | ||
| // - Creates a logical reader for every binary file in the command line, | ||
| // that parses the debug information and creates a high level logical | ||
| // view representation containing scopes, symbols, types and lines. | ||
| // - Prints and compares the logical views. | ||
| // | ||
| // The supported binary formats are: ELF, Mach-O and CodeView. | ||
| class LVReaderHandler { | ||
| ArgVector &Objects; | ||
| ScopedPrinter &W; | ||
| raw_ostream &OS; | ||
| LVReaders TheReaders; | ||
|
|
||
| Error createReaders(); | ||
| void destroyReaders(); | ||
| Error printReaders(); | ||
| Error compareReaders(); | ||
|
|
||
| Error handleArchive(LVReaders &Readers, StringRef Filename, | ||
| object::Archive &Arch); | ||
| Error handleBuffer(LVReaders &Readers, StringRef Filename, | ||
| MemoryBufferRef Buffer, StringRef ExePath = {}); | ||
| Error handleFile(LVReaders &Readers, StringRef Filename, | ||
| StringRef ExePath = {}); | ||
| Error handleMach(LVReaders &Readers, StringRef Filename, | ||
| object::MachOUniversalBinary &Mach); | ||
| Error handleObject(LVReaders &Readers, StringRef Filename, | ||
| object::Binary &Binary); | ||
|
|
||
| Error createReader(StringRef Filename, LVReaders &Readers, PdbOrObj &Input, | ||
| StringRef FileFormatName, StringRef ExePath = {}); | ||
|
|
||
| public: | ||
| LVReaderHandler() = delete; | ||
| LVReaderHandler(ArgVector &Objects, ScopedPrinter &W, | ||
| LVOptions &ReaderOptions) | ||
| : Objects(Objects), W(W), OS(W.getOStream()) { | ||
| setOptions(&ReaderOptions); | ||
| } | ||
| LVReaderHandler(const LVReaderHandler &) = delete; | ||
| LVReaderHandler &operator=(const LVReaderHandler &) = delete; | ||
| ~LVReaderHandler() { destroyReaders(); } | ||
|
|
||
| Error createReader(StringRef Filename, LVReaders &Readers) { | ||
| return handleFile(Readers, Filename); | ||
| } | ||
| Error process(); | ||
|
|
||
| Expected<LVReader *> createReader(StringRef Pathname) { | ||
| LVReaders Readers; | ||
| if (Error Err = createReader(Pathname, Readers)) | ||
| return std::move(Err); | ||
| return Readers[0]; | ||
| } | ||
| void deleteReader(LVReader *Reader) { delete Reader; } | ||
|
|
||
| void print(raw_ostream &OS) const; | ||
|
|
||
| #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) | ||
| void dump() const { print(dbgs()); } | ||
| #endif | ||
| }; | ||
|
|
||
| } // end namespace logicalview | ||
| } // namespace llvm | ||
|
|
||
| #endif // LLVM_DEBUGINFO_LOGICALVIEW_READERS_LVREADERHANDLER_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,180 @@ | ||
| //===-- LVBinaryReader.h ----------------------------------------*- C++ -*-===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This file defines the LVBinaryReader class, which is used to describe a | ||
| // binary reader. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_DEBUGINFO_LOGICALVIEW_READERS_LVBINARYREADER_H | ||
| #define LLVM_DEBUGINFO_LOGICALVIEW_READERS_LVBINARYREADER_H | ||
|
|
||
| #include "llvm/DebugInfo/LogicalView/Core/LVReader.h" | ||
| #include "llvm/MC/MCAsmInfo.h" | ||
| #include "llvm/MC/MCContext.h" | ||
| #include "llvm/MC/MCDisassembler/MCDisassembler.h" | ||
| #include "llvm/MC/MCInstPrinter.h" | ||
| #include "llvm/MC/MCInstrInfo.h" | ||
| #include "llvm/MC/MCObjectFileInfo.h" | ||
| #include "llvm/MC/MCRegisterInfo.h" | ||
| #include "llvm/MC/MCSubtargetInfo.h" | ||
| #include "llvm/MC/TargetRegistry.h" | ||
| #include "llvm/Object/ObjectFile.h" | ||
|
|
||
| namespace llvm { | ||
| namespace logicalview { | ||
|
|
||
| constexpr bool UpdateHighAddress = false; | ||
|
|
||
| // Logical scope, Section address, Section index, IsComdat. | ||
| struct LVSymbolTableEntry final { | ||
| LVScope *Scope = nullptr; | ||
| LVAddress Address = 0; | ||
| LVSectionIndex SectionIndex = 0; | ||
| bool IsComdat = false; | ||
| LVSymbolTableEntry() = default; | ||
| LVSymbolTableEntry(LVScope *Scope, LVAddress Address, | ||
| LVSectionIndex SectionIndex, bool IsComdat) | ||
| : Scope(Scope), Address(Address), SectionIndex(SectionIndex), | ||
| IsComdat(IsComdat) {} | ||
| }; | ||
|
|
||
| // Function names extracted from the object symbol table. | ||
| class LVSymbolTable final { | ||
| using LVSymbolNames = std::map<std::string, LVSymbolTableEntry>; | ||
| LVSymbolNames SymbolNames; | ||
|
|
||
| public: | ||
| LVSymbolTable() = default; | ||
|
|
||
| void add(StringRef Name, LVScope *Function, LVSectionIndex SectionIndex = 0); | ||
| void add(StringRef Name, LVAddress Address, LVSectionIndex SectionIndex, | ||
| bool IsComdat); | ||
| LVSectionIndex update(LVScope *Function); | ||
|
|
||
| const LVSymbolTableEntry &getEntry(StringRef Name); | ||
| LVAddress getAddress(StringRef Name); | ||
| LVSectionIndex getIndex(StringRef Name); | ||
| bool getIsComdat(StringRef Name); | ||
|
|
||
| void print(raw_ostream &OS); | ||
| }; | ||
|
|
||
| class LVBinaryReader : public LVReader { | ||
| // Function names extracted from the object symbol table. | ||
| LVSymbolTable SymbolTable; | ||
|
|
||
| // Instruction lines for a logical scope. These instructions are fetched | ||
| // during its merge with the debug lines. | ||
| LVDoubleMap<LVSectionIndex, LVScope *, LVLines *> ScopeInstructions; | ||
|
|
||
| // Links the scope with its first assembler address line. | ||
| LVDoubleMap<LVSectionIndex, LVAddress, LVScope *> AssemblerMappings; | ||
|
|
||
| // Mapping from virtual address to section. | ||
| // The virtual address refers to the address where the section is loaded. | ||
| using LVSectionAddresses = std::map<LVSectionIndex, object::SectionRef>; | ||
| LVSectionAddresses SectionAddresses; | ||
|
|
||
| void addSectionAddress(const object::SectionRef &Section) { | ||
| if (SectionAddresses.find(Section.getAddress()) == SectionAddresses.end()) | ||
| SectionAddresses.emplace(Section.getAddress(), Section); | ||
| } | ||
|
|
||
| // Scopes with ranges for current compile unit. It is used to find a line | ||
| // giving its exact or closest address. To support comdat functions, all | ||
| // addresses for the same section are recorded in the same map. | ||
| using LVSectionRanges = std::map<LVSectionIndex, LVRange *>; | ||
| LVSectionRanges SectionRanges; | ||
|
|
||
| // Image base and virtual address for Executable file. | ||
| uint64_t ImageBaseAddress = 0; | ||
| uint64_t VirtualAddress = 0; | ||
|
|
||
| // Object sections with machine code. | ||
| using LVSections = std::map<LVSectionIndex, object::SectionRef>; | ||
| LVSections Sections; | ||
|
|
||
| protected: | ||
| // It contains the LVLineDebug elements representing the logical lines for | ||
| // the current compile unit, created by parsing the debug line section. | ||
| LVLines CULines; | ||
|
|
||
| std::unique_ptr<const MCRegisterInfo> MRI; | ||
| std::unique_ptr<const MCAsmInfo> MAI; | ||
| std::unique_ptr<const MCSubtargetInfo> STI; | ||
| std::unique_ptr<const MCInstrInfo> MII; | ||
| std::unique_ptr<const MCDisassembler> MD; | ||
| std::unique_ptr<MCContext> MC; | ||
| std::unique_ptr<MCInstPrinter> MIP; | ||
|
|
||
| // Loads all info for the architecture of the provided object file. | ||
| Error loadGenericTargetInfo(StringRef TheTriple, StringRef TheFeatures); | ||
|
|
||
| virtual void mapRangeAddress(const object::ObjectFile &Obj) {} | ||
| virtual void mapRangeAddress(const object::ObjectFile &Obj, | ||
| const object::SectionRef &Section, | ||
| bool IsComdat) {} | ||
|
|
||
| // Create a mapping from virtual address to section. | ||
| void mapVirtualAddress(const object::ObjectFile &Obj); | ||
| void mapVirtualAddress(const object::COFFObjectFile &COFFObj); | ||
|
|
||
| Expected<std::pair<LVSectionIndex, object::SectionRef>> | ||
| getSection(LVScope *Scope, LVAddress Address, LVSectionIndex SectionIndex); | ||
|
|
||
| void addSectionRange(LVSectionIndex SectionIndex, LVScope *Scope); | ||
| void addSectionRange(LVSectionIndex SectionIndex, LVScope *Scope, | ||
| LVAddress LowerAddress, LVAddress UpperAddress); | ||
| LVRange *getSectionRanges(LVSectionIndex SectionIndex); | ||
|
|
||
| Error createInstructions(); | ||
| Error createInstructions(LVScope *Function, LVSectionIndex SectionIndex); | ||
| Error createInstructions(LVScope *Function, LVSectionIndex SectionIndex, | ||
| const LVNameInfo &NameInfo); | ||
|
|
||
| void processLines(LVLines *DebugLines, LVSectionIndex SectionIndex); | ||
| void processLines(LVLines *DebugLines, LVSectionIndex SectionIndex, | ||
| LVScope *Function); | ||
|
|
||
| public: | ||
| LVBinaryReader() = delete; | ||
| LVBinaryReader(StringRef Filename, StringRef FileFormatName, ScopedPrinter &W, | ||
| LVBinaryType BinaryType) | ||
| : LVReader(Filename, FileFormatName, W, BinaryType) {} | ||
| LVBinaryReader(const LVBinaryReader &) = delete; | ||
| LVBinaryReader &operator=(const LVBinaryReader &) = delete; | ||
| virtual ~LVBinaryReader(); | ||
|
|
||
| void addToSymbolTable(StringRef Name, LVScope *Function, | ||
| LVSectionIndex SectionIndex = 0); | ||
| void addToSymbolTable(StringRef Name, LVAddress Address, | ||
| LVSectionIndex SectionIndex, bool IsComdat); | ||
| LVSectionIndex updateSymbolTable(LVScope *Function); | ||
|
|
||
| const LVSymbolTableEntry &getSymbolTableEntry(StringRef Name); | ||
| LVAddress getSymbolTableAddress(StringRef Name); | ||
| LVSectionIndex getSymbolTableIndex(StringRef Name); | ||
| bool getSymbolTableIsComdat(StringRef Name); | ||
|
|
||
| LVSectionIndex getSectionIndex(LVScope *Scope) override { | ||
| return Scope ? getSymbolTableIndex(Scope->getLinkageName()) | ||
| : DotTextSectionIndex; | ||
| } | ||
|
|
||
| void print(raw_ostream &OS) const; | ||
|
|
||
| #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) | ||
| void dump() const { print(dbgs()); } | ||
| #endif | ||
| }; | ||
|
|
||
| } // end namespace logicalview | ||
| } // end namespace llvm | ||
|
|
||
| #endif // LLVM_DEBUGINFO_LOGICALVIEW_READERS_LVBINARYREADER_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,154 @@ | ||
| //===-- LVELFReader.h -------------------------------------------*- C++ -*-===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This file defines the LVELFReader class, which is used to describe a | ||
| // debug information (DWARF) reader. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_DEBUGINFO_LOGICALVIEW_READERS_LVELFREADER_H | ||
| #define LLVM_DEBUGINFO_LOGICALVIEW_READERS_LVELFREADER_H | ||
|
|
||
| #include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" | ||
| #include "llvm/DebugInfo/DWARF/DWARFContext.h" | ||
| #include "llvm/DebugInfo/LogicalView/Readers/LVBinaryReader.h" | ||
| #include <unordered_set> | ||
|
|
||
| namespace llvm { | ||
| namespace logicalview { | ||
|
|
||
| class LVElement; | ||
| class LVLine; | ||
| class LVScopeCompileUnit; | ||
| class LVSymbol; | ||
| class LVType; | ||
|
|
||
| using AttributeSpec = DWARFAbbreviationDeclaration::AttributeSpec; | ||
|
|
||
| class LVELFReader final : public LVBinaryReader { | ||
| object::ObjectFile &Obj; | ||
|
|
||
| // Indicates if ranges data are available; in the case of split DWARF any | ||
| // reference to ranges is valid only if the skeleton DIE has been loaded. | ||
| bool RangesDataAvailable = false; | ||
| LVAddress CUBaseAddress = 0; | ||
| LVAddress CUHighAddress = 0; | ||
|
|
||
| // Current elements during the processing of a DIE. | ||
| LVElement *CurrentElement = nullptr; | ||
| LVScope *CurrentScope = nullptr; | ||
| LVSymbol *CurrentSymbol = nullptr; | ||
| LVType *CurrentType = nullptr; | ||
| LVOffset CurrentOffset = 0; | ||
| LVOffset CurrentEndOffset = 0; | ||
|
|
||
| // In DWARF v4, the files are 1-indexed. | ||
| // In DWARF v5, the files are 0-indexed. | ||
| // The ELF reader expects the indexes as 1-indexed. | ||
| bool IncrementFileIndex = false; | ||
|
|
||
| // Address ranges collected for current DIE. | ||
| std::vector<LVAddressRange> CurrentRanges; | ||
|
|
||
| // Symbols with locations for current compile unit. | ||
| LVSymbols SymbolsWithLocations; | ||
|
|
||
| // Global Offsets (Offset, Element). | ||
| LVOffsetElementMap GlobalOffsets; | ||
|
|
||
| // Low PC and High PC values for DIE being processed. | ||
| LVAddress CurrentLowPC = 0; | ||
| LVAddress CurrentHighPC = 0; | ||
| bool FoundLowPC = false; | ||
| bool FoundHighPC = false; | ||
|
|
||
| // Cross references (Elements). | ||
| using LVElementSet = std::unordered_set<LVElement *>; | ||
| using LVElementEntry = std::pair<LVElement *, LVElementSet>; | ||
| using LVElementReference = std::unordered_map<LVOffset, LVElementEntry>; | ||
| LVElementReference ElementTable; | ||
|
|
||
| Error loadTargetInfo(const object::ObjectFile &Obj); | ||
|
|
||
| void mapRangeAddress(const object::ObjectFile &Obj) override; | ||
|
|
||
| LVElement *createElement(dwarf::Tag Tag); | ||
| void traverseDieAndChildren(DWARFDie &DIE, LVScope *Parent, | ||
| DWARFDie &SkeletonDie); | ||
| // Process the attributes for the given DIE. | ||
| LVScope *processOneDie(const DWARFDie &InputDIE, LVScope *Parent, | ||
| DWARFDie &SkeletonDie); | ||
| void processOneAttribute(const DWARFDie &Die, LVOffset *OffsetPtr, | ||
| const AttributeSpec &AttrSpec); | ||
| void createLineAndFileRecords(const DWARFDebugLine::LineTable *Lines); | ||
| void processLocationGaps(); | ||
|
|
||
| // Add offset to global map. | ||
| void addGlobalOffset(LVOffset Offset) { | ||
| if (GlobalOffsets.find(Offset) == GlobalOffsets.end()) | ||
| // Just associate the DIE offset with a null element, as we do not | ||
| // know if the referenced element has been created. | ||
| GlobalOffsets.emplace(Offset, nullptr); | ||
| } | ||
|
|
||
| // Remove offset from global map. | ||
| void removeGlobalOffset(LVOffset Offset) { | ||
| LVOffsetElementMap::iterator Iter = GlobalOffsets.find(Offset); | ||
| if (Iter != GlobalOffsets.end()) | ||
| GlobalOffsets.erase(Iter); | ||
| } | ||
|
|
||
| // Get the location information for DW_AT_data_member_location. | ||
| void processLocationMember(dwarf::Attribute Attr, | ||
| const DWARFFormValue &FormValue, | ||
| const DWARFDie &Die, uint64_t OffsetOnEntry); | ||
| void processLocationList(dwarf::Attribute Attr, | ||
| const DWARFFormValue &FormValue, const DWARFDie &Die, | ||
| uint64_t OffsetOnEntry, | ||
| bool CallSiteLocation = false); | ||
| void updateReference(dwarf::Attribute Attr, const DWARFFormValue &FormValue); | ||
|
|
||
| // Get an element given the DIE offset. | ||
| LVElement *getElementForOffset(LVOffset offset, LVElement *Element); | ||
|
|
||
| protected: | ||
| Error createScopes() override; | ||
| void sortScopes() override; | ||
|
|
||
| public: | ||
| LVELFReader() = delete; | ||
| LVELFReader(StringRef Filename, StringRef FileFormatName, | ||
| object::ObjectFile &Obj, ScopedPrinter &W) | ||
| : LVBinaryReader(Filename, FileFormatName, W, LVBinaryType::ELF), | ||
| Obj(Obj) {} | ||
| LVELFReader(const LVELFReader &) = delete; | ||
| LVELFReader &operator=(const LVELFReader &) = delete; | ||
| ~LVELFReader() = default; | ||
|
|
||
| LVAddress getCUBaseAddress() const { return CUBaseAddress; } | ||
| void setCUBaseAddress(LVAddress Address) { CUBaseAddress = Address; } | ||
| LVAddress getCUHighAddress() const { return CUHighAddress; } | ||
| void setCUHighAddress(LVAddress Address) { CUHighAddress = Address; } | ||
|
|
||
| const LVSymbols &GetSymbolsWithLocations() const { | ||
| return SymbolsWithLocations; | ||
| } | ||
|
|
||
| std::string getRegisterName(LVSmall Opcode, uint64_t Operands[2]) override; | ||
|
|
||
| void print(raw_ostream &OS) const; | ||
|
|
||
| #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) | ||
| void dump() const { print(dbgs()); } | ||
| #endif | ||
| }; | ||
|
|
||
| } // end namespace logicalview | ||
| } // end namespace llvm | ||
|
|
||
| #endif // LLVM_DEBUGINFO_LOGICALVIEW_READERS_LVELFREADER_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,194 @@ | ||
| //===-- LVReaderHandler.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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This class implements the Reader Handler. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "llvm/DebugInfo/LogicalView/LVReaderHandler.h" | ||
| #include "llvm/DebugInfo/LogicalView/Core/LVCompare.h" | ||
| #include "llvm/DebugInfo/LogicalView/Readers/LVELFReader.h" | ||
|
|
||
| using namespace llvm; | ||
| using namespace llvm::object; | ||
| using namespace llvm::pdb; | ||
| using namespace llvm::logicalview; | ||
|
|
||
| #define DEBUG_TYPE "ReaderHandler" | ||
|
|
||
| Error LVReaderHandler::process() { | ||
| if (Error Err = createReaders()) | ||
| return Err; | ||
| if (Error Err = printReaders()) | ||
| return Err; | ||
| if (Error Err = compareReaders()) | ||
| return Err; | ||
|
|
||
| return Error::success(); | ||
| } | ||
|
|
||
| void LVReaderHandler::destroyReaders() { | ||
| LLVM_DEBUG(dbgs() << "destroyReaders\n"); | ||
| for (const LVReader *Reader : TheReaders) | ||
| delete Reader; | ||
| } | ||
|
|
||
| Error LVReaderHandler::createReader(StringRef Filename, LVReaders &Readers, | ||
| PdbOrObj &Input, StringRef FileFormatName, | ||
| StringRef ExePath) { | ||
| auto CreateOneReader = [&]() -> LVReader * { | ||
| if (Input.is<ObjectFile *>()) { | ||
| ObjectFile &Obj = *Input.get<ObjectFile *>(); | ||
| if (Obj.isELF() || Obj.isMachO()) | ||
| return new LVELFReader(Filename, FileFormatName, Obj, W); | ||
| } | ||
| return nullptr; | ||
| }; | ||
|
|
||
| LVReader *Reader = CreateOneReader(); | ||
| if (!Reader) | ||
| return createStringError(errc::invalid_argument, | ||
| "unable to create reader for: '%s'", | ||
| Filename.str().c_str()); | ||
|
|
||
| Readers.push_back(Reader); | ||
| return Reader->doLoad(); | ||
| } | ||
|
|
||
| Error LVReaderHandler::handleArchive(LVReaders &Readers, StringRef Filename, | ||
| Archive &Arch) { | ||
| Error Err = Error::success(); | ||
| for (const Archive::Child &Child : Arch.children(Err)) { | ||
| Expected<MemoryBufferRef> BuffOrErr = Child.getMemoryBufferRef(); | ||
| if (Error Err = BuffOrErr.takeError()) | ||
| return createStringError(errorToErrorCode(std::move(Err)), "%s", | ||
| Filename.str().c_str()); | ||
| Expected<StringRef> NameOrErr = Child.getName(); | ||
| if (Error Err = NameOrErr.takeError()) | ||
| return createStringError(errorToErrorCode(std::move(Err)), "%s", | ||
| Filename.str().c_str()); | ||
| std::string Name = (Filename + "(" + NameOrErr.get() + ")").str(); | ||
| if (Error Err = handleBuffer(Readers, Name, BuffOrErr.get())) | ||
| return createStringError(errorToErrorCode(std::move(Err)), "%s", | ||
| Filename.str().c_str()); | ||
| } | ||
|
|
||
| return Error::success(); | ||
| } | ||
|
|
||
| Error LVReaderHandler::handleBuffer(LVReaders &Readers, StringRef Filename, | ||
| MemoryBufferRef Buffer, StringRef ExePath) { | ||
| Expected<std::unique_ptr<Binary>> BinOrErr = createBinary(Buffer); | ||
| if (errorToErrorCode(BinOrErr.takeError())) { | ||
| return createStringError(errc::not_supported, | ||
| "Binary object format in '%s' is not supported.", | ||
| Filename.str().c_str()); | ||
| } | ||
| return handleObject(Readers, Filename, *BinOrErr.get()); | ||
| } | ||
|
|
||
| Error LVReaderHandler::handleFile(LVReaders &Readers, StringRef Filename, | ||
| StringRef ExePath) { | ||
| // Convert any Windows backslashes into forward slashes to get the path. | ||
| std::string ConvertedPath = | ||
| sys::path::convert_to_slash(Filename, sys::path::Style::windows); | ||
| ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr = | ||
| MemoryBuffer::getFileOrSTDIN(ConvertedPath); | ||
| if (BuffOrErr.getError()) { | ||
| return createStringError(errc::bad_file_descriptor, | ||
| "File '%s' does not exist.", | ||
| ConvertedPath.c_str()); | ||
| } | ||
| std::unique_ptr<MemoryBuffer> Buffer = std::move(BuffOrErr.get()); | ||
| return handleBuffer(Readers, ConvertedPath, *Buffer, ExePath); | ||
| } | ||
|
|
||
| Error LVReaderHandler::handleMach(LVReaders &Readers, StringRef Filename, | ||
| MachOUniversalBinary &Mach) { | ||
| for (const MachOUniversalBinary::ObjectForArch &ObjForArch : Mach.objects()) { | ||
| std::string ObjName = (Twine(Filename) + Twine("(") + | ||
| Twine(ObjForArch.getArchFlagName()) + Twine(")")) | ||
| .str(); | ||
| if (Expected<std::unique_ptr<MachOObjectFile>> MachOOrErr = | ||
| ObjForArch.getAsObjectFile()) { | ||
| MachOObjectFile &Obj = **MachOOrErr; | ||
| PdbOrObj Input = &Obj; | ||
| if (Error Err = | ||
| createReader(Filename, Readers, Input, Obj.getFileFormatName())) | ||
| return Err; | ||
| continue; | ||
| } else | ||
| consumeError(MachOOrErr.takeError()); | ||
| if (Expected<std::unique_ptr<Archive>> ArchiveOrErr = | ||
| ObjForArch.getAsArchive()) { | ||
| if (Error Err = handleArchive(Readers, ObjName, *ArchiveOrErr.get())) | ||
| return Err; | ||
| continue; | ||
| } else | ||
| consumeError(ArchiveOrErr.takeError()); | ||
| } | ||
| return Error::success(); | ||
| } | ||
|
|
||
| Error LVReaderHandler::handleObject(LVReaders &Readers, StringRef Filename, | ||
| Binary &Binary) { | ||
| if (PdbOrObj Input = dyn_cast<ObjectFile>(&Binary)) | ||
| return createReader(Filename, Readers, Input, | ||
| Input.get<ObjectFile *>()->getFileFormatName()); | ||
|
|
||
| if (MachOUniversalBinary *Fat = dyn_cast<MachOUniversalBinary>(&Binary)) | ||
| return handleMach(Readers, Filename, *Fat); | ||
|
|
||
| if (Archive *Arch = dyn_cast<Archive>(&Binary)) | ||
| return handleArchive(Readers, Filename, *Arch); | ||
|
|
||
| return createStringError(errc::not_supported, | ||
| "Binary object format in '%s' is not supported.", | ||
| Filename.str().c_str()); | ||
| } | ||
|
|
||
| Error LVReaderHandler::createReaders() { | ||
| LLVM_DEBUG(dbgs() << "createReaders\n"); | ||
| for (std::string &Object : Objects) { | ||
| LVReaders Readers; | ||
| if (Error Err = createReader(Object, Readers)) | ||
| return Err; | ||
| TheReaders.insert(TheReaders.end(), Readers.begin(), Readers.end()); | ||
| } | ||
|
|
||
| return Error::success(); | ||
| } | ||
|
|
||
| Error LVReaderHandler::printReaders() { | ||
| LLVM_DEBUG(dbgs() << "printReaders\n"); | ||
| if (options().getPrintExecute()) | ||
| for (LVReader *Reader : TheReaders) | ||
| if (Error Err = Reader->doPrint()) | ||
| return Err; | ||
|
|
||
| return Error::success(); | ||
| } | ||
|
|
||
| Error LVReaderHandler::compareReaders() { | ||
| LLVM_DEBUG(dbgs() << "compareReaders\n"); | ||
| size_t ReadersCount = TheReaders.size(); | ||
| if (options().getCompareExecute() && ReadersCount >= 2) { | ||
| // If we have more than 2 readers, compare them by pairs. | ||
| size_t ViewPairs = ReadersCount / 2; | ||
| LVCompare Compare(OS); | ||
| for (size_t Pair = 0, Index = 0; Pair < ViewPairs; ++Pair) { | ||
| if (Error Err = Compare.execute(TheReaders[Index], TheReaders[Index + 1])) | ||
| return Err; | ||
| Index += 2; | ||
| } | ||
| } | ||
|
|
||
| return Error::success(); | ||
| } | ||
|
|
||
| void LVReaderHandler::print(raw_ostream &OS) const { OS << "ReaderHandler\n"; } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,101 @@ | ||
| ; Test case 1 - General options | ||
|
|
||
| ; test.cpp | ||
| ; 1 using INTPTR = const int *; | ||
| ; 2 int foo(INTPTR ParamPtr, unsigned ParamUnsigned, bool ParamBool) { | ||
| ; 3 if (ParamBool) { | ||
| ; 4 typedef int INTEGER; | ||
| ; 5 const INTEGER CONSTANT = 7; | ||
| ; 6 return CONSTANT; | ||
| ; 7 } | ||
| ; 8 return ParamUnsigned; | ||
| ; 9 } | ||
|
|
||
| ; Compare mode - Logical view. | ||
| ; The output shows in view form the 'missing (-), added (+)' elements, | ||
| ; giving more context by swapping the reference and target object files. | ||
|
|
||
| ; RUN: llvm-debuginfo-analyzer --attribute=level \ | ||
| ; RUN: --compare=types \ | ||
| ; RUN: --report=view \ | ||
| ; RUN: --print=symbols,types \ | ||
| ; RUN: %p/Inputs/test-dwarf-clang.o \ | ||
| ; RUN: %p/Inputs/test-dwarf-gcc.o 2>&1 | \ | ||
| ; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s | ||
|
|
||
| ; ONE: Reference: 'test-dwarf-clang.o' | ||
| ; ONE-NEXT: Target: 'test-dwarf-gcc.o' | ||
| ; ONE-EMPTY: | ||
| ; ONE-NEXT: Logical View: | ||
| ; ONE-NEXT: [000] {File} 'test-dwarf-clang.o' | ||
| ; ONE-EMPTY: | ||
| ; ONE-NEXT: [001] {CompileUnit} 'test.cpp' | ||
| ; ONE-NEXT: [002] 1 {TypeAlias} 'INTPTR' -> '* const int' | ||
| ; ONE-NEXT: [002] 2 {Function} extern not_inlined 'foo' -> 'int' | ||
| ; ONE-NEXT: [003] {Block} | ||
| ; ONE-NEXT: [004] 5 {Variable} 'CONSTANT' -> 'const INTEGER' | ||
| ; ONE-NEXT: +[004] 4 {TypeAlias} 'INTEGER' -> 'int' | ||
| ; ONE-NEXT: [003] 2 {Parameter} 'ParamBool' -> 'bool' | ||
| ; ONE-NEXT: [003] 2 {Parameter} 'ParamPtr' -> 'INTPTR' | ||
| ; ONE-NEXT: [003] 2 {Parameter} 'ParamUnsigned' -> 'unsigned int' | ||
| ; ONE-NEXT: -[003] 4 {TypeAlias} 'INTEGER' -> 'int' | ||
|
|
||
| ; Compare mode - Logical elements. | ||
| ; The output shows in tabular form the 'missing (-), added (+)' elements, | ||
| ; giving more context by swapping the reference and target object files. | ||
|
|
||
| ; RUN: llvm-debuginfo-analyzer --attribute=level \ | ||
| ; RUN: --compare=types \ | ||
| ; RUN: --report=list \ | ||
| ; RUN: --print=symbols,types,summary \ | ||
| ; RUN: %p/Inputs/test-dwarf-clang.o \ | ||
| ; RUN: %p/Inputs/test-dwarf-gcc.o 2>&1 | \ | ||
| ; RUN: FileCheck --strict-whitespace -check-prefix=TWO %s | ||
|
|
||
| ; TWO: Reference: 'test-dwarf-clang.o' | ||
| ; TWO-NEXT: Target: 'test-dwarf-gcc.o' | ||
| ; TWO-EMPTY: | ||
| ; TWO-NEXT: (1) Missing Types: | ||
| ; TWO-NEXT: -[003] 4 {TypeAlias} 'INTEGER' -> 'int' | ||
| ; TWO-EMPTY: | ||
| ; TWO-NEXT: (1) Added Types: | ||
| ; TWO-NEXT: +[004] 4 {TypeAlias} 'INTEGER' -> 'int' | ||
| ; TWO-EMPTY: | ||
| ; TWO-NEXT: ---------------------------------------- | ||
| ; TWO-NEXT: Element Expected Missing Added | ||
| ; TWO-NEXT: ---------------------------------------- | ||
| ; TWO-NEXT: Scopes 4 0 0 | ||
| ; TWO-NEXT: Symbols 0 0 0 | ||
| ; TWO-NEXT: Types 2 1 1 | ||
| ; TWO-NEXT: Lines 0 0 0 | ||
| ; TWO-NEXT: ---------------------------------------- | ||
| ; TWO-NEXT: Total 6 1 1 | ||
|
|
||
| ; Changing the 'Reference' and 'Target' order: | ||
|
|
||
| ; RUN: llvm-debuginfo-analyzer --attribute=level \ | ||
| ; RUN: --compare=types \ | ||
| ; RUN: --report=list \ | ||
| ; RUN: --print=symbols,types,summary \ | ||
| ; RUN: %p/Inputs/test-dwarf-gcc.o \ | ||
| ; RUN: %p/Inputs/test-dwarf-clang.o 2>&1 | \ | ||
| ; RUN: FileCheck --strict-whitespace -check-prefix=THR %s | ||
|
|
||
| ; THR: Reference: 'test-dwarf-gcc.o' | ||
| ; THR-NEXT: Target: 'test-dwarf-clang.o' | ||
| ; THR-EMPTY: | ||
| ; THR-NEXT: (1) Missing Types: | ||
| ; THR-NEXT: -[004] 4 {TypeAlias} 'INTEGER' -> 'int' | ||
| ; THR-EMPTY: | ||
| ; THR-NEXT: (1) Added Types: | ||
| ; THR-NEXT: +[003] 4 {TypeAlias} 'INTEGER' -> 'int' | ||
| ; THR-EMPTY: | ||
| ; THR-NEXT: ---------------------------------------- | ||
| ; THR-NEXT: Element Expected Missing Added | ||
| ; THR-NEXT: ---------------------------------------- | ||
| ; THR-NEXT: Scopes 4 0 0 | ||
| ; THR-NEXT: Symbols 0 0 0 | ||
| ; THR-NEXT: Types 2 1 1 | ||
| ; THR-NEXT: Lines 0 0 0 | ||
| ; THR-NEXT: ---------------------------------------- | ||
| ; THR-NEXT: Total 6 1 1 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| ; Test case 1 - General options. | ||
|
|
||
| ; test.cpp | ||
| ; 1 using INTPTR = const int *; | ||
| ; 2 int foo(INTPTR ParamPtr, unsigned ParamUnsigned, bool ParamBool) { | ||
| ; 3 if (ParamBool) { | ||
| ; 4 typedef int INTEGER; | ||
| ; 5 const INTEGER CONSTANT = 7; | ||
| ; 6 return CONSTANT; | ||
| ; 7 } | ||
| ; 8 return ParamUnsigned; | ||
| ; 9 } | ||
|
|
||
| ; Print basic details. | ||
| ; The following command prints basic details for all the logical elements | ||
| ; sorted by the debug information internal offset; it includes its lexical | ||
| ; level and debug info format. | ||
|
|
||
| ; RUN: llvm-debuginfo-analyzer --attribute=level,format \ | ||
| ; RUN: --output-sort=offset \ | ||
| ; RUN: --print=scopes,symbols,types,lines,instructions \ | ||
| ; RUN: %p/Inputs/test-dwarf-clang.o 2>&1 | \ | ||
| ; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s | ||
|
|
||
| ; RUN: llvm-debuginfo-analyzer --attribute=level,format \ | ||
| ; RUN: --output-sort=offset \ | ||
| ; RUN: --print=elements \ | ||
| ; RUN: %p/Inputs/test-dwarf-clang.o 2>&1 | \ | ||
| ; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s | ||
|
|
||
| ; ONE: Logical View: | ||
| ; ONE-NEXT: [000] {File} 'test-dwarf-clang.o' -> elf64-x86-64 | ||
| ; ONE-EMPTY: | ||
| ; ONE-NEXT: [001] {CompileUnit} 'test.cpp' | ||
| ; ONE-NEXT: [002] 2 {Function} extern not_inlined 'foo' -> 'int' | ||
| ; ONE-NEXT: [003] 2 {Parameter} 'ParamPtr' -> 'INTPTR' | ||
| ; ONE-NEXT: [003] 2 {Parameter} 'ParamUnsigned' -> 'unsigned int' | ||
| ; ONE-NEXT: [003] 2 {Parameter} 'ParamBool' -> 'bool' | ||
| ; ONE-NEXT: [003] {Block} | ||
| ; ONE-NEXT: [004] 5 {Variable} 'CONSTANT' -> 'const INTEGER' | ||
| ; ONE-NEXT: [004] 5 {Line} | ||
| ; ONE-NEXT: [004] {Code} 'movl $0x7, -0x1c(%rbp)' | ||
| ; ONE-NEXT: [004] 6 {Line} | ||
| ; ONE-NEXT: [004] {Code} 'movl $0x7, -0x4(%rbp)' | ||
| ; ONE-NEXT: [004] {Code} 'jmp 0x6' | ||
| ; ONE-NEXT: [004] 8 {Line} | ||
| ; ONE-NEXT: [004] {Code} 'movl -0x14(%rbp), %eax' | ||
| ; ONE-NEXT: [003] 4 {TypeAlias} 'INTEGER' -> 'int' | ||
| ; ONE-NEXT: [003] 2 {Line} | ||
| ; ONE-NEXT: [003] {Code} 'pushq %rbp' | ||
| ; ONE-NEXT: [003] {Code} 'movq %rsp, %rbp' | ||
| ; ONE-NEXT: [003] {Code} 'movb %dl, %al' | ||
| ; ONE-NEXT: [003] {Code} 'movq %rdi, -0x10(%rbp)' | ||
| ; ONE-NEXT: [003] {Code} 'movl %esi, -0x14(%rbp)' | ||
| ; ONE-NEXT: [003] {Code} 'andb $0x1, %al' | ||
| ; ONE-NEXT: [003] {Code} 'movb %al, -0x15(%rbp)' | ||
| ; ONE-NEXT: [003] 3 {Line} | ||
| ; ONE-NEXT: [003] {Code} 'testb $0x1, -0x15(%rbp)' | ||
| ; ONE-NEXT: [003] {Code} 'je 0x13' | ||
| ; ONE-NEXT: [003] 8 {Line} | ||
| ; ONE-NEXT: [003] {Code} 'movl %eax, -0x4(%rbp)' | ||
| ; ONE-NEXT: [003] 9 {Line} | ||
| ; ONE-NEXT: [003] {Code} 'movl -0x4(%rbp), %eax' | ||
| ; ONE-NEXT: [003] {Code} 'popq %rbp' | ||
| ; ONE-NEXT: [003] {Code} 'retq' | ||
| ; ONE-NEXT: [003] 9 {Line} | ||
| ; ONE-NEXT: [002] 1 {TypeAlias} 'INTPTR' -> '* const int' |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| ; Test case 1 - General options | ||
|
|
||
| ; test.cpp | ||
| ; 1 using INTPTR = const int *; | ||
| ; 2 int foo(INTPTR ParamPtr, unsigned ParamUnsigned, bool ParamBool) { | ||
| ; 3 if (ParamBool) { | ||
| ; 4 typedef int INTEGER; | ||
| ; 5 const INTEGER CONSTANT = 7; | ||
| ; 6 return CONSTANT; | ||
| ; 7 } | ||
| ; 8 return ParamUnsigned; | ||
| ; 9 } | ||
|
|
||
| ; Select logical elements. | ||
| ; The following prints all 'instructions', 'symbols' and 'types' that | ||
| ; contain 'inte' or 'movl' in their names or types, using a tab layout | ||
| ; and given the number of matches. | ||
|
|
||
| ; RUN: llvm-debuginfo-analyzer --attribute=level \ | ||
| ; RUN: --select-nocase --select-regex \ | ||
| ; RUN: --select=INTe --select=movl \ | ||
| ; RUN: --report=list \ | ||
| ; RUN: --print=symbols,types,instructions,summary \ | ||
| ; RUN: %p/Inputs/test-dwarf-clang.o 2>&1 | \ | ||
| ; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s | ||
|
|
||
| ; ONE: Logical View: | ||
| ; ONE-NEXT: [000] {File} 'test-dwarf-clang.o' | ||
| ; ONE-EMPTY: | ||
| ; ONE-NEXT: [001] {CompileUnit} 'test.cpp' | ||
| ; ONE-NEXT: [004] {Code} 'movl $0x7, -0x1c(%rbp)' | ||
| ; ONE-NEXT: [004] {Code} 'movl $0x7, -0x4(%rbp)' | ||
| ; ONE-NEXT: [003] {Code} 'movl %eax, -0x4(%rbp)' | ||
| ; ONE-NEXT: [003] {Code} 'movl %esi, -0x14(%rbp)' | ||
| ; ONE-NEXT: [004] {Code} 'movl -0x14(%rbp), %eax' | ||
| ; ONE-NEXT: [003] {Code} 'movl -0x4(%rbp), %eax' | ||
| ; ONE-NEXT: [003] 4 {TypeAlias} 'INTEGER' -> 'int' | ||
| ; ONE-NEXT: [004] 5 {Variable} 'CONSTANT' -> 'const INTEGER' | ||
| ; ONE-EMPTY: | ||
| ; ONE-NEXT: ----------------------------- | ||
| ; ONE-NEXT: Element Total Printed | ||
| ; ONE-NEXT: ----------------------------- | ||
| ; ONE-NEXT: Scopes 3 0 | ||
| ; ONE-NEXT: Symbols 4 1 | ||
| ; ONE-NEXT: Types 2 1 | ||
| ; ONE-NEXT: Lines 17 6 | ||
| ; ONE-NEXT: ----------------------------- | ||
| ; ONE-NEXT: Total 26 8 | ||
|
|
||
| ; RUN: llvm-debuginfo-analyzer --attribute=level \ | ||
| ; RUN: --select-regex --select-nocase \ | ||
| ; RUN: --select=INTe \ | ||
| ; RUN: --report=list \ | ||
| ; RUN: --print=symbols,types \ | ||
| ; RUN: %p/Inputs/test-dwarf-clang.o \ | ||
| ; RUN: %p/Inputs/test-dwarf-gcc.o 2>&1 | \ | ||
| ; RUN: FileCheck --strict-whitespace -check-prefix=TWO %s | ||
|
|
||
| ; TWO: Logical View: | ||
| ; TWO-NEXT: [000] {File} 'test-dwarf-clang.o' | ||
| ; TWO-EMPTY: | ||
| ; TWO-NEXT: [001] {CompileUnit} 'test.cpp' | ||
| ; TWO-NEXT: [003] 4 {TypeAlias} 'INTEGER' -> 'int' | ||
| ; TWO-NEXT: [004] 5 {Variable} 'CONSTANT' -> 'const INTEGER' | ||
| ; TWO-EMPTY: | ||
| ; TWO-NEXT: Logical View: | ||
| ; TWO-NEXT: [000] {File} 'test-dwarf-gcc.o' | ||
| ; TWO-EMPTY: | ||
| ; TWO-NEXT: [001] {CompileUnit} 'test.cpp' | ||
| ; TWO-NEXT: [004] 4 {TypeAlias} 'INTEGER' -> 'int' | ||
| ; TWO-NEXT: [004] 5 {Variable} 'CONSTANT' -> 'const INTEGER' |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| ; Test case 2 - Assembler instructions. | ||
|
|
||
| ; hello-world.cpp | ||
| ; 1 extern int printf(const char * format, ... ); | ||
| ; 2 | ||
| ; 3 int main() | ||
| ; 4 { | ||
| ; 5 printf("Hello, World\n"); | ||
| ; 6 return 0; | ||
| ; 7 } | ||
|
|
||
| ; Logical lines. | ||
| ; The logical views shows the intermixed lines and assembler instructions, | ||
| ; allowing to compare the code generated by the different toolchains. | ||
|
|
||
| ; RUN: llvm-debuginfo-analyzer --attribute=level,format,producer \ | ||
| ; RUN: --print=lines,instructions \ | ||
| ; RUN: %p/Inputs/hello-world-dwarf-clang.o \ | ||
| ; RUN: %p/Inputs/hello-world-dwarf-gcc.o 2>&1 | \ | ||
| ; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s | ||
|
|
||
| ; ONE: Logical View: | ||
| ; ONE-NEXT: [000] {File} 'hello-world-dwarf-clang.o' -> elf64-x86-64 | ||
| ; ONE-EMPTY: | ||
| ; ONE-NEXT: [001] {CompileUnit} 'hello-world.cpp' | ||
| ; ONE-NEXT: [002] {Producer} 'clang version 15.0.0 {{.*}}' | ||
| ; ONE-NEXT: [002] 3 {Function} extern not_inlined 'main' -> 'int' | ||
| ; ONE-NEXT: [003] 4 {Line} | ||
| ; ONE-NEXT: [003] {Code} 'pushq %rbp' | ||
| ; ONE-NEXT: [003] {Code} 'movq %rsp, %rbp' | ||
| ; ONE-NEXT: [003] {Code} 'subq $0x10, %rsp' | ||
| ; ONE-NEXT: [003] {Code} 'movl $0x0, -0x4(%rbp)' | ||
| ; ONE-NEXT: [003] 5 {Line} | ||
| ; ONE-NEXT: [003] {Code} 'leaq (%rip), %rdi' | ||
| ; ONE-NEXT: [003] {Code} 'movb $0x0, %al' | ||
| ; ONE-NEXT: [003] {Code} 'callq 0x0' | ||
| ; ONE-NEXT: [003] 6 {Line} | ||
| ; ONE-NEXT: [003] {Code} 'xorl %eax, %eax' | ||
| ; ONE-NEXT: [003] {Code} 'addq $0x10, %rsp' | ||
| ; ONE-NEXT: [003] {Code} 'popq %rbp' | ||
| ; ONE-NEXT: [003] {Code} 'retq' | ||
| ; ONE-NEXT: [003] 6 {Line} | ||
| ; ONE-EMPTY: | ||
| ; ONE-NEXT: Logical View: | ||
| ; ONE-NEXT: [000] {File} 'hello-world-dwarf-gcc.o' -> elf64-x86-64 | ||
| ; ONE-EMPTY: | ||
| ; ONE-NEXT: [001] {CompileUnit} 'hello-world.cpp' | ||
| ; ONE-NEXT: [002] {Producer} 'GNU C++14 10.3.0 {{.*}}' | ||
| ; ONE-NEXT: [002] 3 {Function} extern not_inlined 'main' -> 'int' | ||
| ; ONE-NEXT: [003] 4 {Line} | ||
| ; ONE-NEXT: [003] {Code} 'endbr64' | ||
| ; ONE-NEXT: [003] {Code} 'pushq %rbp' | ||
| ; ONE-NEXT: [003] {Code} 'movq %rsp, %rbp' | ||
| ; ONE-NEXT: [003] 5 {Line} | ||
| ; ONE-NEXT: [003] {Code} 'leaq (%rip), %rdi' | ||
| ; ONE-NEXT: [003] {Code} 'movl $0x0, %eax' | ||
| ; ONE-NEXT: [003] {Code} 'callq 0x0' | ||
| ; ONE-NEXT: [003] 6 {Line} | ||
| ; ONE-NEXT: [003] {Code} 'movl $0x0, %eax' | ||
| ; ONE-NEXT: [003] 7 {Line} | ||
| ; ONE-NEXT: [003] {Code} 'popq %rbp' | ||
| ; ONE-NEXT: [003] {Code} 'retq' | ||
| ; ONE-NEXT: [003] 7 {Line} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,124 @@ | ||
| ; Test case 3 - Incorrect lexical scope for typedef. | ||
|
|
||
| ; pr-44884.cpp | ||
| ; 1 int bar(float Input) { return (int)Input; } | ||
| ; 2 | ||
| ; 3 unsigned foo(char Param) { | ||
| ; 4 typedef int INT; // ** Definition for INT ** | ||
| ; 5 INT Value = Param; | ||
| ; 6 { | ||
| ; 7 typedef float FLOAT; // ** Definition for FLOAT ** | ||
| ; 8 { | ||
| ; 9 FLOAT Added = Value + Param; | ||
| ; 10 Value = bar(Added); | ||
| ; 11 } | ||
| ; 12 } | ||
| ; 13 return Value + Param; | ||
| ; 14 } | ||
|
|
||
| ; The lines 4 and 7 contains 2 typedefs, defined at different lexical | ||
| ; scopes. | ||
|
|
||
| ; The above test is used to illustrates a scope issue found in the | ||
| ; Clang compiler. | ||
| ; PR44884: https://bugs.llvm.org/show_bug.cgi?id=44884 | ||
| ; PR44229: https://github.com/llvm/llvm-project/issues/44229 | ||
|
|
||
| ; In the following logical views, we can see that the Clang compiler | ||
| ; emits both typedefs at the same lexical scope (3), which is wrong. | ||
| ; GCC emit correct lexical scope for both typedefs. | ||
|
|
||
| ; RUN: llvm-debuginfo-analyzer --attribute=level,format,producer \ | ||
| ; RUN: --output-sort=kind \ | ||
| ; RUN: --print=symbols,types,lines \ | ||
| ; RUN: %p/Inputs/pr-44884-dwarf-clang.o \ | ||
| ; RUN: %p/Inputs/pr-44884-dwarf-gcc.o 2>&1 | \ | ||
| ; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s | ||
|
|
||
| ; ONE: Logical View: | ||
| ; ONE-NEXT: [000] {File} 'pr-44884-dwarf-clang.o' -> elf64-x86-64 | ||
| ; ONE-EMPTY: | ||
| ; ONE-NEXT: [001] {CompileUnit} 'pr-44884.cpp' | ||
| ; ONE-NEXT: [002] {Producer} 'clang version 15.0.0 {{.*}}' | ||
| ; ONE-NEXT: [002] 1 {Function} extern not_inlined 'bar' -> 'int' | ||
| ; ONE-NEXT: [003] 1 {Parameter} 'Input' -> 'float' | ||
| ; ONE-NEXT: [003] 1 {Line} | ||
| ; ONE-NEXT: [003] 1 {Line} | ||
| ; ONE-NEXT: [003] 1 {Line} | ||
| ; ONE-NEXT: [002] 3 {Function} extern not_inlined 'foo' -> 'unsigned int' | ||
| ; ONE-NEXT: [003] {Block} | ||
| ; ONE-NEXT: [004] 9 {Variable} 'Added' -> 'FLOAT' | ||
| ; ONE-NEXT: [004] 9 {Line} | ||
| ; ONE-NEXT: [004] 9 {Line} | ||
| ; ONE-NEXT: [004] 9 {Line} | ||
| ; ONE-NEXT: [004] 9 {Line} | ||
| ; ONE-NEXT: [004] 9 {Line} | ||
| ; ONE-NEXT: [004] 10 {Line} | ||
| ; ONE-NEXT: [004] 10 {Line} | ||
| ; ONE-NEXT: [004] 10 {Line} | ||
| ; ONE-NEXT: [004] 13 {Line} | ||
| ; ONE-NEXT: [003] 3 {Parameter} 'Param' -> 'char' | ||
| ; ONE-NEXT: [003] 7 {TypeAlias} 'FLOAT' -> 'float' | ||
| ; ONE-NEXT: [003] 4 {TypeAlias} 'INT' -> 'int' | ||
| ; ONE-NEXT: [003] 5 {Variable} 'Value' -> 'INT' | ||
| ; ONE-NEXT: [003] 3 {Line} | ||
| ; ONE-NEXT: [003] 5 {Line} | ||
| ; ONE-NEXT: [003] 5 {Line} | ||
| ; ONE-NEXT: [003] 13 {Line} | ||
| ; ONE-NEXT: [003] 13 {Line} | ||
| ; ONE-NEXT: [003] 13 {Line} | ||
| ; ONE-NEXT: [003] 13 {Line} | ||
| ; ONE-EMPTY: | ||
| ; ONE-NEXT: Logical View: | ||
| ; ONE-NEXT: [000] {File} 'pr-44884-dwarf-gcc.o' -> elf64-x86-64 | ||
| ; ONE-EMPTY: | ||
| ; ONE-NEXT: [001] {CompileUnit} 'pr-44884.cpp' | ||
| ; ONE-NEXT: [002] {Producer} 'GNU C++14 10.3.0 {{.*}}' | ||
| ; ONE-NEXT: [002] 1 {Function} extern not_inlined 'bar' -> 'int' | ||
| ; ONE-NEXT: [003] 1 {Parameter} 'Input' -> 'float' | ||
| ; ONE-NEXT: [003] 1 {Line} | ||
| ; ONE-NEXT: [003] 1 {Line} | ||
| ; ONE-NEXT: [003] 1 {Line} | ||
| ; ONE-NEXT: [002] 3 {Function} extern not_inlined 'foo' -> 'unsigned int' | ||
| ; ONE-NEXT: [003] {Block} | ||
| ; ONE-NEXT: [004] {Block} | ||
| ; ONE-NEXT: [005] 9 {Variable} 'Added' -> 'FLOAT' | ||
| ; ONE-NEXT: [005] 9 {Line} | ||
| ; ONE-NEXT: [005] 9 {Line} | ||
| ; ONE-NEXT: [005] 9 {Line} | ||
| ; ONE-NEXT: [005] 10 {Line} | ||
| ; ONE-NEXT: [005] 13 {Line} | ||
| ; ONE-NEXT: [004] 7 {TypeAlias} 'FLOAT' -> 'float' | ||
| ; ONE-NEXT: [003] 3 {Parameter} 'Param' -> 'char' | ||
| ; ONE-NEXT: [003] 4 {TypeAlias} 'INT' -> 'int' | ||
| ; ONE-NEXT: [003] 5 {Variable} 'Value' -> 'INT' | ||
| ; ONE-NEXT: [003] 3 {Line} | ||
| ; ONE-NEXT: [003] 5 {Line} | ||
| ; ONE-NEXT: [003] 13 {Line} | ||
| ; ONE-NEXT: [003] 14 {Line} | ||
| ; ONE-NEXT: [003] 14 {Line} | ||
|
|
||
| ; Using the selection facilities, we can produce a simple tabular | ||
| ; output showing just the logical types that are 'Typedef'. | ||
|
|
||
| ; RUN: llvm-debuginfo-analyzer --attribute=level,format \ | ||
| ; RUN: --output-sort=name \ | ||
| ; RUN: --select-types=Typedef \ | ||
| ; RUN: --report=list \ | ||
| ; RUN: --print=types \ | ||
| ; RUN: %p/Inputs/pr-44884-*.o 2>&1 | \ | ||
| ; RUN: FileCheck --strict-whitespace -check-prefix=TWO %s | ||
|
|
||
| ; TWO: Logical View: | ||
| ; TWO-NEXT: [000] {File} 'pr-44884-dwarf-clang.o' -> elf64-x86-64 | ||
| ; TWO-EMPTY: | ||
| ; TWO-NEXT: [001] {CompileUnit} 'pr-44884.cpp' | ||
| ; TWO-NEXT: [003] 7 {TypeAlias} 'FLOAT' -> 'float' | ||
| ; TWO-NEXT: [003] 4 {TypeAlias} 'INT' -> 'int' | ||
| ; TWO-EMPTY: | ||
| ; TWO-NEXT: Logical View: | ||
| ; TWO-NEXT: [000] {File} 'pr-44884-dwarf-gcc.o' -> elf64-x86-64 | ||
| ; TWO-EMPTY: | ||
| ; TWO-NEXT: [001] {CompileUnit} 'pr-44884.cpp' | ||
| ; TWO-NEXT: [004] 7 {TypeAlias} 'FLOAT' -> 'float' | ||
| ; TWO-NEXT: [003] 4 {TypeAlias} 'INT' -> 'int' |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,123 @@ | ||
| ; Test case 4 - Missing nested enumerations. | ||
|
|
||
| ; pr-46466.cpp | ||
| ; 1 struct Struct { | ||
| ; 2 union Union { | ||
| ; 3 enum NestedEnum { RED, BLUE }; | ||
| ; 4 }; | ||
| ; 5 Union U; | ||
| ; 6 }; | ||
| ; 7 | ||
| ; 8 Struct S; | ||
| ; 9 int test() { | ||
| ; 10 return S.U.BLUE; | ||
| ; 11 } | ||
|
|
||
| ; The above test is used to illustrate a scope issue found in the Clang | ||
| ; compiler. | ||
| ; PR46466: https://bugs.llvm.org/show_bug.cgi?id=46466 | ||
| ; PR45811: https://github.com/llvm/llvm-project/issues/45811 | ||
|
|
||
| ; In the following logical views, we can see that the DWARF debug | ||
| ; information generated by the Clang compiler does not include any | ||
| ; references to the enumerators 'RED' and 'BLUE'. The DWARF generated | ||
| ; by GCC, does include such references. | ||
|
|
||
| ; RUN: llvm-debuginfo-analyzer --attribute=level,format,producer \ | ||
| ; RUN: --output-sort=name \ | ||
| ; RUN: --print=symbols,types \ | ||
| ; RUN: %p/Inputs/pr-46466-dwarf-clang.o \ | ||
| ; RUN: %p/Inputs/pr-46466-dwarf-gcc.o 2>&1 | \ | ||
| ; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s | ||
|
|
||
| ; ONE: Logical View: | ||
| ; ONE-NEXT: [000] {File} 'pr-46466-dwarf-clang.o' -> elf64-x86-64 | ||
| ; ONE-EMPTY: | ||
| ; ONE-NEXT: [001] {CompileUnit} 'pr-46466.cpp' | ||
| ; ONE-NEXT: [002] {Producer} 'clang version 15.0.0 {{.*}}' | ||
| ; ONE-NEXT: [002] 8 {Variable} extern 'S' -> 'Struct' | ||
| ; ONE-NEXT: [002] 1 {Struct} 'Struct' | ||
| ; ONE-NEXT: [003] 5 {Member} public 'U' -> 'Union' | ||
| ; ONE-EMPTY: | ||
| ; ONE-NEXT: Logical View: | ||
| ; ONE-NEXT: [000] {File} 'pr-46466-dwarf-gcc.o' -> elf64-x86-64 | ||
| ; ONE-EMPTY: | ||
| ; ONE-NEXT: [001] {CompileUnit} 'pr-46466.cpp' | ||
| ; ONE-NEXT: [002] {Producer} 'GNU C++14 10.3.0 {{.*}}' | ||
| ; ONE-NEXT: [002] 8 {Variable} extern 'S' -> 'Struct' | ||
| ; ONE-NEXT: [002] 1 {Struct} 'Struct' | ||
| ; ONE-NEXT: [003] 5 {Member} public 'U' -> 'Union' | ||
| ; ONE-NEXT: [003] 2 {Union} 'Union' | ||
| ; ONE-NEXT: [004] 3 {Enumeration} 'NestedEnum' -> 'unsigned int' | ||
| ; ONE-NEXT: [005] {Enumerator} 'BLUE' = '0x1' | ||
| ; ONE-NEXT: [005] {Enumerator} 'RED' = '0x0' | ||
|
|
||
| ; Using the selection facilities, we can produce a logical view | ||
| ; showing just the logical types that are 'Enumerator' and its | ||
| ; parents. The logical view is sorted by the types name. | ||
|
|
||
| ; RUN: llvm-debuginfo-analyzer --attribute=level,format \ | ||
| ; RUN: --output-sort=name \ | ||
| ; RUN: --select-types=Enumerator \ | ||
| ; RUN: --report=parents \ | ||
| ; RUN: --print=types \ | ||
| ; RUN: %p/Inputs/pr-46466-*.o 2>&1 | \ | ||
| ; RUN: FileCheck --strict-whitespace -check-prefix=TWO %s | ||
|
|
||
| ; TWO: Logical View: | ||
| ; TWO-NEXT: [000] {File} 'pr-46466-dwarf-clang.o' -> elf64-x86-64 | ||
| ; TWO-EMPTY: | ||
| ; TWO-NEXT: [001] {CompileUnit} 'pr-46466.cpp' | ||
| ; TWO-EMPTY: | ||
| ; TWO-NEXT: Logical View: | ||
| ; TWO-NEXT: [000] {File} 'pr-46466-dwarf-gcc.o' -> elf64-x86-64 | ||
| ; TWO-EMPTY: | ||
| ; TWO-NEXT: [001] {CompileUnit} 'pr-46466.cpp' | ||
| ; TWO-NEXT: [002] 1 {Struct} 'Struct' | ||
| ; TWO-NEXT: [003] 2 {Union} 'Union' | ||
| ; TWO-NEXT: [004] 3 {Enumeration} 'NestedEnum' -> 'unsigned int' | ||
| ; TWO-NEXT: [005] {Enumerator} 'BLUE' = '0x1' | ||
| ; TWO-NEXT: [005] {Enumerator} 'RED' = '0x0' | ||
|
|
||
| ; Using the selection facilities, we can produce a simple tabular output | ||
| ; including a summary for the logical types that are 'Enumerator'. The | ||
| ; logical view is sorted by the types name. | ||
|
|
||
| ; RUN: llvm-debuginfo-analyzer --attribute=level,format \ | ||
| ; RUN: --output-sort=name \ | ||
| ; RUN: --select-types=Enumerator \ | ||
| ; RUN: --print=types,summary \ | ||
| ; RUN: %p/Inputs/pr-46466-*.o 2>&1 | \ | ||
| ; RUN: FileCheck --strict-whitespace -check-prefix=THR %s | ||
|
|
||
| ; THR: Logical View: | ||
| ; THR-NEXT: [000] {File} 'pr-46466-dwarf-clang.o' -> elf64-x86-64 | ||
| ; THR-EMPTY: | ||
| ; THR-NEXT: [001] {CompileUnit} 'pr-46466.cpp' | ||
| ; THR-EMPTY: | ||
| ; THR-NEXT: ----------------------------- | ||
| ; THR-NEXT: Element Total Printed | ||
| ; THR-NEXT: ----------------------------- | ||
| ; THR-NEXT: Scopes 4 0 | ||
| ; THR-NEXT: Symbols 0 0 | ||
| ; THR-NEXT: Types 0 0 | ||
| ; THR-NEXT: Lines 0 0 | ||
| ; THR-NEXT: ----------------------------- | ||
| ; THR-NEXT: Total 4 0 | ||
| ; THR-EMPTY: | ||
| ; THR-NEXT: Logical View: | ||
| ; THR-NEXT: [000] {File} 'pr-46466-dwarf-gcc.o' -> elf64-x86-64 | ||
| ; THR-EMPTY: | ||
| ; THR-NEXT: [001] {CompileUnit} 'pr-46466.cpp' | ||
| ; THR-NEXT: [005] {Enumerator} 'BLUE' = '0x1' | ||
| ; THR-NEXT: [005] {Enumerator} 'RED' = '0x0' | ||
| ; THR-EMPTY: | ||
| ; THR-NEXT: ----------------------------- | ||
| ; THR-NEXT: Element Total Printed | ||
| ; THR-NEXT: ----------------------------- | ||
| ; THR-NEXT: Scopes 5 0 | ||
| ; THR-NEXT: Symbols 0 0 | ||
| ; THR-NEXT: Types 2 2 | ||
| ; THR-NEXT: Lines 0 0 | ||
| ; THR-NEXT: ----------------------------- | ||
| ; THR-NEXT: Total 7 2 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,108 @@ | ||
| ; Test case 5 - Incorrect lexical scope variable. | ||
|
|
||
| ; pr-43860.cpp | ||
| ; 1 #include "definitions.h" | ||
| ; 2 forceinline int InlineFunction(int Param) { | ||
| ; 3 int Var_1 = Param; | ||
| ; 4 { | ||
| ; 5 int Var_2 = Param + Var_1; | ||
| ; 6 Var_1 = Var_2; | ||
| ; 7 } | ||
| ; 8 return Var_1; | ||
| ; 9 } | ||
| ; 10 | ||
| ; 11 int test(int Param_1, int Param_2) { | ||
| ; 12 int A = Param_1; | ||
| ; 13 A += InlineFunction(Param_2); | ||
| ; 14 return A; | ||
| ; 15 } | ||
|
|
||
| ; The above test is used to illustrate a variable issue found in the | ||
| ; Clang compiler. | ||
| ; PR43860: https://bugs.llvm.org/show_bug.cgi?id=43860 | ||
| ; PR43205: https://github.com/llvm/llvm-project/issues/43205 | ||
|
|
||
| ; In the following logical views, we can see that the DWARF debug | ||
| ; information generated by the Clang compiler shows the variables | ||
| ; 'Var_1' and 'Var_2' are at the same lexical scope (4) in the function | ||
| ; 'InlineFuction'. | ||
| ; The DWARF generated by GCC/Clang show those variables at the correct | ||
| ; lexical scope: '3' and '4' respectively. | ||
|
|
||
| ; RUN: llvm-debuginfo-analyzer --attribute=level,format,producer \ | ||
| ; RUN: --output-sort=name \ | ||
| ; RUN: --print=symbols \ | ||
| ; RUN: %p/Inputs/pr-43860-dwarf-clang.o \ | ||
| ; RUN: %p/Inputs/pr-43860-dwarf-gcc.o 2>&1 | \ | ||
| ; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s | ||
|
|
||
| ; ONE: Logical View: | ||
| ; ONE-NEXT: [000] {File} 'pr-43860-dwarf-clang.o' -> elf64-x86-64 | ||
| ; 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: [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] 14 {InlinedFunction} not_inlined 'InlineFunction' -> 'int' | ||
| ; ONE-NEXT: [004] {Block} | ||
| ; ONE-NEXT: [005] {Variable} 'Var_2' -> 'int' | ||
| ; ONE-NEXT: [004] {Parameter} 'Param' -> 'int' | ||
| ; ONE-NEXT: [004] {Variable} 'Var_1' -> 'int' | ||
| ; ONE-NEXT: [003] 11 {Parameter} 'Param_1' -> 'int' | ||
| ; ONE-NEXT: [003] 11 {Parameter} 'Param_2' -> 'int' | ||
| ; ONE-EMPTY: | ||
| ; ONE-NEXT: Logical View: | ||
| ; ONE-NEXT: [000] {File} 'pr-43860-dwarf-gcc.o' -> elf64-x86-64 | ||
| ; ONE-EMPTY: | ||
| ; ONE-NEXT: [001] {CompileUnit} 'pr-43860.cpp' | ||
| ; ONE-NEXT: [002] {Producer} 'GNU C++14 10.3.0 {{.*}}' | ||
| ; ONE-NEXT: [002] 2 {Function} extern declared_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} declared_inlined 'InlineFunction' -> 'int' | ||
| ; ONE-NEXT: [004] {Block} | ||
| ; ONE-NEXT: [005] {Variable} 'Var_2' -> 'int' | ||
| ; ONE-NEXT: [004] {Parameter} 'Param' -> 'int' | ||
| ; ONE-NEXT: [004] {Variable} 'Var_1' -> 'int' | ||
| ; ONE-NEXT: [003] 11 {Parameter} 'Param_1' -> 'int' | ||
| ; ONE-NEXT: [003] 11 {Parameter} 'Param_2' -> 'int' | ||
|
|
||
| ; Using the selection facilities, we can produce a simple tabular output | ||
| ; showing just the logical elements that have in their name the 'var' | ||
| ; pattern. The logical view is sorted by the variables name. | ||
|
|
||
| ; RUN: llvm-debuginfo-analyzer --attribute=level,format \ | ||
| ; RUN: --output-sort=name \ | ||
| ; RUN: --select-regex --select-nocase \ | ||
| ; RUN: --select=Var \ | ||
| ; RUN: --report=list \ | ||
| ; RUN: --print=symbols \ | ||
| ; RUN: %p/Inputs/pr-43860-*.o 2>&1 | \ | ||
| ; RUN: FileCheck --strict-whitespace -check-prefix=TWO %s | ||
|
|
||
| ; TWO: Logical View: | ||
| ; TWO-NEXT: [000] {File} 'pr-43860-dwarf-clang.o' -> elf64-x86-64 | ||
| ; TWO-EMPTY: | ||
| ; TWO-NEXT: [001] {CompileUnit} 'pr-43860.cpp' | ||
| ; TWO-NEXT: [004] {Variable} 'Var_1' -> 'int' | ||
| ; TWO-NEXT: [003] 3 {Variable} 'Var_1' -> 'int' | ||
| ; TWO-NEXT: [005] {Variable} 'Var_2' -> 'int' | ||
| ; TWO-NEXT: [004] 5 {Variable} 'Var_2' -> 'int' | ||
| ; TWO-EMPTY: | ||
| ; TWO-NEXT: Logical View: | ||
| ; TWO-NEXT: [000] {File} 'pr-43860-dwarf-gcc.o' -> elf64-x86-64 | ||
| ; TWO-EMPTY: | ||
| ; TWO-NEXT: [001] {CompileUnit} 'pr-43860.cpp' | ||
| ; TWO-NEXT: [004] {Variable} 'Var_1' -> 'int' | ||
| ; TWO-NEXT: [003] 3 {Variable} 'Var_1' -> 'int' | ||
| ; TWO-NEXT: [005] {Variable} 'Var_2' -> 'int' | ||
| ; TWO-NEXT: [004] 5 {Variable} 'Var_2' -> 'int' |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| ; Test case 6 - Full logical view | ||
|
|
||
| ; test.cpp | ||
| ; 1 using INTPTR = const int *; | ||
| ; 2 int foo(INTPTR ParamPtr, unsigned ParamUnsigned, bool ParamBool) { | ||
| ; 3 if (ParamBool) { | ||
| ; 4 typedef int INTEGER; | ||
| ; 5 const INTEGER CONSTANT = 7; | ||
| ; 6 return CONSTANT; | ||
| ; 7 } | ||
| ; 8 return ParamUnsigned; | ||
| ; 9 } | ||
|
|
||
| ; Print low level details. | ||
| ; The following command prints low level information that includes | ||
| ; offsets within the debug information section, debug location | ||
| ; operands, linkage names, etc. | ||
|
|
||
| ; RUN: llvm-debuginfo-analyzer --attribute=all \ | ||
| ; RUN: --print=all \ | ||
| ; RUN: %p/Inputs/test-dwarf-clang.o 2>&1 | \ | ||
| ; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s | ||
|
|
||
| ; ONE: Logical View: | ||
| ; ONE-NEXT: [0x0000000000][000] {File} '{{.*}}test-dwarf-clang.o' -> elf64-x86-64 | ||
| ; ONE-EMPTY: | ||
| ; ONE-NEXT: [0x000000000b][001] {CompileUnit} 'test.cpp' | ||
| ; ONE-NEXT: [0x000000000b][002] {Producer} 'clang version 15.0.0 {{.*}}' | ||
| ; ONE-NEXT: {Directory} '/data/projects/tests/input/general' | ||
| ; ONE-NEXT: {File} 'test.cpp' | ||
| ; ONE-NEXT: {Public} 'foo' [0x0000000000:0x000000003a] | ||
| ; ONE-NEXT: [0x000000000b][002] {Range} Lines 2:9 [0x0000000000:0x000000003a] | ||
| ; ONE-NEXT: [0x00000000bc][002] {BaseType} 'bool' | ||
| ; ONE-NEXT: [0x0000000099][002] {BaseType} 'int' | ||
| ; ONE-NEXT: [0x00000000b5][002] {BaseType} 'unsigned int' | ||
| ; ONE-EMPTY: | ||
| ; ONE-NEXT: [0x00000000a0][002] {Source} '/data/projects/tests/input/general/test.cpp' | ||
| ; ONE-NEXT: [0x00000000a0][002] 1 {TypeAlias} 'INTPTR' -> [0x00000000ab]'* const int' | ||
| ; ONE-NEXT: [0x000000002a][002] 2 {Function} extern not_inlined 'foo' -> [0x0000000099]'int' | ||
| ; ONE-NEXT: [0x000000002a][003] {Range} Lines 2:9 [0x0000000000:0x000000003a] | ||
| ; ONE-NEXT: [0x000000002a][003] {Linkage} 0x2 '_Z3fooPKijb' | ||
| ; ONE-NEXT: [0x0000000071][003] {Block} | ||
| ; ONE-NEXT: [0x0000000071][004] {Range} Lines 5:8 [0x000000001c:0x000000002f] | ||
| ; ONE-NEXT: [0x000000007e][004] 5 {Variable} 'CONSTANT' -> [0x00000000c3]'const INTEGER' | ||
| ; ONE-NEXT: [0x000000007e][005] {Coverage} 100.00% | ||
| ; ONE-NEXT: [0x000000007f][005] {Location} | ||
| ; ONE-NEXT: [0x000000007f][006] {Entry} fbreg -28 | ||
| ; ONE-NEXT: [0x000000001c][004] 5 {Line} {NewStatement} '/data/projects/tests/input/general/test.cpp' | ||
| ; ONE-NEXT: [0x000000001c][004] {Code} 'movl $0x7, -0x1c(%rbp)' | ||
| ; ONE-NEXT: [0x0000000023][004] 6 {Line} {NewStatement} '/data/projects/tests/input/general/test.cpp' | ||
| ; ONE-NEXT: [0x0000000023][004] {Code} 'movl $0x7, -0x4(%rbp)' | ||
| ; ONE-NEXT: [0x000000002a][004] {Code} 'jmp 0x6' | ||
| ; ONE-NEXT: [0x000000002f][004] 8 {Line} {NewStatement} '/data/projects/tests/input/general/test.cpp' | ||
| ; ONE-NEXT: [0x000000002f][004] {Code} 'movl -0x14(%rbp), %eax' | ||
| ; ONE-NEXT: [0x0000000063][003] 2 {Parameter} 'ParamBool' -> [0x00000000bc]'bool' | ||
| ; ONE-NEXT: [0x0000000063][004] {Coverage} 100.00% | ||
| ; ONE-NEXT: [0x0000000064][004] {Location} | ||
| ; ONE-NEXT: [0x0000000064][005] {Entry} fbreg -21 | ||
| ; ONE-NEXT: [0x0000000047][003] 2 {Parameter} 'ParamPtr' -> [0x00000000a0]'INTPTR' | ||
| ; ONE-NEXT: [0x0000000047][004] {Coverage} 100.00% | ||
| ; ONE-NEXT: [0x0000000048][004] {Location} | ||
| ; ONE-NEXT: [0x0000000048][005] {Entry} fbreg -16 | ||
| ; ONE-NEXT: [0x0000000055][003] 2 {Parameter} 'ParamUnsigned' -> [0x00000000b5]'unsigned int' | ||
| ; ONE-NEXT: [0x0000000055][004] {Coverage} 100.00% | ||
| ; ONE-NEXT: [0x0000000056][004] {Location} | ||
| ; ONE-NEXT: [0x0000000056][005] {Entry} fbreg -20 | ||
| ; ONE-NEXT: [0x000000008d][003] 4 {TypeAlias} 'INTEGER' -> [0x0000000099]'int' | ||
| ; ONE-NEXT: [0x0000000000][003] 2 {Line} {NewStatement} '/data/projects/tests/input/general/test.cpp' | ||
| ; ONE-NEXT: [0x0000000000][003] {Code} 'pushq %rbp' | ||
| ; ONE-NEXT: [0x0000000001][003] {Code} 'movq %rsp, %rbp' | ||
| ; ONE-NEXT: [0x0000000004][003] {Code} 'movb %dl, %al' | ||
| ; ONE-NEXT: [0x0000000006][003] {Code} 'movq %rdi, -0x10(%rbp)' | ||
| ; ONE-NEXT: [0x000000000a][003] {Code} 'movl %esi, -0x14(%rbp)' | ||
| ; ONE-NEXT: [0x000000000d][003] {Code} 'andb $0x1, %al' | ||
| ; ONE-NEXT: [0x000000000f][003] {Code} 'movb %al, -0x15(%rbp)' | ||
| ; ONE-NEXT: [0x0000000012][003] 3 {Line} {NewStatement} {PrologueEnd} '/data/projects/tests/input/general/test.cpp' | ||
| ; ONE-NEXT: [0x0000000012][003] {Code} 'testb $0x1, -0x15(%rbp)' | ||
| ; ONE-NEXT: [0x0000000016][003] {Code} 'je 0x13' | ||
| ; ONE-NEXT: [0x0000000032][003] 8 {Line} '/data/projects/tests/input/general/test.cpp' | ||
| ; ONE-NEXT: [0x0000000032][003] {Code} 'movl %eax, -0x4(%rbp)' | ||
| ; ONE-NEXT: [0x0000000035][003] 9 {Line} {NewStatement} '/data/projects/tests/input/general/test.cpp' | ||
| ; ONE-NEXT: [0x0000000035][003] {Code} 'movl -0x4(%rbp), %eax' | ||
| ; ONE-NEXT: [0x0000000038][003] {Code} 'popq %rbp' | ||
| ; ONE-NEXT: [0x0000000039][003] {Code} 'retq' | ||
| ; ONE-NEXT: [0x000000003a][003] 9 {Line} {NewStatement} {EndSequence} '/data/projects/tests/input/general/test.cpp' | ||
| ; ONE-EMPTY: | ||
| ; ONE-NEXT: ----------------------------- | ||
| ; ONE-NEXT: Element Total Printed | ||
| ; ONE-NEXT: ----------------------------- | ||
| ; ONE-NEXT: Scopes 3 3 | ||
| ; ONE-NEXT: Symbols 4 4 | ||
| ; ONE-NEXT: Types 5 5 | ||
| ; ONE-NEXT: Lines 25 25 | ||
| ; ONE-NEXT: ----------------------------- | ||
| ; ONE-NEXT: Total 37 37 | ||
| ; ONE-EMPTY: | ||
| ; ONE-NEXT: Scope Sizes: | ||
| ; ONE-NEXT: 189 (100.00%) : [0x000000000b][001] {CompileUnit} 'test.cpp' | ||
| ; ONE-NEXT: 110 ( 58.20%) : [0x000000002a][002] 2 {Function} extern not_inlined 'foo' -> [0x0000000099]'int' | ||
| ; ONE-NEXT: 27 ( 14.29%) : [0x0000000071][003] {Block} | ||
| ; ONE-EMPTY: | ||
| ; ONE-NEXT: Totals by lexical level: | ||
| ; ONE-NEXT: [001]: 189 (100.00%) | ||
| ; ONE-NEXT: [002]: 110 ( 58.20%) | ||
| ; ONE-NEXT: [003]: 27 ( 14.29%) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| ; Ignored attributes with DW_FORM_implicit_const. | ||
| ; https://github.com/llvm/llvm-project/issues/57040 | ||
|
|
||
| ; Output generated by g++ (Debian 11.3.0-3) 11.3.0 | ||
|
|
||
| ; .debug_abbrev contents: | ||
| ; [1] DW_TAG_formal_parameter DW_CHILDREN_no | ||
| ; DW_AT_decl_file DW_FORM_implicit_const 1 | ||
| ; DW_AT_decl_line DW_FORM_implicit_const 2 | ||
|
|
||
| ; [2] DW_TAG_typedef DW_CHILDREN_no | ||
| ; DW_AT_decl_file DW_FORM_implicit_const 1 | ||
| ; DW_AT_decl_line DW_FORM_data1 | ||
|
|
||
| ; Attributes with DW_FORM_implicit_const being ignored by the ELFReader, | ||
| ; causing {Parameter} and {TypeAlias} to omit line numbers. | ||
|
|
||
| ; test.cpp | ||
| ; 1 using INTPTR = const int *; | ||
| ; 2 int foo(INTPTR ParamPtr, unsigned ParamUnsigned, bool ParamBool) { | ||
| ; 3 if (ParamBool) { | ||
| ; 4 typedef int INTEGER; | ||
| ; 5 const INTEGER CONSTANT = 7; | ||
| ; 6 return CONSTANT; | ||
| ; 7 } | ||
| ; 8 return ParamUnsigned; | ||
| ; 9 } | ||
|
|
||
| ; RUN: llvm-debuginfo-analyzer --attribute=level,format,producer \ | ||
| ; RUN: --print=scopes,symbols,types \ | ||
| ; RUN: %p/Inputs/pr-57040-test-dwarf-clang.o 2>&1 | \ | ||
| ; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s | ||
|
|
||
| ; ONE: Logical View: | ||
| ; ONE-NEXT: [000] {File} 'pr-57040-test-dwarf-clang.o' -> elf64-x86-64 | ||
| ; ONE-EMPTY: | ||
| ; ONE-NEXT: [001] {CompileUnit} 'test.cpp' | ||
| ; ONE-NEXT: [002] {Producer} 'clang version 14.0.6' | ||
| ; ONE-NEXT: [002] 1 {TypeAlias} 'INTPTR' -> '* const int' | ||
| ; ONE-NEXT: [002] 2 {Function} extern not_inlined 'foo' -> 'int' | ||
| ; ONE-NEXT: [003] {Block} | ||
| ; ONE-NEXT: [004] 5 {Variable} 'CONSTANT' -> 'const INTEGER' | ||
| ; ONE-NEXT: [003] 2 {Parameter} 'ParamBool' -> 'bool' | ||
| ; ONE-NEXT: [003] 2 {Parameter} 'ParamPtr' -> 'INTPTR' | ||
| ; ONE-NEXT: [003] 2 {Parameter} 'ParamUnsigned' -> 'unsigned int' | ||
| ; ONE-NEXT: [003] 4 {TypeAlias} 'INTEGER' -> 'int' | ||
|
|
||
| ; RUN: llvm-debuginfo-analyzer --attribute=level,format,producer \ | ||
| ; RUN: --print=scopes,symbols,types \ | ||
| ; RUN: %p/Inputs/pr-57040-test-dwarf-gcc.o 2>&1 | \ | ||
| ; RUN: FileCheck --strict-whitespace -check-prefix=TWO %s | ||
|
|
||
| ; TWO: Logical View: | ||
| ; TWO-NEXT: [000] {File} 'pr-57040-test-dwarf-gcc.o' -> elf64-x86-64 | ||
| ; TWO-EMPTY: | ||
| ; TWO-NEXT: [001] {CompileUnit} 'test.cpp' | ||
| ; TWO-NEXT: [002] {Producer} 'GNU C++17 11.3.0 {{.*}}' | ||
| ; TWO-NEXT: [002] 1 {TypeAlias} 'INTPTR' -> '* const int' | ||
| ; TWO-NEXT: [002] 2 {Function} extern not_inlined 'foo' -> 'int' | ||
| ; TWO-NEXT: [003] {Block} | ||
| ; TWO-NEXT: [004] 4 {TypeAlias} 'INTEGER' -> 'int' | ||
| ; TWO-NEXT: [004] 5 {Variable} 'CONSTANT' -> 'const INTEGER' | ||
| ; TWO-NEXT: [003] 2 {Parameter} 'ParamBool' -> 'bool' | ||
| ; TWO-NEXT: [003] 2 {Parameter} 'ParamPtr' -> 'INTPTR' | ||
| ; TWO-NEXT: [003] 2 {Parameter} 'ParamUnsigned' -> 'unsigned int' |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,142 @@ | ||
| ; Incorrect function matching during comparison. | ||
| ; https://github.com/llvm/llvm-project/issues/57040 | ||
|
|
||
| ; Output generated by g++ (Debian 11.3.0-3) 11.3.0 | ||
|
|
||
| ; .debug_info contents: | ||
| ; format = DWARF32, version = 0x0005, unit_type = DW_UT_compile | ||
| ; | ||
| ; DW_TAG_compile_unit | ||
| ; DW_TAG_subprogram ("foo") | ||
| ; DW_AT_decl_file (1) | ||
| ; | ||
| ; DW_TAG_formal_parameter ("ParamPtr") | ||
| ; DW_AT_decl_file (1) | ||
| ; | ||
| ; .debug_line contents: | ||
| ; Line table prologue: | ||
| ; format: DWARF32, version: 5 | ||
| ; include_directories[0] = "/usr/local/google/home/aheejin/test/llvm-dva" | ||
| ; file_names[0]: name: "test.cpp" dir_index: 0 | ||
| ; file_names[1]: name: "test.cpp" dir_index: 0 | ||
|
|
||
| ; The values for DW_AT_decl_file are 1-indexed. | ||
|
|
||
| ; test.cpp | ||
| ; 1 using INTPTR = const int *; | ||
| ; 2 int foo(INTPTR ParamPtr, unsigned ParamUnsigned, bool ParamBool) { | ||
| ; 3 if (ParamBool) { | ||
| ; 4 typedef int INTEGER; | ||
| ; 5 const INTEGER CONSTANT = 7; | ||
| ; 6 return CONSTANT; | ||
| ; 7 } | ||
| ; 8 return ParamUnsigned; | ||
| ; 9 } | ||
|
|
||
| ; RUN: llvm-debuginfo-analyzer --attribute=level,producer \ | ||
| ; RUN: --compare=types \ | ||
| ; RUN: --report=view \ | ||
| ; RUN: --print=symbols,types \ | ||
| ; RUN: %p/Inputs/pr-57040-test-dwarf-clang.o \ | ||
| ; RUN: %p/Inputs/pr-57040-test-dwarf-gcc.o 2>&1 | \ | ||
| ; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s | ||
|
|
||
| ; ONE: Reference: 'pr-57040-test-dwarf-clang.o' | ||
| ; ONE-NEXT: Target: 'pr-57040-test-dwarf-gcc.o' | ||
| ; ONE-EMPTY: | ||
| ; ONE-NEXT: Logical View: | ||
| ; ONE-NEXT: [000] {File} 'pr-57040-test-dwarf-clang.o' | ||
| ; ONE-EMPTY: | ||
| ; ONE-NEXT: [001] {CompileUnit} 'test.cpp' | ||
| ; ONE-NEXT: [002] {Producer} 'clang version 14.0.6' | ||
| ; ONE-NEXT: [002] 1 {TypeAlias} 'INTPTR' -> '* const int' | ||
| ; ONE-NEXT: [002] 2 {Function} extern not_inlined 'foo' -> 'int' | ||
| ; ONE-NEXT: [003] {Block} | ||
| ; ONE-NEXT: [004] 5 {Variable} 'CONSTANT' -> 'const INTEGER' | ||
| ; ONE-NEXT: +[004] 4 {TypeAlias} 'INTEGER' -> 'int' | ||
| ; ONE-NEXT: [003] 2 {Parameter} 'ParamBool' -> 'bool' | ||
| ; ONE-NEXT: [003] 2 {Parameter} 'ParamPtr' -> 'INTPTR' | ||
| ; ONE-NEXT: [003] 2 {Parameter} 'ParamUnsigned' -> 'unsigned int' | ||
| ; ONE-NEXT: -[003] 4 {TypeAlias} 'INTEGER' -> 'int' | ||
|
|
||
| ; RUN: llvm-debuginfo-analyzer --attribute=level \ | ||
| ; RUN: --compare=types \ | ||
| ; RUN: --report=list \ | ||
| ; RUN: --print=symbols,types,summary \ | ||
| ; RUN: %p/Inputs/pr-57040-test-dwarf-clang.o \ | ||
| ; RUN: %p/Inputs/pr-57040-test-dwarf-gcc.o 2>&1 | \ | ||
| ; RUN: FileCheck --strict-whitespace -check-prefix=TWO %s | ||
|
|
||
| ; TWO: Reference: 'pr-57040-test-dwarf-clang.o' | ||
| ; TWO-NEXT: Target: 'pr-57040-test-dwarf-gcc.o' | ||
| ; TWO-EMPTY: | ||
| ; TWO-NEXT: (1) Missing Types: | ||
| ; TWO-NEXT: -[003] 4 {TypeAlias} 'INTEGER' -> 'int' | ||
| ; TWO-EMPTY: | ||
| ; TWO-NEXT: (1) Added Types: | ||
| ; TWO-NEXT: +[004] 4 {TypeAlias} 'INTEGER' -> 'int' | ||
| ; TWO-EMPTY: | ||
| ; TWO-NEXT: ---------------------------------------- | ||
| ; TWO-NEXT: Element Expected Missing Added | ||
| ; TWO-NEXT: ---------------------------------------- | ||
| ; TWO-NEXT: Scopes 4 0 0 | ||
| ; TWO-NEXT: Symbols 0 0 0 | ||
| ; TWO-NEXT: Types 2 1 1 | ||
| ; TWO-NEXT: Lines 0 0 0 | ||
| ; TWO-NEXT: ---------------------------------------- | ||
| ; TWO-NEXT: Total 6 1 1 | ||
|
|
||
| ; Changing the 'Reference' and 'Target' order: | ||
|
|
||
| ; RUN: llvm-debuginfo-analyzer --attribute=level,producer \ | ||
| ; RUN: --compare=types \ | ||
| ; RUN: --report=view \ | ||
| ; RUN: --print=symbols,types \ | ||
| ; RUN: %p/Inputs/pr-57040-test-dwarf-gcc.o \ | ||
| ; RUN: %p/Inputs/pr-57040-test-dwarf-clang.o 2>&1 | \ | ||
| ; RUN: FileCheck --strict-whitespace -check-prefix=THR %s | ||
|
|
||
| ; THR: Reference: 'pr-57040-test-dwarf-gcc.o' | ||
| ; THR-NEXT: Target: 'pr-57040-test-dwarf-clang.o' | ||
| ; THR-EMPTY: | ||
| ; THR-NEXT: Logical View: | ||
| ; THR-NEXT: [000] {File} 'pr-57040-test-dwarf-gcc.o' | ||
| ; THR-EMPTY: | ||
| ; THR-NEXT: [001] {CompileUnit} 'test.cpp' | ||
| ; THR-NEXT: [002] {Producer} 'GNU C++17 11.3.0 {{.*}}' | ||
| ; THR-NEXT: [002] 1 {TypeAlias} 'INTPTR' -> '* const int' | ||
| ; THR-NEXT: [002] 2 {Function} extern not_inlined 'foo' -> 'int' | ||
| ; THR-NEXT: [003] {Block} | ||
| ; THR-NEXT: -[004] 4 {TypeAlias} 'INTEGER' -> 'int' | ||
| ; THR-NEXT: [004] 5 {Variable} 'CONSTANT' -> 'const INTEGER' | ||
| ; THR-NEXT: [003] 2 {Parameter} 'ParamBool' -> 'bool' | ||
| ; THR-NEXT: [003] 2 {Parameter} 'ParamPtr' -> 'INTPTR' | ||
| ; THR-NEXT: [003] 2 {Parameter} 'ParamUnsigned' -> 'unsigned int' | ||
| ; THR-NEXT: +[003] 4 {TypeAlias} 'INTEGER' -> 'int' | ||
|
|
||
| ; RUN: llvm-debuginfo-analyzer --attribute=level \ | ||
| ; RUN: --compare=types \ | ||
| ; RUN: --report=list \ | ||
| ; RUN: --print=symbols,types,summary \ | ||
| ; RUN: %p/Inputs/pr-57040-test-dwarf-gcc.o \ | ||
| ; RUN: %p/Inputs/pr-57040-test-dwarf-clang.o 2>&1 | \ | ||
| ; RUN: FileCheck --strict-whitespace -check-prefix=FOU %s | ||
|
|
||
| ; FOU: Reference: 'pr-57040-test-dwarf-gcc.o' | ||
| ; FOU-NEXT: Target: 'pr-57040-test-dwarf-clang.o' | ||
| ; FOU-EMPTY: | ||
| ; FOU-NEXT: (1) Missing Types: | ||
| ; FOU-NEXT: -[004] 4 {TypeAlias} 'INTEGER' -> 'int' | ||
| ; FOU-EMPTY: | ||
| ; FOU-NEXT: (1) Added Types: | ||
| ; FOU-NEXT: +[003] 4 {TypeAlias} 'INTEGER' -> 'int' | ||
| ; FOU-EMPTY: | ||
| ; FOU-NEXT: ---------------------------------------- | ||
| ; FOU-NEXT: Element Expected Missing Added | ||
| ; FOU-NEXT: ---------------------------------------- | ||
| ; FOU-NEXT: Scopes 4 0 0 | ||
| ; FOU-NEXT: Symbols 0 0 0 | ||
| ; FOU-NEXT: Types 2 1 1 | ||
| ; FOU-NEXT: Lines 0 0 0 | ||
| ; FOU-NEXT: ---------------------------------------- | ||
| ; FOU-NEXT: Total 6 1 1 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,205 @@ | ||
| ; * Added incorrect logical instructions for: --print=lines,instructions | ||
| ; 'bar' and 'foo' showing extra instruction from compiler generated functions: | ||
| ; '_cxx_global_var_init' and '_GLOBAL_sub_l_suite_lexical_01.cpp' | ||
| ; | ||
| ; * Missing logical instructions for: --print=instructions | ||
| ; Only 'foo' showing logical instructions. | ||
|
|
||
| ; pr-incorrect-instructions-dwarf-clang.cpp | ||
| ; 1 int ABCDE = 56; int XYZ = ABCDE * 65; | ||
| ; 2 int bar(int Param) { | ||
| ; 3 return Param + 999999 * Param - 66; | ||
| ; 4 } | ||
| ; 5 | ||
| ; 6 int foo(int Param) { | ||
| ; 7 return Param - bar(Param) / Param * 66 + ABCDE; | ||
| ; 8 } | ||
| ; 9 | ||
| ; 10 int test(int P1) { | ||
| ; 11 int Local_1 = P1 - ABCDE; | ||
| ; 12 { | ||
| ; 13 int Local_A = 0; | ||
| ; 14 Local_A = P1 + foo(Local_1); | ||
| ; 15 ++Local_1; | ||
| ; 16 } | ||
| ; 17 return Local_1; | ||
| ; 18 } | ||
| ; 19 | ||
| ; 20 int main() { | ||
| ; 21 return 0; | ||
| ; 22 } | ||
|
|
||
| ; RUN: llvm-debuginfo-analyzer --attribute=level \ | ||
| ; RUN: --print=lines,instructions \ | ||
| ; RUN: %p/Inputs/pr-incorrect-instructions-dwarf-clang.o 2>&1 | \ | ||
| ; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s | ||
|
|
||
| ; ONE: Logical View: | ||
| ; ONE-NEXT: [000] {File} 'pr-incorrect-instructions-dwarf-clang.o' | ||
| ; ONE-EMPTY: | ||
| ; ONE-NEXT: [001] {CompileUnit} 'pr-incorrect-instructions-dwarf-clang.cpp' | ||
| ; ONE-NEXT: [002] 2 {Function} extern not_inlined 'bar' -> 'int' | ||
| ; ONE-NEXT: [003] 2 {Line} | ||
| ; ONE-NEXT: [003] {Code} 'pushq %rbp' | ||
| ; ONE-NEXT: [003] {Code} 'movq %rsp, %rbp' | ||
| ; ONE-NEXT: [003] {Code} 'movl %edi, -0x4(%rbp)' | ||
| ; ONE-NEXT: [003] 3 {Line} | ||
| ; ONE-NEXT: [003] {Code} 'movl -0x4(%rbp), %eax' | ||
| ; ONE-NEXT: [003] 3 {Line} | ||
| ; ONE-NEXT: [003] {Code} 'imull $0xf423f, -0x4(%rbp), %ecx' | ||
| ; ONE-NEXT: [003] 3 {Line} | ||
| ; ONE-NEXT: [003] {Code} 'addl %ecx, %eax' | ||
| ; ONE-NEXT: [003] 3 {Line} | ||
| ; ONE-NEXT: [003] {Code} 'subl $0x42, %eax' | ||
| ; ONE-NEXT: [003] 3 {Line} | ||
| ; ONE-NEXT: [003] {Code} 'popq %rbp' | ||
| ; ONE-NEXT: [003] {Code} 'retq' | ||
| ; ONE-NEXT: [002] 6 {Function} extern not_inlined 'foo' -> 'int' | ||
| ; ONE-NEXT: [003] 6 {Line} | ||
| ; ONE-NEXT: [003] {Code} 'pushq %rbp' | ||
| ; ONE-NEXT: [003] {Code} 'movq %rsp, %rbp' | ||
| ; ONE-NEXT: [003] {Code} 'subq $0x10, %rsp' | ||
| ; ONE-NEXT: [003] {Code} 'movl %edi, -0x4(%rbp)' | ||
| ; ONE-NEXT: [003] 7 {Line} | ||
| ; ONE-NEXT: [003] {Code} 'movl -0x4(%rbp), %eax' | ||
| ; ONE-NEXT: [003] {Code} 'movl %eax, -0x8(%rbp)' | ||
| ; ONE-NEXT: [003] 7 {Line} | ||
| ; ONE-NEXT: [003] {Code} 'movl -0x4(%rbp), %edi' | ||
| ; ONE-NEXT: [003] 7 {Line} | ||
| ; ONE-NEXT: [003] {Code} 'callq 0x0' | ||
| ; ONE-NEXT: [003] 7 {Line} | ||
| ; ONE-NEXT: [003] {Code} 'cltd' | ||
| ; ONE-NEXT: [003] {Code} 'idivl -0x4(%rbp)' | ||
| ; ONE-NEXT: [003] {Code} 'movl %eax, %ecx' | ||
| ; ONE-NEXT: [003] {Code} 'movl -0x8(%rbp), %eax' | ||
| ; ONE-NEXT: [003] 7 {Line} | ||
| ; ONE-NEXT: [003] {Code} 'imull $0x42, %ecx, %ecx' | ||
| ; ONE-NEXT: [003] 7 {Line} | ||
| ; ONE-NEXT: [003] {Code} 'subl %ecx, %eax' | ||
| ; ONE-NEXT: [003] 7 {Line} | ||
| ; ONE-NEXT: [003] {Code} 'addl (%rip), %eax' | ||
| ; ONE-NEXT: [003] 7 {Line} | ||
| ; ONE-NEXT: [003] {Code} 'addq $0x10, %rsp' | ||
| ; ONE-NEXT: [003] {Code} 'popq %rbp' | ||
| ; ONE-NEXT: [003] {Code} 'retq' | ||
| ; ONE-NEXT: [003] {Code} 'data16' | ||
| ; ONE-NEXT: [002] 10 {Function} extern not_inlined 'test' -> 'int' | ||
| ; ONE-NEXT: [003] {Block} | ||
| ; ONE-NEXT: [004] 13 {Line} | ||
| ; ONE-NEXT: [004] {Code} 'movl $0x0, -0xc(%rbp)' | ||
| ; ONE-NEXT: [004] 14 {Line} | ||
| ; ONE-NEXT: [004] {Code} 'movl -0x4(%rbp), %eax' | ||
| ; ONE-NEXT: [004] {Code} 'movl %eax, -0x10(%rbp)' | ||
| ; ONE-NEXT: [004] 14 {Line} | ||
| ; ONE-NEXT: [004] {Code} 'movl -0x8(%rbp), %edi' | ||
| ; ONE-NEXT: [004] 14 {Line} | ||
| ; ONE-NEXT: [004] {Code} 'callq 0x0' | ||
| ; ONE-NEXT: [004] {Code} 'movl %eax, %ecx' | ||
| ; ONE-NEXT: [004] {Code} 'movl -0x10(%rbp), %eax' | ||
| ; ONE-NEXT: [004] 14 {Line} | ||
| ; ONE-NEXT: [004] {Code} 'addl %ecx, %eax' | ||
| ; ONE-NEXT: [004] 14 {Line} | ||
| ; ONE-NEXT: [004] {Code} 'movl %eax, -0xc(%rbp)' | ||
| ; ONE-NEXT: [004] 15 {Line} | ||
| ; ONE-NEXT: [004] {Code} 'movl -0x8(%rbp), %eax' | ||
| ; ONE-NEXT: [004] {Code} 'addl $0x1, %eax' | ||
| ; ONE-NEXT: [004] {Code} 'movl %eax, -0x8(%rbp)' | ||
| ; ONE-NEXT: [004] 17 {Line} | ||
| ; ONE-NEXT: [004] {Code} 'movl -0x8(%rbp), %eax' | ||
| ; ONE-NEXT: [003] 10 {Line} | ||
| ; ONE-NEXT: [003] {Code} 'pushq %rbp' | ||
| ; ONE-NEXT: [003] {Code} 'movq %rsp, %rbp' | ||
| ; ONE-NEXT: [003] {Code} 'subq $0x10, %rsp' | ||
| ; ONE-NEXT: [003] {Code} 'movl %edi, -0x4(%rbp)' | ||
| ; ONE-NEXT: [003] 11 {Line} | ||
| ; ONE-NEXT: [003] {Code} 'movl -0x4(%rbp), %eax' | ||
| ; ONE-NEXT: [003] 11 {Line} | ||
| ; ONE-NEXT: [003] {Code} 'subl (%rip), %eax' | ||
| ; ONE-NEXT: [003] 11 {Line} | ||
| ; ONE-NEXT: [003] {Code} 'movl %eax, -0x8(%rbp)' | ||
| ; ONE-NEXT: [003] 17 {Line} | ||
| ; ONE-NEXT: [003] {Code} 'addq $0x10, %rsp' | ||
| ; ONE-NEXT: [003] {Code} 'popq %rbp' | ||
| ; ONE-NEXT: [003] {Code} 'retq' | ||
| ; ONE-NEXT: [002] 20 {Function} extern not_inlined 'main' -> 'int' | ||
| ; ONE-NEXT: [003] 20 {Line} | ||
| ; ONE-NEXT: [003] {Code} 'pushq %rbp' | ||
| ; ONE-NEXT: [003] {Code} 'movq %rsp, %rbp' | ||
| ; ONE-NEXT: [003] {Code} 'movl $0x0, -0x4(%rbp)' | ||
| ; ONE-NEXT: [003] 21 {Line} | ||
| ; ONE-NEXT: [003] {Code} 'xorl %eax, %eax' | ||
| ; ONE-NEXT: [003] {Code} 'popq %rbp' | ||
| ; ONE-NEXT: [003] {Code} 'retq' | ||
| ; ONE-NEXT: [003] 21 {Line} | ||
|
|
||
| ; RUN: llvm-debuginfo-analyzer --attribute=level \ | ||
| ; RUN: --print=instructions \ | ||
| ; RUN: %p/Inputs/pr-incorrect-instructions-dwarf-clang.o 2>&1 | \ | ||
| ; RUN: FileCheck --strict-whitespace -check-prefix=TWO %s | ||
|
|
||
| ; TWO: Logical View: | ||
| ; TWO-NEXT: [000] {File} 'pr-incorrect-instructions-dwarf-clang.o' | ||
| ; TWO-EMPTY: | ||
| ; TWO-NEXT: [001] {CompileUnit} 'pr-incorrect-instructions-dwarf-clang.cpp' | ||
| ; TWO-NEXT: [002] 2 {Function} extern not_inlined 'bar' -> 'int' | ||
| ; TWO-NEXT: [003] {Code} 'pushq %rbp' | ||
| ; TWO-NEXT: [003] {Code} 'movq %rsp, %rbp' | ||
| ; TWO-NEXT: [003] {Code} 'movl %edi, -0x4(%rbp)' | ||
| ; TWO-NEXT: [003] {Code} 'movl -0x4(%rbp), %eax' | ||
| ; TWO-NEXT: [003] {Code} 'imull $0xf423f, -0x4(%rbp), %ecx' | ||
| ; TWO-NEXT: [003] {Code} 'addl %ecx, %eax' | ||
| ; TWO-NEXT: [003] {Code} 'subl $0x42, %eax' | ||
| ; TWO-NEXT: [003] {Code} 'popq %rbp' | ||
| ; TWO-NEXT: [003] {Code} 'retq' | ||
| ; TWO-NEXT: [002] 6 {Function} extern not_inlined 'foo' -> 'int' | ||
| ; TWO-NEXT: [003] {Code} 'pushq %rbp' | ||
| ; TWO-NEXT: [003] {Code} 'movq %rsp, %rbp' | ||
| ; TWO-NEXT: [003] {Code} 'subq $0x10, %rsp' | ||
| ; TWO-NEXT: [003] {Code} 'movl %edi, -0x4(%rbp)' | ||
| ; TWO-NEXT: [003] {Code} 'movl -0x4(%rbp), %eax' | ||
| ; TWO-NEXT: [003] {Code} 'movl %eax, -0x8(%rbp)' | ||
| ; TWO-NEXT: [003] {Code} 'movl -0x4(%rbp), %edi' | ||
| ; TWO-NEXT: [003] {Code} 'callq 0x0' | ||
| ; TWO-NEXT: [003] {Code} 'cltd' | ||
| ; TWO-NEXT: [003] {Code} 'idivl -0x4(%rbp)' | ||
| ; TWO-NEXT: [003] {Code} 'movl %eax, %ecx' | ||
| ; TWO-NEXT: [003] {Code} 'movl -0x8(%rbp), %eax' | ||
| ; TWO-NEXT: [003] {Code} 'imull $0x42, %ecx, %ecx' | ||
| ; TWO-NEXT: [003] {Code} 'subl %ecx, %eax' | ||
| ; TWO-NEXT: [003] {Code} 'addl (%rip), %eax' | ||
| ; TWO-NEXT: [003] {Code} 'addq $0x10, %rsp' | ||
| ; TWO-NEXT: [003] {Code} 'popq %rbp' | ||
| ; TWO-NEXT: [003] {Code} 'retq' | ||
| ; TWO-NEXT: [003] {Code} 'data16' | ||
| ; TWO-NEXT: [002] 10 {Function} extern not_inlined 'test' -> 'int' | ||
| ; TWO-NEXT: [003] {Block} | ||
| ; TWO-NEXT: [004] {Code} 'movl $0x0, -0xc(%rbp)' | ||
| ; TWO-NEXT: [004] {Code} 'movl -0x4(%rbp), %eax' | ||
| ; TWO-NEXT: [004] {Code} 'movl %eax, -0x10(%rbp)' | ||
| ; TWO-NEXT: [004] {Code} 'movl -0x8(%rbp), %edi' | ||
| ; TWO-NEXT: [004] {Code} 'callq 0x0' | ||
| ; TWO-NEXT: [004] {Code} 'movl %eax, %ecx' | ||
| ; TWO-NEXT: [004] {Code} 'movl -0x10(%rbp), %eax' | ||
| ; TWO-NEXT: [004] {Code} 'addl %ecx, %eax' | ||
| ; TWO-NEXT: [004] {Code} 'movl %eax, -0xc(%rbp)' | ||
| ; TWO-NEXT: [004] {Code} 'movl -0x8(%rbp), %eax' | ||
| ; TWO-NEXT: [004] {Code} 'addl $0x1, %eax' | ||
| ; TWO-NEXT: [004] {Code} 'movl %eax, -0x8(%rbp)' | ||
| ; TWO-NEXT: [004] {Code} 'movl -0x8(%rbp), %eax' | ||
| ; TWO-NEXT: [003] {Code} 'pushq %rbp' | ||
| ; TWO-NEXT: [003] {Code} 'movq %rsp, %rbp' | ||
| ; TWO-NEXT: [003] {Code} 'subq $0x10, %rsp' | ||
| ; TWO-NEXT: [003] {Code} 'movl %edi, -0x4(%rbp)' | ||
| ; TWO-NEXT: [003] {Code} 'movl -0x4(%rbp), %eax' | ||
| ; TWO-NEXT: [003] {Code} 'subl (%rip), %eax' | ||
| ; TWO-NEXT: [003] {Code} 'movl %eax, -0x8(%rbp)' | ||
| ; TWO-NEXT: [003] {Code} 'addq $0x10, %rsp' | ||
| ; TWO-NEXT: [003] {Code} 'popq %rbp' | ||
| ; TWO-NEXT: [003] {Code} 'retq' | ||
| ; TWO-NEXT: [002] 20 {Function} extern not_inlined 'main' -> 'int' | ||
| ; TWO-NEXT: [003] {Code} 'pushq %rbp' | ||
| ; TWO-NEXT: [003] {Code} 'movq %rsp, %rbp' | ||
| ; TWO-NEXT: [003] {Code} 'movl $0x0, -0x4(%rbp)' | ||
| ; TWO-NEXT: [003] {Code} 'xorl %eax, %eax' | ||
| ; TWO-NEXT: [003] {Code} 'popq %rbp' | ||
| ; TWO-NEXT: [003] {Code} 'retq' |