Commit e37ddb82500393cb417c3ab0fe0726d9a8652372

Authored by Michal Marek
1 parent 01762c4ec5

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>

Showing 4 changed files with 127 additions and 13 deletions Side-by-side Diff

scripts/genksyms/genksyms.c
... ... @@ -62,6 +62,7 @@
62 62 [SYM_ENUM] = {'e', "enum"},
63 63 [SYM_STRUCT] = {'s', "struct"},
64 64 [SYM_UNION] = {'u', "union"},
  65 + [SYM_ENUM_CONST] = {'E', "enum constant"},
65 66 };
66 67  
67 68 static int equal_list(struct string_list *a, struct string_list *b);
... ... @@ -149,10 +150,16 @@
149 150  
150 151 static enum symbol_type map_to_ns(enum symbol_type t)
151 152 {
152   - if (t == SYM_TYPEDEF)
153   - t = SYM_NORMAL;
154   - else if (t == SYM_UNION)
155   - t = SYM_STRUCT;
  153 + switch (t) {
  154 + case SYM_ENUM_CONST:
  155 + case SYM_NORMAL:
  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 163 return t;
157 164 }
158 165  
159 166  
160 167  
... ... @@ -191,10 +198,47 @@
191 198 struct string_list *defn, int is_extern,
192 199 int is_reference)
193 200 {
194   - unsigned long h = crc32(name) % HASH_BUCKETS;
  201 + unsigned long h;
195 202 struct symbol *sym;
196 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;
197 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 + }
  240 +
  241 + h = crc32(name) % HASH_BUCKETS;
198 242 for (sym = symtab[h]; sym; sym = sym->hash_next) {
199 243 if (map_to_ns(sym->type) == map_to_ns(type) &&
200 244 strcmp(name, sym->name) == 0) {
... ... @@ -343,6 +387,22 @@
343 387 return newnode;
344 388 }
345 389  
  390 +struct 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 +
346 406 static int equal_list(struct string_list *a, struct string_list *b)
347 407 {
348 408 while (a && b) {
... ... @@ -512,6 +572,7 @@
512 572 crc = partial_crc32_one(' ', crc);
513 573 break;
514 574  
  575 + case SYM_ENUM_CONST:
515 576 case SYM_TYPEDEF:
516 577 subsym = find_symbol(cur->string, cur->tag, 0);
517 578 /* FIXME: Bad reference files can segfault here. */
scripts/genksyms/genksyms.h
... ... @@ -26,7 +26,8 @@
26 26 #include <stdio.h>
27 27  
28 28 enum 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  
32 33 enum symbol_status {
... ... @@ -66,6 +67,8 @@
66 67 void free_node(struct string_list *list);
67 68 void free_list(struct string_list *s, struct string_list *e);
68 69 struct string_list *copy_node(struct string_list *);
  70 +struct string_list *copy_list_range(struct string_list *start,
  71 + struct string_list *end);
69 72  
70 73 int yylex(void);
71 74 int yyparse(void);
scripts/genksyms/lex.l
... ... @@ -99,12 +99,23 @@
99 99  
100 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 111 #define _APP(T,L) do { \
103 112 cur_node = next_node; \
104 113 next_node = xmalloc(sizeof(*next_node)); \
105 114 next_node->next = cur_node; \
106 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 119 } while (0)
109 120  
110 121 #define APP _APP(yytext, yyleng)
111 122  
... ... @@ -182,8 +193,8 @@
182 193  
183 194 case STRUCT_KEYW:
184 195 case UNION_KEYW:
185   - dont_want_brace_phrase = 3;
186 196 case ENUM_KEYW:
  197 + dont_want_brace_phrase = 3;
187 198 suppress_type_lookup = 2;
188 199 goto fini;
189 200  
... ... @@ -312,7 +323,20 @@
312 323 ++count;
313 324 APP;
314 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 340 --count;
317 341 APP;
318 342 goto repeat;
scripts/genksyms/parse.y
... ... @@ -25,6 +25,7 @@
25 25  
26 26 #include <assert.h>
27 27 #include <stdlib.h>
  28 +#include <string.h>
28 29 #include "genksyms.h"
29 30  
30 31 static int is_typedef;
31 32  
... ... @@ -227,16 +228,19 @@
227 228 add_symbol(i->string, SYM_UNION, s, is_extern);
228 229 $$ = $3;
229 230 }
230   - | ENUM_KEYW IDENT BRACE_PHRASE
  231 + | ENUM_KEYW IDENT enum_body
231 232 { struct string_list *s = *$3, *i = *$2, *r;
232 233 r = copy_node(i); r->tag = SYM_ENUM;
233 234 r->next = (*$1)->next; *$3 = r; (*$1)->next = NULL;
234 235 add_symbol(i->string, SYM_ENUM, s, is_extern);
235 236 $$ = $3;
236 237 }
237   -
238   - /* Anonymous s/u/e definitions. Nothing needs doing. */
239   - | ENUM_KEYW BRACE_PHRASE { $$ = $2; }
  238 + /*
  239 + * Anonymous enum definition. Tell add_symbol() to restart its counter.
  240 + */
  241 + | ENUM_KEYW enum_body
  242 + { add_symbol(NULL, SYM_ENUM, NULL, 0); $$ = $2; }
  243 + /* Anonymous s/u definitions. Nothing needs doing. */
240 244 | STRUCT_KEYW class_body { $$ = $2; }
241 245 | UNION_KEYW class_body { $$ = $2; }
242 246 ;
... ... @@ -448,6 +452,28 @@
448 452 /* empty */ { $$ = NULL; }
449 453 | attribute_opt ATTRIBUTE_PHRASE
450 454 ;
  455 +
  456 +enum_body:
  457 + '{' enumerator_list '}' { $$ = $3; }
  458 + | '{' enumerator_list ',' '}' { $$ = $4; }
  459 + ;
  460 +
  461 +enumerator_list:
  462 + enumerator
  463 + | enumerator_list ',' enumerator
  464 +
  465 +enumerator:
  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 + }
451 477  
452 478 asm_definition:
453 479 ASM_PHRASE ';' { $$ = $2; }