output.c revision ce377d567ccc0b14693619b69ebe0ac6deb0ba90
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(output, "%*s", opt_n * 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 ((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 *
108name2func(char *name) {
109	struct function *tmp;
110	const char *str1, *str2;
111
112	tmp = list_of_functions;
113	while (tmp) {
114#ifdef USE_DEMANGLE
115		str1 = options.demangle ? my_demangle(tmp->name) : tmp->name;
116		str2 = options.demangle ? 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
131output_line(struct process *proc, char *fmt, ...) {
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
158tabto(int col) {
159	if (current_column < col) {
160		fprintf(output, "%*s", col - current_column, "");
161	}
162}
163
164void
165output_left(enum tof type, struct process *proc, char *function_name) {
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		    options.demangle ? 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		for (i = 0; i < 4; i++) {
195			current_column +=
196			    display_arg(type, proc, i, arg_unknown);
197			current_column += fprintf(output, ", ");
198		}
199		current_column += display_arg(type, proc, 4, arg_unknown);
200		return;
201	} else {
202		int i;
203		for (i = 0; i < func->num_params - func->params_right - 1; i++) {
204			current_column +=
205			    display_arg(type, proc, i, func->arg_info[i]);
206			current_column += fprintf(output, ", ");
207		}
208		if (func->num_params > func->params_right) {
209			current_column +=
210			    display_arg(type, proc, i, func->arg_info[i]);
211			if (func->params_right) {
212				current_column += fprintf(output, ", ");
213			}
214		}
215		if (func->params_right) {
216			save_register_args(type, proc);
217		}
218	}
219}
220
221void
222output_right(enum tof type, struct process *proc, char *function_name) {
223	struct function *func = name2func(function_name);
224	static arg_type_info *arg_unknown = NULL;
225	if (arg_unknown == NULL)
226	    arg_unknown = lookup_prototype(ARGTYPE_UNKNOWN);
227
228	if (opt_c) {
229		struct opt_c_struct *st;
230		if (!dict_opt_c) {
231			dict_opt_c =
232			    dict_init(dict_key2hash_string,
233				      dict_key_cmp_string);
234		}
235		st = dict_find_entry(dict_opt_c, function_name);
236		if (!st) {
237			char *na;
238			st = malloc(sizeof(struct opt_c_struct));
239			na = strdup(function_name);
240			if (!st || !na) {
241				perror("malloc()");
242				exit(1);
243			}
244			st->count = 0;
245			st->tv.tv_sec = st->tv.tv_usec = 0;
246			dict_enter(dict_opt_c, na, st);
247		}
248		if (st->tv.tv_usec + current_time_spent.tv_usec > 1000000) {
249			st->tv.tv_usec += current_time_spent.tv_usec - 1000000;
250			st->tv.tv_sec++;
251		} else {
252			st->tv.tv_usec += current_time_spent.tv_usec;
253		}
254		st->count++;
255		st->tv.tv_sec += current_time_spent.tv_sec;
256
257//              fprintf(output, "%s <%lu.%06d>\n", function_name,
258//                              current_time_spent.tv_sec, (int)current_time_spent.tv_usec);
259		return;
260	}
261	if (current_proc && (current_proc != proc ||
262			    current_depth != proc->callstack_depth)) {
263		fprintf(output, " <unfinished ...>\n");
264		current_proc = 0;
265	}
266	if (current_proc != proc) {
267		begin_of_line(type, proc);
268#ifdef USE_DEMANGLE
269		current_column +=
270		    fprintf(output, "<... %s resumed> ",
271			    options.demangle ? my_demangle(function_name) : function_name);
272#else
273		current_column +=
274		    fprintf(output, "<... %s resumed> ", function_name);
275#endif
276	}
277
278	if (!func) {
279		current_column += fprintf(output, ") ");
280		tabto(options.align - 1);
281		fprintf(output, "= ");
282		display_arg(type, proc, -1, arg_unknown);
283	} else {
284		int i;
285		for (i = func->num_params - func->params_right;
286		     i < func->num_params - 1; i++) {
287			current_column +=
288			    display_arg(type, proc, i, func->arg_info[i]);
289			current_column += fprintf(output, ", ");
290		}
291		if (func->params_right) {
292			current_column +=
293			    display_arg(type, proc, i, func->arg_info[i]);
294		}
295		current_column += fprintf(output, ") ");
296		tabto(options.align - 1);
297		fprintf(output, "= ");
298		if (func->return_info->type == ARGTYPE_VOID) {
299			fprintf(output, "<void>");
300		} else {
301			display_arg(type, proc, -1, func->return_info);
302		}
303	}
304	if (opt_T) {
305		fprintf(output, " <%lu.%06d>",
306			current_time_spent.tv_sec,
307			(int)current_time_spent.tv_usec);
308	}
309	fprintf(output, "\n");
310	current_proc = 0;
311	current_column = 0;
312}
313