blob: a232aafadc5ce9a4c43a23ffa7b90d239ee81fd5 [file] [log] [blame]
//===- 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