| 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/DIContext.h" |
| 13 | #include "llvm/DebugInfo/DWARF/DWARFAddressRange.h" |
| 14 | #include "llvm/DebugInfo/DWARF/DWARFExpressionPrinter.h" |
| 15 | #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" |
| 16 | #include "llvm/DebugInfo/DWARF/DWARFLocationExpression.h" |
| 17 | #include "llvm/DebugInfo/DWARF/DWARFUnit.h" |
| 18 | #include "llvm/DebugInfo/DWARF/LowLevel/DWARFExpression.h" |
| 19 | #include "llvm/Support/Format.h" |
| 20 | #include "llvm/Support/raw_ostream.h" |
| 21 | #include <algorithm> |
| 22 | #include <cinttypes> |
| 23 | #include <cstdint> |
| 24 | |
| 25 | using namespace llvm; |
| 26 | using object::SectionedAddress; |
| 27 | |
| 28 | namespace llvm { |
| 29 | class DWARFObject; |
| 30 | } |
| 31 | |
| 32 | namespace { |
| 33 | class DWARFLocationInterpreter { |
| 34 | std::optional<object::SectionedAddress> Base; |
| 35 | std::function<std::optional<object::SectionedAddress>(uint32_t)> LookupAddr; |
| 36 | |
| 37 | public: |
| 38 | DWARFLocationInterpreter( |
| 39 | std::optional<object::SectionedAddress> Base, |
| 40 | std::function<std::optional<object::SectionedAddress>(uint32_t)> |
| 41 | LookupAddr) |
| 42 | : Base(Base), LookupAddr(std::move(LookupAddr)) {} |
| 43 | |
| 44 | Expected<std::optional<DWARFLocationExpression>> |
| 45 | Interpret(const DWARFLocationEntry &E); |
| 46 | }; |
| 47 | } // namespace |
| 48 | |
| 49 | static Error createResolverError(uint32_t Index, unsigned Kind) { |
| 50 | return make_error<ResolverError>(Args&: Index, Args: (dwarf::LoclistEntries)Kind); |
| 51 | } |
| 52 | |
| 53 | Expected<std::optional<DWARFLocationExpression>> |
| 54 | DWARFLocationInterpreter::Interpret(const DWARFLocationEntry &E) { |
| 55 | switch (E.Kind) { |
| 56 | case dwarf::DW_LLE_end_of_list: |
| 57 | return std::nullopt; |
| 58 | case dwarf::DW_LLE_base_addressx: { |
| 59 | Base = LookupAddr(E.Value0); |
| 60 | if (!Base) |
| 61 | return createResolverError(Index: E.Value0, Kind: E.Kind); |
| 62 | return std::nullopt; |
| 63 | } |
| 64 | case dwarf::DW_LLE_startx_endx: { |
| 65 | std::optional<SectionedAddress> LowPC = LookupAddr(E.Value0); |
| 66 | if (!LowPC) |
| 67 | return createResolverError(Index: E.Value0, Kind: E.Kind); |
| 68 | std::optional<SectionedAddress> HighPC = LookupAddr(E.Value1); |
| 69 | if (!HighPC) |
| 70 | return createResolverError(Index: E.Value1, Kind: E.Kind); |
| 71 | return DWARFLocationExpression{ |
| 72 | .Range: DWARFAddressRange{LowPC->Address, HighPC->Address, LowPC->SectionIndex}, |
| 73 | .Expr: E.Loc}; |
| 74 | } |
| 75 | case dwarf::DW_LLE_startx_length: { |
| 76 | std::optional<SectionedAddress> LowPC = LookupAddr(E.Value0); |
| 77 | if (!LowPC) |
| 78 | return createResolverError(Index: E.Value0, Kind: E.Kind); |
| 79 | return DWARFLocationExpression{.Range: DWARFAddressRange{LowPC->Address, |
| 80 | LowPC->Address + E.Value1, |
| 81 | LowPC->SectionIndex}, |
| 82 | .Expr: E.Loc}; |
| 83 | } |
| 84 | case dwarf::DW_LLE_offset_pair: { |
| 85 | if (!Base) { |
| 86 | return createStringError(EC: inconvertibleErrorCode(), |
| 87 | S: "Unable to resolve location list offset pair: " |
| 88 | "Base address not defined" ); |
| 89 | } |
| 90 | DWARFAddressRange Range{Base->Address + E.Value0, Base->Address + E.Value1, |
| 91 | Base->SectionIndex}; |
| 92 | if (Range.SectionIndex == SectionedAddress::UndefSection) |
| 93 | Range.SectionIndex = E.SectionIndex; |
| 94 | return DWARFLocationExpression{.Range: Range, .Expr: E.Loc}; |
| 95 | } |
| 96 | case dwarf::DW_LLE_default_location: |
| 97 | return DWARFLocationExpression{.Range: std::nullopt, .Expr: E.Loc}; |
| 98 | case dwarf::DW_LLE_base_address: |
| 99 | Base = SectionedAddress{.Address: E.Value0, .SectionIndex: E.SectionIndex}; |
| 100 | return std::nullopt; |
| 101 | case dwarf::DW_LLE_start_end: |
| 102 | return DWARFLocationExpression{ |
| 103 | .Range: DWARFAddressRange{E.Value0, E.Value1, E.SectionIndex}, .Expr: E.Loc}; |
| 104 | case dwarf::DW_LLE_start_length: |
| 105 | return DWARFLocationExpression{ |
| 106 | .Range: DWARFAddressRange{E.Value0, E.Value0 + E.Value1, E.SectionIndex}, |
| 107 | .Expr: E.Loc}; |
| 108 | default: |
| 109 | llvm_unreachable("unreachable locations list kind" ); |
| 110 | } |
| 111 | } |
| 112 | |
| 113 | static void dumpExpression(raw_ostream &OS, DIDumpOptions DumpOpts, |
| 114 | ArrayRef<uint8_t> Data, bool IsLittleEndian, |
| 115 | unsigned AddressSize, DWARFUnit *U) { |
| 116 | DWARFDataExtractor (Data, IsLittleEndian, AddressSize); |
| 117 | std::optional<dwarf::DwarfFormat> Format; |
| 118 | if (U) |
| 119 | Format = U->getFormat(); |
| 120 | DWARFExpression E(Extractor, AddressSize, Format); |
| 121 | printDwarfExpression(E: &E, OS, DumpOpts, U); |
| 122 | } |
| 123 | |
| 124 | bool DWARFLocationTable::dumpLocationList( |
| 125 | uint64_t *Offset, raw_ostream &OS, std::optional<SectionedAddress> BaseAddr, |
| 126 | const DWARFObject &Obj, DWARFUnit *U, DIDumpOptions DumpOpts, |
| 127 | unsigned Indent) const { |
| 128 | DWARFLocationInterpreter Interp( |
| 129 | BaseAddr, [U](uint32_t Index) -> std::optional<SectionedAddress> { |
| 130 | if (U) |
| 131 | return U->getAddrOffsetSectionItem(Index); |
| 132 | return std::nullopt; |
| 133 | }); |
| 134 | OS << format(Fmt: "0x%8.8" PRIx64 ": " , Vals: *Offset); |
| 135 | Error E = visitLocationList(Offset, Callback: [&](const DWARFLocationEntry &E) { |
| 136 | Expected<std::optional<DWARFLocationExpression>> Loc = Interp.Interpret(E); |
| 137 | if (!Loc || DumpOpts.DisplayRawContents) |
| 138 | dumpRawEntry(Entry: E, OS, Indent, DumpOpts, Obj); |
| 139 | if (Loc && *Loc) { |
| 140 | OS << "\n" ; |
| 141 | OS.indent(NumSpaces: Indent); |
| 142 | if (DumpOpts.DisplayRawContents) |
| 143 | OS << " => " ; |
| 144 | |
| 145 | DIDumpOptions RangeDumpOpts(DumpOpts); |
| 146 | RangeDumpOpts.DisplayRawContents = false; |
| 147 | if (Loc.get()->Range) |
| 148 | Loc.get()->Range->dump(OS, AddressSize: Data.getAddressSize(), DumpOpts: RangeDumpOpts, Obj: &Obj); |
| 149 | else |
| 150 | OS << "<default>" ; |
| 151 | } |
| 152 | if (!Loc) |
| 153 | consumeError(Err: Loc.takeError()); |
| 154 | |
| 155 | if (E.Kind != dwarf::DW_LLE_base_address && |
| 156 | E.Kind != dwarf::DW_LLE_base_addressx && |
| 157 | E.Kind != dwarf::DW_LLE_end_of_list) { |
| 158 | OS << ": " ; |
| 159 | dumpExpression(OS, DumpOpts, Data: E.Loc, IsLittleEndian: Data.isLittleEndian(), |
| 160 | AddressSize: Data.getAddressSize(), U); |
| 161 | } |
| 162 | return true; |
| 163 | }); |
| 164 | if (E) { |
| 165 | DumpOpts.RecoverableErrorHandler(std::move(E)); |
| 166 | return false; |
| 167 | } |
| 168 | return true; |
| 169 | } |
| 170 | |
| 171 | Error DWARFLocationTable::visitAbsoluteLocationList( |
| 172 | uint64_t Offset, std::optional<SectionedAddress> BaseAddr, |
| 173 | std::function<std::optional<SectionedAddress>(uint32_t)> LookupAddr, |
| 174 | function_ref<bool(Expected<DWARFLocationExpression>)> Callback) const { |
| 175 | DWARFLocationInterpreter Interp(BaseAddr, std::move(LookupAddr)); |
| 176 | return visitLocationList(Offset: &Offset, Callback: [&](const DWARFLocationEntry &E) { |
| 177 | Expected<std::optional<DWARFLocationExpression>> Loc = Interp.Interpret(E); |
| 178 | if (!Loc) |
| 179 | return Callback(Loc.takeError()); |
| 180 | if (*Loc) |
| 181 | return Callback(**Loc); |
| 182 | return true; |
| 183 | }); |
| 184 | } |
| 185 | |
| 186 | void DWARFDebugLoc::dump(raw_ostream &OS, const DWARFObject &Obj, |
| 187 | DIDumpOptions DumpOpts, |
| 188 | std::optional<uint64_t> DumpOffset) const { |
| 189 | auto BaseAddr = std::nullopt; |
| 190 | unsigned Indent = 12; |
| 191 | if (DumpOffset) { |
| 192 | dumpLocationList(Offset: &*DumpOffset, OS, BaseAddr, Obj, U: nullptr, DumpOpts, |
| 193 | Indent); |
| 194 | } else { |
| 195 | uint64_t Offset = 0; |
| 196 | StringRef Separator; |
| 197 | bool CanContinue = true; |
| 198 | while (CanContinue && Data.isValidOffset(offset: Offset)) { |
| 199 | OS << Separator; |
| 200 | Separator = "\n" ; |
| 201 | |
| 202 | CanContinue = dumpLocationList(Offset: &Offset, OS, BaseAddr, Obj, U: nullptr, |
| 203 | DumpOpts, Indent); |
| 204 | OS << '\n'; |
| 205 | } |
| 206 | } |
| 207 | } |
| 208 | |
| 209 | Error DWARFDebugLoc::visitLocationList( |
| 210 | uint64_t *Offset, |
| 211 | function_ref<bool(const DWARFLocationEntry &)> Callback) const { |
| 212 | DataExtractor::Cursor C(*Offset); |
| 213 | while (true) { |
| 214 | uint64_t SectionIndex; |
| 215 | uint64_t Value0 = Data.getRelocatedAddress(C); |
| 216 | uint64_t Value1 = Data.getRelocatedAddress(C, SecIx: &SectionIndex); |
| 217 | |
| 218 | DWARFLocationEntry E; |
| 219 | |
| 220 | // The end of any given location list is marked by an end of list entry, |
| 221 | // which consists of a 0 for the beginning address offset and a 0 for the |
| 222 | // ending address offset. A beginning offset of 0xff...f marks the base |
| 223 | // address selection entry. |
| 224 | if (Value0 == 0 && Value1 == 0) { |
| 225 | E.Kind = dwarf::DW_LLE_end_of_list; |
| 226 | } else if (Value0 == (Data.getAddressSize() == 4 ? -1U : -1ULL)) { |
| 227 | E.Kind = dwarf::DW_LLE_base_address; |
| 228 | E.Value0 = Value1; |
| 229 | E.SectionIndex = SectionIndex; |
| 230 | } else { |
| 231 | E.Kind = dwarf::DW_LLE_offset_pair; |
| 232 | E.Value0 = Value0; |
| 233 | E.Value1 = Value1; |
| 234 | E.SectionIndex = SectionIndex; |
| 235 | unsigned Bytes = Data.getU16(C); |
| 236 | // A single location description describing the location of the object... |
| 237 | Data.getU8(C, Dst&: E.Loc, Count: Bytes); |
| 238 | } |
| 239 | |
| 240 | if (!C) |
| 241 | return C.takeError(); |
| 242 | if (!Callback(E) || E.Kind == dwarf::DW_LLE_end_of_list) |
| 243 | break; |
| 244 | } |
| 245 | *Offset = C.tell(); |
| 246 | return Error::success(); |
| 247 | } |
| 248 | |
| 249 | void DWARFDebugLoc::dumpRawEntry(const DWARFLocationEntry &Entry, |
| 250 | raw_ostream &OS, unsigned Indent, |
| 251 | DIDumpOptions DumpOpts, |
| 252 | const DWARFObject &Obj) const { |
| 253 | uint64_t Value0, Value1; |
| 254 | switch (Entry.Kind) { |
| 255 | case dwarf::DW_LLE_base_address: |
| 256 | Value0 = Data.getAddressSize() == 4 ? -1U : -1ULL; |
| 257 | Value1 = Entry.Value0; |
| 258 | break; |
| 259 | case dwarf::DW_LLE_offset_pair: |
| 260 | Value0 = Entry.Value0; |
| 261 | Value1 = Entry.Value1; |
| 262 | break; |
| 263 | case dwarf::DW_LLE_end_of_list: |
| 264 | return; |
| 265 | default: |
| 266 | llvm_unreachable("Not possible in DWARF4!" ); |
| 267 | } |
| 268 | OS << '\n'; |
| 269 | OS.indent(NumSpaces: Indent); |
| 270 | OS << '(' << format_hex(N: Value0, Width: 2 + Data.getAddressSize() * 2) << ", " |
| 271 | << format_hex(N: Value1, Width: 2 + Data.getAddressSize() * 2) << ')'; |
| 272 | DWARFFormValue::dumpAddressSection(Obj, OS, DumpOpts, SectionIndex: Entry.SectionIndex); |
| 273 | } |
| 274 | |
| 275 | Error DWARFDebugLoclists::visitLocationList( |
| 276 | uint64_t *Offset, function_ref<bool(const DWARFLocationEntry &)> F) const { |
| 277 | |
| 278 | DataExtractor::Cursor C(*Offset); |
| 279 | bool Continue = true; |
| 280 | while (Continue) { |
| 281 | DWARFLocationEntry E; |
| 282 | E.Kind = Data.getU8(C); |
| 283 | switch (E.Kind) { |
| 284 | case dwarf::DW_LLE_end_of_list: |
| 285 | break; |
| 286 | case dwarf::DW_LLE_base_addressx: |
| 287 | E.Value0 = Data.getULEB128(C); |
| 288 | break; |
| 289 | case dwarf::DW_LLE_startx_endx: |
| 290 | E.Value0 = Data.getULEB128(C); |
| 291 | E.Value1 = Data.getULEB128(C); |
| 292 | break; |
| 293 | case dwarf::DW_LLE_startx_length: |
| 294 | E.Value0 = Data.getULEB128(C); |
| 295 | // Pre-DWARF 5 has different interpretation of the length field. We have |
| 296 | // to support both pre- and standartized styles for the compatibility. |
| 297 | if (Version < 5) |
| 298 | E.Value1 = Data.getU32(C); |
| 299 | else |
| 300 | E.Value1 = Data.getULEB128(C); |
| 301 | break; |
| 302 | case dwarf::DW_LLE_offset_pair: |
| 303 | E.Value0 = Data.getULEB128(C); |
| 304 | E.Value1 = Data.getULEB128(C); |
| 305 | E.SectionIndex = SectionedAddress::UndefSection; |
| 306 | break; |
| 307 | case dwarf::DW_LLE_default_location: |
| 308 | break; |
| 309 | case dwarf::DW_LLE_base_address: |
| 310 | E.Value0 = Data.getRelocatedAddress(C, SecIx: &E.SectionIndex); |
| 311 | break; |
| 312 | case dwarf::DW_LLE_start_end: |
| 313 | E.Value0 = Data.getRelocatedAddress(C, SecIx: &E.SectionIndex); |
| 314 | E.Value1 = Data.getRelocatedAddress(C); |
| 315 | break; |
| 316 | case dwarf::DW_LLE_start_length: |
| 317 | E.Value0 = Data.getRelocatedAddress(C, SecIx: &E.SectionIndex); |
| 318 | E.Value1 = Data.getULEB128(C); |
| 319 | break; |
| 320 | default: |
| 321 | cantFail(Err: C.takeError()); |
| 322 | return createStringError(EC: errc::illegal_byte_sequence, |
| 323 | Fmt: "LLE of kind %x not supported" , Vals: (int)E.Kind); |
| 324 | } |
| 325 | |
| 326 | if (E.Kind != dwarf::DW_LLE_base_address && |
| 327 | E.Kind != dwarf::DW_LLE_base_addressx && |
| 328 | E.Kind != dwarf::DW_LLE_end_of_list) { |
| 329 | unsigned Bytes = Version >= 5 ? Data.getULEB128(C) : Data.getU16(C); |
| 330 | // A single location description describing the location of the object... |
| 331 | Data.getU8(C, Dst&: E.Loc, Count: Bytes); |
| 332 | } |
| 333 | |
| 334 | if (!C) |
| 335 | return C.takeError(); |
| 336 | Continue = F(E) && E.Kind != dwarf::DW_LLE_end_of_list; |
| 337 | } |
| 338 | *Offset = C.tell(); |
| 339 | return Error::success(); |
| 340 | } |
| 341 | |
| 342 | void DWARFDebugLoclists::dumpRawEntry(const DWARFLocationEntry &Entry, |
| 343 | raw_ostream &OS, unsigned Indent, |
| 344 | DIDumpOptions DumpOpts, |
| 345 | const DWARFObject &Obj) const { |
| 346 | size_t MaxEncodingStringLength = 0; |
| 347 | #define HANDLE_DW_LLE(ID, NAME) \ |
| 348 | MaxEncodingStringLength = std::max(MaxEncodingStringLength, \ |
| 349 | dwarf::LocListEncodingString(ID).size()); |
| 350 | #include "llvm/BinaryFormat/Dwarf.def" |
| 351 | |
| 352 | OS << "\n" ; |
| 353 | OS.indent(NumSpaces: Indent); |
| 354 | StringRef EncodingString = dwarf::LocListEncodingString(Encoding: Entry.Kind); |
| 355 | // Unsupported encodings should have been reported during parsing. |
| 356 | assert(!EncodingString.empty() && "Unknown loclist entry encoding" ); |
| 357 | OS << format(Fmt: "%-*s(" , Vals: MaxEncodingStringLength, Vals: EncodingString.data()); |
| 358 | unsigned FieldSize = 2 + 2 * Data.getAddressSize(); |
| 359 | switch (Entry.Kind) { |
| 360 | case dwarf::DW_LLE_end_of_list: |
| 361 | case dwarf::DW_LLE_default_location: |
| 362 | break; |
| 363 | case dwarf::DW_LLE_startx_endx: |
| 364 | case dwarf::DW_LLE_startx_length: |
| 365 | case dwarf::DW_LLE_offset_pair: |
| 366 | case dwarf::DW_LLE_start_end: |
| 367 | case dwarf::DW_LLE_start_length: |
| 368 | OS << format_hex(N: Entry.Value0, Width: FieldSize) << ", " |
| 369 | << format_hex(N: Entry.Value1, Width: FieldSize); |
| 370 | break; |
| 371 | case dwarf::DW_LLE_base_addressx: |
| 372 | case dwarf::DW_LLE_base_address: |
| 373 | OS << format_hex(N: Entry.Value0, Width: FieldSize); |
| 374 | break; |
| 375 | } |
| 376 | OS << ')'; |
| 377 | switch (Entry.Kind) { |
| 378 | case dwarf::DW_LLE_base_address: |
| 379 | case dwarf::DW_LLE_start_end: |
| 380 | case dwarf::DW_LLE_start_length: |
| 381 | DWARFFormValue::dumpAddressSection(Obj, OS, DumpOpts, SectionIndex: Entry.SectionIndex); |
| 382 | break; |
| 383 | default: |
| 384 | break; |
| 385 | } |
| 386 | } |
| 387 | |
| 388 | void DWARFDebugLoclists::dumpRange(uint64_t StartOffset, uint64_t Size, |
| 389 | raw_ostream &OS, const DWARFObject &Obj, |
| 390 | DIDumpOptions DumpOpts) { |
| 391 | if (!Data.isValidOffsetForDataOfSize(offset: StartOffset, length: Size)) { |
| 392 | OS << "Invalid dump range\n" ; |
| 393 | return; |
| 394 | } |
| 395 | uint64_t Offset = StartOffset; |
| 396 | StringRef Separator; |
| 397 | bool CanContinue = true; |
| 398 | while (CanContinue && Offset < StartOffset + Size) { |
| 399 | OS << Separator; |
| 400 | Separator = "\n" ; |
| 401 | |
| 402 | CanContinue = dumpLocationList(Offset: &Offset, OS, /*BaseAddr=*/std::nullopt, Obj, |
| 403 | U: nullptr, DumpOpts, /*Indent=*/12); |
| 404 | OS << '\n'; |
| 405 | } |
| 406 | } |
| 407 | |
| 408 | void llvm::ResolverError::log(raw_ostream &OS) const { |
| 409 | OS << format(Fmt: "unable to resolve indirect address %u for: %s" , Vals: Index, |
| 410 | Vals: dwarf::LocListEncodingString(Encoding: Kind).data()); |
| 411 | } |
| 412 | |
| 413 | char llvm::ResolverError::ID; |
| 414 | |