diff options
Diffstat (limited to 'scripts')
-rwxr-xr-x | scripts/checkkconfigsymbols.py | 234 | ||||
-rwxr-xr-x | scripts/ld-version.sh | 4 | ||||
-rwxr-xr-x | scripts/link-vmlinux.sh | 2 | ||||
-rw-r--r-- | scripts/mod/file2alias.c | 2 | ||||
-rw-r--r-- | scripts/recordmcount.c | 137 |
5 files changed, 304 insertions, 75 deletions
diff --git a/scripts/checkkconfigsymbols.py b/scripts/checkkconfigsymbols.py index 2f4b7ffd5570..d8f6c094cce5 100755 --- a/scripts/checkkconfigsymbols.py +++ b/scripts/checkkconfigsymbols.py @@ -8,11 +8,14 @@ # Licensed under the terms of the GNU GPL License version 2 +import difflib import os import re +import signal import sys -from subprocess import Popen, PIPE, STDOUT +from multiprocessing import Pool, cpu_count from optparse import OptionParser +from subprocess import Popen, PIPE, STDOUT # regex expressions @@ -26,7 +29,7 @@ SOURCE_FEATURE = r"(?:\W|\b)+[D]{,1}CONFIG_(" + FEATURE + r")" # regex objects REGEX_FILE_KCONFIG = re.compile(r".*Kconfig[\.\w+\-]*$") -REGEX_FEATURE = re.compile(r'(?!\B"[^"]*)' + FEATURE + r'(?![^"]*"\B)') +REGEX_FEATURE = re.compile(r'(?!\B)' + FEATURE + r'(?!\B)') REGEX_SOURCE_FEATURE = re.compile(SOURCE_FEATURE) REGEX_KCONFIG_DEF = re.compile(DEF) REGEX_KCONFIG_EXPR = re.compile(EXPR) @@ -34,6 +37,7 @@ REGEX_KCONFIG_STMT = re.compile(STMT) REGEX_KCONFIG_HELP = re.compile(r"^\s+(help|---help---)\s*$") REGEX_FILTER_FEATURES = re.compile(r"[A-Za-z0-9]$") REGEX_NUMERIC = re.compile(r"0[xX][0-9a-fA-F]+|[0-9]+") +REGEX_QUOTES = re.compile("(\"(.*?)\")") def parse_options(): @@ -71,6 +75,9 @@ def parse_options(): "the pattern needs to be a Python regex. To " "ignore defconfigs, specify -i '.*defconfig'.") + parser.add_option('-s', '--sim', dest='sim', action='store', default="", + help="Print a list of maximum 10 string-similar symbols.") + parser.add_option('', '--force', dest='force', action='store_true', default=False, help="Reset current Git tree even when it's dirty.") @@ -109,6 +116,18 @@ def main(): """Main function of this module.""" opts = parse_options() + if opts.sim and not opts.commit and not opts.diff: + sims = find_sims(opts.sim, opts.ignore) + if sims: + print "%s: %s" % (yel("Similar symbols"), ', '.join(sims)) + else: + print "%s: no similar symbols found" % yel("Similar symbols") + sys.exit(0) + + # dictionary of (un)defined symbols + defined = {} + undefined = {} + if opts.commit or opts.diff: head = get_head() @@ -127,40 +146,56 @@ def main(): # get undefined items before the commit execute("git reset --hard %s" % commit_a) - undefined_a = check_symbols(opts.ignore) + undefined_a, _ = check_symbols(opts.ignore) # get undefined items for the commit execute("git reset --hard %s" % commit_b) - undefined_b = check_symbols(opts.ignore) + undefined_b, defined = check_symbols(opts.ignore) # report cases that are present for the commit but not before for feature in sorted(undefined_b): # feature has not been undefined before if not feature in undefined_a: files = sorted(undefined_b.get(feature)) - print "%s\t%s" % (yel(feature), ", ".join(files)) - if opts.find: - commits = find_commits(feature, opts.diff) - print red(commits) + undefined[feature] = files # check if there are new files that reference the undefined feature else: files = sorted(undefined_b.get(feature) - undefined_a.get(feature)) if files: - print "%s\t%s" % (yel(feature), ", ".join(files)) - if opts.find: - commits = find_commits(feature, opts.diff) - print red(commits) + undefined[feature] = files # reset to head execute("git reset --hard %s" % head) # default to check the entire tree else: - undefined = check_symbols(opts.ignore) - for feature in sorted(undefined): - files = sorted(undefined.get(feature)) - print "%s\t%s" % (yel(feature), ", ".join(files)) + undefined, defined = check_symbols(opts.ignore) + + # now print the output + for feature in sorted(undefined): + print red(feature) + + files = sorted(undefined.get(feature)) + print "%s: %s" % (yel("Referencing files"), ", ".join(files)) + + sims = find_sims(feature, opts.ignore, defined) + sims_out = yel("Similar symbols") + if sims: + print "%s: %s" % (sims_out, ', '.join(sims)) + else: + print "%s: %s" % (sims_out, "no similar symbols found") + + if opts.find: + print "%s:" % yel("Commits changing symbol") + commits = find_commits(feature, opts.diff) + if commits: + for commit in commits: + commit = commit.split(" ", 1) + print "\t- %s (\"%s\")" % (yel(commit[0]), commit[1]) + else: + print "\t- no commit found" + print # new line def yel(string): @@ -190,7 +225,7 @@ def find_commits(symbol, diff): """Find commits changing %symbol in the given range of %diff.""" commits = execute("git log --pretty=oneline --abbrev-commit -G %s %s" % (symbol, diff)) - return commits + return [x for x in commits.split("\n") if x] def tree_is_dirty(): @@ -209,43 +244,107 @@ def get_head(): return stdout.strip('\n') -def check_symbols(ignore): - """Find undefined Kconfig symbols and return a dict with the symbol as key - and a list of referencing files as value. Files matching %ignore are not - checked for undefined symbols.""" - source_files = [] - kconfig_files = [] - defined_features = set() - referenced_features = dict() # {feature: [files]} +def partition(lst, size): + """Partition list @lst into eveni-sized lists of size @size.""" + return [lst[i::size] for i in xrange(size)] + + +def init_worker(): + """Set signal handler to ignore SIGINT.""" + signal.signal(signal.SIGINT, signal.SIG_IGN) + + +def find_sims(symbol, ignore, defined = []): + """Return a list of max. ten Kconfig symbols that are string-similar to + @symbol.""" + if defined: + return sorted(difflib.get_close_matches(symbol, set(defined), 10)) + + pool = Pool(cpu_count(), init_worker) + kfiles = [] + for gitfile in get_files(): + if REGEX_FILE_KCONFIG.match(gitfile): + kfiles.append(gitfile) + arglist = [] + for part in partition(kfiles, cpu_count()): + arglist.append((part, ignore)) + + for res in pool.map(parse_kconfig_files, arglist): + defined.extend(res[0]) + + return sorted(difflib.get_close_matches(symbol, set(defined), 10)) + + +def get_files(): + """Return a list of all files in the current git directory.""" # use 'git ls-files' to get the worklist stdout = execute("git ls-files") if len(stdout) > 0 and stdout[-1] == "\n": stdout = stdout[:-1] + files = [] for gitfile in stdout.rsplit("\n"): if ".git" in gitfile or "ChangeLog" in gitfile or \ ".log" in gitfile or os.path.isdir(gitfile) or \ gitfile.startswith("tools/"): continue + files.append(gitfile) + return files + + +def check_symbols(ignore): + """Find undefined Kconfig symbols and return a dict with the symbol as key + and a list of referencing files as value. Files matching %ignore are not + checked for undefined symbols.""" + pool = Pool(cpu_count(), init_worker) + try: + return check_symbols_helper(pool, ignore) + except KeyboardInterrupt: + pool.terminate() + pool.join() + sys.exit(1) + + +def check_symbols_helper(pool, ignore): + """Helper method for check_symbols(). Used to catch keyboard interrupts in + check_symbols() in order to properly terminate running worker processes.""" + source_files = [] + kconfig_files = [] + defined_features = [] + referenced_features = dict() # {file: [features]} + + for gitfile in get_files(): if REGEX_FILE_KCONFIG.match(gitfile): kconfig_files.append(gitfile) else: - # all non-Kconfig files are checked for consistency + if ignore and not re.match(ignore, gitfile): + continue + # add source files that do not match the ignore pattern source_files.append(gitfile) - for sfile in source_files: - if ignore and re.match(ignore, sfile): - # do not check files matching %ignore - continue - parse_source_file(sfile, referenced_features) + # parse source files + arglist = partition(source_files, cpu_count()) + for res in pool.map(parse_source_files, arglist): + referenced_features.update(res) - for kfile in kconfig_files: - if ignore and re.match(ignore, kfile): - # do not collect references for files matching %ignore - parse_kconfig_file(kfile, defined_features, dict()) - else: - parse_kconfig_file(kfile, defined_features, referenced_features) + + # parse kconfig files + arglist = [] + for part in partition(kconfig_files, cpu_count()): + arglist.append((part, ignore)) + for res in pool.map(parse_kconfig_files, arglist): + defined_features.extend(res[0]) + referenced_features.update(res[1]) + defined_features = set(defined_features) + + # inverse mapping of referenced_features to dict(feature: [files]) + inv_map = dict() + for _file, features in referenced_features.iteritems(): + for feature in features: + inv_map[feature] = inv_map.get(feature, set()) + inv_map[feature].add(_file) + referenced_features = inv_map undefined = {} # {feature: [files]} for feature in sorted(referenced_features): @@ -259,12 +358,26 @@ def check_symbols(ignore): if feature[:-len("_MODULE")] in defined_features: continue undefined[feature] = referenced_features.get(feature) - return undefined + return undefined, defined_features -def parse_source_file(sfile, referenced_features): - """Parse @sfile for referenced Kconfig features.""" +def parse_source_files(source_files): + """Parse each source file in @source_files and return dictionary with source + files as keys and lists of references Kconfig symbols as values.""" + referenced_features = dict() + for sfile in source_files: + referenced_features[sfile] = parse_source_file(sfile) + return referenced_features + + +def parse_source_file(sfile): + """Parse @sfile and return a list of referenced Kconfig features.""" lines = [] + references = [] + + if not os.path.exists(sfile): + return references + with open(sfile, "r") as stream: lines = stream.readlines() @@ -275,9 +388,9 @@ def parse_source_file(sfile, referenced_features): for feature in features: if not REGEX_FILTER_FEATURES.search(feature): continue - sfiles = referenced_features.get(feature, set()) - sfiles.add(sfile) - referenced_features[feature] = sfiles + references.append(feature) + + return references def get_features_in_line(line): @@ -285,11 +398,35 @@ def get_features_in_line(line): return REGEX_FEATURE.findall(line) -def parse_kconfig_file(kfile, defined_features, referenced_features): +def parse_kconfig_files(args): + """Parse kconfig files and return tuple of defined and references Kconfig + symbols. Note, @args is a tuple of a list of files and the @ignore + pattern.""" + kconfig_files = args[0] + ignore = args[1] + defined_features = [] + referenced_features = dict() + + for kfile in kconfig_files: + defined, references = parse_kconfig_file(kfile) + defined_features.extend(defined) + if ignore and re.match(ignore, kfile): + # do not collect references for files that match the ignore pattern + continue + referenced_features[kfile] = references + return (defined_features, referenced_features) + + +def parse_kconfig_file(kfile): """Parse @kfile and update feature definitions and references.""" lines = [] + defined = [] + references = [] skip = False + if not os.path.exists(kfile): + return defined, references + with open(kfile, "r") as stream: lines = stream.readlines() @@ -300,7 +437,7 @@ def parse_kconfig_file(kfile, defined_features, referenced_features): if REGEX_KCONFIG_DEF.match(line): feature_def = REGEX_KCONFIG_DEF.findall(line) - defined_features.add(feature_def[0]) + defined.append(feature_def[0]) skip = False elif REGEX_KCONFIG_HELP.match(line): skip = True @@ -308,6 +445,7 @@ def parse_kconfig_file(kfile, defined_features, referenced_features): # ignore content of help messages pass elif REGEX_KCONFIG_STMT.match(line): + line = REGEX_QUOTES.sub("", line) features = get_features_in_line(line) # multi-line statements while line.endswith("\\"): @@ -319,9 +457,9 @@ def parse_kconfig_file(kfile, defined_features, referenced_features): if REGEX_NUMERIC.match(feature): # ignore numeric values continue - paths = referenced_features.get(feature, set()) - paths.add(kfile) - referenced_features[feature] = paths + references.append(feature) + + return defined, references if __name__ == "__main__": diff --git a/scripts/ld-version.sh b/scripts/ld-version.sh index 198580d245e0..d154f0877fd8 100755 --- a/scripts/ld-version.sh +++ b/scripts/ld-version.sh @@ -2,7 +2,9 @@ # extract linker version number from stdin and turn into single number { gsub(".*)", ""); + gsub(".*version ", ""); + gsub("-.*", ""); split($1,a, "."); - print a[1]*10000000 + a[2]*100000 + a[3]*10000 + a[4]*100 + a[5]; + print a[1]*100000000 + a[2]*1000000 + a[3]*10000 + a[4]*100 + a[5]; exit } diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh index 1a10d8ac8162..ba6c34ea5429 100755 --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh @@ -62,7 +62,7 @@ vmlinux_link() -Wl,--start-group \ ${KBUILD_VMLINUX_MAIN} \ -Wl,--end-group \ - -lutil ${1} + -lutil -lrt -lpthread ${1} rm -f linux fi } diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 5b96206e9aab..8adca4406198 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -917,7 +917,7 @@ static int do_vmbus_entry(const char *filename, void *symval, char guid_name[(sizeof(*guid) + 1) * 2]; for (i = 0; i < (sizeof(*guid) * 2); i += 2) - sprintf(&guid_name[i], "%02x", TO_NATIVE((*guid)[i/2])); + sprintf(&guid_name[i], "%02x", TO_NATIVE((guid->b)[i/2])); strcpy(alias, "vmbus:"); strcat(alias, guid_name); diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c index 698768bdc581..e167592793a7 100644 --- a/scripts/recordmcount.c +++ b/scripts/recordmcount.c @@ -48,12 +48,17 @@ static int fd_map; /* File descriptor for file being modified. */ static int mmap_failed; /* Boolean flag. */ -static void *ehdr_curr; /* current ElfXX_Ehdr * for resource cleanup */ static char gpfx; /* prefix for global symbol name (sometimes '_') */ static struct stat sb; /* Remember .st_size, etc. */ static jmp_buf jmpenv; /* setjmp/longjmp per-file error escape */ static const char *altmcount; /* alternate mcount symbol name */ static int warn_on_notrace_sect; /* warn when section has mcount not being recorded */ +static void *file_map; /* pointer of the mapped file */ +static void *file_end; /* pointer to the end of the mapped file */ +static int file_updated; /* flag to state file was changed */ +static void *file_ptr; /* current file pointer location */ +static void *file_append; /* added to the end of the file */ +static size_t file_append_size; /* how much is added to end of file */ /* setjmp() return values */ enum { @@ -67,10 +72,14 @@ static void cleanup(void) { if (!mmap_failed) - munmap(ehdr_curr, sb.st_size); + munmap(file_map, sb.st_size); else - free(ehdr_curr); - close(fd_map); + free(file_map); + file_map = NULL; + free(file_append); + file_append = NULL; + file_append_size = 0; + file_updated = 0; } static void __attribute__((noreturn)) @@ -92,12 +101,22 @@ succeed_file(void) static off_t ulseek(int const fd, off_t const offset, int const whence) { - off_t const w = lseek(fd, offset, whence); - if (w == (off_t)-1) { - perror("lseek"); + switch (whence) { + case SEEK_SET: + file_ptr = file_map + offset; + break; + case SEEK_CUR: + file_ptr += offset; + break; + case SEEK_END: + file_ptr = file_map + (sb.st_size - offset); + break; + } + if (file_ptr < file_map) { + fprintf(stderr, "lseek: seek before file\n"); fail_file(); } - return w; + return file_ptr - file_map; } static size_t @@ -114,12 +133,38 @@ uread(int const fd, void *const buf, size_t const count) static size_t uwrite(int const fd, void const *const buf, size_t const count) { - size_t const n = write(fd, buf, count); - if (n != count) { - perror("write"); - fail_file(); + size_t cnt = count; + off_t idx = 0; + + file_updated = 1; + + if (file_ptr + count >= file_end) { + off_t aoffset = (file_ptr + count) - file_end; + + if (aoffset > file_append_size) { + file_append = realloc(file_append, aoffset); + file_append_size = aoffset; + } + if (!file_append) { + perror("write"); + fail_file(); + } + if (file_ptr < file_end) { + cnt = file_end - file_ptr; + } else { + cnt = 0; + idx = aoffset - count; + } } - return n; + + if (cnt) + memcpy(file_ptr, buf, cnt); + + if (cnt < count) + memcpy(file_append + idx, buf + cnt, count - cnt); + + file_ptr += count; + return count; } static void * @@ -192,9 +237,7 @@ static int make_nop_arm64(void *map, size_t const offset) */ static void *mmap_file(char const *fname) { - void *addr; - - fd_map = open(fname, O_RDWR); + fd_map = open(fname, O_RDONLY); if (fd_map < 0 || fstat(fd_map, &sb) < 0) { perror(fname); fail_file(); @@ -203,15 +246,58 @@ static void *mmap_file(char const *fname) fprintf(stderr, "not a regular file: %s\n", fname); fail_file(); } - addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, - fd_map, 0); + file_map = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, + fd_map, 0); mmap_failed = 0; - if (addr == MAP_FAILED) { + if (file_map == MAP_FAILED) { mmap_failed = 1; - addr = umalloc(sb.st_size); - uread(fd_map, addr, sb.st_size); + file_map = umalloc(sb.st_size); + uread(fd_map, file_map, sb.st_size); + } + close(fd_map); + + file_end = file_map + sb.st_size; + + return file_map; +} + +static void write_file(const char *fname) +{ + char tmp_file[strlen(fname) + 4]; + size_t n; + + if (!file_updated) + return; + + sprintf(tmp_file, "%s.rc", fname); + + /* + * After reading the entire file into memory, delete it + * and write it back, to prevent weird side effects of modifying + * an object file in place. + */ + fd_map = open(tmp_file, O_WRONLY | O_TRUNC | O_CREAT, sb.st_mode); + if (fd_map < 0) { + perror(fname); + fail_file(); + } + n = write(fd_map, file_map, sb.st_size); + if (n != sb.st_size) { + perror("write"); + fail_file(); + } + if (file_append_size) { + n = write(fd_map, file_append, file_append_size); + if (n != file_append_size) { + perror("write"); + fail_file(); + } + } + close(fd_map); + if (rename(tmp_file, fname) < 0) { + perror(fname); + fail_file(); } - return addr; } /* w8rev, w8nat, ...: Handle endianness. */ @@ -318,7 +404,6 @@ do_file(char const *const fname) Elf32_Ehdr *const ehdr = mmap_file(fname); unsigned int reltype = 0; - ehdr_curr = ehdr; w = w4nat; w2 = w2nat; w8 = w8nat; @@ -441,6 +526,7 @@ do_file(char const *const fname) } } /* end switch */ + write_file(fname); cleanup(); } @@ -493,11 +579,14 @@ main(int argc, char *argv[]) case SJ_SETJMP: /* normal sequence */ /* Avoid problems if early cleanup() */ fd_map = -1; - ehdr_curr = NULL; mmap_failed = 1; + file_map = NULL; + file_ptr = NULL; + file_updated = 0; do_file(file); break; case SJ_FAIL: /* error in do_file or below */ + fprintf(stderr, "%s: failed\n", file); ++n_error; break; case SJ_SUCCEED: /* premature success */ |