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 if (object->IsNode() && ConfigNode::CastFrom(object)->GetNodeType() == NODE_TEMPLATE) {
78 object->Separate();
79 return NOERR;
80 }
81 auto opcode = ToOpCode(object->Type());
82 if (opcode.opCode == 0) {
83 Logger().Error() << object->SourceInfo() << "cannot covert type " << object->Type() << " to opcode";
84 return EINVALF;
85 }
86 object->SetOpCode(opcode.opCode);
87 CalculateSize(object);
88 return NOERR;
89 });
90 }
91
Align(uint32_t size) const92 uint32_t ByteCodeGen::Align(uint32_t size) const
93 {
94 return needAlign_ ? ((size + ALIGN_SIZE - 1) & (~(ALIGN_SIZE - 1))) : size;
95 }
96
ToOpCode(uint32_t objectType)97 const OpCode &ByteCodeGen::ToOpCode(uint32_t objectType)
98 {
99 static std::map<uint32_t, OpCode> byteCodeMap = {
100 {PARSEROP_UINT8, {HCS_BYTE_OP, BYTE_SIZE, "Uint8"} },
101 {PARSEROP_UINT16, {HCS_WORD_OP, WORD_SIZE, "Uint16"} },
102 {PARSEROP_UINT32, {HCS_DWORD_OP, DWORD_SIZE, "Uint32"} },
103 {PARSEROP_UINT64, {HCS_QWORD_OP, QWORD_SIZE, "Uint64"} },
104 {PARSEROP_STRING, {HCS_STRING_OP, 0, "String"} },
105 {PARSEROP_ARRAY, {HCS_ARRAY_OP, WORD_SIZE, "Array"} }, /* ElementCount - WORD */
106 {PARSEROP_CONFNODE, {HCS_NODE_OP, DWORD_SIZE, "ConfigNode"}}, /* SubSize - DWORD */
107 {PARSEROP_CONFTERM, {HCS_TERM_OP, 0, "ConfigTerm"} },
108 {PARSEROP_NODEREF, {HCS_NODEREF_OP, DWORD_SIZE, "NodeRef"}}, /* RefHashCode - DWORD */
109 };
110 return byteCodeMap[objectType];
111 }
112
Write(const std::string & data)113 void ByteCodeGen::Write(const std::string &data)
114 {
115 Write(data.c_str(), static_cast<uint32_t>(data.size() + 1));
116 }
117
118 template <typename T>
Write(T & data)119 void ByteCodeGen::Write(T &data)
120 {
121 auto p = &data;
122 uint32_t size = sizeof(data);
123 auto d = reinterpret_cast<const char *>(p);
124 Write(d, size);
125 }
126
Write(const char * data,uint32_t size)127 void ByteCodeGen::Write(const char *data, uint32_t size)
128 {
129 FsWrite(data, size);
130 static char stubData[ALIGN_SIZE] = {0};
131 auto alignSize = Align(size);
132 auto stubSize = alignSize - size;
133
134 if (stubSize != 0) {
135 FsWrite(stubData, stubSize);
136 }
137
138 writeSize_ += alignSize;
139 }
140
CalculateSize(const std::shared_ptr<AstObject> & object)141 void ByteCodeGen::CalculateSize(const std::shared_ptr<AstObject> &object)
142 {
143 uint32_t size = Align(OPCODE_BYTE_WIDTH) + Align(ToOpCode(object->Type()).size);
144 switch (object->OpCode()) {
145 case HCS_NODE_OP: /* fall-through */
146 case HCS_TERM_OP:
147 /* name string */
148 size += Align(object->Name().size() + 1); // add 1 for '\0'
149 break;
150 case HCS_STRING_OP:
151 size += Align(object->StringValue().size() + 1);
152 break;
153 default:
154 break;
155 }
156
157 auto child = object->Child();
158 uint32_t subSize = 0;
159 while (child != nullptr) {
160 subSize += child->GetSize();
161 child = child->Next();
162 }
163
164 object->SetSize(subSize + size);
165 object->SetSubSize(subSize);
166 }
167
ByteCodeWrite(bool dummy)168 bool ByteCodeGen::ByteCodeWrite(bool dummy)
169 {
170 dummyOutput_ = dummy;
171 writeSize_ = 0;
172
173 HcbHeader header = {
174 .magicNumber = HCB_MAGIC_NUM,
175 .versionMajor = 0,
176 .versionMinor = 0,
177 .checkSum = 0,
178 .totalSize = static_cast<int32_t>(
179 Option::Instance().ShouldAlign() ? -ast_->GetAstRoot()->GetSize() : ast_->GetAstRoot()->GetSize()),
180 };
181 Option::Instance().GetVersion(header.versionMinor, header.versionMajor);
182 Write(header);
183 if (WriteBad()) {
184 return false;
185 }
186
187 return ByteCodeWriteWalk();
188 }
189
ByteCodeWriteWalk()190 bool ByteCodeGen::ByteCodeWriteWalk()
191 {
192 return ast_->WalkForward([this](std::shared_ptr<AstObject> ¤t, int32_t depth) {
193 current->SetHash(writeSize_);
194 auto opcode = current->OpCode();
195 Write(opcode);
196 switch (current->OpCode()) {
197 case HCS_BYTE_OP:
198 case HCS_WORD_OP:
199 case HCS_DWORD_OP:
200 case HCS_QWORD_OP: {
201 auto value = current->IntegerValue();
202 Write(reinterpret_cast<const char *>(&value), ToOpCode(current->Type()).size);
203 break;
204 }
205 case HCS_STRING_OP:
206 Write(current->StringValue());
207 break;
208 case HCS_TERM_OP:
209 Write(current->Name());
210
211 break;
212 case HCS_NODE_OP: {
213 Write(current->Name());
214 auto subSize = current->GetSubSize();
215 Write(subSize);
216 break;
217 }
218 case HCS_ARRAY_OP: {
219 uint16_t arraySize = ConfigArray::CastFrom(current)->ArraySize();
220 Write(arraySize);
221 break;
222 }
223 case HCS_NODEREF_OP: {
224 auto term = ConfigTerm::CastFrom(current->Parent());
225 uint32_t hashCode = term->RefNode().lock()->GetHash();
226 Write(hashCode);
227 break;
228 }
229 default:
230 break;
231 }
232 if (WriteBad()) {
233 return EOUTPUT;
234 }
235 return NOERR;
236 });
237 }
238
FsWrite(const char * data,uint32_t size)239 void ByteCodeGen::FsWrite(const char *data, uint32_t size)
240 {
241 if (dummyOutput_)
242 return;
243
244 ofs_.write(data, size);
245 }
246
WriteBad()247 bool ByteCodeGen::WriteBad()
248 {
249 if (ofs_.bad()) {
250 Logger().Error() << "failed to write file " << outFileName_;
251 return true;
252 }
253 return false;
254 }
255
HexdumpInitialize(FILE * & in,FILE * & out)256 bool ByteCodeGen::HexdumpInitialize(FILE *&in, FILE *&out)
257 {
258 ofs_.close();
259 std::string hexdumpOutName = Util::File::StripSuffix(outFileName_).append("_hex.c");
260
261 in = fopen(outFileName_.data(), "rb");
262 if (in == nullptr) {
263 Logger().Error() << "failed to open " << outFileName_;
264 return false;
265 }
266
267 out = fopen(hexdumpOutName.data(), "wb");
268 if (out == nullptr) {
269 fclose(in);
270 in = nullptr;
271 Logger().Error() << "failed to open " << hexdumpOutName;
272 return false;
273 }
274 return true;
275 }
276
Hexdump()277 bool ByteCodeGen::Hexdump()
278 {
279 FILE *in = nullptr;
280 FILE *out = nullptr;
281 if (!HexdumpInitialize(in, out)) {
282 return false;
283 }
284
285 auto ret = HexdumpOutput(in, out);
286 fclose(in);
287 fclose(out);
288
289 return ret;
290 }
291
HexdumpOutput(FILE * in,FILE * out)292 bool ByteCodeGen::HexdumpOutput(FILE *in, FILE *out)
293 {
294 constexpr const char *HCS_HEXDUMP_ENTRY_SYMBOL = "hdfConfigEntrySymbol";
295 constexpr const int PRINT_SKIP_STEP = 2;
296 constexpr const int NUMS_PER_LINE = 16;
297 std::string prefix = Option::Instance().GetSymbolPrefix();
298 if (fprintf(out, "static const unsigned char g_%s%s[] = {\n", prefix.data(), HCS_HEXDUMP_ENTRY_SYMBOL) < 0) {
299 return false;
300 }
301 uint32_t writeCount = 0;
302 int32_t byte;
303 while ((byte = getc(in)) != EOF) {
304 if (fprintf(out, "%s0x%02x", (writeCount % NUMS_PER_LINE) ? ", " : &",\n "[PRINT_SKIP_STEP * !writeCount],
305 byte) < 0) {
306 return false;
307 }
308 writeCount++;
309 }
310 if (fprintf(out, "\n};\n") < 0) {
311 return false;
312 }
313
314 if (fprintf(out, "static const unsigned int g_%sLen = %u;\n", HCS_HEXDUMP_ENTRY_SYMBOL, writeCount) < 0) {
315 return false;
316 }
317 if (fprintf(out,
318 "void HdfGetBuildInConfigData(const unsigned char** data, unsigned int* size)\n"
319 "{\n"
320 " *data = g_%s%s;\n"
321 " *size = g_%s%sLen;\n"
322 "}",
323 prefix.data(), HCS_HEXDUMP_ENTRY_SYMBOL, prefix.data(), HCS_HEXDUMP_ENTRY_SYMBOL) < 0) {
324 return false;
325 }
326 return true;
327 }
328