brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.8 KiB · 98eaf1a Raw
185 lines · cpp
1//===- DWARFDebugAddr.cpp -------------------------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/DebugInfo/DWARF/DWARFDebugAddr.h"10#include "llvm/BinaryFormat/Dwarf.h"11#include "llvm/DebugInfo/DWARF/DWARFContext.h"12#include "llvm/Support/Errc.h"13 14using namespace llvm;15 16Error DWARFDebugAddrTable::extractAddresses(const DWARFDataExtractor &Data,17                                            uint64_t *OffsetPtr,18                                            uint64_t EndOffset) {19  assert(EndOffset >= *OffsetPtr);20  uint64_t DataSize = EndOffset - *OffsetPtr;21  assert(Data.isValidOffsetForDataOfSize(*OffsetPtr, DataSize));22  if (Error SizeErr = DWARFContext::checkAddressSizeSupported(23          AddrSize, errc::not_supported, "address table at offset 0x%" PRIx64,24          Offset))25    return SizeErr;26  if (DataSize % AddrSize != 0) {27    invalidateLength();28    return createStringError(errc::invalid_argument,29                             "address table at offset 0x%" PRIx6430                             " contains data of size 0x%" PRIx6431                             " which is not a multiple of addr size %" PRIu8,32                             Offset, DataSize, AddrSize);33  }34  Addrs.clear();35  size_t Count = DataSize / AddrSize;36  Addrs.reserve(Count);37  while (Count--)38    Addrs.push_back(Data.getRelocatedValue(AddrSize, OffsetPtr));39  return Error::success();40}41 42Error DWARFDebugAddrTable::extractV5(const DWARFDataExtractor &Data,43                                     uint64_t *OffsetPtr, uint8_t CUAddrSize,44                                     std::function<void(Error)> WarnCallback) {45  Offset = *OffsetPtr;46  llvm::Error Err = Error::success();47  std::tie(Length, Format) = Data.getInitialLength(OffsetPtr, &Err);48  if (Err) {49    invalidateLength();50    return createStringError(errc::invalid_argument,51                             "parsing address table at offset 0x%" PRIx6452                             ": %s",53                             Offset, toString(std::move(Err)).c_str());54  }55 56  if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, Length)) {57    uint64_t DiagnosticLength = Length;58    invalidateLength();59    return createStringError(60        errc::invalid_argument,61        "section is not large enough to contain an address table "62        "at offset 0x%" PRIx64 " with a unit_length value of 0x%" PRIx64,63        Offset, DiagnosticLength);64  }65  uint64_t EndOffset = *OffsetPtr + Length;66  // Ensure that we can read the remaining header fields.67  if (Length < 4) {68    uint64_t DiagnosticLength = Length;69    invalidateLength();70    return createStringError(71        errc::invalid_argument,72        "address table at offset 0x%" PRIx6473        " has a unit_length value of 0x%" PRIx6474        ", which is too small to contain a complete header",75        Offset, DiagnosticLength);76  }77 78  Version = Data.getU16(OffsetPtr);79  AddrSize = Data.getU8(OffsetPtr);80  SegSize = Data.getU8(OffsetPtr);81 82  // Perform a basic validation of the header fields.83  if (Version != 5)84    return createStringError(errc::not_supported,85                             "address table at offset 0x%" PRIx6486                             " has unsupported version %" PRIu16,87                             Offset, Version);88  // TODO: add support for non-zero segment selector size.89  if (SegSize != 0)90    return createStringError(errc::not_supported,91                             "address table at offset 0x%" PRIx6492                             " has unsupported segment selector size %" PRIu8,93                             Offset, SegSize);94 95  if (Error Err = extractAddresses(Data, OffsetPtr, EndOffset))96    return Err;97  if (CUAddrSize && AddrSize != CUAddrSize) {98    WarnCallback(createStringError(99        errc::invalid_argument,100        "address table at offset 0x%" PRIx64 " has address size %" PRIu8101        " which is different from CU address size %" PRIu8,102        Offset, AddrSize, CUAddrSize));103  }104  return Error::success();105}106 107Error DWARFDebugAddrTable::extractPreStandard(const DWARFDataExtractor &Data,108                                              uint64_t *OffsetPtr,109                                              uint16_t CUVersion,110                                              uint8_t CUAddrSize) {111  assert(CUVersion > 0 && CUVersion < 5);112 113  Offset = *OffsetPtr;114  Length = 0;115  Version = CUVersion;116  AddrSize = CUAddrSize;117  SegSize = 0;118 119  return extractAddresses(Data, OffsetPtr, Data.size());120}121 122Error DWARFDebugAddrTable::extract(const DWARFDataExtractor &Data,123                                   uint64_t *OffsetPtr,124                                   uint16_t CUVersion,125                                   uint8_t CUAddrSize,126                                   std::function<void(Error)> WarnCallback) {127  if (CUVersion > 0 && CUVersion < 5)128    return extractPreStandard(Data, OffsetPtr, CUVersion, CUAddrSize);129  if (CUVersion == 0)130    WarnCallback(createStringError(errc::invalid_argument,131                                   "DWARF version is not defined in CU,"132                                   " assuming version 5"));133  return extractV5(Data, OffsetPtr, CUAddrSize, WarnCallback);134}135 136void DWARFDebugAddrTable::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {137  if (DumpOpts.Verbose)138    OS << format("0x%8.8" PRIx64 ": ", Offset);139  if (Length) {140    int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(Format);141    OS << "Address table header: "142       << format("length = 0x%0*" PRIx64, OffsetDumpWidth, Length)143       << ", format = " << dwarf::FormatString(Format)144       << format(", version = 0x%4.4" PRIx16, Version)145       << format(", addr_size = 0x%2.2" PRIx8, AddrSize)146       << format(", seg_size = 0x%2.2" PRIx8, SegSize) << "\n";147  }148 149  if (Addrs.size() > 0) {150    const char *AddrFmt;151    switch (AddrSize) {152    case 2:153      AddrFmt = "0x%4.4" PRIx64 "\n";154      break;155    case 4:156      AddrFmt = "0x%8.8" PRIx64 "\n";157      break;158    case 8:159      AddrFmt = "0x%16.16" PRIx64 "\n";160      break;161    default:162      llvm_unreachable("unsupported address size");163    }164    OS << "Addrs: [\n";165    for (uint64_t Addr : Addrs)166      OS << format(AddrFmt, Addr);167    OS << "]\n";168  }169}170 171Expected<uint64_t> DWARFDebugAddrTable::getAddrEntry(uint32_t Index) const {172  if (Index < Addrs.size())173    return Addrs[Index];174  return createStringError(errc::invalid_argument,175                           "Index %" PRIu32 " is out of range of the "176                           "address table at offset 0x%" PRIx64,177                           Index, Offset);178}179 180std::optional<uint64_t> DWARFDebugAddrTable::getFullLength() const {181  if (Length == 0)182    return std::nullopt;183  return Length + dwarf::getUnitLengthFieldByteSize(Format);184}185