diff options
Diffstat (limited to 'tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp')
| -rw-r--r-- | tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp | 210 |
1 files changed, 174 insertions, 36 deletions
diff --git a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp index fe68689def60a..319e34d882dcc 100644 --- a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp +++ b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp @@ -27,8 +27,8 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/StringExtras.h" #include "llvm/Bitcode/BitstreamReader.h" -#include "llvm/ADT/Optional.h" #include "llvm/Bitcode/LLVMBitCodes.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/IR/Verifier.h" @@ -37,6 +37,7 @@ #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/SHA1.h" #include "llvm/Support/Signals.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> @@ -103,23 +104,24 @@ static const char *GetBlockName(unsigned BlockID, if (CurStreamType != LLVMIRBitstream) return nullptr; switch (BlockID) { - default: return nullptr; - case bitc::MODULE_BLOCK_ID: return "MODULE_BLOCK"; - case bitc::PARAMATTR_BLOCK_ID: return "PARAMATTR_BLOCK"; - case bitc::PARAMATTR_GROUP_BLOCK_ID: return "PARAMATTR_GROUP_BLOCK_ID"; - case bitc::TYPE_BLOCK_ID_NEW: return "TYPE_BLOCK_ID"; - case bitc::CONSTANTS_BLOCK_ID: return "CONSTANTS_BLOCK"; - case bitc::FUNCTION_BLOCK_ID: return "FUNCTION_BLOCK"; + default: return nullptr; + case bitc::OPERAND_BUNDLE_TAGS_BLOCK_ID: return "OPERAND_BUNDLE_TAGS_BLOCK"; + case bitc::MODULE_BLOCK_ID: return "MODULE_BLOCK"; + case bitc::PARAMATTR_BLOCK_ID: return "PARAMATTR_BLOCK"; + case bitc::PARAMATTR_GROUP_BLOCK_ID: return "PARAMATTR_GROUP_BLOCK_ID"; + case bitc::TYPE_BLOCK_ID_NEW: return "TYPE_BLOCK_ID"; + case bitc::CONSTANTS_BLOCK_ID: return "CONSTANTS_BLOCK"; + case bitc::FUNCTION_BLOCK_ID: return "FUNCTION_BLOCK"; case bitc::IDENTIFICATION_BLOCK_ID: - return "IDENTIFICATION_BLOCK_ID"; - case bitc::VALUE_SYMTAB_BLOCK_ID: return "VALUE_SYMTAB"; - case bitc::METADATA_BLOCK_ID: return "METADATA_BLOCK"; - case bitc::METADATA_KIND_BLOCK_ID: return "METADATA_KIND_BLOCK"; - case bitc::METADATA_ATTACHMENT_ID: return "METADATA_ATTACHMENT_BLOCK"; - case bitc::USELIST_BLOCK_ID: return "USELIST_BLOCK_ID"; - case bitc::FUNCTION_SUMMARY_BLOCK_ID: - return "FUNCTION_SUMMARY_BLOCK"; - case bitc::MODULE_STRTAB_BLOCK_ID: return "MODULE_STRTAB_BLOCK"; + return "IDENTIFICATION_BLOCK_ID"; + case bitc::VALUE_SYMTAB_BLOCK_ID: return "VALUE_SYMTAB"; + case bitc::METADATA_BLOCK_ID: return "METADATA_BLOCK"; + case bitc::METADATA_KIND_BLOCK_ID: return "METADATA_KIND_BLOCK"; + case bitc::METADATA_ATTACHMENT_ID: return "METADATA_ATTACHMENT_BLOCK"; + case bitc::USELIST_BLOCK_ID: return "USELIST_BLOCK_ID"; + case bitc::GLOBALVAL_SUMMARY_BLOCK_ID: + return "GLOBALVAL_SUMMARY_BLOCK"; + case bitc::MODULE_STRTAB_BLOCK_ID: return "MODULE_STRTAB_BLOCK"; } } @@ -172,7 +174,9 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID, STRINGIFY_CODE(MODULE_CODE, PURGEVALS) STRINGIFY_CODE(MODULE_CODE, GCNAME) STRINGIFY_CODE(MODULE_CODE, VSTOFFSET) - STRINGIFY_CODE(MODULE_CODE, METADATA_VALUES) + STRINGIFY_CODE(MODULE_CODE, METADATA_VALUES_UNUSED) + STRINGIFY_CODE(MODULE_CODE, SOURCE_FILENAME) + STRINGIFY_CODE(MODULE_CODE, HASH) } case bitc::IDENTIFICATION_BLOCK_ID: switch (CodeID) { @@ -187,6 +191,10 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID, // FIXME: Should these be different? case bitc::PARAMATTR_CODE_ENTRY_OLD: return "ENTRY"; case bitc::PARAMATTR_CODE_ENTRY: return "ENTRY"; + } + case bitc::PARAMATTR_GROUP_BLOCK_ID: + switch (CodeID) { + default: return nullptr; case bitc::PARAMATTR_GRP_CODE_ENTRY: return "ENTRY"; } case bitc::TYPE_BLOCK_ID_NEW: @@ -272,6 +280,7 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID, STRINGIFY_CODE(FUNC_CODE, INST_CALL) STRINGIFY_CODE(FUNC_CODE, DEBUG_LOC) STRINGIFY_CODE(FUNC_CODE, INST_GEP) + STRINGIFY_CODE(FUNC_CODE, OPERAND_BUNDLE) } case bitc::VALUE_SYMTAB_BLOCK_ID: switch (CodeID) { @@ -279,20 +288,29 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID, STRINGIFY_CODE(VST_CODE, ENTRY) STRINGIFY_CODE(VST_CODE, BBENTRY) STRINGIFY_CODE(VST_CODE, FNENTRY) - STRINGIFY_CODE(VST_CODE, COMBINED_FNENTRY) + STRINGIFY_CODE(VST_CODE, COMBINED_ENTRY) } case bitc::MODULE_STRTAB_BLOCK_ID: switch (CodeID) { default: return nullptr; STRINGIFY_CODE(MST_CODE, ENTRY) + STRINGIFY_CODE(MST_CODE, HASH) } - case bitc::FUNCTION_SUMMARY_BLOCK_ID: + case bitc::GLOBALVAL_SUMMARY_BLOCK_ID: switch (CodeID) { default: return nullptr; - STRINGIFY_CODE(FS_CODE, PERMODULE_ENTRY) - STRINGIFY_CODE(FS_CODE, COMBINED_ENTRY) + STRINGIFY_CODE(FS, PERMODULE) + STRINGIFY_CODE(FS, PERMODULE_PROFILE) + STRINGIFY_CODE(FS, PERMODULE_GLOBALVAR_INIT_REFS) + STRINGIFY_CODE(FS, COMBINED) + STRINGIFY_CODE(FS, COMBINED_PROFILE) + STRINGIFY_CODE(FS, COMBINED_GLOBALVAR_INIT_REFS) + STRINGIFY_CODE(FS, ALIAS) + STRINGIFY_CODE(FS, COMBINED_ALIAS) + STRINGIFY_CODE(FS, COMBINED_ORIGINAL_NAME) + STRINGIFY_CODE(FS, VERSION) } case bitc::METADATA_ATTACHMENT_ID: switch(CodeID) { @@ -302,7 +320,8 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID, case bitc::METADATA_BLOCK_ID: switch(CodeID) { default:return nullptr; - STRINGIFY_CODE(METADATA, STRING) + STRINGIFY_CODE(METADATA, STRING_OLD) + STRINGIFY_CODE(METADATA, STRINGS) STRINGIFY_CODE(METADATA, NAME) STRINGIFY_CODE(METADATA, KIND) // Older bitcode has it in a MODULE_BLOCK STRINGIFY_CODE(METADATA, NODE) @@ -346,6 +365,12 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID, case bitc::USELIST_CODE_DEFAULT: return "USELIST_CODE_DEFAULT"; case bitc::USELIST_CODE_BB: return "USELIST_CODE_BB"; } + + case bitc::OPERAND_BUNDLE_TAGS_BLOCK_ID: + switch(CodeID) { + default: return nullptr; + case bitc::OPERAND_BUNDLE_TAG: return "OPERAND_BUNDLE_TAG"; + } } #undef STRINGIFY_CODE } @@ -394,6 +419,57 @@ static bool Error(const Twine &Err) { return true; } +static bool decodeMetadataStringsBlob(BitstreamReader &Reader, StringRef Indent, + ArrayRef<uint64_t> Record, + StringRef Blob) { + if (Blob.empty()) + return true; + + if (Record.size() != 2) + return true; + + unsigned NumStrings = Record[0]; + unsigned StringsOffset = Record[1]; + outs() << " num-strings = " << NumStrings << " {\n"; + + StringRef Lengths = Blob.slice(0, StringsOffset); + SimpleBitstreamCursor R(Reader); + R.jumpToPointer(Lengths.begin()); + + // Ensure that Blob doesn't get invalidated, even if this is reading from a + // StreamingMemoryObject with corrupt data. + R.setArtificialByteLimit(R.getCurrentByteNo() + StringsOffset); + + StringRef Strings = Blob.drop_front(StringsOffset); + do { + if (R.AtEndOfStream()) + return Error("bad length"); + + unsigned Size = R.ReadVBR(6); + if (Strings.size() < Size) + return Error("truncated chars"); + + outs() << Indent << " '"; + outs().write_escaped(Strings.slice(0, Size), /*hex=*/true); + outs() << "'\n"; + Strings = Strings.drop_front(Size); + } while (--NumStrings); + + outs() << Indent << " }"; + return false; +} + +static bool decodeBlob(unsigned Code, unsigned BlockID, BitstreamReader &Reader, + StringRef Indent, ArrayRef<uint64_t> Record, + StringRef Blob) { + if (BlockID != bitc::METADATA_BLOCK_ID) + return true; + if (Code != bitc::METADATA_STRINGS) + return true; + + return decodeMetadataStringsBlob(Reader, Indent, Record, Blob); +} + /// ParseBlock - Read a block, updating statistics, etc. static bool ParseBlock(BitstreamCursor &Stream, unsigned BlockID, unsigned IndentLevel, CurStreamTypeType CurStreamType) { @@ -406,21 +482,24 @@ static bool ParseBlock(BitstreamCursor &Stream, unsigned BlockID, BlockStats.NumInstances++; // BLOCKINFO is a special part of the stream. + bool DumpRecords = Dump; if (BlockID == bitc::BLOCKINFO_BLOCK_ID) { if (Dump) outs() << Indent << "<BLOCKINFO_BLOCK/>\n"; - if (Stream.ReadBlockInfoBlock()) + if (BitstreamCursor(Stream).ReadBlockInfoBlock()) return Error("Malformed BlockInfoBlock"); - uint64_t BlockBitEnd = Stream.GetCurrentBitNo(); - BlockStats.NumBits += BlockBitEnd-BlockBitStart; - return false; + // It's not really interesting to dump the contents of the blockinfo block. + DumpRecords = false; } unsigned NumWords = 0; if (Stream.EnterSubBlock(BlockID, &NumWords)) return Error("Malformed block record"); + // Keep it for later, when we see a MODULE_HASH record + uint64_t BlockEntryPos = Stream.getCurrentByteNo(); + const char *BlockName = nullptr; - if (Dump) { + if (DumpRecords) { outs() << Indent << "<"; if ((BlockName = GetBlockName(BlockID, *Stream.getBitStreamReader(), CurStreamType))) @@ -453,7 +532,7 @@ static bool ParseBlock(BitstreamCursor &Stream, unsigned BlockID, case BitstreamEntry::EndBlock: { uint64_t BlockBitEnd = Stream.GetCurrentBitNo(); BlockStats.NumBits += BlockBitEnd-BlockBitStart; - if (Dump) { + if (DumpRecords) { outs() << Indent << "</"; if (BlockName) outs() << BlockName << ">\n"; @@ -490,6 +569,7 @@ static bool ParseBlock(BitstreamCursor &Stream, unsigned BlockID, ++BlockStats.NumRecords; StringRef Blob; + unsigned CurrentRecordPos = Stream.getCurrentByteNo(); unsigned Code = Stream.readRecord(Entry.ID, Record, &Blob); // Increment the # occurrences of this code. @@ -503,7 +583,7 @@ static bool ParseBlock(BitstreamCursor &Stream, unsigned BlockID, ++BlockStats.NumAbbreviatedRecords; } - if (Dump) { + if (DumpRecords) { outs() << Indent << " <"; if (const char *CodeName = GetCodeName(Code, BlockID, *Stream.getBitStreamReader(), @@ -524,6 +604,37 @@ static bool ParseBlock(BitstreamCursor &Stream, unsigned BlockID, for (unsigned i = 0, e = Record.size(); i != e; ++i) outs() << " op" << i << "=" << (int64_t)Record[i]; + // If we found a module hash, let's verify that it matches! + if (BlockID == bitc::MODULE_BLOCK_ID && Code == bitc::MODULE_CODE_HASH) { + if (Record.size() != 5) + outs() << " (invalid)"; + else { + // Recompute the hash and compare it to the one in the bitcode + SHA1 Hasher; + StringRef Hash; + { + int BlockSize = CurrentRecordPos - BlockEntryPos; + auto Ptr = Stream.getPointerToByte(BlockEntryPos, BlockSize); + Hasher.update(ArrayRef<uint8_t>(Ptr, BlockSize)); + Hash = Hasher.result(); + } + SmallString<20> RecordedHash; + RecordedHash.resize(20); + int Pos = 0; + for (auto &Val : Record) { + assert(!(Val >> 32) && "Unexpected high bits set"); + RecordedHash[Pos++] = (Val >> 24) & 0xFF; + RecordedHash[Pos++] = (Val >> 16) & 0xFF; + RecordedHash[Pos++] = (Val >> 8) & 0xFF; + RecordedHash[Pos++] = (Val >> 0) & 0xFF; + } + if (Hash == RecordedHash) + outs() << " (match)"; + else + outs() << " (!mismatch!)"; + } + } + outs() << "/>"; if (Abbv) { @@ -547,7 +658,8 @@ static bool ParseBlock(BitstreamCursor &Stream, unsigned BlockID, } } - if (Blob.data()) { + if (Blob.data() && decodeBlob(Code, BlockID, *Stream.getBitStreamReader(), + Indent, Record, Blob)) { outs() << " blob data = "; if (ShowBinaryBlobs) { outs() << "'"; @@ -600,9 +712,28 @@ static bool openBitcodeFile(StringRef Path, // If we have a wrapper header, parse it and ignore the non-bc file contents. // The magic number is 0x0B17C0DE stored in little endian. - if (isBitcodeWrapper(BufPtr, EndBufPtr)) + if (isBitcodeWrapper(BufPtr, EndBufPtr)) { + if (MemBuf->getBufferSize() < BWH_HeaderSize) + return Error("Invalid bitcode wrapper header"); + + if (Dump) { + unsigned Magic = support::endian::read32le(&BufPtr[BWH_MagicField]); + unsigned Version = support::endian::read32le(&BufPtr[BWH_VersionField]); + unsigned Offset = support::endian::read32le(&BufPtr[BWH_OffsetField]); + unsigned Size = support::endian::read32le(&BufPtr[BWH_SizeField]); + unsigned CPUType = support::endian::read32le(&BufPtr[BWH_CPUTypeField]); + + outs() << "<BITCODE_WRAPPER_HEADER" + << " Magic=" << format_hex(Magic, 10) + << " Version=" << format_hex(Version, 10) + << " Offset=" << format_hex(Offset, 10) + << " Size=" << format_hex(Size, 10) + << " CPUType=" << format_hex(CPUType, 10) << "/>\n"; + } + if (SkipBitcodeWrapperHeader(BufPtr, EndBufPtr, true)) return Error("Invalid bitcode wrapper header"); + } StreamFile = BitstreamReader(BufPtr, EndBufPtr); Stream = BitstreamCursor(StreamFile); @@ -745,7 +876,7 @@ static int AnalyzeBitcode() { std::reverse(FreqPairs.begin(), FreqPairs.end()); outs() << "\tRecord Histogram:\n"; - outs() << "\t\t Count # Bits %% Abv Record Kind\n"; + outs() << "\t\t Count # Bits b/Rec % Abv Record Kind\n"; for (unsigned i = 0, e = FreqPairs.size(); i != e; ++i) { const PerRecordStats &RecStats = Stats.CodeFreq[FreqPairs[i].second]; @@ -753,13 +884,20 @@ static int AnalyzeBitcode() { RecStats.NumInstances, (unsigned long)RecStats.TotalBits); + if (RecStats.NumInstances > 1) + outs() << format(" %9.1f", + (double)RecStats.TotalBits/RecStats.NumInstances); + else + outs() << " "; + if (RecStats.NumAbbrev) outs() << - format("%7.2f ", + format(" %7.2f", (double)RecStats.NumAbbrev/RecStats.NumInstances*100); else - outs() << " "; + outs() << " "; + outs() << " "; if (const char *CodeName = GetCodeName(FreqPairs[i].second, I->first, StreamFile, CurStreamType)) @@ -777,7 +915,7 @@ static int AnalyzeBitcode() { int main(int argc, char **argv) { // Print a stack trace if we signal out. - sys::PrintStackTraceOnErrorSignal(); + sys::PrintStackTraceOnErrorSignal(argv[0]); PrettyStackTraceProgram X(argc, argv); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. cl::ParseCommandLineOptions(argc, argv, "llvm-bcanalyzer file analyzer\n"); |
