blob: 34d28134fef7d69ead7ed879b191ab7c958aae21 [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;
Petr Machata31af32c2012-01-08 02:36:50 +0100189 struct lens *lens = NULL;
Petr Machata940ec062012-01-06 22:43:51 +0100190
191 for (; self->ptr < self->end; ++self->ptr) {
192 if (!self->percent) {
193 if (*self->ptr == '%')
194 self->percent = 1;
195 continue;
196 }
197
198 switch (*self->ptr) {
199 case '#': case ' ': case '-':
200 case '+': case 'I': case '\'':
201 /* These are only important for formatting,
202 * not for interpreting the type. */
203 continue;
204
205 case '*':
206 /* Length parameter given in the next
207 * argument. */
208 if (self->future_length == NULL)
209 /* This should really be an assert,
210 * but we can't just fail on invalid
211 * format string. */
212 self->future_length
213 = malloc(sizeof(*self->future_length));
214
215 if (self->future_length != NULL) {
216 ++self->ptr;
217 format_type = ARGTYPE_INT;
218 break;
219 }
220
221 case '0':
222 case '1': case '2': case '3':
223 case '4': case '5': case '6':
224 case '7': case '8': case '9':
225 /* Field length likewise, but we need to parse
226 * this to attach the appropriate string
227 * length expression. */
228 if (len_buf_len < sizeof(len_buf) - 1)
229 len_buf[len_buf_len++] = *self->ptr;
230 continue;
231
232 case 'h':
233 if (hlf < 2)
234 hlf++;
235 continue;
236
237 case 'l':
238 if (lng < 2)
239 lng++;
240 continue;
241
242 case 'q':
243 lng = 2;
244 continue;
245
246 case 'L': /* long double */
247 lng = 1;
248 continue;
249
250 case 'j': /* intmax_t */
251 /* XXX ABI should know */
252 lng = 2;
253 continue;
254
255 case 't': /* ptrdiff_t */
256 case 'Z': case 'z': /* size_t */
257 lng = 1; /* XXX ABI should tell */
258 continue;
259
260 case 'd':
261 case 'i':
262 format_type = ARGTYPE_INT;
263 self->percent = 0;
264 break;
265
266 case 'u':
267 case 'o':
268 case 'x': case 'X':
269 format_type = ARGTYPE_UINT;
270 self->percent = 0;
271 break;
272
273 case 'e': case 'E':
274 case 'f': case 'F':
275 case 'g': case 'G':
276 case 'a': case 'A':
277 format_type = ARGTYPE_DOUBLE;
278 self->percent = 0;
279 break;
280
281 case 'C': /* like "lc" */
282 if (lng == 0)
283 lng++;
284 case 'c':
285 /* XXX "lc" means wchar_t string. */
286 format_type = ARGTYPE_CHAR;
287 self->percent = 0;
288 break;
289
290 case 'S': /* like "ls" */
291 if (lng == 0)
292 lng++;
293 case 's':
294 format_type = ARGTYPE_ARRAY;
295 /* XXX "ls" means wchar_t string. */
296 elt_type = ARGTYPE_CHAR;
297 self->percent = 0;
298 break;
299
300 case 'p':
301 case 'n': /* int* where to store no. of printed chars. */
302 format_type = ARGTYPE_POINTER;
303 elt_type = ARGTYPE_VOID;
304 self->percent = 0;
305 break;
306
307 case 'm': /* (glibc) print argument of errno */
308 case '%':
309 lng = 0;
310 hlf = 0;
311 self->percent = 0;
312 continue;
313
314 default:
315 continue;
316 }
317
318 /* If we got here, the type must have been set. */
319 assert(format_type != ARGTYPE_UNKNOWN);
320
321 if (form_next_param(self, format_type, elt_type, hlf, lng,
322 len_buf, len_buf_len, infop) < 0)
323 return -1;
324
Petr Machata31af32c2012-01-08 02:36:50 +0100325 infop->lens = lens;
326 infop->own_lens = 0;
327
Petr Machata940ec062012-01-06 22:43:51 +0100328 return 0;
329 }
330
331 infop->type = ARGTYPE_VOID;
332 return 0;
333}
334
335static enum param_status
336param_printf_stop(struct param_enum *self, struct value *value)
337{
338 if (self->future_length != NULL
339 && value_extract_word(value, (long *)self->future_length, NULL) < 0)
340 drop_future_length(self);
341
342 return PPCB_CONT;
343}
344
345static void
346param_printf_done(struct param_enum *context)
347{
348 free(context);
349}
350
351void
352param_pack_init_printf(struct param *param, struct expr_node *arg, int own_arg)
353{
354 param_init_pack(param, arg, 1, own_arg,
355 &param_printf_init, &param_printf_next,
356 &param_printf_stop, &param_printf_done);
357}