lens_default.c revision f6a56e15530b179e404aab075dab8661af64155e
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		switch (format) {					\
65		case INT_FMT_unknown:					\
66			if (i < -10000 || i > 10000)			\
67		case INT_FMT_x:						\
68			return fprintf(stream, "%#"PRIx##BITS, i);	\
69		case INT_FMT_i:						\
70			return fprintf(stream, "%"PRIi##BITS, i);	\
71		case INT_FMT_u:						\
72			return fprintf(stream, "%"PRIu##BITS, i);	\
73		case INT_FMT_o:						\
74			return fprintf(stream, "0%"PRIo##BITS, i);	\
75		}							\
76	} while (0)
77
78enum int_fmt_t
79{
80	INT_FMT_i,
81	INT_FMT_u,
82	INT_FMT_o,
83	INT_FMT_x,
84	INT_FMT_unknown,
85};
86
87static int
88format_integer(FILE *stream, struct value *value, enum int_fmt_t format,
89	       struct value_dict *arguments)
90{
91	switch (type_sizeof(value->inferior, value->type)) {
92
93	case 1: HANDLE_WIDTH(8);
94	case 2: HANDLE_WIDTH(16);
95	case 4: HANDLE_WIDTH(32);
96	case 8: HANDLE_WIDTH(64);
97
98	default:
99		assert(!"unsupported integer width");
100		abort();
101
102	case -1:
103		return -1;
104	}
105}
106
107#undef HANDLE_WIDTH
108
109static int
110account(int *countp, int c)
111{
112	if (c >= 0)
113		*countp += c;
114	return c;
115}
116
117static int
118acc_fprintf(int *countp, FILE *stream, const char *format, ...)
119{
120	va_list pa;
121	va_start(pa, format);
122	int i = account(countp, vfprintf(stream, format, pa));
123	va_end(pa);
124
125	return i;
126}
127
128static int
129format_char(FILE *stream, struct value *value, struct value_dict *arguments)
130{
131	long lc;
132	if (value_extract_word(value, &lc, arguments) < 0)
133		return -1;
134	int c = (int)lc;
135
136	const char *fmt;
137	switch (c) {
138	case -1:
139		fmt = "EOF";
140		break;
141	case 0:
142		fmt = "\\0";
143		break;
144	case '\a':
145		fmt = "\\a";
146		break;
147	case '\b':
148		fmt = "\\b";
149		break;
150	case '\t':
151		fmt = "\\t";
152		break;
153	case '\n':
154		fmt = "\\n";
155		break;
156	case '\v':
157		fmt = "\\v";
158		break;
159	case '\f':
160		fmt = "\\f";
161		break;
162	case '\r':
163		fmt = "\\r";
164		break;
165	case '\\':
166		fmt = "\\\\";
167		break;
168	default:
169		if (isprint(c) || c == ' ')
170			fmt = "%c";
171		else
172			fmt = "\\%03o";
173	}
174
175	return fprintf(stream, fmt, c);
176}
177
178static int
179format_naked_char(FILE *stream, struct value *value,
180		  struct value_dict *arguments)
181{
182	int written = 0;
183	if (acc_fprintf(&written, stream, "'") < 0
184	    || account(&written, format_char(stream, value, arguments)) < 0
185	    || acc_fprintf(&written, stream, "'") < 0)
186		return -1;
187
188	return written;
189}
190
191static int
192format_floating(FILE *stream, struct value *value, struct value_dict *arguments)
193{
194	switch (value->type->type) {
195		float f;
196		double d;
197	case ARGTYPE_FLOAT:
198		if (read_float(value, &f, arguments) < 0)
199			return -1;
200		return fprintf(stream, "%f", (double)f);
201	case ARGTYPE_DOUBLE:
202		if (read_double(value, &d, arguments) < 0)
203			return -1;
204		return fprintf(stream, "%f", d);
205	default:
206		abort();
207	}
208}
209
210static int
211format_struct(FILE *stream, struct value *value, struct value_dict *arguments)
212{
213	int written = 0;
214	if (acc_fprintf(&written, stream, "{ ") < 0)
215		return -1;
216	size_t i;
217	for (i = 0; i < type_struct_size(value->type); ++i) {
218		if (i > 0 && acc_fprintf(&written, stream, ", ") < 0)
219			return -1;
220
221		struct value element;
222		if (value_init_element(&element, value, i) < 0)
223			return -1;
224		int o = format_argument(stream, &element, arguments);
225		if (o < 0)
226			return -1;
227		written += o;
228	}
229	if (acc_fprintf(&written, stream, " }") < 0)
230		return -1;
231	return written;
232}
233
234int
235format_pointer(FILE *stream, struct value *value, struct value_dict *arguments)
236{
237	struct value element;
238	if (value_init_deref(&element, value) < 0)
239		return -1;
240	return format_argument(stream, &element, arguments);
241}
242
243/*
244 * LENGTH is an expression whose evaluation will yield the actual
245 *    length of the array.
246 *
247 * MAXLEN is the actual maximum length that we care about
248 *
249 * BEFORE if LENGTH>MAXLEN, we display ellipsis.  We display it before
250 *    the closing parenthesis if BEFORE, otherwise after it.
251 *
252 * OPEN, CLOSE, DELIM are opening and closing parenthesis and element
253 *    delimiter.
254 */
255int
256format_array(FILE *stream, struct value *value, struct value_dict *arguments,
257	     struct expr_node *length, size_t maxlen, int before,
258	     const char *open, const char *close, const char *delim)
259{
260	/* We need "long" to be long enough to cover the whole address
261	 * space.  */
262	typedef char assert__long_enough_long[-(sizeof(long) < sizeof(void *))];
263	long l;
264	if (expr_eval_word(length, value, arguments, &l) < 0)
265		return -1;
266	size_t len = (size_t)l;
267
268	int written = 0;
269	if (acc_fprintf(&written, stream, "%s", open) < 0)
270		return -1;
271
272	size_t i;
273	for (i = 0; i < len && i <= maxlen; ++i) {
274		if (i == maxlen) {
275			if (before && acc_fprintf(&written, stream, "...") < 0)
276				return -1;
277			break;
278		}
279
280		if (i > 0 && acc_fprintf(&written, stream, "%s", delim) < 0)
281			return -1;
282
283		struct value element;
284		if (value_init_element(&element, value, i) < 0)
285			return -1;
286		int o = format_argument(stream, &element, arguments);
287		if (o < 0)
288			return -1;
289		written += o;
290	}
291	if (acc_fprintf(&written, stream, "%s", close) < 0)
292		return -1;
293	if (i == maxlen && !before && acc_fprintf(&written, stream, "...") < 0)
294		return -1;
295
296	return written;
297}
298
299static int
300toplevel_format_lens(struct lens *lens, FILE *stream,
301		     struct value *value, struct value_dict *arguments,
302		     enum int_fmt_t int_fmt)
303{
304	switch (value->type->type) {
305	case ARGTYPE_VOID:
306		return fprintf(stream, "<void>");
307
308	case ARGTYPE_SHORT:
309	case ARGTYPE_INT:
310	case ARGTYPE_LONG:
311		return format_integer(stream, value, int_fmt, arguments);
312
313	case ARGTYPE_USHORT:
314	case ARGTYPE_UINT:
315	case ARGTYPE_ULONG:
316		if (int_fmt == INT_FMT_i)
317			int_fmt = INT_FMT_u;
318		return format_integer(stream, value, int_fmt, arguments);
319
320	case ARGTYPE_CHAR:
321		return format_naked_char(stream, value, arguments);
322
323	case ARGTYPE_FLOAT:
324	case ARGTYPE_DOUBLE:
325		return format_floating(stream, value, arguments);
326
327	case ARGTYPE_STRUCT:
328		return format_struct(stream, value, arguments);
329
330	case ARGTYPE_POINTER:
331		if (value->type->u.array_info.elt_type->type != ARGTYPE_VOID)
332			return format_pointer(stream, value, arguments);
333		return format_integer(stream, value, INT_FMT_x, arguments);
334
335	case ARGTYPE_ARRAY:
336		return format_array(stream, value, arguments,
337				    value->type->u.array_info.length,
338				    options.arraylen, 1, "[ ", " ]", ", ");
339	}
340	abort();
341}
342
343static int
344default_lens_format_cb(struct lens *lens, FILE *stream,
345		       struct value *value, struct value_dict *arguments)
346{
347	return toplevel_format_lens(lens, stream, value, arguments, INT_FMT_i);
348}
349
350struct lens default_lens = {
351	.format_cb = default_lens_format_cb,
352};
353
354
355static int
356blind_lens_format_cb(struct lens *lens, FILE *stream,
357		     struct value *value, struct value_dict *arguments)
358{
359	return 0;
360}
361
362struct lens blind_lens = {
363	.format_cb = blind_lens_format_cb,
364};
365
366
367static int
368octal_lens_format_cb(struct lens *lens, FILE *stream,
369		     struct value *value, struct value_dict *arguments)
370{
371	return toplevel_format_lens(lens, stream, value, arguments, INT_FMT_o);
372}
373
374struct lens octal_lens = {
375	.format_cb = octal_lens_format_cb,
376};
377
378
379static int
380hex_lens_format_cb(struct lens *lens, FILE *stream,
381		   struct value *value, struct value_dict *arguments)
382{
383	return toplevel_format_lens(lens, stream, value, arguments, INT_FMT_x);
384}
385
386struct lens hex_lens = {
387	.format_cb = hex_lens_format_cb,
388};
389
390
391static int
392guess_lens_format_cb(struct lens *lens, FILE *stream,
393		     struct value *value, struct value_dict *arguments)
394{
395	return toplevel_format_lens(lens, stream, value, arguments,
396				    INT_FMT_unknown);
397}
398
399struct lens guess_lens = {
400	.format_cb = guess_lens_format_cb,
401};
402
403
404static int
405bool_lens_format_cb(struct lens *lens, FILE *stream,
406		    struct value *value, struct value_dict *arguments)
407{
408	switch (value->type->type) {
409	case ARGTYPE_VOID:
410	case ARGTYPE_FLOAT:
411	case ARGTYPE_DOUBLE:
412	case ARGTYPE_STRUCT:
413	case ARGTYPE_POINTER:
414	case ARGTYPE_ARRAY:
415		return toplevel_format_lens(lens, stream, value,
416					    arguments, INT_FMT_i);
417
418		int zero;
419	case ARGTYPE_SHORT:
420	case ARGTYPE_INT:
421	case ARGTYPE_LONG:
422	case ARGTYPE_USHORT:
423	case ARGTYPE_UINT:
424	case ARGTYPE_ULONG:
425	case ARGTYPE_CHAR:
426		if ((zero = value_is_zero(value, arguments)) < 0)
427			return -1;
428		if (zero)
429			return fprintf(stream, "false");
430		else
431			return fprintf(stream, "true");
432	}
433	abort();
434}
435
436struct lens bool_lens = {
437	.format_cb = bool_lens_format_cb,
438};
439
440
441static int
442string_lens_format_cb(struct lens *lens, FILE *stream,
443		      struct value *value, struct value_dict *arguments)
444{
445	switch (value->type->type) {
446	case ARGTYPE_POINTER:
447		/* This should really be written as either "string",
448		 * or, if lens, then string(array(char, zero)*).  But
449		 * I suspect people are so used to the char * C idiom,
450		 * that string(char *) might actually turn up.  So
451		 * let's just support it.  */
452		if (value->type->u.ptr_info.info->type == ARGTYPE_CHAR) {
453			struct arg_type_info info[2];
454			type_init_array(&info[1],
455					value->type->u.ptr_info.info, 0,
456					expr_node_zero(), 0);
457			type_init_pointer(&info[0], &info[1], 0);
458			info->lens = lens;
459			info->own_lens = 0;
460			struct value tmp;
461			if (value_clone(&tmp, value) < 0)
462				return -1;
463			value_set_type(&tmp, info, 0);
464			int ret = string_lens_format_cb(lens, stream, &tmp,
465							arguments);
466			type_destroy(&info[0]);
467			type_destroy(&info[1]);
468			value_destroy(&tmp);
469			return ret;
470		}
471
472		/* fall-through */
473	case ARGTYPE_VOID:
474	case ARGTYPE_FLOAT:
475	case ARGTYPE_DOUBLE:
476	case ARGTYPE_STRUCT:
477	case ARGTYPE_SHORT:
478	case ARGTYPE_INT:
479	case ARGTYPE_LONG:
480	case ARGTYPE_USHORT:
481	case ARGTYPE_UINT:
482	case ARGTYPE_ULONG:
483		return toplevel_format_lens(lens, stream, value,
484					    arguments, INT_FMT_i);
485
486	case ARGTYPE_CHAR:
487		return format_char(stream, value, arguments);
488
489	case ARGTYPE_ARRAY:
490		return format_array(stream, value, arguments,
491				    value->type->u.array_info.length,
492				    options.strlen, 0, "\"", "\"", "");
493	}
494	abort();
495}
496
497struct lens string_lens = {
498	.format_cb = string_lens_format_cb,
499};
500