blob: 52b212cd16a00896325174c8c3c8aa84036c65ee [file] [log] [blame]
Petr Machata940ec062012-01-06 22:43:51 +01001/*
2 * This file is part of ltrace.
Petr Machata0441baf2013-01-09 16:22:14 +01003 * Copyright (C) 2011,2012,2013 Petr Machata, Red Hat Inc.
Petr Machata940ec062012-01-06 22:43:51 +01004 * 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);
Petr Machata43417842012-10-29 17:59:17 +010070 if (self->format == NULL) {
71 value_destroy(&self->array);
Petr Machata940ec062012-01-06 22:43:51 +010072 goto fail;
Petr Machata43417842012-10-29 17:59:17 +010073 }
Petr Machata940ec062012-01-06 22:43:51 +010074
75 size_t size = value_size(&self->array, arguments);
Petr Machata43417842012-10-29 17:59:17 +010076 if (size == (size_t)-1) {
77 value_destroy(&self->array);
Petr Machata940ec062012-01-06 22:43:51 +010078 goto fail;
Petr Machata43417842012-10-29 17:59:17 +010079 }
Petr Machata940ec062012-01-06 22:43:51 +010080
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;
Petr Machatab7819162012-01-09 04:26:15 +0100115 if (format_type == ARGTYPE_ARRAY || format_type == ARGTYPE_POINTER)
Petr Machata940ec062012-01-06 22:43:51 +0100116 elt_info = type_get_simple(elt_type);
Petr Machatab7819162012-01-09 04:26:15 +0100117 else if (format_type == ARGTYPE_INT)
Petr Machata940ec062012-01-06 22:43:51 +0100118 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) {
Petr Machata84c86d72012-10-30 00:28:44 +0100124 struct arg_type_info *array = malloc(sizeof(*array));
125 if (array == NULL)
126 return -1;
127
Petr Machata940ec062012-01-06 22:43:51 +0100128 struct expr_node *node = NULL;
Petr Machata58e75f52012-10-30 00:22:46 +0100129 int own_node;
Petr Machata940ec062012-01-06 22:43:51 +0100130 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);
Petr Machata84c86d72012-10-30 00:28:44 +0100140 free(array);
Petr Machata940ec062012-01-06 22:43:51 +0100141 return -1;
142 }
143
Petr Machata16804482012-10-30 00:19:36 +0100144 len->type = *type_get_simple(ARGTYPE_LONG);
Petr Machata940ec062012-01-06 22:43:51 +0100145
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;
Petr Machata58e75f52012-10-30 00:22:46 +0100159 own_node = 1;
Petr Machata940ec062012-01-06 22:43:51 +0100160
161 } else {
162 node = expr_node_zero();
Petr Machata58e75f52012-10-30 00:22:46 +0100163 own_node = 0;
Petr Machata940ec062012-01-06 22:43:51 +0100164 }
Petr Machata940ec062012-01-06 22:43:51 +0100165 assert(node != NULL);
Petr Machata940ec062012-01-06 22:43:51 +0100166
Petr Machata84c86d72012-10-30 00:28:44 +0100167 type_init_array(array, elt_info, 0, node, own_node);
168 type_init_pointer(infop, array, 1);
169
Petr Machata940ec062012-01-06 22:43:51 +0100170 } else if (format_type == ARGTYPE_POINTER) {
Peter Wucae76962013-09-26 00:55:57 +0200171 type_init_pointer(infop, elt_info, 0);
Petr Machata940ec062012-01-06 22:43:51 +0100172
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;
Petr Machatab7819162012-01-09 04:26:15 +0100186 enum arg_type format_type = ARGTYPE_VOID;
187 enum arg_type elt_type = ARGTYPE_VOID;
Petr Machata940ec062012-01-06 22:43:51 +0100188 char len_buf[25] = {};
189 size_t len_buf_len = 0;
Petr Machata31af32c2012-01-08 02:36:50 +0100190 struct lens *lens = NULL;
Petr Machata940ec062012-01-06 22:43:51 +0100191
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
Petr Machata940ec062012-01-06 22:43:51 +0100267 case 'o':
Petr Machatac70b1952012-04-27 21:00:26 +0200268 lens = &octal_lens;
269 goto uint;
270
Petr Machata940ec062012-01-06 22:43:51 +0100271 case 'x': case 'X':
Petr Machatac70b1952012-04-27 21:00:26 +0200272 lens = &hex_lens;
Petr Machata0441baf2013-01-09 16:22:14 +0100273 /* Fall through. */
Petr Machatac70b1952012-04-27 21:00:26 +0200274 case 'u':
275 uint:
Petr Machata940ec062012-01-06 22:43:51 +0100276 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;
Petr Machatae3f4a982012-01-09 04:27:26 +0100305 lens = &string_lens;
Petr Machata940ec062012-01-06 22:43:51 +0100306 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. */
Petr Machatab7819162012-01-09 04:26:15 +0100327 assert(format_type != ARGTYPE_VOID);
Petr Machata940ec062012-01-06 22:43:51 +0100328
329 if (form_next_param(self, format_type, elt_type, hlf, lng,
330 len_buf, len_buf_len, infop) < 0)
331 return -1;
332
Petr Machata31af32c2012-01-08 02:36:50 +0100333 infop->lens = lens;
334 infop->own_lens = 0;
335
Petr Machata940ec062012-01-06 22:43:51 +0100336 return 0;
337 }
338
Petr Machata16804482012-10-30 00:19:36 +0100339 *infop = *type_get_simple(ARGTYPE_VOID);
Petr Machata940ec062012-01-06 22:43:51 +0100340 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{
Petr Machata43417842012-10-29 17:59:17 +0100356 value_destroy(&context->array);
Petr Machata940ec062012-01-06 22:43:51 +0100357 free(context);
358}
359
360void
361param_pack_init_printf(struct param *param, struct expr_node *arg, int own_arg)
362{
Petr Machatae36298a2012-09-13 17:12:41 +0200363 param_init_pack(param, PARAM_PACK_VARARGS, arg, 1, own_arg,
Petr Machata940ec062012-01-06 22:43:51 +0100364 &param_printf_init, &param_printf_next,
365 &param_printf_stop, &param_printf_done);
366}