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