diff options
| author | Andreas Gruenbacher <agruen@suse.de> | 2008-12-01 17:21:01 -0500 |
|---|---|---|
| committer | Sam Ravnborg <sam@ravnborg.org> | 2008-12-03 16:33:11 -0500 |
| commit | 64e6c1e12372840e7caf8e25325a9e9c5fd370e6 (patch) | |
| tree | aa47aa4e170dd4bb39c99cc7356231e2c61d64d2 /scripts | |
| parent | a680eedc6c621c75695c68198533fc3c98f4053b (diff) | |
genksyms: track symbol checksum changes
Sometimes it is preferable to avoid changes of exported symbol checksums
(to avoid breaking externally provided modules). When a checksum change
occurs, it can be hard to figure out what caused this change: underlying
types may have changed, or additional type information may simply have
become available at the point where a symbol is exported.
Add a new --reference option to genksyms which allows it to report why
checksums change, based on the type information dumps it creates with the
--dump-types flag. Genksyms will read in such a dump from a previous run,
and report which symbols have changed (and why).
The behavior can be controlled for an entire build as follows: If
KBUILD_SYMTYPES is set, genksyms uses --dump-types to produce *.symtypes
dump files. If any *.symref files exist, those will be used as the
reference to check against. If KBUILD_PRESERVE is set, checksum changes
will fail the build.
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Cc: Randy Dunlap <randy.dunlap@oracle.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
Diffstat (limited to 'scripts')
| -rw-r--r-- | scripts/Makefile.build | 16 | ||||
| -rw-r--r-- | scripts/genksyms/genksyms.c | 236 | ||||
| -rw-r--r-- | scripts/genksyms/genksyms.h | 6 |
3 files changed, 239 insertions, 19 deletions
diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 468fbc9016c7..d21f0eac2e52 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build | |||
| @@ -153,12 +153,18 @@ $(obj)/%.i: $(src)/%.c FORCE | |||
| 153 | 153 | ||
| 154 | quiet_cmd_cc_symtypes_c = SYM $(quiet_modtag) $@ | 154 | quiet_cmd_cc_symtypes_c = SYM $(quiet_modtag) $@ |
| 155 | cmd_cc_symtypes_c = \ | 155 | cmd_cc_symtypes_c = \ |
| 156 | set -e; \ | ||
| 156 | $(CPP) -D__GENKSYMS__ $(c_flags) $< \ | 157 | $(CPP) -D__GENKSYMS__ $(c_flags) $< \ |
| 157 | | $(GENKSYMS) -T $@ >/dev/null; \ | 158 | | $(GENKSYMS) -T $@ \ |
| 159 | -r $(firstword $(wildcard \ | ||
| 160 | $(@:.symtypes=.symref) /dev/null)) \ | ||
| 161 | $(if $(KBUILD_PRESERVE),-p) \ | ||
| 162 | -a $(ARCH) \ | ||
| 163 | >/dev/null; \ | ||
| 158 | test -s $@ || rm -f $@ | 164 | test -s $@ || rm -f $@ |
| 159 | 165 | ||
| 160 | $(obj)/%.symtypes : $(src)/%.c FORCE | 166 | $(obj)/%.symtypes : $(src)/%.c FORCE |
| 161 | $(call if_changed_dep,cc_symtypes_c) | 167 | $(call cmd,cc_symtypes_c) |
| 162 | 168 | ||
| 163 | # C (.c) files | 169 | # C (.c) files |
| 164 | # The C file is compiled and updated dependency information is generated. | 170 | # The C file is compiled and updated dependency information is generated. |
| @@ -187,7 +193,11 @@ cmd_modversions = \ | |||
| 187 | if $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then \ | 193 | if $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then \ |
| 188 | $(CPP) -D__GENKSYMS__ $(c_flags) $< \ | 194 | $(CPP) -D__GENKSYMS__ $(c_flags) $< \ |
| 189 | | $(GENKSYMS) $(if $(KBUILD_SYMTYPES), \ | 195 | | $(GENKSYMS) $(if $(KBUILD_SYMTYPES), \ |
| 190 | -T $(@D)/$(@F:.o=.symtypes)) -a $(ARCH) \ | 196 | -T $(@:.o=.symtypes)) \ |
| 197 | -r $(firstword $(wildcard \ | ||
| 198 | $(@:.o=.symref) /dev/null)) \ | ||
| 199 | $(if $(KBUILD_PRESERVE),-p) \ | ||
| 200 | -a $(ARCH) \ | ||
| 191 | > $(@D)/.tmp_$(@F:.o=.ver); \ | 201 | > $(@D)/.tmp_$(@F:.o=.ver); \ |
| 192 | \ | 202 | \ |
| 193 | $(LD) $(LDFLAGS) -r -o $@ $(@D)/.tmp_$(@F) \ | 203 | $(LD) $(LDFLAGS) -r -o $@ $(@D)/.tmp_$(@F) \ |
diff --git a/scripts/genksyms/genksyms.c b/scripts/genksyms/genksyms.c index c249274e005a..ddac1746908e 100644 --- a/scripts/genksyms/genksyms.c +++ b/scripts/genksyms/genksyms.c | |||
| @@ -42,7 +42,8 @@ static FILE *debugfile; | |||
| 42 | int cur_line = 1; | 42 | int cur_line = 1; |
| 43 | char *cur_filename; | 43 | char *cur_filename; |
| 44 | 44 | ||
| 45 | static int flag_debug, flag_dump_defs, flag_dump_types, flag_warnings; | 45 | static int flag_debug, flag_dump_defs, flag_reference, flag_dump_types, |
| 46 | flag_preserve, flag_warnings; | ||
| 46 | static const char *arch = ""; | 47 | static const char *arch = ""; |
| 47 | static const char *mod_prefix = ""; | 48 | static const char *mod_prefix = ""; |
| 48 | 49 | ||
| @@ -58,6 +59,8 @@ static const char *const symbol_type_name[] = { | |||
| 58 | 59 | ||
| 59 | static int equal_list(struct string_list *a, struct string_list *b); | 60 | static int equal_list(struct string_list *a, struct string_list *b); |
| 60 | static void print_list(FILE * f, struct string_list *list); | 61 | static void print_list(FILE * f, struct string_list *list); |
| 62 | static void print_location(void); | ||
| 63 | static void print_type_name(enum symbol_type type, const char *name); | ||
| 61 | 64 | ||
| 62 | /*----------------------------------------------------------------------*/ | 65 | /*----------------------------------------------------------------------*/ |
| 63 | 66 | ||
| @@ -151,27 +154,68 @@ struct symbol *find_symbol(const char *name, enum symbol_type ns) | |||
| 151 | 154 | ||
| 152 | for (sym = symtab[h]; sym; sym = sym->hash_next) | 155 | for (sym = symtab[h]; sym; sym = sym->hash_next) |
| 153 | if (map_to_ns(sym->type) == map_to_ns(ns) && | 156 | if (map_to_ns(sym->type) == map_to_ns(ns) && |
| 154 | strcmp(name, sym->name) == 0) | 157 | strcmp(name, sym->name) == 0 && |
| 158 | sym->is_declared) | ||
| 155 | break; | 159 | break; |
| 156 | 160 | ||
| 157 | return sym; | 161 | return sym; |
| 158 | } | 162 | } |
| 159 | 163 | ||
| 160 | struct symbol *add_symbol(const char *name, enum symbol_type type, | 164 | static int is_unknown_symbol(struct symbol *sym) |
| 161 | struct string_list *defn, int is_extern) | 165 | { |
| 166 | struct string_list *defn; | ||
| 167 | |||
| 168 | return ((sym->type == SYM_STRUCT || | ||
| 169 | sym->type == SYM_UNION || | ||
| 170 | sym->type == SYM_ENUM) && | ||
| 171 | (defn = sym->defn) && defn->tag == SYM_NORMAL && | ||
| 172 | strcmp(defn->string, "}") == 0 && | ||
| 173 | (defn = defn->next) && defn->tag == SYM_NORMAL && | ||
| 174 | strcmp(defn->string, "UNKNOWN") == 0 && | ||
| 175 | (defn = defn->next) && defn->tag == SYM_NORMAL && | ||
| 176 | strcmp(defn->string, "{") == 0); | ||
| 177 | } | ||
| 178 | |||
| 179 | struct symbol *__add_symbol(const char *name, enum symbol_type type, | ||
| 180 | struct string_list *defn, int is_extern, | ||
| 181 | int is_reference) | ||
| 162 | { | 182 | { |
| 163 | unsigned long h = crc32(name) % HASH_BUCKETS; | 183 | unsigned long h = crc32(name) % HASH_BUCKETS; |
| 164 | struct symbol *sym; | 184 | struct symbol *sym; |
| 185 | enum symbol_status status = STATUS_UNCHANGED; | ||
| 165 | 186 | ||
| 166 | for (sym = symtab[h]; sym; sym = sym->hash_next) { | 187 | for (sym = symtab[h]; sym; sym = sym->hash_next) { |
| 167 | if (map_to_ns(sym->type) == map_to_ns(type) | 188 | if (map_to_ns(sym->type) == map_to_ns(type) && |
| 168 | && strcmp(name, sym->name) == 0) { | 189 | strcmp(name, sym->name) == 0) { |
| 169 | if (!equal_list(sym->defn, defn)) | 190 | if (is_reference) |
| 191 | /* fall through */ ; | ||
| 192 | else if (sym->type == type && | ||
| 193 | equal_list(sym->defn, defn)) { | ||
| 194 | sym->is_declared = 1; | ||
| 195 | return sym; | ||
| 196 | } else if (!sym->is_declared) { | ||
| 197 | status = is_unknown_symbol(sym) ? | ||
| 198 | STATUS_DEFINED : STATUS_MODIFIED; | ||
| 199 | } else { | ||
| 170 | error_with_pos("redefinition of %s", name); | 200 | error_with_pos("redefinition of %s", name); |
| 171 | return sym; | 201 | return sym; |
| 202 | } | ||
| 203 | break; | ||
| 172 | } | 204 | } |
| 173 | } | 205 | } |
| 174 | 206 | ||
| 207 | if (sym) { | ||
| 208 | struct symbol **psym; | ||
| 209 | |||
| 210 | for (psym = &symtab[h]; *psym; psym = &(*psym)->hash_next) { | ||
| 211 | if (*psym == sym) { | ||
| 212 | *psym = sym->hash_next; | ||
| 213 | break; | ||
| 214 | } | ||
| 215 | } | ||
| 216 | --nsyms; | ||
| 217 | } | ||
| 218 | |||
| 175 | sym = xmalloc(sizeof(*sym)); | 219 | sym = xmalloc(sizeof(*sym)); |
| 176 | sym->name = name; | 220 | sym->name = name; |
| 177 | sym->type = type; | 221 | sym->type = type; |
| @@ -183,6 +227,9 @@ struct symbol *add_symbol(const char *name, enum symbol_type type, | |||
| 183 | sym->hash_next = symtab[h]; | 227 | sym->hash_next = symtab[h]; |
| 184 | symtab[h] = sym; | 228 | symtab[h] = sym; |
| 185 | 229 | ||
| 230 | sym->is_declared = !is_reference; | ||
| 231 | sym->status = status; | ||
| 232 | |||
| 186 | if (flag_debug) { | 233 | if (flag_debug) { |
| 187 | fprintf(debugfile, "Defn for %s %s == <", | 234 | fprintf(debugfile, "Defn for %s %s == <", |
| 188 | symbol_type_name[type], name); | 235 | symbol_type_name[type], name); |
| @@ -196,6 +243,18 @@ struct symbol *add_symbol(const char *name, enum symbol_type type, | |||
| 196 | return sym; | 243 | return sym; |
| 197 | } | 244 | } |
| 198 | 245 | ||
| 246 | struct symbol *add_symbol(const char *name, enum symbol_type type, | ||
| 247 | struct string_list *defn, int is_extern) | ||
| 248 | { | ||
| 249 | return __add_symbol(name, type, defn, is_extern, 0); | ||
| 250 | } | ||
| 251 | |||
| 252 | struct symbol *add_reference_symbol(const char *name, enum symbol_type type, | ||
| 253 | struct string_list *defn, int is_extern) | ||
| 254 | { | ||
| 255 | return __add_symbol(name, type, defn, is_extern, 1); | ||
| 256 | } | ||
| 257 | |||
| 199 | /*----------------------------------------------------------------------*/ | ||
