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