- 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.
This commit is contained in:
christos 1996-03-30 04:35:04 +00:00
parent 3bf9d01bf7
commit a323f3fc97

View File

@ -38,6 +38,14 @@ static void add_attribute PROTO((enum attrs, char *,
int, int, int)); int, int, int));
static void init_attributes PROTO((void)); 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__. */ /* Make bindings for __FUNCTION__ and __PRETTY_FUNCTION__. */
void void
@ -535,7 +543,7 @@ decl_attributes (node, attributes, prefix_attributes)
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args))); = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
int format_num; int format_num;
int first_arg_num; int first_arg_num;
int is_scan; int format_kind;
tree argument; tree argument;
int arg_num; 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")
|| !strcmp (IDENTIFIER_POINTER (format_type), || !strcmp (IDENTIFIER_POINTER (format_type),
"__printf__"))) "__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 else if (TREE_CODE (format_type) == IDENTIFIER_NODE
&& (!strcmp (IDENTIFIER_POINTER (format_type), "scanf") && (!strcmp (IDENTIFIER_POINTER (format_type), "scanf")
|| !strcmp (IDENTIFIER_POINTER (format_type), || !strcmp (IDENTIFIER_POINTER (format_type),
"__scanf__"))) "__scanf__")))
is_scan = 1; format_kind = F_USER|F_SCAN;
else else
{ {
error ("unrecognized format specifier for `%s'"); error ("unrecognized format specifier for `%s'");
@ -625,7 +638,7 @@ decl_attributes (node, attributes, prefix_attributes)
record_function_format (DECL_NAME (decl), record_function_format (DECL_NAME (decl),
DECL_ASSEMBLER_NAME (decl), DECL_ASSEMBLER_NAME (decl),
is_scan, format_num, first_arg_num); format_kind, format_num, first_arg_num);
break; break;
} }
@ -674,8 +687,10 @@ decl_attributes (node, attributes, prefix_attributes)
#define T_W &wchar_type_node #define T_W &wchar_type_node
#define T_ST &sizetype #define T_ST &sizetype
typedef struct { typedef struct {
char *format_chars; char *format_chars;
int format_kind;
int pointer_count; int pointer_count;
/* Type of argument if no length modifier is used. */ /* Type of argument if no length modifier is used. */
tree *nolen; tree *nolen;
@ -696,33 +711,38 @@ typedef struct {
} format_char_info; } format_char_info;
static format_char_info print_char_table[] = { static format_char_info print_char_table[] = {
{ "di", 0, T_I, T_I, T_L, T_LL, T_LL, "-wp0 +" }, { "di", F_USER|F_KERN, 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#" }, { "oxX", F_USER|F_KERN, 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" }, { "u", F_USER|F_KERN, 0, T_UI,T_UI, T_UL, T_ULL, T_ULL, "-wp0" },
/* Two GNU extensions. */ /* Two GNU extensions. */
{ "Z", 0, T_ST, NULL, NULL, NULL, NULL, "-wp0" }, { "Z", F_USER, 0, T_ST,NULL, NULL, NULL, NULL, "-wp0" },
{ "m", 0, T_V, NULL, NULL, NULL, NULL, "-wp" }, { "m", F_USER, 0, T_V, NULL, NULL, NULL, NULL, "-wp" },
{ "feEgG", 0, T_D, NULL, NULL, NULL, T_LD, "-wp0 +#" }, { "feEgG", F_USER, 0, T_D, NULL, NULL, NULL, T_LD, "-wp0 +#" },
{ "c", 0, T_I, NULL, T_W, NULL, NULL, "-w" }, { "c", F_USER|F_KERN, 0, T_I, NULL, T_W, NULL, NULL, "-w" },
{ "C", 0, T_W, NULL, NULL, NULL, NULL, "-w" }, { "C", F_USER, 0, T_W, NULL, NULL, NULL, NULL, "-w" },
{ "s", 1, T_C, NULL, T_W, NULL, NULL, "-wp" }, { "s", F_USER|F_KERN, 1, T_C, NULL, T_W, NULL, NULL, "-wp" },
{ "S", 1, T_W, NULL, NULL, NULL, NULL, "-wp" }, { "S", F_USER, 1, T_W, NULL, NULL, NULL, NULL, "-wp" },
{ "p", 1, T_V, NULL, NULL, NULL, NULL, "-w" }, { "p", F_USER|F_KERN, 1, T_V, NULL, NULL, NULL, NULL, "-w" },
{ "n", 1, T_I, T_S, T_L, T_LL, NULL, "" }, { "n", F_USER, 1, T_I, T_S, T_L, T_LL, NULL, "" },
{ "b", 1, T_C, NULL, NULL, NULL, 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 } { NULL }
}; };
static format_char_info scan_char_table[] = { static format_char_info scan_char_table[] = {
{ "di", 1, T_I, T_S, T_L, T_LL, T_LL, "*" }, { "di", F_SCAN|F_USER, 1, T_I, T_S, T_L, T_LL, T_LL, "*" },
{ "ouxX", 1, T_UI, T_US, T_UL, T_ULL, T_ULL, "*" }, { "ouxX", F_SCAN|F_USER, 1, T_UI,T_US, T_UL, T_ULL, T_ULL, "*" },
{ "efgEG", 1, T_F, NULL, T_D, NULL, T_LD, "*" }, { "efgEG", F_SCAN|F_USER, 1, T_F, NULL, T_D, NULL, T_LD, "*" },
{ "sc", 1, T_C, NULL, T_W, NULL, NULL, "*a" }, { "sc", F_SCAN|F_USER, 1, T_C, NULL, T_W, NULL, NULL, "*a" },
{ "[", 1, T_C, NULL, NULL, NULL, NULL, "*a" }, { "[", F_SCAN|F_USER, 1, T_C, NULL, NULL, NULL, NULL, "*a" },
{ "C", 1, T_W, NULL, NULL, NULL, NULL, "*" }, { "C", F_SCAN|F_USER, 1, T_W, NULL, NULL, NULL, NULL, "*" },
{ "S", 1, T_W, NULL, NULL, NULL, NULL, "*" }, { "S", F_SCAN|F_USER, 1, T_W, NULL, NULL, NULL, NULL, "*" },
{ "p", 2, T_V, NULL, NULL, NULL, NULL, "*" }, { "p", F_SCAN|F_USER, 2, T_V, NULL, NULL, NULL, NULL, "*" },
{ "n", 1, T_I, T_S, T_L, T_LL, NULL, "" }, { "n", F_SCAN|F_USER, 1, T_I, T_S, T_L, T_LL, NULL, "" },
{ NULL } { NULL }
}; };
@ -730,7 +750,7 @@ typedef struct function_format_info {
struct function_format_info *next; /* next structure on the list */ struct function_format_info *next; /* next structure on the list */
tree name; /* identifier such as "printf" */ tree name; /* identifier such as "printf" */
tree assembler_name; /* optional mangled identifier (for C++) */ 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 format_num; /* number of format argument */
int first_arg_num; /* number of first arg (zero for varargs) */ int first_arg_num; /* number of first arg (zero for varargs) */
} function_format_info; } function_format_info;
@ -749,32 +769,32 @@ static void check_format_info PROTO((function_format_info *, tree));
void void
init_function_format_info () init_function_format_info ()
{ {
record_function_format (get_identifier ("printf"), NULL_TREE, 0, 1, 2); record_function_format (get_identifier ("printf"), NULL_TREE, F_USER, 1, 2);
record_function_format (get_identifier ("fprintf"), NULL_TREE, 0, 2, 3); record_function_format (get_identifier ("fprintf"), NULL_TREE, F_USER, 2, 3);
record_function_format (get_identifier ("sprintf"), NULL_TREE, 0, 2, 3); record_function_format (get_identifier ("sprintf"), NULL_TREE, F_USER, 2, 3);
record_function_format (get_identifier ("scanf"), NULL_TREE, 1, 1, 2); record_function_format (get_identifier ("scanf"), NULL_TREE, F_SCAN|F_USER, 1, 2);
record_function_format (get_identifier ("fscanf"), NULL_TREE, 1, 2, 3); record_function_format (get_identifier ("fscanf"), NULL_TREE, F_SCAN|F_USER, 2, 3);
record_function_format (get_identifier ("sscanf"), NULL_TREE, 1, 2, 3); record_function_format (get_identifier ("sscanf"), NULL_TREE, F_SCAN|F_USER, 2, 3);
record_function_format (get_identifier ("vprintf"), NULL_TREE, 0, 1, 0); record_function_format (get_identifier ("vprintf"), NULL_TREE, F_USER, 1, 0);
record_function_format (get_identifier ("vfprintf"), NULL_TREE, 0, 2, 0); record_function_format (get_identifier ("vfprintf"), NULL_TREE, F_USER, 2, 0);
record_function_format (get_identifier ("vsprintf"), NULL_TREE, 0, 2, 0); record_function_format (get_identifier ("vsprintf"), NULL_TREE, F_USER, 2, 0);
} }
/* Record information for argument format checking. FUNCTION_IDENT is /* Record information for argument format checking. FUNCTION_IDENT is
the identifier node for the name of the function to check (its decl 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; need not exist yet). FORMAT_KIND specifies if the it is a user or
false indicates printf-style format checking. FORMAT_NUM is the number kernel printing function or a user scanning function. FORMAT_NUM
of the argument which is the format control string (starting from 1). is the number of the argument which is the format control string
FIRST_ARG_NUM is the number of the first actual argument to check (starting from 1). FIRST_ARG_NUM is the number of the first
against the format string, or zero if no checking is not be done actual argument to check against the format string, or zero if
(e.g. for varargs such as vfprintf). */ no checking is not be done (e.g. for varargs such as vfprintf). */
void void
record_function_format (name, assembler_name, is_scan, record_function_format (name, assembler_name, format_kind,
format_num, first_arg_num) format_num, first_arg_num)
tree name; tree name;
tree assembler_name; tree assembler_name;
int is_scan; int format_kind;
int format_num; int format_num;
int first_arg_num; int first_arg_num;
{ {
@ -797,7 +817,7 @@ record_function_format (name, assembler_name, is_scan,
info->assembler_name = assembler_name; info->assembler_name = assembler_name;
} }
info->is_scan = is_scan; info->format_kind = format_kind;
info->format_num = format_num; info->format_num = format_num;
info->first_arg_num = first_arg_num; info->first_arg_num = first_arg_num;
} }
@ -929,7 +949,7 @@ check_format_info (info, params)
} }
flag_chars[0] = 0; flag_chars[0] = 0;
suppressed = wide = precise = FALSE; suppressed = wide = precise = FALSE;
if (info->is_scan) if (FORMAT_IS_SCAN(info))
{ {
suppressed = *format_chars == '*'; suppressed = *format_chars == '*';
if (suppressed) if (suppressed)
@ -1022,32 +1042,80 @@ check_format_info (info, params)
} }
} }
} }
else else if ((FORMAT_CONTEXT(info) & F_KERN) != 0)
if (*format_chars == 'b') { {
if (params == 0) switch (*format_chars)
{ {
warning (tfaff); case 'b':
return; if (params == 0)
}
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))
{ {
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, sprintf (message,
"bitfield is not type unsigned int (arg %d)", "format argument is not a string (arg %d)",
arg_num); arg_num);
warning (message); warning (message);
} }
break;
default:
while (isdigit (*format_chars))
{
wide = TRUE;
++format_chars;
}
break;
} }
} }
else else
@ -1133,9 +1201,10 @@ check_format_info (info, params)
continue; continue;
} }
format_chars++; 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 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; ++fci;
if (fci->format_chars == 0) if (fci->format_chars == 0)
{ {
@ -1168,7 +1237,7 @@ check_format_info (info, params)
format_char); format_char);
warning (message); 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. */ /* Skip over scan set, in case it happens to have '%' in it. */
if (*format_chars == '^') if (*format_chars == '^')