1 //===- DWARFEmitter - Convert YAML to DWARF binary data -------------------===// 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 /// \file 11 /// \brief The DWARF component of yaml2obj. Provided as library code for tests. 12 /// 13 //===----------------------------------------------------------------------===// 14 15 #include "llvm/ObjectYAML/DWARFEmitter.h" 16 #include "llvm/ObjectYAML/DWARFYAML.h" 17 #include "llvm/Support/Error.h" 18 #include "llvm/Support/LEB128.h" 19 #include "llvm/Support/raw_ostream.h" 20 #include "llvm/Support/SwapByteOrder.h" 21 22 #include "DWARFVisitor.h" 23 24 #include <algorithm> 25 26 using namespace llvm; 27 28 template <typename T> 29 static void writeInteger(T Integer, raw_ostream &OS, bool IsLittleEndian) { 30 if (IsLittleEndian != sys::IsLittleEndianHost) 31 sys::swapByteOrder(Integer); 32 OS.write(reinterpret_cast<char *>(&Integer), sizeof(T)); 33 } 34 35 static void writeVariableSizedInteger(uint64_t Integer, size_t Size, 36 raw_ostream &OS, bool IsLittleEndian) { 37 if (8 == Size) 38 writeInteger((uint64_t)Integer, OS, IsLittleEndian); 39 else if (4 == Size) 40 writeInteger((uint32_t)Integer, OS, IsLittleEndian); 41 else if (2 == Size) 42 writeInteger((uint16_t)Integer, OS, IsLittleEndian); 43 else if (1 == Size) 44 writeInteger((uint8_t)Integer, OS, IsLittleEndian); 45 else 46 assert(false && "Invalid integer write size."); 47 } 48 49 static void ZeroFillBytes(raw_ostream &OS, size_t Size) { 50 std::vector<uint8_t> FillData; 51 FillData.insert(FillData.begin(), Size, 0); 52 OS.write(reinterpret_cast<char *>(FillData.data()), Size); 53 } 54 55 void writeInitialLength(const DWARFYAML::InitialLength &Length, raw_ostream &OS, 56 bool IsLittleEndian) { 57 writeInteger((uint32_t)Length.TotalLength, OS, IsLittleEndian); 58 if (Length.isDWARF64()) 59 writeInteger((uint64_t)Length.TotalLength64, OS, IsLittleEndian); 60 } 61 62 void DWARFYAML::EmitDebugStr(raw_ostream &OS, const DWARFYAML::Data &DI) { 63 for (auto Str : DI.DebugStrings) { 64 OS.write(Str.data(), Str.size()); 65 OS.write('\0'); 66 } 67 } 68 69 void DWARFYAML::EmitDebugAbbrev(raw_ostream &OS, const DWARFYAML::Data &DI) { 70 for (auto AbbrevDecl : DI.AbbrevDecls) { 71 encodeULEB128(AbbrevDecl.Code, OS); 72 encodeULEB128(AbbrevDecl.Tag, OS); 73 OS.write(AbbrevDecl.Children); 74 for (auto Attr : AbbrevDecl.Attributes) { 75 encodeULEB128(Attr.Attribute, OS); 76 encodeULEB128(Attr.Form, OS); 77 if (Attr.Form == dwarf::DW_FORM_implicit_const) 78 encodeSLEB128(Attr.Value, OS); 79 } 80 encodeULEB128(0, OS); 81 encodeULEB128(0, OS); 82 } 83 } 84 85 void DWARFYAML::EmitDebugAranges(raw_ostream &OS, const DWARFYAML::Data &DI) { 86 for (auto Range : DI.ARanges) { 87 auto HeaderStart = OS.tell(); 88 writeInitialLength(Range.Length, OS, DI.IsLittleEndian); 89 writeInteger((uint16_t)Range.Version, OS, DI.IsLittleEndian); 90 writeInteger((uint32_t)Range.CuOffset, OS, DI.IsLittleEndian); 91 writeInteger((uint8_t)Range.AddrSize, OS, DI.IsLittleEndian); 92 writeInteger((uint8_t)Range.SegSize, OS, DI.IsLittleEndian); 93 94 auto HeaderSize = OS.tell() - HeaderStart; 95 auto FirstDescriptor = alignTo(HeaderSize, Range.AddrSize * 2); 96 ZeroFillBytes(OS, FirstDescriptor - HeaderSize); 97 98 for (auto Descriptor : Range.Descriptors) { 99 writeVariableSizedInteger(Descriptor.Address, Range.AddrSize, OS, 100 DI.IsLittleEndian); 101 writeVariableSizedInteger(Descriptor.Length, Range.AddrSize, OS, 102 DI.IsLittleEndian); 103 } 104 ZeroFillBytes(OS, Range.AddrSize * 2); 105 } 106 } 107 108 void DWARFYAML::EmitPubSection(raw_ostream &OS, 109 const DWARFYAML::PubSection &Sect, 110 bool IsLittleEndian) { 111 writeInitialLength(Sect.Length, OS, IsLittleEndian); 112 writeInteger((uint16_t)Sect.Version, OS, IsLittleEndian); 113 writeInteger((uint32_t)Sect.UnitOffset, OS, IsLittleEndian); 114 writeInteger((uint32_t)Sect.UnitSize, OS, IsLittleEndian); 115 for (auto Entry : Sect.Entries) { 116 writeInteger((uint32_t)Entry.DieOffset, OS, IsLittleEndian); 117 if (Sect.IsGNUStyle) 118 writeInteger((uint32_t)Entry.Descriptor, OS, IsLittleEndian); 119 OS.write(Entry.Name.data(), Entry.Name.size()); 120 OS.write('\0'); 121 } 122 } 123 124 /// \brief An extension of the DWARFYAML::ConstVisitor which writes compile 125 /// units and DIEs to a stream. 126 class DumpVisitor : public DWARFYAML::ConstVisitor { 127 raw_ostream &OS; 128 129 protected: 130 virtual void onStartCompileUnit(const DWARFYAML::Unit &CU) { 131 writeInitialLength(CU.Length, OS, DebugInfo.IsLittleEndian); 132 writeInteger((uint16_t)CU.Version, OS, DebugInfo.IsLittleEndian); 133 if(CU.Version >= 5) { 134 writeInteger((uint8_t)CU.Type, OS, DebugInfo.IsLittleEndian); 135 writeInteger((uint8_t)CU.AddrSize, OS, DebugInfo.IsLittleEndian); 136 writeInteger((uint32_t)CU.AbbrOffset, OS, DebugInfo.IsLittleEndian); 137 }else { 138 writeInteger((uint32_t)CU.AbbrOffset, OS, DebugInfo.IsLittleEndian); 139 writeInteger((uint8_t)CU.AddrSize, OS, DebugInfo.IsLittleEndian); 140 } 141 142 } 143 144 virtual void onStartDIE(const DWARFYAML::Unit &CU, 145 const DWARFYAML::Entry &DIE) { 146 encodeULEB128(DIE.AbbrCode, OS); 147 } 148 149 virtual void onValue(const uint8_t U) { 150 writeInteger(U, OS, DebugInfo.IsLittleEndian); 151 } 152 153 virtual void onValue(const uint16_t U) { 154 writeInteger(U, OS, DebugInfo.IsLittleEndian); 155 } 156 virtual void onValue(const uint32_t U) { 157 writeInteger(U, OS, DebugInfo.IsLittleEndian); 158 } 159 virtual void onValue(const uint64_t U, const bool LEB = false) { 160 if (LEB) 161 encodeULEB128(U, OS); 162 else 163 writeInteger(U, OS, DebugInfo.IsLittleEndian); 164 } 165 166 virtual void onValue(const int64_t S, const bool LEB = false) { 167 if (LEB) 168 encodeSLEB128(S, OS); 169 else 170 writeInteger(S, OS, DebugInfo.IsLittleEndian); 171 } 172 173 virtual void onValue(const StringRef String) { 174 OS.write(String.data(), String.size()); 175 OS.write('\0'); 176 } 177 178 virtual void onValue(const MemoryBufferRef MBR) { 179 OS.write(MBR.getBufferStart(), MBR.getBufferSize()); 180 } 181 182 public: 183 DumpVisitor(const DWARFYAML::Data &DI, raw_ostream &Out) 184 : DWARFYAML::ConstVisitor(DI), OS(Out) {} 185 }; 186 187 void DWARFYAML::EmitDebugInfo(raw_ostream &OS, const DWARFYAML::Data &DI) { 188 DumpVisitor Visitor(DI, OS); 189 Visitor.traverseDebugInfo(); 190 } 191 192 static void EmitFileEntry(raw_ostream &OS, const DWARFYAML::File &File) { 193 OS.write(File.Name.data(), File.Name.size()); 194 OS.write('\0'); 195 encodeULEB128(File.DirIdx, OS); 196 encodeULEB128(File.ModTime, OS); 197 encodeULEB128(File.Length, OS); 198 } 199 200 void DWARFYAML::EmitDebugLine(raw_ostream &OS, const DWARFYAML::Data &DI) { 201 for (const auto &LineTable : DI.DebugLines) { 202 writeInitialLength(LineTable.Length, OS, DI.IsLittleEndian); 203 uint64_t SizeOfPrologueLength = LineTable.Length.isDWARF64() ? 8 : 4; 204 writeInteger((uint16_t)LineTable.Version, OS, DI.IsLittleEndian); 205 writeVariableSizedInteger(LineTable.PrologueLength, SizeOfPrologueLength, 206 OS, DI.IsLittleEndian); 207 writeInteger((uint8_t)LineTable.MinInstLength, OS, DI.IsLittleEndian); 208 if (LineTable.Version >= 4) 209 writeInteger((uint8_t)LineTable.MaxOpsPerInst, OS, DI.IsLittleEndian); 210 writeInteger((uint8_t)LineTable.DefaultIsStmt, OS, DI.IsLittleEndian); 211 writeInteger((uint8_t)LineTable.LineBase, OS, DI.IsLittleEndian); 212 writeInteger((uint8_t)LineTable.LineRange, OS, DI.IsLittleEndian); 213 writeInteger((uint8_t)LineTable.OpcodeBase, OS, DI.IsLittleEndian); 214 215 for (auto OpcodeLength : LineTable.StandardOpcodeLengths) 216 writeInteger((uint8_t)OpcodeLength, OS, DI.IsLittleEndian); 217 218 for (auto IncludeDir : LineTable.IncludeDirs) { 219 OS.write(IncludeDir.data(), IncludeDir.size()); 220 OS.write('\0'); 221 } 222 OS.write('\0'); 223 224 for (auto File : LineTable.Files) 225 EmitFileEntry(OS, File); 226 OS.write('\0'); 227 228 for (auto Op : LineTable.Opcodes) { 229 writeInteger((uint8_t)Op.Opcode, OS, DI.IsLittleEndian); 230 if (Op.Opcode == 0) { 231 encodeULEB128(Op.ExtLen, OS); 232 writeInteger((uint8_t)Op.SubOpcode, OS, DI.IsLittleEndian); 233 switch (Op.SubOpcode) { 234 case dwarf::DW_LNE_set_address: 235 case dwarf::DW_LNE_set_discriminator: 236 writeVariableSizedInteger(Op.Data, DI.CompileUnits[0].AddrSize, OS, 237 DI.IsLittleEndian); 238 break; 239 case dwarf::DW_LNE_define_file: 240 EmitFileEntry(OS, Op.FileEntry); 241 break; 242 case dwarf::DW_LNE_end_sequence: 243 break; 244 default: 245 for (auto OpByte : Op.UnknownOpcodeData) 246 writeInteger((uint8_t)OpByte, OS, DI.IsLittleEndian); 247 } 248 } else if (Op.Opcode < LineTable.OpcodeBase) { 249 switch (Op.Opcode) { 250 case dwarf::DW_LNS_copy: 251 case dwarf::DW_LNS_negate_stmt: 252 case dwarf::DW_LNS_set_basic_block: 253 case dwarf::DW_LNS_const_add_pc: 254 case dwarf::DW_LNS_set_prologue_end: 255 case dwarf::DW_LNS_set_epilogue_begin: 256 break; 257 258 case dwarf::DW_LNS_advance_pc: 259 case dwarf::DW_LNS_set_file: 260 case dwarf::DW_LNS_set_column: 261 case dwarf::DW_LNS_set_isa: 262 encodeULEB128(Op.Data, OS); 263 break; 264 265 case dwarf::DW_LNS_advance_line: 266 encodeSLEB128(Op.SData, OS); 267 break; 268 269 case dwarf::DW_LNS_fixed_advance_pc: 270 writeInteger((uint16_t)Op.Data, OS, DI.IsLittleEndian); 271 break; 272 273 default: 274 for (auto OpData : Op.StandardOpcodeData) { 275 encodeULEB128(OpData, OS); 276 } 277 } 278 } 279 } 280 } 281 } 282 283 typedef void (*EmitFuncType)(raw_ostream &, const DWARFYAML::Data &); 284 285 static void 286 EmitDebugSectionImpl(const DWARFYAML::Data &DI, EmitFuncType EmitFunc, 287 StringRef Sec, 288 StringMap<std::unique_ptr<MemoryBuffer>> &OutputBuffers) { 289 std::string Data; 290 raw_string_ostream DebugInfoStream(Data); 291 EmitFunc(DebugInfoStream, DI); 292 DebugInfoStream.flush(); 293 if (!Data.empty()) 294 OutputBuffers[Sec] = MemoryBuffer::getMemBufferCopy(Data); 295 } 296 297 Expected<StringMap<std::unique_ptr<MemoryBuffer>>> 298 DWARFYAML::EmitDebugSections(StringRef YAMLString, 299 bool IsLittleEndian) { 300 StringMap<std::unique_ptr<MemoryBuffer>> DebugSections; 301 302 yaml::Input YIn(YAMLString); 303 304 DWARFYAML::Data DI; 305 DI.IsLittleEndian = IsLittleEndian; 306 YIn >> DI; 307 if (YIn.error()) 308 return errorCodeToError(YIn.error()); 309 310 EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugInfo, "debug_info", 311 DebugSections); 312 EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugLine, "debug_line", 313 DebugSections); 314 EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugStr, "debug_str", 315 DebugSections); 316 EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugAbbrev, "debug_abbrev", 317 DebugSections); 318 EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugAranges, "debug_aranges", 319 DebugSections); 320 return std::move(DebugSections); 321 } 322