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