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"
13*cba595daSVictor Leschuk #include "llvm/Support/Errc.h"
14c2dfd502SJames Henderson #include "llvm/Support/Error.h"
15c2dfd502SJames Henderson #include "llvm/Support/Format.h"
16c2dfd502SJames Henderson #include "llvm/Support/raw_ostream.h"
17c2dfd502SJames Henderson 
18c2dfd502SJames Henderson using namespace llvm;
19c2dfd502SJames Henderson 
20439801baSWolfgang Pieb Error RangeListEntry::extract(DWARFDataExtractor Data, uint32_t End,
213fb9e3f3SWolfgang Pieb                               uint32_t *OffsetPtr) {
223fb9e3f3SWolfgang Pieb   Offset = *OffsetPtr;
23ad60559bSWolfgang Pieb   SectionIndex = -1ULL;
243fb9e3f3SWolfgang Pieb   // The caller should guarantee that we have at least 1 byte available, so
253fb9e3f3SWolfgang Pieb   // we just assert instead of revalidate.
263fb9e3f3SWolfgang Pieb   assert(*OffsetPtr < End &&
273fb9e3f3SWolfgang Pieb          "not enough space to extract a rangelist encoding");
28c2dfd502SJames Henderson   uint8_t Encoding = Data.getU8(OffsetPtr);
293fb9e3f3SWolfgang Pieb 
30c2dfd502SJames Henderson   switch (Encoding) {
31c2dfd502SJames Henderson   case dwarf::DW_RLE_end_of_list:
323fb9e3f3SWolfgang Pieb     Value0 = Value1 = 0;
33c2dfd502SJames Henderson     break;
34c2dfd502SJames Henderson   // TODO: Support other encodings.
35c2dfd502SJames Henderson   case dwarf::DW_RLE_base_addressx:
36*cba595daSVictor Leschuk     return createStringError(errc::not_supported,
37*cba595daSVictor Leschuk                        "unsupported rnglists encoding DW_RLE_base_addressx "
38c2dfd502SJames Henderson                        "at offset 0x%" PRIx32,
39c2dfd502SJames Henderson                        *OffsetPtr - 1);
40c2dfd502SJames Henderson   case dwarf::DW_RLE_startx_endx:
41*cba595daSVictor Leschuk     return createStringError(errc::not_supported,
42*cba595daSVictor Leschuk                        "unsupported rnglists encoding DW_RLE_startx_endx at "
43c2dfd502SJames Henderson                        "offset 0x%" PRIx32,
44c2dfd502SJames Henderson                        *OffsetPtr - 1);
45c2dfd502SJames Henderson   case dwarf::DW_RLE_startx_length:
46*cba595daSVictor Leschuk     return createStringError(errc::not_supported,
47*cba595daSVictor Leschuk                        "unsupported rnglists encoding DW_RLE_startx_length "
48c2dfd502SJames Henderson                        "at offset 0x%" PRIx32,
49c2dfd502SJames Henderson                        *OffsetPtr - 1);
50ab068eaaSWolfgang Pieb   case dwarf::DW_RLE_offset_pair: {
51ab068eaaSWolfgang Pieb     uint32_t PreviousOffset = *OffsetPtr - 1;
523fb9e3f3SWolfgang Pieb     Value0 = Data.getULEB128(OffsetPtr);
533fb9e3f3SWolfgang Pieb     Value1 = Data.getULEB128(OffsetPtr);
54ab068eaaSWolfgang Pieb     if (End < *OffsetPtr)
55*cba595daSVictor Leschuk       return createStringError(errc::invalid_argument,
56*cba595daSVictor Leschuk                          "read past end of table when reading "
57ab068eaaSWolfgang Pieb                          "DW_RLE_offset_pair encoding at offset 0x%" PRIx32,
58ab068eaaSWolfgang Pieb                          PreviousOffset);
59ab068eaaSWolfgang Pieb     break;
60ab068eaaSWolfgang Pieb   }
61ab068eaaSWolfgang Pieb   case dwarf::DW_RLE_base_address: {
623fb9e3f3SWolfgang Pieb     if ((End - *OffsetPtr) < Data.getAddressSize())
63*cba595daSVictor Leschuk       return createStringError(errc::invalid_argument,
64*cba595daSVictor Leschuk                          "insufficient space remaining in table for "
65ab068eaaSWolfgang Pieb                          "DW_RLE_base_address encoding at offset 0x%" PRIx32,
66c2dfd502SJames Henderson                          *OffsetPtr - 1);
67ad60559bSWolfgang Pieb     Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
68ab068eaaSWolfgang Pieb     break;
69ab068eaaSWolfgang Pieb   }
70c2dfd502SJames Henderson   case dwarf::DW_RLE_start_end: {
713fb9e3f3SWolfgang Pieb     if ((End - *OffsetPtr) < unsigned(Data.getAddressSize() * 2))
72*cba595daSVictor Leschuk       return createStringError(errc::invalid_argument,
73*cba595daSVictor Leschuk                          "insufficient space remaining in table for "
74c2dfd502SJames Henderson                          "DW_RLE_start_end encoding "
75c2dfd502SJames Henderson                          "at offset 0x%" PRIx32,
76c2dfd502SJames Henderson                          *OffsetPtr - 1);
77ad60559bSWolfgang Pieb     Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
78ad60559bSWolfgang Pieb     Value1 = Data.getRelocatedAddress(OffsetPtr);
79c2dfd502SJames Henderson     break;
80c2dfd502SJames Henderson   }
81c2dfd502SJames Henderson   case dwarf::DW_RLE_start_length: {
82c2dfd502SJames Henderson     uint32_t PreviousOffset = *OffsetPtr - 1;
83ad60559bSWolfgang Pieb     Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
843fb9e3f3SWolfgang Pieb     Value1 = Data.getULEB128(OffsetPtr);
85c2dfd502SJames Henderson     if (End < *OffsetPtr)
86*cba595daSVictor Leschuk       return createStringError(errc::invalid_argument,
87*cba595daSVictor Leschuk                          "read past end of table when reading "
88c2dfd502SJames Henderson                          "DW_RLE_start_length encoding at offset 0x%" PRIx32,
89c2dfd502SJames Henderson                          PreviousOffset);
90c2dfd502SJames Henderson     break;
91c2dfd502SJames Henderson   }
92c2dfd502SJames Henderson   default:
93*cba595daSVictor Leschuk     return createStringError(errc::not_supported,
94*cba595daSVictor Leschuk                        "unknown rnglists encoding 0x%" PRIx32
95c2dfd502SJames Henderson                        " at offset 0x%" PRIx32,
96c2dfd502SJames Henderson                        uint32_t(Encoding), *OffsetPtr - 1);
97c2dfd502SJames Henderson   }
983fb9e3f3SWolfgang Pieb 
993fb9e3f3SWolfgang Pieb   EntryKind = Encoding;
1003fb9e3f3SWolfgang Pieb   return Error::success();
101c2dfd502SJames Henderson }
102c2dfd502SJames Henderson 
103ad60559bSWolfgang Pieb DWARFAddressRangesVector DWARFDebugRnglist::getAbsoluteRanges(
104ad60559bSWolfgang Pieb     llvm::Optional<BaseAddress> BaseAddr) const {
105ad60559bSWolfgang Pieb   DWARFAddressRangesVector Res;
106ad60559bSWolfgang Pieb   for (const RangeListEntry &RLE : Entries) {
107ad60559bSWolfgang Pieb     if (RLE.EntryKind == dwarf::DW_RLE_end_of_list)
108ad60559bSWolfgang Pieb       break;
109ad60559bSWolfgang Pieb     if (RLE.EntryKind == dwarf::DW_RLE_base_address) {
110ad60559bSWolfgang Pieb       BaseAddr = {RLE.Value0, RLE.SectionIndex};
111ad60559bSWolfgang Pieb       continue;
112ad60559bSWolfgang Pieb     }
113ad60559bSWolfgang Pieb 
114ad60559bSWolfgang Pieb     DWARFAddressRange E;
115ad60559bSWolfgang Pieb     E.SectionIndex = RLE.SectionIndex;
116ad60559bSWolfgang Pieb     if (BaseAddr && E.SectionIndex == -1ULL)
117ad60559bSWolfgang Pieb       E.SectionIndex = BaseAddr->SectionIndex;
118ad60559bSWolfgang Pieb 
119ad60559bSWolfgang Pieb     switch (RLE.EntryKind) {
120ad60559bSWolfgang Pieb     case dwarf::DW_RLE_offset_pair:
121ad60559bSWolfgang Pieb       E.LowPC = RLE.Value0;
122ad60559bSWolfgang Pieb       E.HighPC = RLE.Value1;
123ad60559bSWolfgang Pieb       if (BaseAddr) {
124ad60559bSWolfgang Pieb         E.LowPC += BaseAddr->Address;
125ad60559bSWolfgang Pieb         E.HighPC += BaseAddr->Address;
126ad60559bSWolfgang Pieb       }
127ad60559bSWolfgang Pieb       break;
128ad60559bSWolfgang Pieb     case dwarf::DW_RLE_start_end:
129ad60559bSWolfgang Pieb       E.LowPC = RLE.Value0;
130ad60559bSWolfgang Pieb       E.HighPC = RLE.Value1;
131ad60559bSWolfgang Pieb       break;
132ad60559bSWolfgang Pieb     case dwarf::DW_RLE_start_length:
133ad60559bSWolfgang Pieb       E.LowPC = RLE.Value0;
134ad60559bSWolfgang Pieb       E.HighPC = E.LowPC + RLE.Value1;
135ad60559bSWolfgang Pieb       break;
136ad60559bSWolfgang Pieb     default:
137ad60559bSWolfgang Pieb       // Unsupported encodings should have been reported during extraction,
138ad60559bSWolfgang Pieb       // so we should not run into any here.
139ad60559bSWolfgang Pieb       llvm_unreachable("Unsupported range list encoding");
140ad60559bSWolfgang Pieb     }
141ad60559bSWolfgang Pieb     Res.push_back(E);
142ad60559bSWolfgang Pieb   }
143ad60559bSWolfgang Pieb   return Res;
144ad60559bSWolfgang Pieb }
145ad60559bSWolfgang Pieb 
146439801baSWolfgang Pieb void RangeListEntry::dump(raw_ostream &OS, uint8_t AddrSize,
147439801baSWolfgang Pieb                           uint8_t MaxEncodingStringLength,
148439801baSWolfgang Pieb                           uint64_t &CurrentBase, DIDumpOptions DumpOpts) const {
149439801baSWolfgang Pieb   auto PrintRawEntry = [](raw_ostream &OS, const RangeListEntry &Entry,
150ab068eaaSWolfgang Pieb                           uint8_t AddrSize, DIDumpOptions DumpOpts) {
151ab068eaaSWolfgang Pieb     if (DumpOpts.Verbose) {
152ab068eaaSWolfgang Pieb       DumpOpts.DisplayRawContents = true;
153ab068eaaSWolfgang Pieb       DWARFAddressRange(Entry.Value0, Entry.Value1)
154ab068eaaSWolfgang Pieb           .dump(OS, AddrSize, DumpOpts);
155ab068eaaSWolfgang Pieb       OS << " => ";
156ab068eaaSWolfgang Pieb     }
157ab068eaaSWolfgang Pieb   };
158ab068eaaSWolfgang Pieb 
159a0729d41SWolfgang Pieb   if (DumpOpts.Verbose) {
160a0729d41SWolfgang Pieb     // Print the section offset in verbose mode.
161439801baSWolfgang Pieb     OS << format("0x%8.8" PRIx32 ":", Offset);
162439801baSWolfgang Pieb     auto EncodingString = dwarf::RangeListEncodingString(EntryKind);
163a0729d41SWolfgang Pieb     // Unsupported encodings should have been reported during parsing.
164a0729d41SWolfgang Pieb     assert(!EncodingString.empty() && "Unknown range entry encoding");
165a0729d41SWolfgang Pieb     OS << format(" [%s%*c", EncodingString.data(),
166a0729d41SWolfgang Pieb                  MaxEncodingStringLength - EncodingString.size() + 1, ']');
167439801baSWolfgang Pieb     if (EntryKind != dwarf::DW_RLE_end_of_list)
168a0729d41SWolfgang Pieb       OS << ": ";
169a0729d41SWolfgang Pieb   }
170a0729d41SWolfgang Pieb 
171439801baSWolfgang Pieb   switch (EntryKind) {
172a0729d41SWolfgang Pieb   case dwarf::DW_RLE_end_of_list:
173a0729d41SWolfgang Pieb     OS << (DumpOpts.Verbose ? "" : "<End of list>");
174a0729d41SWolfgang Pieb     break;
175ab068eaaSWolfgang Pieb   case dwarf::DW_RLE_base_address:
176ab068eaaSWolfgang Pieb     // In non-verbose mode we do not print anything for this entry.
177439801baSWolfgang Pieb     CurrentBase = Value0;
178ab068eaaSWolfgang Pieb     if (!DumpOpts.Verbose)
179ab068eaaSWolfgang Pieb       return;
180439801baSWolfgang Pieb     OS << format(" 0x%*.*" PRIx64, AddrSize * 2, AddrSize * 2, Value0);
181ab068eaaSWolfgang Pieb     break;
182a0729d41SWolfgang Pieb   case dwarf::DW_RLE_start_length:
183439801baSWolfgang Pieb     PrintRawEntry(OS, *this, AddrSize, DumpOpts);
184439801baSWolfgang Pieb     DWARFAddressRange(Value0, Value0 + Value1).dump(OS, AddrSize, DumpOpts);
185a0729d41SWolfgang Pieb     break;
186ab068eaaSWolfgang Pieb   case dwarf::DW_RLE_offset_pair:
187439801baSWolfgang Pieb     PrintRawEntry(OS, *this, AddrSize, DumpOpts);
188439801baSWolfgang Pieb     DWARFAddressRange(Value0 + CurrentBase, Value1 + CurrentBase)
189ab068eaaSWolfgang Pieb         .dump(OS, AddrSize, DumpOpts);
190ab068eaaSWolfgang Pieb     break;
191a0729d41SWolfgang Pieb   case dwarf::DW_RLE_start_end:
192439801baSWolfgang Pieb     DWARFAddressRange(Value0, Value1).dump(OS, AddrSize, DumpOpts);
193a0729d41SWolfgang Pieb     break;
194a0729d41SWolfgang Pieb   default:
195a0729d41SWolfgang Pieb     llvm_unreachable("Unsupported range list encoding");
196a0729d41SWolfgang Pieb   }
197a0729d41SWolfgang Pieb   OS << "\n";
198a0729d41SWolfgang Pieb }
199