1//===- NaClBitcodeParser.cpp ----------------------------------------------===//
2//     Low-level bitcode driver to parse PNaCl bitcode files.
3//
4//                     The LLVM Compiler Infrastructure
5//
6// This file is distributed under the University of Illinois Open Source
7// License. See LICENSE.TXT for details.
8//
9//===----------------------------------------------------------------------===//
10
11#include "llvm/Bitcode/NaCl/NaClBitcodeParser.h"
12
13using namespace llvm;
14
15void NaClBitcodeRecordData::Print(raw_ostream &os) const {
16  os << "[" << Code;
17  for (NaClRecordVector::const_iterator
18           Iter = Values.begin(), IterEnd = Values.end();
19       Iter != IterEnd; ++Iter) {
20    os << ", " << *Iter;
21  }
22  os << "]";
23}
24
25void NaClBitcodeRecord::Print(raw_ostream& os) const {
26  Block.Print(os);
27  os << ", Code " << Data.Code << ", EntryID " << Entry.ID << ", <";
28  for (unsigned i = 0, e = Data.Values.size(); i != e; ++i) {
29    if (i > 0) os << " ";
30    os << Data.Values[i];
31  }
32  os << ">";
33}
34
35NaClBitcodeBlock::NaClBitcodeBlock(unsigned BlockID,
36                                   const NaClBitcodeRecord &Record)
37    : NaClBitcodeData(Record),
38      BlockID(BlockID),
39      EnclosingBlock(&Record.GetBlock()),
40      LocalStartBit(Record.GetStartBit())
41{}
42
43void NaClBitcodeBlock::Print(raw_ostream &os) const {
44  os << "Block " << BlockID;
45}
46
47void NaClBitcodeParserListener::BeginBlockInfoBlock(unsigned NumWords) {
48  Parser->EnterBlock(NumWords);
49}
50
51void NaClBitcodeParserListener::SetBID() {
52  Parser->Record.SetStartBit(StartBit);
53  Parser->Record.Entry.Kind = NaClBitstreamEntry::Record;
54  Parser->Record.Entry.ID = naclbitc::UNABBREV_RECORD;
55  Parser->Record.Data.Code = naclbitc::BLOCKINFO_CODE_SETBID;
56  Parser->Record.Data.Values = Values;
57  GlobalBlockID = Values[0];
58  Parser->SetBID();
59  Values.clear();
60}
61
62void NaClBitcodeParserListener::EndBlockInfoBlock() {
63  Parser->Record.SetStartBit(StartBit);
64  Parser->Record.Entry.Kind = NaClBitstreamEntry::EndBlock;
65  Parser->Record.Entry.ID = naclbitc::END_BLOCK;
66  Parser->Record.Data.Code = naclbitc::END_BLOCK;
67  Parser->Record.Data.Values.clear();
68  GlobalBlockID = naclbitc::BLOCKINFO_BLOCK_ID;
69  Parser->ExitBlock();
70}
71
72void NaClBitcodeParserListener::
73ProcessAbbreviation(NaClBitCodeAbbrev *Abbrev, bool IsLocal) {
74  Parser->Record.SetStartBit(StartBit);
75  Parser->Record.Entry.Kind = NaClBitstreamEntry::Record;
76  Parser->Record.Entry.ID = naclbitc::DEFINE_ABBREV;
77  Parser->Record.Data.Code = naclbitc::BLK_CODE_DEFINE_ABBREV;
78  Parser->Record.Data.Values = Values;
79  Parser->ProcessAbbreviation(IsLocal ? Parser->GetBlockID() : GlobalBlockID,
80                              Abbrev, IsLocal);
81}
82
83NaClBitcodeParser::~NaClBitcodeParser() {
84  if (EnclosingParser) {
85    EnclosingParser->Block.LocalStartBit += Block.GetNumBits();
86  }
87}
88
89bool NaClBitcodeParser::ErrorAt(
90    naclbitc::ErrorLevel Level, uint64_t BitPosition,
91    const std::string &Message) {
92  naclbitc::ErrorAt(*ErrStream, Level, BitPosition) << Message << "\n";
93  if (Level == naclbitc::Fatal)
94    report_fatal_error("Unable to continue");
95  return true;
96}
97
98bool NaClBitcodeParser::Parse() {
99  Record.ReadEntry();
100
101  if (Record.GetEntryKind() != NaClBitstreamEntry::SubBlock)
102    return Error("Expected block, but not found");
103
104  return ParseBlock(Record.GetEntryID());
105}
106
107bool NaClBitcodeParser::ParseBlockInfoInternal() {
108  // BLOCKINFO is a special part of the stream. Let the bitstream
109  // reader process this block.
110  bool Result = Record.GetCursor().ReadBlockInfoBlock(Listener);
111  if (Result) return Error("Malformed BlockInfoBlock");
112  return Result;
113}
114
115bool NaClBitcodeParser::ParseBlockInternal() {
116  // Regular block. Enter subblock.
117  unsigned NumWords;
118  if (Record.GetCursor().EnterSubBlock(GetBlockID(), &NumWords)) {
119    return Error("Malformed block record");
120  }
121
122  EnterBlock(NumWords);
123
124  // Process records.
125  while (1) {
126    if (Record.GetCursor().AtEndOfStream())
127      return Error("Premature end of bitstream");
128
129    // Read entry defining type of entry.
130    Record.ReadEntry();
131
132    switch (Record.GetEntryKind()) {
133    case NaClBitstreamEntry::Error:
134      return Error("malformed bitcode file");
135    case NaClBitstreamEntry::EndBlock: {
136      return false;
137    }
138    case NaClBitstreamEntry::SubBlock: {
139      if (ParseBlock(Record.GetEntryID())) return true;
140      break;
141    }
142    case NaClBitstreamEntry::Record:
143      // The interesting case.
144      if (Record.GetEntryID() == naclbitc::DEFINE_ABBREV) {
145        // Since this abbreviation is local, the listener doesn't
146        // have the start bit set (it is only set when processing
147        // the BlockInfo block). Fix this by setting it here.
148        if (Listener) Listener->StartBit = Record.GetStartBit();
149        Record.GetCursor().ReadAbbrevRecord(true, Listener);
150      } else {
151        // Read in a record.
152        Record.ReadValues();
153        ProcessRecord();
154      }
155      break;
156    }
157  }
158  return false;
159}
160