1 //===------ utils/obj2yaml.cpp - obj2yaml conversion tool -------*- C++ -*-===// 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 "obj2yaml.h" 11 #include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" 12 #include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h" 13 #include "llvm/DebugInfo/CodeView/StringsAndChecksums.h" 14 #include "llvm/Object/COFF.h" 15 #include "llvm/ObjectYAML/COFFYAML.h" 16 #include "llvm/ObjectYAML/CodeViewYAMLSymbols.h" 17 #include "llvm/ObjectYAML/CodeViewYAMLTypes.h" 18 #include "llvm/Support/ErrorHandling.h" 19 #include "llvm/Support/YAMLTraits.h" 20 21 using namespace llvm; 22 23 namespace { 24 25 class COFFDumper { 26 const object::COFFObjectFile &Obj; 27 COFFYAML::Object YAMLObj; 28 template <typename T> 29 void dumpOptionalHeader(T OptionalHeader); 30 void dumpHeader(); 31 void dumpSections(unsigned numSections); 32 void dumpSymbols(unsigned numSymbols); 33 34 public: 35 COFFDumper(const object::COFFObjectFile &Obj); 36 COFFYAML::Object &getYAMLObj(); 37 }; 38 39 } 40 41 COFFDumper::COFFDumper(const object::COFFObjectFile &Obj) : Obj(Obj) { 42 const object::pe32_header *PE32Header = nullptr; 43 Obj.getPE32Header(PE32Header); 44 if (PE32Header) { 45 dumpOptionalHeader(PE32Header); 46 } else { 47 const object::pe32plus_header *PE32PlusHeader = nullptr; 48 Obj.getPE32PlusHeader(PE32PlusHeader); 49 if (PE32PlusHeader) { 50 dumpOptionalHeader(PE32PlusHeader); 51 } 52 } 53 dumpHeader(); 54 dumpSections(Obj.getNumberOfSections()); 55 dumpSymbols(Obj.getNumberOfSymbols()); 56 } 57 58 template <typename T> void COFFDumper::dumpOptionalHeader(T OptionalHeader) { 59 YAMLObj.OptionalHeader = COFFYAML::PEHeader(); 60 YAMLObj.OptionalHeader->Header.AddressOfEntryPoint = 61 OptionalHeader->AddressOfEntryPoint; 62 YAMLObj.OptionalHeader->Header.AddressOfEntryPoint = 63 OptionalHeader->AddressOfEntryPoint; 64 YAMLObj.OptionalHeader->Header.ImageBase = OptionalHeader->ImageBase; 65 YAMLObj.OptionalHeader->Header.SectionAlignment = 66 OptionalHeader->SectionAlignment; 67 YAMLObj.OptionalHeader->Header.FileAlignment = OptionalHeader->FileAlignment; 68 YAMLObj.OptionalHeader->Header.MajorOperatingSystemVersion = 69 OptionalHeader->MajorOperatingSystemVersion; 70 YAMLObj.OptionalHeader->Header.MinorOperatingSystemVersion = 71 OptionalHeader->MinorOperatingSystemVersion; 72 YAMLObj.OptionalHeader->Header.MajorImageVersion = 73 OptionalHeader->MajorImageVersion; 74 YAMLObj.OptionalHeader->Header.MinorImageVersion = 75 OptionalHeader->MinorImageVersion; 76 YAMLObj.OptionalHeader->Header.MajorSubsystemVersion = 77 OptionalHeader->MajorSubsystemVersion; 78 YAMLObj.OptionalHeader->Header.MinorSubsystemVersion = 79 OptionalHeader->MinorSubsystemVersion; 80 YAMLObj.OptionalHeader->Header.Subsystem = OptionalHeader->Subsystem; 81 YAMLObj.OptionalHeader->Header.DLLCharacteristics = 82 OptionalHeader->DLLCharacteristics; 83 YAMLObj.OptionalHeader->Header.SizeOfStackReserve = 84 OptionalHeader->SizeOfStackReserve; 85 YAMLObj.OptionalHeader->Header.SizeOfStackCommit = 86 OptionalHeader->SizeOfStackCommit; 87 YAMLObj.OptionalHeader->Header.SizeOfHeapReserve = 88 OptionalHeader->SizeOfHeapReserve; 89 YAMLObj.OptionalHeader->Header.SizeOfHeapCommit = 90 OptionalHeader->SizeOfHeapCommit; 91 unsigned I = 0; 92 for (auto &DestDD : YAMLObj.OptionalHeader->DataDirectories) { 93 const object::data_directory *DD; 94 if (Obj.getDataDirectory(I++, DD)) 95 continue; 96 DestDD = COFF::DataDirectory(); 97 DestDD->RelativeVirtualAddress = DD->RelativeVirtualAddress; 98 DestDD->Size = DD->Size; 99 } 100 } 101 102 void COFFDumper::dumpHeader() { 103 YAMLObj.Header.Machine = Obj.getMachine(); 104 YAMLObj.Header.Characteristics = Obj.getCharacteristics(); 105 } 106 107 static void 108 initializeFileAndStringTable(const llvm::object::COFFObjectFile &Obj, 109 codeview::StringsAndChecksumsRef &SC) { 110 111 ExitOnError Err("Invalid .debug$S section!"); 112 // Iterate all .debug$S sections looking for the checksums and string table. 113 // Exit as soon as both sections are found. 114 for (const auto &S : Obj.sections()) { 115 if (SC.hasStrings() && SC.hasChecksums()) 116 break; 117 118 StringRef SectionName; 119 S.getName(SectionName); 120 ArrayRef<uint8_t> sectionData; 121 if (SectionName != ".debug$S") 122 continue; 123 124 const object::coff_section *COFFSection = Obj.getCOFFSection(S); 125 126 Obj.getSectionContents(COFFSection, sectionData); 127 128 BinaryStreamReader Reader(sectionData, support::little); 129 uint32_t Magic; 130 131 Err(Reader.readInteger(Magic)); 132 assert(Magic == COFF::DEBUG_SECTION_MAGIC && "Invalid .debug$S section!"); 133 134 codeview::DebugSubsectionArray Subsections; 135 Err(Reader.readArray(Subsections, Reader.bytesRemaining())); 136 137 SC.initialize(Subsections); 138 } 139 } 140 141 void COFFDumper::dumpSections(unsigned NumSections) { 142 std::vector<COFFYAML::Section> &YAMLSections = YAMLObj.Sections; 143 codeview::StringsAndChecksumsRef SC; 144 initializeFileAndStringTable(Obj, SC); 145 146 for (const auto &ObjSection : Obj.sections()) { 147 const object::coff_section *COFFSection = Obj.getCOFFSection(ObjSection); 148 COFFYAML::Section NewYAMLSection; 149 ObjSection.getName(NewYAMLSection.Name); 150 NewYAMLSection.Header.Characteristics = COFFSection->Characteristics; 151 NewYAMLSection.Header.VirtualAddress = ObjSection.getAddress(); 152 NewYAMLSection.Header.VirtualSize = COFFSection->VirtualSize; 153 NewYAMLSection.Header.NumberOfLineNumbers = 154 COFFSection->NumberOfLinenumbers; 155 NewYAMLSection.Header.NumberOfRelocations = 156 COFFSection->NumberOfRelocations; 157 NewYAMLSection.Header.PointerToLineNumbers = 158 COFFSection->PointerToLinenumbers; 159 NewYAMLSection.Header.PointerToRawData = COFFSection->PointerToRawData; 160 NewYAMLSection.Header.PointerToRelocations = 161 COFFSection->PointerToRelocations; 162 NewYAMLSection.Header.SizeOfRawData = COFFSection->SizeOfRawData; 163 NewYAMLSection.Alignment = ObjSection.getAlignment(); 164 assert(NewYAMLSection.Alignment <= 8192); 165 166 ArrayRef<uint8_t> sectionData; 167 if (!ObjSection.isBSS()) 168 Obj.getSectionContents(COFFSection, sectionData); 169 NewYAMLSection.SectionData = yaml::BinaryRef(sectionData); 170 171 if (NewYAMLSection.Name == ".debug$S") 172 NewYAMLSection.DebugS = CodeViewYAML::fromDebugS(sectionData, SC); 173 else if (NewYAMLSection.Name == ".debug$T") 174 NewYAMLSection.DebugT = CodeViewYAML::fromDebugT(sectionData); 175 176 std::vector<COFFYAML::Relocation> Relocations; 177 for (const auto &Reloc : ObjSection.relocations()) { 178 const object::coff_relocation *reloc = Obj.getCOFFRelocation(Reloc); 179 COFFYAML::Relocation Rel; 180 object::symbol_iterator Sym = Reloc.getSymbol(); 181 Expected<StringRef> SymbolNameOrErr = Sym->getName(); 182 if (!SymbolNameOrErr) { 183 std::string Buf; 184 raw_string_ostream OS(Buf); 185 logAllUnhandledErrors(SymbolNameOrErr.takeError(), OS, ""); 186 OS.flush(); 187 report_fatal_error(Buf); 188 } 189 Rel.SymbolName = *SymbolNameOrErr; 190 Rel.VirtualAddress = reloc->VirtualAddress; 191 Rel.Type = reloc->Type; 192 Relocations.push_back(Rel); 193 } 194 NewYAMLSection.Relocations = Relocations; 195 YAMLSections.push_back(NewYAMLSection); 196 } 197 } 198 199 static void 200 dumpFunctionDefinition(COFFYAML::Symbol *Sym, 201 const object::coff_aux_function_definition *ObjFD) { 202 COFF::AuxiliaryFunctionDefinition YAMLFD; 203 YAMLFD.TagIndex = ObjFD->TagIndex; 204 YAMLFD.TotalSize = ObjFD->TotalSize; 205 YAMLFD.PointerToLinenumber = ObjFD->PointerToLinenumber; 206 YAMLFD.PointerToNextFunction = ObjFD->PointerToNextFunction; 207 208 Sym->FunctionDefinition = YAMLFD; 209 } 210 211 static void 212 dumpbfAndEfLineInfo(COFFYAML::Symbol *Sym, 213 const object::coff_aux_bf_and_ef_symbol *ObjBES) { 214 COFF::AuxiliarybfAndefSymbol YAMLAAS; 215 YAMLAAS.Linenumber = ObjBES->Linenumber; 216 YAMLAAS.PointerToNextFunction = ObjBES->PointerToNextFunction; 217 218 Sym->bfAndefSymbol = YAMLAAS; 219 } 220 221 static void dumpWeakExternal(COFFYAML::Symbol *Sym, 222 const object::coff_aux_weak_external *ObjWE) { 223 COFF::AuxiliaryWeakExternal YAMLWE; 224 YAMLWE.TagIndex = ObjWE->TagIndex; 225 YAMLWE.Characteristics = ObjWE->Characteristics; 226 227 Sym->WeakExternal = YAMLWE; 228 } 229 230 static void 231 dumpSectionDefinition(COFFYAML::Symbol *Sym, 232 const object::coff_aux_section_definition *ObjSD, 233 bool IsBigObj) { 234 COFF::AuxiliarySectionDefinition YAMLASD; 235 int32_t AuxNumber = ObjSD->getNumber(IsBigObj); 236 YAMLASD.Length = ObjSD->Length; 237 YAMLASD.NumberOfRelocations = ObjSD->NumberOfRelocations; 238 YAMLASD.NumberOfLinenumbers = ObjSD->NumberOfLinenumbers; 239 YAMLASD.CheckSum = ObjSD->CheckSum; 240 YAMLASD.Number = AuxNumber; 241 YAMLASD.Selection = ObjSD->Selection; 242 243 Sym->SectionDefinition = YAMLASD; 244 } 245 246 static void 247 dumpCLRTokenDefinition(COFFYAML::Symbol *Sym, 248 const object::coff_aux_clr_token *ObjCLRToken) { 249 COFF::AuxiliaryCLRToken YAMLCLRToken; 250 YAMLCLRToken.AuxType = ObjCLRToken->AuxType; 251 YAMLCLRToken.SymbolTableIndex = ObjCLRToken->SymbolTableIndex; 252 253 Sym->CLRToken = YAMLCLRToken; 254 } 255 256 void COFFDumper::dumpSymbols(unsigned NumSymbols) { 257 std::vector<COFFYAML::Symbol> &Symbols = YAMLObj.Symbols; 258 for (const auto &S : Obj.symbols()) { 259 object::COFFSymbolRef Symbol = Obj.getCOFFSymbol(S); 260 COFFYAML::Symbol Sym; 261 Obj.getSymbolName(Symbol, Sym.Name); 262 Sym.SimpleType = COFF::SymbolBaseType(Symbol.getBaseType()); 263 Sym.ComplexType = COFF::SymbolComplexType(Symbol.getComplexType()); 264 Sym.Header.StorageClass = Symbol.getStorageClass(); 265 Sym.Header.Value = Symbol.getValue(); 266 Sym.Header.SectionNumber = Symbol.getSectionNumber(); 267 Sym.Header.NumberOfAuxSymbols = Symbol.getNumberOfAuxSymbols(); 268 269 if (Symbol.getNumberOfAuxSymbols() > 0) { 270 ArrayRef<uint8_t> AuxData = Obj.getSymbolAuxData(Symbol); 271 if (Symbol.isFunctionDefinition()) { 272 // This symbol represents a function definition. 273 assert(Symbol.getNumberOfAuxSymbols() == 1 && 274 "Expected a single aux symbol to describe this function!"); 275 276 const object::coff_aux_function_definition *ObjFD = 277 reinterpret_cast<const object::coff_aux_function_definition *>( 278 AuxData.data()); 279 dumpFunctionDefinition(&Sym, ObjFD); 280 } else if (Symbol.isFunctionLineInfo()) { 281 // This symbol describes function line number information. 282 assert(Symbol.getNumberOfAuxSymbols() == 1 && 283 "Expected a single aux symbol to describe this function!"); 284 285 const object::coff_aux_bf_and_ef_symbol *ObjBES = 286 reinterpret_cast<const object::coff_aux_bf_and_ef_symbol *>( 287 AuxData.data()); 288 dumpbfAndEfLineInfo(&Sym, ObjBES); 289 } else if (Symbol.isAnyUndefined()) { 290 // This symbol represents a weak external definition. 291 assert(Symbol.getNumberOfAuxSymbols() == 1 && 292 "Expected a single aux symbol to describe this weak symbol!"); 293 294 const object::coff_aux_weak_external *ObjWE = 295 reinterpret_cast<const object::coff_aux_weak_external *>( 296 AuxData.data()); 297 dumpWeakExternal(&Sym, ObjWE); 298 } else if (Symbol.isFileRecord()) { 299 // This symbol represents a file record. 300 Sym.File = StringRef(reinterpret_cast<const char *>(AuxData.data()), 301 Symbol.getNumberOfAuxSymbols() * 302 Obj.getSymbolTableEntrySize()) 303 .rtrim(StringRef("\0", /*length=*/1)); 304 } else if (Symbol.isSectionDefinition()) { 305 // This symbol represents a section definition. 306 assert(Symbol.getNumberOfAuxSymbols() == 1 && 307 "Expected a single aux symbol to describe this section!"); 308 309 const object::coff_aux_section_definition *ObjSD = 310 reinterpret_cast<const object::coff_aux_section_definition *>( 311 AuxData.data()); 312 dumpSectionDefinition(&Sym, ObjSD, Symbol.isBigObj()); 313 } else if (Symbol.isCLRToken()) { 314 // This symbol represents a CLR token definition. 315 assert(Symbol.getNumberOfAuxSymbols() == 1 && 316 "Expected a single aux symbol to describe this CLR Token!"); 317 318 const object::coff_aux_clr_token *ObjCLRToken = 319 reinterpret_cast<const object::coff_aux_clr_token *>( 320 AuxData.data()); 321 dumpCLRTokenDefinition(&Sym, ObjCLRToken); 322 } else { 323 llvm_unreachable("Unhandled auxiliary symbol!"); 324 } 325 } 326 Symbols.push_back(Sym); 327 } 328 } 329 330 COFFYAML::Object &COFFDumper::getYAMLObj() { 331 return YAMLObj; 332 } 333 334 std::error_code coff2yaml(raw_ostream &Out, const object::COFFObjectFile &Obj) { 335 COFFDumper Dumper(Obj); 336 337 yaml::Output Yout(Out); 338 Yout << Dumper.getYAMLObj(); 339 340 return std::error_code(); 341 } 342