Imported Upstream version 0.7.2
[platform/upstream/ltrace.git] / printf.c
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
35 struct 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
44 static struct param_enum *
45 param_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
88 static void
89 drop_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
97 static int
98 form_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
180 static int
181 param_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                 case 'u':
274                 uint:
275                         format_type = ARGTYPE_UINT;
276                         self->percent = 0;
277                         break;
278
279                 case 'e': case 'E':
280                 case 'f': case 'F':
281                 case 'g': case 'G':
282                 case 'a': case 'A':
283                         format_type = ARGTYPE_DOUBLE;
284                         self->percent = 0;
285                         break;
286
287                 case 'C': /* like "lc" */
288                         if (lng == 0)
289                                 lng++;
290                 case 'c':
291                         /* XXX "lc" means wchar_t string.  */
292                         format_type = ARGTYPE_CHAR;
293                         self->percent = 0;
294                         break;
295
296                 case 'S': /* like "ls" */
297                         if (lng == 0)
298                                 lng++;
299                 case 's':
300                         format_type = ARGTYPE_ARRAY;
301                         /* XXX "ls" means wchar_t string.  */
302                         elt_type = ARGTYPE_CHAR;
303                         self->percent = 0;
304                         lens = &string_lens;
305                         break;
306
307                 case 'p':
308                 case 'n': /* int* where to store no. of printed chars.  */
309                         format_type = ARGTYPE_POINTER;
310                         elt_type = ARGTYPE_VOID;
311                         self->percent = 0;
312                         break;
313
314                 case 'm': /* (glibc) print argument of errno */
315                 case '%':
316                         lng = 0;
317                         hlf = 0;
318                         self->percent = 0;
319                         continue;
320
321                 default:
322                         continue;
323                 }
324
325                 /* If we got here, the type must have been set.  */
326                 assert(format_type != ARGTYPE_VOID);
327
328                 if (form_next_param(self, format_type, elt_type, hlf, lng,
329                                     len_buf, len_buf_len, infop) < 0)
330                         return -1;
331
332                 infop->lens = lens;
333                 infop->own_lens = 0;
334
335                 return 0;
336         }
337
338         *infop = *type_get_simple(ARGTYPE_VOID);
339         return 0;
340 }
341
342 static enum param_status
343 param_printf_stop(struct param_enum *self, struct value *value)
344 {
345         if (self->future_length != NULL
346             && value_extract_word(value, (long *)self->future_length, NULL) < 0)
347                 drop_future_length(self);
348
349         return PPCB_CONT;
350 }
351
352 static void
353 param_printf_done(struct param_enum *context)
354 {
355         value_destroy(&context->array);
356         free(context);
357 }
358
359 void
360 param_pack_init_printf(struct param *param, struct expr_node *arg, int own_arg)
361 {
362         param_init_pack(param, PARAM_PACK_VARARGS, arg, 1, own_arg,
363                         &param_printf_init, &param_printf_next,
364                         &param_printf_stop, &param_printf_done);
365 }