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 9 #include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h" 10 #include "llvm/ADT/StringRef.h" 11 #include "llvm/BinaryFormat/Dwarf.h" 12 #include "llvm/DebugInfo/DWARF/DWARFContext.h" 13 #include "llvm/DebugInfo/DWARF/DWARFExpression.h" 14 #include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" 15 #include "llvm/DebugInfo/DWARF/DWARFUnit.h" 16 #include "llvm/Support/Compiler.h" 17 #include "llvm/Support/Format.h" 18 #include "llvm/Support/WithColor.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<uint8_t> Data, 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 56 DWARFDebugLoc::LocationList const * 57 DWARFDebugLoc::getLocationListAtOffset(uint64_t Offset) const { 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 65 void DWARFDebugLoc::dump(raw_ostream &OS, const MCRegisterInfo *MRI, 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 84 Expected<DWARFDebugLoc::LocationList> 85 DWARFDebugLoc::parseOneLocationList(const DWARFDataExtractor &Data, 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 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 *Offset = C.tell(); 110 return LL; 111 } 112 113 if (E.Begin != (AddressSize == 4 ? -1U : -1ULL)) { 114 unsigned Bytes = Data.getU16(C); 115 // A single location description describing the location of the object... 116 Data.getU8(C, E.Loc, Bytes); 117 } 118 119 LL.Entries.push_back(std::move(E)); 120 } 121 } 122 123 void DWARFDebugLoc::parse(const DWARFDataExtractor &data) { 124 IsLittleEndian = data.isLittleEndian(); 125 AddressSize = data.getAddressSize(); 126 127 uint64_t Offset = 0; 128 while (Offset < data.getData().size()) { 129 if (auto LL = parseOneLocationList(data, &Offset)) 130 Locations.push_back(std::move(*LL)); 131 else { 132 logAllUnhandledErrors(LL.takeError(), WithColor::error()); 133 break; 134 } 135 } 136 } 137 138 Expected<DWARFDebugLoclists::LocationList> 139 DWARFDebugLoclists::parseOneLocationList(const DataExtractor &Data, 140 uint64_t *Offset, unsigned Version) { 141 LocationList LL; 142 LL.Offset = *Offset; 143 DataExtractor::Cursor C(*Offset); 144 145 // dwarf::DW_LLE_end_of_list_entry is 0 and indicates the end of the list. 146 while (auto Kind = Data.getU8(C)) { 147 Entry E; 148 E.Kind = Kind; 149 switch (Kind) { 150 case dwarf::DW_LLE_startx_length: 151 E.Value0 = Data.getULEB128(C); 152 // Pre-DWARF 5 has different interpretation of the length field. We have 153 // to support both pre- and standartized styles for the compatibility. 154 if (Version < 5) 155 E.Value1 = Data.getU32(C); 156 else 157 E.Value1 = Data.getULEB128(C); 158 break; 159 case dwarf::DW_LLE_start_length: 160 E.Value0 = Data.getAddress(C); 161 E.Value1 = Data.getULEB128(C); 162 break; 163 case dwarf::DW_LLE_offset_pair: 164 E.Value0 = Data.getULEB128(C); 165 E.Value1 = Data.getULEB128(C); 166 break; 167 case dwarf::DW_LLE_base_address: 168 E.Value0 = Data.getAddress(C); 169 break; 170 default: 171 cantFail(C.takeError()); 172 return createStringError(errc::illegal_byte_sequence, 173 "LLE of kind %x not supported", (int)Kind); 174 } 175 176 if (Kind != dwarf::DW_LLE_base_address) { 177 unsigned Bytes = Version >= 5 ? Data.getULEB128(C) : Data.getU16(C); 178 // A single location description describing the location of the object... 179 Data.getU8(C, E.Loc, Bytes); 180 } 181 182 LL.Entries.push_back(std::move(E)); 183 } 184 if (Error Err = C.takeError()) 185 return std::move(Err); 186 *Offset = C.tell(); 187 return LL; 188 } 189 190 void DWARFDebugLoclists::parse(DataExtractor data, uint64_t Offset, uint64_t EndOffset, uint16_t Version) { 191 IsLittleEndian = data.isLittleEndian(); 192 AddressSize = data.getAddressSize(); 193 194 while (Offset < EndOffset) { 195 if (auto LL = parseOneLocationList(data, &Offset, Version)) 196 Locations.push_back(std::move(*LL)); 197 else { 198 logAllUnhandledErrors(LL.takeError(), WithColor::error()); 199 return; 200 } 201 } 202 } 203 204 DWARFDebugLoclists::LocationList const * 205 DWARFDebugLoclists::getLocationListAtOffset(uint64_t Offset) const { 206 auto It = partition_point( 207 Locations, [=](const LocationList &L) { return L.Offset < Offset; }); 208 if (It != Locations.end() && It->Offset == Offset) 209 return &(*It); 210 return nullptr; 211 } 212 213 void DWARFDebugLoclists::LocationList::dump(raw_ostream &OS, uint64_t BaseAddr, 214 bool IsLittleEndian, 215 unsigned AddressSize, 216 const MCRegisterInfo *MRI, 217 DWARFUnit *U, 218 unsigned Indent) const { 219 for (const Entry &E : Entries) { 220 switch (E.Kind) { 221 case dwarf::DW_LLE_startx_length: 222 OS << '\n'; 223 OS.indent(Indent); 224 OS << "Addr idx " << E.Value0 << " (w/ length " << E.Value1 << "): "; 225 break; 226 case dwarf::DW_LLE_start_length: 227 OS << '\n'; 228 OS.indent(Indent); 229 OS << format("[0x%*.*" PRIx64 ", 0x%*.*" PRIx64 "): ", AddressSize * 2, 230 AddressSize * 2, E.Value0, AddressSize * 2, AddressSize * 2, 231 E.Value0 + E.Value1); 232 break; 233 case dwarf::DW_LLE_offset_pair: 234 OS << '\n'; 235 OS.indent(Indent); 236 OS << format("[0x%*.*" PRIx64 ", 0x%*.*" PRIx64 "): ", AddressSize * 2, 237 AddressSize * 2, BaseAddr + E.Value0, AddressSize * 2, 238 AddressSize * 2, BaseAddr + E.Value1); 239 break; 240 case dwarf::DW_LLE_base_address: 241 BaseAddr = E.Value0; 242 break; 243 default: 244 llvm_unreachable("unreachable locations list kind"); 245 } 246 247 dumpExpression(OS, E.Loc, IsLittleEndian, AddressSize, MRI, U); 248 } 249 } 250 251 void DWARFDebugLoclists::dump(raw_ostream &OS, uint64_t BaseAddr, 252 const MCRegisterInfo *MRI, 253 Optional<uint64_t> Offset) const { 254 auto DumpLocationList = [&](const LocationList &L) { 255 OS << format("0x%8.8" PRIx64 ": ", L.Offset); 256 L.dump(OS, BaseAddr, IsLittleEndian, AddressSize, MRI, nullptr, /*Indent=*/12); 257 OS << "\n\n"; 258 }; 259 260 if (Offset) { 261 if (auto *L = getLocationListAtOffset(*Offset)) 262 DumpLocationList(*L); 263 return; 264 } 265 266 for (const LocationList &L : Locations) { 267 DumpLocationList(L); 268 } 269 } 270