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<char> Data, 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 58 DWARFDebugLoc::LocationList const * 59 DWARFDebugLoc::getLocationListAtOffset(uint64_t Offset) const { 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 67 void DWARFDebugLoc::dump(raw_ostream &OS, const MCRegisterInfo *MRI, 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 86 Optional<DWARFDebugLoc::LocationList> 87 DWARFDebugLoc::parseOneLocationList(DWARFDataExtractor Data, unsigned *Offset) { 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 131 void DWARFDebugLoc::parse(const DWARFDataExtractor &data) { 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 146 Optional<DWARFDebugLoclists::LocationList> 147 DWARFDebugLoclists::parseOneLocationList(DataExtractor Data, unsigned *Offset, 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) { 159 case dwarf::DW_LLE_startx_length: 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; 168 case dwarf::DW_LLE_start_length: 169 E.Value0 = Data.getAddress(Offset); 170 E.Value1 = Data.getULEB128(Offset); 171 break; 172 case dwarf::DW_LLE_offset_pair: 173 E.Value0 = Data.getULEB128(Offset); 174 E.Value1 = Data.getULEB128(Offset); 175 break; 176 case dwarf::DW_LLE_base_address: 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 185 if (Kind != dwarf::DW_LLE_base_address) { 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 200 void DWARFDebugLoclists::parse(DataExtractor data, unsigned Version) { 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 213 DWARFDebugLoclists::LocationList const * 214 DWARFDebugLoclists::getLocationListAtOffset(uint64_t Offset) const { 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 222 void DWARFDebugLoclists::LocationList::dump(raw_ostream &OS, uint64_t BaseAddr, 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) { 230 case dwarf::DW_LLE_startx_length: 231 OS << '\n'; 232 OS.indent(Indent); 233 OS << "Addr idx " << E.Value0 << " (w/ length " << E.Value1 << "): "; 234 break; 235 case dwarf::DW_LLE_start_length: 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; 242 case dwarf::DW_LLE_offset_pair: 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; 249 case dwarf::DW_LLE_base_address: 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 } 279