blob: 909102d2393eecf454fbac578ddef38059246867 [file] [log] [blame]
Damien Zammit06853222016-11-16 21:06:54 +11001/*
2 * blobtool - Compiler/Decompiler for data blobs with specs
3 * Copyright (C) 2017 Damien Zammit <damien@zamaudio.com>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16%{
17#include <stdio.h>
18#include <inttypes.h>
19#include <stdlib.h>
20#include <string.h>
21//#define YYDEBUG 1
22int yylex (void);
23void yyerror (char const *);
24
25struct field {
26 char *name;
27 unsigned int width;
28 unsigned int value;
29 struct field *next;
30};
31
32extern struct field *sym_table;
33struct field *putsym (char const *, unsigned int);
34struct field *getsym (char const *);
35
36struct field *sym_table;
37struct field *sym_table_tail;
38
39FILE* fp;
40
41/* Bit array intermediary representation */
42struct blob {
43 unsigned int bloblen;
44 unsigned char *blb;
45 unsigned short checksum;
46 unsigned char *actualblob;
47 unsigned int lenactualblob;
48};
49
50#define VALID_BIT 0x80
51#define MAX_WIDTH 32
52#define CHECKSUM_SIZE 16
53
54struct blob *binary;
55
56unsigned char* value_to_bits (unsigned int v, unsigned int w)
57{
58 unsigned int i;
59 unsigned char* bitarr;
60
61 if (w > MAX_WIDTH) w = MAX_WIDTH;
62 bitarr = (unsigned char *) malloc (w * sizeof (unsigned char));
63 memset (bitarr, 0, w);
64
65 for (i = 0; i < w; i++) {
66 bitarr[i] = VALID_BIT | ((v & (1 << i)) >> i);
67 }
68 return bitarr;
69}
70
71/* Store each bit of a bitfield in a new byte sequentially 0x80 or 0x81 */
72void append_field_to_blob (unsigned char b[], unsigned int w)
73{
74 unsigned int i, j;
75 binary->blb = (unsigned char *) realloc (binary->blb, binary->bloblen + w);
76 for (j = 0, i = binary->bloblen; i < binary->bloblen + w; i++, j++) {
77 binary->blb[i] = VALID_BIT | (b[j] & 1);
78 //fprintf (stderr, "blob[%d] = %d\n", i, binary->blb[i] & 1);
79 }
80 binary->bloblen += w;
81}
82
83void set_bitfield(char *name, unsigned int value)
84{
85 unsigned long long i;
86 struct field *bf = getsym (name);
87 if (bf) {
88 bf->value = value & 0xffffffff;
89 i = (1 << bf->width) - 1;
90 if (bf->width > 8 * sizeof (unsigned int)) {
91 fprintf(stderr, "Overflow in bitfield, truncating bits to fit\n");
92 bf->value = value & i;
93 }
94 //fprintf(stderr, "Setting `%s` = %d\n", bf->name, bf->value);
95 } else {
96 fprintf(stderr, "Can't find bitfield `%s` in spec\n", name);
97 }
98}
99
100void set_bitfield_array(char *name, unsigned int n, unsigned int value)
101{
102 unsigned int i;
103 unsigned int len = strlen (name);
104 char *namen = (char *) malloc ((len + 9) * sizeof (char));
105 for (i = 0; i < n; i++) {
106 snprintf (namen, len + 8, "%s%x", name, i);
107 set_bitfield (namen, value);
108 }
109 free(namen);
110}
111
112void create_new_bitfield(char *name, unsigned int width)
113{
114 struct field *bf;
115
116 if (!(bf = putsym (name, width))) return;
117 //fprintf(stderr, "Added bitfield `%s` : %d\n", bf->name, width);
118}
119
120void create_new_bitfields(char *name, unsigned int n, unsigned int width)
121{
122 unsigned int i;
123 unsigned int len = strlen (name);
124 char *namen = (char *) malloc ((len + 9) * sizeof (char));
125 for (i = 0; i < n; i++) {
126 snprintf (namen, len + 8, "%s%x", name, i);
127 create_new_bitfield (namen, width);
128 }
129 free(namen);
130}
131
132struct field *putsym (char const *sym_name, unsigned int w)
133{
134 if (getsym(sym_name)) {
135 fprintf(stderr, "Cannot add duplicate named bitfield `%s`\n", sym_name);
136 return 0;
137 }
138 struct field *ptr = (struct field *) malloc (sizeof (struct field));
139 ptr->name = (char *) malloc (strlen (sym_name) + 1);
140 strcpy (ptr->name, sym_name);
141 ptr->width = w;
142 ptr->value = 0;
143 ptr->next = (struct field *)0;
144 if (sym_table_tail) {
145 sym_table_tail->next = ptr;
146 } else {
147 sym_table = ptr;
148 }
149 sym_table_tail = ptr;
150 return ptr;
151}
152
153struct field *getsym (char const *sym_name)
154{
155 struct field *ptr;
156 for (ptr = sym_table; ptr != (struct field *) 0;
157 ptr = (struct field *)ptr->next) {
158 if (strcmp (ptr->name, sym_name) == 0)
159 return ptr;
160 }
161 return 0;
162}
163
164void dump_all_values (void)
165{
166 struct field *ptr;
167 for (ptr = sym_table; ptr != (struct field *) 0;
168 ptr = (struct field *)ptr->next) {
169 fprintf(stderr, "%s = %d (%d bits)\n",
170 ptr->name,
171 ptr->value,
172 ptr->width);
173 }
174}
175
176void empty_field_table(void)
177{
178 struct field *ptr;
179 struct field *ptrnext;
180
181 for (ptr = sym_table; ptr != (struct field *) 0; ptr = ptrnext) {
182 if (ptr) {
183 ptrnext = ptr->next;
184 free(ptr);
185 } else {
186 ptrnext = (struct field *) 0;
187 }
188 }
189 sym_table = 0;
190 sym_table_tail = 0;
191}
192
193void create_binary_blob (void)
194{
195 if (binary && binary->blb) {
196 free(binary->blb);
197 free(binary);
198 }
199 binary = (struct blob *) malloc (sizeof (struct blob));
200 binary->blb = (unsigned char *) malloc (sizeof (unsigned char));
201 binary->bloblen = 0;
202 binary->blb[0] = VALID_BIT;
203}
204
205void interpret_next_blob_value (struct field *f)
206{
207 int i;
208 unsigned int v = 0;
209
210 if (binary->bloblen >= binary->lenactualblob * 8) {
211 f->value = 0;
212 return;
213 }
214
215 for (i = 0; i < f->width; i++) {
216 v |= (binary->blb[binary->bloblen++] & 1) << i;
217 }
218
219 f->value = v;
220}
221
222/* {}%BIN -> {} */
223void generate_setter_bitfields(unsigned char *bin)
224{
225 unsigned int i;
226 struct field *ptr;
227
228 /* Convert bytes to bit array */
229 for (i = 0; i < binary->lenactualblob; i++) {
230 append_field_to_blob (value_to_bits(bin[i], 8), 8);
231 }
232
233 /* Reset blob position to zero */
234 binary->bloblen = 0;
235
236 fprintf (fp, "# AUTOGENERATED SETTER BY BLOBTOOL\n{\n");
237
238 /* Traverse spec and output bitfield setters based on blob values */
239 for (ptr = sym_table; ptr != (struct field *) 0; ptr = ptr->next) {
240
241 interpret_next_blob_value(ptr);
242 fprintf (fp, "\t\"%s\" = 0x%x,\n", ptr->name, ptr->value);
243 }
244 fseek(fp, -2, SEEK_CUR);
245 fprintf (fp, "\n}\n");
246}
247
248void generate_binary_with_gbe_checksum(void)
249{
250 int i;
251 unsigned short checksum;
252
253 /* traverse spec, push to blob and add up for checksum */
254 struct field *ptr;
255 unsigned int uptochksum = 0;
256 for (ptr = sym_table; ptr != (struct field *) 0; ptr = ptr->next) {
257 if (strcmp (ptr->name, "checksum_gbe") == 0) {
258 /* Stop traversing because we hit checksum */
259 ptr = ptr->next;
260 break;
261 }
262 append_field_to_blob (
263 value_to_bits(ptr->value, ptr->width),
264 ptr->width);
265 uptochksum += ptr->width;
266 }
267
268 /* deserialize bits of blob up to checksum */
269 for (i = 0; i < uptochksum; i += 8) {
270 unsigned char byte = (((binary->blb[i+0] & 1) << 0)
271 | ((binary->blb[i+1] & 1) << 1)
272 | ((binary->blb[i+2] & 1) << 2)
273 | ((binary->blb[i+3] & 1) << 3)
274 | ((binary->blb[i+4] & 1) << 4)
275 | ((binary->blb[i+5] & 1) << 5)
276 | ((binary->blb[i+6] & 1) << 6)
277 | ((binary->blb[i+7] & 1) << 7)
278 );
279 fprintf(fp, "%c", byte);
280
281 /* incremental 16 bit checksum */
282 if ((i % 16) < 8) {
283 binary->checksum += byte;
284 } else {
285 binary->checksum += byte << 8;
286 }
287 }
288
289 checksum = (0xbaba - binary->checksum) & 0xffff;
290
291 /* Now write checksum */
292 set_bitfield ("checksum_gbe", checksum);
293
294 fprintf(fp, "%c", checksum & 0xff);
295 fprintf(fp, "%c", (checksum & 0xff00) >> 8);
296
297 append_field_to_blob (value_to_bits(checksum, 16), 16);
298
299 for (; ptr != (struct field *) 0; ptr = ptr->next) {
300 append_field_to_blob (
301 value_to_bits(ptr->value, ptr->width), ptr->width);
302 }
303
304 /* deserialize rest of blob past checksum */
305 for (i = uptochksum + CHECKSUM_SIZE; i < binary->bloblen; i += 8) {
306 unsigned char byte = (((binary->blb[i+0] & 1) << 0)
307 | ((binary->blb[i+1] & 1) << 1)
308 | ((binary->blb[i+2] & 1) << 2)
309 | ((binary->blb[i+3] & 1) << 3)
310 | ((binary->blb[i+4] & 1) << 4)
311 | ((binary->blb[i+5] & 1) << 5)
312 | ((binary->blb[i+6] & 1) << 6)
313 | ((binary->blb[i+7] & 1) << 7)
314 );
315 fprintf(fp, "%c", byte);
316 }
317}
318
319/* {}{} -> BIN */
320void generate_binary(void)
321{
322 unsigned int i;
323 struct field *ptr;
324
325 if (binary->bloblen % 8) {
326 fprintf (stderr, "ERROR: Spec must be multiple of 8 bits wide\n");
327 exit (1);
328 }
329
330 if (getsym ("checksum_gbe")) {
331 generate_binary_with_gbe_checksum();
332 return;
333 }
334
335 /* traverse spec, push to blob */
336 for (ptr = sym_table; ptr != (struct field *) 0; ptr = ptr->next) {
337 append_field_to_blob (
338 value_to_bits(ptr->value, ptr->width),
339 ptr->width);
340 }
341
342 /* deserialize bits of blob */
343 for (i = 0; i < binary->bloblen; i += 8) {
344 unsigned char byte = (((binary->blb[i+0] & 1) << 0)
345 | ((binary->blb[i+1] & 1) << 1)
346 | ((binary->blb[i+2] & 1) << 2)
347 | ((binary->blb[i+3] & 1) << 3)
348 | ((binary->blb[i+4] & 1) << 4)
349 | ((binary->blb[i+5] & 1) << 5)
350 | ((binary->blb[i+6] & 1) << 6)
351 | ((binary->blb[i+7] & 1) << 7)
352 );
353 fprintf(fp, "%c", byte);
354 }
355}
356
357%}
358
359%union
360{
361 char *str;
362 unsigned int u32;
363 unsigned int *u32array;
364 unsigned char u8;
365 unsigned char *u8array;
366}
367
368%token <str> name
369%token <u32> val
370%token <u32array> vals
371%token <u8> hexbyte
372%token <u8array> binblob
373%token <u8> eof
374
375%left '%'
376%left '{' '}'
377%left ','
378%left ':'
379%left '='
380
381%%
382
383input:
384 /* empty */
385| input spec setter eof { empty_field_table(); YYACCEPT;}
386| input spec blob { fprintf (stderr, "Parsed all bytes\n");
387 empty_field_table(); YYACCEPT;}
388;
389
390blob:
391 '%' eof { generate_setter_bitfields(binary->actualblob); }
392;
393
394spec:
395 '{' '}' { fprintf (stderr, "No spec\n"); }
396| '{' specmembers '}' { fprintf (stderr, "Parsed all spec\n");
397 create_binary_blob(); }
398;
399
400specmembers:
401 specpair
402| specpair ',' specmembers
403;
404
405specpair:
406 name ':' val { create_new_bitfield($1, $3); }
407| name '[' val ']' ':' val { create_new_bitfields($1, $3, $6); }
408;
409
410setter:
411 '{' '}' { fprintf (stderr, "No values\n"); }
412| '{' valuemembers '}' { fprintf (stderr, "Parsed all values\n");
413 generate_binary(); }
414;
415
416valuemembers:
417 setpair
418| setpair ',' valuemembers
419;
420
421setpair:
422 name '=' val { set_bitfield($1, $3); }
423| name '[' val ']' '=' val { set_bitfield_array($1, $3, $6); }
424;
425
426%%
427
428/* Called by yyparse on error. */
429void yyerror (char const *s)
430{
431 fprintf (stderr, "yyerror: %s\n", s);
432}
433
434/* Declarations */
435void set_input_string(char* in);
436
437/* This function parses a string */
438int parse_string(unsigned char* in) {
439 set_input_string ((char *)in);
440 return yyparse ();
441}
442
443int main (int argc, char *argv[])
444{
445 unsigned int lenspec, lensetter;
446 unsigned char *parsestring;
447 unsigned char c;
448 unsigned int pos = 0;
449 int ret = 0;
450
451#if YYDEBUG == 1
452 yydebug = 1;
453#endif
454 create_binary_blob();
455 binary->lenactualblob = 0;
456
457 if (argc == 4 && strcmp(argv[1], "-d") != 0) {
458 /* Compile mode */
459
460 /* Load Spec */
461 fp = fopen(argv[1], "r");
462 fseek(fp, 0, SEEK_END);
463 lenspec = ftell(fp);
464 fseek(fp, 0, SEEK_SET);
465 parsestring = (unsigned char *) malloc (lenspec);
466 if (!parsestring) {
467 printf("Out of memory\n");
468 exit(1);
469 }
470 fread(parsestring, 1, lenspec, fp);
471 fclose(fp);
472
473 /* Load Setter */
474 fp = fopen(argv[2], "r");
475 fseek(fp, 0, SEEK_END);
476 lensetter = ftell(fp);
477 fseek(fp, 0, SEEK_SET);
478 parsestring = (unsigned char *) realloc (parsestring,
479 lenspec + lensetter);
480 if (!parsestring) {
481 printf("Out of memory\n");
482 exit(1);
483 }
484 fread(parsestring + lenspec, 1, lensetter, fp);
485 fclose(fp);
486
487 /* Open output and parse string - output to fp */
488 fp = fopen(argv[3], "wb");
489 ret = parse_string(parsestring);
490 free(parsestring);
491 } else if (argc == 5 && strcmp (argv[1], "-d") == 0) {
492 /* Decompile mode */
493
494 /* Load Spec */
495 fp = fopen(argv[2], "r");
496 fseek(fp, 0, SEEK_END);
497 lenspec = ftell(fp);
498 fseek(fp, 0, SEEK_SET);
499 parsestring = (unsigned char *) malloc (lenspec + 1);
500 fread(parsestring, 1, lenspec, fp);
501 if (!parsestring) {
502 printf("Out of memory\n");
503 exit(1);
504 }
505 fclose(fp);
506
507 /* Add binary read trigger token */
508 parsestring[lenspec] = '%';
509
510 /* Load Actual Binary */
511 fp = fopen(argv[3], "rb");
512 fseek(fp, 0, SEEK_END);
513 binary->lenactualblob = ftell(fp);
514 fseek(fp, 0, SEEK_SET);
515 binary->actualblob = (unsigned char *) malloc (binary->lenactualblob);
516 if (!binary->actualblob) {
517 printf("Out of memory\n");
518 exit(1);
519 }
520 fread(binary->actualblob, 1, binary->lenactualblob, fp);
521 fclose(fp);
522
523 /* Open output and parse - output to fp */
524 fp = fopen(argv[4], "w");
525 ret = parse_string(parsestring);
526 free(parsestring);
527 free(binary->actualblob);
528 fclose(fp);
529 } else {
530 printf("Usage: Compile mode\n\n");
531 printf(" blobtool spec setter binaryoutput\n");
532 printf(" (file) (file) (file)\n");
533 printf(" OR : Decompile mode\n\n");
534 printf(" blobtool -d spec binary setteroutput\n");
535 }
536 return ret;
537}