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 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); 55 } 56 } 57 58 DWARFDebugLoc::LocationList const * 59 DWARFDebugLoc::getLocationListAtOffset(uint64_t Offset) const { 60 auto It = std::lower_bound( 61 Locations.begin(), Locations.end(), Offset, 62 [](const LocationList &L, uint64_t Offset) { return L.Offset < Offset; }); 63 if (It != Locations.end() && It->Offset == Offset) 64 return &(*It); 65 return nullptr; 66 } 67 68 void DWARFDebugLoc::dump(raw_ostream &OS, const MCRegisterInfo *MRI, 69 Optional<uint64_t> Offset) const { 70 auto DumpLocationList = [&](const LocationList &L) { 71 OS << format("0x%8.8x: ", L.Offset); 72 L.dump(OS, IsLittleEndian, AddressSize, MRI, 0, 12); 73 OS << "\n\n"; 74 }; 75 76 if (Offset) { 77 if (auto *L = getLocationListAtOffset(*Offset)) 78 DumpLocationList(*L); 79 return; 80 } 81 82 for (const LocationList &L : Locations) { 83 DumpLocationList(L); 84 } 85 } 86 87 Optional<DWARFDebugLoc::LocationList> 88 DWARFDebugLoc::parseOneLocationList(DWARFDataExtractor Data, unsigned *Offset) { 89 LocationList LL; 90 LL.Offset = *Offset; 91 92 // 2.6.2 Location Lists 93 // A location list entry consists of: 94 while (true) { 95 Entry E; 96 if (!Data.isValidOffsetForDataOfSize(*Offset, 2 * Data.getAddressSize())) { 97 WithColor::error() << "location list overflows the debug_loc section.\n"; 98 return None; 99 } 100 101 // 1. A beginning address offset. ... 102 E.Begin = Data.getRelocatedAddress(Offset); 103 104 // 2. An ending address offset. ... 105 E.End = Data.getRelocatedAddress(Offset); 106 107 // The end of any given location list is marked by an end of list entry, 108 // which consists of a 0 for the beginning address offset and a 0 for the 109 // ending address offset. 110 if (E.Begin == 0 && E.End == 0) 111 return LL; 112 113 if (!Data.isValidOffsetForDataOfSize(*Offset, 2)) { 114 WithColor::error() << "location list overflows the debug_loc section.\n"; 115 return None; 116 } 117 118 unsigned Bytes = Data.getU16(Offset); 119 if (!Data.isValidOffsetForDataOfSize(*Offset, Bytes)) { 120 WithColor::error() << "location list overflows the debug_loc section.\n"; 121 return None; 122 } 123 // A single location description describing the location of the object... 124 StringRef str = Data.getData().substr(*Offset, Bytes); 125 *Offset += Bytes; 126 E.Loc.reserve(str.size()); 127 llvm::copy(str, std::back_inserter(E.Loc)); 128 LL.Entries.push_back(std::move(E)); 129 } 130 } 131 132 void DWARFDebugLoc::parse(const DWARFDataExtractor &data) { 133 IsLittleEndian = data.isLittleEndian(); 134 AddressSize = data.getAddressSize(); 135 136 uint32_t Offset = 0; 137 while (data.isValidOffset(Offset + data.getAddressSize() - 1)) { 138 if (auto LL = parseOneLocationList(data, &Offset)) 139 Locations.push_back(std::move(*LL)); 140 else 141 break; 142 } 143 if (data.isValidOffset(Offset)) 144 WithColor::error() << "failed to consume entire .debug_loc section\n"; 145 } 146 147 Optional<DWARFDebugLoclists::LocationList> 148 DWARFDebugLoclists::parseOneLocationList(DataExtractor Data, unsigned *Offset, 149 unsigned Version) { 150 LocationList LL; 151 LL.Offset = *Offset; 152 153 // dwarf::DW_LLE_end_of_list_entry is 0 and indicates the end of the list. 154 while (auto Kind = 155 static_cast<dwarf::LocationListEntry>(Data.getU8(Offset))) { 156 157 Entry E; 158 E.Kind = Kind; 159 switch (Kind) { 160 case dwarf::DW_LLE_startx_length: 161 E.Value0 = Data.getULEB128(Offset); 162 // Pre-DWARF 5 has different interpretation of the length field. We have 163 // to support both pre- and standartized styles for the compatibility. 164 if (Version < 5) 165 E.Value1 = Data.getU32(Offset); 166 else 167 E.Value1 = Data.getULEB128(Offset); 168 break; 169 case dwarf::DW_LLE_start_length: 170 E.Value0 = Data.getAddress(Offset); 171 E.Value1 = Data.getULEB128(Offset); 172 break; 173 case dwarf::DW_LLE_offset_pair: 174 E.Value0 = Data.getULEB128(Offset); 175 E.Value1 = Data.getULEB128(Offset); 176 break; 177 case dwarf::DW_LLE_base_address: 178 E.Value0 = Data.getAddress(Offset); 179 break; 180 default: 181 WithColor::error() << "dumping support for LLE of kind " << (int)Kind 182 << " not implemented\n"; 183 return None; 184 } 185 186 if (Kind != dwarf::DW_LLE_base_address) { 187 unsigned Bytes = 188 Version >= 5 ? Data.getULEB128(Offset) : Data.getU16(Offset); 189 // A single location description describing the location of the object... 190 StringRef str = Data.getData().substr(*Offset, Bytes); 191 *Offset += Bytes; 192 E.Loc.resize(str.size()); 193 llvm::copy(str, E.Loc.begin()); 194 } 195 196 LL.Entries.push_back(std::move(E)); 197 } 198 return LL; 199 } 200 201 void DWARFDebugLoclists::parse(DataExtractor data, unsigned Version) { 202 IsLittleEndian = data.isLittleEndian(); 203 AddressSize = data.getAddressSize(); 204 205 uint32_t Offset = 0; 206 while (data.isValidOffset(Offset)) { 207 if (auto LL = parseOneLocationList(data, &Offset, Version)) 208 Locations.push_back(std::move(*LL)); 209 else 210 return; 211 } 212 } 213 214 DWARFDebugLoclists::LocationList const * 215 DWARFDebugLoclists::getLocationListAtOffset(uint64_t Offset) const { 216 auto It = std::lower_bound( 217 Locations.begin(), Locations.end(), Offset, 218 [](const LocationList &L, uint64_t Offset) { return L.Offset < Offset; }); 219 if (It != Locations.end() && It->Offset == Offset) 220 return &(*It); 221 return nullptr; 222 } 223 224 void DWARFDebugLoclists::LocationList::dump(raw_ostream &OS, uint64_t BaseAddr, 225 bool IsLittleEndian, 226 unsigned AddressSize, 227 const MCRegisterInfo *MRI, 228 unsigned Indent) const { 229 for (const Entry &E : Entries) { 230 switch (E.Kind) { 231 case dwarf::DW_LLE_startx_length: 232 OS << '\n'; 233 OS.indent(Indent); 234 OS << "Addr idx " << E.Value0 << " (w/ length " << E.Value1 << "): "; 235 break; 236 case dwarf::DW_LLE_start_length: 237 OS << '\n'; 238 OS.indent(Indent); 239 OS << format("[0x%*.*" PRIx64 ", 0x%*.*" PRIx64 "): ", AddressSize * 2, 240 AddressSize * 2, E.Value0, AddressSize * 2, AddressSize * 2, 241 E.Value0 + E.Value1); 242 break; 243 case dwarf::DW_LLE_offset_pair: 244 OS << '\n'; 245 OS.indent(Indent); 246 OS << format("[0x%*.*" PRIx64 ", 0x%*.*" PRIx64 "): ", AddressSize * 2, 247 AddressSize * 2, BaseAddr + E.Value0, AddressSize * 2, 248 AddressSize * 2, BaseAddr + E.Value1); 249 break; 250 case dwarf::DW_LLE_base_address: 251 BaseAddr = E.Value0; 252 break; 253 default: 254 llvm_unreachable("unreachable locations list kind"); 255 } 256 257 dumpExpression(OS, E.Loc, IsLittleEndian, AddressSize, MRI); 258 } 259 } 260 261 void DWARFDebugLoclists::dump(raw_ostream &OS, uint64_t BaseAddr, 262 const MCRegisterInfo *MRI, 263 Optional<uint64_t> Offset) const { 264 auto DumpLocationList = [&](const LocationList &L) { 265 OS << format("0x%8.8x: ", L.Offset); 266 L.dump(OS, BaseAddr, IsLittleEndian, AddressSize, MRI, /*Indent=*/12); 267 OS << "\n\n"; 268 }; 269 270 if (Offset) { 271 if (auto *L = getLocationListAtOffset(*Offset)) 272 DumpLocationList(*L); 273 return; 274 } 275 276 for (const LocationList &L : Locations) { 277 DumpLocationList(L); 278 } 279 } 280