From f1cc458cf3b1c972082b14c7901b43300634a78a Mon Sep 17 00:00:00 2001 From: Guilherme Maciel Ferreira Date: Sun, 1 Dec 2013 12:43:09 -0700 Subject: mkimage: added 'static' specifier to match function's prototype. This function should be declared static. Signed-off-by: Guilherme Maciel Ferreira Signed-off-by: Simon Glass --- tools/mkimage.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/mkimage.c b/tools/mkimage.c index 7f221013e3..e12bc318bb 100644 --- a/tools/mkimage.c +++ b/tools/mkimage.c @@ -632,8 +632,7 @@ copy_file (int ifd, const char *datafile, int pad) (void) close (dfd); } -void -usage () +static void usage(void) { fprintf (stderr, "Usage: %s -l image\n" " -l ==> list image header information\n", -- cgit From f86ed6a8d52c99bb2d17d3cac1647edca0c4399c Mon Sep 17 00:00:00 2001 From: Guilherme Maciel Ferreira Date: Sun, 1 Dec 2013 12:43:10 -0700 Subject: tools: moved code common to all image tools to a separated module. In order to avoid duplicating code and keep only one point of modification, the functions, structs and defines useful for "dumpimage" were moved from "mkimage" to a common module called "imagetool". This modification also weakens the coupling between image types (FIT, IMX, MXS, and so on) and image tools (mkimage and dumpimage). Any tool may initialize the "imagetool" through register_image_tool() function, while the image types register themselves within an image tool using the register_image_type() function: +---------------+ +------| fit_image | +--------------+ +-----------+ | +---------------+ | mkimage |--------> | | <-----+ +--------------+ | | +---------------+ | imagetool | <------------| imximage | +--------------+ | | +---------------+ | dumpimage |--------> | | <-----+ +--------------+ +-----------+ | +---------------+ +------| default_image | +---------------+ register_image_tool() register_image_type() Also, the struct "mkimage_params" was renamed to "image_tool_params" to make clear its general purpose. Signed-off-by: Guilherme Maciel Ferreira Signed-off-by: Simon Glass --- tools/Makefile | 2 + tools/aisimage.c | 16 ++--- tools/default_image.c | 10 ++-- tools/fit_image.c | 11 ++-- tools/imagetool.c | 58 ++++++++++++++++++ tools/imagetool.h | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++ tools/imximage.c | 12 ++-- tools/kwbimage.c | 10 ++-- tools/mkimage.c | 22 +------ tools/mkimage.h | 123 +------------------------------------- tools/mxsimage.c | 12 ++-- tools/omapimage.c | 10 ++-- tools/pblimage.c | 10 ++-- tools/ublimage.c | 10 ++-- 14 files changed, 276 insertions(+), 191 deletions(-) create mode 100644 tools/imagetool.c create mode 100644 tools/imagetool.h (limited to 'tools') diff --git a/tools/Makefile b/tools/Makefile index 14d94e39a0..154eae3a36 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -76,6 +76,7 @@ NOPED_OBJ_FILES-y += fit_image.o NOPED_OBJ_FILES-y += image-host.o NOPED_OBJ_FILES-y += imximage.o NOPED_OBJ_FILES-y += kwbimage.o +NOPED_OBJ_FILES-y += imagetool.o NOPED_OBJ_FILES-y += mkenvimage.o NOPED_OBJ_FILES-y += mkimage.o NOPED_OBJ_FILES-y += mxsimage.o @@ -212,6 +213,7 @@ $(obj)mkimage$(SFX): $(obj)aisimage.o \ $(obj)image-fit.o \ $(obj)image-host.o \ $(obj)image.o \ + $(obj)imagetool.o \ $(obj)imximage.o \ $(obj)kwbimage.o \ $(obj)md5.o \ diff --git a/tools/aisimage.c b/tools/aisimage.c index 04fb649899..8de370a2e0 100644 --- a/tools/aisimage.c +++ b/tools/aisimage.c @@ -5,7 +5,7 @@ * SPDX-License-Identifier: GPL-2.0+ */ -#include "mkimage.h" +#include "imagetool.h" #include "aisimage.h" #include @@ -176,7 +176,7 @@ static uint32_t *ais_insert_cmd_header(uint32_t cmd, uint32_t nargs, } -static uint32_t *ais_alloc_buffer(struct mkimage_params *params) +static uint32_t *ais_alloc_buffer(struct image_tool_params *params) { int dfd; struct stat sbuf; @@ -216,7 +216,7 @@ static uint32_t *ais_alloc_buffer(struct mkimage_params *params) return ptr; } -static uint32_t *ais_copy_image(struct mkimage_params *params, +static uint32_t *ais_copy_image(struct image_tool_params *params, uint32_t *aisptr) { @@ -252,7 +252,7 @@ static uint32_t *ais_copy_image(struct mkimage_params *params, } -static int aisimage_generate(struct mkimage_params *params, +static int aisimage_generate(struct image_tool_params *params, struct image_type_params *tparams) { FILE *fd = NULL; @@ -370,7 +370,7 @@ static int aisimage_check_image_types(uint8_t type) } static int aisimage_verify_header(unsigned char *ptr, int image_size, - struct mkimage_params *params) + struct image_tool_params *params) { struct ais_header *ais_hdr = (struct ais_header *)ptr; @@ -384,11 +384,11 @@ static int aisimage_verify_header(unsigned char *ptr, int image_size, } static void aisimage_set_header(void *ptr, struct stat *sbuf, int ifd, - struct mkimage_params *params) + struct image_tool_params *params) { } -int aisimage_check_params(struct mkimage_params *params) +int aisimage_check_params(struct image_tool_params *params) { if (!params) return CFG_INVALID; @@ -427,5 +427,5 @@ static struct image_type_params aisimage_params = { void init_ais_image_type(void) { - mkimage_register(&aisimage_params); + register_image_type(&aisimage_params); } diff --git a/tools/default_image.c b/tools/default_image.c index fd8b9f5f15..cc790b247a 100644 --- a/tools/default_image.c +++ b/tools/default_image.c @@ -14,7 +14,7 @@ * SPDX-License-Identifier: GPL-2.0+ */ -#include "mkimage.h" +#include "imagetool.h" #include #include @@ -29,7 +29,7 @@ static int image_check_image_types(uint8_t type) return EXIT_FAILURE; } -static int image_check_params(struct mkimage_params *params) +static int image_check_params(struct image_tool_params *params) { return ((params->dflag && (params->fflag || params->lflag)) || (params->fflag && (params->dflag || params->lflag)) || @@ -37,7 +37,7 @@ static int image_check_params(struct mkimage_params *params) } static int image_verify_header(unsigned char *ptr, int image_size, - struct mkimage_params *params) + struct image_tool_params *params) { uint32_t len; const unsigned char *data; @@ -86,7 +86,7 @@ static int image_verify_header(unsigned char *ptr, int image_size, } static void image_set_header(void *ptr, struct stat *sbuf, int ifd, - struct mkimage_params *params) + struct image_tool_params *params) { uint32_t checksum; @@ -133,5 +133,5 @@ static struct image_type_params defimage_params = { void init_default_image_type(void) { - mkimage_register(&defimage_params); + register_image_type(&defimage_params); } diff --git a/tools/fit_image.c b/tools/fit_image.c index 0400a60678..1466164f0a 100644 --- a/tools/fit_image.c +++ b/tools/fit_image.c @@ -14,6 +14,7 @@ * SPDX-License-Identifier: GPL-2.0+ */ +#include "imagetool.h" #include "mkimage.h" #include #include @@ -21,7 +22,7 @@ static image_header_t header; static int fit_verify_header (unsigned char *ptr, int image_size, - struct mkimage_params *params) + struct image_tool_params *params) { return fdt_check_header(ptr); } @@ -34,7 +35,7 @@ static int fit_check_image_types (uint8_t type) return EXIT_FAILURE; } -int mmap_fdt(struct mkimage_params *params, const char *fname, void **blobp, +int mmap_fdt(struct image_tool_params *params, const char *fname, void **blobp, struct stat *sbuf) { void *ptr; @@ -88,7 +89,7 @@ int mmap_fdt(struct mkimage_params *params, const char *fname, void **blobp, * returns: * only on success, otherwise calls exit (EXIT_FAILURE); */ -static int fit_handle_file (struct mkimage_params *params) +static int fit_handle_file(struct image_tool_params *params) { char tmpfile[MKIMAGE_MAX_TMPFILE_LEN]; char cmd[MKIMAGE_MAX_DTC_CMDLINE_LEN]; @@ -184,7 +185,7 @@ err_system: return -1; } -static int fit_check_params (struct mkimage_params *params) +static int fit_check_params(struct image_tool_params *params) { return ((params->dflag && (params->fflag || params->lflag)) || (params->fflag && (params->dflag || params->lflag)) || @@ -205,5 +206,5 @@ static struct image_type_params fitimage_params = { void init_fit_image_type (void) { - mkimage_register (&fitimage_params); + register_image_type(&fitimage_params); } diff --git a/tools/imagetool.c b/tools/imagetool.c new file mode 100644 index 0000000000..29d2189097 --- /dev/null +++ b/tools/imagetool.c @@ -0,0 +1,58 @@ +/* + * (C) Copyright 2013 + * + * Written by Guilherme Maciel Ferreira + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "imagetool.h" + +/* + * Callback function to register a image type within a tool + */ +static imagetool_register_t register_func; + +/* + * register_image_tool - + * + * The tool provides its own registration function in order to all image + * types initialize themselves. + */ +void register_image_tool(imagetool_register_t image_register) +{ + /* + * Save the image tool callback function. It will be used to register + * image types within that tool + */ + register_func = image_register; + + /* Init Freescale PBL Boot image generation/list support */ + init_pbl_image_type(); + /* Init Kirkwood Boot image generation/list support */ + init_kwb_image_type(); + /* Init Freescale imx Boot image generation/list support */ + init_imx_image_type(); + /* Init Freescale mxs Boot image generation/list support */ + init_mxs_image_type(); + /* Init FIT image generation/list support */ + init_fit_image_type(); + /* Init TI OMAP Boot image generation/list support */ + init_omap_image_type(); + /* Init Default image generation/list support */ + init_default_image_type(); + /* Init Davinci UBL support */ + init_ubl_image_type(); + /* Init Davinci AIS support */ + init_ais_image_type(); +} + +/* + * register_image_type - + * + * Register a image type within a tool + */ +void register_image_type(struct image_type_params *tparams) +{ + register_func(tparams); +} diff --git a/tools/imagetool.h b/tools/imagetool.h new file mode 100644 index 0000000000..b8adb61ed9 --- /dev/null +++ b/tools/imagetool.h @@ -0,0 +1,161 @@ +/* + * (C) Copyright 2013 + * + * Written by Guilherme Maciel Ferreira + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _IMAGETOOL_H_ +#define _IMAGETOOL_H_ + +#include "os_support.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "fdt_host.h" + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +#define IH_ARCH_DEFAULT IH_ARCH_INVALID + +/* + * This structure defines all such variables those are initialized by + * mkimage and dumpimage main core and need to be referred by image + * type specific functions + */ +struct image_tool_params { + int dflag; + int eflag; + int fflag; + int lflag; + int vflag; + int xflag; + int skipcpy; + int os; + int arch; + int type; + int comp; + char *dtc; + unsigned int addr; + unsigned int ep; + char *imagename; + char *imagename2; + char *datafile; + char *imagefile; + char *cmdname; + const char *keydir; /* Directory holding private keys */ + const char *keydest; /* Destination .dtb for public key */ + const char *comment; /* Comment to add to signature node */ + int require_keys; /* 1 to mark signing keys as 'required' */ +}; + +/* + * image type specific variables and callback functions + */ +struct image_type_params { + /* name is an identification tag string for added support */ + char *name; + /* + * header size is local to the specific image type to be supported, + * mkimage core treats this as number of bytes + */ + uint32_t header_size; + /* Image type header pointer */ + void *hdr; + /* + * There are several arguments that are passed on the command line + * and are registered as flags in image_tool_params structure. + * This callback function can be used to check the passed arguments + * are in-lined with the image type to be supported + * + * Returns 1 if parameter check is successful + */ + int (*check_params) (struct image_tool_params *); + /* + * This function is used by list command (i.e. mkimage -l ) + * image type verification code must be put here + * + * Returns 0 if image header verification is successful + * otherwise, returns respective negative error codes + */ + int (*verify_header) (unsigned char *, int, struct image_tool_params *); + /* Prints image information abstracting from image header */ + void (*print_header) (const void *); + /* + * The header or image contents need to be set as per image type to + * be generated using this callback function. + * further output file post processing (for ex. checksum calculation, + * padding bytes etc..) can also be done in this callback function. + */ + void (*set_header) (void *, struct stat *, int, + struct image_tool_params *); + /* + * Some image generation support for ex (default image type) supports + * more than one type_ids, this callback function is used to check + * whether input (-T ) is supported by registered image + * generation/list low level code + */ + int (*check_image_type) (uint8_t); + /* This callback function will be executed if fflag is defined */ + int (*fflag_handle) (struct image_tool_params *); + /* + * This callback function will be executed for variable size record + * It is expected to build this header in memory and return its length + * and a pointer to it by using image_type_params.header_size and + * image_type_params.hdr. The return value shall indicate if an + * additional padding should be used when copying the data image + * by returning the padding length. + */ + int (*vrec_header) (struct image_tool_params *, + struct image_type_params *); + /* pointer to the next registered entry in linked list */ + struct image_type_params *next; +}; + +/* + * Tool registration function. + */ +typedef void (*imagetool_register_t)(struct image_type_params *); + +/* + * Initializes all image types with the given registration callback + * function. + * An image tool uses this function to initialize all image types. + */ +void register_image_tool(imagetool_register_t image_register); + +/* + * Register a image type within a tool. + * An image type uses this function to register itself within + * all tools. + */ +void register_image_type(struct image_type_params *tparams); + +/* + * There is a c file associated with supported image type low level code + * for ex. default_image.c, fit_image.c + * init_xxx_type() is the only function referred by image tool core to avoid + * a single lined header file, you can define them here + * + * Supported image types init functions + */ +void init_default_image_type(void); +void init_pbl_image_type(void); +void init_ais_image_type(void); +void init_kwb_image_type(void); +void init_imx_image_type(void); +void init_mxs_image_type(void); +void init_fit_image_type(void); +void init_ubl_image_type(void); +void init_omap_image_type(void); + +void pbl_load_uboot(int fd, struct image_tool_params *mparams); + +#endif /* _IMAGETOOL_H_ */ diff --git a/tools/imximage.c b/tools/imximage.c index 511e3f2038..18dc051c5e 100644 --- a/tools/imximage.c +++ b/tools/imximage.c @@ -9,7 +9,7 @@ * SPDX-License-Identifier: GPL-2.0+ */ -#include "mkimage.h" +#include "imagetool.h" #include #include "imximage.h" @@ -520,7 +520,7 @@ static int imximage_check_image_types(uint8_t type) } static int imximage_verify_header(unsigned char *ptr, int image_size, - struct mkimage_params *params) + struct image_tool_params *params) { struct imx_header *imx_hdr = (struct imx_header *) ptr; @@ -549,7 +549,7 @@ static void imximage_print_header(const void *ptr) } static void imximage_set_header(void *ptr, struct stat *sbuf, int ifd, - struct mkimage_params *params) + struct image_tool_params *params) { struct imx_header *imxhdr = (struct imx_header *)ptr; uint32_t dcd_len; @@ -589,7 +589,7 @@ static void imximage_set_header(void *ptr, struct stat *sbuf, int ifd, } } -int imximage_check_params(struct mkimage_params *params) +int imximage_check_params(struct image_tool_params *params) { if (!params) return CFG_INVALID; @@ -611,7 +611,7 @@ int imximage_check_params(struct mkimage_params *params) (params->xflag) || !(strlen(params->imagename)); } -static int imximage_generate(struct mkimage_params *params, +static int imximage_generate(struct image_tool_params *params, struct image_type_params *tparams) { struct imx_header *imxhdr; @@ -701,5 +701,5 @@ static struct image_type_params imximage_params = { void init_imx_image_type(void) { - mkimage_register(&imximage_params); + register_image_type(&imximage_params); } diff --git a/tools/kwbimage.c b/tools/kwbimage.c index 1df6b2051e..109d61686e 100644 --- a/tools/kwbimage.c +++ b/tools/kwbimage.c @@ -6,7 +6,7 @@ * SPDX-License-Identifier: GPL-2.0+ */ -#include "mkimage.h" +#include "imagetool.h" #include #include "kwbimage.h" @@ -54,7 +54,7 @@ static int lineno = -1; /* * Report Error if xflag is set in addition to default */ -static int kwbimage_check_params (struct mkimage_params *params) +static int kwbimage_check_params(struct image_tool_params *params) { if (!strlen (params->imagename)) { printf ("Error:%s - Configuration file not specified, " @@ -288,7 +288,7 @@ INVL_CMD: } static void kwbimage_set_header (void *ptr, struct stat *sbuf, int ifd, - struct mkimage_params *params) + struct image_tool_params *params) { struct kwb_header *hdr = (struct kwb_header *)ptr; bhr_t *mhdr = &hdr->kwb_hdr; @@ -322,7 +322,7 @@ static void kwbimage_set_header (void *ptr, struct stat *sbuf, int ifd, } static int kwbimage_verify_header (unsigned char *ptr, int image_size, - struct mkimage_params *params) + struct image_tool_params *params) { struct kwb_header *hdr = (struct kwb_header *)ptr; bhr_t *mhdr = &hdr->kwb_hdr; @@ -382,5 +382,5 @@ static struct image_type_params kwbimage_params = { void init_kwb_image_type (void) { - mkimage_register (&kwbimage_params); + register_image_type(&kwbimage_params); } diff --git a/tools/mkimage.c b/tools/mkimage.c index e12bc318bb..123d0c7d93 100644 --- a/tools/mkimage.c +++ b/tools/mkimage.c @@ -19,7 +19,7 @@ static void usage(void); struct image_type_params *mkimage_tparams = NULL; /* parameters initialized by core will be used by the image type code */ -struct mkimage_params params = { +struct image_tool_params params = { .os = IH_OS_LINUX, .arch = IH_ARCH_PPC, .type = IH_TYPE_KERNEL, @@ -139,24 +139,8 @@ main (int argc, char **argv) struct image_type_params *tparams = NULL; int pad_len = 0; - /* Init Freescale PBL Boot image generation/list support */ - init_pbl_image_type(); - /* Init Kirkwood Boot image generation/list support */ - init_kwb_image_type (); - /* Init Freescale imx Boot image generation/list support */ - init_imx_image_type (); - /* Init Freescale mxs Boot image generation/list support */ - init_mxs_image_type(); - /* Init FIT image generation/list support */ - init_fit_image_type (); - /* Init TI OMAP Boot image generation/list support */ - init_omap_image_type(); - /* Init Default image generation/list support */ - init_default_image_type (); - /* Init Davinci UBL support */ - init_ubl_image_type(); - /* Init Davinci AIS support */ - init_ais_image_type(); + /* Init all image generation/list support */ + register_image_tool(mkimage_register); params.cmdname = *argv; params.addr = params.ep = 0; diff --git a/tools/mkimage.h b/tools/mkimage.h index af491544e4..d5491b6e60 100644 --- a/tools/mkimage.h +++ b/tools/mkimage.h @@ -20,6 +20,7 @@ #include #include #include "fdt_host.h" +#include "imagetool.h" #undef MKIMAGE_DEBUG @@ -29,8 +30,6 @@ #define debug(fmt,args...) #endif /* MKIMAGE_DEBUG */ -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) - static inline void *map_sysmem(ulong paddr, unsigned long len) { return (void *)(uintptr_t)paddr; @@ -47,124 +46,4 @@ static inline ulong map_to_sysmem(void *ptr) #define MKIMAGE_MAX_DTC_CMDLINE_LEN 512 #define MKIMAGE_DTC "dtc" /* assume dtc is in $PATH */ -#define IH_ARCH_DEFAULT IH_ARCH_INVALID - -/* - * This structure defines all such variables those are initialized by - * mkimage main core and need to be referred by image type specific - * functions - */ -struct mkimage_params { - int dflag; - int eflag; - int fflag; - int lflag; - int vflag; - int xflag; - int skipcpy; - int os; - int arch; - int type; - int comp; - char *dtc; - unsigned int addr; - unsigned int ep; - char *imagename; - char *imagename2; - char *datafile; - char *imagefile; - char *cmdname; - const char *keydir; /* Directory holding private keys */ - const char *keydest; /* Destination .dtb for public key */ - const char *comment; /* Comment to add to signature node */ - int require_keys; /* 1 to mark signing keys as 'required' */ -}; - -/* - * image type specific variables and callback functions - */ -struct image_type_params { - /* name is an identification tag string for added support */ - char *name; - /* - * header size is local to the specific image type to be supported, - * mkimage core treats this as number of bytes - */ - uint32_t header_size; - /* Image type header pointer */ - void *hdr; - /* - * There are several arguments that are passed on the command line - * and are registered as flags in mkimage_params structure. - * This callback function can be used to check the passed arguments - * are in-lined with the image type to be supported - * - * Returns 1 if parameter check is successful - */ - int (*check_params) (struct mkimage_params *); - /* - * This function is used by list command (i.e. mkimage -l ) - * image type verification code must be put here - * - * Returns 0 if image header verification is successful - * otherwise, returns respective negative error codes - */ - int (*verify_header) (unsigned char *, int, struct mkimage_params *); - /* Prints image information abstracting from image header */ - void (*print_header) (const void *); - /* - * The header or image contents need to be set as per image type to - * be generated using this callback function. - * further output file post processing (for ex. checksum calculation, - * padding bytes etc..) can also be done in this callback function. - */ - void (*set_header) (void *, struct stat *, int, - struct mkimage_params *); - /* - * Some image generation support for ex (default image type) supports - * more than one type_ids, this callback function is used to check - * whether input (-T ) is supported by registered image - * generation/list low level code - */ - int (*check_image_type) (uint8_t); - /* This callback function will be executed if fflag is defined */ - int (*fflag_handle) (struct mkimage_params *); - /* - * This callback function will be executed for variable size record - * It is expected to build this header in memory and return its length - * and a pointer to it by using image_type_params.header_size and - * image_type_params.hdr. The return value shall indicate if an - * additional padding should be used when copying the data image - * by returning the padding length. - */ - int (*vrec_header) (struct mkimage_params *, - struct image_type_params *); - /* pointer to the next registered entry in linked list */ - struct image_type_params *next; -}; - -/* - * Exported functions - */ -void mkimage_register (struct image_type_params *tparams); - -/* - * There is a c file associated with supported image type low level code - * for ex. default_image.c, fit_image.c - * init is the only function referred by mkimage core. - * to avoid a single lined header file, you can define them here - * - * Supported image types init functions - */ -void pbl_load_uboot(int fd, struct mkimage_params *mparams); -void init_pbl_image_type(void); -void init_ais_image_type(void); -void init_kwb_image_type (void); -void init_imx_image_type (void); -void init_mxs_image_type(void); -void init_default_image_type (void); -void init_fit_image_type (void); -void init_ubl_image_type(void); -void init_omap_image_type(void); - #endif /* _MKIIMAGE_H_ */ diff --git a/tools/mxsimage.c b/tools/mxsimage.c index 5db19b216f..b214050deb 100644 --- a/tools/mxsimage.c +++ b/tools/mxsimage.c @@ -17,7 +17,7 @@ #include -#include "mkimage.h" +#include "imagetool.h" #include "mxsimage.h" #include @@ -2148,11 +2148,11 @@ static int mxsimage_check_image_types(uint8_t type) } static void mxsimage_set_header(void *ptr, struct stat *sbuf, int ifd, - struct mkimage_params *params) + struct image_tool_params *params) { } -int mxsimage_check_params(struct mkimage_params *params) +int mxsimage_check_params(struct image_tool_params *params) { if (!params) return -1; @@ -2193,7 +2193,7 @@ static int mxsimage_verify_print_header(char *file, int silent) char *imagefile; static int mxsimage_verify_header(unsigned char *ptr, int image_size, - struct mkimage_params *params) + struct image_tool_params *params) { struct sb_boot_image_header *hdr; @@ -2291,7 +2291,7 @@ static int sb_build_image(struct sb_image_ctx *ictx, return 0; } -static int mxsimage_generate(struct mkimage_params *params, +static int mxsimage_generate(struct image_tool_params *params, struct image_type_params *tparams) { int ret; @@ -2337,7 +2337,7 @@ static struct image_type_params mxsimage_params = { void init_mxs_image_type(void) { - mkimage_register(&mxsimage_params); + register_image_type(&mxsimage_params); } #else diff --git a/tools/omapimage.c b/tools/omapimage.c index 8774a7e3ac..d59bc4d40d 100644 --- a/tools/omapimage.c +++ b/tools/omapimage.c @@ -14,7 +14,7 @@ * SPDX-License-Identifier: GPL-2.0+ */ -#include "mkimage.h" +#include "imagetool.h" #include #include "omapimage.h" @@ -69,7 +69,7 @@ static int valid_gph_load_addr(uint32_t load_addr) } static int omapimage_verify_header(unsigned char *ptr, int image_size, - struct mkimage_params *params) + struct image_tool_params *params) { struct ch_toc *toc = (struct ch_toc *)ptr; struct gp_header *gph = (struct gp_header *)(ptr+OMAP_CH_HDR_SIZE); @@ -188,7 +188,7 @@ static int toc_offset(void *hdr, void *member) } static void omapimage_set_header(void *ptr, struct stat *sbuf, int ifd, - struct mkimage_params *params) + struct image_tool_params *params) { struct ch_toc *toc = (struct ch_toc *)ptr; struct ch_settings *chs = (struct ch_settings *) @@ -224,7 +224,7 @@ static void omapimage_set_header(void *ptr, struct stat *sbuf, int ifd, } } -int omapimage_check_params(struct mkimage_params *params) +int omapimage_check_params(struct image_tool_params *params) { return (params->dflag && (params->fflag || params->lflag)) || (params->fflag && (params->dflag || params->lflag)) || @@ -247,5 +247,5 @@ static struct image_type_params omapimage_params = { void init_omap_image_type(void) { - mkimage_register(&omapimage_params); + register_image_type(&omapimage_params); } diff --git a/tools/pblimage.c b/tools/pblimage.c index bac5faff98..ef3d7f6296 100644 --- a/tools/pblimage.c +++ b/tools/pblimage.c @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: GPL-2.0+ */ -#include "mkimage.h" +#include "imagetool.h" #include #include "pblimage.h" @@ -242,7 +242,7 @@ static void add_end_cmd(void) } } -void pbl_load_uboot(int ifd, struct mkimage_params *params) +void pbl_load_uboot(int ifd, struct image_tool_params *params) { FILE *fp_uboot; int size; @@ -281,7 +281,7 @@ static int pblimage_check_image_types(uint8_t type) } static int pblimage_verify_header(unsigned char *ptr, int image_size, - struct mkimage_params *params) + struct image_tool_params *params) { struct pbl_header *pbl_hdr = (struct pbl_header *) ptr; @@ -308,7 +308,7 @@ static void pblimage_print_header(const void *ptr) } static void pblimage_set_header(void *ptr, struct stat *sbuf, int ifd, - struct mkimage_params *params) + struct image_tool_params *params) { /*nothing need to do, pbl_load_uboot takes care of whole file. */ } @@ -327,5 +327,5 @@ static struct image_type_params pblimage_params = { void init_pbl_image_type(void) { pbl_size = 0; - mkimage_register(&pblimage_params); + register_image_type(&pblimage_params); } diff --git a/tools/ublimage.c b/tools/ublimage.c index aafe248758..cbbbe205da 100644 --- a/tools/ublimage.c +++ b/tools/ublimage.c @@ -13,7 +13,7 @@ * SPDX-License-Identifier: GPL-2.0+ */ -#include "mkimage.h" +#include "imagetool.h" #include #include "ublimage.h" @@ -193,7 +193,7 @@ static int ublimage_check_image_types(uint8_t type) } static int ublimage_verify_header(unsigned char *ptr, int image_size, - struct mkimage_params *params) + struct image_tool_params *params) { struct ubl_header *ubl_hdr = (struct ubl_header *)ptr; @@ -211,7 +211,7 @@ static void ublimage_print_header(const void *ptr) } static void ublimage_set_header(void *ptr, struct stat *sbuf, int ifd, - struct mkimage_params *params) + struct image_tool_params *params) { struct ubl_header *ublhdr = (struct ubl_header *)ptr; @@ -219,7 +219,7 @@ static void ublimage_set_header(void *ptr, struct stat *sbuf, int ifd, parse_cfg_file(ublhdr, params->imagename); } -int ublimage_check_params(struct mkimage_params *params) +int ublimage_check_params(struct image_tool_params *params) { if (!params) return CFG_INVALID; @@ -257,5 +257,5 @@ static struct image_type_params ublimage_params = { void init_ubl_image_type(void) { - mkimage_register(&ublimage_params); + register_image_type(&ublimage_params); } -- cgit From a804b5ce2d84dca6f9e145003e588876adf2c71f Mon Sep 17 00:00:00 2001 From: Guilherme Maciel Ferreira Date: Sun, 1 Dec 2013 12:43:11 -0700 Subject: Add dumpimage, a tool to extract data from U-Boot images Given a multi-file image created through the mkimage's -d option: $ mkimage -A x86 -O linux -T multi -n x86 -d vmlinuz:initrd.img:System.map \ multi.img Image Name: x86 Created: Thu Jul 25 10:29:13 2013 Image Type: Intel x86 Linux Multi-File Image (gzip compressed) Data Size: 13722956 Bytes = 13401.32 kB = 13.09 MB Load Address: 00000000 Entry Point: 00000000 Contents: Image 0: 4040128 Bytes = 3945.44 kB = 3.85 MB Image 1: 7991719 Bytes = 7804.41 kB = 7.62 MB Image 2: 1691092 Bytes = 1651.46 kB = 1.61 MB It is possible to perform the innverse operation -- extracting any file from the image -- by using the dumpimage's -i option: $ dumpimage -i multi.img -p 2 System.map Although it's feasible to retrieve "data files" from image through scripting, the requirement to embed tools such 'dd', 'awk' and 'sed' for this sole purpose is cumbersome and unreliable -- once you must keep track of file sizes inside the image. Furthermore, extracting data files using "dumpimage" tool is faster than through scripting. Signed-off-by: Guilherme Maciel Ferreira Signed-off-by: Simon Glass --- tools/.gitignore | 1 + tools/Makefile | 26 +++++ tools/default_image.c | 57 ++++++++++ tools/dumpimage.c | 305 ++++++++++++++++++++++++++++++++++++++++++++++++++ tools/dumpimage.h | 33 ++++++ tools/imagetool.h | 12 ++ 6 files changed, 434 insertions(+) create mode 100644 tools/dumpimage.c create mode 100644 tools/dumpimage.h (limited to 'tools') diff --git a/tools/.gitignore b/tools/.gitignore index a7fee26cdd..2320fd80a1 100644 --- a/tools/.gitignore +++ b/tools/.gitignore @@ -3,6 +3,7 @@ /gen_eth_addr /img2srec /kwboot +/dumpimage /mkenvimage /mkimage /mpc86x_clk diff --git a/tools/Makefile b/tools/Makefile index 154eae3a36..e1264fd38b 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -50,6 +50,7 @@ BIN_FILES-$(CONFIG_BUILD_ENVCRC) += envcrc$(SFX) BIN_FILES-$(CONFIG_CMD_NET) += gen_eth_addr$(SFX) BIN_FILES-$(CONFIG_CMD_LOADS) += img2srec$(SFX) BIN_FILES-$(CONFIG_XWAY_SWAP_BYTES) += xway-swap-bytes$(SFX) +BIN_FILES-y += dumpimage$(SFX) BIN_FILES-y += mkenvimage$(SFX) BIN_FILES-y += mkimage$(SFX) BIN_FILES-$(CONFIG_EXYNOS5250) += mk$(BOARD)spl$(SFX) @@ -72,6 +73,7 @@ EXT_OBJ_FILES-y += lib/sha1.o # Source files located in the tools directory NOPED_OBJ_FILES-y += aisimage.o NOPED_OBJ_FILES-y += default_image.o +NOPED_OBJ_FILES-y += dumpimage.o NOPED_OBJ_FILES-y += fit_image.o NOPED_OBJ_FILES-y += image-host.o NOPED_OBJ_FILES-y += imximage.o @@ -200,6 +202,30 @@ $(obj)xway-swap-bytes$(SFX): $(obj)xway-swap-bytes.o $(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^ $(HOSTSTRIP) $@ +$(obj)dumpimage$(SFX): $(obj)aisimage.o \ + $(FIT_SIG_OBJS) \ + $(obj)crc32.o \ + $(obj)default_image.o \ + $(obj)fit_image.o \ + $(obj)image-fit.o \ + $(obj)image.o \ + $(obj)image-host.o \ + $(obj)imagetool.o \ + $(obj)imximage.o \ + $(obj)kwbimage.o \ + $(obj)dumpimage.o \ + $(obj)md5.o \ + $(obj)mxsimage.o \ + $(obj)omapimage.o \ + $(obj)os_support.o \ + $(obj)pblimage.o \ + $(obj)sha1.o \ + $(obj)ublimage.o \ + $(LIBFDT_OBJS) \ + $(RSA_OBJS) + $(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^ $(HOSTLIBS) + $(HOSTSTRIP) $@ + $(obj)mkenvimage$(SFX): $(obj)crc32.o $(obj)mkenvimage.o \ $(obj)os_support.o $(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^ diff --git a/tools/default_image.c b/tools/default_image.c index cc790b247a..0a0792e503 100644 --- a/tools/default_image.c +++ b/tools/default_image.c @@ -117,6 +117,62 @@ static void image_set_header(void *ptr, struct stat *sbuf, int ifd, image_set_hcrc(hdr, checksum); } +static int image_save_datafile(struct image_tool_params *params, + ulong file_data, ulong file_len) +{ + int dfd; + const char *datafile = params->outfile; + + dfd = open(datafile, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, + S_IRUSR | S_IWUSR); + if (dfd < 0) { + fprintf(stderr, "%s: Can't open \"%s\": %s\n", + params->cmdname, datafile, strerror(errno)); + return -1; + } + + if (write(dfd, (void *)file_data, file_len) != (ssize_t)file_len) { + fprintf(stderr, "%s: Write error on \"%s\": %s\n", + params->cmdname, datafile, strerror(errno)); + close(dfd); + return -1; + } + + close(dfd); + + return 0; +} + +static int image_extract_datafile(void *ptr, struct image_tool_params *params) +{ + const image_header_t *hdr = (const image_header_t *)ptr; + ulong file_data; + ulong file_len; + + if (image_check_type(hdr, IH_TYPE_MULTI)) { + ulong idx = params->pflag; + ulong count; + + /* get the number of data files present in the image */ + count = image_multi_count(hdr); + + /* retrieve the "data file" at the idx position */ + image_multi_getimg(hdr, idx, &file_data, &file_len); + + if ((file_len == 0) || (idx >= count)) { + fprintf(stderr, "%s: No such data file %ld in \"%s\"\n", + params->cmdname, idx, params->imagefile); + return -1; + } + } else { + file_data = image_get_data(hdr); + file_len = image_get_size(hdr); + } + + /* save the "data file" into the file system */ + return image_save_datafile(params, file_data, file_len); +} + /* * Default image type parameters definition */ @@ -128,6 +184,7 @@ static struct image_type_params defimage_params = { .verify_header = image_verify_header, .print_header = image_print_contents, .set_header = image_set_header, + .extract_datafile = image_extract_datafile, .check_params = image_check_params, }; diff --git a/tools/dumpimage.c b/tools/dumpimage.c new file mode 100644 index 0000000000..542ee28210 --- /dev/null +++ b/tools/dumpimage.c @@ -0,0 +1,305 @@ +/* + * Based on mkimage.c. + * + * Written by Guilherme Maciel Ferreira + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "dumpimage.h" +#include +#include + +static void usage(void); + +/* image_type_params linked list to maintain registered image types supports */ +static struct image_type_params *dumpimage_tparams; + +/* parameters initialized by core will be used by the image type code */ +static struct image_tool_params params = { + .type = IH_TYPE_KERNEL, +}; + +/** + * dumpimage_register() - register respective image generation/list support + * + * the input struct image_type_params is checked and appended to the link + * list, if the input structure is already registered, issue an error + * + * @tparams: Image type parameters + */ +static void dumpimage_register(struct image_type_params *tparams) +{ + struct image_type_params **tp; + + if (!tparams) { + fprintf(stderr, "%s: %s: Null input\n", params.cmdname, + __func__); + exit(EXIT_FAILURE); + } + + /* scan the linked list, check for registry and point the last one */ + for (tp = &dumpimage_tparams; *tp != NULL; tp = &(*tp)->next) { + if (!strcmp((*tp)->name, tparams->name)) { + fprintf(stderr, "%s: %s already registered\n", + params.cmdname, tparams->name); + return; + } + } + + /* add input struct entry at the end of link list */ + *tp = tparams; + /* mark input entry as last entry in the link list */ + tparams->next = NULL; + + debug("Registered %s\n", tparams->name); +} + +/** + * dumpimage_get_type() - find the image type params for a given image type + * + * Scan all registered image types and check the input type_id for each + * supported image type + * + * @return respective image_type_params pointer. If the input type is not + * supported by any of registered image types, returns NULL + */ +static struct image_type_params *dumpimage_get_type(int type) +{ + struct image_type_params *curr; + + for (curr = dumpimage_tparams; curr != NULL; curr = curr->next) { + if (curr->check_image_type) { + if (!curr->check_image_type(type)) + return curr; + } + } + return NULL; +} + +/* + * dumpimage_verify_print_header() - verifies the image header + * + * Scan registered image types and verify the image_header for each + * supported image type. If verification is successful, this prints + * the respective header. + * + * @return 0 on success, negative if input image format does not match with + * any of supported image types + */ +static int dumpimage_verify_print_header(void *ptr, struct stat *sbuf) +{ + int retval = -1; + struct image_type_params *curr; + + for (curr = dumpimage_tparams; curr != NULL; curr = curr->next) { + if (curr->verify_header) { + retval = curr->verify_header((unsigned char *)ptr, + sbuf->st_size, ¶ms); + if (retval != 0) + continue; + /* + * Print the image information if verify is + * successful + */ + if (curr->print_header) { + curr->print_header(ptr); + } else { + fprintf(stderr, + "%s: print_header undefined for %s\n", + params.cmdname, curr->name); + } + break; + } + } + + return retval; +} + +/* + * dumpimage_extract_datafile - + * + * It scans all registered image types, + * verifies image_header for each supported image type + * if verification is successful, it extracts the desired file, + * indexed by pflag, from the image + * + * returns negative if input image format does not match with any of + * supported image types + */ +static int dumpimage_extract_datafile(void *ptr, struct stat *sbuf) +{ + int retval = -1; + struct image_type_params *curr; + + for (curr = dumpimage_tparams; curr != NULL; curr = curr->next) { + if (curr->verify_header) { + retval = curr->verify_header((unsigned char *)ptr, + sbuf->st_size, ¶ms); + if (retval != 0) + continue; + /* + * Extract the file from the image + * if verify is successful + */ + if (curr->extract_datafile) { + curr->extract_datafile(ptr, ¶ms); + } else { + fprintf(stderr, + "%s: extract_datafile undefined for %s\n", + params.cmdname, curr->name); + break; + } + } + } + + return retval; +} + +int main(int argc, char **argv) +{ + int opt; + int ifd = -1; + struct stat sbuf; + char *ptr; + int retval = 0; + struct image_type_params *tparams = NULL; + + /* Init all image generation/list support */ + register_image_tool(dumpimage_register); + + params.cmdname = *argv; + + while ((opt = getopt(argc, argv, "li:o:p:V")) != -1) { + switch (opt) { + case 'l': + params.lflag = 1; + break; + case 'i': + params.imagefile = optarg; + params.iflag = 1; + break; + case 'o': + params.outfile = optarg; + break; + case 'p': + params.pflag = strtoul(optarg, &ptr, 10); + if (*ptr) { + fprintf(stderr, + "%s: invalid file position %s\n", + params.cmdname, *argv); + exit(EXIT_FAILURE); + } + break; + case 'V': + printf("dumpimage version %s\n", PLAIN_VERSION); + exit(EXIT_SUCCESS); + default: + usage(); + } + } + + if (optind >= argc) + usage(); + + /* set tparams as per input type_id */ + tparams = dumpimage_get_type(params.type); + if (tparams == NULL) { + fprintf(stderr, "%s: unsupported type %s\n", + params.cmdname, genimg_get_type_name(params.type)); + exit(EXIT_FAILURE); + } + + /* + * check the passed arguments parameters meets the requirements + * as per image type to be generated/listed + */ + if (tparams->check_params) { + if (tparams->check_params(¶ms)) + usage(); + } + + if (params.iflag) + params.datafile = argv[optind]; + else + params.imagefile = argv[optind]; + if (!params.outfile) + params.outfile = params.datafile; + + ifd = open(params.imagefile, O_RDONLY|O_BINARY); + if (ifd < 0) { + fprintf(stderr, "%s: Can't open \"%s\": %s\n", + params.cmdname, params.imagefile, + strerror(errno)); + exit(EXIT_FAILURE); + } + + if (params.lflag || params.iflag) { + if (fstat(ifd, &sbuf) < 0) { + fprintf(stderr, "%s: Can't stat \"%s\": %s\n", + params.cmdname, params.imagefile, + strerror(errno)); + exit(EXIT_FAILURE); + } + + if ((unsigned)sbuf.st_size < tparams->header_size) { + fprintf(stderr, + "%s: Bad size: \"%s\" is not valid image\n", + params.cmdname, params.imagefile); + exit(EXIT_FAILURE); + } + + ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, ifd, 0); + if (ptr == MAP_FAILED) { + fprintf(stderr, "%s: Can't read \"%s\": %s\n", + params.cmdname, params.imagefile, + strerror(errno)); + exit(EXIT_FAILURE); + } + + /* + * Both calls bellow scan through dumpimage registry for all + * supported image types and verify the input image file + * header for match + */ + if (params.iflag) { + /* + * Extract the data files from within the matched + * image type. Returns the error code if not matched + */ + retval = dumpimage_extract_datafile(ptr, &sbuf); + } else { + /* + * Print the image information for matched image type + * Returns the error code if not matched + */ + retval = dumpimage_verify_print_header(ptr, &sbuf); + } + + (void)munmap((void *)ptr, sbuf.st_size); + (void)close(ifd); + + return retval; + } + + (void)close(ifd); + + return EXIT_SUCCESS; +} + +static void usage(void) +{ + fprintf(stderr, "Usage: %s -l image\n" + " -l ==> list image header information\n", + params.cmdname); + fprintf(stderr, + " %s -i image [-p position] [-o outfile] data_file\n" + " -i ==> extract from the 'image' a specific 'data_file'" + ", indexed by 'position' (starting at 0)\n", + params.cmdname); + fprintf(stderr, + " %s -V ==> print version information and exit\n", + params.cmdname); + + exit(EXIT_FAILURE); +} diff --git a/tools/dumpimage.h b/tools/dumpimage.h new file mode 100644 index 0000000000..d78523ded7 --- /dev/null +++ b/tools/dumpimage.h @@ -0,0 +1,33 @@ +/* + * Based on mkimage.c. + * + * Written by Guilherme Maciel Ferreira + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _DUMPIMAGE_H_ +#define _DUMPIMAGE_H_ + +#include "os_support.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "fdt_host.h" +#include "imagetool.h" + +#undef DUMPIMAGE_DEBUG + +#ifdef DUMPIMAGE_DEBUG +#define debug(fmt, args...) printf(fmt, ##args) +#else +#define debug(fmt, args...) +#endif /* DUMPIMAGE_DEBUG */ + +#endif /* _DUMPIMAGE_H_ */ diff --git a/tools/imagetool.h b/tools/imagetool.h index b8adb61ed9..c2c9aea60e 100644 --- a/tools/imagetool.h +++ b/tools/imagetool.h @@ -34,7 +34,9 @@ struct image_tool_params { int dflag; int eflag; int fflag; + int iflag; int lflag; + int pflag; int vflag; int xflag; int skipcpy; @@ -50,6 +52,7 @@ struct image_tool_params { char *datafile; char *imagefile; char *cmdname; + const char *outfile; /* Output filename */ const char *keydir; /* Directory holding private keys */ const char *keydest; /* Destination .dtb for public key */ const char *comment; /* Comment to add to signature node */ @@ -96,6 +99,15 @@ struct image_type_params { */ void (*set_header) (void *, struct stat *, int, struct image_tool_params *); + /* + * This function is used by the command to retrieve a data file from + * the image (i.e. dumpimage -i -p ). + * Thus the code to extract a file from an image must be put here. + * + * Returns 0 if the file was successfully retrieved from the image, + * or a negative value on error. + */ + int (*extract_datafile) (void *, struct image_tool_params *); /* * Some image generation support for ex (default image type) supports * more than one type_ids, this callback function is used to check -- cgit From dd88ab325cfcc7f803afd40600571b3f9c79319c Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 28 Nov 2013 16:29:23 +0900 Subject: Makefile: Move some scripts imported from Linux We have some scripts imported from Linux Kernel: setlocalversion, checkstack.pl, checkpatch.pl, cleanpatch They are located under tools/ directory in U-Boot now. But they were originally located under scripts/ directory in Linux Kernel. This commit moves them to the original location. It is true that binutils-version.sh and dtc-version.sh do not originate in Linux Kernel, but they should be moved by analogy to gcc-version.sh. Signed-off-by: Masahiro Yamada --- tools/binutils-version.sh | 20 - tools/checkpatch.pl | 3709 --------------------------------------------- tools/checkstack.pl | 171 --- tools/cleanpatch | 258 ---- tools/dtc-version.sh | 20 - tools/gcc-version.sh | 32 - tools/setlocalversion | 177 --- 7 files changed, 4387 deletions(-) delete mode 100755 tools/binutils-version.sh delete mode 100755 tools/checkpatch.pl delete mode 100755 tools/checkstack.pl delete mode 100755 tools/cleanpatch delete mode 100755 tools/dtc-version.sh delete mode 100755 tools/gcc-version.sh delete mode 100755 tools/setlocalversion (limited to 'tools') diff --git a/tools/binutils-version.sh b/tools/binutils-version.sh deleted file mode 100755 index d4d9eb4361..0000000000 --- a/tools/binutils-version.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh -# -# binutils-version [-p] gas-command -# -# Prints the binutils version of `gas-command' in a canonical 4-digit form -# such as `0222' for binutils 2.22 -# - -gas="$*" - -if [ ${#gas} -eq 0 ]; then - echo "Error: No assembler specified." - printf "Usage:\n\t$0 \n" - exit 1 -fi - -MAJOR=$($gas --version | head -1 | awk '{print $NF}' | cut -d . -f 1) -MINOR=$($gas --version | head -1 | awk '{print $NF}' | cut -d . -f 2) - -printf "%02d%02d\\n" $MAJOR $MINOR diff --git a/tools/checkpatch.pl b/tools/checkpatch.pl deleted file mode 100755 index 88c5bc7735..0000000000 --- a/tools/checkpatch.pl +++ /dev/null @@ -1,3709 +0,0 @@ -#!/usr/bin/perl -w -# (c) 2001, Dave Jones. (the file handling bit) -# (c) 2005, Joel Schopp (the ugly bit) -# (c) 2007,2008, Andy Whitcroft (new conditions, test suite) -# (c) 2008-2010 Andy Whitcroft -# Licensed under the terms of the GNU GPL License version 2 - -use strict; - -my $P = $0; -$P =~ s@.*/@@g; - -my $V = '0.32'; - -use Getopt::Long qw(:config no_auto_abbrev); - -my $quiet = 0; -my $tree = 1; -my $chk_signoff = 1; -my $chk_patch = 1; -my $tst_only; -my $emacs = 0; -my $terse = 0; -my $file = 0; -my $check = 0; -my $summary = 1; -my $mailback = 0; -my $summary_file = 0; -my $show_types = 0; -my $root; -my %debug; -my %ignore_type = (); -my @ignore = (); -my $help = 0; -my $configuration_file = ".checkpatch.conf"; -my $max_line_length = 80; - -sub help { - my ($exitcode) = @_; - - print << "EOM"; -Usage: $P [OPTION]... [FILE]... -Version: $V - -Options: - -q, --quiet quiet - --no-tree run without a kernel tree - --no-signoff do not check for 'Signed-off-by' line - --patch treat FILE as patchfile (default) - --emacs emacs compile window format - --terse one line per report - -f, --file treat FILE as regular source file - --subjective, --strict enable more subjective tests - --ignore TYPE(,TYPE2...) ignore various comma separated message types - --max-line-length=n set the maximum line length, if exceeded, warn - --show-types show the message "types" in the output - --root=PATH PATH to the kernel tree root - --no-summary suppress the per-file summary - --mailback only produce a report in case of warnings/errors - --summary-file include the filename in summary - --debug KEY=[0|1] turn on/off debugging of KEY, where KEY is one of - 'values', 'possible', 'type', and 'attr' (default - is all off) - --test-only=WORD report only warnings/errors containing WORD - literally - -h, --help, --version display this help and exit - -When FILE is - read standard input. -EOM - - exit($exitcode); -} - -my $conf = which_conf($configuration_file); -if (-f $conf) { - my @conf_args; - open(my $conffile, '<', "$conf") - or warn "$P: Can't find a readable $configuration_file file $!\n"; - - while (<$conffile>) { - my $line = $_; - - $line =~ s/\s*\n?$//g; - $line =~ s/^\s*//g; - $line =~ s/\s+/ /g; - - next if ($line =~ m/^\s*#/); - next if ($line =~ m/^\s*$/); - - my @words = split(" ", $line); - foreach my $word (@words) { - last if ($word =~ m/^#/); - push (@conf_args, $word); - } - } - close($conffile); - unshift(@ARGV, @conf_args) if @conf_args; -} - -GetOptions( - 'q|quiet+' => \$quiet, - 'tree!' => \$tree, - 'signoff!' => \$chk_signoff, - 'patch!' => \$chk_patch, - 'emacs!' => \$emacs, - 'terse!' => \$terse, - 'f|file!' => \$file, - 'subjective!' => \$check, - 'strict!' => \$check, - 'ignore=s' => \@ignore, - 'show-types!' => \$show_types, - 'max-line-length=i' => \$max_line_length, - 'root=s' => \$root, - 'summary!' => \$summary, - 'mailback!' => \$mailback, - 'summary-file!' => \$summary_file, - - 'debug=s' => \%debug, - 'test-only=s' => \$tst_only, - 'h|help' => \$help, - 'version' => \$help -) or help(1); - -help(0) if ($help); - -my $exit = 0; - -if ($#ARGV < 0) { - print "$P: no input files\n"; - exit(1); -} - -@ignore = split(/,/, join(',',@ignore)); -foreach my $word (@ignore) { - $word =~ s/\s*\n?$//g; - $word =~ s/^\s*//g; - $word =~ s/\s+/ /g; - $word =~ tr/[a-z]/[A-Z]/; - - next if ($word =~ m/^\s*#/); - next if ($word =~ m/^\s*$/); - - $ignore_type{$word}++; -} - -my $dbg_values = 0; -my $dbg_possible = 0; -my $dbg_type = 0; -my $dbg_attr = 0; -for my $key (keys %debug) { - ## no critic - eval "\${dbg_$key} = '$debug{$key}';"; - die "$@" if ($@); -} - -my $rpt_cleaners = 0; - -if ($terse) { - $emacs = 1; - $quiet++; -} - -if ($tree) { - if (defined $root) { - if (!top_of_kernel_tree($root)) { - die "$P: $root: --root does not point at a valid tree\n"; - } - } else { - if (top_of_kernel_tree('.')) { - $root = '.'; - } elsif ($0 =~ m@(.*)/scripts/[^/]*$@ && - top_of_kernel_tree($1)) { - $root = $1; - } - } - - if (!defined $root) { - print "Must be run from the top-level dir. of a kernel tree\n"; - exit(2); - } -} - -my $emitted_corrupt = 0; - -our $Ident = qr{ - [A-Za-z_][A-Za-z\d_]* - (?:\s*\#\#\s*[A-Za-z_][A-Za-z\d_]*)* - }x; -our $Storage = qr{extern|static|asmlinkage}; -our $Sparse = qr{ - __user| - __kernel| - __force| - __iomem| - __must_check| - __init_refok| - __kprobes| - __ref| - __rcu - }x; - -# Notes to $Attribute: -# We need \b after 'init' otherwise 'initconst' will cause a false positive in a check -our $Attribute = qr{ - const| - __percpu| - __nocast| - __safe| - __bitwise__| - __packed__| - __packed2__| - __naked| - __maybe_unused| - __always_unused| - __noreturn| - __used| - __cold| - __noclone| - __deprecated| - __read_mostly| - __kprobes| - __(?:mem|cpu|dev|)(?:initdata|initconst|init\b)| - ____cacheline_aligned| - ____cacheline_aligned_in_smp| - ____cacheline_internodealigned_in_smp| - __weak - }x; -our $Modifier; -our $Inline = qr{inline|__always_inline|noinline}; -our $Member = qr{->$Ident|\.$Ident|\[[^]]*\]}; -our $Lval = qr{$Ident(?:$Member)*}; - -our $Float_hex = qr{(?i)0x[0-9a-f]+p-?[0-9]+[fl]?}; -our $Float_dec = qr{(?i)(?:[0-9]+\.[0-9]*|[0-9]*\.[0-9]+)(?:e-?[0-9]+)?[fl]?}; -our $Float_int = qr{(?i)[0-9]+e-?[0-9]+[fl]?}; -our $Float = qr{$Float_hex|$Float_dec|$Float_int}; -our $Constant = qr{$Float|(?i)(?:0x[0-9a-f]+|[0-9]+)[ul]*}; -our $Assignment = qr{\*\=|/=|%=|\+=|-=|<<=|>>=|&=|\^=|\|=|=}; -our $Compare = qr{<=|>=|==|!=|<|>}; -our $Operators = qr{ - <=|>=|==|!=| - =>|->|<<|>>|<|>|!|~| - &&|\|\||,|\^|\+\+|--|&|\||\+|-|\*|\/|% - }x; - -our $NonptrType; -our $Type; -our $Declare; - -our $NON_ASCII_UTF8 = qr{ - [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte - | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs - | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte - | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates - | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3 - | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15 - | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16 -}x; - -our $UTF8 = qr{ - [\x09\x0A\x0D\x20-\x7E] # ASCII - | $NON_ASCII_UTF8 -}x; - -our $typeTypedefs = qr{(?x: - (?:__)?(?:u|s|be|le)(?:8|16|32|64)| - atomic_t -)}; - -our $logFunctions = qr{(?x: - printk(?:_ratelimited|_once|)| - [a-z0-9]+_(?:printk|emerg|alert|crit|err|warning|warn|notice|info|debug|dbg|vdbg|devel|cont|WARN)(?:_ratelimited|_once|)| - WARN(?:_RATELIMIT|_ONCE|)| - panic| - debug| - printf| - MODULE_[A-Z_]+ -)}; - -our $signature_tags = qr{(?xi: - Signed-off-by:| - Acked-by:| - Tested-by:| - Reviewed-by:| - Reported-by:| - To:| - Cc: -)}; - -our @typeList = ( - qr{void}, - qr{(?:unsigned\s+)?char}, - qr{(?:unsigned\s+)?short}, - qr{(?:unsigned\s+)?int}, - qr{(?:unsigned\s+)?long}, - qr{(?:unsigned\s+)?long\s+int}, - qr{(?:unsigned\s+)?long\s+long}, - qr{(?:unsigned\s+)?long\s+long\s+int}, - qr{unsigned}, - qr{float}, - qr{double}, - qr{bool}, - qr{struct\s+$Ident}, - qr{union\s+$Ident}, - qr{enum\s+$Ident}, - qr{${Ident}_t}, - qr{${Ident}_handler}, - qr{${Ident}_handler_fn}, -); -our @modifierList = ( - qr{fastcall}, -); - -our $allowed_asm_includes = qr{(?x: - irq| - memory -)}; -# memory.h: ARM has a custom one - -sub build_types { - my $mods = "(?x: \n" . join("|\n ", @modifierList) . "\n)"; - my $all = "(?x: \n" . join("|\n ", @typeList) . "\n)"; - $Modifier = qr{(?:$Attribute|$Sparse|$mods)}; - $NonptrType = qr{ - (?:$Modifier\s+|const\s+)* - (?: - (?:typeof|__typeof__)\s*\([^\)]*\)| - (?:$typeTypedefs\b)| - (?:${all}\b) - ) - (?:\s+$Modifier|\s+const)* - }x; - $Type = qr{ - $NonptrType - (?:(?:\s|\*|\[\])+\s*const|(?:\s|\*|\[\])+|(?:\s*\[\s*\])+)? - (?:\s+$Inline|\s+$Modifier)* - }x; - $Declare = qr{(?:$Storage\s+)?$Type}; -} -build_types(); - - -our $Typecast = qr{\s*(\(\s*$NonptrType\s*\)){0,1}\s*}; - -# Using $balanced_parens, $LvalOrFunc, or $FuncArg -# requires at least perl version v5.10.0 -# Any use must be runtime checked with $^V - -our $balanced_parens = qr/(\((?:[^\(\)]++|(?-1))*\))/; -our $LvalOrFunc = qr{($Lval)\s*($balanced_parens{0,1})\s*}; -our $FuncArg = qr{$Typecast{0,1}($LvalOrFunc|$Constant)}; - -sub deparenthesize { - my ($string) = @_; - return "" if (!defined($string)); - $string =~ s@^\s*\(\s*@@g; - $string =~ s@\s*\)\s*$@@g; - $string =~ s@\s+@ @g; - return $string; -} - -$chk_signoff = 0 if ($file); - -my @rawlines = (); -my @lines = (); -my $vname; -for my $filename (@ARGV) { - my $FILE; - if ($file) { - open($FILE, '-|', "diff -u /dev/null $filename") || - die "$P: $filename: diff failed - $!\n"; - } elsif ($filename eq '-') { - open($FILE, '<&STDIN'); - } else { - open($FILE, '<', "$filename") || - die "$P: $filename: open failed - $!\n"; - } - if ($filename eq '-') { - $vname = 'Your patch'; - } else { - $vname = $filename; - } - while (<$FILE>) { - chomp; - push(@rawlines, $_); - } - close($FILE); - if (!process($filename)) { - $exit = 1; - } - @rawlines = (); - @lines = (); -} - -exit($exit); - -sub top_of_kernel_tree { - my ($root) = @_; - - my @tree_check = ( - "COPYING", "CREDITS", "Kbuild", "Makefile", - "README", "Documentation", "arch", "include", "drivers", - "fs", "init", "ipc", "kernel", "lib", "scripts", - ); - - foreach my $check (@tree_check) { - if (! -e $root . '/' . $check) { - return 0; - } - } - return 1; -} - -sub parse_email { - my ($formatted_email) = @_; - - my $name = ""; - my $address = ""; - my $comment = ""; - - if ($formatted_email =~ /^(.*)<(\S+\@\S+)>(.*)$/) { - $name = $1; - $address = $2; - $comment = $3 if defined $3; - } elsif ($formatted_email =~ /^\s*<(\S+\@\S+)>(.*)$/) { - $address = $1; - $comment = $2 if defined $2; - } elsif ($formatted_email =~ /(\S+\@\S+)(.*)$/) { - $address = $1; - $comment = $2 if defined $2; - $formatted_email =~ s/$address.*$//; - $name = $formatted_email; - $name =~ s/^\s+|\s+$//g; - $name =~ s/^\"|\"$//g; - # If there's a name left after stripping spaces and - # leading quotes, and the address doesn't have both - # leading and trailing angle brackets, the address - # is invalid. ie: - # "joe smith joe@smith.com" bad - # "joe smith ]+>$/) { - $name = ""; - $address = ""; - $comment = ""; - } - } - - $name =~ s/^\s+|\s+$//g; - $name =~ s/^\"|\"$//g; - $address =~ s/^\s+|\s+$//g; - $address =~ s/^\<|\>$//g; - - if ($name =~ /[^\w \-]/i) { ##has "must quote" chars - $name =~ s/(?"; - } - - return $formatted_email; -} - -sub which_conf { - my ($conf) = @_; - - foreach my $path (split(/:/, ".:$ENV{HOME}:.scripts")) { - if (-e "$path/$conf") { - return "$path/$conf"; - } - } - - return ""; -} - -sub expand_tabs { - my ($str) = @_; - - my $res = ''; - my $n = 0; - for my $c (split(//, $str)) { - if ($c eq "\t") { - $res .= ' '; - $n++; - for (; ($n % 8) != 0; $n++) { - $res .= ' '; - } - next; - } - $res .= $c; - $n++; - } - - return $res; -} -sub copy_spacing { - (my $res = shift) =~ tr/\t/ /c; - return $res; -} - -sub line_stats { - my ($line) = @_; - - # Drop the diff line leader and expand tabs - $line =~ s/^.//; - $line = expand_tabs($line); - - # Pick the indent from the front of the line. - my ($white) = ($line =~ /^(\s*)/); - - return (length($line), length($white)); -} - -my $sanitise_quote = ''; - -sub sanitise_line_reset { - my ($in_comment) = @_; - - if ($in_comment) { - $sanitise_quote = '*/'; - } else { - $sanitise_quote = ''; - } -} -sub sanitise_line { - my ($line) = @_; - - my $res = ''; - my $l = ''; - - my $qlen = 0; - my $off = 0; - my $c; - - # Always copy over the diff marker. - $res = substr($line, 0, 1); - - for ($off = 1; $off < length($line); $off++) { - $c = substr($line, $off, 1); - - # Comments we are wacking completly including the begin - # and end, all to $;. - if ($sanitise_quote eq '' && substr($line, $off, 2) eq '/*') { - $sanitise_quote = '*/'; - - substr($res, $off, 2, "$;$;"); - $off++; - next; - } - if ($sanitise_quote eq '*/' && substr($line, $off, 2) eq '*/') { - $sanitise_quote = ''; - substr($res, $off, 2, "$;$;"); - $off++; - next; - } - if ($sanitise_quote eq '' && substr($line, $off, 2) eq '//') { - $sanitise_quote = '//'; - - substr($res, $off, 2, $sanitise_quote); - $off++; - next; - } - - # A \ in a string means ignore the next character. - if (($sanitise_quote eq "'" || $sanitise_quote eq '"') && - $c eq "\\") { - substr($res, $off, 2, 'XX'); - $off++; - next; - } - # Regular quotes. - if ($c eq "'" || $c eq '"') { - if ($sanitise_quote eq '') { - $sanitise_quote = $c; - - substr($res, $off, 1, $c); - next; - } elsif ($sanitise_quote eq $c) { - $sanitise_quote = ''; - } - } - - #print "c<$c> SQ<$sanitise_quote>\n"; - if ($off != 0 && $sanitise_quote eq '*/' && $c ne "\t") { - substr($res, $off, 1, $;); - } elsif ($off != 0 && $sanitise_quote eq '//' && $c ne "\t") { - substr($res, $off, 1, $;); - } elsif ($off != 0 && $sanitise_quote && $c ne "\t") { - substr($res, $off, 1, 'X'); - } else { - substr($res, $off, 1, $c); - } - } - - if ($sanitise_quote eq '//') { - $sanitise_quote = ''; - } - - # The pathname on a #include may be surrounded by '<' and '>'. - if ($res =~ /^.\s*\#\s*include\s+\<(.*)\>/) { - my $clean = 'X' x length($1); - $res =~ s@\<.*\>@<$clean>@; - - # The whole of a #error is a string. - } elsif ($res =~ /^.\s*\#\s*(?:error|warning)\s+(.*)\b/) { - my $clean = 'X' x length($1); - $res =~ s@(\#\s*(?:error|warning)\s+).*@$1$clean@; - } - - return $res; -} - -sub ctx_statement_block { - my ($linenr, $remain, $off) = @_; - my $line = $linenr - 1; - my $blk = ''; - my $soff = $off; - my $coff = $off - 1; - my $coff_set = 0; - - my $loff = 0; - - my $type = ''; - my $level = 0; - my @stack = (); - my $p; - my $c; - my $len = 0; - - my $remainder; - while (1) { - @stack = (['', 0]) if ($#stack == -1); - - #warn "CSB: blk<$blk> remain<$remain>\n"; - # If we are about to drop off the end, pull in more - # context. - if ($off >= $len) { - for (; $remain > 0; $line++) { - last if (!defined $lines[$line]); - next if ($lines[$line] =~ /^-/); - $remain--; - $loff = $len; - $blk .= $lines[$line] . "\n"; - $len = length($blk); - $line++; - last; - } - # Bail if there is no further context. - #warn "CSB: blk<$blk> off<$off> len<$len>\n"; - if ($off >= $len) { - last; - } - if ($level == 0 && substr($blk, $off) =~ /^.\s*#\s*define/) { - $level++; - $type = '#'; - } - } - $p = $c; - $c = substr($blk, $off, 1); - $remainder = substr($blk, $off); - - #warn "CSB: c<$c> type<$type> level<$level> remainder<$remainder> coff_set<$coff_set>\n"; - - # Handle nested #if/#else. - if ($remainder =~ /^#\s*(?:ifndef|ifdef|if)\s/) { - push(@stack, [ $type, $level ]); - } elsif ($remainder =~ /^#\s*(?:else|elif)\b/) { - ($type, $level) = @{$stack[$#stack - 1]}; - } elsif ($remainder =~ /^#\s*endif\b/) { - ($type, $level) = @{pop(@stack)}; - } - - # Statement ends at the ';' or a close '}' at the - # outermost level. - if ($level == 0 && $c eq ';') { - last; - } - - # An else is really a conditional as long as its not else if - if ($level == 0 && $coff_set == 0 && - (!defined($p) || $p =~ /(?:\s|\}|\+)/) && - $remainder =~ /^(else)(?:\s|{)/ && - $remainder !~ /^else\s+if\b/) { - $coff = $off + length($1) - 1; - $coff_set = 1; - #warn "CSB: mark coff<$coff> soff<$soff> 1<$1>\n"; - #warn "[" . substr($blk, $soff, $coff - $soff + 1) . "]\n"; - } - - if (($type eq '' || $type eq '(') && $c eq '(') { - $level++; - $type = '('; - } - if ($type eq '(' && $c eq ')') { - $level--; - $type = ($level != 0)? '(' : ''; - - if ($level == 0 && $coff < $soff) { - $coff = $off; - $coff_set = 1; - #warn "CSB: mark coff<$coff>\n"; - } - } - if (($type eq '' || $type eq '{') && $c eq '{') { - $level++; - $type = '{'; - } - if ($type eq '{' && $c eq '}') { - $level--; - $type = ($level != 0)? '{' : ''; - - if ($level == 0) { - if (substr($blk, $off + 1, 1) eq ';') { - $off++; - } - last; - } - } - # Preprocessor commands end at the newline unless escaped. - if ($type eq '#' && $c eq "\n" && $p ne "\\") { - $level--; - $type = ''; - $off++; - last; - } - $off++; - } - # We are truly at the end, so shuffle to the next line. - if ($off == $len) { - $loff = $len + 1; - $line++; - $remain--; - } - - my $statement = substr($blk, $soff, $off - $soff + 1); - my $condition = substr($blk, $soff, $coff - $soff + 1); - - #warn "STATEMENT<$statement>\n"; - #warn "CONDITION<$condition>\n"; - - #print "coff<$coff> soff<$off> loff<$loff>\n"; - - return ($statement, $condition, - $line, $remain + 1, $off - $loff + 1, $level); -} - -sub statement_lines { - my ($stmt) = @_; - - # Strip the diff line prefixes and rip blank lines at start and end. - $stmt =~ s/(^|\n)./$1/g; - $stmt =~ s/^\s*//; - $stmt =~ s/\s*$//; - - my @stmt_lines = ($stmt =~ /\n/g); - - return $#stmt_lines + 2; -} - -sub statement_rawlines { - my ($stmt) = @_; - - my @stmt_lines = ($stmt =~ /\n/g); - - return $#stmt_lines + 2; -} - -sub statement_block_size { - my ($stmt) = @_; - - $stmt =~ s/(^|\n)./$1/g; - $stmt =~ s/^\s*{//; - $stmt =~ s/}\s*$//; - $stmt =~ s/^\s*//; - $stmt =~ s/\s*$//; - - my @stmt_lines = ($stmt =~ /\n/g); - my @stmt_statements = ($stmt =~ /;/g); - - my $stmt_lines = $#stmt_lines + 2; - my $stmt_statements = $#stmt_statements + 1; - - if ($stmt_lines > $stmt_statements) { - return $stmt_lines; - } else { - return $stmt_statements; - } -} - -sub ctx_statement_full { - my ($linenr, $remain, $off) = @_; - my ($statement, $condition, $level); - - my (@chunks); - - # Grab the first conditional/block pair. - ($statement, $condition, $linenr, $remain, $off, $level) = - ctx_statement_block($linenr, $remain, $off); - #print "F: c<$condition> s<$statement> remain<$remain>\n"; - push(@chunks, [ $condition, $statement ]); - if (!($remain > 0 && $condition =~ /^\s*(?:\n[+-])?\s*(?:if|else|do)\b/s)) { - return ($level, $linenr, @chunks); - } - - # Pull in the following conditional/block pairs and see if they - # could continue the statement. - for (;;) { - ($statement, $condition, $linenr, $remain, $off, $level) = - ctx_statement_block($linenr, $remain, $off); - #print "C: c<$condition> s<$statement> remain<$remain>\n"; - last if (!($remain > 0 && $condition =~ /^(?:\s*\n[+-])*\s*(?:else|do)\b/s)); - #print "C: push\n"; - push(@chunks, [ $condition, $statement ]); - } - - return ($level, $linenr, @chunks); -} - -sub ctx_block_get { - my ($linenr, $remain, $outer, $open, $close, $off) = @_; - my $line; - my $start = $linenr - 1; - my $blk = ''; - my @o; - my @c; - my @res = (); - - my $level = 0; - my @stack = ($level); - for ($line = $start; $remain > 0; $line++) { - next if ($rawlines[$line] =~ /^-/); - $remain--; - - $blk .= $rawlines[$line]; - - # Handle nested #if/#else. - if ($lines[$line] =~ /^.\s*#\s*(?:ifndef|ifdef|if)\s/) { - push(@stack, $level); - } elsif ($lines[$line] =~ /^.\s*#\s*(?:else|elif)\b/) { - $level = $stack[$#stack - 1]; - } elsif ($lines[$line] =~ /^.\s*#\s*endif\b/) { - $level = pop(@stack); - } - - foreach my $c (split(//, $lines[$line])) { - ##print "C<$c>L<$level><$open$close>O<$off>\n"; - if ($off > 0) { - $off--; - next; - } - - if ($c eq $close && $level > 0) { - $level--; - last if ($level == 0); - } elsif ($c eq $open) { - $level++; - } - } - - if (!$outer || $level <= 1) { - push(@res, $rawlines[$line]); - } - - last if ($level == 0); - } - - return ($level, @res); -} -sub ctx_block_outer { - my ($linenr, $remain) = @_; - - my ($level, @r) = ctx_block_get($linenr, $remain, 1, '{', '}', 0); - return @r; -} -sub ctx_block { - my ($linenr, $remain) = @_; - - my ($level, @r) = ctx_block_get($linenr, $remain, 0, '{', '}', 0); - return @r; -} -sub ctx_statement { - my ($linenr, $remain, $off) = @_; - - my ($level, @r) = ctx_block_get($linenr, $remain, 0, '(', ')', $off); - return @r; -} -sub ctx_block_level { - my ($linenr, $remain) = @_; - - return ctx_block_get($linenr, $remain, 0, '{', '}', 0); -} -sub ctx_statement_level { - my ($linenr, $remain, $off) = @_; - - return ctx_block_get($linenr, $remain, 0, '(', ')', $off); -} - -sub ctx_locate_comment { - my ($first_line, $end_line) = @_; - - # Catch a comment on the end of the line itself. - my ($current_comment) = ($rawlines[$end_line - 1] =~ m@.*(/\*.*\*/)\s*(?:\\\s*)?$@); - return $current_comment if (defined $current_comment); - - # Look through the context and try and figure out if there is a - # comment. - my $in_comment = 0; - $current_comment = ''; - for (my $linenr = $first_line; $linenr < $end_line; $linenr++) { - my $line = $rawlines[$linenr - 1]; - #warn " $line\n"; - if ($linenr == $first_line and $line =~ m@^.\s*\*@) { - $in_comment = 1; - } - if ($line =~ m@/\*@) { - $in_comment = 1; - } - if (!$in_comment && $current_comment ne '') { - $current_comment = ''; - } - $current_comment .= $line . "\n" if ($in_comment); - if ($line =~ m@\*/@) { - $in_comment = 0; - } - } - - chomp($current_comment); - return($current_comment); -} -sub ctx_has_comment { - my ($first_line, $end_line) = @_; - my $cmt = ctx_locate_comment($first_line, $end_line); - - ##print "LINE: $rawlines[$end_line - 1 ]\n"; - ##print "CMMT: $cmt\n"; - - 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); - - $res = ''; - while ($vet =~ /([^[:cntrl:]]*)([[:cntrl:]]|$)/g) { - $res .= $1; - if ($2 ne '') { - $coded = sprintf("^%c", unpack('C', $2) + 64); - $res .= $coded; - } - } - $res =~ s/$/\$/; - - return $res; -} - -my $av_preprocessor = 0; -my $av_pending; -my @av_paren_type; -my $av_pend_colon; - -sub annotate_reset { - $av_preprocessor = 0; - $av_pending = '_'; - @av_paren_type = ('E'); - $av_pend_colon = 'O'; -} - -sub annotate_values { - my ($stream, $type) = @_; - - my $res; - my $var = '_' x length($stream); - my $cur = $stream; - - print "$stream\n" if ($dbg_values > 1); - - while (length($cur)) { - @av_paren_type = ('E') if ($#av_paren_type < 0); - print " <" . join('', @av_paren_type) . - "> <$type> <$av_pending>" if ($dbg_values > 1); - if ($cur =~ /^(\s+)/o) { - print "WS($1)\n" if ($dbg_values > 1); - if ($1 =~ /\n/ && $av_preprocessor) { - $type = pop(@av_paren_type); - $av_preprocessor = 0; - } - - } elsif ($cur =~ /^(\(\s*$Type\s*)\)/ && $av_pending eq '_') { - print "CAST($1)\n" if ($dbg_values > 1); - push(@av_paren_type, $type); - $type = 'c'; - - } elsif ($cur =~ /^($Type)\s*(?:$Ident|,|\)|\(|\s*$)/) { - print "DECLARE($1)\n" if ($dbg_values > 1); - $type = 'T'; - - } elsif ($cur =~ /^($Modifier)\s*/) { - print "MODIFIER($1)\n" if ($dbg_values > 1); - $type = 'T'; - - } elsif ($cur =~ /^(\#\s*define\s*$Ident)(\(?)/o) { - print "DEFINE($1,$2)\n" if ($dbg_values > 1); - $av_preprocessor = 1; - push(@av_paren_type, $type); - if ($2 ne '') { - $av_pending = 'N'; - } - $type = 'E'; - - } elsif ($cur =~ /^(\#\s*(?:undef\s*$Ident|include\b))/o) { - print "UNDEF($1)\n" if ($dbg_values > 1); - $av_preprocessor = 1; - push(@av_paren_type, $type); - - } elsif ($cur =~ /^(\#\s*(?:ifdef|ifndef|if))/o) { - print "PRE_START($1)\n" if ($dbg_values > 1); - $av_preprocessor = 1; - - push(@av_paren_type, $type); - push(@av_paren_type, $type); - $type = 'E'; - - } elsif ($cur =~ /^(\#\s*(?:else|elif))/o) { - print "PRE_RESTART($1)\n" if ($dbg_values > 1); - $av_preprocessor = 1; - - push(@av_paren_type, $av_paren_type[$#av_paren_type]); - - $type = 'E'; - - } elsif ($cur =~ /^(\#\s*(?:endif))/o) { - print "PRE_END($1)\n" if ($dbg_values > 1); - - $av_preprocessor = 1; - - # Assume all arms of the conditional end as this - # one does, and continue as if the #endif was not here. - pop(@av_paren_type); - push(@av_paren_type, $type); - $type = 'E'; - - } elsif ($cur =~ /^(\\\n)/o) { - print "PRECONT($1)\n" if ($dbg_values > 1); - - } elsif ($cur =~ /^(__attribute__)\s*\(?/o) { - print "ATTR($1)\n" if ($dbg_values > 1); - $av_pending = $type; - $type = 'N'; - - } elsif ($cur =~ /^(sizeof)\s*(\()?/o) { - print "SIZEOF($1)\n" if ($dbg_values > 1); - if (defined $2) { - $av_pending = 'V'; - } - $type = 'N'; - - } elsif ($cur =~ /^(if|while|for)\b/o) { - print "COND($1)\n" if ($dbg_values > 1); - $av_pending = 'E'; - $type = 'N'; - - } elsif ($cur =~/^(case)/o) { - print "CASE($1)\n" if ($dbg_values > 1); - $av_pend_colon = 'C'; - $type = 'N'; - - } elsif ($cur =~/^(return|else|goto|typeof|__typeof__)\b/o) { - print "KEYWORD($1)\n" if ($dbg_values > 1); - $type = 'N'; - - } elsif ($cur =~ /^(\()/o) { - print "PAREN('$1')\n" if ($dbg_values > 1); - push(@av_paren_type, $av_pending); - $av_pending = '_'; - $type = 'N'; - - } elsif ($cur =~ /^(\))/o) { - my $new_type = pop(@av_paren_type); - if ($new_type ne '_') { - $type = $new_type; - print "PAREN('$1') -> $type\n" - if ($dbg_values > 1); - } else { - print "PAREN('$1')\n" if ($dbg_values > 1); - } - - } elsif ($cur =~ /^($Ident)\s*\(/o) { - print "FUNC($1)\n" if ($dbg_values > 1); - $type = 'V'; - $av_pending = 'V'; - - } elsif ($cur =~ /^($Ident\s*):(?:\s*\d+\s*(,|=|;))?/) { - if (defined $2 && $type eq 'C' || $type eq 'T') { - $av_pend_colon = 'B'; - } elsif ($type eq 'E') { - $av_pend_colon = 'L'; - } - print "IDENT_COLON($1,$type>$av_pend_colon)\n" if ($dbg_values > 1); - $type = 'V'; - - } elsif ($cur =~ /^($Ident|$Constant)/o) { - print "IDENT($1)\n" if ($dbg_values > 1); - $type = 'V'; - - } elsif ($cur =~ /^($Assignment)/o) { - print "ASSIGN($1)\n" if ($dbg_values > 1); - $type = 'N'; - - } elsif ($cur =~/^(;|{|})/) { - print "END($1)\n" if ($dbg_values > 1); - $type = 'E'; - $av_pend_colon = 'O'; - - } elsif ($cur =~/^(,)/) { - print "COMMA($1)\n" if ($dbg_values > 1); - $type = 'C'; - - } elsif ($cur =~ /^(\?)/o) { - print "QUESTION($1)\n" if ($dbg_values > 1); - $type = 'N'; - - } elsif ($cur =~ /^(:)/o) { - print "COLON($1,$av_pend_colon)\n" if ($dbg_values > 1); - - substr($var, length($res), 1, $av_pend_colon); - if ($av_pend_colon eq 'C' || $av_pend_colon eq 'L') { - $type = 'E'; - } else { - $type = 'N'; - } - $av_pend_colon = 'O'; - - } elsif ($cur =~ /^(\[)/o) { - print "CLOSE($1)\n" if ($dbg_values > 1); - $type = 'N'; - - } elsif ($cur =~ /^(-(?![->])|\+(?!\+)|\*|\&\&|\&)/o) { - my $variant; - - print "OPV($1)\n" if ($dbg_values > 1); - if ($type eq 'V') { - $variant = 'B'; - } else { - $variant = 'U'; - } - - substr($var, length($res), 1, $variant); - $type = 'N'; - - } elsif ($cur =~ /^($Operators)/o) { - print "OP($1)\n" if ($dbg_values > 1); - if ($1 ne '++' && $1 ne '--') { - $type = 'N'; - } - - } elsif ($cur =~ /(^.)/o) { - print "C($1)\n" if ($dbg_values > 1); - } - if (defined $1) { - $cur = substr($cur, length($1)); - $res .= $type x length($1); - } - } - - return ($res, $var); -} - -sub possible { - my ($possible, $line) = @_; - my $notPermitted = qr{(?: - ^(?: - $Modifier| - $Storage| - $Type| - DEFINE_\S+ - )$| - ^(?: - goto| - return| - case| - else| - asm|__asm__| - do| - \#| - \#\#| - )(?:\s|$)| - ^(?:typedef|struct|enum)\b - )}x; - warn "CHECK<$possible> ($line)\n" if ($dbg_possible > 2); - if ($possible !~ $notPermitted) { - # Check for modifiers. - $possible =~ s/\s*$Storage\s*//g; - $possible =~ s/\s*$Sparse\s*//g; - if ($possible =~ /^\s*$/) { - - } elsif ($possible =~ /\s/) { - $possible =~ s/\s*$Type\s*//g; - for my $modifier (split(' ', $possible)) { - if ($modifier !~ $notPermitted) { - warn "MODIFIER: $modifier ($possible) ($line)\n" if ($dbg_possible); - push(@modifierList, $modifier); - } - } - - } else { - warn "POSSIBLE: $possible ($line)\n" if ($dbg_possible); - push(@typeList, $possible); - } - build_types(); - } else { - warn "NOTPOSS: $possible ($line)\n" if ($dbg_possible > 1); - } -} - -my $prefix = ''; - -sub show_type { - return !defined $ignore_type{$_[0]}; -} - -sub report { - if (!show_type($_[1]) || - (defined $tst_only && $_[2] !~ /\Q$tst_only\E/)) { - return 0; - } - my $line; - if ($show_types) { - $line = "$prefix$_[0]:$_[1]: $_[2]\n"; - } else { - $line = "$prefix$_[0]: $_[2]\n"; - } - $line = (split('\n', $line))[0] . "\n" if ($terse); - - push(our @report, $line); - - return 1; -} -sub report_dump { - our @report; -} - -sub ERROR { - if (report("ERROR", $_[0], $_[1])) { - our $clean = 0; - our $cnt_error++; - } -} -sub WARN { - if (report("WARNING", $_[0], $_[1])) { - our $clean = 0; - our $cnt_warn++; - } -} -sub CHK { - if ($check && report("CHECK", $_[0], $_[1])) { - our $clean = 0; - our $cnt_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_PATH", - "use relative pathname instead of absolute in changelog text\n" . $herecurr); - } -} - -sub pos_last_openparen { - my ($line) = @_; - - my $pos = 0; - - my $opens = $line =~ tr/\(/\(/; - my $closes = $line =~ tr/\)/\)/; - - my $last_openparen = 0; - - if (($opens == 0) || ($closes >= $opens)) { - return -1; - } - - my $len = length($line); - - for ($pos = 0; $pos < $len; $pos++) { - my $string = substr($line, $pos); - if ($string =~ /^($FuncArg|$balanced_parens)/) { - $pos += length($1) - 1; - } elsif (substr($line, $pos, 1) eq '(') { - $last_openparen = $pos; - } elsif (index($string, '(') == -1) { - last; - } - } - - return $last_openparen + 1; -} - -sub process { - my $filename = shift; - - my $linenr=0; - my $prevline=""; - my $prevrawline=""; - my $stashline=""; - my $stashrawline=""; - - my $length; - my $indent; - my $previndent=0; - my $stashindent=0; - - our $clean = 1; - my $signoff = 0; - my $is_patch = 0; - - my $in_header_lines = 1; - my $in_commit_log = 0; #Scanning lines before patch - - my $non_utf8_charset = 0; - - our @report = (); - our $cnt_lines = 0; - our $cnt_error = 0; - our $cnt_warn = 0; - our $cnt_chk = 0; - - # Trace the real file/line as we go. - my $realfile = ''; - my $realline = 0; - my $realcnt = 0; - my $here = ''; - my $in_comment = 0; - my $comment_edge = 0; - my $first_line = 0; - my $p1_prefix = ''; - - my $prev_values = 'E'; - - # suppression flags - my %suppress_ifbraces; - my %suppress_whiletrailers; - my %suppress_export; - my $suppress_statement = 0; - - my %camelcase = (); - - # Pre-scan the patch sanitizing the lines. - # Pre-scan the patch looking for any __setup documentation. - # - my @setup_docs = (); - my $setup_docs = 0; - - sanitise_line_reset(); - my $line; - foreach my $rawline (@rawlines) { - $linenr++; - $line = $rawline; - - if ($rawline=~/^\+\+\+\s+(\S+)/) { - $setup_docs = 0; - if ($1 =~ m@Documentation/kernel-parameters.txt$@) { - $setup_docs = 1; - } - #next; - } - if ($rawline=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) { - $realline=$1-1; - if (defined $2) { - $realcnt=$3+1; - } else { - $realcnt=1+1; - } - $in_comment = 0; - - # Guestimate if this is a continuing comment. Run - # the context looking for a comment "edge". If this - # edge is a close comment then we must be in a comment - # at context start. - my $edge; - 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"; - last if (!defined $rawlines[$ln - 1]); - if ($rawlines[$ln - 1] =~ m@(/\*|\*/)@ && - $rawlines[$ln - 1] !~ m@"[^"]*(?:/\*|\*/)[^"]*"@) { - ($edge) = $1; - last; - } - } - if (defined $edge && $edge eq '*/') { - $in_comment = 1; - } - - # Guestimate if this is a continuing comment. If this - # is the start of a diff block and this line starts - # ' *' then it is very likely a comment. - if (!defined $edge && - $rawlines[$linenr] =~ m@^.\s*(?:\*\*+| \*)(?:\s|$)@) - { - $in_comment = 1; - } - - ##print "COMMENT:$in_comment edge<$edge> $rawline\n"; - sanitise_line_reset($in_comment); - - } elsif ($realcnt && $rawline =~ /^(?:\+| |$)/) { - # Standardise the strings and chars within the input to - # simplify matching -- only bother with positive lines. - $line = sanitise_line($rawline); - } - push(@lines, $line); - - if ($realcnt > 1) { - $realcnt-- if ($line =~ /^(?:\+| |$)/); - } else { - $realcnt = 0; - } - - #print "==>$rawline\n"; - #print "-->$line\n"; - - if ($setup_docs && $line =~ /^\+/) { - push(@setup_docs, $line); - } - } - - $prefix = ''; - - $realcnt = 0; - $linenr = 0; - foreach my $line (@lines) { - $linenr++; - - my $rawline = $rawlines[$linenr - 1]; - -#extract the line range in the file after the patch is applied - if ($line=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) { - $is_patch = 1; - $first_line = $linenr + 1; - $realline=$1-1; - if (defined $2) { - $realcnt=$3+1; - } else { - $realcnt=1+1; - } - annotate_reset(); - $prev_values = 'E'; - - %suppress_ifbraces = (); - %suppress_whiletrailers = (); - %suppress_export = (); - $suppress_statement = 0; - next; - -# track the line number as we move through the hunk, note that -# new versions of GNU diff omit the leading space on completely -# blank context lines so we need to count that too. - } elsif ($line =~ /^( |\+|$)/) { - $realline++; - $realcnt-- if ($realcnt != 0); - - # Measure the line length and indent. - ($length, $indent) = line_stats($rawline); - - # Track the previous line. - ($prevline, $stashline) = ($stashline, $line); - ($previndent, $stashindent) = ($stashindent, $indent); - ($prevrawline, $stashrawline) = ($stashrawline, $rawline); - - #warn "line<$line>\n"; - - } elsif ($realcnt == 1) { - $realcnt--; - } - - my $hunk_line = ($realcnt != 0); - -#make up the handle for any error we report on this line - $prefix = "$filename:$realline: " if ($emacs && $file); - $prefix = "$filename:$linenr: " if ($emacs && !$file); - - $here = "#$linenr: " if (!$file); - $here = "#$realline: " if ($file); - - # extract the filename as it passes - if ($line =~ /^diff --git.*?(\S+)$/) { - $realfile = $1; - $realfile =~ s@^([^/]*)/@@; - $in_commit_log = 0; - } elsif ($line =~ /^\+\+\+\s+(\S+)/) { - $realfile = $1; - $realfile =~ s@^([^/]*)/@@; - $in_commit_log = 0; - - $p1_prefix = $1; - if (!$file && $tree && $p1_prefix ne '' && - -e "$root/$p1_prefix") { - WARN("PATCH_PREFIX", - "patch prefix '$p1_prefix' exists, appears to be a -p0 patch\n"); - } - - if ($realfile =~ m@^include/asm/@) { - ERROR("MODIFIED_INCLUDE_ASM", - "do not modify files in include/asm, change architecture specific files in include/asm-\n" . "$here$rawline\n"); - } - next; - } - - $here .= "FILE: $realfile:$realline:" if ($realcnt != 0); - - my $hereline = "$here\n$rawline\n"; - my $herecurr = "$here\n$rawline\n"; - my $hereprev = "$here\n$prevrawline\n$rawline\n"; - - $cnt_lines++ if ($realcnt != 0); - -# Check for incorrect file permissions - if ($line =~ /^new (file )?mode.*[7531]\d{0,2}$/) { - my $permhere = $here . "FILE: $realfile\n"; - if ($realfile =~ /(Makefile|Kconfig|\.c|\.h|\.S|\.tmpl)$/) { - ERROR("EXECUTE_PERMISSIONS", - "do not set execute permissions for source files\n" . $permhere); - } - } - -# Check the patch for a signoff: - if ($line =~ /^\s*signed-off-by:/i) { - $signoff++; - $in_commit_log = 0; - } - -# Check signature styles - if (!$in_header_lines && - $line =~ /^(\s*)([a-z0-9_-]+by:|$signature_tags)(\s*)(.*)/i) { - my $space_before = $1; - my $sign_off = $2; - my $space_after = $3; - my $email = $4; - my $ucfirst_sign_off = ucfirst(lc($sign_off)); - - if ($sign_off !~ /$signature_tags/) { - WARN("BAD_SIGN_OFF", - "Non-standard signature: $sign_off\n" . $herecurr); - } - if (defined $space_before && $space_before ne "") { - WARN("BAD_SIGN_OFF", - "Do not use whitespace before $ucfirst_sign_off\n" . $herecurr); - } - if ($sign_off =~ /-by:$/i && $sign_off ne $ucfirst_sign_off) { - WARN("BAD_SIGN_OFF", - "'$ucfirst_sign_off' is the preferred signature form\n" . $herecurr); - } - if (!defined $space_after || $space_after ne " ") { - WARN("BAD_SIGN_OFF", - "Use a single space after $ucfirst_sign_off\n" . $herecurr); - } - - my ($email_name, $email_address, $comment) = parse_email($email); - my $suggested_email = format_email(($email_name, $email_address)); - if ($suggested_email eq "") { - ERROR("BAD_SIGN_OFF", - "Unrecognized email address: '$email'\n" . $herecurr); - } else { - my $dequoted = $suggested_email; - $dequoted =~ s/^"//; - $dequoted =~ s/" $comment" ne $email && - "$suggested_email$comment" ne $email) { - WARN("BAD_SIGN_OFF", - "email address '$email' might be better as '$suggested_email$comment'\n" . $herecurr); - } - } - } - -# Check for wrappage within a valid hunk of the file - if ($realcnt != 0 && $line !~ m{^(?:\+|-| |\\ No newline|$)}) { - ERROR("CORRUPTED_PATCH", - "patch seems to be corrupt (line wrapped?)\n" . - $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*$/) { - my ($utf8_prefix) = ($rawline =~ /^($UTF8*)/); - - my $blank = copy_spacing($rawline); - my $ptr = substr($blank, 0, length($utf8_prefix)) . "^"; - my $hereptr = "$hereline$ptr\n"; - - CHK("INVALID_UTF8", - "Invalid UTF-8, patch and commit message should be encoded in UTF-8\n" . $hereptr); - } - -# Check if it's the start of a commit log -# (not a header line and we haven't seen the patch filename) - if ($in_header_lines && $realfile =~ /^$/ && - $rawline !~ /^(commit\b|from\b|[\w-]+:).+$/i) { - $in_header_lines = 0; - $in_commit_log = 1; - } - -# Check if there is UTF-8 in a commit log when a mail header has explicitly -# declined it, i.e defined some charset where it is missing. - if ($in_header_lines && - $rawline =~ /^Content-Type:.+charset="(.+)".*$/ && - $1 !~ /utf-8/i) { - $non_utf8_charset = 1; - } - - if ($in_commit_log && $non_utf8_charset && $realfile =~ /^$/ && - $rawline =~ /$NON_ASCII_UTF8/) { - WARN("UTF8_BEFORE_PATCH", - "8-bit UTF-8 used in possible commit log\n" . $herecurr); - } - -# ignore non-hunk lines and lines being removed - next if (!$hunk_line || $line =~ /^-/); - -#trailing whitespace - if ($line =~ /^\+.*\015/) { - my $herevet = "$here\n" . cat_vet($rawline) . "\n"; - ERROR("DOS_LINE_ENDINGS", - "DOS line endings\n" . $herevet); - - } elsif ($rawline =~ /^\+.*\S\s+$/ || $rawline =~ /^\+\s+$/) { - my $herevet = "$here\n" . cat_vet($rawline) . "\n"; - ERROR("TRAILING_WHITESPACE", - "trailing whitespace\n" . $herevet); - $rpt_cleaners = 1; - } - -# check for Kconfig help text having a real description -# Only applies when adding the entry originally, after that we do not have -# sufficient context to determine whether it is indeed long enough. - if ($realfile =~ /Kconfig/ && - $line =~ /.\s*config\s+/) { - my $length = 0; - my $cnt = $realcnt; - my $ln = $linenr + 1; - my $f; - my $is_start = 0; - my $is_end = 0; - for (; $cnt > 0 && defined $lines[$ln - 1]; $ln++) { - $f = $lines[$ln - 1]; - $cnt-- if ($lines[$ln - 1] !~ /^-/); - $is_end = $lines[$ln - 1] =~ /^\+/; - - next if ($f =~ /^-/); - - if ($lines[$ln - 1] =~ /.\s*(?:bool|tristate)\s*\"/) { - $is_start = 1; - } elsif ($lines[$ln - 1] =~ /.\s*(?:---)?help(?:---)?$/) { - $length = -1; - } - - $f =~ s/^.//; - $f =~ s/#.*//; - $f =~ s/^\s+//; - next if ($f =~ /^$/); - if ($f =~ /^\s*config\s/) { - $is_end = 1; - last; - } - $length++; - } - WARN("CONFIG_DESCRIPTION", - "please write a paragraph that describes the config symbol fully\n" . $herecurr) if ($is_start && $is_end && $length < 4); - #print "is_start<$is_start> is_end<$is_end> length<$length>\n"; - } - -# discourage the addition of CONFIG_EXPERIMENTAL in Kconfig. - if ($realfile =~ /Kconfig/ && - $line =~ /.\s*depends on\s+.*\bEXPERIMENTAL\b/) { - WARN("CONFIG_EXPERIMENTAL", - "Use of CONFIG_EXPERIMENTAL is deprecated. For alternatives, see https://lkml.org/lkml/2012/10/23/580\n"); - } - - if (($realfile =~ /Makefile.*/ || $realfile =~ /Kbuild.*/) && - ($line =~ /\+(EXTRA_[A-Z]+FLAGS).*/)) { - my $flag = $1; - my $replacement = { - 'EXTRA_AFLAGS' => 'asflags-y', - 'EXTRA_CFLAGS' => 'ccflags-y', - 'EXTRA_CPPFLAGS' => 'cppflags-y', - 'EXTRA_LDFLAGS' => 'ldflags-y', - }; - - WARN("DEPRECATED_VARIABLE", - "Use of $flag is deprecated, please use \`$replacement->{$flag} instead.\n" . $herecurr) if ($replacement->{$flag}); - } - -# check we are in a valid source file if not then ignore this hunk - next if ($realfile !~ /\.(h|c|s|S|pl|sh)$/); - -#line length limit - if ($line =~ /^\+/ && $prevrawline !~ /\/\*\*/ && - $rawline !~ /^.\s*\*\s*\@$Ident\s/ && - !($line =~ /^\+\s*$logFunctions\s*\(\s*(?:(KERN_\S+\s*|[^"]*))?"[X\t]*"\s*(?:|,|\)\s*;)\s*$/ || - $line =~ /^\+\s*"[^"]*"\s*(?:\s*|,|\)\s*;)\s*$/) && - $length > $max_line_length) - { - WARN("LONG_LINE", - "line over $max_line_length characters\n" . $herecurr); - } - -# Check for user-visible strings broken across lines, which breaks the ability -# to grep for the string. Limited to strings used as parameters (those -# following an open parenthesis), which almost completely eliminates false -# positives, as well as warning only once per parameter rather than once per -# line of the string. Make an exception when the previous string ends in a -# newline (multiple lines in one string constant) or \n\t (common in inline -# assembly to indent the instruction on the following line). - if ($line =~ /^\+\s*"/ && - $prevline =~ /"\s*$/ && - $prevline =~ /\(/ && - $prevrawline !~ /\\n(?:\\t)*"\s*$/) { - WARN("SPLIT_STRING", - "quoted string split across lines\n" . $hereprev); - } - -# check for spaces before a quoted newline - if ($rawline =~ /^.*\".*\s\\n/) { - WARN("QUOTED_WHITESPACE_BEFORE_NEWLINE", - "unnecessary whitespace before a quoted newline\n" . $herecurr); - } - -# check for adding lines without a newline. - if ($line =~ /^\+/ && defined $lines[$linenr] && $lines[$linenr] =~ /^\\ No newline at end of file/) { - WARN("MISSING_EOF_NEWLINE", - "adding a line without newline at end of file\n" . $herecurr); - } - -# Blackfin: use hi/lo macros - if ($realfile =~ m@arch/blackfin/.*\.S$@) { - if ($line =~ /\.[lL][[:space:]]*=.*&[[:space:]]*0x[fF][fF][fF][fF]/) { - my $herevet = "$here\n" . cat_vet($line) . "\n"; - ERROR("LO_MACRO", - "use the LO() macro, not (... & 0xFFFF)\n" . $herevet); - } - if ($line =~ /\.[hH][[:space:]]*=.*>>[[:space:]]*16/) { - my $herevet = "$here\n" . cat_vet($line) . "\n"; - ERROR("HI_MACRO", - "use the HI() macro, not (... >> 16)\n" . $herevet); - } - } - -# 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. - if ($rawline =~ /^\+\s* \t\s*\S/ || - $rawline =~ /^\+\s* \s*/) { - my $herevet = "$here\n" . cat_vet($rawline) . "\n"; - ERROR("CODE_INDENT", - "code indent should use tabs where possible\n" . $herevet); - $rpt_cleaners = 1; - } - -# check for space before tabs. - if ($rawline =~ /^\+/ && $rawline =~ / \t/) { - my $herevet = "$here\n" . cat_vet($rawline) . "\n"; - WARN("SPACE_BEFORE_TAB", - "please, no space before tabs\n" . $herevet); - } - -# check for && or || at the start of a line - if ($rawline =~ /^\+\s*(&&|\|\|)/) { - CHK("LOGICAL_CONTINUATIONS", - "Logical continuations should be on the previous line\n" . $hereprev); - } - -# check multi-line statement indentation matches previous line - if ($^V && $^V ge 5.10.0 && - $prevline =~ /^\+(\t*)(if \(|$Ident\().*(\&\&|\|\||,)\s*$/) { - $prevline =~ /^\+(\t*)(.*)$/; - my $oldindent = $1; - my $rest = $2; - - my $pos = pos_last_openparen($rest); - if ($pos >= 0) { - $line =~ /^(\+| )([ \t]*)/; - my $newindent = $2; - - my $goodtabindent = $oldindent . - "\t" x ($pos / 8) . - " " x ($pos % 8); - my $goodspaceindent = $oldindent . " " x $pos; - - if ($newindent ne $goodtabindent && - $newindent ne $goodspaceindent) { - CHK("PARENTHESIS_ALIGNMENT", - "Alignment should match open parenthesis\n" . $hereprev); - } - } - } - - if ($line =~ /^\+.*\*[ \t]*\)[ \t]+/) { - CHK("SPACING", - "No space is necessary after a cast\n" . $hereprev); - } - - if ($realfile =~ m@^(drivers/net/|net/)@ && - $rawline =~ /^\+[ \t]*\/\*[ \t]*$/ && - $prevrawline =~ /^\+[ \t]*$/) { - WARN("NETWORKING_BLOCK_COMMENT_STYLE", - "networking block comments don't use an empty /* line, use /* Comment...\n" . $hereprev); - } - - if ($realfile =~ m@^(drivers/net/|net/)@ && - $rawline !~ m@^\+[ \t]*\*/[ \t]*$@ && #trailing */ - $rawline !~ m@^\+.*/\*.*\*/[ \t]*$@ && #inline /*...*/ - $rawline !~ m@^\+.*\*{2,}/[ \t]*$@ && #trailing **/ - $rawline =~ m@^\+[ \t]*.+\*\/[ \t]*$@) { #non blank */ - WARN("NETWORKING_BLOCK_COMMENT_STYLE", - "networking block comments put the trailing */ on a separate line\n" . $herecurr); - } - -# check for spaces at the beginning of a line. -# Exceptions: -# 1) within comments -# 2) indented preprocessor commands -# 3) hanging labels - if ($rawline =~ /^\+ / && $line !~ /\+ *(?:$;|#|$Ident:)/) { - my $herevet = "$here\n" . cat_vet($rawline) . "\n"; - WARN("LEADING_SPACE", - "please, no spaces at the start of a line\n" . $herevet); - } - -# check we are in a valid C source file if not then ignore this hunk - next if ($realfile !~ /\.(h|c)$/); - -# discourage the addition of CONFIG_EXPERIMENTAL in #if(def). - if ($line =~ /^\+\s*\#\s*if.*\bCONFIG_EXPERIMENTAL\b/) { - WARN("CONFIG_EXPERIMENTAL", - "Use of CONFIG_EXPERIMENTAL is deprecated. For alternatives, see https://lkml.org/lkml/2012/10/23/580\n"); - } - -# check for RCS/CVS revision markers - if ($rawline =~ /^\+.*\$(Revision|Log|Id)(?:\$|)/) { - WARN("CVS_KEYWORD", - "CVS style keyword markers, these will _not_ be updated\n". $herecurr); - } - -# Blackfin: don't use __builtin_bfin_[cs]sync - if ($line =~ /__builtin_bfin_csync/) { - my $herevet = "$here\n" . cat_vet($line) . "\n"; - ERROR("CSYNC", - "use the CSYNC() macro in asm/blackfin.h\n" . $herevet); - } - if ($line =~ /__builtin_bfin_ssync/) { - my $herevet = "$here\n" . cat_vet($line) . "\n"; - ERROR("SSYNC", - "use the SSYNC() macro in asm/blackfin.h\n" . $herevet); - } - -# check for old HOTPLUG __dev section markings - if ($line =~ /\b(__dev(init|exit)(data|const|))\b/) { - WARN("HOTPLUG_SECTION", - "Using $1 is unnecessary\n" . $herecurr); - } - -# Check for potential 'bare' types - my ($stat, $cond, $line_nr_next, $remain_next, $off_next, - $realline_next); -#print "LINE<$line>\n"; - if ($linenr >= $suppress_statement && - $realcnt && $line =~ /.\s*\S/) { - ($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; - -#print "linenr<$linenr> <$stat>\n"; - # If this statement has no statement boundaries within - # it there is no point in retrying a statement scan - # until we hit end of it. - my $frag = $stat; $frag =~ s/;+\s*$//; - if ($frag !~ /(?:{|;)/) { -#print "skip<$line_nr_next>\n"; - $suppress_statement = $line_nr_next; - } - - # Find the real next line. - $realline_next = $line_nr_next; - if (defined $realline_next && - (!defined $lines[$realline_next - 1] || - substr($lines[$realline_next - 1], $off_next) =~ /^\s*$/)) { - $realline_next++; - } - - my $s = $stat; - $s =~ s/{.*$//s; - - # Ignore goto labels. - if ($s =~ /$Ident:\*$/s) { - - # Ignore functions being called - } elsif ($s =~ /^.\s*$Ident\s*\(/s) { - - } elsif ($s =~ /^.\s*else\b/s) { - - # declarations always start with types - } elsif ($prev_values eq 'E' && $s =~ /^.\s*(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?((?:\s*$Ident)+?)\b(?:\s+$Sparse)?\s*\**\s*(?:$Ident|\(\*[^\)]*\))(?:\s*$Modifier)?\s*(?:;|=|,|\()/s) { - my $type = $1; - $type =~ s/\s+/ /g; - possible($type, "A:" . $s); - - # definitions in global scope can only start with types - } elsif ($s =~ /^.(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?($Ident)\b\s*(?!:)/s) { - possible($1, "B:" . $s); - } - - # any (foo ... *) is a pointer cast, and foo is a type - while ($s =~ /\(($Ident)(?:\s+$Sparse)*[\s\*]+\s*\)/sg) { - possible($1, "C:" . $s); - } - - # Check for any sort of function declaration. - # int foo(something bar, other baz); - # void (*store_gdt)(x86_descr_ptr *); - if ($prev_values eq 'E' && $s =~ /^(.(?:typedef\s*)?(?:(?:$Storage|$Inline)\s*)*\s*$Type\s*(?:\b$Ident|\(\*\s*$Ident\))\s*)\(/s) { - my ($name_len) = length($1); - - my $ctx = $s; - substr($ctx, 0, $name_len + 1, ''); - $ctx =~ s/\)[^\)]*$//; - - for my $arg (split(/\s*,\s*/, $ctx)) { - if ($arg =~ /^(?:const\s+)?($Ident)(?:\s+$Sparse)*\s*\**\s*(:?\b$Ident)?$/s || $arg =~ /^($Ident)$/s) { - - possible($1, "D:" . $s); - } - } - } - - } - -# -# Checks which may be anchored in the context. -# - -# Check for switch () and associated case and default -# statements should be at the same indent. - if ($line=~/\bswitch\s*\(.*\)/) { - my $err = ''; - my $sep = ''; - my @ctx = ctx_block_outer($linenr, $realcnt); - shift(@ctx); - for my $ctx (@ctx) { - my ($clen, $cindent) = line_stats($ctx); - if ($ctx =~ /^\+\s*(case\s+|default:)/ && - $indent != $cindent) { - $err .= "$sep$ctx\n"; - $sep = ''; - } else { - $sep = "[...]\n"; - } - } - if ($err ne '') { - ERROR("SWITCH_CASE_INDENT_LEVEL", - "switch and case should be at the same indent\n$hereline$err"); - } - } - -# 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 - if ($line =~ /(.*)\b((?:if|while|for|switch)\s*\(|do\b|else\b)/ && $line !~ /^.\s*\#/) { - my $pre_ctx = "$1$2"; - - my ($level, @ctx) = ctx_statement_level($linenr, $realcnt, 0); - - if ($line =~ /^\+\t{6,}/) { - WARN("DEEP_INDENTATION", - "Too many leading tabs - consider code refactoring\n" . $herecurr); - } - - my $ctx_cnt = $realcnt - $#ctx - 1; - my $ctx = join("\n", @ctx); - - my $ctx_ln = $linenr; - my $ctx_skip = $realcnt; - - while ($ctx_skip > $ctx_cnt || ($ctx_skip == $ctx_cnt && - defined $lines[$ctx_ln - 1] && - $lines[$ctx_ln - 1] =~ /^-/)) { - ##print "SKIP<$ctx_skip> CNT<$ctx_cnt>\n"; - $ctx_skip-- if (!defined $lines[$ctx_ln - 1] || $lines[$ctx_ln - 1] !~ /^-/); - $ctx_ln++; - } - - #print "realcnt<$realcnt> ctx_cnt<$ctx_cnt>\n"; - #print "pre<$pre_ctx>\nline<$line>\nctx<$ctx>\nnext<$lines[$ctx_ln - 1]>\n"; - - if ($ctx !~ /{\s*/ && defined($lines[$ctx_ln -1]) && $lines[$ctx_ln - 1] =~ /^\+\s*{/) { - ERROR("OPEN_BRACE", - "that open brace { should be on the previous line\n" . - "$here\n$ctx\n$rawlines[$ctx_ln - 1]\n"); - } - if ($level == 0 && $pre_ctx !~ /}\s*while\s*\($/ && - $ctx =~ /\)\s*\;\s*$/ && - defined $lines[$ctx_ln - 1]) - { - my ($nlength, $nindent) = line_stats($lines[$ctx_ln - 1]); - if ($nindent > $indent) { - WARN("TRAILING_SEMICOLON", - "trailing semicolon indicates no statements, indent implies otherwise\n" . - "$here\n$ctx\n$rawlines[$ctx_ln - 1]\n"); - } - } - } - -# Check relative indent for conditionals and blocks. - if ($line =~ /\b(?:(?:if|while|for)\s*\(|do\b)/ && $line !~ /^.\s*#/ && $line !~ /\}\s*while\s*/) { - ($stat, $cond, $line_nr_next, $remain_next, $off_next) = - ctx_statement_block($linenr, $realcnt, 0) - if (!defined $stat); - 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; - if ($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", - "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) = - annotate_values($opline . "\n", $prev_values); - $curr_values = $prev_values . $curr_values; - if ($dbg_values) { - my $outline = $opline; $outline =~ s/\t/ /g; - print "$linenr > .$outline\n"; - print "$linenr > $curr_values\n"; - print "$linenr > $curr_vars\n"; - } - $prev_values = substr($curr_values, -1); - -#ignore lines not being added - if ($line=~/^[^\+]/) {next;} - -# TEST: allow direct testing of the type matcher. - if ($dbg_type) { - if ($line =~ /^.\s*$Declare\s*$/) { - ERROR("TEST_TYPE", - "TEST: is type\n" . $herecurr); - } elsif ($dbg_type > 1 && $line =~ /^.+($Declare)/) { - ERROR("TEST_NOT_TYPE", - "TEST: is not type ($1 is)\n". $herecurr); - } - next; - } -# TEST: allow direct testing of the attribute matcher. - if ($dbg_attr) { - if ($line =~ /^.\s*$Modifier\s*$/) { - ERROR("TEST_ATTR", - "TEST: is attr\n" . $herecurr); - } elsif ($dbg_attr > 1 && $line =~ /^.+($Modifier)/) { - ERROR("TEST_NOT_ATTR", - "TEST: is not attr ($1 is)\n". $herecurr); - } - next; - } - -# check for initialisation to aggregates open brace on the next line - if ($line =~ /^.\s*{/ && - $prevline =~ /(?:^|[^=])=\s*$/) { - ERROR("OPEN_BRACE", - "that open brace { should be on the previous line\n" . $hereprev); - } - -# -# Checks which are anchored on the added line. -# - -# check for malformed paths in #include statements (uses RAW line) - if ($rawline =~ m{^.\s*\#\s*include\s+[<"](.*)[">]}) { - my $path = $1; - if ($path =~ m{//}) { - ERROR("MALFORMED_INCLUDE", - "malformed #include filename\n" . $herecurr); - } - if ($path =~ "^uapi/" && $realfile =~ m@\binclude/uapi/@) { - ERROR("UAPI_INCLUDE", - "No #include in ...include/uapi/... should use a uapi/ path prefix\n" . $herecurr); - } - } - -# no C99 // comments - if ($line =~ m{//}) { - ERROR("C99_COMMENTS", - "do not use C99 // comments\n" . $herecurr); - } - # Remove C99 comments. - $line =~ s@//.*@@; - $opline =~ s@//.*@@; - -# EXPORT_SYMBOL should immediately follow the thing it is exporting, consider -# the whole statement. -#print "APW <$lines[$realline_next - 1]>\n"; - if (defined $realline_next && - exists $lines[$realline_next - 1] && - !defined $suppress_export{$realline_next} && - ($lines[$realline_next - 1] =~ /EXPORT_SYMBOL.*\((.*)\)/ || - $lines[$realline_next - 1] =~ /EXPORT_UNUSED_SYMBOL.*\((.*)\)/)) { - # Handle definitions which produce identifiers with - # a prefix: - # XXX(foo); - # EXPORT_SYMBOL(something_foo); - my $name = $1; - if ($stat =~ /^(?:.\s*}\s*\n)?.([A-Z_]+)\s*\(\s*($Ident)/ && - $name =~ /^${Ident}_$2/) { -#print "FOO C name<$name>\n"; - $suppress_export{$realline_next} = 1; - - } elsif ($stat !~ /(?: - \n.}\s*$| - ^.DEFINE_$Ident\(\Q$name\E\)| - ^.DECLARE_$Ident\(\Q$name\E\)| - ^.LIST_HEAD\(\Q$name\E\)| - ^.(?:$Storage\s+)?$Type\s*\(\s*\*\s*\Q$name\E\s*\)\s*\(| - \b\Q$name\E(?:\s+$Attribute)*\s*(?:;|=|\[|\() - )/x) { -#print "FOO A<$lines[$realline_next - 1]> stat<$stat> name<$name>\n"; - $suppress_export{$realline_next} = 2; - } else { - $suppress_export{$realline_next} = 1; - } - } - if (!defined $suppress_export{$linenr} && - $prevline =~ /^.\s*$/ && - ($line =~ /EXPORT_SYMBOL.*\((.*)\)/ || - $line =~ /EXPORT_UNUSED_SYMBOL.*\((.*)\)/)) { -#print "FOO B <$lines[$linenr - 1]>\n"; - $suppress_export{$linenr} = 2; - } - if (defined $suppress_export{$linenr} && - $suppress_export{$linenr} == 2) { - WARN("EXPORT_SYMBOL", - "EXPORT_SYMBOL(foo); should immediately follow its function/variable\n" . $herecurr); - } - -# check for global initialisers. - if ($line =~ /^.$Type\s*$Ident\s*(?:\s+$Modifier)*\s*=\s*(0|NULL|false)\s*;/) { - ERROR("GLOBAL_INITIALISERS", - "do not initialise globals to 0 or NULL\n" . - $herecurr); - } -# check for static initialisers. - if ($line =~ /\bstatic\s.*=\s*(0|NULL|false)\s*;/) { - ERROR("INITIALISED_STATIC", - "do not initialise statics to 0 or NULL\n" . - $herecurr); - } - -# check for static const char * arrays. - if ($line =~ /\bstatic\s+const\s+char\s*\*\s*(\w+)\s*\[\s*\]\s*=\s*/) { - WARN("STATIC_CONST_CHAR_ARRAY", - "static const char * array should probably be static const char * const\n" . - $herecurr); - } - -# check for static char foo[] = "bar" declarations. - if ($line =~ /\bstatic\s+char\s+(\w+)\s*\[\s*\]\s*=\s*"/) { - WARN("STATIC_CONST_CHAR_ARRAY", - "static char array declaration should probably be static const char\n" . - $herecurr); - } - -# check for declarations of struct pci_device_id - if ($line =~ /\bstruct\s+pci_device_id\s+\w+\s*\[\s*\]\s*\=\s*\{/) { - WARN("DEFINE_PCI_DEVICE_TABLE", - "Use DEFINE_PCI_DEVICE_TABLE for struct pci_device_id\n" . $herecurr); - } - -# check for new typedefs, only function parameters and sparse annotations -# make sense. - 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("NEW_TYPEDEFS", - "do not add new typedefs\n" . $herecurr); - } - -# * goes on variable not on type - # (char*[ const]) - while ($line =~ m{(\($NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)\))}g) { - #print "AA<$1>\n"; - my ($from, $to) = ($2, $2); - - # Should start with a space. - $to =~ s/^(\S)/ $1/; - # Should not end with a space. - $to =~ s/\s+$//; - # '*'s should not have spaces between. - while ($to =~ s/\*\s+\*/\*\*/) { - } - - #print "from<$from> to<$to>\n"; - if ($from ne $to) { - ERROR("POINTER_LOCATION", - "\"(foo$from)\" should be \"(foo$to)\"\n" . $herecurr); - } - } - while ($line =~ m{(\b$NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)($Ident))}g) { - #print "BB<$1>\n"; - my ($from, $to, $ident) = ($2, $2, $3); - - # Should start with a space. - $to =~ s/^(\S)/ $1/; - # Should not end with a space. - $to =~ s/\s+$//; - # '*'s should not have spaces between. - while ($to =~ s/\*\s+\*/\*\*/) { - } - # Modifiers should have spaces. - $to =~ s/(\b$Modifier$)/$1 /; - - #print "from<$from> to<$to> ident<$ident>\n"; - if ($from ne $to && $ident !~ /^$Modifier$/) { - ERROR("POINTER_LOCATION", - "\"foo${from}bar\" should be \"foo${to}bar\"\n" . $herecurr); - } - } - -# # no BUG() or BUG_ON() -# if ($line =~ /\b(BUG|BUG_ON)\b/) { -# print "Try to use WARN_ON & Recovery code rather than BUG() or BUG_ON()\n"; -# print "$herecurr"; -# $clean = 0; -# } - - if ($line =~ /\bLINUX_VERSION_CODE\b/) { - WARN("LINUX_VERSION_CODE", - "LINUX_VERSION_CODE should be avoided, code should be for the version to which it is merged\n" . $herecurr); - } - -# check for uses of printk_ratelimit - if ($line =~ /\bprintk_ratelimit\s*\(/) { - WARN("PRINTK_RATELIMITED", -"Prefer printk_ratelimited or pr__ratelimited to printk_ratelimit\n" . $herecurr); - } - -# printk should use KERN_* levels. Note that follow on printk's on the -# same line do not need a level, so we use the current block context -# to try and find and validate the current printk. In summary the current -# printk includes all preceding printk's which have no newline on the end. -# we assume the first bad printk is the one to report. - if ($line =~ /\bprintk\((?!KERN_)\s*"/) { - my $ok = 0; - for (my $ln = $linenr - 1; $ln >= $first_line; $ln--) { - #print "CHECK<$lines[$ln - 1]\n"; - # we have a preceding printk if it ends - # with "\n" ignore it, else it is to blame - if ($lines[$ln - 1] =~ m{\bprintk\(}) { - if ($rawlines[$ln - 1] !~ m{\\n"}) { - $ok = 1; - } - last; - } - } - if ($ok == 0) { - WARN("PRINTK_WITHOUT_KERN_LEVEL", - "printk() should include KERN_ facility level\n" . $herecurr); - } - } - - if ($line =~ /\bprintk\s*\(\s*KERN_([A-Z]+)/) { - my $orig = $1; - my $level = lc($orig); - $level = "warn" if ($level eq "warning"); - my $level2 = $level; - $level2 = "dbg" if ($level eq "debug"); - WARN("PREFER_PR_LEVEL", - "Prefer netdev_$level2(netdev, ... then dev_$level2(dev, ... then pr_$level(... to printk(KERN_$orig ...\n" . $herecurr); - } - - if ($line =~ /\bpr_warning\s*\(/) { - WARN("PREFER_PR_LEVEL", - "Prefer pr_warn(... to pr_warning(...\n" . $herecurr); - } - - if ($line =~ /\bdev_printk\s*\(\s*KERN_([A-Z]+)/) { - my $orig = $1; - my $level = lc($orig); - $level = "warn" if ($level eq "warning"); - $level = "dbg" if ($level eq "debug"); - WARN("PREFER_DEV_LEVEL", - "Prefer dev_$level(... to dev_printk(KERN_$orig, ...\n" . $herecurr); - } - -# function brace can't be on same line, except for #defines of do while, -# or if closed on same line - if (($line=~/$Type\s*$Ident\(.*\).*\s{/) and - !($line=~/\#\s*define.*do\s{/) and !($line=~/}/)) { - ERROR("OPEN_BRACE", - "open brace '{' following function declarations go on the next line\n" . $herecurr); - } - -# open braces for enum, union and struct go on the same line. - if ($line =~ /^.\s*{/ && - $prevline =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident)?\s*$/) { - ERROR("OPEN_BRACE", - "open brace '{' following $1 go on the same line\n" . $hereprev); - } - -# missing space after union, struct or enum definition - if ($line =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident)?(?:\s+$Ident)?[=\{]/) { - WARN("SPACING", - "missing space after $1 definition\n" . $herecurr); - } - -# 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, -# 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+$/) && - $prefix !~ /[{,]\s+$/) { - ERROR("BRACKET_SPACE", - "space prohibited before open square bracket '['\n" . $herecurr); - } - } - -# check for spaces between functions and their parentheses. - while ($line =~ /($Ident)\s+\(/g) { - my $name = $1; - my $ctx_before = substr($line, 0, $-[1]); - my $ctx = "$ctx_before$name"; - - # Ignore those directives where spaces _are_ permitted. - if ($name =~ /^(?: - if|for|while|switch|return|case| - volatile|__volatile__| - __attribute__|format|__extension__| - asm|__asm__)$/x) - { - - # cpp #define statements have non-optional spaces, ie - # if there is a space between the name and the open - # parenthesis it is simply not a parameter group. - } elsif ($ctx_before =~ /^.\s*\#\s*define\s*$/) { - - # cpp #elif statement condition may start with a ( - } elsif ($ctx =~ /^.\s*\#\s*elif\s*$/) { - - # If this whole things ends with a type its most - # likely a typedef for a function. - } elsif ($ctx =~ /$Type$/) { - - } else { - WARN("SPACING", - "space prohibited between function name and open parenthesis '('\n" . $herecurr); - } - } - -# check for whitespace before a non-naked semicolon - if ($line =~ /^\+.*\S\s+;/) { - CHK("SPACING", - "space prohibited before semicolon\n" . $herecurr); - } - -# Check operator spacing. - if (!($line=~/\#\s*include/)) { - my $ops = qr{ - <<=|>>=|<=|>=|==|!=| - \+=|-=|\*=|\/=|%=|\^=|\|=|&=| - =>|->|<<|>>|<|>|=|!|~| - &&|\|\||,|\^|\+\+|--|&|\||\+|-|\*|\/|%| - \?|: - }x; - my @elements = split(/($ops|;)/, $opline); - my $off = 0; - - my $blank = copy_spacing($opline); - - for (my $n = 0; $n < $#elements; $n += 2) { - $off += length($elements[$n]); - - # Pick up the preceding and succeeding characters. - my $ca = substr($opline, 0, $off); - my $cc = ''; - if (length($opline) >= ($off + length($elements[$n + 1]))) { - $cc = substr($opline, $off + length($elements[$n + 1])); - } - my $cb = "$ca$;$cc"; - - my $a = ''; - $a = 'V' if ($elements[$n] ne ''); - $a = 'W' if ($elements[$n] =~ /\s$/); - $a = 'C' if ($elements[$n] =~ /$;$/); - $a = 'B' if ($elements[$n] =~ /(\[|\()$/); - $a = 'O' if ($elements[$n] eq ''); - $a = 'E' if ($ca =~ /^\s*$/); - - my $op = $elements[$n + 1]; - - my $c = ''; - if (defined $elements[$n + 2]) { - $c = 'V' if ($elements[$n + 2] ne ''); - $c = 'W' if ($elements[$n + 2] =~ /^\s/); - $c = 'C' if ($elements[$n + 2] =~ /^$;/); - $c = 'B' if ($elements[$n + 2] =~ /^(\)|\]|;)/); - $c = 'O' if ($elements[$n + 2] eq ''); - $c = 'E' if ($elements[$n + 2] =~ /^\s*\\$/); - } else { - $c = 'E'; - } - - my $ctx = "${a}x${c}"; - - my $at = "(ctx:$ctx)"; - - my $ptr = substr($blank, 0, $off) . "^"; - my $hereptr = "$hereline$ptr\n"; - - # Pull out the value of this operator. - my $op_type = substr($curr_values, $off + 1, 1); - - # Get the full operator variant. - my $opv = $op . substr($curr_vars, $off, 1); - - # Ignore operators passed as parameters. - if ($op_type ne 'V' && - $ca =~ /\s$/ && $cc =~ /^\s*,/) { - -# # Ignore comments -# } elsif ($op =~ /^$;+$/) { - - # ; should have either the end of line or a space or \ after it - } elsif ($op eq ';') { - if ($ctx !~ /.x[WEBC]/ && - $cc !~ /^\\/ && $cc !~ /^;/) { - ERROR("SPACING", - "space required after that '$op' $at\n" . $hereptr); - } - - # // is a comment - } elsif ($op eq '//') { - - # No spaces for: - # -> - # : when part of a bitfield - } elsif ($op eq '->' || $opv eq ':B') { - if ($ctx =~ /Wx.|.xW/) { - ERROR("SPACING", - "spaces prohibited around that '$op' $at\n" . $hereptr); - } - - # , must have a space on the right. - } elsif ($op eq ',') { - if ($ctx !~ /.x[WEC]/ && $cc !~ /^}/) { - ERROR("SPACING", - "space required after that '$op' $at\n" . $hereptr); - } - - # '*' as part of a type definition -- reported already. - } elsif ($opv eq '*_') { - #warn "'*' is part of type\n"; - - # unary operators should have a space before and - # none after. May be left adjacent to another - # unary operator, or a cast - } elsif ($op eq '!' || $op eq '~' || - $opv eq '*U' || $opv eq '-U' || - $opv eq '&U' || $opv eq '&&U') { - if ($ctx !~ /[WEBC]x./ && $ca !~ /(?:\)|!|~|\*|-|\&|\||\+\+|\-\-|\{)$/) { - ERROR("SPACING", - "space required before that '$op' $at\n" . $hereptr); - } - if ($op eq '*' && $cc =~/\s*$Modifier\b/) { - # A unary '*' may be const - - } elsif ($ctx =~ /.xW/) { - ERROR("SPACING", - "space prohibited after that '$op' $at\n" . $hereptr); - } - - # unary ++ and unary -- are allowed no space on one side. - } elsif ($op eq '++' or $op eq '--') { - if ($ctx !~ /[WEOBC]x[^W]/ && $ctx !~ /[^W]x[WOBEC]/) { - ERROR("SPACING", - "space required one side of that '$op' $at\n" . $hereptr); - } - if ($ctx =~ /Wx[BE]/ || - ($ctx =~ /Wx./ && $cc =~ /^;/)) { - ERROR("SPACING", - "space prohibited before that '$op' $at\n" . $hereptr); - } - if ($ctx =~ /ExW/) { - ERROR("SPACING", - "space prohibited after that '$op' $at\n" . $hereptr); - } - - - # << and >> may either have or not have spaces both sides - } elsif ($op eq '<<' or $op eq '>>' or - $op eq '&' or $op eq '^' or $op eq '|' or - $op eq '+' or $op eq '-' or - $op eq '*' or $op eq '/' or - $op eq '%') - { - if ($ctx =~ /Wx[^WCE]|[^WCE]xW/) { - ERROR("SPACING", - "need consistent spacing around '$op' $at\n" . - $hereptr); - } - - # A colon needs no spaces before when it is - # terminating a case value or a label. - } elsif ($opv eq ':C' || $opv eq ':L') { - if ($ctx =~ /Wx./) { - ERROR("SPACING", - "space prohibited before that '$op' $at\n" . $hereptr); - } - - # All the others need spaces both sides. - } elsif ($ctx !~ /[EWC]x[CWE]/) { - my $ok = 0; - - # Ignore email addresses - if (($op eq '<' && - $cc =~ /^\S+\@\S+>/) || - ($op eq '>' && - $ca =~ /<\S+\@\S+$/)) - { - $ok = 1; - } - - # Ignore ?: - if (($opv eq ':O' && $ca =~ /\?$/) || - ($op eq '?' && $cc =~ /^:/)) { - $ok = 1; - } - - if ($ok == 0) { - ERROR("SPACING", - "spaces required around that '$op' $at\n" . $hereptr); - } - } - $off += length($elements[$n + 1]); - } - } - -# check for multiple assignments - if ($line =~ /^.\s*$Lval\s*=\s*$Lval\s*=(?!=)/) { - CHK("MULTIPLE_ASSIGNMENTS", - "multiple assignments should be avoided\n" . $herecurr); - } - -## # check for multiple declarations, allowing for a function declaration -## # continuation. -## if ($line =~ /^.\s*$Type\s+$Ident(?:\s*=[^,{]*)?\s*,\s*$Ident.*/ && -## $line !~ /^.\s*$Type\s+$Ident(?:\s*=[^,{]*)?\s*,\s*$Type\s*$Ident.*/) { -## -## # Remove any bracketed sections to ensure we do not -## # falsly report the parameters of functions. -## my $ln = $line; -## while ($ln =~ s/\([^\(\)]*\)//g) { -## } -## if ($ln =~ /,/) { -## WARN("MULTIPLE_DECLARATION", -## "declaring multiple variables together should be avoided\n" . $herecurr); -## } -## } - -#need space before brace following if, while, etc - if (($line =~ /\(.*\){/ && $line !~ /\($Type\){/) || - $line =~ /do{/) { - ERROR("SPACING", - "space required before the open brace '{'\n" . $herecurr); - } - -# closing brace should have a space following it when it has anything -# on the line - if ($line =~ /}(?!(?:,|;|\)))\S/) { - ERROR("SPACING", - "space required after that close brace '}'\n" . $herecurr); - } - -# check spacing on square brackets - if ($line =~ /\[\s/ && $line !~ /\[\s*$/) { - ERROR("SPACING", - "space prohibited after that open square bracket '['\n" . $herecurr); - } - if ($line =~ /\s\]/) { - ERROR("SPACING", - "space prohibited before that close square bracket ']'\n" . $herecurr); - } - -# check spacing on parentheses - if ($line =~ /\(\s/ && $line !~ /\(\s*(?:\\)?$/ && - $line !~ /for\s*\(\s+;/) { - ERROR("SPACING", - "space prohibited after that open parenthesis '('\n" . $herecurr); - } - if ($line =~ /(\s+)\)/ && $line !~ /^.\s*\)/ && - $line !~ /for\s*\(.*;\s+\)/ && - $line !~ /:\s+\)/) { - ERROR("SPACING", - "space prohibited before that close parenthesis ')'\n" . $herecurr); - } - -#goto labels aren't indented, allow a single space however - if ($line=~/^.\s+[A-Za-z\d_]+:(?![0-9]+)/ and - !($line=~/^. [A-Za-z\d_]+:/) and !($line=~/^.\s+default:/)) { - WARN("INDENTED_LABEL", - "labels should not be indented\n" . $herecurr); - } - -# Return is not a function. - if (defined($stat) && $stat =~ /^.\s*return(\s*)(\(.*);/s) { - my $spacing = $1; - my $value = $2; - - # Flatten any parentheses - $value =~ s/\(/ \(/g; - $value =~ s/\)/\) /g; - while ($value =~ s/\[[^\[\]]*\]/1/ || - $value !~ /(?:$Ident|-?$Constant)\s* - $Compare\s* - (?:$Ident|-?$Constant)/x && - $value =~ s/\([^\(\)]*\)/1/) { - } -#print "value<$value>\n"; - if ($value =~ /^\s*(?:$Ident|-?$Constant)\s*$/) { - ERROR("RETURN_PARENTHESES", - "return is not a function, parentheses are not required\n" . $herecurr); - - } elsif ($spacing !~ /\s+/) { - ERROR("SPACING", - "space required before the open parenthesis '('\n" . $herecurr); - } - } -# Return of what appears to be an errno should normally be -'ve - if ($line =~ /^.\s*return\s*(E[A-Z]*)\s*;/) { - my $name = $1; - if ($name ne 'EOF' && $name ne 'ERROR') { - WARN("USE_NEGATIVE_ERRNO", - "return of an errno should typically be -ve (return -$1)\n" . $herecurr); - } - } - -# Need a space before open parenthesis after if, while etc - if ($line=~/\b(if|while|for|switch)\(/) { - ERROR("SPACING", "space required before the open parenthesis '('\n" . $herecurr); - } - -# Check for illegal assignment in if conditional -- and check for trailing -# statements after the conditional. - if ($line =~ /do\s*(?!{)/) { - ($stat, $cond, $line_nr_next, $remain_next, $off_next) = - ctx_statement_block($linenr, $realcnt, 0) - if (!defined $stat); - 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*\(.*[^<>!=]=[^=].*/s) { - ERROR("ASSIGN_IN_IF", - "do not use assignment in if condition\n" . $herecurr); - } - - # Find out what is on the end of the line after the - # conditional. - substr($s, 0, length($c), ''); - $s =~ s/\n.*//g; - $s =~ s/$;//g; # Remove any comments - if (length($c) && $s !~ /^\s*{?\s*\\*\s*$/ && - $c !~ /}\s*while\s*/) - { - # Find out how long the conditional actually is. - my @newlines = ($c =~ /\n/gs); - my $cond_lines = 1 + $#newlines; - my $stat_real = ''; - - $stat_real = raw_line($linenr, $cond_lines) - . "\n" if ($cond_lines); - if (defined($stat_real) && $cond_lines > 1) { - $stat_real = "[...]\n$stat_real"; - } - - ERROR("TRAILING_STATEMENTS", - "trailing statements should be on next line\n" . $herecurr . $stat_real); - } - } - -# Check for bitwise tests written as boolean - if ($line =~ / - (?: - (?:\[|\(|\&\&|\|\|) - \s*0[xX][0-9]+\s* - (?:\&\&|\|\|) - | - (?:\&\&|\|\|) - \s*0[xX][0-9]+\s* - (?:\&\&|\|\||\)|\]) - )/x) - { - WARN("HEXADECIMAL_BOOLEAN_TEST", - "boolean test with hexadecimal, perhaps just 1 \& or \|?\n" . $herecurr); - } - -# if and else should not have general statements after it - if ($line =~ /^.\s*(?:}\s*)?else\b(.*)/) { - my $s = $1; - $s =~ s/$;//g; # Remove any comments - if ($s !~ /^\s*(?:\sif|(?:{|)\s*\\?\s*$)/) { - ERROR("TRAILING_STATEMENTS", - "trailing statements should be on next line\n" . $herecurr); - } - } -# if should not continue a brace - if ($line =~ /}\s*if\b/) { - ERROR("TRAILING_STATEMENTS", - "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", - "trailing statements should be on next line\n" . $herecurr); - } - - # Check for }else {, these must be at the same - # indent level to be relevant to each other. - if ($prevline=~/}\s*$/ and $line=~/^.\s*else\s*/ and - $previndent == $indent) { - ERROR("ELSE_AFTER_BRACE", - "else should follow close brace '}'\n" . $hereprev); - } - - if ($prevline=~/}\s*$/ and $line=~/^.\s*while\s*/ and - $previndent == $indent) { - my ($s, $c) = ctx_statement_block($linenr, $realcnt, 0); - - # Find out what is on the end of the line after the - # conditional. - substr($s, 0, length($c), ''); - $s =~ s/\n.*//g; - - if ($s =~ /^\s*;/) { - ERROR("WHILE_AFTER_BRACE", - "while should follow close brace '}'\n" . $hereprev); - } - } - -#CamelCase - while ($line =~ m{($Constant|$Lval)}g) { - my $var = $1; - if ($var !~ /$Constant/ && - $var =~ /[A-Z]\w*[a-z]|[a-z]\w*[A-Z]/ && - $var !~ /"^(?:Clear|Set|TestClear|TestSet|)Page[A-Z]/ && - !defined $camelcase{$var}) { - $camelcase{$var} = 1; - WARN("CAMELCASE", - "Avoid CamelCase: <$var>\n" . $herecurr); - } - } - -#no spaces allowed after \ in define - if ($line=~/\#\s*define.*\\\s$/) { - WARN("WHITESPACE_AFTER_LINE_CONTINUATION", - "Whitepspace after \\ makes next lines useless\n" . $herecurr); - } - -#warn if is #included and is available (uses RAW line) - if ($tree && $rawline =~ m{^.\s*\#\s*include\s*\}) { - my $file = "$1.h"; - my $checkfile = "include/linux/$file"; - if (-f "$root/$checkfile" && - $realfile ne $checkfile && - $1 !~ /$allowed_asm_includes/) - { - if ($realfile =~ m{^arch/}) { - CHK("ARCH_INCLUDE_LINUX", - "Consider using #include instead of \n" . $herecurr); - } else { - WARN("INCLUDE_LINUX", - "Use #include instead of \n" . $herecurr); - } - } - } - -# multi-statement macros should be enclosed in a do while loop, grab the -# first statement and ensure its the whole macro if its not enclosed -# in a known good container - if ($realfile !~ m@/vmlinux.lds.h$@ && - $line =~ /^.\s*\#\s*define\s*$Ident(\()?/) { - my $ln = $linenr; - my $cnt = $realcnt; - my ($off, $dstat, $dcond, $rest); - my $ctx = ''; - ($dstat, $dcond, $ln, $cnt, $off) = - ctx_statement_block($linenr, $realcnt, 0); - $ctx = $dstat; - #print "dstat<$dstat> dcond<$dcond> cnt<$cnt> off<$off>\n"; - #print "LINE<$lines[$ln-1]> len<" . length($lines[$ln-1]) . "\n"; - - $dstat =~ s/^.\s*\#\s*define\s+$Ident(?:\([^\)]*\))?\s*//; - $dstat =~ s/$;//g; - $dstat =~ s/\\\n.//g; - $dstat =~ s/^\s*//s; - $dstat =~ s/\s*$//s; - - # Flatten any parentheses and braces - while ($dstat =~ s/\([^\(\)]*\)/1/ || - $dstat =~ s/\{[^\{\}]*\}/1/ || - $dstat =~ s/\[[^\[\]]*\]/1/) - { - } - - # Flatten any obvious string concatentation. - while ($dstat =~ s/("X*")\s*$Ident/$1/ || - $dstat =~ s/$Ident\s*("X*")/$1/) - { - } - - my $exceptions = qr{ - $Declare| - module_param_named| - MODULE_PARM_DESC| - DECLARE_PER_CPU| - DEFINE_PER_CPU| - __typeof__\(| - union| - struct| - \.$Ident\s*=\s*| - ^\"|\"$ - }x; - #print "REST<$rest> dstat<$dstat> ctx<$ctx>\n"; - if ($dstat ne '' && - $dstat !~ /^(?:$Ident|-?$Constant),$/ && # 10, // foo(), - $dstat !~ /^(?:$Ident|-?$Constant);$/ && # foo(); - $dstat !~ /^[!~-]?(?:$Ident|$Constant)$/ && # 10 // foo() // !foo // ~foo // -foo - $dstat !~ /^'X'$/ && # character constants - $dstat !~ /$exceptions/ && - $dstat !~ /^\.$Ident\s*=/ && # .foo = - $dstat !~ /^do\s*$Constant\s*while\s*$Constant;?$/ && # do {...} while (...); // do {...} while (...) - $dstat !~ /^for\s*$Constant$/ && # for (...) - $dstat !~ /^for\s*$Constant\s+(?:$Ident|-?$Constant)$/ && # for (...) bar() - $dstat !~ /^do\s*{/ && # do {... - $dstat !~ /^\({/) # ({... - { - $ctx =~ s/\n*$//; - my $herectx = $here . "\n"; - my $cnt = statement_rawlines($ctx); - - for (my $n = 0; $n < $cnt; $n++) { - $herectx .= raw_line($linenr, $n) . "\n"; - } - - if ($dstat =~ /;/) { - ERROR("MULTISTATEMENT_MACRO_USE_DO_WHILE", - "Macros with multiple statements should be enclosed in a do - while loop\n" . "$herectx"); - } else { - ERROR("COMPLEX_MACRO", - "Macros with complex values should be enclosed in parenthesis\n" . "$herectx"); - } - } - -# check for line continuations outside of #defines, preprocessor #, and asm - - } else { - if ($prevline !~ /^..*\\$/ && - $line !~ /^\+\s*\#.*\\$/ && # preprocessor - $line !~ /^\+.*\b(__asm__|asm)\b.*\\$/ && # asm - $line =~ /^\+.*\\$/) { - WARN("LINE_CONTINUATIONS", - "Avoid unnecessary line continuations\n" . $herecurr); - } - } - -# do {} while (0) macro tests: -# single-statement macros do not need to be enclosed in do while (0) loop, -# macro should not end with a semicolon - if ($^V && $^V ge 5.10.0 && - $realfile !~ m@/vmlinux.lds.h$@ && - $line =~ /^.\s*\#\s*define\s+$Ident(\()?/) { - my $ln = $linenr; - my $cnt = $realcnt; - my ($off, $dstat, $dcond, $rest); - my $ctx = ''; - ($dstat, $dcond, $ln, $cnt, $off) = - ctx_statement_block($linenr, $realcnt, 0); - $ctx = $dstat; - - $dstat =~ s/\\\n.//g; - - if ($dstat =~ /^\+\s*#\s*define\s+$Ident\s*${balanced_parens}\s*do\s*{(.*)\s*}\s*while\s*\(\s*0\s*\)\s*([;\s]*)\s*$/) { - my $stmts = $2; - my $semis = $3; - - $ctx =~ s/\n*$//; - my $cnt = statement_rawlines($ctx); - my $herectx = $here . "\n"; - - for (my $n = 0; $n < $cnt; $n++) { - $herectx .= raw_line($linenr, $n) . "\n"; - } - - if (($stmts =~ tr/;/;/) == 1 && - $stmts !~ /^\s*(if|while|for|switch)\b/) { - WARN("SINGLE_STATEMENT_DO_WHILE_MACRO", - "Single statement macros should not use a do {} while (0) loop\n" . "$herectx"); - } - if (defined $semis && $semis ne "") { - WARN("DO_WHILE_MACRO_WITH_TRAILING_SEMICOLON", - "do {} while (0) macros should not be semicolon terminated\n" . "$herectx"); - } - } - } - -# make sure symbols are always wrapped with VMLINUX_SYMBOL() ... -# all assignments may have only one of the following with an assignment: -# . -# ALIGN(...) -# VMLINUX_SYMBOL(...) - if ($realfile eq 'vmlinux.lds.h' && $line =~ /(?:(?:^|\s)$Ident\s*=|=\s*$Ident(?:\s|$))/) { - WARN("MISSING_VMLINUX_SYMBOL", - "vmlinux.lds.h needs VMLINUX_SYMBOL() around C-visible symbols\n" . $herecurr); - } - -# check for redundant bracing round if etc - if ($line =~ /(^.*)\bif\b/ && $1 !~ /else\s*$/) { - my ($level, $endln, @chunks) = - ctx_statement_full($linenr, $realcnt, 1); - #print "chunks<$#chunks> linenr<$linenr> endln<$endln> level<$level>\n"; - #print "APW: <<$chunks[1][0]>><<$chunks[1][1]>>\n"; - if ($#chunks > 0 && $level == 0) { - my @allowed = (); - my $allow = 0; - my $seen = 0; - my $herectx = $here . "\n"; - my $ln = $linenr - 1; - for my $chunk (@chunks) { - my ($cond, $block) = @{$chunk}; - - # If the condition carries leading newlines, then count those as offsets. - my ($whitespace) = ($cond =~ /^((?:\s*\n[+-])*\s*)/s); - my $offset = statement_rawlines($whitespace) - 1; - - $allowed[$allow] = 0; - #print "COND<$cond> whitespace<$whitespace> offset<$offset>\n"; - - # We have looked at and allowed this specific line. - $suppress_ifbraces{$ln + $offset} = 1; - - $herectx .= "$rawlines[$ln + $offset]\n[...]\n"; - $ln += statement_rawlines($block) - 1; - - substr($block, 0, length($cond), ''); - - $seen++ if ($block =~ /^\s*{/); - - #print "cond<$cond> block<$block> allowed<$allowed[$allow]>\n"; - if (statement_lines($cond) > 1) { - #print "APW: ALLOWED: cond<$cond>\n"; - $allowed[$allow] = 1; - } - if ($block =~/\b(?:if|for|while)\b/) { - #print "APW: ALLOWED: block<$block>\n"; - $allowed[$allow] = 1; - } - if (statement_block_size($block) > 1) { - #print "APW: ALLOWED: lines block<$block>\n"; - $allowed[$allow] = 1; - } - $allow++; - } - if ($seen) { - my $sum_allowed = 0; - foreach (@allowed) { - $sum_allowed += $_; - } - if ($sum_allowed == 0) { - WARN("BRACES", - "braces {} are not necessary for any arm of this statement\n" . $herectx); - } elsif ($sum_allowed != $allow && - $seen != $allow) { - CHK("BRACES", - "braces {} should be used on all arms of this statement\n" . $herectx); - } - } - } - } - if (!defined $suppress_ifbraces{$linenr - 1} && - $line =~ /\b(if|while|for|else)\b/) { - my $allowed = 0; - - # Check the pre-context. - if (substr($line, 0, $-[0]) =~ /(\}\s*)$/) { - #print "APW: ALLOWED: pre<$1>\n"; - $allowed = 1; - } - - my ($level, $endln, @chunks) = - ctx_statement_full($linenr, $realcnt, $-[0]); - - # Check the condition. - my ($cond, $block) = @{$chunks[0]}; - #print "CHECKING<$linenr> cond<$cond> block<$block>\n"; - if (defined $cond) { - substr($block, 0, length($cond), ''); - } - if (statement_lines($cond) > 1) { - #print "APW: ALLOWED: cond<$cond>\n"; - $allowed = 1; - } - if ($block =~/\b(?:if|for|while)\b/) { - #print "APW: ALLOWED: block<$block>\n"; - $allowed = 1; - } - if (statement_block_size($block) > 1) { - #print "APW: ALLOWED: lines block<$block>\n"; - $allowed = 1; - } - # Check the post-context. - if (defined $chunks[1]) { - my ($cond, $block) = @{$chunks[1]}; - if (defined $cond) { - substr($block, 0, length($cond), ''); - } - if ($block =~ /^\s*\{/) { - #print "APW: ALLOWED: chunk-1 block<$block>\n"; - $allowed = 1; - } - } - if ($level == 0 && $block =~ /^\s*\{/ && !$allowed) { - my $herectx = $here . "\n"; - my $cnt = statement_rawlines($block); - - for (my $n = 0; $n < $cnt; $n++) { - $herectx .= raw_line($linenr, $n) . "\n"; - } - - WARN("BRACES", - "braces {} are not necessary for single statement blocks\n" . $herectx); - } - } - -# check for unnecessary blank lines around braces - if (($line =~ /^..*}\s*$/ && $prevline =~ /^.\s*$/)) { - CHK("BRACES", - "Blank lines aren't necessary before a close brace '}'\n" . $hereprev); - } - if (($line =~ /^.\s*$/ && $prevline =~ /^..*{\s*$/)) { - CHK("BRACES", - "Blank lines aren't necessary after an open brace '{'\n" . $hereprev); - } - -# no volatiles please - my $asm_volatile = qr{\b(__asm__|asm)\s+(__volatile__|volatile)\b}; - if ($line =~ /\bvolatile\b/ && $line !~ /$asm_volatile/) { - WARN("VOLATILE", - "Use of volatile is usually wrong: see Documentation/volatile-considered-harmful.txt\n" . $herecurr); - } - -# warn about #if 0 - if ($line =~ /^.\s*\#\s*if\s+0\b/) { - CHK("REDUNDANT_CODE", - "if this code is redundant consider removing it\n" . - $herecurr); - } - -# check for needless "if () fn()" uses - if ($prevline =~ /\bif\s*\(\s*($Lval)\s*\)/) { - my $expr = '\s*\(\s*' . quotemeta($1) . '\s*\)\s*;'; - if ($line =~ /\b(kfree|usb_free_urb|debugfs_remove(?:_recursive)?)$expr/) { - WARN('NEEDLESS_IF', - "$1(NULL) is safe this check is probably not required\n" . $hereprev); - } - } - -# prefer usleep_range over udelay - if ($line =~ /\budelay\s*\(\s*(\d+)\s*\)/) { - # ignore udelay's < 10, however - if (! ($1 < 10) ) { - CHK("USLEEP_RANGE", - "usleep_range is preferred over udelay; see Documentation/timers/timers-howto.txt\n" . $line); - } - } - -# warn about unexpectedly long msleep's - if ($line =~ /\bmsleep\s*\((\d+)\);/) { - if ($1 < 20) { - WARN("MSLEEP", - "msleep < 20ms can sleep for up to 20ms; see Documentation/timers/timers-howto.txt\n" . $line); - } - } - -# warn about #ifdefs in C files -# if ($line =~ /^.\s*\#\s*if(|n)def/ && ($realfile =~ /\.c$/)) { -# print "#ifdef in C files should be avoided\n"; -# print "$herecurr"; -# $clean = 0; -# } - -# warn about spacing in #ifdefs - if ($line =~ /^.\s*\#\s*(ifdef|ifndef|elif)\s\s+/) { - ERROR("SPACING", - "exactly one space required after that #$1\n" . $herecurr); - } - -# check for spinlock_t definitions without a comment. - if ($line =~ /^.\s*(struct\s+mutex|spinlock_t)\s+\S+;/ || - $line =~ /^.\s*(DEFINE_MUTEX)\s*\(/) { - my $which = $1; - if (!ctx_has_comment($first_line, $linenr)) { - CHK("UNCOMMENTED_DEFINITION", - "$1 definition without comment\n" . $herecurr); - } - } -# check for memory barriers without a comment. - if ($line =~ /\b(mb|rmb|wmb|read_barrier_depends|smp_mb|smp_rmb|smp_wmb|smp_read_barrier_depends)\(/) { - if (!ctx_has_comment($first_line, $linenr)) { - CHK("MEMORY_BARRIER", - "memory barrier without comment\n" . $herecurr); - } - } -# check of hardware specific defines - if ($line =~ m@^.\s*\#\s*if.*\b(__i386__|__powerpc64__|__sun__|__s390x__)\b@ && $realfile !~ m@include/asm-@) { - CHK("ARCH_DEFINES", - "architecture specific defines should be avoided\n" . $herecurr); - } - -# Check that the storage class is at the beginning of a declaration - if ($line =~ /\b$Storage\b/ && $line !~ /^.\s*$Storage\b/) { - WARN("STORAGE_CLASS", - "storage class should be at the beginning of the declaration\n" . $herecurr) - } - -# check the location of the inline attribute, that it is between -# storage class and type. - if ($line =~ /\b$Type\s+$Inline\b/ || - $line =~ /\b$Inline\s+$Storage\b/) { - ERROR("INLINE_LOCATION", - "inline keyword should sit between storage class and type\n" . $herecurr); - } - -# Check for __inline__ and __inline, prefer inline - if ($line =~ /\b(__inline__|__inline)\b/) { - WARN("INLINE", - "plain inline is preferred over $1\n" . $herecurr); - } - -# Check for __attribute__ packed, prefer __packed - if ($line =~ /\b__attribute__\s*\(\s*\(.*\bpacked\b/) { - WARN("PREFER_PACKED", - "__packed is preferred over __attribute__((packed))\n" . $herecurr); - } - -# Check for __attribute__ aligned, prefer __aligned - if ($line =~ /\b__attribute__\s*\(\s*\(.*aligned/) { - WARN("PREFER_ALIGNED", - "__aligned(size) is preferred over __attribute__((aligned(size)))\n" . $herecurr); - } - -# Check for __attribute__ format(printf, prefer __printf - if ($line =~ /\b__attribute__\s*\(\s*\(\s*format\s*\(\s*printf/) { - WARN("PREFER_PRINTF", - "__printf(string-index, first-to-check) is preferred over __attribute__((format(printf, string-index, first-to-check)))\n" . $herecurr); - } - -# Check for __attribute__ format(scanf, prefer __scanf - if ($line =~ /\b__attribute__\s*\(\s*\(\s*format\s*\(\s*scanf\b/) { - WARN("PREFER_SCANF", - "__scanf(string-index, first-to-check) is preferred over __attribute__((format(scanf, string-index, first-to-check)))\n" . $herecurr); - } - -# check for sizeof(&) - if ($line =~ /\bsizeof\s*\(\s*\&/) { - WARN("SIZEOF_ADDRESS", - "sizeof(& should be avoided\n" . $herecurr); - } - -# check for sizeof without parenthesis - if ($line =~ /\bsizeof\s+((?:\*\s*|)$Lval|$Type(?:\s+$Lval|))/) { - WARN("SIZEOF_PARENTHESIS", - "sizeof $1 should be sizeof($1)\n" . $herecurr); - } - -# check for line continuations in quoted strings with odd counts of " - if ($rawline =~ /\\$/ && $rawline =~ tr/"/"/ % 2) { - WARN("LINE_CONTINUATIONS", - "Avoid line continuations in quoted strings\n" . $herecurr); - } - -# check for struct spinlock declarations - if ($line =~ /^.\s*\bstruct\s+spinlock\s+\w+\s*;/) { - WARN("USE_SPINLOCK_T", - "struct spinlock should be spinlock_t\n" . $herecurr); - } - -# Check for misused memsets - if ($^V && $^V ge 5.10.0 && - defined $stat && - $stat =~ /^\+(?:.*?)\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*$FuncArg\s*\)/s) { - - my $ms_addr = $2; - my $ms_val = $7; - my $ms_size = $12; - - if ($ms_size =~ /^(0x|)0$/i) { - ERROR("MEMSET", - "memset to 0's uses 0 as the 2nd argument, not the 3rd\n" . "$here\n$stat\n"); - } elsif ($ms_size =~ /^(0x|)1$/i) { - WARN("MEMSET", - "single byte memset is suspicious. Swapped 2nd/3rd argument?\n" . "$here\n$stat\n"); - } - } - -# typecasts on min/max could be min_t/max_t - if ($^V && $^V ge 5.10.0 && - defined $stat && - $stat =~ /^\+(?:.*?)\b(min|max)\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\)/) { - if (defined $2 || defined $7) { - my $call = $1; - my $cast1 = deparenthesize($2); - my $arg1 = $3; - my $cast2 = deparenthesize($7); - my $arg2 = $8; - my $cast; - - if ($cast1 ne "" && $cast2 ne "" && $cast1 ne $cast2) { - $cast = "$cast1 or $cast2"; - } elsif ($cast1 ne "") { - $cast = $cast1; - } else { - $cast = $cast2; - } - WARN("MINMAX", - "$call() should probably be ${call}_t($cast, $arg1, $arg2)\n" . "$here\n$stat\n"); - } - } - -# check usleep_range arguments - if ($^V && $^V ge 5.10.0 && - defined $stat && - $stat =~ /^\+(?:.*?)\busleep_range\s*\(\s*($FuncArg)\s*,\s*($FuncArg)\s*\)/) { - my $min = $1; - my $max = $7; - if ($min eq $max) { - WARN("USLEEP_RANGE", - "usleep_range should not use min == max args; see Documentation/timers/timers-howto.txt\n" . "$here\n$stat\n"); - } elsif ($min =~ /^\d+$/ && $max =~ /^\d+$/ && - $min > $max) { - WARN("USLEEP_RANGE", - "usleep_range args reversed, use min then max; see Documentation/timers/timers-howto.txt\n" . "$here\n$stat\n"); - } - } - -# check for new externs in .c files. - if ($realfile =~ /\.c$/ && defined $stat && - $stat =~ /^.\s*(?:extern\s+)?$Type\s+($Ident)(\s*)\(/s) - { - my $function_name = $1; - my $paren_space = $2; - - my $s = $stat; - if (defined $cond) { - substr($s, 0, length($cond), ''); - } - if ($s =~ /^\s*;/ && - $function_name ne 'uninitialized_var') - { - WARN("AVOID_EXTERNS", - "externs should be avoided in .c files\n" . $herecurr); - } - - if ($paren_space =~ /\n/) { - WARN("FUNCTION_ARGUMENTS", - "arguments for function declarations should follow identifier\n" . $herecurr); - } - - } elsif ($realfile =~ /\.c$/ && defined $stat && - $stat =~ /^.\s*extern\s+/) - { - WARN("AVOID_EXTERNS", - "externs should be avoided in .c files\n" . $herecurr); - } - -# checks for new __setup's - if ($rawline =~ /\b__setup\("([^"]*)"/) { - my $name = $1; - - if (!grep(/$name/, @setup_docs)) { - CHK("UNDOCUMENTED_SETUP", - "__setup appears un-documented -- check Documentation/kernel-parameters.txt\n" . $herecurr); - } - } - -# check for pointless casting of kmalloc return - if ($line =~ /\*\s*\)\s*[kv][czm]alloc(_node){0,1}\b/) { - WARN("UNNECESSARY_CASTS", - "unnecessary cast may hide bugs, see http://c-faq.com/malloc/mallocnocast.html\n" . $herecurr); - } - -# check for alloc argument mismatch - if ($line =~ /\b(kcalloc|kmalloc_array)\s*\(\s*sizeof\b/) { - WARN("ALLOC_ARRAY_ARGS", - "$1 uses number as first arg, sizeof is generally wrong\n" . $herecurr); - } - -# check for multiple semicolons - if ($line =~ /;\s*;\s*$/) { - WARN("ONE_SEMICOLON", - "Statements terminations use 1 semicolon\n" . $herecurr); - } - -# check for switch/default statements without a break; - if ($^V && $^V ge 5.10.0 && - defined $stat && - $stat =~ /^\+[$;\s]*(?:case[$;\s]+\w+[$;\s]*:[$;\s]*|)*[$;\s]*\bdefault[$;\s]*:[$;\s]*;/g) { - my $ctx = ''; - my $herectx = $here . "\n"; - my $cnt = statement_rawlines($stat); - for (my $n = 0; $n < $cnt; $n++) { - $herectx .= raw_line($linenr, $n) . "\n"; - } - WARN("DEFAULT_NO_BREAK", - "switch default: should use break\n" . $herectx); - } - -# check for gcc specific __FUNCTION__ - if ($line =~ /__FUNCTION__/) { - WARN("USE_FUNC", - "__func__ should be used instead of gcc specific __FUNCTION__\n" . $herecurr); - } - -# check for use of yield() - if ($line =~ /\byield\s*\(\s*\)/) { - WARN("YIELD", - "Using yield() is generally wrong. See yield() kernel-doc (sched/core.c)\n" . $herecurr); - } - -# check for semaphores initialized locked - if ($line =~ /^.\s*sema_init.+,\W?0\W?\)/) { - WARN("CONSIDER_COMPLETION", - "consider using a completion\n" . $herecurr); - } - -# recommend kstrto* over simple_strto* and strict_strto* - if ($line =~ /\b((simple|strict)_(strto(l|ll|ul|ull)))\s*\(/) { - WARN("CONSIDER_KSTRTO", - "$1 is obsolete, use k$3 instead\n" . $herecurr); - } - -# check for __initcall(), use device_initcall() explicitly please - if ($line =~ /^.\s*__initcall\s*\(/) { - WARN("USE_DEVICE_INITCALL", - "please use device_initcall() instead of __initcall()\n" . $herecurr); - } - -# check for various ops structs, ensure they are const. - my $struct_ops = qr{acpi_dock_ops| - address_space_operations| - backlight_ops| - block_device_operations| - dentry_operations| - dev_pm_ops| - dma_map_ops| - extent_io_ops| - file_lock_operations| - file_operations| - hv_ops| - ide_dma_ops| - intel_dvo_dev_ops| - item_operations| - iwl_ops| - kgdb_arch| - kgdb_io| - kset_uevent_ops| - lock_manager_operations| - microcode_ops| - mtrr_ops| - neigh_ops| - nlmsvc_binding| - pci_raw_ops| - pipe_buf_operations| - platform_hibernation_ops| - platform_suspend_ops| - proto_ops| - rpc_pipe_ops| - seq_operations| - snd_ac97_build_ops| - soc_pcmcia_socket_ops| - stacktrace_ops| - sysfs_ops| - tty_operations| - usb_mon_operations| - wd_ops}x; - if ($line !~ /\bconst\b/ && - $line =~ /\bstruct\s+($struct_ops)\b/) { - WARN("CONST_STRUCT", - "struct $1 should normally be const\n" . - $herecurr); - } - -# use of NR_CPUS is usually wrong -# ignore definitions of NR_CPUS and usage to define arrays as likely right - if ($line =~ /\bNR_CPUS\b/ && - $line !~ /^.\s*\s*#\s*if\b.*\bNR_CPUS\b/ && - $line !~ /^.\s*\s*#\s*define\b.*\bNR_CPUS\b/ && - $line !~ /^.\s*$Declare\s.*\[[^\]]*NR_CPUS[^\]]*\]/ && - $line !~ /\[[^\]]*\.\.\.[^\]]*NR_CPUS[^\]]*\]/ && - $line !~ /\[[^\]]*NR_CPUS[^\]]*\.\.\.[^\]]*\]/) - { - WARN("NR_CPUS", - "usage of NR_CPUS is often wrong - consider using cpu_possible(), num_possible_cpus(), for_each_possible_cpu(), etc\n" . $herecurr); - } - -# check for %L{u,d,i} in strings - my $string; - while ($line =~ /(?:^|")([X\t]*)(?:"|$)/g) { - $string = substr($rawline, $-[1], $+[1] - $-[1]); - $string =~ s/%%/__/g; - if ($string =~ /(?mutex.\n" . $herecurr); - } - } - - if ($line =~ /debugfs_create_file.*S_IWUGO/ || - $line =~ /DEVICE_ATTR.*S_IWUGO/ ) { - WARN("EXPORTED_WORLD_WRITABLE", - "Exporting world writable files is usually an error. Consider more restrictive permissions.\n" . $herecurr); - } - } - - # If we have no input at all, then there is nothing to report on - # so just keep quiet. - if ($#rawlines == -1) { - exit(0); - } - - # In mailback mode only produce a report in the negative, for - # things that appear to be patches. - if ($mailback && ($clean == 1 || !$is_patch)) { - exit(0); - } - - # This is not a patch, and we are are in 'no-patch' mode so - # just keep quiet. - if (!$chk_patch && !$is_patch) { - exit(0); - } - - if (!$is_patch) { - ERROR("NOT_UNIFIED_DIFF", - "Does not appear to be a unified-diff format patch\n"); - } - if ($is_patch && $chk_signoff && $signoff == 0) { - ERROR("MISSING_SIGN_OFF", - "Missing Signed-off-by: line(s)\n"); - } - - print report_dump(); - if ($summary && !($clean == 1 && $quiet == 1)) { - print "$filename " if ($summary_file); - print "total: $cnt_error errors, $cnt_warn warnings, " . - (($check)? "$cnt_chk checks, " : "") . - "$cnt_lines lines checked\n"; - print "\n" if ($quiet == 0); - } - - if ($quiet == 0) { - - if ($^V lt 5.10.0) { - print("NOTE: perl $^V is not modern enough to detect all possible issues.\n"); - print("An upgrade to at least perl v5.10.0 is suggested.\n\n"); - } - - # If there were whitespace errors which cleanpatch can fix - # then suggest that. - if ($rpt_cleaners) { - print "NOTE: whitespace errors detected, you may wish to use scripts/cleanpatch or\n"; - print " scripts/cleanfile\n\n"; - $rpt_cleaners = 0; - } - } - - if ($quiet == 0 && keys %ignore_type) { - print "NOTE: Ignored message types:"; - foreach my $ignore (sort keys %ignore_type) { - print " $ignore"; - } - print "\n\n"; - } - - if ($clean == 1 && $quiet == 0) { - print "$vname has no obvious style problems and is ready for submission.\n" - } - if ($clean == 0 && $quiet == 0) { - print << "EOM"; -$vname has style problems, please review. - -If any of these errors are false positives, please report -them to the maintainer, see boards.cfg. -EOM - } - - return $clean; -} diff --git a/tools/checkstack.pl b/tools/checkstack.pl deleted file mode 100755 index c1cdc0a92a..0000000000 --- a/tools/checkstack.pl +++ /dev/null @@ -1,171 +0,0 @@ -#!/usr/bin/perl - -# Check the stack usage of functions -# -# Copyright Joern Engel -# Inspired by Linus Torvalds -# Original idea maybe from Keith Owens -# s390 port and big speedup by Arnd Bergmann -# Mips port by Juan Quintela -# IA64 port via Andreas Dilger -# Arm port by Holger Schurig -# sh64 port by Paul Mundt -# Random bits by Matt Mackall -# M68k port by Geert Uytterhoeven and Andreas Schwab -# AVR32 port by Haavard Skinnemoen (Atmel) -# PARISC port by Kyle McMartin -# sparc port by Martin Habets -# -# Usage: -# objdump -d vmlinux | scripts/checkstack.pl [arch] -# -# TODO : Port to all architectures (one regex per arch) - -use strict; - -# check for arch -# -# $re is used for two matches: -# $& (whole re) matches the complete objdump line with the stack growth -# $1 (first bracket) matches the size of the stack growth -# -# $dre is similar, but for dynamic stack redutions: -# $& (whole re) matches the complete objdump line with the stack growth -# $1 (first bracket) matches the dynamic amount of the stack growth -# -# use anything else and feel the pain ;) -my (@stack, $re, $dre, $x, $xs); -{ - my $arch = shift; - if ($arch eq "") { - $arch = `uname -m`; - chomp($arch); - } - - $x = "[0-9a-f]"; # hex character - $xs = "[0-9a-f ]"; # hex character or space - if ($arch eq 'arm') { - #c0008ffc: e24dd064 sub sp, sp, #100 ; 0x64 - $re = qr/.*sub.*sp, sp, #(([0-9]{2}|[3-9])[0-9]{2})/o; - } elsif ($arch eq 'avr32') { - #8000008a: 20 1d sub sp,4 - #80000ca8: fa cd 05 b0 sub sp,sp,1456 - $re = qr/^.*sub.*sp.*,([0-9]{1,8})/o; - } elsif ($arch =~ /^i[3456]86$/) { - #c0105234: 81 ec ac 05 00 00 sub $0x5ac,%esp - $re = qr/^.*[as][du][db] \$(0x$x{1,8}),\%esp$/o; - $dre = qr/^.*[as][du][db] (%.*),\%esp$/o; - } elsif ($arch eq 'x86_64') { - # 2f60: 48 81 ec e8 05 00 00 sub $0x5e8,%rsp - $re = qr/^.*[as][du][db] \$(0x$x{1,8}),\%rsp$/o; - $dre = qr/^.*[as][du][db] (\%.*),\%rsp$/o; - } elsif ($arch eq 'ia64') { - #e0000000044011fc: 01 0f fc 8c adds r12=-384,r12 - $re = qr/.*adds.*r12=-(([0-9]{2}|[3-9])[0-9]{2}),r12/o; - } elsif ($arch eq 'm68k') { - # 2b6c: 4e56 fb70 linkw %fp,#-1168 - # 1df770: defc ffe4 addaw #-28,%sp - $re = qr/.*(?:linkw %fp,|addaw )#-([0-9]{1,4})(?:,%sp)?$/o; - } elsif ($arch eq 'mips64') { - #8800402c: 67bdfff0 daddiu sp,sp,-16 - $re = qr/.*daddiu.*sp,sp,-(([0-9]{2}|[3-9])[0-9]{2})/o; - } elsif ($arch eq 'mips') { - #88003254: 27bdffe0 addiu sp,sp,-32 - $re = qr/.*addiu.*sp,sp,-(([0-9]{2}|[3-9])[0-9]{2})/o; - } elsif ($arch eq 'parisc' || $arch eq 'parisc64') { - $re = qr/.*ldo ($x{1,8})\(sp\),sp/o; - } elsif ($arch eq 'ppc') { - #c00029f4: 94 21 ff 30 stwu r1,-208(r1) - $re = qr/.*stwu.*r1,-($x{1,8})\(r1\)/o; - } elsif ($arch eq 'ppc64') { - #XXX - $re = qr/.*stdu.*r1,-($x{1,8})\(r1\)/o; - } elsif ($arch eq 'powerpc') { - $re = qr/.*st[dw]u.*r1,-($x{1,8})\(r1\)/o; - } elsif ($arch =~ /^s390x?$/) { - # 11160: a7 fb ff 60 aghi %r15,-160 - # or - # 100092: e3 f0 ff c8 ff 71 lay %r15,-56(%r15) - $re = qr/.*(?:lay|ag?hi).*\%r15,-(([0-9]{2}|[3-9])[0-9]{2}) - (?:\(\%r15\))?$/ox; - } elsif ($arch =~ /^sh64$/) { - #XXX: we only check for the immediate case presently, - # though we will want to check for the movi/sub - # pair for larger users. -- PFM. - #a00048e0: d4fc40f0 addi.l r15,-240,r15 - $re = qr/.*addi\.l.*r15,-(([0-9]{2}|[3-9])[0-9]{2}),r15/o; - } 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 - } -} - -# -# main() -# -my $funcre = qr/^$x* <(.*)>:$/; -my ($func, $file, $lastslash); - -while (my $line = ) { - if ($line =~ m/$funcre/) { - $func = $1; - } - elsif ($line =~ m/(.*):\s*file format/) { - $file = $1; - $file =~ s/\.ko//; - $lastslash = rindex($file, "/"); - if ($lastslash != -1) { - $file = substr($file, $lastslash + 1); - } - } - elsif ($line =~ m/$re/) { - my $size = $1; - $size = hex($size) if ($size =~ /^0x/); - - if ($size > 0xf0000000) { - $size = - $size; - $size += 0x80000000; - $size += 0x80000000; - } - next if ($size > 0x10000000); - - next if $line !~ m/^($xs*)/; - my $addr = $1; - $addr =~ s/ /0/g; - $addr = "0x$addr"; - - my $intro = "$addr $func [$file]:"; - my $padlen = 56 - length($intro); - while ($padlen > 0) { - $intro .= ' '; - $padlen -= 8; - } - next if ($size < 100); - push @stack, "$intro$size\n"; - } - elsif (defined $dre && $line =~ m/$dre/) { - my $size = "Dynamic ($1)"; - - next if $line !~ m/^($xs*)/; - my $addr = $1; - $addr =~ s/ /0/g; - $addr = "0x$addr"; - - my $intro = "$addr $func [$file]:"; - my $padlen = 56 - length($intro); - while ($padlen > 0) { - $intro .= ' '; - $padlen -= 8; - } - push @stack, "$intro$size\n"; - } -} - -# Sort output by size (last field) -print sort { ($b =~ /:\t*(\d+)$/)[0] <=> ($a =~ /:\t*(\d+)$/)[0] } @stack; diff --git a/tools/cleanpatch b/tools/cleanpatch deleted file mode 100755 index 9680d03ad2..0000000000 --- a/tools/cleanpatch +++ /dev/null @@ -1,258 +0,0 @@ -#!/usr/bin/perl -w -# -# Clean a patch file -- or directory of patch files -- of stealth whitespace. -# WARNING: this can be a highly destructive operation. Use with caution. -# - -use bytes; -use File::Basename; - -# Default options -$max_width = 79; - -# Clean up space-tab sequences, either by removing spaces or -# replacing them with tabs. -sub clean_space_tabs($) -{ - no bytes; # Tab alignment depends on characters - - my($li) = @_; - my($lo) = ''; - my $pos = 0; - my $nsp = 0; - my($i, $c); - - for ($i = 0; $i < length($li); $i++) { - $c = substr($li, $i, 1); - if ($c eq "\t") { - my $npos = ($pos+$nsp+8) & ~7; - my $ntab = ($npos >> 3) - ($pos >> 3); - $lo .= "\t" x $ntab; - $pos = $npos; - $nsp = 0; - } elsif ($c eq "\n" || $c eq "\r") { - $lo .= " " x $nsp; - $pos += $nsp; - $nsp = 0; - $lo .= $c; - $pos = 0; - } elsif ($c eq " ") { - $nsp++; - } else { - $lo .= " " x $nsp; - $pos += $nsp; - $nsp = 0; - $lo .= $c; - $pos++; - } - } - $lo .= " " x $nsp; - return $lo; -} - -# Compute the visual width of a string -sub strwidth($) { - no bytes; # Tab alignment depends on characters - - my($li) = @_; - my($c, $i); - my $pos = 0; - my $mlen = 0; - - for ($i = 0; $i < length($li); $i++) { - $c = substr($li,$i,1); - if ($c eq "\t") { - $pos = ($pos+8) & ~7; - } elsif ($c eq "\n") { - $mlen = $pos if ($pos > $mlen); - $pos = 0; - } else { - $pos++; - } - } - - $mlen = $pos if ($pos > $mlen); - return $mlen; -} - -$name = basename($0); - -@files = (); - -while (defined($a = shift(@ARGV))) { - if ($a =~ /^-/) { - if ($a eq '-width' || $a eq '-w') { - $max_width = shift(@ARGV)+0; - } else { - print STDERR "Usage: $name [-width #] files...\n"; - exit 1; - } - } else { - push(@files, $a); - } -} - -foreach $f ( @files ) { - print STDERR "$name: $f\n"; - - if (! -f $f) { - print STDERR "$f: not a file\n"; - next; - } - - if (!open(FILE, '+<', $f)) { - print STDERR "$name: Cannot open file: $f: $!\n"; - next; - } - - binmode FILE; - - # First, verify that it is not a binary file; consider any file - # with a zero byte to be a binary file. Is there any better, or - # additional, heuristic that should be applied? - $is_binary = 0; - - while (read(FILE, $data, 65536) > 0) { - if ($data =~ /\0/) { - $is_binary = 1; - last; - } - } - - if ($is_binary) { - print STDERR "$name: $f: binary file\n"; - next; - } - - seek(FILE, 0, 0); - - $in_bytes = 0; - $out_bytes = 0; - $lineno = 0; - - @lines = (); - - $in_hunk = 0; - $err = 0; - - while ( defined($line = ) ) { - $lineno++; - $in_bytes += length($line); - - if (!$in_hunk) { - if ($line =~ - /^\@\@\s+\-([0-9]+),([0-9]+)\s+\+([0-9]+),([0-9]+)\s\@\@/) { - $minus_lines = $2; - $plus_lines = $4; - if ($minus_lines || $plus_lines) { - $in_hunk = 1; - @hunk_lines = ($line); - } - } else { - push(@lines, $line); - $out_bytes += length($line); - } - } else { - # We're in a hunk - - if ($line =~ /^\+/) { - $plus_lines--; - - $text = substr($line, 1); - $text =~ s/[ \t\r]*$//; # Remove trailing spaces - $text = clean_space_tabs($text); - - $l_width = strwidth($text); - if ($max_width && $l_width > $max_width) { - print STDERR - "$f:$lineno: adds line exceeds $max_width ", - "characters ($l_width)\n"; - } - - push(@hunk_lines, '+'.$text); - } elsif ($line =~ /^\-/) { - $minus_lines--; - push(@hunk_lines, $line); - } elsif ($line =~ /^ /) { - $plus_lines--; - $minus_lines--; - push(@hunk_lines, $line); - } else { - print STDERR "$name: $f: malformed patch\n"; - $err = 1; - last; - } - - if ($plus_lines < 0 || $minus_lines < 0) { - print STDERR "$name: $f: malformed patch\n"; - $err = 1; - last; - } elsif ($plus_lines == 0 && $minus_lines == 0) { - # End of a hunk. Process this hunk. - my $i; - my $l; - my @h = (); - my $adj = 0; - my $done = 0; - - for ($i = scalar(@hunk_lines)-1; $i > 0; $i--) { - $l = $hunk_lines[$i]; - if (!$done && $l eq "+\n") { - $adj++; # Skip this line - } elsif ($l =~ /^[ +]/) { - $done = 1; - unshift(@h, $l); - } else { - unshift(@h, $l); - } - } - - $l = $hunk_lines[0]; # Hunk header - undef @hunk_lines; # Free memory - - if ($adj) { - die unless - ($l =~ /^\@\@\s+\-([0-9]+),([0-9]+)\s+\+([0-9]+),([0-9]+)\s\@\@(.*)$/); - my $mstart = $1; - my $mlin = $2; - my $pstart = $3; - my $plin = $4; - my $tail = $5; # doesn't include the final newline - - $l = sprintf("@@ -%d,%d +%d,%d @@%s\n", - $mstart, $mlin, $pstart, $plin-$adj, - $tail); - } - unshift(@h, $l); - - # Transfer to the output array - foreach $l (@h) { - $out_bytes += length($l); - push(@lines, $l); - } - - $in_hunk = 0; - } - } - } - - if ($in_hunk) { - print STDERR "$name: $f: malformed patch\n"; - $err = 1; - } - - if (!$err) { - if ($in_bytes != $out_bytes) { - # Only write to the file if changed - seek(FILE, 0, 0); - print FILE @lines; - - if ( !defined($where = tell(FILE)) || - !truncate(FILE, $where) ) { - die "$name: Failed to truncate modified file: $f: $!\n"; - } - } - } - - close(FILE); -} diff --git a/tools/dtc-version.sh b/tools/dtc-version.sh deleted file mode 100755 index e8c94d390b..0000000000 --- a/tools/dtc-version.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh -# -# dtc-version dtc-command -# -# Prints the dtc version of `dtc-command' in a canonical 4-digit form -# such as `0222' for binutils 2.22 -# - -dtc="$*" - -if [ ${#dtc} -eq 0 ]; then - echo "Error: No dtc command specified." - printf "Usage:\n\t$0 \n" - exit 1 -fi - -MAJOR=$($dtc -v | head -1 | awk '{print $NF}' | cut -d . -f 1) -MINOR=$($dtc -v | head -1 | awk '{print $NF}' | cut -d . -f 2) - -printf "%02d%02d\\n" $MAJOR $MINOR diff --git a/tools/gcc-version.sh b/tools/gcc-version.sh deleted file mode 100755 index debecb5561..0000000000 --- a/tools/gcc-version.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/sh -# -# gcc-version [-p] gcc-command -# -# Prints the gcc version of `gcc-command' in a canonical 4-digit form -# such as `0295' for gcc-2.95, `0303' for gcc-3.3, etc. -# -# With the -p option, prints the patchlevel as well, for example `029503' for -# gcc-2.95.3, `030301' for gcc-3.3.1, etc. -# - -if [ "$1" = "-p" ] ; then - with_patchlevel=1; - shift; -fi - -compiler="$*" - -if [ ${#compiler} -eq 0 ]; then - echo "Error: No compiler specified." - printf "Usage:\n\t$0 \n" - exit 1 -fi - -MAJOR=$(echo __GNUC__ | $compiler -E -xc - | tail -n 1) -MINOR=$(echo __GNUC_MINOR__ | $compiler -E -xc - | tail -n 1) -if [ "x$with_patchlevel" != "x" ] ; then - PATCHLEVEL=$(echo __GNUC_PATCHLEVEL__ | $compiler -E -xc - | tail -n 1) - printf "%02d%02d%02d\\n" $MAJOR $MINOR $PATCHLEVEL -else - printf "%02d%02d\\n" $MAJOR $MINOR -fi diff --git a/tools/setlocalversion b/tools/setlocalversion deleted file mode 100755 index f551b4c4f4..0000000000 --- a/tools/setlocalversion +++ /dev/null @@ -1,177 +0,0 @@ -#!/bin/sh -# -# This scripts adds local version information from the version -# control systems git, mercurial (hg) and subversion (svn). -# -# It was originally copied from the Linux kernel v3.2.0-rc4 and modified -# to support the U-Boot build-system. -# - -usage() { - echo "Usage: $0 [--save-scmversion] [srctree]" >&2 - exit 1 -} - -scm_only=false -srctree=. -if test "$1" = "--save-scmversion"; then - scm_only=true - shift -fi -if test $# -gt 0; then - srctree=$1 - shift -fi -if test $# -gt 0 -o ! -d "$srctree"; then - usage -fi - -scm_version() -{ - local short - short=false - - cd "$srctree" - if test -e .scmversion; then - cat .scmversion - return - fi - if test "$1" = "--short"; then - short=true - fi - - # Check for git and a git repo. - if test -e .git && head=`git rev-parse --verify --short HEAD 2>/dev/null`; then - - # If we are at a tagged commit (like "v2.6.30-rc6"), we ignore - # it, because this version is defined in the top level Makefile. - if [ -z "`git describe --exact-match 2>/dev/null`" ]; then - - # If only the short version is requested, don't bother - # running further git commands - if $short; then - echo "+" - return - fi - # If we are past a tagged commit (like - # "v2.6.30-rc5-302-g72357d5"), we pretty print it. - if atag="`git describe 2>/dev/null`"; then - echo "$atag" | awk -F- '{printf("-%05d-%s", $(NF-1),$(NF))}' - - # If we don't have a tag at all we print -g{commitish}. - 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 - - # Update index only on r/w media - [ -w . ] && git update-index --refresh --unmerged > /dev/null - - # Check for uncommitted changes - if git diff-index --name-only HEAD | grep -v "^scripts/package" \ - | read dummy; then - printf '%s' -dirty - fi - - # All done with git - return - fi - - # Check for mercurial and a mercurial repo. - if test -d .hg && hgid=`hg id 2>/dev/null`; then - # Do we have an tagged version? If so, latesttagdistance == 1 - if [ "`hg log -r . --template '{latesttagdistance}'`" == "1" ]; then - id=`hg log -r . --template '{latesttag}'` - printf '%s%s' -hg "$id" - else - tag=`printf '%s' "$hgid" | cut -d' ' -f2` - if [ -z "$tag" -o "$tag" = tip ]; then - id=`printf '%s' "$hgid" | sed 's/[+ ].*//'` - printf '%s%s' -hg "$id" - fi - fi - - # Are there uncommitted changes? - # These are represented by + after the changeset id. - case "$hgid" in - *+|*+\ *) printf '%s' -dirty ;; - esac - - # All done with mercurial - return - fi - - # Check for svn and a svn repo. - if rev=`svn info 2>/dev/null | grep '^Last Changed Rev'`; then - rev=`echo $rev | awk '{print $NF}'` - printf -- '-svn%s' "$rev" - - # All done with svn - return - fi -} - -collect_files() -{ - local file res - - for file; do - case "$file" in - *\~*) - continue - ;; - esac - if test -e "$file"; then - res="$res$(cat "$file")" - fi - done - echo "$res" -} - -if $scm_only; then - if test ! -e .scmversion; then - res=$(scm_version) - echo "$res" >.scmversion - fi - exit -fi - -#if test -e include/config/auto.conf; then -# . include/config/auto.conf -#else -# echo "Error: kernelrelease not valid - run 'make prepare' to update it" -# exit 1 -#fi -CONFIG_LOCALVERSION= -CONFIG_LOCALVERSION_AUTO=y - -# localversion* files in the build and source directory -res="$(collect_files localversion*)" -if test ! "$srctree" -ef .; then - res="$res$(collect_files "$srctree"/localversion*)" -fi - -# CONFIG_LOCALVERSION and LOCALVERSION (if set) -res="${res}${CONFIG_LOCALVERSION}${LOCALVERSION}" - -# scm version string if not at a tagged commit -if test "$CONFIG_LOCALVERSION_AUTO" = "y"; then - # full scm version string - res="$res$(scm_version)" -else - # append a plus sign if the repository is not in a clean - # annotated or signed tagged state (as git describe only - # looks at signed or annotated tags - git tag -a/-s) and - # LOCALVERSION= is not specified - if test "${LOCALVERSION+set}" != "set"; then - scm=$(scm_version --short) - res="$res${scm:++}" - fi -fi - -echo "$res" -- cgit From 475c506d08b20314f68c5280095a26802490c981 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 6 Dec 2013 16:34:10 +0900 Subject: Makefile, .gitignore: Cleanup non-existing binaries Signed-off-by: Masahiro Yamada --- tools/.gitignore | 1 - 1 file changed, 1 deletion(-) (limited to 'tools') diff --git a/tools/.gitignore b/tools/.gitignore index 2320fd80a1..930fa2e8a0 100644 --- a/tools/.gitignore +++ b/tools/.gitignore @@ -9,7 +9,6 @@ /mpc86x_clk /mxsboot /ncb -/ncp /proftool /ubsha1 /xway-swap-bytes -- cgit From 8137af19e75a761d4d9e3ada6820ea7824078a54 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Sat, 14 Dec 2013 11:47:32 +0800 Subject: arm64: Add tool to statically apply RELA relocations ARM64 uses the newer RELA-style relocations rather than the older REL. RELA relocations have an addend in the relocation struct, rather than expecting the loader to read a value from the location to be updated. While this is beneficial for ordinary program loading, it's problematic for U-Boot because the location to be updated starts out with zero, rather than a pre-relocation value. Since we need to be able to run C code before relocation, we need a tool to apply the relocations at build time. In theory this tool is applicable to other newer architectures (mainly 64-bit), but currently the only relocations it supports are for arm64, and it assumes a 64-bit little-endian target. If the latter limitation is ever to be changed, we'll need a way to tell the tool what format the image is in. Eventually this may be replaced by a tool that uses libelf or similar and operates directly on the ELF file. I've written some code for such an approach but libelf does not make it easy to poke addresses by memory address (rather than by section), and I was hesitant to write code to manually parse the program headers and do the update outside of libelf (or to iterate over sections) -- especially since it wouldn't get test coverage on things like binaries with multiple PT_LOAD segments. This should be good enough for now to let the manual relocation stuff be removed from the arm64 patches. Signed-off-by: Scott Wood Signed-off-by: David Feng --- tools/Makefile | 6 ++ tools/relocate-rela.c | 189 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 195 insertions(+) create mode 100644 tools/relocate-rela.c (limited to 'tools') diff --git a/tools/Makefile b/tools/Makefile index d4bc84d278..4a7e7e5728 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -60,6 +60,7 @@ BIN_FILES-$(CONFIG_NETCONSOLE) += ncb$(SFX) BIN_FILES-$(CONFIG_SHA1_CHECK_UB_IMG) += ubsha1$(SFX) BIN_FILES-$(CONFIG_KIRKWOOD) += kwboot$(SFX) BIN_FILES-y += proftool(SFX) +BIN_FILES-$(CONFIG_STATIC_RELA) += relocate-rela$(SFX) # Source files which exist outside the tools directory EXT_OBJ_FILES-$(CONFIG_BUILD_ENVCRC) += common/env_embedded.o @@ -85,6 +86,7 @@ NOPED_OBJ_FILES-y += os_support.o NOPED_OBJ_FILES-y += pblimage.o NOPED_OBJ_FILES-y += proftool.o NOPED_OBJ_FILES-y += ublimage.o +NOPED_OBJ_FILES-y += relocate-rela.o OBJ_FILES-$(CONFIG_BUILD_ENVCRC) += envcrc.o OBJ_FILES-$(CONFIG_CMD_LOADS) += img2srec.o OBJ_FILES-$(CONFIG_CMD_NET) += gen_eth_addr.o @@ -251,6 +253,10 @@ $(obj)kwboot$(SFX): $(obj)kwboot.o $(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^ $(HOSTSTRIP) $@ +$(obj)relocate-rela$(SFX): $(obj)relocate-rela.o + $(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^ + $(HOSTSTRIP) $@ + # Some of the tool objects need to be accessed from outside the tools directory $(obj)%.o: $(SRCTREE)/common/%.c $(HOSTCC) -g $(HOSTCFLAGS_NOPED) -c -o $@ $< diff --git a/tools/relocate-rela.c b/tools/relocate-rela.c new file mode 100644 index 0000000000..93b4c3923e --- /dev/null +++ b/tools/relocate-rela.c @@ -0,0 +1,189 @@ +/* + * Copyright 2013 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ BSD-2-Clause + * + * 64-bit and little-endian target only until we need to support a different + * arch that needs this. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef R_AARCH64_RELATIVE +#define R_AARCH64_RELATIVE 1027 +#endif + +static const bool debug_en; + +static void debug(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + if (debug_en) + vprintf(fmt, args); +} + +static bool supported_rela(Elf64_Rela *rela) +{ + uint64_t mask = 0xffffffffULL; /* would be different on 32-bit */ + uint32_t type = rela->r_info & mask; + + switch (type) { +#ifdef R_AARCH64_RELATIVE + case R_AARCH64_RELATIVE: + return true; +#endif + default: + fprintf(stderr, "warning: unsupported relocation type %" + PRIu32 " at %" PRIx64 "\n", + type, rela->r_offset); + + return false; + } +} + +static inline uint64_t swap64(uint64_t val) +{ + return ((val >> 56) & 0x00000000000000ffULL) | + ((val >> 40) & 0x000000000000ff00ULL) | + ((val >> 24) & 0x0000000000ff0000ULL) | + ((val >> 8) & 0x00000000ff000000ULL) | + ((val << 8) & 0x000000ff00000000ULL) | + ((val << 24) & 0x0000ff0000000000ULL) | + ((val << 40) & 0x00ff000000000000ULL) | + ((val << 56) & 0xff00000000000000ULL); +} + +#if __BYTE_ORDER == __LITTLE_ENDIAN +static inline uint64_t be64(uint64_t val) +{ + return swap64(val); +} + +static inline uint64_t le64(uint64_t val) +{ + return val; +} +#else +static inline uint64_t le64(uint64_t val) +{ + return swap64(val); +} + +static inline uint64_t be64(uint64_t val) +{ + return val; +} +#endif + +static bool read_num(const char *str, uint64_t *num) +{ + char *endptr; + *num = strtoull(str, &endptr, 16); + return str[0] && !endptr[0]; +} + +int main(int argc, char **argv) +{ + FILE *f; + int i, num; + uint64_t rela_start, rela_end, text_base; + + if (argc != 5) { + fprintf(stderr, "Statically apply ELF rela relocations\n"); + fprintf(stderr, "Usage: %s " \ + " \n", argv[0]); + fprintf(stderr, "All numbers in hex.\n"); + return 1; + } + + f = fopen(argv[1], "r+b"); + if (!f) { + fprintf(stderr, "%s: Cannot open %s: %s\n", + argv[0], argv[1], strerror(errno)); + return 2; + } + + if (!read_num(argv[2], &text_base) || + !read_num(argv[3], &rela_start) || + !read_num(argv[4], &rela_end)) { + fprintf(stderr, "%s: bad number\n", argv[0]); + return 3; + } + + if (rela_start > rela_end || rela_start < text_base || + (rela_end - rela_start) % 24) { + fprintf(stderr, "%s: bad rela bounds\n", argv[0]); + return 3; + } + + rela_start -= text_base; + rela_end -= text_base; + + num = (rela_end - rela_start) / sizeof(Elf64_Rela); + + for (i = 0; i < num; i++) { + Elf64_Rela rela, swrela; + uint64_t pos = rela_start + sizeof(Elf64_Rela) * i; + uint64_t addr; + + if (fseek(f, pos, SEEK_SET) < 0) { + fprintf(stderr, "%s: %s: seek to %" PRIx64 + " failed: %s\n", + argv[0], argv[1], pos, strerror(errno)); + } + + if (fread(&rela, sizeof(rela), 1, f) != 1) { + fprintf(stderr, "%s: %s: read rela failed at %" + PRIx64 "\n", + argv[0], argv[1], pos); + return 4; + } + + swrela.r_offset = le64(rela.r_offset); + swrela.r_info = le64(rela.r_info); + swrela.r_addend = le64(rela.r_addend); + + if (!supported_rela(&swrela)) + continue; + + debug("Rela %" PRIx64 " %" PRIu64 " %" PRIx64 "\n", + swrela.r_offset, swrela.r_info, swrela.r_addend); + + if (swrela.r_offset < text_base) { + fprintf(stderr, "%s: %s: bad rela at %" PRIx64 "\n", + argv[0], argv[1], pos); + return 4; + } + + addr = swrela.r_offset - text_base; + + if (fseek(f, addr, SEEK_SET) < 0) { + fprintf(stderr, "%s: %s: seek to %" + PRIx64 " failed: %s\n", + argv[0], argv[1], addr, strerror(errno)); + } + + if (fwrite(&rela.r_addend, sizeof(rela.r_addend), 1, f) != 1) { + fprintf(stderr, "%s: %s: write failed at %" PRIx64 "\n", + argv[0], argv[1], addr); + return 4; + } + } + + if (fclose(f) < 0) { + fprintf(stderr, "%s: %s: close failed: %s\n", + argv[0], argv[1], strerror(errno)); + return 4; + } + + return 0; +} -- cgit