From a323f3fc97655c1338d7eaffaef6757e25ec21db Mon Sep 17 00:00:00 2001 From: christos Date: Sat, 30 Mar 1996 04:35:04 +0000 Subject: [PATCH] - Add a kprintf format specifier, so that it includes only the formats valid for kernel printf functions - understand the db_printf %n,%r,%z format specifiers - understand the kernel printf %: format specifier - Be more permissive to %b arguments: accept any integer type, not only unsigned ints. --- gnu/usr.bin/gcc/common/c-common.c | 207 ++++++++++++++++++++---------- 1 file changed, 138 insertions(+), 69 deletions(-) diff --git a/gnu/usr.bin/gcc/common/c-common.c b/gnu/usr.bin/gcc/common/c-common.c index fffd886814ad..66dbf9aee0d2 100644 --- a/gnu/usr.bin/gcc/common/c-common.c +++ b/gnu/usr.bin/gcc/common/c-common.c @@ -38,6 +38,14 @@ static void add_attribute PROTO((enum attrs, char *, int, int, int)); static void init_attributes PROTO((void)); +/* Format kinds */ +#define F_USER 0x1 /* Format used in user-land printf/scanf */ +#define F_KERN 0x2 /* Format used in kprintf/scanf etc. */ +#define F_SCAN 0x80000000 /* Format is scan* instead of print* */ + +#define FORMAT_IS_SCAN(p) (((p)->format_kind & F_SCAN) == F_SCAN) +#define FORMAT_CONTEXT(p) (((p)->format_kind & (F_USER|F_KERN))) + /* Make bindings for __FUNCTION__ and __PRETTY_FUNCTION__. */ void @@ -535,7 +543,7 @@ decl_attributes (node, attributes, prefix_attributes) = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args))); int format_num; int first_arg_num; - int is_scan; + int format_kind; tree argument; int arg_num; @@ -550,12 +558,17 @@ decl_attributes (node, attributes, prefix_attributes) && (!strcmp (IDENTIFIER_POINTER (format_type), "printf") || !strcmp (IDENTIFIER_POINTER (format_type), "__printf__"))) - is_scan = 0; + format_kind = F_USER; + else if (TREE_CODE (format_type) == IDENTIFIER_NODE + && (!strcmp (IDENTIFIER_POINTER (format_type), "kprintf") + || !strcmp (IDENTIFIER_POINTER (format_type), + "__kprintf__"))) + format_kind = F_KERN; else if (TREE_CODE (format_type) == IDENTIFIER_NODE && (!strcmp (IDENTIFIER_POINTER (format_type), "scanf") || !strcmp (IDENTIFIER_POINTER (format_type), "__scanf__"))) - is_scan = 1; + format_kind = F_USER|F_SCAN; else { error ("unrecognized format specifier for `%s'"); @@ -625,7 +638,7 @@ decl_attributes (node, attributes, prefix_attributes) record_function_format (DECL_NAME (decl), DECL_ASSEMBLER_NAME (decl), - is_scan, format_num, first_arg_num); + format_kind, format_num, first_arg_num); break; } @@ -674,8 +687,10 @@ decl_attributes (node, attributes, prefix_attributes) #define T_W &wchar_type_node #define T_ST &sizetype + typedef struct { char *format_chars; + int format_kind; int pointer_count; /* Type of argument if no length modifier is used. */ tree *nolen; @@ -696,33 +711,38 @@ typedef struct { } format_char_info; static format_char_info print_char_table[] = { - { "di", 0, T_I, T_I, T_L, T_LL, T_LL, "-wp0 +" }, - { "oxX", 0, T_UI, T_UI, T_UL, T_ULL, T_ULL, "-wp0#" }, - { "u", 0, T_UI, T_UI, T_UL, T_ULL, T_ULL, "-wp0" }, + { "di", F_USER|F_KERN, 0, T_I, T_I, T_L, T_LL, T_LL, "-wp0 +" }, + { "oxX", F_USER|F_KERN, 0, T_UI,T_UI, T_UL, T_ULL, T_ULL, "-wp0#" }, + { "u", F_USER|F_KERN, 0, T_UI,T_UI, T_UL, T_ULL, T_ULL, "-wp0" }, /* Two GNU extensions. */ - { "Z", 0, T_ST, NULL, NULL, NULL, NULL, "-wp0" }, - { "m", 0, T_V, NULL, NULL, NULL, NULL, "-wp" }, - { "feEgG", 0, T_D, NULL, NULL, NULL, T_LD, "-wp0 +#" }, - { "c", 0, T_I, NULL, T_W, NULL, NULL, "-w" }, - { "C", 0, T_W, NULL, NULL, NULL, NULL, "-w" }, - { "s", 1, T_C, NULL, T_W, NULL, NULL, "-wp" }, - { "S", 1, T_W, NULL, NULL, NULL, NULL, "-wp" }, - { "p", 1, T_V, NULL, NULL, NULL, NULL, "-w" }, - { "n", 1, T_I, T_S, T_L, T_LL, NULL, "" }, - { "b", 1, T_C, NULL, NULL, NULL, NULL, "" }, + { "Z", F_USER, 0, T_ST,NULL, NULL, NULL, NULL, "-wp0" }, + { "m", F_USER, 0, T_V, NULL, NULL, NULL, NULL, "-wp" }, + { "feEgG", F_USER, 0, T_D, NULL, NULL, NULL, T_LD, "-wp0 +#" }, + { "c", F_USER|F_KERN, 0, T_I, NULL, T_W, NULL, NULL, "-w" }, + { "C", F_USER, 0, T_W, NULL, NULL, NULL, NULL, "-w" }, + { "s", F_USER|F_KERN, 1, T_C, NULL, T_W, NULL, NULL, "-wp" }, + { "S", F_USER, 1, T_W, NULL, NULL, NULL, NULL, "-wp" }, + { "p", F_USER|F_KERN, 1, T_V, NULL, NULL, NULL, NULL, "-w" }, + { "n", F_USER, 1, T_I, T_S, T_L, T_LL, NULL, "" }, +/* Kernel bitmap formatting */ + { "b", F_KERN, 1, T_C, NULL, NULL, NULL, NULL, "" }, +/* Kernel recursive format */ + { ":", F_KERN, 1, T_V, NULL, NULL, NULL, NULL, "" }, +/* Kernel debugger auto-radix printing */ + { "nrz", F_KERN, 0, T_I, T_I, T_L, T_LL, T_LL, "-wp0# +" }, { NULL } }; static format_char_info scan_char_table[] = { - { "di", 1, T_I, T_S, T_L, T_LL, T_LL, "*" }, - { "ouxX", 1, T_UI, T_US, T_UL, T_ULL, T_ULL, "*" }, - { "efgEG", 1, T_F, NULL, T_D, NULL, T_LD, "*" }, - { "sc", 1, T_C, NULL, T_W, NULL, NULL, "*a" }, - { "[", 1, T_C, NULL, NULL, NULL, NULL, "*a" }, - { "C", 1, T_W, NULL, NULL, NULL, NULL, "*" }, - { "S", 1, T_W, NULL, NULL, NULL, NULL, "*" }, - { "p", 2, T_V, NULL, NULL, NULL, NULL, "*" }, - { "n", 1, T_I, T_S, T_L, T_LL, NULL, "" }, + { "di", F_SCAN|F_USER, 1, T_I, T_S, T_L, T_LL, T_LL, "*" }, + { "ouxX", F_SCAN|F_USER, 1, T_UI,T_US, T_UL, T_ULL, T_ULL, "*" }, + { "efgEG", F_SCAN|F_USER, 1, T_F, NULL, T_D, NULL, T_LD, "*" }, + { "sc", F_SCAN|F_USER, 1, T_C, NULL, T_W, NULL, NULL, "*a" }, + { "[", F_SCAN|F_USER, 1, T_C, NULL, NULL, NULL, NULL, "*a" }, + { "C", F_SCAN|F_USER, 1, T_W, NULL, NULL, NULL, NULL, "*" }, + { "S", F_SCAN|F_USER, 1, T_W, NULL, NULL, NULL, NULL, "*" }, + { "p", F_SCAN|F_USER, 2, T_V, NULL, NULL, NULL, NULL, "*" }, + { "n", F_SCAN|F_USER, 1, T_I, T_S, T_L, T_LL, NULL, "" }, { NULL } }; @@ -730,7 +750,7 @@ typedef struct function_format_info { struct function_format_info *next; /* next structure on the list */ tree name; /* identifier such as "printf" */ tree assembler_name; /* optional mangled identifier (for C++) */ - int is_scan; /* TRUE if *scanf */ + int format_kind; /* user/kernel/print/scan */ int format_num; /* number of format argument */ int first_arg_num; /* number of first arg (zero for varargs) */ } function_format_info; @@ -749,32 +769,32 @@ static void check_format_info PROTO((function_format_info *, tree)); void init_function_format_info () { - record_function_format (get_identifier ("printf"), NULL_TREE, 0, 1, 2); - record_function_format (get_identifier ("fprintf"), NULL_TREE, 0, 2, 3); - record_function_format (get_identifier ("sprintf"), NULL_TREE, 0, 2, 3); - record_function_format (get_identifier ("scanf"), NULL_TREE, 1, 1, 2); - record_function_format (get_identifier ("fscanf"), NULL_TREE, 1, 2, 3); - record_function_format (get_identifier ("sscanf"), NULL_TREE, 1, 2, 3); - record_function_format (get_identifier ("vprintf"), NULL_TREE, 0, 1, 0); - record_function_format (get_identifier ("vfprintf"), NULL_TREE, 0, 2, 0); - record_function_format (get_identifier ("vsprintf"), NULL_TREE, 0, 2, 0); + record_function_format (get_identifier ("printf"), NULL_TREE, F_USER, 1, 2); + record_function_format (get_identifier ("fprintf"), NULL_TREE, F_USER, 2, 3); + record_function_format (get_identifier ("sprintf"), NULL_TREE, F_USER, 2, 3); + record_function_format (get_identifier ("scanf"), NULL_TREE, F_SCAN|F_USER, 1, 2); + record_function_format (get_identifier ("fscanf"), NULL_TREE, F_SCAN|F_USER, 2, 3); + record_function_format (get_identifier ("sscanf"), NULL_TREE, F_SCAN|F_USER, 2, 3); + record_function_format (get_identifier ("vprintf"), NULL_TREE, F_USER, 1, 0); + record_function_format (get_identifier ("vfprintf"), NULL_TREE, F_USER, 2, 0); + record_function_format (get_identifier ("vsprintf"), NULL_TREE, F_USER, 2, 0); } /* Record information for argument format checking. FUNCTION_IDENT is the identifier node for the name of the function to check (its decl - need not exist yet). IS_SCAN is true for scanf-type format checking; - false indicates printf-style format checking. FORMAT_NUM is the number - of the argument which is the format control string (starting from 1). - FIRST_ARG_NUM is the number of the first actual argument to check - against the format string, or zero if no checking is not be done - (e.g. for varargs such as vfprintf). */ + need not exist yet). FORMAT_KIND specifies if the it is a user or + kernel printing function or a user scanning function. FORMAT_NUM + is the number of the argument which is the format control string + (starting from 1). FIRST_ARG_NUM is the number of the first + actual argument to check against the format string, or zero if + no checking is not be done (e.g. for varargs such as vfprintf). */ void -record_function_format (name, assembler_name, is_scan, +record_function_format (name, assembler_name, format_kind, format_num, first_arg_num) tree name; tree assembler_name; - int is_scan; + int format_kind; int format_num; int first_arg_num; { @@ -797,7 +817,7 @@ record_function_format (name, assembler_name, is_scan, info->assembler_name = assembler_name; } - info->is_scan = is_scan; + info->format_kind = format_kind; info->format_num = format_num; info->first_arg_num = first_arg_num; } @@ -929,7 +949,7 @@ check_format_info (info, params) } flag_chars[0] = 0; suppressed = wide = precise = FALSE; - if (info->is_scan) + if (FORMAT_IS_SCAN(info)) { suppressed = *format_chars == '*'; if (suppressed) @@ -1022,32 +1042,80 @@ check_format_info (info, params) } } } - else - if (*format_chars == 'b') { - if (params == 0) + else if ((FORMAT_CONTEXT(info) & F_KERN) != 0) + { + switch (*format_chars) { - warning (tfaff); - return; - } - if (info->first_arg_num != 0) - { - cur_param = TREE_VALUE (params); - cur_type = TREE_TYPE (cur_param); - params = TREE_CHAIN (params); - ++arg_num; - /* - * `%b' takes two arguments: - * an unsigned int (the bits), type-checked here - * a string (the bit names), checked for in mainstream - * code below (see `%b' entry in print_char_table[]) - */ - if ((TYPE_MAIN_VARIANT (cur_type) != unsigned_type_node)) + case 'b': + if (params == 0) { + warning (tfaff); + return; + } + if (info->first_arg_num != 0) + { + cur_param = TREE_VALUE (params); + cur_type = TREE_TYPE (cur_param); + params = TREE_CHAIN (params); + ++arg_num; + /* + * `%b' takes two arguments: + * an integer type (the bits), type-checked here + * a string (the bit names), checked for in mainstream + * code below (see `%b' entry in print_char_table[]) + */ + + if (TREE_CODE (TYPE_MAIN_VARIANT (cur_type)) != INTEGER_TYPE) + { + sprintf (message, + "bitfield is not an integer type (arg %d)", + arg_num); + warning (message); + } + } + break; + + case ':': + if (params == 0) + { + warning (tfaff); + return; + } + if (info->first_arg_num != 0) + { + cur_param = TREE_VALUE (params); + cur_type = TREE_TYPE (cur_param); + params = TREE_CHAIN (params); + ++arg_num; + /* + * `%r' takes two arguments: + * a string (the recursive format), type-checked here + * a pointer (va_list of format arguments), checked for + * in mainstream code below (see `%r' entry in + * print_char_table[]) + */ + if (TREE_CODE (cur_type) == POINTER_TYPE) + { + cur_type = TREE_TYPE (cur_type); + if (TYPE_MAIN_VARIANT (cur_type) == char_type_node) + { + break; + } + } sprintf (message, - "bitfield is not type unsigned int (arg %d)", + "format argument is not a string (arg %d)", arg_num); warning (message); } + break; + + default: + while (isdigit (*format_chars)) + { + wide = TRUE; + ++format_chars; + } + break; } } else @@ -1133,9 +1201,10 @@ check_format_info (info, params) continue; } format_chars++; - fci = info->is_scan ? scan_char_table : print_char_table; + fci = FORMAT_IS_SCAN(info) ? scan_char_table : print_char_table; while (fci->format_chars != 0 - && index (fci->format_chars, format_char) == 0) + && ((FORMAT_CONTEXT(fci) & FORMAT_CONTEXT(info)) == 0 + || index (fci->format_chars, format_char) == 0)) ++fci; if (fci->format_chars == 0) { @@ -1168,7 +1237,7 @@ check_format_info (info, params) format_char); warning (message); } - if (info->is_scan && format_char == '[') + if (FORMAT_IS_SCAN(info) && format_char == '[') { /* Skip over scan set, in case it happens to have '%' in it. */ if (*format_chars == '^')