| 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;
|
| +}
|
| +
|
| +}
|
|
|