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 <algorithm> 23 24 using namespace llvm; 25 26 template <typename T> 27 void writeInteger(T Integer, raw_ostream &OS, bool IsLittleEndian) { 28 if (IsLittleEndian != sys::IsLittleEndianHost) 29 sys::swapByteOrder(Integer); 30 OS.write(reinterpret_cast<char *>(&Integer), sizeof(T)); 31 } 32 33 void writeVariableSizedInteger(uint64_t Integer, size_t Size, raw_ostream &OS, 34 bool IsLittleEndian) { 35 if (8 == Size) 36 writeInteger((uint64_t)Integer, OS, IsLittleEndian); 37 else if (4 == Size) 38 writeInteger((uint32_t)Integer, OS, IsLittleEndian); 39 else if (2 == Size) 40 writeInteger((uint16_t)Integer, OS, IsLittleEndian); 41 else if (1 == Size) 42 writeInteger((uint8_t)Integer, OS, IsLittleEndian); 43 else 44 assert(false && "Invalid integer write size."); 45 } 46 47 void ZeroFillBytes(raw_ostream &OS, size_t Size) { 48 std::vector<uint8_t> FillData; 49 FillData.insert(FillData.begin(), Size, 0); 50 OS.write(reinterpret_cast<char *>(FillData.data()), Size); 51 } 52 53 void DWARFYAML::EmitDebugStr(raw_ostream &OS, const DWARFYAML::Data &DI) { 54 for (auto Str : DI.DebugStrings) { 55 OS.write(Str.data(), Str.size()); 56 OS.write('\0'); 57 } 58 } 59 60 void DWARFYAML::EmitDebugAbbrev(raw_ostream &OS, const DWARFYAML::Data &DI) { 61 for (auto AbbrevDecl : DI.AbbrevDecls) { 62 encodeULEB128(AbbrevDecl.Code, OS); 63 encodeULEB128(AbbrevDecl.Tag, OS); 64 OS.write(AbbrevDecl.Children); 65 for (auto Attr : AbbrevDecl.Attributes) { 66 encodeULEB128(Attr.Attribute, OS); 67 encodeULEB128(Attr.Form, OS); 68 } 69 encodeULEB128(0, OS); 70 encodeULEB128(0, OS); 71 } 72 } 73 74 void DWARFYAML::EmitDebugAranges(raw_ostream &OS, const DWARFYAML::Data &DI) { 75 for (auto Range : DI.ARanges) { 76 auto HeaderStart = OS.tell(); 77 writeInteger((uint32_t)Range.Length, OS, DI.IsLittleEndian); 78 writeInteger((uint16_t)Range.Version, OS, DI.IsLittleEndian); 79 writeInteger((uint32_t)Range.CuOffset, OS, DI.IsLittleEndian); 80 writeInteger((uint8_t)Range.AddrSize, OS, DI.IsLittleEndian); 81 writeInteger((uint8_t)Range.SegSize, OS, DI.IsLittleEndian); 82 83 auto HeaderSize = OS.tell() - HeaderStart; 84 auto FirstDescriptor = alignTo(HeaderSize, Range.AddrSize * 2); 85 ZeroFillBytes(OS, FirstDescriptor - HeaderSize); 86 87 for (auto Descriptor : Range.Descriptors) { 88 writeVariableSizedInteger(Descriptor.Address, Range.AddrSize, OS, 89 DI.IsLittleEndian); 90 writeVariableSizedInteger(Descriptor.Length, Range.AddrSize, OS, 91 DI.IsLittleEndian); 92 } 93 ZeroFillBytes(OS, Range.AddrSize * 2); 94 } 95 } 96 97 void DWARFYAML::EmitPubSection(raw_ostream &OS, 98 const DWARFYAML::PubSection &Sect, 99 bool IsLittleEndian) { 100 writeInteger((uint32_t)Sect.Length, OS, IsLittleEndian); 101 writeInteger((uint16_t)Sect.Version, OS, IsLittleEndian); 102 writeInteger((uint32_t)Sect.UnitOffset, OS, IsLittleEndian); 103 writeInteger((uint32_t)Sect.UnitSize, OS, IsLittleEndian); 104 for (auto Entry : Sect.Entries) { 105 writeInteger((uint32_t)Entry.DieOffset, OS, IsLittleEndian); 106 if (Sect.IsGNUStyle) 107 writeInteger((uint32_t)Entry.Descriptor, OS, IsLittleEndian); 108 OS.write(Entry.Name.data(), Entry.Name.size()); 109 OS.write('\0'); 110 } 111 } 112 113 void DWARFYAML::EmitDebugInfo(raw_ostream &OS, const DWARFYAML::Data &DI) { 114 115 for (auto CU : DI.CompileUnits) { 116 writeInteger((uint32_t)CU.Length, OS, DI.IsLittleEndian); 117 writeInteger((uint16_t)CU.Version, OS, DI.IsLittleEndian); 118 writeInteger((uint32_t)CU.AbbrOffset, OS, DI.IsLittleEndian); 119 writeInteger((uint8_t)CU.AddrSize, OS, DI.IsLittleEndian); 120 121 auto FirstAbbrevCode = CU.Entries[0].AbbrCode; 122 123 for (auto Entry : CU.Entries) { 124 encodeULEB128(Entry.AbbrCode, OS); 125 if (Entry.AbbrCode == 0u) 126 continue; 127 bool Indirect = false; 128 assert(Entry.AbbrCode - FirstAbbrevCode < DI.AbbrevDecls.size() && 129 "Out of range AbbCode"); 130 auto &Abbrev = DI.AbbrevDecls[Entry.AbbrCode - FirstAbbrevCode]; 131 132 auto FormVal = Entry.Values.begin(); 133 auto AbbrForm = Abbrev.Attributes.begin(); 134 for (; 135 FormVal != Entry.Values.end() && AbbrForm != Abbrev.Attributes.end(); 136 ++FormVal, ++AbbrForm) { 137 dwarf::Form Form = AbbrForm->Form; 138 do { 139 Indirect = false; 140 switch (Form) { 141 case dwarf::DW_FORM_addr: 142 writeVariableSizedInteger(FormVal->Value, CU.AddrSize, OS, 143 DI.IsLittleEndian); 144 break; 145 case dwarf::DW_FORM_ref_addr: { 146 // TODO: Handle DWARF32/DWARF64 after Line Table data is done 147 auto writeSize = CU.Version == 2 ? CU.AddrSize : 4; 148 writeVariableSizedInteger(FormVal->Value, writeSize, OS, 149 DI.IsLittleEndian); 150 break; 151 } 152 case dwarf::DW_FORM_exprloc: 153 case dwarf::DW_FORM_block: 154 encodeULEB128(FormVal->BlockData.size(), OS); 155 OS.write(reinterpret_cast<char *>(&FormVal->BlockData[0]), 156 FormVal->BlockData.size()); 157 break; 158 case dwarf::DW_FORM_block1: { 159 auto writeSize = FormVal->BlockData.size(); 160 writeInteger((uint8_t)writeSize, OS, DI.IsLittleEndian); 161 OS.write(reinterpret_cast<char *>(&FormVal->BlockData[0]), 162 FormVal->BlockData.size()); 163 break; 164 } 165 case dwarf::DW_FORM_block2: { 166 auto writeSize = FormVal->BlockData.size(); 167 writeInteger((uint16_t)writeSize, OS, DI.IsLittleEndian); 168 OS.write(reinterpret_cast<char *>(&FormVal->BlockData[0]), 169 FormVal->BlockData.size()); 170 break; 171 } 172 case dwarf::DW_FORM_block4: { 173 auto writeSize = FormVal->BlockData.size(); 174 writeInteger((uint32_t)writeSize, OS, DI.IsLittleEndian); 175 OS.write(reinterpret_cast<char *>(&FormVal->BlockData[0]), 176 FormVal->BlockData.size()); 177 break; 178 } 179 case dwarf::DW_FORM_data1: 180 case dwarf::DW_FORM_ref1: 181 case dwarf::DW_FORM_flag: 182 writeInteger((uint8_t)FormVal->Value, OS, DI.IsLittleEndian); 183 break; 184 case dwarf::DW_FORM_data2: 185 case dwarf::DW_FORM_ref2: 186 writeInteger((uint16_t)FormVal->Value, OS, DI.IsLittleEndian); 187 break; 188 case dwarf::DW_FORM_data4: 189 case dwarf::DW_FORM_ref4: 190 writeInteger((uint32_t)FormVal->Value, OS, DI.IsLittleEndian); 191 break; 192 case dwarf::DW_FORM_data8: 193 case dwarf::DW_FORM_ref8: 194 writeInteger((uint64_t)FormVal->Value, OS, DI.IsLittleEndian); 195 break; 196 case dwarf::DW_FORM_sdata: 197 encodeSLEB128(FormVal->Value, OS); 198 break; 199 case dwarf::DW_FORM_udata: 200 case dwarf::DW_FORM_ref_udata: 201 encodeULEB128(FormVal->Value, OS); 202 break; 203 case dwarf::DW_FORM_string: 204 OS.write(FormVal->CStr.data(), FormVal->CStr.size()); 205 OS.write('\0'); 206 break; 207 case dwarf::DW_FORM_indirect: 208 encodeULEB128(FormVal->Value, OS); 209 Indirect = true; 210 Form = static_cast<dwarf::Form>((uint64_t)FormVal->Value); 211 ++FormVal; 212 break; 213 case dwarf::DW_FORM_strp: 214 case dwarf::DW_FORM_sec_offset: 215 case dwarf::DW_FORM_GNU_ref_alt: 216 case dwarf::DW_FORM_GNU_strp_alt: 217 case dwarf::DW_FORM_line_strp: 218 case dwarf::DW_FORM_strp_sup: 219 case dwarf::DW_FORM_ref_sup: 220 // TODO: Handle DWARF32/64 221 writeInteger((uint32_t)FormVal->Value, OS, DI.IsLittleEndian); 222 break; 223 case dwarf::DW_FORM_ref_sig8: 224 writeInteger((uint64_t)FormVal->Value, OS, DI.IsLittleEndian); 225 break; 226 case dwarf::DW_FORM_GNU_addr_index: 227 case dwarf::DW_FORM_GNU_str_index: 228 encodeULEB128(FormVal->Value, OS); 229 break; 230 default: 231 break; 232 } 233 } while (Indirect); 234 } 235 } 236 } 237 } 238 239 void EmitFileEntry(raw_ostream &OS, const DWARFYAML::File &File) { 240 OS.write(File.Name.data(), File.Name.size()); 241 OS.write('\0'); 242 encodeULEB128(File.DirIdx, OS); 243 encodeULEB128(File.ModTime, OS); 244 encodeULEB128(File.Length, OS); 245 } 246 247 void DWARFYAML::EmitDebugLine(raw_ostream &OS, const DWARFYAML::Data &DI) { 248 for (const auto LineTable : DI.DebugLines) { 249 writeInteger((uint32_t)LineTable.TotalLength, OS, DI.IsLittleEndian); 250 uint64_t SizeOfPrologueLength = 4; 251 if (LineTable.TotalLength == UINT32_MAX) { 252 writeInteger((uint64_t)LineTable.TotalLength64, OS, DI.IsLittleEndian); 253 SizeOfPrologueLength = 8; 254 } 255 writeInteger((uint16_t)LineTable.Version, OS, DI.IsLittleEndian); 256 writeVariableSizedInteger(LineTable.PrologueLength, SizeOfPrologueLength, 257 OS, DI.IsLittleEndian); 258 writeInteger((uint8_t)LineTable.MinInstLength, OS, DI.IsLittleEndian); 259 if (LineTable.Version >= 4) 260 writeInteger((uint8_t)LineTable.MaxOpsPerInst, OS, DI.IsLittleEndian); 261 writeInteger((uint8_t)LineTable.DefaultIsStmt, OS, DI.IsLittleEndian); 262 writeInteger((uint8_t)LineTable.LineBase, OS, DI.IsLittleEndian); 263 writeInteger((uint8_t)LineTable.LineRange, OS, DI.IsLittleEndian); 264 writeInteger((uint8_t)LineTable.OpcodeBase, OS, DI.IsLittleEndian); 265 266 for (auto OpcodeLength : LineTable.StandardOpcodeLengths) 267 writeInteger((uint8_t)OpcodeLength, OS, DI.IsLittleEndian); 268 269 for (auto IncludeDir : LineTable.IncludeDirs) { 270 OS.write(IncludeDir.data(), IncludeDir.size()); 271 OS.write('\0'); 272 } 273 OS.write('\0'); 274 275 for (auto File : LineTable.Files) 276 EmitFileEntry(OS, File); 277 OS.write('\0'); 278 279 for (auto Op : LineTable.Opcodes) { 280 writeInteger((uint8_t)Op.Opcode, OS, DI.IsLittleEndian); 281 if (Op.Opcode == 0) { 282 encodeULEB128(Op.ExtLen, OS); 283 writeInteger((uint8_t)Op.SubOpcode, OS, DI.IsLittleEndian); 284 switch (Op.SubOpcode) { 285 case dwarf::DW_LNE_set_address: 286 case dwarf::DW_LNE_set_discriminator: 287 writeVariableSizedInteger(Op.Data, DI.CompileUnits[0].AddrSize, OS, 288 DI.IsLittleEndian); 289 break; 290 case dwarf::DW_LNE_define_file: 291 EmitFileEntry(OS, Op.FileEntry); 292 break; 293 case dwarf::DW_LNE_end_sequence: 294 break; 295 default: 296 for (auto OpByte : Op.UnknownOpcodeData) 297 writeInteger((uint8_t)OpByte, OS, DI.IsLittleEndian); 298 } 299 } else if (Op.Opcode < LineTable.OpcodeBase) { 300 switch (Op.Opcode) { 301 case dwarf::DW_LNS_copy: 302 case dwarf::DW_LNS_negate_stmt: 303 case dwarf::DW_LNS_set_basic_block: 304 case dwarf::DW_LNS_const_add_pc: 305 case dwarf::DW_LNS_set_prologue_end: 306 case dwarf::DW_LNS_set_epilogue_begin: 307 break; 308 309 case dwarf::DW_LNS_advance_pc: 310 case dwarf::DW_LNS_set_file: 311 case dwarf::DW_LNS_set_column: 312 case dwarf::DW_LNS_set_isa: 313 encodeULEB128(Op.Data, OS); 314 break; 315 316 case dwarf::DW_LNS_advance_line: 317 encodeSLEB128(Op.SData, OS); 318 break; 319 320 case dwarf::DW_LNS_fixed_advance_pc: 321 writeInteger((uint16_t)Op.Data, OS, DI.IsLittleEndian); 322 break; 323 324 default: 325 for (auto OpData : Op.StandardOpcodeData) { 326 encodeULEB128(OpData, OS); 327 } 328 } 329 } 330 } 331 } 332 } 333 334 typedef void (*EmitFuncType)(raw_ostream &, const DWARFYAML::Data &); 335 336 void EmitDebugSectionImpl( 337 const DWARFYAML::Data &DI, EmitFuncType EmitFunc, StringRef Sec, 338 StringMap<std::unique_ptr<MemoryBuffer>> &OutputBuffers) { 339 std::string Data; 340 raw_string_ostream DebugInfoStream(Data); 341 EmitFunc(DebugInfoStream, DI); 342 DebugInfoStream.flush(); 343 if (!Data.empty()) 344 OutputBuffers[Sec] = MemoryBuffer::getMemBufferCopy(Data); 345 } 346 347 Expected<StringMap<std::unique_ptr<MemoryBuffer>>> 348 DWARFYAML::EmitDebugSections(StringRef YAMLString, 349 bool IsLittleEndian) { 350 StringMap<std::unique_ptr<MemoryBuffer>> DebugSections; 351 352 yaml::Input YIn(YAMLString); 353 354 DWARFYAML::Data DI; 355 DI.IsLittleEndian = IsLittleEndian; 356 YIn >> DI; 357 if (YIn.error()) 358 return errorCodeToError(YIn.error()); 359 360 EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugInfo, "debug_info", 361 DebugSections); 362 EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugLine, "debug_line", 363 DebugSections); 364 EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugStr, "debug_str", 365 DebugSections); 366 EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugAbbrev, "debug_abbrev", 367 DebugSections); 368 EmitDebugSectionImpl(DI, &DWARFYAML::EmitDebugAranges, "debug_aranges", 369 DebugSections); 370 return std::move(DebugSections); 371 } 372