LLVM  10.0.0svn
DWARFDebugLoc.cpp
Go to the documentation of this file.
1 //===- DWARFDebugLoc.cpp --------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
10 #include "llvm/ADT/StringRef.h"
16 #include "llvm/Support/Compiler.h"
17 #include "llvm/Support/Format.h"
18 #include "llvm/Support/WithColor.h"
20 #include <algorithm>
21 #include <cinttypes>
22 #include <cstdint>
23 
24 using namespace llvm;
25 
26 // When directly dumping the .debug_loc without a compile unit, we have to guess
27 // at the DWARF version. This only affects DW_OP_call_ref, which is a rare
28 // expression that LLVM doesn't produce. Guessing the wrong version means we
29 // won't be able to pretty print expressions in DWARF2 binaries produced by
30 // non-LLVM tools.
32  bool IsLittleEndian, unsigned AddressSize,
33  const MCRegisterInfo *MRI, DWARFUnit *U) {
34  DWARFDataExtractor Extractor(toStringRef(Data), IsLittleEndian, AddressSize);
35  DWARFExpression(Extractor, dwarf::DWARF_VERSION, AddressSize).print(OS, MRI, U);
36 }
37 
38 void DWARFDebugLoc::LocationList::dump(raw_ostream &OS, uint64_t BaseAddress,
39  bool IsLittleEndian,
40  unsigned AddressSize,
41  const MCRegisterInfo *MRI, DWARFUnit *U,
42  unsigned Indent) const {
43  for (const Entry &E : Entries) {
44  OS << '\n';
45  OS.indent(Indent);
46  OS << format("[0x%*.*" PRIx64 ", ", AddressSize * 2, AddressSize * 2,
47  BaseAddress + E.Begin);
48  OS << format(" 0x%*.*" PRIx64 ")", AddressSize * 2, AddressSize * 2,
49  BaseAddress + E.End);
50  OS << ": ";
51 
52  dumpExpression(OS, E.Loc, IsLittleEndian, AddressSize, MRI, U);
53  }
54 }
55 
58  auto It = partition_point(
59  Locations, [=](const LocationList &L) { return L.Offset < Offset; });
60  if (It != Locations.end() && It->Offset == Offset)
61  return &(*It);
62  return nullptr;
63 }
64 
66  Optional<uint64_t> Offset) const {
67  auto DumpLocationList = [&](const LocationList &L) {
68  OS << format("0x%8.8" PRIx64 ": ", L.Offset);
69  L.dump(OS, 0, IsLittleEndian, AddressSize, MRI, nullptr, 12);
70  OS << "\n\n";
71  };
72 
73  if (Offset) {
74  if (auto *L = getLocationListAtOffset(*Offset))
75  DumpLocationList(*L);
76  return;
77  }
78 
79  for (const LocationList &L : Locations) {
80  DumpLocationList(L);
81  }
82 }
83 
86  uint64_t *Offset) {
87  LocationList LL;
88  LL.Offset = *Offset;
89  DataExtractor::Cursor C(*Offset);
90 
91  // 2.6.2 Location Lists
92  // A location list entry consists of:
93  while (true) {
94  Entry E;
95 
96  // 1. A beginning address offset. ...
97  E.Begin = Data.getRelocatedAddress(C);
98 
99  // 2. An ending address offset. ...
100  E.End = Data.getRelocatedAddress(C);
101 
102  if (Error Err = C.takeError())
103  return std::move(Err);
104  // The end of any given location list is marked by an end of list entry,
105  // which consists of a 0 for the beginning address offset and a 0 for the
106  // ending address offset.
107  if (E.Begin == 0 && E.End == 0) {
108  *Offset = C.tell();
109  return LL;
110  }
111 
112  unsigned Bytes = Data.getU16(C);
113  // A single location description describing the location of the object...
114  Data.getU8(C, E.Loc, Bytes);
115  LL.Entries.push_back(std::move(E));
116  }
117 }
118 
120  IsLittleEndian = data.isLittleEndian();
121  AddressSize = data.getAddressSize();
122 
123  uint64_t Offset = 0;
124  while (Offset < data.getData().size()) {
125  if (auto LL = parseOneLocationList(data, &Offset))
126  Locations.push_back(std::move(*LL));
127  else {
128  logAllUnhandledErrors(LL.takeError(), WithColor::error());
129  break;
130  }
131  }
132 }
133 
136  uint64_t *Offset, unsigned Version) {
137  LocationList LL;
138  LL.Offset = *Offset;
139  DataExtractor::Cursor C(*Offset);
140 
141  // dwarf::DW_LLE_end_of_list_entry is 0 and indicates the end of the list.
142  while (auto Kind = static_cast<dwarf::LocationListEntry>(Data.getU8(C))) {
143  Entry E;
144  E.Kind = Kind;
145  switch (Kind) {
147  E.Value0 = Data.getULEB128(C);
148  // Pre-DWARF 5 has different interpretation of the length field. We have
149  // to support both pre- and standartized styles for the compatibility.
150  if (Version < 5)
151  E.Value1 = Data.getU32(C);
152  else
153  E.Value1 = Data.getULEB128(C);
154  break;
156  E.Value0 = Data.getAddress(C);
157  E.Value1 = Data.getULEB128(C);
158  break;
160  E.Value0 = Data.getULEB128(C);
161  E.Value1 = Data.getULEB128(C);
162  break;
164  E.Value0 = Data.getAddress(C);
165  break;
166  default:
167  cantFail(C.takeError());
169  "LLE of kind %x not supported", (int)Kind);
170  }
171 
173  unsigned Bytes = Version >= 5 ? Data.getULEB128(C) : Data.getU16(C);
174  // A single location description describing the location of the object...
175  Data.getU8(C, E.Loc, Bytes);
176  }
177 
178  LL.Entries.push_back(std::move(E));
179  }
180  if (Error Err = C.takeError())
181  return std::move(Err);
182  *Offset = C.tell();
183  return LL;
184 }
185 
187  IsLittleEndian = data.isLittleEndian();
188  AddressSize = data.getAddressSize();
189 
190  uint64_t Offset = 0;
191  while (Offset < data.getData().size()) {
192  if (auto LL = parseOneLocationList(data, &Offset, Version))
193  Locations.push_back(std::move(*LL));
194  else {
195  logAllUnhandledErrors(LL.takeError(), WithColor::error());
196  return;
197  }
198  }
199 }
200 
203  auto It = partition_point(
204  Locations, [=](const LocationList &L) { return L.Offset < Offset; });
205  if (It != Locations.end() && It->Offset == Offset)
206  return &(*It);
207  return nullptr;
208 }
209 
211  bool IsLittleEndian,
212  unsigned AddressSize,
213  const MCRegisterInfo *MRI,
214  DWARFUnit *U,
215  unsigned Indent) const {
216  for (const Entry &E : Entries) {
217  switch (E.Kind) {
219  OS << '\n';
220  OS.indent(Indent);
221  OS << "Addr idx " << E.Value0 << " (w/ length " << E.Value1 << "): ";
222  break;
224  OS << '\n';
225  OS.indent(Indent);
226  OS << format("[0x%*.*" PRIx64 ", 0x%*.*" PRIx64 "): ", AddressSize * 2,
227  AddressSize * 2, E.Value0, AddressSize * 2, AddressSize * 2,
228  E.Value0 + E.Value1);
229  break;
231  OS << '\n';
232  OS.indent(Indent);
233  OS << format("[0x%*.*" PRIx64 ", 0x%*.*" PRIx64 "): ", AddressSize * 2,
234  AddressSize * 2, BaseAddr + E.Value0, AddressSize * 2,
235  AddressSize * 2, BaseAddr + E.Value1);
236  break;
238  BaseAddr = E.Value0;
239  break;
240  default:
241  llvm_unreachable("unreachable locations list kind");
242  }
243 
244  dumpExpression(OS, E.Loc, IsLittleEndian, AddressSize, MRI, U);
245  }
246 }
247 
248 void DWARFDebugLoclists::dump(raw_ostream &OS, uint64_t BaseAddr,
249  const MCRegisterInfo *MRI,
250  Optional<uint64_t> Offset) const {
251  auto DumpLocationList = [&](const LocationList &L) {
252  OS << format("0x%8.8" PRIx64 ": ", L.Offset);
253  L.dump(OS, BaseAddr, IsLittleEndian, AddressSize, MRI, nullptr, /*Indent=*/12);
254  OS << "\n\n";
255  };
256 
257  if (Offset) {
258  if (auto *L = getLocationListAtOffset(*Offset))
259  DumpLocationList(*L);
260  return;
261  }
262 
263  for (const LocationList &L : Locations) {
264  DumpLocationList(L);
265  }
266 }
A list of locations that contain one variable.
Definition: DWARFDebugLoc.h:36
void cantFail(Error Err, const char *Msg=nullptr)
Report a fatal error if Err is a failure value.
Definition: Error.h:703
uint64_t CallInst * C
uint8_t getU8(uint64_t *offset_ptr, Error *Err=nullptr) const
Extract a uint8_t value from *offset_ptr.
uint64_t getRelocatedAddress(uint64_t *Off, uint64_t *SecIx=nullptr) const
Extracts an address-sized value and applies a relocation to the result if one exists for the given of...
uint16_t getU16(uint64_t *offset_ptr, Error *Err=nullptr) const
Extract a uint16_t value from *offset_ptr.
This class represents lattice values for constants.
Definition: AllocatorList.h:23
void dump(raw_ostream &OS, const MCRegisterInfo *RegInfo, Optional< uint64_t > Offset) const
Print the location lists found within the debug_loc section.
uint64_t tell() const
Return the current position of this Cursor.
Definition: DataExtractor.h:71
static raw_ostream & error()
Convenience method for printing "error: " to stderr.
Definition: WithColor.cpp:60
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
Definition: Format.h:124
raw_ostream & indent(unsigned NumSpaces)
indent - Insert &#39;NumSpaces&#39; spaces.
uint32_t getU32(uint64_t *offset_ptr, Error *Err=nullptr) const
Extract a uint32_t value from *offset_ptr.
StringRef getData() const
Get the data pointed to by this extractor.
Definition: DataExtractor.h:87
void dump(raw_ostream &OS, uint64_t BaseAddr, const MCRegisterInfo *RegInfo, Optional< uint64_t > Offset) const
Error takeError()
Return error contained inside this Cursor, if any.
Definition: DataExtractor.h:75
A single location within a location list.
Definition: DWARFDebugLoc.h:26
Tagged union holding either a T or a Error.
Definition: yaml2obj.h:21
auto partition_point(R &&Range, Predicate P) -> decltype(adl_begin(Range))
Binary search for the first iterator in a range where a predicate is false.
Definition: STLExtras.h:1302
LLVM_NODISCARD size_t size() const
size - Get the string size.
Definition: StringRef.h:144
bool isLittleEndian() const
Get the endianness for this extractor.
Definition: DataExtractor.h:89
MCRegisterInfo base class - We assume that the target defines a static array of MCRegisterDesc object...
void dump(raw_ostream &OS, uint64_t BaseAddress, bool IsLittleEndian, unsigned AddressSize, const MCRegisterInfo *MRI, DWARFUnit *U, unsigned Indent) const
Dump this list on OS.
unsigned const MachineRegisterInfo * MRI
LocationList const * getLocationListAtOffset(uint64_t Offset) const
Return the location list at the given offset or nullptr.
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
uint8_t getAddressSize() const
Get the address size for this extractor.
Definition: DataExtractor.h:91
static Expected< LocationList > parseOneLocationList(const DWARFDataExtractor &Data, uint64_t *Offset)
A class representing a position in a DataExtractor, as well as any error encountered during extractio...
Definition: DataExtractor.h:54
uint64_t getULEB128(uint64_t *offset_ptr, llvm::Error *Err=nullptr) const
Extract a unsigned LEB128 value from *offset_ptr.
StringRef toStringRef(bool B)
Construct a string ref from a boolean.
Definition: StringExtras.h:52
void logAllUnhandledErrors(Error E, raw_ostream &OS, Twine ErrorBanner={})
Log all errors (if any) in E to OS.
Definition: Error.cpp:61
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
SmallVector< uint8_t, 4 > Loc
Definition: DWARFDebugLoc.h:81
A DataExtractor (typically for an in-memory copy of an object-file section) plus a relocation map for...
static Expected< LocationList > parseOneLocationList(const DataExtractor &Data, uint64_t *Offset, unsigned Version)
uint64_t Begin
The beginning address of the instruction range.
Definition: DWARFDebugLoc.h:28
LocationList const * getLocationListAtOffset(uint64_t Offset) const
Return the location list at the given offset or nullptr.
static void dumpExpression(raw_ostream &OS, ArrayRef< uint8_t > Data, bool IsLittleEndian, unsigned AddressSize, const MCRegisterInfo *MRI, DWARFUnit *U)
void print(raw_ostream &OS, const MCRegisterInfo *RegInfo, DWARFUnit *U, bool IsEH=false) const
This file contains constants used for implementing Dwarf debug support.
void parse(DataExtractor data, unsigned Version)
SmallVector< uint8_t, 4 > Loc
The location of the variable within the specified range.
Definition: DWARFDebugLoc.h:32
void dump(raw_ostream &OS, uint64_t BaseAddr, bool IsLittleEndian, unsigned AddressSize, const MCRegisterInfo *RegInfo, DWARFUnit *U, unsigned Indent) const
uint64_t Offset
The beginning offset where this location list is stored in the debug_loc section. ...
Definition: DWARFDebugLoc.h:39
uint64_t End
The ending address of the instruction range.
Definition: DWARFDebugLoc.h:30
uint64_t getAddress(uint64_t *offset_ptr) const
Extract an pointer from *offset_ptr.
Lightweight error class with error context and mandatory checking.
Definition: Error.h:157
This class implements an extremely fast bulk output stream that can only output to a stream...
Definition: raw_ostream.h:45
SmallVector< Entry, 2 > Entries
All the locations in which the variable is stored.
Definition: DWARFDebugLoc.h:41
const uint64_t Version
Definition: InstrProf.h:984
void parse(const DWARFDataExtractor &data)
Parse the debug_loc section accessible via the &#39;data&#39; parameter using the address size also given in ...
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition: Error.h:1177