summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2023-02-07 20:36:16 -0500
committerTom Rini <trini@konsulko.com>2023-02-07 20:36:16 -0500
commit94fe4ed9455d559ccca45865c195fe4ecdaffb51 (patch)
treeb56e39c0847ac222c122e8feda40c27af21a0a30 /tools
parentb69026c91f2e98b247120e217a986f5056724baf (diff)
parentd727ace9abf13eb72e7ac29113f52fa3fd3357bb (diff)
Merge branch '2023-02-07-Kconfig-cleanup-dead-code-removal'
To quote the author: This series adds source scanning to moveconfig.py so that it can look for Kconfig options mentioned in the source which do not appear in Kconfig, and vice versa. This tool is then used to clean up the unused or obsolete options mentioned in Makefiles, along with any attached source code.
Diffstat (limited to 'tools')
-rw-r--r--tools/.gitignore1
-rw-r--r--tools/Makefile14
-rwxr-xr-xtools/moveconfig.py334
-rw-r--r--tools/mxsimage.c2
-rw-r--r--tools/ubsha1.c83
-rw-r--r--tools/xway-swap-bytes.c38
6 files changed, 337 insertions, 135 deletions
diff --git a/tools/.gitignore b/tools/.gitignore
index 28e8ce2a07a..788ea260a07 100644
--- a/tools/.gitignore
+++ b/tools/.gitignore
@@ -33,7 +33,6 @@
/relocate-rela
/spl_size_limit
/sunxi-spl-image-builder
-/ubsha1
/update_octeon_header
/version.h
/xway-swap-bytes
diff --git a/tools/Makefile b/tools/Makefile
index edfa40903d9..041c437e65b 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -27,9 +27,7 @@ ifneq ($(HOST_TOOLS_ALL),)
CONFIG_ARCH_KIRKWOOD = y
CONFIG_CMD_LOADS = y
CONFIG_CMD_NET = y
-CONFIG_XWAY_SWAP_BYTES = y
CONFIG_NETCONSOLE = y
-CONFIG_SHA1_CHECK_UB_IMG = y
CONFIG_ARCH_SUNXI = y
endif
@@ -62,9 +60,6 @@ HOSTCFLAGS_gen_ethaddr_crc.o := -pedantic
hostprogs-$(CONFIG_CMD_LOADS) += img2srec
HOSTCFLAGS_img2srec.o := -pedantic
-hostprogs-$(CONFIG_XWAY_SWAP_BYTES) += xway-swap-bytes
-HOSTCFLAGS_xway-swap-bytes.o := -pedantic
-
hostprogs-y += mkenvimage
mkenvimage-objs := mkenvimage.o os_support.o lib/crc32.o
@@ -158,9 +153,9 @@ fit_check_sign-objs := $(dumpimage-mkimage-objs) fit_check_sign.o
file2include-objs := file2include.o
ifneq ($(CONFIG_MX23)$(CONFIG_MX28)$(CONFIG_TOOLS_LIBCRYPTO),)
-# Add CONFIG_MXS into host CFLAGS, so we can check whether or not register
+# Add CFG_MXS into host CFLAGS, so we can check whether or not register
# the mxsimage support within tools/mxsimage.c .
-HOSTCFLAGS_mxsimage.o += -DCONFIG_MXS
+HOSTCFLAGS_mxsimage.o += -DCFG_MXS
endif
ifdef CONFIG_TOOLS_LIBCRYPTO
@@ -217,11 +212,6 @@ hostprogs-$(CONFIG_ARCH_SUNXI) += sunxi-spl-image-builder
sunxi-spl-image-builder-objs := sunxi-spl-image-builder.o lib/bch.o
hostprogs-$(CONFIG_NETCONSOLE) += ncb
-hostprogs-$(CONFIG_SHA1_CHECK_UB_IMG) += ubsha1
-
-ubsha1-objs := os_support.o ubsha1.o lib/sha1.o
-
-HOSTCFLAGS_ubsha1.o := -pedantic
hostprogs-$(CONFIG_ARCH_KIRKWOOD) += kwboot
hostprogs-$(CONFIG_ARCH_MVEBU) += kwboot
diff --git a/tools/moveconfig.py b/tools/moveconfig.py
index 8f084a6070a..c4d72ede368 100755
--- a/tools/moveconfig.py
+++ b/tools/moveconfig.py
@@ -93,6 +93,18 @@ SIZES = {
RE_REMOVE_DEFCONFIG = re.compile(r'(.*)_defconfig')
+# CONFIG symbols present in the build system (from Linux) but not actually used
+# in U-Boot; KCONFIG symbols
+IGNORE_SYMS = ['DEBUG_SECTION_MISMATCH', 'FTRACE_MCOUNT_RECORD', 'GCOV_KERNEL',
+ 'GCOV_PROFILE_ALL', 'KALLSYMS', 'KASAN', 'MODVERSIONS', 'SHELL',
+ 'TPL_BUILD', 'VPL_BUILD', 'IS_ENABLED', 'FOO', 'IF_ENABLED_INT',
+ 'IS_ENABLED_', 'IS_ENABLED_1', 'IS_ENABLED_2', 'IS_ENABLED_3',
+ 'SPL_', 'TPL_', 'SPL_FOO', 'TPL_FOO', 'TOOLS_FOO',
+ 'ACME', 'SPL_ACME', 'TPL_ACME', 'TRACE_BRANCH_PROFILING',
+ 'VAL', '_UNDEFINED', 'SPL_BUILD', ]
+
+SPL_PREFIXES = ['SPL_', 'TPL_', 'VPL_', 'TOOLS_']
+
### helper functions ###
def check_top_directory():
"""Exit if we are not at the top of source directory."""
@@ -536,6 +548,7 @@ class KconfigScanner:
os.environ['srctree'] = os.getcwd()
os.environ['UBOOTVERSION'] = 'dummy'
os.environ['KCONFIG_OBJDIR'] = ''
+ os.environ['CC'] = 'gcc'
self.conf = kconfiglib.Kconfig()
@@ -1593,6 +1606,319 @@ def prefix_config(cfg):
return op + cfg
+RE_MK_CONFIGS = re.compile('CONFIG_(\$\(SPL_(?:TPL_)?\))?([A-Za-z0-9_]*)')
+RE_IFDEF = re.compile('(ifdef|ifndef)')
+RE_C_CONFIGS = re.compile('CONFIG_([A-Za-z0-9_]*)')
+RE_CONFIG_IS = re.compile('CONFIG_IS_ENABLED\(([A-Za-z0-9_]*)\)')
+
+class ConfigUse:
+ def __init__(self, cfg, is_spl, fname, rest):
+ self.cfg = cfg
+ self.is_spl = is_spl
+ self.fname = fname
+ self.rest = rest
+
+ def __hash__(self):
+ return hash((self.cfg, self.is_spl))
+
+def scan_makefiles(fnames):
+ """Scan Makefiles looking for Kconfig options
+
+ Looks for uses of CONFIG options in Makefiles
+
+ Args:
+ fnames (list of tuple):
+ str: Makefile filename where the option was found
+ str: Line of the Makefile
+
+ Returns:
+ tuple:
+ dict: all_uses
+ key (ConfigUse): object
+ value (list of str): matching lines
+ dict: Uses by filename
+ key (str): filename
+ value (set of ConfigUse): uses in that filename
+
+ >>> RE_MK_CONFIGS.search('CONFIG_FRED').groups()
+ (None, 'FRED')
+ >>> RE_MK_CONFIGS.search('CONFIG_$(SPL_)MARY').groups()
+ ('$(SPL_)', 'MARY')
+ >>> RE_MK_CONFIGS.search('CONFIG_$(SPL_TPL_)MARY').groups()
+ ('$(SPL_TPL_)', 'MARY')
+ """
+ all_uses = collections.defaultdict(list)
+ fname_uses = {}
+ for fname, rest in fnames:
+ m_iter = RE_MK_CONFIGS.finditer(rest)
+ found = False
+ for m in m_iter:
+ found = True
+ real_opt = m.group(2)
+ if real_opt == '':
+ continue
+ is_spl = False
+ if m.group(1):
+ is_spl = True
+ use = ConfigUse(real_opt, is_spl, fname, rest)
+ if fname not in fname_uses:
+ fname_uses[fname] = set()
+ fname_uses[fname].add(use)
+ all_uses[use].append(rest)
+ return all_uses, fname_uses
+
+
+def scan_src_files(fnames):
+ """Scan source files (other than Makefiles) looking for Kconfig options
+
+ Looks for uses of CONFIG options
+
+ Args:
+ fnames (list of tuple):
+ str: Makefile filename where the option was found
+ str: Line of the Makefile
+
+ Returns:
+ tuple:
+ dict: all_uses
+ key (ConfigUse): object
+ value (list of str): matching lines
+ dict: Uses by filename
+ key (str): filename
+ value (set of ConfigUse): uses in that filename
+
+ >>> RE_C_CONFIGS.search('CONFIG_FRED').groups()
+ ('FRED',)
+ >>> RE_CONFIG_IS.search('CONFIG_IS_ENABLED(MARY)').groups()
+ ('MARY',)
+ >>> RE_CONFIG_IS.search('#if CONFIG_IS_ENABLED(OF_PLATDATA)').groups()
+ ('OF_PLATDATA',)
+ """
+ def add_uses(m_iter, is_spl):
+ for m in m_iter:
+ found = True
+ real_opt = m.group(1)
+ if real_opt == '':
+ continue
+ use = ConfigUse(real_opt, is_spl, fname, rest)
+ if fname not in fname_uses:
+ fname_uses[fname] = set()
+ fname_uses[fname].add(use)
+ all_uses[use].append(rest)
+
+ all_uses = collections.defaultdict(list)
+ fname_uses = {}
+ for fname, rest in fnames:
+ m_iter = RE_C_CONFIGS.finditer(rest)
+ add_uses(m_iter, False)
+
+ m_iter2 = RE_CONFIG_IS.finditer(rest)
+ add_uses(m_iter2, True)
+
+ return all_uses, fname_uses
+
+
+MODE_NORMAL, MODE_SPL, MODE_PROPER = range(3)
+
+def do_scan_source(path, do_update):
+ """Scan the source tree for Kconfig inconsistencies
+
+ Args:
+ path (str): Path to source tree
+ do_update (bool) : True to write to scripts/kconf_... files
+ """
+ def is_not_proper(name):
+ for prefix in SPL_PREFIXES:
+ if name.startswith(prefix):
+ return name[len(prefix):]
+ return False
+
+ def check_not_found(all_uses, spl_mode):
+ """Check for Kconfig options mentioned in the source but not in Kconfig
+
+ Args:
+ all_uses (dict):
+ key (ConfigUse): object
+ value (list of str): matching lines
+ spl_mode (int): If MODE_SPL, look at source code which implies
+ an SPL_ option, but for which there is none;
+ for MOD_PROPER, look at source code which implies a Proper
+ option (i.e. use of CONFIG_IS_ENABLED() or $(SPL_) or
+ $(SPL_TPL_) but for which there none;
+ if MODE_NORMAL, ignore SPL
+
+ Returns:
+ dict:
+ key (str): CONFIG name (without 'CONFIG_' prefix
+ value (list of ConfigUse): List of uses of this CONFIG
+ """
+ # Make sure we know about all the options
+ not_found = collections.defaultdict(list)
+ for use, rest in all_uses.items():
+ name = use.cfg
+ if name in IGNORE_SYMS:
+ continue
+ check = True
+
+ if spl_mode == MODE_SPL:
+ check = use.is_spl
+
+ # If it is an SPL symbol, try prepending all SPL_ prefixes to
+ # find at least one SPL symbol
+ if use.is_spl:
+ add_to_dict = False
+ for prefix in SPL_PREFIXES:
+ try_name = prefix + name
+ sym = kconf.syms.get(try_name)
+ if sym:
+ break
+ if not sym:
+ not_found[f'SPL_{name}'].append(use)
+ continue
+ elif spl_mode == MODE_PROPER:
+ # Try to find the Proper version of this symbol, i.e. without
+ # the SPL_ prefix
+ proper_name = is_not_proper(name)
+ if proper_name:
+ name = proper_name
+ elif not use.is_spl:
+ check = False
+ else: # MODE_NORMAL
+ debug = False
+ sym = kconf.syms.get(name)
+ if not sym:
+ proper_name = is_not_proper(name)
+ if proper_name:
+ name = proper_name
+ sym = kconf.syms.get(name)
+ if not sym:
+ for prefix in SPL_PREFIXES:
+ try_name = prefix + name
+ sym = kconf.syms.get(try_name)
+ if sym:
+ break
+ if not sym:
+ not_found[name].append(use)
+ continue
+
+ sym = kconf.syms.get(name)
+ if not sym and check:
+ not_found[name].append(use)
+ return not_found
+
+ def show_uses(uses):
+ """Show a list of uses along with their filename and code snippet
+
+ Args:
+ uses (dict):
+ key (str): CONFIG name (without 'CONFIG_' prefix
+ value (list of ConfigUse): List of uses of this CONFIG
+ """
+ for name in sorted(uses):
+ print(f'{name}: ', end='')
+ for i, use in enumerate(uses[name]):
+ print(f'{" " if i else ""}{use.fname}: {use.rest.strip()}')
+
+
+ print('Scanning Kconfig')
+ kconf = KconfigScanner().conf
+ print(f'Scanning source in {path}')
+ args = ['git', 'grep', '-E', r'IS_ENABLED|\bCONFIG']
+ with subprocess.Popen(args, stdout=subprocess.PIPE) as proc:
+ out, err = proc.communicate()
+ lines = out.splitlines()
+ re_fname = re.compile('^([^:]*):(.*)')
+ src_list = []
+ mk_list = []
+ for line in lines:
+ linestr = line.decode('utf-8')
+ m_fname = re_fname.search(linestr)
+ if not m_fname:
+ continue
+ fname, rest = m_fname.groups()
+ dirname, leaf = os.path.split(fname)
+ root, ext = os.path.splitext(leaf)
+ if ext == '.autoconf':
+ pass
+ elif ext in ['.c', '.h', '.S', '.lds', '.dts', '.dtsi', '.asl', '.cfg',
+ '.env', '.tmpl']:
+ src_list.append([fname, rest])
+ elif 'Makefile' in root or ext == '.mk':
+ mk_list.append([fname, rest])
+ elif ext in ['.yml', '.sh', '.py', '.awk', '.pl', '.rst', '', '.sed']:
+ pass
+ elif 'Kconfig' in root or 'Kbuild' in root:
+ pass
+ elif 'README' in root:
+ pass
+ elif dirname in ['configs']:
+ pass
+ elif dirname.startswith('doc') or dirname.startswith('scripts/kconfig'):
+ pass
+ else:
+ print(f'Not sure how to handle file {fname}')
+
+ # Scan the Makefiles
+ all_uses, fname_uses = scan_makefiles(mk_list)
+
+ spl_not_found = set()
+ proper_not_found = set()
+
+ # Make sure we know about all the options
+ print('\nCONFIG options present in Makefiles but not Kconfig:')
+ not_found = check_not_found(all_uses, MODE_NORMAL)
+ show_uses(not_found)
+
+ print('\nCONFIG options present in Makefiles but not Kconfig (SPL):')
+ not_found = check_not_found(all_uses, MODE_SPL)
+ show_uses(not_found)
+ spl_not_found |= set([is_not_proper(key) or key for key in not_found.keys()])
+
+ print('\nCONFIG options used as Proper in Makefiles but without a non-SPL_ variant:')
+ not_found = check_not_found(all_uses, MODE_PROPER)
+ show_uses(not_found)
+ proper_not_found |= set([key for key in not_found.keys()])
+
+ # Scan the source code
+ all_uses, fname_uses = scan_src_files(src_list)
+
+ # Make sure we know about all the options
+ print('\nCONFIG options present in source but not Kconfig:')
+ not_found = check_not_found(all_uses, MODE_NORMAL)
+ show_uses(not_found)
+
+ print('\nCONFIG options present in source but not Kconfig (SPL):')
+ not_found = check_not_found(all_uses, MODE_SPL)
+ show_uses(not_found)
+ spl_not_found |= set([is_not_proper(key) or key for key in not_found.keys()])
+
+ print('\nCONFIG options used as Proper in source but without a non-SPL_ variant:')
+ not_found = check_not_found(all_uses, MODE_PROPER)
+ show_uses(not_found)
+ proper_not_found |= set([key for key in not_found.keys()])
+
+ print('\nCONFIG options used as SPL but without an SPL_ variant:')
+ for item in sorted(spl_not_found):
+ print(f' {item}')
+
+ print('\nCONFIG options used as Proper but without a non-SPL_ variant:')
+ for item in sorted(proper_not_found):
+ print(f' {item}')
+
+ # Write out the updated information
+ if do_update:
+ with open(os.path.join(path, 'scripts', 'conf_nospl'), 'w') as out:
+ print('# These options should not be enabled in SPL builds\n',
+ file=out)
+ for item in sorted(spl_not_found):
+ print(item, file=out)
+ with open(os.path.join(path, 'scripts', 'conf_noproper'), 'w') as out:
+ print('# These options should not be enabled in Proper builds\n',
+ file=out)
+ for item in sorted(proper_not_found):
+ print(item, file=out)
+
+
def main():
try:
cpu_count = multiprocessing.cpu_count()
@@ -1642,10 +1968,14 @@ doc/develop/moveconfig.rst for documentation.'''
help='force sync by savedefconfig')
parser.add_argument('-S', '--spl', action='store_true', default=False,
help='parse config options defined for SPL build')
+ parser.add_argument('--scan-source', action='store_true', default=False,
+ help='scan source for uses of CONFIG options')
parser.add_argument('-t', '--test', action='store_true', default=False,
help='run unit tests')
parser.add_argument('-y', '--yes', action='store_true', default=False,
help="respond 'yes' to any prompts")
+ parser.add_argument('-u', '--update', action='store_true', default=False,
+ help="update scripts/ files (use with --scan-source)")
parser.add_argument('-v', '--verbose', action='store_true', default=False,
help='show any build errors as boards are built')
parser.add_argument('configs', nargs='*')
@@ -1660,6 +1990,10 @@ doc/develop/moveconfig.rst for documentation.'''
return 1
unittest.main()
+ if args.scan_source:
+ do_scan_source(os.getcwd(), args.update)
+ return
+
if not any((len(configs), args.force_sync, args.build_db, args.imply,
args.find)):
parser.print_usage()
diff --git a/tools/mxsimage.c b/tools/mxsimage.c
index fee022aab46..fbe46c47fae 100644
--- a/tools/mxsimage.c
+++ b/tools/mxsimage.c
@@ -5,7 +5,7 @@
* Copyright (C) 2012-2013 Marek Vasut <marex@denx.de>
*/
-#ifdef CONFIG_MXS
+#ifdef CFG_MXS
#include <errno.h>
#include <fcntl.h>
diff --git a/tools/ubsha1.c b/tools/ubsha1.c
deleted file mode 100644
index 90a6f3f59d2..00000000000
--- a/tools/ubsha1.c
+++ /dev/null
@@ -1,83 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * (C) Copyright 2007
- * Heiko Schocher, DENX Software Engineering, <hs@denx.de>
- */
-
-#include "os_support.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <u-boot/sha1.h>
-
-int main (int argc, char **argv)
-{
- unsigned char output[20];
- int i, len;
-
- char *imagefile;
- char *cmdname = *argv;
- unsigned char *ptr;
- unsigned char *data;
- struct stat sbuf;
- unsigned char *ptroff;
- int ifd;
- int off;
-
- if (argc > 1) {
- imagefile = argv[1];
- ifd = open (imagefile, O_RDWR|O_BINARY);
- if (ifd < 0) {
- fprintf (stderr, "%s: Can't open %s: %s\n",
- cmdname, imagefile, strerror(errno));
- exit (EXIT_FAILURE);
- }
- if (fstat (ifd, &sbuf) < 0) {
- fprintf (stderr, "%s: Can't stat %s: %s\n",
- cmdname, imagefile, strerror(errno));
- exit (EXIT_FAILURE);
- }
- len = sbuf.st_size;
- ptr = (unsigned char *)mmap(0, len,
- PROT_READ, MAP_SHARED, ifd, 0);
- if (ptr == (unsigned char *)MAP_FAILED) {
- fprintf (stderr, "%s: Can't read %s: %s\n",
- cmdname, imagefile, strerror(errno));
- exit (EXIT_FAILURE);
- }
-
- /* create a copy, so we can blank out the sha1 sum */
- data = malloc (len);
- memcpy (data, ptr, len);
- off = SHA1_SUM_POS;
- ptroff = &data[len + off];
- for (i = 0; i < SHA1_SUM_LEN; i++) {
- ptroff[i] = 0;
- }
-
- sha1_csum ((unsigned char *) data, len, (unsigned char *)output);
-
- printf ("U-Boot sum:\n");
- for (i = 0; i < 20 ; i++) {
- printf ("%02X ", output[i]);
- }
- printf ("\n");
- /* overwrite the sum in the bin file, with the actual */
- lseek (ifd, SHA1_SUM_POS, SEEK_END);
- if (write (ifd, output, SHA1_SUM_LEN) != SHA1_SUM_LEN) {
- fprintf (stderr, "%s: Can't write %s: %s\n",
- cmdname, imagefile, strerror(errno));
- exit (EXIT_FAILURE);
- }
-
- free (data);
- (void) munmap((void *)ptr, len);
- (void) close (ifd);
- }
-
- return EXIT_SUCCESS;
-}
diff --git a/tools/xway-swap-bytes.c b/tools/xway-swap-bytes.c
deleted file mode 100644
index 3a6d82d54a0..00000000000
--- a/tools/xway-swap-bytes.c
+++ /dev/null
@@ -1,38 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#ifndef BUFSIZ
-# define BUFSIZ 4096
-#endif
-
-#undef BUFSIZ
-# define BUFSIZ 64
-int main (void)
-{
- short ibuff[BUFSIZ], obuff[BUFSIZ];
- int rc, i, len;
-
- while ((rc = read (0, ibuff, sizeof (ibuff))) > 0) {
- memset (obuff, 0, sizeof (obuff));
- for (i = 0; i < (rc + 1) / 2; i++) {
- obuff[i] = ibuff[i ^ 1];
- }
-
- len = (rc + 1) & ~1;
-
- if (write (1, obuff, len) != len) {
- perror ("read error");
- return (EXIT_FAILURE);
- }
-
- memset (ibuff, 0, sizeof (ibuff));
- }
-
- if (rc < 0) {
- perror ("read error");
- return (EXIT_FAILURE);
- }
- return (EXIT_SUCCESS);
-}