Index: lib/Bitcode/NaCl/Analysis/NaClObjDump.cpp |
diff --git a/lib/Bitcode/NaCl/Analysis/NaClObjDump.cpp b/lib/Bitcode/NaCl/Analysis/NaClObjDump.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..c313eeb74e1e89589f23c068ce036ff58bebd3e3 |
--- /dev/null |
+++ b/lib/Bitcode/NaCl/Analysis/NaClObjDump.cpp |
@@ -0,0 +1,3578 @@ |
+//===-- NaClObjDump.cpp - Dump PNaCl bitcode contents ---------------------===// |
+// |
+// The LLVM Compiler Infrastructure |
+// |
+// This file is distributed under the University of Illinois Open Source |
+// License. See LICENSE.TXT for details. |
+// |
+//===----------------------------------------------------------------------===// |
+ |
+#include "llvm/ADT/STLExtras.h" |
+#include "llvm/Analysis/NaCl/PNaClABIProps.h" |
+#include "llvm/Analysis/NaCl/PNaClABITypeChecker.h" |
+#include "llvm/Analysis/NaCl/PNaClAllowedIntrinsics.h" |
+#include "llvm/Bitcode/NaCl/NaClBitcodeDecoders.h" |
+#include "llvm/Bitcode/NaCl/NaClBitcodeHeader.h" |
+#include "llvm/Bitcode/NaCl/NaClBitcodeParser.h" |
+#include "llvm/Bitcode/NaCl/NaClBitCodes.h" |
+#include "llvm/Bitcode/NaCl/NaClObjDumpStream.h" |
+#include "llvm/Bitcode/NaCl/NaClReaderWriter.h" |
+#include "llvm/IR/Constants.h" |
+#include "llvm/IR/DataLayout.h" |
+#include "llvm/IR/InstrTypes.h" |
+#include "llvm/IR/LLVMContext.h" |
+#include "llvm/IR/Module.h" |
+#include "llvm/Support/CommandLine.h" |
+#include "llvm/Support/MemoryBuffer.h" |
+#include "llvm/Support/Format.h" |
+#include "llvm/Support/raw_ostream.h" |
+ |
+#include <map> |
+ |
+namespace { |
+ |
+using namespace llvm; |
+ |
+static cl::opt<bool> |
+ReportWarningsAsErrors( |
+ "Werror", |
+ cl::desc("Report warnings as errors."), |
+ cl::init(false)); |
+ |
+static cl::opt<bool> |
+IgnorePNaClABIChecks( |
+ "ignore-pnaclabi-checks", |
+ cl::desc("Ignore checking bitcode for PNaCl ABI violations"), |
+ cl::init(false)); |
+ |
+/// Class to handle sign rotations in a human readable form. That is, |
+/// the sign is in the low bit. The two special cases are: |
+/// 1) -1 is true for i1. |
+/// 2) The representation allows -0 (which is different than 0). |
+class SignRotatedInt { |
+public: |
+ SignRotatedInt(uint64_t Value, Type* ValueType) |
+ : SignedValue(Value >> 1), |
+ IsNegated((Value & 0x1) |
+ && !(ValueType->isIntegerTy() |
+ && ValueType->getIntegerBitWidth() == 1)) { |
+ } |
+ |
+ SignRotatedInt() |
+ : SignedValue(0), IsNegated(false) {} |
+ |
+ explicit SignRotatedInt(const SignRotatedInt &V) |
+ : SignedValue(V.SignedValue), IsNegated(V.IsNegated) {} |
+ |
+ void operator=(const SignRotatedInt &V) { |
+ SignedValue = V.SignedValue; |
+ IsNegated = V.IsNegated; |
+ } |
+ |
+ void Print(raw_ostream &Strm) const { |
+ if (IsNegated) Strm << "-"; |
+ Strm << SignedValue; |
+ } |
+ |
+private: |
+ int64_t SignedValue; |
+ bool IsNegated; |
+}; |
+ |
+inline raw_ostream &operator<<(raw_ostream &Strm, const SignRotatedInt &V) { |
+ V.Print(Strm); |
+ return Strm; |
+} |
+ |
+/// Convenience class to be able to print value ids to raw_ostream's. |
+/// Kinds of bitcode Ids: |
+/// a : For abbreviations. |
+/// b : For basic blocks. |
+/// c : For local constants. |
+/// f : For function addresses. |
+/// g : For global variable addresses. |
+/// p : For parameter arguments. |
+/// t : For type values. |
+/// v : For values generated by instructions. |
+class BitcodeId { |
+public: |
+ BitcodeId(char Kind, uint32_t Index) |
+ : Kind(Kind), Index(Index), IsGlobal(IsGlobalKind(Kind)) { |
+ } |
+ |
+ BitcodeId(const BitcodeId &Id) |
+ : Kind(Id.Kind), Index(Id.Index), IsGlobal(Id.IsGlobal) {} |
+ |
+ BitcodeId(char Kind, uint32_t Index, bool IsGlobal) |
+ : Kind(Kind), Index(Index), IsGlobal(IsGlobal) {} |
+ |
+ void operator=(const BitcodeId &Id) { |
+ Kind = Id.Kind; |
+ Index = Id.Index; |
+ IsGlobal = Id.IsGlobal; |
+ } |
+ |
+ raw_ostream &Print(raw_ostream &Stream) const { |
+ return Stream << Prefix() << Kind << Index; |
+ } |
+ |
+ char GetKind() const { |
+ return Kind; |
+ } |
+ |
+ std::string GetName() const { |
+ std::string Buffer; |
+ raw_string_ostream StrBuf(Buffer); |
+ Print(StrBuf); |
+ return StrBuf.str(); |
+ } |
+ |
+private: |
+ char Kind; |
+ uint32_t Index; |
+ bool IsGlobal; |
+ |
+ // Returns true if (default) assumption for kind implies global. |
+ static bool IsGlobalKind(char Kind); |
+ |
+ // Returns the bitcode prefix character that communicates if the |
+ // bitcode Id is lcoal or global. |
+ char Prefix() const { return IsGlobal ? '@' : '%'; } |
+}; |
+ |
+bool BitcodeId::IsGlobalKind(char Kind) { |
+ switch (Kind) { |
+ case 'f': |
+ case 'g': |
+ case 't': |
+ return true; |
+ case 'b': |
+ case 'c': |
+ case 'p': |
+ case 'v': |
+ return false; |
+ default: |
+ errs() << "Bad bitcode id, can't determine (statically) if global: " |
+ << Kind << "\n"; |
+ report_fatal_error("Unable to continue"); |
+ } |
+} |
+ |
+raw_ostream &operator<<(raw_ostream &Stream, const BitcodeId &Id) { |
+ return Id.Print(Stream); |
+} |
+ |
+class NaClDisBlockParser; |
+ |
+/// The text formatter for PNaClAsm instructions. |
+class AssemblyTextFormatter : public naclbitc::TextFormatter { |
+public: |
+ // Special directive to tokenize type expressions. Used to convert |
+ // type signatures into a sequence of tokens. |
+ class TypeDirective : public naclbitc::TextFormatter::Directive { |
+ public: |
+ TypeDirective(TextFormatter *Formatter) |
+ : naclbitc::TextFormatter::Directive(Formatter), |
+ Typ(0), |
+ FcnId(0), |
+ AddParams(false) {} |
+ |
+ ~TypeDirective() override {} |
+ |
+ private: |
+ /// Calls the corresponding method in AssemblyTextFormatter, with |
+ /// the locally stored arguments. |
+ void MyApply(bool Replay) const override; |
+ |
+ void MaybeSaveForReplay() const override {} |
+ |
+ // The type to tokenize. |
+ Type *Typ; |
+ // Pointer to function id, if not NULL. |
+ BitcodeId *FcnId; |
+ // true if parameter id's should be added to function signature. |
+ bool AddParams; |
+ |
+ friend class AssemblyTextFormatter; |
+ |
+ // Internal routine to allow AssemblyTextFormatter::AllocateTypeDirective |
+ // to initialize a type directive. |
+ void Init(Type *NewTyp, BitcodeId *NewFcnId, bool NewAddParams) { |
+ Typ = NewTyp; |
+ FcnId = NewFcnId; |
+ AddParams = NewAddParams; |
+ } |
+ }; |
+ |
+ // Special directive to tokenize an abbreviation. Used to convert |
+ // an abbreviation (pointer) into a sequence of tokens. |
+ class AbbreviationDirective : public naclbitc::TextFormatter::Directive { |
+ public: |
+ AbbreviationDirective(TextFormatter *Formatter) |
+ : naclbitc::TextFormatter::Directive(Formatter), |
+ Abbrev(0) {} |
+ |
+ ~AbbreviationDirective() override {} |
+ |
+ private: |
+ void MyApply(bool Replay) const override; |
+ |
+ void MaybeSaveForReplay() const override {} |
+ |
+ // The abbreviation to tokenize. |
+ NaClBitCodeAbbrev *Abbrev; |
+ |
+ friend class AssemblyTextFormatter; |
+ }; |
+ |
+ // Special directive to tokenize an abbreviation index, if the corresponding |
+ // record in the block parser used a user-defined abbreviation. |
+ class AbbrevIndexDirective : public naclbitc::TextFormatter::Directive { |
+ public: |
+ AbbrevIndexDirective(TextFormatter *Formatter) |
+ : naclbitc::TextFormatter::Directive(Formatter), |
+ Record(0), NumGlobalAbbreviations(0) {} |
+ |
+ ~AbbrevIndexDirective() override {} |
+ |
+ private: |
+ void MyApply(bool Replay) const override; |
+ |
+ void MaybeSaveForReplay() const override {} |
+ |
+ // The record containing the associated abbreviation. |
+ NaClBitcodeRecord *Record; |
+ |
+ // The number of global abbreviations defined for the block the |
+ // record appears in. |
+ unsigned NumGlobalAbbreviations; |
+ |
+ friend class AssemblyTextFormatter; |
+ }; |
+ |
+public: |
+ |
+ /// Creates an assembly text formatter for the given dump stream. |
+ AssemblyTextFormatter(naclbitc::ObjDumpStream &ObjDump) |
+ : TextFormatter(ObjDump.Assembly(), |
+ std::max(20U, GetAssemblyWidth(ObjDump)), |
+ " "), |
+ Comma(this, ","), |
+ Semicolon(this, ";"), |
+ Colon(this, ":"), |
+ Space(this), |
+ OpenParen(this, "("), |
+ CloseParen(this, ")"), |
+ OpenAngle(this, "<"), |
+ CloseAngle(this, ">"), |
+ OpenCurly(this, "{"), |
+ CloseCurly(this, "}"), |
+ OpenSquare(this, "["), |
+ CloseSquare(this, "]"), |
+ Endline(this), |
+ StartCluster(this), |
+ FinishCluster(this) |
+ { |
+ ContinuationIndent = GetIndent(2); |
+ } |
+ |
+ ~AssemblyTextFormatter() override {} |
+ |
+ naclbitc::TokenTextDirective Comma; |
+ naclbitc::TokenTextDirective Semicolon; |
+ naclbitc::TokenTextDirective Colon; |
+ naclbitc::SpaceTextDirective Space; |
+ naclbitc::OpenTextDirective OpenParen; |
+ naclbitc::CloseTextDirective CloseParen; |
+ naclbitc::OpenTextDirective OpenAngle; |
+ naclbitc::CloseTextDirective CloseAngle; |
+ naclbitc::OpenTextDirective OpenCurly; |
+ naclbitc::CloseTextDirective CloseCurly; |
+ naclbitc::OpenTextDirective OpenSquare; |
+ naclbitc::CloseTextDirective CloseSquare; |
+ naclbitc::EndlineTextDirective Endline; |
+ naclbitc::StartClusteringDirective StartCluster; |
+ naclbitc::FinishClusteringDirective FinishCluster; |
+ |
+ /// Prints the given type as a sequence of tokens. |
+ TypeDirective &TokenizeType(Type *Typ) { |
+ return AllocateTypeDirective(Typ, 0, false); |
+ } |
+ |
+ /// Prints the named function type as a sequence of tokens. |
+ /// Typ is the type signature of the function, and FunctionName |
+ /// points to the name of the function. |
+ TypeDirective &TokenizeFunctionType(FunctionType *Typ, |
+ BitcodeId *FunctionName) { |
+ return AllocateTypeDirective(Typ, FunctionName, false); |
+ } |
+ |
+ /// Prints the function signature of the function type. Typ is |
+ /// the type signature of the function. FunctionName points to the |
+ /// name of the function. Note: Unlike TokenizeFunctionType, this |
+ /// method also adds the parameter names to paramter argumements. |
+ TypeDirective &TokenizeFunctionSignature(FunctionType *Typ, |
+ BitcodeId *FunctionName) { |
+ return AllocateTypeDirective(Typ, FunctionName, true); |
+ } |
+ |
+ /// Prints out the abbreviation defined by Abbrev. |
+ AbbreviationDirective &TokenizeAbbreviation(NaClBitCodeAbbrev *Abbrev) { |
+ AbbreviationDirective *Dir = AbbrevDirMemoryPool.Allocate(this); |
+ Dir->Abbrev = Abbrev; |
+ return *Dir; |
+ } |
+ |
+ /// If the record was read using a user-defined abbreviation, |
+ /// generates assembly tokens describing the abbreviation index |
+ /// used. Otherwise, no tokens are generated. NumGlobalAbbreviations |
+ /// is used to determine if the user-defined abbreviation is local |
+ /// or global. |
+ AbbrevIndexDirective &TokenizeAbbrevIndex(NaClBitcodeRecord &Record, |
+ unsigned NumGlobalAbbreviations) { |
+ AbbrevIndexDirective *Dir = AbbrevIndexDirMemoryPool.Allocate(this); |
+ Dir->Record = &Record; |
+ Dir->NumGlobalAbbreviations = NumGlobalAbbreviations; |
+ return *Dir; |
+ } |
+ |
+private: |
+ // Converts the given type to tokens, based on the values passed in |
+ // by TokenizeType, TokenizeFunctionType, or TokenizeFunctionSignature. |
+ void TokenizeTypeInternal(Type *Typ, BitcodeId* FcnName, bool AddParams); |
+ |
+ // The free list of type directives. |
+ naclbitc::DirectiveMemoryPool<TypeDirective> TypeDirMemoryPool; |
+ |
+ // Allocates an instance of TypeDirective with the following fields. |
+ TypeDirective &AllocateTypeDirective(Type *Typ, BitcodeId *FcnId, |
+ bool AddParams); |
+ |
+ // Converts the given abbreviation to tokens. |
+ void TokenizeAbbreviationInternal(const NaClBitCodeAbbrev *Abbrev); |
+ |
+ // Helper function that prints out the abbreviation expression |
+ // located at Index in the given abbreviation. Updates Index to |
+ // next expression in the abbreviation. |
+ void TokenizeAbbrevExpression(const NaClBitCodeAbbrev *Abbrev, |
+ unsigned &Index); |
+ |
+ // Prints out the given abbreviation operator. |
+ void TokenizeAbbrevOp(const NaClBitCodeAbbrevOp &Op); |
+ |
+ // The free list for abbreviation directives. |
+ naclbitc::DirectiveMemoryPool<AbbreviationDirective> AbbrevDirMemoryPool; |
+ |
+ // The free list for abbreviation index directives. |
+ naclbitc::DirectiveMemoryPool<AbbrevIndexDirective> AbbrevIndexDirMemoryPool; |
+ |
+ // Computes how wide the assembly portion of the dump file should be. |
+ static unsigned GetAssemblyWidth(naclbitc::ObjDumpStream &ObjDump) { |
+ int Diff = 80 - (ObjDump.GetRecordWidth()+1); |
+ // Make sure there is enough room to print out assembly. |
+ return Diff < 20 ? 20 : Diff; |
+ } |
+}; |
+ |
+void AssemblyTextFormatter::TypeDirective::MyApply(bool Replay) const { |
+ assert(!Replay && "Shouldn't have been saved for replay"); |
+ AssemblyTextFormatter *AssemblyFormatter = |
+ reinterpret_cast<AssemblyTextFormatter*>(Formatter); |
+ AssemblyFormatter->TokenizeTypeInternal(Typ, FcnId, AddParams); |
+ AssemblyFormatter->TypeDirMemoryPool.Free(const_cast<TypeDirective*>(this)); |
+} |
+ |
+void AssemblyTextFormatter::AbbreviationDirective::MyApply(bool Replay) const { |
+ assert(!Replay && "Shouldn't have been saved for replay"); |
+ AssemblyTextFormatter *AssemblyFormatter = |
+ reinterpret_cast<AssemblyTextFormatter*>(Formatter); |
+ AssemblyFormatter->TokenizeAbbreviationInternal(Abbrev); |
+ AssemblyFormatter->AbbrevDirMemoryPool.Free( |
+ const_cast<AbbreviationDirective*>(this)); |
+} |
+ |
+AssemblyTextFormatter::TypeDirective &AssemblyTextFormatter:: |
+AllocateTypeDirective(Type *Typ, BitcodeId *FcnId, bool AddParams) { |
+ TypeDirective *Element = TypeDirMemoryPool.Allocate(this); |
+ Element->Init(Typ, FcnId, AddParams); |
+ return *Element; |
+} |
+ |
+void AssemblyTextFormatter::TokenizeTypeInternal( |
+ Type *Typ, BitcodeId* FcnName, bool AddParams) { |
+ switch (Typ->getTypeID()) { |
+ case Type::VoidTyID: |
+ TextStream << "void"; |
+ break; |
+ case Type::FloatTyID: |
+ TextStream << "float"; |
+ break; |
+ case Type::DoubleTyID: |
+ TextStream << "double"; |
+ break; |
+ case Type::IntegerTyID: |
+ TextStream << "i" << Typ->getIntegerBitWidth(); |
+ break; |
+ case Type::VectorTyID: { |
+ VectorType *VecType = cast<VectorType>(Typ); |
+ TextStream << StartCluster << OpenAngle << VecType->getNumElements() |
+ << Space << "x" << Space |
+ << TokenizeType(VecType->getElementType()) |
+ << CloseAngle << FinishCluster; |
+ break; |
+ } |
+ case Type::FunctionTyID: { |
+ FunctionType *FcnType = cast<FunctionType>(Typ); |
+ unsigned NumParams = FcnType->getFunctionNumParams(); |
+ TextStream << StartCluster |
+ << TokenizeType(FcnType->getReturnType()) |
+ << Space |
+ << StartCluster; |
+ if (NumParams > 0) TextStream << StartCluster; |
+ if (FcnName) TextStream << *FcnName; |
+ TextStream << OpenParen << FinishCluster; |
+ bool HasParamStartCluster = false; |
+ for (unsigned i = 0, NumParams = FcnType->getFunctionNumParams(); |
+ i < NumParams; ++i) { |
+ if (i > 0) { |
+ TextStream << Comma << FinishCluster << Space; |
+ HasParamStartCluster = false; |
+ } |
+ TextStream << StartCluster |
+ << TokenizeType(FcnType->getFunctionParamType(i)); |
+ if (AddParams) TextStream << Space << BitcodeId('p', i); |
+ HasParamStartCluster = true; |
+ } |
+ if (FcnType->isFunctionVarArg()) { |
+ if (HasParamStartCluster) { |
+ TextStream << Comma << FinishCluster << Space; |
+ } |
+ TextStream << StartCluster << "..."; |
+ HasParamStartCluster = true; |
+ } |
+ if (HasParamStartCluster) TextStream << FinishCluster; |
+ TextStream << CloseParen << FinishCluster; |
+ if (NumParams > 0) TextStream << FinishCluster; |
+ break; |
+ } |
+ default: |
+ report_fatal_error("Unsupported PNaCl type found"); |
+ break; |
+ } |
+} |
+ |
+void AssemblyTextFormatter::TokenizeAbbrevOp(const NaClBitCodeAbbrevOp &Op) { |
+ // Note: Mimics NaClBitCodeAbbrevOp::Print in NaClBitCodes.cpp |
+ switch (Op.getEncoding()) { |
+ case NaClBitCodeAbbrevOp::Literal: |
+ Tokens() << Op.getValue(); |
+ return; |
+ case NaClBitCodeAbbrevOp::Fixed: |
+ Tokens() << StartCluster << "fixed" << OpenParen << Op.getValue() |
+ << CloseParen << FinishCluster; |
+ return; |
+ case NaClBitCodeAbbrevOp::VBR: |
+ Tokens() << StartCluster << "vbr" << OpenParen << Op.getValue() |
+ << CloseParen << FinishCluster; |
+ return; |
+ case NaClBitCodeAbbrevOp::Array: |
+ Tokens() << "array"; |
+ return; |
+ case NaClBitCodeAbbrevOp::Char6: |
+ Tokens() << "char6"; |
+ return; |
+ } |
+} |
+ |
+void AssemblyTextFormatter:: |
+TokenizeAbbrevExpression(const NaClBitCodeAbbrev *Abbrev, unsigned &Index) { |
+ // Note: Mimics PrintExpression in NaClBitCodes.cpp |
+ const NaClBitCodeAbbrevOp &Op = Abbrev->getOperandInfo(Index); |
+ TokenizeAbbrevOp(Op); |
+ if (unsigned NumArgs = Op.NumArguments()) { |
+ Tokens() << StartCluster << OpenParen; |
+ for (unsigned i = 0; i < NumArgs; ++i) { |
+ ++Index; |
+ if (i > 0) { |
+ Tokens() << Comma << FinishCluster << Space << StartCluster; |
+ } |
+ TokenizeAbbrevExpression(Abbrev, Index); |
+ } |
+ Tokens() << CloseParen << FinishCluster; |
+ } |
+} |
+ |
+void AssemblyTextFormatter:: |
+TokenizeAbbreviationInternal(const NaClBitCodeAbbrev *Abbrev) { |
+ Tokens() << StartCluster << OpenAngle; |
+ for (unsigned i = 0; i < Abbrev->getNumOperandInfos(); ++i) { |
+ if (i > 0) { |
+ Tokens() << Comma << FinishCluster << Space << StartCluster; |
+ } |
+ TokenizeAbbrevExpression(Abbrev, i); |
+ } |
+ Tokens() << CloseAngle << FinishCluster; |
+} |
+ |
+void AssemblyTextFormatter::AbbrevIndexDirective::MyApply(bool Replay) const { |
+ assert(!Replay && "Shouldn't have been saved for replay"); |
+ if (!Record->UsedAnAbbreviation()) return; |
+ unsigned Index = Record->GetAbbreviationIndex(); |
+ if (Index < naclbitc::FIRST_APPLICATION_ABBREV) return; |
+ Index -= naclbitc::FIRST_APPLICATION_ABBREV; |
+ bool IsGlobal = Index < NumGlobalAbbreviations; |
+ if (!IsGlobal) Index -= NumGlobalAbbreviations; |
+ BitcodeId AbbrevIndex('a', Index, IsGlobal); |
+ AssemblyTextFormatter *Fmtr = |
+ reinterpret_cast<AssemblyTextFormatter*>(Formatter); |
+ Tokens() << Fmtr->Space << Fmtr->StartCluster << Fmtr->OpenAngle |
+ << AbbrevIndex << Fmtr->CloseAngle << Fmtr->FinishCluster; |
+ Fmtr->AbbrevIndexDirMemoryPool.Free(const_cast<AbbrevIndexDirective*>(this)); |
+} |
+ |
+// Holds possible alignements for loads/stores etc. Used to extract |
+// expected values. |
+static unsigned NaClPossibleLoadStoreAlignments[] = { |
+ 1, 2, 4, 8 |
+}; |
+ |
+// Finds the expected alignments for the load/store, for type Ty. |
+static void NaClGetExpectedLoadStoreAlignment( |
+ const DataLayout &DL, Type *Ty, std::vector<unsigned> &ValidAlignments) { |
+ for (size_t i = 0; i < array_lengthof(NaClPossibleLoadStoreAlignments); ++i) { |
+ unsigned Alignment = NaClPossibleLoadStoreAlignments[i]; |
+ if (PNaClABIProps::isAllowedAlignment(&DL, Alignment, Ty)) { |
+ ValidAlignments.push_back(Alignment); |
+ } |
+ } |
+} |
+ |
+/// Top-level class to parse bitcode file and transform to |
+/// corresponding disassembled code. |
+class NaClDisTopLevelParser : public NaClBitcodeParser { |
+ NaClDisTopLevelParser(const NaClDisTopLevelParser&) LLVM_DELETED_FUNCTION; |
+ void operator=(const NaClDisTopLevelParser&) LLVM_DELETED_FUNCTION; |
+ |
+public: |
+ NaClDisTopLevelParser(NaClBitcodeHeader &Header, |
+ const unsigned char *HeaderBuffer, |
+ NaClBitstreamCursor &Cursor, |
+ naclbitc::ObjDumpStream &ObjDump) |
+ : NaClBitcodeParser(Cursor), |
+ Mod("ObjDump", getGlobalContext()), |
+ ObjDump(ObjDump), |
+ AbbrevListener(this), |
+ DL(&Mod), |
+ AllowedIntrinsics(&Mod.getContext()), |
+ AssemblyFormatter(ObjDump), |
+ Header(Header), |
+ HeaderBuffer(HeaderBuffer), |
+ NumFunctions(0), |
+ NumGlobals(0), |
+ ExpectedNumGlobals(0), |
+ NumParams(0), |
+ NumConstants(0), |
+ NumValuedInsts(0), |
+ UnknownType(Type::getVoidTy(Mod.getContext())), |
+ PointerType(Type::getInt32Ty(Mod.getContext())), |
+ ComparisonType(Type::getInt1Ty(Mod.getContext())), |
+ NumDefinedFunctions(0) { |
+ SetListener(&AbbrevListener); |
+ } |
+ |
+ ~NaClDisTopLevelParser() override { |
+ // Be sure to flush any remaining errors. |
+ ObjDump.Flush(); |
+ } |
+ |
+ // Returns the number of errors that were sent to the ObjDump. |
+ unsigned GetNumErrors() { |
+ return ObjDump.GetNumErrors(); |
+ } |
+ |
+ /// Generates an error with the given message. |
+ bool Error(const std::string &Message) override { |
+ // Use local error routine so that all errors are treated uniformly. |
+ ObjDump.Error() << Message << "\n"; |
+ return true; |
+ } |
+ |
+ /// Flushes out objdump and then exits with fatal error. |
+ void Fatal() { |
+ Fatal(""); |
+ } |
+ |
+ /// Flushes out objdump and then exits with fatal error, using |
+ /// the given message. |
+ void Fatal(const std::string &Message) { |
+ ObjDump.Fatal(Message); |
+ } |
+ |
+ /// Parses the top-level module block. |
+ bool ParseBlock(unsigned BlockID) override; |
+ |
+ /// Installs the given type to the next available type index. |
+ void InstallType(Type *Ty) { |
+ TypeIdType.push_back(Ty); |
+ } |
+ |
+ /// Returns the type associated with the given type index. |
+ Type *GetType(uint32_t Index) { |
+ if (Index >= TypeIdType.size()) { |
+ BitcodeId Id('t', Index); |
+ Errors() << "Can't find definition for " << Id << "\n"; |
+ // Recover so that additional errors can be found. |
+ return UnknownType; |
+ } |
+ return TypeIdType[Index]; |
+ } |
+ |
+ /// Returns the number of types (currently) defined in the bitcode |
+ /// file. |
+ uint32_t GetNumTypes() const { |
+ return TypeIdType.size(); |
+ } |
+ |
+ /// Returns true if Type represents a (non-zero sized) value. |
+ bool isValidValueType(Type *Ty) const { |
+ return Ty->isIntegerTy() || Ty->isFloatTy() || Ty->isDoubleTy() |
+ || Ty->isVectorTy(); |
+ } |
+ |
+ /// Installs the given type to the next available function index. |
+ void InstallFunctionType(FunctionType *Ty, uint64_t BitAddress) { |
+ assert(FunctionIdType.size() == NumFunctions); |
+ ++NumFunctions; |
+ FunctionIdType.push_back(Ty); |
+ FunctionIdAddress.push_back(BitAddress); |
+ // Let Valuesymtab change this to true if appropriate. |
+ FunctionIdIsIntrinsic.push_back(false); |
+ } |
+ |
+ /// Returns the bit address where the function record appeared in |
+ /// the bitcode file. Returns 0 if unknown. |
+ uint64_t GetFunctionIdAddress(uint32_t Index) { |
+ if (Index >= FunctionIdAddress.size()) return 0; |
+ return FunctionIdAddress[Index]; |
+ } |
+ |
+ /// Sets the record bit address to the function ID address (if known). |
+ void SetRecordAddressToFunctionIdAddress(uint32_t Index) { |
+ uint64_t Address = GetFunctionIdAddress(Index); |
+ if (Address) |
+ ObjDump.SetRecordBitAddress(Address); |
+ } |
+ |
+ //// Returns the type associated with the given function index. |
+ FunctionType *GetFunctionType(uint32_t Index) { |
+ if (Index >= FunctionIdType.size()) { |
+ BitcodeId Id('f', Index); |
+ Errors() << "Can't find definition for " << Id << "\n"; |
+ Fatal(); |
+ } |
+ return FunctionIdType[Index]; |
+ } |
+ |
+ /// Marks the function associated with the given Index as intrinsic. |
+ void MarkFunctionAsIntrinsic(uint32_t Index) { |
+ if (Index >= FunctionIdIsIntrinsic.size()) { |
+ BitcodeId Id('f', Index); |
+ Errors() << "Can't define " << Id << " as intrinsic, no definition"; |
+ } |
+ FunctionIdIsIntrinsic[Index] = true; |
+ } |
+ |
+ /// Returns true if the given Index is for a function intrinsic. |
+ bool IsFunctionIntrinsic(uint32_t Index) { |
+ if (Index >= FunctionIdIsIntrinsic.size()) return false; |
+ return FunctionIdIsIntrinsic[Index]; |
+ } |
+ |
+ /// Returns true if the function is an intrinsic function. |
+ bool IsIntrinsicAllowed(const std::string &FuncName, |
+ const FunctionType *FuncType) { |
+ return AllowedIntrinsics.isAllowed(FuncName, FuncType); |
+ } |
+ |
+ /// Returns the type of the Name'd intrinsic, if defined as an |
+ /// allowed intrinsic name. Otherwise returns 0. |
+ FunctionType *GetIntrinsicType(const std::string &Name) { |
+ return AllowedIntrinsics.getIntrinsicType(Name); |
+ } |
+ |
+ /// Returns the number of functions (currently) defined/declared in |
+ /// the bitcode file. |
+ uint32_t GetNumFunctions() const { |
+ return NumFunctions; |
+ } |
+ |
+ /// Installs that the given function index as having a function body |
+ /// (i.e. the function address uses the "define" keyword instead of |
+ /// the "declare" keyword). |
+ void InstallDefinedFunction(uint32_t Index) { |
+ DefinedFunctions.push_back(Index); |
+ } |
+ |
+ /// Returns true if there is an Index defined function block. |
+ bool HasDefinedFunctionIndex(uint32_t Index) const { |
+ return Index < DefinedFunctions.size(); |
+ } |
+ |
+ /// Returns the function index associated with the Index defined |
+ /// function block. |
+ uint32_t GetDefinedFunctionIndex(uint32_t Index) const { |
+ assert(Index < DefinedFunctions.size()); |
+ return DefinedFunctions[NumDefinedFunctions]; |
+ } |
+ |
+ /// Returns true if there is a next defined function index. |
+ bool HasNextDefinedFunctionIndex() const { |
+ return HasDefinedFunctionIndex(NumDefinedFunctions); |
+ } |
+ |
+ /// Returns the function index associated with the next defined function. |
+ uint32_t GetNextDefinedFunctionIndex() const { |
+ return GetDefinedFunctionIndex(NumDefinedFunctions); |
+ } |
+ |
+ /// Returns true if the given value ID corresponds to a declared (rather |
+ /// than defined) function. |
+ bool IsDeclaredFunction(uint32_t Index) { |
+ if (Index >= NumFunctions) return false; |
+ for (size_t i = 0, e = DefinedFunctions.size(); i < e; ++i) { |
+ if (DefinedFunctions[i] == Index) return false; |
+ } |
+ return true; |
+ } |
+ |
+ /// Increments the number of (currently) defined functions in the |
+ /// bitcode file by one. |
+ void IncNumDefinedFunctions() { |
+ ++NumDefinedFunctions; |
+ } |
+ |
+ void IncNumGlobals() { |
+ NumGlobals++; |
+ } |
+ |
+ /// Returns the number of globals (currently) defined in the bitcode |
+ /// file. |
+ uint32_t GetNumGlobals() const { |
+ return NumGlobals; |
+ } |
+ |
+ /// Returns the expected number of globals (as defined by the count |
+ /// record of the globals block). |
+ uint32_t GetExpectedNumGlobals() const { |
+ return ExpectedNumGlobals; |
+ } |
+ |
+ /// Sets field ExpectedNumGlobals to the given value. |
+ void SetExpectedNumGlobals(uint32_t NewValue) { |
+ ExpectedNumGlobals = NewValue; |
+ } |
+ |
+ /// Installs the given type to the next available parameter index. |
+ void InstallParamType(Type *Ty) { |
+ while (ParamIdType.size() <= NumParams) { |
+ ParamIdType.push_back(UnknownType); |
+ } |
+ ParamIdType[NumParams++] = Ty; |
+ } |
+ |
+ /// Returns the type associated with the given parameter index. |
+ Type *GetParamType(uint32_t Index) { |
+ if (Index >= ParamIdType.size()) { |
+ BitcodeId Id('p', Index); |
+ Errors() << "Can't find defintion for " << Id << "\n"; |
+ Fatal(); |
+ } |
+ return ParamIdType[Index]; |
+ } |
+ |
+ /// Returns the number of parameters (currently) defined in the |
+ /// enclosing defined function. |
+ uint32_t GetNumParams() const { |
+ return NumParams; |
+ } |
+ |
+ /// Installs the given type to the next available constant index. |
+ void InstallConstantType(Type *Ty) { |
+ while (ConstantIdType.size() <= NumConstants) { |
+ ConstantIdType.push_back(UnknownType); |
+ } |
+ ConstantIdType[NumConstants++] = Ty; |
+ } |
+ |
+ /// Returns the type associated with the given constant index. |
+ Type *GetConstantType(uint32_t Index) { |
+ if (Index >= ConstantIdType.size()) { |
+ BitcodeId Id('c', Index); |
+ Errors() << "Can't find definition for " << Id << "\n"; |
+ Fatal(); |
+ } |
+ return ConstantIdType[Index]; |
+ } |
+ |
+ /// Returns the number of constants (currently) defined in the |
+ /// enclosing defined function. |
+ uint32_t GetNumConstants() const { |
+ return NumConstants; |
+ } |
+ |
+ /// Installs the given type to the given instruction index. Note: |
+ /// Instruction indices are only associated with instructions that |
+ /// generate values. |
+ void InstallInstType(Type *Ty, uint32_t Index) { |
+ while (InstIdType.size() <= Index) { |
+ InstIdType.push_back(UnknownType); |
+ } |
+ if (InstIdType[Index] != UnknownType && Ty != InstIdType[Index]) { |
+ Errors() << BitcodeId('v', Index) << " defined with multiple types: " |
+ << *Ty << " and " << *InstIdType[Index] << "\n"; |
+ } |
+ InstIdType[Index] = Ty; |
+ } |
+ |
+ /// Installs the given type to the next available instruction index. |
+ void InstallInstType(Type *Ty) { |
+ InstallInstType(Ty, NumValuedInsts++); |
+ } |
+ |
+ /// Returns the type associated with the given instruction index. |
+ /// Note: Instruction indices are only associated with instructions |
+ /// that generate values. |
+ Type *GetInstType(uint32_t Index) { |
+ if (Index >= InstIdType.size()) { |
+ Errors() << "Can't find type for " << BitcodeId('v', Index) << "\n"; |
+ return UnknownType; |
+ } |
+ return InstIdType[Index]; |
+ } |
+ |
+ /// Returns the number of instructions (in the defined function) |
+ /// that (currently) generate values. |
+ uint32_t GetNumValuedInstructions() const { |
+ return NumValuedInsts; |
+ } |
+ |
+ /// Resets index counters local to a defined function. |
+ void ResetLocalCounters() { |
+ ParamIdType.clear(); |
+ NumParams = 0; |
+ NumConstants = 0; |
+ InstIdType.clear(); |
+ NumValuedInsts = 0; |
+ } |
+ |
+ /// Returns the bitcode id associated with the absolute value index |
+ BitcodeId GetBitcodeId(uint32_t Index); |
+ |
+ /// Returns the type associated with the given absolute value index. |
+ /// If UnderlyingType is false, function indices always return a |
+ /// pointer type. Otherwise, function indices returns the declared |
+ /// type of the function index. |
+ Type *GetValueType(uint32_t Index, bool UnderlyingType = false); |
+ |
+ /// Returns a type to use when the type is unknown. |
+ Type *GetUnknownType() const { |
+ return UnknownType; |
+ } |
+ |
+ /// Returns the type used to represent a pointer. |
+ Type *GetPointerType() const { |
+ return PointerType; |
+ } |
+ |
+ /// Returns the type used to represent comparison results. |
+ Type *GetComparisonType() const { |
+ return ComparisonType; |
+ } |
+ |
+ /// Returns the void type. |
+ Type *GetVoidType() const { |
+ return Type::getVoidTy(getGlobalContext()); |
+ } |
+ |
+ /// Returns the float (32-bit) type. |
+ Type *GetFloatType() const { |
+ return Type::getFloatTy(getGlobalContext()); |
+ } |
+ |
+ /// Returns the double (64-bit) type. |
+ Type *GetDoubleType() const { |
+ return Type::getDoubleTy(getGlobalContext()); |
+ } |
+ |
+ /// Returns an integer type of N bits. |
+ Type *GetIntegerType(unsigned N) const { |
+ return Type::getIntNTy(getGlobalContext(), N); |
+ } |
+ |
+ /// Returns the number of defined global abbreviations (currently) |
+ /// for the given block id. |
+ unsigned GetNumGlobalAbbreviations(unsigned BlockID) { |
+ return GlobalAbbrevsCountMap[BlockID]; |
+ } |
+ |
+ /// Increments the current number of defined global abbreviations. |
+ void IncNumGlobalAbbreviations(unsigned BlockID) { |
+ ++GlobalAbbrevsCountMap[BlockID]; |
+ } |
+ |
+ /// Verifies the given integer operator has the right type. Returns |
+ /// the operator. |
+ const char *VerifyIntArithmeticOp(const char *Op, Type *OpTy) { |
+ if (!IgnorePNaClABIChecks && |
+ !PNaClABITypeChecker::isValidIntArithmeticType(OpTy)) { |
+ Errors() << Op << ": Invalid integer arithmetic type: " << *OpTy; |
+ } |
+ return Op; |
+ } |
+ |
+ // Checks the Alignment for loading/storing a value of type Ty. If |
+ // invalid, generates an appropriate error message. |
+ void VerifyMemoryAccessAlignment(const char *Op, Type *Ty, |
+ unsigned Alignment) { |
+ if (IgnorePNaClABIChecks) return; |
+ if (!PNaClABIProps::isAllowedAlignment(&DL, Alignment, Ty)) { |
+ raw_ostream &Errs = Errors(); |
+ std::vector<unsigned> Alignments; |
+ NaClGetExpectedLoadStoreAlignment(DL, Ty, Alignments); |
+ if (!Alignments.empty()) { |
+ Errs << Op << ": Illegal alignment for " << *Ty << ". Expects: "; |
+ bool isFirst = true; |
+ for (auto Align : Alignments) { |
+ if (isFirst) |
+ isFirst = false; |
+ else |
+ Errs << " or "; |
+ Errs << Align; |
+ } |
+ Errs << "\n"; |
+ } else { |
+ Errs << Op << ": Not allowed for type: " << *Ty << "\n"; |
+ } |
+ } |
+ } |
+ |
+ // ****************************************************** |
+ // The following return the corresponding methods/fields |
+ // from the the assembly formatter/objdumper. |
+ // ****************************************************** |
+ |
+ naclbitc::TokenTextDirective &Semicolon() { |
+ return AssemblyFormatter.Semicolon; |
+ } |
+ |
+ naclbitc::TokenTextDirective &Colon() { |
+ return AssemblyFormatter.Colon; |
+ } |
+ |
+ naclbitc::SpaceTextDirective &Space() { |
+ return AssemblyFormatter.Space; |
+ } |
+ |
+ naclbitc::TokenTextDirective &Comma() { |
+ return AssemblyFormatter.Comma; |
+ } |
+ |
+ naclbitc::OpenTextDirective &OpenParen() { |
+ return AssemblyFormatter.OpenParen; |
+ } |
+ |
+ naclbitc::CloseTextDirective &CloseParen() { |
+ return AssemblyFormatter.CloseParen; |
+ } |
+ |
+ naclbitc::OpenTextDirective &OpenAngle() { |
+ return AssemblyFormatter.OpenAngle; |
+ } |
+ |
+ naclbitc::CloseTextDirective &CloseAngle() { |
+ return AssemblyFormatter.CloseAngle; |
+ } |
+ |
+ naclbitc::OpenTextDirective &OpenCurly() { |
+ return AssemblyFormatter.OpenCurly; |
+ } |
+ |
+ naclbitc::CloseTextDirective &CloseCurly() { |
+ return AssemblyFormatter.CloseCurly; |
+ } |
+ |
+ naclbitc::OpenTextDirective &OpenSquare() { |
+ return AssemblyFormatter.OpenSquare; |
+ } |
+ |
+ naclbitc::CloseTextDirective &CloseSquare() { |
+ return AssemblyFormatter.CloseSquare; |
+ } |
+ |
+ naclbitc::EndlineTextDirective &Endline() { |
+ return AssemblyFormatter.Endline; |
+ } |
+ |
+ naclbitc::StartClusteringDirective &StartCluster() { |
+ return AssemblyFormatter.StartCluster; |
+ } |
+ |
+ naclbitc::FinishClusteringDirective &FinishCluster() { |
+ return AssemblyFormatter.FinishCluster; |
+ } |
+ |
+ raw_ostream &Tokens() { |
+ return AssemblyFormatter.Tokens(); |
+ } |
+ |
+ raw_ostream &Errors() { |
+ return ObjDump.Error(); |
+ } |
+ |
+ raw_ostream &Warnings() { |
+ if (ReportWarningsAsErrors) return Errors(); |
+ return ObjDump.Warning(); |
+ } |
+ |
+ const std::string &GetAssemblyIndent() const { |
+ return AssemblyFormatter.GetIndent(); |
+ } |
+ |
+ unsigned GetAssemblyNumTabs() const { |
+ return AssemblyFormatter.GetNumTabs(); |
+ } |
+ |
+ void IncAssemblyIndent() { |
+ AssemblyFormatter.Inc(); |
+ } |
+ |
+ void DecAssemblyIndent() { |
+ AssemblyFormatter.Dec(); |
+ } |
+ |
+ void IncRecordIndent() { |
+ ObjDump.IncRecordIndent(); |
+ } |
+ |
+ void DecRecordIndent() { |
+ ObjDump.DecRecordIndent(); |
+ } |
+ |
+ void ObjDumpFlush() { |
+ ObjDump.Flush(); |
+ } |
+ |
+ void ObjDumpSetRecordBitAddress(uint64_t Bit) { |
+ ObjDump.SetRecordBitAddress(Bit); |
+ } |
+ |
+ void ObjDumpWrite(uint64_t Bit, |
+ const NaClBitcodeRecordData &Record, |
+ int32_t AbbrevIndex = |
+ naclbitc::ABBREV_INDEX_NOT_SPECIFIED) { |
+ ObjDump.Write(Bit, Record, AbbrevIndex); |
+ } |
+ |
+ void ObjDumpWrite(uint64_t Bit, |
+ const NaClBitcodeRecord &Record) { |
+ ObjDump.Write(Bit, Record.GetRecordData(), Record.GetAbbreviationIndex()); |
+ } |
+ |
+ AssemblyTextFormatter::TypeDirective & |
+ TokenizeType(Type *Typ) { |
+ return AssemblyFormatter.TokenizeType(Typ); |
+ } |
+ |
+ AssemblyTextFormatter::TypeDirective & |
+ TokenizeFunctionType(FunctionType *Type, BitcodeId *FcnId) { |
+ return AssemblyFormatter.TokenizeFunctionType(Type, FcnId); |
+ } |
+ |
+ AssemblyTextFormatter::TypeDirective & |
+ TokenizeFunctionSignature(FunctionType *Typ, BitcodeId *FcnId) { |
+ return AssemblyFormatter.TokenizeFunctionSignature(Typ, FcnId); |
+ } |
+ |
+ AssemblyTextFormatter::AbbreviationDirective & |
+ TokenizeAbbreviation(NaClBitCodeAbbrev *Abbrev) { |
+ return AssemblyFormatter.TokenizeAbbreviation(Abbrev); |
+ } |
+ |
+ AssemblyTextFormatter::AbbrevIndexDirective & |
+ TokenizeAbbrevIndex(NaClBitcodeRecord &Record, |
+ unsigned NumGlobalAbbreviations) { |
+ return AssemblyFormatter.TokenizeAbbrevIndex(Record, |
+ NumGlobalAbbreviations); |
+ } |
+ |
+private: |
+ // A placeholder module for associating context and data layout. |
+ Module Mod; |
+ // The output stream to generate disassembly into. |
+ naclbitc::ObjDumpStream &ObjDump; |
+ // Listener used to get abbreviations as they are read. |
+ NaClBitcodeParserListener AbbrevListener; |
+ // DataLayout to use. |
+ const DataLayout DL; |
+ // The set of allowed intrinsics. |
+ PNaClAllowedIntrinsics AllowedIntrinsics; |
+ // The formatter to use to format assembly code. |
+ AssemblyTextFormatter AssemblyFormatter; |
+ // The header appearing before the beginning of the input stream. |
+ NaClBitcodeHeader &Header; |
+ // Pointer to the buffer containing the header. |
+ const unsigned char *HeaderBuffer; |
+ // The list of known types (index i defines the type associated with |
+ // type index i). |
+ std::vector<Type*> TypeIdType; |
+ // The list of known function signatures (index i defines the type |
+ // signature associated with function index i). |
+ std::vector<FunctionType*> FunctionIdType; |
+ // boolean flag defining if function id is an intrinsic. |
+ std::vector<bool> FunctionIdIsIntrinsic; |
+ // The list of record bit addresses associated with corresponding |
+ // declaration of function IDs. |
+ std::vector<uint64_t> FunctionIdAddress; |
+ // The number of function indices currently defined. |
+ uint32_t NumFunctions; |
+ // The number of global indices currently defined. |
+ uint32_t NumGlobals; |
+ // The expected number of global indices (i.e. value of count record |
+ // in the globals block). |
+ uint32_t ExpectedNumGlobals; |
+ // The list of known parameter types (index i defines the type |
+ // associated with parameter index i). |
+ std::vector<Type*>ParamIdType; |
+ // The number of parameter indices currently defined. |
+ uint32_t NumParams; |
+ std::vector<Type*>ConstantIdType; |
+ // The number of constant indices currently defined. |
+ uint32_t NumConstants; |
+ // The list of known instruction types (index i defines the type |
+ // associated with valued instruction index i). |
+ std::vector<Type*> InstIdType; |
+ // The number of valued instructions currently defined. |
+ uint32_t NumValuedInsts; |
+ // Models an unknown type. |
+ Type *UnknownType; |
+ // Models the pointer type. |
+ Type *PointerType; |
+ // Models a result of a comparison. |
+ Type *ComparisonType; |
+ // Keeps list of function indicies (in the order found in the bitcode) |
+ // that correspond to defined functions. |
+ std::vector<uint32_t> DefinedFunctions; |
+ // The number of function indices currently known to be defined. |
+ uint32_t NumDefinedFunctions; |
+ // Holds the number of global abbreviations defined for each block. |
+ std::map<unsigned, unsigned> GlobalAbbrevsCountMap; |
+}; |
+ |
+BitcodeId NaClDisTopLevelParser::GetBitcodeId(uint32_t Index) { |
+ if (Index < NumFunctions) { |
+ return BitcodeId('f', Index); |
+ } |
+ Index -= NumFunctions; |
+ if (Index < ExpectedNumGlobals) { |
+ return BitcodeId('g', Index); |
+ } |
+ Index -= ExpectedNumGlobals; |
+ if (Index < NumParams) { |
+ return BitcodeId('p', Index); |
+ } |
+ Index -= NumParams; |
+ if (Index < NumConstants) { |
+ return BitcodeId('c', Index); |
+ } |
+ Index -= NumConstants; |
+ return BitcodeId('v', Index); |
+} |
+ |
+Type *NaClDisTopLevelParser::GetValueType(uint32_t Index, bool UnderlyingType) { |
+ uint32_t Idx = Index; |
+ if (Idx < NumFunctions) |
+ return UnderlyingType ? GetFunctionType(Idx) : PointerType; |
+ Idx -= NumFunctions; |
+ if (Idx < ExpectedNumGlobals) |
+ return PointerType; |
+ Idx -= ExpectedNumGlobals; |
+ if (Idx < NumParams) |
+ return GetParamType(Idx); |
+ Idx -= NumParams; |
+ if (Idx < NumConstants) |
+ return GetConstantType(Idx); |
+ Idx -= NumConstants; |
+ return GetInstType(Idx); |
+} |
+ |
+// Base class of all block parsers for the bitcode file. Handles |
+// common actions needed by derived blocks. |
+// |
+// Note: This class also handles blocks with unknown block ID's. |
+class NaClDisBlockParser : public NaClBitcodeParser { |
+protected: |
+ /// Constructor for the top-level block parser. |
+ NaClDisBlockParser(unsigned BlockID, NaClDisTopLevelParser *Context) |
+ : NaClBitcodeParser(BlockID, Context), |
+ Context(Context){ |
+ InitAbbreviations(); |
+ } |
+ |
+ /// Constructor for nested block parsers. |
+ NaClDisBlockParser(unsigned BlockID, NaClDisBlockParser *EnclosingParser) |
+ : NaClBitcodeParser(BlockID, EnclosingParser), |
+ Context(EnclosingParser->Context) { |
+ InitAbbreviations(); |
+ } |
+ |
+public: |
+ |
+ ~NaClDisBlockParser() override { |
+ // Be sure to flush any remaining errors reported at end of block. |
+ ObjDumpFlush(); |
+ } |
+ |
+ bool ParseBlock(unsigned BlockID) override; |
+ |
+protected: |
+ void EnterBlock(unsigned NumWords) override; |
+ |
+ void ExitBlock() override; |
+ |
+ void ProcessRecord() override; |
+ |
+ void ProcessAbbreviation(unsigned BlockID, NaClBitCodeAbbrev *Abbrev, |
+ bool IsLocal) override; |
+ |
+ void InitAbbreviations() { |
+ NumGlobalAbbreviations = Context->GetNumGlobalAbbreviations(GetBlockID()); |
+ NumLocalAbbreviations = 0; |
+ } |
+ |
+ // Prints the block header instruction for the block. Called by EnterBlock. |
+ virtual void PrintBlockHeader(); |
+ |
+ // Dumps the corresponding record for a block enter. |
+ void DumpEnterBlockRecord(); |
+ |
+ // Returns the identifier for the next local abbreviation appearing in |
+ // the block. |
+ BitcodeId NextLocalAbbreviationId() { |
+ return BitcodeId('a', NumLocalAbbreviations, false); |
+ } |
+ |
+ AssemblyTextFormatter::AbbrevIndexDirective &TokenizeAbbrevIndex() { |
+ return Context->TokenizeAbbrevIndex(Record, NumGlobalAbbreviations); |
+ } |
+ |
+ // ***************************************************************** |
+ // The following are dispatching methods that call the corresponding |
+ // method on the Context (i.e. NaClDisTopLevelParser). |
+ // ***************************************************************** |
+ |
+ /// Returns a directive to tokenize the given type. |
+ AssemblyTextFormatter::TypeDirective &TokenizeType(Type *Type) { |
+ return Context->TokenizeType(Type); |
+ } |
+ |
+ /// Returns a directive to tokenize the given function type, |
+ /// using the given function id. |
+ AssemblyTextFormatter::TypeDirective |
+ &TokenizeFunctionType(FunctionType *Type, BitcodeId *FcnId) { |
+ return Context->TokenizeFunctionType(Type, FcnId); |
+ } |
+ |
+ /// Returns a directive to tokenize the function signature, given the |
+ /// type of the function signature, and the given function id. |
+ AssemblyTextFormatter::TypeDirective |
+ &TokenizeFunctionSignature(FunctionType *Typ, BitcodeId *FcnId) { |
+ return Context->TokenizeFunctionSignature(Typ, FcnId); |
+ } |
+ |
+ AssemblyTextFormatter::AbbreviationDirective &TokenizeAbbreviation( |
+ NaClBitCodeAbbrev *Abbrev) { |
+ return Context->TokenizeAbbreviation(Abbrev); |
+ } |
+ |
+ naclbitc::TokenTextDirective &Semicolon() { |
+ return Context->Semicolon(); |
+ } |
+ |
+ naclbitc::TokenTextDirective &Colon() { |
+ return Context->Colon(); |
+ } |
+ |
+ naclbitc::SpaceTextDirective &Space() { |
+ return Context->Space(); |
+ } |
+ |
+ naclbitc::TokenTextDirective &Comma() { |
+ return Context->Comma(); |
+ } |
+ |
+ naclbitc::OpenTextDirective &OpenParen() { |
+ return Context->OpenParen(); |
+ } |
+ |
+ |
+ naclbitc::CloseTextDirective &CloseParen() { |
+ return Context->CloseParen(); |
+ } |
+ |
+ naclbitc::OpenTextDirective &OpenAngle() { |
+ return Context->OpenAngle(); |
+ } |
+ |
+ naclbitc::CloseTextDirective &CloseAngle() { |
+ return Context->CloseAngle(); |
+ } |
+ |
+ naclbitc::OpenTextDirective &OpenCurly() { |
+ return Context->OpenCurly(); |
+ } |
+ |
+ naclbitc::CloseTextDirective &CloseCurly() { |
+ return Context->CloseCurly(); |
+ } |
+ |
+ naclbitc::OpenTextDirective &OpenSquare() { |
+ return Context->OpenSquare(); |
+ } |
+ |
+ naclbitc::CloseTextDirective &CloseSquare() { |
+ return Context->CloseSquare(); |
+ } |
+ |
+ naclbitc::EndlineTextDirective &Endline() { |
+ return Context->Endline(); |
+ } |
+ |
+ naclbitc::StartClusteringDirective &StartCluster() { |
+ return Context->StartCluster(); |
+ } |
+ |
+ naclbitc::FinishClusteringDirective &FinishCluster() { |
+ return Context->FinishCluster(); |
+ } |
+ |
+ raw_ostream &Tokens() { |
+ return Context->Tokens(); |
+ } |
+ |
+ raw_ostream &Errors() { |
+ return Context->Errors(); |
+ } |
+ |
+ raw_ostream &Warnings() { |
+ return Context->Warnings(); |
+ } |
+ |
+ void Fatal() { |
+ return Context->Fatal(); |
+ } |
+ |
+ void Fatal(const std::string &Message) { |
+ return Context->Fatal(Message); |
+ } |
+ |
+ const std::string &GetAssemblyIndent() const { |
+ return Context->GetAssemblyIndent(); |
+ } |
+ |
+ unsigned GetAssemblyNumTabs() const { |
+ return Context->GetAssemblyNumTabs(); |
+ } |
+ |
+ void IncAssemblyIndent() { |
+ Context->IncAssemblyIndent(); |
+ } |
+ |
+ void DecAssemblyIndent() { |
+ Context->DecAssemblyIndent(); |
+ } |
+ |
+ void IncRecordIndent() { |
+ Context->IncRecordIndent(); |
+ } |
+ |
+ void DecRecordIndent() { |
+ Context->DecRecordIndent(); |
+ } |
+ |
+ void ObjDumpFlush() { |
+ Context->ObjDumpFlush(); |
+ } |
+ |
+ void ObjDumpWrite(uint64_t Bit, |
+ const NaClBitcodeRecordData &Record, |
+ int32_t AbbrevIndex = |
+ naclbitc::ABBREV_INDEX_NOT_SPECIFIED) { |
+ Context->ObjDumpWrite(Bit, Record, AbbrevIndex); |
+ } |
+ |
+ void ObjDumpWrite(uint64_t Bit, |
+ const NaClBitcodeRecord &Record) { |
+ Context->ObjDumpWrite(Bit, Record); |
+ } |
+ |
+ void ObjDumpSetRecordBitAddress(uint64_t Bit) { |
+ Context->ObjDumpSetRecordBitAddress(Bit); |
+ } |
+ |
+ void InstallType(Type *Ty) { |
+ Context->InstallType(Ty); |
+ } |
+ |
+ Type *GetType(uint32_t Index) { |
+ return Context->GetType(Index); |
+ } |
+ |
+ uint32_t GetNumTypes() const { |
+ return Context->GetNumTypes(); |
+ } |
+ |
+ bool isValidValueType(Type *Ty) const { |
+ return Context->isValidValueType(Ty); |
+ } |
+ |
+ FunctionType *GetFunctionType(uint32_t Index) { |
+ return Context->GetFunctionType(Index); |
+ } |
+ |
+ uint32_t GetNumFunctions() const { |
+ return Context->GetNumFunctions(); |
+ } |
+ |
+ void IncNumGlobals() { |
+ Context->IncNumGlobals(); |
+ } |
+ |
+ uint32_t GetNumGlobals() const { |
+ return Context->GetNumGlobals(); |
+ } |
+ |
+ void InstallFunctionType(FunctionType *Ty) { |
+ return Context->InstallFunctionType(Ty, Record.GetStartBit()); |
+ } |
+ |
+ void InstallDefinedFunction(uint32_t Index) { |
+ Context->InstallDefinedFunction(Index); |
+ } |
+ |
+ BitcodeId GetBitcodeId(uint32_t Id) { |
+ return Context->GetBitcodeId(Id); |
+ } |
+ |
+ void InstallParamType(Type *Ty) { |
+ Context->InstallParamType(Ty); |
+ } |
+ |
+ uint32_t GetNumParams() const { |
+ return Context->GetNumParams(); |
+ } |
+ void InstallConstantType(Type *ConstantType) { |
+ Context->InstallConstantType(ConstantType); |
+ } |
+ |
+ Type *GetConstantType(uint32_t Index) { |
+ return Context->GetConstantType(Index); |
+ } |
+ |
+ uint32_t GetNumConstants() const { |
+ return Context->GetNumConstants(); |
+ } |
+ |
+ void InstallInstType(Type *Ty, uint32_t Index) { |
+ Context->InstallInstType(Ty, Index); |
+ } |
+ |
+ void InstallInstType(Type *Ty) { |
+ Context->InstallInstType(Ty); |
+ } |
+ |
+ uint32_t GetNumValuedInstructions() const { |
+ return Context->GetNumValuedInstructions(); |
+ } |
+ |
+ Type *GetValueType(uint32_t Id, bool UnderlyingType = false) { |
+ return Context->GetValueType(Id, UnderlyingType); |
+ } |
+ |
+ Type *GetFunctionValueType(uint32_t Id) { |
+ return GetValueType(Id, /* UnderlyingType = */ true); |
+ } |
+ |
+ Type *GetUnknownType() const { |
+ return Context->GetUnknownType(); |
+ } |
+ |
+ Type *GetPointerType() const { |
+ return Context->GetPointerType(); |
+ } |
+ |
+ Type *GetComparisonType() const { |
+ return Context->GetComparisonType(); |
+ } |
+ |
+ Type *GetVoidType() const { |
+ return Context->GetVoidType(); |
+ } |
+ |
+ Type *GetFloatType() const { |
+ return Context->GetFloatType(); |
+ } |
+ |
+ Type *GetDoubleType() const { |
+ return Context->GetDoubleType(); |
+ } |
+ |
+ Type *GetIntegerType(unsigned Size) const { |
+ return Context->GetIntegerType(Size); |
+ } |
+ |
+ const char *VerifyIntArithmeticOp(const char *Op, Type *OpTy) { |
+ return Context->VerifyIntArithmeticOp(Op, OpTy); |
+ } |
+ |
+protected: |
+ // The context parser that contains decoding state. |
+ NaClDisTopLevelParser *Context; |
+ // The number of global abbreviations defined for this block. |
+ unsigned NumGlobalAbbreviations; |
+ // The current number of local abbreviations defined for this block. |
+ unsigned NumLocalAbbreviations; |
+}; |
+ |
+bool NaClDisBlockParser::ParseBlock(unsigned BlockId) { |
+ // Only called if we don't know the details about the block. |
+ ObjDumpSetRecordBitAddress(GetBlock().GetStartBit()); |
+ Errors() << "Don't know how to parse block " << BlockId |
+ << ", when in block " << GetBlockID() << "\n"; |
+ NaClDisBlockParser Parser(BlockId, this); |
+ return Parser.ParseThisBlock(); |
+} |
+ |
+void NaClDisBlockParser::PrintBlockHeader() { |
+ Errors() << "Unknown block id found: " << GetBlockID() << "\n"; |
+ Tokens() << "unknown" << Space() << OpenCurly() |
+ << Space() << Space() << "// BlockID = " |
+ << GetBlockID() << Endline(); |
+} |
+ |
+void NaClDisBlockParser::EnterBlock(unsigned NumWords) { |
+ PrintBlockHeader(); |
+ DumpEnterBlockRecord(); |
+ IncRecordIndent(); |
+ IncAssemblyIndent(); |
+} |
+ |
+void NaClDisBlockParser::ExitBlock() { |
+ DecAssemblyIndent(); |
+ DecRecordIndent(); |
+ Tokens() << CloseCurly() << Endline(); |
+ NaClBitcodeRecordData Exit; |
+ Exit.Code = naclbitc::BLK_CODE_EXIT; |
+ ObjDumpWrite(Record.GetStartBit(), Exit, naclbitc::END_BLOCK); |
+} |
+ |
+void NaClDisBlockParser::DumpEnterBlockRecord() { |
+ // TODO(kschimpf): Better integrate this with the bitstream reader |
+ // (which currently doesn't build any records). |
+ NaClBitcodeRecordData Enter; |
+ Enter.Code = naclbitc::BLK_CODE_ENTER; |
+ Enter.Values.push_back(GetBlockID()); |
+ Enter.Values.push_back(Record.GetCursor().getAbbrevIDWidth()); |
+ ObjDumpWrite(GetBlock().GetStartBit(), Enter, naclbitc::ENTER_SUBBLOCK); |
+} |
+ |
+void NaClDisBlockParser::ProcessAbbreviation(unsigned BlockID, |
+ NaClBitCodeAbbrev *Abbrev, |
+ bool IsLocal) { |
+ Tokens() << NextLocalAbbreviationId() << Space() << "=" << Space() |
+ << "abbrev" << Space() << TokenizeAbbreviation(Abbrev) |
+ << Semicolon() << Endline(); |
+ ++NumLocalAbbreviations; |
+ ObjDumpWrite(Record.GetStartBit(), Record); |
+} |
+ |
+void NaClDisBlockParser::ProcessRecord() { |
+ // Note: Only called if block is not understood. Hence, we |
+ // only report the records. |
+ ObjDumpWrite(Record.GetStartBit(), Record); |
+} |
+ |
+/// Parses and disassembles the blockinfo block. |
+class NaClDisBlockInfoParser : public NaClDisBlockParser { |
+public: |
+ NaClDisBlockInfoParser(unsigned BlockID, |
+ NaClDisBlockParser *EnclosingParser) |
+ : NaClDisBlockParser(BlockID, EnclosingParser) { |
+ } |
+ |
+ ~NaClDisBlockInfoParser() override {} |
+ |
+private: |
+ void PrintBlockHeader() override; |
+ |
+ void SetBID() override; |
+ |
+ void ProcessAbbreviation(unsigned BlockID, NaClBitCodeAbbrev *Abbrev, |
+ bool IsLocal) override; |
+ |
+ /// Returns the abbreviation id for the next global abbreviation |
+ /// to be defined for the given block id. |
+ BitcodeId NextGlobalAbbreviationId(unsigned BlockID) { |
+ return BitcodeId('a', Context->GetNumGlobalAbbreviations(BlockID), true); |
+ } |
+}; |
+ |
+void NaClDisBlockInfoParser::PrintBlockHeader() { |
+ Tokens() << "abbreviations" << Space() << OpenCurly() |
+ << Space() << Space() << "// BlockID = " |
+ << GetBlockID() << Endline(); |
+} |
+ |
+void NaClDisBlockInfoParser::SetBID() { |
+ std::string BlockName; |
+ uint64_t BlockID = Record.GetValues()[0]; |
+ switch (BlockID) { |
+ case naclbitc::MODULE_BLOCK_ID: |
+ Tokens() << "module"; |
+ break; |
+ case naclbitc::CONSTANTS_BLOCK_ID: |
+ Tokens() << "constants"; |
+ break; |
+ case naclbitc::FUNCTION_BLOCK_ID: |
+ Tokens() << "function"; |
+ break; |
+ case naclbitc::VALUE_SYMTAB_BLOCK_ID: |
+ Tokens() << "valuesymtab"; |
+ break; |
+ case naclbitc::TYPE_BLOCK_ID_NEW: |
+ Tokens() << "types"; |
+ break; |
+ case naclbitc::GLOBALVAR_BLOCK_ID: |
+ Tokens() << "globals"; |
+ break; |
+ default: |
+ Tokens() << "block" << OpenParen() << BlockID << CloseParen(); |
+ Errors() << "Block id " << BlockID << " not understood.\n"; |
+ break; |
+ } |
+ Tokens() << Colon() << Endline(); |
+ ObjDumpWrite(Record.GetStartBit(), Record); |
+} |
+ |
+void NaClDisBlockInfoParser::ProcessAbbreviation(unsigned BlockID, |
+ NaClBitCodeAbbrev *Abbrev, |
+ bool IsLocal) { |
+ IncAssemblyIndent(); |
+ Tokens() << NextGlobalAbbreviationId(BlockID) << Space() << "=" << Space() |
+ << "abbrev" << Space() << TokenizeAbbreviation(Abbrev) |
+ << Semicolon() << Endline(); |
+ Context->IncNumGlobalAbbreviations(BlockID); |
+ DecAssemblyIndent(); |
+ ObjDumpWrite(Record.GetStartBit(), Record); |
+} |
+ |
+/// Parses and disassembles the types block. |
+class NaClDisTypesParser : public NaClDisBlockParser { |
+public: |
+ NaClDisTypesParser(unsigned BlockID, |
+ NaClDisBlockParser *EnclosingParser) |
+ : NaClDisBlockParser(BlockID, EnclosingParser), |
+ ExpectedNumTypes(0), |
+ IsFirstRecord(true) |
+ { |
+ } |
+ |
+ ~NaClDisTypesParser() override; |
+ |
+private: |
+ void PrintBlockHeader() override; |
+ |
+ void ProcessRecord() override; |
+ |
+ /// Returns the value id for the next type to be defined. |
+ BitcodeId NextTypeId() { |
+ return BitcodeId('t', GetNumTypes()); |
+ } |
+ |
+ // Installs unknown type as definition of next type. |
+ void InstallUnknownTypeForNextId(); |
+ |
+ |
+ uint32_t ExpectedNumTypes; |
+ bool IsFirstRecord; |
+}; |
+ |
+NaClDisTypesParser::~NaClDisTypesParser() { |
+ if (GetNumTypes() != ExpectedNumTypes) { |
+ Errors() << "Expected " << ExpectedNumTypes << " types but found: " |
+ << GetNumTypes() << "\n"; |
+ } |
+} |
+ |
+void NaClDisTypesParser::PrintBlockHeader() { |
+ Tokens() << "types" << Space() << OpenCurly() |
+ << Space() << Space() << "// BlockID = " << GetBlockID() |
+ << Endline(); |
+} |
+ |
+void NaClDisTypesParser::InstallUnknownTypeForNextId() { |
+ Type *UnknownType = GetUnknownType(); |
+ Tokens() << NextTypeId() << Space() << "=" << Space() |
+ << TokenizeType(UnknownType) << Semicolon() |
+ << TokenizeAbbrevIndex() << Endline(); |
+ InstallType(UnknownType); |
+} |
+ |
+void NaClDisTypesParser::ProcessRecord() { |
+ ObjDumpSetRecordBitAddress(Record.GetStartBit()); |
+ const NaClBitcodeRecord::RecordVector &Values = Record.GetValues(); |
+ switch (Record.GetCode()) { |
+ case naclbitc::TYPE_CODE_NUMENTRY: { |
+ // NUMENTRY: [numentries] |
+ uint64_t Size = 0; |
+ if (Values.size() == 1) { |
+ Size = Values[0]; |
+ } else { |
+ Errors() << "Count record should have 1 argument. Found: " |
+ << Values.size() << "\n"; |
+ } |
+ if (!IsFirstRecord) { |
+ Errors() << "Count record not first record of types block\n"; |
+ } |
+ Tokens() << "count" << Space() << Size << Semicolon() |
+ << TokenizeAbbrevIndex() << Endline(); |
+ ExpectedNumTypes = Size; |
+ break; |
+ } |
+ case naclbitc::TYPE_CODE_VOID: { |
+ // VOID |
+ if (!Values.empty()) |
+ Errors() << "Void record shouldn't have arguments. Found: " |
+ << Values.size() << "\n"; |
+ Type *VoidType = GetVoidType(); |
+ Tokens() << NextTypeId() << Space() << "=" << Space() |
+ << TokenizeType(VoidType) << Semicolon() |
+ << TokenizeAbbrevIndex() << Endline(); |
+ InstallType(VoidType); |
+ break; |
+ } |
+ case naclbitc::TYPE_CODE_FLOAT: { |
+ // FLOAT |
+ if (!Values.empty()) |
+ Errors() << "Float record shoudn't have arguments. Found: " |
+ << Values.size() << "\n"; |
+ Type *FloatType = GetFloatType(); |
+ Tokens() << NextTypeId() << Space() << "=" << Space() |
+ << TokenizeType(FloatType) << Semicolon() |
+ << TokenizeAbbrevIndex() << Endline(); |
+ InstallType(FloatType); |
+ break; |
+ } |
+ case naclbitc::TYPE_CODE_DOUBLE: { |
+ // DOUBLE |
+ if (!Values.empty()) |
+ Errors() << "Double record shound't have arguments. Found: " |
+ << Values.size() << "\n"; |
+ Type *DoubleType = GetDoubleType(); |
+ Tokens() << NextTypeId() << Space() << "=" << Space() |
+ << TokenizeType(DoubleType) << Semicolon() |
+ << TokenizeAbbrevIndex() << Endline(); |
+ InstallType(DoubleType); |
+ break; |
+ } |
+ case naclbitc::TYPE_CODE_INTEGER: { |
+ // INTEGER: [width] |
+ uint64_t Size; |
+ if (Values.size() == 1) { |
+ Size = Values[0]; |
+ } else { |
+ Errors() << "Integer record should have one argument. Found: " |
+ << Values.size() << "\n"; |
+ Size = 32; |
+ } |
+ switch (Size) { |
+ case 1: |
+ case 8: |
+ case 16: |
+ case 32: |
+ case 64: { |
+ break; |
+ } |
+ default: |
+ if (!IgnorePNaClABIChecks) { |
+ Errors() << "Integer record contains bad integer size: " |
+ << Size << "\n"; |
+ Size = 32; |
+ } |
+ break; |
+ } |
+ Type *IntType = GetIntegerType(Size); |
+ Tokens() << NextTypeId() << Space() << "=" << Space() |
+ << TokenizeType(IntType) << Semicolon() |
+ << TokenizeAbbrevIndex() << Endline(); |
+ InstallType(IntType); |
+ break; |
+ } |
+ case naclbitc::TYPE_CODE_VECTOR: { |
+ // VECTOR: [numelts, eltty] |
+ if (Values.size() != 2) { |
+ Errors() << "Vector record should contain two arguments. Found: " |
+ << Values.size() << "\n"; |
+ InstallUnknownTypeForNextId(); |
+ break; |
+ } |
+ Type *BaseType = GetType(Values[1]); |
+ if (!(BaseType->isIntegerTy() |
+ || BaseType->isFloatTy() |
+ || BaseType->isDoubleTy())) { |
+ Type *ErrorRecoveryTy = GetIntegerType(32); |
+ Errors() << "Vectors can only be defined on primitive types. Found " |
+ << *BaseType << ". Assuming " << *ErrorRecoveryTy |
+ << " instead.\n"; |
+ BaseType = ErrorRecoveryTy; |
+ } |
+ uint64_t NumElements = Values[0]; |
+ Type *VecType = VectorType::get(BaseType, NumElements); |
+ if (!IgnorePNaClABIChecks && |
+ !PNaClABITypeChecker::isValidVectorType(VecType)) { |
+ Errors() << "Vector type " << *VecType << " not allowed.\n"; |
+ } |
+ Tokens() << NextTypeId() << Space() << "=" << Space() |
+ << TokenizeType(VecType) << Semicolon() |
+ << TokenizeAbbrevIndex() << Endline(); |
+ InstallType(VecType); |
+ break; |
+ } |
+ case naclbitc::TYPE_CODE_FUNCTION: { |
+ // FUNCTION: [vararg, retty, paramty x N] |
+ if (Values.size() < 2) { |
+ Errors() |
+ << "Function record should contain at least 2 arguments. Found: " |
+ << Values.size() << "\n"; |
+ InstallUnknownTypeForNextId(); |
+ break; |
+ } |
+ if (Values[0]) { |
+ Errors() << "Functions with variable length arguments is not supported\n"; |
+ } |
+ Type *ReturnType = GetType(Values[1]); |
+ if (!(isValidValueType(ReturnType) || ReturnType->isVoidTy())) { |
+ Type *ReplaceType = GetIntegerType(32); |
+ Errors() << "Invalid return type. Found: " << *ReturnType |
+ << ". Assuming: " << *ReplaceType << "\n"; |
+ ReturnType = ReplaceType; |
+ } |
+ SmallVector<Type*, 8> Signature; |
+ for (size_t i = 2; i < Values.size(); ++i) { |
+ Type *Ty = GetType(Values[i]); |
+ if (!isValidValueType(Ty)) { |
+ Type *ReplaceTy = GetIntegerType(32); |
+ Errors() << "Invalid type for parameter " << (i - 1) << ". Found: " |
+ << *Ty << ". Assuming: " << *ReplaceTy << "\n"; |
+ Ty = ReplaceTy; |
+ } |
+ Signature.push_back(Ty); |
+ } |
+ Type *FcnType = FunctionType::get(ReturnType, Signature, Values[0]); |
+ Tokens() << NextTypeId() << Space() << "=" << Space() |
+ << StartCluster() << TokenizeType(FcnType) |
+ << Semicolon() << FinishCluster() << TokenizeAbbrevIndex() |
+ << Endline(); |
+ InstallType(FcnType); |
+ break; |
+ } |
+ default: |
+ Errors() << "Unknown record code in types block. Found: " |
+ << Record.GetCode() << "\n"; |
+ break; |
+ } |
+ ObjDumpWrite(Record.GetStartBit(), Record); |
+ IsFirstRecord = false; |
+} |
+ |
+/// Parses and disassembles the globalvars block. |
+class NaClDisGlobalsParser : public NaClDisBlockParser { |
+public: |
+ NaClDisGlobalsParser(unsigned BlockID, |
+ NaClDisBlockParser *EnclosingParser) |
+ : NaClDisBlockParser(BlockID, EnclosingParser), |
+ NumInitializers(0), |
+ InsideCompound(false), |
+ BaseTabs(GetAssemblyNumTabs()+1) {} |
+ |
+ ~NaClDisGlobalsParser() override {} |
+ |
+private: |
+ void PrintBlockHeader() override; |
+ |
+ void ProcessRecord() override; |
+ |
+ void ExitBlock() override; |
+ |
+ // Expected number of initializers associated with last globalvars |
+ // record |
+ uint32_t NumInitializers; |
+ // True if last globalvars record was defined by a compound record. |
+ bool InsideCompound; |
+ // Number of tabs used to indent elements in the globals block. |
+ unsigned BaseTabs; |
+ |
+ // Returns the ID for the next defined global. |
+ BitcodeId NextGlobalId() { |
+ return BitcodeId('g', GetNumGlobals()); |
+ } |
+ |
+ // Prints out the close initializer "}" if necessary, and fixes |
+ // the indentation to match previous indentation. |
+ void InsertCloseInitializer(); |
+ |
+ uint32_t GetExpectedNumGlobals() const { |
+ return Context->GetExpectedNumGlobals(); |
+ } |
+}; |
+ |
+void NaClDisGlobalsParser::PrintBlockHeader() { |
+ Tokens() << "globals" << Space() << OpenCurly() |
+ << Space() << Space() << "// BlockID = " << GetBlockID() |
+ << Endline(); |
+} |
+ |
+void NaClDisGlobalsParser::InsertCloseInitializer() { |
+ if (InsideCompound) { |
+ while (BaseTabs + 1 < GetAssemblyNumTabs()) DecAssemblyIndent(); |
+ Tokens() << CloseCurly() << Endline(); |
+ } |
+ while (BaseTabs < GetAssemblyNumTabs()) DecAssemblyIndent(); |
+ ObjDumpFlush(); |
+ NumInitializers = 0; |
+ InsideCompound = false; |
+} |
+ |
+void NaClDisGlobalsParser::ExitBlock() { |
+ if (NumInitializers > 0) { |
+ BitcodeId LastGlobal('g', (GetNumGlobals()-1)); |
+ Errors() << "More initializers for " << LastGlobal << " expected: " |
+ << NumInitializers << "\n"; |
+ } |
+ if (GetNumGlobals() != GetExpectedNumGlobals()) { |
+ Errors() << "Expected " << GetExpectedNumGlobals() |
+ << " globals but found: " << GetNumGlobals() << "\n"; |
+ } |
+ NaClDisBlockParser::ExitBlock(); |
+} |
+ |
+void NaClDisGlobalsParser::ProcessRecord() { |
+ ObjDumpSetRecordBitAddress(Record.GetStartBit()); |
+ const NaClBitcodeRecord::RecordVector &Values = Record.GetValues(); |
+ switch (Record.GetCode()) { |
+ case naclbitc::GLOBALVAR_VAR: { |
+ // VAR: [align, isconst] |
+ if (Values.size() != 2) { |
+ Errors() << "Globalvar record expects two arguments. Found: " |
+ << Values.size() << "\n"; |
+ break; |
+ } |
+ if (GetNumGlobals() == GetExpectedNumGlobals()) { |
+ Errors() << "Exceeded expected number of globals: " |
+ << GetExpectedNumGlobals() << "\n"; |
+ } |
+ if (NumInitializers > 0) { |
+ Errors() << "Previous initializer list too short. Expects " |
+ << NumInitializers << " more initializers\n"; |
+ InsertCloseInitializer(); |
+ } |
+ uint32_t Alignment = (1 << Values[0]) >> 1; |
+ Tokens() << StartCluster() << (Values[1] ? "const" : "var") |
+ << Space() << NextGlobalId() |
+ << Comma() << FinishCluster() << Space() |
+ << StartCluster() << "align" << Space() << Alignment |
+ << Comma() << FinishCluster() << TokenizeAbbrevIndex() |
+ << Endline(); |
+ IncAssemblyIndent(); |
+ IncNumGlobals(); |
+ NumInitializers = 1; |
+ break; |
+ } |
+ case naclbitc::GLOBALVAR_COMPOUND: |
+ // COMPOUND: [size] |
+ if (Values.size() != 1) { |
+ Errors() << "Compound record expects one argument. Found: " |
+ << Values.size() << "\n"; |
+ break; |
+ } |
+ if (NumInitializers == 1) { |
+ if (InsideCompound) { |
+ Errors() << "Nested initialization records not allowed\n"; |
+ InsertCloseInitializer(); |
+ } |
+ } else { |
+ Errors() << "Compound record must follow globalvars record\n"; |
+ InsertCloseInitializer(); |
+ } |
+ Tokens() << StartCluster() << "initializers" << Space() |
+ << Values[0] << FinishCluster() << Space() |
+ << OpenCurly() << TokenizeAbbrevIndex() << Endline(); |
+ IncAssemblyIndent(); |
+ NumInitializers = Values[0]; |
+ InsideCompound = true; |
+ break; |
+ case naclbitc::GLOBALVAR_ZEROFILL: |
+ // ZEROFILL: [size] |
+ if (Values.size() != 1) { |
+ Errors() << "Zerofill record expects one argument. Found: " |
+ << Values.size() << "\n"; |
+ break; |
+ } |
+ if (NumInitializers == 0) { |
+ Errors() << "Zerofill initializer not associated with globalvar record\n"; |
+ } |
+ Tokens() << "zerofill" << Space() << Values[0] << Semicolon() |
+ << TokenizeAbbrevIndex() << Endline(); |
+ --NumInitializers; |
+ break; |
+ case naclbitc::GLOBALVAR_DATA: { |
+ // DATA: [b0, b1, ...] |
+ if (Values.empty()) { |
+ Errors() << "Globals data record must have arguments.\n"; |
+ } |
+ if (NumInitializers == 0) { |
+ Errors() << "Data initializer not associated with globalvar record\n"; |
+ } |
+ Tokens() << StartCluster() << OpenCurly(); |
+ for (size_t i = 0; i < Values.size(); ++i) { |
+ if (i > 0) Tokens() << Comma() << FinishCluster() << Space(); |
+ uint64_t Byte = Values[i]; |
+ if (Byte >= 256) { |
+ Errors() << "Invalid byte value in data record: " << Byte << "\n"; |
+ Byte &= 0xFF; |
+ } |
+ if (i > 0) Tokens() << StartCluster(); |
+ Tokens() << format("%3u", static_cast<unsigned>(Byte)); |
+ } |
+ Tokens() << CloseCurly() << FinishCluster() << TokenizeAbbrevIndex() |
+ << Endline(); |
+ --NumInitializers; |
+ break; |
+ } |
+ case naclbitc::GLOBALVAR_RELOC: |
+ // RELOC: [val, [addend]] |
+ if (Values.empty() || Values.size() > 2) { |
+ Errors() << "Invalid reloc record size: " << Values.size() << "\n"; |
+ break; |
+ } |
+ if (NumInitializers == 0) { |
+ Errors() << |
+ "Relocation initializer not associated with globalvar record\n"; |
+ } |
+ Tokens() << "reloc" << Space() << StartCluster() << GetBitcodeId(Values[0]); |
+ if (Values.size() == 2) { |
+ int32_t Addend = static_cast<int32_t>(Values[1]); |
+ char Operator = '+'; |
+ if (Addend < 0) { |
+ Operator = '-'; |
+ Addend = -Addend; |
+ } |
+ Tokens() << Space()<< Operator << Space() << Addend; |
+ } |
+ Tokens() << Semicolon() << FinishCluster() << TokenizeAbbrevIndex() |
+ << Endline(); |
+ --NumInitializers; |
+ break; |
+ case naclbitc::GLOBALVAR_COUNT: { |
+ // COUNT: [n] |
+ uint32_t Count = 0; |
+ if (Values.size() == 1) { |
+ Count = Values[0]; |
+ } else { |
+ Errors() << "Globals count record expects one argument. Found: " |
+ << Values.size() << "\n"; |
+ } |
+ if (GetNumGlobals() != 0) |
+ Errors() << "Count record not first record in block.\n"; |
+ Tokens() << "count" << Space() << Count << Semicolon() |
+ << TokenizeAbbrevIndex() << Endline(); |
+ Context->SetExpectedNumGlobals(Count); |
+ break; |
+ } |
+ default: |
+ Errors() << "Unknown record found in globals block.\n"; |
+ } |
+ |
+ ObjDumpWrite(Record.GetStartBit(), Record); |
+ |
+ if (GetNumGlobals() > 0 && NumInitializers == 0) |
+ InsertCloseInitializer(); |
+} |
+ |
+/// Parsers and disassembles a valuesymtab block. |
+class NaClDisValueSymtabParser : public NaClDisBlockParser { |
+public: |
+ NaClDisValueSymtabParser(unsigned BlockID, |
+ NaClDisBlockParser *EnclosingParser) |
+ : NaClDisBlockParser(BlockID, EnclosingParser) { |
+ } |
+ |
+ ~NaClDisValueSymtabParser() override {} |
+ |
+private: |
+ void PrintBlockHeader() override; |
+ |
+ void ProcessRecord() override; |
+ |
+ // Displays the context of the name (in Values) for the given Id. |
+ void DisplayEntry(BitcodeId &Id, |
+ const NaClBitcodeRecord::RecordVector &Values); |
+}; |
+ |
+void NaClDisValueSymtabParser::PrintBlockHeader() { |
+ Tokens() << "valuesymtab" << Space() << OpenCurly() |
+ << Space() << Space() << "// BlockID = " << GetBlockID() |
+ << Endline(); |
+} |
+ |
+void NaClDisValueSymtabParser:: |
+DisplayEntry(BitcodeId &Id, |
+ const NaClBitcodeRecord::RecordVector &Values) { |
+ if (Values.size() <= 1) { |
+ Errors() << "Valuesymtab entry record expects 2 arguments. Found: " |
+ << Values.size() << "\n"; |
+ return; |
+ } |
+ Tokens() << Id << Space() << Colon() << Space(); |
+ // Check if the name of the symbol is alphanumeric. If so, print |
+ // as a string. Otherwise, print a sequence of bytes. |
+ // Note: The check isChar6 is a test for aphanumeric + {'.', '_'}. |
+ bool IsChar6 = true; // Until proven otherwise. |
+ for (size_t i = 1; i < Values.size(); ++i) { |
+ uint64_t Byte = Values[i]; |
+ if (Byte >= 256) { |
+ Errors() << "Argument " << i << " of symbol entry not byte: " |
+ << Byte << "\n"; |
+ IsChar6 = false; |
+ break; |
+ } |
+ if (!NaClBitCodeAbbrevOp::isChar6(Byte)) |
+ IsChar6 = false; |
+ } |
+ if (IsChar6) { |
+ Tokens() << StartCluster() << "\""; |
+ for (size_t i = 1; i < Values.size(); ++i) { |
+ Tokens() << static_cast<char>(Values[i]); |
+ } |
+ Tokens() << "\"" << Semicolon(); |
+ } else { |
+ Tokens() << StartCluster() << OpenCurly(); |
+ for (size_t i = 1; i < Values.size(); ++i) { |
+ if (i > 1) { |
+ Tokens() << Comma() << FinishCluster() << Space() |
+ << StartCluster(); |
+ } |
+ char ch = Values[i]; |
+ if (NaClBitCodeAbbrevOp::isChar6(ch)) { |
+ Tokens() << "'" << ch << "'"; |
+ } else { |
+ Tokens() << format("%3u", static_cast<unsigned>(ch)); |
+ } |
+ } |
+ Tokens() << CloseCurly(); |
+ } |
+ Tokens() << FinishCluster() << TokenizeAbbrevIndex() << Endline(); |
+} |
+ |
+void NaClDisValueSymtabParser::ProcessRecord() { |
+ ObjDumpSetRecordBitAddress(Record.GetStartBit()); |
+ const NaClBitcodeRecord::RecordVector &Values = Record.GetValues(); |
+ switch (Record.GetCode()) { |
+ case naclbitc::VST_CODE_ENTRY: { |
+ // VST_ENTRY: [valueid, namechar x N] |
+ uint32_t ValID = Values[0]; |
+ BitcodeId ID(GetBitcodeId(ValID)); |
+ DisplayEntry(ID, Values); |
+ if (ValID < GetNumFunctions()) { |
+ // Check if value is intrinsic name. If so, verify function signature. |
+ std::string Name; |
+ for (unsigned i = 1; i < Values.size(); ++i) { |
+ Name.push_back(static_cast<char>(Values[i])); |
+ } |
+ FunctionType *IntrinTy = Context->GetIntrinsicType(Name); |
+ if (IntrinTy == 0) |
+ // TODO(kschimpf): Check for _start? Complain about other names? |
+ break; |
+ Context->MarkFunctionAsIntrinsic(ValID); |
+ // Verify that expected intrinsic function type matches declared |
+ // type signature. |
+ FunctionType *FcnTy = GetFunctionType(ValID); |
+ if (FcnTy->getNumParams() != IntrinTy->getNumParams()) { |
+ Errors() << "Intrinsic " << Name |
+ << " expects " << IntrinTy->getNumParams() |
+ << " arguments. Found: " << FcnTy->getNumParams() |
+ << "\n"; |
+ break; |
+ } |
+ if (!IgnorePNaClABIChecks && !PNaClABITypeChecker::IsPointerEquivType( |
+ IntrinTy->getReturnType(), FcnTy->getReturnType())) { |
+ Errors() << "Intrinsic " << Name |
+ << " expects return type " << *IntrinTy->getReturnType() |
+ << ". Found: " << *FcnTy->getReturnType() << "\n"; |
+ break; |
+ } |
+ for (size_t i = 0; i < FcnTy->getNumParams(); ++i) { |
+ if (!IgnorePNaClABIChecks && !PNaClABITypeChecker::IsPointerEquivType( |
+ IntrinTy->getParamType(i), |
+ FcnTy->getParamType(i))) { |
+ Errors() << "Intrinsic " << Name |
+ << " expects " << *IntrinTy->getParamType(i) |
+ << " for argument " << (i+1) << ". Found: " |
+ << *FcnTy->getParamType(i) << "\n"; |
+ break; |
+ } |
+ } |
+ } |
+ break; |
+ } |
+ case naclbitc::VST_CODE_BBENTRY: { |
+ // [bbid, namechar x N] |
+ BitcodeId ID('b', Values[0]); |
+ DisplayEntry(ID, Values); |
+ break; |
+ } |
+ default: |
+ Errors() << "Unknown record in valuesymtab block.\n"; |
+ break; |
+ } |
+ ObjDumpWrite(Record.GetStartBit(), Record); |
+} |
+ |
+/// Parses and disassembles a constants block. |
+class NaClDisConstantsParser : public NaClDisBlockParser { |
+public: |
+ NaClDisConstantsParser(unsigned BlockID, |
+ NaClDisBlockParser *EnclosingParser) |
+ : NaClDisBlockParser(BlockID, EnclosingParser), |
+ ConstantType(0), |
+ BlockTabs(GetAssemblyNumTabs()) {} |
+ |
+ virtual ~NaClDisConstantsParser() { |
+ while (BlockTabs < GetAssemblyNumTabs()) DecAssemblyIndent(); |
+ } |
+ |
+private: |
+ void PrintBlockHeader() override; |
+ |
+ void ProcessRecord() override; |
+ |
+ /// Generates the value id for the next generated constant. |
+ BitcodeId NextConstId() { |
+ return BitcodeId('c', GetNumConstants()); |
+ } |
+ |
+ // The type associated with the constant. |
+ Type *ConstantType; |
+ // The number of tabs used to indent the globals block. |
+ unsigned BlockTabs; |
+}; |
+ |
+void NaClDisConstantsParser::PrintBlockHeader() { |
+ Tokens() << "constants" << Space() << OpenCurly() |
+ << Space() << Space() << "// BlockID = " << GetBlockID() |
+ << Endline(); |
+} |
+ |
+void NaClDisConstantsParser::ProcessRecord() { |
+ ObjDumpSetRecordBitAddress(Record.GetStartBit()); |
+ const NaClBitcodeRecord::RecordVector Values = Record.GetValues(); |
+ switch (Record.GetCode()) { |
+ case naclbitc::CST_CODE_SETTYPE: |
+ // SETTYPE: [typeid] |
+ while (BlockTabs + 1 < GetAssemblyNumTabs()) DecAssemblyIndent(); |
+ if (Values.size() == 1) { |
+ ConstantType = GetType(Values[0]); |
+ Tokens() << TokenizeType(ConstantType) << ":" |
+ << TokenizeAbbrevIndex() << Endline(); |
+ } else { |
+ Errors() << "Settype record should have 1 argument. Found: " |
+ << Values.size() << "\n"; |
+ // Make up a type, so we can continue. |
+ ConstantType = GetIntegerType(32); |
+ } |
+ IncAssemblyIndent(); |
+ break; |
+ case naclbitc::CST_CODE_UNDEF: |
+ // CST_CODE_UNDEF: [] |
+ if (!Values.empty()) { |
+ Errors() << "Undefined record should not have arguments: Found: " |
+ << Values.size() << "\n"; |
+ } |
+ Tokens() << NextConstId() << Space() << "=" << Space() |
+ << StartCluster() << TokenizeType(ConstantType) |
+ << Space() << "undef" |
+ << Semicolon() << FinishCluster() |
+ << TokenizeAbbrevIndex() << Endline(); |
+ InstallConstantType(ConstantType); |
+ break; |
+ case naclbitc::CST_CODE_INTEGER: { |
+ // INTEGER: [intval] |
+ SignRotatedInt Value; |
+ if (Values.size() == 1) { |
+ const SignRotatedInt MyValue(Values[0], ConstantType); |
+ Value = MyValue; |
+ } else { |
+ Errors() << "Integer record should have 1 argument. Found: " |
+ << Values.size() << "\n"; |
+ } |
+ Tokens() << NextConstId() << Space() << "=" << Space() << StartCluster() |
+ << StartCluster() << TokenizeType(ConstantType) << Space() |
+ << Value << Semicolon() << FinishCluster() << FinishCluster() |
+ << TokenizeAbbrevIndex() << Endline(); |
+ InstallConstantType(ConstantType); |
+ break; |
+ } |
+ case naclbitc::CST_CODE_FLOAT: { |
+ // FLOAT: [fpval] |
+ // Define initially with default value zero, in case of errors. |
+ const fltSemantics &FloatRep = |
+ ConstantType->isFloatTy() ? APFloat::IEEEsingle : APFloat::IEEEdouble; |
+ APFloat Value(APFloat::getZero(FloatRep)); |
+ if (Values.size() == 1) { |
+ if (ConstantType->isFloatTy()) { |
+ Value = APFloat(FloatRep, APInt(32, static_cast<uint32_t>(Values[0]))); |
+ } |
+ else if (ConstantType->isDoubleTy()) { |
+ Value = APFloat(FloatRep, APInt(64, Values[0])); |
+ } else { |
+ Errors() << "Bad floating point constant argument: " |
+ << Values[0] << "\n"; |
+ } |
+ } else { |
+ Errors() << "Float record should have 1 argument. Found: " |
+ << Values.size() << "\n"; |
+ } |
+ Tokens() << NextConstId() << Space() << "=" << Space() << StartCluster() |
+ << TokenizeType(ConstantType) << Space(); |
+ if (ConstantType->isFloatTy()) { |
+ Tokens() << format("%g", Value.convertToFloat()); |
+ } else { |
+ Tokens() << format("%g", Value.convertToDouble()); |
+ } |
+ Tokens() << Semicolon() << FinishCluster() |
+ << TokenizeAbbrevIndex() << Endline(); |
+ InstallConstantType(ConstantType); |
+ break; |
+ } |
+ default: |
+ Errors() << "Unknown record in valuesymtab block.\n"; |
+ break; |
+ } |
+ ObjDumpWrite(Record.GetStartBit(), Record); |
+} |
+ |
+/// Parses and disassembles function blocks. |
+class NaClDisFunctionParser : public NaClDisBlockParser { |
+public: |
+ NaClDisFunctionParser(unsigned BlockID, |
+ NaClDisBlockParser *EnclosingParser); |
+ |
+ ~NaClDisFunctionParser() override {} |
+ |
+ void PrintBlockHeader() override; |
+ |
+ bool ParseBlock(unsigned BlockID) override; |
+ |
+ void ProcessRecord() override; |
+ |
+ /// Returns the absolute value index of the first instruction that |
+ /// generates a value in the defined function. |
+ uint32_t FirstValuedInstructionId() const { |
+ return GetNumFunctions() + GetNumGlobals() + GetNumParams() |
+ + GetNumConstants(); |
+ } |
+ |
+ /// Converts an instruction index to the corresponding absolute value |
+ /// index. |
+ uint32_t ValuedInstToAbsId(uint32_t Id) const { |
+ return FirstValuedInstructionId() + Id; |
+ } |
+ |
+ /// Converts the (function) relative index to the corresponding |
+ /// absolute value index. |
+ uint32_t RelativeToAbsId(int32_t Id) { |
+ uint32_t AbsNextId = ValuedInstToAbsId(GetNumValuedInstructions()); |
+ if (Id > 0 && AbsNextId < static_cast<uint32_t>(Id)) { |
+ Errors() << "Invalid relative value id: " << Id |
+ << " (Must be <= " << AbsNextId << ")\n"; |
+ AbsNextId = Id; |
+ } |
+ return AbsNextId - Id; |
+ } |
+ |
+ /// Converts the given absolute value index to a corresponding |
+ /// valued instruction index. |
+ uint32_t AbsToValuedInstId(uint32_t Id) const { |
+ return Id - FirstValuedInstructionId(); |
+ } |
+ |
+ /// Returns the text representation of the encoded binary operator, |
+ /// assuming the binary operator is operating on the given type. |
+ /// Generates appropriate error messages if the given type is not |
+ // allowed for the given Opcode. |
+ const char *GetBinop(uint32_t Opcode, Type *Type); |
+ |
+ /// Returns the text representation of the encoded cast operator. |
+ /// Generates appropriate error messages if the given Opcode is |
+ /// not allowed for the given types. |
+ const char *GetCastOp(uint32_t Opcode, Type *FromType, Type *ToType); |
+ |
+ /// Returns the text representation of the encoded integer compare |
+ /// predicate. Generates appropriate error message if the given |
+ /// Opcode is not defined. |
+ const char *GetIcmpPredicate(uint32_t Opcode); |
+ |
+ /// Returns the text representation of the encoded floating point |
+ /// compare predicate. Generates appropriate error message if the |
+ /// given Opcode is not defined. |
+ const char *GetFcmpPredicate(uint32_t Opcode); |
+ |
+ /// Returns the value id for the next instruction to be defined. |
+ BitcodeId NextInstId() const { |
+ return BitcodeId('v', GetNumValuedInstructions()); |
+ } |
+ |
+private: |
+ // The function index of the function being defined. |
+ uint32_t FcnId; |
+ // The function type for the function being defined. |
+ FunctionType *FcnTy; |
+ // The current basic block being printed. |
+ int32_t CurrentBbIndex; |
+ // The expected number of basic blocks. |
+ uint64_t ExpectedNumBbs; |
+ // True if the previously printed instruction was a terminating |
+ // instruction. Used to figure out where to insert block labels. |
+ bool InstIsTerminating; |
+ |
+ /// Returns scalar type of vector type Ty, if vector type. Otherwise |
+ /// returns Ty. |
+ Type *UnderlyingType(Type *Ty) { |
+ return Ty->isVectorTy() ? Ty->getVectorElementType() : Ty; |
+ } |
+ |
+ bool isFloatingType(Type *Ty) { |
+ return Ty->isFloatTy() || Ty->isDoubleTy(); |
+ } |
+ |
+ /// Verifies that OpTy is an integer, or a vector of integers, for |
+ /// operator Op. Generates error messages if appropriate. Returns Op. |
+ const char *VerifyIntegerOrVectorOp(const char *Op, Type *OpTy) { |
+ Type *BaseTy = OpTy; |
+ if (OpTy->isVectorTy()) { |
+ if (!IgnorePNaClABIChecks && |
+ !PNaClABITypeChecker::isValidVectorType(OpTy)) { |
+ Errors() << Op << ": invalid vector type: " << *OpTy << "\n"; |
+ return Op; |
+ } |
+ BaseTy = OpTy->getVectorElementType(); |
+ } |
+ if (BaseTy->isIntegerTy()) { |
+ if (IgnorePNaClABIChecks || |
+ PNaClABITypeChecker::isValidScalarType(BaseTy)) { |
+ return Op; |
+ } |
+ Errors() << Op << ": Invalid integer type: " << *OpTy << "\n"; |
+ } else { |
+ Errors() << Op << ": Expects integer type. Found: " << *OpTy << "\n"; |
+ } |
+ return Op; |
+ } |
+ |
+ /// Verifies that Opty is a floating point type, or a vector of a |
+ /// floating points, for operator Op. Generates error messages if |
+ /// appropriate. Returns Op. |
+ const char *VerifyFloatingOrVectorOp(const char *Op, Type *OpTy) { |
+ Type *BaseTy = OpTy; |
+ if (OpTy->isVectorTy()) { |
+ if (!IgnorePNaClABIChecks && |
+ !PNaClABITypeChecker::isValidVectorType(OpTy)) { |
+ Errors() << Op << ": invalid vector type: " << *OpTy << "\n"; |
+ return Op; |
+ } |
+ BaseTy = OpTy->getVectorElementType(); |
+ } |
+ if (!isFloatingType(BaseTy)) { |
+ Errors() << Op << ": Expects floating point. Found " |
+ << OpTy << "\n"; |
+ return Op; |
+ } |
+ if (!IgnorePNaClABIChecks && |
+ !PNaClABITypeChecker::isValidScalarType(BaseTy)) { |
+ Errors() << Op << ": type not allowed: " << OpTy << "\n"; |
+ } |
+ return Op; |
+ } |
+ |
+ /// Op is the name of the operation that called this. Checks if |
+ /// OpTy is either a (non-void) scalar, or a vector of scalars. If |
+ /// not, generates an appropriate error message. Always returns Op. |
+ const char *VerifyScalarOrVectorOp(const char *Op, Type *OpTy) { |
+ if (IgnorePNaClABIChecks) return Op; |
+ if (PNaClABITypeChecker::isValidScalarType(OpTy)) { |
+ if (OpTy->isVoidTy()) |
+ Errors() << Op << ": Type void not allowed\n"; |
+ } else if (!PNaClABITypeChecker::isValidVectorType(OpTy)) { |
+ Errors() << Op << ": Expects scalar/vector type. Found: " |
+ << OpTy << "\n"; |
+ } |
+ return Op; |
+ } |
+ |
+ void VerifyIndexedVector(const char *Op, uint32_t VecValue, |
+ uint32_t IdxValue) { |
+ Type *VecType = GetValueType(VecValue); |
+ Type *IdxType = GetValueType(IdxValue); |
+ if (!IgnorePNaClABIChecks && |
+ !PNaClABITypeChecker::isValidVectorType(VecType)){ |
+ if (VecType->isVectorTy()) |
+ Errors() << Op << ": Vector type " << *VecType << " not allowed\n"; |
+ else |
+ Errors() << Op << ": Vector type expected. Found: " << *VecType << "\n"; |
+ } |
+ // Note: This restriction appears to be LLVM specific. |
+ if (!IdxType->isIntegerTy(32)) { |
+ Errors() << Op << ": Index not i32. Found: " << *IdxType << "\n"; |
+ } |
+ BitcodeId IdxId(GetBitcodeId(IdxValue)); |
+ if (IdxId.GetKind() != 'c') { |
+ Errors() << Op << ": Vector index not constant: " << IdxId << "\n"; |
+ // TODO(kschimpf): We should check that Idx is a constant with |
+ // valid access. However, we currently don't store constant |
+ // values, so it can't be tested. |
+ } |
+ } |
+ |
+ /// Checks if block Value is a valid branch target for the current |
+ /// function block. If not, generates an appropriate error message. |
+ void VerifyBranchRange(uint64_t Value) { |
+ if (0 == Value || Value >= ExpectedNumBbs) { |
+ Errors() << "Branch " << BitcodeId('b', Value) |
+ << " out of range. Not in [1," << ExpectedNumBbs << "]\n"; |
+ } |
+ } |
+ |
+ /// Convert alignment exponent (i.e. power of two (or zero)) to the |
+ /// corresponding alignment to use. If alignment is too large, it generates |
+ /// an error message and returns 0. |
+ unsigned getAlignmentValue(uint64_t Exponent); |
+}; |
+ |
+NaClDisFunctionParser::NaClDisFunctionParser( |
+ unsigned BlockID, |
+ NaClDisBlockParser *EnclosingParser) |
+ : NaClDisBlockParser(BlockID, EnclosingParser), |
+ CurrentBbIndex(-1), |
+ ExpectedNumBbs(0), |
+ InstIsTerminating(false) { |
+ Context->ResetLocalCounters(); |
+ if (Context->HasNextDefinedFunctionIndex()) { |
+ FcnId = Context->GetNextDefinedFunctionIndex(); |
+ FcnTy = GetFunctionType(FcnId); |
+ } else { |
+ FcnId = 0; |
+ SmallVector<Type*, 8> Signature; |
+ FcnTy = FunctionType::get(GetVoidType(), Signature, 0); |
+ Errors() << |
+ "No corresponding defining function address for function block.\n"; |
+ return; |
+ } |
+ Context->IncNumDefinedFunctions(); |
+ |
+ // Now install parameters. |
+ for (size_t Index = 0; Index < FcnTy->getFunctionNumParams(); ++Index) { |
+ InstallParamType(FcnTy->getFunctionParamType(Index)); |
+ } |
+} |
+ |
+void NaClDisFunctionParser::PrintBlockHeader() { |
+ Tokens() << "function" << Space(); |
+ BitcodeId FunctionId('f', FcnId); |
+ bool InvalidSignature = true; // until proven otherwise. |
+ if (Context->IsFunctionIntrinsic(FcnId)) |
+ InvalidSignature = false; |
+ else if (IgnorePNaClABIChecks || |
+ PNaClABITypeChecker::isValidFunctionType(FcnTy)) { |
+ InvalidSignature = false; |
+ } |
+ if (InvalidSignature) { |
+ Errors() << "Invalid type signature for " |
+ << BitcodeId('f', FcnId) << ": " << *FcnTy << "\n"; |
+ } |
+ Tokens() << TokenizeFunctionSignature(FcnTy, &FunctionId) |
+ << Space() << OpenCurly() |
+ << Space() << Space() << "// BlockID = " << GetBlockID() |
+ << Endline(); |
+} |
+ |
+const char *NaClDisFunctionParser::GetBinop(uint32_t Opcode, Type *Ty) { |
+ Instruction::BinaryOps LLVMOpcode; |
+ if (!naclbitc::DecodeBinaryOpcode(Opcode, Ty, LLVMOpcode)) { |
+ Errors() << "Binary opcode not understood: " << Opcode << "\n"; |
+ return "???"; |
+ } |
+ switch (LLVMOpcode) { |
+ default: |
+ Errors() << "Binary opcode not understood: " << Opcode << "\n"; |
+ return "???"; |
+ case Instruction::Add: |
+ return VerifyIntArithmeticOp("add", Ty); |
+ case Instruction::FAdd: |
+ return VerifyFloatingOrVectorOp("fadd", Ty); |
+ case Instruction::Sub: |
+ return VerifyIntArithmeticOp("sub", Ty); |
+ case Instruction::FSub: |
+ return VerifyFloatingOrVectorOp("fsub", Ty); |
+ case Instruction::Mul: |
+ return VerifyIntArithmeticOp("mul", Ty); |
+ case Instruction::FMul: |
+ return VerifyFloatingOrVectorOp("fmul", Ty); |
+ case Instruction::UDiv: |
+ return VerifyIntArithmeticOp("udiv", Ty); |
+ case Instruction::SDiv: |
+ return VerifyIntArithmeticOp("sdiv", Ty); |
+ case Instruction::FDiv: |
+ return VerifyFloatingOrVectorOp("fdiv", Ty); |
+ case Instruction::URem: |
+ return VerifyIntArithmeticOp("urem", Ty); |
+ case Instruction::SRem: |
+ return VerifyIntArithmeticOp("srem", Ty); |
+ case Instruction::FRem: |
+ return VerifyFloatingOrVectorOp("frem", Ty); |
+ case Instruction::Shl: |
+ return VerifyIntArithmeticOp("shl", Ty); |
+ case Instruction::LShr: |
+ return VerifyIntArithmeticOp("lshr", Ty); |
+ case Instruction::AShr: |
+ return VerifyIntArithmeticOp("ashr", Ty); |
+ case Instruction::And: |
+ return VerifyIntegerOrVectorOp("and", Ty); |
+ case Instruction::Or: |
+ return VerifyIntegerOrVectorOp("or", Ty); |
+ case Instruction::Xor: |
+ return VerifyIntegerOrVectorOp("xor", Ty); |
+ } |
+} |
+ |
+const char *NaClDisFunctionParser::GetCastOp(uint32_t Opcode, |
+ Type *FromType, Type *ToType) { |
+ Instruction::CastOps Cast; |
+ const char *CastName = "???"; |
+ if (!naclbitc::DecodeCastOpcode(Opcode, Cast)) { |
+ Errors() << "Cast opcode not understood: " << Opcode << "\n"; |
+ return CastName; |
+ } |
+ switch (Cast) { |
+ default: |
+ Errors() << "Cast opcode not understood: " << Opcode << "\n"; |
+ return CastName; |
+ case Instruction::BitCast: |
+ CastName = "bitcast"; |
+ break; |
+ case Instruction::Trunc: |
+ CastName = "trunc"; |
+ break; |
+ case Instruction::ZExt: |
+ CastName = "zext"; |
+ break; |
+ case Instruction::SExt: |
+ CastName = "sext"; |
+ break; |
+ case Instruction::FPToUI: |
+ CastName = "fptoui"; |
+ break; |
+ case Instruction::FPToSI: |
+ CastName = "fptosi"; |
+ break; |
+ case Instruction::UIToFP: |
+ CastName = "uitofp"; |
+ break; |
+ case Instruction::SIToFP: |
+ CastName = "sitofp"; |
+ break; |
+ case Instruction::FPTrunc: |
+ CastName = "fptrunc"; |
+ break; |
+ case Instruction::FPExt: |
+ CastName = "fpext"; |
+ break; |
+ } |
+ if (!CastInst::castIsValid(Cast, FromType, ToType)) { |
+ Errors() << "Invalid cast '" << CastName << "'. Not defined on " |
+ << FromType << " to " << ToType << "\n"; |
+ } |
+ return CastName; |
+} |
+ |
+const char *NaClDisFunctionParser::GetIcmpPredicate(uint32_t Opcode) { |
+ CmpInst::Predicate Predicate; |
+ if (!naclbitc::DecodeIcmpPredicate(Opcode, Predicate)) { |
+ Errors() << "Icmp predicate not understood: " << Opcode << "\n"; |
+ return "???"; |
+ } |
+ switch (Predicate) { |
+ default: |
+ Errors() << "Icmp predicate not understood: " << Opcode << "\n"; |
+ return "???"; |
+ case CmpInst::ICMP_EQ: |
+ return "eq"; |
+ case CmpInst::ICMP_NE: |
+ return "ne"; |
+ case CmpInst::ICMP_UGT: |
+ return "ugt"; |
+ case CmpInst::ICMP_UGE: |
+ return "uge"; |
+ case CmpInst::ICMP_ULT: |
+ return "ult"; |
+ case CmpInst::ICMP_ULE: |
+ return "ule"; |
+ case CmpInst::ICMP_SGT: |
+ return "sgt"; |
+ case CmpInst::ICMP_SGE: |
+ return "sge"; |
+ case CmpInst::ICMP_SLT: |
+ return "slt"; |
+ case CmpInst::ICMP_SLE: |
+ return "sle"; |
+ } |
+} |
+ |
+const char *NaClDisFunctionParser::GetFcmpPredicate(uint32_t Opcode) { |
+ CmpInst::Predicate Predicate; |
+ if (!naclbitc::DecodeFcmpPredicate(Opcode, Predicate)) { |
+ Errors() << "Fcmp predicate not understood: " << Opcode << "\n"; |
+ return "???"; |
+ } |
+ switch (Predicate) { |
+ default: |
+ Errors() << "Fcmp predicate not understood: " << Opcode << "\n"; |
+ return "???"; |
+ case CmpInst::FCMP_FALSE: |
+ return "false"; |
+ case CmpInst::FCMP_OEQ: |
+ return "oeq"; |
+ case CmpInst::FCMP_OGT: |
+ return "ogt"; |
+ case CmpInst::FCMP_OGE: |
+ return "oge"; |
+ case CmpInst::FCMP_OLT: |
+ return "olt"; |
+ case CmpInst::FCMP_OLE: |
+ return "ole"; |
+ case CmpInst::FCMP_ONE: |
+ return "one"; |
+ case CmpInst::FCMP_ORD: |
+ return "ord"; |
+ case CmpInst::FCMP_UNO: |
+ return "uno"; |
+ case CmpInst::FCMP_UEQ: |
+ return "ueq"; |
+ case CmpInst::FCMP_UGT: |
+ return "ugt"; |
+ case CmpInst::FCMP_UGE: |
+ return "uge"; |
+ case CmpInst::FCMP_ULT: |
+ return "ult"; |
+ case CmpInst::FCMP_ULE: |
+ return "ule"; |
+ case CmpInst::FCMP_UNE: |
+ return "une"; |
+ case CmpInst::FCMP_TRUE: |
+ return "true"; |
+ } |
+} |
+ |
+namespace { |
+ |
+static const unsigned MaxAlignmentExponent = 29; |
+static_assert( |
+ (1u << MaxAlignmentExponent) == Value::MaximumAlignment, |
+ "Inconsistency between Value.MaxAlignment and PNaCl alignment limit"); |
+} |
+ |
+unsigned NaClDisFunctionParser::getAlignmentValue(uint64_t Exponent) { |
+ if (Exponent > MaxAlignmentExponent + 1) { |
+ Errors() << "Alignment can't be greater than 2**" << MaxAlignmentExponent |
+ << ". Found: 2**" << (Exponent - 1) << "\n"; |
+ return 0; |
+ } |
+ return (1 << static_cast<unsigned>(Exponent)) >> 1; |
+} |
+ |
+bool NaClDisFunctionParser::ParseBlock(unsigned BlockID) { |
+ ObjDumpSetRecordBitAddress(GetBlock().GetStartBit()); |
+ switch (BlockID) { |
+ case naclbitc::CONSTANTS_BLOCK_ID: { |
+ NaClDisConstantsParser Parser(BlockID, this); |
+ return Parser.ParseThisBlock(); |
+ } |
+ case naclbitc::VALUE_SYMTAB_BLOCK_ID: { |
+ if (!PNaClAllowLocalSymbolTables) break; |
+ NaClDisValueSymtabParser Parser(BlockID, this); |
+ return Parser.ParseThisBlock(); |
+ } |
+ default: |
+ break; |
+ } |
+ return NaClDisBlockParser::ParseBlock(BlockID); |
+} |
+ |
+void NaClDisFunctionParser::ProcessRecord() { |
+ ObjDumpSetRecordBitAddress(Record.GetStartBit()); |
+ const NaClBitcodeRecord::RecordVector Values = Record.GetValues(); |
+ // Start by adding block label if previous instruction is terminating. |
+ if (InstIsTerminating) { |
+ InstIsTerminating = false; |
+ ++CurrentBbIndex; |
+ DecAssemblyIndent(); |
+ Tokens() << BitcodeId('b', CurrentBbIndex) << ":" << Endline(); |
+ ObjDumpFlush(); |
+ IncAssemblyIndent(); |
+ } |
+ switch (Record.GetCode()) { |
+ case naclbitc::FUNC_CODE_DECLAREBLOCKS: |
+ // DECLAREBLOCKS: [n] |
+ InstIsTerminating = true; // Force block label on first instruction. |
+ if (Values.size() != 1) { |
+ Errors() << "Function blocks record expects a size argument.\n"; |
+ break; |
+ } |
+ ExpectedNumBbs = Values[0]; |
+ if (ExpectedNumBbs == 0) { |
+ Errors() << "Functions must contain at least one block.\n"; |
+ } |
+ Tokens() << "blocks" << Space() << ExpectedNumBbs << Semicolon(); |
+ break; |
+ case naclbitc::FUNC_CODE_INST_BINOP: { |
+ // BINOP: [opval, opval, opcode] |
+ if (Values.size() != 3) { |
+ Errors() << "Binop record expects 3 arguments. Found: " |
+ << Values.size() << "\n"; |
+ break; |
+ } |
+ uint32_t Op1 = RelativeToAbsId(Values[0]); |
+ uint32_t Op2 = RelativeToAbsId(Values[1]); |
+ Type *Type1 = GetValueType(Op1); |
+ Type *Type2 = GetValueType(Op2); |
+ if (Type1 != Type2) { |
+ Errors() << "Binop argument types differ: " << *Type1 << " and " |
+ << *Type2 << "\n"; |
+ } |
+ const char *Binop = GetBinop(Values[2], Type1); |
+ Tokens() << NextInstId() << Space() << "=" << Space() << Binop << Space() |
+ << TokenizeType(Type1) << Space() << GetBitcodeId(Op1) << Comma() |
+ << Space() << GetBitcodeId(Op2) << Semicolon(); |
+ InstallInstType(Type1); |
+ break; |
+ } |
+ case naclbitc::FUNC_CODE_INST_CAST: { |
+ // CAST: [opval, destty, castopc] |
+ if (Values.size() != 3) { |
+ Errors() << "Cast record expects 3 argments. Found: " |
+ << Values.size() << "\n"; |
+ break; |
+ } |
+ uint32_t Op = RelativeToAbsId(Values[0]); |
+ Type *FromType = GetValueType(Op); |
+ Type *ToType = GetType(Values[1]); |
+ const char *CastOp = GetCastOp(Values[2], FromType, ToType); |
+ Tokens() << NextInstId() << Space() << "=" << Space() << CastOp << Space() |
+ << TokenizeType(FromType) << Space() << GetBitcodeId(Op) |
+ << Space() << "to" << Space() << TokenizeType(ToType) |
+ << Semicolon(); |
+ InstallInstType(ToType); |
+ break; |
+ } |
+ case naclbitc::FUNC_CODE_INST_RET: { |
+ // RET: [opval?] |
+ InstIsTerminating = true; |
+ Tokens() << "ret" << Space(); |
+ switch (Values.size()) { |
+ default: |
+ Errors() << "Function return record expects an optional return argument. " |
+ << "Found: " << Values.size() << " arguments\n"; |
+ break; |
+ case 0: |
+ Tokens() << "void"; |
+ break; |
+ case 1: { |
+ uint32_t Op = RelativeToAbsId(Values[0]); |
+ Tokens() << TokenizeType(GetValueType(Op)) << Space()<< GetBitcodeId(Op); |
+ break; |
+ } |
+ } |
+ Tokens() << Semicolon(); |
+ break; |
+ } |
+ case naclbitc::FUNC_CODE_INST_BR: { |
+ // BR: [bb#, bb#, opval] or [bb#] |
+ InstIsTerminating = true; |
+ if (Values.size() != 1 && Values.size() != 3) { |
+ Errors() << "Function branch record expects 1 or 3 arguments. Found: " |
+ << Values.size() << "\n"; |
+ break; |
+ } |
+ Tokens() << "br" << Space(); |
+ if (Values.size() == 3) { |
+ uint32_t OpIndex = RelativeToAbsId(Values[2]); |
+ if (GetValueType(OpIndex) != GetComparisonType()) |
+ Errors() << "Branch condition not i1\n"; |
+ Tokens() << StartCluster() << "i1" << Space() << GetBitcodeId(OpIndex) |
+ << Comma() << FinishCluster() << Space(); |
+ } |
+ VerifyBranchRange(Values[0]); |
+ Tokens() << StartCluster() << "label" << Space() |
+ << BitcodeId('b', Values[0]); |
+ if (Values.size() == 3) { |
+ VerifyBranchRange(Values[1]); |
+ Tokens() << Comma() << FinishCluster() << Space() |
+ << StartCluster() << "label" << Space() |
+ << BitcodeId('b', Values[1]); |
+ } |
+ Tokens() << Semicolon() << FinishCluster(); |
+ break; |
+ } |
+ case naclbitc::FUNC_CODE_INST_SWITCH: { |
+ // SWITCH: [opty, op, bb#, n, (1, 1, int, bb#)*] |
+ InstIsTerminating = true; |
+ if (Values.size() < 4) { |
+ Errors() |
+ << "Function switch record expects at least 4 arguments. Found: " |
+ << Values.size() << "\n"; |
+ break; |
+ } |
+ Type *OpType = GetType(Values[0]); |
+ uint32_t CondId = RelativeToAbsId(Values[1]); |
+ Type *CondType = GetValueType(CondId); |
+ if (OpType != CondType) |
+ Errors() << "Specified select type " << *OpType << " but found: " |
+ << *CondType << "\n"; |
+ if (!IgnorePNaClABIChecks && |
+ !PNaClABITypeChecker::isValidSwitchConditionType(CondType)) { |
+ Errors() << PNaClABITypeChecker::ExpectedSwitchConditionType(CondType) |
+ << "\n"; |
+ } |
+ uint32_t DefaultBb = Values[2]; |
+ unsigned NumCases = Values[3]; |
+ VerifyBranchRange(DefaultBb); |
+ Tokens() << "switch" << Space() << StartCluster() << StartCluster() |
+ << TokenizeType(OpType) << Space() << GetBitcodeId(CondId) |
+ << FinishCluster() << Space() << "{" << FinishCluster() |
+ << Endline(); |
+ IncAssemblyIndent(); |
+ Tokens() << StartCluster() << "default" << ":" << Space() |
+ << FinishCluster() << StartCluster() << "br" << Space() << "label" |
+ << Space() << BitcodeId('b', DefaultBb) << Semicolon() |
+ << FinishCluster() << Endline(); |
+ unsigned CurIdx = 4; |
+ for (unsigned i = 0; i < NumCases; ++i) { |
+ unsigned NumItems = Values[CurIdx++]; |
+ bool IsSingleNumber = Values[CurIdx++]; |
+ if (NumItems != 1 || !IsSingleNumber) { |
+ Errors() << "Case ranges are not supported in PNaCl\n"; |
+ break; |
+ } |
+ SignRotatedInt CaseValue(Values[CurIdx++], OpType); |
+ // TODO(kschimpf) Check if CaseValue possible based on OpType. |
+ uint64_t Label = Values[CurIdx++]; |
+ VerifyBranchRange(Label); |
+ Tokens() << StartCluster() << TokenizeType(OpType) << Space() |
+ << CaseValue << ":" << Space() << FinishCluster() |
+ << StartCluster() << "br" << Space() << "label" << Space() |
+ << BitcodeId('b', Label) << Semicolon() << FinishCluster() |
+ << Endline(); |
+ } |
+ DecAssemblyIndent(); |
+ Tokens() << "}"; |
+ break; |
+ } |
+ case naclbitc::FUNC_CODE_INST_UNREACHABLE: |
+ // UNREACHABLE |
+ InstIsTerminating = true; |
+ if (!Values.empty()) { |
+ Errors() << "Function unreachable record expects no arguments. Found: " |
+ << Values.size() << "\n"; |
+ } |
+ Tokens() << "unreachable" << Semicolon(); |
+ break; |
+ case naclbitc::FUNC_CODE_INST_PHI: { |
+ // PHI: [ty, (val0, bb0)*] |
+ if (Values.size() < 3) { |
+ Errors() << "Function phi record expects at least 3 arguments. Found: " |
+ << Values.size() << "\n"; |
+ break; |
+ } else if (Values.size() % 2 == 0) { |
+ Errors() |
+ << "Function phi records should have an odd number of arguments. " |
+ << "Found: " << Values.size() << "\n"; |
+ } |
+ Type* OpType = GetType(Values[0]); |
+ Tokens() << NextInstId() << Space() << "=" << StartCluster() << Space() |
+ << "phi" << Space() << TokenizeType(OpType); |
+ for (size_t i = 1; i < Values.size(); i += 2) { |
+ if (i > 1) Tokens() << Comma(); |
+ uint32_t Index = RelativeToAbsId(NaClDecodeSignRotatedValue(Values[i])); |
+ Tokens() << FinishCluster() << Space() << StartCluster() << OpenSquare() |
+ << GetBitcodeId(Index) << Comma() << Space() |
+ << BitcodeId('b', Values[i+1]) << CloseSquare(); |
+ } |
+ Tokens() << Semicolon() << FinishCluster(); |
+ InstallInstType(OpType); |
+ break; |
+ }; |
+ case naclbitc::FUNC_CODE_INST_ALLOCA: { |
+ // ALLOCA: [size, align] |
+ if (Values.size() != 2) { |
+ Errors() << "Function alloca record expects 2 arguments. Found: " |
+ << Values.size() << "\n"; |
+ break; |
+ } |
+ uint32_t SizeOp = RelativeToAbsId(Values[0]); |
+ Type* SizeType = GetValueType(SizeOp); |
+ BitcodeId SizeId(GetBitcodeId(SizeOp)); |
+ unsigned Alignment = getAlignmentValue(Values[1]); |
+ if (!IgnorePNaClABIChecks && !PNaClABIProps::isAllocaSizeType(SizeType)) |
+ Errors() << PNaClABIProps::ExpectedAllocaSizeType() << "\n"; |
+ // TODO(kschimpf) Are there any constraints on alignment? |
+ Tokens() << NextInstId() << Space() << "=" << Space() << StartCluster() |
+ << "alloca" << Space() << "i8" << Comma() << FinishCluster() |
+ << Space() << StartCluster() << TokenizeType(SizeType) << Space() |
+ << SizeId << Comma() << FinishCluster() << Space() |
+ << StartCluster() <<"align" << Space() << Alignment << Semicolon() |
+ << FinishCluster(); |
+ InstallInstType(GetPointerType()); |
+ break; |
+ } |
+ case naclbitc::FUNC_CODE_INST_LOAD: { |
+ // LOAD: [op, align, ty] |
+ if (Values.size() != 3) { |
+ Errors() << "Function load record expects 3 arguments. Found: " |
+ << Values.size() << "\n"; |
+ break; |
+ } |
+ unsigned Alignment = getAlignmentValue(Values[1]); |
+ Type *LoadType = GetType(Values[2]); |
+ VerifyScalarOrVectorOp("load", LoadType); |
+ Context->VerifyMemoryAccessAlignment("load", LoadType, Alignment); |
+ Tokens() << NextInstId() << Space() << "=" << Space() << StartCluster() |
+ << "load" << Space() << TokenizeType(LoadType) << "*" << Space() |
+ << GetBitcodeId(RelativeToAbsId(Values[0])) << Comma() |
+ << FinishCluster() << Space() << StartCluster() |
+ << "align" << Space() << Alignment << Semicolon() |
+ << FinishCluster(); |
+ InstallInstType(LoadType); |
+ break; |
+ } |
+ case naclbitc::FUNC_CODE_INST_STORE: { |
+ // STORE: [ptr, val, align] |
+ if (Values.size() != 3) { |
+ Errors() << "Function store record expects 3 arguments. Found: " |
+ << Values.size() << "\n"; |
+ break; |
+ } |
+ unsigned Alignment = getAlignmentValue(Values[2]); |
+ uint32_t Val = RelativeToAbsId(Values[1]); |
+ Type *ValType = GetValueType(Val); |
+ VerifyScalarOrVectorOp("store", ValType); |
+ Context->VerifyMemoryAccessAlignment("store", ValType, Alignment); |
+ Tokens() << StartCluster() << "store" << Space() << TokenizeType(ValType) |
+ << Space() << GetBitcodeId(Val) << Comma() << FinishCluster() |
+ << Space() << StartCluster() << TokenizeType(ValType) << "*" |
+ << Space() << GetBitcodeId(RelativeToAbsId(Values[0])) << Comma() |
+ << FinishCluster() << Space() << StartCluster() << "align" |
+ << Space() << Alignment << Semicolon() << FinishCluster(); |
+ break; |
+ } |
+ case naclbitc::FUNC_CODE_INST_CMP2: { |
+ // CMP2: [opval, opval, pred] |
+ if (Values.size() != 3) { |
+ Errors() << "Function compare record expects 3 arguments. Found: " |
+ << Values.size() << "\n"; |
+ break; |
+ } |
+ uint32_t Arg1 = RelativeToAbsId(Values[0]); |
+ uint32_t Arg2 = RelativeToAbsId(Values[1]); |
+ Type *Arg1Type = GetValueType(Arg1); |
+ Type *Arg2Type = GetValueType(Arg2); |
+ if (Arg1Type != Arg2Type) { |
+ Errors() << "Arguments not of same type: " << *Arg1Type << " and " |
+ << *Arg2Type << "\n"; |
+ } |
+ const char *Pred = "???"; |
+ Tokens() << NextInstId() << Space() << "=" << Space() << StartCluster(); |
+ Type* BaseType = UnderlyingType(Arg1Type); |
+ if (BaseType->isIntegerTy()) { |
+ Pred = GetIcmpPredicate(Values[2]); |
+ Tokens() << "icmp" << Space() << Pred; |
+ } else if (isFloatingType(BaseType)) { |
+ Pred = GetFcmpPredicate(Values[2]); |
+ Tokens() << "fcmp" << Space() << Pred; |
+ } else { |
+ Errors() << "Compare not on integer/float type. Found: " |
+ << *Arg1Type << "\n"; |
+ Tokens() << "cmp" << Space() << "???" "(" << Values[2] << ")"; |
+ } |
+ Tokens() << FinishCluster() << Space() << StartCluster() |
+ << TokenizeType(Arg1Type) << Space () << GetBitcodeId(Arg1) |
+ << Comma() << FinishCluster() << Space() << StartCluster() |
+ << GetBitcodeId(Arg2) << Semicolon() << FinishCluster(); |
+ Type *ResultType = GetComparisonType(); |
+ if (Arg1Type->isVectorTy()) { |
+ ResultType = VectorType::get(ResultType, |
+ Arg1Type->getVectorNumElements()); |
+ } |
+ InstallInstType(ResultType); |
+ break; |
+ } |
+ case naclbitc::FUNC_CODE_INST_VSELECT: { |
+ // VSELECT: [opval, opval, pred] |
+ if (Values.size() != 3) { |
+ Errors() << "Select record expects 3 arguments. Found: " |
+ << Values.size() << "\n"; |
+ break; |
+ } |
+ uint32_t CondValue = RelativeToAbsId(Values[2]); |
+ uint32_t ThenValue = RelativeToAbsId(Values[0]); |
+ uint32_t ElseValue = RelativeToAbsId(Values[1]); |
+ Type *CondType = GetValueType(CondValue); |
+ Type *ThenType = GetValueType(ThenValue); |
+ Type *ElseType = GetValueType(ElseValue); |
+ if (ThenType != ElseType) { |
+ Errors() << "Selected arguments not of same type: " |
+ << *ThenType << " and " << *ElseType << "\n"; |
+ } |
+ Type *BaseType = UnderlyingType(ThenType); |
+ if (!(BaseType->isIntegerTy() || isFloatingType(BaseType))) { |
+ Errors() << "Select arguments not integer/float. Found: " << *ThenType; |
+ } |
+ Tokens() << NextInstId() << Space() << "=" << Space() << StartCluster() |
+ << "select" << Space() << TokenizeType(CondType) << Space() |
+ << GetBitcodeId(CondValue) << Comma() << FinishCluster() << Space() |
+ << StartCluster() << TokenizeType(ThenType) << Space() |
+ << GetBitcodeId(ThenValue) << Comma() << FinishCluster() << Space() |
+ << StartCluster() << TokenizeType(ElseType) << Space() |
+ << GetBitcodeId(ElseValue) << Semicolon() |
+ << FinishCluster(); |
+ InstallInstType(ThenType); |
+ break; |
+ } |
+ case naclbitc::FUNC_CODE_INST_EXTRACTELT: { |
+ // EXTRACTELT: [opval, opval] |
+ if (Values.size() != 2) { |
+ Errors() << "Extract element record expects 2 arguments. Found: " |
+ << Values.size() << "\n"; |
+ break; |
+ } |
+ uint32_t VecValue = RelativeToAbsId(Values[0]); |
+ uint32_t IdxValue = RelativeToAbsId(Values[1]); |
+ VerifyIndexedVector("extractelement", VecValue, IdxValue); |
+ Type *VecType = GetValueType(VecValue); |
+ Type *IdxType = GetValueType(IdxValue); |
+ Tokens() << NextInstId() << Space() << " = " << Space() << StartCluster() |
+ << "extractelement" << Space() << TokenizeType(VecType) << Space() |
+ << GetBitcodeId(VecValue) << Comma() << FinishCluster() << Space() |
+ << StartCluster() << TokenizeType(IdxType) << Space() |
+ << GetBitcodeId(IdxValue) << Semicolon() << FinishCluster(); |
+ InstallInstType(UnderlyingType(VecType)); |
+ break; |
+ } |
+ case naclbitc::FUNC_CODE_INST_INSERTELT: { |
+ // INSERTELT: [opval, opval, opval] |
+ uint32_t VecValue = RelativeToAbsId(Values[0]); |
+ uint32_t EltValue = RelativeToAbsId(Values[1]); |
+ uint32_t IdxValue = RelativeToAbsId(Values[2]); |
+ VerifyIndexedVector("insertelement", VecValue, IdxValue); |
+ Type *VecType = GetValueType(VecValue); |
+ Type *EltType = GetValueType(EltValue); |
+ Type *IdxType = GetValueType(IdxValue); |
+ if (EltType != UnderlyingType(VecType)) { |
+ Errors() << "insertelement: Illegal element type " << *EltType |
+ << ". Expected: " << *UnderlyingType(VecType) << "\n"; |
+ } |
+ Tokens() << NextInstId() << Space() << " = " << Space() << StartCluster() |
+ << "insertelement" << Space() << TokenizeType(VecType) << Space() |
+ << GetBitcodeId(VecValue) << Comma() << FinishCluster() << Space() |
+ << StartCluster() << TokenizeType(EltType) << Space() |
+ << GetBitcodeId(EltValue) << Comma() << FinishCluster() << Space() |
+ << StartCluster() << TokenizeType(IdxType) << Space() |
+ << GetBitcodeId(IdxValue) << Semicolon() << FinishCluster(); |
+ InstallInstType(VecType); |
+ break; |
+ } |
+ case naclbitc::FUNC_CODE_INST_CALL: |
+ case naclbitc::FUNC_CODE_INST_CALL_INDIRECT: { |
+ // CALL: [cc, fnid, arg0, arg1...] |
+ // CALL_INDIRECT: [cc, fnid, returnty, args...] |
+ if (Record.GetCode() == naclbitc::FUNC_CODE_INST_CALL) { |
+ if (Values.size() < 2) { |
+ Errors() << "Call record expects at least 2 arguments. Found: " |
+ << Values.size() << "\n"; |
+ break; |
+ } |
+ } else if (Record.GetCode() == naclbitc::FUNC_CODE_INST_CALL_INDIRECT) { |
+ if (Values.size() < 3) { |
+ Errors() << "Call indirect record expects at least 3 arguments. Found: " |
+ << Values.size() << "\n"; |
+ break; |
+ } |
+ } |
+ unsigned IsTailCall = (Values[0] & 0x1); |
+ CallingConv::ID CallingConv; |
+ uint32_t FcnId = RelativeToAbsId(Values[1]); |
+ if (!naclbitc::DecodeCallingConv(Values[0]>>1, CallingConv)) |
+ Errors() << "Call unknown calling convention:" << (Values[0]>>1) << "\n"; |
+ if (!IgnorePNaClABIChecks && |
+ !PNaClABIProps::isValidCallingConv(CallingConv)) { |
+ Errors() << "Call uses disallowed calling convention: " |
+ << PNaClABIProps::CallingConvName(CallingConv) << "(" |
+ << CallingConv << ")\n"; |
+ } |
+ FunctionType *FcnType = 0; |
+ Type *ReturnType = 0; |
+ size_t ArgIndex = 2; |
+ // Flag defining if type checking should be done on argument/return |
+ // types. |
+ bool CheckArgRetTypes = true; |
+ if (Record.GetCode() == naclbitc::FUNC_CODE_INST_CALL) { |
+ Type *FcnTy = GetFunctionValueType(FcnId); |
+ if (FunctionType *FcnTyp = dyn_cast<FunctionType>(FcnTy)) { |
+ // TODO(kschimpf) Add back signature checking once we know how |
+ // to handle intrinsics (which can violate general signature |
+ // rules). |
+ CheckArgRetTypes = false; |
+ FcnType = FcnTyp; |
+ ReturnType = FcnType->getReturnType(); |
+ } else { |
+ Errors() << "Invalid function signature: " << *FcnTy << "\n"; |
+ ReturnType = GetVoidType(); |
+ } |
+ } else { |
+ ReturnType = GetType(Values[2]); |
+ ArgIndex = 3; |
+ } |
+ if (!ReturnType->isVoidTy()) { |
+ Tokens() << NextInstId() << Space() << "=" << Space(); |
+ } |
+ if (IsTailCall) { |
+ Tokens() << "tail" << Space(); |
+ } |
+ if (CheckArgRetTypes && |
+ !IgnorePNaClABIChecks && |
+ !PNaClABITypeChecker::isValidParamType(ReturnType)) { |
+ Errors() << "Invalid return type: " << *ReturnType << "\n"; |
+ } |
+ Tokens() << "call" << Space(); |
+ if (CallingConv != CallingConv::C) { |
+ Tokens() << PNaClABIProps::CallingConvName(CallingConv) << Space(); |
+ } |
+ Tokens() << TokenizeType(ReturnType) << Space() |
+ << StartCluster() << GetBitcodeId(FcnId) << OpenParen() |
+ << StartCluster(); |
+ unsigned ParamIndex = 0; |
+ unsigned NumParams = Values.size() + 1 - ArgIndex; |
+ for (size_t i = ArgIndex; i < Values.size(); ++i, ++ParamIndex) { |
+ uint32_t ParamId = RelativeToAbsId(Values[i]); |
+ Type *ParamType = GetValueType(ParamId); |
+ if (CheckArgRetTypes && |
+ !IgnorePNaClABIChecks && |
+ !PNaClABITypeChecker::isValidParamType(ParamType)) { |
+ Errors() << "invalid type for parameter " << i << ": " |
+ << *ParamType << "\n"; |
+ } |
+ if (FcnType) { |
+ if (ParamIndex < FcnType->getNumParams()) { |
+ Type *ExpectedType = FcnType->getParamType(ParamIndex); |
+ if (ParamType != ExpectedType) { |
+ Warnings() << "Parameter " << (ParamIndex + 1) << " mismatch: " |
+ << *ParamType << " and " << *ExpectedType << "\n"; |
+ } |
+ } |
+ else if (ParamIndex == FcnType->getNumParams()) { |
+ Warnings() << "Call expects " << FcnType->getNumParams() |
+ << " arguments. Got: " << NumParams << "\n"; |
+ } |
+ } |
+ if (i > ArgIndex) { |
+ Tokens() << Comma() << FinishCluster() << Space() << StartCluster(); |
+ } |
+ Tokens() << TokenizeType(ParamType) << Space() << GetBitcodeId(ParamId); |
+ } |
+ Tokens() << CloseParen() << Semicolon() << FinishCluster() |
+ << FinishCluster(); |
+ if (!ReturnType->isVoidTy()) InstallInstType(ReturnType); |
+ break; |
+ } |
+ case naclbitc::FUNC_CODE_INST_FORWARDTYPEREF: { |
+ // TYPE: [opval, ty] |
+ if (Values.size() != 2) { |
+ Errors() << "Forward declare record expects 2 arguments. Found: " |
+ << Values.size() << "\n"; |
+ break; |
+ } |
+ Type *OpType = GetType(Values[1]); |
+ Tokens() << "declare" << Space() << StartCluster() |
+ << TokenizeType(OpType) << Space() |
+ << GetBitcodeId(Values[0]) << Semicolon() << FinishCluster(); |
+ InstallInstType(OpType, AbsToValuedInstId(Values[0])); |
+ break; |
+ } |
+ default: |
+ Errors() << "Unknown record found in module block.\n"; |
+ break; |
+ } |
+ Tokens() << TokenizeAbbrevIndex() << Endline(); |
+ ObjDumpWrite(Record.GetStartBit(), Record); |
+} |
+ |
+/// Parses and disassembles the module block. |
+class NaClDisModuleParser : public NaClDisBlockParser { |
+public: |
+ NaClDisModuleParser(unsigned BlockID, NaClDisTopLevelParser *Context) |
+ : NaClDisBlockParser(BlockID, Context) { |
+ } |
+ |
+ ~NaClDisModuleParser() override; |
+ |
+ bool ParseBlock(unsigned BlockID) override; |
+ |
+ void PrintBlockHeader() override; |
+ |
+ void ProcessRecord() override; |
+}; |
+ |
+NaClDisModuleParser::~NaClDisModuleParser() { |
+ // Note: Since we can't check type signatures of most functions till |
+ // we know intrinsic names, and that isn't known until the (optional) |
+ // valuesymtab block is parsed, the only reasonable spot to check |
+ // function signatures is once the module block has been processed. |
+ unsigned NextFcnDefinedId = 0; |
+ for (unsigned i = 0, e = GetNumFunctions(); i < e; ++i) { |
+ // Note: If the type of a function isn't a function type, that |
+ // was checked in method ProcessRecord. |
+ // Note: If the function was defined, the type was checked in |
+ // NaClDisFunctionParser::PrintBlockHeader. |
+ if (Context->HasDefinedFunctionIndex(NextFcnDefinedId) |
+ && i == Context->GetDefinedFunctionIndex(NextFcnDefinedId)) { |
+ ++NextFcnDefinedId; |
+ continue; |
+ } |
+ if (FunctionType *FcnTy = dyn_cast<FunctionType>(GetFunctionValueType(i))) { |
+ if (!Context->IsFunctionIntrinsic(i) && |
+ !IgnorePNaClABIChecks && |
+ !PNaClABITypeChecker::isValidFunctionType(FcnTy)) { |
+ Context->SetRecordAddressToFunctionIdAddress(i); |
+ Errors() << "Invalid type signature for " |
+ << BitcodeId('f', i) << ": " << *FcnTy << "\n"; |
+ } |
+ } |
+ } |
+} |
+ |
+bool NaClDisModuleParser::ParseBlock(unsigned BlockID) { |
+ ObjDumpSetRecordBitAddress(GetBlock().GetStartBit()); |
+ switch (BlockID) { |
+ case naclbitc::BLOCKINFO_BLOCK_ID: { |
+ NaClDisBlockInfoParser Parser(BlockID, this); |
+ return Parser.ParseThisBlock(); |
+ } |
+ case naclbitc::TYPE_BLOCK_ID_NEW: { |
+ NaClDisTypesParser Parser(BlockID, this); |
+ return Parser.ParseThisBlock(); |
+ } |
+ case naclbitc::GLOBALVAR_BLOCK_ID: { |
+ NaClDisGlobalsParser Parser(BlockID, this); |
+ return Parser.ParseThisBlock(); |
+ } |
+ case naclbitc::VALUE_SYMTAB_BLOCK_ID: { |
+ NaClDisValueSymtabParser Parser(BlockID, this); |
+ return Parser.ParseThisBlock(); |
+ } |
+ case naclbitc::FUNCTION_BLOCK_ID: { |
+ NaClDisFunctionParser Parser(BlockID, this); |
+ return Parser.ParseThisBlock(); |
+ } |
+ default: |
+ return NaClDisBlockParser::ParseBlock(BlockID); |
+ } |
+} |
+ |
+void NaClDisModuleParser::PrintBlockHeader() { |
+ Tokens() << "module" << Space() << OpenCurly() |
+ << Space() << Space() << "// BlockID = " << GetBlockID() |
+ << Endline(); |
+} |
+ |
+void NaClDisModuleParser::ProcessRecord() { |
+ ObjDumpSetRecordBitAddress(Record.GetStartBit()); |
+ const NaClBitcodeRecord::RecordVector &Values = Record.GetValues(); |
+ switch (Record.GetCode()) { |
+ case naclbitc::MODULE_CODE_VERSION: |
+ // [version#] |
+ if (Values.size() != 1) { |
+ Errors() << "Version record should have one argument. Found: " |
+ << Values.size() << "\n"; |
+ break; |
+ } |
+ Tokens() << "version" << Space() << Values[0] << Semicolon() |
+ << TokenizeAbbrevIndex() << Endline(); |
+ break; |
+ case naclbitc::MODULE_CODE_FUNCTION: { |
+ // [type, callingconv, isproto, linkage] |
+ if (Values.size() != 4) { |
+ Errors() << "Function record should have 4 arguments. Found: " |
+ << Values.size() << "\n"; |
+ break; |
+ } |
+ bool IsProto = (Values[2] != 0); |
+ Tokens() << StartCluster() << (IsProto ? "declare" : "define"); |
+ uint32_t FcnId = GetNumFunctions(); |
+ BitcodeId FcnName('f', FcnId); |
+ std::string FcnStrName(FcnName.GetName()); |
+ GlobalValue::LinkageTypes Linkage; |
+ if (!naclbitc::DecodeLinkage(Values[3], Linkage)) { |
+ Errors() << "Unknown linkage value: " << Values[3] << "\n"; |
+ } else { |
+ if (!IgnorePNaClABIChecks && |
+ !PNaClABIProps::isValidGlobalLinkage(Linkage)) { |
+ Errors() << "Disallowed linkage type: " |
+ << PNaClABIProps::LinkageName(Linkage) << "\n"; |
+ } |
+ Tokens() << Space() << PNaClABIProps::LinkageName(Linkage); |
+ } |
+ CallingConv::ID CallingConv; |
+ if (!naclbitc::DecodeCallingConv(Values[1], CallingConv)) { |
+ Errors() << "Unknown calling convention value: " << Values[1] << "\n"; |
+ } else if (PNaClABIProps::isValidCallingConv(CallingConv)) { |
+ if (CallingConv != CallingConv::C) { |
+ Tokens() << Space() << PNaClABIProps::CallingConvName(CallingConv); |
+ } |
+ } else { |
+ Errors() << "Function " << FcnStrName |
+ << " has disallowed calling convention: " |
+ << PNaClABIProps::CallingConvName(CallingConv) |
+ << " (" << CallingConv << ")\n"; |
+ } |
+ Tokens() << FinishCluster() << Space() << StartCluster(); |
+ Type *FcnType = GetType(Values[0]); |
+ FunctionType *FunctionTy = dyn_cast<FunctionType>(FcnType); |
+ if (FunctionTy) { |
+ Tokens() << TokenizeFunctionType(FunctionTy, &FcnName); |
+ } else { |
+ BitcodeId FcnTypeId('t', Values[0]); |
+ Errors() << "Not function type: " << FcnTypeId << " = " |
+ << *FcnType << "\n"; |
+ Tokens() << "???"; |
+ SmallVector<Type*, 1> Signature; |
+ FunctionTy = FunctionType::get(GetVoidType(), Signature, 0); |
+ } |
+ Tokens() << Semicolon() << FinishCluster() << TokenizeAbbrevIndex() |
+ << Endline(); |
+ InstallFunctionType(FunctionTy); |
+ if (!IsProto) InstallDefinedFunction(FcnId); |
+ break; |
+ } |
+ default: |
+ Errors() << "Unknown record found in module block\n"; |
+ break; |
+ } |
+ ObjDumpWrite(Record.GetStartBit(), Record); |
+} |
+ |
+bool NaClDisTopLevelParser::ParseBlock(unsigned BlockID) { |
+ // Before parsing top-level module block. Describe header. |
+ NaClBitcodeRecordData Record; |
+ size_t HeaderSize = Header.getHeaderSize(); |
+ Record.Code = naclbitc::BLK_CODE_HEADER; |
+ for (size_t i = 0; i < HeaderSize; ++i) { |
+ Record.Values.push_back(HeaderBuffer[i]); |
+ } |
+ if (ObjDump.GetDumpRecords() && ObjDump.GetDumpAssembly()) { |
+ if (HeaderSize >= 4) { |
+ const NaClRecordVector &Values = Record.Values; |
+ Tokens() << "Magic" << Space() << "Number" << Colon() |
+ << Space() << StartCluster() << StartCluster() << "'" |
+ << (char) Values[0] << (char) Values[1] |
+ << (char) Values[2] << (char) Values[3] |
+ << "'" << FinishCluster() << Space() |
+ << StartCluster() << OpenParen() |
+ << Values[0] << Comma() << Space() |
+ << Values[1] << Comma() << Space() |
+ << Values[2] << Comma() << Space() |
+ << Values[3] << CloseParen() << FinishCluster() |
+ << FinishCluster() << Endline(); |
+ } |
+ // Show interpretation of header as assembly. |
+ for (size_t i = 0; i < Header.NumberFields(); ++i) { |
+ Tokens() << Header.GetField(i)->Contents() << Endline(); |
+ } |
+ } |
+ ObjDump.Write(0, Record); |
+ ObjDump.SetStartOffset(HeaderSize * 8); |
+ |
+ if (BlockID != naclbitc::MODULE_BLOCK_ID) |
+ return Error("Module block expected at top-level, but not found"); |
+ |
+ // Now parse a module block. |
+ NaClDisModuleParser Parser(BlockID, this); |
+ return Parser.ParseThisBlock(); |
+} |
+ |
+} |
+ |
+namespace llvm { |
+ |
+bool NaClObjDump(MemoryBuffer *MemBuf, raw_ostream &Output, |
+ bool NoRecords, bool NoAssembly) { |
+ // Create objects needed to run parser. |
+ naclbitc::ObjDumpStream ObjDump(Output, !NoRecords, !NoAssembly); |
+ |
+ if (MemBuf->getBufferSize() % 4 != 0) { |
+ ObjDump.Error() |
+ << "Bitcode stream should be a multiple of 4 bytes in length.\n"; |
+ return true; |
+ } |
+ |
+ const unsigned char *BufPtr = (const unsigned char *)MemBuf->getBufferStart(); |
+ const unsigned char *EndBufPtr = BufPtr+MemBuf->getBufferSize(); |
+ const unsigned char *HeaderPtr = BufPtr; |
+ |
+ // Read header and verify it is good. |
+ NaClBitcodeHeader Header; |
+ if (Header.Read(BufPtr, EndBufPtr) || !Header.IsSupported()) { |
+ ObjDump.Error() << "Invalid PNaCl bitcode header.\n"; |
+ return true; |
+ } |
+ |
+ // Create a bitstream reader to read the bitcode file. |
+ NaClBitstreamReader InputStreamFile(BufPtr, EndBufPtr); |
+ NaClBitstreamCursor InputStream(InputStreamFile); |
+ |
+ // Parse the the bitcode file. |
+ ::NaClDisTopLevelParser Parser(Header, HeaderPtr, InputStream, ObjDump); |
+ int NumBlocksRead = 0; |
+ bool ErrorsFound = false; |
+ while (!InputStream.AtEndOfStream()) { |
+ ++NumBlocksRead; |
+ if (Parser.Parse()) ErrorsFound = true; |
+ } |
+ |
+ if (NumBlocksRead != 1) { |
+ ObjDump.Error() << "Expected 1 top level block in bitcode: Found:" |
+ << NumBlocksRead << "\n"; |
+ ErrorsFound = true; |
+ } |
+ |
+ ObjDump.Flush(); |
+ return ErrorsFound || Parser.GetNumErrors() > 0; |
+} |
+ |
+} |