1 //===- YAMLOutputStyle.cpp ------------------------------------ *- 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 "YAMLOutputStyle.h" 11 12 #include "PdbYaml.h" 13 #include "llvm-pdbutil.h" 14 15 #include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" 16 #include "llvm/DebugInfo/CodeView/DebugSubsection.h" 17 #include "llvm/DebugInfo/CodeView/DebugUnknownSubsection.h" 18 #include "llvm/DebugInfo/CodeView/StringsAndChecksums.h" 19 #include "llvm/DebugInfo/MSF/MappedBlockStream.h" 20 #include "llvm/DebugInfo/PDB/Native/DbiStream.h" 21 #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" 22 #include "llvm/DebugInfo/PDB/Native/InfoStream.h" 23 #include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h" 24 #include "llvm/DebugInfo/PDB/Native/PDBFile.h" 25 #include "llvm/DebugInfo/PDB/Native/PublicsStream.h" 26 #include "llvm/DebugInfo/PDB/Native/RawConstants.h" 27 #include "llvm/DebugInfo/PDB/Native/SymbolStream.h" 28 #include "llvm/DebugInfo/PDB/Native/TpiStream.h" 29 30 using namespace llvm; 31 using namespace llvm::codeview; 32 using namespace llvm::pdb; 33 34 static bool checkModuleSubsection(opts::ModuleSubsection MS) { 35 return any_of(opts::pdb2yaml::DumpModuleSubsections, 36 [=](opts::ModuleSubsection M) { 37 return M == MS || M == opts::ModuleSubsection::All; 38 }); 39 } 40 41 YAMLOutputStyle::YAMLOutputStyle(PDBFile &File) 42 : File(File), Out(outs()), Obj(File.getAllocator()) { 43 Out.setWriteDefaultValues(!opts::pdb2yaml::Minimal); 44 } 45 46 Error YAMLOutputStyle::dump() { 47 if (opts::pdb2yaml::StreamDirectory) 48 opts::pdb2yaml::StreamMetadata = true; 49 50 if (auto EC = dumpFileHeaders()) 51 return EC; 52 53 if (auto EC = dumpStreamMetadata()) 54 return EC; 55 56 if (auto EC = dumpStreamDirectory()) 57 return EC; 58 59 if (auto EC = dumpStringTable()) 60 return EC; 61 62 if (auto EC = dumpPDBStream()) 63 return EC; 64 65 if (auto EC = dumpDbiStream()) 66 return EC; 67 68 if (auto EC = dumpTpiStream()) 69 return EC; 70 71 if (auto EC = dumpIpiStream()) 72 return EC; 73 74 if (auto EC = dumpPublics()) 75 return EC; 76 77 flush(); 78 return Error::success(); 79 } 80 81 82 Error YAMLOutputStyle::dumpFileHeaders() { 83 if (opts::pdb2yaml::NoFileHeaders) 84 return Error::success(); 85 86 yaml::MSFHeaders Headers; 87 Obj.Headers.emplace(); 88 Obj.Headers->SuperBlock.NumBlocks = File.getBlockCount(); 89 Obj.Headers->SuperBlock.BlockMapAddr = File.getBlockMapIndex(); 90 Obj.Headers->SuperBlock.BlockSize = File.getBlockSize(); 91 auto Blocks = File.getDirectoryBlockArray(); 92 Obj.Headers->DirectoryBlocks.assign(Blocks.begin(), Blocks.end()); 93 Obj.Headers->NumDirectoryBlocks = File.getNumDirectoryBlocks(); 94 Obj.Headers->SuperBlock.NumDirectoryBytes = File.getNumDirectoryBytes(); 95 Obj.Headers->NumStreams = 96 opts::pdb2yaml::StreamMetadata ? File.getNumStreams() : 0; 97 Obj.Headers->SuperBlock.FreeBlockMapBlock = File.getFreeBlockMapBlock(); 98 Obj.Headers->SuperBlock.Unknown1 = File.getUnknown1(); 99 Obj.Headers->FileSize = File.getFileSize(); 100 101 return Error::success(); 102 } 103 104 Error YAMLOutputStyle::dumpStringTable() { 105 bool RequiresStringTable = opts::pdb2yaml::DumpModuleFiles || 106 !opts::pdb2yaml::DumpModuleSubsections.empty(); 107 bool RequestedStringTable = opts::pdb2yaml::StringTable; 108 if (!RequiresStringTable && !RequestedStringTable) 109 return Error::success(); 110 111 auto ExpectedST = File.getStringTable(); 112 if (!ExpectedST) 113 return ExpectedST.takeError(); 114 115 Obj.StringTable.emplace(); 116 const auto &ST = ExpectedST.get(); 117 for (auto ID : ST.name_ids()) { 118 auto S = ST.getStringForID(ID); 119 if (!S) 120 return S.takeError(); 121 if (S->empty()) 122 continue; 123 Obj.StringTable->push_back(*S); 124 } 125 return Error::success(); 126 } 127 128 Error YAMLOutputStyle::dumpStreamMetadata() { 129 if (!opts::pdb2yaml::StreamMetadata) 130 return Error::success(); 131 132 Obj.StreamSizes.emplace(); 133 Obj.StreamSizes->assign(File.getStreamSizes().begin(), 134 File.getStreamSizes().end()); 135 return Error::success(); 136 } 137 138 Error YAMLOutputStyle::dumpStreamDirectory() { 139 if (!opts::pdb2yaml::StreamDirectory) 140 return Error::success(); 141 142 auto StreamMap = File.getStreamMap(); 143 Obj.StreamMap.emplace(); 144 for (auto &Stream : StreamMap) { 145 pdb::yaml::StreamBlockList BlockList; 146 BlockList.Blocks.assign(Stream.begin(), Stream.end()); 147 Obj.StreamMap->push_back(BlockList); 148 } 149 150 return Error::success(); 151 } 152 153 Error YAMLOutputStyle::dumpPDBStream() { 154 if (!opts::pdb2yaml::PdbStream) 155 return Error::success(); 156 157 auto IS = File.getPDBInfoStream(); 158 if (!IS) 159 return IS.takeError(); 160 161 auto &InfoS = IS.get(); 162 Obj.PdbStream.emplace(); 163 Obj.PdbStream->Age = InfoS.getAge(); 164 Obj.PdbStream->Guid = InfoS.getGuid(); 165 Obj.PdbStream->Signature = InfoS.getSignature(); 166 Obj.PdbStream->Version = InfoS.getVersion(); 167 Obj.PdbStream->Features = InfoS.getFeatureSignatures(); 168 169 return Error::success(); 170 } 171 172 static opts::ModuleSubsection convertSubsectionKind(DebugSubsectionKind K) { 173 switch (K) { 174 case DebugSubsectionKind::CrossScopeExports: 175 return opts::ModuleSubsection::CrossScopeExports; 176 case DebugSubsectionKind::CrossScopeImports: 177 return opts::ModuleSubsection::CrossScopeImports; 178 case DebugSubsectionKind::FileChecksums: 179 return opts::ModuleSubsection::FileChecksums; 180 case DebugSubsectionKind::InlineeLines: 181 return opts::ModuleSubsection::InlineeLines; 182 case DebugSubsectionKind::Lines: 183 return opts::ModuleSubsection::Lines; 184 case DebugSubsectionKind::Symbols: 185 return opts::ModuleSubsection::Symbols; 186 case DebugSubsectionKind::StringTable: 187 return opts::ModuleSubsection::StringTable; 188 case DebugSubsectionKind::FrameData: 189 return opts::ModuleSubsection::FrameData; 190 default: 191 return opts::ModuleSubsection::Unknown; 192 } 193 llvm_unreachable("Unreachable!"); 194 } 195 196 Error YAMLOutputStyle::dumpDbiStream() { 197 if (!opts::pdb2yaml::DbiStream) 198 return Error::success(); 199 200 if (!File.hasPDBDbiStream()) 201 return Error::success(); 202 203 auto DbiS = File.getPDBDbiStream(); 204 if (!DbiS) 205 return DbiS.takeError(); 206 207 auto &DS = DbiS.get(); 208 Obj.DbiStream.emplace(); 209 Obj.DbiStream->Age = DS.getAge(); 210 Obj.DbiStream->BuildNumber = DS.getBuildNumber(); 211 Obj.DbiStream->Flags = DS.getFlags(); 212 Obj.DbiStream->MachineType = DS.getMachineType(); 213 Obj.DbiStream->PdbDllRbld = DS.getPdbDllRbld(); 214 Obj.DbiStream->PdbDllVersion = DS.getPdbDllVersion(); 215 Obj.DbiStream->VerHeader = DS.getDbiVersion(); 216 if (opts::pdb2yaml::DumpModules) { 217 const auto &Modules = DS.modules(); 218 for (uint32_t I = 0; I < Modules.getModuleCount(); ++I) { 219 DbiModuleDescriptor MI = Modules.getModuleDescriptor(I); 220 221 Obj.DbiStream->ModInfos.emplace_back(); 222 yaml::PdbDbiModuleInfo &DMI = Obj.DbiStream->ModInfos.back(); 223 224 DMI.Mod = MI.getModuleName(); 225 DMI.Obj = MI.getObjFileName(); 226 if (opts::pdb2yaml::DumpModuleFiles) { 227 auto Files = Modules.source_files(I); 228 DMI.SourceFiles.assign(Files.begin(), Files.end()); 229 } 230 231 uint16_t ModiStream = MI.getModuleStreamIndex(); 232 if (ModiStream == kInvalidStreamIndex) 233 continue; 234 235 auto ModStreamData = msf::MappedBlockStream::createIndexedStream( 236 File.getMsfLayout(), File.getMsfBuffer(), ModiStream, 237 File.getAllocator()); 238 239 pdb::ModuleDebugStreamRef ModS(MI, std::move(ModStreamData)); 240 if (auto EC = ModS.reload()) 241 return EC; 242 243 auto ExpectedST = File.getStringTable(); 244 if (!ExpectedST) 245 return ExpectedST.takeError(); 246 if (!opts::pdb2yaml::DumpModuleSubsections.empty() && 247 ModS.hasDebugSubsections()) { 248 auto ExpectedChecksums = ModS.findChecksumsSubsection(); 249 if (!ExpectedChecksums) 250 return ExpectedChecksums.takeError(); 251 252 StringsAndChecksumsRef SC(ExpectedST->getStringTable(), 253 *ExpectedChecksums); 254 255 for (const auto &SS : ModS.subsections()) { 256 opts::ModuleSubsection OptionKind = convertSubsectionKind(SS.kind()); 257 if (!checkModuleSubsection(OptionKind)) 258 continue; 259 260 auto Converted = 261 CodeViewYAML::YAMLDebugSubsection::fromCodeViewSubection(SC, SS); 262 if (!Converted) 263 return Converted.takeError(); 264 DMI.Subsections.push_back(*Converted); 265 } 266 } 267 268 if (opts::pdb2yaml::DumpModuleSyms) { 269 DMI.Modi.emplace(); 270 271 DMI.Modi->Signature = ModS.signature(); 272 bool HadError = false; 273 for (auto &Sym : ModS.symbols(&HadError)) { 274 auto ES = CodeViewYAML::SymbolRecord::fromCodeViewSymbol(Sym); 275 if (!ES) 276 return ES.takeError(); 277 278 DMI.Modi->Symbols.push_back(*ES); 279 } 280 } 281 } 282 } 283 return Error::success(); 284 } 285 286 Error YAMLOutputStyle::dumpTpiStream() { 287 if (!opts::pdb2yaml::TpiStream) 288 return Error::success(); 289 290 auto TpiS = File.getPDBTpiStream(); 291 if (!TpiS) 292 return TpiS.takeError(); 293 294 auto &TS = TpiS.get(); 295 Obj.TpiStream.emplace(); 296 Obj.TpiStream->Version = TS.getTpiVersion(); 297 for (auto &Record : TS.types(nullptr)) { 298 auto ExpectedRecord = CodeViewYAML::LeafRecord::fromCodeViewRecord(Record); 299 if (!ExpectedRecord) 300 return ExpectedRecord.takeError(); 301 Obj.TpiStream->Records.push_back(*ExpectedRecord); 302 } 303 304 return Error::success(); 305 } 306 307 Error YAMLOutputStyle::dumpIpiStream() { 308 if (!opts::pdb2yaml::IpiStream) 309 return Error::success(); 310 311 auto InfoS = File.getPDBInfoStream(); 312 if (!InfoS) 313 return InfoS.takeError(); 314 if (!InfoS->containsIdStream()) 315 return Error::success(); 316 317 auto IpiS = File.getPDBIpiStream(); 318 if (!IpiS) 319 return IpiS.takeError(); 320 321 auto &IS = IpiS.get(); 322 Obj.IpiStream.emplace(); 323 Obj.IpiStream->Version = IS.getTpiVersion(); 324 for (auto &Record : IS.types(nullptr)) { 325 auto ExpectedRecord = CodeViewYAML::LeafRecord::fromCodeViewRecord(Record); 326 if (!ExpectedRecord) 327 return ExpectedRecord.takeError(); 328 329 Obj.IpiStream->Records.push_back(*ExpectedRecord); 330 } 331 332 return Error::success(); 333 } 334 335 Error YAMLOutputStyle::dumpPublics() { 336 if (!opts::pdb2yaml::PublicsStream) 337 return Error::success(); 338 339 Obj.PublicsStream.emplace(); 340 auto ExpectedPublics = File.getPDBPublicsStream(); 341 if (!ExpectedPublics) { 342 llvm::consumeError(ExpectedPublics.takeError()); 343 return Error::success(); 344 } 345 346 PublicsStream &Publics = *ExpectedPublics; 347 const GSIHashTable &PublicsTable = Publics.getPublicsTable(); 348 349 auto ExpectedSyms = File.getPDBSymbolStream(); 350 if (!ExpectedSyms) { 351 llvm::consumeError(ExpectedSyms.takeError()); 352 return Error::success(); 353 } 354 355 BinaryStreamRef SymStream = 356 ExpectedSyms->getSymbolArray().getUnderlyingStream(); 357 for (uint32_t PubSymOff : PublicsTable) { 358 Expected<CVSymbol> Sym = readSymbolFromStream(SymStream, PubSymOff); 359 if (!Sym) 360 return Sym.takeError(); 361 auto ES = CodeViewYAML::SymbolRecord::fromCodeViewSymbol(*Sym); 362 if (!ES) 363 return ES.takeError(); 364 365 Obj.PublicsStream->PubSyms.push_back(*ES); 366 } 367 368 return Error::success(); 369 } 370 371 void YAMLOutputStyle::flush() { 372 Out << Obj; 373 outs().flush(); 374 } 375