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