YAMLOutputStyle.cpp 11 KB

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