675 lines · cpp
1//===-- LVLocation.cpp ----------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This implements the LVOperation and LVLocation classes.10//11//===----------------------------------------------------------------------===//12 13#include "llvm/DebugInfo/LogicalView/Core/LVLocation.h"14#include "llvm/DebugInfo/LogicalView/Core/LVReader.h"15#include "llvm/DebugInfo/LogicalView/Core/LVScope.h"16#include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h"17 18using namespace llvm;19using namespace llvm::logicalview;20 21#define DEBUG_TYPE "Location"22 23void LVOperation::print(raw_ostream &OS, bool Full) const {}24 25// Identify the most common type of operations and print them using a high26// level format, trying to isolate the DWARF complexity.27std::string LVOperation::getOperandsDWARFInfo() {28 std::string String;29 raw_string_ostream Stream(String);30 31 auto PrintRegisterInfo = [&](LVSmall Code) {32 //-----------------------------------------------------------------------33 // 2.5.1.1 Literal encodings.34 //-----------------------------------------------------------------------35 if (dwarf::DW_OP_lit0 <= Code && Code <= dwarf::DW_OP_lit31) {36 Stream << format("lit%d", Code - dwarf::DW_OP_lit0);37 return;38 }39 40 //-----------------------------------------------------------------------41 // 2.5.1.2 Register values.42 //-----------------------------------------------------------------------43 if (dwarf::DW_OP_breg0 <= Code && Code <= dwarf::DW_OP_breg31) {44 std::string RegisterName(getReader().getRegisterName(Code, Operands));45 Stream << format("breg%d+%d%s", Code - dwarf::DW_OP_breg0, Operands[0],46 RegisterName.c_str());47 return;48 }49 50 //-----------------------------------------------------------------------51 // 2.6.1.1.3 Register location descriptions.52 //-----------------------------------------------------------------------53 if (dwarf::DW_OP_reg0 <= Code && Code <= dwarf::DW_OP_reg31) {54 std::string RegisterName(getReader().getRegisterName(Code, Operands));55 Stream << format("reg%d%s", Code - dwarf::DW_OP_reg0,56 RegisterName.c_str());57 return;58 }59 60 Stream << format("#0x%02x ", Code) << hexString(Operands[0]) << " "61 << hexString(Operands[1]) << "#";62 };63 64 switch (Opcode) {65 //-------------------------------------------------------------------------66 // 2.5.1.1 Literal encodings.67 //-------------------------------------------------------------------------68 case dwarf::DW_OP_addr:69 Stream << "addr " << hexString(Operands[0]);70 break;71 case dwarf::DW_OP_constu:72 case dwarf::DW_OP_const1u:73 case dwarf::DW_OP_const2u:74 case dwarf::DW_OP_const4u:75 case dwarf::DW_OP_const8u:76 Stream << "const_u " << unsigned(Operands[0]);77 break;78 case dwarf::DW_OP_consts:79 case dwarf::DW_OP_const1s:80 case dwarf::DW_OP_const2s:81 case dwarf::DW_OP_const4s:82 case dwarf::DW_OP_const8s:83 Stream << "const_s " << int(Operands[0]);84 break;85 case dwarf::DW_OP_addrx:86 Stream << "addrx " << unsigned(Operands[0]);87 break;88 case dwarf::DW_OP_constx:89 Stream << "constx " << unsigned(Operands[0]);90 break;91 case dwarf::DW_OP_const_type:92 Stream << "TODO: DW_OP_const_type";93 break;94 95 //-------------------------------------------------------------------------96 // 2.5.1.2 Register values.97 //-------------------------------------------------------------------------98 case dwarf::DW_OP_fbreg:99 Stream << "fbreg " << int(Operands[0]);100 break;101 case dwarf::DW_OP_bregx: {102 std::string RegisterName(getReader().getRegisterName(Opcode, Operands));103 Stream << format("bregx %d%s+%d", Operands[0], RegisterName.c_str(),104 unsigned(Operands[1]));105 break;106 }107 case dwarf::DW_OP_regval_type: {108 std::string RegisterName(getReader().getRegisterName(Opcode, Operands));109 Stream << format("regval_type %d%s+%d", Operands[0], RegisterName.c_str(),110 unsigned(Operands[1]));111 break;112 }113 114 //-------------------------------------------------------------------------115 // 2.5.1.3 Stack operations.116 //-------------------------------------------------------------------------117 case dwarf::DW_OP_dup:118 Stream << "dup";119 break;120 case dwarf::DW_OP_drop:121 Stream << "drop";122 break;123 case dwarf::DW_OP_pick:124 Stream << "pick " << unsigned(Operands[0]);125 break;126 case dwarf::DW_OP_over:127 Stream << "over";128 break;129 case dwarf::DW_OP_swap:130 Stream << "swap";131 break;132 case dwarf::DW_OP_rot:133 Stream << "rot";134 break;135 case dwarf::DW_OP_deref:136 Stream << "deref";137 break;138 case dwarf::DW_OP_deref_size:139 Stream << "deref_size " << unsigned(Operands[0]);140 break;141 case dwarf::DW_OP_deref_type:142 Stream << "deref_type " << unsigned(Operands[0]) << " DIE offset "143 << hexString(Operands[1]);144 break;145 case dwarf::DW_OP_xderef:146 Stream << "xderef";147 break;148 case dwarf::DW_OP_xderef_size:149 Stream << "xderef_size " << unsigned(Operands[0]);150 break;151 case dwarf::DW_OP_xderef_type:152 Stream << "xderef_type " << unsigned(Operands[0]) << " DIE offset "153 << hexString(Operands[1]);154 break;155 case dwarf::DW_OP_push_object_address:156 Stream << "push_object_address";157 break;158 case dwarf::DW_OP_form_tls_address:159 Stream << "form_tls_address";160 break;161 case dwarf::DW_OP_call_frame_cfa:162 Stream << "call_frame_cfa";163 break;164 165 //-------------------------------------------------------------------------166 // 2.5.1.4 Arithmetic and Logical Operations.167 //-------------------------------------------------------------------------168 case dwarf::DW_OP_abs:169 Stream << "abs";170 break;171 case dwarf::DW_OP_and:172 Stream << "and";173 break;174 case dwarf::DW_OP_div:175 Stream << "div";176 break;177 case dwarf::DW_OP_minus:178 Stream << "minus";179 break;180 case dwarf::DW_OP_mod:181 Stream << "mod";182 break;183 case dwarf::DW_OP_mul:184 Stream << "mul";185 break;186 case dwarf::DW_OP_neg:187 Stream << "neg";188 break;189 case dwarf::DW_OP_not:190 Stream << "not";191 break;192 case dwarf::DW_OP_or:193 Stream << "or";194 break;195 case dwarf::DW_OP_plus:196 Stream << "plus";197 break;198 case dwarf::DW_OP_plus_uconst:199 Stream << "plus_uconst " << unsigned(Operands[0]);200 break;201 case dwarf::DW_OP_shl:202 Stream << "shl";203 break;204 case dwarf::DW_OP_shr:205 Stream << "shr";206 break;207 case dwarf::DW_OP_shra:208 Stream << "shra";209 break;210 case dwarf::DW_OP_xor:211 Stream << "xor";212 break;213 214 //-------------------------------------------------------------------------215 // 2.5.1.5 Control Flow Operations.216 //-------------------------------------------------------------------------217 case dwarf::DW_OP_le:218 Stream << "le";219 break;220 case dwarf::DW_OP_ge:221 Stream << "ge";222 break;223 case dwarf::DW_OP_eq:224 Stream << "eq";225 break;226 case dwarf::DW_OP_lt:227 Stream << "lt";228 break;229 case dwarf::DW_OP_gt:230 Stream << "gt";231 break;232 case dwarf::DW_OP_ne:233 Stream << "ne";234 break;235 case dwarf::DW_OP_skip:236 Stream << "skip " << signed(Operands[0]);237 break;238 case dwarf::DW_OP_bra:239 Stream << "bra " << signed(Operands[0]);240 break;241 case dwarf::DW_OP_call2:242 Stream << "call2 DIE offset " << hexString(Operands[0]);243 break;244 case dwarf::DW_OP_call4:245 Stream << "call4 DIE offset " << hexString(Operands[0]);246 break;247 case dwarf::DW_OP_call_ref:248 Stream << "call_ref DIE offset " << hexString(Operands[0]);249 break;250 251 //-------------------------------------------------------------------------252 // 2.5.1.6 Type Conversions.253 //-------------------------------------------------------------------------254 case dwarf::DW_OP_convert:255 Stream << "convert DIE offset " << hexString(Operands[0]);256 break;257 case dwarf::DW_OP_reinterpret:258 Stream << "reinterpret DIE offset " << hexString(Operands[0]);259 break;260 261 //-------------------------------------------------------------------------262 // 2.5.1.7 Special Operations.263 //-------------------------------------------------------------------------264 case dwarf::DW_OP_nop:265 Stream << "nop";266 break;267 case dwarf::DW_OP_entry_value:268 Stream << "TODO: DW_OP_entry_value";269 break;270 271 //-------------------------------------------------------------------------272 // 2.6.1.1.3 Register location descriptions.273 //-------------------------------------------------------------------------274 case dwarf::DW_OP_regx:275 Stream << "regx" << getReader().getRegisterName(Opcode, Operands);276 break;277 278 //-------------------------------------------------------------------------279 // 2.6.1.1.4 Implicit location descriptions.280 //-------------------------------------------------------------------------281 case dwarf::DW_OP_stack_value:282 Stream << "stack_value";283 break;284 case dwarf::DW_OP_implicit_value:285 Stream << "TODO: DW_OP_implicit_value";286 break;287 case dwarf::DW_OP_implicit_pointer:288 Stream << "implicit_pointer DIE offset " << hexString(Operands[0]) << " "289 << int(Operands[1]);290 break;291 292 //-------------------------------------------------------------------------293 // 2.6.1.2 Composite location descriptions.294 //-------------------------------------------------------------------------295 case dwarf::DW_OP_piece:296 Stream << "piece " << int(Operands[0]);297 break;298 case dwarf::DW_OP_bit_piece:299 Stream << "bit_piece " << int(Operands[0]) << " offset "300 << int(Operands[1]);301 break;302 303 //-------------------------------------------------------------------------304 // GNU extensions.305 //-------------------------------------------------------------------------306 case dwarf::DW_OP_GNU_entry_value:307 Stream << "gnu_entry_value ";308 PrintRegisterInfo(dwarf::DW_OP_reg0);309 break;310 case dwarf::DW_OP_GNU_push_tls_address:311 Stream << "gnu_push_tls_address";312 break;313 case dwarf::DW_OP_GNU_addr_index:314 Stream << "gnu_addr_index " << unsigned(Operands[0]);315 break;316 case dwarf::DW_OP_GNU_const_index:317 Stream << "gnu_const_index " << unsigned(Operands[0]);318 break;319 320 //-------------------------------------------------------------------------321 // Member location.322 //-------------------------------------------------------------------------323 case LVLocationMemberOffset:324 Stream << "offset " << int(Operands[0]);325 break;326 327 //-------------------------------------------------------------------------328 // Missing location.329 //-------------------------------------------------------------------------330 case dwarf::DW_OP_hi_user:331 Stream << "missing";332 break;333 334 //-------------------------------------------------------------------------335 // Register values.336 //-------------------------------------------------------------------------337 default:338 PrintRegisterInfo(Opcode);339 break;340 }341 342 return String;343}344 345// Identify the most common type of operations and print them using a high346// level format, trying to isolate the CodeView complexity.347std::string LVOperation::getOperandsCodeViewInfo() {348 std::string String;349 raw_string_ostream Stream(String);350 351 // Get original CodeView operation code.352 uint16_t OperationCode = getCodeViewOperationCode(Opcode);353 354 switch (OperationCode) {355 // Operands: [Offset].356 case codeview::SymbolKind::S_DEFRANGE_FRAMEPOINTER_REL:357 Stream << "frame_pointer_rel " << int(Operands[0]);358 break;359 case codeview::SymbolKind::S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE:360 Stream << "frame_pointer_rel_full_scope " << int(Operands[0]);361 break;362 363 // Operands: [Register].364 case codeview::SymbolKind::S_DEFRANGE_REGISTER:365 Stream << "register " << getReader().getRegisterName(Opcode, Operands);366 break;367 case codeview::SymbolKind::S_DEFRANGE_SUBFIELD_REGISTER:368 Stream << "subfield_register "369 << getReader().getRegisterName(Opcode, Operands);370 break;371 372 // Operands: [Register, Offset].373 case codeview::SymbolKind::S_DEFRANGE_REGISTER_REL:374 Stream << "register_rel " << getReader().getRegisterName(Opcode, Operands)375 << " offset " << int(Operands[1]);376 break;377 378 // Operands: [Program].379 case codeview::SymbolKind::S_DEFRANGE:380 Stream << "frame " << int(Operands[0]);381 break;382 case codeview::SymbolKind::S_DEFRANGE_SUBFIELD:383 Stream << "subfield " << int(Operands[0]);384 break;385 386 default:387 Stream << format("#0x%02x: ", Opcode) << hexString(Operands[0]) << " "388 << hexString(Operands[1]) << "#";389 break;390 }391 392 return String;393}394 395namespace {396const char *const KindBaseClassOffset = "BaseClassOffset";397const char *const KindBaseClassStep = "BaseClassStep";398const char *const KindClassOffset = "ClassOffset";399const char *const KindFixedAddress = "FixedAddress";400const char *const KindMissingInfo = "Missing";401const char *const KindOperation = "Operation";402const char *const KindOperationList = "OperationList";403const char *const KindRegister = "Register";404const char *const KindUndefined = "Undefined";405} // end anonymous namespace406 407//===----------------------------------------------------------------------===//408// DWARF location information.409//===----------------------------------------------------------------------===//410const char *LVLocation::kind() const {411 const char *Kind = KindUndefined;412 if (getIsBaseClassOffset())413 Kind = KindBaseClassOffset;414 else if (getIsBaseClassStep())415 Kind = KindBaseClassStep;416 else if (getIsClassOffset())417 Kind = KindClassOffset;418 else if (getIsFixedAddress())419 Kind = KindFixedAddress;420 else if (getIsGapEntry())421 Kind = KindMissingInfo;422 else if (getIsOperation())423 Kind = KindOperation;424 else if (getIsOperationList())425 Kind = KindOperationList;426 else if (getIsRegister())427 Kind = KindRegister;428 return Kind;429}430 431std::string LVLocation::getIntervalInfo() const {432 static const char *const Question = "?";433 std::string String;434 raw_string_ostream Stream(String);435 if (getIsAddressRange())436 Stream << "{Range}";437 438 auto PrintLine = [&](const LVLine *Line) {439 if (Line) {440 std::string TheLine;441 TheLine = Line->lineNumberAsStringStripped();442 Stream << TheLine.c_str();443 } else {444 Stream << Question;445 }446 };447 448 Stream << " Lines ";449 PrintLine(getLowerLine());450 Stream << ":";451 PrintLine(getUpperLine());452 453 if (options().getAttributeOffset())454 // Print the active range (low pc and high pc).455 Stream << " [" << hexString(getLowerAddress()) << ":"456 << hexString(getUpperAddress()) << "]";457 458 return String;459}460 461// Validate the ranges associated with the location.462bool LVLocation::validateRanges() {463 // Traverse the locations and validate them against the address to line464 // mapping in the current compile unit. Record those invalid ranges.465 // A valid range must meet the following conditions:466 // a) line(lopc) <= line(hipc)467 // b) line(lopc) and line(hipc) are valid.468 469 if (!hasAssociatedRange())470 return true;471 472 LVLineRange Range = getReaderCompileUnit()->lineRange(this);473 LVLine *LowLine = Range.first;474 LVLine *HighLine = Range.second;475 if (LowLine)476 setLowerLine(LowLine);477 else {478 setIsInvalidLower();479 return false;480 }481 if (HighLine)482 setUpperLine(HighLine);483 else {484 setIsInvalidUpper();485 return false;486 }487 // Check for a valid interval.488 if (LowLine->getLineNumber() > HighLine->getLineNumber()) {489 setIsInvalidRange();490 return false;491 }492 493 return true;494}495 496bool LVLocation::calculateCoverage(LVLocations *Locations, unsigned &Factor,497 float &Percentage) {498 if (!options().getAttributeCoverage() && !Locations)499 return false;500 501 // Calculate the coverage depending on the kind of location. We have502 // the simple and composed locations.503 if (Locations->size() == 1) {504 // Simple: fixed address, class offset, stack offset.505 LVLocation *Location = Locations->front();506 // Some types of locations do not have specific kind. Now is the time507 // to set those types, depending on the operation type.508 Location->updateKind();509 if (Location->getIsLocationSimple()) {510 Factor = 100;511 Percentage = 100;512 return true;513 }514 }515 516 // Composed locations.517 LVAddress LowerAddress = 0;518 LVAddress UpperAddress = 0;519 for (const LVLocation *Location : *Locations)520 // Do not include locations representing a gap.521 if (!Location->getIsGapEntry()) {522 LowerAddress = Location->getLowerAddress();523 UpperAddress = Location->getUpperAddress();524 Factor += (UpperAddress > LowerAddress) ? UpperAddress - LowerAddress525 : LowerAddress - UpperAddress;526 }527 528 Percentage = 0;529 return false;530}531 532void LVLocation::printRaw(raw_ostream &OS, bool Full) const {533 // Print the active range (low pc and high pc).534 OS << " [" << hexString(getLowerAddress()) << ":"535 << hexString(getUpperAddress()) << "]\n";536 // Print any DWARF operations.537 printRawExtra(OS, Full);538}539 540void LVLocation::printInterval(raw_ostream &OS, bool Full) const {541 if (hasAssociatedRange())542 OS << getIntervalInfo();543}544 545void LVLocation::print(raw_ostream &OS, bool Full) const {546 if (getReader().doPrintLocation(this)) {547 LVObject::print(OS, Full);548 printExtra(OS, Full);549 }550}551 552void LVLocation::printExtra(raw_ostream &OS, bool Full) const {553 printInterval(OS, Full);554 OS << "\n";555}556 557//===----------------------------------------------------------------------===//558// DWARF location for a symbol.559//===----------------------------------------------------------------------===//560// Add a Location Entry.561void LVLocationSymbol::addObject(LVAddress LowPC, LVAddress HighPC,562 LVUnsigned SectionOffset,563 uint64_t LocDescOffset) {564 setLowerAddress(LowPC);565 setUpperAddress(HighPC);566 567 // Record the offset where the location information begins.568 setOffset(LocDescOffset ? LocDescOffset : SectionOffset);569 570 // A -1 HighPC value, indicates no range.571 if (HighPC == LVAddress(UINT64_MAX))572 setIsDiscardedRange();573 574 // Update the location kind, using the DWARF attribute.575 setKind();576}577 578// Add a Location Record.579void LVLocationSymbol::addObject(LVSmall Opcode,580 ArrayRef<LVUnsigned> Operands) {581 if (!Entries)582 Entries = std::make_unique<LVOperations>();583 Entries->push_back(getReader().createOperation(Opcode, Operands));584}585 586// Based on the DWARF attribute, define the location kind.587void LVLocation::setKind() {588 switch (getAttr()) {589 case dwarf::DW_AT_data_member_location:590 setIsClassOffset();591 break;592 case dwarf::DW_AT_location:593 // Depending on the operand, we have a fixed address.594 setIsFixedAddress();595 break;596 default:597 break;598 }599 // For those symbols with absolute location information, ignore any600 // gaps in their location description; that is the case with absolute601 // memory addresses and members located at specific offsets.602 if (hasAssociatedRange())603 getParentSymbol()->setFillGaps();604}605 606void LVLocationSymbol::updateKind() {607 // Update the location type for simple ones.608 if (Entries && Entries->size() == 1) {609 if (dwarf::DW_OP_fbreg == Entries->front()->getOpcode())610 setIsStackOffset();611 }612}613 614void LVLocationSymbol::printRawExtra(raw_ostream &OS, bool Full) const {615 if (Entries)616 for (const LVOperation *Operation : *Entries)617 Operation->print(OS, Full);618}619 620// Print location (formatted version).621void LVLocation::print(LVLocations *Locations, raw_ostream &OS, bool Full) {622 if (!Locations || Locations->empty())623 return;624 625 // Print the symbol coverage.626 if (options().getAttributeCoverage()) {627 // The location entries are contained within a symbol. Get a location,628 // to access basic information about indentation, parent, etc.629 LVLocation *Location = Locations->front();630 LVSymbol *Symbol = Location->getParentSymbol();631 float Percentage = Symbol->getCoveragePercentage();632 633 // The coverage is dependent on the kind of location.634 std::string String;635 raw_string_ostream Stream(String);636 Stream << format("%.2f%%", Percentage);637 if (!Location->getIsLocationSimple())638 Stream << format(" (%d/%d)", Symbol->getCoverageFactor(),639 Symbol->getParentScope()->getCoverageFactor());640 Symbol->printAttributes(OS, Full, "{Coverage} ", Symbol, StringRef(String),641 /*UseQuotes=*/false,642 /*PrintRef=*/false);643 }644 645 // Print the symbol location, including the missing entries.646 if (getReader().doPrintLocation(/*Location=*/nullptr))647 for (const LVLocation *Location : *Locations)648 Location->print(OS, Full);649}650 651void LVLocationSymbol::printExtra(raw_ostream &OS, bool Full) const {652 OS << "{Location}";653 if (getIsCallSite())654 OS << " -> CallSite";655 printInterval(OS, Full);656 OS << "\n";657 658 // Print location entries.659 if (Full && Entries) {660 bool CodeViewLocation = getParentSymbol()->getHasCodeViewLocation();661 std::stringstream Stream;662 std::string Leading;663 for (LVOperation *Operation : *Entries) {664 Stream << Leading665 << (CodeViewLocation ? Operation->getOperandsCodeViewInfo()666 : Operation->getOperandsDWARFInfo());667 Leading = ", ";668 }669 printAttributes(OS, Full, "{Entry} ", const_cast<LVLocationSymbol *>(this),670 StringRef(Stream.str()),671 /*UseQuotes=*/false,672 /*PrintRef=*/false);673 }674}675