1 //===- DWARFDebugRnglists.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/DWARFDebugRnglists.h"
11 #include "llvm/BinaryFormat/Dwarf.h"
12 #include "llvm/DebugInfo/DWARF/DWARFUnit.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 template <typename... Ts>
20 static Error createError(char const *Fmt, const Ts &... Vals) {
21   std::string Buffer;
22   raw_string_ostream Stream(Buffer);
23   Stream << format(Fmt, Vals...);
24   return make_error<StringError>(Stream.str(), inconvertibleErrorCode());
25 }
26 
27 namespace llvm {   // workaround for gcc bug
28 template <>
29 Error DWARFListType<RangeListEntry>::createError(const char *Fmt, const char *s,
30                                                  uint32_t Val) {
31   return ::createError(Fmt, s, Val);
32 }
33 }
34 
35 Error RangeListEntry::extract(DWARFDataExtractor Data, uint32_t End,
36                               uint32_t *OffsetPtr) {
37   Offset = *OffsetPtr;
38   SectionIndex = -1ULL;
39   // The caller should guarantee that we have at least 1 byte available, so
40   // we just assert instead of revalidate.
41   assert(*OffsetPtr < End &&
42          "not enough space to extract a rangelist encoding");
43   uint8_t Encoding = Data.getU8(OffsetPtr);
44 
45   switch (Encoding) {
46   case dwarf::DW_RLE_end_of_list:
47     Value0 = Value1 = 0;
48     break;
49   // TODO: Support other encodings.
50   case dwarf::DW_RLE_base_addressx:
51     return createError("unsupported rnglists encoding DW_RLE_base_addressx "
52                        "at offset 0x%" PRIx32,
53                        *OffsetPtr - 1);
54   case dwarf::DW_RLE_startx_endx:
55     return createError("unsupported rnglists encoding DW_RLE_startx_endx at "
56                        "offset 0x%" PRIx32,
57                        *OffsetPtr - 1);
58   case dwarf::DW_RLE_startx_length:
59     return createError("unsupported rnglists encoding DW_RLE_startx_length "
60                        "at offset 0x%" PRIx32,
61                        *OffsetPtr - 1);
62   case dwarf::DW_RLE_offset_pair: {
63     uint32_t PreviousOffset = *OffsetPtr - 1;
64     Value0 = Data.getULEB128(OffsetPtr);
65     Value1 = Data.getULEB128(OffsetPtr);
66     if (End < *OffsetPtr)
67       return createError("read past end of table when reading "
68                          "DW_RLE_offset_pair encoding at offset 0x%" PRIx32,
69                          PreviousOffset);
70     break;
71   }
72   case dwarf::DW_RLE_base_address: {
73     if ((End - *OffsetPtr) < Data.getAddressSize())
74       return createError("insufficient space remaining in table for "
75                          "DW_RLE_base_address encoding at offset 0x%" PRIx32,
76                          *OffsetPtr - 1);
77     Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
78     break;
79   }
80   case dwarf::DW_RLE_start_end: {
81     if ((End - *OffsetPtr) < unsigned(Data.getAddressSize() * 2))
82       return createError("insufficient space remaining in table for "
83                          "DW_RLE_start_end encoding "
84                          "at offset 0x%" PRIx32,
85                          *OffsetPtr - 1);
86     Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
87     Value1 = Data.getRelocatedAddress(OffsetPtr);
88     break;
89   }
90   case dwarf::DW_RLE_start_length: {
91     uint32_t PreviousOffset = *OffsetPtr - 1;
92     Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
93     Value1 = Data.getULEB128(OffsetPtr);
94     if (End < *OffsetPtr)
95       return createError("read past end of table when reading "
96                          "DW_RLE_start_length encoding at offset 0x%" PRIx32,
97                          PreviousOffset);
98     break;
99   }
100   default:
101     return createError("unknown rnglists encoding 0x%" PRIx32
102                        " at offset 0x%" PRIx32,
103                        uint32_t(Encoding), *OffsetPtr - 1);
104   }
105 
106   EntryKind = Encoding;
107   return Error::success();
108 }
109 
110 DWARFAddressRangesVector DWARFDebugRnglist::getAbsoluteRanges(
111     llvm::Optional<BaseAddress> BaseAddr) const {
112   DWARFAddressRangesVector Res;
113   for (const RangeListEntry &RLE : Entries) {
114     if (RLE.EntryKind == dwarf::DW_RLE_end_of_list)
115       break;
116     if (RLE.EntryKind == dwarf::DW_RLE_base_address) {
117       BaseAddr = {RLE.Value0, RLE.SectionIndex};
118       continue;
119     }
120 
121     DWARFAddressRange E;
122     E.SectionIndex = RLE.SectionIndex;
123     if (BaseAddr && E.SectionIndex == -1ULL)
124       E.SectionIndex = BaseAddr->SectionIndex;
125 
126     switch (RLE.EntryKind) {
127     case dwarf::DW_RLE_offset_pair:
128       E.LowPC = RLE.Value0;
129       E.HighPC = RLE.Value1;
130       if (BaseAddr) {
131         E.LowPC += BaseAddr->Address;
132         E.HighPC += BaseAddr->Address;
133       }
134       break;
135     case dwarf::DW_RLE_start_end:
136       E.LowPC = RLE.Value0;
137       E.HighPC = RLE.Value1;
138       break;
139     case dwarf::DW_RLE_start_length:
140       E.LowPC = RLE.Value0;
141       E.HighPC = E.LowPC + RLE.Value1;
142       break;
143     default:
144       // Unsupported encodings should have been reported during extraction,
145       // so we should not run into any here.
146       llvm_unreachable("Unsupported range list encoding");
147     }
148     Res.push_back(E);
149   }
150   return Res;
151 }
152 
153 void RangeListEntry::dump(raw_ostream &OS, uint8_t AddrSize,
154                           uint8_t MaxEncodingStringLength,
155                           uint64_t &CurrentBase, DIDumpOptions DumpOpts) const {
156   auto PrintRawEntry = [](raw_ostream &OS, const RangeListEntry &Entry,
157                           uint8_t AddrSize, DIDumpOptions DumpOpts) {
158     if (DumpOpts.Verbose) {
159       DumpOpts.DisplayRawContents = true;
160       DWARFAddressRange(Entry.Value0, Entry.Value1)
161           .dump(OS, AddrSize, DumpOpts);
162       OS << " => ";
163     }
164   };
165 
166   if (DumpOpts.Verbose) {
167     // Print the section offset in verbose mode.
168     OS << format("0x%8.8" PRIx32 ":", Offset);
169     auto EncodingString = dwarf::RangeListEncodingString(EntryKind);
170     // Unsupported encodings should have been reported during parsing.
171     assert(!EncodingString.empty() && "Unknown range entry encoding");
172     OS << format(" [%s%*c", EncodingString.data(),
173                  MaxEncodingStringLength - EncodingString.size() + 1, ']');
174     if (EntryKind != dwarf::DW_RLE_end_of_list)
175       OS << ": ";
176   }
177 
178   switch (EntryKind) {
179   case dwarf::DW_RLE_end_of_list:
180     OS << (DumpOpts.Verbose ? "" : "<End of list>");
181     break;
182   case dwarf::DW_RLE_base_address:
183     // In non-verbose mode we do not print anything for this entry.
184     CurrentBase = Value0;
185     if (!DumpOpts.Verbose)
186       return;
187     OS << format(" 0x%*.*" PRIx64, AddrSize * 2, AddrSize * 2, Value0);
188     break;
189   case dwarf::DW_RLE_start_length:
190     PrintRawEntry(OS, *this, AddrSize, DumpOpts);
191     DWARFAddressRange(Value0, Value0 + Value1).dump(OS, AddrSize, DumpOpts);
192     break;
193   case dwarf::DW_RLE_offset_pair:
194     PrintRawEntry(OS, *this, AddrSize, DumpOpts);
195     DWARFAddressRange(Value0 + CurrentBase, Value1 + CurrentBase)
196         .dump(OS, AddrSize, DumpOpts);
197     break;
198   case dwarf::DW_RLE_start_end:
199     DWARFAddressRange(Value0, Value1).dump(OS, AddrSize, DumpOpts);
200     break;
201   default:
202     llvm_unreachable("Unsupported range list encoding");
203   }
204   OS << "\n";
205 }
206