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