blob: 42ad5a93664fd16ae15c701d33a25883587edc9b [file] [log] [blame]
* 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
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* See the License for the specific language governing permissions and
* limitations under the License.
// Define utility class to wrap/unwrap bitcode files. Does wrapping/unwrapping
// in such a way that the wrappered bitcode file is still a bitcode file.
#include <stdint.h>
#include <stddef.h>
#include <vector>
#include "bcinfo/Wrap/support_macros.h"
#include "bcinfo/Wrap/BCHeaderField.h"
#include "bcinfo/Wrap/wrapper_input.h"
#include "bcinfo/Wrap/wrapper_output.h"
// The bitcode wrapper header is the following 7 fixed 4-byte fields:
// 1) 0B17C0DE - The magic number expected by llvm for wrapped bitcodes
// 2) Version # 0 - The current version of wrapped bitcode files
// 3) (raw) bitcode offset
// 4) (raw) bitcode size
// 5) Android header version
// 6) Android target API
// 7) PNaCl Bitcode version
// plus 0 or more variable-length fields (consisting of ID, length, data)
// Initial buffer size. It is expanded if needed to hold large variable-size
// fields.
static const size_t kBitcodeWrappererBufferSize = 1024;
// Support class for outputting a wrapped bitcode file from a raw bitcode
// file (and optionally additional header fields), or for outputting a raw
// bitcode file from a wrapped one.
class BitcodeWrapperer {
// Create a bitcode wrapperer using the following
// input and output files.
BitcodeWrapperer(WrapperInput* infile, WrapperOutput* outfile);
// Returns true if the input file begins with a bitcode
// wrapper magic number. As a side effect, _wrapper_ fields are set.
bool IsInputBitcodeWrapper();
// Returns true if the input file begins with a bitcode
// file magic number.
bool IsInputBitcodeFile();
// Add a variable-length field to the header. The caller is responsible
// for freeing the data pointed to by the BCHeaderField.
void AddHeaderField(BCHeaderField* field);
// Generate a wrapped bitcode file from the input bitcode file
// and the current header data. Return true on success.
bool GenerateWrappedBitcodeFile();
// Unwrap the wrapped bitcode file, to the corresponding
// outfile. Return true on success.
bool GenerateRawBitcodeFile();
// Print current wrapper header fields to stderr for debugging.
void PrintWrapperHeader();
uint32_t getAndroidHeaderVersion() {
return android_header_version_;
uint32_t getAndroidTargetAPI() {
return android_target_api_;
uint32_t getAndroidCompilerVersion() {
return android_compiler_version_;
uint32_t getAndroidOptimizationLevel() {
return android_optimization_level_;
// Refills the buffer with more bytes. Does this in a way
// such that it is maximally filled.
void FillBuffer();
// Returns the number of bytes in infile.
off_t GetInFileSize() {
if (infile_ != nullptr) {
return infile_->Size();
} else {
return 0;
// Returns the offset of bitcode (i.e. the size of the wrapper header)
// if the output file were to be written now.
size_t BitcodeOffset();
// Returns true if we can read a word. If necessary, fills the buffer
// with enough characters so that there are at least a 32-bit value
// in the buffer. Returns false if there isn't a 32-bit value
// to read from the input file.
bool CanReadWord();
// Read a (32-bit) word from the input. Return true
// if able to read the word.
bool ReadWord(uint32_t& word);
// Write a (32-bit) word to the output. Return true if successful
bool WriteWord(uint32_t word);
// Write all variable-sized header fields to the output. Return true
// if successful.
bool WriteVariableFields();
// Parse the bitcode wrapper header in the infile, if any. Return true
// if successful.
bool ParseWrapperHeader();
// Returns the i-th character in front of the cursor in the buffer.
uint8_t BufferLookahead(int i) { return buffer_[cursor_ + i]; }
// Returns how many unread bytes are in the buffer.
size_t GetBufferUnreadBytes() { return buffer_size_ - cursor_; }
// Backs up the read cursor to the beginning of the input buffer.
void ResetCursor() {
cursor_ = 0;
// Generates the header sequence for the wrapped bitcode being
// generated.
bool WriteBitcodeWrapperHeader();
// Copies size bytes of infile to outfile, using the buffer.
bool BufferCopyInToOut(uint32_t size);
// Discards the old infile and replaces it with the given file.
void ReplaceInFile(WrapperInput* new_infile);
// Discards the old outfile and replaces it with the given file.
void ReplaceOutFile(WrapperOutput* new_outfile);
// Moves to the given position in the input file. Returns false
// if unsuccessful.
bool Seek(uint32_t pos);
// Clear the buffer of all contents.
void ClearBuffer();
// The input file being processed. Can be either
// a bitcode file, a wrappered bitcode file, or a secondary
// file to be wrapped.
WrapperInput* infile_;
// The output file being generated. Can be either
// a bitcode file, a wrappered bitcode file, or a secondary
// unwrapped file.
WrapperOutput* outfile_;
// A buffer of bytes read from the input file.
std::vector<uint8_t> buffer_;
// The number of bytes that were read from the input file
// into the buffer.
size_t buffer_size_;
// The index to the current read point within the buffer.
size_t cursor_;
// True when eof of input is reached.
bool infile_at_eof_;
// The 32-bit value defining the offset of the raw bitcode in the input file.
uint32_t infile_bc_offset_;
// The 32-bit value defining the generated offset of the wrapped bitcode.
// This value changes as new fields are added with AddHeaderField
uint32_t wrapper_bc_offset_;
// The 32-bit value defining the size of the raw wrapped bitcode.
uint32_t wrapper_bc_size_;
// Android header version and target API
uint32_t android_header_version_;
uint32_t android_target_api_;
uint32_t android_compiler_version_;
uint32_t android_optimization_level_;
// PNaCl bitcode version
uint32_t pnacl_bc_version_;
// Vector of variable header fields
std::vector<BCHeaderField> header_fields_;
// If any bufferdata from header fields is owned, it is stored here and
// freed on destruction.
std::vector<uint8_t*> variable_field_data_;
// True if there was an error condition (e.g. the file is not bitcode)
bool error_;