• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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> &current, 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