1 /*
2 * Copyright (c) 2020-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 "hcs_decompiler.h"
10 #include <string.h>
11 #include "hcs_option.h"
12 #include "hcs_file.h"
13 #include "hcs_opcode.h"
14 #include "hcs_parser.h"
15 #include "hcs_log.h"
16 #include "hcs_compiler.h"
17
18 static ParserObject *RebuildObject(uint8_t opCode);
19
HcsVerifyHbcFile()20 static bool HcsVerifyHbcFile()
21 {
22 struct HcsFile *input = HcsSourceQueueTop();
23 HbcHeader header = { 0 };
24 uint32_t size = HcsSourceFileRead(input, (uint8_t*)&header, sizeof(header));
25 if (size != sizeof(header)) {
26 HCS_ERROR("Illegal hcb file, invalid file size");
27 return false;
28 }
29
30 if (header.magicNumber != HBC_MAGIC_NUM) {
31 HCS_ERROR("file %s is not a hcb file", HcsGetCurrentSourceName());
32 return false;
33 }
34 if (header.totalSize < 0) {
35 HcsOptSetAlign(true);
36 header.totalSize = -header.totalSize;
37 }
38 uint32_t fileSize = HcsSourceFileGetSize(input);
39 if (fileSize != (sizeof(header) + header.totalSize)) {
40 HCS_ERROR("size mismatch, may broken file");
41 return false;
42 }
43
44 HCS_INFO("Build by hcs compile %u.%u", header.versionMajor, header.versionMinor);
45 HCS_INFO("hcb file total size: %d\n", header.totalSize);
46 return true;
47 }
48
49 #define HCS_STRING_READ_BUF_LEN 256
50
ReadCString()51 static char *ReadCString()
52 {
53 char buff[HCS_STRING_READ_BUF_LEN] = {'\0'};
54 int32_t index = 0;
55 while (HcsSourceFileRead(NULL, (uint8_t*)&buff[index], sizeof(char))) {
56 if (index == HCS_STRING_READ_BUF_LEN || buff[index] == '\0') {
57 break;
58 }
59 index++;
60 }
61
62 if (index >= HCS_STRING_READ_BUF_LEN || buff[index] != '\0') {
63 HCS_ERROR("read unterminated or too long c string at %u", HcsGetSourceFilePos(NULL));
64 return NULL;
65 }
66 uint32_t stringFullSize = index + 1;
67 uint32_t alignAppendSize = HcsAlign(stringFullSize) - stringFullSize;
68 if (alignAppendSize) {
69 uint8_t alignReadBuffer[ALIGN_SIZE];
70 if (HcsSourceFileRead(NULL, alignReadBuffer, alignAppendSize) != alignAppendSize) {
71 HCS_ERROR("read c string length mismatch %u", HcsGetSourceFilePos(NULL));
72 return NULL;
73 }
74 }
75 char *str = strdup(buff);
76 if (str == NULL) {
77 HCS_ERROR("%s:%d OOM", __func__, __LINE__);
78 return NULL;
79 }
80 return str;
81 }
82
ReadUint64(uint64_t * value)83 static bool ReadUint64(uint64_t *value)
84 {
85 if (HcsSourceFileRead(NULL, (uint8_t*)value, sizeof(*value)) != sizeof(*value)) {
86 HCS_ERROR("fail to read uint64");
87 return false;
88 }
89 return true;
90 }
91
ReadUint32(uint32_t * value)92 static bool ReadUint32(uint32_t *value)
93 {
94 if (HcsSourceFileRead(NULL, (uint8_t*)value, sizeof(*value)) != sizeof(*value)) {
95 HCS_ERROR("fail to read uint32");
96 return false;
97 }
98
99 return true;
100 }
101
ReadUint16(uint16_t * value)102 static bool ReadUint16(uint16_t *value)
103 {
104 if (HcsAlign(sizeof(uint16_t)) != sizeof(uint16_t)) {
105 uint32_t readValue = 0;
106 if (!ReadUint32(&readValue)) {
107 return false;
108 }
109 *value = (uint16_t)readValue;
110 return true;
111 }
112 if (HcsSourceFileRead(NULL, (uint8_t*)value, sizeof(*value)) != sizeof(*value)) {
113 HCS_ERROR("fail to read uint16");
114 return false;
115 }
116
117 return true;
118 }
119
ReadUint8(uint8_t * value)120 static bool ReadUint8(uint8_t *value)
121 {
122 if (HcsAlign(sizeof(uint8_t)) != sizeof(uint8_t)) {
123 uint32_t readValue = 0;
124 if (!ReadUint32(&readValue)) {
125 return false;
126 }
127 *value = (uint8_t)readValue;
128 return true;
129 }
130
131 if (HcsSourceFileRead(NULL, value, sizeof(*value)) != sizeof(*value)) {
132 HCS_ERROR("fail to read uint8");
133 return false;
134 }
135
136 return true;
137 }
138
NextByteCode(uint32_t * byteCode)139 static bool NextByteCode(uint32_t *byteCode)
140 {
141 switch (HcsAlign(OPCODE_BYTE_WIDTH)) {
142 case BYTE_SIZE: {
143 uint8_t value = 0;
144 bool ret = ReadUint8(&value);
145 *byteCode = value;
146 return ret;
147 }
148 case DWORD_SIZE:
149 return ReadUint32(byteCode);
150 default:
151 break;
152 }
153 return false;
154 }
155
RebuildNode()156 static ParserObject *RebuildNode()
157 {
158 uint32_t nodeHash = HcsGetSourceFilePos(NULL) - HcsAlign(OPCODE_BYTE_WIDTH);
159 char *nodeName = ReadCString();
160 if (nodeName == NULL) {
161 return NULL;
162 }
163
164 ParserObject *node = HcsNewConfigNode(nodeName, CONFIG_NODE_NOREF, NULL);
165 if (node == NULL) {
166 HcsMemFree(nodeName);
167 return NULL;
168 }
169 uint32_t nodeSize = 0;
170 if (!ReadUint32(&nodeSize)) {
171 goto ERROR;
172 }
173 node->objectBase.hash = nodeHash;
174 node->objectBase.size = nodeSize;
175 uint32_t pos = HcsGetSourceFilePos(NULL); // node content start
176 uint64_t nodeEnd = nodeSize + pos;
177 while (pos < nodeEnd) {
178 uint32_t childOpCode;
179 if (!NextByteCode(&childOpCode)) {
180 HCS_ERROR("broken node");
181 goto ERROR;
182 }
183 ParserObject *child = RebuildObject(childOpCode);
184 if (child == NULL) {
185 goto ERROR;
186 }
187 HcsAstAddChild(node, child);
188 pos = HcsGetSourceFilePos(NULL);
189 }
190
191 return node;
192 ERROR:
193 HcsDeleteParserObjectTree(node);
194 return NULL;
195 }
196
RebuildTerm()197 static ParserObject *RebuildTerm()
198 {
199 char *termName = ReadCString();
200 if (termName == NULL) {
201 return NULL;
202 }
203 uint32_t childOpCode;
204 if (!NextByteCode(&childOpCode)) {
205 HCS_ERROR("broken term");
206 HcsMemFree(termName);
207 return NULL;
208 }
209
210 ParserObject *value = RebuildObject(childOpCode);
211 if (value == NULL) {
212 HcsMemFree(termName);
213 return NULL;
214 }
215 ParserObject *term = HcsNewConfigTerm(termName, value);
216 if (term == NULL) {
217 HcsMemFree(termName);
218 HcsAstFreeObject(value);
219 }
220 return term;
221 }
222
RebuildArray()223 static ParserObject *RebuildArray()
224 {
225 uint16_t arraySize = 0;
226 if (!ReadUint16(&arraySize)) {
227 return NULL;
228 }
229 ParserObject *array = HcsNewParserObject(NULL, PARSEROP_ARRAY, 0);
230 if (array == NULL) {
231 return NULL;
232 }
233 for (int32_t i = 0; i < arraySize; ++i) {
234 uint32_t elementOpCode;
235 if (!NextByteCode(&elementOpCode)) {
236 HCS_ERROR("broken term");
237 goto ERROR;
238 }
239 ParserObject *element = RebuildObject(elementOpCode);
240 if (element == NULL) {
241 goto ERROR;
242 }
243 HcsAstAddChild(array, element);
244 }
245 return array;
246 ERROR:
247 HcsDeleteParserObjectTree(array);
248 return NULL;
249 }
250
RebuildNumberObject(uint8_t type)251 static ParserObject *RebuildNumberObject(uint8_t type)
252 {
253 uint8_t u8Value = 0;
254 uint16_t u16Value = 0;
255 uint32_t u32Value = 0;
256 uint64_t u64Value = 0;
257 switch (type) {
258 case HCS_BYTE_OP:
259 if (!ReadUint8(&u8Value)) {
260 return NULL;
261 }
262 return HcsNewParserObject(NULL, PARSEROP_UINT8, u8Value);
263 case HCS_WORD_OP:
264 if (!ReadUint16(&u16Value)) {
265 return NULL;
266 }
267 return HcsNewParserObject(NULL, PARSEROP_UINT16, u16Value);
268 case HCS_DWORD_OP:
269 if (!ReadUint32(&u32Value)) {
270 return NULL;
271 }
272 return HcsNewParserObject(NULL, PARSEROP_UINT32, u32Value);
273 case HCS_QWORD_OP:
274 if (!ReadUint64(&u64Value)) {
275 return NULL;
276 }
277 return HcsNewParserObject(NULL, PARSEROP_UINT64, u64Value);
278 default:
279 break;
280 }
281
282 return NULL;
283 }
284
RebuildStringObject()285 static ParserObject *RebuildStringObject()
286 {
287 char *objectName = ReadCString();
288 if (objectName == NULL) {
289 return NULL;
290 }
291 ParserObject *object = HcsNewParserObject(NULL, PARSEROP_STRING, (uint64_t)objectName);
292 if (object == NULL) {
293 HcsMemFree(objectName);
294 }
295 return object;
296 }
297
RebuildNodeRefObject()298 static ParserObject *RebuildNodeRefObject()
299 {
300 uint32_t refNodeHash = 0;
301 if (!ReadUint32(&refNodeHash)) {
302 return NULL;
303 }
304
305 return HcsNewParserObject(NULL, PARSEROP_NODEREF, refNodeHash);
306 }
307
RebuildObject(uint8_t opCode)308 static ParserObject *RebuildObject(uint8_t opCode)
309 {
310 switch (opCode) {
311 case HCS_NODE_OP:
312 return RebuildNode();
313 case HCS_TERM_OP:
314 return RebuildTerm();
315 case HCS_NODEREF_OP:
316 return RebuildNodeRefObject();
317 case HCS_BYTE_OP: /* fall-through */
318 case HCS_WORD_OP: /* fall-through */
319 case HCS_DWORD_OP: /* fall-through */
320 case HCS_QWORD_OP:
321 return RebuildNumberObject(opCode);
322 case HCS_ARRAY_OP:
323 return RebuildArray();
324 case HCS_STRING_OP:
325 return RebuildStringObject();
326 default:
327 break;
328 }
329 HCS_ERROR("unknown OpCode %u", opCode);
330 return NULL;
331 }
332
RebuildAst()333 static bool RebuildAst()
334 {
335 uint32_t currByteCode = 0;
336 bool ret = NextByteCode(&currByteCode);
337 if (!ret || currByteCode != HCS_NODE_OP) {
338 HCS_ERROR("miss root node");
339 return false;
340 }
341
342 ParserObject *rootObject = RebuildObject(currByteCode);
343 if (rootObject == NULL) {
344 return false;
345 }
346
347 HcsSetParserRoot(rootObject);
348 return true;
349 }
350
HcsDoDecompile(void)351 int32_t HcsDoDecompile(void)
352 {
353 struct HcsFile *source = NULL;
354 uint32_t ret = HcsOpenSourceFile(HcsGetInputFileName(), &source, "rb");
355 if (ret) {
356 return ret;
357 }
358 HcsSourceQueuePush(source);
359
360 do {
361 if (!HcsVerifyHbcFile()) {
362 ret = EDECOMP;
363 break;
364 }
365
366 if (!RebuildAst()) {
367 HCS_ERROR("failed to rebuild ast from hcb file");
368 ret = EDECOMP;
369 break;
370 }
371 if (HcsVerbosePrint()) {
372 HcsDumpAst("Rebuild");
373 }
374 } while (0);
375
376 HcsSourceQueuePop();
377 HcsCloseFile(source);
378 if (ret == NOERR) {
379 ret = HcsDecompileOutput();
380 }
381 HcsDeleteParserObjectTree(HcsGetParserRoot());
382 HcsSetParserRoot(NULL);
383 HcsSourceNameSetClean();
384 return ret;
385 }