1 //===- DWARFDebugLoc.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/DWARFDebugLoc.h"
11 #include "llvm/ADT/StringRef.h"
12 #include "llvm/BinaryFormat/Dwarf.h"
13 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
14 #include "llvm/DebugInfo/DWARF/DWARFExpression.h"
15 #include "llvm/DebugInfo/DWARF/DWARFRelocMap.h"
16 #include "llvm/DebugInfo/DWARF/DWARFUnit.h"
17 #include "llvm/Support/Compiler.h"
18 #include "llvm/Support/Format.h"
19 #include "llvm/Support/raw_ostream.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.
31 static void dumpExpression(raw_ostream &OS, ArrayRef<char> Data,
32                            bool IsLittleEndian, unsigned AddressSize,
33                            const MCRegisterInfo *MRI) {
34   DWARFDataExtractor Extractor(StringRef(Data.data(), Data.size()),
35                                IsLittleEndian, AddressSize);
36   DWARFExpression(Extractor, AddressSize, dwarf::DWARF_VERSION).print(OS, MRI);
37 }
38 
39 void DWARFDebugLoc::LocationList::dump(raw_ostream &OS, bool IsLittleEndian,
40                                        unsigned AddressSize,
41                                        const MCRegisterInfo *MRI,
42                                        unsigned Indent) const {
43   for (const Entry &E : Entries) {
44     OS << '\n';
45     OS.indent(Indent);
46     OS << format("0x%016" PRIx64, E.Begin) << " - "
47        << format("0x%016" PRIx64, E.End) << ": ";
48 
49     dumpExpression(OS, E.Loc, IsLittleEndian, AddressSize, MRI);
50   }
51 }
52 
53 void DWARFDebugLoc::dump(raw_ostream &OS, const MCRegisterInfo *MRI) const {
54   for (const LocationList &L : Locations) {
55     OS << format("0x%8.8x: ", L.Offset);
56     L.dump(OS, IsLittleEndian, AddressSize, MRI, 12);
57     OS << "\n\n";
58   }
59 }
60 
61 Optional<DWARFDebugLoc::LocationList>
62 DWARFDebugLoc::parseOneLocationList(DWARFDataExtractor Data, unsigned *Offset) {
63   LocationList LL;
64   LL.Offset = *Offset;
65 
66   // 2.6.2 Location Lists
67   // A location list entry consists of:
68   while (true) {
69     Entry E;
70     if (!Data.isValidOffsetForDataOfSize(*Offset, 2 * Data.getAddressSize())) {
71       llvm::errs() << "Location list overflows the debug_loc section.\n";
72       return None;
73     }
74 
75     // 1. A beginning address offset. ...
76     E.Begin = Data.getRelocatedAddress(Offset);
77 
78     // 2. An ending address offset. ...
79     E.End = Data.getRelocatedAddress(Offset);
80 
81     // The end of any given location list is marked by an end of list entry,
82     // which consists of a 0 for the beginning address offset and a 0 for the
83     // ending address offset.
84     if (E.Begin == 0 && E.End == 0)
85       return LL;
86 
87     if (!Data.isValidOffsetForDataOfSize(*Offset, 2)) {
88       llvm::errs() << "Location list overflows the debug_loc section.\n";
89       return None;
90     }
91 
92     unsigned Bytes = Data.getU16(Offset);
93     if (!Data.isValidOffsetForDataOfSize(*Offset, Bytes)) {
94       llvm::errs() << "Location list overflows the debug_loc section.\n";
95       return None;
96     }
97     // A single location description describing the location of the object...
98     StringRef str = Data.getData().substr(*Offset, Bytes);
99     *Offset += Bytes;
100     E.Loc.reserve(str.size());
101     std::copy(str.begin(), str.end(), std::back_inserter(E.Loc));
102     LL.Entries.push_back(std::move(E));
103   }
104 }
105 
106 void DWARFDebugLoc::parse(const DWARFDataExtractor &data) {
107   IsLittleEndian = data.isLittleEndian();
108   AddressSize = data.getAddressSize();
109 
110   uint32_t Offset = 0;
111   while (data.isValidOffset(Offset + data.getAddressSize() - 1)) {
112     if (auto LL = parseOneLocationList(data, &Offset))
113       Locations.push_back(std::move(*LL));
114     else
115       break;
116   }
117   if (data.isValidOffset(Offset))
118     errs() << "error: failed to consume entire .debug_loc section\n";
119 }
120 
121 Optional<DWARFDebugLocDWO::LocationList>
122 DWARFDebugLocDWO::parseOneLocationList(DataExtractor Data, unsigned *Offset) {
123   LocationList LL;
124   LL.Offset = *Offset;
125 
126   // dwarf::DW_LLE_end_of_list_entry is 0 and indicates the end of the list.
127   while (auto Kind =
128              static_cast<dwarf::LocationListEntry>(Data.getU8(Offset))) {
129     if (Kind != dwarf::DW_LLE_startx_length) {
130       llvm::errs() << "error: dumping support for LLE of kind " << (int)Kind
131                    << " not implemented\n";
132       return None;
133     }
134 
135     Entry E;
136     E.Start = Data.getULEB128(Offset);
137     E.Length = Data.getU32(Offset);
138 
139     unsigned Bytes = Data.getU16(Offset);
140     // A single location description describing the location of the object...
141     StringRef str = Data.getData().substr(*Offset, Bytes);
142     *Offset += Bytes;
143     E.Loc.resize(str.size());
144     std::copy(str.begin(), str.end(), E.Loc.begin());
145 
146     LL.Entries.push_back(std::move(E));
147   }
148   return LL;
149 }
150 
151 void DWARFDebugLocDWO::parse(DataExtractor data) {
152   IsLittleEndian = data.isLittleEndian();
153   AddressSize = data.getAddressSize();
154 
155   uint32_t Offset = 0;
156   while (data.isValidOffset(Offset)) {
157     if (auto LL = parseOneLocationList(data, &Offset))
158       Locations.push_back(std::move(*LL));
159     else
160       return;
161   }
162 }
163 
164 void DWARFDebugLocDWO::LocationList::dump(raw_ostream &OS, bool IsLittleEndian,
165                                           unsigned AddressSize,
166                                           const MCRegisterInfo *MRI,
167                                           unsigned Indent) const {
168   for (const Entry &E : Entries) {
169     OS << '\n';
170     OS.indent(Indent);
171     OS << "Addr idx " << E.Start << " (w/ length " << E.Length << "): ";
172     dumpExpression(OS, E.Loc, IsLittleEndian, AddressSize, MRI);
173   }
174 }
175 
176 void DWARFDebugLocDWO::dump(raw_ostream &OS, const MCRegisterInfo *MRI) const {
177   for (const LocationList &L : Locations) {
178     OS << format("0x%8.8x: ", L.Offset);
179     L.dump(OS, IsLittleEndian, AddressSize, MRI, /*Indent=*/12);
180     OS << "\n\n";
181   }
182 }
183