value.c revision e3f4a984db115979e09414b7281da98399dd8949
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 <string.h> 22#include <assert.h> 23#include <stdlib.h> 24 25#include "value.h" 26#include "type.h" 27#include "common.h" 28#include "expr.h" 29#include "backend.h" 30 31static void 32value_common_init(struct value *valp, struct Process *inferior, 33 struct value *parent, struct arg_type_info *type, 34 int own_type) 35{ 36 valp->type = type; 37 valp->own_type = own_type; 38 valp->inferior = inferior; 39 memset(&valp->u, 0, sizeof(valp->u)); 40 valp->where = VAL_LOC_NODATA; 41 valp->parent = parent; 42 valp->size = (size_t)-1; 43} 44 45void 46value_init(struct value *valp, struct Process *inferior, struct value *parent, 47 struct arg_type_info *type, int own_type) 48{ 49 assert(inferior != NULL); 50 value_common_init(valp, inferior, parent, type, own_type); 51} 52 53void 54value_init_detached(struct value *valp, struct value *parent, 55 struct arg_type_info *type, int own_type) 56{ 57 value_common_init(valp, NULL, parent, type, own_type); 58} 59 60void 61value_set_type(struct value *value, struct arg_type_info *type, int own_type) 62{ 63 if (value->own_type) 64 type_destroy(value->type); 65 value->type = type; 66 value->own_type = own_type; 67} 68 69void 70value_take_type(struct value *value, struct arg_type_info **type, 71 int *own_type) 72{ 73 *type = value->type; 74 *own_type = value->own_type; 75 value->own_type = 0; 76} 77 78void 79value_release(struct value *val) 80{ 81 if (val == NULL) 82 return; 83 if (val->where == VAL_LOC_COPY) { 84 free(val->u.address); 85 val->where = VAL_LOC_NODATA; 86 } 87} 88 89void 90value_destroy(struct value *val) 91{ 92 if (val == NULL) 93 return; 94 value_release(val); 95 value_set_type(val, NULL, 0); 96} 97 98void 99value_set_long(struct value *valp, long value) 100{ 101 valp->where = VAL_LOC_WORD; 102 valp->u.value = value; 103} 104 105unsigned char * 106value_reserve(struct value *valp, size_t size) 107{ 108 if (size <= sizeof(valp->u.value)) { 109 value_set_long(valp, 0); 110 } else { 111 valp->where = VAL_LOC_COPY; 112 valp->u.address = calloc(size, 1); 113 if (valp->u.address == 0) 114 return NULL; 115 } 116 return value_get_raw_data(valp); 117} 118 119int 120value_reify(struct value *val, struct value_dict *arguments) 121{ 122 if (val->where != VAL_LOC_INFERIOR) 123 return 0; 124 assert(val->inferior != NULL); 125 126 size_t size = value_size(val, arguments); 127 if (size == (size_t)-1) 128 return -1; 129 130 void *data; 131 enum value_location_t nloc; 132 if (size <= sizeof(val->u.value)) { 133 data = &val->u.value; 134 nloc = VAL_LOC_WORD; 135 } else { 136 data = malloc(size); 137 if (data == NULL) 138 return -1; 139 nloc = VAL_LOC_COPY; 140 } 141 142 if (umovebytes(val->inferior, val->u.address, data, size) < size) { 143 if (nloc == VAL_LOC_COPY) 144 free(data); 145 return -1; 146 } 147 148 val->where = nloc; 149 if (nloc == VAL_LOC_COPY) 150 val->u.address = data; 151 152 return 0; 153} 154 155unsigned char * 156value_get_data(struct value *val, struct value_dict *arguments) 157{ 158 if (value_reify(val, arguments) < 0) 159 return NULL; 160 return value_get_raw_data(val); 161} 162 163unsigned char * 164value_get_raw_data(struct value *val) 165{ 166 switch (val->where) { 167 case VAL_LOC_INFERIOR: 168 abort(); 169 case VAL_LOC_NODATA: 170 return NULL; 171 case VAL_LOC_COPY: 172 case VAL_LOC_SHARED: 173 return val->u.address; 174 case VAL_LOC_WORD: 175 return val->u.buf; 176 } 177 178 assert(!"Unexpected value of val->where"); 179 abort(); 180} 181 182int 183value_clone(struct value *retp, struct value *val) 184{ 185 *retp = *val; 186 if (val->where == VAL_LOC_COPY) { 187 assert(val->inferior != NULL); 188 size_t size = type_sizeof(val->inferior, val->type); 189 if (size == (size_t)-1) 190 return -1; 191 192 retp->u.address = malloc(size); 193 if (retp->u.address == NULL) 194 return -1; 195 196 memcpy(retp->u.address, val->u.address, size); 197 } 198 199 return 0; 200} 201 202size_t 203value_size(struct value *val, struct value_dict *arguments) 204{ 205 if (val->size != (size_t)-1) 206 return val->size; 207 208 if (val->type->type != ARGTYPE_ARRAY) 209 return val->size = type_sizeof(val->inferior, val->type); 210 211 struct value length; 212 if (expr_eval(val->type->u.array_info.length, val, 213 arguments, &length) < 0) 214 return (size_t)-1; 215 216 size_t l; 217 int o = value_extract_word(&length, (long *)&l, arguments); 218 value_destroy(&length); 219 220 if (o < 0) 221 return (size_t)-1; 222 223 size_t elt_size = type_sizeof(val->inferior, 224 val->type->u.array_info.elt_type); 225 if (elt_size == (size_t)-1) 226 return (size_t)-1; 227 228 return val->size = elt_size * l; 229} 230 231int 232value_init_element(struct value *ret_val, struct value *val, size_t element) 233{ 234 size_t off = type_offsetof(val->inferior, val->type, element); 235 if (off == (size_t)-1) 236 return -1; 237 238 struct arg_type_info *e_info = type_element(val->type, element); 239 if (e_info == NULL) 240 return -1; 241 242 value_common_init(ret_val, val->inferior, val, e_info, 0); 243 244 switch (val->where) { 245 case VAL_LOC_COPY: 246 case VAL_LOC_SHARED: 247 ret_val->u.address = val->u.address + off; 248 ret_val->where = VAL_LOC_SHARED; 249 return 0; 250 251 case VAL_LOC_WORD: 252 ret_val->u.address = value_get_raw_data(val) + off; 253 ret_val->where = VAL_LOC_SHARED; 254 return 0; 255 256 case VAL_LOC_INFERIOR: 257 ret_val->u.address = val->u.address + off; 258 ret_val->where = VAL_LOC_INFERIOR; 259 return 0; 260 261 case VAL_LOC_NODATA: 262 assert(!"Can't offset NODATA."); 263 abort(); 264 } 265 abort(); 266} 267 268int 269value_init_deref(struct value *ret_val, struct value *valp) 270{ 271 assert(valp->type->type == ARGTYPE_POINTER); 272 273 /* Note: extracting a pointer value should not need value_dict 274 * with function arguments. */ 275 long l; 276 if (value_extract_word(valp, &l, NULL) < 0) 277 return -1; 278 279 /* We need "long" to be long enough to hold platform 280 * pointers. */ 281 typedef char assert__long_enough_long[-(sizeof(l) < sizeof(void *))]; 282 283 value_common_init(ret_val, valp->inferior, valp, 284 valp->type->u.ptr_info.info, 0); 285 ret_val->u.value = l; /* Set the address. */ 286 ret_val->where = VAL_LOC_INFERIOR; 287 return 0; 288} 289 290int 291value_extract_word(struct value *value, long *retp, struct value_dict *arguments) 292{ 293 union { 294 long val; 295 unsigned char buf[0]; 296 } u; 297 memset(u.buf, 0, sizeof(u)); 298 if (value_extract_buf(value, u.buf, arguments) < 0) 299 return -1; 300 *retp = u.val; 301 return 0; 302} 303 304int 305value_extract_buf(struct value *value, unsigned char *tgt, 306 struct value_dict *arguments) 307{ 308 unsigned char *data = value_get_data(value, arguments); 309 if (data == NULL) 310 return -1; 311 312 size_t sz = type_sizeof(value->inferior, value->type); 313 if (sz == (size_t)-1) 314 return -1; 315 316 memcpy(tgt, data, sz); 317 return 0; 318} 319 320struct value * 321value_get_parental_struct(struct value *val) 322{ 323 struct value *parent; 324 for (parent = val->parent; parent != NULL; parent = parent->parent) 325 if (parent->type->type == ARGTYPE_STRUCT) 326 return parent; 327 return NULL; 328} 329 330int 331value_is_zero(struct value *val, struct value_dict *arguments) 332{ 333 unsigned char *data = value_get_data(val, arguments); 334 if (data == NULL) 335 return -1; 336 size_t sz = type_sizeof(val->inferior, val->type); 337 if (sz == (size_t)-1) 338 return -1; 339 340 int zero = 1; 341 size_t j; 342 for (j = 0; j < sz; ++j) { 343 if (data[j] != 0) { 344 zero = 0; 345 break; 346 } 347 } 348 return zero; 349} 350