blob: 792a922085a0687b2c7ae173c9d55912d2228bd4 [file] [log] [blame]
Juan Cespedesac3db291998-04-25 14:31:58 +02001#if HAVE_CONFIG_H
2#include "config.h"
3#endif
4
Juan Cespedes3268a161997-08-25 16:45:22 +02005#include <stdio.h>
Juan Cespedesd65efa32003-02-03 00:22:30 +01006#include <stdlib.h>
Juan Cespedes5e4455b1997-08-24 01:48:26 +02007#include <stdarg.h>
Juan Cespedes1cd999a2001-07-03 00:46:04 +02008#include <string.h>
Juan Cespedes5e0acdb1998-04-04 08:34:07 +02009#include <time.h>
10#include <sys/time.h>
11#include <unistd.h>
Juan Cespedes5e4455b1997-08-24 01:48:26 +020012
13#include "ltrace.h"
Juan Cespedes5e01f651998-03-08 22:31:44 +010014#include "options.h"
15#include "output.h"
Juan Cespedesd65efa32003-02-03 00:22:30 +010016#include "dict.h"
Juan Cespedes5e4455b1997-08-24 01:48:26 +020017
Juan Cespedesd914a202004-11-10 00:15:33 +010018#ifdef USE_DEMANGLE
Juan Cespedesac3db291998-04-25 14:31:58 +020019#include "demangle.h"
20#endif
21
Juan Cespedesd65efa32003-02-03 00:22:30 +010022/* TODO FIXME XXX: include in ltrace.h: */
23extern struct timeval current_time_spent;
24
Ian Wienand2d45b1a2006-02-20 22:48:07 +010025struct dict *dict_opt_c = NULL;
Juan Cespedesd65efa32003-02-03 00:22:30 +010026
Juan Cespedesa8909f72009-04-28 20:02:41 +020027static Process *current_proc = 0;
Juan Cespedes5916fda2002-02-25 00:19:21 +010028static int current_depth = 0;
Juan Cespedes5e01f651998-03-08 22:31:44 +010029static int current_column = 0;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +020030
Juan Cespedesf1350522008-12-16 18:19:58 +010031static void
Juan Cespedesa8909f72009-04-28 20:02:41 +020032output_indent(Process *proc) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +010033 current_column +=
Juan Cespedesb65bdc52008-12-16 19:50:16 +010034 fprintf(options.output, "%*s", options.indent * proc->callstack_depth, "");
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +020035}
Juan Cespedes5e4455b1997-08-24 01:48:26 +020036
Juan Cespedesf1350522008-12-16 18:19:58 +010037static void
Juan Cespedesa8909f72009-04-28 20:02:41 +020038begin_of_line(enum tof type, Process *proc) {
Juan Cespedes5e01f651998-03-08 22:31:44 +010039 current_column = 0;
40 if (!proc) {
41 return;
Juan Cespedes5e4455b1997-08-24 01:48:26 +020042 }
Juan Cespedescc813cd2009-04-07 15:45:53 +020043 if (list_of_processes->next) {
Juan Cespedesb65bdc52008-12-16 19:50:16 +010044 current_column += fprintf(options.output, "[pid %u] ", proc->pid);
Juan Cespedes5e01f651998-03-08 22:31:44 +010045 }
Juan Cespedesf666d191998-09-20 23:04:34 +020046 if (opt_r) {
47 struct timeval tv;
48 struct timezone tz;
Ian Wienand2d45b1a2006-02-20 22:48:07 +010049 static struct timeval old_tv = { 0, 0 };
Juan Cespedesf666d191998-09-20 23:04:34 +020050 struct timeval diff;
51
52 gettimeofday(&tv, &tz);
53
Ian Wienand2d45b1a2006-02-20 22:48:07 +010054 if (old_tv.tv_sec == 0 && old_tv.tv_usec == 0) {
55 old_tv.tv_sec = tv.tv_sec;
56 old_tv.tv_usec = tv.tv_usec;
Juan Cespedesf666d191998-09-20 23:04:34 +020057 }
58 diff.tv_sec = tv.tv_sec - old_tv.tv_sec;
59 if (tv.tv_usec >= old_tv.tv_usec) {
60 diff.tv_usec = tv.tv_usec - old_tv.tv_usec;
61 } else {
Juan Cespedes5c3fe062004-06-14 18:08:37 +020062 diff.tv_sec--;
Juan Cespedesf666d191998-09-20 23:04:34 +020063 diff.tv_usec = 1000000 + tv.tv_usec - old_tv.tv_usec;
64 }
65 old_tv.tv_sec = tv.tv_sec;
66 old_tv.tv_usec = tv.tv_usec;
Juan Cespedesb65bdc52008-12-16 19:50:16 +010067 current_column += fprintf(options.output, "%3lu.%06d ",
Ian Wienand2d45b1a2006-02-20 22:48:07 +010068 diff.tv_sec, (int)diff.tv_usec);
Juan Cespedesf666d191998-09-20 23:04:34 +020069 }
Juan Cespedes5e0acdb1998-04-04 08:34:07 +020070 if (opt_t) {
71 struct timeval tv;
72 struct timezone tz;
Juan Cespedes5e0acdb1998-04-04 08:34:07 +020073
74 gettimeofday(&tv, &tz);
Ian Wienand2d45b1a2006-02-20 22:48:07 +010075 if (opt_t > 2) {
Juan Cespedesb65bdc52008-12-16 19:50:16 +010076 current_column += fprintf(options.output, "%lu.%06d ",
Ian Wienand2d45b1a2006-02-20 22:48:07 +010077 tv.tv_sec, (int)tv.tv_usec);
78 } else if (opt_t > 1) {
79 struct tm *tmp = localtime(&tv.tv_sec);
80 current_column +=
Juan Cespedesb65bdc52008-12-16 19:50:16 +010081 fprintf(options.output, "%02d:%02d:%02d.%06d ",
Ian Wienand2d45b1a2006-02-20 22:48:07 +010082 tmp->tm_hour, tmp->tm_min, tmp->tm_sec,
83 (int)tv.tv_usec);
Juan Cespedes5e0acdb1998-04-04 08:34:07 +020084 } else {
Ian Wienand2d45b1a2006-02-20 22:48:07 +010085 struct tm *tmp = localtime(&tv.tv_sec);
Juan Cespedesb65bdc52008-12-16 19:50:16 +010086 current_column += fprintf(options.output, "%02d:%02d:%02d ",
Ian Wienand2d45b1a2006-02-20 22:48:07 +010087 tmp->tm_hour, tmp->tm_min,
88 tmp->tm_sec);
Juan Cespedes5e0acdb1998-04-04 08:34:07 +020089 }
90 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010091 if (opt_i) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +010092 if (type == LT_TOF_FUNCTION || type == LT_TOF_FUNCTIONR) {
Juan Cespedesb65bdc52008-12-16 19:50:16 +010093 current_column += fprintf(options.output, "[%p] ",
Ian Wienand2d45b1a2006-02-20 22:48:07 +010094 proc->return_addr);
Juan Cespedes5e01f651998-03-08 22:31:44 +010095 } else {
Juan Cespedesb65bdc52008-12-16 19:50:16 +010096 current_column += fprintf(options.output, "[%p] ",
Ian Wienand2d45b1a2006-02-20 22:48:07 +010097 proc->instruction_pointer);
Juan Cespedes5e01f651998-03-08 22:31:44 +010098 }
99 }
Juan Cespedesb65bdc52008-12-16 19:50:16 +0100100 if (options.indent > 0 && type != LT_TOF_NONE) {
Juan Cespedes3f0b62e2001-07-09 01:02:52 +0200101 output_indent(proc);
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200102 }
Juan Cespedes5e4455b1997-08-24 01:48:26 +0200103}
104
Juan Cespedescde58262009-05-07 11:09:00 +0200105static Function *
Juan Cespedesf1350522008-12-16 18:19:58 +0100106name2func(char *name) {
Juan Cespedescde58262009-05-07 11:09:00 +0200107 Function *tmp;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100108 const char *str1, *str2;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100109
110 tmp = list_of_functions;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100111 while (tmp) {
Juan Cespedesd914a202004-11-10 00:15:33 +0100112#ifdef USE_DEMANGLE
Juan Cespedesce377d52008-12-16 19:38:10 +0100113 str1 = options.demangle ? my_demangle(tmp->name) : tmp->name;
114 str2 = options.demangle ? my_demangle(name) : name;
Juan Cespedes1b9cfd61999-08-30 19:34:50 +0200115#else
116 str1 = tmp->name;
117 str2 = name;
118#endif
119 if (!strcmp(str1, str2)) {
120
Juan Cespedes5e01f651998-03-08 22:31:44 +0100121 return tmp;
122 }
123 tmp = tmp->next;
124 }
125 return NULL;
126}
127
Juan Cespedesf1350522008-12-16 18:19:58 +0100128void
Juan Cespedesa8909f72009-04-28 20:02:41 +0200129output_line(Process *proc, char *fmt, ...) {
Juan Cespedes5e4455b1997-08-24 01:48:26 +0200130 va_list args;
131
Juan Cespedesda9b9532009-04-07 15:33:50 +0200132 if (options.summary) {
Juan Cespedesd65efa32003-02-03 00:22:30 +0100133 return;
134 }
Paul Gilliam76c61f12006-06-14 06:55:21 +0200135 if (current_proc) {
136 if (current_proc->callstack[current_depth].return_addr) {
Juan Cespedesb65bdc52008-12-16 19:50:16 +0100137 fprintf(options.output, " <unfinished ...>\n");
Paul Gilliam76c61f12006-06-14 06:55:21 +0200138 } else {
Juan Cespedesb65bdc52008-12-16 19:50:16 +0100139 fprintf(options.output, " <no return ...>\n");
Paul Gilliam76c61f12006-06-14 06:55:21 +0200140 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100141 }
Paul Gilliam76c61f12006-06-14 06:55:21 +0200142 current_proc = 0;
Juan Cespedes28f60191998-04-12 00:04:39 +0200143 if (!fmt) {
144 return;
145 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100146 begin_of_line(LT_TOF_NONE, proc);
147
Juan Cespedes21c63a12001-07-07 20:56:56 +0200148 va_start(args, fmt);
Juan Cespedesb65bdc52008-12-16 19:50:16 +0100149 vfprintf(options.output, fmt, args);
150 fprintf(options.output, "\n");
Juan Cespedes21c63a12001-07-07 20:56:56 +0200151 va_end(args);
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100152 current_column = 0;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100153}
154
Juan Cespedesf1350522008-12-16 18:19:58 +0100155static void
156tabto(int col) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100157 if (current_column < col) {
Juan Cespedesb65bdc52008-12-16 19:50:16 +0100158 fprintf(options.output, "%*s", col - current_column, "");
Juan Cespedes5e01f651998-03-08 22:31:44 +0100159 }
160}
161
Juan Cespedesf1350522008-12-16 18:19:58 +0100162void
Juan Cespedesa8909f72009-04-28 20:02:41 +0200163output_left(enum tof type, Process *proc, char *function_name) {
Juan Cespedescde58262009-05-07 11:09:00 +0200164 Function *func;
Steve Finkb0315a02006-08-07 04:22:06 +0200165 static arg_type_info *arg_unknown = NULL;
166 if (arg_unknown == NULL)
Steve Fink65b53df2006-09-25 02:27:08 +0200167 arg_unknown = lookup_prototype(ARGTYPE_UNKNOWN);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100168
Juan Cespedesda9b9532009-04-07 15:33:50 +0200169 if (options.summary) {
Juan Cespedesd65efa32003-02-03 00:22:30 +0100170 return;
171 }
Paul Gilliam76c61f12006-06-14 06:55:21 +0200172 if (current_proc) {
Juan Cespedesb65bdc52008-12-16 19:50:16 +0100173 fprintf(options.output, " <unfinished ...>\n");
Paul Gilliam76c61f12006-06-14 06:55:21 +0200174 current_proc = 0;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100175 current_column = 0;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100176 }
Paul Gilliam76c61f12006-06-14 06:55:21 +0200177 current_proc = proc;
Juan Cespedes5916fda2002-02-25 00:19:21 +0100178 current_depth = proc->callstack_depth;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100179 proc->type_being_displayed = type;
180 begin_of_line(type, proc);
Juan Cespedesd914a202004-11-10 00:15:33 +0100181#ifdef USE_DEMANGLE
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100182 current_column +=
Juan Cespedesb65bdc52008-12-16 19:50:16 +0100183 fprintf(options.output, "%s(",
Juan Cespedesce377d52008-12-16 19:38:10 +0100184 options.demangle ? my_demangle(function_name) : function_name);
Juan Cespedesac3db291998-04-25 14:31:58 +0200185#else
Juan Cespedesb65bdc52008-12-16 19:50:16 +0100186 current_column += fprintf(options.output, "%s(", function_name);
Juan Cespedesac3db291998-04-25 14:31:58 +0200187#endif
Juan Cespedes5e01f651998-03-08 22:31:44 +0100188
189 func = name2func(function_name);
190 if (!func) {
191 int i;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100192 for (i = 0; i < 4; i++) {
193 current_column +=
Juan Cespedesa413e5b2007-09-04 17:34:53 +0200194 display_arg(type, proc, i, arg_unknown);
Juan Cespedesb65bdc52008-12-16 19:50:16 +0100195 current_column += fprintf(options.output, ", ");
Juan Cespedes5e01f651998-03-08 22:31:44 +0100196 }
Juan Cespedesa413e5b2007-09-04 17:34:53 +0200197 current_column += display_arg(type, proc, 4, arg_unknown);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100198 return;
199 } else {
200 int i;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100201 for (i = 0; i < func->num_params - func->params_right - 1; i++) {
202 current_column +=
Juan Cespedesa413e5b2007-09-04 17:34:53 +0200203 display_arg(type, proc, i, func->arg_info[i]);
Juan Cespedesb65bdc52008-12-16 19:50:16 +0100204 current_column += fprintf(options.output, ", ");
Juan Cespedes5e01f651998-03-08 22:31:44 +0100205 }
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100206 if (func->num_params > func->params_right) {
207 current_column +=
Juan Cespedesa413e5b2007-09-04 17:34:53 +0200208 display_arg(type, proc, i, func->arg_info[i]);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100209 if (func->params_right) {
Juan Cespedesb65bdc52008-12-16 19:50:16 +0100210 current_column += fprintf(options.output, ", ");
Juan Cespedes5e01f651998-03-08 22:31:44 +0100211 }
212 }
Juan Cespedes5c3fe062004-06-14 18:08:37 +0200213 if (func->params_right) {
214 save_register_args(type, proc);
215 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100216 }
217}
218
Juan Cespedesf1350522008-12-16 18:19:58 +0100219void
Juan Cespedesa8909f72009-04-28 20:02:41 +0200220output_right(enum tof type, Process *proc, char *function_name) {
Juan Cespedescde58262009-05-07 11:09:00 +0200221 Function *func = name2func(function_name);
Steve Finkb0315a02006-08-07 04:22:06 +0200222 static arg_type_info *arg_unknown = NULL;
223 if (arg_unknown == NULL)
Steve Fink65b53df2006-09-25 02:27:08 +0200224 arg_unknown = lookup_prototype(ARGTYPE_UNKNOWN);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100225
Juan Cespedesda9b9532009-04-07 15:33:50 +0200226 if (options.summary) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100227 struct opt_c_struct *st;
Juan Cespedesd65efa32003-02-03 00:22:30 +0100228 if (!dict_opt_c) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100229 dict_opt_c =
230 dict_init(dict_key2hash_string,
231 dict_key_cmp_string);
Juan Cespedesd65efa32003-02-03 00:22:30 +0100232 }
233 st = dict_find_entry(dict_opt_c, function_name);
234 if (!st) {
235 char *na;
236 st = malloc(sizeof(struct opt_c_struct));
237 na = strdup(function_name);
238 if (!st || !na) {
239 perror("malloc()");
240 exit(1);
241 }
242 st->count = 0;
243 st->tv.tv_sec = st->tv.tv_usec = 0;
244 dict_enter(dict_opt_c, na, st);
245 }
246 if (st->tv.tv_usec + current_time_spent.tv_usec > 1000000) {
247 st->tv.tv_usec += current_time_spent.tv_usec - 1000000;
248 st->tv.tv_sec++;
249 } else {
250 st->tv.tv_usec += current_time_spent.tv_usec;
251 }
252 st->count++;
253 st->tv.tv_sec += current_time_spent.tv_sec;
254
Juan Cespedesb65bdc52008-12-16 19:50:16 +0100255// fprintf(options.output, "%s <%lu.%06d>\n", function_name,
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100256// current_time_spent.tv_sec, (int)current_time_spent.tv_usec);
Juan Cespedesd65efa32003-02-03 00:22:30 +0100257 return;
258 }
Paul Gilliam76c61f12006-06-14 06:55:21 +0200259 if (current_proc && (current_proc != proc ||
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100260 current_depth != proc->callstack_depth)) {
Juan Cespedesb65bdc52008-12-16 19:50:16 +0100261 fprintf(options.output, " <unfinished ...>\n");
Paul Gilliam76c61f12006-06-14 06:55:21 +0200262 current_proc = 0;
Juan Cespedes1b9cfd61999-08-30 19:34:50 +0200263 }
Paul Gilliam76c61f12006-06-14 06:55:21 +0200264 if (current_proc != proc) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100265 begin_of_line(type, proc);
Juan Cespedesd914a202004-11-10 00:15:33 +0100266#ifdef USE_DEMANGLE
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100267 current_column +=
Juan Cespedesb65bdc52008-12-16 19:50:16 +0100268 fprintf(options.output, "<... %s resumed> ",
Juan Cespedesce377d52008-12-16 19:38:10 +0100269 options.demangle ? my_demangle(function_name) : function_name);
Juan Cespedes1b9cfd61999-08-30 19:34:50 +0200270#else
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100271 current_column +=
Juan Cespedesb65bdc52008-12-16 19:50:16 +0100272 fprintf(options.output, "<... %s resumed> ", function_name);
Juan Cespedes1b9cfd61999-08-30 19:34:50 +0200273#endif
Juan Cespedes5e01f651998-03-08 22:31:44 +0100274 }
275
276 if (!func) {
Juan Cespedesb65bdc52008-12-16 19:50:16 +0100277 current_column += fprintf(options.output, ") ");
Juan Cespedesce377d52008-12-16 19:38:10 +0100278 tabto(options.align - 1);
Juan Cespedesb65bdc52008-12-16 19:50:16 +0100279 fprintf(options.output, "= ");
Juan Cespedesa413e5b2007-09-04 17:34:53 +0200280 display_arg(type, proc, -1, arg_unknown);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100281 } else {
282 int i;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100283 for (i = func->num_params - func->params_right;
284 i < func->num_params - 1; i++) {
285 current_column +=
Juan Cespedesa413e5b2007-09-04 17:34:53 +0200286 display_arg(type, proc, i, func->arg_info[i]);
Juan Cespedesb65bdc52008-12-16 19:50:16 +0100287 current_column += fprintf(options.output, ", ");
Juan Cespedes5e01f651998-03-08 22:31:44 +0100288 }
289 if (func->params_right) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100290 current_column +=
Juan Cespedesa413e5b2007-09-04 17:34:53 +0200291 display_arg(type, proc, i, func->arg_info[i]);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100292 }
Juan Cespedesb65bdc52008-12-16 19:50:16 +0100293 current_column += fprintf(options.output, ") ");
Juan Cespedesce377d52008-12-16 19:38:10 +0100294 tabto(options.align - 1);
Juan Cespedesb65bdc52008-12-16 19:50:16 +0100295 fprintf(options.output, "= ");
Steve Finkb0315a02006-08-07 04:22:06 +0200296 if (func->return_info->type == ARGTYPE_VOID) {
Juan Cespedesb65bdc52008-12-16 19:50:16 +0100297 fprintf(options.output, "<void>");
Juan Cespedes5e01f651998-03-08 22:31:44 +0100298 } else {
Juan Cespedesa413e5b2007-09-04 17:34:53 +0200299 display_arg(type, proc, -1, func->return_info);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100300 }
Juan Cespedes5e4455b1997-08-24 01:48:26 +0200301 }
Juan Cespedesd65efa32003-02-03 00:22:30 +0100302 if (opt_T) {
Juan Cespedesb65bdc52008-12-16 19:50:16 +0100303 fprintf(options.output, " <%lu.%06d>",
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100304 current_time_spent.tv_sec,
305 (int)current_time_spent.tv_usec);
Juan Cespedesd65efa32003-02-03 00:22:30 +0100306 }
Juan Cespedesb65bdc52008-12-16 19:50:16 +0100307 fprintf(options.output, "\n");
Paul Gilliam76c61f12006-06-14 06:55:21 +0200308 current_proc = 0;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100309 current_column = 0;
Juan Cespedesc40e64a1997-10-26 20:34:00 +0100310}