Convert LTTngTop to C++ and state system
[lttngtop.git] / src / iostreamtop.cpp
CommitLineData
715cf83c
PBT
1/*
2 * Copyright (C) 2011-2012 Mathieu Bain <mathieu.bain@polymtl.ca>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 */
17
18#include <stdlib.h>
19#include <unistd.h>
20#include <sys/types.h>
21#include <sys/stat.h>
22#include <string.h>
23extern "C"
24{
25#include <babeltrace/babeltrace.h>
26}
27
28#include "lttngtoptypes.h"
29#include "common.h"
30#include "iostreamtop.h"
31
32void add_file(Quark proc_quark, Quark file, int fd,
33 unsigned long timestamp)
34{
35 Quark parent;
36 Quark file_pointer;
37 Quark old_file;
38 std::string filename;
39 std::string old_filename;
40 std::string path;
41 int flag;
42
43 if (state_system->attributeExists(proc_quark, "threadparent")) {
44 parent = state_system->getQuark(proc_quark, "threadparent");
45 insert_file(parent, fd, timestamp);
46 }
47
48 path = path_name_from_fd(fd);
49 if (state_system->attributeExists(proc_quark, path + "/file")) {
50 file_pointer = state_system->getQuark(proc_quark, path);
51 get_current_attribute_value_quark(&file_pointer, "file",
52 old_file);
53 get_current_attribute_value_string(&old_file, "name",
54 old_filename);
55 get_current_attribute_value_string(&file, "name", filename);
56 if (old_filename != filename) {
57 /* Different file with same fd, we overwrite the
58 file pointer */
59 modify_attribute(timestamp, &file_pointer, "file",
60 file);
61 } else {
62 modify_attribute(timestamp, &old_file, "flag",
63 __NR_open);
64 }
65 } else {
66 file_pointer = state_system->getQuark(proc_quark, path);
67 modify_attribute(timestamp, &file_pointer, "file", file);
68
69 }
70 /* To easily retrieve file pointer from files_history */
71 modify_attribute(timestamp, &file, "fd", fd);
72
73 /* The file may have been created in the parent */
74 get_current_attribute_value_int(&file, "flag", flag);
75 if (flag == -1) {
76 modify_attribute(timestamp, &file, "fd", fd);
77 modify_attribute(timestamp, &file, "flag", __NR_open);
78 increment_attribute(timestamp, NULL, "nbfiles");
79 increment_attribute(timestamp, NULL, "nbnewfiles");
80 }
81}
82
83/*
84 * Edit the file
85 * Called by handled_statedump_filename
86 */
87void edit_file(unsigned long timestamp, Quark proc, Quark file, int fd)
88{
89 std::string path;
90
91 path = path_name_from_fd(fd);
92 if (!state_system->attributeExists(proc, path)) {
93 add_file(proc, file, fd, timestamp);
94 }
95}
96
97Quark create_file(Quark proc, std::string file_name, unsigned long timestamp)
98{
99 Quark file_history;
100 Quark old_newest;
101 bool has_old;
102 std::string current_path;
103 int index;
104 std::stringstream ss;
105
106 if (!get_current_attribute_value_quark(&proc, "files_history/current",
107 file_history)) {
108 /* First file for process */
109 file_history = state_system->getQuark(
110 proc, "files_history/file_0");
111 } else {
112
113 current_path = state_system->getFullAttributeName(file_history);
114 index = atoi(current_path.substr(current_path.find_last_of('_')
115 + 1).c_str());
116 ss << "files_history/file_" << index + 1;
117 current_path = ss.str();
118 file_history = state_system->getQuark(
119 proc, current_path);
120 }
121
122 has_old = get_current_attribute_value_quark(
123 &proc,"files_history/current", old_newest);
124 modify_attribute(timestamp, &proc, "files_history/current",
125 file_history);
126 modify_attribute(timestamp, &file_history, "file/name", file_name);
127 modify_attribute(timestamp, &file_history, "file/read", 0);
128 modify_attribute(timestamp, &file_history, "file/write", 0);
129 modify_attribute(timestamp, &file_history, "file/flag", -1);
130 modify_attribute(timestamp, &file_history, "file/fd", -1);
131 modify_attribute(timestamp, &file_history, "file/birth", timestamp);
132 if (has_old)
133 modify_attribute(timestamp, &file_history, "next", old_newest);
134 else
135 nullify_attribute(timestamp, &file_history, "next");
136
137 return state_system->getQuark(file_history, "file");
138}
139
140void insert_file(Quark proc, int fd, unsigned long timestamp)
141{
142 Quark file;
143 Quark parent;
144 Quark parent_file;
145 bool parent_has_file;
146 std::string name;
147
148 if (fd < 0)
149 return;
150
151 if (get_file(proc, fd, file)) {
152 if (state_system->attributeExists(proc, "threadparent")) {
153 parent = state_system->getQuark(proc, "threadparent");
154 parent_has_file = get_file(parent, fd,
155 parent_file);
156 if (parent_has_file) {
157 get_current_attribute_value_string(&parent_file,
158 "name",
159 name);
160 modify_attribute(timestamp, &file, "name",
161 name);
162 }
163 }
164 } else {
165 file = create_file(proc, "Unknown", timestamp);
166 add_file(proc, file, fd, timestamp);
167 }
168}
169
170void close_file(unsigned long timestamp, Quark proc, int fd)
171{
172 Quark file;
173 bool file_found;
174
175 file_found = get_current_attribute_value_quark(&proc,
176 path_name_from_fd(fd),
177 file);
178 if (file_found) {
179 modify_attribute(timestamp, &file, "flag", __NR_close);
180 decrement_attribute(timestamp, NULL, "nbfiles");
181 }
182 increment_attribute(timestamp, NULL, "nbdeadfiles");
183}
184
185bool get_file(Quark proc_quark, int fd, Quark &file_quark)
186{
187 std::string path = path_name_from_fd(fd);
188 Quark file_pointer;
189 if (state_system->attributeExists(proc_quark, path)) {
190 file_pointer = state_system->getQuark(proc_quark, path);
191 return get_current_attribute_value_quark(&file_pointer, "file",
192 file_quark);
193 } else {
194 return false;
195 }
196}
197
198void show_history(Quark proc)
199{
200 Quark file;
201 int fd;
202 std::string name;
203
204 if (get_current_attribute_value_quark(&proc, "files_history", file)) {
205 do {
206 fd = -1;
207 name = "";
208 get_current_attribute_value_int(&file, "file/fd", fd);
209 get_current_attribute_value_string(
210 &file, "file/name", name);
211 fprintf(stderr, "fd = %d, name = %s\n", fd,
212 name.c_str());
213 } while (get_current_attribute_value_quark(
214 &file, "next", file));
215 }
216
217}
218
219int update_iostream_ret(int tid, char *comm, unsigned long timestamp,
220 uint64_t cpu_id, int ret)
221{
222 Quark proc_quark;
223 Quark syscall_info_quark;
224 Quark file_quark;
225 Quark file_history_quark;
226 bool file_found;
227 int syscall_type;
228 int fd;
229 int err = 0;
230
231 proc_quark = get_proc(tid, comm, timestamp);
232
233 if (state_system->attributeExists(proc_quark, "syscall_info")) {
234 syscall_info_quark = state_system->getQuark(proc_quark,
235 "syscall_info");
236 get_current_attribute_value_int(&syscall_info_quark, "type",
237 syscall_type);
238 if (syscall_type == __NR_read && ret > 0) {
239 increase_attribute(timestamp, &proc_quark,
240 "totalfileread", ret);
241 increase_attribute(timestamp, &proc_quark,
242 "fileread", ret);
243 get_current_attribute_value_int(&syscall_info_quark,
244 "fd", fd);
245 file_found = get_file(proc_quark, fd,
246 file_quark);
247 if (file_found)
248 increase_attribute(timestamp, &file_quark,
249 "read", ret);
250 } else if (syscall_type == __NR_write && ret > 0) {
251
252 increase_attribute(timestamp, &proc_quark,
253 "totalfilewrite", ret);
254 increase_attribute(timestamp, &proc_quark,
255 "filewrite", ret);
256 get_current_attribute_value_int(&syscall_info_quark,
257 "fd", fd);
258 file_found = get_file(proc_quark, fd,
259 file_quark);
260 if (file_found)
261 increase_attribute(timestamp, &file_quark,
262 "write", ret);
263 } else if (syscall_type == __NR_open && ret > 0) {
264 file_history_quark = state_system->getQuark(proc_quark,
265 "files_history");
266 file_quark = state_system->getQuark(file_history_quark,
267 "current/file");
268 add_file(proc_quark, file_quark, ret,
269 timestamp);
270 modify_attribute(timestamp, &file_quark, "fd", fd);
271 } else {
272 err = -1;
273 }
274 }
275 return err;
276}
277
278void update_syscall_info(unsigned long timestamp, int type, int cpu_id,
279 Quark proc, int fd)
280{
281 int tid;
282
283 get_current_attribute_value_int(&proc, "tid", tid);
284 modify_attribute(timestamp, &proc, "syscall_info/type", type);
285 modify_attribute(timestamp, &proc, "syscall_info/cpu_id", cpu_id);
286 modify_attribute(timestamp, &proc, "syscall_info/tid", tid);
287 modify_attribute(timestamp, &proc, "syscall_info/fd", fd);
288}
289
290enum bt_cb_ret handle_exit_syscall(struct bt_ctf_event *call_data,
291 void *private_data)
292{
293 const struct definition *scope;
294 unsigned long timestamp;
295 char *comm;
296 uint64_t ret, tid;
297 uint64_t cpu_id;
298
299 timestamp = bt_ctf_get_timestamp(call_data);
300 if (timestamp == -1ULL)
301 goto error;
302
303 comm = get_context_comm(call_data);
304 tid = get_context_tid(call_data);
305
306 scope = bt_ctf_get_top_level_scope(call_data,
307 BT_EVENT_FIELDS);
308 ret = bt_ctf_get_int64(bt_ctf_get_field(call_data,
309 scope, "_ret"));
310 if (bt_ctf_field_get_error()) {
311 fprintf(stderr, "Missing ret context info\n");
312 goto error;
313 }
314
315 cpu_id = get_cpu_id(call_data);
316
317 /*
318 * if we encounter an exit_syscall and
319 * it is not for a syscall read or write
320 * we just abort the execution of this callback
321 */
322 if (update_iostream_ret(
323 tid, comm, timestamp, cpu_id, ret) < 0)
324 return BT_CB_ERROR_CONTINUE;
325
326 return BT_CB_OK;
327
328error:
329 return BT_CB_ERROR_STOP;
330}
331
332enum bt_cb_ret handle_sys_write(struct bt_ctf_event *call_data,
333 void *private_data)
334{
335 const struct definition *scope;
336 Quark proc;
337 unsigned long timestamp;
338 int cpu_id;
339 int tid;
340 char *procname;
341 int fd;
342
343 timestamp = bt_ctf_get_timestamp(call_data);
344 if (timestamp == -1ULL)
345 goto error;
346
347 tid = get_context_tid(call_data);
348 cpu_id = get_cpu_id(call_data);
349
350 procname = get_context_comm(call_data);
351
352 scope = bt_ctf_get_top_level_scope(call_data,
353 BT_EVENT_FIELDS);
354 fd = bt_ctf_get_uint64(bt_ctf_get_field(call_data,
355 scope, "_fd"));
356 if (bt_ctf_field_get_error()) {
357 fprintf(stderr, "Missing fd context info\n");
358 goto error;
359 }
360
361 proc = get_proc(tid, procname, timestamp);
362 update_syscall_info(timestamp, __NR_write, cpu_id, proc, fd);
363
364 insert_file(proc, fd, timestamp);
365
366 return BT_CB_OK;
367
368error:
369 return BT_CB_ERROR_STOP;
370}
371
372enum bt_cb_ret handle_sys_read(struct bt_ctf_event *call_data,
373 void *private_data)
374{
375 const struct definition *scope;
376 Quark proc;
377 unsigned long timestamp;
378 uint64_t cpu_id;
379 int64_t tid;
380 char *procname;
381 int fd;
382
383 timestamp = bt_ctf_get_timestamp(call_data);
384 if (timestamp == -1ULL)
385 goto error;
386
387 tid = get_context_tid(call_data);
388 cpu_id = get_cpu_id(call_data);
389
390 procname = get_context_comm(call_data);
391
392 scope = bt_ctf_get_top_level_scope(call_data,
393 BT_EVENT_FIELDS);
394 fd = bt_ctf_get_uint64(bt_ctf_get_field(call_data,
395 scope, "_fd"));
396 if (bt_ctf_field_get_error()) {
397 fprintf(stderr, "Missing fd context info\n");
398 goto error;
399 }
400
401 proc = get_proc(tid, procname, timestamp);
402 update_syscall_info(timestamp, __NR_read, cpu_id, proc, fd);
403
404 insert_file(proc, fd, timestamp);
405
406 return BT_CB_OK;
407
408error:
409 return BT_CB_ERROR_STOP;
410}
411
412enum bt_cb_ret handle_sys_open(struct bt_ctf_event *call_data,
413 void *private_data)
414{
415 Quark proc;
416 const struct definition *scope;
417 unsigned long timestamp;
418 uint64_t cpu_id;
419 int64_t tid;
420 char *procname;
421 char *file;
422
423 timestamp = bt_ctf_get_timestamp(call_data);
424 if (timestamp == -1ULL)
425 goto error;
426
427 tid = get_context_tid(call_data);
428 cpu_id = get_cpu_id(call_data);
429
430 procname = get_context_comm(call_data);
431
432 scope = bt_ctf_get_top_level_scope(call_data,
433 BT_EVENT_FIELDS);
434 file = bt_ctf_get_string(bt_ctf_get_field(call_data,
435 scope, "_filename"));
436 if (bt_ctf_field_get_error()) {
437 fprintf(stderr, "Missing file name context info\n");
438 goto error;
439 }
440
441 proc = get_proc(tid, procname, timestamp);
442 update_syscall_info(timestamp, __NR_open, cpu_id, proc, -1);
443
444 create_file(proc, file, timestamp);
445
446 return BT_CB_OK;
447
448error:
449 return BT_CB_ERROR_STOP;
450}
451
452enum bt_cb_ret handle_sys_close(struct bt_ctf_event *call_data,
453 void *private_data)
454{
455 const struct definition *scope;
456 Quark proc;
457 unsigned long timestamp;
458 int64_t tid;
459 char *procname;
460 int fd;
461
462 timestamp = bt_ctf_get_timestamp(call_data);
463 if (timestamp == -1ULL)
464 goto error;
465
466 tid = get_context_tid(call_data);
467
468 procname = get_context_comm(call_data);
469
470 scope = bt_ctf_get_top_level_scope(call_data,
471 BT_EVENT_FIELDS);
472 fd = bt_ctf_get_uint64(bt_ctf_get_field(call_data,
473 scope, "_fd"));
474 if (bt_ctf_field_get_error()) {
475 fprintf(stderr, "Missing fd context info\n");
476 goto error;
477 }
478
479 proc = get_proc(tid, procname, timestamp);
480
481 close_file(timestamp, proc, fd);
482
483 return BT_CB_OK;
484
485error:
486 return BT_CB_ERROR_STOP;
487}
488
489enum bt_cb_ret handle_statedump_file_descriptor(
490 struct bt_ctf_event *call_data, void *private_data)
491{
492 const struct definition *scope;
493 Quark parent;
494 Quark file;
495 unsigned long timestamp;
496 int64_t pid;
497 char *file_name;
498 int fd;
499
500 timestamp = bt_ctf_get_timestamp(call_data);
501 if (timestamp == -1ULL)
502 goto error;
503
504 scope = bt_ctf_get_top_level_scope(call_data,
505 BT_EVENT_FIELDS);
506 pid = bt_ctf_get_int64(bt_ctf_get_field(call_data,
507 scope, "_pid"));
508 if (bt_ctf_field_get_error()) {
509 fprintf(stderr, "Missing tid context info\n");
510 goto error;
511 }
512
513 scope = bt_ctf_get_top_level_scope(call_data,
514 BT_EVENT_FIELDS);
515 fd = bt_ctf_get_int64(bt_ctf_get_field(call_data,
516 scope, "_fd"));
517 if (bt_ctf_field_get_error()) {
518 fprintf(stderr, "Missing fd context info\n");
519 goto error;
520 }
521
522 scope = bt_ctf_get_top_level_scope(call_data,
523 BT_EVENT_FIELDS);
524 file_name = bt_ctf_get_string(bt_ctf_get_field(call_data,
525 scope, "_filename"));
526 if (bt_ctf_field_get_error()) {
527 fprintf(stderr, "Missing file name context info\n");
528 goto error;
529 }
530
531 parent = get_proc_pid(pid, pid, timestamp);
532 create_file(parent, file_name, timestamp);
533 file = state_system->getQuark(parent, "files_history/current/file");
534 edit_file(timestamp, parent, file, fd);
535
536 return BT_CB_OK;
537
538error:
539 return BT_CB_ERROR_STOP;
540}
This page took 0.040587 seconds and 4 git commands to generate.