blob: 0276b259528cc9cb7f6b8b24e98285cd3f395ff1 [file] [log] [blame]
Petr Machata94078ec2012-01-05 18:07:02 +01001/*
2 * This file is part of ltrace.
3 * Copyright (C) 2011,2012 Petr Machata, Red Hat Inc.
4 * Copyright (C) 2010 Joe Damato
5 * Copyright (C) 1997,1998,1999,2001,2002,2003,2004,2007,2008,2009 Juan Cespedes
6 * Copyright (C) 2006 Paul Gilliam
7 * Copyright (C) 2006 Ian Wienand
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22 * 02110-1301 USA
23 */
24
Juan Cespedesac3db291998-04-25 14:31:58 +020025#include "config.h"
Juan Cespedesac3db291998-04-25 14:31:58 +020026
Juan Cespedes3268a161997-08-25 16:45:22 +020027#include <stdio.h>
Juan Cespedesd65efa32003-02-03 00:22:30 +010028#include <stdlib.h>
Juan Cespedes5e4455b1997-08-24 01:48:26 +020029#include <stdarg.h>
Juan Cespedes1cd999a2001-07-03 00:46:04 +020030#include <string.h>
Juan Cespedes5e0acdb1998-04-04 08:34:07 +020031#include <time.h>
32#include <sys/time.h>
33#include <unistd.h>
Petr Machataf6ec08a2012-01-06 16:58:54 +010034#include <errno.h>
Petr Machata865303f2012-01-06 18:40:38 +010035#include <assert.h>
Juan Cespedes5e4455b1997-08-24 01:48:26 +020036
Juan Cespedesf7281232009-06-25 16:11:21 +020037#include "common.h"
Petr Machata366c2f42012-02-09 19:34:36 +010038#include "proc.h"
Petr Machata29add4f2012-02-18 16:38:05 +010039#include "library.h"
Petr Machata000e3112012-01-03 17:03:39 +010040#include "type.h"
Petr Machata94078ec2012-01-05 18:07:02 +010041#include "value.h"
42#include "value_dict.h"
Petr Machata865303f2012-01-06 18:40:38 +010043#include "param.h"
Petr Machataf6ec08a2012-01-06 16:58:54 +010044#include "fetch.h"
Juan Cespedesac3db291998-04-25 14:31:58 +020045
Juan Cespedesf7281232009-06-25 16:11:21 +020046/* TODO FIXME XXX: include in common.h: */
Juan Cespedesd65efa32003-02-03 00:22:30 +010047extern struct timeval current_time_spent;
48
Juan Cespedes8d1b92b2009-07-03 10:39:34 +020049Dict *dict_opt_c = NULL;
Juan Cespedesd65efa32003-02-03 00:22:30 +010050
Juan Cespedesa8909f72009-04-28 20:02:41 +020051static Process *current_proc = 0;
Juan Cespedes5916fda2002-02-25 00:19:21 +010052static int current_depth = 0;
Juan Cespedes5e01f651998-03-08 22:31:44 +010053static int current_column = 0;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +020054
Juan Cespedesf1350522008-12-16 18:19:58 +010055static void
Petr Machata54004752012-05-03 18:36:48 +020056output_indent(struct Process *proc)
57{
58 int d = options.indent * (proc->callstack_depth - 1);
59 current_column += fprintf(options.output, "%*s", d, "");
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +020060}
Juan Cespedes5e4455b1997-08-24 01:48:26 +020061
Juan Cespedesf1350522008-12-16 18:19:58 +010062static void
Petr Machata37b73c02012-01-06 16:00:25 +010063begin_of_line(Process *proc, int is_func, int indent)
64{
Juan Cespedes5e01f651998-03-08 22:31:44 +010065 current_column = 0;
66 if (!proc) {
67 return;
Juan Cespedes5e4455b1997-08-24 01:48:26 +020068 }
Juan Cespedesc693f022009-05-21 18:59:41 +020069 if ((options.output != stderr) && (opt_p || options.follow)) {
70 current_column += fprintf(options.output, "%u ", proc->pid);
Juan Cespedese12df4c2009-05-28 19:06:35 +020071 } else if (options.follow) {
Juan Cespedesb65bdc52008-12-16 19:50:16 +010072 current_column += fprintf(options.output, "[pid %u] ", proc->pid);
Juan Cespedes5e01f651998-03-08 22:31:44 +010073 }
Juan Cespedesf666d191998-09-20 23:04:34 +020074 if (opt_r) {
75 struct timeval tv;
76 struct timezone tz;
Ian Wienand2d45b1a2006-02-20 22:48:07 +010077 static struct timeval old_tv = { 0, 0 };
Juan Cespedesf666d191998-09-20 23:04:34 +020078 struct timeval diff;
79
80 gettimeofday(&tv, &tz);
81
Ian Wienand2d45b1a2006-02-20 22:48:07 +010082 if (old_tv.tv_sec == 0 && old_tv.tv_usec == 0) {
83 old_tv.tv_sec = tv.tv_sec;
84 old_tv.tv_usec = tv.tv_usec;
Juan Cespedesf666d191998-09-20 23:04:34 +020085 }
86 diff.tv_sec = tv.tv_sec - old_tv.tv_sec;
87 if (tv.tv_usec >= old_tv.tv_usec) {
88 diff.tv_usec = tv.tv_usec - old_tv.tv_usec;
89 } else {
Juan Cespedes5c3fe062004-06-14 18:08:37 +020090 diff.tv_sec--;
Juan Cespedesf666d191998-09-20 23:04:34 +020091 diff.tv_usec = 1000000 + tv.tv_usec - old_tv.tv_usec;
92 }
93 old_tv.tv_sec = tv.tv_sec;
94 old_tv.tv_usec = tv.tv_usec;
Juan Cespedesb65bdc52008-12-16 19:50:16 +010095 current_column += fprintf(options.output, "%3lu.%06d ",
Ian Wienand2d45b1a2006-02-20 22:48:07 +010096 diff.tv_sec, (int)diff.tv_usec);
Juan Cespedesf666d191998-09-20 23:04:34 +020097 }
Juan Cespedes5e0acdb1998-04-04 08:34:07 +020098 if (opt_t) {
99 struct timeval tv;
100 struct timezone tz;
Juan Cespedes5e0acdb1998-04-04 08:34:07 +0200101
102 gettimeofday(&tv, &tz);
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100103 if (opt_t > 2) {
Juan Cespedesb65bdc52008-12-16 19:50:16 +0100104 current_column += fprintf(options.output, "%lu.%06d ",
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100105 tv.tv_sec, (int)tv.tv_usec);
106 } else if (opt_t > 1) {
107 struct tm *tmp = localtime(&tv.tv_sec);
108 current_column +=
Juan Cespedesb65bdc52008-12-16 19:50:16 +0100109 fprintf(options.output, "%02d:%02d:%02d.%06d ",
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100110 tmp->tm_hour, tmp->tm_min, tmp->tm_sec,
111 (int)tv.tv_usec);
Juan Cespedes5e0acdb1998-04-04 08:34:07 +0200112 } else {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100113 struct tm *tmp = localtime(&tv.tv_sec);
Juan Cespedesb65bdc52008-12-16 19:50:16 +0100114 current_column += fprintf(options.output, "%02d:%02d:%02d ",
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100115 tmp->tm_hour, tmp->tm_min,
116 tmp->tm_sec);
Juan Cespedes5e0acdb1998-04-04 08:34:07 +0200117 }
118 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100119 if (opt_i) {
Petr Machata37b73c02012-01-06 16:00:25 +0100120 if (is_func)
Juan Cespedesb65bdc52008-12-16 19:50:16 +0100121 current_column += fprintf(options.output, "[%p] ",
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100122 proc->return_addr);
Petr Machata37b73c02012-01-06 16:00:25 +0100123 else
Juan Cespedesb65bdc52008-12-16 19:50:16 +0100124 current_column += fprintf(options.output, "[%p] ",
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100125 proc->instruction_pointer);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100126 }
Petr Machata37b73c02012-01-06 16:00:25 +0100127 if (options.indent > 0 && indent) {
Juan Cespedes3f0b62e2001-07-09 01:02:52 +0200128 output_indent(proc);
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200129 }
Juan Cespedes5e4455b1997-08-24 01:48:26 +0200130}
131
Petr Machataf6ec08a2012-01-06 16:58:54 +0100132/* The default prototype is: long X(long, long, long, long). */
133static Function *
134build_default_prototype(void)
135{
136 Function *ret = malloc(sizeof(*ret));
137 size_t i = 0;
138 if (ret == NULL)
139 goto err;
140 memset(ret, 0, sizeof(*ret));
141
142 struct arg_type_info *unknown_type = type_get_simple(ARGTYPE_UNKNOWN);
143
144 ret->return_info = unknown_type;
Petr Machata3a9bf6d2012-01-06 21:44:10 +0100145 ret->own_return_info = 0;
Petr Machataf6ec08a2012-01-06 16:58:54 +0100146
147 ret->num_params = 4;
Petr Machata865303f2012-01-06 18:40:38 +0100148 ret->params = malloc(sizeof(*ret->params) * ret->num_params);
149 if (ret->params == NULL)
150 goto err;
151
152 for (i = 0; i < ret->num_params; ++i)
153 param_init_type(&ret->params[i], unknown_type, 0);
Petr Machataf6ec08a2012-01-06 16:58:54 +0100154
155 return ret;
156
157err:
158 report_global_error("malloc: %s", strerror(errno));
Petr Machata865303f2012-01-06 18:40:38 +0100159 if (ret->params != NULL) {
160 while (i-- > 0)
161 param_destroy(&ret->params[i]);
162 free(ret->params);
163 }
164
Petr Machataf6ec08a2012-01-06 16:58:54 +0100165 free(ret);
166
167 return NULL;
168}
169
Juan Cespedescde58262009-05-07 11:09:00 +0200170static Function *
Petr Machata9a7f2322011-07-08 19:00:37 +0200171name2func(char const *name) {
Juan Cespedescde58262009-05-07 11:09:00 +0200172 Function *tmp;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100173 const char *str1, *str2;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100174
Petr Machataf6ec08a2012-01-06 16:58:54 +0100175 for (tmp = list_of_functions; tmp != NULL; tmp = tmp->next) {
Juan Cespedes1b9cfd61999-08-30 19:34:50 +0200176 str1 = tmp->name;
177 str2 = name;
Petr Machataf6ec08a2012-01-06 16:58:54 +0100178 if (!strcmp(str1, str2))
Juan Cespedes5e01f651998-03-08 22:31:44 +0100179 return tmp;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100180 }
Petr Machataf6ec08a2012-01-06 16:58:54 +0100181
182 static Function *def = NULL;
183 if (def == NULL)
184 def = build_default_prototype();
185
186 return def;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100187}
188
Juan Cespedesf1350522008-12-16 18:19:58 +0100189void
Juan Cespedesa8909f72009-04-28 20:02:41 +0200190output_line(Process *proc, char *fmt, ...) {
Juan Cespedes5e4455b1997-08-24 01:48:26 +0200191 va_list args;
192
Juan Cespedesda9b9532009-04-07 15:33:50 +0200193 if (options.summary) {
Juan Cespedesd65efa32003-02-03 00:22:30 +0100194 return;
195 }
Paul Gilliam76c61f12006-06-14 06:55:21 +0200196 if (current_proc) {
197 if (current_proc->callstack[current_depth].return_addr) {
Juan Cespedesb65bdc52008-12-16 19:50:16 +0100198 fprintf(options.output, " <unfinished ...>\n");
Paul Gilliam76c61f12006-06-14 06:55:21 +0200199 } else {
Juan Cespedesb65bdc52008-12-16 19:50:16 +0100200 fprintf(options.output, " <no return ...>\n");
Paul Gilliam76c61f12006-06-14 06:55:21 +0200201 }
Juan Cespedes5e01f651998-03-08 22:31:44 +0100202 }
Paul Gilliam76c61f12006-06-14 06:55:21 +0200203 current_proc = 0;
Juan Cespedes28f60191998-04-12 00:04:39 +0200204 if (!fmt) {
205 return;
206 }
Petr Machata37b73c02012-01-06 16:00:25 +0100207 begin_of_line(proc, 0, 0);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100208
Juan Cespedes21c63a12001-07-07 20:56:56 +0200209 va_start(args, fmt);
Juan Cespedesb65bdc52008-12-16 19:50:16 +0100210 vfprintf(options.output, fmt, args);
211 fprintf(options.output, "\n");
Juan Cespedes21c63a12001-07-07 20:56:56 +0200212 va_end(args);
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100213 current_column = 0;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100214}
215
Juan Cespedesf1350522008-12-16 18:19:58 +0100216static void
217tabto(int col) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100218 if (current_column < col) {
Juan Cespedesb65bdc52008-12-16 19:50:16 +0100219 fprintf(options.output, "%*s", col - current_column, "");
Juan Cespedes5e01f651998-03-08 22:31:44 +0100220 }
221}
222
Petr Machataf6ec08a2012-01-06 16:58:54 +0100223static int
224account_output(int o)
225{
226 if (o < 0)
227 return -1;
228 current_column += o;
229 return 0;
230}
231
232static int
233output_error(void)
234{
235 return account_output(fprintf(options.output, "?"));
236}
237
238static int
239fetch_simple_param(enum tof type, Process *proc, struct fetch_context *context,
240 struct value_dict *arguments, struct arg_type_info *info,
241 struct value *valuep)
242{
243 /* Arrays decay into pointers per C standard. We check for
244 * this here, because here we also capture arrays that come
245 * from parameter packs. */
246 int own = 0;
247 if (info->type == ARGTYPE_ARRAY) {
248 struct arg_type_info *tmp = malloc(sizeof(*tmp));
249 if (tmp != NULL) {
250 type_init_pointer(tmp, info, 0);
251 info = tmp;
252 own = 1;
253 }
254 }
255
256 struct value value;
257 value_init(&value, proc, NULL, info, own);
258 if (fetch_arg_next(context, type, proc, info, &value) < 0)
259 return -1;
260
261 if (val_dict_push_next(arguments, &value) < 0) {
262 value_destroy(&value);
263 return -1;
264 }
265
266 if (valuep != NULL)
267 *valuep = value;
268
269 return 0;
270}
271
272static void
273fetch_param_stop(struct value_dict *arguments, ssize_t *params_leftp)
274{
275 if (*params_leftp == -1)
276 *params_leftp = val_dict_count(arguments);
277}
278
279static int
Petr Machata865303f2012-01-06 18:40:38 +0100280fetch_param_pack(enum tof type, Process *proc, struct fetch_context *context,
281 struct value_dict *arguments, struct param *param,
282 ssize_t *params_leftp)
283{
284 struct param_enum *e = param_pack_init(param, arguments);
285 if (e == NULL)
286 return -1;
287
288 int ret = 0;
289 while (1) {
290 int insert_stop = 0;
291 struct arg_type_info *info = malloc(sizeof(*info));
292 if (info == NULL
293 || param_pack_next(param, e, info, &insert_stop) < 0) {
294 fail:
295 free(info);
296 ret = -1;
297 break;
298 }
299
300 if (insert_stop)
301 fetch_param_stop(arguments, params_leftp);
302
303 if (info->type == ARGTYPE_VOID)
304 break;
305
306 struct value val;
307 if (fetch_simple_param(type, proc, context, arguments,
308 info, &val) < 0)
309 goto fail;
310
311 int stop = 0;
312 switch (param_pack_stop(param, e, &val)) {
313 case PPCB_ERR:
314 goto fail;
315 case PPCB_STOP:
316 stop = 1;
317 case PPCB_CONT:
318 break;
319 }
320
321 if (stop)
322 break;
323 }
324
325 param_pack_done(param, e);
326 return ret;
327}
328
329static int
Petr Machataf6ec08a2012-01-06 16:58:54 +0100330fetch_one_param(enum tof type, Process *proc, struct fetch_context *context,
Petr Machata865303f2012-01-06 18:40:38 +0100331 struct value_dict *arguments, struct param *param,
Petr Machataf6ec08a2012-01-06 16:58:54 +0100332 ssize_t *params_leftp)
333{
Petr Machata865303f2012-01-06 18:40:38 +0100334 switch (param->flavor) {
335 case PARAM_FLAVOR_TYPE:
336 return fetch_simple_param(type, proc, context, arguments,
337 param->u.type.type, NULL);
338
339 case PARAM_FLAVOR_PACK:
340 return fetch_param_pack(type, proc, context, arguments,
341 param, params_leftp);
342
343 case PARAM_FLAVOR_STOP:
344 fetch_param_stop(arguments, params_leftp);
345 return 0;
346 }
347
348 assert(!"Invalid param flavor!");
349 abort();
Petr Machataf6ec08a2012-01-06 16:58:54 +0100350}
351
352static int
353fetch_params(enum tof type, Process *proc, struct fetch_context *context,
354 struct value_dict *arguments, Function *func, ssize_t *params_leftp)
355{
356 size_t i;
Petr Machata865303f2012-01-06 18:40:38 +0100357 for (i = 0; i < func->num_params; ++i)
Petr Machataf6ec08a2012-01-06 16:58:54 +0100358 if (fetch_one_param(type, proc, context, arguments,
Petr Machata865303f2012-01-06 18:40:38 +0100359 &func->params[i], params_leftp) < 0)
Petr Machataf6ec08a2012-01-06 16:58:54 +0100360 return -1;
Petr Machataf6ec08a2012-01-06 16:58:54 +0100361
362 /* Implicit stop at the end of parameter list. */
363 fetch_param_stop(arguments, params_leftp);
Petr Machata865303f2012-01-06 18:40:38 +0100364
Petr Machataf6ec08a2012-01-06 16:58:54 +0100365 return 0;
366}
367
368static int
369output_one(struct value *val, struct value_dict *arguments)
370{
371 int o = format_argument(options.output, val, arguments);
372 if (account_output(o) < 0) {
373 if (output_error() < 0)
374 return -1;
375 o = 1;
376 }
377 return o;
378}
379
380static int
381output_params(struct value_dict *arguments, size_t start, size_t end,
382 int *need_delimp)
383{
384 size_t i;
385 int need_delim = *need_delimp;
386 for (i = start; i < end; ++i) {
387 if (need_delim
388 && account_output(fprintf(options.output, ", ")) < 0)
389 return -1;
390 struct value *value = val_dict_get_num(arguments, i);
391 if (value == NULL)
392 return -1;
393 need_delim = output_one(value, arguments);
394 if (need_delim < 0)
395 return -1;
396 }
397 *need_delimp = need_delim;
398 return 0;
399}
400
Juan Cespedesf1350522008-12-16 18:19:58 +0100401void
Petr Machata29add4f2012-02-18 16:38:05 +0100402output_left(enum tof type, struct Process *proc,
403 struct library_symbol *libsym)
404{
405 const char *function_name = libsym->name;
Juan Cespedescde58262009-05-07 11:09:00 +0200406 Function *func;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100407
Juan Cespedesda9b9532009-04-07 15:33:50 +0200408 if (options.summary) {
Juan Cespedesd65efa32003-02-03 00:22:30 +0100409 return;
410 }
Paul Gilliam76c61f12006-06-14 06:55:21 +0200411 if (current_proc) {
Juan Cespedesb65bdc52008-12-16 19:50:16 +0100412 fprintf(options.output, " <unfinished ...>\n");
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100413 current_column = 0;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100414 }
Paul Gilliam76c61f12006-06-14 06:55:21 +0200415 current_proc = proc;
Juan Cespedes5916fda2002-02-25 00:19:21 +0100416 current_depth = proc->callstack_depth;
Petr Machataf6ec08a2012-01-06 16:58:54 +0100417 begin_of_line(proc, type == LT_TOF_FUNCTION, 1);
Petr Machata53bc49b2012-04-25 17:23:02 +0200418 if (!options.hide_caller && libsym->lib != NULL
419 && libsym->plt_type != LS_TOPLT_NONE)
Petr Machatab89c2562012-04-03 17:00:28 +0200420 current_column += fprintf(options.output, "%s->",
421 libsym->lib->soname);
Petr Machataf6ec08a2012-01-06 16:58:54 +0100422
423 const char *name = function_name;
Juan Cespedesd914a202004-11-10 00:15:33 +0100424#ifdef USE_DEMANGLE
Petr Machataf6ec08a2012-01-06 16:58:54 +0100425 if (options.demangle)
426 name = my_demangle(function_name);
Juan Cespedesac3db291998-04-25 14:31:58 +0200427#endif
Petr Machataf6ec08a2012-01-06 16:58:54 +0100428 if (account_output(fprintf(options.output, "%s(", name)) < 0)
429 return;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100430
431 func = name2func(function_name);
Petr Machataf6ec08a2012-01-06 16:58:54 +0100432 if (func == NULL)
433 return;
Petr Machata94078ec2012-01-05 18:07:02 +0100434
Petr Machataf6ec08a2012-01-06 16:58:54 +0100435 struct fetch_context *context = fetch_arg_init(type, proc,
436 func->return_info);
Petr Machata94078ec2012-01-05 18:07:02 +0100437 struct value_dict *arguments = malloc(sizeof(*arguments));
438 if (arguments == NULL)
439 return;
440 val_dict_init(arguments);
441
Petr Machataf6ec08a2012-01-06 16:58:54 +0100442 ssize_t params_left = -1;
443 int need_delim = 0;
444 if (fetch_params(type, proc, context, arguments, func, &params_left) < 0
445 || output_params(arguments, 0, params_left, &need_delim) < 0) {
446 val_dict_destroy(arguments);
447 fetch_arg_done(context);
Petr Machata865303f2012-01-06 18:40:38 +0100448 arguments = NULL;
449 context = NULL;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100450 }
Petr Machata94078ec2012-01-05 18:07:02 +0100451
452 struct callstack_element *stel
453 = &proc->callstack[proc->callstack_depth - 1];
Petr Machataf6ec08a2012-01-06 16:58:54 +0100454 stel->fetch_context = context;
Petr Machata94078ec2012-01-05 18:07:02 +0100455 stel->arguments = arguments;
Petr Machataf6ec08a2012-01-06 16:58:54 +0100456 stel->out.params_left = params_left;
457 stel->out.need_delim = need_delim;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100458}
459
Juan Cespedesf1350522008-12-16 18:19:58 +0100460void
Petr Machata29add4f2012-02-18 16:38:05 +0100461output_right(enum tof type, struct Process *proc, struct library_symbol *libsym)
Petr Machata14184b32012-02-10 13:10:26 +0100462{
Petr Machata29add4f2012-02-18 16:38:05 +0100463 const char *function_name = libsym->name;
Juan Cespedescde58262009-05-07 11:09:00 +0200464 Function *func = name2func(function_name);
Petr Machataf6ec08a2012-01-06 16:58:54 +0100465 if (func == NULL)
466 return;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100467
Juan Cespedesda9b9532009-04-07 15:33:50 +0200468 if (options.summary) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100469 struct opt_c_struct *st;
Juan Cespedesd65efa32003-02-03 00:22:30 +0100470 if (!dict_opt_c) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100471 dict_opt_c =
472 dict_init(dict_key2hash_string,
473 dict_key_cmp_string);
Juan Cespedesd65efa32003-02-03 00:22:30 +0100474 }
475 st = dict_find_entry(dict_opt_c, function_name);
476 if (!st) {
477 char *na;
478 st = malloc(sizeof(struct opt_c_struct));
479 na = strdup(function_name);
480 if (!st || !na) {
481 perror("malloc()");
482 exit(1);
483 }
484 st->count = 0;
485 st->tv.tv_sec = st->tv.tv_usec = 0;
486 dict_enter(dict_opt_c, na, st);
487 }
488 if (st->tv.tv_usec + current_time_spent.tv_usec > 1000000) {
489 st->tv.tv_usec += current_time_spent.tv_usec - 1000000;
490 st->tv.tv_sec++;
491 } else {
492 st->tv.tv_usec += current_time_spent.tv_usec;
493 }
494 st->count++;
495 st->tv.tv_sec += current_time_spent.tv_sec;
496
Juan Cespedesb65bdc52008-12-16 19:50:16 +0100497// fprintf(options.output, "%s <%lu.%06d>\n", function_name,
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100498// current_time_spent.tv_sec, (int)current_time_spent.tv_usec);
Juan Cespedesd65efa32003-02-03 00:22:30 +0100499 return;
500 }
Paul Gilliam76c61f12006-06-14 06:55:21 +0200501 if (current_proc && (current_proc != proc ||
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100502 current_depth != proc->callstack_depth)) {
Juan Cespedesb65bdc52008-12-16 19:50:16 +0100503 fprintf(options.output, " <unfinished ...>\n");
Paul Gilliam76c61f12006-06-14 06:55:21 +0200504 current_proc = 0;
Juan Cespedes1b9cfd61999-08-30 19:34:50 +0200505 }
Paul Gilliam76c61f12006-06-14 06:55:21 +0200506 if (current_proc != proc) {
Petr Machata37b73c02012-01-06 16:00:25 +0100507 begin_of_line(proc, type == LT_TOF_FUNCTIONR, 1);
Juan Cespedesd914a202004-11-10 00:15:33 +0100508#ifdef USE_DEMANGLE
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100509 current_column +=
Juan Cespedesb65bdc52008-12-16 19:50:16 +0100510 fprintf(options.output, "<... %s resumed> ",
Juan Cespedesce377d52008-12-16 19:38:10 +0100511 options.demangle ? my_demangle(function_name) : function_name);
Juan Cespedes1b9cfd61999-08-30 19:34:50 +0200512#else
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100513 current_column +=
Juan Cespedesb65bdc52008-12-16 19:50:16 +0100514 fprintf(options.output, "<... %s resumed> ", function_name);
Juan Cespedes1b9cfd61999-08-30 19:34:50 +0200515#endif
Juan Cespedes5e01f651998-03-08 22:31:44 +0100516 }
517
Petr Machata94078ec2012-01-05 18:07:02 +0100518 struct callstack_element *stel
519 = &proc->callstack[proc->callstack_depth - 1];
520
Petr Machataf6ec08a2012-01-06 16:58:54 +0100521 struct fetch_context *context = stel->fetch_context;
Petr Machata94078ec2012-01-05 18:07:02 +0100522
Petr Machataf6ec08a2012-01-06 16:58:54 +0100523 /* Fetch & enter into dictionary the retval first, so that
524 * other values can use it in expressions. */
525 struct value retval;
526 int own_retval = 0;
527 if (context != NULL) {
528 value_init(&retval, proc, NULL, func->return_info, 0);
529 own_retval = 1;
530 if (fetch_retval(context, type, proc, func->return_info,
531 &retval) == 0) {
532 if (stel->arguments != NULL
533 && val_dict_push_named(stel->arguments, &retval,
534 "retval", 0) == 0)
535 own_retval = 0;
Juan Cespedes5e01f651998-03-08 22:31:44 +0100536 }
Juan Cespedes5e4455b1997-08-24 01:48:26 +0200537 }
Petr Machata94078ec2012-01-05 18:07:02 +0100538
Petr Machataf6ec08a2012-01-06 16:58:54 +0100539 if (stel->arguments != NULL)
540 output_params(stel->arguments, stel->out.params_left,
541 val_dict_count(stel->arguments),
542 &stel->out.need_delim);
543
544 current_column += fprintf(options.output, ") ");
545 tabto(options.align - 1);
546 fprintf(options.output, "= ");
547
548 output_one(&retval, stel->arguments);
549
550 if (own_retval)
551 value_destroy(&retval);
552
Petr Machata865303f2012-01-06 18:40:38 +0100553 if (stel->arguments != NULL) {
554 val_dict_destroy(stel->arguments);
555 free(stel->arguments);
556 }
557 if (context != NULL)
558 fetch_arg_done(context);
Petr Machata94078ec2012-01-05 18:07:02 +0100559
Juan Cespedesd65efa32003-02-03 00:22:30 +0100560 if (opt_T) {
Juan Cespedesb65bdc52008-12-16 19:50:16 +0100561 fprintf(options.output, " <%lu.%06d>",
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100562 current_time_spent.tv_sec,
563 (int)current_time_spent.tv_usec);
Juan Cespedesd65efa32003-02-03 00:22:30 +0100564 }
Juan Cespedesb65bdc52008-12-16 19:50:16 +0100565 fprintf(options.output, "\n");
Joe Damatoab3b72c2010-10-31 00:21:53 -0700566
567#if defined(HAVE_LIBUNWIND)
568 if (options.bt_depth > 0) {
569 unw_cursor_t cursor;
570 unw_word_t ip, sp;
571 int unwind_depth = options.bt_depth;
572 char fn_name[100];
573
574 unw_init_remote(&cursor, proc->unwind_as, proc->unwind_priv);
575 while (unwind_depth) {
576 unw_get_reg(&cursor, UNW_REG_IP, &ip);
577 unw_get_reg(&cursor, UNW_REG_SP, &sp);
578 unw_get_proc_name(&cursor, fn_name, 100, NULL);
579 fprintf(options.output, "\t\t\t%s (ip = 0x%lx)\n", fn_name, (long) ip);
580 if (unw_step(&cursor) <= 0)
581 break;
582 unwind_depth--;
583 }
584 fprintf(options.output, "\n");
585 }
586#endif /* defined(HAVE_LIBUNWIND) */
587
Paul Gilliam76c61f12006-06-14 06:55:21 +0200588 current_proc = 0;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100589 current_column = 0;
Juan Cespedesc40e64a1997-10-26 20:34:00 +0100590}
Petr Machatad71cf2d2012-01-05 18:28:31 +0100591
592static void
593do_report(const char *filename, unsigned line_no, const char *severity,
594 const char *fmt, va_list args)
595{
596 char buf[128];
597 vsnprintf(buf, sizeof(buf), fmt, args);
598 buf[sizeof(buf) - 1] = 0;
599 if (filename != NULL)
600 output_line(0, "%s:%d: %s: %s",
601 filename, line_no, severity, buf);
602 else
603 output_line(0, "%s: %s", severity, buf);
604}
605
606void
607report_error(const char *filename, unsigned line_no, char *fmt, ...)
608{
609 va_list args;
610 va_start(args, fmt);
611 do_report(filename, line_no, "error", fmt, args);
612 va_end(args);
613}
614
615void
616report_warning(const char *filename, unsigned line_no, char *fmt, ...)
617{
618 va_list args;
619 va_start(args, fmt);
620 do_report(filename, line_no, "warning", fmt, args);
621 va_end(args);
622}
623
624void
625report_global_error(char *fmt, ...)
626{
627 va_list args;
628 va_start(args, fmt);
629 do_report(NULL, 0, "error", fmt, args);
630 va_end(args);
631}