1 /*
2  * Copyright 2012, The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef LLVM_WRAP_BCHEADER_FIELD_H__
18 #define LLVM_WRAP_BCHEADER_FIELD_H__
19 
20 #include <stdint.h>
21 #include <stdio.h>
22 #include <string.h>
23 
24 // Class representing a variable-size metadata field in the bitcode header.
25 // Also contains the list of known Tag IDs.
26 // Contains a pointer to the data but does not own the data, so it can be
27 // copied with the trivial copy constructor/assignment operator.
28 
29 // The serialized format has 2 fixed subfields (ID and length) and the
30 // variable-length data subfield
31 class BCHeaderField {
32  public:
33   typedef enum {
34     kInvalid = 0,
35     kBitcodeHash = 1,
36     kAndroidCompilerVersion = 0x4001,
37     kAndroidOptimizationLevel = 0x4002
38   } Tag;
39   typedef uint16_t FixedSubfield;
40 
BCHeaderField(Tag ID,size_t len,uint8_t * data)41   BCHeaderField(Tag ID, size_t len, uint8_t* data) :
42       ID_(ID), len_(len), data_(data) {}
GetTotalSize()43   size_t GetTotalSize() {
44     // Round up to 4 byte alignment
45     return (kTagLenSize + len_ + 3) & ~3;
46   }
47 
Write(uint8_t * buf,size_t buf_len)48   bool Write(uint8_t* buf, size_t buf_len) {
49     size_t fields_len = kTagLenSize + len_;
50     size_t pad_len = (4 - (fields_len & 3)) & 3;
51     // Ensure buffer is large enough and that length can be represented
52     // in 16 bits
53     const size_t max_uint16_t = 65535;
54     if (buf_len < fields_len + pad_len ||
55         len_ > max_uint16_t) return false;
56 
57     WriteFixedSubfield(static_cast<FixedSubfield>(ID_), buf);
58     WriteFixedSubfield(static_cast<FixedSubfield>(len_),
59                        buf + sizeof(FixedSubfield));
60     memcpy(buf + kTagLenSize, data_, len_);
61     // Pad out to 4 byte alignment
62     if (pad_len) {
63       memset(buf + fields_len, 0, pad_len);
64     }
65     return true;
66   }
67 
Read(const uint8_t * buf,size_t buf_len)68   bool Read(const uint8_t* buf, size_t buf_len) {
69     if (buf_len < kTagLenSize) return false;
70     FixedSubfield field;
71     ReadFixedSubfield(&field, buf);
72     ID_ = static_cast<Tag>(field);
73     ReadFixedSubfield(&field, buf + sizeof(FixedSubfield));
74     len_ = static_cast<size_t>(field);
75     if (buf_len < kTagLenSize + len_) return false;
76     memcpy(data_, buf + kTagLenSize, len_);
77     return true;
78   }
79 
Print()80   void Print() {
81     fprintf(stderr, "Field ID: %d, data length %d, total length %d\n",
82             ID_, static_cast<int>(len_), static_cast<int>(GetTotalSize()));
83     fprintf(stderr, "Data:");
84     for (size_t i = 0; i < len_; i++) fprintf(stderr, "0x%x ", data_[i]);
85     fprintf(stderr, "\n");
86   }
87 
88   // Get the data size from a serialized field to allow allocation
GetDataSizeFromSerialized(const uint8_t * buf)89   static size_t GetDataSizeFromSerialized(const uint8_t* buf) {
90     FixedSubfield len;
91     ReadFixedSubfield(&len, buf + sizeof(FixedSubfield));
92     return len;
93   }
94 
getID()95   Tag getID() const {
96     return ID_;
97   }
98 
getLen()99   size_t getLen() const {
100     return len_;
101   }
102 
103  private:
104  // Combined size of the fixed subfields
105  const static size_t kTagLenSize = 2 * sizeof(FixedSubfield);
WriteFixedSubfield(FixedSubfield value,uint8_t * buf)106   static void WriteFixedSubfield(FixedSubfield value, uint8_t* buf) {
107     buf[0] = value & 0xFF;
108     buf[1] = (value >> 8) & 0xFF;
109   }
ReadFixedSubfield(FixedSubfield * value,const uint8_t * buf)110   static void ReadFixedSubfield(FixedSubfield* value, const uint8_t* buf) {
111     *value = buf[0] | buf[1] << 8;
112   }
113   Tag ID_;
114   size_t len_;
115   uint8_t *data_;
116 };
117 
118 #endif  // LLVM_WRAP_BCHEADER_FIELD_H__
119