brintos

brintos / llvm-project-archived public Read only

0
0
Text · 21.3 KiB · 3c078d8 Raw
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