output.c revision cc813cd481c74ee4861baa5dd6154c3f234c7901
1#if HAVE_CONFIG_H
2#include "config.h"
3#endif
4
5#include <stdio.h>
6#include <stdlib.h>
7#include <stdarg.h>
8#include <string.h>
9#include <time.h>
10#include <sys/time.h>
11#include <unistd.h>
12
13#include "ltrace.h"
14#include "options.h"
15#include "output.h"
16#include "dict.h"
17
18#ifdef USE_DEMANGLE
19#include "demangle.h"
20#endif
21
22/* TODO FIXME XXX: include in ltrace.h: */
23extern struct timeval current_time_spent;
24
25struct dict *dict_opt_c = NULL;
26
27static struct process *current_proc = 0;
28static int current_depth = 0;
29static int current_column = 0;
30
31static void
32output_indent(struct process *proc) {
33	current_column +=
34	    fprintf(options.output, "%*s", options.indent * proc->callstack_depth, "");
35}
36
37static void
38begin_of_line(enum tof type, struct process *proc) {
39	current_column = 0;
40	if (!proc) {
41		return;
42	}
43	if (list_of_processes->next) {
44		current_column += fprintf(options.output, "[pid %u] ", proc->pid);
45	}
46	if (opt_r) {
47		struct timeval tv;
48		struct timezone tz;
49		static struct timeval old_tv = { 0, 0 };
50		struct timeval diff;
51
52		gettimeofday(&tv, &tz);
53
54		if (old_tv.tv_sec == 0 && old_tv.tv_usec == 0) {
55			old_tv.tv_sec = tv.tv_sec;
56			old_tv.tv_usec = tv.tv_usec;
57		}
58		diff.tv_sec = tv.tv_sec - old_tv.tv_sec;
59		if (tv.tv_usec >= old_tv.tv_usec) {
60			diff.tv_usec = tv.tv_usec - old_tv.tv_usec;
61		} else {
62			diff.tv_sec--;
63			diff.tv_usec = 1000000 + tv.tv_usec - old_tv.tv_usec;
64		}
65		old_tv.tv_sec = tv.tv_sec;
66		old_tv.tv_usec = tv.tv_usec;
67		current_column += fprintf(options.output, "%3lu.%06d ",
68					  diff.tv_sec, (int)diff.tv_usec);
69	}
70	if (opt_t) {
71		struct timeval tv;
72		struct timezone tz;
73
74		gettimeofday(&tv, &tz);
75		if (opt_t > 2) {
76			current_column += fprintf(options.output, "%lu.%06d ",
77						  tv.tv_sec, (int)tv.tv_usec);
78		} else if (opt_t > 1) {
79			struct tm *tmp = localtime(&tv.tv_sec);
80			current_column +=
81			    fprintf(options.output, "%02d:%02d:%02d.%06d ",
82				    tmp->tm_hour, tmp->tm_min, tmp->tm_sec,
83				    (int)tv.tv_usec);
84		} else {
85			struct tm *tmp = localtime(&tv.tv_sec);
86			current_column += fprintf(options.output, "%02d:%02d:%02d ",
87						  tmp->tm_hour, tmp->tm_min,
88						  tmp->tm_sec);
89		}
90	}
91	if (opt_i) {
92		if (type == LT_TOF_FUNCTION || type == LT_TOF_FUNCTIONR) {
93			current_column += fprintf(options.output, "[%p] ",
94						  proc->return_addr);
95		} else {
96			current_column += fprintf(options.output, "[%p] ",
97						  proc->instruction_pointer);
98		}
99	}
100	if (options.indent > 0 && type != LT_TOF_NONE) {
101		output_indent(proc);
102	}
103}
104
105static struct function *
106name2func(char *name) {
107	struct function *tmp;
108	const char *str1, *str2;
109
110	tmp = list_of_functions;
111	while (tmp) {
112#ifdef USE_DEMANGLE
113		str1 = options.demangle ? my_demangle(tmp->name) : tmp->name;
114		str2 = options.demangle ? my_demangle(name) : name;
115#else
116		str1 = tmp->name;
117		str2 = name;
118#endif
119		if (!strcmp(str1, str2)) {
120
121			return tmp;
122		}
123		tmp = tmp->next;
124	}
125	return NULL;
126}
127
128void
129output_line(struct process *proc, char *fmt, ...) {
130	va_list args;
131
132	if (options.summary) {
133		return;
134	}
135	if (current_proc) {
136		if (current_proc->callstack[current_depth].return_addr) {
137			fprintf(options.output, " <unfinished ...>\n");
138		} else {
139			fprintf(options.output, " <no return ...>\n");
140		}
141	}
142	current_proc = 0;
143	if (!fmt) {
144		return;
145	}
146	begin_of_line(LT_TOF_NONE, proc);
147
148	va_start(args, fmt);
149	vfprintf(options.output, fmt, args);
150	fprintf(options.output, "\n");
151	va_end(args);
152	current_column = 0;
153}
154
155static void
156tabto(int col) {
157	if (current_column < col) {
158		fprintf(options.output, "%*s", col - current_column, "");
159	}
160}
161
162void
163output_left(enum tof type, struct process *proc, char *function_name) {
164	struct function *func;
165	static arg_type_info *arg_unknown = NULL;
166	if (arg_unknown == NULL)
167	    arg_unknown = lookup_prototype(ARGTYPE_UNKNOWN);
168
169	if (options.summary) {
170		return;
171	}
172	if (current_proc) {
173		fprintf(options.output, " <unfinished ...>\n");
174		current_proc = 0;
175		current_column = 0;
176	}
177	current_proc = proc;
178	current_depth = proc->callstack_depth;
179	proc->type_being_displayed = type;
180	begin_of_line(type, proc);
181#ifdef USE_DEMANGLE
182	current_column +=
183	    fprintf(options.output, "%s(",
184		    options.demangle ? my_demangle(function_name) : function_name);
185#else
186	current_column += fprintf(options.output, "%s(", function_name);
187#endif
188
189	func = name2func(function_name);
190	if (!func) {
191		int i;
192		for (i = 0; i < 4; i++) {
193			current_column +=
194			    display_arg(type, proc, i, arg_unknown);
195			current_column += fprintf(options.output, ", ");
196		}
197		current_column += display_arg(type, proc, 4, arg_unknown);
198		return;
199	} else {
200		int i;
201		for (i = 0; i < func->num_params - func->params_right - 1; i++) {
202			current_column +=
203			    display_arg(type, proc, i, func->arg_info[i]);
204			current_column += fprintf(options.output, ", ");
205		}
206		if (func->num_params > func->params_right) {
207			current_column +=
208			    display_arg(type, proc, i, func->arg_info[i]);
209			if (func->params_right) {
210				current_column += fprintf(options.output, ", ");
211			}
212		}
213		if (func->params_right) {
214			save_register_args(type, proc);
215		}
216	}
217}
218
219void
220output_right(enum tof type, struct process *proc, char *function_name) {
221	struct function *func = name2func(function_name);
222	static arg_type_info *arg_unknown = NULL;
223	if (arg_unknown == NULL)
224	    arg_unknown = lookup_prototype(ARGTYPE_UNKNOWN);
225
226	if (options.summary) {
227		struct opt_c_struct *st;
228		if (!dict_opt_c) {
229			dict_opt_c =
230			    dict_init(dict_key2hash_string,
231				      dict_key_cmp_string);
232		}
233		st = dict_find_entry(dict_opt_c, function_name);
234		if (!st) {
235			char *na;
236			st = malloc(sizeof(struct opt_c_struct));
237			na = strdup(function_name);
238			if (!st || !na) {
239				perror("malloc()");
240				exit(1);
241			}
242			st->count = 0;
243			st->tv.tv_sec = st->tv.tv_usec = 0;
244			dict_enter(dict_opt_c, na, st);
245		}
246		if (st->tv.tv_usec + current_time_spent.tv_usec > 1000000) {
247			st->tv.tv_usec += current_time_spent.tv_usec - 1000000;
248			st->tv.tv_sec++;
249		} else {
250			st->tv.tv_usec += current_time_spent.tv_usec;
251		}
252		st->count++;
253		st->tv.tv_sec += current_time_spent.tv_sec;
254
255//              fprintf(options.output, "%s <%lu.%06d>\n", function_name,
256//                              current_time_spent.tv_sec, (int)current_time_spent.tv_usec);
257		return;
258	}
259	if (current_proc && (current_proc != proc ||
260			    current_depth != proc->callstack_depth)) {
261		fprintf(options.output, " <unfinished ...>\n");
262		current_proc = 0;
263	}
264	if (current_proc != proc) {
265		begin_of_line(type, proc);
266#ifdef USE_DEMANGLE
267		current_column +=
268		    fprintf(options.output, "<... %s resumed> ",
269			    options.demangle ? my_demangle(function_name) : function_name);
270#else
271		current_column +=
272		    fprintf(options.output, "<... %s resumed> ", function_name);
273#endif
274	}
275
276	if (!func) {
277		current_column += fprintf(options.output, ") ");
278		tabto(options.align - 1);
279		fprintf(options.output, "= ");
280		display_arg(type, proc, -1, arg_unknown);
281	} else {
282		int i;
283		for (i = func->num_params - func->params_right;
284		     i < func->num_params - 1; i++) {
285			current_column +=
286			    display_arg(type, proc, i, func->arg_info[i]);
287			current_column += fprintf(options.output, ", ");
288		}
289		if (func->params_right) {
290			current_column +=
291			    display_arg(type, proc, i, func->arg_info[i]);
292		}
293		current_column += fprintf(options.output, ") ");
294		tabto(options.align - 1);
295		fprintf(options.output, "= ");
296		if (func->return_info->type == ARGTYPE_VOID) {
297			fprintf(options.output, "<void>");
298		} else {
299			display_arg(type, proc, -1, func->return_info);
300		}
301	}
302	if (opt_T) {
303		fprintf(options.output, " <%lu.%06d>",
304			current_time_spent.tv_sec,
305			(int)current_time_spent.tv_usec);
306	}
307	fprintf(options.output, "\n");
308	current_proc = 0;
309	current_column = 0;
310}
311