lens_default.c revision 26c0c9413c2558c3f95cb466b3734ea5ba57444d
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	if (value_is_zero(value, arguments))
251		return fprintf(stream, "nil");
252
253	struct value element;
254	int o;
255	if (value_init_deref(&element, value) < 0) {
256		o = -1;
257		goto done;
258	}
259	o = format_argument(stream, &element, arguments);
260	value_destroy(&element);
261
262done:
263	return o;
264}
265
266/*
267 * LENGTH is an expression whose evaluation will yield the actual
268 *    length of the array.
269 *
270 * MAXLEN is the actual maximum length that we care about
271 *
272 * BEFORE if LENGTH>MAXLEN, we display ellipsis.  We display it before
273 *    the closing parenthesis if BEFORE, otherwise after it.
274 *
275 * OPEN, CLOSE, DELIM are opening and closing parenthesis and element
276 *    delimiter.
277 */
278int
279format_array(FILE *stream, struct value *value, struct value_dict *arguments,
280	     struct expr_node *length, size_t maxlen, int before,
281	     const char *open, const char *close, const char *delim)
282{
283	/* We need "long" to be long enough to cover the whole address
284	 * space.  */
285	typedef char assert__long_enough_long[-(sizeof(long) < sizeof(void *))];
286	long l;
287	if (expr_eval_word(length, value, arguments, &l) < 0)
288		return -1;
289	size_t len = (size_t)l;
290
291	int written = 0;
292	if (acc_fprintf(&written, stream, "%s", open) < 0)
293		return -1;
294
295	size_t i;
296	for (i = 0; i < len && i <= maxlen; ++i) {
297		if (i == maxlen) {
298			if (before && acc_fprintf(&written, stream, "...") < 0)
299				return -1;
300			break;
301		}
302
303		if (i > 0 && acc_fprintf(&written, stream, "%s", delim) < 0)
304			return -1;
305
306		struct value element;
307		if (value_init_element(&element, value, i) < 0)
308			return -1;
309		int o = format_argument(stream, &element, arguments);
310		value_destroy(&element);
311		if (o < 0)
312			return -1;
313		written += o;
314	}
315	if (acc_fprintf(&written, stream, "%s", close) < 0)
316		return -1;
317	if (i == maxlen && !before && acc_fprintf(&written, stream, "...") < 0)
318		return -1;
319
320	return written;
321}
322
323static int
324toplevel_format_lens(struct lens *lens, FILE *stream,
325		     struct value *value, struct value_dict *arguments,
326		     enum int_fmt_t int_fmt)
327{
328	switch (value->type->type) {
329	case ARGTYPE_VOID:
330		return fprintf(stream, "<void>");
331
332	case ARGTYPE_SHORT:
333	case ARGTYPE_INT:
334	case ARGTYPE_LONG:
335		return format_integer(stream, value, int_fmt, arguments);
336
337	case ARGTYPE_USHORT:
338	case ARGTYPE_UINT:
339	case ARGTYPE_ULONG:
340		if (int_fmt == INT_FMT_i || int_fmt == INT_FMT_default)
341			int_fmt = INT_FMT_u;
342		return format_integer(stream, value, int_fmt, arguments);
343
344	case ARGTYPE_CHAR:
345		if (int_fmt == INT_FMT_default)
346			return format_naked_char(stream, value, arguments);
347		return format_integer(stream, value, int_fmt, arguments);
348
349	case ARGTYPE_FLOAT:
350	case ARGTYPE_DOUBLE:
351		return format_floating(stream, value, arguments);
352
353	case ARGTYPE_STRUCT:
354		return format_struct(stream, value, arguments);
355
356	case ARGTYPE_POINTER:
357		if (value->type->u.array_info.elt_type->type != ARGTYPE_VOID)
358			return format_pointer(stream, value, arguments);
359		return format_integer(stream, value, INT_FMT_x, arguments);
360
361	case ARGTYPE_ARRAY:
362		return format_array(stream, value, arguments,
363				    value->type->u.array_info.length,
364				    options.arraylen, 1, "[ ", " ]", ", ");
365	}
366	abort();
367}
368
369static int
370default_lens_format_cb(struct lens *lens, FILE *stream,
371		       struct value *value, struct value_dict *arguments)
372{
373	return toplevel_format_lens(lens, stream, value, arguments,
374				    INT_FMT_default);
375}
376
377struct lens default_lens = {
378	.format_cb = default_lens_format_cb,
379};
380
381
382static int
383blind_lens_format_cb(struct lens *lens, FILE *stream,
384		     struct value *value, struct value_dict *arguments)
385{
386	return 0;
387}
388
389struct lens blind_lens = {
390	.format_cb = blind_lens_format_cb,
391};
392
393
394static int
395octal_lens_format_cb(struct lens *lens, FILE *stream,
396		     struct value *value, struct value_dict *arguments)
397{
398	return toplevel_format_lens(lens, stream, value, arguments, INT_FMT_o);
399}
400
401struct lens octal_lens = {
402	.format_cb = octal_lens_format_cb,
403};
404
405
406static int
407hex_lens_format_cb(struct lens *lens, FILE *stream,
408		   struct value *value, struct value_dict *arguments)
409{
410	return toplevel_format_lens(lens, stream, value, arguments, INT_FMT_x);
411}
412
413struct lens hex_lens = {
414	.format_cb = hex_lens_format_cb,
415};
416
417
418static int
419guess_lens_format_cb(struct lens *lens, FILE *stream,
420		     struct value *value, struct value_dict *arguments)
421{
422	return toplevel_format_lens(lens, stream, value, arguments,
423				    INT_FMT_unknown);
424}
425
426struct lens guess_lens = {
427	.format_cb = guess_lens_format_cb,
428};
429
430
431static int
432bool_lens_format_cb(struct lens *lens, FILE *stream,
433		    struct value *value, struct value_dict *arguments)
434{
435	switch (value->type->type) {
436	case ARGTYPE_VOID:
437	case ARGTYPE_FLOAT:
438	case ARGTYPE_DOUBLE:
439	case ARGTYPE_STRUCT:
440	case ARGTYPE_POINTER:
441	case ARGTYPE_ARRAY:
442		return toplevel_format_lens(lens, stream, value,
443					    arguments, INT_FMT_default);
444
445		int zero;
446	case ARGTYPE_SHORT:
447	case ARGTYPE_INT:
448	case ARGTYPE_LONG:
449	case ARGTYPE_USHORT:
450	case ARGTYPE_UINT:
451	case ARGTYPE_ULONG:
452	case ARGTYPE_CHAR:
453		if ((zero = value_is_zero(value, arguments)) < 0)
454			return -1;
455		if (zero)
456			return fprintf(stream, "false");
457		else
458			return fprintf(stream, "true");
459	}
460	abort();
461}
462
463struct lens bool_lens = {
464	.format_cb = bool_lens_format_cb,
465};
466
467
468static int
469string_lens_format_cb(struct lens *lens, FILE *stream,
470		      struct value *value, struct value_dict *arguments)
471{
472	switch (value->type->type) {
473	case ARGTYPE_POINTER:
474		/* This should really be written as either "string",
475		 * or, if lens, then string(array(char, zero)*).  But
476		 * I suspect people are so used to the char * C idiom,
477		 * that string(char *) might actually turn up.  So
478		 * let's just support it.  */
479		if (value->type->u.ptr_info.info->type == ARGTYPE_CHAR) {
480			struct arg_type_info info[2];
481			type_init_array(&info[1],
482					value->type->u.ptr_info.info, 0,
483					expr_node_zero(), 0);
484			type_init_pointer(&info[0], &info[1], 0);
485			info->lens = lens;
486			info->own_lens = 0;
487			struct value tmp;
488			if (value_clone(&tmp, value) < 0)
489				return -1;
490			value_set_type(&tmp, info, 0);
491			int ret = string_lens_format_cb(lens, stream, &tmp,
492							arguments);
493			type_destroy(&info[0]);
494			type_destroy(&info[1]);
495			value_destroy(&tmp);
496			return ret;
497		}
498
499		/* fall-through */
500	case ARGTYPE_VOID:
501	case ARGTYPE_FLOAT:
502	case ARGTYPE_DOUBLE:
503	case ARGTYPE_STRUCT:
504	case ARGTYPE_SHORT:
505	case ARGTYPE_INT:
506	case ARGTYPE_LONG:
507	case ARGTYPE_USHORT:
508	case ARGTYPE_UINT:
509	case ARGTYPE_ULONG:
510		return toplevel_format_lens(lens, stream, value,
511					    arguments, INT_FMT_default);
512
513	case ARGTYPE_CHAR:
514		return format_char(stream, value, arguments);
515
516	case ARGTYPE_ARRAY:
517		return format_array(stream, value, arguments,
518				    value->type->u.array_info.length,
519				    options.strlen, 0, "\"", "\"", "");
520	}
521	abort();
522}
523
524struct lens string_lens = {
525	.format_cb = string_lens_format_cb,
526};
527