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