diff options
| author | Ingo Molnar <mingo@elte.hu> | 2008-12-31 10:31:57 +0300 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2008-12-31 10:31:57 +0300 |
| commit | a9de18eb761f7c1c860964b2e5addc1a35c7e861 (patch) | |
| tree | 886e75fdfd09690cd262ca69cb7f5d1d42b48602 /scripts | |
| parent | b2aaf8f74cdc84a9182f6cabf198b7763bcb9d40 (diff) | |
| parent | 6a94cb73064c952255336cc57731904174b2c58f (diff) | |
| download | linux-a9de18eb761f7c1c860964b2e5addc1a35c7e861.tar.xz | |
Merge branch 'linus' into stackprotector
Conflicts:
arch/x86/include/asm/pda.h
kernel/fork.c
Diffstat (limited to 'scripts')
40 files changed, 2096 insertions, 357 deletions
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index 982dcae7bbe2..c29be8f90248 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include @@ -25,6 +25,13 @@ basetarget = $(basename $(notdir $@)) escsq = $(subst $(squote),'\$(squote)',$1) ### +# Easy method for doing a status message + kecho := : + quiet_kecho := echo +silent_kecho := : +kecho := $($(quiet)kecho) + +### # filechk is used to check if the content of a generated file is updated. # Sample usage: # define filechk_sample @@ -39,22 +46,15 @@ escsq = $(subst $(squote),'\$(squote)',$1) # - If they are equal no change, and no timestamp update # - stdin is piped in from the first prerequisite ($<) so one has # to specify a valid file as first prerequisite (often the kbuild file) - chk_filechk = : - quiet_chk_filechk = echo ' CHK $@' -silent_chk_filechk = : - upd_filechk = : - quiet_upd_filechk = echo ' UPD $@' -silent_upd_filechk = : - define filechk $(Q)set -e; \ - $($(quiet)chk_filechk); \ + $(kecho) ' CHK $@'; \ mkdir -p $(dir $@); \ $(filechk_$(1)) < $< > $@.tmp; \ if [ -r $@ ] && cmp -s $@ $@.tmp; then \ rm -f $@.tmp; \ else \ - $($(quiet)upd_filechk); \ + $(kecho) ' UPD $@'; \ mv -f $@.tmp $@; \ fi endef @@ -144,7 +144,9 @@ ld-option = $(call try-run,\ build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj # Prefix -I with $(srctree) if it is not an absolute path. -addtree = $(if $(filter-out -I/%,$(1)),$(patsubst -I%,-I$(srctree)/%,$(1))) $(1) +# skip if -I has no parameter +addtree = $(if $(patsubst -I%,%,$(1)), \ +$(if $(filter-out -I/%,$(1)),$(patsubst -I%,-I$(srctree)/%,$(1))) $(1)) # Find all -I options and call addtree flags = $(foreach o,$($(1)),$(if $(filter -I%,$(o)),$(call addtree,$(o)),$(o))) diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 277cfe0b7100..5d900307de3e 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -151,14 +151,20 @@ cmd_cc_i_c = $(CPP) $(c_flags) -o $@ $< $(obj)/%.i: $(src)/%.c FORCE $(call if_changed_dep,cc_i_c) +cmd_genksyms = \ + $(CPP) -D__GENKSYMS__ $(c_flags) $< | \ + $(GENKSYMS) -T $@ -A -a $(ARCH) \ + $(if $(KBUILD_PRESERVE),-p) \ + $(if $(1),-r $(firstword $(wildcard $(@:.symtypes=.symref) /dev/null))) + quiet_cmd_cc_symtypes_c = SYM $(quiet_modtag) $@ -cmd_cc_symtypes_c = \ - $(CPP) -D__GENKSYMS__ $(c_flags) $< \ - | $(GENKSYMS) -T $@ >/dev/null; \ - test -s $@ || rm -f $@ +cmd_cc_symtypes_c = \ + set -e; \ + $(call cmd_genksyms, true) >/dev/null; \ + test -s $@ || rm -f $@ $(obj)/%.symtypes : $(src)/%.c FORCE - $(call if_changed_dep,cc_symtypes_c) + $(call cmd,cc_symtypes_c) # C (.c) files # The C file is compiled and updated dependency information is generated. @@ -171,40 +177,60 @@ cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< else # When module versioning is enabled the following steps are executed: -# o compile a .tmp_<file>.o from <file>.c -# o if .tmp_<file>.o doesn't contain a __ksymtab version, i.e. does -# not export symbols, we just rename .tmp_<file>.o to <file>.o and +# o compile a .tmp_<file>.s from <file>.c +# o if .tmp_<file>.s doesn't contain a __ksymtab version, i.e. does +# not export symbols, we just assemble .tmp_<file>.s to <file>.o and # are done. # o otherwise, we calculate symbol versions using the good old # genksyms on the preprocessed source and postprocess them in a way -# that they are usable as a linker script -# o generate <file>.o from .tmp_<file>.o using the linker to -# replace the unresolved symbols __crc_exported_symbol with -# the actual value of the checksum generated by genksyms +# that they are usable as assembly source +# o assemble <file>.o from .tmp_<file>.s forcing inclusion of directives +# defining the actual values of __crc_*, followed by objcopy-ing them +# to force these symbols to be local to permit stripping them later. +s_file = $(@D)/.tmp_$(@F:.o=.s) +v_file = $(@D)/.tmp_$(@F:.o=.v) +tmp_o_file = $(@D)/.tmp_$(@F) +no_g_c_flags = $(filter-out -g%,$(c_flags)) + +cmd_cc_o_c = $(CC) $(c_flags) -S -o $(s_file) $< -cmd_cc_o_c = $(CC) $(c_flags) -c -o $(@D)/.tmp_$(@F) $< cmd_modversions = \ - if $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then \ - $(CPP) -D__GENKSYMS__ $(c_flags) $< \ - | $(GENKSYMS) $(if $(KBUILD_SYMTYPES), \ - -T $(@D)/$(@F:.o=.symtypes)) -a $(ARCH) \ - > $(@D)/.tmp_$(@F:.o=.ver); \ - \ - $(LD) $(LDFLAGS) -r -o $@ $(@D)/.tmp_$(@F) \ - -T $(@D)/.tmp_$(@F:.o=.ver); \ - rm -f $(@D)/.tmp_$(@F) $(@D)/.tmp_$(@F:.o=.ver); \ + if grep -q __ksymtab $(s_file); then \ + if $(call cmd_genksyms, $(KBUILD_SYMTYPES)) > $(v_file) \ + && $(CC) $(no_g_c_flags) -c -Wa,$(v_file) \ + -o $(tmp_o_file) $(s_file) \ + && $(OBJCOPY) -L '__crc_*' -L '___crc_*' -w \ + $(tmp_o_file) $@; \ + then \ + : ; \ + else \ + rm -f $@; exit 1; \ + fi; \ else \ - mv -f $(@D)/.tmp_$(@F) $@; \ + rm -f $(v_file); \ + $(CC) $(no_g_c_flags) -c -o $@ $(s_file); \ fi; endif +ifdef CONFIG_FTRACE_MCOUNT_RECORD +cmd_record_mcount = perl $(srctree)/scripts/recordmcount.pl "$(ARCH)" \ + "$(if $(CONFIG_64BIT),64,32)" \ + "$(OBJDUMP)" "$(OBJCOPY)" "$(CC)" "$(LD)" "$(NM)" "$(RM)" "$(MV)" "$(@)"; +endif + define rule_cc_o_c $(call echo-cmd,checksrc) $(cmd_checksrc) \ $(call echo-cmd,cc_o_c) $(cmd_cc_o_c); \ $(cmd_modversions) \ + $(cmd_record_mcount) \ scripts/basic/fixdep $(depfile) $@ '$(call make-cmd,cc_o_c)' > \ $(dot-target).tmp; \ - rm -f $(depfile); \ + if [ -r $(@D)/.tmp_$(@F:.o=.v) ]; then \ + echo >> $(dot-target).tmp; \ + echo '$@: $(GENKSYMS)' >> $(dot-target).tmp; \ + echo '$(GENKSYMS):: ;' >> $(dot-target).tmp; \ + fi; \ + rm -f $(depfile) $(@D)/.tmp_$(@F:.o=.?); \ mv -f $(dot-target).tmp $(dot-target).cmd endef diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index ea48b82a3707..e06365775bdf 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -96,9 +96,19 @@ basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(basetarget)))" modname_flags = $(if $(filter 1,$(words $(modname))),\ -D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))") -orig_c_flags = $(KBUILD_CFLAGS) $(ccflags-y) $(CFLAGS_$(basetarget).o) +#hash values +ifdef CONFIG_DYNAMIC_PRINTK_DEBUG +debug_flags = -D"DEBUG_HASH=$(shell ./scripts/basic/hash djb2 $(@D)$(modname))"\ + -D"DEBUG_HASH2=$(shell ./scripts/basic/hash r5 $(@D)$(modname))" +else +debug_flags = +endif + +orig_c_flags = $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) \ + $(ccflags-y) $(CFLAGS_$(basetarget).o) _c_flags = $(filter-out $(CFLAGS_REMOVE_$(basetarget).o), $(orig_c_flags)) -_a_flags = $(KBUILD_AFLAGS) $(asflags-y) $(AFLAGS_$(basetarget).o) +_a_flags = $(KBUILD_CPPFLAGS) $(KBUILD_AFLAGS) \ + $(asflags-y) $(AFLAGS_$(basetarget).o) _cpp_flags = $(KBUILD_CPPFLAGS) $(cppflags-y) $(CPPFLAGS_$(@F)) # If building the kernel in a separate objtree expand all occurrences @@ -119,14 +129,16 @@ __a_flags = $(call flags,_a_flags) __cpp_flags = $(call flags,_cpp_flags) endif -c_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(KBUILD_CPPFLAGS) \ - $(__c_flags) $(modkern_cflags) \ - -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags) +c_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) \ + $(__c_flags) $(modkern_cflags) \ + -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags) \ + $(debug_flags) -a_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(KBUILD_CPPFLAGS) \ +a_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) \ $(__a_flags) $(modkern_aflags) -cpp_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(__cpp_flags) +cpp_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) \ + $(__cpp_flags) ld_flags = $(LDFLAGS) $(ldflags-y) diff --git a/scripts/Makefile.modinst b/scripts/Makefile.modinst index efa5d940e632..a5122dce1264 100644 --- a/scripts/Makefile.modinst +++ b/scripts/Makefile.modinst @@ -17,7 +17,8 @@ __modinst: $(modules) @: quiet_cmd_modules_install = INSTALL $@ - cmd_modules_install = mkdir -p $(2); cp $@ $(2) ; $(mod_strip_cmd) $(2)/$(notdir $@) + cmd_modules_install = mkdir -p $(2); \ + $(mod_strip_cmd) $@ $(2)/$(notdir $@) || cp $@ $(2) # Modules built outside the kernel source tree go into extra by default INSTALL_MOD_DIR ?= extra diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost index 9ee9783aea57..f4053dc7b5d6 100644 --- a/scripts/Makefile.modpost +++ b/scripts/Makefile.modpost @@ -82,7 +82,7 @@ modpost = scripts/mod/modpost \ $(if $(CONFIG_MODULE_SRCVERSION_ALL),-a,) \ $(if $(KBUILD_EXTMOD),-i,-o) $(kernelsymfile) \ $(if $(KBUILD_EXTMOD),-I $(modulesymfile)) \ - $(if $(KBUILD_EXTRA_SYMBOLS), $(patsubst %, -e %,$(EXTRA_SYMBOLS))) \ + $(if $(KBUILD_EXTRA_SYMBOLS), $(patsubst %, -e %,$(KBUILD_EXTRA_SYMBOLS))) \ $(if $(KBUILD_EXTMOD),-o $(modulesymfile)) \ $(if $(CONFIG_DEBUG_SECTION_MISMATCH),,-S) \ $(if $(CONFIG_MARKERS),-K $(kernelmarkersfile)) \ diff --git a/scripts/basic/.gitignore b/scripts/basic/.gitignore index 7304e19782c7..bf8b199ec598 100644 --- a/scripts/basic/.gitignore +++ b/scripts/basic/.gitignore @@ -1,3 +1,3 @@ +hash fixdep -split-include docproc diff --git a/scripts/basic/Makefile b/scripts/basic/Makefile index 4c324a1f1e0e..09559951df12 100644 --- a/scripts/basic/Makefile +++ b/scripts/basic/Makefile @@ -9,7 +9,7 @@ # fixdep: Used to generate dependency information during build process # docproc: Used in Documentation/DocBook -hostprogs-y := fixdep docproc +hostprogs-y := fixdep docproc hash always := $(hostprogs-y) # fixdep is needed to compile other host programs diff --git a/scripts/basic/hash.c b/scripts/basic/hash.c new file mode 100644 index 000000000000..3299ad7fc8c0 --- /dev/null +++ b/scripts/basic/hash.c @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2008 Red Hat, Inc., Jason Baron <jbaron@redhat.com> + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define DYNAMIC_DEBUG_HASH_BITS 6 + +static const char *program; + +static void usage(void) +{ + printf("Usage: %s <djb2|r5> <modname>\n", program); + exit(1); +} + +/* djb2 hashing algorithm by Dan Bernstein. From: + * http://www.cse.yorku.ca/~oz/hash.html + */ + +unsigned int djb2_hash(char *str) +{ + unsigned long hash = 5381; + int c; + + c = *str; + while (c) { + hash = ((hash << 5) + hash) + c; + c = *++str; + } + return (unsigned int)(hash & ((1 << DYNAMIC_DEBUG_HASH_BITS) - 1)); +} + +unsigned int r5_hash(char *str) +{ + unsigned long hash = 0; + int c; + + c = *str; + while (c) { + hash = (hash + (c << 4) + (c >> 4)) * 11; + c = *++str; + } + return (unsigned int)(hash & ((1 << DYNAMIC_DEBUG_HASH_BITS) - 1)); +} + +int main(int argc, char *argv[]) +{ + program = argv[0]; + + if (argc != 3) + usage(); + if (!strcmp(argv[1], "djb2")) + printf("%d\n", djb2_hash(argv[2])); + else if (!strcmp(argv[1], "r5")) + printf("%d\n", r5_hash(argv[2])); + else + usage(); + exit(0); +} + diff --git a/scripts/bootgraph.pl b/scripts/bootgraph.pl index 2243353fe55d..f0af9aa9b243 100644 --- a/scripts/bootgraph.pl +++ b/scripts/bootgraph.pl @@ -37,13 +37,16 @@ # dmesg | perl scripts/bootgraph.pl > output.svg # -my @rows; -my %start, %end, %row; +use strict; + +my %start; +my %end; my $done = 0; -my $rowcount = 0; my $maxtime = 0; my $firsttime = 100; my $count = 0; +my %pids; + while (<>) { my $line = $_; if ($line =~ /([0-9\.]+)\] calling ([a-zA-Z0-9\_]+)\+/) { @@ -54,14 +57,8 @@ while (<>) { $firsttime = $1; } } - $row{$func} = 1; if ($line =~ /\@ ([0-9]+)/) { - my $pid = $1; - if (!defined($rows[$pid])) { - $rowcount = $rowcount + 1; - $rows[$pid] = $rowcount; - } - $row{$func} = $rows[$pid]; + $pids{$func} = $1; } $count = $count + 1; } @@ -81,11 +78,13 @@ while (<>) { } if ($count == 0) { - print "No data found in the dmesg. Make sure that 'printk.time=1' and\n"; - print "'initcall_debug' are passed on the kernel command line.\n\n"; - print "Usage: \n"; - print " dmesg | perl scripts/bootgraph.pl > output.svg\n\n"; - exit; + print STDERR <<END; +No data found in the dmesg. Make sure that 'printk.time=1' and +'initcall_debug' are passed on the kernel command line. +Usage: + dmesg | perl scripts/bootgraph.pl > output.svg +END + exit 1; } print "<?xml version=\"1.0\" standalone=\"no\"?> \n"; @@ -109,17 +108,27 @@ $styles[11] = "fill:rgb(128,255,255);fill-opacity:0.5;stroke-width:1;stroke:rgb( my $mult = 950.0 / ($maxtime - $firsttime); my $threshold = ($maxtime - $firsttime) / 60.0; my $stylecounter = 0; -while (($key,$value) = each %start) { +my %rows; +my $rowscount = 1; +my @initcalls = sort { $start{$a} <=> $start{$b} } keys(%start); + +foreach my $key (@initcalls) { my $duration = $end{$key} - $start{$key}; if ($duration >= $threshold) { - my $s, $s2, $e, $y; - $s = ($value - $firsttime) * $mult; + my ($s, $s2, $e, $w, $y, $y2, $style); + my $pid = $pids{$key}; + + if (!defined($rows{$pid})) { + $rows{$pid} = $rowscount; + $rowscount = $rowscount + 1; + } + $s = ($start{$key} - $firsttime) * $mult; $s2 = $s + 6; $e = ($end{$key} - $firsttime) * $mult; $w = $e - $s; - $y = $row{$key} * 150; + $y = $rows{$pid} * 150; $y2 = $y + 4; $style = $styles[$stylecounter]; @@ -138,9 +147,9 @@ while (($key,$value) = each %start) { my $time = $firsttime; my $step = ($maxtime - $firsttime) / 15; while ($time < $maxtime) { - my $s2 = ($time - $firsttime) * $mult; + my $s3 = ($time - $firsttime) * $mult; my $tm = int($time * 100) / 100.0; - print "<text transform=\"translate($s2,89) rotate(90)\">$tm</text>\n"; + print "<text transform=\"translate($s3,89) rotate(90)\">$tm</text>\n"; $time = $time + $step; } diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index bc6779398229..f88bb3e21cda 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -1,5 +1,5 @@ #!/usr/bin/perl -w -# (c) 2001, Dave Jones. <davej@codemonkey.org.uk> (the file handling bit) +# (c) 2001, Dave Jones. <davej@redhat.com> (the file handling bit) # (c) 2005, Joel Schopp <jschopp@austin.ibm.com> (the ugly bit) # (c) 2007, Andy Whitcroft <apw@uk.ibm.com> (new conditions, test suite, etc) # Licensed under the terms of the GNU GPL License version 2 @@ -9,7 +9,7 @@ use strict; my $P = $0; $P =~ s@.*/@@g; -my $V = '0.21'; +my $V = '0.24'; use Getopt::Long qw(:config no_auto_abbrev); @@ -66,6 +66,7 @@ if ($#ARGV < 0) { my $dbg_values = 0; my $dbg_possible = 0; my $dbg_type = 0; +my $dbg_attr = 0; for my $key (keys %debug) { eval "\${dbg_$key} = '$debug{$key}';" } @@ -112,7 +113,10 @@ our $Attribute = qr{ const| __read_mostly| __kprobes| - __(?:mem|cpu|dev|)(?:initdata|init) + __(?:mem|cpu|dev|)(?:initdata|init)| + ____cacheline_aligned| + ____cacheline_aligned_in_smp| + ____cacheline_internodealigned_in_smp }x; our $Modifier; our $Inline = qr{inline|__always_inline|noinline}; @@ -142,6 +146,11 @@ our $UTF8 = qr { | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16 }x; +our $typeTypedefs = qr{(?x: + (?:__)?(?:u|s|be|le)(?:\d|\d\d)| + atomic_t +)}; + our @typeList = ( qr{void}, qr{(?:unsigned\s+)?char}, @@ -155,7 +164,6 @@ our @typeList = ( qr{float}, qr{double}, qr{bool}, - qr{(?:__)?(?:u|s|be|le)(?:8|16|32|64)}, qr{struct\s+$Ident}, qr{union\s+$Ident}, qr{enum\s+$Ident}, @@ -175,6 +183,7 @@ sub build_types { (?:$Modifier\s+|const\s+)* (?: (?:typeof|__typeof__)\s*\(\s*\**\s*$Ident\s*\)| + (?:$typeTypedefs\b)| (?:${all}\b) ) (?:\s+$Modifier|\s+const)* @@ -331,7 +340,7 @@ sub sanitise_line { $off++; next; } - if (substr($line, $off, 2) eq '*/') { + if ($sanitise_quote eq '*/' && substr($line, $off, 2) eq '*/') { $sanitise_quote = ''; substr($res, $off, 2, "$;$;"); $off++; @@ -404,6 +413,7 @@ sub ctx_statement_block { # context. if ($off >= $len) { for (; $remain > 0; $line++) { + last if (!defined $lines[$line]); next if ($lines[$line] =~ /^-/); $remain--; $loff = $len; @@ -669,6 +679,22 @@ sub ctx_has_comment { return ($cmt ne ''); } +sub raw_line { + my ($linenr, $cnt) = @_; + + my $offset = $linenr - 1; + $cnt++; + + my $line; + while ($cnt) { + $line = $rawlines[$offset++]; + next if (defined($line) && $line =~ /^-/); + $cnt--; + } + + return $line; +} + sub cat_vet { my ($vet) = @_; my ($res, $coded); @@ -782,9 +808,9 @@ sub annotate_values { } $type = 'N'; - } elsif ($cur =~ /^(if|while|typeof|__typeof__|for)\b/o) { + } elsif ($cur =~ /^(if|while|for)\b/o) { print "COND($1)\n" if ($dbg_values > 1); - $av_pending = 'N'; + $av_pending = 'E'; $type = 'N'; } elsif ($cur =~/^(case)/o) { @@ -792,7 +818,7 @@ sub annotate_values { $av_pend_colon = 'C'; $type = 'N'; - } elsif ($cur =~/^(return|else|goto)/o) { + } elsif ($cur =~/^(return|else|goto|typeof|__typeof__)\b/o) { print "KEYWORD($1)\n" if ($dbg_values > 1); $type = 'N'; @@ -858,7 +884,7 @@ sub annotate_values { print "CLOSE($1)\n" if ($dbg_values > 1); $type = 'N'; - } elsif ($cur =~ /^(-(?![->])|\+(?!\+)|\*|\&(?!\&))/o) { + } elsif ($cur =~ /^(-(?![->])|\+(?!\+)|\*|\&\&|\&)/o) { my $variant; print "OPV($1)\n" if ($dbg_values > 1); @@ -892,12 +918,22 @@ sub annotate_values { sub possible { my ($possible, $line) = @_; - print "CHECK<$possible> ($line)\n" if ($dbg_possible > 1); - if ($possible !~ /^(?:$Modifier|$Storage|$Type|DEFINE_\S+)$/ && - $possible ne 'goto' && $possible ne 'return' && - $possible ne 'case' && $possible ne 'else' && - $possible ne 'asm' && $possible ne '__asm__' && - $possible !~ /^(typedef|struct|enum)\b/) { + print "CHECK<$possible> ($line)\n" if ($dbg_possible > 2); + if ($possible !~ /(?: + ^(?: + $Modifier| + $Storage| + $Type| + DEFINE_\S+| + goto| + return| + case| + else| + asm|__asm__| + do + )$| + ^(?:typedef|struct|enum)\b + )/x) { # Check for modifiers. $possible =~ s/\s*$Storage\s*//g; $possible =~ s/\s*$Sparse\s*//g; @@ -915,6 +951,8 @@ sub possible { push(@typeList, $possible); } build_types(); + } else { + warn "NOTPOSS: $possible ($line)\n" if ($dbg_possible > 1); } } @@ -954,6 +992,33 @@ sub CHK { } } +sub check_absolute_file { + my ($absolute, $herecurr) = @_; + my $file = $absolute; + + ##print "absolute<$absolute>\n"; + + # See if any suffix of this path is a path within the tree. + while ($file =~ s@^[^/]*/@@) { + if (-f "$root/$file") { + ##print "file<$file>\n"; + last; + } + } + if (! -f _) { + return 0; + } + + # It is, so see if the prefix is acceptable. + my $prefix = $absolute; + substr($prefix, -length($file)) = ''; + + ##print "prefix<$prefix>\n"; + if ($prefix ne ".../") { + WARN("use relative pathname instead of absolute in changelog text\n" . $herecurr); + } +} + sub process { my $filename = shift; @@ -991,6 +1056,7 @@ sub process { # suppression flags my %suppress_ifbraces; + my %suppress_whiletrailers; # Pre-scan the patch sanitizing the lines. # Pre-scan the patch looking for any __setup documentation. @@ -1025,9 +1091,14 @@ sub process { # edge is a close comment then we must be in a comment # at context start. my $edge; - for (my $ln = $linenr + 1; $ln < ($linenr + $realcnt); $ln++) { - next if ($line =~ /^-/); - ($edge) = ($rawlines[$ln - 1] =~ m@(/\*|\*/)@); + my $cnt = $realcnt; + for (my $ln = $linenr + 1; $cnt > 0; $ln++) { + next if (defined $rawlines[$ln - 1] && + $rawlines[$ln - 1] =~ /^-/); + $cnt--; + #print "RAW<$rawlines[$ln - 1]>\n"; + ($edge) = (defined $rawlines[$ln - 1] && + $rawlines[$ln - 1] =~ m@(/\*|\*/)@); last if (defined $edge); } if (defined $edge && $edge eq '*/') { @@ -1075,6 +1146,7 @@ sub process { $linenr++; my $rawline = $rawlines[$linenr - 1]; + my $hunk_line = ($realcnt != 0); #extract the line range in the file after the patch is applied if ($line=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) { @@ -1090,6 +1162,7 @@ sub process { $prev_values = 'E'; %suppress_ifbraces = (); + %suppress_whiletrailers = (); next; # track the line number as we move through the hunk, note that @@ -1125,7 +1198,7 @@ sub process { $realfile = $1; $realfile =~ s@^[^/]*/@@; - if ($realfile =~ m@include/asm/@) { + if ($realfile =~ m@^include/asm/@) { ERROR("do not modify files in include/asm, change architecture specific files in include/asm-<architecture>\n" . "$here$rawline\n"); } next; @@ -1159,6 +1232,20 @@ sub process { $herecurr) if (!$emitted_corrupt++); } +# Check for absolute kernel paths. + if ($tree) { + while ($line =~ m{(?:^|\s)(/\S*)}g) { + my $file = $1; + + if ($file =~ m{^(.*?)(?::\d+)+:?$} && + check_absolute_file($1, $herecurr)) { + # + } else { + check_absolute_file($file, $herecurr); + } + } + } + # UTF-8 regex found at http://www.w3.org/International/questions/qa-forms-utf-8.en.php if (($realfile =~ /^$/ || $line =~ /^\+/) && $rawline !~ m/^$UTF8*$/) { @@ -1171,11 +1258,8 @@ sub process { ERROR("Invalid UTF-8, patch and commit message should be encoded in UTF-8\n" . $hereptr); } -#ignore lines being removed - if ($line=~/^-/) {next;} - -# check we are in a valid source file if not then ignore this hunk - next if ($realfile !~ /\.(h|c|s|S|pl|sh)$/); +# ignore non-hunk lines and lines being removed + next if (!$hunk_line || $line =~ /^-/); #trailing whitespace if ($line =~ /^\+.*\015/) { @@ -1186,6 +1270,10 @@ sub process { my $herevet = "$here\n" . cat_vet($rawline) . "\n"; ERROR("trailing whitespace\n" . $herevet); } + +# check we are in a valid source file if not then ignore this hunk + next if ($realfile !~ /\.(h|c|s|S|pl|sh)$/); + #80 column limit if ($line =~ /^\+/ && $prevrawline !~ /\/\*\*/ && $rawline !~ /^.\s*\*\s*\@$Ident\s/ && @@ -1200,8 +1288,8 @@ sub process { WARN("adding a line without newline at end of file\n" . $herecurr); } -# check we are in a valid source file *.[hc] if not then ignore this hunk - next if ($realfile !~ /\.[hc]$/); +# check we are in a valid source file C or perl if not then ignore this hunk + next if ($realfile !~ /\.(h|c|pl)$/); # at the beginning of a line any tabs must come first and anything # more than 8 must use tabs. @@ -1211,15 +1299,18 @@ sub process { ERROR("code indent should use tabs where possible\n" . $herevet); } +# check we are in a valid C source file if not then ignore this hunk + next if ($realfile !~ /\.(h|c)$/); + # check for RCS/CVS revision markers if ($rawline =~ /^\+.*\$(Revision|Log|Id)(?:\$|)/) { WARN("CVS style keyword markers, these will _not_ be updated\n". $herecurr); } # Check for potential 'bare' types - my ($stat, $cond, $line_nr_next, $remain_next); + my ($stat, $cond, $line_nr_next, $remain_next, $off_next); if ($realcnt && $line =~ /.\s*\S/) { - ($stat, $cond, $line_nr_next, $remain_next) = + ($stat, $cond, $line_nr_next, $remain_next, $off_next) = ctx_statement_block($linenr, $realcnt, 0); $stat =~ s/\n./\n /g; $cond =~ s/\n./\n /g; @@ -1240,7 +1331,7 @@ sub process { possible($type, "A:" . $s); # definitions in global scope can only start with types - } elsif ($s =~ /^.(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?($Ident)\b/s) { + } elsif ($s =~ /^.(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?($Ident)\b\s*(?!:)/s) { possible($1, "B:" . $s); } @@ -1294,10 +1385,6 @@ sub process { ERROR("switch and case should be at the same indent\n$hereline$err"); } } - if ($line =~ /^.\s*(?:case\s*.*|default\s*):/g && - $line !~ /\G(?:\s*{)?(?:\s*$;*)(?:\s*\\)?\s*$/g) { - ERROR("trailing statements should be on next line\n" . $herecurr); - } # if/while/etc brace do not go on next line, unless defining a do while loop, # or if that brace on the next line is for something else @@ -1338,6 +1425,91 @@ sub process { } } +# Check relative indent for conditionals and blocks. + if ($line =~ /\b(?:(?:if|while|for)\s*\(|do\b)/ && $line !~ /^.\s*#/ && $line !~ /\}\s*while\s*/) { + my ($s, $c) = ($stat, $cond); + + substr($s, 0, length($c), ''); + + # Make sure we remove the line prefixes as we have + # none on the first line, and are going to readd them + # where necessary. + $s =~ s/\n./\n/gs; + + # Find out how long the conditional actually is. + my @newlines = ($c =~ /\n/gs); + my $cond_lines = 1 + $#newlines; + + # We want to check the first line inside the block + # starting at the end of the conditional, so remove: + # 1) any blank line termination + # 2) any opening brace { on end of the line + # 3) any do (...) { + my $continuation = 0; + my $check = 0; + $s =~ s/^.*\bdo\b//; + $s =~ s/^\s*{//; + if ($s =~ s/^\s*\\//) { + $continuation = 1; + } + if ($s =~ s/^\s*?\n//) { + $check = 1; + $cond_lines++; + } + + # Also ignore a loop construct at the end of a + # preprocessor statement. + if (($prevline =~ /^.\s*#\s*define\s/ || + $prevline =~ /\\\s*$/) && $continuation == 0) { + $check = 0; + } + + my $cond_ptr = -1; + $continuation = 0; + while ($cond_ptr != $cond_lines) { + $cond_ptr = $cond_lines; + + # If we see an #else/#elif then the code + # is not linear. + if ($s =~ /^\s*\#\s*(?:else|elif)/) { + $check = 0; + } + + # Ignore: + # 1) blank lines, they should be at 0, + # 2) preprocessor lines, and + # 3) labels. + if ($continuation || + $s =~ /^\s*?\n/ || + $s =~ /^\s*#\s*?/ || + $s =~ /^\s*$Ident\s*:/) { + $continuation = ($s =~ /^.*?\\\n/) ? 1 : 0; + $s =~ s/^.*?\n//; + $cond_lines++; + } + } + + my (undef, $sindent) = line_stats("+" . $s); + my $stat_real = raw_line($linenr, $cond_lines); + + # Check if either of these lines are modified, else + # this is not this patch's fault. + if (!defined($stat_real) || + $stat !~ /^\+/ && $stat_real !~ /^\+/) { + $check = 0; + } + if (defined($stat_real) && $cond_lines > 1) { + $stat_real = "[...]\n$stat_real"; + } + + #print "line<$line> prevline<$prevline> indent<$indent> sindent<$sindent> check<$check> continuation<$continuation> s<$s> cond_lines<$cond_lines> stat_real<$stat_real> stat<$stat>\n"; + + if ($check && (($sindent % 8) != 0 || + ($sindent <= $indent && $s ne ''))) { + WARN("suspect code indent for conditional statements ($indent, $sindent)\n" . $herecurr . "$stat_real\n"); + } + } + # Track the 'values' across context and added lines. my $opline = $line; $opline =~ s/^./ /; my ($curr_values, $curr_vars) = @@ -1363,6 +1535,15 @@ sub process { } next; } +# TEST: allow direct testing of the attribute matcher. + if ($dbg_attr) { + if ($line =~ /^.\s*$Attribute\s*$/) { + ERROR("TEST: is attr\n" . $herecurr); + } elsif ($dbg_attr > 1 && $line =~ /^.+($Attribute)/) { + ERROR("TEST: is not attr ($1 is)\n". $herecurr); + } + next; + } # check for initialisation to aggregates open brace on the next line if ($prevline =~ /$Declare\s*$Ident\s*=\s*$/ && @@ -1395,13 +1576,14 @@ sub process { if (($line =~ /EXPORT_SYMBOL.*\((.*)\)/) || ($line =~ /EXPORT_UNUSED_SYMBOL.*\((.*)\)/)) { my $name = $1; - if (($prevline !~ /^}/) && - ($prevline !~ /^\+}/) && - ($prevline !~ /^ }/) && - ($prevline !~ /^.DECLARE_$Ident\(\Q$name\E\)/) && - ($prevline !~ /^.LIST_HEAD\(\Q$name\E\)/) && - ($prevline !~ /^.$Type\s*\(\s*\*\s*\Q$name\E\s*\)\s*\(/) && - ($prevline !~ /\b\Q$name\E(?:\s+$Attribute)?\s*(?:;|=|\[)/)) { + if ($prevline !~ /(?: + ^.}| + ^.DEFINE_$Ident\(\Q$name\E\)| + ^.DECLARE_$Ident\(\Q$name\E\)| + ^.LIST_HEAD\(\Q$name\E\)| + ^.$Type\s*\(\s*\*\s*\Q$name\E\s*\)\s*\(| + \b\Q$name\E(?:\s+$Attribute)?\s*(?:;|=|\[) + )/x) { WARN("EXPORT_SYMBOL(foo); should immediately follow its function/variable\n" . $herecurr); } } @@ -1422,6 +1604,7 @@ sub process { if ($line =~ /\btypedef\s/ && $line !~ /\btypedef\s+$Type\s+\(\s*\*?$Ident\s*\)\s*\(/ && $line !~ /\btypedef\s+$Type\s+$Ident\s*\(/ && + $line !~ /\b$typeTypedefs\b/ && $line !~ /\b__bitwise(?:__|)\b/) { WARN("do not add new typedefs\n" . $herecurr); } @@ -1493,11 +1676,13 @@ sub process { # check for spacing round square brackets; allowed: # 1. with a type on the left -- int [] a; -# 2. at the beginning of a line for slice initialisers -- [0..10] = 5, +# 2. at the beginning of a line for slice initialisers -- [0...10] = 5, +# 3. inside a curly brace -- = { [0...10] = 5 } while ($line =~ /(.*?\s)\[/g) { my ($where, $prefix) = ($-[1], $1); if ($prefix !~ /$Type\s+$/ && - ($where != 0 || $prefix !~ /^.\s+$/)) { + ($where != 0 || $prefix !~ /^.\s+$/) && + $prefix !~ /{\s+$/) { ERROR("space prohibited before open square bracket '['\n" . $herecurr); } } @@ -1632,7 +1817,7 @@ sub process { # unary operator, or a cast } elsif ($op eq '!' || $op eq '~' || $opv eq '*U' || $opv eq '-U' || - $opv eq '&U') { + $opv eq '&U' || $opv eq '&&U') { if ($ctx !~ /[WEBC]x./ && $ca !~ /(?:\)|!|~|\*|-|\&|\||\+\+|\-\-|\{)$/) { ERROR("space required before that '$op' $at\n" . $hereptr); } @@ -1785,7 +1970,26 @@ sub process { # Check for illegal assignment in if conditional -- and check for trailing # statements after the conditional. - if ($line =~ /\b(?:if|while|for)\s*\(/ && $line !~ /^.\s*#/) { + if ($line =~ /do\s*(?!{)/) { + my ($stat_next) = ctx_statement_block($line_nr_next, + $remain_next, $off_next); + $stat_next =~ s/\n./\n /g; + ##print "stat<$stat> stat_next<$stat_next>\n"; + + if ($stat_next =~ /^\s*while\b/) { + # If the statement carries leading newlines, + # then count those as offsets. + my ($whitespace) = + ($stat_next =~ /^((?:\s*\n[+-])*\s*)/s); + my $offset = + statement_rawlines($whitespace) - 1; + + $suppress_whiletrailers{$line_nr_next + + $offset} = 1; + } + } + if (!defined $suppress_whiletrailers{$linenr} && + $line =~ /\b(?:if|while|for)\s*\(/ && $line !~ /^.\s*#/) { my ($s, $c) = ($stat, $cond); if ($c =~ /\bif\s*\(.*[^<>!=]=[^=].*/) { @@ -1800,57 +2004,16 @@ sub process { if (length($c) && $s !~ /^\s*{?\s*\\*\s*$/ && $c !~ /}\s*while\s*/) { - ERROR("trailing statements should be on next line\n" . $herecurr); - } - } - -# Check relative indent for conditionals and blocks. - if ($line =~ /\b(?:(?:if|while|for)\s*\(|do\b)/ && $line !~ /^.\s*#/ && $line !~ /\}\s*while\s*/) { - my ($s, $c) = ($stat, $cond); - - substr($s, 0, length($c), ''); + # Find out how long the conditional actually is. + my @newlines = ($c =~ /\n/gs); + my $cond_lines = 1 + $#newlines; - # Make sure we remove the line prefixes as we have - # none on the first line, and are going to readd them - # where necessary. - $s =~ s/\n./\n/gs; - - # We want to check the first line inside the block - # starting at the end of the conditional, so remove: - # 1) any blank line termination - # 2) any opening brace { on end of the line - # 3) any do (...) { - my $continuation = 0; - my $check = 0; - $s =~ s/^.*\bdo\b//; - $s =~ s/^\s*{//; - if ($s =~ s/^\s*\\//) { - $continuation = 1; - } - if ($s =~ s/^\s*\n//) { - $check = 1; - } - - # Also ignore a loop construct at the end of a - # preprocessor statement. - if (($prevline =~ /^.\s*#\s*define\s/ || - $prevline =~ /\\\s*$/) && $continuation == 0) { - $check = 0; - } - - # Ignore the current line if its is a preprocessor - # line. - if ($s =~ /^\s*#\s*/) { - $check = 0; - } - - my (undef, $sindent) = line_stats("+" . $s); - - ##print "line<$line> prevline<$prevline> indent<$indent> sindent<$sindent> check<$check> continuation<$continuation> s<$s>\n"; + my $stat_real = raw_line($linenr, $cond_lines); + if (defined($stat_real) && $cond_lines > 1) { + $stat_real = "[...]\n$stat_real"; + } - if ($check && (($sindent % 8) != 0 || - ($sindent <= $indent && $s ne ''))) { - WARN("suspect code indent for conditional statements\n" . $herecurr); + ERROR("trailing statements should be on next line\n" . $herecurr . $stat_real); } } @@ -1877,6 +2040,15 @@ sub process { ERROR("trailing statements should be on next line\n" . $herecurr); } } +# case and default should not have general statements after them + if ($line =~ /^.\s*(?:case\s*.*|default\s*):/g && + $line !~ /\G(?: + (?:\s*$;*)(?:\s*{)?(?:\s*$;*)(?:\s*\\)?\s*$| + \s*return\s+ + )/xg) + { + ERROR("trailing statements should be on next line\n" . $herecurr); + } # Check for }<nl>else {, these must be at the same # indent level to be relevant to each other. @@ -1913,12 +2085,17 @@ sub process { #warn if <asm/foo.h> is #included and <linux/foo.h> is available (uses RAW line) if ($tree && $rawline =~ m{^.\s*\#\s*include\s*\<asm\/(.*)\.h\>}) { - my $checkfile = "include/linux/$1.h"; - if (-f "$root/$checkfile" && $realfile ne $checkfile && + my $file = "$1.h"; + my $checkfile = "include/linux/$file"; + if (-f "$root/$checkfile" && + $realfile ne $checkfile && $1 ne 'irq') { - WARN("Use #include <linux/$1.h> instead of <asm/$1.h>\n" . - $herecurr); + if ($realfile =~ m{^arch/}) { + CHK("Consider using #include <linux/$file> instead of <asm/$file>\n" . $herecurr); + } else { + WARN("Use #include <linux/$file> instead of <asm/$file>\n" . $herecurr); + } } } @@ -1953,8 +2130,8 @@ sub process { # Extract the remainder of the define (if any) and # rip off surrounding spaces, and trailing \'s. $rest = ''; - while ($off != 0 || ($cnt > 0 && $rest =~ /(?:^|\\)\s*$/)) { - #print "ADDING $off <" . substr($lines[$ln - 1], $off) . ">\n"; + while ($off != 0 || ($cnt > 0 && $rest =~ /\\\s*$/)) { + #print "ADDING cnt<$cnt> $off <" . substr($lines[$ln - 1], $off) . "> rest<$rest>\n"; if ($off != 0 || $lines[$ln - 1] !~ /^-/) { $rest .= substr($lines[$ln - 1], $off) . "\n"; $cnt--; @@ -1978,9 +2155,10 @@ sub process { $dstat =~ s/\s*$//s; # Flatten any parentheses and braces - while ($dstat =~ s/\([^\(\)]*\)/1/) { - } - while ($dstat =~ s/\{[^\{\}]*\}/1/) { + while ($dstat =~ s/\([^\(\)]*\)/1/ || + $dstat =~ s/\{[^\{\}]*\}/1/ || + $dstat =~ s/\[[^\{\}]*\]/1/) + { } my $exceptions = qr{ @@ -2003,6 +2181,7 @@ sub process { if ($dstat ne '' && $dstat !~ /^(?:$Ident|-?$Constant)$/ && $dstat !~ /$exceptions/ && + $dstat !~ /^\.$Ident\s*=/ && $dstat =~ /$Operators/) { ERROR("Macros with complex values should be enclosed in parenthesis\n" . "$here\n$ctx\n"); @@ -2103,10 +2282,10 @@ sub process { } if ($level == 0 && $block =~ /^\s*\{/ && !$allowed) { my $herectx = $here . "\n";; - my $end = $linenr + statement_rawlines($block) - 1; + my $cnt = statement_rawlines($block); - for (my $ln = $linenr - 1; $ln < $end; $ln++) { - $herectx .= $rawlines[$ln] . "\n";; + for (my $n = 0; $n < $cnt; $n++) { + $herectx .= raw_line($linenr, $n) . "\n";; } WARN("braces {} are not necessary for single statement blocks\n" . $herectx); @@ -2281,6 +2460,7 @@ sub process { my $string; while ($line =~ /(?:^|")([X\t]*)(?:"|$)/g) { $string = substr($rawline, $-[1], $+[1] - $-[1]); + $string =~ s/%%/__/g; if ($string =~ /(?<!%)%L[udi]/) { WARN("\%Ld/%Lu are not-standard C, use %lld/%llu\n" . $herecurr); last; diff --git a/scripts/checkstack.pl b/scripts/checkstack.pl index f7e8e93ff30d..14ee68e991dd 100755 --- a/scripts/checkstack.pl +++ b/scripts/checkstack.pl @@ -14,6 +14,7 @@ # M68k port by Geert Uytterhoeven and Andreas Schwab # AVR32 port by Haavard Skinnemoen <hskinnemoen@atmel.com> # PARISC port by Kyle McMartin <kyle@parisc-linux.org> +# sparc port by Martin Habets <errandir_news@mph.eclipse.co.uk> # # Usage: # objdump -d vmlinux | scripts/checkstack.pl [arch] @@ -94,6 +95,9 @@ my (@stack, $re, $dre, $x, $xs); } elsif ($arch =~ /^blackfin$/) { # 0: 00 e8 38 01 LINK 0x4e0; $re = qr/.*[[:space:]]LINK[[:space:]]*(0x$x{1,8})/o; + } elsif ($arch eq 'sparc' || $arch eq 'sparc64') { + # f0019d10: 9d e3 bf 90 save %sp, -112, %sp + $re = qr/.*save.*%sp, -(([0-9]{2}|[3-9])[0-9]{2}), %sp/o; } else { print("wrong or unknown architecture \"$arch\"\n"); exit diff --git a/scripts/checksyscalls.sh b/scripts/checksyscalls.sh index 366f8c7f62bf..60d00d1c4eee 100755 --- a/scripts/checksyscalls.sh +++ b/scripts/checksyscalls.sh @@ -113,11 +113,11 @@ EOF } syscall_list() { -sed -n -e '/^\#define/ { s/[^_]*__NR_\([^[:space:]]*\).*/\ +sed -n -e '/^\#define/ s/[^_]*__NR_\([^[:space:]]*\).*/\ \#if !defined \(__NR_\1\) \&\& !defined \(__IGNORE_\1\)\ \#warning syscall \1 not implemented\ -\#endif/p }' $1 +\#endif/p' $1 } -(ignore_list && syscall_list ${srctree}/include/asm-x86/unistd_32.h) | \ +(ignore_list && syscall_list ${srctree}/arch/x86/include/asm/unistd_32.h) | \ $* -E -x c - > /dev/null diff --git a/scripts/decodecode b/scripts/decodecode index 235d3938529d..4b00647814bc 100755 --- a/scripts/decodecode +++ b/scripts/decodecode @@ -7,7 +7,7 @@ # AFLAGS=--32 decodecode < 386.oops cleanup() { - rm -f $T $T.s $T.o + rm -f $T $T.s $T.o $T.oo $T.aa $T.aaa exit 1 } @@ -44,21 +44,33 @@ if [ $marker -eq 0 ]; then marker=`expr index "$code" "\("` fi +touch $T.oo if [ $marker -ne 0 ]; then - beforemark=`echo "$code" | cut -c-$((${marker} - 1))` + echo All code >> $T.oo + echo ======== >> $T.oo + beforemark=`echo "$code"` echo -n " .byte 0x" > $T.s - echo $beforemark | sed -e 's/ /,0x/g' >> $T.s - as $AFLAGS -o $T.o $T.s - objdump -S $T.o - rm $T.o $T.s + echo $beforemark | sed -e 's/ /,0x/g' | sed -e 's/<//g' | sed -e 's/>//g' >> $T.s + as $AFLAGS -o $T.o $T.s &> /dev/null + objdump -S $T.o | grep -v "/tmp" | grep -v "Disassembly" | grep -v "\.text" | grep -v "^$" &> $T.ooo + cat $T.ooo >> $T.oo + rm -f $T.o $T.s $T.ooo # and fix code at-and-after marker code=`echo "$code" | cut -c$((${marker} + 1))-` fi - +echo Code starting with the faulting instruction > $T.aa +echo =========================================== >> $T.aa code=`echo $code | sed -e 's/ [<(]/ /;s/[>)] / /;s/ /,0x/g'` echo -n " .byte 0x" > $T.s echo $code >> $T.s -as $AFLAGS -o $T.o $T.s -objdump -S $T.o -rm $T $T.s $T.o +as $AFLAGS -o $T.o $T.s &> /dev/null +objdump -S $T.o | grep -v "Disassembly" | grep -v "/tmp" | grep -v "\.text" | grep -v "^$" &> $T.aaa +cat $T.aaa >> $T.aa + +faultline=`cat $T.aaa | head -1 | cut -d":" -f2` + +cat $T.oo | sed -e "s/\($faultline\)/\*\1 <-- trapping instruction/g" +echo +cat $T.aa +cleanup diff --git a/scripts/extract-ikconfig b/scripts/extract-ikconfig index 8187e6f0dc2f..72997c353cb3 100755 --- a/scripts/extract-ikconfig +++ b/scripts/extract-ikconfig @@ -8,8 +8,8 @@ test -e $binoffset || cc -o $binoffset ./scripts/binoffset.c || exit 1 IKCFG_ST="0x49 0x4b 0x43 0x46 0x47 0x5f 0x53 0x54" IKCFG_ED="0x49 0x4b 0x43 0x46 0x47 0x5f 0x45 0x44" -function dump_config { - typeset file="$1" +dump_config() { + file="$1" start=`$binoffset $file $IKCFG_ST 2>/dev/null` [ "$?" != "0" ] && start="-1" @@ -18,8 +18,8 @@ function dump_config { fi end=`$binoffset $file $IKCFG_ED 2>/dev/null` - let start="$start + 8" - let size="$end - $start" + start=`expr $start + 8` + size=`expr $end - $start` dd if="$file" ibs=1 skip="$start" count="$size" 2>/dev/null | zcat diff --git a/scripts/genksyms/genksyms.c b/scripts/genksyms/genksyms.c index c249274e005a..f8bb4cabd62d 100644 --- a/scripts/genksyms/genksyms.c +++ b/scripts/genksyms/genksyms.c @@ -42,7 +42,8 @@ static FILE *debugfile; int cur_line = 1; char *cur_filename; -static int flag_debug, flag_dump_defs, flag_dump_types, flag_warnings; +static int flag_debug, flag_dump_defs, flag_reference, flag_dump_types, + flag_preserve, flag_warnings, flag_asm; static const char *arch = ""; static const char *mod_prefix = ""; @@ -58,6 +59,8 @@ static const char *const symbol_type_name[] = { static int equal_list(struct string_list *a, struct string_list *b); static void print_list(FILE * f, struct string_list *list); +static void print_location(void); +static void print_type_name(enum symbol_type type, const char *name); /*----------------------------------------------------------------------*/ @@ -151,27 +154,83 @@ struct symbol *find_symbol(const char *name, enum symbol_type ns) for (sym = symtab[h]; sym; sym = sym->hash_next) if (map_to_ns(sym->type) == map_to_ns(ns) && - strcmp(name, sym->name) == 0) + strcmp(name, sym->name) == 0 && + sym->is_declared) break; return sym; } -struct symbol *add_symbol(const char *name, enum symbol_type type, - struct string_list *defn, int is_extern) +static int is_unknown_symbol(struct symbol *sym) +{ + struct string_list *defn; + + return ((sym->type == SYM_STRUCT || + sym->type == SYM_UNION || + sym->type == SYM_ENUM) && + (defn = sym->defn) && defn->tag == SYM_NORMAL && + strcmp(defn->string, "}") == 0 && + (defn = defn->next) && defn->tag == SYM_NORMAL && + strcmp(defn->string, "UNKNOWN") == 0 && + (defn = defn->next) && defn->tag == SYM_NORMAL && + strcmp(defn->string, "{") == 0); +} + +struct symbol *__add_symbol(const char *name, enum symbol_type type, + struct string_list *defn, int is_extern, + int is_reference) { unsigned long h = crc32(name) % HASH_BUCKETS; struct symbol *sym; + enum symbol_status status = STATUS_UNCHANGED; for (sym = symtab[h]; sym; sym = sym->hash_next) { - if (map_to_ns(sym->type) == map_to_ns(type) - && strcmp(name, sym->name) == 0) { - if (!equal_list(sym->defn, defn)) + if (map_to_ns(sym->type) == map_to_ns(type) && + strcmp(name, sym->name) == 0) { + if (is_reference) + /* fall through */ ; + else if (sym->type == type && + equal_list(sym->defn, defn)) { + if (!sym->is_declared && sym->is_override) { + print_location(); + print_type_name(type, name); + fprintf(stderr, " modversion is " + "unchanged\n"); + } + sym->is_declared = 1; + return sym; + } else if (!sym->is_declared) { + if (sym->is_override && flag_preserve) { + print_location(); + fprintf(stderr, "ignoring "); + print_type_name(type, name); + fprintf(stderr, " modversion change\n"); + sym->is_declared = 1; + return sym; + } else { + status = is_unknown_symbol(sym) ? + STATUS_DEFINED : STATUS_MODIFIED; + } + } else { error_with_pos("redefinition of %s", name); - return sym; + return sym; + } + break; } } + if (sym) { + struct symbol **psym; + + for (psym = &symtab[h]; *psym; psym = &(*psym)->hash_next) { + if (*psym == sym) { + *psym = sym->hash_next; + break; + } + } + --nsyms; + } + sym = xmalloc(sizeof(*sym)); sym->name = name; sym->type = type; @@ -183,6 +242,10 @@ struct symbol *add_symbol(const char *name, enum symbol_type type, sym->hash_next = symtab[h]; symtab[h] = sym; + sym->is_declared = !is_reference; + sym->status = status; + sym->is_override = 0; + if (flag_debug) { fprintf(debugfile, "Defn for %s %s == <", symbol_type_name[type], name); @@ -196,6 +259,18 @@ struct symbol *add_symbol(const char *name, enum symbol_type type, return sym; } +struct symbol *add_symbol(const char *name, enum symbol_type type, + struct string_list *defn, int is_extern) +{ + return __add_symbol(name, type, defn, is_extern, 0); +} + +struct symbol *add_reference_symbol(const char *name, enum symbol_type type, + struct string_list *defn, int is_extern) +{ + return __add_symbol(name, type, defn, is_extern, 1); +} + /*----------------------------------------------------------------------*/ void free_node(struct string_list *node) @@ -236,6 +311,90 @@ static int equal_list(struct string_list *a, struct string_list *b) return !a && !b; } +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +struct string_list *read_node(FILE *f) +{ + char buffer[256]; + struct string_list node = { + .string = buffer, + .tag = SYM_NORMAL }; + int c; + + while ((c = fgetc(f)) != EOF) { + if (c == ' ') { + if (node.string == buffer) + continue; + break; + } else if (c == '\n') { + if (node.string == buffer) + return NULL; + ungetc(c, f); + break; + } + if (node.string >= buffer + sizeof(buffer) - 1) { + fprintf(stderr, "Token too long\n"); + exit(1); + } + *node.string++ = c; + } + if (node.string == buffer) + return NULL; + *node.string = 0; + node.string = buffer; + + if (node.string[1] == '#') { + int n; + + for (n = 0; n < ARRAY_SIZE(symbol_type_name); n++) { + if (node.string[0] == symbol_type_name[n][0]) { + node.tag = n; + node.string += 2; + return copy_node(&node); + } + } + fprintf(stderr, "Unknown type %c\n", node.string[0]); + exit(1); + } + return copy_node(&node); +} + +static void read_reference(FILE *f) +{ + while (!feof(f)) { + struct string_list *defn = NULL; + struct string_list *sym, *def; + int is_extern = 0, is_override = 0; + struct symbol *subsym; + + sym = read_node(f); + if (sym && sym->tag == SYM_NORMAL && + !strcmp(sym->string, "override")) { + is_override = 1; + free_node(sym); + sym = read_node(f); + } + if (!sym) + continue; + def = read_node(f); + if (def && def->tag == SYM_NORMAL && + !strcmp(def->string, "extern")) { + is_extern = 1; + free_node(def); + def = read_node(f); + } + while (def) { + def->next = defn; + defn = def; + def = read_node(f); + } + subsym = add_reference_symbol(xstrdup(sym->string), sym->tag, + defn, is_extern); + subsym->is_override = is_override; + free_node(sym); + } +} + static void print_node(FILE * f, struct string_list *list) { if (list->tag != SYM_NORMAL) { @@ -311,6 +470,7 @@ static unsigned long expand_and_crc_sym(struct symbol *sym, unsigned long crc) case SYM_TYPEDEF: subsym = find_symbol(cur->string, cur->tag); + /* FIXME: Bad reference files can segfault here. */ if (subsym->expansion_trail) { if (flag_dump_defs) fprintf(debugfile, "%s ", cur->string); @@ -347,9 +507,22 @@ static unsigned long expand_and_crc_sym(struct symbol *sym, unsigned long crc) t = n; n = xmalloc(sizeof(*n)); - n->string = xstrdup("{ UNKNOWN }"); + n->string = xstrdup("{"); + n->tag = SYM_NORMAL; + n->next = t; + t = n; + + n = xmalloc(sizeof(*n)); + n->string = xstrdup("UNKNOWN"); + n->tag = SYM_NORMAL; + n->next = t; + t = n; + + n = xmalloc(sizeof(*n)); + n->string = xstrdup("}"); n->tag = SYM_NORMAL; n->next = t; + t = n; subsym = add_symbol(cur->string, cur->tag, n, 0); @@ -397,37 +570,75 @@ void export_symbol(const char *name) error_with_pos("export undefined symbol %s", name); else { unsigned long crc; + int has_changed = 0; if (flag_dump_defs) fprintf(debugfile, "Export %s == <", name); expansion_trail = (struct symbol *)-1L; + sym->expansion_trail = expansion_trail; + expansion_trail = sym; crc = expand_and_crc_sym(sym, 0xffffffff) ^ 0xffffffff; sym = expansion_trail; while (sym != (struct symbol *)-1L) { struct symbol *n = sym->expansion_trail; + + if (sym->status != STATUS_UNCHANGED) { + if (!has_changed) { + print_location(); + fprintf(stderr, "%s: %s: modversion " + "changed because of changes " + "in ", flag_preserve ? "error" : + "warning", name); + } else + fprintf(stderr, ", "); + print_type_name(sym->type, sym->name); + if (sym->status == STATUS_DEFINED) + fprintf(stderr, " (became defined)"); + has_changed = 1; + if (flag_preserve) + errors++; + } sym->expansion_trail = 0; sym = n; } + if (has_changed) + fprintf(stderr, "\n"); if (flag_dump_defs) fputs(">\n", debugfile); - /* Used as a linker script. */ - printf("%s__crc_%s = 0x%08lx ;\n", mod_prefix, name, crc); + /* Used as assembly source or a linker script. */ + printf(flag_asm + ? ".equiv %s__crc_%s, %#08lx\n" + : "%s__crc_%s = %#08lx ;\n", + mod_prefix, name, crc); } } /*----------------------------------------------------------------------*/ + +static void print_location(void) +{ + fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>", cur_line); +} + +static void print_type_name(enum symbol_type type, const char *name) +{ + if (type != SYM_NORMAL) + fprintf(stderr, "%s %s", symbol_type_name[type], name); + else + fprintf(stderr, "%s", name); +} + void error_with_pos(const char *fmt, ...) { va_list args; if (flag_warnings) { - fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>", - cur_line); + print_location(); va_start(args, fmt); vfprintf(stderr, fmt, args); @@ -440,21 +651,27 @@ void error_with_pos(const char *fmt, ...) static void genksyms_usage(void) { - fputs("Usage:\n" "genksyms [-adDTwqhV] > /path/to/.tmp_obj.ver\n" "\n" + fputs("Usage:\n" "genksyms [-aAdDTwqhV] > /path/to/.tmp_obj.ver\n" "\n" #ifdef __GNU_LIBRARY__ " -a, --arch Select architecture\n" + " -A, --asm Generate assembly rather than linker script\n" " -d, --debug Increment the debug level (repeatable)\n" " -D, --dump Dump expanded symbol defs (for debugging only)\n" - " -T, --dump-types file Dump expanded types into file (for debugging only)\n" + " -r, --reference file Read reference symbols from a file\n" + " -T, --dump-types file Dump expanded types into file\n" + " -p, --preserve Preserve reference modversions or fail\n" " -w, --warnings Enable warnings\n" " -q, --quiet Disable warnings (default)\n" " -h, --help Print this message\n" " -V, --version Print the release version\n" #else /* __GNU_LIBRARY__ */ " -a Select architecture\n" + " -A Generate assembly rather than linker script\n" " -d Increment the debug level (repeatable)\n" " -D Dump expanded symbol defs (for debugging only)\n" - " -T file Dump expanded types into file (for debugging only)\n" + " -r file Read reference symbols from a file\n" + " -T file Dump expanded types into file\n" + " -p Preserve reference modversions or fail\n" " -w Enable warnings\n" " -q Disable warnings (default)\n" " -h Print this message\n" @@ -465,26 +682,29 @@ static void genksyms_usage(void) int main(int argc, char **argv) { - FILE *dumpfile = NULL; + FILE *dumpfile = NULL, *ref_file = NULL; int o; #ifdef __GNU_LIBRARY__ struct option long_opts[] = { {"arch", 1, 0, 'a'}, + {"asm", 0, 0, 'A'}, {"debug", 0, 0, 'd'}, {"warnings", 0, 0, 'w'}, {"quiet", 0, 0, 'q'}, {"dump", 0, 0, 'D'}, + {"reference", 1, 0, 'r'}, {"dump-types", 1, 0, 'T'}, + {"preserve", 0, 0, 'p'}, {"version", 0, 0, 'V'}, {"help", 0, 0, 'h'}, {0, 0, 0, 0} }; - while ((o = getopt_long(argc, argv, "a:dwqVDT:h", + while ((o = getopt_long(argc, argv, "a:dwqVADr:T:ph", &long_opts[0], NULL)) != EOF) #else /* __GNU_LIBRARY__ */ - while ((o = getopt(argc, argv, "a:dwqVDT:h")) != EOF) + while ((o = getopt(argc, argv, "a:dwqVADr:T:ph")) != EOF) #endif /* __GNU_LIBRARY__ */ switch (o) { case 'a': @@ -502,9 +722,20 @@ int main(int argc, char **argv) case 'V': fputs("genksyms version 2.5.60\n", stderr); break; + case 'A': + flag_asm = 1; + break; case 'D': flag_dump_defs = 1; break; + case 'r': + flag_reference = 1; + ref_file = fopen(optarg, "r"); + if (!ref_file) { + perror(optarg); + return 1; + } + break; case 'T': flag_dump_types = 1; dumpfile = fopen(optarg, "w"); @@ -513,6 +744,9 @@ int main(int argc, char **argv) return 1; } break; + case 'p': + flag_preserve = 1; + break; case 'h': genksyms_usage(); return 0; @@ -533,12 +767,17 @@ int main(int argc, char **argv) /* setlinebuf(debugfile); */ } + if (flag_reference) + read_reference(ref_file); + yyparse(); if (flag_dump_types && visited_symbols) { while (visited_symbols != (struct symbol *)-1L) { struct symbol *sym = visited_symbols; + if (sym->is_override) + fputs("override ", dumpfile); if (sym->type != SYM_NORMAL) { putc(symbol_type_name[sym->type][0], dumpfile); putc('#', dumpfile); diff --git a/scripts/genksyms/genksyms.h b/scripts/genksyms/genksyms.h index 2668287aa498..25c4d40cefc1 100644 --- a/scripts/genksyms/genksyms.h +++ b/scripts/genksyms/genksyms.h @@ -29,6 +29,10 @@ enum symbol_type { SYM_NORMAL, SYM_TYPEDEF, SYM_ENUM, SYM_STRUCT, SYM_UNION }; +enum symbol_status { + STATUS_UNCHANGED, STATUS_DEFINED, STATUS_MODIFIED +}; + struct string_list { struct string_list *next; enum symbol_type tag; @@ -43,6 +47,9 @@ struct symbol { struct symbol *expansion_trail; struct symbol *visited; int is_extern; + int is_declared; + enum symbol_status status; + int is_override; }; typedef struct string_list **yystype; diff --git a/scripts/genksyms/keywords.c_shipped b/scripts/genksyms/keywords.c_shipped index 971e0113ae7a..83484fe93ede 100644 --- a/scripts/genksyms/keywords.c_shipped +++ b/scripts/genksyms/keywords.c_shipped @@ -1,4 +1,4 @@ -/* ANSI-C code produced by gperf version 3.0.2 */ +/* ANSI-C code produced by gperf version 3.0.1 */ /* Command-line: gperf -L ANSI-C -a -C -E -g -H is_reserved_hash -k '1,3,$' -N is_reserved_word -p -t scripts/genksyms/keywords.gperf */ #if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ @@ -32,7 +32,7 @@ #line 3 "scripts/genksyms/keywords.gperf" struct resword { const char *name; int token; }; -/* maximum key range = 62, duplicates = 0 */ +/* maximum key range = 64, duplicates = 0 */ #ifdef __GNUC__ __inline @@ -46,32 +46,32 @@ is_reserved_hash (register const char *str, register unsigned int len) { static const unsigned char asso_values[] = { - 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, 65, 5, - 65, 65, 65, 65, 65, 65, 35, 65, 65, 65, - 0, 65, 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 0, 65, 0, 65, 5, - 20, 15, 10, 30, 65, 15, 65, 65, 20, 0, - 10, 35, 20, 65, 10, 5, 0, 10, 5, 65, - 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65 + 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, 67, 0, + 67, 67, 67, 67, 67, 67, 15, 67, 67, 67, + 0, 67, 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 0, 67, 0, 67, 5, + 25, 20, 15, 30, 67, 15, 67, 67, 10, 0, + 10, 40, 20, 67, 10, 5, 0, 10, 15, 67, + 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67 }; return len + asso_values[(unsigned char)str[2]] + asso_values[(unsigned char)str[0]] + asso_values[(unsigned char)str[len - 1]]; } @@ -84,116 +84,119 @@ is_reserved_word (register const char *str, register unsigned int len) { enum { - TOTAL_KEYWORDS = 43, + TOTAL_KEYWORDS = 45, MIN_WORD_LENGTH = 3, MAX_WORD_LENGTH = 24, MIN_HASH_VALUE = 3, - MAX_HASH_VALUE = 64 + MAX_HASH_VALUE = 66 }; static const struct resword wordlist[] = { {""}, {""}, {""}, -#line 26 "scripts/genksyms/keywords.gperf" +#line 28 "scripts/genksyms/keywords.gperf" {"asm", ASM_KEYW}, {""}, -#line 8 "scripts/genksyms/keywords.gperf" +#line 10 "scripts/genksyms/keywords.gperf" {"__asm", ASM_KEYW}, {""}, -#line 9 "scripts/genksyms/keywords.gperf" +#line 11 "scripts/genksyms/keywords.gperf" {"__asm__", ASM_KEYW}, {""}, {""}, -#line 52 "scripts/genksyms/keywords.gperf" +#line 54 "scripts/genksyms/keywords.gperf" {"__typeof__", TYPEOF_KEYW}, {""}, -#line 12 "scripts/genksyms/keywords.gperf" +#line 14 "scripts/genksyms/keywords.gperf" {"__const", CONST_KEYW}, -#line 11 "scripts/genksyms/keywords.gperf" - {"__attribute__", ATTRIBUTE_KEYW}, #line 13 "scripts/genksyms/keywords.gperf" + {"__attribute__", ATTRIBUTE_KEYW}, +#line 15 "scripts/genksyms/keywords.gperf" {"__const__", CONST_KEYW}, -#line 18 "scripts/genksyms/keywords.gperf" +#line 20 "scripts/genksyms/keywords.gperf" {"__signed__", SIGNED_KEYW}, -#line 44 "scripts/genksyms/keywords.gperf" +#line 46 "scripts/genksyms/keywords.gperf" {"static", STATIC_KEYW}, -#line 20 "scripts/genksyms/keywords.gperf" - {"__volatile__", VOLATILE_KEYW}, -#line 39 "scripts/genksyms/keywords.gperf" + {""}, +#line 41 "scripts/genksyms/keywords.gperf" {"int", INT_KEYW}, -#line 32 "scripts/genksyms/keywords.gperf" +#line 34 "scripts/genksyms/keywords.gperf" {"char", CHAR_KEYW}, -#line 33 "scripts/genksyms/keywords.gperf" +#line 35 "scripts/genksyms/keywords.gperf" {"const", CONST_KEYW}, -#line 45 "scripts/genksyms/keywords.gperf" +#line 47 "scripts/genksyms/keywords.gperf" {"struct", STRUCT_KEYW}, -#line 24 "scripts/genksyms/keywords.gperf" +#line 26 "scripts/genksyms/keywords.gperf" {"__restrict__", RESTRICT_KEYW}, -#line 25 "scripts/genksyms/keywords.gperf" +#line 27 "scripts/genksyms/keywords.gperf" {"restrict", RESTRICT_KEYW}, -#line 23 "scripts/genksyms/keywords.gperf" - {"_restrict", RESTRICT_KEYW}, -#line 16 "scripts/genksyms/keywords.gperf" +#line 7 "scripts/genksyms/keywords.gperf" + {"EXPORT_SYMBOL_GPL_FUTURE", EXPORT_SYMBOL_KEYW}, +#line 18 "scripts/genksyms/keywords.gperf" {"__inline__", INLINE_KEYW}, -#line 10 "scripts/genksyms/keywords.gperf" - {"__attribute", ATTRIBUTE_KEYW}, {""}, -#line 14 "scripts/genksyms/keywords.gperf" +#line 22 "scripts/genksyms/keywords.gperf" + {"__volatile__", VOLATILE_KEYW}, +#line 5 "scripts/genksyms/keywords.gperf" + {"EXPORT_SYMBOL", EXPORT_SYMBOL_KEYW}, +#line 25 "scripts/genksyms/keywords.gperf" + {"_restrict", RESTRICT_KEYW}, + {""}, +#line 12 "scripts/genksyms/keywords.gperf" + {"__attribute", ATTRIBUTE_KEYW}, +#line 6 "scripts/genksyms/keywords.gperf" + {"EXPORT_SYMBOL_GPL", EXPORT_SYMBOL_KEYW}, +#line 16 "scripts/genksyms/keywords.gperf" {"__extension__", EXTENSION_KEYW}, -#line 35 "scripts/genksyms/keywords.gperf" +#line 37 "scripts/genksyms/keywords.gperf" {"enum", ENUM_KEYW}, -#line 19 "scripts/genksyms/keywords.gperf" - {"__volatile", VOLATILE_KEYW}, -#line 36 "scripts/genksyms/keywords.gperf" +#line 8 "scripts/genksyms/keywords.gperf" + {"EXPORT_UNUSED_SYMBOL", EXPORT_SYMBOL_KEYW}, +#line 38 "scripts/genksyms/keywords.gperf" {"extern", EXTERN_KEYW}, {""}, -#line 17 "scripts/genksyms/keywords.gperf" +#line 19 "scripts/genksyms/keywords.gperf" {"__signed", SIGNED_KEYW}, -#line 7 "scripts/genksyms/keywords.gperf" - {"EXPORT_SYMBOL_GPL_FUTURE", EXPORT_SYMBOL_KEYW}, - {""}, -#line 51 "scripts/genksyms/keywords.gperf" +#line 9 "scripts/genksyms/keywords.gperf" + {"EXPORT_UNUSED_SYMBOL_GPL", EXPORT_SYMBOL_KEYW}, +#line 49 "scripts/genksyms/keywords.gperf" + {"union", UNION_KEYW}, +#line 53 "scripts/genksyms/keywords.gperf" {"typeof", TYPEOF_KEYW}, -#line 46 "scripts/genksyms/keywords.gperf" +#line 48 "scripts/genksyms/keywords.gperf" {"typedef", TYPEDEF_KEYW}, -#line 15 "scripts/genksyms/keywords.gperf" +#line 17 "scripts/genksyms/keywords.gperf" {"__inline", INLINE_KEYW}, -#line 31 "scripts/genksyms/keywords.gperf" +#line 33 "scripts/genksyms/keywords.gperf" {"auto", AUTO_KEYW}, -#line 47 "scripts/genksyms/keywords.gperf" - {"union", UNION_KEYW}, - {""}, {""}, -#line 48 "scripts/genksyms/keywords.gperf" - {"unsigned", UNSIGNED_KEYW}, -#line 49 "scripts/genksyms/keywords.gperf" - {"void", VOID_KEYW}, -#line 42 "scripts/genksyms/keywords.gperf" - {"short", SHORT_KEYW}, +#line 21 "scripts/genksyms/keywords.gperf" + {"__volatile", VOLATILE_KEYW}, {""}, {""}, #line 50 "scripts/genksyms/keywords.gperf" - {"volatile", VOLATILE_KEYW}, - {""}, -#line 37 "scripts/genksyms/keywords.gperf" - {"float", FLOAT_KEYW}, -#line 34 "scripts/genksyms/keywords.gperf" - {"double", DOUBLE_KEYW}, + {"unsigned", UNSIGNED_KEYW}, {""}, -#line 5 "scripts/genksyms/keywords.gperf" - {"EXPORT_SYMBOL", EXPORT_SYMBOL_KEYW}, - {""}, {""}, -#line 38 "scripts/genksyms/keywords.gperf" +#line 44 "scripts/genksyms/keywords.gperf" + {"short", SHORT_KEYW}, +#line 40 "scripts/genksyms/keywords.gperf" {"inline", INLINE_KEYW}, -#line 6 "scripts/genksyms/keywords.gperf" - {"EXPORT_SYMBOL_GPL", EXPORT_SYMBOL_KEYW}, -#line 41 "scripts/genksyms/keywords.gperf" - {"register", REGISTER_KEYW}, {""}, -#line 22 "scripts/genksyms/keywords.gperf" +#line 52 "scripts/genksyms/keywords.gperf" + {"volatile", VOLATILE_KEYW}, +#line 42 "scripts/genksyms/keywords.gperf" + {"long", LONG_KEYW}, +#line 24 "scripts/genksyms/keywords.gperf" {"_Bool", BOOL_KEYW}, -#line 43 "scripts/genksyms/keywords.gperf" - {"signed", SIGNED_KEYW}, {""}, {""}, -#line 40 "scripts/genksyms/keywords.gperf" - {"long", LONG_KEYW} +#line 43 "scripts/genksyms/keywords.gperf" + {"register", REGISTER_KEYW}, +#line 51 "scripts/genksyms/keywords.gperf" + {"void", VOID_KEYW}, +#line 39 "scripts/genksyms/keywords.gperf" + {"float", FLOAT_KEYW}, +#line 36 "scripts/genksyms/keywords.gperf" + {"double", DOUBLE_KEYW}, + {""}, {""}, {""}, {""}, +#line 45 "scripts/genksyms/keywords.gperf" + {"signed", SIGNED_KEYW} }; if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) diff --git a/scripts/genksyms/keywords.gperf b/scripts/genksyms/keywords.gperf index 5ef3733225fb..8abe7ab8d88f 100644 --- a/scripts/genksyms/keywords.gperf +++ b/scripts/genksyms/keywords.gperf @@ -5,6 +5,8 @@ struct resword { const char *name; int token; } EXPORT_SYMBOL, EXPORT_SYMBOL_KEYW EXPORT_SYMBOL_GPL, EXPORT_SYMBOL_KEYW EXPORT_SYMBOL_GPL_FUTURE, EXPORT_SYMBOL_KEYW +EXPORT_UNUSED_SYMBOL, EXPORT_SYMBOL_KEYW +EXPORT_UNUSED_SYMBOL_GPL, EXPORT_SYMBOL_KEYW __asm, ASM_KEYW __asm__, ASM_KEYW __attribute, ATTRIBUTE_KEYW diff --git a/scripts/headerdep.pl b/scripts/headerdep.pl new file mode 100755 index 000000000000..97399da89ef2 --- /dev/null +++ b/scripts/headerdep.pl @@ -0,0 +1,193 @@ +#! /usr/bin/perl +# +# Detect cycles in the header file dependency graph +# Vegard Nossum <vegardno@ifi.uio.no> +# + +use strict; +use warnings; + +use Getopt::Long; + +my $opt_all; +my @opt_include; +my $opt_graph; + +&Getopt::Long::Configure(qw(bundling pass_through)); +&GetOptions( + help => \&help, + version => \&version, + + all => \$opt_all, + I => \@opt_include, + graph => \$opt_graph, +); + +push @opt_include, 'include'; +my %deps = (); +my %linenos = (); + +my @headers = grep { strip($_) } @ARGV; + +parse_all(@headers); + +if($opt_graph) { + graph(); +} else { + detect_cycles(@headers); +} + + +sub help { + print "Usage: $0 [options] file...\n"; + print "\n"; + print "Options:\n"; + print " --all\n"; + print " --graph\n"; + print "\n"; + print " -I includedir\n"; + print "\n"; + print "To make nice graphs, try:\n"; + print " $0 --graph include/linux/kernel.h | dot -Tpng -o graph.png\n"; + exit; +} + +sub version { + print "headerdep version 2\n"; + exit; +} + +# Get a file name that is relative to our include paths +sub strip { + my $filename = shift; + + for my $i (@opt_include) { + my $stripped = $filename; + $stripped =~ s/^$i\///; + + return $stripped if $stripped ne $filename; + } + + return $filename; +} + +# Search for the file name in the list of include paths +sub search { + my $filename = shift; + return $filename if -f $filename; + + for my $i (@opt_include) { + my $path = "$i/$filename"; + return $path if -f $path; + } + + return undef; +} + +sub parse_all { + # Parse all the headers. + my @queue = @_; + while(@queue) { + my $header = pop @queue; + next if exists $deps{$header}; + + $deps{$header} = [] unless exists $deps{$header}; + + my $path = search($header); + next unless $path; + + open(my $file, '<', $path) or die($!); + chomp(my @lines = <$file>); + close($file); + + for my $i (0 .. $#lines) { + my $line = $lines[$i]; + if(my($dep) = ($line =~ m/^#\s*include\s*<(.*?)>/)) { + push @queue, $dep; + push @{$deps{$header}}, [$i + 1, $dep]; + } + } + } +} + +sub print_cycle { + # $cycle[n] includes $cycle[n + 1]; + # $cycle[-1] will be the culprit + my $cycle = shift; + + # Adjust the line numbers + for my $i (0 .. $#$cycle - 1) { + $cycle->[$i]->[0] = $cycle->[$i + 1]->[0]; + } + $cycle->[-1]->[0] = 0; + + my $first = shift @$cycle; + my $last = pop @$cycle; + + my $msg = "In file included"; + printf "%s from %s,\n", $msg, $last->[1] if defined $last; + + for my $header (reverse @$cycle) { + printf "%s from %s:%d%s\n", + " " x length $msg, + $header->[1], $header->[0], + $header->[1] eq $last->[1] ? ' <-- here' : ''; + } + + printf "%s:%d: warning: recursive header inclusion\n", + $first->[1], $first->[0]; +} + +# Find and print the smallest cycle starting in the specified node. +sub detect_cycles { + my @queue = map { [[0, $_]] } @_; + while(@queue) { + my $top = pop @queue; + my $name = $top->[-1]->[1]; + + for my $dep (@{$deps{$name}}) { + my $chain = [@$top, [$dep->[0], $dep->[1]]]; + + # If the dep already exists in the chain, we have a + # cycle... + if(grep { $_->[1] eq $dep->[1] } @$top) { + print_cycle($chain); + next if $opt_all; + return; + } + + push @queue, $chain; + } + } +} + +sub mangle { + $_ = shift; + s/\//__/g; + s/\./_/g; + s/-/_/g; + $_; +} + +# Output dependency graph in GraphViz language. +sub graph { + print "digraph {\n"; + + print "\t/* vertices */\n"; + for my $header (keys %deps) { + printf "\t%s [label=\"%s\"];\n", + mangle($header), $header; + } + + print "\n"; + + print "\t/* edges */\n"; + for my $header (keys %deps) { + for my $dep (@{$deps{$header}}) { + printf "\t%s -> %s;\n", + mangle($header), mangle($dep->[1]); + } + } + + print "}\n"; +} diff --git a/scripts/headers_check.pl b/scripts/headers_check.pl index 15d53a6b1a1f..488a3b1f760f 100644 --- a/scripts/headers_check.pl +++ b/scripts/headers_check.pl @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/bin/perl -w # # headers_check.pl execute a number of trivial consistency checks # @@ -17,7 +17,6 @@ # 2) TODO: check for leaked CONFIG_ symbols use strict; -use warnings; my ($dir, $arch, @files) = @ARGV; @@ -27,14 +26,15 @@ my $lineno = 0; my $filename; foreach my $file (@files) { + local *FH; $filename = $file; - open(my $fh, '<', "$filename") or die "$filename: $!\n"; + open(FH, "<$filename") or die "$filename: $!\n"; $lineno = 0; - while ($line = <$fh>) { + while ($line = <FH>) { $lineno++; check_include(); } - close $fh; + close FH; } exit $ret; diff --git a/scripts/headers_install.pl b/scripts/headers_install.pl index 68591cd08731..7d2b4146e02f 100644 --- a/scripts/headers_install.pl +++ b/scripts/headers_install.pl @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/bin/perl -w # # headers_install prepare the listed header files for use in # user space and copy the files to their destination. @@ -17,28 +17,29 @@ # 3) Drop all sections defined out by __KERNEL__ (using unifdef) use strict; -use warnings; my ($readdir, $installdir, $arch, @files) = @ARGV; my $unifdef = "scripts/unifdef -U__KERNEL__"; foreach my $file (@files) { + local *INFILE; + local *OUTFILE; my $tmpfile = "$installdir/$file.tmp"; - open(my $infile, '<', "$readdir/$file") + open(INFILE, "<$readdir/$file") or die "$readdir/$file: $!\n"; - open(my $outfile, '>', "$tmpfile") or die "$tmpfile: $!\n"; - while (my $line = <$infile>) { + open(OUTFILE, ">$tmpfile") or die "$tmpfile: $!\n"; + while (my $line = <INFILE>) { $line =~ s/([\s(])__user\s/$1/g; $line =~ s/([\s(])__force\s/$1/g; $line =~ s/([\s(])__iomem\s/$1/g; $line =~ s/\s__attribute_const__\s/ /g; $line =~ s/\s__attribute_const__$//g; $line =~ s/^#include <linux\/compiler.h>//; - printf $outfile "%s", $line; + printf OUTFILE "%s", $line; } - close $outfile; - close $infile; + close OUTFILE; + close INFILE; system $unifdef . " $tmpfile > $installdir/$file"; unlink $tmpfile; } diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c index ad2434b26970..92758120a767 100644 --- a/scripts/kallsyms.c +++ b/scripts/kallsyms.c @@ -130,18 +130,9 @@ static int read_symbol(FILE *in, struct sym_entry *s) static int symbol_valid(struct sym_entry *s) { /* Symbols which vary between passes. Passes 1 and 2 must have - * identical symbol lists. The kallsyms_* symbols below are only added - * after pass 1, they would be included in pass 2 when --all-symbols is - * specified so exclude them to get a stable symbol list. + * identical symbol lists. */ static char *special_symbols[] = { - "kallsyms_addresses", - "kallsyms_num_syms", - "kallsyms_names", - "kallsyms_markers", - "kallsyms_token_table", - "kallsyms_token_index", - /* Exclude linker generated symbols which vary between passes */ "_SDA_BASE_", /* ppc */ "_SDA2_BASE_", /* ppc */ @@ -173,7 +164,9 @@ static int symbol_valid(struct sym_entry *s) } /* Exclude symbols which vary between passes. */ - if (strstr((char *)s->sym + offset, "_compiled.")) + if (strstr((char *)s->sym + offset, "_compiled.") || + strncmp((char*)s->sym + offset, "__compound_literal.", 19) == 0 || + strncmp((char*)s->sym + offset, "__compound_literal$", 19) == 0) return 0; for (i = 0; special_symbols[i]; i++) @@ -550,8 +543,10 @@ int main(int argc, char **argv) usage(); read_map(stdin); - sort_symbols(); - optimize_token_table(); + if (table_cnt) { + sort_symbols(); + optimize_token_table(); + } write_src(); return 0; diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile index fa1a7d565903..fa8c2dd9c983 100644 --- a/scripts/kconfig/Makefile +++ b/scripts/kconfig/Makefile @@ -4,7 +4,11 @@ PHONY += oldconfig xconfig gconfig menuconfig config silentoldconfig update-po-config +ifdef KBUILD_KCONFIG +Kconfig := $(KBUILD_KCONFIG) +else Kconfig := arch/$(SRCARCH)/Kconfig +endif xconfig: $(obj)/qconf $< $(Kconfig) diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index b91cf241a539..830d9eae11f9 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -852,8 +852,7 @@ void conf_set_all_new_symbols(enum conf_def_mode mode) } - if (modules_sym) - sym_calc_value(modules_sym); + sym_clear_all_valid(); if (mode != def_random) return; diff --git a/scripts/kconfig/lxdialog/check-lxdialog.sh b/scripts/kconfig/lxdialog/check-lxdialog.sh index 5552154cbedb..fcef0f59d553 100644 --- a/scripts/kconfig/lxdialog/check-lxdialog.sh +++ b/scripts/kconfig/lxdialog/check-lxdialog.sh @@ -52,7 +52,7 @@ EOF } usage() { - printf "Usage: $0 [-check compiler options|-header|-library]\n" + printf "Usage: $0 [-check compiler options|-ccflags|-ldflags compiler options]\n" } if [ $# -eq 0 ]; then diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 44ee94d2ab76..8bb83a100edb 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -289,6 +289,8 @@ my %parameterdescs; my @parameterlist; my %sections; my @sectionlist; +my $sectcheck; +my $struct_actual; my $contents = ""; my $section_default = "Description"; # default section @@ -378,6 +380,12 @@ sub dump_section { # print STDERR "parameter def '$1' = '$contents'\n"; $name = $1; $parameterdescs{$name} = $contents; + $sectcheck = $sectcheck . $name . " "; + } elsif ($name eq "@\.\.\.") { +# print STDERR "parameter def '...' = '$contents'\n"; + $name = "..."; + $parameterdescs{$name} = $contents; + $sectcheck = $sectcheck . $name . " "; } else { # print STDERR "other section '$name' = '$contents'\n"; if (defined($sections{$name}) && ($sections{$name} ne "")) { @@ -1401,21 +1409,25 @@ sub dump_union($$) { sub dump_struct($$) { my $x = shift; my $file = shift; + my $nested; if ($x =~/(struct|union)\s+(\w+)\s*{(.*)}/) { $declaration_name = $2; my $members = $3; # ignore embedded structs or unions - $members =~ s/{.*}//g; + $members =~ s/({.*})//g; + $nested = $1; # ignore members marked private: $members =~ s/\/\*.*?private:.*?public:.*?\*\///gos; $members =~ s/\/\*.*?private:.*//gos; # strip comments: $members =~ s/\/\*.*?\*\///gos; + $nested =~ s/\/\*.*?\*\///gos; create_parameterlist($members, ';', $file); + check_sections($file, $declaration_name, "struct", $sectcheck, $struct_actual, $nested); output_declaration($declaration_name, 'struct', @@ -1501,6 +1513,14 @@ sub dump_typedef($$) { } } +sub save_struct_actual($) { + my $actual = shift; + + # strip all spaces from the actual param so that it looks like one string item + $actual =~ s/\s*//g; + $struct_actual = $struct_actual . $actual . " "; +} + sub create_parameterlist($$$) { my $args = shift; my $splitter = shift; @@ -1533,6 +1553,7 @@ sub create_parameterlist($$$) { $param = $1; $type = $arg; $type =~ s/([^\(]+\(\*?)\s*$param/$1/; + save_struct_actual($param); push_parameter($param, $type, $file); } elsif ($arg) { $arg =~ s/\s*:\s*/:/g; @@ -1557,14 +1578,17 @@ sub create_parameterlist($$$) { foreach $param (@args) { if ($param =~ m/^(\*+)\s*(.*)/) { + save_struct_actual($2); push_parameter($2, "$type $1", $file); } elsif ($param =~ m/(.*?):(\d+)/) { if ($type ne "") { # skip unnamed bit-fields + save_struct_actual($1); push_parameter($1, "$type:$2", $file) } } else { + save_struct_actual($param); push_parameter($param, $type, $file); } } @@ -1588,12 +1612,12 @@ sub push_parameter($$$) { if ($type eq "" && $param =~ /\.\.\.$/) { - $type=""; - $parameterdescs{$param} = "variable arguments"; + if (!defined $parameterdescs{$param} || $parameterdescs{$param} eq "") { + $parameterdescs{$param} = "variable arguments"; + } } elsif ($type eq "" && ($param eq "" or $param eq "void")) { - $type=""; $param="void"; $parameterdescs{void} = "no arguments"; } @@ -1630,6 +1654,46 @@ sub push_parameter($$$) { $parametertypes{$param} = $type; } +sub check_sections($$$$$$) { + my ($file, $decl_name, $decl_type, $sectcheck, $prmscheck, $nested) = @_; + my @sects = split ' ', $sectcheck; + my @prms = split ' ', $prmscheck; + my $err; + my ($px, $sx); + my $prm_clean; # strip trailing "[array size]" and/or beginning "*" + + foreach $sx (0 .. $#sects) { + $err = 1; + foreach $px (0 .. $#prms) { + $prm_clean = $prms[$px]; + $prm_clean =~ s/\[.*\]//; + $prm_clean =~ s/__attribute__\s*\(\([a-z,_\*\s\(\)]*\)\)//; + ##$prm_clean =~ s/^\**//; + if ($prm_clean eq $sects[$sx]) { + $err = 0; + last; + } + } + if ($err) { + if ($decl_type eq "function") { + print STDERR "Warning(${file}:$.): " . + "Excess function parameter " . + "'$sects[$sx]' " . + "description in '$decl_name'\n"; + ++$warnings; + } else { + if ($nested !~ m/\Q$sects[$sx]\E/) { + print STDERR "Warning(${file}:$.): " . + "Excess struct/union/enum/typedef member " . + "'$sects[$sx]' " . + "description in '$decl_name'\n"; + ++$warnings; + } + } + } + } +} + ## # takes a function prototype and the name of the current file being # processed and spits out all the details stored in the global @@ -1648,7 +1712,7 @@ sub dump_function($$) { $prototype =~ s/^noinline +//; $prototype =~ s/__devinit +//; $prototype =~ s/__init +//; - $prototype =~ s/^#define\s+//; #ak added + $prototype =~ s/^#\s*define\s+//; #ak added $prototype =~ s/__attribute__\s*\(\([a-z,]*\)\)//; # Yes, this truly is vile. We are looking for: @@ -1695,6 +1759,9 @@ sub dump_function($$) { return; } + my $prms = join " ", @parameterlist; + check_sections($file, $declaration_name, "function", $sectcheck, $prms, ""); + output_declaration($declaration_name, 'function', {'function' => $declaration_name, @@ -1753,6 +1820,8 @@ sub reset_state { @parameterlist = (); %sections = (); @sectionlist = (); + $sectcheck = ""; + $struct_actual = ""; $prototype = ""; $state = 0; @@ -1764,13 +1833,13 @@ sub process_state3_function($$) { $x =~ s@\/\/.*$@@gos; # strip C99-style comments to end of line - if ($x =~ m#\s*/\*\s+MACDOC\s*#io || ($x =~ /^#/ && $x !~ /^#define/)) { + if ($x =~ m#\s*/\*\s+MACDOC\s*#io || ($x =~ /^#/ && $x !~ /^#\s*define/)) { # do nothing } elsif ($x =~ /([^\{]*)/) { $prototype .= $1; } - if (($x =~ /\{/) || ($x =~ /\#define/) || ($x =~ /;/)) { + if (($x =~ /\{/) || ($x =~ /\#\s*define/) || ($x =~ /;/)) { $prototype =~ s@/\*.*?\*/@@gos; # strip comments. $prototype =~ s@[\r\n]+@ @gos; # strip newlines/cr's. $prototype =~ s@^\s+@@gos; # strip leading spaces diff --git a/scripts/mkcompile_h b/scripts/mkcompile_h index a8740df07b09..6a12dd9f1181 100755 --- a/scripts/mkcompile_h +++ b/scripts/mkcompile_h @@ -4,6 +4,8 @@ SMP=$3 PREEMPT=$4 CC=$5 +vecho() { [ "${quiet}" = "silent_" ] || echo "$@" ; } + # If compile.h exists already and we don't own autoconf.h # (i.e. we're not the same user who did make *config), don't # modify compile.h @@ -11,7 +13,7 @@ CC=$5 # do "compiled by root" if [ -r $TARGET -a ! -O include/linux/autoconf.h ]; then - echo " SKIPPED $TARGET" + vecho " SKIPPED $TARGET" exit 0 fi @@ -89,7 +91,7 @@ if [ -r $TARGET ] && \ cmp -s .tmpver.1 .tmpver.2; then rm -f .tmpcompile else - echo " UPD $TARGET" + vecho " UPD $TARGET" mv -f .tmpcompile $TARGET fi rm -f .tmpver.1 .tmpver.2 diff --git a/scripts/mkmakefile b/scripts/mkmakefile index e65d8b33faa4..67d59c7a18dc 100644 --- a/scripts/mkmakefile +++ b/scripts/mkmakefile @@ -17,7 +17,9 @@ if test -e $2/Makefile && ! grep -q Automatically $2/Makefile then exit 0 fi -echo " GEN $2/Makefile" +if [ "${quiet}" != "silent_" ]; then + echo " GEN $2/Makefile" +fi cat << EOF > $2/Makefile # Automatically generated by $0: don't edit diff --git a/scripts/mksysmap b/scripts/mksysmap index 6e133a0bae7a..1db316a3712b 100644 --- a/scripts/mksysmap +++ b/scripts/mksysmap @@ -37,9 +37,6 @@ # readprofile starts reading symbols when _stext is found, and # continue until it finds a symbol which is not either of 'T', 't', -# 'W' or 'w'. __crc_ are 'A' and placed in the middle -# so we just ignore them to let readprofile continue to work. -# (At least sparc64 has __crc_ in the middle). - -$NM -n $1 | grep -v '\( [aNUw] \)\|\(__crc_\)\|\( \$[adt]\)' > $2 +# 'W' or 'w'. +$NM -n $1 | grep -v '\( [aNUw] \)\|\( \$[adt]\)' > $2 diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 8e0de6a5e18a..88921611b22e 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -1726,6 +1726,14 @@ static void add_header(struct buffer *b, struct module *mod) buf_printf(b, "};\n"); } +void add_staging_flag(struct buffer *b, const char *name) +{ + static const char *staging_dir = "drivers/staging"; + + if (strncmp(staging_dir, name, strlen(staging_dir)) == 0) + buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n"); +} + /** * Record CRCs for unresolved symbols **/ @@ -2135,6 +2143,7 @@ int main(int argc, char **argv) buf.pos = 0; add_header(&buf, mod); + add_staging_flag(&buf, mod->name); err |= add_versions(&buf, mod); add_depends(&buf, mod, modules); add_moddevtable(&buf, mod); diff --git a/scripts/mod/sumversion.c b/scripts/mod/sumversion.c index d9cc6901d680..aadc5223dcdb 100644 --- a/scripts/mod/sumversion.c +++ b/scripts/mod/sumversion.c @@ -290,6 +290,15 @@ static int parse_file(const char *fname, struct md4_ctx *md) release_file(file, len); return 1; } +/* Check whether the file is a static library or not */ +static int is_static_library(const char *objfile) +{ + int len = strlen(objfile); + if (objfile[len - 2] == '.' && objfile[len - 1] == 'a') + return 1; + else + return 0; +} /* We have dir/file.o. Open dir/.file.o.cmd, look for deps_ line to * figure out source file. */ @@ -420,7 +429,8 @@ void get_src_version(const char *modname, char sum[], unsigned sumlen) while ((fname = strsep(&sources, " ")) != NULL) { if (!*fname) continue; - if (!parse_source_files(fname, &md)) + if (!(is_static_library(fname)) && + !parse_source_files(fname, &md)) goto release; } diff --git a/scripts/package/Makefile b/scripts/package/Makefile index 5e326078a4a2..8c6b7b09606a 100644 --- a/scripts/package/Makefile +++ b/scripts/package/Makefile @@ -1,10 +1,6 @@ # Makefile for the different targets used to generate full packages of a kernel # It uses the generic clean infrastructure of kbuild -# Ignore the following files/directories during tar operation -TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn --exclude CVS - - # RPM target # --------------------------------------------------------------------------- # The rpm target generates two rpm files: @@ -47,7 +43,7 @@ rpm-pkg rpm: $(objtree)/kernel.spec FORCE set -e; \ mv -f $(objtree)/.tmp_version $(objtree)/.version - $(RPM) --target $(UTS_MACHINE) -ta ../$(KERNELPATH).tar.gz + $(RPM) $(RPMOPTS) --target $(UTS_MACHINE) -ta ../$(KERNELPATH).tar.gz rm ../$(KERNELPATH).tar.gz clean-files := $(objtree)/kernel.spec @@ -64,7 +60,8 @@ binrpm-pkg: $(objtree)/binkernel.spec FORCE set -e; \ mv -f $(objtree)/.tmp_version $(objtree)/.version - $(RPM) --define "_builddir $(srctree)" --target $(UTS_MACHINE) -bb $< + $(RPM) $(RPMOPTS) --define "_builddir $(srctree)" --target \ + $(UTS_MACHINE) -bb $< clean-files += $(objtree)/binkernel.spec diff --git a/scripts/package/builddeb b/scripts/package/builddeb index ba6bf5d5abf9..1264b8e2829d 100644 --- a/scripts/package/builddeb +++ b/scripts/package/builddeb @@ -15,15 +15,18 @@ set -e version=$KERNELRELEASE revision=`cat .version` tmpdir="$objtree/debian/tmp" +fwdir="$objtree/debian/fwtmp" packagename=linux-$version +fwpackagename=linux-firmware-image if [ "$ARCH" == "um" ] ; then packagename=user-mode-linux-$version fi # Setup the directory structure -rm -rf "$tmpdir" +rm -rf "$tmpdir" "$fwdir" mkdir -p "$tmpdir/DEBIAN" "$tmpdir/lib" "$tmpdir/boot" +mkdir -p "$fwdir/DEBIAN" "$fwdir/lib" if [ "$ARCH" == "um" ] ; then mkdir -p "$tmpdir/usr/lib/uml/modules/$version" "$tmpdir/usr/share/doc/$packagename" "$tmpdir/usr/bin" fi @@ -107,6 +110,7 @@ Standards-Version: 3.6.1 Package: $packagename Provides: kernel-image-$version, linux-image-$version +Suggests: $fwpackagename Architecture: any Description: Linux kernel, version $version This package contains the Linux kernel, modules and corresponding other @@ -118,8 +122,24 @@ fi chown -R root:root "$tmpdir" chmod -R go-w "$tmpdir" +# Do we have firmware? Move it out of the way and build it into a package. +if [ -e "$tmpdir/lib/firmware" ]; then + mv "$tmpdir/lib/firmware" "$fwdir/lib/" + + cat <<EOF >> debian/control + +Package: $fwpackagename +Architecture: all +Description: Linux kernel firmware, version $version + This package contains firmware from the Linux kernel, version $version +EOF + + dpkg-gencontrol -isp -p$fwpackagename -P"$fwdir" + dpkg --build "$fwdir" .. +fi + # Perform the final magic -dpkg-gencontrol -isp +dpkg-gencontrol -isp -p$packagename dpkg --build "$tmpdir" .. exit 0 diff --git a/scripts/package/mkspec b/scripts/package/mkspec index ffd61fe0c1ad..2500886fb90a 100755 --- a/scripts/package/mkspec +++ b/scripts/package/mkspec @@ -57,15 +57,17 @@ fi echo "%build" if ! $PREBUILT; then -echo "make clean && make %{_smp_mflags}" +echo "make clean && make %{?_smp_mflags}" echo "" fi echo "%install" echo "%ifarch ia64" echo 'mkdir -p $RPM_BUILD_ROOT/boot/efi $RPM_BUILD_ROOT/lib/modules' +echo 'mkdir -p $RPM_BUILD_ROOT/lib/firmware' echo "%else" echo 'mkdir -p $RPM_BUILD_ROOT/boot $RPM_BUILD_ROOT/lib/modules' +echo 'mkdir -p $RPM_BUILD_ROOT/lib/firmware' echo "%endif" echo 'INSTALL_MOD_PATH=$RPM_BUILD_ROOT make %{_smp_mflags} modules_install' @@ -92,5 +94,6 @@ echo "%files" echo '%defattr (-, root, root)' echo "%dir /lib/modules" echo "/lib/modules/$KERNELRELEASE" +echo "/lib/firmware" echo "/boot/*" echo "" diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl new file mode 100755 index 000000000000..fe831412bea9 --- /dev/null +++ b/scripts/recordmcount.pl @@ -0,0 +1,450 @@ +#!/usr/bin/perl -w +# (c) 2008, Steven Rostedt <srostedt@redhat.com> +# Licensed under the terms of the GNU GPL License version 2 +# +# recordmcount.pl - makes a section called __mcount_loc that holds +# all the offsets to the calls to mcount. +# +# +# What we want to end up with is a section in vmlinux called +# __mcount_loc that contains a list of pointers to all the +# call sites in the kernel that call mcount. Later on boot up, the kernel +# will read this list, save the locations and turn them into nops. +# When tracing or profiling is later enabled, these locations will then +# be converted back to pointers to some function. +# +# This is no easy feat. This script is called just after the original +# object is compiled and before it is linked. +# +# The references to the call sites are offsets from the section of text +# that the call site is in. Hence, all functions in a section that +# has a call site to mcount, will have the offset from the beginning of +# the section and not the beginning of the function. +# +# The trick is to find a way to record the beginning of the section. +# The way we do this is to look at the first function in the section +# which will also be the location of that section after final link. +# e.g. +# +# .section ".text.sched" +# .globl my_func +# my_func: +# [...] +# call mcount (offset: 0x5) +# [...] +# ret +# other_func: +# [...] +# call mcount (offset: 0x1b) +# [...] +# +# Both relocation offsets for the mcounts in the above example will be +# offset from .text.sched. If we make another file called tmp.s with: +# +# .section __mcount_loc +# .quad my_func + 0x5 +# .quad my_func + 0x1b +# +# We can then compile this tmp.s into tmp.o, and link it to the original +# object. +# +# But this gets hard if my_func is not globl (a static function). +# In such a case we have: +# +# .section ".text.sched" +# my_func: +# [...] +# call mcount (offset: 0x5) +# [...] +# ret +# .globl my_func +# other_func: +# [...] +# call mcount (offset: 0x1b) +# [...] +# +# If we make the tmp.s the same as above, when we link together with +# the original object, we will end up with two symbols for my_func: +# one local, one global. After final compile, we will end up with +# an undefined reference to my_func. +# +# Since local objects can reference local variables, we need to find +# a way to make tmp.o reference the local objects of the original object +# file after it is linked together. To do this, we convert the my_func +# into a global symbol before linking tmp.o. Then after we link tmp.o +# we will only have a single symbol for my_func that is global. +# We can convert my_func back into a local symbol and we are done. +# +# Here are the steps we take: +# +# 1) Record all the local symbols by using 'nm' +# 2) Use objdump to find all the call site offsets and sections for +# mcount. +# 3) Compile the list into its own object. +# 4) Do we have to deal with local functions? If not, go to step 8. +# 5) Make an object that converts these local functions to global symbols +# with objcopy. +# 6) Link together this new object with the list object. +# 7) Convert the local functions back to local symbols and rename +# the result as the original object. +# End. +# 8) Link the object with the list object. +# 9) Move the result back to the original object. +# End. +# + +use strict; + +my $P = $0; +$P =~ s@.*/@@g; + +my $V = '0.1'; + +if ($#ARGV < 6) { + print "usage: $P arch objdump objcopy cc ld nm rm mv inputfile\n"; + print "version: $V\n"; + exit(1); +} + +my ($arch, $bits, $objdump, $objcopy, $cc, + $ld, $nm, $rm, $mv, $inputfile) = @ARGV; + +# Acceptable sections to record. +my %text_sections = ( + ".text" => 1, + ".sched.text" => 1, + ".spinlock.text" => 1, + ".irqentry.text" => 1, +); + +$objdump = "objdump" if ((length $objdump) == 0); +$objcopy = "objcopy" if ((length $objcopy) == 0); +$cc = "gcc" if ((length $cc) == 0); +$ld = "ld" if ((length $ld) == 0); +$nm = "nm" if ((length $nm) == 0); +$rm = "rm" if ((length $rm) == 0); +$mv = "mv" if ((length $mv) == 0); + +#print STDERR "running: $P '$arch' '$objdump' '$objcopy' '$cc' '$ld' " . +# "'$nm' '$rm' '$mv' '$inputfile'\n"; + +my %locals; # List of local (static) functions +my %weak; # List of weak functions +my %convert; # List of local functions used that needs conversion + +my $type; +my $nm_regex; # Find the local functions (return function) +my $section_regex; # Find the start of a section +my $function_regex; # Find the name of a function + # (return offset and func name) +my $mcount_regex; # Find the call site to mcount (return offset) +my $alignment; # The .align value to use for $mcount_section +my $section_type; # Section header plus possible alignment command + +if ($arch eq "x86") { + if ($bits == 64) { + $arch = "x86_64"; + } else { + $arch = "i386"; + } +} + +# +# We base the defaults off of i386, the other archs may +# feel free to change them in the below if statements. +# +$nm_regex = "^[0-9a-fA-F]+\\s+t\\s+(\\S+)"; +$section_regex = "Disassembly of section\\s+(\\S+):"; +$function_regex = "^([0-9a-fA-F]+)\\s+<(.*?)>:"; +$mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\smcount\$"; +$section_type = '@progbits'; +$type = ".long"; + +if ($arch eq "x86_64") { + $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\smcount([+-]0x[0-9a-zA-Z]+)?\$"; + $type = ".quad"; + $alignment = 8; + + # force flags for this arch + $ld .= " -m elf_x86_64"; + $objdump .= " -M x86-64"; + $objcopy .= " -O elf64-x86-64"; + $cc .= " -m64"; + +} elsif ($arch eq "i386") { + $alignment = 4; + + # force flags for this arch + $ld .= " -m elf_i386"; + $objdump .= " -M i386"; + $objcopy .= " -O elf32-i386"; + $cc .= " -m32"; + +} elsif ($arch eq "sh") { + $alignment = 2; + + # force flags for this arch + $ld .= " -m shlelf_linux"; + $objcopy .= " -O elf32-sh-linux"; + $cc .= " -m32"; + +} elsif ($arch eq "powerpc") { + $nm_regex = "^[0-9a-fA-F]+\\s+t\\s+(\\.?\\S+)"; + $function_regex = "^([0-9a-fA-F]+)\\s+<(\\.?.*?)>:"; + $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s\\.?_mcount\$"; + + if ($bits == 64) { + $type = ".quad"; + } + +} elsif ($arch eq "arm") { + $alignment = 2; + $section_type = '%progbits'; + +} else { + die "Arch $arch is not supported with CONFIG_FTRACE_MCOUNT_RECORD"; +} + +my $text_found = 0; +my $read_function = 0; +my $opened = 0; +my $mcount_section = "__mcount_loc"; + +my $dirname; +my $filename; +my $prefix; +my $ext; + +if ($inputfile =~ m,^(.*)/([^/]*)$,) { + $dirname = $1; + $filename = $2; +} else { + $dirname = "."; + $filename = $inputfile; +} + +if ($filename =~ m,^(.*)(\.\S),) { + $prefix = $1; + $ext = $2; +} else { + $prefix = $filename; + $ext = ""; +} + +my $mcount_s = $dirname . "/.tmp_mc_" . $prefix . ".s"; +my $mcount_o = $dirname . "/.tmp_mc_" . $prefix . ".o"; + +# +# --globalize-symbols came out in 2.17, we must test the version +# of objcopy, and if it is less than 2.17, then we can not +# record local functions. +my $use_locals = 01; +my $local_warn_once = 0; +my $found_version = 0; + +open (IN, "$objcopy --version |") || die "error running $objcopy"; +while (<IN>) { + if (/objcopy.*\s(\d+)\.(\d+)/) { + my $major = $1; + my $minor = $2; + + $found_version = 1; + if ($major < 2 || + ($major == 2 && $minor < 17)) { + $use_locals = 0; + } + last; + } +} +close (IN); + +if (!$found_version) { + print STDERR "WARNING: could not find objcopy version.\n" . + "\tDisabling local function references.\n"; +} + + +# +# Step 1: find all the local (static functions) and weak symbols. +# 't' is local, 'w/W' is weak (we never use a weak function) +# +open (IN, "$nm $inputfile|") || die "error running $nm"; +while (<IN>) { + if (/$nm_regex/) { + $locals{$1} = 1; + } elsif (/^[0-9a-fA-F]+\s+([wW])\s+(\S+)/) { + $weak{$2} = $1; + } +} +close(IN); + +my @offsets; # Array of offsets of mcount callers +my $ref_func; # reference function to use for offsets +my $offset = 0; # offset of ref_func to section beginning + +## +# update_funcs - print out the current mcount callers +# +# Go through the list of offsets to callers and write them to +# the output file in a format that can be read by an assembler. +# +sub update_funcs +{ + return if ($#offsets < 0); + + defined($ref_func) || die "No function to reference"; + + # A section only had a weak function, to represent it. + # Unfortunately, a weak function may be overwritten by another + # function of the same name, making all these offsets incorrect. + # To be safe, we simply print a warning and bail. + if (defined $weak{$ref_func}) { + print STDERR + "$inputfile: WARNING: referencing weak function" . + " $ref_func for mcount\n"; + return; + } + + # is this function static? If so, note this fact. + if (defined $locals{$ref_func}) { + + # only use locals if objcopy supports globalize-symbols + if (!$use_locals) { + return; + } + $convert{$ref_func} = 1; + } + + # Loop through all the mcount caller offsets and print a reference + # to the caller based from the ref_func. + for (my $i=0; $i <= $#offsets; $i++) { + if (!$opened) { + open(FILE, ">$mcount_s") || die "can't create $mcount_s\n"; + $opened = 1; + print FILE "\t.section $mcount_section,\"a\",$section_type\n"; + print FILE "\t.align $alignment\n" if (defined($alignment)); + } + printf FILE "\t%s %s + %d\n", $type, $ref_func, $offsets[$i] - $offset; + } +} + +# +# Step 2: find the sections and mcount call sites +# +open(IN, "$objdump -dr $inputfile|") || die "error running $objdump"; + +my $text; + +while (<IN>) { + # is it a section? + if (/$section_regex/) { + + # Only record text sections that we know are safe + if (defined($text_sections{$1})) { + $read_function = 1; + } else { + $read_function = 0; + } + # print out any recorded offsets + update_funcs() if ($text_found); + + # reset all markers and arrays + $text_found = 0; + undef($ref_func); + undef(@offsets); + + # section found, now is this a start of a function? + } elsif ($read_function && /$function_regex/) { + $text_found = 1; + $offset = hex $1; + $text = $2; + + # if this is either a local function or a weak function + # keep looking for functions that are global that + # we can use safely. + if (!defined($locals{$text}) && !defined($weak{$text})) { + $ref_func = $text; + $read_function = 0; + } else { + # if we already have a function, and this is weak, skip it + if (!defined($ref_func) || !defined($weak{$text})) { + $ref_func = $text; + } + } + } + + # is this a call site to mcount? If so, record it to print later + if ($text_found && /$mcount_regex/) { + $offsets[$#offsets + 1] = hex $1; + } +} + +# dump out anymore offsets that may have been found +update_funcs() if ($text_found); + +# If we did not find any mcount callers, we are done (do nothing). +if (!$opened) { + exit(0); +} + +close(FILE); + +# +# Step 3: Compile the file that holds the list of call sites to mcount. +# +`$cc -o $mcount_o -c $mcount_s`; + +my @converts = keys %convert; + +# +# Step 4: Do we have sections that started with local functions? +# +if ($#converts >= 0) { + my $globallist = ""; + my $locallist = ""; + + foreach my $con (@converts) { + $globallist .= " --globalize-symbol $con"; + $locallist .= " --localize-symbol $con"; + } + + my $globalobj = $dirname . "/.tmp_gl_" . $filename; + my $globalmix = $dirname . "/.tmp_mx_" . $filename; + + # + # Step 5: set up each local function as a global + # + `$objcopy $globallist $inputfile $globalobj`; + + # + # Step 6: Link the global version to our list. + # + `$ld -r $globalobj $mcount_o -o $globalmix`; + + # + # Step 7: Convert the local functions back into local symbols + # + `$objcopy $locallist $globalmix $inputfile`; + + # Remove the temp files + `$rm $globalobj $globalmix`; + +} else { + + my $mix = $dirname . "/.tmp_mx_" . $filename; + + # + # Step 8: Link the object with our list of call sites object. + # + `$ld -r $inputfile $mcount_o -o $mix`; + + # + # Step 9: Move the result back to the original object. + # + `$mv $mix $inputfile`; +} + +# Clean up the temp files +`$rm $mcount_o $mcount_s`; + +exit(0); diff --git a/scripts/setlocalversion b/scripts/setlocalversion index 83b75126c9f7..f6946cf99ce1 100755 --- a/scripts/setlocalversion +++ b/scripts/setlocalversion @@ -9,14 +9,21 @@ usage() { cd "${1:-.}" || usage # Check for git and a git repo. -if head=`git rev-parse --verify HEAD 2>/dev/null`; then +if head=`git rev-parse --verify --short HEAD 2>/dev/null`; then # Do we have an untagged version? if git name-rev --tags HEAD | grep -E '^HEAD[[:space:]]+(.*~[0-9]*|undefined)$' > /dev/null; then if tag=`git describe 2>/dev/null`; then echo $tag | awk -F- '{printf("-%05d-%s", $(NF-1),$(NF))}' + else + printf '%s%s' -g $head fi fi + # Is this git on svn? + if git config --get svn-remote.svn.url >/dev/null; then + printf -- '-svn%s' "`git-svn find-rev $head`" + fi + # Are there uncommitted changes? git update-index --refresh --unmerged > /dev/null if git diff-index --name-only HEAD | grep -v "^scripts/package" \ @@ -49,13 +56,13 @@ if hgid=`hg id 2>/dev/null`; then fi # Check for svn and a svn repo. -if rev=`svn info 2>/dev/null | grep '^Revision'`; then +if rev=`svn info 2>/dev/null | grep '^Last Changed Rev'`; then rev=`echo $rev | awk '{print $NF}'` changes=`svn status 2>/dev/null | grep '^[AMD]' | wc -l` # Are there uncommitted changes? if [ $changes != 0 ]; then - printf -- '-svn%s%s%s' "$rev" -dirty "$changes" + printf -- '-svn%s%s' "$rev" -dirty else printf -- '-svn%s' "$rev" fi diff --git a/scripts/strip-symbols b/scripts/strip-symbols new file mode 100644 index 000000000000..29ee8c1a014b --- /dev/null +++ b/scripts/strip-symbols @@ -0,0 +1,22 @@ +<*> +*.h +__compound_literal[$.][0-9]* +__crc_[a-zA-Z_]* +__exitcall_[a-zA-Z_]* +__func__[$.][0-9]* +__FUNCTION__[$.][0-9]* +gcc[0-9]_compiled[$.] +__initcall_[a-zA-Z_]* +__kcrctab_[a-zA-Z_]* +__kstrtab_[a-zA-Z_]* +__ksymtab_[a-zA-Z_]* +__mod_[a-zA-Z_]*[0-9] +__module_depends +__param_[a-zA-Z_]* +__pci_fixup_*PCI_ANY_IDPCI_ANY_ID* +__pci_fixup_*PCI_ANY_IDPCI_DEVICE_ID_* +__pci_fixup_*PCI_VENDOR_ID_*PCI_ANY_ID* +__pci_fixup_*PCI_VENDOR_ID_*PCI_DEVICE_ID_* +__PRETTY_FUNCTION__[$.][0-9]* +__setup_[a-zA-Z_]* +____versions diff --git a/scripts/tags.sh b/scripts/tags.sh new file mode 100755 index 000000000000..4e7547209852 --- /dev/null +++ b/scripts/tags.sh @@ -0,0 +1,160 @@ +#!/bin/sh +# Generate tags or cscope files +# Usage tags.sh <mode> +# +# mode may be any of: tags, TAGS, cscope +# +# Uses the following environment variables: +# ARCH, SUBARCH, srctree, src, obj + +if [ "$KBUILD_VERBOSE" = "1" ]; then + set -x +fi + +# This is a duplicate of RCS_FIND_IGNORE without escaped '()' +ignore="( -name SCCS -o -name BitKeeper -o -name .svn -o \ + -name CVS -o -name .pc -o -name .hg -o \ + -name .git ) \ + -prune -o" + +# Do not use full path is we do not use O=.. builds +if [ "${KBUILD_SRC}" = "" ]; then + tree= +else + tree=${srctree}/ +fi + +# find sources in arch/$ARCH +find_arch_sources() +{ + find ${tree}arch/$1 $ignore -name "$2" -print; +} + +# find sources in arch/$1/include +find_arch_include_sources() +{ + find ${tree}arch/$1/include $ignore -name "$2" -print; +} + +# find sources in include/ +find_include_sources() +{ + find ${tree}include $ignore -name config -prune -o -name "$1" -print; +} + +# find sources in rest of tree +# we could benefit from a list of dirs to search in here +find_other_sources() +{ + find ${tree}* $ignore \ + \( -name include -o -name arch -o -name '.tmp_*' \) -prune -o \ + -name "$1" -print; +} + +find_sources() +{ + find_arch_sources $1 "$2" + find_include_sources "$2" + find_other_sources "$2" +} + +all_sources() +{ + find_sources $SRCARCH '*.[chS]' + if [ ! -z "$archinclude" ]; then + find_arch_include_sources $archinclude '*.[chS]' + fi +} + +all_kconfigs() +{ + find_sources $SRCARCH 'Kconfig*' +} + +all_defconfigs() +{ + find_sources $SRCARCH "defconfig" +} + +docscope() +{ + (echo \-k; echo \-q; all_sources) > cscope.files + cscope -b -f cscope.out +} + +exuberant() +{ + all_sources > all + all_sources | xargs $1 -a \ + -I __initdata,__exitdata,__acquires,__releases \ + -I __read_mostly,____cacheline_aligned \ + -I ____cacheline_aligned_in_smp \ + -I ____cacheline_internodealigned_in_smp \ + -I EXPORT_SYMBOL,EXPORT_SYMBOL_GPL \ + --extra=+f --c-kinds=+px \ + --regex-asm='/^ENTRY\(([^)]*)\).*/\1/' + + all_kconfigs | xargs $1 -a \ + --langdef=kconfig --language-force=kconfig \ + --regex-kconfig='/^[[:blank:]]*(menu|)config[[:blank:]]+([[:alnum:]_]+)/\2/' + + all_kconfigs | xargs $1 -a \ + --langdef=kconfig --language-force=kconfig \ + --regex-kconfig='/^[[:blank:]]*(menu|)config[[:blank:]]+([[:alnum:]_]+)/CONFIG_\2/' + + all_defconfigs | xargs -r $1 -a \ + --langdef=dotconfig --language-force=dotconfig \ + --regex-dotconfig='/^#?[[:blank:]]*(CONFIG_[[:alnum:]_]+)/\1/' + +} + +emacs() +{ + all_sources | xargs $1 -a + + all_kconfigs | xargs $1 -a \ + --regex='/^[ \t]*\(\(menu\)*config\)[ \t]+\([a-zA-Z0-9_]+\)/\3/' + + all_kconfigs | xargs $1 -a \ + --regex='/^[ \t]*\(\(menu\)*config\)[ \t]+\([a-zA-Z0-9_]+\)/CONFIG_\3/' + + all_defconfigs | xargs -r $1 -a \ + --regex='/^#?[ \t]?\(CONFIG_[a-zA-Z0-9_]+\)/\1/' +} + +xtags() +{ + if $1 --version 2>&1 | grep -iq exuberant; then + exuberant $1 + elif $1 --version 2>&1 | grep -iq emacs; then + emacs $1 + else + all_sources | xargs $1 -a + fi +} + + +# Support um (which uses SUBARCH) +if [ "${ARCH}" = "um" ]; then + if [ "$SUBARCH" = "i386" ]; then + archinclude=x86 + elif [ "$SUBARCH" = "x86_64" ]; then + archinclude=x86 + else + archinclude=${SUBARCH} + fi +fi + +case "$1" in + "cscope") + docscope + ;; + + "tags") + xtags ctags + ;; + + "TAGS") + xtags etags + ;; +esac diff --git a/scripts/trace/power.pl b/scripts/trace/power.pl new file mode 100644 index 000000000000..4f729b3501e0 --- /dev/null +++ b/scripts/trace/power.pl @@ -0,0 +1,108 @@ +#!/usr/bin/perl + +# Copyright 2008, Intel Corporation +# +# This file is part of the Linux kernel +# +# This program file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# +# Authors: +# Arjan van de Ven <arjan@linux.intel.com> + + +# +# This script turns a cstate ftrace output into a SVG graphic that shows +# historic C-state information +# +# +# cat /sys/kernel/debug/tracing/trace | perl power.pl > out.svg +# + +my @styles; +my $base = 0; + +my @pstate_last; +my @pstate_level; + +$styles[0] = "fill:rgb(0,0,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)"; +$styles[1] = "fill:rgb(0,255,0);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)"; +$styles[2] = "fill:rgb(255,0,20);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)"; +$styles[3] = "fill:rgb(255,255,20);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)"; +$styles[4] = "fill:rgb(255,0,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)"; +$styles[5] = "fill:rgb(0,255,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)"; +$styles[6] = "fill:rgb(0,128,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)"; +$styles[7] = "fill:rgb(0,255,128);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)"; +$styles[8] = "fill:rgb(0,25,20);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)"; + + +print "<?xml version=\"1.0\" standalone=\"no\"?> \n"; +print "<svg width=\"10000\" height=\"100%\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n"; + +my $scale = 30000.0; +while (<>) { + my $line = $_; + if ($line =~ /([0-9\.]+)\] CSTATE: Going to C([0-9]) on cpu ([0-9]+) for ([0-9\.]+)/) { + if ($base == 0) { + $base = $1; + } + my $time = $1 - $base; + $time = $time * $scale; + my $C = $2; + my $cpu = $3; + my $y = 400 * $cpu; + my $duration = $4 * $scale; + my $msec = int($4 * 100000)/100.0; + my $height = $C * 20; + $style = $styles[$C]; + + $y = $y + 140 - $height; + + $x2 = $time + 4; + $y2 = $y + 4; + + + print "<rect x=\"$time\" width=\"$duration\" y=\"$y\" height=\"$height\" style=\"$style\"/>\n"; + print "<text transform=\"translate($x2,$y2) rotate(90)\">C$C $msec</text>\n"; + } + if ($line =~ /([0-9\.]+)\] PSTATE: Going to P([0-9]) on cpu ([0-9]+)/) { + my $time = $1 - $base; + my $state = $2; + my $cpu = $3; + + if (defined($pstate_last[$cpu])) { + my $from = $pstate_last[$cpu]; + my $oldstate = $pstate_state[$cpu]; + my $duration = ($time-$from) * $scale; + + $from = $from * $scale; + my $to = $from + $duration; + my $height = 140 - ($oldstate * (140/8)); + + my $y = 400 * $cpu + 200 + $height; + my $y2 = $y+4; + my $style = $styles[8]; + + print "<rect x=\"$from\" y=\"$y\" width=\"$duration\" height=\"5\" style=\"$style\"/>\n"; + print "<text transform=\"translate($from,$y2)\">P$oldstate (cpu $cpu)</text>\n"; + }; + + $pstate_last[$cpu] = $time; + $pstate_state[$cpu] = $state; + } +} + + +print "</svg>\n"; diff --git a/scripts/tracing/draw_functrace.py b/scripts/tracing/draw_functrace.py new file mode 100644 index 000000000000..902f9a992620 --- /dev/null +++ b/scripts/tracing/draw_functrace.py @@ -0,0 +1,130 @@ +#!/usr/bin/python + +""" +Copyright 2008 (c) Frederic Weisbecker <fweisbec@gmail.com> +Licensed under the terms of the GNU GPL License version 2 + +This script parses a trace provided by the function tracer in +kernel/trace/trace_functions.c +The resulted trace is processed into a tree to produce a more human +view of the call stack by drawing textual but hierarchical tree of +calls. Only the functions's names and the the call time are provided. + +Usage: + Be sure that you have CONFIG_FUNCTION_TRACER + # mkdir /debugfs + # mount -t debug debug /debug + # echo function > /debug/tracing/current_tracer + $ cat /debug/tracing/trace_pipe > ~/raw_trace_func + Wait some times but not too much, the script is a bit slow. + Break the pipe (Ctrl + Z) + $ scripts/draw_functrace.py < raw_trace_func > draw_functrace + Then you have your drawn trace in draw_functrace +""" + + +import sys, re + +class CallTree: + """ This class provides a tree representation of the functions + call stack. If a function has no parent in the kernel (interrupt, + syscall, kernel thread...) then it is attached to a virtual parent + called ROOT. + """ + ROOT = None + + def __init__(self, func, time = None, parent = None): + self._func = func + self._time = time + if parent is None: + self._parent = CallTree.ROOT + else: + self._parent = parent + self._children = [] + + def calls(self, func, calltime): + """ If a function calls another one, call this method to insert it + into the tree at the appropriate place. + @return: A reference to the newly created child node. + """ + child = CallTree(func, calltime, self) + self._children.append(child) + return child + + def getParent(self, func): + """ Retrieve the last parent of the current node that + has the name given by func. If this function is not + on a parent, then create it as new child of root + @return: A reference to the parent. + """ + tree = self + while tree != CallTree.ROOT and tree._func != func: + tree = tree._parent + if tree == CallTree.ROOT: + child = CallTree.ROOT.calls(func, None) + return child + return tree + + def __repr__(self): + return self.__toString("", True) + + def __toString(self, branch, lastChild): + if self._time is not None: + s = "%s----%s (%s)\n" % (branch, self._func, self._time) + else: + s = "%s----%s\n" % (branch, self._func) + + i = 0 + if lastChild: + branch = branch[:-1] + " " + while i < len(self._children): + if i != len(self._children) - 1: + s += "%s" % self._children[i].__toString(branch +\ + " |", False) + else: + s += "%s" % self._children[i].__toString(branch +\ + " |", True) + i += 1 + return s + +class BrokenLineException(Exception): + """If the last line is not complete because of the pipe breakage, + we want to stop the processing and ignore this line. + """ + pass + +class CommentLineException(Exception): + """ If the line is a comment (as in the beginning of the trace file), + just ignore it. + """ + pass + + +def parseLine(line): + line = line.strip() + if line.startswith("#"): + raise CommentLineException + m = re.match("[^]]+?\\] +([0-9.]+): (\\w+) <-(\\w+)", line) + if m is None: + raise BrokenLineException + return (m.group(1), m.group(2), m.group(3)) + + +def main(): + CallTree.ROOT = CallTree("Root (Nowhere)", None, None) + tree = CallTree.ROOT + + for line in sys.stdin: + try: + calltime, callee, caller = parseLine(line) + except BrokenLineException: + break + except CommentLineException: + continue + tree = tree.getParent(caller) + tree = tree.calls(callee, calltime) + + print CallTree.ROOT + +if __name__ == "__main__": + main() |
