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(attr: dwarf::DW_AT_location); |
104 | if (!LocationIdx) |
105 | return std::make_pair(x: false, y: std::nullopt); |
106 | |
107 | // Get offset to the DW_AT_location attribute. |
108 | uint64_t AttrOffset = |
109 | Abbrev->getAttributeOffsetFromIndex(AttrIndex: *LocationIdx, DIEOffset: DIE.getOffset(), U: *U); |
110 | |
111 | // Get value of the DW_AT_location attribute. |
112 | std::optional<DWARFFormValue> LocationValue = |
113 | Abbrev->getAttributeValueFromOffset(AttrIndex: *LocationIdx, Offset: AttrOffset, U: *U); |
114 | if (!LocationValue) |
115 | return std::make_pair(x: false, y: 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(x: false, y: std::nullopt); |
123 | |
124 | // Parse 'exprloc' expression. |
125 | DataExtractor Data(toStringRef(Input: *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(DW_OP_Code: 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&: *U, Op, StartOffset: AttrOffset + CurExprOffset, |
154 | EndOffset: AttrOffset + Op.getEndOffset(), Verbose)) |
155 | return std::make_pair(x&: HasLocationAddress, y&: *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 | Index: Op.getRawOperand(Idx: 0))) { |
163 | // Check relocation for the address. |
164 | if (std::optional<int64_t> RelocAdjustment = |
165 | getExprOpAddressRelocAdjustment( |
166 | U&: *U, Op, StartOffset: *AddressOffset, |
167 | EndOffset: *AddressOffset + DIE.getDwarfUnit()->getAddressByteSize(), |
168 | Verbose)) |
169 | return std::make_pair(x&: HasLocationAddress, y&: *RelocAdjustment); |
170 | } |
171 | } break; |
172 | default: { |
173 | // Nothing to do. |
174 | } break; |
175 | } |
176 | CurExprOffset = Op.getEndOffset(); |
177 | } |
178 | |
179 | return std::make_pair(x&: HasLocationAddress, y: 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 | |