1 /* 2 * This file is part of ltrace. 3 * Copyright (C) 2011, 2012 Petr Machata, Red Hat Inc. 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public License as 7 * published by the Free Software Foundation; either version 2 of the 8 * License, or (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, but 11 * WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 * 02110-1301 USA 19 */ 20 21 #include <stdlib.h> 22 #include <assert.h> 23 #include <string.h> 24 25 #include "lens_enum.h" 26 #include "lens_default.h" 27 #include "value.h" 28 #include "sysdep.h" 29 #include "type.h" 30 31 struct enum_entry { 32 char *key; 33 int own_key; 34 struct value *value; 35 int own_value; 36 }; 37 38 static void 39 enum_entry_dtor(struct enum_entry *entry, void *data) 40 { 41 if (entry->own_key) 42 free(entry->key); 43 if (entry->own_value) { 44 value_destroy(entry->value); 45 free(entry->value); 46 } 47 } 48 49 static void 50 enum_lens_destroy_cb(struct lens *lens) 51 { 52 struct enum_lens *self = (void *)lens; 53 54 VECT_DESTROY(&self->entries, struct enum_entry, 55 enum_entry_dtor, NULL); 56 } 57 58 enum { 59 #ifdef ARCH_ENDIAN_BIG 60 big_endian = 1, 61 #elif defined (ARCH_ENDIAN_LITTLE) 62 big_endian = 0, 63 #else 64 # error Undefined endianness. 65 #endif 66 }; 67 68 /* Returns 0 if they are not equal, >0 if they are, and <0 if there 69 * was an error. */ 70 static int 71 enum_values_equal(struct value *inf_value, struct value *enum_value, 72 struct value_dict *arguments) 73 { 74 /* Width may not match between what's defined in config file 75 * and what arrives from the back end. Typically, if there is 76 * a mismatch, the config file size will be larger, as we are 77 * in a situation where 64-bit tracer traces 32-bit process. 78 * But opposite situation can occur e.g. on PPC, where it's 79 * apparently possible for 32-bit tracer to trace 64-bit 80 * inferior, or hypothetically in a x32/x86_64 situation. */ 81 82 unsigned char *inf_data = value_get_data(inf_value, arguments); 83 size_t inf_sz = value_size(inf_value, arguments); 84 if (inf_data == NULL || inf_sz == (size_t)-1) 85 return -1; 86 87 assert(inf_value->type->type == enum_value->type->type); 88 89 unsigned char *enum_data = value_get_data(enum_value, arguments); 90 size_t enum_sz = value_size(enum_value, arguments); 91 if (enum_data == NULL || enum_sz == (size_t)-1) 92 return -1; 93 94 size_t sz = enum_sz > inf_sz ? inf_sz : enum_sz; 95 96 if (big_endian) 97 return memcmp(enum_data + enum_sz - sz, 98 inf_data + inf_sz - sz, sz) == 0; 99 else 100 return memcmp(enum_data, inf_data, sz) == 0; 101 } 102 103 static const char * 104 enum_get(struct enum_lens *lens, struct value *value, 105 struct value_dict *arguments) 106 { 107 size_t i; 108 for (i = 0; i < vect_size(&lens->entries); ++i) { 109 struct enum_entry *entry = VECT_ELEMENT(&lens->entries, 110 struct enum_entry, i); 111 int st = enum_values_equal(value, entry->value, arguments); 112 if (st < 0) 113 return NULL; 114 else if (st != 0) 115 return entry->key; 116 } 117 return NULL; 118 } 119 120 static int 121 enum_lens_format_cb(struct lens *lens, FILE *stream, 122 struct value *value, struct value_dict *arguments) 123 { 124 struct enum_lens *self = (void *)lens; 125 126 const char *name = enum_get(self, value, arguments); 127 if (name != NULL) 128 return fprintf(stream, "%s", name); 129 130 return lens_format(&default_lens, stream, value, arguments); 131 } 132 133 134 void 135 lens_init_enum(struct enum_lens *lens) 136 { 137 *lens = (struct enum_lens){ 138 { 139 .format_cb = enum_lens_format_cb, 140 .destroy_cb = enum_lens_destroy_cb, 141 }, 142 }; 143 VECT_INIT(&lens->entries, struct enum_entry); 144 } 145 146 int 147 lens_enum_add(struct enum_lens *lens, 148 const char *key, int own_key, 149 struct value *value, int own_value) 150 { 151 struct enum_entry entry = { (char *)key, own_key, value, own_value }; 152 return VECT_PUSHBACK(&lens->entries, &entry); 153 } 154 155 size_t 156 lens_enum_size(struct enum_lens *lens) 157 { 158 return vect_size(&lens->entries); 159 } 160