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