lens_default.c revision e773f634dc1283a47786788e747aa5217f61c6fc
1/*
2 * This file is part of ltrace.
3 * Copyright (C) 2011,2012 Petr Machata, Red Hat Inc.
4 * Copyright (C) 1998,2004,2007,2008,2009 Juan Cespedes
5 * Copyright (C) 2006 Ian Wienand
6 * Copyright (C) 2006 Steve Fink
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 * 02110-1301 USA
22 */
23
24#include <ctype.h>
25#include <stdlib.h>
26#include <assert.h>
27#include <inttypes.h>
28#include <stdarg.h>
29#include <stdio.h>
30
31#include "proc.h"
32#include "lens_default.h"
33#include "value.h"
34#include "expr.h"
35#include "type.h"
36#include "common.h"
37#include "zero.h"
38
39#define READER(NAME, TYPE)						\
40	static int							\
41	NAME(struct value *value, TYPE *ret, struct value_dict *arguments) \
42	{								\
43		union {							\
44			TYPE val;					\
45			unsigned char buf[0];				\
46		} u;							\
47		if (value_extract_buf(value, u.buf, arguments) < 0)	\
48			return -1;					\
49		*ret = u.val;						\
50		return 0;						\
51	}
52
53READER(read_float, float)
54READER(read_double, double)
55
56#undef READER
57
58#define HANDLE_WIDTH(BITS)						\
59	do {								\
60		long l;							\
61		if (value_extract_word(value, &l, arguments) < 0)	\
62			return -1;					\
63		int##BITS##_t i = l;					\
64		uint64_t v = (uint64_t)(uint##BITS##_t)i;		\
65		switch (format) {					\
66		case INT_FMT_unknown:					\
67			if (l < -10000 || l > 10000)			\
68		case INT_FMT_x:						\
69			return fprintf(stream, "%#"PRIx64, v);		\
70		case INT_FMT_i:						\
71		case INT_FMT_default:					\
72			return fprintf(stream, "%"PRIi##BITS, i);	\
73		case INT_FMT_u:						\
74			return fprintf(stream, "%"PRIu64, v);		\
75		case INT_FMT_o:						\
76			return fprintf(stream, "0%"PRIo64, v);		\
77		}							\
78	} while (0)
79
80enum int_fmt_t
81{
82	INT_FMT_i,
83	INT_FMT_u,
84	INT_FMT_o,
85	INT_FMT_x,
86	INT_FMT_unknown,
87	INT_FMT_default,
88};
89
90static int
91format_integer(FILE *stream, struct value *value, enum int_fmt_t format,
92	       struct value_dict *arguments)
93{
94	switch (type_sizeof(value->inferior, value->type)) {
95
96	case 1: HANDLE_WIDTH(8);
97	case 2: HANDLE_WIDTH(16);
98	case 4: HANDLE_WIDTH(32);
99	case 8: HANDLE_WIDTH(64);
100
101	default:
102		assert(!"unsupported integer width");
103		abort();
104
105	case -1:
106		return -1;
107	}
108}
109
110#undef HANDLE_WIDTH
111
112static int
113acc_fprintf(int *countp, FILE *stream, const char *format, ...)
114{
115	va_list pa;
116	va_start(pa, format);
117	int i = account_output(countp, vfprintf(stream, format, pa));
118	va_end(pa);
119
120	return i;
121}
122
123static int
124format_char(FILE *stream, struct value *value, struct value_dict *arguments)
125{
126	long lc;
127	if (value_extract_word(value, &lc, arguments) < 0)
128		return -1;
129	int c = (int)lc;
130
131	const char *fmt;
132	switch (c) {
133	case -1:
134		fmt = "EOF";
135		break;
136	case 0:
137		fmt = "\\0";
138		break;
139	case '\a':
140		fmt = "\\a";
141		break;
142	case '\b':
143		fmt = "\\b";
144		break;
145	case '\t':
146		fmt = "\\t";
147		break;
148	case '\n':
149		fmt = "\\n";
150		break;
151	case '\v':
152		fmt = "\\v";
153		break;
154	case '\f':
155		fmt = "\\f";
156		break;
157	case '\r':
158		fmt = "\\r";
159		break;
160	case '\\':
161		fmt = "\\\\";
162		break;
163	default:
164		if (isprint(c) || c == ' ')
165			fmt = "%c";
166		else
167			fmt = "\\%03o";
168	}
169
170	return fprintf(stream, fmt, c);
171}
172
173static int
174format_naked_char(FILE *stream, struct value *value,
175		  struct value_dict *arguments)
176{
177	int written = 0;
178	if (acc_fprintf(&written, stream, "'") < 0
179	    || account_output(&written,
180			      format_char(stream, value, arguments)) < 0
181	    || acc_fprintf(&written, stream, "'") < 0)
182		return -1;
183
184	return written;
185}
186
187static int
188format_floating(FILE *stream, struct value *value, struct value_dict *arguments)
189{
190	switch (value->type->type) {
191		float f;
192		double d;
193	case ARGTYPE_FLOAT:
194		if (read_float(value, &f, arguments) < 0)
195			return -1;
196		return fprintf(stream, "%f", (double)f);
197	case ARGTYPE_DOUBLE:
198		if (read_double(value, &d, arguments) < 0)
199			return -1;
200		return fprintf(stream, "%f", d);
201	default:
202		abort();
203	}
204}
205
206struct format_argument_data
207{
208	struct value *value;
209	struct value_dict *arguments;
210};
211
212static int
213format_argument_cb(FILE *stream, void *ptr)
214{
215	struct format_argument_data *data = ptr;
216	return format_argument(stream, data->value, data->arguments);
217}
218
219static int
220format_struct(FILE *stream, struct value *value, struct value_dict *arguments)
221{
222	int written = 0;
223	if (acc_fprintf(&written, stream, "{ ") < 0)
224		return -1;
225
226	int need_delim = 0;
227	size_t i;
228	for (i = 0; i < type_struct_size(value->type); ++i) {
229		struct value element;
230		if (value_init_element(&element, value, i) < 0)
231			return -1;
232
233		struct format_argument_data data = { &element, arguments };
234		int o = delim_output(stream, &need_delim,
235				     format_argument_cb, &data);
236		value_destroy(&element);
237		if (o < 0)
238			return -1;
239
240		written += o;
241	}
242	if (acc_fprintf(&written, stream, " }") < 0)
243		return -1;
244	return written;
245}
246
247int
248format_pointer(FILE *stream, struct value *value, struct value_dict *arguments)
249{
250	struct value element;
251	if (value_init_deref(&element, value) < 0)
252		return -1;
253	int o = format_argument(stream, &element, arguments);
254	value_destroy(&element);
255	return o;
256}
257
258/*
259 * LENGTH is an expression whose evaluation will yield the actual
260 *    length of the array.
261 *
262 * MAXLEN is the actual maximum length that we care about
263 *
264 * BEFORE if LENGTH>MAXLEN, we display ellipsis.  We display it before
265 *    the closing parenthesis if BEFORE, otherwise after it.
266 *
267 * OPEN, CLOSE, DELIM are opening and closing parenthesis and element
268 *    delimiter.
269 */
270int
271format_array(FILE *stream, struct value *value, struct value_dict *arguments,
272	     struct expr_node *length, size_t maxlen, int before,
273	     const char *open, const char *close, const char *delim)
274{
275	/* We need "long" to be long enough to cover the whole address
276	 * space.  */
277	typedef char assert__long_enough_long[-(sizeof(long) < sizeof(void *))];
278	long l;
279	if (expr_eval_word(length, value, arguments, &l) < 0)
280		return -1;
281	size_t len = (size_t)l;
282
283	int written = 0;
284	if (acc_fprintf(&written, stream, "%s", open) < 0)
285		return -1;
286
287	size_t i;
288	for (i = 0; i < len && i <= maxlen; ++i) {
289		if (i == maxlen) {
290			if (before && acc_fprintf(&written, stream, "...") < 0)
291				return -1;
292			break;
293		}
294
295		if (i > 0 && acc_fprintf(&written, stream, "%s", delim) < 0)
296			return -1;
297
298		struct value element;
299		if (value_init_element(&element, value, i) < 0)
300			return -1;
301		int o = format_argument(stream, &element, arguments);
302		value_destroy(&element);
303		if (o < 0)
304			return -1;
305		written += o;
306	}
307	if (acc_fprintf(&written, stream, "%s", close) < 0)
308		return -1;
309	if (i == maxlen && !before && acc_fprintf(&written, stream, "...") < 0)
310		return -1;
311
312	return written;
313}
314
315static int
316toplevel_format_lens(struct lens *lens, FILE *stream,
317		     struct value *value, struct value_dict *arguments,
318		     enum int_fmt_t int_fmt)
319{
320	switch (value->type->type) {
321	case ARGTYPE_VOID:
322		return fprintf(stream, "<void>");
323
324	case ARGTYPE_SHORT:
325	case ARGTYPE_INT:
326	case ARGTYPE_LONG:
327		return format_integer(stream, value, int_fmt, arguments);
328
329	case ARGTYPE_USHORT:
330	case ARGTYPE_UINT:
331	case ARGTYPE_ULONG:
332		if (int_fmt == INT_FMT_i || int_fmt == INT_FMT_default)
333			int_fmt = INT_FMT_u;
334		return format_integer(stream, value, int_fmt, arguments);
335
336	case ARGTYPE_CHAR:
337		if (int_fmt == INT_FMT_default)
338			return format_naked_char(stream, value, arguments);
339		return format_integer(stream, value, int_fmt, arguments);
340
341	case ARGTYPE_FLOAT:
342	case ARGTYPE_DOUBLE:
343		return format_floating(stream, value, arguments);
344
345	case ARGTYPE_STRUCT:
346		return format_struct(stream, value, arguments);
347
348	case ARGTYPE_POINTER:
349		if (value->type->u.array_info.elt_type->type != ARGTYPE_VOID)
350			return format_pointer(stream, value, arguments);
351		return format_integer(stream, value, INT_FMT_x, arguments);
352
353	case ARGTYPE_ARRAY:
354		return format_array(stream, value, arguments,
355				    value->type->u.array_info.length,
356				    options.arraylen, 1, "[ ", " ]", ", ");
357	}
358	abort();
359}
360
361static int
362default_lens_format_cb(struct lens *lens, FILE *stream,
363		       struct value *value, struct value_dict *arguments)
364{
365	return toplevel_format_lens(lens, stream, value, arguments,
366				    INT_FMT_default);
367}
368
369struct lens default_lens = {
370	.format_cb = default_lens_format_cb,
371};
372
373
374static int
375blind_lens_format_cb(struct lens *lens, FILE *stream,
376		     struct value *value, struct value_dict *arguments)
377{
378	return 0;
379}
380
381struct lens blind_lens = {
382	.format_cb = blind_lens_format_cb,
383};
384
385
386static int
387octal_lens_format_cb(struct lens *lens, FILE *stream,
388		     struct value *value, struct value_dict *arguments)
389{
390	return toplevel_format_lens(lens, stream, value, arguments, INT_FMT_o);
391}
392
393struct lens octal_lens = {
394	.format_cb = octal_lens_format_cb,
395};
396
397
398static int
399hex_lens_format_cb(struct lens *lens, FILE *stream,
400		   struct value *value, struct value_dict *arguments)
401{
402	return toplevel_format_lens(lens, stream, value, arguments, INT_FMT_x);
403}
404
405struct lens hex_lens = {
406	.format_cb = hex_lens_format_cb,
407};
408
409
410static int
411guess_lens_format_cb(struct lens *lens, FILE *stream,
412		     struct value *value, struct value_dict *arguments)
413{
414	return toplevel_format_lens(lens, stream, value, arguments,
415				    INT_FMT_unknown);
416}
417
418struct lens guess_lens = {
419	.format_cb = guess_lens_format_cb,
420};
421
422
423static int
424bool_lens_format_cb(struct lens *lens, FILE *stream,
425		    struct value *value, struct value_dict *arguments)
426{
427	switch (value->type->type) {
428	case ARGTYPE_VOID:
429	case ARGTYPE_FLOAT:
430	case ARGTYPE_DOUBLE:
431	case ARGTYPE_STRUCT:
432	case ARGTYPE_POINTER:
433	case ARGTYPE_ARRAY:
434		return toplevel_format_lens(lens, stream, value,
435					    arguments, INT_FMT_default);
436
437		int zero;
438	case ARGTYPE_SHORT:
439	case ARGTYPE_INT:
440	case ARGTYPE_LONG:
441	case ARGTYPE_USHORT:
442	case ARGTYPE_UINT:
443	case ARGTYPE_ULONG:
444	case ARGTYPE_CHAR:
445		if ((zero = value_is_zero(value, arguments)) < 0)
446			return -1;
447		if (zero)
448			return fprintf(stream, "false");
449		else
450			return fprintf(stream, "true");
451	}
452	abort();
453}
454
455struct lens bool_lens = {
456	.format_cb = bool_lens_format_cb,
457};
458
459
460static int
461string_lens_format_cb(struct lens *lens, FILE *stream,
462		      struct value *value, struct value_dict *arguments)
463{
464	switch (value->type->type) {
465	case ARGTYPE_POINTER:
466		/* This should really be written as either "string",
467		 * or, if lens, then string(array(char, zero)*).  But
468		 * I suspect people are so used to the char * C idiom,
469		 * that string(char *) might actually turn up.  So
470		 * let's just support it.  */
471		if (value->type->u.ptr_info.info->type == ARGTYPE_CHAR) {
472			struct arg_type_info info[2];
473			type_init_array(&info[1],
474					value->type->u.ptr_info.info, 0,
475					expr_node_zero(), 0);
476			type_init_pointer(&info[0], &info[1], 0);
477			info->lens = lens;
478			info->own_lens = 0;
479			struct value tmp;
480			if (value_clone(&tmp, value) < 0)
481				return -1;
482			value_set_type(&tmp, info, 0);
483			int ret = string_lens_format_cb(lens, stream, &tmp,
484							arguments);
485			type_destroy(&info[0]);
486			type_destroy(&info[1]);
487			value_destroy(&tmp);
488			return ret;
489		}
490
491		/* fall-through */
492	case ARGTYPE_VOID:
493	case ARGTYPE_FLOAT:
494	case ARGTYPE_DOUBLE:
495	case ARGTYPE_STRUCT:
496	case ARGTYPE_SHORT:
497	case ARGTYPE_INT:
498	case ARGTYPE_LONG:
499	case ARGTYPE_USHORT:
500	case ARGTYPE_UINT:
501	case ARGTYPE_ULONG:
502		return toplevel_format_lens(lens, stream, value,
503					    arguments, INT_FMT_default);
504
505	case ARGTYPE_CHAR:
506		return format_char(stream, value, arguments);
507
508	case ARGTYPE_ARRAY:
509		return format_array(stream, value, arguments,
510				    value->type->u.array_info.length,
511				    options.strlen, 0, "\"", "\"", "");
512	}
513	abort();
514}
515
516struct lens string_lens = {
517	.format_cb = string_lens_format_cb,
518};
519