From nobody Fri May 17 04:59:47 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=fail(p=none dis=none) header.from=arm.com Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 16509767752991012.8046162491779; Tue, 26 Apr 2022 05:39:35 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.313870.531645 (Exim 4.92) (envelope-from ) id 1njKT5-0000II-Jd; Tue, 26 Apr 2022 12:38:59 +0000 Received: by outflank-mailman (output) from mailman id 313870.531645; Tue, 26 Apr 2022 12:38:59 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1njKT5-0000IB-Gd; Tue, 26 Apr 2022 12:38:59 +0000 Received: by outflank-mailman (input) for mailman id 313870; Tue, 26 Apr 2022 12:38:58 +0000 Received: from se1-gles-flk1-in.inumbo.com ([94.247.172.50] helo=se1-gles-flk1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1njKT4-0000I5-EQ for xen-devel@lists.xenproject.org; Tue, 26 Apr 2022 12:38:58 +0000 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by se1-gles-flk1.inumbo.com (Halon) with ESMTP id d6d4e53e-c55d-11ec-8fc2-03012f2f19d4; Tue, 26 Apr 2022 14:38:57 +0200 (CEST) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 7939823A; Tue, 26 Apr 2022 05:38:56 -0700 (PDT) Received: from e109506.cambridge.arm.com (e109506.cambridge.arm.com [10.1.199.62]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 282903F774; Tue, 26 Apr 2022 05:38:55 -0700 (PDT) X-Outflank-Mailman: Message body and most headers restored to incoming version X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: d6d4e53e-c55d-11ec-8fc2-03012f2f19d4 From: Bertrand Marquis To: xen-devel@lists.xenproject.org Cc: Andrew Cooper , George Dunlap , Jan Beulich , Julien Grall , Stefano Stabellini , Wei Liu , Volodymyr Babchuk , Michal Orzel Subject: [PATCH v3] xen/build: Add cppcheck and cppcheck-html make rules Date: Tue, 26 Apr 2022 13:38:41 +0100 Message-Id: <8a8ffce11591efb284c93214b77534fa4e4134b2.1650976647.git.bertrand.marquis@arm.com> X-Mailer: git-send-email 2.25.1 MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ZM-MESSAGEID: 1650976777768100001 Content-Type: text/plain; charset="utf-8" cppcheck can be used to check Xen code quality. To create a report do "make cppcheck" on a built tree adding any options you added during the process you used to build xen (like CROSS_COMPILE or XEN_TARGET_ARCH). This will generate an xml report xen-cppcheck.xml. To create a html report do "make cppcheck-html" in the same way and a full report to be seen in a browser will be generated in cppcheck-htmlreport/index.html. For better results it is recommended to build your own cppcheck from the latest sources that you can find at [1]. Development and result analysis has been done with cppcheck 2.7. The Makefile rule is searching for all C files which have been compiled (ie which have a generated .o file) and is running cppcheck on all of them using the current configuration of xen so only the code actually compiled is checked. A new tool is introduced to merge all cppcheck reports into one global report including all findings and removing duplicates. Some extra variables can be used to customize the report: - CPPCHECK can be used to give the full path to the cppcheck binary to use (default is to use the one from the standard path). - CPPCHECK_HTMLREPORT can be used to give the full path to cppcheck-htmlreport (default is to use the one from the standard path). This has been tested on several arm configurations (x86 should work but has not been tested). [1] https://cppcheck.sourceforge.io/ Signed-off-by: Bertrand Marquis Signed-off-by: Michal Orzel Acked-by: Julien Grall Acked-by: Stefano Stabellini Tested-by: Stefano Stabellini --- Changes in v3: - add more checks in merge script and catch all possible exception from the xml parser (suggested by Stefano) Changes in v2: - catch parsing errors during merge and tell the user to update cppcheck - fix alignments in Makefile - use srctree and objtree instead of BASEDIR - remove SCTLR invalid change - add a check of cppcheck version and mandate version 2.7 or greater - rework a bit the merge script to make it faster and display progress --- .gitignore | 3 + xen/Makefile | 84 ++++++++++++++++++++++++++- xen/arch/arm/include/asm/processor.h | 2 + xen/include/xen/config.h | 4 ++ xen/include/xen/kconfig.h | 5 ++ xen/tools/merge_cppcheck_reports.py | 86 ++++++++++++++++++++++++++++ 6 files changed, 182 insertions(+), 2 deletions(-) create mode 100755 xen/tools/merge_cppcheck_reports.py diff --git a/.gitignore b/.gitignore index c6d2c4b4f1..18ef56a780 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ *.o *.d *.d2 +*.c.cppcheck *.opic *.a *.so @@ -296,6 +297,7 @@ xen/.banner xen/.config xen/.config.old xen/.xen.elf32 +xen/xen-cppcheck.xml xen/System.map xen/arch/x86/boot/mkelf32 xen/arch/x86/boot/cmdline.S @@ -316,6 +318,7 @@ xen/arch/*/efi/runtime.c xen/arch/*/include/asm/asm-offsets.h xen/common/config_data.S xen/common/config.gz +xen/cppcheck-htmlreport xen/include/headers*.chk xen/include/compat/* xen/include/config/ diff --git a/xen/Makefile b/xen/Makefile index ec34524ed2..255360440e 100644 --- a/xen/Makefile +++ b/xen/Makefile @@ -449,7 +449,7 @@ endif # need-config =20 __all: build =20 -main-targets :=3D build install uninstall clean distclean MAP +main-targets :=3D build install uninstall clean distclean MAP cppcheck cpp= check-html .PHONY: $(main-targets) ifneq ($(XEN_TARGET_ARCH),x86_32) $(main-targets): %: _% ; @@ -537,15 +537,17 @@ _clean: $(Q)$(MAKE) $(clean)=3Dtools/kconfig find . \( -name "*.o" -o -name ".*.d" -o -name ".*.d2" \ -o -name ".*.o.tmp" -o -name "*~" -o -name "core" \ - -o -name '*.lex.c' -o -name '*.tab.[ch]' \ + -o -name '*.lex.c' -o -name '*.tab.[ch]' -o -name '*.c.cppcheck' \ -o -name "*.gcno" -o -name ".*.cmd" -o -name "lib.a" \) -exec rm -f {} \; rm -f include/asm $(TARGET) $(TARGET).gz $(TARGET).efi $(TARGET).efi.map = $(TARGET)-syms $(TARGET)-syms.map rm -f asm-offsets.s arch/*/include/asm/asm-offsets.h rm -f .banner .allconfig.tmp include/xen/compile.h + rm -f xen-cppcheck.xml =20 .PHONY: _distclean _distclean: clean rm -f tags TAGS cscope.files cscope.in.out cscope.out cscope.po.out GTAGS= GPATH GRTAGS GSYMS .config source + rm -rf $(CPPCHECK_HTMLREPORT_OUTDIR) =20 $(TARGET).gz: $(TARGET) gzip -n -f -9 < $< > $@.new @@ -619,6 +621,84 @@ cloc: done; \ done | cloc --list-file=3D- =20 +# What cppcheck command to use. +# To get proper results, it is recommended to build cppcheck manually from= the +# latest source and use CPPCHECK to give the full path to the built versio= n. +CPPCHECK ?=3D cppcheck + +# What cppcheck-htmlreport to use. +# If you give the full path to a self compiled cppcheck, this should be set +# to the full path to cppcheck-html in the htmlreport directory of cppchec= k. +# On recent distribution, this is available in the standard path. +CPPCHECK_HTMLREPORT ?=3D cppcheck-htmlreport + +# By default we generate the report in cppcheck-htmlreport directory in the +# build directory. This can be changed by giving a directory in this varia= ble. +CPPCHECK_HTMLREPORT_OUTDIR ?=3D cppcheck-htmlreport + +# Compile flags to pass to cppcheck: +# - include directories and defines Xen Makefile is passing (from CFLAGS) +# - include config.h as this is passed directly to the compiler. +# - define CPPCHECK as we use to disable or enable some specific part of t= he +# code to solve some cppcheck issues. +# - explicitely enable some cppcheck checks as we do not want to use "all" +# which includes unusedFunction which gives wrong positives as we check = file +# per file. +# +# Compiler defines are in compiler-def.h which is included in config.h +# +CPPCHECKFLAGS :=3D -DCPPCHECK --max-ctu-depth=3D10 \ + --enable=3Dstyle,information,missingInclude \ + --include=3D$(srctree)/include/xen/config.h \ + -I $(srctree)/xsm/flask/include \ + -I $(srctree)/include/xen/libfdt \ + $(filter -D% -I%,$(CFLAGS)) + +# We need to find all C files (as we are not checking assembly files) so +# we find all generated .o files which have a .c corresponding file. +CPPCHECKFILES :=3D $(wildcard $(patsubst $(objtree)/%.o,$(srctree)/%.c, \ + $(filter-out $(objtree)/tools/%, \ + $(shell find $(objtree) -name "*.o")))) + +quiet_cmd_cppcheck_xml =3D CPPCHECK $(patsubst $(srctree)/%,%,$<) +cmd_cppcheck_xml =3D $(CPPCHECK) -v -q --xml $(CPPCHECKFLAGS) \ + --output-file=3D$@ $< + +quiet_cmd_merge_cppcheck_reports =3D CPPCHECK-MERGE $@ +cmd_merge_cppcheck_reports =3D $(srctree)/tools/merge_cppcheck_reports.py = $^ $@ + +quiet_cmd_cppcheck_html =3D CPPCHECK-HTML $< +cmd_cppcheck_html =3D $(CPPCHECK_HTMLREPORT) --file=3D$< --source-dir=3D$(= srctree) \ + --report-dir=3D$(CPPCHECK_HTMLREPORT_OUTDIR) --title= =3DXen + +PHONY +=3D _cppcheck _cppcheck-html cppcheck-version + +_cppcheck-html: xen-cppcheck.xml + $(call if_changed,cppcheck_html) + +_cppcheck: xen-cppcheck.xml + +xen-cppcheck.xml: $(patsubst $(srctree)/%.c,$(objtree)/%.c.cppcheck,$(CPPC= HECKFILES)) +ifeq ($(CPPCHECKFILES),) + $(error Please build Xen before running cppcheck) +endif + $(call if_changed,merge_cppcheck_reports) + +$(objtree)/%.c.cppcheck: $(srctree)/%.c $(objtree)/include/generated/autoc= onf.h $(objtree)/include/generated/compiler-def.h | cppcheck-version + $(call if_changed,cppcheck_xml) + +cppcheck-version: +ifeq ($(shell which $(CPPCHECK)),) + $(error Cannot find cppcheck executable: $(CPPCHECK)) +endif +ifeq ($(shell $(CPPCHECK) --version | awk '{print ($$2 < 2.7)}'),1) + $(error Please upgrade your cppcheck to version 2.7 or greater) +endif + +# Put this in generated headers this way it is cleaned by include/Makefile +$(objtree)/include/generated/compiler-def.h: + $(Q)$(CC) -dM -E -o $@ - < /dev/null + endif #config-build endif # need-sub-make =20 diff --git a/xen/arch/arm/include/asm/processor.h b/xen/arch/arm/include/as= m/processor.h index 852b5f3c24..ef37cfa16f 100644 --- a/xen/arch/arm/include/asm/processor.h +++ b/xen/arch/arm/include/asm/processor.h @@ -219,9 +219,11 @@ SCTLR_Axx_ELx_A | SCTLR_Axx_ELx_C |\ SCTLR_Axx_ELx_WXN | SCTLR_Axx_ELx_EE) =20 +#ifndef CPPCHECK #if (SCTLR_EL2_SET ^ SCTLR_EL2_CLEAR) !=3D 0xffffffffffffffffUL #error "Inconsistent SCTLR_EL2 set/clear bits" #endif +#endif =20 #endif =20 diff --git a/xen/include/xen/config.h b/xen/include/xen/config.h index 85c6f59be9..d888b2314d 100644 --- a/xen/include/xen/config.h +++ b/xen/include/xen/config.h @@ -7,6 +7,10 @@ #ifndef __XEN_CONFIG_H__ #define __XEN_CONFIG_H__ =20 +#ifdef CPPCHECK +#include +#endif + #include =20 #ifndef __ASSEMBLY__ diff --git a/xen/include/xen/kconfig.h b/xen/include/xen/kconfig.h index 4d58c5bb3c..a717b0819c 100644 --- a/xen/include/xen/kconfig.h +++ b/xen/include/xen/kconfig.h @@ -8,6 +8,10 @@ * these only work with boolean option. */ =20 +/* cppcheck is failing to parse the macro so use a dummy one */ +#ifdef CPPCHECK +#define IS_ENABLED(option) option +#else /* * Getting something that works in C and CPP for an arg that may or may * not be defined is tricky. Here, if we have "#define CONFIG_BOOGER 1" @@ -27,5 +31,6 @@ * otherwise. */ #define IS_ENABLED(option) config_enabled(option) +#endif =20 #endif /* __XEN_KCONFIG_H */ diff --git a/xen/tools/merge_cppcheck_reports.py b/xen/tools/merge_cppcheck= _reports.py new file mode 100755 index 0000000000..1c1b63ba56 --- /dev/null +++ b/xen/tools/merge_cppcheck_reports.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python + +""" +This script acts as a tool to merge XML files created by cppcheck. +Usage: + merge_cppcheck_reports.py [FILES] [OUTPUT] + + FILES - list of XML files with extension .cppcheck + OUTPUT - file to store results (with .xml extension). + If not specified, the script will print results to stdout. +""" + +import sys +from xml.etree import ElementTree + +def elements_equal(el1, el2): + if type(el1) !=3D type(el2): return False + + if el1.find('location') is None: return False + if el2.find('location') is None: return False + + el1_location =3D str(el1.find('location').attrib) + el2_location =3D str(el2.find('location').attrib) + + if el1_location !=3D el2_location: return False + + return True + +def contain_element(new, lst): + for elem in lst: + if elements_equal(new, elem): + return True + return False + +def merge(files): + try: + result_xml_root =3D ElementTree.parse(files[0]).getroot() + except: + print("Xml parsing error in %s\n" % (files[0])) + print("Please upgrade your cppcheck to version 2.7 or greater") + sys.exit(1) + insert_point =3D result_xml_root.findall("errors")[0] + curr =3D 1 + total =3D len(files) + numelem =3D len(insert_point) + for xml_file in files[1:]: + try: + xml_root =3D ElementTree.parse(xml_file).getroot() + except: + print("Xml parsing error in %s\n" % (xml_file)) + print("Please upgrade your cppcheck to version 2.7 or greater") + sys.exit(1) + curr_elem_list =3D list(insert_point) + new_elem_list =3D list(xml_root.findall("errors")[0]) + for xml_error_elem in new_elem_list: + if not contain_element(xml_error_elem, curr_elem_list): + insert_point.insert(1,xml_error_elem) + numelem =3D numelem + 1 + curr =3D curr + 1 + sys.stdout.write('\r') + sys.stdout.write(" %d / %d" % (curr,total)) + sys.stdout.flush() + + sys.stdout.write('\r\n') + print("Done: %d elements" % (numelem)) + return result_xml_root + +def run(): + files =3D [] + output =3D None + for i in sys.argv[1:]: + output =3D i if '.xml' in i else None + files.append(i) if '.cppcheck' in i else None + + result =3D merge(files) + + if result is None: + return + + if output is not None: + ElementTree.ElementTree(result).write(output) + else: + print(ElementTree.tostring(result).decode('utf-8')) + +if __name__ =3D=3D '__main__': + run() --=20 2.25.1