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/WithColor.h" 20 #include "llvm/Support/raw_ostream.h" 21 #include <algorithm> 22 #include <cinttypes> 23 #include <cstdint> 24 25 using namespace llvm; 26 27 // When directly dumping the .debug_loc without a compile unit, we have to guess 28 // at the DWARF version. This only affects DW_OP_call_ref, which is a rare 29 // expression that LLVM doesn't produce. Guessing the wrong version means we 30 // won't be able to pretty print expressions in DWARF2 binaries produced by 31 // non-LLVM tools. 32 static void dumpExpression(raw_ostream &OS, ArrayRef<char> Data, 33 bool IsLittleEndian, unsigned AddressSize, 34 const MCRegisterInfo *MRI) { 35 DWARFDataExtractor Extractor(StringRef(Data.data(), Data.size()), 36 IsLittleEndian, AddressSize); 37 DWARFExpression(Extractor, dwarf::DWARF_VERSION, AddressSize).print(OS, MRI); 38 } 39 40 void DWARFDebugLoc::LocationList::dump(raw_ostream &OS, bool IsLittleEndian, 41 unsigned AddressSize, 42 const MCRegisterInfo *MRI, 43 unsigned Indent) const { 44 for (const Entry &E : Entries) { 45 OS << '\n'; 46 OS.indent(Indent); 47 OS << format("[0x%*.*" PRIx64 ", ", AddressSize * 2, AddressSize * 2, 48 E.Begin) 49 << format(" 0x%*.*" PRIx64 ")", AddressSize * 2, AddressSize * 2, E.End); 50 OS << ": "; 51 52 dumpExpression(OS, E.Loc, IsLittleEndian, AddressSize, MRI); 53 } 54 } 55 56 DWARFDebugLoc::LocationList const * 57 DWARFDebugLoc::getLocationListAtOffset(uint64_t Offset) const { 58 auto It = std::lower_bound( 59 Locations.begin(), Locations.end(), Offset, 60 [](const LocationList &L, uint64_t Offset) { return L.Offset < Offset; }); 61 if (It != Locations.end() && It->Offset == Offset) 62 return &(*It); 63 return nullptr; 64 } 65 66 void DWARFDebugLoc::dump(raw_ostream &OS, const MCRegisterInfo *MRI, 67 Optional<uint64_t> Offset) const { 68 auto DumpLocationList = [&](const LocationList &L) { 69 OS << format("0x%8.8x: ", L.Offset); 70 L.dump(OS, IsLittleEndian, AddressSize, MRI, 12); 71 OS << "\n\n"; 72 }; 73 74 if (Offset) { 75 if (auto *L = getLocationListAtOffset(*Offset)) 76 DumpLocationList(*L); 77 return; 78 } 79 80 for (const LocationList &L : Locations) { 81 DumpLocationList(L); 82 } 83 } 84 85 Optional<DWARFDebugLoc::LocationList> 86 DWARFDebugLoc::parseOneLocationList(DWARFDataExtractor Data, unsigned *Offset) { 87 LocationList LL; 88 LL.Offset = *Offset; 89 90 // 2.6.2 Location Lists 91 // A location list entry consists of: 92 while (true) { 93 Entry E; 94 if (!Data.isValidOffsetForDataOfSize(*Offset, 2 * Data.getAddressSize())) { 95 WithColor::error() << "location list overflows the debug_loc section.\n"; 96 return None; 97 } 98 99 // 1. A beginning address offset. ... 100 E.Begin = Data.getRelocatedAddress(Offset); 101 102 // 2. An ending address offset. ... 103 E.End = Data.getRelocatedAddress(Offset); 104 105 // The end of any given location list is marked by an end of list entry, 106 // which consists of a 0 for the beginning address offset and a 0 for the 107 // ending address offset. 108 if (E.Begin == 0 && E.End == 0) 109 return LL; 110 111 if (!Data.isValidOffsetForDataOfSize(*Offset, 2)) { 112 WithColor::error() << "location list overflows the debug_loc section.\n"; 113 return None; 114 } 115 116 unsigned Bytes = Data.getU16(Offset); 117 if (!Data.isValidOffsetForDataOfSize(*Offset, Bytes)) { 118 WithColor::error() << "location list overflows the debug_loc section.\n"; 119 return None; 120 } 121 // A single location description describing the location of the object... 122 StringRef str = Data.getData().substr(*Offset, Bytes); 123 *Offset += Bytes; 124 E.Loc.reserve(str.size()); 125 std::copy(str.begin(), str.end(), std::back_inserter(E.Loc)); 126 LL.Entries.push_back(std::move(E)); 127 } 128 } 129 130 void DWARFDebugLoc::parse(const DWARFDataExtractor &data) { 131 IsLittleEndian = data.isLittleEndian(); 132 AddressSize = data.getAddressSize(); 133 134 uint32_t Offset = 0; 135 while (data.isValidOffset(Offset + data.getAddressSize() - 1)) { 136 if (auto LL = parseOneLocationList(data, &Offset)) 137 Locations.push_back(std::move(*LL)); 138 else 139 break; 140 } 141 if (data.isValidOffset(Offset)) 142 WithColor::error() << "failed to consume entire .debug_loc section\n"; 143 } 144 145 Optional<DWARFDebugLocDWO::LocationList> 146 DWARFDebugLocDWO::parseOneLocationList(DataExtractor Data, unsigned *Offset) { 147 LocationList LL; 148 LL.Offset = *Offset; 149 150 // dwarf::DW_LLE_end_of_list_entry is 0 and indicates the end of the list. 151 while (auto Kind = 152 static_cast<dwarf::LocationListEntry>(Data.getU8(Offset))) { 153 if (Kind != dwarf::DW_LLE_startx_length) { 154 WithColor::error() << "dumping support for LLE of kind " << (int)Kind 155 << " not implemented\n"; 156 return None; 157 } 158 159 Entry E; 160 E.Start = Data.getULEB128(Offset); 161 E.Length = Data.getU32(Offset); 162 163 unsigned Bytes = Data.getU16(Offset); 164 // A single location description describing the location of the object... 165 StringRef str = Data.getData().substr(*Offset, Bytes); 166 *Offset += Bytes; 167 E.Loc.resize(str.size()); 168 std::copy(str.begin(), str.end(), E.Loc.begin()); 169 170 LL.Entries.push_back(std::move(E)); 171 } 172 return LL; 173 } 174 175 void DWARFDebugLocDWO::parse(DataExtractor data) { 176 IsLittleEndian = data.isLittleEndian(); 177 AddressSize = data.getAddressSize(); 178 179 uint32_t Offset = 0; 180 while (data.isValidOffset(Offset)) { 181 if (auto LL = parseOneLocationList(data, &Offset)) 182 Locations.push_back(std::move(*LL)); 183 else 184 return; 185 } 186 } 187 188 DWARFDebugLocDWO::LocationList const * 189 DWARFDebugLocDWO::getLocationListAtOffset(uint64_t Offset) const { 190 auto It = std::lower_bound( 191 Locations.begin(), Locations.end(), Offset, 192 [](const LocationList &L, uint64_t Offset) { return L.Offset < Offset; }); 193 if (It != Locations.end() && It->Offset == Offset) 194 return &(*It); 195 return nullptr; 196 } 197 198 void DWARFDebugLocDWO::LocationList::dump(raw_ostream &OS, bool IsLittleEndian, 199 unsigned AddressSize, 200 const MCRegisterInfo *MRI, 201 unsigned Indent) const { 202 for (const Entry &E : Entries) { 203 OS << '\n'; 204 OS.indent(Indent); 205 OS << "Addr idx " << E.Start << " (w/ length " << E.Length << "): "; 206 dumpExpression(OS, E.Loc, IsLittleEndian, AddressSize, MRI); 207 } 208 } 209 210 void DWARFDebugLocDWO::dump(raw_ostream &OS, const MCRegisterInfo *MRI, 211 Optional<uint64_t> Offset) const { 212 auto DumpLocationList = [&](const LocationList &L) { 213 OS << format("0x%8.8x: ", L.Offset); 214 L.dump(OS, IsLittleEndian, AddressSize, MRI, /*Indent=*/12); 215 OS << "\n\n"; 216 }; 217 218 if (Offset) { 219 if (auto *L = getLocationListAtOffset(*Offset)) 220 DumpLocationList(*L); 221 return; 222 } 223 224 for (const LocationList &L : Locations) { 225 DumpLocationList(L); 226 } 227 } 228