aboutsummaryrefslogtreecommitdiffstats
path: root/scripts/genksyms/genksyms.c
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/genksyms/genksyms.c
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/genksyms/genksyms.c')
-rw-r--r--scripts/genksyms/genksyms.c71
1 files changed, 66 insertions, 5 deletions
diff --git a/scripts/genksyms/genksyms.c b/scripts/genksyms/genksyms.c
index 4a350816a9e..f9e75531ea0 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. */