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>
This commit is contained in:
@@ -25,6 +25,7 @@
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "genksyms.h"
|
||||
|
||||
static int is_typedef;
|
||||
@@ -227,16 +228,19 @@ type_specifier:
|
||||
add_symbol(i->string, SYM_UNION, s, is_extern);
|
||||
$$ = $3;
|
||||
}
|
||||
| ENUM_KEYW IDENT BRACE_PHRASE
|
||||
| ENUM_KEYW IDENT enum_body
|
||||
{ struct string_list *s = *$3, *i = *$2, *r;
|
||||
r = copy_node(i); r->tag = SYM_ENUM;
|
||||
r->next = (*$1)->next; *$3 = r; (*$1)->next = NULL;
|
||||
add_symbol(i->string, SYM_ENUM, s, is_extern);
|
||||
$$ = $3;
|
||||
}
|
||||
|
||||
/* Anonymous s/u/e definitions. Nothing needs doing. */
|
||||
| ENUM_KEYW BRACE_PHRASE { $$ = $2; }
|
||||
/*
|
||||
* Anonymous enum definition. Tell add_symbol() to restart its counter.
|
||||
*/
|
||||
| ENUM_KEYW enum_body
|
||||
{ add_symbol(NULL, SYM_ENUM, NULL, 0); $$ = $2; }
|
||||
/* Anonymous s/u definitions. Nothing needs doing. */
|
||||
| STRUCT_KEYW class_body { $$ = $2; }
|
||||
| UNION_KEYW class_body { $$ = $2; }
|
||||
;
|
||||
@@ -449,6 +453,28 @@ attribute_opt:
|
||||
| attribute_opt ATTRIBUTE_PHRASE
|
||||
;
|
||||
|
||||
enum_body:
|
||||
'{' enumerator_list '}' { $$ = $3; }
|
||||
| '{' enumerator_list ',' '}' { $$ = $4; }
|
||||
;
|
||||
|
||||
enumerator_list:
|
||||
enumerator
|
||||
| enumerator_list ',' enumerator
|
||||
|
||||
enumerator:
|
||||
IDENT
|
||||
{
|
||||
const char *name = strdup((*$1)->string);
|
||||
add_symbol(name, SYM_ENUM_CONST, NULL, 0);
|
||||
}
|
||||
| IDENT '=' EXPRESSION_PHRASE
|
||||
{
|
||||
const char *name = strdup((*$1)->string);
|
||||
struct string_list *expr = copy_list_range(*$3, *$2);
|
||||
add_symbol(name, SYM_ENUM_CONST, expr, 0);
|
||||
}
|
||||
|
||||
asm_definition:
|
||||
ASM_PHRASE ';' { $$ = $2; }
|
||||
;
|
||||
|
||||
Reference in New Issue
Block a user