Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(756)

Unified Diff: lib/Bitcode/NaCl/Analysis/NaClObjDump.cpp

Issue 939073008: Rebased PNaCl localmods in LLVM to 223109 (Closed)
Patch Set: undo localmod Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « lib/Bitcode/NaCl/Analysis/NaClCompressCodeDist.cpp ('k') | lib/Bitcode/NaCl/Analysis/NaClObjDumpStream.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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;
+}
+
+}
« no previous file with comments | « lib/Bitcode/NaCl/Analysis/NaClCompressCodeDist.cpp ('k') | lib/Bitcode/NaCl/Analysis/NaClObjDumpStream.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698