- 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:
parent
3bf9d01bf7
commit
a323f3fc97
@ -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 == '^')
|
||||||
|
Loading…
Reference in New Issue
Block a user