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
31class 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
41  BCHeaderField(Tag ID, size_t len, uint8_t* data) :
42      ID_(ID), len_(len), data_(data) {}
43  size_t GetTotalSize() {
44    // Round up to 4 byte alignment
45    return (kTagLenSize + len_ + 3) & ~3;
46  }
47
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
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
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
89  static size_t GetDataSizeFromSerialized(const uint8_t* buf) {
90    FixedSubfield len;
91    ReadFixedSubfield(&len, buf + sizeof(FixedSubfield));
92    return len;
93  }
94
95  Tag getID() const {
96    return ID_;
97  }
98
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);
106  static void WriteFixedSubfield(FixedSubfield value, uint8_t* buf) {
107    buf[0] = value & 0xFF;
108    buf[1] = (value >> 8) & 0xFF;
109  }
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