output.c revision a43876e21c337f554a42ae8bfd596636abf253b9
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#include "proc.h" 13#include "library.h" 14 15/* TODO FIXME XXX: include in common.h: */ 16extern struct timeval current_time_spent; 17 18Dict *dict_opt_c = NULL; 19 20static Process *current_proc = 0; 21static int current_depth = 0; 22static int current_column = 0; 23 24static void 25output_indent(Process *proc) { 26 current_column += 27 fprintf(options.output, "%*s", options.indent * proc->callstack_depth, ""); 28} 29 30static void 31begin_of_line(enum tof type, Process *proc) { 32 current_column = 0; 33 if (!proc) { 34 return; 35 } 36 if ((options.output != stderr) && (opt_p || options.follow)) { 37 current_column += fprintf(options.output, "%u ", proc->pid); 38 } else if (options.follow) { 39 current_column += fprintf(options.output, "[pid %u] ", proc->pid); 40 } 41 if (opt_r) { 42 struct timeval tv; 43 struct timezone tz; 44 static struct timeval old_tv = { 0, 0 }; 45 struct timeval diff; 46 47 gettimeofday(&tv, &tz); 48 49 if (old_tv.tv_sec == 0 && old_tv.tv_usec == 0) { 50 old_tv.tv_sec = tv.tv_sec; 51 old_tv.tv_usec = tv.tv_usec; 52 } 53 diff.tv_sec = tv.tv_sec - old_tv.tv_sec; 54 if (tv.tv_usec >= old_tv.tv_usec) { 55 diff.tv_usec = tv.tv_usec - old_tv.tv_usec; 56 } else { 57 diff.tv_sec--; 58 diff.tv_usec = 1000000 + tv.tv_usec - old_tv.tv_usec; 59 } 60 old_tv.tv_sec = tv.tv_sec; 61 old_tv.tv_usec = tv.tv_usec; 62 current_column += fprintf(options.output, "%3lu.%06d ", 63 diff.tv_sec, (int)diff.tv_usec); 64 } 65 if (opt_t) { 66 struct timeval tv; 67 struct timezone tz; 68 69 gettimeofday(&tv, &tz); 70 if (opt_t > 2) { 71 current_column += fprintf(options.output, "%lu.%06d ", 72 tv.tv_sec, (int)tv.tv_usec); 73 } else if (opt_t > 1) { 74 struct tm *tmp = localtime(&tv.tv_sec); 75 current_column += 76 fprintf(options.output, "%02d:%02d:%02d.%06d ", 77 tmp->tm_hour, tmp->tm_min, tmp->tm_sec, 78 (int)tv.tv_usec); 79 } else { 80 struct tm *tmp = localtime(&tv.tv_sec); 81 current_column += fprintf(options.output, "%02d:%02d:%02d ", 82 tmp->tm_hour, tmp->tm_min, 83 tmp->tm_sec); 84 } 85 } 86 if (opt_i) { 87 if (type == LT_TOF_FUNCTION || type == LT_TOF_FUNCTIONR) { 88 current_column += fprintf(options.output, "[%p] ", 89 proc->return_addr); 90 } else { 91 current_column += fprintf(options.output, "[%p] ", 92 proc->instruction_pointer); 93 } 94 } 95 if (options.indent > 0 && type != LT_TOF_NONE) { 96 output_indent(proc); 97 } 98} 99 100static Function * 101name2func(char const *name) { 102 Function *tmp; 103 const char *str1, *str2; 104 105 tmp = list_of_functions; 106 while (tmp) { 107#ifdef USE_DEMANGLE 108 str1 = options.demangle ? my_demangle(tmp->name) : tmp->name; 109 str2 = options.demangle ? my_demangle(name) : name; 110#else 111 str1 = tmp->name; 112 str2 = name; 113#endif 114 if (!strcmp(str1, str2)) { 115 116 return tmp; 117 } 118 tmp = tmp->next; 119 } 120 return NULL; 121} 122 123void 124output_line(Process *proc, char *fmt, ...) { 125 va_list args; 126 127 if (options.summary) { 128 return; 129 } 130 if (current_proc) { 131 if (current_proc->callstack[current_depth].return_addr) { 132 fprintf(options.output, " <unfinished ...>\n"); 133 } else { 134 fprintf(options.output, " <no return ...>\n"); 135 } 136 } 137 current_proc = 0; 138 if (!fmt) { 139 return; 140 } 141 begin_of_line(LT_TOF_NONE, proc); 142 143 va_start(args, fmt); 144 vfprintf(options.output, fmt, args); 145 fprintf(options.output, "\n"); 146 va_end(args); 147 current_column = 0; 148} 149 150static void 151tabto(int col) { 152 if (current_column < col) { 153 fprintf(options.output, "%*s", col - current_column, ""); 154 } 155} 156 157void 158output_left(enum tof type, struct Process *proc, 159 struct library_symbol *libsym) 160{ 161 const char *function_name = libsym->name; 162 Function *func; 163 static arg_type_info *arg_unknown = NULL; 164 if (arg_unknown == NULL) 165 arg_unknown = lookup_prototype(ARGTYPE_UNKNOWN); 166 167 if (options.summary) { 168 return; 169 } 170 if (current_proc) { 171 fprintf(options.output, " <unfinished ...>\n"); 172 current_column = 0; 173 } 174 current_proc = proc; 175 current_depth = proc->callstack_depth; 176 begin_of_line(type, proc); 177 if (!options.hide_caller) 178 current_column += fprintf(options.output, "%s->", 179 libsym->lib->soname); 180#ifdef USE_DEMANGLE 181 current_column += 182 fprintf(options.output, "%s(", 183 (options.demangle 184 ? 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 || func->return_info->type == ARGTYPE_STRING_N 215 || func->return_info->type == ARGTYPE_ARRAY) { 216 save_register_args(type, proc); 217 } 218 } 219} 220 221void 222output_right(enum tof type, struct Process *proc, struct library_symbol *libsym) 223{ 224 const char *function_name = libsym->name; 225 Function *func = name2func(function_name); 226 static arg_type_info *arg_unknown = NULL; 227 if (arg_unknown == NULL) 228 arg_unknown = lookup_prototype(ARGTYPE_UNKNOWN); 229 230 if (options.summary) { 231 struct opt_c_struct *st; 232 if (!dict_opt_c) { 233 dict_opt_c = 234 dict_init(dict_key2hash_string, 235 dict_key_cmp_string); 236 } 237 st = dict_find_entry(dict_opt_c, function_name); 238 if (!st) { 239 char *na; 240 st = malloc(sizeof(struct opt_c_struct)); 241 na = strdup(function_name); 242 if (!st || !na) { 243 perror("malloc()"); 244 exit(1); 245 } 246 st->count = 0; 247 st->tv.tv_sec = st->tv.tv_usec = 0; 248 dict_enter(dict_opt_c, na, st); 249 } 250 if (st->tv.tv_usec + current_time_spent.tv_usec > 1000000) { 251 st->tv.tv_usec += current_time_spent.tv_usec - 1000000; 252 st->tv.tv_sec++; 253 } else { 254 st->tv.tv_usec += current_time_spent.tv_usec; 255 } 256 st->count++; 257 st->tv.tv_sec += current_time_spent.tv_sec; 258 259// fprintf(options.output, "%s <%lu.%06d>\n", function_name, 260// current_time_spent.tv_sec, (int)current_time_spent.tv_usec); 261 return; 262 } 263 if (current_proc && (current_proc != proc || 264 current_depth != proc->callstack_depth)) { 265 fprintf(options.output, " <unfinished ...>\n"); 266 current_proc = 0; 267 } 268 if (current_proc != proc) { 269 begin_of_line(type, proc); 270#ifdef USE_DEMANGLE 271 current_column += 272 fprintf(options.output, "<... %s resumed> ", 273 options.demangle ? my_demangle(function_name) : function_name); 274#else 275 current_column += 276 fprintf(options.output, "<... %s resumed> ", function_name); 277#endif 278 } 279 280 if (!func) { 281 current_column += fprintf(options.output, ") "); 282 tabto(options.align - 1); 283 fprintf(options.output, "= "); 284 display_arg(type, proc, -1, arg_unknown); 285 } else { 286 int i; 287 for (i = func->num_params - func->params_right; 288 i < func->num_params - 1; i++) { 289 current_column += 290 display_arg(type, proc, i, func->arg_info[i]); 291 current_column += fprintf(options.output, ", "); 292 } 293 if (func->params_right) { 294 current_column += 295 display_arg(type, proc, i, func->arg_info[i]); 296 } 297 current_column += fprintf(options.output, ") "); 298 tabto(options.align - 1); 299 fprintf(options.output, "= "); 300 if (func->return_info->type == ARGTYPE_VOID) { 301 fprintf(options.output, "<void>"); 302 } else { 303 display_arg(type, proc, -1, func->return_info); 304 } 305 } 306 if (opt_T) { 307 fprintf(options.output, " <%lu.%06d>", 308 current_time_spent.tv_sec, 309 (int)current_time_spent.tv_usec); 310 } 311 fprintf(options.output, "\n"); 312 313#if defined(HAVE_LIBUNWIND) 314 if (options.bt_depth > 0) { 315 unw_cursor_t cursor; 316 unw_word_t ip, sp; 317 int unwind_depth = options.bt_depth; 318 char fn_name[100]; 319 320 unw_init_remote(&cursor, proc->unwind_as, proc->unwind_priv); 321 while (unwind_depth) { 322 unw_get_reg(&cursor, UNW_REG_IP, &ip); 323 unw_get_reg(&cursor, UNW_REG_SP, &sp); 324 unw_get_proc_name(&cursor, fn_name, 100, NULL); 325 fprintf(options.output, "\t\t\t%s (ip = 0x%lx)\n", fn_name, (long) ip); 326 if (unw_step(&cursor) <= 0) 327 break; 328 unwind_depth--; 329 } 330 fprintf(options.output, "\n"); 331 } 332#endif /* defined(HAVE_LIBUNWIND) */ 333 334 current_proc = 0; 335 current_column = 0; 336} 337