aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/llvm/include/llvm/DWARFLinkerParallel/AddressesMap.h
blob: b451fee4e0b723af38b2caf07b6fe7ebdabf70ae (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
//===- AddressesMap.h -------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_DWARFLINKERPARALLEL_ADDRESSESMAP_H
#define LLVM_DWARFLINKERPARALLEL_ADDRESSESMAP_H

#include "llvm/ADT/AddressRanges.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/DebugInfo/DWARF/DWARFDie.h"
#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
#include <cstdint>

namespace llvm {
namespace dwarflinker_parallel {

/// Mapped value in the address map is the offset to apply to the
/// linked address.
using RangesTy = AddressRangesMap;

/// AddressesMap represents information about valid addresses used
/// by debug information. Valid addresses are those which points to
/// live code sections. i.e. relocations for these addresses point
/// into sections which would be/are placed into resulting binary.
class AddressesMap {
public:
  virtual ~AddressesMap() = default;

  /// Checks that there are valid relocations in the .debug_info
  /// section.
  virtual bool hasValidRelocs() = 0;

  /// Checks that the specified DWARF expression operand \p Op references live
  /// code section and returns the relocation adjustment value (to get the
  /// linked address this value might be added to the source expression operand
  /// address).
  /// \returns relocation adjustment value or std::nullopt if there is no
  /// corresponding live address.
  virtual std::optional<int64_t>
  getExprOpAddressRelocAdjustment(DWARFUnit &U,
                                  const DWARFExpression::Operation &Op,
                                  uint64_t StartOffset, uint64_t EndOffset) = 0;

  /// Checks that the specified subprogram \p DIE references the live code
  /// section and returns the relocation adjustment value (to get the linked
  /// address this value might be added to the source subprogram address).
  /// Allowed kinds of input DIE: DW_TAG_subprogram, DW_TAG_label.
  /// \returns relocation adjustment value or std::nullopt if there is no
  /// corresponding live address.
  virtual std::optional<int64_t>
  getSubprogramRelocAdjustment(const DWARFDie &DIE) = 0;

  // Returns the library install name associated to the AddessesMap.
  virtual std::optional<StringRef> getLibraryInstallName() = 0;

  /// Apply the valid relocations to the buffer \p Data, taking into
  /// account that Data is at \p BaseOffset in the .debug_info section.
  ///
  /// \returns true whether any reloc has been applied.
  virtual bool applyValidRelocs(MutableArrayRef<char> Data, uint64_t BaseOffset,
                                bool IsLittleEndian) = 0;

  /// Check if the linker needs to gather and save relocation info.
  virtual bool needToSaveValidRelocs() = 0;

  /// Update and save relocation values to be serialized
  virtual void updateAndSaveValidRelocs(bool IsDWARF5,
                                        uint64_t OriginalUnitOffset,
                                        int64_t LinkedOffset,
                                        uint64_t StartOffset,
                                        uint64_t EndOffset) = 0;

  /// Update the valid relocations that used OriginalUnitOffset as the compile
  /// unit offset, and update their values to reflect OutputUnitOffset.
  virtual void updateRelocationsWithUnitOffset(uint64_t OriginalUnitOffset,
                                               uint64_t OutputUnitOffset) = 0;

  /// Erases all data.
  virtual void clear() = 0;

  /// This function checks whether variable has DWARF expression containing
  /// operation referencing live address(f.e. DW_OP_addr, DW_OP_addrx...).
  /// \returns first is true if the expression has an operation referencing an
  /// address.
  ///          second is the relocation adjustment value if the live address is
  ///          referenced.
  std::pair<bool, std::optional<int64_t>>
  getVariableRelocAdjustment(const DWARFDie &DIE) {
    assert((DIE.getTag() == dwarf::DW_TAG_variable ||
            DIE.getTag() == dwarf::DW_TAG_constant) &&
           "Wrong type of input die");

    const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();

    // Check if DIE has DW_AT_location attribute.
    DWARFUnit *U = DIE.getDwarfUnit();
    std::optional<uint32_t> LocationIdx =
        Abbrev->findAttributeIndex(dwarf::DW_AT_location);
    if (!LocationIdx)
      return std::make_pair(false, std::nullopt);

    // Get offset to the DW_AT_location attribute.
    uint64_t AttrOffset =
        Abbrev->getAttributeOffsetFromIndex(*LocationIdx, DIE.getOffset(), *U);

    // Get value of the DW_AT_location attribute.
    std::optional<DWARFFormValue> LocationValue =
        Abbrev->getAttributeValueFromOffset(*LocationIdx, AttrOffset, *U);
    if (!LocationValue)
      return std::make_pair(false, std::nullopt);

    // Check that DW_AT_location attribute is of 'exprloc' class.
    // Handling value of location expressions for attributes of 'loclist'
    // class is not implemented yet.
    std::optional<ArrayRef<uint8_t>> Expr = LocationValue->getAsBlock();
    if (!Expr)
      return std::make_pair(false, std::nullopt);

    // Parse 'exprloc' expression.
    DataExtractor Data(toStringRef(*Expr), U->getContext().isLittleEndian(),
                       U->getAddressByteSize());
    DWARFExpression Expression(Data, U->getAddressByteSize(),
                               U->getFormParams().Format);

    bool HasLocationAddress = false;
    uint64_t CurExprOffset = 0;
    for (DWARFExpression::iterator It = Expression.begin();
         It != Expression.end(); ++It) {
      DWARFExpression::iterator NextIt = It;
      ++NextIt;

      const DWARFExpression::Operation &Op = *It;
      switch (Op.getCode()) {
      case dwarf::DW_OP_const2u:
      case dwarf::DW_OP_const4u:
      case dwarf::DW_OP_const8u:
      case dwarf::DW_OP_const2s:
      case dwarf::DW_OP_const4s:
      case dwarf::DW_OP_const8s:
        if (NextIt == Expression.end() || !isTlsAddressCode(NextIt->getCode()))
          break;
        [[fallthrough]];
      case dwarf::DW_OP_addr: {
        HasLocationAddress = true;
        // Check relocation for the address.
        if (std::optional<int64_t> RelocAdjustment =
                getExprOpAddressRelocAdjustment(*U, Op,
                                                AttrOffset + CurExprOffset,
                                                AttrOffset + Op.getEndOffset()))
          return std::make_pair(HasLocationAddress, *RelocAdjustment);
      } break;
      case dwarf::DW_OP_constx:
      case dwarf::DW_OP_addrx: {
        HasLocationAddress = true;
        if (std::optional<uint64_t> AddressOffset =
                DIE.getDwarfUnit()->getIndexedAddressOffset(
                    Op.getRawOperand(0))) {
          // Check relocation for the address.
          if (std::optional<int64_t> RelocAdjustment =
                  getExprOpAddressRelocAdjustment(
                      *U, Op, *AddressOffset,
                      *AddressOffset +
                          DIE.getDwarfUnit()->getAddressByteSize()))
            return std::make_pair(HasLocationAddress, *RelocAdjustment);
        }
      } break;
      default: {
        // Nothing to do.
      } break;
      }
      CurExprOffset = Op.getEndOffset();
    }

    return std::make_pair(HasLocationAddress, std::nullopt);
  }

protected:
  inline bool isTlsAddressCode(uint8_t DW_OP_Code) {
    return DW_OP_Code == dwarf::DW_OP_form_tls_address ||
           DW_OP_Code == dwarf::DW_OP_GNU_push_tls_address;
  }
};

} // end of namespace dwarflinker_parallel
} // end namespace llvm

#endif // LLVM_DWARFLINKERPARALLEL_ADDRESSESMAP_H