diff options
Diffstat (limited to 'llvm/lib/DebugInfo/LogicalView/Core/LVLocation.cpp')
-rw-r--r-- | llvm/lib/DebugInfo/LogicalView/Core/LVLocation.cpp | 675 |
1 files changed, 675 insertions, 0 deletions
diff --git a/llvm/lib/DebugInfo/LogicalView/Core/LVLocation.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVLocation.cpp new file mode 100644 index 000000000000..115b903c6c7f --- /dev/null +++ b/llvm/lib/DebugInfo/LogicalView/Core/LVLocation.cpp @@ -0,0 +1,675 @@ +//===-- LVLocation.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 implements the LVOperation and LVLocation classes. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/LogicalView/Core/LVLocation.h" +#include "llvm/DebugInfo/LogicalView/Core/LVReader.h" +#include "llvm/DebugInfo/LogicalView/Core/LVScope.h" +#include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h" + +using namespace llvm; +using namespace llvm::logicalview; + +#define DEBUG_TYPE "Location" + +void LVOperation::print(raw_ostream &OS, bool Full) const {} + +// Identify the most common type of operations and print them using a high +// level format, trying to isolate the DWARF complexity. +std::string LVOperation::getOperandsDWARFInfo() { + std::string String; + raw_string_ostream Stream(String); + + auto PrintRegisterInfo = [&](LVSmall Code) { + //----------------------------------------------------------------------- + // 2.5.1.1 Literal encodings. + //----------------------------------------------------------------------- + if (dwarf::DW_OP_lit0 <= Code && Code <= dwarf::DW_OP_lit31) { + Stream << format("lit%d", Code - dwarf::DW_OP_lit0); + return; + } + + //----------------------------------------------------------------------- + // 2.5.1.2 Register values. + //----------------------------------------------------------------------- + if (dwarf::DW_OP_breg0 <= Code && Code <= dwarf::DW_OP_breg31) { + std::string RegisterName(getReader().getRegisterName(Code, Operands)); + Stream << format("breg%d+%d%s", Code - dwarf::DW_OP_breg0, Operands[0], + RegisterName.c_str()); + return; + } + + //----------------------------------------------------------------------- + // 2.6.1.1.3 Register location descriptions. + //----------------------------------------------------------------------- + if (dwarf::DW_OP_reg0 <= Code && Code <= dwarf::DW_OP_reg31) { + std::string RegisterName(getReader().getRegisterName(Code, Operands)); + Stream << format("reg%d%s", Code - dwarf::DW_OP_reg0, + RegisterName.c_str()); + return; + } + + Stream << format("#0x%02x ", Code) << hexString(Operands[0]) << " " + << hexString(Operands[1]) << "#"; + }; + + switch (Opcode) { + //------------------------------------------------------------------------- + // 2.5.1.1 Literal encodings. + //------------------------------------------------------------------------- + case dwarf::DW_OP_addr: + Stream << "addr " << hexString(Operands[0]); + break; + case dwarf::DW_OP_constu: + case dwarf::DW_OP_const1u: + case dwarf::DW_OP_const2u: + case dwarf::DW_OP_const4u: + case dwarf::DW_OP_const8u: + Stream << "const_u " << unsigned(Operands[0]); + break; + case dwarf::DW_OP_consts: + case dwarf::DW_OP_const1s: + case dwarf::DW_OP_const2s: + case dwarf::DW_OP_const4s: + case dwarf::DW_OP_const8s: + Stream << "const_s " << int(Operands[0]); + break; + case dwarf::DW_OP_addrx: + Stream << "addrx " << unsigned(Operands[0]); + break; + case dwarf::DW_OP_constx: + Stream << "constx " << unsigned(Operands[0]); + break; + case dwarf::DW_OP_const_type: + Stream << "TODO: DW_OP_const_type"; + break; + + //------------------------------------------------------------------------- + // 2.5.1.2 Register values. + //------------------------------------------------------------------------- + case dwarf::DW_OP_fbreg: + Stream << "fbreg " << int(Operands[0]); + break; + case dwarf::DW_OP_bregx: { + std::string RegisterName(getReader().getRegisterName(Opcode, Operands)); + Stream << format("bregx %d%s+%d", Operands[0], RegisterName.c_str(), + unsigned(Operands[1])); + break; + } + case dwarf::DW_OP_regval_type: { + std::string RegisterName(getReader().getRegisterName(Opcode, Operands)); + Stream << format("regval_type %d%s+%d", Operands[0], RegisterName.c_str(), + unsigned(Operands[1])); + break; + } + + //------------------------------------------------------------------------- + // 2.5.1.3 Stack operations. + //------------------------------------------------------------------------- + case dwarf::DW_OP_dup: + Stream << "dup"; + break; + case dwarf::DW_OP_drop: + Stream << "drop"; + break; + case dwarf::DW_OP_pick: + Stream << "pick " << unsigned(Operands[0]); + break; + case dwarf::DW_OP_over: + Stream << "over"; + break; + case dwarf::DW_OP_swap: + Stream << "swap"; + break; + case dwarf::DW_OP_rot: + Stream << "rot"; + break; + case dwarf::DW_OP_deref: + Stream << "deref"; + break; + case dwarf::DW_OP_deref_size: + Stream << "deref_size " << unsigned(Operands[0]); + break; + case dwarf::DW_OP_deref_type: + Stream << "deref_type " << unsigned(Operands[0]) << " DIE offset " + << hexString(Operands[1]); + break; + case dwarf::DW_OP_xderef: + Stream << "xderef"; + break; + case dwarf::DW_OP_xderef_size: + Stream << "xderef_size " << unsigned(Operands[0]); + break; + case dwarf::DW_OP_xderef_type: + Stream << "xderef_type " << unsigned(Operands[0]) << " DIE offset " + << hexString(Operands[1]); + break; + case dwarf::DW_OP_push_object_address: + Stream << "push_object_address"; + break; + case dwarf::DW_OP_form_tls_address: + Stream << "form_tls_address " << hexString(Operands[0]); + break; + case dwarf::DW_OP_call_frame_cfa: + Stream << "call_frame_cfa"; + break; + + //------------------------------------------------------------------------- + // 2.5.1.4 Arithmetic and Logical Operations. + //------------------------------------------------------------------------- + case dwarf::DW_OP_abs: + Stream << "abs"; + break; + case dwarf::DW_OP_and: + Stream << "and"; + break; + case dwarf::DW_OP_div: + Stream << "div"; + break; + case dwarf::DW_OP_minus: + Stream << "minus"; + break; + case dwarf::DW_OP_mod: + Stream << "mod"; + break; + case dwarf::DW_OP_mul: + Stream << "mul"; + break; + case dwarf::DW_OP_neg: + Stream << "neg"; + break; + case dwarf::DW_OP_not: + Stream << "not"; + break; + case dwarf::DW_OP_or: + Stream << "or"; + break; + case dwarf::DW_OP_plus: + Stream << "plus"; + break; + case dwarf::DW_OP_plus_uconst: + Stream << "plus_uconst " << unsigned(Operands[0]); + break; + case dwarf::DW_OP_shl: + Stream << "shl"; + break; + case dwarf::DW_OP_shr: + Stream << "shr"; + break; + case dwarf::DW_OP_shra: + Stream << "shra"; + break; + case dwarf::DW_OP_xor: + Stream << "xor"; + break; + + //------------------------------------------------------------------------- + // 2.5.1.5 Control Flow Operations. + //------------------------------------------------------------------------- + case dwarf::DW_OP_le: + Stream << "le"; + break; + case dwarf::DW_OP_ge: + Stream << "ge"; + break; + case dwarf::DW_OP_eq: + Stream << "eq"; + break; + case dwarf::DW_OP_lt: + Stream << "lt"; + break; + case dwarf::DW_OP_gt: + Stream << "gt"; + break; + case dwarf::DW_OP_ne: + Stream << "ne"; + break; + case dwarf::DW_OP_skip: + Stream << "skip " << signed(Operands[0]); + break; + case dwarf::DW_OP_bra: + Stream << "bra " << signed(Operands[0]); + break; + case dwarf::DW_OP_call2: + Stream << "call2 DIE offset " << hexString(Operands[0]); + break; + case dwarf::DW_OP_call4: + Stream << "call4 DIE offset " << hexString(Operands[0]); + break; + case dwarf::DW_OP_call_ref: + Stream << "call_ref DIE offset " << hexString(Operands[0]); + break; + + //------------------------------------------------------------------------- + // 2.5.1.6 Type Conversions. + //------------------------------------------------------------------------- + case dwarf::DW_OP_convert: + Stream << "convert DIE offset " << hexString(Operands[0]); + break; + case dwarf::DW_OP_reinterpret: + Stream << "reinterpret DIE offset " << hexString(Operands[0]); + break; + + //------------------------------------------------------------------------- + // 2.5.1.7 Special Operations. + //------------------------------------------------------------------------- + case dwarf::DW_OP_nop: + Stream << "nop"; + break; + case dwarf::DW_OP_entry_value: + Stream << "TODO: DW_OP_entry_value"; + break; + + //------------------------------------------------------------------------- + // 2.6.1.1.3 Register location descriptions. + //------------------------------------------------------------------------- + case dwarf::DW_OP_regx: + Stream << "regx" << getReader().getRegisterName(Opcode, Operands); + break; + + //------------------------------------------------------------------------- + // 2.6.1.1.4 Implicit location descriptions. + //------------------------------------------------------------------------- + case dwarf::DW_OP_stack_value: + Stream << "stack_value"; + break; + case dwarf::DW_OP_implicit_value: + Stream << "TODO: DW_OP_implicit_value"; + break; + case dwarf::DW_OP_implicit_pointer: + Stream << "implicit_pointer DIE offset " << hexString(Operands[0]) << " " + << int(Operands[1]); + break; + + //------------------------------------------------------------------------- + // 2.6.1.2 Composite location descriptions. + //------------------------------------------------------------------------- + case dwarf::DW_OP_piece: + Stream << "piece " << int(Operands[0]); + break; + case dwarf::DW_OP_bit_piece: + Stream << "bit_piece " << int(Operands[0]) << " offset " + << int(Operands[1]); + break; + + //------------------------------------------------------------------------- + // GNU extensions. + //------------------------------------------------------------------------- + case dwarf::DW_OP_GNU_entry_value: + Stream << "gnu_entry_value "; + PrintRegisterInfo(dwarf::DW_OP_reg0); + break; + case dwarf::DW_OP_GNU_push_tls_address: + Stream << "gnu_push_tls_address " << hexString(Operands[0]); + break; + case dwarf::DW_OP_GNU_addr_index: + Stream << "gnu_addr_index " << unsigned(Operands[0]); + break; + case dwarf::DW_OP_GNU_const_index: + Stream << "gnu_const_index " << unsigned(Operands[0]); + break; + + //------------------------------------------------------------------------- + // Member location. + //------------------------------------------------------------------------- + case LVLocationMemberOffset: + Stream << "offset " << int(Operands[0]); + break; + + //------------------------------------------------------------------------- + // Missing location. + //------------------------------------------------------------------------- + case dwarf::DW_OP_hi_user: + Stream << "missing"; + break; + + //------------------------------------------------------------------------- + // Register values. + //------------------------------------------------------------------------- + default: + PrintRegisterInfo(Opcode); + break; + } + + return String; +} + +// Identify the most common type of operations and print them using a high +// level format, trying to isolate the CodeView complexity. +std::string LVOperation::getOperandsCodeViewInfo() { + std::string String; + raw_string_ostream Stream(String); + + // Get original CodeView operation code. + uint16_t OperationCode = getCodeViewOperationCode(Opcode); + + switch (OperationCode) { + // Operands: [Offset, 0]. + case codeview::SymbolKind::S_DEFRANGE_FRAMEPOINTER_REL: + Stream << "frame_pointer_rel " << int(Operands[0]); + break; + case codeview::SymbolKind::S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE: + Stream << "frame_pointer_rel_full_scope " << int(Operands[0]); + break; + + // Operands: [Register, 0]. + case codeview::SymbolKind::S_DEFRANGE_REGISTER: + Stream << "register " << getReader().getRegisterName(Opcode, Operands); + break; + case codeview::SymbolKind::S_DEFRANGE_SUBFIELD_REGISTER: + Stream << "subfield_register " + << getReader().getRegisterName(Opcode, Operands); + break; + + // Operands: [Register, Offset]. + case codeview::SymbolKind::S_DEFRANGE_REGISTER_REL: + Stream << "register_rel " << getReader().getRegisterName(Opcode, Operands) + << " offset " << int(Operands[1]); + break; + + // Operands: [Program, 0]. + case codeview::SymbolKind::S_DEFRANGE: + Stream << "frame " << int(Operands[0]); + break; + case codeview::SymbolKind::S_DEFRANGE_SUBFIELD: + Stream << "subfield " << int(Operands[0]); + break; + + default: + Stream << format("#0x%02x: ", Opcode) << hexString(Operands[0]) << " " + << hexString(Operands[1]) << "#"; + break; + } + + return String; +} + +namespace { +const char *const KindBaseClassOffset = "BaseClassOffset"; +const char *const KindBaseClassStep = "BaseClassStep"; +const char *const KindClassOffset = "ClassOffset"; +const char *const KindFixedAddress = "FixedAddress"; +const char *const KindMissingInfo = "Missing"; +const char *const KindOperation = "Operation"; +const char *const KindOperationList = "OperationList"; +const char *const KindRegister = "Register"; +const char *const KindUndefined = "Undefined"; +} // end anonymous namespace + +//===----------------------------------------------------------------------===// +// DWARF location information. +//===----------------------------------------------------------------------===// +const char *LVLocation::kind() const { + const char *Kind = KindUndefined; + if (getIsBaseClassOffset()) + Kind = KindBaseClassOffset; + else if (getIsBaseClassStep()) + Kind = KindBaseClassStep; + else if (getIsClassOffset()) + Kind = KindClassOffset; + else if (getIsFixedAddress()) + Kind = KindFixedAddress; + else if (getIsGapEntry()) + Kind = KindMissingInfo; + else if (getIsOperation()) + Kind = KindOperation; + else if (getIsOperationList()) + Kind = KindOperationList; + else if (getIsRegister()) + Kind = KindRegister; + return Kind; +} + +std::string LVLocation::getIntervalInfo() const { + static const char *const Question = "?"; + std::string String; + raw_string_ostream Stream(String); + if (getIsAddressRange()) + Stream << "{Range}"; + + auto PrintLine = [&](const LVLine *Line) { + if (Line) { + std::string TheLine; + TheLine = Line->lineNumberAsStringStripped(); + Stream << TheLine.c_str(); + } else { + Stream << Question; + } + }; + + Stream << " Lines "; + PrintLine(getLowerLine()); + Stream << ":"; + PrintLine(getUpperLine()); + + if (options().getAttributeOffset()) + // Print the active range (low pc and high pc). + Stream << " [" << hexString(getLowerAddress()) << ":" + << hexString(getUpperAddress()) << "]"; + + return String; +} + +// Validate the ranges associated with the location. +bool LVLocation::validateRanges() { + // Traverse the locations and validate them against the address to line + // mapping in the current compile unit. Record those invalid ranges. + // A valid range must meet the following conditions: + // a) line(lopc) <= line(hipc) + // b) line(lopc) and line(hipc) are valid. + + if (!hasAssociatedRange()) + return true; + + LVLineRange Range = getReaderCompileUnit()->lineRange(this); + LVLine *LowLine = Range.first; + LVLine *HighLine = Range.second; + if (LowLine) + setLowerLine(LowLine); + else { + setIsInvalidLower(); + return false; + } + if (HighLine) + setUpperLine(HighLine); + else { + setIsInvalidUpper(); + return false; + } + // Check for a valid interval. + if (LowLine->getLineNumber() > HighLine->getLineNumber()) { + setIsInvalidRange(); + return false; + } + + return true; +} + +bool LVLocation::calculateCoverage(LVLocations *Locations, unsigned &Factor, + float &Percentage) { + if (!options().getAttributeCoverage() && !Locations) + return false; + + // Calculate the coverage depending on the kind of location. We have + // the simple and composed locations. + if (Locations->size() == 1) { + // Simple: fixed address, class offset, stack offset. + LVLocation *Location = Locations->front(); + // Some types of locations do not have specific kind. Now is the time + // to set those types, depending on the operation type. + Location->updateKind(); + if (Location->getIsLocationSimple()) { + Factor = 100; + Percentage = 100; + return true; + } + } + + // Composed locations. + LVAddress LowerAddress = 0; + LVAddress UpperAddress = 0; + for (const LVLocation *Location : *Locations) + // Do not include locations representing a gap. + if (!Location->getIsGapEntry()) { + LowerAddress = Location->getLowerAddress(); + UpperAddress = Location->getUpperAddress(); + Factor += (UpperAddress > LowerAddress) ? UpperAddress - LowerAddress + : LowerAddress - UpperAddress; + } + + Percentage = 0; + return false; +} + +void LVLocation::printRaw(raw_ostream &OS, bool Full) const { + // Print the active range (low pc and high pc). + OS << " [" << hexString(getLowerAddress()) << ":" + << hexString(getUpperAddress()) << "]\n"; + // Print any DWARF operations. + printRawExtra(OS, Full); +} + +void LVLocation::printInterval(raw_ostream &OS, bool Full) const { + if (hasAssociatedRange()) + OS << getIntervalInfo(); +} + +void LVLocation::print(raw_ostream &OS, bool Full) const { + if (getReader().doPrintLocation(this)) { + LVObject::print(OS, Full); + printExtra(OS, Full); + } +} + +void LVLocation::printExtra(raw_ostream &OS, bool Full) const { + printInterval(OS, Full); + OS << "\n"; +} + +//===----------------------------------------------------------------------===// +// DWARF location for a symbol. +//===----------------------------------------------------------------------===// +// Add a Location Entry. +void LVLocationSymbol::addObject(LVAddress LowPC, LVAddress HighPC, + LVUnsigned SectionOffset, + uint64_t LocDescOffset) { + setLowerAddress(LowPC); + setUpperAddress(HighPC); + + // Record the offset where the location information begins. + setOffset(LocDescOffset ? LocDescOffset : SectionOffset); + + // A -1 HighPC value, indicates no range. + if (HighPC == LVAddress(UINT64_MAX)) + setIsDiscardedRange(); + + // Update the location kind, using the DWARF attribute. + setKind(); +} + +// Add a Location Record. +void LVLocationSymbol::addObject(LVSmall Opcode, LVUnsigned Operand1, + LVUnsigned Operand2) { + if (!Entries) + Entries = new LVAutoOperations(); + Entries->emplace_back(new LVOperation(Opcode, Operand1, Operand2)); +} + +// Based on the DWARF attribute, define the location kind. +void LVLocation::setKind() { + switch (getAttr()) { + case dwarf::DW_AT_data_member_location: + setIsClassOffset(); + break; + case dwarf::DW_AT_location: + // Depending on the operand, we have a fixed address. + setIsFixedAddress(); + break; + default: + break; + } + // For those symbols with absolute location information, ignore any + // gaps in their location description; that is the case with absolute + // memory addresses and members located at specific offsets. + if (hasAssociatedRange()) + getParentSymbol()->setFillGaps(); +} + +void LVLocationSymbol::updateKind() { + // Update the location type for simple ones. + if (Entries && Entries->size() == 1) { + LVOperation *Operation = Entries->front(); + if (dwarf::DW_OP_fbreg == Operation->getOpcode()) + setIsStackOffset(); + } +} + +void LVLocationSymbol::printRawExtra(raw_ostream &OS, bool Full) const { + if (Entries) + for (const LVOperation *Operation : *Entries) + Operation->print(OS, Full); +} + +// Print location (formatted version). +void LVLocation::print(LVLocations *Locations, raw_ostream &OS, bool Full) { + if (!Locations || Locations->empty()) + return; + + // Print the symbol coverage. + if (options().getAttributeCoverage()) { + // The location entries are contained within a symbol. Get a location, + // to access basic information about indentation, parent, etc. + LVLocation *Location = Locations->front(); + LVSymbol *Symbol = Location->getParentSymbol(); + float Percentage = Symbol->getCoveragePercentage(); + + // The coverage is dependent on the kind of location. + std::string String; + raw_string_ostream Stream(String); + Stream << format("%.2f%%", Percentage); + if (!Location->getIsLocationSimple()) + Stream << format(" (%d/%d)", Symbol->getCoverageFactor(), + Symbol->getParentScope()->getCoverageFactor()); + Symbol->printAttributes(OS, Full, "{Coverage} ", Symbol, StringRef(String), + /*UseQuotes=*/false, + /*PrintRef=*/false); + } + + // Print the symbol location, including the missing entries. + if (getReader().doPrintLocation(/*Location=*/nullptr)) + for (const LVLocation *Location : *Locations) + Location->print(OS, Full); +} + +void LVLocationSymbol::printExtra(raw_ostream &OS, bool Full) const { + OS << "{Location}"; + if (getIsCallSite()) + OS << " -> CallSite"; + printInterval(OS, Full); + OS << "\n"; + + // Print location entries. + if (Full && Entries) { + bool CodeViewLocation = getParentSymbol()->getHasCodeViewLocation(); + std::stringstream Stream; + std::string Leading = ""; + for (LVOperation *Operation : *Entries) { + Stream << Leading + << (CodeViewLocation ? Operation->getOperandsCodeViewInfo() + : Operation->getOperandsDWARFInfo()); + Leading = ", "; + } + printAttributes(OS, Full, "{Entry} ", const_cast<LVLocationSymbol *>(this), + StringRef(Stream.str()), + /*UseQuotes=*/false, + /*PrintRef=*/false); + } +} |