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> &current, 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