1 //===- DWARFListTable.cpp ---------------------------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "llvm/DebugInfo/DWARF/DWARFListTable.h"
11 #include "llvm/BinaryFormat/Dwarf.h"
12 #include "llvm/Support/Errc.h"
13 #include "llvm/Support/Error.h"
14 #include "llvm/Support/Format.h"
15 #include "llvm/Support/raw_ostream.h"
16 
17 using namespace llvm;
18 
19 Error DWARFListTableHeader::extract(DWARFDataExtractor Data,
20                                     uint32_t *OffsetPtr) {
21   HeaderOffset = *OffsetPtr;
22   // Read and verify the length field.
23   if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, sizeof(uint32_t))) {
24     // By setting *OffsetPtr to 0, we indicate to the caller that
25     // we could not detemine the length of the table.
26     *OffsetPtr = 0;
27     return createStringError(errc::invalid_argument,
28                              "section is not large enough to contain a "
29                              "%s table length at offset 0x%" PRIx32,
30                              SectionName.data(), HeaderOffset);
31   }
32   // TODO: Add support for DWARF64.
33   HeaderData.Length = Data.getU32(OffsetPtr);
34   if (HeaderData.Length == 0xffffffffu) {
35     *OffsetPtr = 0;
36     return createStringError(errc::not_supported,
37                        "DWARF64 is not supported in %s at offset 0x%" PRIx32,
38                        SectionName.data(), HeaderOffset);
39   }
40 
41   uint32_t TableLength = HeaderData.Length + sizeof(uint32_t);
42   uint32_t End = HeaderOffset + TableLength;
43   Format = dwarf::DwarfFormat::DWARF32;
44   if (TableLength < sizeof(Header)) {
45     *OffsetPtr = End;
46     return createStringError(errc::invalid_argument,
47                              "%s table at offset 0x%" PRIx32
48                              " has too small length (0x%" PRIx32
49                              ") to contain a complete header",
50                              SectionName.data(), HeaderOffset, TableLength);
51   }
52   if (!Data.isValidOffsetForDataOfSize(HeaderOffset, TableLength)) {
53     *OffsetPtr = 0; // No recovery if the length exceeds the section size.
54     return createStringError(
55         errc::invalid_argument,
56         "section is not large enough to contain a %s table "
57         "of length 0x%" PRIx32 " at offset 0x%" PRIx32,
58         SectionName.data(), TableLength, HeaderOffset);
59   }
60 
61   HeaderData.Version = Data.getU16(OffsetPtr);
62   HeaderData.AddrSize = Data.getU8(OffsetPtr);
63   HeaderData.SegSize = Data.getU8(OffsetPtr);
64   HeaderData.OffsetEntryCount = Data.getU32(OffsetPtr);
65 
66   // Perform basic validation of the remaining header fields.
67   if (HeaderData.Version != 5) {
68     *OffsetPtr = End;
69     return createStringError(errc::invalid_argument,
70                              "unrecognised %s table version %" PRIu16
71                              " in table at offset 0x%" PRIx32,
72                              SectionName.data(), HeaderData.Version,
73                              HeaderOffset);
74   }
75   if (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8) {
76     *OffsetPtr = End;
77     return createStringError(errc::not_supported,
78                        "%s table at offset 0x%" PRIx32
79                        " has unsupported address size %" PRIu8,
80                        SectionName.data(), HeaderOffset, HeaderData.AddrSize);
81   }
82   if (HeaderData.SegSize != 0) {
83     *OffsetPtr = End;
84     return createStringError(errc::not_supported,
85                        "%s table at offset 0x%" PRIx32
86                        " has unsupported segment selector size %" PRIu8,
87                        SectionName.data(), HeaderOffset, HeaderData.SegSize);
88   }
89   if (End < HeaderOffset + sizeof(HeaderData) +
90                 HeaderData.OffsetEntryCount * sizeof(uint32_t)) {
91     *OffsetPtr = End;
92     return createStringError(errc::invalid_argument,
93         "%s table at offset 0x%" PRIx32 " has more offset entries (%" PRIu32
94         ") than there is space for",
95         SectionName.data(), HeaderOffset, HeaderData.OffsetEntryCount);
96   }
97   Data.setAddressSize(HeaderData.AddrSize);
98   for (uint32_t I = 0; I < HeaderData.OffsetEntryCount; ++I)
99     Offsets.push_back(Data.getU32(OffsetPtr));
100   return Error::success();
101 }
102 
103 void DWARFListTableHeader::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
104   if (DumpOpts.Verbose)
105     OS << format("0x%8.8" PRIx32 ": ", HeaderOffset);
106   OS << format(
107       "%s list header: length = 0x%8.8" PRIx32 ", version = 0x%4.4" PRIx16 ", "
108       "addr_size = 0x%2.2" PRIx8 ", seg_size = 0x%2.2" PRIx8
109       ", offset_entry_count = "
110       "0x%8.8" PRIx32 "\n",
111       ListTypeString.data(), HeaderData.Length, HeaderData.Version,
112       HeaderData.AddrSize, HeaderData.SegSize, HeaderData.OffsetEntryCount);
113 
114   if (HeaderData.OffsetEntryCount > 0) {
115     OS << "offsets: [";
116     for (const auto &Off : Offsets) {
117       OS << format("\n0x%8.8" PRIx32, Off);
118       if (DumpOpts.Verbose)
119         OS << format(" => 0x%8.8" PRIx32,
120                      Off + HeaderOffset + sizeof(HeaderData));
121     }
122     OS << "\n]\n";
123   }
124 }
125 
126 uint32_t DWARFListTableHeader::getTableLength() const {
127   if (HeaderData.Length == 0)
128     return 0;
129   assert(HeaderData.Version > 0 &&
130          "No DWARF version in header when using getTableLength()");
131   // TODO: DWARF64 support.
132   return HeaderData.Length + (HeaderData.Version > 4) * sizeof(uint32_t);
133 }
134