printf.c revision 0441bafdfecfb9d475912d6ca6e4abe6a66664d6
1/* 2 * This file is part of ltrace. 3 * Copyright (C) 2011,2012,2013 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 /* Fall through. */ 274 case 'u': 275 uint: 276 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; 305 lens = &string_lens; 306 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. */ 327 assert(format_type != ARGTYPE_VOID); 328 329 if (form_next_param(self, format_type, elt_type, hlf, lng, 330 len_buf, len_buf_len, infop) < 0) 331 return -1; 332 333 infop->lens = lens; 334 infop->own_lens = 0; 335 336 return 0; 337 } 338 339 *infop = *type_get_simple(ARGTYPE_VOID); 340 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{ 356 value_destroy(&context->array); 357 free(context); 358} 359 360void 361param_pack_init_printf(struct param *param, struct expr_node *arg, int own_arg) 362{ 363 param_init_pack(param, PARAM_PACK_VARARGS, arg, 1, own_arg, 364 ¶m_printf_init, ¶m_printf_next, 365 ¶m_printf_stop, ¶m_printf_done); 366} 367