Skip to content

Commit e37ddb8

Browse files
committed
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 <[email protected]> Acked-by: Sam Ravnborg <[email protected]>
1 parent 01762c4 commit e37ddb8

File tree

4 files changed

+127
-13
lines changed

4 files changed

+127
-13
lines changed

scripts/genksyms/genksyms.c

Lines changed: 66 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ static const struct {
6262
[SYM_ENUM] = {'e', "enum"},
6363
[SYM_STRUCT] = {'s', "struct"},
6464
[SYM_UNION] = {'u', "union"},
65+
[SYM_ENUM_CONST] = {'E', "enum constant"},
6566
};
6667

6768
static int equal_list(struct string_list *a, struct string_list *b);
@@ -149,10 +150,16 @@ static unsigned long crc32(const char *s)
149150

150151
static enum symbol_type map_to_ns(enum symbol_type t)
151152
{
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+
}
156163
return t;
157164
}
158165

@@ -191,10 +198,47 @@ static struct symbol *__add_symbol(const char *name, enum symbol_type type,
191198
struct string_list *defn, int is_extern,
192199
int is_reference)
193200
{
194-
unsigned long h = crc32(name) % HASH_BUCKETS;
201+
unsigned long h;
195202
struct symbol *sym;
196203
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+
}
197240

241+
h = crc32(name) % HASH_BUCKETS;
198242
for (sym = symtab[h]; sym; sym = sym->hash_next) {
199243
if (map_to_ns(sym->type) == map_to_ns(type) &&
200244
strcmp(name, sym->name) == 0) {
@@ -343,6 +387,22 @@ struct string_list *copy_node(struct string_list *node)
343387
return newnode;
344388
}
345389

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+
346406
static int equal_list(struct string_list *a, struct string_list *b)
347407
{
348408
while (a && b) {
@@ -512,6 +572,7 @@ static unsigned long expand_and_crc_sym(struct symbol *sym, unsigned long crc)
512572
crc = partial_crc32_one(' ', crc);
513573
break;
514574

575+
case SYM_ENUM_CONST:
515576
case SYM_TYPEDEF:
516577
subsym = find_symbol(cur->string, cur->tag, 0);
517578
/* FIXME: Bad reference files can segfault here. */

scripts/genksyms/genksyms.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
#include <stdio.h>
2727

2828
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
3031
};
3132

3233
enum symbol_status {
@@ -66,6 +67,8 @@ void export_symbol(const char *);
6667
void free_node(struct string_list *list);
6768
void free_list(struct string_list *s, struct string_list *e);
6869
struct string_list *copy_node(struct string_list *);
70+
struct string_list *copy_list_range(struct string_list *start,
71+
struct string_list *end);
6972

7073
int yylex(void);
7174
int yyparse(void);

scripts/genksyms/lex.l

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,23 @@ MC_TOKEN ([~%^&*+=|<>/-]=)|(&&)|("||")|(->)|(<<)|(>>)
9999
100100
/* Macros to append to our phrase collection list. */
101101
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+
*/
102111
#define _APP(T,L) do { \
103112
cur_node = next_node; \
104113
next_node = xmalloc(sizeof(*next_node)); \
105114
next_node->next = cur_node; \
106115
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 ; \
108119
} while (0)
109120
110121
#define APP _APP(yytext, yyleng)
@@ -182,8 +193,8 @@ repeat:
182193
183194
case STRUCT_KEYW:
184195
case UNION_KEYW:
185-
dont_want_brace_phrase = 3;
186196
case ENUM_KEYW:
197+
dont_want_brace_phrase = 3;
187198
suppress_type_lookup = 2;
188199
goto fini;
189200
@@ -312,7 +323,20 @@ repeat:
312323
++count;
313324
APP;
314325
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 ']':
316340
--count;
317341
APP;
318342
goto repeat;

scripts/genksyms/parse.y

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
#include <assert.h>
2727
#include <stdlib.h>
28+
#include <string.h>
2829
#include "genksyms.h"
2930

3031
static int is_typedef;
@@ -227,16 +228,19 @@ type_specifier:
227228
add_symbol(i->string, SYM_UNION, s, is_extern);
228229
$$ = $3;
229230
}
230-
| ENUM_KEYW IDENT BRACE_PHRASE
231+
| ENUM_KEYW IDENT enum_body
231232
{ struct string_list *s = *$3, *i = *$2, *r;
232233
r = copy_node(i); r->tag = SYM_ENUM;
233234
r->next = (*$1)->next; *$3 = r; (*$1)->next = NULL;
234235
add_symbol(i->string, SYM_ENUM, s, is_extern);
235236
$$ = $3;
236237
}
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. */
240244
| STRUCT_KEYW class_body { $$ = $2; }
241245
| UNION_KEYW class_body { $$ = $2; }
242246
;
@@ -449,6 +453,28 @@ attribute_opt:
449453
| attribute_opt ATTRIBUTE_PHRASE
450454
;
451455

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+
}
477+
452478
asm_definition:
453479
ASM_PHRASE ';' { $$ = $2; }
454480
;

0 commit comments

Comments
 (0)