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>>
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:
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