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(StringRef(Data.data(), Data.size()),
35  IsLittleEndian, AddressSize);
36  DWARFExpression(Extractor, dwarf::DWARF_VERSION, AddressSize).print(OS, MRI, U);
37 }
38 
39 void DWARFDebugLoc::LocationList::dump(raw_ostream &OS, bool IsLittleEndian,
40  unsigned AddressSize,
41  const MCRegisterInfo *MRI,
42  DWARFUnit *U,
43  uint64_t BaseAddress,
44  unsigned Indent) const {
45  for (const Entry &E : Entries) {
46  OS << '\n';
47  OS.indent(Indent);
48  OS << format("[0x%*.*" PRIx64 ", ", AddressSize * 2, AddressSize * 2,
49  BaseAddress + E.Begin);
50  OS << format(" 0x%*.*" PRIx64 ")", AddressSize * 2, AddressSize * 2,
51  BaseAddress + E.End);
52  OS << ": ";
53 
54  dumpExpression(OS, E.Loc, IsLittleEndian, AddressSize, MRI, U);
55  }
56 }
57 
60  auto It = partition_point(
61  Locations, [=](const LocationList &L) { return L.Offset < Offset; });
62  if (It != Locations.end() && It->Offset == Offset)
63  return &(*It);
64  return nullptr;
65 }
66 
68  Optional<uint64_t> Offset) const {
69  auto DumpLocationList = [&](const LocationList &L) {
70  OS << format("0x%8.8x: ", L.Offset);
71  L.dump(OS, IsLittleEndian, AddressSize, MRI, nullptr, 0, 12);
72  OS << "\n\n";
73  };
74 
75  if (Offset) {
76  if (auto *L = getLocationListAtOffset(*Offset))
77  DumpLocationList(*L);
78  return;
79  }
80 
81  for (const LocationList &L : Locations) {
82  DumpLocationList(L);
83  }
84 }
85 
88  LocationList LL;
89  LL.Offset = *Offset;
90 
91  // 2.6.2 Location Lists
92  // A location list entry consists of:
93  while (true) {
94  Entry E;
95  if (!Data.isValidOffsetForDataOfSize(*Offset, 2 * Data.getAddressSize())) {
96  WithColor::error() << "location list overflows the debug_loc section.\n";
97  return None;
98  }
99 
100  // 1. A beginning address offset. ...
101  E.Begin = Data.getRelocatedAddress(Offset);
102 
103  // 2. An ending address offset. ...
104  E.End = Data.getRelocatedAddress(Offset);
105 
106  // The end of any given location list is marked by an end of list entry,
107  // which consists of a 0 for the beginning address offset and a 0 for the
108  // ending address offset.
109  if (E.Begin == 0 && E.End == 0)
110  return LL;
111 
112  if (!Data.isValidOffsetForDataOfSize(*Offset, 2)) {
113  WithColor::error() << "location list overflows the debug_loc section.\n";
114  return None;
115  }
116 
117  unsigned Bytes = Data.getU16(Offset);
118  if (!Data.isValidOffsetForDataOfSize(*Offset, Bytes)) {
119  WithColor::error() << "location list overflows the debug_loc section.\n";
120  return None;
121  }
122  // A single location description describing the location of the object...
123  StringRef str = Data.getData().substr(*Offset, Bytes);
124  *Offset += Bytes;
125  E.Loc.reserve(str.size());
126  llvm::copy(str, std::back_inserter(E.Loc));
127  LL.Entries.push_back(std::move(E));
128  }
129 }
130 
132  IsLittleEndian = data.isLittleEndian();
133  AddressSize = data.getAddressSize();
134 
135  uint32_t Offset = 0;
136  while (data.isValidOffset(Offset + data.getAddressSize() - 1)) {
137  if (auto LL = parseOneLocationList(data, &Offset))
138  Locations.push_back(std::move(*LL));
139  else
140  break;
141  }
142  if (data.isValidOffset(Offset))
143  WithColor::error() << "failed to consume entire .debug_loc section\n";
144 }
145 
148  unsigned Version) {
149  LocationList LL;
150  LL.Offset = *Offset;
151 
152  // dwarf::DW_LLE_end_of_list_entry is 0 and indicates the end of the list.
153  while (auto Kind =
154  static_cast<dwarf::LocationListEntry>(Data.getU8(Offset))) {
155 
156  Entry E;
157  E.Kind = Kind;
158  switch (Kind) {
160  E.Value0 = Data.getULEB128(Offset);
161  // Pre-DWARF 5 has different interpretation of the length field. We have
162  // to support both pre- and standartized styles for the compatibility.
163  if (Version < 5)
164  E.Value1 = Data.getU32(Offset);
165  else
166  E.Value1 = Data.getULEB128(Offset);
167  break;
169  E.Value0 = Data.getAddress(Offset);
170  E.Value1 = Data.getULEB128(Offset);
171  break;
173  E.Value0 = Data.getULEB128(Offset);
174  E.Value1 = Data.getULEB128(Offset);
175  break;
177  E.Value0 = Data.getAddress(Offset);
178  break;
179  default:
180  WithColor::error() << "dumping support for LLE of kind " << (int)Kind
181  << " not implemented\n";
182  return None;
183  }
184 
186  unsigned Bytes =
187  Version >= 5 ? Data.getULEB128(Offset) : Data.getU16(Offset);
188  // A single location description describing the location of the object...
189  StringRef str = Data.getData().substr(*Offset, Bytes);
190  *Offset += Bytes;
191  E.Loc.resize(str.size());
192  llvm::copy(str, E.Loc.begin());
193  }
194 
195  LL.Entries.push_back(std::move(E));
196  }
197  return LL;
198 }
199 
201  IsLittleEndian = data.isLittleEndian();
202  AddressSize = data.getAddressSize();
203 
204  uint32_t Offset = 0;
205  while (data.isValidOffset(Offset)) {
206  if (auto LL = parseOneLocationList(data, &Offset, Version))
207  Locations.push_back(std::move(*LL));
208  else
209  return;
210  }
211 }
212 
215  auto It = partition_point(
216  Locations, [=](const LocationList &L) { return L.Offset < Offset; });
217  if (It != Locations.end() && It->Offset == Offset)
218  return &(*It);
219  return nullptr;
220 }
221 
223  bool IsLittleEndian,
224  unsigned AddressSize,
225  const MCRegisterInfo *MRI,
226  DWARFUnit *U,
227  unsigned Indent) const {
228  for (const Entry &E : Entries) {
229  switch (E.Kind) {
231  OS << '\n';
232  OS.indent(Indent);
233  OS << "Addr idx " << E.Value0 << " (w/ length " << E.Value1 << "): ";
234  break;
236  OS << '\n';
237  OS.indent(Indent);
238  OS << format("[0x%*.*" PRIx64 ", 0x%*.*" PRIx64 "): ", AddressSize * 2,
239  AddressSize * 2, E.Value0, AddressSize * 2, AddressSize * 2,
240  E.Value0 + E.Value1);
241  break;
243  OS << '\n';
244  OS.indent(Indent);
245  OS << format("[0x%*.*" PRIx64 ", 0x%*.*" PRIx64 "): ", AddressSize * 2,
246  AddressSize * 2, BaseAddr + E.Value0, AddressSize * 2,
247  AddressSize * 2, BaseAddr + E.Value1);
248  break;
250  BaseAddr = E.Value0;
251  break;
252  default:
253  llvm_unreachable("unreachable locations list kind");
254  }
255 
256  dumpExpression(OS, E.Loc, IsLittleEndian, AddressSize, MRI, U);
257  }
258 }
259 
260 void DWARFDebugLoclists::dump(raw_ostream &OS, uint64_t BaseAddr,
261  const MCRegisterInfo *MRI,
262  Optional<uint64_t> Offset) const {
263  auto DumpLocationList = [&](const LocationList &L) {
264  OS << format("0x%8.8x: ", L.Offset);
265  L.dump(OS, BaseAddr, IsLittleEndian, AddressSize, MRI, nullptr, /*Indent=*/12);
266  OS << "\n\n";
267  };
268 
269  if (Offset) {
270  if (auto *L = getLocationListAtOffset(*Offset))
271  DumpLocationList(*L);
272  return;
273  }
274 
275  for (const LocationList &L : Locations) {
276  DumpLocationList(L);
277  }
278 }
A list of locations that contain one variable.
Definition: DWARFDebugLoc.h:36
uint64_t getULEB128(uint32_t *offset_ptr) const
Extract a unsigned LEB128 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.
unsigned Offset
The beginning offset where this location list is stored in the debug_loc section. ...
Definition: DWARFDebugLoc.h:39
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:123
raw_ostream & indent(unsigned NumSpaces)
indent - Insert &#39;NumSpaces&#39; spaces.
uint64_t getRelocatedAddress(uint32_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...
StringRef getData() const
Get the data pointed to by this extractor.
Definition: DataExtractor.h:54
void reserve(size_type N)
Definition: SmallVector.h:369
uint16_t getU16(uint32_t *offset_ptr) const
Extract a uint16_t value from *offset_ptr.
void dump(raw_ostream &OS, uint64_t BaseAddr, const MCRegisterInfo *RegInfo, Optional< uint64_t > Offset) const
uint32_t getU32(uint32_t *offset_ptr) const
Extract a uint32_t value from *offset_ptr.
A single location within a location list.
Definition: DWARFDebugLoc.h:26
LLVM_NODISCARD StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
Definition: StringRef.h:578
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:1329
SmallVector< char, 4 > Loc
The location of the variable within the specified range.
Definition: DWARFDebugLoc.h:32
void dump(raw_ostream &OS, bool IsLittleEndian, unsigned AddressSize, const MCRegisterInfo *MRI, DWARFUnit *U, uint64_t BaseAddress, unsigned Indent) const
Dump this list on OS.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory)...
Definition: APInt.h:32
LLVM_NODISCARD size_t size() const
size - Get the string size.
Definition: StringRef.h:130
bool isLittleEndian() const
Get the endianness for this extractor.
Definition: DataExtractor.h:56
static void dumpExpression(raw_ostream &OS, ArrayRef< char > Data, bool IsLittleEndian, unsigned AddressSize, const MCRegisterInfo *MRI, DWARFUnit *U)
MCRegisterInfo base class - We assume that the target defines a static array of MCRegisterDesc object...
bool isValidOffsetForDataOfSize(uint32_t offset, uint32_t length) const
Test the availability of length bytes of data from offset.
unsigned const MachineRegisterInfo * MRI
LocationList const * getLocationListAtOffset(uint64_t Offset) const
Return the location list at the given offset or nullptr.
size_t size() const
size - Get the array size.
Definition: ArrayRef.h:148
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
uint8_t getAddressSize() const
Get the address size for this extractor.
Definition: DataExtractor.h:58
static Optional< LocationList > parseOneLocationList(DataExtractor Data, unsigned *Offset, unsigned Version)
uint8_t getU8(uint32_t *offset_ptr) const
Extract a uint8_t value from *offset_ptr.
uint64_t getAddress(uint32_t *offset_ptr) const
Extract an pointer from *offset_ptr.
Optional< LocationList > parseOneLocationList(DWARFDataExtractor Data, uint32_t *Offset)
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
const T * data() const
Definition: ArrayRef.h:145
A DataExtractor (typically for an in-memory copy of an object-file section) plus a relocation map for...
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.
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)
void dump(raw_ostream &OS, uint64_t BaseAddr, bool IsLittleEndian, unsigned AddressSize, const MCRegisterInfo *RegInfo, DWARFUnit *U, unsigned Indent) const
uint64_t End
The ending address of the instruction range.
Definition: DWARFDebugLoc.h:30
bool isValidOffset(uint32_t offset) const
Test the validity of offset.
SmallVector< char, 4 > Loc
Definition: DWARFDebugLoc.h:81
This class implements an extremely fast bulk output stream that can only output to a stream...
Definition: raw_ostream.h:45
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:48
OutputIt copy(R &&Range, OutputIt Out)
Definition: STLExtras.h:1244
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 ...
void resize(size_type N)
Definition: SmallVector.h:344