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