diff options
Diffstat (limited to 'printf.c')
-rw-r--r-- | printf.c | 66 |
1 files changed, 52 insertions, 14 deletions
@@ -1,6 +1,6 @@ /* * This file is part of ltrace. - * Copyright (C) 2011,2012 Petr Machata, Red Hat Inc. + * Copyright (C) 2011,2012,2013 Petr Machata, Red Hat Inc. * Copyright (C) 1998,2004,2007,2008,2009 Juan Cespedes * Copyright (C) 2006 Steve Fink * Copyright (C) 2006 Ian Wienand @@ -22,7 +22,9 @@ */ #include <assert.h> +#include <stdint.h> #include <stdlib.h> +#include <string.h> #include "printf.h" #include "type.h" @@ -39,6 +41,7 @@ struct param_enum { char *format; char const *ptr; char const *end; + size_t width; }; static struct param_enum * @@ -47,12 +50,30 @@ param_printf_init(struct value *cb_args, size_t nargs, { assert(nargs == 1); - /* We expect a char array pointer. */ + struct process *proc = cb_args[0].inferior; + assert(proc != NULL); + + /* We expect a pointer to array. */ if (cb_args->type->type != ARGTYPE_POINTER - || cb_args->type->u.ptr_info.info->type != ARGTYPE_ARRAY - || (cb_args->type->u.ptr_info.info->u.array_info.elt_type->type - != ARGTYPE_CHAR)) + || cb_args->type->u.ptr_info.info->type != ARGTYPE_ARRAY) + return NULL; + + /* The element type should be either character (for narrow + * strings) or an integral type (for wide strings). */ + struct arg_type_info *et + = cb_args->type->u.ptr_info.info->u.array_info.elt_type; + switch (et->type) { + case ARGTYPE_CHAR: + case ARGTYPE_SHORT: + case ARGTYPE_USHORT: + case ARGTYPE_INT: + case ARGTYPE_UINT: + case ARGTYPE_LONG: + case ARGTYPE_ULONG: + break; + default: return NULL; + } struct param_enum *self = malloc(sizeof(*self)); if (self == NULL) { @@ -60,10 +81,12 @@ param_printf_init(struct value *cb_args, size_t nargs, free(self); return NULL; } + self->width = type_sizeof(proc, et); + if (self->width == (size_t) -1) + goto fail; if (value_init_deref(&self->array, cb_args) < 0) goto fail; - assert(self->array.type->type == ARGTYPE_ARRAY); self->format = (char *)value_get_data(&self->array, arguments); @@ -168,7 +191,7 @@ form_next_param(struct param_enum *self, type_init_pointer(infop, array, 1); } else if (format_type == ARGTYPE_POINTER) { - type_init_pointer(infop, elt_info, 1); + type_init_pointer(infop, elt_info, 0); } else { *infop = *type_get_simple(format_type); @@ -189,14 +212,29 @@ param_printf_next(struct param_enum *self, struct arg_type_info *infop, size_t len_buf_len = 0; struct lens *lens = NULL; - for (; self->ptr < self->end; ++self->ptr) { + for (; self->ptr < self->end; self->ptr += self->width) { + union { + uint8_t u8; + uint16_t u16; + uint32_t u32; + uint64_t u64; + char buf[0]; + } u; + memcpy(u.buf, self->ptr, self->width); + switch (self->width) { + case 1: u.u64 = u.u8; break; + case 2: u.u64 = u.u16; break; + case 4: u.u64 = u.u32; break; + } + uint64_t c = u.u64; + if (!self->percent) { - if (*self->ptr == '%') + if (c == '%') self->percent = 1; continue; } - switch (*self->ptr) { + switch (c) { case '#': case ' ': case '-': case '+': case 'I': case '\'': /* These are only important for formatting, @@ -214,7 +252,7 @@ param_printf_next(struct param_enum *self, struct arg_type_info *infop, = malloc(sizeof(*self->future_length)); if (self->future_length != NULL) { - ++self->ptr; + self->ptr += self->width; format_type = ARGTYPE_INT; break; } @@ -227,7 +265,7 @@ param_printf_next(struct param_enum *self, struct arg_type_info *infop, * this to attach the appropriate string * length expression. */ if (len_buf_len < sizeof(len_buf) - 1) - len_buf[len_buf_len++] = *self->ptr; + len_buf[len_buf_len++] = c; continue; case 'h': @@ -270,6 +308,7 @@ param_printf_next(struct param_enum *self, struct arg_type_info *infop, case 'x': case 'X': lens = &hex_lens; + /* Fall through. */ case 'u': uint: format_type = ARGTYPE_UINT; @@ -298,8 +337,7 @@ param_printf_next(struct param_enum *self, struct arg_type_info *infop, lng++; case 's': format_type = ARGTYPE_ARRAY; - /* XXX "ls" means wchar_t string. */ - elt_type = ARGTYPE_CHAR; + elt_type = lng == 0 ? ARGTYPE_CHAR : ARGTYPE_INT; self->percent = 0; lens = &string_lens; break; |