OLD | NEW |
---|---|
(Empty) | |
1 //===- NaClBitcodeMungeWriter.cpp - Write munged bitcode --------*- C++ -*-===// | |
2 // | |
3 // The LLVM Compiler Infrastructure | |
4 // | |
5 // This file is distributed under the University of Illinois Open Source | |
6 // License. See LICENSE.TXT for details. | |
7 // | |
8 //===----------------------------------------------------------------------===// | |
9 // | |
10 // Implements method NaClMungedBitcode.write(), which writes out a munged | |
11 // list of bitcode records using a bitstream writer. | |
12 | |
13 #include "llvm/Bitcode/NaCl/NaClBitcodeMungeUtils.h" | |
14 | |
15 #include "llvm/Bitcode/NaCl/NaClBitstreamWriter.h" | |
16 #include "llvm/Bitcode/NaCl/NaClReaderWriter.h" | |
17 | |
18 using namespace llvm; | |
19 | |
20 namespace { | |
21 | |
22 // For debugging. When true, shows each PNaCl record that is | |
23 // emitted to the bitcode file. | |
24 static bool DebugEmitRecord = false; | |
25 | |
26 // State of bitcode writing. | |
27 struct WriteState { | |
28 // The block ID associated with the block being written. | |
29 int WriteBlockID = -1; | |
30 // The SetBID for the blockinfo block. | |
31 int SetBID = -1; | |
32 // The stack of maximum abbreviation indices allowed by block enter record. | |
33 SmallVector<uint64_t, 3> AbbrevIndexLimitStack; | |
34 // The set of write flags to use. | |
35 const NaClMungedBitcode::WriteFlags &Flags; | |
36 // The results of the attempted write. | |
37 NaClMungedBitcode::WriteResults Results; | |
38 | |
39 WriteState(const NaClMungedBitcode::WriteFlags &Flags) : Flags(Flags) {} | |
40 | |
41 // Returns stream to print error message to. | |
42 raw_ostream &Error() { | |
43 Results.HasErrors = true; | |
44 return errs() << "Error (Block " << WriteBlockID << "): "; | |
45 } | |
46 | |
47 // Returns stream to print error message to, assuming that | |
48 // the error message can be repaired if Flags.TryToRecover is true. | |
49 raw_ostream &RecoverableError() { | |
50 if (Flags.TryToRecover) | |
51 Results.HasRepairs = true; | |
52 return Error(); | |
53 } | |
54 | |
55 // Converts the abbreviation record to the corresponding abbreviation. | |
56 // Returns nullptr if unable to build abbreviation. | |
57 NaClBitCodeAbbrev *buildAbbrev(const NaClBitcodeAbbrevRecord &Record); | |
58 | |
59 // Emits the given record to the bitcode file. Returns true if | |
60 // successful. | |
61 bool emitRecord(NaClBitstreamWriter &Writer, | |
62 const NaClBitcodeAbbrevRecord &Record); | |
63 | |
64 // Adds any missing end blocks to written bitcode. | |
65 void writeMissingEndBlocks(NaClBitstreamWriter &Writer) { | |
66 while (!AbbrevIndexLimitStack.empty()) { | |
67 Writer.ExitBlock(); | |
68 AbbrevIndexLimitStack.pop_back(); | |
69 } | |
70 } | |
71 }; | |
72 | |
73 bool WriteState::emitRecord(NaClBitstreamWriter &Writer, | |
74 const NaClBitcodeAbbrevRecord &Record) { | |
75 size_t NumValues = Record.Values.size(); | |
76 if (DebugEmitRecord) { | |
77 errs() << "Emit " << Record.Abbrev << ": <" << Record.Code; | |
78 for (size_t i = 0; i < NumValues; ++i) { | |
79 errs() << ", " << Record.Values[i]; | |
80 } | |
81 errs() << ">\n"; | |
82 } | |
83 | |
84 switch (Record.Code) { | |
85 case naclbitc::BLK_CODE_ENTER: { | |
86 unsigned NumBits = naclbitc::DEFAULT_MAX_ABBREV; | |
jvoung (off chromium)
2015/05/06 22:08:09
Should this also be NaClBitsNeededForValue( naclbi
Karl
2015/05/07 20:09:18
Good catch. Fixing!
| |
87 WriteBlockID = -1; | |
88 if (Record.Abbrev != naclbitc::ENTER_SUBBLOCK) { | |
89 RecoverableError() | |
90 << "Uses illegal abbreviation index in enter block record: " | |
91 << Record << "\n"; | |
92 if (!Flags.TryToRecover) | |
93 return false; | |
94 } | |
95 if (NumValues == 2) { | |
96 WriteBlockID = Record.Values[0]; | |
97 NumBits = Record.Values[1]; | |
98 if (NumBits > 32 || NumBits < 2) { | |
99 RecoverableError() | |
100 << "Bit size " << NumBits << " for record should be " | |
101 << (NumBits > 32 ? "<= 32" : ">= 2") << ": " << Record << "\n"; | |
102 if (!Flags.TryToRecover) | |
103 return false; | |
104 NumBits = 32; | |
105 } | |
106 } else { | |
107 Error() << "Values for enter record should be of size 2, but found " | |
108 << NumValues << ": " << Record << "\n"; | |
109 return false; | |
110 } | |
111 uint64_t MaxAbbrev = (static_cast<uint64_t>(1) << NumBits) - 1; | |
112 AbbrevIndexLimitStack.push_back(MaxAbbrev); | |
113 if (WriteBlockID == naclbitc::BLOCKINFO_BLOCK_ID) { | |
114 unsigned DefaultMaxBits = | |
115 NaClBitsNeededForValue(naclbitc::DEFAULT_MAX_ABBREV); | |
116 if (NumBits != DefaultMaxBits) { | |
117 RecoverableError() | |
118 << "Numbits entry for abbreviations record not " | |
119 << DefaultMaxBits << " but found " << NumBits << | |
120 ": " << Record << "\n"; | |
121 if (!Flags.TryToRecover) | |
122 return false; | |
123 } | |
124 Writer.EnterBlockInfoBlock(); | |
125 } else { | |
126 NaClBitcodeSelectorAbbrev CurCodeLen(MaxAbbrev); | |
127 Writer.EnterSubblock(WriteBlockID, CurCodeLen); | |
128 } | |
129 break; | |
130 } | |
131 case naclbitc::BLK_CODE_EXIT: | |
132 if (Record.Abbrev != naclbitc::END_BLOCK) { | |
133 RecoverableError() | |
134 << "Uses illegal abbreviation index in exit block record: " | |
135 << Record << "\n"; | |
136 if (!Flags.TryToRecover) | |
137 return false; | |
138 } | |
139 if (NumValues != 0) { | |
140 RecoverableError() << "Exit block should not have values: " | |
141 << Record << "\n"; | |
142 if (!Flags.TryToRecover) | |
143 return false; | |
144 } | |
145 if (!AbbrevIndexLimitStack.empty()) | |
146 AbbrevIndexLimitStack.pop_back(); | |
147 Writer.ExitBlock(); | |
148 break; | |
149 case naclbitc::BLK_CODE_DEFINE_ABBREV: { | |
150 if (Record.Abbrev != naclbitc::DEFINE_ABBREV) { | |
151 RecoverableError() | |
152 << "Uses illegal abbreviation index in define abbreviation record: " | |
153 << Record << "\n"; | |
154 if (!Flags.TryToRecover) | |
155 return false; | |
156 } | |
157 NaClBitCodeAbbrev *Abbrev = buildAbbrev(Record); | |
158 if (Abbrev == NULL) | |
159 return Flags.TryToRecover; | |
160 if (WriteBlockID == naclbitc::BLOCKINFO_BLOCK_ID) { | |
161 Writer.EmitBlockInfoAbbrev(SetBID, Abbrev); | |
162 } else { | |
163 Writer.EmitAbbrev(Abbrev); | |
164 } | |
165 break; | |
166 } | |
167 case naclbitc::BLK_CODE_HEADER: | |
168 // Note: There is no abbreviation index here. Ignore. | |
169 for (uint64_t Value : Record.Values) | |
170 Writer.Emit(Value, 8); | |
171 break; | |
172 default: | |
173 bool UsesDefaultAbbrev = Record.Abbrev == naclbitc::UNABBREV_RECORD; | |
174 if (!UsesDefaultAbbrev | |
175 && !Writer.isUserRecordAbbreviation(Record.Abbrev)) { | |
176 uint64_t BlockAbbrevIndexLimit = 0; | |
177 if (!AbbrevIndexLimitStack.empty()) | |
178 BlockAbbrevIndexLimit = AbbrevIndexLimitStack.back(); | |
179 // Can't generate abbreviation ID because not enough bits | |
180 // specified in block ID. | |
181 raw_ostream &ErrStrm = RecoverableError(); | |
182 ErrStrm << "Uses illegal abbreviation index"; | |
183 if (Record.Abbrev > BlockAbbrevIndexLimit) | |
jvoung (off chromium)
2015/05/06 22:08:09
When does this > check fail? If for some reason th
Karl
2015/05/07 20:09:18
Decided to simplify this code and be more generic.
| |
184 ErrStrm << ". Must not exceed " << BlockAbbrevIndexLimit; | |
185 ErrStrm << ": " << Record << "\n"; | |
186 if (!Flags.TryToRecover && !Flags.SaveBadAbbrevIndices) | |
jvoung (off chromium)
2015/05/06 22:08:09
So this code is saying that SaveBadAbbrevIndices w
Karl
2015/05/07 20:09:18
Hopefully the code is now clearer since I simplifi
jvoung (off chromium)
2015/05/07 21:33:56
Thanks -- I like the new version more.
| |
187 return false; | |
188 if (Flags.SaveBadAbbrevIndices) { | |
189 // Note: If this point is reached, the abbreviation is bad and | |
190 // RecoverOnBadAbbrevID is true. Generate bad abbreviation index | |
jvoung (off chromium)
2015/05/06 22:08:09
there is no RecoverOnBadAbbrevID anymore
You also
Karl
2015/05/07 20:09:18
Again, I simplified this code so that we don't nee
| |
191 // so that the bitcode reader can be tested. | |
192 Writer.EmitCode(Record.Abbrev); | |
193 // Note: We need to close blocks or the bitcode Writer will terminate | |
194 // due to assertions. | |
195 writeMissingEndBlocks(Writer); | |
196 Results.SavedBadAbbrevIndices = true; | |
jvoung (off chromium)
2015/05/06 22:08:09
Perhaps "Save..." should be "Write..." ?
In some
Karl
2015/05/07 20:09:18
Hopefully I have clarified that the Save Case (now
| |
197 return false; | |
198 } | |
199 UsesDefaultAbbrev = true; | |
200 } | |
201 if (WriteBlockID == naclbitc::BLOCKINFO_BLOCK_ID | |
202 && Record.Code == naclbitc::BLOCKINFO_CODE_SETBID) { | |
203 // Note: SetBID records are handled by Writer->EmitBlockInfoAbbrev, | |
204 // based on the SetBID value. Don't bother to generate SetBID record here. | |
205 // Rather just set SetBID and let call to Writer->EmitBlockInfoAbbrev | |
206 // generate the SetBID record. | |
207 if (NumValues != 1) { | |
208 Error() << "SetBID record expects 1 value but found " | |
209 << NumValues << ": " << Record << "\n"; | |
210 return false; | |
211 } | |
212 SetBID = Record.Values[0]; | |
213 return true; | |
214 } | |
215 if (UsesDefaultAbbrev) | |
216 Writer.EmitRecord(Record.Code, Record.Values); | |
217 else | |
218 Writer.EmitRecord(Record.Code, Record.Values, Record.Abbrev); | |
219 } | |
220 return true; | |
221 } | |
222 | |
223 static NaClBitCodeAbbrev *deleteAbbrev(NaClBitCodeAbbrev *Abbrev) { | |
224 Abbrev->dropRef(); | |
225 return nullptr; | |
226 } | |
227 | |
228 NaClBitCodeAbbrev *WriteState::buildAbbrev( | |
229 const NaClBitcodeAbbrevRecord &Record) { | |
230 // Note: Recover by removing abbreviation. | |
231 NaClBitCodeAbbrev *Abbrev = new NaClBitCodeAbbrev(); | |
232 size_t Index = 0; | |
233 size_t NumValues = Record.Values.size(); | |
234 if (NumValues == 0) { | |
235 RecoverableError() << "Empty abbreviation record not allowed: " | |
236 << Record << "\n"; | |
237 return deleteAbbrev(Abbrev); | |
238 } | |
239 size_t NumAbbreviations = Record.Values[Index++]; | |
240 if (NumAbbreviations == 0) { | |
241 RecoverableError() << "Abbreviation must contain at least one operator: " | |
242 << Record << "\n"; | |
243 return deleteAbbrev(Abbrev); | |
244 } | |
245 for (size_t Count = 0; Count < NumAbbreviations; ++Count) { | |
246 if (Index >= NumValues) { | |
247 RecoverableError() | |
248 << "Malformed abbreviation found. Expects " << NumAbbreviations | |
249 << " operands but ound " << Count << ": " << Record << "\n"; | |
250 return deleteAbbrev(Abbrev); | |
251 } | |
252 switch (Record.Values[Index++]) { | |
253 case 1: | |
254 if (Index >= NumValues) { | |
255 RecoverableError() << "Malformed literal abbreviation: " | |
256 << Record << "\n"; | |
257 return deleteAbbrev(Abbrev); | |
258 } | |
259 Abbrev->Add(NaClBitCodeAbbrevOp(Record.Values[Index++])); | |
260 break; | |
261 case 0: { | |
262 if (Index >= NumValues) { | |
263 RecoverableError() << "Malformed abbreviation found: " | |
264 << Record << "\n"; | |
265 return deleteAbbrev(Abbrev); | |
266 } | |
267 unsigned Kind = Record.Values[Index++]; | |
268 switch (Kind) { | |
269 case NaClBitCodeAbbrevOp::Fixed: | |
270 if (Index >= NumValues) { | |
271 RecoverableError() << "Malformed fixed abbreviation found: " | |
272 << Record << "\n"; | |
273 return deleteAbbrev(Abbrev); | |
274 } | |
275 Abbrev->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Fixed, | |
276 Record.Values[Index++])); | |
277 break; | |
278 case NaClBitCodeAbbrevOp::VBR: | |
279 if (Index >= NumValues) { | |
280 RecoverableError() << "Malformed vbr abbreviation found: " | |
281 << Record << "\n"; | |
282 return deleteAbbrev(Abbrev); | |
283 } | |
284 Abbrev->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::VBR, | |
285 Record.Values[Index++])); | |
286 break; | |
287 case NaClBitCodeAbbrevOp::Array: | |
288 if (Index >= NumValues) { | |
289 RecoverableError() << "Malformed array abbreviation found: " | |
290 << Record << "\n"; | |
291 return deleteAbbrev(Abbrev); | |
292 } | |
293 Abbrev->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Array)); | |
294 break; | |
295 case NaClBitCodeAbbrevOp::Char6: | |
296 Abbrev->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Char6)); | |
297 break; | |
298 default: | |
299 RecoverableError() << "Unknown abbreviation kind " << Kind | |
300 << ": " << Record << "\n"; | |
301 return deleteAbbrev(Abbrev); | |
302 } | |
303 break; | |
304 } | |
305 default: | |
306 RecoverableError() << "Error: Bad literal flag " << Record.Values[Index] | |
307 << ": " << Record << "\n"; | |
308 return deleteAbbrev(Abbrev); | |
309 } | |
310 } | |
311 return Abbrev; | |
312 } | |
313 | |
314 } // end of anonymous namespace. | |
315 | |
316 NaClMungedBitcode::WriteResults NaClMungedBitcode::writeMaybeRepair( | |
317 SmallVectorImpl<char> &Buffer, bool AddHeader, | |
318 const WriteFlags &Flags) const { | |
319 NaClBitstreamWriter Writer(Buffer); | |
320 WriteState State(Flags); | |
321 if (AddHeader) { | |
322 NaClWriteHeader(Writer, true); | |
323 } | |
324 for (const NaClBitcodeAbbrevRecord &Record : *this) { | |
325 if (!State.emitRecord(Writer, Record)) | |
326 break; | |
327 } | |
328 if (!State.AbbrevIndexLimitStack.empty()) { | |
329 State.RecoverableError() | |
330 << "Bitcode missing " << State.AbbrevIndexLimitStack.size() | |
331 << " close blocks.\n"; | |
332 if (Flags.TryToRecover) | |
333 State.writeMissingEndBlocks(Writer); | |
334 } | |
335 return State.Results; | |
336 } | |
OLD | NEW |