1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
|
//===- NaClBitcodeParser.h -----------------------------------*- C++ -*-===//
// Low-level bitcode driver to parse PNaCl bitcode files.
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Parses and processes low-level PNaCl bitcode files. Defines class
// NaClBitcodeParser.
//
// The concepts of PNaCl bitcode files are basically the same as for
// LLVM bitcode files (see http://llvm.org/docs/BitCodeFormat.html for
// details).
//
// The bitstream format is an abstract encoding of structured data,
// very similar to XML in some ways. Like XML, bitstream files contain
// tags, and nested structures, and you can parse the file without
// having to understand the tags. Unlike XML, the bitstream format is
// a binary encoding, and provides a mechanism for the file to
// self-describe "abbreviations". Abbreviations are effectively size
// optimizations for the content.
//
// The bitcode file is conceptually a sequence of "blocks", defining
// the content. Blocks contain a sequence of records and
// blocks. Nested content is defined using nested blocks. A (data)
// "record" is a tag, and a vector of (unsigned integer) values.
//
// Blocks are identified using Block IDs. Each kind of block has a
// unique block "ID". Records have two elements:
//
// a) A "code" identifying what type of record it is.
// b) A vector of "values" defining the contents of the record.
//
// The bitstream "reader" (defined in NaClBitstreamReader.h) defines
// the implementation that converts the low-level bit file into
// records and blocks. The bit stream is processed by moving a
// "cursor" over the sequence of bits.
//
// The bitstream reader assumes that each block/record is read in by
// first reading the "entry". The entry defines whether it corresponds
// to one of the following:
//
// a) At the beginning of a (possibly nested) block
// b) At the end of the current block.
// c) The input defines an abberviation.
// d) The input defines a record.
//
// An entry contains two values, a "kind" and an "ID". The kind
// defines which of the four cases above occurs. The ID provides
// identifying information on how to further process the input. For
// case (a), the ID is the identifier associated with the the block
// being processed. For case (b) and (c) the ID is ignored. For case
// (d) the ID identifies the abbreviation that should be used to parse
// the values.
//
// The class NaClBitcodeParser defines a bitcode parser that extracts
// the blocks and records, which are then processed using virtual
// callbacks. In general, you will want to implement derived classes
// for each type of block, so that the corresponding data is processed
// appropriately.
//
// The class NaClBitcodeParser parses a bitcode block, and defines a
// set of callbacks for that block, including:
//
// a) EnterBlock: What to do once we have entered the block.
// b) ProcessRecord: What to do with each parsed record.
// c) ProcessAbbrevRecord: What to do with a parsed abbreviation.
// d) ParseBlock: Parse the (nested) block with the given ID.
// e) ExitBlock: What to do once we have finished processing the block.
//
// Note that a separate instance of NaClBitcodeParser (or a
// corresponding derived class) is created for each nested block. Each
// instance is responsible for only parsing a single block. Method
// ParseBlock creates new instances to parse nested blocks. Method
// GetEnclosingParser() can be used to refer to the parser associated
// with the enclosing block.
//
// TODO(kschimpf): Define an intermediate derived class of
// NaClBitcodeParser that defines callbacks based on the actual
// structure of PNaCl bitcode files. That is, it has callbacks for
// each of the types of blocks (i.e. module, types, global variables,
// function, symbol tables etc). This derivied class can then be used
// as the base class for the bitcode reader.
//
// TODO(kschimpf): Currently, the processing of abbreviations is
// handled by the PNaCl bitstream reader, rather than by the
// parser. Hence, we currently require defining methods
// EnterBlockInfo, ExitBlockInfo, and ProcessRecordAbbrev. BlockInfo
// is a special block that defines abbreviations to be applied to all
// blocks. Record abbreviations (which are a special kind of record)
// define abbreviations for a the current block.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_BITCODE_NACL_NACLBITCODEPARSER_H
#define LLVM_BITCODE_NACL_NACLBITCODEPARSER_H
#include "llvm/Bitcode/NaCl/NaClBitstreamReader.h"
#include "llvm/Support/raw_ostream.h"
#include <vector>
using namespace llvm;
class NaClBitcodeParser;
/// Defines the data associated with reading a block record in the
/// PNaCl bitcode stream.
class NaClBitcodeRecord {
public:
/// Type for vector of values representing a record.
typedef SmallVector<uint64_t, 64> RecordVector;
NaClBitcodeRecord(unsigned BlockID, NaClBitstreamCursor &Cursor)
: BlockID(BlockID),
Cursor(Cursor),
StartBit(Cursor.GetCurrentBitNo()) {
}
/// Print the contents out to the given stream (for debugging).
void Print(raw_ostream& os) const;
/// Returns the bitstream reader being used.
NaClBitstreamReader &GetReader() const {
return *Cursor.getBitStreamReader();
}
/// Returns the cursor position within the bitstream.
NaClBitstreamCursor &GetCursor() const {
return Cursor;
}
/// Returns the block ID of the record.
unsigned GetBlockID() const {
return BlockID;
}
/// Returns the kind of entry read from the input stream.
unsigned GetEntryKind() const {
return Entry.Kind;
}
/// Returns the code value (i.e. selector) associated with the
/// record.
unsigned GetCode() const {
return Code;
}
/// Returns the EntryID (e.g. abbreviation if !=
/// naclbitcod::UNABBREV_RECORD) associated with the record. Note:
/// for block-enter, block-exit, and define-abbreviation, EntryID is
/// not the corresponding abbreviation.
unsigned GetEntryID() const {
return Entry.ID;
}
/// Returns the (value) record associated with the read record.
const RecordVector &GetValues() const {
return Values;
}
/// Returns the number of bits in this record.
unsigned GetNumBits() const {
return GetCursor().GetCurrentBitNo() - StartBit;
}
protected:
// The block ID associated with this record.
unsigned BlockID;
// The bitstream cursor defining location within the bitcode file.
NaClBitstreamCursor &Cursor;
// The entry ID associated with the record.
unsigned EntryID;
// The selector code associated with the record.
unsigned Code;
// The sequence of values defining the parsed record.
RecordVector Values;
// The entry (i.e. value(s) preceding the record that define what
// value comes next).
NaClBitstreamEntry Entry;
// Start bit for the record.
uint64_t StartBit;
/// Returns the position of the start bit for this record.
unsigned GetStartBit() const {
return StartBit;
}
private:
// Allows class NaClBitcodeParser to read values into the
// record, thereby hiding the details of how to read values.
friend class NaClBitcodeParser;
/// Read bitstream entry. Defines what construct appears next in the
/// bitstream.
void ReadEntry() {
StartBit = GetCursor().GetCurrentBitNo();
Entry = GetCursor().advance(NaClBitstreamCursor::AF_DontAutoprocessAbbrevs);
}
/// Reads in a record's values, if the entry defines a record (Must
/// be called after ReadEntry).
void ReadValues() {
Values.clear();
Code = GetCursor().readRecord(Entry.ID, Values);
}
NaClBitcodeRecord(const NaClBitcodeRecord &Rcd) LLVM_DELETED_FUNCTION;
void operator=(const NaClBitcodeRecord &Rcd) LLVM_DELETED_FUNCTION;
};
/// Parses a block in the PNaCL bitcode stream.
class NaClBitcodeParser {
public:
// Creates a parser to parse the the block at the given cursor in
// the PNaCl bitcode stream. This instance is a "dummy" instance
// that starts the parser.
explicit NaClBitcodeParser(NaClBitstreamCursor &Cursor)
: EnclosingParser(0),
Record(ILLEGAL_BLOCK_ID, Cursor),
StartBit(Cursor.GetCurrentBitNo()) {
BlockStart = StartBit;
}
virtual ~NaClBitcodeParser();
/// Reads the (top-level) block associated with the given block
/// record at the stream cursor. Returns true if unable to parse.
/// Can be called multiple times to parse multiple blocks.
bool Parse();
// Called once the bitstream reader has entered the corresponding
// subblock. Argument NumWords is set to the number of words in the
// corresponding subblock.
virtual void EnterBlock(unsigned NumWords) {}
// Called when the corresponding EndBlock of the block being parsed
// is found.
virtual void ExitBlock() {}
// Called before a BlockInfo block is parsed. Note: BlockInfo blocks
// are special. They include abbreviations to be used for blocks.
// After this routine is called, the NaClBitstreamParser is called
// to parse the BlockInfo block (rather than making a call to
// Parser->Parse()).
virtual void EnterBlockInfo() {}
// Called after a BlockInfo block is parsed.
virtual void ExitBlockInfo() { ExitBlock(); }
// Called after each record (within the block) is read (into field Record).
virtual void ProcessRecord() {}
// Called if a block-specific abbreviation is read (into field
// Record), after processing by the bitstream reader.
virtual void ProcessRecordAbbrev() {}
// Creates an instance of the NaClBitcodeParser to use to parse the
// block with the given block ID, and then call's method
// ParseThisBlock() to parse the corresponding block. Note:
// Each derived class should define it's own version of this
// method, following the pattern below.
virtual bool ParseBlock(unsigned BlockID) {
// Default implementation just builds a parser that does nothing.
NaClBitcodeParser Parser(BlockID, this);
return Parser.ParseThisBlock();
}
// Called when error occurs. Message is the error to report. Always
// returns true (the error return value of Parse).
virtual bool Error(const std::string Message) {
errs() << "Error: " << Message << "\n";
return true;
}
// Returns the number of bits in this block.
unsigned GetNumBits() {
return Record.GetCursor().GetCurrentBitNo() - StartBit;
}
// Returns the number of bits in this block, but not subblocks
// within this block.
unsigned GetLocalNumBits() {
return Record.GetCursor().GetCurrentBitNo() - BlockStart;
}
/// Returns the block ID associated with the Parser.
unsigned GetBlockID() {
return Record.GetBlockID();
}
/// Returns the enclosing block parser of this block.
NaClBitcodeParser *GetEnclosingParser() const {
// Note: The top-level parser instance is a dummy instance
// and is not considered an enclosing parser.
return EnclosingParser->EnclosingParser ? EnclosingParser : 0;
}
protected:
// The containing parser.
NaClBitcodeParser *EnclosingParser;
// The current record (within the block) being processed.
NaClBitcodeRecord Record;
// Creates a block parser to parse the block associated with the
// bitcode entry that defines the beginning of a block. This
// instance actually parses the corresponding block.
NaClBitcodeParser(unsigned BlockID,
NaClBitcodeParser *EnclosingParser)
: EnclosingParser(EnclosingParser),
Record(BlockID, EnclosingParser->Record.GetCursor()),
StartBit(EnclosingParser->Record.GetStartBit()) {
BlockStart = StartBit;
}
// Parses the block using the parser defined by
// ParseBlock(unsigned). Returns true if unable to parse the
// block. Note: Should only be called by virtual
// ParseBlock(unsigned).
bool ParseThisBlock();
private:
// Special constant identifying the top-level instance.
static const unsigned ILLEGAL_BLOCK_ID = UINT_MAX;
// The start bit of the block.
unsigned StartBit;
// The start bit of the block, plus the bits in all subblocks. Used
// to compute the number of (block local) bits.
unsigned BlockStart;
// Updates BlockStart in the enclosingblock, so that bits in this
// block are not counted as local bits for the enclosing block.
void RemoveBlockBitsFromEnclosingBlock() {
EnclosingParser->BlockStart += GetNumBits();
}
void operator=(const NaClBitcodeParser &Parser) LLVM_DELETED_FUNCTION;
NaClBitcodeParser(const NaClBitcodeParser &Parser) LLVM_DELETED_FUNCTION;
};
#endif
|