tizen 2.0
[external/ltrace.git] / output.c
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: */
14 extern struct timeval current_time_spent;
15
16 Dict *dict_opt_c = NULL;
17
18 static Process *current_proc = 0;
19 static int current_depth = 0;
20 static int current_column = 0;
21
22 static void
23 output_indent(Process *proc) {
24         current_column +=
25             fprintf(options.output, "%*s", options.indent * proc->callstack_depth, "");
26 }
27
28 static void
29 begin_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
98 static Function *
99 name2func(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
121 void
122 output_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
148 static void
149 tabto(int col) {
150         if (current_column < col) {
151                 fprintf(options.output, "%*s", col - current_column, "");
152         }
153 }
154
155 void
156 output_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_proc = 0;
168                 current_column = 0;
169         }
170         current_proc = proc;
171         current_depth = proc->callstack_depth;
172         proc->type_being_displayed = type;
173         begin_of_line(type, proc);
174 #ifdef USE_DEMANGLE
175         current_column +=
176             fprintf(options.output, "%s(",
177                     options.demangle ? my_demangle(function_name) : function_name);
178 #else
179         current_column += fprintf(options.output, "%s(", function_name);
180 #endif
181
182         func = name2func(function_name);
183         if (!func) {
184                 int i;
185                 for (i = 0; i < 4; i++) {
186                         current_column +=
187                             display_arg(type, proc, i, arg_unknown);
188                         current_column += fprintf(options.output, ", ");
189                 }
190                 current_column += display_arg(type, proc, 4, arg_unknown);
191                 return;
192         } else {
193                 int i;
194                 for (i = 0; i < func->num_params - func->params_right - 1; i++) {
195                         current_column +=
196                             display_arg(type, proc, i, func->arg_info[i]);
197                         current_column += fprintf(options.output, ", ");
198                 }
199                 if (func->num_params > func->params_right) {
200                         current_column +=
201                             display_arg(type, proc, i, func->arg_info[i]);
202                         if (func->params_right) {
203                                 current_column += fprintf(options.output, ", ");
204                         }
205                 }
206                 if (func->params_right) {
207                         save_register_args(type, proc);
208                 }
209         }
210 }
211
212 void
213 output_right(enum tof type, Process *proc, char *function_name) {
214         Function *func = name2func(function_name);
215         static arg_type_info *arg_unknown = NULL;
216         if (arg_unknown == NULL)
217             arg_unknown = lookup_prototype(ARGTYPE_UNKNOWN);
218
219         if (options.summary) {
220                 struct opt_c_struct *st;
221                 if (!dict_opt_c) {
222                         dict_opt_c =
223                             dict_init(dict_key2hash_string,
224                                       dict_key_cmp_string);
225                 }
226                 st = dict_find_entry(dict_opt_c, function_name);
227                 if (!st) {
228                         char *na;
229                         st = malloc(sizeof(struct opt_c_struct));
230                         na = strdup(function_name);
231                         if (!st || !na) {
232                                 perror("malloc()");
233                                 exit(1);
234                         }
235                         st->count = 0;
236                         st->tv.tv_sec = st->tv.tv_usec = 0;
237                         dict_enter(dict_opt_c, na, st);
238                 }
239                 if (st->tv.tv_usec + current_time_spent.tv_usec > 1000000) {
240                         st->tv.tv_usec += current_time_spent.tv_usec - 1000000;
241                         st->tv.tv_sec++;
242                 } else {
243                         st->tv.tv_usec += current_time_spent.tv_usec;
244                 }
245                 st->count++;
246                 st->tv.tv_sec += current_time_spent.tv_sec;
247
248 //              fprintf(options.output, "%s <%lu.%06d>\n", function_name,
249 //                              current_time_spent.tv_sec, (int)current_time_spent.tv_usec);
250                 return;
251         }
252         if (current_proc && (current_proc != proc ||
253                             current_depth != proc->callstack_depth)) {
254                 fprintf(options.output, " <unfinished ...>\n");
255                 current_proc = 0;
256         }
257         if (current_proc != proc) {
258                 begin_of_line(type, proc);
259 #ifdef USE_DEMANGLE
260                 current_column +=
261                     fprintf(options.output, "<... %s resumed> ",
262                             options.demangle ? my_demangle(function_name) : function_name);
263 #else
264                 current_column +=
265                     fprintf(options.output, "<... %s resumed> ", function_name);
266 #endif
267         }
268
269         if (!func) {
270                 current_column += fprintf(options.output, ") ");
271                 tabto(options.align - 1);
272                 fprintf(options.output, "= ");
273                 display_arg(type, proc, -1, arg_unknown);
274         } else {
275                 int i;
276                 for (i = func->num_params - func->params_right;
277                      i < func->num_params - 1; i++) {
278                         current_column +=
279                             display_arg(type, proc, i, func->arg_info[i]);
280                         current_column += fprintf(options.output, ", ");
281                 }
282                 if (func->params_right) {
283                         current_column +=
284                             display_arg(type, proc, i, func->arg_info[i]);
285                 }
286                 current_column += fprintf(options.output, ") ");
287                 tabto(options.align - 1);
288                 fprintf(options.output, "= ");
289                 if (func->return_info->type == ARGTYPE_VOID) {
290                         fprintf(options.output, "<void>");
291                 } else {
292                         display_arg(type, proc, -1, func->return_info);
293                 }
294         }
295         if (opt_T) {
296                 fprintf(options.output, " <%lu.%06d>",
297                         current_time_spent.tv_sec,
298                         (int)current_time_spent.tv_usec);
299         }
300         fprintf(options.output, "\n");
301         current_proc = 0;
302         current_column = 0;
303 }