Commit | Line | Data |
---|---|---|
e09e518e GM |
1 | #include <lttv/lttv.h> |
2 | #include <lttv/option.h> | |
3 | #include <lttv/module.h> | |
4 | #include <lttv/hook.h> | |
5 | #include <lttv/attribute.h> | |
6 | #include <lttv/iattribute.h> | |
7 | #include <lttv/stats.h> | |
8 | #include <lttv/filter.h> | |
9 | #include <ltt/ltt.h> | |
10 | #include <ltt/event.h> | |
11 | #include <ltt/trace.h> | |
12 | #include <stdio.h> | |
13 | #include "fd.h" | |
14 | ||
15 | GArray *_fsm_list; | |
16 | GArray * _fsms_to_remove; | |
17 | struct timeval *tv1, *tv2; | |
18 | int max_fsms = 0; | |
19 | int total_forks = 0; | |
20 | int count_events = 0; | |
21 | int skip=0; | |
22 | ||
23 | static gboolean fs_close(void *hook_data, void *call_data){ | |
24 | count_events++; | |
25 | LttvTracefileState *s = (LttvTracefileState *) call_data; | |
26 | LttEvent *e = ltt_tracefile_get_event(s->parent.tf); | |
27 | LttvTraceHook *th = (LttvTraceHook *)hook_data; | |
28 | ||
29 | struct marker_field *f = lttv_trace_get_hook_field(th, 0); | |
30 | guint32 fd = ltt_event_get_long_unsigned(e, f); | |
31 | ||
32 | LttvTracefileState *tfs = (LttvTracefileState *)call_data; | |
33 | LttvTraceState *ts = (LttvTraceState *) tfs->parent.t_context; | |
34 | LttvProcessState *process = ts->running_process[tfs->cpu]; | |
35 | int pid=process->pid; | |
36 | ||
37 | //initialize a new finite state machine | |
38 | struct fd *fdstruct = fd_Init(); | |
39 | total_forks++; | |
40 | //add new fsm to list | |
41 | g_array_append_val(_fsm_list, fdstruct); | |
42 | //call corresponding transition | |
43 | fdContext_fs_close(&(fdstruct->_fsm), pid, fd); | |
44 | ||
45 | if(max_fsms<_fsm_list->len) | |
46 | max_fsms=_fsm_list->len; | |
47 | return FALSE; | |
48 | ||
49 | } | |
50 | ||
51 | static gboolean fs_open(void *hook_data, void *call_data){ | |
52 | count_events++; | |
53 | LttvTracefileState *s = (LttvTracefileState *) call_data; | |
54 | LttEvent *e = ltt_tracefile_get_event(s->parent.tf); | |
55 | LttvTraceHook *th = (LttvTraceHook *)hook_data; | |
56 | ||
57 | struct marker_field *f = lttv_trace_get_hook_field(th, 0); | |
58 | guint32 fd = ltt_event_get_long_unsigned(e, f); | |
59 | ||
60 | LttvTracefileState *tfs = (LttvTracefileState *)call_data; | |
61 | LttvTraceState *ts = (LttvTraceState *) tfs->parent.t_context; | |
62 | LttvProcessState *process = ts->running_process[tfs->cpu]; | |
63 | int pid=process->pid; | |
64 | ||
65 | //for every fsm in the list, call appropriate transition | |
66 | //index i is sent as an argument in case fsm is to be freed | |
67 | struct fd *fdstruct; | |
68 | int i; | |
69 | for(i=_fsm_list->len-1; i>=0; i--){ | |
70 | if (skip) | |
71 | break; | |
72 | fdstruct = (struct fd *) g_array_index(_fsm_list, struct fdstruct *, i); | |
73 | fdContext_fs_open(&(fdstruct->_fsm), pid, fd, i); | |
74 | } | |
75 | skip=0; | |
76 | return FALSE; | |
77 | } | |
78 | ||
79 | static gboolean fs_read(void *hook_data, void *call_data){ | |
80 | count_events++; | |
81 | LttvTracefileState *s = (LttvTracefileState *) call_data; | |
82 | LttEvent *e = ltt_tracefile_get_event(s->parent.tf); | |
83 | LttvTraceHook *th = (LttvTraceHook *)hook_data; | |
84 | ||
85 | struct marker_field *f = lttv_trace_get_hook_field(th, 0); | |
86 | guint32 fd = ltt_event_get_long_unsigned(e, f); | |
87 | ||
88 | LttvTracefileState *tfs = (LttvTracefileState *)call_data; | |
89 | LttvTraceState *ts = (LttvTraceState *) tfs->parent.t_context; | |
90 | LttvProcessState *process = ts->running_process[tfs->cpu]; | |
91 | int pid=process->pid; | |
92 | ||
93 | LttTime time = ltt_event_time(e); | |
94 | long ts_nsec, ts_sec; | |
95 | ts_sec = (long) time.tv_sec; | |
96 | ts_nsec=(long) time.tv_nsec; | |
97 | ||
98 | //for every fsm in the list, call appropriate transition | |
99 | struct fd *fdstruct; | |
100 | int i; | |
101 | for(i=0; i<_fsm_list->len; i++){ | |
102 | if (skip) | |
103 | break; | |
104 | fdstruct = (struct fd *)g_array_index(_fsm_list, struct fd *, i); | |
105 | fdContext_fs_read(&(fdstruct->_fsm), pid, fd, ts_sec, ts_nsec); | |
106 | } | |
107 | ||
108 | skip=0; | |
109 | return FALSE; | |
110 | } | |
111 | static gboolean fs_write(void *hook_data, void *call_data){ | |
112 | count_events++; | |
113 | LttvTracefileState *s = (LttvTracefileState *) call_data; | |
114 | LttEvent *e = ltt_tracefile_get_event(s->parent.tf); | |
115 | LttvTraceHook *th = (LttvTraceHook *)hook_data; | |
116 | ||
117 | struct marker_field *f = lttv_trace_get_hook_field(th, 0); | |
118 | guint32 fd = ltt_event_get_long_unsigned(e, f); | |
119 | ||
120 | LttvTracefileState *tfs = (LttvTracefileState *)call_data; | |
121 | LttvTraceState *ts = (LttvTraceState *) tfs->parent.t_context; | |
122 | LttvProcessState *process = ts->running_process[tfs->cpu]; | |
123 | int pid=process->pid; | |
124 | ||
125 | //for every fsm in the list, call appropriate transition | |
126 | struct fd *fdstruct; | |
127 | int i; | |
128 | for(i=0; i<_fsm_list->len; i++){ | |
129 | if (skip) | |
130 | break; | |
131 | fdstruct = g_array_index(_fsm_list, struct fd *, i); | |
132 | fdContext_fs_write(&(fdstruct->_fsm), pid, fd); | |
133 | } | |
134 | skip=0; | |
135 | return FALSE; | |
136 | } | |
137 | static gboolean process_exit(void *hook_data, void *call_data){ | |
138 | count_events++; | |
139 | LttvTracefileState *s = (LttvTracefileState *) call_data; | |
140 | LttEvent *e = ltt_tracefile_get_event(s->parent.tf); | |
141 | LttvTraceHook *th = (LttvTraceHook *)hook_data; | |
142 | ||
143 | LttvTracefileState *tfs = (LttvTracefileState *)call_data; | |
144 | LttvTraceState *ts = (LttvTraceState *) tfs->parent.t_context; | |
145 | LttvProcessState *process = ts->running_process[tfs->cpu]; | |
146 | int pid=process->pid; | |
147 | ||
148 | ||
149 | //for every fsm in the list, call appropriate transition | |
150 | struct fd *fdstruct; | |
151 | int i; | |
152 | for(i=_fsm_list->len-1; i>=0 ; i--){ | |
153 | fdstruct =(struct fd *) g_array_index(_fsm_list, struct fd *, i); | |
154 | fdContext_process_exit(&(fdstruct->_fsm), pid, i); | |
155 | } | |
156 | skip=0; | |
157 | return FALSE; | |
158 | } | |
159 | static gboolean fs_dup3(void *hook_data, void *call_data){ | |
160 | count_events++; | |
161 | LttvTracefileState *s = (LttvTracefileState *) call_data; | |
162 | LttEvent *e = ltt_tracefile_get_event(s->parent.tf); | |
163 | LttvTraceHook *th = (LttvTraceHook *)hook_data; | |
164 | ||
165 | LttvTracefileState *tfs = (LttvTracefileState *)call_data; | |
166 | LttvTraceState *ts = (LttvTraceState *) tfs->parent.t_context; | |
167 | LttvProcessState *process = ts->running_process[tfs->cpu]; | |
168 | int pid=process->pid; | |
169 | ||
170 | struct marker_field *f = lttv_trace_get_hook_field(th, 1); | |
171 | guint32 newfd = ltt_event_get_long_unsigned(e, f); | |
172 | ||
173 | //for every fsm in the list, call appropriate transition | |
174 | struct fd *fdstruct; | |
175 | int i; | |
176 | for(i=_fsm_list->len-1; i>=0; i--){ | |
177 | if (skip) | |
178 | break; | |
179 | fdstruct =(struct fd *) g_array_index(_fsm_list, struct fd *, i); | |
180 | fdContext_fs_dup3(&(fdstruct->_fsm), pid, newfd, i); | |
181 | } | |
182 | skip=0; | |
183 | return FALSE; | |
184 | ||
185 | } | |
186 | ||
187 | void skip_FSM(){ | |
188 | skip=1; | |
189 | } | |
190 | ||
191 | int removefsm(int i){ | |
192 | g_array_remove_index(_fsm_list, i); | |
193 | } | |
194 | static int add_events_by_id_hooks(void *hook_data, void *call_data){ | |
195 | LttvTraceContext *tc = (LttvTraceContext *) call_data; | |
196 | LttTrace *t = tc->t; | |
197 | ||
198 | //EVENT CHROOT | |
199 | GQuark LTT_FACILITY_FS = g_quark_from_string("fs"); | |
200 | GQuark LTT_FACILITY_KERNEL = g_quark_from_string("kernel"); | |
201 | ||
202 | GQuark LTT_EVENT_CLOSE = g_quark_from_string("close"); | |
203 | //EVENT FIELDS | |
204 | GQuark LTT_FIELD_FD = g_quark_from_string("fd"); | |
205 | GQuark LTT_FIELD_OLD_FD = g_quark_from_string("oldfd"); | |
206 | GQuark LTT_FIELD_NEW_FD = g_quark_from_string("newfd"); | |
207 | ||
208 | GQuark LTT_EVENT_OPEN = g_quark_from_string("open"); | |
209 | ||
210 | GQuark LTT_EVENT_READ = g_quark_from_string("read"); | |
211 | ||
212 | GQuark LTT_EVENT_WRITE = g_quark_from_string("write"); | |
213 | ||
214 | GQuark LTT_EVENT_DUP3 = g_quark_from_string("dup3"); | |
215 | ||
216 | GQuark LTT_EVENT_PROCESS_EXIT = g_quark_from_string("process_exit"); | |
217 | ||
218 | GArray *hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 6); | |
219 | ||
220 | lttv_trace_find_hook(t, LTT_FACILITY_FS, LTT_EVENT_CLOSE, | |
221 | FIELD_ARRAY(LTT_FIELD_FD), | |
222 | fs_close, | |
223 | NULL, | |
224 | &hooks); | |
225 | ||
226 | lttv_trace_find_hook(t, LTT_FACILITY_FS, LTT_EVENT_OPEN, | |
227 | FIELD_ARRAY(LTT_FIELD_FD), | |
228 | fs_open, | |
229 | NULL, | |
230 | &hooks); | |
231 | ||
232 | lttv_trace_find_hook(t, LTT_FACILITY_FS, LTT_EVENT_READ, | |
233 | FIELD_ARRAY(LTT_FIELD_FD), | |
234 | fs_read, | |
235 | NULL, | |
236 | &hooks); | |
237 | ||
238 | ||
239 | lttv_trace_find_hook(t, LTT_FACILITY_FS, LTT_EVENT_WRITE, | |
240 | FIELD_ARRAY(LTT_FIELD_FD), | |
241 | fs_write, | |
242 | NULL, | |
243 | &hooks); | |
244 | ||
245 | lttv_trace_find_hook(t, LTT_FACILITY_KERNEL, LTT_EVENT_PROCESS_EXIT, | |
246 | NULL, | |
247 | process_exit, | |
248 | NULL, | |
249 | &hooks); | |
250 | ||
251 | lttv_trace_find_hook(t, LTT_FACILITY_FS, LTT_EVENT_DUP3, | |
252 | FIELD_ARRAY(LTT_FIELD_OLD_FD, LTT_FIELD_NEW_FD), | |
253 | fs_dup3, | |
254 | NULL, | |
255 | &hooks); | |
256 | ||
257 | int nb_tracefiles = tc->tracefiles->len; | |
258 | LttvTracefileContext **tfc; | |
259 | LttvHooks *needed_hooks; | |
260 | LttvTraceHook *th = (LttvTraceHook *)hook_data; | |
261 | int i, j; | |
262 | for(i=0; i<nb_tracefiles; i++){ | |
263 | tfc = &g_array_index(tc->tracefiles, LttvTracefileContext*, i); | |
264 | for(j=0; j<hooks->len; j++){ | |
265 | th=&g_array_index(hooks, LttvTraceHook, j); | |
266 | needed_hooks = lttv_hooks_by_id_find((*tfc)->event_by_id, th->id); | |
267 | lttv_hooks_add(needed_hooks, th->h, th, LTTV_PRIO_DEFAULT); | |
268 | } | |
269 | } | |
270 | } | |
271 | static void init(){ | |
272 | ||
273 | gboolean result; | |
274 | ||
275 | LttvAttributeValue value; | |
276 | ||
277 | LttvIAttribute *attributes = LTTV_IATTRIBUTE(lttv_global_attributes()); | |
278 | ||
279 | static LttvHooks *before_trace; | |
280 | ||
281 | result = lttv_iattribute_find_by_path(attributes, "hooks/trace/before", LTTV_POINTER, &value); | |
282 | g_assert(result); | |
283 | before_trace = *(value.v_pointer); | |
284 | g_assert(before_trace); | |
285 | ||
286 | //Register add_events_by_id_hook to be called before starting to read the trace | |
287 | //This function will be overwritten between checkers | |
288 | lttv_hooks_add(before_trace, add_events_by_id_hooks, NULL, LTTV_PRIO_DEFAULT); | |
289 | ||
290 | //Initialize empty GArray for FSMs | |
291 | _fsm_list = g_array_new(FALSE, FALSE, sizeof(struct fd *)); | |
292 | ||
293 | tv1 = (struct timeval *)malloc(sizeof(struct timeval)); | |
294 | gettimeofday(tv1, NULL); | |
295 | } | |
296 | static void destroy(){ | |
297 | tv2 = (struct timeval *)malloc(sizeof(struct timeval)); | |
298 | gettimeofday(tv2, NULL); | |
299 | int seconds = tv2->tv_sec - tv1->tv_sec; | |
300 | printf("analysis took: %d seconds \n", seconds); | |
301 | printf("total number of coexisting fsms is: %d\n",max_fsms); | |
302 | printf("total number of forked fsms is: %d\n", total_forks); | |
303 | printf("size of one fsm (in bytes) is: %d\n", sizeof(struct fd)); | |
304 | printf("total number of pertinent events is %d\n", count_events); | |
305 | ||
306 | } | |
307 | ||
308 | LTTV_MODULE("fd_checker", "Detects improper fd usage", | |
309 | "finds read/write access to a closed fd in a trace file", | |
310 | init, destroy, "stats", "batchAnalysis", "option") |