aboutsummaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
authorMichal Marek <mmarek@suse.cz>2011-02-03 17:57:09 -0500
committerMichal Marek <mmarek@suse.cz>2011-03-17 10:13:56 -0400
commite37ddb82500393cb417c3ab0fe0726d9a8652372 (patch)
tree6ecc94992cb5affad4fe438d9b586a61b803f928 /scripts
parent01762c4ec5f6f62c550304b9c70e824293cefdd0 (diff)
genksyms: Track changes to enum constants
Enum constants can be used as array sizes; if the enum itself does not appear in the symbol expansion, a change in the enum constant will go unnoticed. Example patch that changes the ABI but does not change the checksum with current genksyms: | enum e { | E1, | E2, |+ E3, | E_MAX | }; | | struct s { | int a[E_MAX]; | } | | int f(struct s *s) { ... } | EXPORT_SYMBOL(f) Therefore, remember the value of each enum constant and expand each occurence to <constant> <value>. The value is not actually computed, but instead an expression in the form (last explicitly assigned value) + N is used. This avoids having to parse and semantically understand whole of C. Note: The changes won't take effect until the lexer and parser are rebuilt by the next patch. Signed-off-by: Michal Marek <mmarek@suse.cz> Acked-by: Sam Ravnborg <sam@ravnborg.org>
Diffstat (limited to 'scripts')
-rw-r--r--scripts/genksyms/genksyms.c71
-rw-r--r--scripts/genksyms/genksyms.h5
-rw-r--r--scripts/genksyms/lex.l30
-rw-r--r--scripts/genksyms/parse.y34
4 files changed, 127 insertions, 13 deletions
diff --git a/scripts/genksyms/genksyms.c b/scripts/genksyms/genksyms.c
index 4a350816a9e8..f9e75531ea03 100644
--- a/scripts/genksyms/genksyms.c
+++ b/scripts/genksyms/genksyms.c
@@ -62,6 +62,7 @@ static const struct {
62 [SYM_ENUM] = {'e', "enum"}, 62 [SYM_ENUM] = {'e', "enum"},
63 [SYM_STRUCT] = {'s', "struct"}, 63 [SYM_STRUCT] = {'s', "struct"},
64 [SYM_UNION] = {'u', "union"}, 64 [SYM_UNION] = {'u', "union"},
65 [SYM_ENUM_CONST] = {'E', "enum constant"},
65}; 66};
66 67
67static int equal_list(struct string_list *a, struct string_list *b); 68static int equal_list(struct string_list *a, struct string_list *b);
@@ -149,10 +150,16 @@ static unsigned long crc32(const char *s)
149 150
150static enum symbol_type map_to_ns(enum symbol_type t) 151static enum symbol_type map_to_ns(enum symbol_type t)
151{ 152{
152 if (t == SYM_TYPEDEF) 153 switch (t) {
153 t = SYM_NORMAL; 154 case SYM_ENUM_CONST:
154 else if (t == SYM_UNION) 155 case SYM_NORMAL:
155 t = SYM_STRUCT; 156 case SYM_TYPEDEF:
157 return SYM_NORMAL;
158 case SYM_ENUM:
159 case SYM_STRUCT:
160 case SYM_UNION:
161 return SYM_STRUCT;
162 }
156 return t; 163 return t;
157} 164}
158 165
@@ -191,10 +198,47 @@ static struct symbol *__add_symbol(const char *name, enum symbol_type type,
191 struct string_list *defn, int is_extern, 198 struct string_list *defn, int is_extern,
192 int is_reference) 199 int is_reference)
193{ 200{
194 unsigned long h = crc32(name) % HASH_BUCKETS; 201 unsigned long h;
195 struct symbol *sym; 202 struct symbol *sym;
196 enum symbol_status status = STATUS_UNCHANGED; 203 enum symbol_status status = STATUS_UNCHANGED;
204 /* The parser adds symbols in the order their declaration completes,
205 * so it is safe to store the value of the previous enum constant in
206 * a static variable.
207 */
208 static int enum_counter;
209 static struct string_list *last_enum_expr;
210
211 if (type == SYM_ENUM_CONST) {
212 if (defn) {
213 free_list(last_enum_expr, NULL);
214 last_enum_expr = copy_list_range(defn, NULL);
215 enum_counter = 1;
216 } else {
217 struct string_list *expr;
218 char buf[20];
219
220 snprintf(buf, sizeof(buf), "%d", enum_counter++);
221 if (last_enum_expr) {
222 expr = copy_list_range(last_enum_expr, NULL);
223 defn = concat_list(mk_node("("),
224 expr,
225 mk_node(")"),
226 mk_node("+"),
227 mk_node(buf), NULL);
228 } else {
229 defn = mk_node(buf);
230 }
231 }
232 } else if (type == SYM_ENUM) {
233 free_list(last_enum_expr, NULL);
234 last_enum_expr = NULL;
235 enum_counter = 0;
236 if (!name)
237 /* Anonymous enum definition, nothing more to do */
238 return NULL;
239 }
197 240
241 h = crc32(name) % HASH_BUCKETS;
198 for (sym = symtab[h]; sym; sym = sym->hash_next) { 242 for (sym = symtab[h]; sym; sym = sym->hash_next) {
199 if (map_to_ns(sym->type) == map_to_ns(type) && 243 if (map_to_ns(sym->type) == map_to_ns(type) &&
200 strcmp(name, sym->name) == 0) { 244 strcmp(name, sym->name) == 0) {
@@ -343,6 +387,22 @@ struct string_list *copy_node(struct string_list *node)
343 return newnode; 387 return newnode;
344} 388}
345 389
390struct string_list *copy_list_range(struct string_list *start,
391 struct string_list *end)
392{
393 struct string_list *res, *n;
394
395 if (start == end)
396 return NULL;
397 n = res = copy_node(start);
398 for (start = start->next; start != end; start = start->next) {
399 n->next = copy_node(start);
400 n = n->next;
401 }
402 n->next = NULL;
403 return res;
404}
405
346static int equal_list(struct string_list *a, struct string_list *b) 406static int equal_list(struct string_list *a, struct string_list *b)
347{ 407{
348 while (a && b) { 408 while (a && b) {
@@ -512,6 +572,7 @@ static unsigned long expand_and_crc_sym(struct symbol *sym, unsigned long crc)
512 crc = partial_crc32_one(' ', crc); 572 crc = partial_crc32_one(' ', crc);
513 break; 573 break;
514 574
575 case SYM_ENUM_CONST:
515 case SYM_TYPEDEF: 576 case SYM_TYPEDEF:
516 subsym = find_symbol(cur->string, cur->tag, 0); 577 subsym = find_symbol(cur->string, cur->tag, 0);
517 /* FIXME: Bad reference files can segfault here. */ 578 /* FIXME: Bad reference files can segfault here. */
diff --git a/scripts/genksyms/genksyms.h b/scripts/genksyms/genksyms.h
index 9fdafb667e76..7ec52ae3846a 100644
--- a/scripts/genksyms/genksyms.h
+++ b/scripts/genksyms/genksyms.h
@@ -26,7 +26,8 @@
26#include <stdio.h> 26#include <stdio.h>
27 27
28enum symbol_type { 28enum symbol_type {
29 SYM_NORMAL, SYM_TYPEDEF, SYM_ENUM, SYM_STRUCT, SYM_UNION 29 SYM_NORMAL, SYM_TYPEDEF, SYM_ENUM, SYM_STRUCT, SYM_UNION,
30 SYM_ENUM_CONST
30}; 31};
31 32
32enum symbol_status { 33enum symbol_status {
@@ -66,6 +67,8 @@ void export_symbol(const char *);
66void free_node(struct string_list *list); 67void free_node(struct string_list *list);
67void free_list(struct string_list *s, struct string_list *e); 68void free_list(struct string_list *s, struct string_list *e);
68struct string_list *copy_node(struct string_list *); 69struct string_list *copy_node(struct string_list *);
70struct string_list *copy_list_range(struct string_list *start,
71 struct string_list *end);
69 72
70int yylex(void); 73int yylex(void);
71int yyparse(void); 74int yyparse(void);
diff --git a/scripts/genksyms/lex.l b/scripts/genksyms/lex.l
index c125d06fbd36..e4ddd493fec3 100644
--- a/scripts/genksyms/lex.l
+++ b/scripts/genksyms/lex.l
@@ -99,12 +99,23 @@ MC_TOKEN ([~%^&*+=|<>/-]=)|(&&)|("||")|(->)|(<<)|(>>)
99 99
100/* Macros to append to our phrase collection list. */ 100/* Macros to append to our phrase collection list. */
101 101
102/*
103 * We mark any token, that that equals to a known enumerator, as
104 * SYM_ENUM_CONST. The parser will change this for struct and union tags later,
105 * the only problem is struct and union members:
106 * enum e { a, b }; struct s { int a, b; }
107 * but in this case, the only effect will be, that the ABI checksums become
108 * more volatile, which is acceptable. Also, such collisions are quite rare,
109 * so far it was only observed in include/linux/telephony.h.
110 */
102#define _APP(T,L) do { \ 111#define _APP(T,L) do { \
103 cur_node = next_node; \ 112 cur_node = next_node; \
104 next_node = xmalloc(sizeof(*next_node)); \ 113 next_node = xmalloc(sizeof(*next_node)); \
105 next_node->next = cur_node; \ 114 next_node->next = cur_node; \
106 cur_node->string = memcpy(xmalloc(L+1), T, L+1); \ 115 cur_node->string = memcpy(xmalloc(L+1), T, L+1); \
107 cur_node->tag = SYM_NORMAL; \ 116 cur_node->tag = \
117 find_symbol(cur_node->string, SYM_ENUM_CONST, 1)?\
118 SYM_ENUM_CONST : SYM_NORMAL ; \
108 } while (0) 119 } while (0)
109 120
110#define APP _APP(yytext, yyleng) 121#define APP _APP(yytext, yyleng)
@@ -182,8 +193,8 @@ repeat:
182 193
183 case STRUCT_KEYW: 194 case STRUCT_KEYW:
184 case UNION_KEYW: 195 case UNION_KEYW:
185 dont_want_brace_phrase = 3;
186 case ENUM_KEYW: 196 case ENUM_KEYW:
197 dont_want_brace_phrase = 3;
187 suppress_type_lookup = 2; 198 suppress_type_lookup = 2;
188 goto fini; 199 goto fini;
189 200
@@ -312,7 +323,20 @@ repeat:
312 ++count; 323 ++count;
313 APP; 324 APP;
314 goto repeat; 325 goto repeat;
315 case ')': case ']': case '}': 326 case '}':
327 /* is this the last line of an enum declaration? */
328 if (count == 0)
329 {
330 /* Put back the token we just read so's we can find it again
331 after registering the expression. */
332 unput(token);
333
334 lexstate = ST_NORMAL;
335 token = EXPRESSION_PHRASE;
336 break;
337 }
338 /* FALLTHRU */
339 case ')': case ']':
316 --count; 340 --count;
317 APP; 341 APP;
318 goto repeat; 342 goto repeat;
diff --git a/scripts/genksyms/parse.y b/scripts/genksyms/parse.y
index 09a265cd7193..ba5c242866c1 100644
--- a/scripts/genksyms/parse.y
+++ b/scripts/genksyms/parse.y
@@ -25,6 +25,7 @@
25 25
26#include <assert.h> 26#include <assert.h>
27#include <stdlib.h> 27#include <stdlib.h>
28#include <string.h>
28#include "genksyms.h" 29#include "genksyms.h"
29 30
30static int is_typedef; 31static int is_typedef;
@@ -227,16 +228,19 @@ type_specifier:
227 add_symbol(i->string, SYM_UNION, s, is_extern); 228 add_symbol(i->string, SYM_UNION, s, is_extern);
228 $$ = $3; 229 $$ = $3;
229 } 230 }
230 | ENUM_KEYW IDENT BRACE_PHRASE 231 | ENUM_KEYW IDENT enum_body
231 { struct string_list *s = *$3, *i = *$2, *r; 232 { struct string_list *s = *$3, *i = *$2, *r;
232 r = copy_node(i); r->tag = SYM_ENUM; 233 r = copy_node(i); r->tag = SYM_ENUM;
233 r->next = (*$1)->next; *$3 = r; (*$1)->next = NULL; 234 r->next = (*$1)->next; *$3 = r; (*$1)->next = NULL;
234 add_symbol(i->string, SYM_ENUM, s, is_extern); 235 add_symbol(i->string, SYM_ENUM, s, is_extern);
235 $$ = $3; 236 $$ = $3;
236 } 237 }
237 238 /*
238 /* Anonymous s/u/e definitions. Nothing needs doing. */ 239 * Anonymous enum definition. Tell add_symbol() to restart its counter.
239 | ENUM_KEYW BRACE_PHRASE { $$ = $2; } 240 */
241 | ENUM_KEYW enum_body
242 { add_symbol(NULL, SYM_ENUM, NULL, 0); $$ = $2; }
243 /* Anonymous s/u definitions. Nothing needs doing. */
240 | STRUCT_KEYW class_body { $$ = $2; } 244 | STRUCT_KEYW class_body { $$ = $2; }
241 | UNION_KEYW class_body { $$ = $2; } 245 | UNION_KEYW class_body { $$ = $2; }
242 ; 246 ;
@@ -449,6 +453,28 @@ attribute_opt:
449 | attribute_opt ATTRIBUTE_PHRASE 453 | attribute_opt ATTRIBUTE_PHRASE
450 ; 454 ;
451 455
456enum_body:
457 '{' enumerator_list '}' { $$ = $3; }
458 | '{' enumerator_list ',' '}' { $$ = $4; }
459 ;
460
461enumerator_list:
462 enumerator
463 | enumerator_list ',' enumerator
464
465enumerator:
466 IDENT
467 {
468 const char *name = strdup((*$1)->string);
469 add_symbol(name, SYM_ENUM_CONST, NULL, 0);
470 }
471 | IDENT '=' EXPRESSION_PHRASE
472 {
473 const char *name = strdup((*$1)->string);
474 struct string_list *expr = copy_list_range(*$3, *$2);
475 add_symbol(name, SYM_ENUM_CONST, expr, 0);
476 }
477
452asm_definition: 478asm_definition:
453 ASM_PHRASE ';' { $$ = $2; } 479 ASM_PHRASE ';' { $$ = $2; }
454 ; 480 ;