/* * 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. */ // 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. #ifndef LLVM_WRAP_BITCODE_WRAPPERER_H__ #define LLVM_WRAP_BITCODE_WRAPPERER_H__ #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 { public: // 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_; } ~BitcodeWrapperer(); private: DISALLOW_CLASS_COPY_AND_ASSIGN(BitcodeWrapperer); // 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_; }; #endif // LLVM_WRAP_BITCODE_WRAPPERER_H__