value.c revision 4c2109ab8912d6c6616702ec9fa0cbaf65e7f751
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 98unsigned char * 99value_reserve(struct value *valp, size_t size) 100{ 101 if (size <= sizeof(valp->u.value)) { 102 value_set_word(valp, 0); 103 } else { 104 valp->where = VAL_LOC_COPY; 105 valp->u.address = calloc(size, 1); 106 if (valp->u.address == 0) 107 return NULL; 108 } 109 return value_get_raw_data(valp); 110} 111 112int 113value_reify(struct value *val, struct value_dict *arguments) 114{ 115 if (val->where != VAL_LOC_INFERIOR) 116 return 0; 117 assert(val->inferior != NULL); 118 119 size_t size = value_size(val, arguments); 120 if (size == (size_t)-1) 121 return -1; 122 123 void *data; 124 enum value_location_t nloc; 125 if (size <= sizeof(val->u.value)) { 126 data = &val->u.value; 127 nloc = VAL_LOC_WORD; 128 } else { 129 data = malloc(size); 130 if (data == NULL) 131 return -1; 132 nloc = VAL_LOC_COPY; 133 } 134 135 if (umovebytes(val->inferior, val->u.address, data, size) < size) { 136 if (nloc == VAL_LOC_COPY) 137 free(data); 138 return -1; 139 } 140 141 val->where = nloc; 142 if (nloc == VAL_LOC_COPY) 143 val->u.address = data; 144 145 return 0; 146} 147 148unsigned char * 149value_get_data(struct value *val, struct value_dict *arguments) 150{ 151 if (value_reify(val, arguments) < 0) 152 return NULL; 153 return value_get_raw_data(val); 154} 155 156unsigned char * 157value_get_raw_data(struct value *val) 158{ 159 switch (val->where) { 160 case VAL_LOC_INFERIOR: 161 abort(); 162 case VAL_LOC_NODATA: 163 return NULL; 164 case VAL_LOC_COPY: 165 case VAL_LOC_SHARED: 166 return val->u.address; 167 case VAL_LOC_WORD: 168 return val->u.buf; 169 } 170 171 assert(!"Unexpected value of val->where"); 172 abort(); 173} 174 175int 176value_clone(struct value *retp, struct value *val) 177{ 178 *retp = *val; 179 if (val->where == VAL_LOC_COPY) { 180 assert(val->inferior != NULL); 181 size_t size = type_sizeof(val->inferior, val->type); 182 if (size == (size_t)-1) 183 return -1; 184 185 retp->u.address = malloc(size); 186 if (retp->u.address == NULL) 187 return -1; 188 189 memcpy(retp->u.address, val->u.address, size); 190 } 191 192 return 0; 193} 194 195size_t 196value_size(struct value *val, struct value_dict *arguments) 197{ 198 if (val->size != (size_t)-1) 199 return val->size; 200 201 if (val->type->type != ARGTYPE_ARRAY) 202 return val->size = type_sizeof(val->inferior, val->type); 203 204 struct value length; 205 if (expr_eval(val->type->u.array_info.length, val, 206 arguments, &length) < 0) 207 return (size_t)-1; 208 209 size_t l; 210 int o = value_extract_word(&length, (long *)&l, arguments); 211 value_destroy(&length); 212 213 if (o < 0) 214 return (size_t)-1; 215 216 size_t elt_size = type_sizeof(val->inferior, 217 val->type->u.array_info.elt_type); 218 if (elt_size == (size_t)-1) 219 return (size_t)-1; 220 221 return val->size = elt_size * l; 222} 223 224int 225value_init_element(struct value *ret_val, struct value *val, size_t element) 226{ 227 size_t off = type_offsetof(val->inferior, val->type, element); 228 if (off == (size_t)-1) 229 return -1; 230 231 struct arg_type_info *e_info = type_element(val->type, element); 232 if (e_info == NULL) 233 return -1; 234 235 value_common_init(ret_val, val->inferior, val, e_info, 0); 236 237 switch (val->where) { 238 case VAL_LOC_COPY: 239 case VAL_LOC_SHARED: 240 ret_val->u.address = val->u.address + off; 241 ret_val->where = VAL_LOC_SHARED; 242 return 0; 243 244 case VAL_LOC_WORD: 245 ret_val->u.address = value_get_raw_data(val) + off; 246 ret_val->where = VAL_LOC_SHARED; 247 return 0; 248 249 case VAL_LOC_INFERIOR: 250 ret_val->u.address = val->u.address + off; 251 ret_val->where = VAL_LOC_INFERIOR; 252 return 0; 253 254 case VAL_LOC_NODATA: 255 assert(!"Can't offset NODATA."); 256 abort(); 257 } 258 abort(); 259} 260 261int 262value_init_deref(struct value *ret_val, struct value *valp) 263{ 264 assert(valp->type->type == ARGTYPE_POINTER); 265 266 /* Note: extracting a pointer value should not need value_dict 267 * with function arguments. */ 268 long l; 269 if (value_extract_word(valp, &l, NULL) < 0) 270 return -1; 271 272 /* We need "long" to be long enough to hold platform 273 * pointers. */ 274 typedef char assert__long_enough_long[-(sizeof(l) < sizeof(void *))]; 275 276 value_common_init(ret_val, valp->inferior, valp, 277 valp->type->u.ptr_info.info, 0); 278 ret_val->u.value = l; /* Set the address. */ 279 ret_val->where = VAL_LOC_INFERIOR; 280 return 0; 281} 282 283/* The functions value_extract_buf and value_extract_word assume that 284 * data in VALUE is stored at the start of the internal buffer. For 285 * value_extract_buf in particular there's no other reasonable 286 * default. If we need to copy out four bytes, they need to be the 287 * bytes pointed to by the buffer pointer. 288 * 289 * But actually the situation is similar for value_extract_word as 290 * well. This function is used e.g. to extract characters from 291 * strings. Those weren't stored by value_set_word, they might still 292 * be in client for all we know. So value_extract_word has to assume 293 * that the whole of data is data is stored at the buffer pointer. 294 * 295 * This is a problem on big endian machines, where 2-byte quantity 296 * carried in 4- or 8-byte long is stored at the end of that long. 297 * (Though that quantity itself is still big endian.) So we need to 298 * make a little dance to shift the value to the right part of the 299 * buffer. */ 300 301union word_data { 302 uint8_t u8; 303 uint16_t u16; 304 uint32_t u32; 305 uint64_t u64; 306 long l; 307 unsigned char buf[0]; 308} u; 309 310void 311value_set_word(struct value *value, long word) 312{ 313 size_t sz = type_sizeof(value->inferior, value->type); 314 assert(sz != (size_t)-1); 315 assert(sz <= sizeof(long)); 316 317 value->where = VAL_LOC_WORD; 318 319 union word_data u = {}; 320 321 switch (sz) { 322 case 0: 323 u.l = 0; 324 break; 325 case 1: 326 u.u8 = word; 327 break; 328 case 2: 329 u.u16 = word; 330 break; 331 case 4: 332 u.u32 = word; 333 break; 334 case 8: 335 u.u64 = word; 336 break; 337 default: 338 assert(sz != sz); 339 abort(); 340 } 341 342 value->u.value = u.l; 343} 344 345static int 346value_extract_buf_sz(struct value *value, unsigned char *tgt, size_t sz, 347 struct value_dict *arguments) 348{ 349 unsigned char *data = value_get_data(value, arguments); 350 if (data == NULL) 351 return -1; 352 353 memcpy(tgt, data, sz); 354 return 0; 355} 356 357int 358value_extract_word(struct value *value, long *retp, 359 struct value_dict *arguments) 360{ 361 size_t sz = type_sizeof(value->inferior, value->type); 362 if (sz == (size_t)-1) 363 return -1; 364 assert(sz <= sizeof(long)); 365 366 if (sz == 0) { 367 *retp = 0; 368 return 0; 369 } 370 371 union word_data u = {}; 372 if (value_extract_buf_sz(value, u.buf, sz, arguments) < 0) 373 return -1; 374 375 switch (sz) { 376 case 1: 377 *retp = (long)u.u8; 378 return 0; 379 case 2: 380 *retp = (long)u.u16; 381 return 0; 382 case 4: 383 *retp = (long)u.u32; 384 return 0; 385 case 8: 386 *retp = (long)u.u64; 387 return 0; 388 default: 389 assert(sz != sz); 390 abort(); 391 } 392} 393 394int 395value_extract_buf(struct value *value, unsigned char *tgt, 396 struct value_dict *arguments) 397{ 398 size_t sz = type_sizeof(value->inferior, value->type); 399 if (sz == (size_t)-1) 400 return -1; 401 402 return value_extract_buf_sz(value, tgt, sz, arguments); 403} 404 405struct value * 406value_get_parental_struct(struct value *val) 407{ 408 struct value *parent; 409 for (parent = val->parent; parent != NULL; parent = parent->parent) 410 if (parent->type->type == ARGTYPE_STRUCT) 411 return parent; 412 return NULL; 413} 414 415int 416value_is_zero(struct value *val, struct value_dict *arguments) 417{ 418 unsigned char *data = value_get_data(val, arguments); 419 if (data == NULL) 420 return -1; 421 size_t sz = type_sizeof(val->inferior, val->type); 422 if (sz == (size_t)-1) 423 return -1; 424 425 int zero = 1; 426 size_t j; 427 for (j = 0; j < sz; ++j) { 428 if (data[j] != 0) { 429 zero = 0; 430 break; 431 } 432 } 433 return zero; 434} 435