123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386 |
- /*
- * 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 "bcinfo/Wrap/bitcode_wrapperer.h"
- #define LOG_TAG "bcinfo"
- #include <stdio.h>
- #include <sys/stat.h>
- #include <log/log.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 {
- ALOGE("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_ != nullptr && 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_ == nullptr) {
- 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_)) {
- ALOGW("Error: file not long enough to contain header\n");
- return false;
- }
- if (pnacl_bc_version_ != kPnaclBitcodeVersion) {
- ALOGW("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
- ALOGE("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_);
- }
|