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/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) { 34 DWARFDataExtractor Extractor(StringRef(Data.data(), Data.size()), 35 IsLittleEndian, AddressSize); 36 DWARFExpression(Extractor, AddressSize, dwarf::DWARF_VERSION).print(OS, MRI); 37 } 38 39 void DWARFDebugLoc::LocationList::dump(raw_ostream &OS, bool IsLittleEndian, 40 unsigned AddressSize, 41 const MCRegisterInfo *MRI, 42 unsigned Indent) const { 43 for (const Entry &E : Entries) { 44 OS << '\n'; 45 OS.indent(Indent); 46 OS << format("0x%016" PRIx64, E.Begin) << " - " 47 << format("0x%016" PRIx64, E.End) << ": "; 48 49 dumpExpression(OS, E.Loc, IsLittleEndian, AddressSize, MRI); 50 } 51 } 52 53 void DWARFDebugLoc::dump(raw_ostream &OS, const MCRegisterInfo *MRI) const { 54 for (const LocationList &L : Locations) { 55 OS << format("0x%8.8x: ", L.Offset); 56 L.dump(OS, IsLittleEndian, AddressSize, MRI, 12); 57 OS << "\n\n"; 58 } 59 } 60 61 Optional<DWARFDebugLoc::LocationList> 62 DWARFDebugLoc::parseOneLocationList(DWARFDataExtractor Data, unsigned *Offset) { 63 LocationList LL; 64 LL.Offset = *Offset; 65 66 // 2.6.2 Location Lists 67 // A location list entry consists of: 68 while (true) { 69 Entry E; 70 if (!Data.isValidOffsetForDataOfSize(*Offset, 2 * Data.getAddressSize())) { 71 llvm::errs() << "Location list overflows the debug_loc section.\n"; 72 return None; 73 } 74 75 // 1. A beginning address offset. ... 76 E.Begin = Data.getRelocatedAddress(Offset); 77 78 // 2. An ending address offset. ... 79 E.End = Data.getRelocatedAddress(Offset); 80 81 // The end of any given location list is marked by an end of list entry, 82 // which consists of a 0 for the beginning address offset and a 0 for the 83 // ending address offset. 84 if (E.Begin == 0 && E.End == 0) 85 return LL; 86 87 if (!Data.isValidOffsetForDataOfSize(*Offset, 2)) { 88 llvm::errs() << "Location list overflows the debug_loc section.\n"; 89 return None; 90 } 91 92 unsigned Bytes = Data.getU16(Offset); 93 if (!Data.isValidOffsetForDataOfSize(*Offset, Bytes)) { 94 llvm::errs() << "Location list overflows the debug_loc section.\n"; 95 return None; 96 } 97 // A single location description describing the location of the object... 98 StringRef str = Data.getData().substr(*Offset, Bytes); 99 *Offset += Bytes; 100 E.Loc.reserve(str.size()); 101 std::copy(str.begin(), str.end(), std::back_inserter(E.Loc)); 102 LL.Entries.push_back(std::move(E)); 103 } 104 } 105 106 void DWARFDebugLoc::parse(const DWARFDataExtractor &data) { 107 IsLittleEndian = data.isLittleEndian(); 108 AddressSize = data.getAddressSize(); 109 110 uint32_t Offset = 0; 111 while (data.isValidOffset(Offset + data.getAddressSize() - 1)) { 112 if (auto LL = parseOneLocationList(data, &Offset)) 113 Locations.push_back(std::move(*LL)); 114 else 115 break; 116 } 117 if (data.isValidOffset(Offset)) 118 errs() << "error: failed to consume entire .debug_loc section\n"; 119 } 120 121 Optional<DWARFDebugLocDWO::LocationList> 122 DWARFDebugLocDWO::parseOneLocationList(DataExtractor Data, unsigned *Offset) { 123 LocationList LL; 124 LL.Offset = *Offset; 125 126 // dwarf::DW_LLE_end_of_list_entry is 0 and indicates the end of the list. 127 while (auto Kind = 128 static_cast<dwarf::LocationListEntry>(Data.getU8(Offset))) { 129 if (Kind != dwarf::DW_LLE_startx_length) { 130 llvm::errs() << "error: dumping support for LLE of kind " << (int)Kind 131 << " not implemented\n"; 132 return None; 133 } 134 135 Entry E; 136 E.Start = Data.getULEB128(Offset); 137 E.Length = Data.getU32(Offset); 138 139 unsigned Bytes = Data.getU16(Offset); 140 // A single location description describing the location of the object... 141 StringRef str = Data.getData().substr(*Offset, Bytes); 142 *Offset += Bytes; 143 E.Loc.resize(str.size()); 144 std::copy(str.begin(), str.end(), E.Loc.begin()); 145 146 LL.Entries.push_back(std::move(E)); 147 } 148 return LL; 149 } 150 151 void DWARFDebugLocDWO::parse(DataExtractor data) { 152 IsLittleEndian = data.isLittleEndian(); 153 AddressSize = data.getAddressSize(); 154 155 uint32_t Offset = 0; 156 while (data.isValidOffset(Offset)) { 157 if (auto LL = parseOneLocationList(data, &Offset)) 158 Locations.push_back(std::move(*LL)); 159 else 160 return; 161 } 162 } 163 164 void DWARFDebugLocDWO::LocationList::dump(raw_ostream &OS, bool IsLittleEndian, 165 unsigned AddressSize, 166 const MCRegisterInfo *MRI, 167 unsigned Indent) const { 168 for (const Entry &E : Entries) { 169 OS << '\n'; 170 OS.indent(Indent); 171 OS << "Addr idx " << E.Start << " (w/ length " << E.Length << "): "; 172 dumpExpression(OS, E.Loc, IsLittleEndian, AddressSize, MRI); 173 } 174 } 175 176 void DWARFDebugLocDWO::dump(raw_ostream &OS, const MCRegisterInfo *MRI) const { 177 for (const LocationList &L : Locations) { 178 OS << format("0x%8.8x: ", L.Offset); 179 L.dump(OS, IsLittleEndian, AddressSize, MRI, /*Indent=*/12); 180 OS << "\n\n"; 181 } 182 } 183