lens_default.c revision d8286ed3496bcd69cd4796f57a5b5c04859d2378
1/*
2 * This file is part of ltrace.
3 * Copyright (C) 2011,2012,2013 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#include <string.h>
31
32#include "bits.h"
33#include "proc.h"
34#include "lens_default.h"
35#include "value.h"
36#include "expr.h"
37#include "type.h"
38#include "common.h"
39#include "zero.h"
40
41#define READER(NAME, TYPE)						\
42	static int							\
43	NAME(struct value *value, TYPE *ret, struct value_dict *arguments) \
44	{								\
45		union {							\
46			TYPE val;					\
47			unsigned char buf[0];				\
48		} u;							\
49		if (value_extract_buf(value, u.buf, arguments) < 0)	\
50			return -1;					\
51		*ret = u.val;						\
52		return 0;						\
53	}
54
55READER(read_float, float)
56READER(read_double, double)
57
58#undef READER
59
60#define HANDLE_WIDTH(BITS)						\
61	do {								\
62		long l;							\
63		if (value_extract_word(value, &l, arguments) < 0)	\
64			return -1;					\
65		int##BITS##_t i = l;					\
66		uint64_t v = (uint64_t)(uint##BITS##_t)i;		\
67		switch (format) {					\
68		case INT_FMT_unknown:					\
69			if (l < -10000 || l > 10000)			\
70		case INT_FMT_x:						\
71			return fprintf(stream, "%#"PRIx64, v);		\
72		case INT_FMT_i:						\
73		case INT_FMT_default:					\
74			return fprintf(stream, "%"PRIi##BITS, i);	\
75		case INT_FMT_u:						\
76			return fprintf(stream, "%"PRIu64, v);		\
77		case INT_FMT_o:						\
78			return fprintf(stream, "0%"PRIo64, v);		\
79		}							\
80	} while (0)
81
82enum int_fmt_t
83{
84	INT_FMT_i,
85	INT_FMT_u,
86	INT_FMT_o,
87	INT_FMT_x,
88	INT_FMT_unknown,
89	INT_FMT_default,
90};
91
92static int
93format_integer(FILE *stream, struct value *value, enum int_fmt_t format,
94	       struct value_dict *arguments)
95{
96	switch (type_sizeof(value->inferior, value->type)) {
97
98	case 1: HANDLE_WIDTH(8);
99	case 2: HANDLE_WIDTH(16);
100	case 4: HANDLE_WIDTH(32);
101	case 8: HANDLE_WIDTH(64);
102
103	default:
104		assert(!"unsupported integer width");
105		abort();
106
107	case -1:
108		return -1;
109	}
110}
111
112#undef HANDLE_WIDTH
113
114static int
115acc_fprintf(int *countp, FILE *stream, const char *format, ...)
116{
117	va_list pa;
118	va_start(pa, format);
119	int i = account_output(countp, vfprintf(stream, format, pa));
120	va_end(pa);
121
122	return i;
123}
124
125static int
126format_char(FILE *stream, struct value *value, struct value_dict *arguments)
127{
128	long lc;
129	if (value_extract_word(value, &lc, arguments) < 0)
130		return -1;
131	int c = (int)lc;
132
133	const char *fmt;
134	switch (c) {
135	case -1:
136		fmt = "EOF";
137		break;
138	case 0:
139		fmt = "\\0";
140		break;
141	case '\a':
142		fmt = "\\a";
143		break;
144	case '\b':
145		fmt = "\\b";
146		break;
147	case '\t':
148		fmt = "\\t";
149		break;
150	case '\n':
151		fmt = "\\n";
152		break;
153	case '\v':
154		fmt = "\\v";
155		break;
156	case '\f':
157		fmt = "\\f";
158		break;
159	case '\r':
160		fmt = "\\r";
161		break;
162	case '\\':
163		fmt = "\\\\";
164		break;
165	default:
166		if (isprint(c) || c == ' ')
167			fmt = "%c";
168		else
169			fmt = "\\%03o";
170	}
171
172	return fprintf(stream, fmt, c);
173}
174
175static int
176format_naked_char(FILE *stream, struct value *value,
177		  struct value_dict *arguments)
178{
179	int written = 0;
180	if (acc_fprintf(&written, stream, "'") < 0
181	    || account_output(&written,
182			      format_char(stream, value, arguments)) < 0
183	    || acc_fprintf(&written, stream, "'") < 0)
184		return -1;
185
186	return written;
187}
188
189static int
190format_double(FILE *stream, double value, enum int_fmt_t format)
191{
192	if (format == INT_FMT_x)
193		return fprintf(stream, "%a", value);
194	else
195		return fprintf(stream, "%f", value);
196}
197
198static int
199format_floating(FILE *stream, struct value *value, struct value_dict *arguments,
200		enum int_fmt_t format)
201{
202	switch (value->type->type) {
203		float f;
204		double d;
205	case ARGTYPE_FLOAT:
206		if (read_float(value, &f, arguments) < 0)
207			return -1;
208		return format_double(stream, f, format);
209	case ARGTYPE_DOUBLE:
210		if (read_double(value, &d, arguments) < 0)
211			return -1;
212		return format_double(stream, d, format);
213	default:
214		abort();
215	}
216}
217
218struct format_argument_data
219{
220	struct value *value;
221	struct value_dict *arguments;
222};
223
224static int
225format_argument_cb(FILE *stream, void *ptr)
226{
227	struct format_argument_data *data = ptr;
228	return format_argument(stream, data->value, data->arguments);
229}
230
231static int
232format_struct(FILE *stream, struct value *value, struct value_dict *arguments)
233{
234	int written = 0;
235	if (acc_fprintf(&written, stream, "{ ") < 0)
236		return -1;
237
238	int need_delim = 0;
239	size_t i;
240	for (i = 0; i < type_struct_size(value->type); ++i) {
241		struct value element;
242		if (value_init_element(&element, value, i) < 0)
243			return -1;
244
245		struct format_argument_data data = { &element, arguments };
246		int o = delim_output(stream, &need_delim,
247				     format_argument_cb, &data);
248		value_destroy(&element);
249		if (o < 0)
250			return -1;
251
252		written += o;
253	}
254	if (acc_fprintf(&written, stream, " }") < 0)
255		return -1;
256	return written;
257}
258
259static const char null_message[] = "nil";
260int
261format_pointer(FILE *stream, struct value *value, struct value_dict *arguments)
262{
263	if (value_is_zero(value, arguments))
264		return fprintf(stream, null_message);
265
266	/* The following is for detecting recursion.  We keep track of
267	 * the values that were already displayed.  Each time a
268	 * pointer should be dereferenced, we compare its value to the
269	 * value of each of the pointers dereferenced so far.  If one
270	 * of them matches, instead of recursing, we just printf which
271	 * superstructure this pointer recurses to.  */
272	static struct vect pointers = {};
273	if (pointers.elt_size == 0)
274		VECT_INIT(&pointers, struct value *);
275
276	/* Trim number of expanded structures of the same type.  Even
277	 * for non-recursive structure, we don't want to expand all of
278	 * it if it's huge.  */
279	size_t i;
280	size_t len = vect_size(&pointers);
281	assert(value->type->type == ARGTYPE_POINTER);
282	struct arg_type_info *pointee = value->type->u.ptr_info.info;
283	if (pointee->type == ARGTYPE_STRUCT) {
284		size_t depth = 0;
285		for (i = 0; i < len; ++i) {
286			struct value *old
287				= *VECT_ELEMENT(&pointers, struct value *, i);
288			assert(old->type->type == ARGTYPE_POINTER);
289			struct arg_type_info *old_pointee
290				= old->type->u.ptr_info.info;
291			if (old_pointee == pointee)
292				depth++;
293		}
294		if (depth >= options.arraylen)
295			return fprintf(stream, "...");
296	}
297
298	for (i = len; i-- > 0 ;) {
299		struct value **old = VECT_ELEMENT(&pointers, struct value *, i);
300		int rc = value_equal(value, *old, arguments);
301		if (rc < 0)
302			return -1;
303		if (rc > 0) {
304			size_t reclevel = len - i - 1;
305			char buf[reclevel + 1];
306			memset(buf, '^', sizeof buf);
307			buf[reclevel] = 0;
308			return fprintf(stream, "recurse%s", buf);
309		}
310	}
311
312	/* OK, not a recursion.  Remember this value for tracking.  */
313	if (VECT_PUSHBACK(&pointers, &value) < 0)
314		return -1;
315
316	struct value element;
317	int o;
318	if (value_init_deref(&element, value) < 0) {
319		o = -1;
320		goto done;
321	}
322	o = format_argument(stream, &element, arguments);
323	value_destroy(&element);
324
325done:
326	VECT_POPBACK(&pointers, struct value *, NULL, NULL);
327	return o;
328}
329
330/*
331 * LENGTH is an expression whose evaluation will yield the actual
332 *    length of the array.
333 *
334 * MAXLEN is the actual maximum length that we care about
335 *
336 * BEFORE if LENGTH>MAXLEN, we display ellipsis.  We display it before
337 *    the closing parenthesis if BEFORE, otherwise after it.
338 *
339 * OPEN, CLOSE, DELIM are opening and closing parenthesis and element
340 *    delimiter.
341 */
342int
343format_array(FILE *stream, struct value *value, struct value_dict *arguments,
344	     struct expr_node *length, size_t maxlen, int before,
345	     const char *open, const char *close, const char *delim)
346{
347	/* We need "long" to be long enough to cover the whole address
348	 * space.  */
349	(void)sizeof(char[1 - 2*(sizeof(long) < sizeof(void *))]);
350	long l;
351	if (expr_eval_word(length, value, arguments, &l) < 0)
352		return -1;
353	size_t len = (size_t)l;
354
355	int written = 0;
356	if (acc_fprintf(&written, stream, "%s", open) < 0)
357		return -1;
358
359	size_t i;
360	for (i = 0; i < len && i <= maxlen; ++i) {
361		if (i == maxlen) {
362			if (before && acc_fprintf(&written, stream, "...") < 0)
363				return -1;
364			break;
365		}
366
367		if (i > 0 && acc_fprintf(&written, stream, "%s", delim) < 0)
368			return -1;
369
370		struct value element;
371		if (value_init_element(&element, value, i) < 0)
372			return -1;
373		int o = format_argument(stream, &element, arguments);
374		value_destroy(&element);
375		if (o < 0)
376			return -1;
377		written += o;
378	}
379	if (acc_fprintf(&written, stream, "%s", close) < 0)
380		return -1;
381	if (i == maxlen && !before && acc_fprintf(&written, stream, "...") < 0)
382		return -1;
383
384	return written;
385}
386
387static int
388toplevel_format_lens(struct lens *lens, FILE *stream,
389		     struct value *value, struct value_dict *arguments,
390		     enum int_fmt_t int_fmt)
391{
392	switch (value->type->type) {
393	case ARGTYPE_VOID:
394		return fprintf(stream, "<void>");
395
396	case ARGTYPE_SHORT:
397	case ARGTYPE_INT:
398	case ARGTYPE_LONG:
399		return format_integer(stream, value, int_fmt, arguments);
400
401	case ARGTYPE_USHORT:
402	case ARGTYPE_UINT:
403	case ARGTYPE_ULONG:
404		if (int_fmt == INT_FMT_i || int_fmt == INT_FMT_default)
405			int_fmt = INT_FMT_u;
406		return format_integer(stream, value, int_fmt, arguments);
407
408	case ARGTYPE_CHAR:
409		if (int_fmt == INT_FMT_default)
410			return format_naked_char(stream, value, arguments);
411		return format_integer(stream, value, int_fmt, arguments);
412
413	case ARGTYPE_FLOAT:
414	case ARGTYPE_DOUBLE:
415		return format_floating(stream, value, arguments, int_fmt);
416
417	case ARGTYPE_STRUCT:
418		return format_struct(stream, value, arguments);
419
420	case ARGTYPE_POINTER:
421		if (value_is_zero(value, arguments))
422			return fprintf(stream, null_message);
423		if (value->type->u.array_info.elt_type->type != ARGTYPE_VOID)
424			return format_pointer(stream, value, arguments);
425		return format_integer(stream, value, INT_FMT_x, arguments);
426
427	case ARGTYPE_ARRAY:
428		return format_array(stream, value, arguments,
429				    value->type->u.array_info.length,
430				    options.arraylen, 1, "[ ", " ]", ", ");
431	}
432	abort();
433}
434
435static int
436default_lens_format_cb(struct lens *lens, FILE *stream,
437		       struct value *value, struct value_dict *arguments)
438{
439	return toplevel_format_lens(lens, stream, value, arguments,
440				    INT_FMT_default);
441}
442
443struct lens default_lens = {
444	.format_cb = default_lens_format_cb,
445};
446
447
448static int
449blind_lens_format_cb(struct lens *lens, FILE *stream,
450		     struct value *value, struct value_dict *arguments)
451{
452	return 0;
453}
454
455struct lens blind_lens = {
456	.format_cb = blind_lens_format_cb,
457};
458
459
460static int
461octal_lens_format_cb(struct lens *lens, FILE *stream,
462		     struct value *value, struct value_dict *arguments)
463{
464	return toplevel_format_lens(lens, stream, value, arguments, INT_FMT_o);
465}
466
467struct lens octal_lens = {
468	.format_cb = octal_lens_format_cb,
469};
470
471
472static int
473hex_lens_format_cb(struct lens *lens, FILE *stream,
474		   struct value *value, struct value_dict *arguments)
475{
476	return toplevel_format_lens(lens, stream, value, arguments, INT_FMT_x);
477}
478
479struct lens hex_lens = {
480	.format_cb = hex_lens_format_cb,
481};
482
483
484static int
485dec_lens_format_cb(struct lens *lens, FILE *stream,
486		   struct value *value, struct value_dict *arguments)
487{
488	return toplevel_format_lens(lens, stream, value, arguments, INT_FMT_u);
489}
490
491struct lens dec_lens = {
492	.format_cb = dec_lens_format_cb,
493};
494
495
496static int
497guess_lens_format_cb(struct lens *lens, FILE *stream,
498		     struct value *value, struct value_dict *arguments)
499{
500	return toplevel_format_lens(lens, stream, value, arguments,
501				    INT_FMT_unknown);
502}
503
504struct lens guess_lens = {
505	.format_cb = guess_lens_format_cb,
506};
507
508
509static int
510bool_lens_format_cb(struct lens *lens, FILE *stream,
511		    struct value *value, struct value_dict *arguments)
512{
513	switch (value->type->type) {
514	case ARGTYPE_VOID:
515	case ARGTYPE_FLOAT:
516	case ARGTYPE_DOUBLE:
517	case ARGTYPE_STRUCT:
518	case ARGTYPE_POINTER:
519	case ARGTYPE_ARRAY:
520		return toplevel_format_lens(lens, stream, value,
521					    arguments, INT_FMT_default);
522
523		int zero;
524	case ARGTYPE_SHORT:
525	case ARGTYPE_INT:
526	case ARGTYPE_LONG:
527	case ARGTYPE_USHORT:
528	case ARGTYPE_UINT:
529	case ARGTYPE_ULONG:
530	case ARGTYPE_CHAR:
531		if ((zero = value_is_zero(value, arguments)) < 0)
532			return -1;
533		if (zero)
534			return fprintf(stream, "false");
535		else
536			return fprintf(stream, "true");
537	}
538	abort();
539}
540
541struct lens bool_lens = {
542	.format_cb = bool_lens_format_cb,
543};
544
545
546static int
547string_lens_format_cb(struct lens *lens, FILE *stream,
548		      struct value *value, struct value_dict *arguments)
549{
550	switch (value->type->type) {
551	case ARGTYPE_POINTER:
552		/* This should really be written as either "string",
553		 * or, if lens, then string(array(char, zero)*).  But
554		 * I suspect people are so used to the char * C idiom,
555		 * that string(char *) might actually turn up.  So
556		 * let's just support it.  */
557		if (value->type->u.ptr_info.info->type == ARGTYPE_CHAR) {
558			struct arg_type_info info[2];
559			type_init_array(&info[1],
560					value->type->u.ptr_info.info, 0,
561					expr_node_zero(), 0);
562			type_init_pointer(&info[0], &info[1], 0);
563			info->lens = lens;
564			info->own_lens = 0;
565			struct value tmp;
566			if (value_clone(&tmp, value) < 0)
567				return -1;
568			value_set_type(&tmp, info, 0);
569			int ret = string_lens_format_cb(lens, stream, &tmp,
570							arguments);
571			type_destroy(&info[0]);
572			type_destroy(&info[1]);
573			value_destroy(&tmp);
574			return ret;
575		}
576
577		/* fall-through */
578	case ARGTYPE_VOID:
579	case ARGTYPE_FLOAT:
580	case ARGTYPE_DOUBLE:
581	case ARGTYPE_STRUCT:
582	case ARGTYPE_SHORT:
583	case ARGTYPE_INT:
584	case ARGTYPE_LONG:
585	case ARGTYPE_USHORT:
586	case ARGTYPE_UINT:
587	case ARGTYPE_ULONG:
588		return toplevel_format_lens(lens, stream, value,
589					    arguments, INT_FMT_default);
590
591	case ARGTYPE_CHAR:
592		return format_char(stream, value, arguments);
593
594	case ARGTYPE_ARRAY:
595		return format_array(stream, value, arguments,
596				    value->type->u.array_info.length,
597				    options.strlen, 0, "\"", "\"", "");
598	}
599	abort();
600}
601
602struct lens string_lens = {
603	.format_cb = string_lens_format_cb,
604};
605
606static int
607out_bits(FILE *stream, size_t low, size_t high)
608{
609	if (low == high)
610		return fprintf(stream, "%zd", low);
611	else
612		return fprintf(stream, "%zd-%zd", low, high);
613}
614
615static int
616bitvect_lens_format_cb(struct lens *lens, FILE *stream,
617		       struct value *value, struct value_dict *arguments)
618{
619	unsigned char *data = value_get_data(value, arguments);
620	if (data == NULL)
621		return -1;
622	size_t sz = type_sizeof(value->inferior, value->type);
623	if (sz == (size_t)-1)
624		return -1;
625
626	size_t i;
627	unsigned char buf[sz];
628	switch ((int)value->type->type) {
629		union bitvect_integral_64
630		{
631			uint8_t u8;
632			uint16_t u16;
633			uint32_t u32;
634			uint64_t u64;
635			unsigned char buf[0];
636		} bv;
637
638	case ARGTYPE_POINTER:
639		return format_pointer(stream, value, arguments);
640
641	case ARGTYPE_STRUCT:
642	case ARGTYPE_ARRAY:
643		break;
644
645	default:
646		assert(sz <= sizeof(bv));
647		memmove(bv.buf, data, sz);
648
649		if (sz == 1)
650			bv.u64 = bv.u8;
651		else if (sz == 2)
652			bv.u64 = bv.u16;
653		else if (sz == 4)
654			bv.u64 = bv.u32;
655
656		for (i = 0; i < sz; ++i) {
657			buf[i] = bv.u64 & 0xff;
658			bv.u64 >>= 8;
659		}
660		data = buf;
661	}
662
663	size_t bits = 0;
664	for (i = 0; i < sz; ++i)
665		bits += bitcount(data[i]);
666
667	/* If there's more 1's than 0's, show inverse.  */
668	unsigned neg = bits > sz * 4 ? 0xff : 0x00;
669
670	int o = 0;
671	if (acc_fprintf(&o, stream, "%s<", &"~"[neg == 0x00]) < 0)
672		return -1;
673
674	size_t bitno = 0;
675	ssize_t low = -1;
676	for (i = 0; i < sz; ++i) {
677		unsigned char m;
678		unsigned char d = data[i] ^ neg;
679		for (m = 0x01; m != 0; m <<= 1) {
680			int bit = !!(m & d);
681			if (low < 0) {
682				if (bit) {
683					if (low == -2
684					    && acc_fprintf(&o, stream, ",") < 0)
685						return -1;
686					low = bitno;
687				}
688			} else if (!bit) {
689				if (account_output(&o, out_bits(stream, low,
690								bitno-1)) < 0)
691					return -1;
692				low = -2;
693			}
694			bitno++;
695		}
696	}
697	if (low >= 0 && account_output(&o, out_bits(stream, low, bitno-1)) < 0)
698		return -1;
699
700	if (fputc('>', stream) < 0)
701		return -1;
702	o += 1;
703
704	return o;
705}
706
707struct lens bitvect_lens = {
708	.format_cb = bitvect_lens_format_cb,
709};
710