• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- DWARFDebugAddr.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/DWARFDebugAddr.h"
11 #include "llvm/BinaryFormat/Dwarf.h"
12 #include "llvm/DebugInfo/DWARF/DWARFUnit.h"
13 
14 using namespace llvm;
15 
clear()16 void DWARFDebugAddrTable::clear() {
17   HeaderData = {};
18   Addrs.clear();
19   invalidateLength();
20 }
21 
extract(DWARFDataExtractor Data,uint32_t * OffsetPtr,uint16_t Version,uint8_t AddrSize,std::function<void (Error)> WarnCallback)22 Error DWARFDebugAddrTable::extract(DWARFDataExtractor Data,
23                                    uint32_t *OffsetPtr,
24                                    uint16_t Version,
25                                    uint8_t AddrSize,
26                                    std::function<void(Error)> WarnCallback) {
27   clear();
28   HeaderOffset = *OffsetPtr;
29   // Read and verify the length field.
30   if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, sizeof(uint32_t)))
31     return createStringError(errc::invalid_argument,
32                        "section is not large enough to contain a "
33                        ".debug_addr table length at offset 0x%"
34                        PRIx32, *OffsetPtr);
35   uint16_t UnitVersion;
36   if (Version == 0) {
37     WarnCallback(createStringError(errc::invalid_argument,
38                        "DWARF version is not defined in CU,"
39                        " assuming version 5"));
40     UnitVersion = 5;
41   } else {
42     UnitVersion = Version;
43   }
44   // TODO: Add support for DWARF64.
45   Format = dwarf::DwarfFormat::DWARF32;
46   if (UnitVersion >= 5) {
47     HeaderData.Length = Data.getU32(OffsetPtr);
48     if (HeaderData.Length == 0xffffffffu) {
49       invalidateLength();
50       return createStringError(errc::not_supported,
51           "DWARF64 is not supported in .debug_addr at offset 0x%" PRIx32,
52           HeaderOffset);
53     }
54     if (HeaderData.Length + sizeof(uint32_t) < sizeof(Header)) {
55       uint32_t TmpLength = getLength();
56       invalidateLength();
57       return createStringError(errc::invalid_argument,
58                          ".debug_addr table at offset 0x%" PRIx32
59                          " has too small length (0x%" PRIx32
60                          ") to contain a complete header",
61                          HeaderOffset, TmpLength);
62     }
63     uint32_t End = HeaderOffset + getLength();
64     if (!Data.isValidOffsetForDataOfSize(HeaderOffset, End - HeaderOffset)) {
65       uint32_t TmpLength = getLength();
66       invalidateLength();
67       return createStringError(errc::invalid_argument,
68           "section is not large enough to contain a .debug_addr table "
69           "of length 0x%" PRIx32 " at offset 0x%" PRIx32,
70           TmpLength, HeaderOffset);
71     }
72 
73     HeaderData.Version = Data.getU16(OffsetPtr);
74     HeaderData.AddrSize = Data.getU8(OffsetPtr);
75     HeaderData.SegSize = Data.getU8(OffsetPtr);
76     DataSize = getDataSize();
77   } else {
78     HeaderData.Version = UnitVersion;
79     HeaderData.AddrSize = AddrSize;
80     // TODO: Support for non-zero SegSize.
81     HeaderData.SegSize = 0;
82     DataSize = Data.size();
83   }
84 
85   // Perform basic validation of the remaining header fields.
86 
87   // We support DWARF version 5 for now as well as pre-DWARF5
88   // implementations of .debug_addr table, which doesn't contain a header
89   // and consists only of a series of addresses.
90   if (HeaderData.Version > 5) {
91     return createStringError(errc::not_supported, "version %" PRIu16
92         " of .debug_addr section at offset 0x%" PRIx32 " is not supported",
93         HeaderData.Version, HeaderOffset);
94   }
95   // FIXME: For now we just treat version mismatch as an error,
96   // however the correct way to associate a .debug_addr table
97   // with a .debug_info table is to look at the DW_AT_addr_base
98   // attribute in the info table.
99   if (HeaderData.Version != UnitVersion)
100     return createStringError(errc::invalid_argument,
101                        ".debug_addr table at offset 0x%" PRIx32
102                        " has version %" PRIu16
103                        " which is different from the version suggested"
104                        " by the DWARF unit header: %" PRIu16,
105                        HeaderOffset, HeaderData.Version, UnitVersion);
106   if (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8)
107     return createStringError(errc::not_supported,
108                        ".debug_addr table at offset 0x%" PRIx32
109                        " has unsupported address size %" PRIu8,
110                        HeaderOffset, HeaderData.AddrSize);
111   if (HeaderData.AddrSize != AddrSize && AddrSize != 0)
112     return createStringError(errc::invalid_argument,
113                        ".debug_addr table at offset 0x%" PRIx32
114                        " has address size %" PRIu8
115                        " which is different from CU address size %" PRIu8,
116                        HeaderOffset, HeaderData.AddrSize, AddrSize);
117 
118   // TODO: add support for non-zero segment selector size.
119   if (HeaderData.SegSize != 0)
120     return createStringError(errc::not_supported,
121                        ".debug_addr table at offset 0x%" PRIx32
122                        " has unsupported segment selector size %" PRIu8,
123                        HeaderOffset, HeaderData.SegSize);
124   if (DataSize % HeaderData.AddrSize != 0) {
125     invalidateLength();
126     return createStringError(errc::invalid_argument,
127                        ".debug_addr table at offset 0x%" PRIx32
128                        " contains data of size %" PRIu32
129                        " which is not a multiple of addr size %" PRIu8,
130                        HeaderOffset, DataSize, HeaderData.AddrSize);
131   }
132   Data.setAddressSize(HeaderData.AddrSize);
133   uint32_t AddrCount = DataSize / HeaderData.AddrSize;
134   for (uint32_t I = 0; I < AddrCount; ++I)
135     if (HeaderData.AddrSize == 4)
136       Addrs.push_back(Data.getU32(OffsetPtr));
137     else
138       Addrs.push_back(Data.getU64(OffsetPtr));
139   return Error::success();
140 }
141 
dump(raw_ostream & OS,DIDumpOptions DumpOpts) const142 void DWARFDebugAddrTable::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
143   if (DumpOpts.Verbose)
144     OS << format("0x%8.8" PRIx32 ": ", HeaderOffset);
145   OS << format("Addr Section: length = 0x%8.8" PRIx32
146                ", version = 0x%4.4" PRIx16 ", "
147                "addr_size = 0x%2.2" PRIx8 ", seg_size = 0x%2.2" PRIx8 "\n",
148                HeaderData.Length, HeaderData.Version, HeaderData.AddrSize,
149                HeaderData.SegSize);
150 
151   static const char *Fmt32 = "0x%8.8" PRIx32;
152   static const char *Fmt64 = "0x%16.16" PRIx64;
153   std::string AddrFmt = "\n";
154   std::string AddrFmtVerbose = " => ";
155   if (HeaderData.AddrSize == 4) {
156     AddrFmt.append(Fmt32);
157     AddrFmtVerbose.append(Fmt32);
158   }
159   else {
160     AddrFmt.append(Fmt64);
161     AddrFmtVerbose.append(Fmt64);
162   }
163 
164   if (Addrs.size() > 0) {
165     OS << "Addrs: [";
166     for (uint64_t Addr : Addrs) {
167       OS << format(AddrFmt.c_str(), Addr);
168       if (DumpOpts.Verbose)
169         OS << format(AddrFmtVerbose.c_str(),
170                      Addr + HeaderOffset + sizeof(HeaderData));
171     }
172     OS << "\n]\n";
173   }
174 }
175 
getAddrEntry(uint32_t Index) const176 Expected<uint64_t> DWARFDebugAddrTable::getAddrEntry(uint32_t Index) const {
177   if (Index < Addrs.size())
178     return Addrs[Index];
179   return createStringError(errc::invalid_argument,
180                            "Index %" PRIu32 " is out of range of the "
181                            ".debug_addr table at offset 0x%" PRIx32,
182                            Index, HeaderOffset);
183 }
184 
getLength() const185 uint32_t DWARFDebugAddrTable::getLength() const {
186   if (HeaderData.Length == 0)
187     return 0;
188   // TODO: DWARF64 support.
189   return HeaderData.Length + sizeof(uint32_t);
190 }
191 
getDataSize() const192 uint32_t DWARFDebugAddrTable::getDataSize() const {
193   if (DataSize != 0)
194     return DataSize;
195   if (getLength() == 0)
196     return 0;
197   return getLength() - getHeaderSize();
198 }
199