aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/test-dissect.c
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@tv-sign.ru>2005-12-19 21:36:10 +0300
committerLinus Torvalds <torvalds@g5.osdl.org>2005-12-20 09:29:32 -0800
commitc6e90aa8eb9c0b32a771428aff9f2aff2e9bbd9d (patch)
tree6ca5d8b0d79e2f1a9775432f917d350b052df391 /test-dissect.c
parent9d16f0f6e9a6b894ac413c8c62dfba2a4bbde23b (diff)
downloadsparse-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.c95
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;
+}