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