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