
Update DWARFExpression::Operation and LVOperation to support more than 2 operands. Take the opportunity to use a SmallVector, which will handle at least 2 operands without allocation anyway, and removes the static limit completely. As there is no longer the concept of an "unused operand", remove Operation::Encoding::SizeNA. Any use of it is now replaced with explicit checks for how many operands an operation has. There are still places where the limit remains 2, namely in the DWARFLinker and in DIExpressions, but these can be updated in later patches as-needed. There are no explicit tests as this is nearly NFC: no new operation is added which makes use of the additional operand capacity yet. A future patch adding a new DWARF extension point will include operations which require the support. Reviewed By: Orlando, CarlosAlbertoEnciso Differential Revision: https://reviews.llvm.org/D147270
675 lines
21 KiB
C++
675 lines
21 KiB
C++
//===-- 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].
|
|
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].
|
|
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].
|
|
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,
|
|
ArrayRef<LVUnsigned> Operands) {
|
|
if (!Entries)
|
|
Entries = std::make_unique<LVOperations>();
|
|
Entries->push_back(getReader().createOperation(Opcode, Operands));
|
|
}
|
|
|
|
// 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) {
|
|
if (dwarf::DW_OP_fbreg == Entries->front()->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);
|
|
}
|
|
}
|