diff options
author | Oleg Nesterov <oleg@tv-sign.ru> | 2005-12-19 21:36:10 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-12-20 09:29:32 -0800 |
commit | c6e90aa8eb9c0b32a771428aff9f2aff2e9bbd9d (patch) | |
tree | 6ca5d8b0d79e2f1a9775432f917d350b052df391 /test-dissect.c | |
parent | 9d16f0f6e9a6b894ac413c8c62dfba2a4bbde23b (diff) | |
download | sparse-dev-c6e90aa8eb9c0b32a771428aff9f2aff2e9bbd9d.tar.gz |
[PATCH] dissect.c
This patch adds dissect.{h,c} files to the sparse distribution.
From dissect.h:
struct reporter
{
void (*r_symdef)(struct symbol*);
void (*r_symbol)(unsigned mode, struct position*, struct symbol*);
void (*r_member)(unsigned mode, struct position*, struct symbol*, struct symbol*);
};
extern void dissect(struct symbol_list*, struct reporter*);
dissect() walks the output of the sparse_file() and calls reporter's
callbacks.
->r_symdef() is called when the symbol (variable or function) is defined.
->r_symbol() - when the symbol is used in any way. The 'mode' parameter
denotes how this symbol was used. It is a bitmask of possible flags:
FLAG: Code example:
U_R_VAL return VAR;
U_W_VAL VAR = 0;
U_R_PTR return *VAR;
U_W_PTR *VAR = 0;
U_R_AOF const void *... = &VAR;
U_W_AOF memset(&VAR, ...);
->r_member() tracks the use of members of structures in the same way.
This patch also adds test-dissect.c, a simple and stupid example. It
prints the 'mode' parameter in a human readable format along with the
storage info, variable's name (or struct_name.member_name), and it's
type.
The 'mode' is dumped as a 3-letter string. The first letter denotes
AOF part, 2-nd - VAL, 3-rd - PTR.
0 -> '-'
U_R_xxx -> 'r'
U_W_xxx -> 'w'
U_R_xxx | U_W_xxx -> 'm'
Example:
$ cat -n T.c
1 int var;
2
3 static void func(void)
4 {
5 int *ptr;
6
7 ptr = &var;
8 *ptr = var;
9
10 var = *++ptr;
11 }
$ ./test-dissect T.c
FILE: T.c
1:5 g def var int
3:13 s def func void ( )( ... )
5:6 l def ptr int *
7:2 l -w- ptr int *
7:9 g m-- var int
8:3 l --w ptr int *
8:9 g -r- var int
10:2 g -w- var int
10:11 l -mr ptr int *
Note that '*ptr' does not add U_R_VAL flag, this is a feature, not a bug,
even if technically wrong.
dissect() does not check the code for correctness, for example:
0 = X = Y;
gives this output:
5:6 g -w- X bad type
5:10 g -r- Y bad type
Again, X has no U_R_VAL, notabug.
Members of structures usage:
task_t *tsk;
tsk->parent->real_parent->pid++;
output:
7:2 l --r tsk struct task_struct [usertype] *
7:5 g --r task_struct.parent struct task_struct *
7:13 g --m task_struct.real_parent struct task_struct *
7:26 g -m- task_struct.pid int
dissect() tries to de-anonymize unnamed structures/unions:
1 struct T {
2 struct {
3 int x, y;
4 } m;
5 } t = {
6 { undeclared }
7 };
output:
5:3 g def t struct T
5:3 g -w- t struct T
6:2 s -w- T.m struct T:m
6:4 s -w- T:m.x int
6:4 g -r- undeclared bad type
When entire struct is overwritten, ->r_member() is called with mem == NULL,
this reported as struct_name.*, example:
*new_vma = *vma;
output:
2028:5 l --w new_vma struct vm_area_struct *
2028:13 g -w- vm_area_struct.* struct vm_area_struct
2028:13 g -w- pgprot_t.* struct pgprot_t
2028:13 g -w- rb_node.* struct rb_node
2028:13 g -w- vm_area_struct:shared.* union vm_area_struct:shared
2028:13 g -w- vm_area_struct:shared:vm_set.* struct vm_area_struct:shared:vm_set
2028:13 g -w- list_head.* struct list_head
2028:13 g -w- raw_prio_tree_node.* struct raw_prio_tree_node
2028:13 g -w- list_head.* struct list_head
2028:16 l --r vma struct vm_area_struct *
Function calls use U_R_PTR bit:
5 func();
6 pf = func;
7 pf();
5:2 g --r func void ( )( ... )
6:2 l -w- pf void ( * )( ... )
6:7 g r-- func void ( )( ... )
7:2 l --r pf void ( * )( ... )
BUGS:
1. dissect() confuses array-in-container with a pointer:
3 struct T { int ary[]; } t;
4
5 t.ary[0] = 0;
output:
5:2 l -r- t /* BUG, should be -w- */ struct T
5:3 s -w- T.ary int [0]
2. It can't detect the case when the address is taken only for writing,
eg: *(&i + 1) = 0, so U_W_AOF always implies U_R_AOF.
3. It does not support "flat" initializers without braces:
3 struct O {
4 struct I {
5 int x, y;
6 } a, b;
7 };
8
9 struct O o1 = { 1, 2, 3 };
buggy output:
9:11 l -w- o1 struct O
9:18 s -w- O.a struct I
9:21 s -w- O.b struct I
9:24 s -w- O.? bad type
This is ok:
11 struct O o2 = { { 1 }, .b = { .y = 0 } };
11:11 l -w- o2 struct O
11:18 s -w- O.a struct I
11:20 s -w- I.x int
11:30 s -w- O.b struct I
11:37 s -w- I.y int
4. The implementation is far from perfect. It was really done
in "add some code + printf and see what happens" manner, without
studying the sources first. However I beleive it may be useful
for others, that is why I am posting it.
Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'test-dissect.c')
-rw-r--r-- | test-dissect.c | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/test-dissect.c b/test-dissect.c new file mode 100644 index 00000000..ccdf979f --- /dev/null +++ b/test-dissect.c @@ -0,0 +1,95 @@ +#include "dissect.h" + +static unsigned dotc_stream; + +static inline char storage(struct symbol *sym) +{ + int t = sym->type; + unsigned m = sym->ctype.modifiers; + + if (m & MOD_INLINE || t == SYM_STRUCT || t == SYM_UNION /*|| t == SYM_ENUM*/) + return sym->pos.stream == dotc_stream ? 's' : 'g'; + + return (m & MOD_STATIC) ? 's' : (m & MOD_NONLOCAL) ? 'g' : 'l'; +} + +static inline const char *show_mode(unsigned mode) +{ + static char str[3]; + + if (mode == -1) + return "def"; + +#define U(u_r) "-rwm"[(mode / u_r) & 3] + str[0] = U(U_R_AOF); + str[1] = U(U_R_VAL); + str[2] = U(U_R_PTR); +#undef U + + return str; +} + +static void print_usage(struct position *pos, struct symbol *sym, unsigned mode) +{ + static unsigned curr_stream = -1; + + if (curr_stream != pos->stream) { + curr_stream = pos->stream; + printf("\nFILE: %s\n\n", stream_name(curr_stream)); + } + + printf("%4d:%-3d %c %-5.3s", + pos->line, pos->pos, storage(sym), show_mode(mode)); +} + +static void r_symbol(unsigned mode, struct position *pos, struct symbol *sym) +{ + print_usage(pos, sym, mode); + + if (!sym->ident) + sym->ident = MK_IDENT("__asm__"); + + printf("%-32.*s %s\n", + sym->ident->len, sym->ident->name, + show_typename(sym->ctype.base_type)); +} + +static void r_member(unsigned mode, struct position *pos, struct symbol *sym, struct symbol *mem) +{ + struct ident *ni, *si, *mi; + + print_usage(pos, sym, mode); + + ni = MK_IDENT("?"); + si = sym->ident ?: ni; + /* mem == NULL means entire struct accessed */ + mi = mem ? (mem->ident ?: ni) : MK_IDENT("*"); + + printf("%.*s.%-*.*s %s\n", + si->len, si->name, + 32-1 - si->len, mi->len, mi->name, + show_typename(mem ? mem->ctype.base_type : sym)); +} + +static void r_symdef(struct symbol *sym) +{ + r_symbol(-1, &sym->pos, sym); +} + +int main(int argc, char **argv) +{ + static struct reporter reporter = { + .r_symdef = r_symdef, + .r_symbol = r_symbol, + .r_member = r_member, + }; + + sparse_initialize(argc, argv); + + while (*argv) { + dotc_stream = input_stream_nr; + dissect(__sparse(argv), &reporter); + } + + return 0; +} |