diff options
Diffstat (limited to 'utils')
-rw-r--r-- | utils/sbtools/Makefile | 2 | ||||
-rw-r--r-- | utils/sbtools/dbparser.c | 626 | ||||
-rw-r--r-- | utils/sbtools/dbparser.h | 94 | ||||
-rw-r--r-- | utils/sbtools/elf.c | 20 | ||||
-rw-r--r-- | utils/sbtools/elf.h | 25 | ||||
-rw-r--r-- | utils/sbtools/elftosb.c | 595 | ||||
-rw-r--r-- | utils/sbtools/sb.h | 4 |
7 files changed, 780 insertions, 586 deletions
diff --git a/utils/sbtools/Makefile b/utils/sbtools/Makefile index e8bb68aadd..dc9c0966a7 100644 --- a/utils/sbtools/Makefile +++ b/utils/sbtools/Makefile | |||
@@ -3,7 +3,7 @@ all: elftosb sbtoelf | |||
3 | sbtoelf: sbtoelf.c crc.c crypto.h aes128.c sha1.c elf.c sb.h | 3 | sbtoelf: sbtoelf.c crc.c crypto.h aes128.c sha1.c elf.c sb.h |
4 | gcc -g -std=c99 -o $@ -W -Wall $^ | 4 | gcc -g -std=c99 -o $@ -W -Wall $^ |
5 | 5 | ||
6 | elftosb: elftosb.c crc.c crypto.h aes128.c sha1.c elf.c sb.h | 6 | elftosb: elftosb.c crc.c crypto.h aes128.c sha1.c elf.c sb.h dbparser.h dbparser.c |
7 | gcc -g -std=c99 -o $@ -W -Wall $^ | 7 | gcc -g -std=c99 -o $@ -W -Wall $^ |
8 | 8 | ||
9 | clean: | 9 | clean: |
diff --git a/utils/sbtools/dbparser.c b/utils/sbtools/dbparser.c new file mode 100644 index 0000000000..20f2d66c0e --- /dev/null +++ b/utils/sbtools/dbparser.c | |||
@@ -0,0 +1,626 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2011 Amaury Pouly | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #include <stdio.h> | ||
23 | #include <ctype.h> | ||
24 | #include <stdint.h> | ||
25 | #include "dbparser.h" | ||
26 | |||
27 | typedef uint8_t byte; | ||
28 | |||
29 | extern bool g_debug; | ||
30 | extern void *xmalloc(size_t s); | ||
31 | extern int convxdigit(char digit, byte *val); | ||
32 | |||
33 | #define bug(...) do { fprintf(stderr, __VA_ARGS__); exit(1); } while(0) | ||
34 | #define bugp(...) do { fprintf(stderr, __VA_ARGS__); perror(" "); exit(1); } while(0) | ||
35 | |||
36 | enum lexem_type_t | ||
37 | { | ||
38 | LEX_IDENTIFIER, | ||
39 | LEX_LPAREN, | ||
40 | LEX_RPAREN, | ||
41 | LEX_NUMBER, | ||
42 | LEX_STRING, /* double-quoted string */ | ||
43 | LEX_EQUAL, | ||
44 | LEX_SEMICOLON, | ||
45 | LEX_LBRACE, | ||
46 | LEX_RBRACE, | ||
47 | LEX_RANGLE, | ||
48 | LEX_EOF | ||
49 | }; | ||
50 | |||
51 | struct lexem_t | ||
52 | { | ||
53 | enum lexem_type_t type; | ||
54 | char *str; | ||
55 | uint32_t num; | ||
56 | int line; | ||
57 | const char *file; | ||
58 | }; | ||
59 | |||
60 | struct context_t | ||
61 | { | ||
62 | const char *file; | ||
63 | char *begin; | ||
64 | char *end; | ||
65 | char *ptr; | ||
66 | int line; | ||
67 | }; | ||
68 | |||
69 | #define parse_error(ctx, ...) \ | ||
70 | do { fprintf(stderr, "%s:%d: ", ctx->file, ctx->line); \ | ||
71 | fprintf(stderr, __VA_ARGS__); exit(2); } while(0) | ||
72 | |||
73 | static void advance(struct context_t *ctx, int nr_chars) | ||
74 | { | ||
75 | while(nr_chars--) | ||
76 | { | ||
77 | if(*(ctx->ptr++) == '\n') | ||
78 | ctx->line++; | ||
79 | } | ||
80 | } | ||
81 | |||
82 | static inline bool eof(struct context_t *ctx) | ||
83 | { | ||
84 | return ctx->ptr == ctx->end; | ||
85 | } | ||
86 | |||
87 | static inline bool next_valid(struct context_t *ctx, int nr) | ||
88 | { | ||
89 | return ctx->ptr + nr < ctx->end; | ||
90 | } | ||
91 | |||
92 | static inline char cur_char(struct context_t *ctx) | ||
93 | { | ||
94 | return *ctx->ptr; | ||
95 | } | ||
96 | |||
97 | static inline char next_char(struct context_t *ctx, int nr) | ||
98 | { | ||
99 | return ctx->ptr[nr]; | ||
100 | } | ||
101 | |||
102 | static inline void locate_lexem(struct lexem_t *lex, struct context_t *ctx) | ||
103 | { | ||
104 | lex->file = ctx->file; | ||
105 | lex->line = ctx->line; | ||
106 | } | ||
107 | |||
108 | static void __parse_string(struct context_t *ctx, void *user, void (*emit_fn)(void *user, char c)) | ||
109 | { | ||
110 | while(!eof(ctx)) | ||
111 | { | ||
112 | if(cur_char(ctx) == '"') | ||
113 | break; | ||
114 | else if(cur_char(ctx) == '\\') | ||
115 | { | ||
116 | advance(ctx, 1); | ||
117 | if(eof(ctx)) | ||
118 | parse_error(ctx, "Unfinished string\n"); | ||
119 | if(cur_char(ctx) == '\\') emit_fn(user, '\\'); | ||
120 | else if(cur_char(ctx) == '\'') emit_fn(user, '\''); | ||
121 | else if(cur_char(ctx) == '\"') emit_fn(user, '\"'); | ||
122 | else parse_error(ctx, "Unknown escape sequence \\%c\n", cur_char(ctx)); | ||
123 | advance(ctx, 1); | ||
124 | } | ||
125 | else | ||
126 | { | ||
127 | emit_fn(user, cur_char(ctx)); | ||
128 | advance(ctx, 1); | ||
129 | } | ||
130 | } | ||
131 | if(eof(ctx) || cur_char(ctx) != '"') | ||
132 | parse_error(ctx, "Unfinished string\n"); | ||
133 | advance(ctx, 1); | ||
134 | } | ||
135 | |||
136 | static void __parse_string_emit(void *user, char c) | ||
137 | { | ||
138 | char **pstr = (char **)user; | ||
139 | *(*pstr)++ = c; | ||
140 | } | ||
141 | |||
142 | static void __parse_string_count(void *user, char c) | ||
143 | { | ||
144 | (void) c; | ||
145 | (*(int *)user)++; | ||
146 | } | ||
147 | |||
148 | static void parse_string(struct context_t *ctx, struct lexem_t *lexem) | ||
149 | { | ||
150 | locate_lexem(lexem, ctx); | ||
151 | /* skip " */ | ||
152 | advance(ctx, 1); | ||
153 | /* compute length */ | ||
154 | struct context_t cpy_ctx = *ctx; | ||
155 | int length = 0; | ||
156 | __parse_string(&cpy_ctx, (void *)&length, __parse_string_count); | ||
157 | /* parse again */ | ||
158 | lexem->type = LEX_STRING; | ||
159 | lexem->str = xmalloc(length + 1); | ||
160 | lexem->str[length] = 0; | ||
161 | char *pstr = lexem->str; | ||
162 | __parse_string(ctx, (void *)&pstr, __parse_string_emit); | ||
163 | } | ||
164 | |||
165 | static void parse_ascii_number(struct context_t *ctx, struct lexem_t *lexem) | ||
166 | { | ||
167 | locate_lexem(lexem, ctx); | ||
168 | /* skip ' */ | ||
169 | advance(ctx, 1); | ||
170 | /* we expect n<=4 character and then ' */ | ||
171 | int len = 0; | ||
172 | uint32_t value = 0; | ||
173 | while(!eof(ctx)) | ||
174 | { | ||
175 | if(cur_char(ctx) != '\'') | ||
176 | { | ||
177 | value = value << 8 | cur_char(ctx); | ||
178 | len++; | ||
179 | advance(ctx, 1); | ||
180 | } | ||
181 | else | ||
182 | break; | ||
183 | } | ||
184 | if(eof(ctx) || cur_char(ctx) != '\'') | ||
185 | parse_error(ctx, "Unterminated ascii number literal\n"); | ||
186 | if(len == 0 || len > 4) | ||
187 | parse_error(ctx, "Invalid ascii number literal length: only 1 to 4 characters allowed\n"); | ||
188 | /* skip ' */ | ||
189 | advance(ctx, 1); | ||
190 | lexem->type = LEX_NUMBER; | ||
191 | lexem->num = value; | ||
192 | } | ||
193 | |||
194 | static void parse_number(struct context_t *ctx, struct lexem_t *lexem) | ||
195 | { | ||
196 | locate_lexem(lexem, ctx); | ||
197 | /* check base */ | ||
198 | int base = 10; | ||
199 | if(cur_char(ctx) == '0' && next_valid(ctx, 1) && next_char(ctx, 1) == 'x') | ||
200 | { | ||
201 | advance(ctx, 2); | ||
202 | base = 16; | ||
203 | } | ||
204 | |||
205 | lexem->type = LEX_NUMBER; | ||
206 | lexem->num = 0; | ||
207 | while(!eof(ctx) && isxdigit(cur_char(ctx))) | ||
208 | { | ||
209 | if(base == 10 && !isdigit(cur_char(ctx))) | ||
210 | break; | ||
211 | byte v; | ||
212 | if(convxdigit(cur_char(ctx), &v)) | ||
213 | break; | ||
214 | lexem->num = base * lexem->num + v; | ||
215 | advance(ctx, 1); | ||
216 | } | ||
217 | } | ||
218 | |||
219 | static void parse_identifier(struct context_t *ctx, struct lexem_t *lexem) | ||
220 | { | ||
221 | locate_lexem(lexem, ctx); | ||
222 | /* remember position */ | ||
223 | char *old = ctx->ptr; | ||
224 | while(!eof(ctx) && (isalnum(cur_char(ctx)) || cur_char(ctx) == '_')) | ||
225 | advance(ctx, 1); | ||
226 | lexem->type = LEX_IDENTIFIER; | ||
227 | int len = ctx->ptr - old; | ||
228 | lexem->str = xmalloc(len + 1); | ||
229 | lexem->str[len] = 0; | ||
230 | memcpy(lexem->str, old, len); | ||
231 | } | ||
232 | |||
233 | static void next_lexem(struct context_t *ctx, struct lexem_t *lexem) | ||
234 | { | ||
235 | #define ret_simple(t, adv) \ | ||
236 | do {locate_lexem(lexem, ctx); \ | ||
237 | lexem->type = t; \ | ||
238 | advance(ctx, adv); \ | ||
239 | return;} while(0) | ||
240 | while(!eof(ctx)) | ||
241 | { | ||
242 | char c = cur_char(ctx); | ||
243 | /* skip whitespace */ | ||
244 | if(c == ' ' || c == '\t' || c == '\n' || c == '\r') | ||
245 | { | ||
246 | advance(ctx, 1); | ||
247 | continue; | ||
248 | } | ||
249 | /* skip C++ style comments */ | ||
250 | if(c == '/' && next_valid(ctx, 1) && next_char(ctx, 1) == '/') | ||
251 | { | ||
252 | while(!eof(ctx) && cur_char(ctx) != '\n') | ||
253 | advance(ctx, 1); | ||
254 | continue; | ||
255 | } | ||
256 | /* skip C-style comments */ | ||
257 | if(c == '/' && next_valid(ctx, 1) && next_char(ctx, 1) == '*') | ||
258 | { | ||
259 | advance(ctx, 2); | ||
260 | while(true) | ||
261 | { | ||
262 | if(!next_valid(ctx, 1)) | ||
263 | parse_error(ctx, "Unterminated comment"); | ||
264 | if(cur_char(ctx) == '*' && next_char(ctx, 1) == '/') | ||
265 | { | ||
266 | advance(ctx, 2); | ||
267 | break; | ||
268 | } | ||
269 | advance(ctx, 1); | ||
270 | } | ||
271 | continue; | ||
272 | } | ||
273 | break; | ||
274 | } | ||
275 | if(eof(ctx)) ret_simple(LEX_EOF, 0); | ||
276 | char c = cur_char(ctx); | ||
277 | if(c == '(') ret_simple(LEX_LPAREN, 1); | ||
278 | if(c == ')') ret_simple(LEX_RPAREN, 1); | ||
279 | if(c == '{') ret_simple(LEX_LBRACE, 1); | ||
280 | if(c == '}') ret_simple(LEX_RBRACE, 1); | ||
281 | if(c == '>') ret_simple(LEX_RANGLE, 1); | ||
282 | if(c == '=') ret_simple(LEX_EQUAL, 1); | ||
283 | if(c == ';') ret_simple(LEX_SEMICOLON, 1); | ||
284 | if(c == '"') return parse_string(ctx, lexem); | ||
285 | if(c == '\'') return parse_ascii_number(ctx, lexem); | ||
286 | if(isdigit(c)) return parse_number(ctx, lexem); | ||
287 | if(isalpha(c) || c == '_') return parse_identifier(ctx, lexem); | ||
288 | parse_error(ctx, "Unexpected character '%c'\n", c); | ||
289 | #undef ret_simple | ||
290 | } | ||
291 | |||
292 | #if 0 | ||
293 | static void log_lexem(struct lexem_t *lexem) | ||
294 | { | ||
295 | switch(lexem->type) | ||
296 | { | ||
297 | case LEX_EOF: printf("<eof>"); break; | ||
298 | case LEX_EQUAL: printf("="); break; | ||
299 | case LEX_IDENTIFIER: printf("id(%s)", lexem->str); break; | ||
300 | case LEX_LPAREN: printf("("); break; | ||
301 | case LEX_RPAREN: printf(")"); break; | ||
302 | case LEX_LBRACE: printf("{"); break; | ||
303 | case LEX_RBRACE: printf("}"); break; | ||
304 | case LEX_SEMICOLON: printf(";"); break; | ||
305 | case LEX_NUMBER: printf("num(%d)", lexem->num); break; | ||
306 | case LEX_STRING: printf("str(%s)", lexem->str); break; | ||
307 | default: printf("<unk>"); | ||
308 | } | ||
309 | } | ||
310 | #endif | ||
311 | |||
312 | struct cmd_source_t *db_find_source_by_id(struct cmd_file_t *cmd_file, const char *id) | ||
313 | { | ||
314 | struct cmd_source_t *src = cmd_file->source_list; | ||
315 | while(src) | ||
316 | { | ||
317 | if(strcmp(src->identifier, id) == 0) | ||
318 | return src; | ||
319 | src = src->next; | ||
320 | } | ||
321 | return NULL; | ||
322 | } | ||
323 | |||
324 | static void generate_default_version(struct sb_version_t *ver) | ||
325 | { | ||
326 | ver->major = 0x999; | ||
327 | ver->minor = 0x999; | ||
328 | ver->revision = 0x999; | ||
329 | } | ||
330 | |||
331 | #define INVALID_SB_SUBVERSION 0xffff | ||
332 | |||
333 | static uint16_t parse_sb_subversion(char *str) | ||
334 | { | ||
335 | int len = strlen(str); | ||
336 | uint16_t n = 0; | ||
337 | if(len == 0 || len > 4) | ||
338 | return INVALID_SB_SUBVERSION; | ||
339 | for(int i = 0; i < len; i++) | ||
340 | { | ||
341 | if(!isdigit(str[i])) | ||
342 | return INVALID_SB_SUBVERSION; | ||
343 | n = n << 4 | (str[i] - '0'); | ||
344 | } | ||
345 | return n; | ||
346 | } | ||
347 | |||
348 | bool db_parse_sb_version(struct sb_version_t *ver, char *str) | ||
349 | { | ||
350 | int len = strlen(str); | ||
351 | int cnt = 0; | ||
352 | int pos[2]; | ||
353 | |||
354 | for(int i = 0; i < len; i++) | ||
355 | { | ||
356 | if(str[i] != '.') | ||
357 | continue; | ||
358 | if(cnt == 2) | ||
359 | return false; | ||
360 | pos[cnt++] = i + 1; | ||
361 | str[i] = 0; | ||
362 | } | ||
363 | if(cnt != 2) | ||
364 | return false; | ||
365 | ver->major = parse_sb_subversion(str); | ||
366 | ver->minor = parse_sb_subversion(str + pos[0]); | ||
367 | ver->revision = parse_sb_subversion(str + pos[1]); | ||
368 | return ver->major != INVALID_SB_SUBVERSION && | ||
369 | ver->minor != INVALID_SB_SUBVERSION && | ||
370 | ver->revision != INVALID_SB_SUBVERSION; | ||
371 | } | ||
372 | |||
373 | #undef parse_error | ||
374 | #define parse_error(lexem, ...) \ | ||
375 | do { fprintf(stderr, "%s:%d: ", lexem.file, lexem.line); \ | ||
376 | fprintf(stderr, __VA_ARGS__); exit(2); } while(0) | ||
377 | |||
378 | struct cmd_file_t *db_parse_file(const char *file) | ||
379 | { | ||
380 | size_t size; | ||
381 | FILE *f = fopen(file, "r"); | ||
382 | if(f == NULL) | ||
383 | bugp("Cannot open file '%s'", file); | ||
384 | fseek(f, 0, SEEK_END); | ||
385 | size = ftell(f); | ||
386 | fseek(f, 0, SEEK_SET); | ||
387 | char *buf = xmalloc(size); | ||
388 | if(fread(buf, size, 1, f) != 1) | ||
389 | bugp("Cannot read file '%s'", file); | ||
390 | fclose(f); | ||
391 | |||
392 | if(g_debug) | ||
393 | printf("Parsing db file '%s'\n", file); | ||
394 | struct cmd_file_t *cmd_file = xmalloc(sizeof(struct cmd_file_t)); | ||
395 | memset(cmd_file, 0, sizeof(struct cmd_file_t)); | ||
396 | |||
397 | generate_default_version(&cmd_file->product_ver); | ||
398 | generate_default_version(&cmd_file->component_ver); | ||
399 | |||
400 | struct lexem_t lexem; | ||
401 | struct context_t ctx; | ||
402 | ctx.file = file; | ||
403 | ctx.line = 1; | ||
404 | ctx.begin = buf; | ||
405 | ctx.ptr = buf; | ||
406 | ctx.end = buf + size; | ||
407 | #define next() next_lexem(&ctx, &lexem) | ||
408 | /* init lexer */ | ||
409 | next(); | ||
410 | /* options ? */ | ||
411 | if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "options")) | ||
412 | { | ||
413 | next(); | ||
414 | if(lexem.type != LEX_LBRACE) | ||
415 | parse_error(lexem, "'{' expected after 'options'\n"); | ||
416 | |||
417 | while(true) | ||
418 | { | ||
419 | next(); | ||
420 | if(lexem.type == LEX_RBRACE) | ||
421 | break; | ||
422 | if(lexem.type != LEX_IDENTIFIER) | ||
423 | parse_error(lexem, "Identifier expected in options\n"); | ||
424 | char *opt = lexem.str; | ||
425 | next(); | ||
426 | if(lexem.type != LEX_EQUAL) | ||
427 | parse_error(lexem, "'=' expected after identifier\n"); | ||
428 | next(); | ||
429 | if(!strcmp(opt, "productVersion") || !strcmp(opt, "componentVersion")) | ||
430 | { | ||
431 | if(lexem.type != LEX_STRING) | ||
432 | parse_error(lexem, "String expected after '='\n"); | ||
433 | bool ret; | ||
434 | if(!strcmp(opt, "productVersion")) | ||
435 | ret = db_parse_sb_version(&cmd_file->product_ver, lexem.str); | ||
436 | else | ||
437 | ret = db_parse_sb_version(&cmd_file->component_ver, lexem.str); | ||
438 | if(!ret) | ||
439 | parse_error(lexem, "Invalid product/component version"); | ||
440 | } | ||
441 | else | ||
442 | parse_error(lexem, "Unknown option '%s'\n", opt); | ||
443 | next(); | ||
444 | if(lexem.type != LEX_SEMICOLON) | ||
445 | parse_error(lexem, "';' expected after string\n"); | ||
446 | } | ||
447 | next(); | ||
448 | } | ||
449 | /* sources */ | ||
450 | if(lexem.type != LEX_IDENTIFIER || strcmp(lexem.str, "sources")) | ||
451 | parse_error(lexem, "'sources' expected\n"); | ||
452 | next(); | ||
453 | if(lexem.type != LEX_LBRACE) | ||
454 | parse_error(lexem, "'{' expected after 'sources'\n"); | ||
455 | |||
456 | while(true) | ||
457 | { | ||
458 | next(); | ||
459 | if(lexem.type == LEX_RBRACE) | ||
460 | break; | ||
461 | struct cmd_source_t *src = xmalloc(sizeof(struct cmd_source_t)); | ||
462 | memset(src, 0, sizeof(struct cmd_source_t)); | ||
463 | src->next = cmd_file->source_list; | ||
464 | if(lexem.type != LEX_IDENTIFIER) | ||
465 | parse_error(lexem, "identifier expected in sources\n"); | ||
466 | src->identifier = lexem.str; | ||
467 | next(); | ||
468 | if(lexem.type != LEX_EQUAL) | ||
469 | parse_error(lexem, "'=' expected after identifier\n"); | ||
470 | next(); | ||
471 | if(lexem.type != LEX_STRING) | ||
472 | parse_error(lexem, "String expected after '='\n"); | ||
473 | src->filename = lexem.str; | ||
474 | next(); | ||
475 | if(lexem.type != LEX_SEMICOLON) | ||
476 | parse_error(lexem, "';' expected after string\n"); | ||
477 | if(db_find_source_by_id(cmd_file, src->identifier) != NULL) | ||
478 | parse_error(lexem, "Duplicate source identifier\n"); | ||
479 | /* type filled later */ | ||
480 | src->type = CMD_SRC_UNK; | ||
481 | cmd_file->source_list = src; | ||
482 | } | ||
483 | |||
484 | /* sections */ | ||
485 | struct cmd_section_t *end_sec = NULL; | ||
486 | while(true) | ||
487 | { | ||
488 | struct cmd_section_t *sec = xmalloc(sizeof(struct cmd_section_t)); | ||
489 | struct cmd_inst_t *end_list = NULL; | ||
490 | memset(sec, 0, sizeof(struct cmd_section_t)); | ||
491 | next(); | ||
492 | if(lexem.type == LEX_EOF) | ||
493 | break; | ||
494 | if(lexem.type != LEX_IDENTIFIER || strcmp(lexem.str, "section") != 0) | ||
495 | parse_error(lexem, "'section' expected\n"); | ||
496 | next(); | ||
497 | if(lexem.type != LEX_LPAREN) | ||
498 | parse_error(lexem, "'(' expected after 'section'\n"); | ||
499 | next(); | ||
500 | /* can be a number or a 4 character long string */ | ||
501 | if(lexem.type == LEX_NUMBER) | ||
502 | { | ||
503 | sec->identifier = lexem.num; | ||
504 | } | ||
505 | else | ||
506 | parse_error(lexem, "Number expected as section identifier\n"); | ||
507 | |||
508 | next(); | ||
509 | if(lexem.type != LEX_RPAREN) | ||
510 | parse_error(lexem, "')' expected after section identifier\n"); | ||
511 | next(); | ||
512 | if(lexem.type != LEX_LBRACE) | ||
513 | parse_error(lexem, "'{' expected after section directive\n"); | ||
514 | /* commands */ | ||
515 | while(true) | ||
516 | { | ||
517 | struct cmd_inst_t *inst = xmalloc(sizeof(struct cmd_inst_t)); | ||
518 | memset(inst, 0, sizeof(struct cmd_inst_t)); | ||
519 | next(); | ||
520 | if(lexem.type == LEX_RBRACE) | ||
521 | break; | ||
522 | if(lexem.type != LEX_IDENTIFIER) | ||
523 | parse_error(lexem, "Instruction expected in section\n"); | ||
524 | if(strcmp(lexem.str, "load") == 0) | ||
525 | inst->type = CMD_LOAD; | ||
526 | else if(strcmp(lexem.str, "call") == 0) | ||
527 | inst->type = CMD_CALL; | ||
528 | else if(strcmp(lexem.str, "jump") == 0) | ||
529 | inst->type = CMD_JUMP; | ||
530 | else if(strcmp(lexem.str, "mode") == 0) | ||
531 | inst->type = CMD_MODE; | ||
532 | else | ||
533 | parse_error(lexem, "Instruction expected in section\n"); | ||
534 | next(); | ||
535 | |||
536 | if(inst->type == CMD_LOAD) | ||
537 | { | ||
538 | if(lexem.type != LEX_IDENTIFIER) | ||
539 | parse_error(lexem, "Identifier expected after instruction\n"); | ||
540 | inst->identifier = lexem.str; | ||
541 | if(db_find_source_by_id(cmd_file, inst->identifier) == NULL) | ||
542 | parse_error(lexem, "Undefined reference to source '%s'\n", inst->identifier); | ||
543 | next(); | ||
544 | if(lexem.type == LEX_RANGLE) | ||
545 | { | ||
546 | // load at | ||
547 | inst->type = CMD_LOAD_AT; | ||
548 | next(); | ||
549 | if(lexem.type != LEX_NUMBER) | ||
550 | parse_error(lexem, "Number expected for loading address\n"); | ||
551 | inst->addr = lexem.num; | ||
552 | next(); | ||
553 | } | ||
554 | if(lexem.type != LEX_SEMICOLON) | ||
555 | parse_error(lexem, "';' expected after command\n"); | ||
556 | } | ||
557 | else if(inst->type == CMD_CALL || inst->type == CMD_JUMP) | ||
558 | { | ||
559 | if(lexem.type == LEX_IDENTIFIER) | ||
560 | { | ||
561 | inst->identifier = lexem.str; | ||
562 | if(db_find_source_by_id(cmd_file, inst->identifier) == NULL) | ||
563 | parse_error(lexem, "Undefined reference to source '%s'\n", inst->identifier); | ||
564 | next(); | ||
565 | } | ||
566 | else if(lexem.type == LEX_NUMBER) | ||
567 | { | ||
568 | inst->type = (inst->type == CMD_CALL) ? CMD_CALL_AT : CMD_JUMP_AT; | ||
569 | inst->addr = lexem.num; | ||
570 | next(); | ||
571 | } | ||
572 | else | ||
573 | parse_error(lexem, "Identifier or number expected after jump/load\n"); | ||
574 | |||
575 | if(lexem.type == LEX_LPAREN) | ||
576 | { | ||
577 | next(); | ||
578 | if(lexem.type != LEX_NUMBER) | ||
579 | parse_error(lexem, "Expected numeral expression after (\n"); | ||
580 | inst->argument = lexem.num; | ||
581 | next(); | ||
582 | if(lexem.type != LEX_RPAREN) | ||
583 | parse_error(lexem, "Expected closing brace\n"); | ||
584 | next(); | ||
585 | } | ||
586 | if(lexem.type != LEX_SEMICOLON) | ||
587 | parse_error(lexem, "Expected ';' after command\n"); | ||
588 | } | ||
589 | else if(inst->type == CMD_MODE) | ||
590 | { | ||
591 | if(lexem.type != LEX_NUMBER) | ||
592 | parse_error(lexem, "Number expected after 'mode'\n"); | ||
593 | inst->argument = lexem.num; | ||
594 | next(); | ||
595 | if(lexem.type != LEX_SEMICOLON) | ||
596 | parse_error(lexem, "Expected ';' after command\n"); | ||
597 | } | ||
598 | else | ||
599 | parse_error(lexem, "Internal error"); | ||
600 | if(end_list == NULL) | ||
601 | { | ||
602 | sec->inst_list = inst; | ||
603 | end_list = inst; | ||
604 | } | ||
605 | else | ||
606 | { | ||
607 | end_list->next = inst; | ||
608 | end_list = inst; | ||
609 | } | ||
610 | } | ||
611 | |||
612 | if(end_sec == NULL) | ||
613 | { | ||
614 | cmd_file->section_list = sec; | ||
615 | end_sec = sec; | ||
616 | } | ||
617 | else | ||
618 | { | ||
619 | end_sec->next = sec; | ||
620 | end_sec = sec; | ||
621 | } | ||
622 | } | ||
623 | #undef next | ||
624 | |||
625 | return cmd_file; | ||
626 | } | ||
diff --git a/utils/sbtools/dbparser.h b/utils/sbtools/dbparser.h new file mode 100644 index 0000000000..f1b7ffd77e --- /dev/null +++ b/utils/sbtools/dbparser.h | |||
@@ -0,0 +1,94 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2011 Amaury Pouly | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #ifndef __DBPARSER__ | ||
22 | #define __DBPARSER__ | ||
23 | |||
24 | /** | ||
25 | * Command file parsing | ||
26 | */ | ||
27 | #include "sb.h" | ||
28 | #include "elf.h" | ||
29 | |||
30 | enum cmd_source_type_t | ||
31 | { | ||
32 | CMD_SRC_UNK, | ||
33 | CMD_SRC_ELF, | ||
34 | CMD_SRC_BIN | ||
35 | }; | ||
36 | |||
37 | struct bin_param_t | ||
38 | { | ||
39 | uint32_t size; | ||
40 | void *data; | ||
41 | }; | ||
42 | |||
43 | struct cmd_source_t | ||
44 | { | ||
45 | char *identifier; | ||
46 | char *filename; | ||
47 | struct cmd_source_t *next; | ||
48 | /* for later use */ | ||
49 | enum cmd_source_type_t type; | ||
50 | bool loaded; | ||
51 | struct elf_params_t elf; | ||
52 | struct bin_param_t bin; | ||
53 | }; | ||
54 | |||
55 | enum cmd_inst_type_t | ||
56 | { | ||
57 | CMD_LOAD, /* load image */ | ||
58 | CMD_JUMP, /* jump at image */ | ||
59 | CMD_CALL, /* call image */ | ||
60 | CMD_LOAD_AT, /* load binary at */ | ||
61 | CMD_CALL_AT, /* call at address */ | ||
62 | CMD_JUMP_AT, /* jump at address */ | ||
63 | CMD_MODE, /* change boot mode */ | ||
64 | }; | ||
65 | |||
66 | struct cmd_inst_t | ||
67 | { | ||
68 | enum cmd_inst_type_t type; | ||
69 | char *identifier; | ||
70 | uint32_t argument; // for jump, call, mode | ||
71 | uint32_t addr; // for 'at' | ||
72 | struct cmd_inst_t *next; | ||
73 | }; | ||
74 | |||
75 | struct cmd_section_t | ||
76 | { | ||
77 | uint32_t identifier; | ||
78 | struct cmd_inst_t *inst_list; | ||
79 | struct cmd_section_t *next; | ||
80 | }; | ||
81 | |||
82 | struct cmd_file_t | ||
83 | { | ||
84 | struct sb_version_t product_ver; | ||
85 | struct sb_version_t component_ver; | ||
86 | struct cmd_source_t *source_list; | ||
87 | struct cmd_section_t *section_list; | ||
88 | }; | ||
89 | |||
90 | struct cmd_source_t *db_find_source_by_id(struct cmd_file_t *cmd_file, const char *id); | ||
91 | bool db_parse_sb_version(struct sb_version_t *ver, char *str); | ||
92 | struct cmd_file_t *db_parse_file(const char *file); | ||
93 | |||
94 | #endif /* __DBPARSER__ */ | ||
diff --git a/utils/sbtools/elf.c b/utils/sbtools/elf.c index 57f38b8016..80bff01c4c 100644 --- a/utils/sbtools/elf.c +++ b/utils/sbtools/elf.c | |||
@@ -1,3 +1,23 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2011 Amaury Pouly | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
1 | #include "elf.h" | 21 | #include "elf.h" |
2 | 22 | ||
3 | /** | 23 | /** |
diff --git a/utils/sbtools/elf.h b/utils/sbtools/elf.h index d63b9a93b7..f85595d784 100644 --- a/utils/sbtools/elf.h +++ b/utils/sbtools/elf.h | |||
@@ -1,3 +1,26 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2011 Amaury Pouly | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #ifndef __ELF_H__ | ||
22 | #define __ELF_H__ | ||
23 | |||
1 | #include <stdio.h> | 24 | #include <stdio.h> |
2 | #include <stdint.h> | 25 | #include <stdint.h> |
3 | #include <string.h> | 26 | #include <string.h> |
@@ -67,3 +90,5 @@ void elf_set_start_addr(struct elf_params_t *params, uint32_t addr); | |||
67 | bool elf_get_start_addr(struct elf_params_t *params, uint32_t *addr); | 90 | bool elf_get_start_addr(struct elf_params_t *params, uint32_t *addr); |
68 | int elf_get_nr_sections(struct elf_params_t *params); | 91 | int elf_get_nr_sections(struct elf_params_t *params); |
69 | void elf_release(struct elf_params_t *params); | 92 | void elf_release(struct elf_params_t *params); |
93 | |||
94 | #endif /* __ELF_H__ */ | ||
diff --git a/utils/sbtools/elftosb.c b/utils/sbtools/elftosb.c index cb5cc4c6db..0b659eaf26 100644 --- a/utils/sbtools/elftosb.c +++ b/utils/sbtools/elftosb.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include "crypto.h" | 37 | #include "crypto.h" |
38 | #include "elf.h" | 38 | #include "elf.h" |
39 | #include "sb.h" | 39 | #include "sb.h" |
40 | #include "dbparser.h" | ||
40 | 41 | ||
41 | #define _STR(a) #a | 42 | #define _STR(a) #a |
42 | #define STR(a) _STR(a) | 43 | #define STR(a) _STR(a) |
@@ -76,7 +77,7 @@ void *xmalloc(size_t s) /* malloc helper, used in elf.c */ | |||
76 | return r; | 77 | return r; |
77 | } | 78 | } |
78 | 79 | ||
79 | static int convxdigit(char digit, byte *val) | 80 | int convxdigit(char digit, byte *val) |
80 | { | 81 | { |
81 | if(digit >= '0' && digit <= '9') | 82 | if(digit >= '0' && digit <= '9') |
82 | { | 83 | { |
@@ -164,582 +165,6 @@ static key_array_t read_keys(const char *key_file, int *num_keys) | |||
164 | } | 165 | } |
165 | 166 | ||
166 | /** | 167 | /** |
167 | * Command file parsing | ||
168 | */ | ||
169 | |||
170 | enum cmd_source_type_t | ||
171 | { | ||
172 | CMD_SRC_UNK, | ||
173 | CMD_SRC_ELF, | ||
174 | CMD_SRC_BIN | ||
175 | }; | ||
176 | |||
177 | struct bin_param_t | ||
178 | { | ||
179 | uint32_t size; | ||
180 | void *data; | ||
181 | }; | ||
182 | |||
183 | struct cmd_source_t | ||
184 | { | ||
185 | char *identifier; | ||
186 | char *filename; | ||
187 | struct cmd_source_t *next; | ||
188 | /* for later use */ | ||
189 | enum cmd_source_type_t type; | ||
190 | bool loaded; | ||
191 | struct elf_params_t elf; | ||
192 | struct bin_param_t bin; | ||
193 | }; | ||
194 | |||
195 | enum cmd_inst_type_t | ||
196 | { | ||
197 | CMD_LOAD, /* load image */ | ||
198 | CMD_JUMP, /* jump at image */ | ||
199 | CMD_CALL, /* call image */ | ||
200 | CMD_LOAD_AT, /* load binary at */ | ||
201 | CMD_CALL_AT, /* call at address */ | ||
202 | CMD_JUMP_AT, /* jump at address */ | ||
203 | CMD_MODE, /* change boot mode */ | ||
204 | }; | ||
205 | |||
206 | struct cmd_inst_t | ||
207 | { | ||
208 | enum cmd_inst_type_t type; | ||
209 | char *identifier; | ||
210 | uint32_t argument; // for jump, call, mode | ||
211 | uint32_t addr; // for 'at' | ||
212 | struct cmd_inst_t *next; | ||
213 | }; | ||
214 | |||
215 | struct cmd_section_t | ||
216 | { | ||
217 | uint32_t identifier; | ||
218 | struct cmd_inst_t *inst_list; | ||
219 | struct cmd_section_t *next; | ||
220 | }; | ||
221 | |||
222 | struct cmd_file_t | ||
223 | { | ||
224 | struct sb_version_t product_ver; | ||
225 | struct sb_version_t component_ver; | ||
226 | struct cmd_source_t *source_list; | ||
227 | struct cmd_section_t *section_list; | ||
228 | }; | ||
229 | |||
230 | enum lexem_type_t | ||
231 | { | ||
232 | LEX_IDENTIFIER, | ||
233 | LEX_LPAREN, | ||
234 | LEX_RPAREN, | ||
235 | LEX_NUMBER, | ||
236 | LEX_STRING, /* double-quoted string */ | ||
237 | LEX_EQUAL, | ||
238 | LEX_SEMICOLON, | ||
239 | LEX_LBRACE, | ||
240 | LEX_RBRACE, | ||
241 | LEX_RANGLE, | ||
242 | LEX_EOF | ||
243 | }; | ||
244 | |||
245 | struct lexem_t | ||
246 | { | ||
247 | enum lexem_type_t type; | ||
248 | char *str; | ||
249 | uint32_t num; | ||
250 | }; | ||
251 | |||
252 | static void __parse_string(char **ptr, char *end, void *user, void (*emit_fn)(void *user, char c)) | ||
253 | { | ||
254 | while(*ptr != end) | ||
255 | { | ||
256 | if(**ptr == '"') | ||
257 | break; | ||
258 | else if(**ptr == '\\') | ||
259 | { | ||
260 | (*ptr)++; | ||
261 | if(*ptr == end) | ||
262 | bug("Unfinished string\n"); | ||
263 | if(**ptr == '\\') emit_fn(user, '\\'); | ||
264 | else if(**ptr == '\'') emit_fn(user, '\''); | ||
265 | else if(**ptr == '\"') emit_fn(user, '\"'); | ||
266 | else bug("Unknown escape sequence \\%c\n", **ptr); | ||
267 | (*ptr)++; | ||
268 | } | ||
269 | else | ||
270 | emit_fn(user, *(*ptr)++); | ||
271 | } | ||
272 | if(*ptr == end || **ptr != '"') | ||
273 | bug("unfinished string\n"); | ||
274 | (*ptr)++; | ||
275 | } | ||
276 | |||
277 | static void __parse_string_emit(void *user, char c) | ||
278 | { | ||
279 | char **pstr = (char **)user; | ||
280 | *(*pstr)++ = c; | ||
281 | } | ||
282 | |||
283 | static void __parse_string_count(void *user, char c) | ||
284 | { | ||
285 | (void) c; | ||
286 | (*(int *)user)++; | ||
287 | } | ||
288 | |||
289 | static void parse_string(char **ptr, char *end, struct lexem_t *lexem) | ||
290 | { | ||
291 | /* skip " */ | ||
292 | (*ptr)++; | ||
293 | char *p = *ptr; | ||
294 | /* compute length */ | ||
295 | int length = 0; | ||
296 | __parse_string(&p, end, (void *)&length, __parse_string_count); | ||
297 | /* parse again */ | ||
298 | lexem->type = LEX_STRING; | ||
299 | lexem->str = xmalloc(length + 1); | ||
300 | lexem->str[length] = 0; | ||
301 | char *pstr = lexem->str; | ||
302 | __parse_string(ptr, end, (void *)&pstr, __parse_string_emit); | ||
303 | } | ||
304 | |||
305 | static void parse_ascii_number(char **ptr, char *end, struct lexem_t *lexem) | ||
306 | { | ||
307 | /* skip ' */ | ||
308 | (*ptr)++; | ||
309 | /* we expect 4 character and then ' */ | ||
310 | int len = 0; | ||
311 | uint32_t value = 0; | ||
312 | while(*ptr != end) | ||
313 | { | ||
314 | if(**ptr != '\'') | ||
315 | { | ||
316 | value = value << 8 | **ptr; | ||
317 | len++; | ||
318 | (*ptr)++; | ||
319 | } | ||
320 | else | ||
321 | break; | ||
322 | } | ||
323 | if(*ptr == end || **ptr != '\'') | ||
324 | bug("Unterminated ascii number literal\n"); | ||
325 | if(len != 1 && len != 2 && len != 4) | ||
326 | bug("Invalid ascii number literal length: only 1, 2 or 4 are valid\n"); | ||
327 | /* skip ' */ | ||
328 | (*ptr)++; | ||
329 | lexem->type = LEX_NUMBER; | ||
330 | lexem->num = value; | ||
331 | } | ||
332 | |||
333 | static void parse_number(char **ptr, char *end, struct lexem_t *lexem) | ||
334 | { | ||
335 | int base = 10; | ||
336 | if(**ptr == '0' && (*ptr) + 1 != end && (*ptr)[1] == 'x') | ||
337 | { | ||
338 | (*ptr) += 2; | ||
339 | base = 16; | ||
340 | } | ||
341 | |||
342 | lexem->type = LEX_NUMBER; | ||
343 | lexem->num = 0; | ||
344 | while(*ptr != end && isxdigit(**ptr)) | ||
345 | { | ||
346 | if(base == 10 && !isdigit(**ptr)) | ||
347 | break; | ||
348 | byte v; | ||
349 | if(convxdigit(**ptr, &v)) | ||
350 | break; | ||
351 | lexem->num = base * lexem->num + v; | ||
352 | (*ptr)++; | ||
353 | } | ||
354 | } | ||
355 | |||
356 | static void parse_identifier(char **ptr, char *end, struct lexem_t *lexem) | ||
357 | { | ||
358 | /* remember position */ | ||
359 | char *old = *ptr; | ||
360 | while(*ptr != end && (isalnum(**ptr) || **ptr == '_')) | ||
361 | (*ptr)++; | ||
362 | lexem->type = LEX_IDENTIFIER; | ||
363 | int len = *ptr - old; | ||
364 | lexem->str = xmalloc(len + 1); | ||
365 | lexem->str[len] = 0; | ||
366 | memcpy(lexem->str, old, len); | ||
367 | } | ||
368 | |||
369 | static void next_lexem(char **ptr, char *end, struct lexem_t *lexem) | ||
370 | { | ||
371 | #define ret_simple(t, advance) ({(*ptr) += advance; lexem->type = t; return;}) | ||
372 | while(*ptr != end) | ||
373 | { | ||
374 | /* skip whitespace */ | ||
375 | if(**ptr == ' ' || **ptr == '\t' || **ptr == '\n' || **ptr == '\r') | ||
376 | { | ||
377 | (*ptr)++; | ||
378 | continue; | ||
379 | } | ||
380 | /* skip C++ style comments */ | ||
381 | if(**ptr == '/' && (*ptr) + 1 != end && (*ptr)[1] == '/') | ||
382 | { | ||
383 | while(*ptr != end && **ptr != '\n') | ||
384 | (*ptr)++; | ||
385 | continue; | ||
386 | } | ||
387 | /* skip C-style comments */ | ||
388 | if(**ptr == '/' && (*ptr) + 1 != end && (*ptr)[1] == '*') | ||
389 | { | ||
390 | (*ptr) += 2; | ||
391 | if(*ptr == end) | ||
392 | bug("invalid command file: unterminated comment"); | ||
393 | while(true) | ||
394 | { | ||
395 | if(**ptr == '*' && (*ptr) + 1 != end && (*ptr)[1] == '/') | ||
396 | { | ||
397 | (*ptr) += 2; | ||
398 | break; | ||
399 | } | ||
400 | (*ptr)++; | ||
401 | } | ||
402 | continue; | ||
403 | } | ||
404 | break; | ||
405 | } | ||
406 | if(*ptr == end) ret_simple(LEX_EOF, 0); | ||
407 | if(**ptr == '(') ret_simple(LEX_LPAREN, 1); | ||
408 | if(**ptr == ')') ret_simple(LEX_RPAREN, 1); | ||
409 | if(**ptr == '{') ret_simple(LEX_LBRACE, 1); | ||
410 | if(**ptr == '}') ret_simple(LEX_RBRACE, 1); | ||
411 | if(**ptr == '>') ret_simple(LEX_RANGLE, 1); | ||
412 | if(**ptr == '=') ret_simple(LEX_EQUAL, 1); | ||
413 | if(**ptr == ';') ret_simple(LEX_SEMICOLON, 1); | ||
414 | if(**ptr == '"') return parse_string(ptr, end, lexem); | ||
415 | if(**ptr == '\'') return parse_ascii_number(ptr, end, lexem); | ||
416 | if(isdigit(**ptr)) return parse_number(ptr, end, lexem); | ||
417 | if(isalpha(**ptr) || **ptr == '_') return parse_identifier(ptr, end, lexem); | ||
418 | bug("Unexpected character '%c' in command file\n", **ptr); | ||
419 | #undef ret_simple | ||
420 | } | ||
421 | |||
422 | #if 0 | ||
423 | static void log_lexem(struct lexem_t *lexem) | ||
424 | { | ||
425 | switch(lexem->type) | ||
426 | { | ||
427 | case LEX_EOF: printf("<eof>"); break; | ||
428 | case LEX_EQUAL: printf("="); break; | ||
429 | case LEX_IDENTIFIER: printf("id(%s)", lexem->str); break; | ||
430 | case LEX_LPAREN: printf("("); break; | ||
431 | case LEX_RPAREN: printf(")"); break; | ||
432 | case LEX_LBRACE: printf("{"); break; | ||
433 | case LEX_RBRACE: printf("}"); break; | ||
434 | case LEX_SEMICOLON: printf(";"); break; | ||
435 | case LEX_NUMBER: printf("num(%d)", lexem->num); break; | ||
436 | case LEX_STRING: printf("str(%s)", lexem->str); break; | ||
437 | default: printf("<unk>"); | ||
438 | } | ||
439 | } | ||
440 | #endif | ||
441 | |||
442 | static struct cmd_source_t *find_source_by_id(struct cmd_file_t *cmd_file, const char *id) | ||
443 | { | ||
444 | struct cmd_source_t *src = cmd_file->source_list; | ||
445 | while(src) | ||
446 | { | ||
447 | if(strcmp(src->identifier, id) == 0) | ||
448 | return src; | ||
449 | src = src->next; | ||
450 | } | ||
451 | return NULL; | ||
452 | } | ||
453 | |||
454 | static void generate_default_version(struct sb_version_t *ver) | ||
455 | { | ||
456 | ver->major = 0x999; | ||
457 | ver->minor = 0x999; | ||
458 | ver->revision = 0x999; | ||
459 | } | ||
460 | |||
461 | static uint16_t parse_sb_subversion(char *str) | ||
462 | { | ||
463 | int len = strlen(str); | ||
464 | uint16_t n = 0; | ||
465 | if(len == 0 || len > 4) | ||
466 | bug("invalid command file: invalid version string"); | ||
467 | for(int i = 0; i < len; i++) | ||
468 | { | ||
469 | if(!isdigit(str[i])) | ||
470 | bug("invalid command file: invalid version string"); | ||
471 | n = n << 4 | (str[i] - '0'); | ||
472 | } | ||
473 | return n; | ||
474 | } | ||
475 | |||
476 | static void parse_sb_version(struct sb_version_t *ver, char *str) | ||
477 | { | ||
478 | int len = strlen(str); | ||
479 | int cnt = 0; | ||
480 | int pos[2]; | ||
481 | |||
482 | for(int i = 0; i < len; i++) | ||
483 | { | ||
484 | if(str[i] != '.') | ||
485 | continue; | ||
486 | if(cnt == 2) | ||
487 | bug("invalid command file: invalid version string"); | ||
488 | pos[cnt++] = i + 1; | ||
489 | str[i] = 0; | ||
490 | } | ||
491 | if(cnt != 2) | ||
492 | bug("invalid command file: invalid version string"); | ||
493 | ver->major = parse_sb_subversion(str); | ||
494 | ver->minor = parse_sb_subversion(str + pos[0]); | ||
495 | ver->revision = parse_sb_subversion(str + pos[1]); | ||
496 | } | ||
497 | |||
498 | static struct cmd_file_t *read_command_file(const char *file) | ||
499 | { | ||
500 | int size; | ||
501 | struct stat st; | ||
502 | int fd = open(file,O_RDONLY); | ||
503 | if(fd == -1) | ||
504 | bugp("opening command file failed"); | ||
505 | if(fstat(fd,&st) == -1) | ||
506 | bugp("command file stat() failed"); | ||
507 | size = st.st_size; | ||
508 | char *buf = xmalloc(size); | ||
509 | if(read(fd, buf, size) != (ssize_t)size) | ||
510 | bugp("reading command file"); | ||
511 | close(fd); | ||
512 | |||
513 | if(g_debug) | ||
514 | printf("Parsing command file '%s'...\n", file); | ||
515 | struct cmd_file_t *cmd_file = xmalloc(sizeof(struct cmd_file_t)); | ||
516 | memset(cmd_file, 0, sizeof(struct cmd_file_t)); | ||
517 | |||
518 | generate_default_version(&cmd_file->product_ver); | ||
519 | generate_default_version(&cmd_file->component_ver); | ||
520 | |||
521 | struct lexem_t lexem; | ||
522 | char *p = buf; | ||
523 | char *end = buf + size; | ||
524 | #define next() next_lexem(&p, end, &lexem) | ||
525 | /* init lexer */ | ||
526 | next(); | ||
527 | /* options ? */ | ||
528 | if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "options")) | ||
529 | { | ||
530 | next(); | ||
531 | if(lexem.type != LEX_LBRACE) | ||
532 | bug("invalid command file: '{' expected after 'options'\n"); | ||
533 | |||
534 | while(true) | ||
535 | { | ||
536 | next(); | ||
537 | if(lexem.type == LEX_RBRACE) | ||
538 | break; | ||
539 | if(lexem.type != LEX_IDENTIFIER) | ||
540 | bug("invalid command file: identifier expected in options\n"); | ||
541 | char *opt = lexem.str; | ||
542 | next(); | ||
543 | if(lexem.type != LEX_EQUAL) | ||
544 | bug("invalid command file: '=' expected after identifier\n"); | ||
545 | next(); | ||
546 | if(!strcmp(opt, "productVersion") || !strcmp(opt, "componentVersion")) | ||
547 | { | ||
548 | if(lexem.type != LEX_STRING) | ||
549 | bug("invalid command file: string expected after '='\n"); | ||
550 | if(!strcmp(opt, "productVersion")) | ||
551 | parse_sb_version(&cmd_file->product_ver, lexem.str); | ||
552 | else | ||
553 | parse_sb_version(&cmd_file->component_ver, lexem.str); | ||
554 | } | ||
555 | else | ||
556 | bug("invalid command file: unknown option '%s'\n", opt); | ||
557 | next(); | ||
558 | if(lexem.type != LEX_SEMICOLON) | ||
559 | bug("invalid command file: ';' expected after string\n"); | ||
560 | } | ||
561 | next(); | ||
562 | } | ||
563 | /* sources */ | ||
564 | if(lexem.type != LEX_IDENTIFIER || strcmp(lexem.str, "sources") != 0) | ||
565 | bug("invalid command file: 'sources' expected\n"); | ||
566 | next(); | ||
567 | if(lexem.type != LEX_LBRACE) | ||
568 | bug("invalid command file: '{' expected after 'sources'\n"); | ||
569 | |||
570 | while(true) | ||
571 | { | ||
572 | next(); | ||
573 | if(lexem.type == LEX_RBRACE) | ||
574 | break; | ||
575 | struct cmd_source_t *src = xmalloc(sizeof(struct cmd_source_t)); | ||
576 | memset(src, 0, sizeof(struct cmd_source_t)); | ||
577 | src->next = cmd_file->source_list; | ||
578 | if(lexem.type != LEX_IDENTIFIER) | ||
579 | bug("invalid command file: identifier expected in sources\n"); | ||
580 | src->identifier = lexem.str; | ||
581 | next(); | ||
582 | if(lexem.type != LEX_EQUAL) | ||
583 | bug("invalid command file: '=' expected after identifier\n"); | ||
584 | next(); | ||
585 | if(lexem.type != LEX_STRING) | ||
586 | bug("invalid command file: string expected after '='\n"); | ||
587 | src->filename = lexem.str; | ||
588 | next(); | ||
589 | if(lexem.type != LEX_SEMICOLON) | ||
590 | bug("invalid command file: ';' expected after string\n"); | ||
591 | if(find_source_by_id(cmd_file, src->identifier) != NULL) | ||
592 | bug("invalid command file: duplicated source identifier\n"); | ||
593 | /* type filled later */ | ||
594 | src->type = CMD_SRC_UNK; | ||
595 | cmd_file->source_list = src; | ||
596 | } | ||
597 | |||
598 | /* sections */ | ||
599 | struct cmd_section_t *end_sec = NULL; | ||
600 | while(true) | ||
601 | { | ||
602 | struct cmd_section_t *sec = xmalloc(sizeof(struct cmd_section_t)); | ||
603 | struct cmd_inst_t *end_list = NULL; | ||
604 | memset(sec, 0, sizeof(struct cmd_section_t)); | ||
605 | next(); | ||
606 | if(lexem.type == LEX_EOF) | ||
607 | break; | ||
608 | if(lexem.type != LEX_IDENTIFIER || strcmp(lexem.str, "section") != 0) | ||
609 | bug("invalid command file: 'section' expected\n"); | ||
610 | next(); | ||
611 | if(lexem.type != LEX_LPAREN) | ||
612 | bug("invalid command file: '(' expected after 'section'\n"); | ||
613 | next(); | ||
614 | /* can be a number or a 4 character long string */ | ||
615 | if(lexem.type == LEX_NUMBER) | ||
616 | { | ||
617 | sec->identifier = lexem.num; | ||
618 | } | ||
619 | else | ||
620 | bug("invalid command file: number expected as section identifier\n"); | ||
621 | |||
622 | next(); | ||
623 | if(lexem.type != LEX_RPAREN) | ||
624 | bug("invalid command file: ')' expected after section identifier\n"); | ||
625 | next(); | ||
626 | if(lexem.type != LEX_LBRACE) | ||
627 | bug("invalid command file: '{' expected after section directive\n"); | ||
628 | /* commands */ | ||
629 | while(true) | ||
630 | { | ||
631 | struct cmd_inst_t *inst = xmalloc(sizeof(struct cmd_inst_t)); | ||
632 | memset(inst, 0, sizeof(struct cmd_inst_t)); | ||
633 | next(); | ||
634 | if(lexem.type == LEX_RBRACE) | ||
635 | break; | ||
636 | if(lexem.type != LEX_IDENTIFIER) | ||
637 | bug("invalid command file: instruction expected in section\n"); | ||
638 | if(strcmp(lexem.str, "load") == 0) | ||
639 | inst->type = CMD_LOAD; | ||
640 | else if(strcmp(lexem.str, "call") == 0) | ||
641 | inst->type = CMD_CALL; | ||
642 | else if(strcmp(lexem.str, "jump") == 0) | ||
643 | inst->type = CMD_JUMP; | ||
644 | else if(strcmp(lexem.str, "mode") == 0) | ||
645 | inst->type = CMD_MODE; | ||
646 | else | ||
647 | bug("invalid command file: instruction expected in section\n"); | ||
648 | next(); | ||
649 | |||
650 | if(inst->type == CMD_LOAD) | ||
651 | { | ||
652 | if(lexem.type != LEX_IDENTIFIER) | ||
653 | bug("invalid command file: identifier expected after instruction\n"); | ||
654 | inst->identifier = lexem.str; | ||
655 | if(find_source_by_id(cmd_file, inst->identifier) == NULL) | ||
656 | bug("invalid command file: undefined reference to source '%s'\n", inst->identifier); | ||
657 | next(); | ||
658 | if(lexem.type == LEX_RANGLE) | ||
659 | { | ||
660 | // load at | ||
661 | inst->type = CMD_LOAD_AT; | ||
662 | next(); | ||
663 | if(lexem.type != LEX_NUMBER) | ||
664 | bug("invalid command file: number expected for loading address\n"); | ||
665 | inst->addr = lexem.num; | ||
666 | next(); | ||
667 | } | ||
668 | if(lexem.type != LEX_SEMICOLON) | ||
669 | bug("invalid command file: expected ';' after command\n"); | ||
670 | } | ||
671 | else if(inst->type == CMD_CALL || inst->type == CMD_JUMP) | ||
672 | { | ||
673 | if(lexem.type == LEX_IDENTIFIER) | ||
674 | { | ||
675 | inst->identifier = lexem.str; | ||
676 | if(find_source_by_id(cmd_file, inst->identifier) == NULL) | ||
677 | bug("invalid command file: undefined reference to source '%s'\n", inst->identifier); | ||
678 | next(); | ||
679 | } | ||
680 | else if(lexem.type == LEX_NUMBER) | ||
681 | { | ||
682 | inst->type = (inst->type == CMD_CALL) ? CMD_CALL_AT : CMD_JUMP_AT; | ||
683 | inst->addr = lexem.num; | ||
684 | next(); | ||
685 | } | ||
686 | else | ||
687 | bug("invalid command file: identifier or number expected after jump/load\n"); | ||
688 | |||
689 | if(lexem.type == LEX_LPAREN) | ||
690 | { | ||
691 | next(); | ||
692 | if(lexem.type != LEX_NUMBER) | ||
693 | bug("invalid command file: expected numeral expression after (\n"); | ||
694 | inst->argument = lexem.num; | ||
695 | next(); | ||
696 | if(lexem.type != LEX_RPAREN) | ||
697 | bug("invalid command file: expected closing brace\n"); | ||
698 | next(); | ||
699 | } | ||
700 | if(lexem.type != LEX_SEMICOLON) | ||
701 | bug("invalid command file: expected ';' after command\n"); | ||
702 | } | ||
703 | else if(inst->type == CMD_MODE) | ||
704 | { | ||
705 | if(lexem.type != LEX_NUMBER) | ||
706 | bug("invalid command file: number expected after 'mode'\n"); | ||
707 | inst->argument = lexem.num; | ||
708 | next(); | ||
709 | if(lexem.type != LEX_SEMICOLON) | ||
710 | bug("invalid command file: expected ';' after command\n"); | ||
711 | } | ||
712 | else | ||
713 | bug("die\n"); | ||
714 | if(end_list == NULL) | ||
715 | { | ||
716 | sec->inst_list = inst; | ||
717 | end_list = inst; | ||
718 | } | ||
719 | else | ||
720 | { | ||
721 | end_list->next = inst; | ||
722 | end_list = inst; | ||
723 | } | ||
724 | } | ||
725 | |||
726 | if(end_sec == NULL) | ||
727 | { | ||
728 | cmd_file->section_list = sec; | ||
729 | end_sec = sec; | ||
730 | } | ||
731 | else | ||
732 | { | ||
733 | end_sec->next = sec; | ||
734 | end_sec = sec; | ||
735 | } | ||
736 | } | ||
737 | #undef next | ||
738 | |||
739 | return cmd_file; | ||
740 | } | ||
741 | |||
742 | /** | ||
743 | * command file to sb conversion | 168 | * command file to sb conversion |
744 | */ | 169 | */ |
745 | 170 | ||
@@ -798,7 +223,7 @@ static void elf_printf(void *user, bool error, const char *fmt, ...) | |||
798 | 223 | ||
799 | static void load_elf_by_id(struct cmd_file_t *cmd_file, const char *id) | 224 | static void load_elf_by_id(struct cmd_file_t *cmd_file, const char *id) |
800 | { | 225 | { |
801 | struct cmd_source_t *src = find_source_by_id(cmd_file, id); | 226 | struct cmd_source_t *src = db_find_source_by_id(cmd_file, id); |
802 | if(src == NULL) | 227 | if(src == NULL) |
803 | bug("undefined reference to source '%s'\n", id); | 228 | bug("undefined reference to source '%s'\n", id); |
804 | /* avoid reloading */ | 229 | /* avoid reloading */ |
@@ -822,7 +247,7 @@ static void load_elf_by_id(struct cmd_file_t *cmd_file, const char *id) | |||
822 | 247 | ||
823 | static void load_bin_by_id(struct cmd_file_t *cmd_file, const char *id) | 248 | static void load_bin_by_id(struct cmd_file_t *cmd_file, const char *id) |
824 | { | 249 | { |
825 | struct cmd_source_t *src = find_source_by_id(cmd_file, id); | 250 | struct cmd_source_t *src = db_find_source_by_id(cmd_file, id); |
826 | if(src == NULL) | 251 | if(src == NULL) |
827 | bug("undefined reference to source '%s'\n", id); | 252 | bug("undefined reference to source '%s'\n", id); |
828 | /* avoid reloading */ | 253 | /* avoid reloading */ |
@@ -877,13 +302,13 @@ static struct sb_file_t *apply_cmd_file(struct cmd_file_t *cmd_file) | |||
877 | if(cinst->type == CMD_LOAD) | 302 | if(cinst->type == CMD_LOAD) |
878 | { | 303 | { |
879 | load_elf_by_id(cmd_file, cinst->identifier); | 304 | load_elf_by_id(cmd_file, cinst->identifier); |
880 | struct elf_params_t *elf = &find_source_by_id(cmd_file, cinst->identifier)->elf; | 305 | struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf; |
881 | sec->nr_insts += elf_get_nr_sections(elf); | 306 | sec->nr_insts += elf_get_nr_sections(elf); |
882 | } | 307 | } |
883 | else if(cinst->type == CMD_JUMP || cinst->type == CMD_CALL) | 308 | else if(cinst->type == CMD_JUMP || cinst->type == CMD_CALL) |
884 | { | 309 | { |
885 | load_elf_by_id(cmd_file, cinst->identifier); | 310 | load_elf_by_id(cmd_file, cinst->identifier); |
886 | struct elf_params_t *elf = &find_source_by_id(cmd_file, cinst->identifier)->elf; | 311 | struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf; |
887 | if(!elf_get_start_addr(elf, NULL)) | 312 | if(!elf_get_start_addr(elf, NULL)) |
888 | bug("cannot jump/call '%s' because it has no starting point !\n", cinst->identifier); | 313 | bug("cannot jump/call '%s' because it has no starting point !\n", cinst->identifier); |
889 | sec->nr_insts++; | 314 | sec->nr_insts++; |
@@ -916,7 +341,7 @@ static struct sb_file_t *apply_cmd_file(struct cmd_file_t *cmd_file) | |||
916 | { | 341 | { |
917 | if(cinst->type == CMD_LOAD) | 342 | if(cinst->type == CMD_LOAD) |
918 | { | 343 | { |
919 | struct elf_params_t *elf = &find_source_by_id(cmd_file, cinst->identifier)->elf; | 344 | struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf; |
920 | struct elf_section_t *esec = elf->first_section; | 345 | struct elf_section_t *esec = elf->first_section; |
921 | while(esec) | 346 | while(esec) |
922 | { | 347 | { |
@@ -939,7 +364,7 @@ static struct sb_file_t *apply_cmd_file(struct cmd_file_t *cmd_file) | |||
939 | } | 364 | } |
940 | else if(cinst->type == CMD_JUMP || cinst->type == CMD_CALL) | 365 | else if(cinst->type == CMD_JUMP || cinst->type == CMD_CALL) |
941 | { | 366 | { |
942 | struct elf_params_t *elf = &find_source_by_id(cmd_file, cinst->identifier)->elf; | 367 | struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf; |
943 | sec->insts[idx].argument = cinst->argument; | 368 | sec->insts[idx].argument = cinst->argument; |
944 | sec->insts[idx].inst = (cinst->type == CMD_JUMP) ? SB_INST_JUMP : SB_INST_CALL; | 369 | sec->insts[idx].inst = (cinst->type == CMD_JUMP) ? SB_INST_JUMP : SB_INST_CALL; |
945 | sec->insts[idx++].addr = elf->start_addr; | 370 | sec->insts[idx++].addr = elf->start_addr; |
@@ -952,7 +377,7 @@ static struct sb_file_t *apply_cmd_file(struct cmd_file_t *cmd_file) | |||
952 | } | 377 | } |
953 | else if(cinst->type == CMD_LOAD_AT) | 378 | else if(cinst->type == CMD_LOAD_AT) |
954 | { | 379 | { |
955 | struct bin_param_t *bin = &find_source_by_id(cmd_file, cinst->identifier)->bin; | 380 | struct bin_param_t *bin = &db_find_source_by_id(cmd_file, cinst->identifier)->bin; |
956 | sec->insts[idx].inst = SB_INST_LOAD; | 381 | sec->insts[idx].inst = SB_INST_LOAD; |
957 | sec->insts[idx].addr = cinst->addr; | 382 | sec->insts[idx].addr = cinst->addr; |
958 | sec->insts[idx].data = bin->data; | 383 | sec->insts[idx].data = bin->data; |
@@ -1294,7 +719,7 @@ int main(int argc, const char **argv) | |||
1294 | g_debug = true; | 719 | g_debug = true; |
1295 | 720 | ||
1296 | g_key_array = read_keys(argv[2], &g_nr_keys); | 721 | g_key_array = read_keys(argv[2], &g_nr_keys); |
1297 | struct cmd_file_t *cmd_file = read_command_file(argv[1]); | 722 | struct cmd_file_t *cmd_file = db_parse_file(argv[1]); |
1298 | struct sb_file_t *sb_file = apply_cmd_file(cmd_file); | 723 | struct sb_file_t *sb_file = apply_cmd_file(cmd_file); |
1299 | produce_sb_file(sb_file, argv[3]); | 724 | produce_sb_file(sb_file, argv[3]); |
1300 | 725 | ||
diff --git a/utils/sbtools/sb.h b/utils/sbtools/sb.h index a1482691ce..0a8fad10af 100644 --- a/utils/sbtools/sb.h +++ b/utils/sbtools/sb.h | |||
@@ -18,6 +18,8 @@ | |||
18 | * KIND, either express or implied. | 18 | * KIND, either express or implied. |
19 | * | 19 | * |
20 | ****************************************************************************/ | 20 | ****************************************************************************/ |
21 | #ifndef __SB_H__ | ||
22 | #define __SB_H__ | ||
21 | 23 | ||
22 | #include <stdint.h> | 24 | #include <stdint.h> |
23 | 25 | ||
@@ -147,3 +149,5 @@ struct sb_instruction_tag_t | |||
147 | uint32_t len; /* length of the section */ | 149 | uint32_t len; /* length of the section */ |
148 | uint32_t flags; /* section flags */ | 150 | uint32_t flags; /* section flags */ |
149 | } __attribute__((packed)); | 151 | } __attribute__((packed)); |
152 | |||
153 | #endif /* __SB_H__ */ | ||