printf.c revision e3f4a984db115979e09414b7281da98399dd8949
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 Steve Fink
6 * Copyright (C) 2006 Ian Wienand
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 <assert.h>
25#include <stdlib.h>
26
27#include "printf.h"
28#include "type.h"
29#include "value.h"
30#include "expr.h"
31#include "zero.h"
32#include "param.h"
33#include "lens_default.h"
34
35struct param_enum {
36	struct value array;
37	int percent;
38	size_t *future_length;
39	char *format;
40	char const *ptr;
41	char const *end;
42};
43
44static struct param_enum *
45param_printf_init(struct value *cb_args, size_t nargs,
46		  struct value_dict *arguments)
47{
48	assert(nargs == 1);
49
50	/* We expect a char array pointer.  */
51	if (cb_args->type->type != ARGTYPE_POINTER
52	    || cb_args->type->u.ptr_info.info->type != ARGTYPE_ARRAY
53	    || (cb_args->type->u.ptr_info.info->u.array_info.elt_type->type
54		!= ARGTYPE_CHAR))
55		return NULL;
56
57	struct param_enum *self = malloc(sizeof(*self));
58	if (self == NULL) {
59	fail:
60		free(self);
61		return NULL;
62	}
63
64	if (value_init_deref(&self->array, cb_args) < 0)
65		goto fail;
66
67	assert(self->array.type->type == ARGTYPE_ARRAY);
68
69	self->format = (char *)value_get_data(&self->array, arguments);
70	if (self->format == NULL)
71		goto fail;
72
73	size_t size = value_size(&self->array, arguments);
74	if (size == (size_t)-1)
75		goto fail;
76
77	self->percent = 0;
78	self->ptr = self->format;
79	self->end = self->format + size;
80	self->future_length = NULL;
81	return self;
82}
83
84static void
85drop_future_length(struct param_enum *self)
86{
87	if (self->future_length != NULL) {
88		free(self->future_length);
89		self->future_length = NULL;
90	}
91}
92
93static int
94form_next_param(struct param_enum *self,
95		enum arg_type format_type, enum arg_type elt_type,
96		unsigned hlf, unsigned lng, char *len_buf, size_t len_buf_len,
97		struct arg_type_info *infop)
98{
99	/* XXX note: Some types are wrong because we lack
100	   ARGTYPE_LONGLONG, ARGTYPE_UCHAR and ARGTYPE_SCHAR.  */
101	assert(lng <= 2);
102	assert(hlf <= 2);
103	static enum arg_type ints[] =
104		{ ARGTYPE_CHAR, ARGTYPE_SHORT, ARGTYPE_INT,
105		  ARGTYPE_LONG, ARGTYPE_ULONG };
106	static enum arg_type uints[] =
107		{ ARGTYPE_CHAR, ARGTYPE_USHORT, ARGTYPE_UINT,
108		  ARGTYPE_ULONG, ARGTYPE_ULONG };
109
110	struct arg_type_info *elt_info = NULL;
111	if (format_type == ARGTYPE_ARRAY || format_type == ARGTYPE_POINTER)
112		elt_info = type_get_simple(elt_type);
113	else if (format_type == ARGTYPE_INT)
114		format_type = ints[2 + lng - hlf];
115	else if (format_type == ARGTYPE_UINT)
116		format_type = uints[2 + lng - hlf];
117
118
119	if (format_type == ARGTYPE_ARRAY) {
120		struct expr_node *node = NULL;
121		if (len_buf_len != 0
122		    || self->future_length != NULL) {
123			struct tmp {
124				struct expr_node node;
125				struct arg_type_info type;
126			};
127			struct tmp *len = malloc(sizeof(*len));
128			if (len == NULL) {
129			fail:
130				free(len);
131				return -1;
132			}
133
134			len->type.type = ARGTYPE_LONG;
135
136			long l;
137			if (self->future_length != NULL) {
138				l = *self->future_length;
139				drop_future_length(self);
140			} else {
141				l = atol(len_buf);
142			}
143
144			expr_init_const_word(&len->node, l, &len->type, 0);
145
146			node = build_zero_w_arg(&len->node, 1);
147			if (node == NULL)
148				goto fail;
149
150		} else {
151			node = expr_node_zero();
152		}
153
154		assert(node != NULL);
155		type_init_array(infop, elt_info, 0, node, 1);
156
157	} else if (format_type == ARGTYPE_POINTER) {
158		type_init_pointer(infop, elt_info, 1);
159
160	} else {
161		*infop = *type_get_simple(format_type);
162	}
163
164	return 0;
165}
166
167static int
168param_printf_next(struct param_enum *self, struct arg_type_info *infop,
169		  int *insert_stop)
170{
171	unsigned hlf = 0;
172	unsigned lng = 0;
173	enum arg_type format_type = ARGTYPE_VOID;
174	enum arg_type elt_type = ARGTYPE_VOID;
175	char len_buf[25] = {};
176	size_t len_buf_len = 0;
177	struct lens *lens = NULL;
178
179	for (; self->ptr < self->end; ++self->ptr) {
180		if (!self->percent) {
181			if (*self->ptr == '%')
182				self->percent = 1;
183			continue;
184		}
185
186		switch (*self->ptr) {
187		case '#': case ' ': case '-':
188		case '+': case 'I': case '\'':
189			/* These are only important for formatting,
190			 * not for interpreting the type.  */
191			continue;
192
193		case '*':
194			/* Length parameter given in the next
195			 * argument.  */
196			if (self->future_length == NULL)
197				/* This should really be an assert,
198				 * but we can't just fail on invalid
199				 * format string.  */
200				self->future_length
201					= malloc(sizeof(*self->future_length));
202
203			if (self->future_length != NULL) {
204				++self->ptr;
205				format_type = ARGTYPE_INT;
206				break;
207			}
208
209		case '0':
210		case '1': case '2': case '3':
211		case '4': case '5': case '6':
212		case '7': case '8': case '9':
213			/* Field length likewise, but we need to parse
214			 * this to attach the appropriate string
215			 * length expression.  */
216			if (len_buf_len < sizeof(len_buf) - 1)
217				len_buf[len_buf_len++] = *self->ptr;
218			continue;
219
220		case 'h':
221			if (hlf < 2)
222				hlf++;
223			continue;
224
225		case 'l':
226			if (lng < 2)
227				lng++;
228			continue;
229
230		case 'q':
231			lng = 2;
232			continue;
233
234		case 'L': /* long double */
235			lng = 1;
236			continue;
237
238		case 'j': /* intmax_t */
239			/*   XXX ABI should know */
240			lng = 2;
241			continue;
242
243		case 't': /* ptrdiff_t */
244		case 'Z': case 'z': /* size_t */
245			lng = 1; /* XXX ABI should tell */
246			continue;
247
248		case 'd':
249		case 'i':
250			format_type = ARGTYPE_INT;
251			self->percent = 0;
252			break;
253
254		case 'u':
255		case 'o':
256		case 'x': case 'X':
257			format_type = ARGTYPE_UINT;
258			self->percent = 0;
259			break;
260
261		case 'e': case 'E':
262		case 'f': case 'F':
263		case 'g': case 'G':
264		case 'a': case 'A':
265			format_type = ARGTYPE_DOUBLE;
266			self->percent = 0;
267			break;
268
269		case 'C': /* like "lc" */
270			if (lng == 0)
271				lng++;
272		case 'c':
273			/* XXX "lc" means wchar_t string.  */
274			format_type = ARGTYPE_CHAR;
275			self->percent = 0;
276			break;
277
278		case 'S': /* like "ls" */
279			if (lng == 0)
280				lng++;
281		case 's':
282			format_type = ARGTYPE_ARRAY;
283			/* XXX "ls" means wchar_t string.  */
284			elt_type = ARGTYPE_CHAR;
285			self->percent = 0;
286			lens = &string_lens;
287			break;
288
289		case 'p':
290		case 'n': /* int* where to store no. of printed chars.  */
291			format_type = ARGTYPE_POINTER;
292			elt_type = ARGTYPE_VOID;
293			self->percent = 0;
294			break;
295
296		case 'm': /* (glibc) print argument of errno */
297		case '%':
298			lng = 0;
299			hlf = 0;
300			self->percent = 0;
301			continue;
302
303		default:
304			continue;
305		}
306
307		/* If we got here, the type must have been set.  */
308		assert(format_type != ARGTYPE_VOID);
309
310		if (form_next_param(self, format_type, elt_type, hlf, lng,
311				    len_buf, len_buf_len, infop) < 0)
312			return -1;
313
314		infop->lens = lens;
315		infop->own_lens = 0;
316
317		return 0;
318	}
319
320	infop->type = ARGTYPE_VOID;
321	return 0;
322}
323
324static enum param_status
325param_printf_stop(struct param_enum *self, struct value *value)
326{
327	if (self->future_length != NULL
328	    && value_extract_word(value, (long *)self->future_length, NULL) < 0)
329		drop_future_length(self);
330
331	return PPCB_CONT;
332}
333
334static void
335param_printf_done(struct param_enum *context)
336{
337	free(context);
338}
339
340void
341param_pack_init_printf(struct param *param, struct expr_node *arg, int own_arg)
342{
343	param_init_pack(param, arg, 1, own_arg,
344			&param_printf_init, &param_printf_next,
345			&param_printf_stop, &param_printf_done);
346}
347