aboutsummaryrefslogtreecommitdiff
path: root/lib/Wrap/bitcode_wrapperer.cpp
blob: 65f94b7c67a7ad2b613b70351e1dee06b98ec922 (plain)
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
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
/*
 * Copyright 2012, The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "llvm/Wrap/bitcode_wrapperer.h"

#include <stdio.h>
#include <sys/stat.h>

using std::vector;

// The number of bytes in a 32 bit integer.
static const uint32_t kWordSize = 4;

// Number of LLVM-defined fixed fields in the header.
static const uint32_t kLLVMFields = 4;

// Total number of fixed fields in the header.
static const uint32_t kFixedFields = 7;

// The magic number that must exist for bitcode wrappers.
static const uint32_t kWrapperMagicNumber = 0x0B17C0DE;

// The version number associated with a wrapper file.
// Note: llvm currently only allows the value 0. When this changes,
// we should consider making this a command line option.
static const uint32_t kLLVMVersionNumber = 0;

// Fields defined by Android bitcode header.
static const uint32_t kAndroidHeaderVersion = 0;
static const uint32_t kAndroidTargetAPI = 0;
static const uint32_t kAndroidDefaultCompilerVersion = 0;
static const uint32_t kAndroidDefaultOptimizationLevel = 3;

// PNaCl bitcode version number.
static const uint32_t kPnaclBitcodeVersion = 0;

// Max size for variable fields. Currently only used for writing them
// out to files (the parsing works for arbitrary sizes).
static const size_t kMaxVariableFieldSize = 256;

BitcodeWrapperer::BitcodeWrapperer(WrapperInput* infile, WrapperOutput* outfile)
    : infile_(infile),
      outfile_(outfile),
      buffer_size_(0),
      cursor_(0),
      infile_at_eof_(false),
      infile_bc_offset_(0),
      wrapper_bc_offset_(0),
      wrapper_bc_size_(0),
      android_header_version_(kAndroidHeaderVersion),
      android_target_api_(kAndroidTargetAPI),
      android_compiler_version_(kAndroidDefaultCompilerVersion),
      android_optimization_level_(kAndroidDefaultOptimizationLevel),
      pnacl_bc_version_(0),
      error_(false) {
  buffer_.resize(kBitcodeWrappererBufferSize);
  if (IsInputBitcodeWrapper()) {
    ParseWrapperHeader();
  } else if (IsInputBitcodeFile()) {
    wrapper_bc_offset_ = kWordSize * kFixedFields;
    wrapper_bc_size_ = GetInFileSize();
  } else {
    fprintf(stderr, "Error: input file is not a bitcode file.\n");
    error_ = true;
  }
}

BitcodeWrapperer::~BitcodeWrapperer() {
  for(size_t i = 0; i < variable_field_data_.size(); i++) {
    delete [] variable_field_data_[i];
  }
}


void BitcodeWrapperer::ClearBuffer() {
  buffer_size_ = 0;
  cursor_ = 0;
  infile_at_eof_ = false;
}

bool BitcodeWrapperer::Seek(uint32_t pos) {
  if (infile_ != NULL && infile_->Seek(pos)) {
    ClearBuffer();
    return true;
  }
  return false;
}

bool BitcodeWrapperer::CanReadWord() {
  if (GetBufferUnreadBytes() < kWordSize) {
    FillBuffer();
    return GetBufferUnreadBytes() >= kWordSize;
  } else {
    return true;
  }
}

void BitcodeWrapperer::FillBuffer() {
  if (cursor_ > 0) {
    // Before filling, move any remaining bytes to the
    // front of the buffer. This allows us to assume
    // that after the call to FillBuffer, readable
    // text is contiguous.
    if (cursor_ < buffer_size_) {
      size_t i = 0;
      while (cursor_ < buffer_size_) {
        buffer_[i++] = buffer_[cursor_++];
      }
      cursor_ = 0;
      buffer_size_ = i;
    }
  } else {
    // Assume the buffer contents have been used,
    // and we want to completely refill it.
    buffer_size_ = 0;
  }

  // If we don't have an input, we can't refill the buffer at all.
  if (infile_ == NULL) {
    return;
  }

  // Now fill in remaining space.
  size_t needed = buffer_.size() - buffer_size_;

  while (buffer_.size() > buffer_size_) {
    int actually_read = infile_->Read(&buffer_[buffer_size_], needed);
    if (infile_->AtEof()) {
      infile_at_eof_ = true;
    }
    if (actually_read) {
      buffer_size_ += actually_read;
      needed -= actually_read;
    } else if (infile_at_eof_) {
      break;
    }
  }
}

bool BitcodeWrapperer::ReadWord(uint32_t& word) {
  if (!CanReadWord()) return false;
  word = (((uint32_t) BufferLookahead(0)) << 0)
      | (((uint32_t) BufferLookahead(1)) << 8)
      | (((uint32_t) BufferLookahead(2)) << 16)
      | (((uint32_t) BufferLookahead(3)) << 24);
  cursor_ += kWordSize;
  return true;
}

bool BitcodeWrapperer::WriteWord(uint32_t value) {
  uint8_t buffer[kWordSize];
  buffer[3] = (value >> 24) & 0xFF;
  buffer[2] = (value >> 16) & 0xFF;
  buffer[1] = (value >> 8)  & 0xFF;
  buffer[0] = (value >> 0)  & 0xFF;
  return outfile_->Write(buffer, kWordSize);
}

bool BitcodeWrapperer::WriteVariableFields() {
  // This buffer may have to be bigger if we start using the fields
  // for larger things.
  uint8_t buffer[kMaxVariableFieldSize];
  for (vector<BCHeaderField>::iterator it = header_fields_.begin();
       it != header_fields_.end(); ++it) {
    if (!it->Write(buffer, kMaxVariableFieldSize) ||
        !outfile_->Write(buffer, it->GetTotalSize())) {
      return false;
    }
  }
  return true;
}

bool BitcodeWrapperer::ParseWrapperHeader() {
  // Make sure LLVM-defined fields have been parsed
  if (!IsInputBitcodeWrapper()) return false;
  // Check the android/pnacl fields
  if (!ReadWord(android_header_version_) ||
      !ReadWord(android_target_api_) || !ReadWord(pnacl_bc_version_)) {
    fprintf(stderr, "Error: file not long enough to contain header\n");
    return false;
  }
  if (pnacl_bc_version_ != kPnaclBitcodeVersion) {
    fprintf(stderr, "Error: bad PNaCl Bitcode version\n");
    return false;
  }
  int field_data_total = wrapper_bc_offset_ - kWordSize * kFixedFields;
  if (field_data_total > 0) {
    // Read in the variable fields. We need to allocate space for the data.
    int field_data_read = 0;

    while (field_data_read < field_data_total) {
      FillBuffer();
      size_t buffer_needed = BCHeaderField::GetDataSizeFromSerialized(
          &buffer_[cursor_]);
      if (buffer_needed > buffer_.size()) {
        buffer_.resize(buffer_needed +
                       sizeof(BCHeaderField::FixedSubfield) * 2);
        FillBuffer();
      }
      variable_field_data_.push_back(new uint8_t[buffer_needed]);

      BCHeaderField field(BCHeaderField::kInvalid, 0,
                          variable_field_data_.back());
      field.Read(&buffer_[cursor_], buffer_size_);
      header_fields_.push_back(field);
      size_t field_size = field.GetTotalSize();
      cursor_ += field_size;
      field_data_read += field_size;
      if (field_data_read > field_data_total) {
        // We read too much data, the header is corrupted
        fprintf(stderr, "Error: raw bitcode offset inconsistent with "
              "variable field data\n");
        return false;
      }

      struct IntFieldHelper {
        BCHeaderField::FixedSubfield tag;
        uint16_t len;
        uint32_t val;
      };
      IntFieldHelper tempIntField;

      switch (field.getID()) {
        case BCHeaderField::kAndroidCompilerVersion:
          if (field.Write((uint8_t*)&tempIntField,
                          sizeof(tempIntField))) {
            android_compiler_version_ = tempIntField.val;
          }
          break;
        case BCHeaderField::kAndroidOptimizationLevel:
          if (field.Write((uint8_t*)&tempIntField,
                          sizeof(tempIntField))) {
            android_optimization_level_ = tempIntField.val;
          }
          break;
        default:
          // Ignore other field types for now
          break;
      }
    }
    Seek(0);
  }
  return true;
}

bool BitcodeWrapperer::IsInputBitcodeWrapper() {
  ResetCursor();
  // First make sure that there are enough words (LLVM header)
  // to peek at.
  if (GetBufferUnreadBytes() < kLLVMFields * kWordSize) {
    FillBuffer();
    if (GetBufferUnreadBytes() < kLLVMFields * kWordSize) return false;
  }

  // Now make sure the magic number is right.
  uint32_t first_word;
  if ((!ReadWord(first_word)) ||
      (kWrapperMagicNumber != first_word)) return false;

  // Make sure the version is right.
  uint32_t second_word;
  if ((!ReadWord(second_word)) ||
      (kLLVMVersionNumber != second_word)) return false;

  // Make sure that the offset and size (for llvm) is defined.
  uint32_t bc_offset;
  uint32_t bc_size;
  if (ReadWord(bc_offset) &&
      ReadWord(bc_size)) {
    // Before returning, save the extracted values.
    wrapper_bc_offset_ = bc_offset;
    infile_bc_offset_ = bc_offset;
    wrapper_bc_size_ = bc_size;
    return true;
  }
  // If reached, unable to read wrapped header.
  return false;
}

bool BitcodeWrapperer::IsInputBitcodeFile() {
  ResetCursor();
  // First make sure that there are four bytes to peek at.
  if (GetBufferUnreadBytes() < kWordSize) {
    FillBuffer();
    if (GetBufferUnreadBytes() < kWordSize) return false;
  }
  // If reached, Check if first 4 bytes match bitcode
  // file magic number.
  return (BufferLookahead(0) == 'B') &&
      (BufferLookahead(1) == 'C') &&
      (BufferLookahead(2) == 0xc0) &&
      (BufferLookahead(3) == 0xde);
}

bool BitcodeWrapperer::BufferCopyInToOut(uint32_t size) {
  while (size > 0) {
    // Be sure buffer is non-empty before writing.
    if (0 == buffer_size_) {
      FillBuffer();
      if (0 == buffer_size_) {
        return false;
      }
    }
    // copy the buffer to the output file.
    size_t block = (buffer_size_ < size) ? buffer_size_ : size;
    if (!outfile_->Write(&buffer_[cursor_], block)) return false;
    size -= block;
    buffer_size_ = 0;
  }
  // Be sure that there isn't more bytes on the input stream.
  FillBuffer();
  return buffer_size_ == 0;
}

void BitcodeWrapperer::AddHeaderField(BCHeaderField* field) {
  header_fields_.push_back(*field);
  wrapper_bc_offset_ += field->GetTotalSize();
}

bool BitcodeWrapperer::WriteBitcodeWrapperHeader() {
  return
      // Note: This writes out the 4 word header required by llvm wrapped
      // bitcode.
      WriteWord(kWrapperMagicNumber) &&
      WriteWord(kLLVMVersionNumber) &&
      WriteWord(wrapper_bc_offset_) &&
      WriteWord(wrapper_bc_size_) &&
      // 2 fixed fields defined by Android
      WriteWord(android_header_version_) &&
      WriteWord(android_target_api_) &&
      // PNaClBitcode version
      WriteWord(kPnaclBitcodeVersion) &&
      // Common variable-length fields
      WriteVariableFields();
}

void BitcodeWrapperer::PrintWrapperHeader() {
  if (error_) {
    fprintf(stderr, "Error condition exists: the following"
            "data may not be reliable\n");
  }
  fprintf(stderr, "Wrapper magic:\t\t%x\n", kWrapperMagicNumber);
  fprintf(stderr, "LLVM Bitcode version:\t%d\n", kLLVMVersionNumber);
  fprintf(stderr, "Raw bitcode offset:\t%d\n", wrapper_bc_offset_);
  fprintf(stderr, "Raw bitcode size:\t%d\n", wrapper_bc_size_);
  fprintf(stderr, "Android header version:\t%d\n", android_header_version_);
  fprintf(stderr, "Android target API:\t%d\n", android_target_api_);
  fprintf(stderr, "PNaCl bitcode version:\t%d\n", kPnaclBitcodeVersion);
  for (size_t i = 0; i < header_fields_.size(); i++) header_fields_[i].Print();
}

bool BitcodeWrapperer::GenerateWrappedBitcodeFile() {
  if (!error_ &&
      WriteBitcodeWrapperHeader() &&
      Seek(infile_bc_offset_) &&
      BufferCopyInToOut(wrapper_bc_size_)) {
    off_t dangling = wrapper_bc_size_ & 3;
    if (dangling) {
      return outfile_->Write((const uint8_t*) "\0\0\0\0", 4 - dangling);
    }
    return true;
  }
  return false;
}

bool BitcodeWrapperer::GenerateRawBitcodeFile() {
  return !error_ && Seek(infile_bc_offset_) &&
      BufferCopyInToOut(wrapper_bc_size_);
}