1 //===- AddressesMap.h -------------------------------------------*- C++ -*-===// 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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLVM_DWARFLINKER_ADDRESSESMAP_H 10 #define LLVM_DWARFLINKER_ADDRESSESMAP_H 11 12 #include "llvm/ADT/AddressRanges.h" 13 #include "llvm/DebugInfo/DWARF/DWARFContext.h" 14 #include "llvm/DebugInfo/DWARF/DWARFDie.h" 15 #include "llvm/DebugInfo/DWARF/DWARFExpression.h" 16 #include "llvm/DebugInfo/DWARF/DWARFUnit.h" 17 #include <cstdint> 18 19 namespace llvm { 20 namespace dwarf_linker { 21 22 /// Mapped value in the address map is the offset to apply to the 23 /// linked address. 24 using RangesTy = AddressRangesMap; 25 26 /// AddressesMap represents information about valid addresses used 27 /// by debug information. Valid addresses are those which points to 28 /// live code sections. i.e. relocations for these addresses point 29 /// into sections which would be/are placed into resulting binary. 30 class AddressesMap { 31 public: 32 virtual ~AddressesMap() = default; 33 34 /// Checks that there are valid relocations in the .debug_info 35 /// section. 36 virtual bool hasValidRelocs() = 0; 37 38 /// Checks that the specified DWARF expression operand \p Op references live 39 /// code section and returns the relocation adjustment value (to get the 40 /// linked address this value might be added to the source expression operand 41 /// address). Print debug output if \p Verbose is true. 42 /// \returns relocation adjustment value or std::nullopt if there is no 43 /// corresponding live address. 44 virtual std::optional<int64_t> getExprOpAddressRelocAdjustment( 45 DWARFUnit &U, const DWARFExpression::Operation &Op, uint64_t StartOffset, 46 uint64_t EndOffset, bool Verbose) = 0; 47 48 /// Checks that the specified subprogram \p DIE references the live code 49 /// section and returns the relocation adjustment value (to get the linked 50 /// address this value might be added to the source subprogram address). 51 /// Allowed kinds of input DIE: DW_TAG_subprogram, DW_TAG_label. 52 /// Print debug output if \p Verbose is true. 53 /// \returns relocation adjustment value or std::nullopt if there is no 54 /// corresponding live address. 55 virtual std::optional<int64_t> 56 getSubprogramRelocAdjustment(const DWARFDie &DIE, bool Verbose) = 0; 57 58 // Returns the library install name associated to the AddessesMap. 59 virtual std::optional<StringRef> getLibraryInstallName() = 0; 60 61 /// Apply the valid relocations to the buffer \p Data, taking into 62 /// account that Data is at \p BaseOffset in the .debug_info section. 63 /// 64 /// \returns true whether any reloc has been applied. 65 virtual bool applyValidRelocs(MutableArrayRef<char> Data, uint64_t BaseOffset, 66 bool IsLittleEndian) = 0; 67 68 /// Check if the linker needs to gather and save relocation info. 69 virtual bool needToSaveValidRelocs() = 0; 70 71 /// Update and save relocation values to be serialized 72 virtual void updateAndSaveValidRelocs(bool IsDWARF5, 73 uint64_t OriginalUnitOffset, 74 int64_t LinkedOffset, 75 uint64_t StartOffset, 76 uint64_t EndOffset) = 0; 77 78 /// Update the valid relocations that used OriginalUnitOffset as the compile 79 /// unit offset, and update their values to reflect OutputUnitOffset. 80 virtual void updateRelocationsWithUnitOffset(uint64_t OriginalUnitOffset, 81 uint64_t OutputUnitOffset) = 0; 82 83 /// Erases all data. 84 virtual void clear() = 0; 85 86 /// This function checks whether variable has DWARF expression containing 87 /// operation referencing live address(f.e. DW_OP_addr, DW_OP_addrx...). 88 /// \returns first is true if the expression has an operation referencing an 89 /// address. 90 /// second is the relocation adjustment value if the live address is 91 /// referenced. 92 std::pair<bool, std::optional<int64_t>> getVariableRelocAdjustment(const DWARFDie & DIE,bool Verbose)93 getVariableRelocAdjustment(const DWARFDie &DIE, bool Verbose) { 94 assert((DIE.getTag() == dwarf::DW_TAG_variable || 95 DIE.getTag() == dwarf::DW_TAG_constant) && 96 "Wrong type of input die"); 97 98 const auto *Abbrev = DIE.getAbbreviationDeclarationPtr(); 99 100 // Check if DIE has DW_AT_location attribute. 101 DWARFUnit *U = DIE.getDwarfUnit(); 102 std::optional<uint32_t> LocationIdx = 103 Abbrev->findAttributeIndex(dwarf::DW_AT_location); 104 if (!LocationIdx) 105 return std::make_pair(false, std::nullopt); 106 107 // Get offset to the DW_AT_location attribute. 108 uint64_t AttrOffset = 109 Abbrev->getAttributeOffsetFromIndex(*LocationIdx, DIE.getOffset(), *U); 110 111 // Get value of the DW_AT_location attribute. 112 std::optional<DWARFFormValue> LocationValue = 113 Abbrev->getAttributeValueFromOffset(*LocationIdx, AttrOffset, *U); 114 if (!LocationValue) 115 return std::make_pair(false, std::nullopt); 116 117 // Check that DW_AT_location attribute is of 'exprloc' class. 118 // Handling value of location expressions for attributes of 'loclist' 119 // class is not implemented yet. 120 std::optional<ArrayRef<uint8_t>> Expr = LocationValue->getAsBlock(); 121 if (!Expr) 122 return std::make_pair(false, std::nullopt); 123 124 // Parse 'exprloc' expression. 125 DataExtractor Data(toStringRef(*Expr), U->getContext().isLittleEndian(), 126 U->getAddressByteSize()); 127 DWARFExpression Expression(Data, U->getAddressByteSize(), 128 U->getFormParams().Format); 129 130 bool HasLocationAddress = false; 131 uint64_t CurExprOffset = 0; 132 for (DWARFExpression::iterator It = Expression.begin(); 133 It != Expression.end(); ++It) { 134 DWARFExpression::iterator NextIt = It; 135 ++NextIt; 136 137 const DWARFExpression::Operation &Op = *It; 138 switch (Op.getCode()) { 139 case dwarf::DW_OP_const2u: 140 case dwarf::DW_OP_const4u: 141 case dwarf::DW_OP_const8u: 142 case dwarf::DW_OP_const2s: 143 case dwarf::DW_OP_const4s: 144 case dwarf::DW_OP_const8s: 145 if (NextIt == Expression.end() || !isTlsAddressCode(NextIt->getCode())) 146 break; 147 [[fallthrough]]; 148 case dwarf::DW_OP_addr: { 149 HasLocationAddress = true; 150 // Check relocation for the address. 151 if (std::optional<int64_t> RelocAdjustment = 152 getExprOpAddressRelocAdjustment( 153 *U, Op, AttrOffset + CurExprOffset, 154 AttrOffset + Op.getEndOffset(), Verbose)) 155 return std::make_pair(HasLocationAddress, *RelocAdjustment); 156 } break; 157 case dwarf::DW_OP_constx: 158 case dwarf::DW_OP_addrx: { 159 HasLocationAddress = true; 160 if (std::optional<uint64_t> AddressOffset = 161 DIE.getDwarfUnit()->getIndexedAddressOffset( 162 Op.getRawOperand(0))) { 163 // Check relocation for the address. 164 if (std::optional<int64_t> RelocAdjustment = 165 getExprOpAddressRelocAdjustment( 166 *U, Op, *AddressOffset, 167 *AddressOffset + DIE.getDwarfUnit()->getAddressByteSize(), 168 Verbose)) 169 return std::make_pair(HasLocationAddress, *RelocAdjustment); 170 } 171 } break; 172 default: { 173 // Nothing to do. 174 } break; 175 } 176 CurExprOffset = Op.getEndOffset(); 177 } 178 179 return std::make_pair(HasLocationAddress, std::nullopt); 180 } 181 182 protected: isTlsAddressCode(uint8_t DW_OP_Code)183 inline bool isTlsAddressCode(uint8_t DW_OP_Code) { 184 return DW_OP_Code == dwarf::DW_OP_form_tls_address || 185 DW_OP_Code == dwarf::DW_OP_GNU_push_tls_address; 186 } 187 }; 188 189 } // namespace dwarf_linker 190 } // end namespace llvm 191 192 #endif // LLVM_DWARFLINKER_ADDRESSESMAP_H 193