1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 *
4 * HDF is dual licensed: you can use it either under the terms of
5 * the GPL, or the BSD license, at your option.
6 * See the LICENSE file in the root of this repository for complete details.
7 */
8
9 #include "bytecode_gen.h"
10 #include <string>
11 #include "file.h"
12 #include "logger.h"
13 #include "opcode.h"
14
15 using namespace OHOS::Hardware;
16
ByteCodeGen(std::shared_ptr<Ast> ast)17 ByteCodeGen::ByteCodeGen(std::shared_ptr<Ast> ast)
18 : Generator(ast),
19 needAlign_(false),
20 dummyOutput_(false),
21 writeSize_(0)
22 {
23 }
24
Output()25 bool ByteCodeGen::Output()
26 {
27 if (!Initialize()) {
28 return false;
29 }
30
31 if (!ByteCodeConvert()) {
32 return false;
33 }
34
35 if (!ByteCodeWrite(true)) {
36 return false;
37 }
38
39 if (!ByteCodeWrite(false)) {
40 return false;
41 }
42
43 if (Option::Instance().ShouldGenHexDump()) {
44 return Hexdump();
45 }
46
47 return true;
48 }
49
Initialize()50 bool ByteCodeGen::Initialize()
51 {
52 auto opt = Option::Instance();
53 std::string outFileName = Util::File::StripSuffix(opt.GetOutputName());
54 if (outFileName.empty()) {
55 outFileName = opt.GetSourceNameBase() + ".hcb";
56 }
57
58 if (outFileName.find(".hcb") == std::string::npos) {
59 outFileName.append(".hcb");
60 }
61
62 ofs_.open(outFileName, std::ofstream::out | std::ofstream::binary);
63 if (!ofs_.is_open()) {
64 Logger().Error() << "failed to open output file: " << outFileName;
65 return false;
66 }
67 Logger().Debug() << "output: " << outFileName;
68
69 needAlign_ = opt.ShouldAlign();
70 outFileName_ = std::move(outFileName);
71 return true;
72 }
73
ByteCodeConvert()74 bool ByteCodeGen::ByteCodeConvert()
75 {
76 return ast_->WalkBackward([this](std::shared_ptr<AstObject> &object, int32_t depth) {
77 (void)depth;
78 if (object->IsNode() && ConfigNode::CastFrom(object)->GetNodeType() == NODE_TEMPLATE) {
79 object->Separate();
80 return NOERR;
81 }
82 auto opcode = ToOpCode(object->Type());
83 if (opcode.opCode == 0) {
84 Logger().Error() << object->SourceInfo() << "cannot covert type " << object->Type() << " to opcode";
85 return EINVALF;
86 }
87 object->SetOpCode(opcode.opCode);
88 CalculateSize(object);
89 return NOERR;
90 });
91 }
92
Align(uint32_t size) const93 uint32_t ByteCodeGen::Align(uint32_t size) const
94 {
95 return needAlign_ ? ((size + ALIGN_SIZE - 1) & (~(ALIGN_SIZE - 1))) : size;
96 }
97
ToOpCode(uint32_t objectType)98 const OpCode &ByteCodeGen::ToOpCode(uint32_t objectType)
99 {
100 static std::map<uint32_t, OpCode> byteCodeMap = {
101 {PARSEROP_UINT8, {HCS_BYTE_OP, BYTE_SIZE, "Uint8"} },
102 {PARSEROP_UINT16, {HCS_WORD_OP, WORD_SIZE, "Uint16"} },
103 {PARSEROP_UINT32, {HCS_DWORD_OP, DWORD_SIZE, "Uint32"} },
104 {PARSEROP_UINT64, {HCS_QWORD_OP, QWORD_SIZE, "Uint64"} },
105 {PARSEROP_STRING, {HCS_STRING_OP, 0, "String"} },
106 {PARSEROP_ARRAY, {HCS_ARRAY_OP, WORD_SIZE, "Array"} }, /* ElementCount - WORD */
107 {PARSEROP_CONFNODE, {HCS_NODE_OP, DWORD_SIZE, "ConfigNode"}}, /* SubSize - DWORD */
108 {PARSEROP_CONFTERM, {HCS_TERM_OP, 0, "ConfigTerm"} },
109 {PARSEROP_NODEREF, {HCS_NODEREF_OP, DWORD_SIZE, "NodeRef"}}, /* RefHashCode - DWORD */
110 };
111 return byteCodeMap[objectType];
112 }
113
Write(const std::string & data)114 void ByteCodeGen::Write(const std::string &data)
115 {
116 Write(data.c_str(), static_cast<uint32_t>(data.size() + 1));
117 }
118
119 template <typename T>
Write(T & data)120 void ByteCodeGen::Write(T &data)
121 {
122 auto p = &data;
123 uint32_t size = sizeof(data);
124 auto d = reinterpret_cast<const char *>(p);
125 Write(d, size);
126 }
127
Write(const char * data,uint32_t size)128 void ByteCodeGen::Write(const char *data, uint32_t size)
129 {
130 FsWrite(data, size);
131 auto alignSize = Align(size);
132 auto stubSize = alignSize - size;
133
134 if (stubSize != 0) {
135 static char stubData[ALIGN_SIZE] = {0};
136 FsWrite(stubData, stubSize);
137 }
138
139 writeSize_ += alignSize;
140 }
141
CalculateSize(const std::shared_ptr<AstObject> & object) const142 void ByteCodeGen::CalculateSize(const std::shared_ptr<AstObject> &object) const
143 {
144 uint32_t size = Align(OPCODE_BYTE_WIDTH) + Align(ToOpCode(object->Type()).size);
145 switch (object->OpCode()) {
146 case HCS_NODE_OP: /* fall-through */
147 case HCS_TERM_OP:
148 /* name string */
149 size += Align(object->Name().size() + 1); // add 1 for '\0'
150 break;
151 case HCS_STRING_OP:
152 size += Align(object->StringValue().size() + 1);
153 break;
154 default:
155 break;
156 }
157
158 auto child = object->Child();
159 uint32_t subSize = 0;
160 while (child != nullptr) {
161 subSize += child->GetSize();
162 child = child->Next();
163 }
164
165 object->SetSize(subSize + size);
166 object->SetSubSize(subSize);
167 }
168
ByteCodeWrite(bool dummy)169 bool ByteCodeGen::ByteCodeWrite(bool dummy)
170 {
171 dummyOutput_ = dummy;
172 writeSize_ = 0;
173
174 HcbHeader header = {
175 .magicNumber = HCB_MAGIC_NUM,
176 .versionMajor = 0,
177 .versionMinor = 0,
178 .checkSum = 0,
179 .totalSize = static_cast<int32_t>(
180 Option::Instance().ShouldAlign() ? -ast_->GetAstRoot()->GetSize() : ast_->GetAstRoot()->GetSize()),
181 };
182 Option::Instance().GetVersion(header.versionMinor, header.versionMajor);
183 Write(header);
184 if (WriteBad()) {
185 return false;
186 }
187
188 return ByteCodeWriteWalk();
189 }
190
ByteCodeWriteWalk()191 bool ByteCodeGen::ByteCodeWriteWalk()
192 {
193 return ast_->WalkForward([this](std::shared_ptr<AstObject> ¤t, int32_t depth) {
194 (void)depth;
195 current->SetHash(writeSize_);
196 auto opcode = current->OpCode();
197 Write(opcode);
198 switch (current->OpCode()) {
199 case HCS_BYTE_OP:
200 case HCS_WORD_OP:
201 case HCS_DWORD_OP:
202 case HCS_QWORD_OP: {
203 auto value = current->IntegerValue();
204 Write(reinterpret_cast<const char *>(&value), ToOpCode(current->Type()).size);
205 break;
206 }
207 case HCS_STRING_OP:
208 Write(current->StringValue());
209 break;
210 case HCS_TERM_OP:
211 Write(current->Name());
212
213 break;
214 case HCS_NODE_OP: {
215 Write(current->Name());
216 auto subSize = current->GetSubSize();
217 Write(subSize);
218 break;
219 }
220 case HCS_ARRAY_OP: {
221 uint16_t arraySize = ConfigArray::CastFrom(current)->ArraySize();
222 Write(arraySize);
223 break;
224 }
225 case HCS_NODEREF_OP: {
226 auto term = ConfigTerm::CastFrom(current->Parent());
227 uint32_t hashCode = term->RefNode().lock()->GetHash();
228 Write(hashCode);
229 break;
230 }
231 default:
232 break;
233 }
234 if (WriteBad()) {
235 return EOUTPUT;
236 }
237 return NOERR;
238 });
239 }
240
FsWrite(const char * data,uint32_t size)241 void ByteCodeGen::FsWrite(const char *data, uint32_t size)
242 {
243 if (dummyOutput_) {
244 return;
245 }
246
247 ofs_.write(data, size);
248 }
249
WriteBad()250 bool ByteCodeGen::WriteBad()
251 {
252 if (ofs_.bad()) {
253 Logger().Error() << "failed to write file " << outFileName_;
254 return true;
255 }
256 return false;
257 }
258
HexdumpInitialize(FILE * & in,FILE * & out)259 bool ByteCodeGen::HexdumpInitialize(FILE *&in, FILE *&out)
260 {
261 ofs_.close();
262 std::string hexdumpOutName = Util::File::StripSuffix(outFileName_).append("_hex.c");
263
264 in = fopen(outFileName_.data(), "rb");
265 if (in == nullptr) {
266 Logger().Error() << "failed to open " << outFileName_;
267 return false;
268 }
269
270 out = fopen(hexdumpOutName.data(), "wb");
271 if (out == nullptr) {
272 fclose(in);
273 in = nullptr;
274 Logger().Error() << "failed to open " << hexdumpOutName;
275 return false;
276 }
277 return true;
278 }
279
Hexdump()280 bool ByteCodeGen::Hexdump()
281 {
282 FILE *in = nullptr;
283 FILE *out = nullptr;
284 if (!HexdumpInitialize(in, out)) {
285 return false;
286 }
287
288 auto ret = HexdumpOutput(in, out);
289 (void)fclose(in);
290 (void)fclose(out);
291
292 return ret;
293 }
294
HexdumpOutput(FILE * in,FILE * out)295 bool ByteCodeGen::HexdumpOutput(FILE *in, FILE *out)
296 {
297 constexpr const char *HCS_HEXDUMP_ENTRY_SYMBOL = "hdfConfigEntrySymbol";
298 constexpr const int PRINT_SKIP_STEP = 2;
299 constexpr const int NUMS_PER_LINE = 16;
300 std::string prefix = Option::Instance().GetSymbolPrefix();
301 if (fprintf(out, "static const unsigned char g_%s%s[] = {\n", prefix.data(), HCS_HEXDUMP_ENTRY_SYMBOL) < 0) {
302 return false;
303 }
304 uint32_t writeCount = 0;
305 int32_t byte;
306 while ((byte = getc(in)) != EOF) {
307 if (fprintf(out, "%s0x%02x", (writeCount % NUMS_PER_LINE) ? ", " : &",\n "[PRINT_SKIP_STEP * !writeCount],
308 byte) < 0) {
309 return false;
310 }
311 writeCount++;
312 }
313 if (fprintf(out, "\n};\n") < 0) {
314 return false;
315 }
316
317 if (fprintf(out, "static const unsigned int g_%sLen = %u;\n", HCS_HEXDUMP_ENTRY_SYMBOL, writeCount) < 0) {
318 return false;
319 }
320 if (fprintf(out,
321 "void HdfGetBuildInConfigData(const unsigned char** data, unsigned int* size)\n"
322 "{\n"
323 " *data = g_%s%s;\n"
324 " *size = g_%s%sLen;\n"
325 "}",
326 prefix.data(), HCS_HEXDUMP_ENTRY_SYMBOL, prefix.data(), HCS_HEXDUMP_ENTRY_SYMBOL) < 0) {
327 return false;
328 }
329 return true;
330 }
331