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/ADT/StringMap.h" 12 #include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" 13 #include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h" 14 #include "llvm/DebugInfo/CodeView/StringsAndChecksums.h" 15 #include "llvm/Object/COFF.h" 16 #include "llvm/ObjectYAML/COFFYAML.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 StringMap<bool> SymbolUnique; 147 for (const auto &S : Obj.symbols()) { 148 object::COFFSymbolRef Symbol = Obj.getCOFFSymbol(S); 149 StringRef Name; 150 Obj.getSymbolName(Symbol, Name); 151 StringMap<bool>::iterator It; 152 bool Inserted; 153 std::tie(It, Inserted) = SymbolUnique.insert(std::make_pair(Name, true)); 154 if (!Inserted) 155 It->second = false; 156 } 157 158 for (const auto &ObjSection : Obj.sections()) { 159 const object::coff_section *COFFSection = Obj.getCOFFSection(ObjSection); 160 COFFYAML::Section NewYAMLSection; 161 ObjSection.getName(NewYAMLSection.Name); 162 NewYAMLSection.Header.Characteristics = COFFSection->Characteristics; 163 NewYAMLSection.Header.VirtualAddress = COFFSection->VirtualAddress; 164 NewYAMLSection.Header.VirtualSize = COFFSection->VirtualSize; 165 NewYAMLSection.Header.NumberOfLineNumbers = 166 COFFSection->NumberOfLinenumbers; 167 NewYAMLSection.Header.NumberOfRelocations = 168 COFFSection->NumberOfRelocations; 169 NewYAMLSection.Header.PointerToLineNumbers = 170 COFFSection->PointerToLinenumbers; 171 NewYAMLSection.Header.PointerToRawData = COFFSection->PointerToRawData; 172 NewYAMLSection.Header.PointerToRelocations = 173 COFFSection->PointerToRelocations; 174 NewYAMLSection.Header.SizeOfRawData = COFFSection->SizeOfRawData; 175 uint32_t Shift = (COFFSection->Characteristics >> 20) & 0xF; 176 NewYAMLSection.Alignment = (1U << Shift) >> 1; 177 assert(NewYAMLSection.Alignment <= 8192); 178 179 ArrayRef<uint8_t> sectionData; 180 if (!ObjSection.isBSS()) 181 Obj.getSectionContents(COFFSection, sectionData); 182 NewYAMLSection.SectionData = yaml::BinaryRef(sectionData); 183 184 if (NewYAMLSection.Name == ".debug$S") 185 NewYAMLSection.DebugS = CodeViewYAML::fromDebugS(sectionData, SC); 186 else if (NewYAMLSection.Name == ".debug$T") 187 NewYAMLSection.DebugT = CodeViewYAML::fromDebugT(sectionData, 188 NewYAMLSection.Name); 189 else if (NewYAMLSection.Name == ".debug$P") 190 NewYAMLSection.DebugP = CodeViewYAML::fromDebugT(sectionData, 191 NewYAMLSection.Name); 192 else if (NewYAMLSection.Name == ".debug$H") 193 NewYAMLSection.DebugH = CodeViewYAML::fromDebugH(sectionData); 194 195 std::vector<COFFYAML::Relocation> Relocations; 196 for (const auto &Reloc : ObjSection.relocations()) { 197 const object::coff_relocation *reloc = Obj.getCOFFRelocation(Reloc); 198 COFFYAML::Relocation Rel; 199 object::symbol_iterator Sym = Reloc.getSymbol(); 200 Expected<StringRef> SymbolNameOrErr = Sym->getName(); 201 if (!SymbolNameOrErr) { 202 std::string Buf; 203 raw_string_ostream OS(Buf); 204 logAllUnhandledErrors(SymbolNameOrErr.takeError(), OS); 205 OS.flush(); 206 report_fatal_error(Buf); 207 } 208 if (SymbolUnique.lookup(*SymbolNameOrErr)) 209 Rel.SymbolName = *SymbolNameOrErr; 210 else 211 Rel.SymbolTableIndex = reloc->SymbolTableIndex; 212 Rel.VirtualAddress = reloc->VirtualAddress; 213 Rel.Type = reloc->Type; 214 Relocations.push_back(Rel); 215 } 216 NewYAMLSection.Relocations = Relocations; 217 YAMLSections.push_back(NewYAMLSection); 218 } 219 } 220 221 static void 222 dumpFunctionDefinition(COFFYAML::Symbol *Sym, 223 const object::coff_aux_function_definition *ObjFD) { 224 COFF::AuxiliaryFunctionDefinition YAMLFD; 225 YAMLFD.TagIndex = ObjFD->TagIndex; 226 YAMLFD.TotalSize = ObjFD->TotalSize; 227 YAMLFD.PointerToLinenumber = ObjFD->PointerToLinenumber; 228 YAMLFD.PointerToNextFunction = ObjFD->PointerToNextFunction; 229 230 Sym->FunctionDefinition = YAMLFD; 231 } 232 233 static void 234 dumpbfAndEfLineInfo(COFFYAML::Symbol *Sym, 235 const object::coff_aux_bf_and_ef_symbol *ObjBES) { 236 COFF::AuxiliarybfAndefSymbol YAMLAAS; 237 YAMLAAS.Linenumber = ObjBES->Linenumber; 238 YAMLAAS.PointerToNextFunction = ObjBES->PointerToNextFunction; 239 240 Sym->bfAndefSymbol = YAMLAAS; 241 } 242 243 static void dumpWeakExternal(COFFYAML::Symbol *Sym, 244 const object::coff_aux_weak_external *ObjWE) { 245 COFF::AuxiliaryWeakExternal YAMLWE; 246 YAMLWE.TagIndex = ObjWE->TagIndex; 247 YAMLWE.Characteristics = ObjWE->Characteristics; 248 249 Sym->WeakExternal = YAMLWE; 250 } 251 252 static void 253 dumpSectionDefinition(COFFYAML::Symbol *Sym, 254 const object::coff_aux_section_definition *ObjSD, 255 bool IsBigObj) { 256 COFF::AuxiliarySectionDefinition YAMLASD; 257 int32_t AuxNumber = ObjSD->getNumber(IsBigObj); 258 YAMLASD.Length = ObjSD->Length; 259 YAMLASD.NumberOfRelocations = ObjSD->NumberOfRelocations; 260 YAMLASD.NumberOfLinenumbers = ObjSD->NumberOfLinenumbers; 261 YAMLASD.CheckSum = ObjSD->CheckSum; 262 YAMLASD.Number = AuxNumber; 263 YAMLASD.Selection = ObjSD->Selection; 264 265 Sym->SectionDefinition = YAMLASD; 266 } 267 268 static void 269 dumpCLRTokenDefinition(COFFYAML::Symbol *Sym, 270 const object::coff_aux_clr_token *ObjCLRToken) { 271 COFF::AuxiliaryCLRToken YAMLCLRToken; 272 YAMLCLRToken.AuxType = ObjCLRToken->AuxType; 273 YAMLCLRToken.SymbolTableIndex = ObjCLRToken->SymbolTableIndex; 274 275 Sym->CLRToken = YAMLCLRToken; 276 } 277 278 void COFFDumper::dumpSymbols(unsigned NumSymbols) { 279 std::vector<COFFYAML::Symbol> &Symbols = YAMLObj.Symbols; 280 for (const auto &S : Obj.symbols()) { 281 object::COFFSymbolRef Symbol = Obj.getCOFFSymbol(S); 282 COFFYAML::Symbol Sym; 283 Obj.getSymbolName(Symbol, Sym.Name); 284 Sym.SimpleType = COFF::SymbolBaseType(Symbol.getBaseType()); 285 Sym.ComplexType = COFF::SymbolComplexType(Symbol.getComplexType()); 286 Sym.Header.StorageClass = Symbol.getStorageClass(); 287 Sym.Header.Value = Symbol.getValue(); 288 Sym.Header.SectionNumber = Symbol.getSectionNumber(); 289 Sym.Header.NumberOfAuxSymbols = Symbol.getNumberOfAuxSymbols(); 290 291 if (Symbol.getNumberOfAuxSymbols() > 0) { 292 ArrayRef<uint8_t> AuxData = Obj.getSymbolAuxData(Symbol); 293 if (Symbol.isFunctionDefinition()) { 294 // This symbol represents a function definition. 295 assert(Symbol.getNumberOfAuxSymbols() == 1 && 296 "Expected a single aux symbol to describe this function!"); 297 298 const object::coff_aux_function_definition *ObjFD = 299 reinterpret_cast<const object::coff_aux_function_definition *>( 300 AuxData.data()); 301 dumpFunctionDefinition(&Sym, ObjFD); 302 } else if (Symbol.isFunctionLineInfo()) { 303 // This symbol describes function line number information. 304 assert(Symbol.getNumberOfAuxSymbols() == 1 && 305 "Expected a single aux symbol to describe this function!"); 306 307 const object::coff_aux_bf_and_ef_symbol *ObjBES = 308 reinterpret_cast<const object::coff_aux_bf_and_ef_symbol *>( 309 AuxData.data()); 310 dumpbfAndEfLineInfo(&Sym, ObjBES); 311 } else if (Symbol.isAnyUndefined()) { 312 // This symbol represents a weak external definition. 313 assert(Symbol.getNumberOfAuxSymbols() == 1 && 314 "Expected a single aux symbol to describe this weak symbol!"); 315 316 const object::coff_aux_weak_external *ObjWE = 317 reinterpret_cast<const object::coff_aux_weak_external *>( 318 AuxData.data()); 319 dumpWeakExternal(&Sym, ObjWE); 320 } else if (Symbol.isFileRecord()) { 321 // This symbol represents a file record. 322 Sym.File = StringRef(reinterpret_cast<const char *>(AuxData.data()), 323 Symbol.getNumberOfAuxSymbols() * 324 Obj.getSymbolTableEntrySize()) 325 .rtrim(StringRef("\0", /*length=*/1)); 326 } else if (Symbol.isSectionDefinition()) { 327 // This symbol represents a section definition. 328 assert(Symbol.getNumberOfAuxSymbols() == 1 && 329 "Expected a single aux symbol to describe this section!"); 330 331 const object::coff_aux_section_definition *ObjSD = 332 reinterpret_cast<const object::coff_aux_section_definition *>( 333 AuxData.data()); 334 dumpSectionDefinition(&Sym, ObjSD, Symbol.isBigObj()); 335 } else if (Symbol.isCLRToken()) { 336 // This symbol represents a CLR token definition. 337 assert(Symbol.getNumberOfAuxSymbols() == 1 && 338 "Expected a single aux symbol to describe this CLR Token!"); 339 340 const object::coff_aux_clr_token *ObjCLRToken = 341 reinterpret_cast<const object::coff_aux_clr_token *>( 342 AuxData.data()); 343 dumpCLRTokenDefinition(&Sym, ObjCLRToken); 344 } else { 345 llvm_unreachable("Unhandled auxiliary symbol!"); 346 } 347 } 348 Symbols.push_back(Sym); 349 } 350 } 351 352 COFFYAML::Object &COFFDumper::getYAMLObj() { 353 return YAMLObj; 354 } 355 356 std::error_code coff2yaml(raw_ostream &Out, const object::COFFObjectFile &Obj) { 357 COFFDumper Dumper(Obj); 358 359 yaml::Output Yout(Out); 360 Yout << Dumper.getYAMLObj(); 361 362 return std::error_code(); 363 } 364