clang 20.0.0 (based on r547379) from build 12806354. Bug: http://b/379133546 Test: N/A Change-Id: I2eb8938af55d809de674be63cb30cf27e801862b Upstream-Commit: ad834e67b1105d15ef907f6255d4c96e8e733f57
193 lines
7.7 KiB
C++
193 lines
7.7 KiB
C++
//===- 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_DWARFLINKER_ADDRESSESMAP_H
|
|
#define LLVM_DWARFLINKER_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 dwarf_linker {
|
|
|
|
/// 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). Print debug output if \p Verbose is true.
|
|
/// \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, bool Verbose) = 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.
|
|
/// Print debug output if \p Verbose is true.
|
|
/// \returns relocation adjustment value or std::nullopt if there is no
|
|
/// corresponding live address.
|
|
virtual std::optional<int64_t>
|
|
getSubprogramRelocAdjustment(const DWARFDie &DIE, bool Verbose) = 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, bool Verbose) {
|
|
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(), Verbose))
|
|
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(),
|
|
Verbose))
|
|
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;
|
|
}
|
|
};
|
|
|
|
} // namespace dwarf_linker
|
|
} // end namespace llvm
|
|
|
|
#endif // LLVM_DWARFLINKER_ADDRESSESMAP_H
|