printf.c revision 84c86d73716b1e785f2690918403d7094393e1f3
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 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. */ 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 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; 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 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; 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 342static enum param_status 343param_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 352static void 353param_printf_done(struct param_enum *context) 354{ 355 value_destroy(&context->array); 356 free(context); 357} 358 359void 360param_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 ¶m_printf_init, ¶m_printf_next, 364 ¶m_printf_stop, ¶m_printf_done); 365} 366