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