diff options
author | Petr Machata <pmachata@redhat.com> | 2013-11-11 02:24:42 +0100 |
---|---|---|
committer | Chanho Park <chanho61.park@samsung.com> | 2014-08-22 20:38:23 +0900 |
commit | e6c25f6799825812e2b87990333c649ba796f600 (patch) | |
tree | 8d68002e600f53c912433310ced3b13fb2883b95 /printf.c | |
parent | f292cf4e52c73fcc3b63ba2b032d17822f63e6e8 (diff) | |
download | ltrace-e6c25f6799825812e2b87990333c649ba796f600.tar.gz ltrace-e6c25f6799825812e2b87990333c649ba796f600.tar.bz2 ltrace-e6c25f6799825812e2b87990333c649ba796f600.zip |
Support wide character strings
- "string" lens and "format" pack were extended such that using an
integer as underlying array type denotes a wide character string.
- several prototypes from wchar.h were added to libc.so.conf.
- ltrace.conf.5 was updated
Diffstat (limited to 'printf.c')
-rw-r--r-- | printf.c | 61 |
1 files changed, 49 insertions, 12 deletions
@@ -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); @@ -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': @@ -299,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; |