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