blob: 1fe3025279d92d08762353c239b69e368a5eac6b [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"
Petr Machatae3f4a982012-01-09 04:27:26 +010033#include "lens_default.h"
Petr Machata940ec062012-01-06 22:43:51 +010034
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. */
Petr Machatae3f4a982012-01-09 04:27:26 +010051 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))
Petr Machata940ec062012-01-06 22:43:51 +010055 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
Petr Machatae3f4a982012-01-09 04:27:26 +010064 if (value_init_deref(&self->array, cb_args) < 0)
Petr Machata940ec062012-01-06 22:43:51 +010065 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;
Petr Machatab7819162012-01-09 04:26:15 +0100111 if (format_type == ARGTYPE_ARRAY || format_type == ARGTYPE_POINTER)
Petr Machata940ec062012-01-06 22:43:51 +0100112 elt_info = type_get_simple(elt_type);
Petr Machatab7819162012-01-09 04:26:15 +0100113 else if (format_type == ARGTYPE_INT)
Petr Machata940ec062012-01-06 22:43:51 +0100114 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;
Petr Machatab7819162012-01-09 04:26:15 +0100173 enum arg_type format_type = ARGTYPE_VOID;
174 enum arg_type elt_type = ARGTYPE_VOID;
Petr Machata940ec062012-01-06 22:43:51 +0100175 char len_buf[25] = {};
176 size_t len_buf_len = 0;
Petr Machata31af32c2012-01-08 02:36:50 +0100177 struct lens *lens = NULL;
Petr Machata940ec062012-01-06 22:43:51 +0100178
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
Petr Machata940ec062012-01-06 22:43:51 +0100254 case 'o':
Petr Machatac70b1952012-04-27 21:00:26 +0200255 lens = &octal_lens;
256 goto uint;
257
Petr Machata940ec062012-01-06 22:43:51 +0100258 case 'x': case 'X':
Petr Machatac70b1952012-04-27 21:00:26 +0200259 lens = &hex_lens;
260 case 'u':
261 uint:
Petr Machata940ec062012-01-06 22:43:51 +0100262 format_type = ARGTYPE_UINT;
263 self->percent = 0;
264 break;
265
266 case 'e': case 'E':
267 case 'f': case 'F':
268 case 'g': case 'G':
269 case 'a': case 'A':
270 format_type = ARGTYPE_DOUBLE;
271 self->percent = 0;
272 break;
273
274 case 'C': /* like "lc" */
275 if (lng == 0)
276 lng++;
277 case 'c':
278 /* XXX "lc" means wchar_t string. */
279 format_type = ARGTYPE_CHAR;
280 self->percent = 0;
281 break;
282
283 case 'S': /* like "ls" */
284 if (lng == 0)
285 lng++;
286 case 's':
287 format_type = ARGTYPE_ARRAY;
288 /* XXX "ls" means wchar_t string. */
289 elt_type = ARGTYPE_CHAR;
290 self->percent = 0;
Petr Machatae3f4a982012-01-09 04:27:26 +0100291 lens = &string_lens;
Petr Machata940ec062012-01-06 22:43:51 +0100292 break;
293
294 case 'p':
295 case 'n': /* int* where to store no. of printed chars. */
296 format_type = ARGTYPE_POINTER;
297 elt_type = ARGTYPE_VOID;
298 self->percent = 0;
299 break;
300
301 case 'm': /* (glibc) print argument of errno */
302 case '%':
303 lng = 0;
304 hlf = 0;
305 self->percent = 0;
306 continue;
307
308 default:
309 continue;
310 }
311
312 /* If we got here, the type must have been set. */
Petr Machatab7819162012-01-09 04:26:15 +0100313 assert(format_type != ARGTYPE_VOID);
Petr Machata940ec062012-01-06 22:43:51 +0100314
315 if (form_next_param(self, format_type, elt_type, hlf, lng,
316 len_buf, len_buf_len, infop) < 0)
317 return -1;
318
Petr Machata31af32c2012-01-08 02:36:50 +0100319 infop->lens = lens;
320 infop->own_lens = 0;
321
Petr Machata940ec062012-01-06 22:43:51 +0100322 return 0;
323 }
324
325 infop->type = ARGTYPE_VOID;
326 return 0;
327}
328
329static enum param_status
330param_printf_stop(struct param_enum *self, struct value *value)
331{
332 if (self->future_length != NULL
333 && value_extract_word(value, (long *)self->future_length, NULL) < 0)
334 drop_future_length(self);
335
336 return PPCB_CONT;
337}
338
339static void
340param_printf_done(struct param_enum *context)
341{
342 free(context);
343}
344
345void
346param_pack_init_printf(struct param *param, struct expr_node *arg, int own_arg)
347{
348 param_init_pack(param, arg, 1, own_arg,
349 &param_printf_init, &param_printf_next,
350 &param_printf_stop, &param_printf_done);
351}