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