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 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
|
//===- DWARFListTable.h -----------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_DEBUGINFO_DWARFLISTTABLE_H
#define LLVM_DEBUGINFO_DWARFLISTTABLE_H
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/DebugInfo/DIContext.h"
#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
#include <cstdint>
#include <map>
#include <vector>
namespace llvm {
/// A base class for DWARF list entries, such as range or location list
/// entries.
struct DWARFListEntryBase {
/// The offset at which the entry is located in the section.
uint32_t Offset;
/// The DWARF encoding (DW_RLE_* or DW_LLE_*).
uint8_t EntryKind;
/// The index of the section this entry belongs to.
uint64_t SectionIndex;
};
/// A base class for lists of entries that are extracted from a particular
/// section, such as range lists or location lists.
template <typename ListEntryType> class DWARFListType {
using EntryType = ListEntryType;
using ListEntries = std::vector<EntryType>;
protected:
ListEntries Entries;
public:
// FIXME: We need to consolidate the various verions of "createError"
// that are used in the DWARF consumer. Until then, this is a workaround.
Error createError(const char *, const char *, uint32_t);
const ListEntries &getEntries() const { return Entries; }
bool empty() const { return Entries.empty(); }
void clear() { Entries.clear(); }
Error extract(DWARFDataExtractor Data, uint32_t HeaderOffset, uint32_t End,
uint32_t *OffsetPtr, StringRef SectionName,
StringRef ListStringName);
};
/// A class representing the header of a list table such as the range list
/// table in the .debug_rnglists section.
class DWARFListTableHeader {
struct Header {
/// The total length of the entries for this table, not including the length
/// field itself.
uint32_t Length = 0;
/// The DWARF version number.
uint16_t Version;
/// The size in bytes of an address on the target architecture. For
/// segmented addressing, this is the size of the offset portion of the
/// address.
uint8_t AddrSize;
/// The size in bytes of a segment selector on the target architecture.
/// If the target system uses a flat address space, this value is 0.
uint8_t SegSize;
/// The number of offsets that follow the header before the range lists.
uint32_t OffsetEntryCount;
};
Header HeaderData;
/// The offset table, which contains offsets to the individual list entries.
/// It is used by forms such as DW_FORM_rnglistx.
/// FIXME: Generate the table and use the appropriate forms.
std::vector<uint32_t> Offsets;
/// The table's format, either DWARF32 or DWARF64.
dwarf::DwarfFormat Format;
/// The offset at which the header (and hence the table) is located within
/// its section.
uint32_t HeaderOffset;
/// The name of the section the list is located in.
StringRef SectionName;
/// A characterization of the list for dumping purposes, e.g. "range" or
/// "location".
StringRef ListTypeString;
public:
DWARFListTableHeader(StringRef SectionName, StringRef ListTypeString)
: SectionName(SectionName), ListTypeString(ListTypeString) {}
void clear() {
HeaderData = {};
Offsets.clear();
}
uint32_t getHeaderOffset() const { return HeaderOffset; }
uint8_t getAddrSize() const { return HeaderData.AddrSize; }
uint32_t getLength() const { return HeaderData.Length; }
StringRef getSectionName() const { return SectionName; }
StringRef getListTypeString() const { return ListTypeString; }
dwarf::DwarfFormat getFormat() const { return Format; }
void dump(raw_ostream &OS, DIDumpOptions DumpOpts = {}) const;
Optional<uint32_t> getOffsetEntry(uint32_t Index) const {
if (Index < Offsets.size())
return Offsets[Index];
return None;
}
/// Extract the table header and the array of offsets.
Error extract(DWARFDataExtractor Data, uint32_t *OffsetPtr);
/// Returns the length of the table, including the length field, or 0 if the
/// length has not been determined (e.g. because the table has not yet been
/// parsed, or there was a problem in parsing).
uint32_t length() const;
};
/// A class representing a table of lists as specified in the DWARF v5
/// standard for location lists and range lists. The table consists of a header
/// followed by an array of offsets into a DWARF section, followed by zero or
/// more list entries. The list entries are kept in a map where the keys are
/// the lists' section offsets.
template <typename DWARFListType> class DWARFListTableBase {
DWARFListTableHeader Header;
/// A mapping between file offsets and lists. It is used to find a particular
/// list based on an offset (obtained from DW_AT_ranges, for example).
std::map<uint32_t, DWARFListType> ListMap;
/// This string is displayed as a heading before the list is dumped
/// (e.g. "ranges:").
StringRef HeaderString;
protected:
DWARFListTableBase(StringRef SectionName, StringRef HeaderString,
StringRef ListTypeString)
: Header(SectionName, ListTypeString), HeaderString(HeaderString) {}
public:
void clear() {
Header.clear();
ListMap.clear();
}
/// Extract the table header and the array of offsets.
Error extractHeaderAndOffsets(DWARFDataExtractor Data, uint32_t *OffsetPtr) {
return Header.extract(Data, OffsetPtr);
}
/// Extract an entire table, including all list entries.
Error extract(DWARFDataExtractor Data, uint32_t *OffsetPtr);
/// Look up a list based on a given offset. Extract it and enter it into the
/// list map if necessary.
Expected<DWARFListType> findList(DWARFDataExtractor Data, uint32_t Offset);
uint32_t getHeaderOffset() const { return Header.getHeaderOffset(); }
uint8_t getAddrSize() const { return Header.getAddrSize(); }
void dump(raw_ostream &OS, DIDumpOptions DumpOpts = {}) const;
/// Return the contents of the offset entry designated by a given index.
Optional<uint32_t> getOffsetEntry(uint32_t Index) const {
return Header.getOffsetEntry(Index);
}
/// Return the size of the table header including the length but not including
/// the offsets. This is dependent on the table format, which is unambiguously
/// derived from parsing the table.
uint8_t getHeaderSize() const {
switch (Header.getFormat()) {
case dwarf::DwarfFormat::DWARF32:
return 12;
case dwarf::DwarfFormat::DWARF64:
return 20;
}
llvm_unreachable("Invalid DWARF format (expected DWARF32 or DWARF64");
}
uint32_t length() { return Header.length(); }
};
template <typename DWARFListType>
Error DWARFListTableBase<DWARFListType>::extract(DWARFDataExtractor Data,
uint32_t *OffsetPtr) {
clear();
if (Error E = extractHeaderAndOffsets(Data, OffsetPtr))
return E;
Data.setAddressSize(Header.getAddrSize());
uint32_t End = getHeaderOffset() + Header.length();
while (*OffsetPtr < End) {
DWARFListType CurrentList;
uint32_t Off = *OffsetPtr;
if (Error E = CurrentList.extract(Data, getHeaderOffset(), End, OffsetPtr,
Header.getSectionName(),
Header.getListTypeString()))
return E;
ListMap[Off] = CurrentList;
}
assert(*OffsetPtr == End &&
"mismatch between expected length of table and length "
"of extracted data");
return Error::success();
}
template <typename ListEntryType>
Error DWARFListType<ListEntryType>::extract(DWARFDataExtractor Data,
uint32_t HeaderOffset, uint32_t End,
uint32_t *OffsetPtr,
StringRef SectionName,
StringRef ListTypeString) {
if (*OffsetPtr < HeaderOffset || *OffsetPtr >= End)
return createError("invalid %s list offset 0x%" PRIx32,
ListTypeString.data(), *OffsetPtr);
Entries.clear();
while (*OffsetPtr < End) {
ListEntryType Entry;
if (Error E = Entry.extract(Data, End, OffsetPtr))
return E;
Entries.push_back(Entry);
if (Entry.isSentinel())
return Error::success();
}
return createError("no end of list marker detected at end of %s table "
"starting at offset 0x%" PRIx32,
SectionName.data(), HeaderOffset);
}
template <typename DWARFListType>
void DWARFListTableBase<DWARFListType>::dump(raw_ostream &OS,
DIDumpOptions DumpOpts) const {
Header.dump(OS, DumpOpts);
OS << HeaderString << "\n";
// Determine the length of the longest encoding string we have in the table,
// so we can align the output properly. We only need this in verbose mode.
size_t MaxEncodingStringLength = 0;
if (DumpOpts.Verbose) {
for (const auto &List : ListMap)
for (const auto &Entry : List.second.getEntries())
MaxEncodingStringLength =
std::max(MaxEncodingStringLength,
dwarf::RangeListEncodingString(Entry.EntryKind).size());
}
uint64_t CurrentBase = 0;
for (const auto &List : ListMap)
for (const auto &Entry : List.second.getEntries())
Entry.dump(OS, getAddrSize(), MaxEncodingStringLength, CurrentBase,
DumpOpts);
}
template <typename DWARFListType>
Expected<DWARFListType>
DWARFListTableBase<DWARFListType>::findList(DWARFDataExtractor Data,
uint32_t Offset) {
auto Entry = ListMap.find(Offset);
if (Entry != ListMap.end())
return Entry->second;
// Extract the list from the section and enter it into the list map.
DWARFListType List;
uint32_t End = getHeaderOffset() + Header.length();
uint32_t StartingOffset = Offset;
if (Error E =
List.extract(Data, getHeaderOffset(), End, &Offset,
Header.getSectionName(), Header.getListTypeString()))
return std::move(E);
ListMap[StartingOffset] = List;
return List;
}
} // end namespace llvm
#endif // LLVM_DEBUGINFO_DWARFLISTTABLE_H
|