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