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 
31 static void
value_common_init(struct value * valp,struct process * inferior,struct value * parent,struct arg_type_info * type,int own_type)32 value_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 
45 void
value_init(struct value * valp,struct process * inferior,struct value * parent,struct arg_type_info * type,int own_type)46 value_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 
53 void
value_init_detached(struct value * valp,struct value * parent,struct arg_type_info * type,int own_type)54 value_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 
60 void
value_set_type(struct value * value,struct arg_type_info * type,int own_type)61 value_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 		free(value->type);
66 	}
67 	value->type = type;
68 	value->own_type = own_type;
69 }
70 
71 void
value_take_type(struct value * value,struct arg_type_info ** type,int * own_type)72 value_take_type(struct value *value, struct arg_type_info **type,
73 		int *own_type)
74 {
75 	*type = value->type;
76 	*own_type = value->own_type;
77 	value->own_type = 0;
78 }
79 
80 void
value_release(struct value * val)81 value_release(struct value *val)
82 {
83 	if (val == NULL)
84 		return;
85 	if (val->where == VAL_LOC_COPY) {
86 		free(val->u.address);
87 		val->where = VAL_LOC_NODATA;
88 	}
89 }
90 
91 void
value_destroy(struct value * val)92 value_destroy(struct value *val)
93 {
94 	if (val == NULL)
95 		return;
96 	value_release(val);
97 	value_set_type(val, NULL, 0);
98 }
99 
100 unsigned char *
value_reserve(struct value * valp,size_t size)101 value_reserve(struct value *valp, size_t size)
102 {
103 	value_release(valp);
104 
105 	if (size <= sizeof(valp->u.value)) {
106 		valp->where = VAL_LOC_WORD;
107 		valp->u.value = 0;
108 	} else {
109 		valp->where = VAL_LOC_COPY;
110 		valp->u.address = calloc(size, 1);
111 		if (valp->u.address == 0)
112 			return NULL;
113 	}
114 	return value_get_raw_data(valp);
115 }
116 
117 void
value_in_inferior(struct value * valp,arch_addr_t address)118 value_in_inferior(struct value *valp, arch_addr_t address)
119 {
120 	value_release(valp);
121 	valp->where = VAL_LOC_INFERIOR;
122 	valp->u.address = address;
123 }
124 
125 int
value_reify(struct value * val,struct value_dict * arguments)126 value_reify(struct value *val, struct value_dict *arguments)
127 {
128 	if (val->where != VAL_LOC_INFERIOR)
129 		return 0;
130 	assert(val->inferior != NULL);
131 
132 	size_t size = value_size(val, arguments);
133 	if (size == (size_t)-1)
134 		return -1;
135 
136 	void *data;
137 	enum value_location_t nloc;
138 	if (size <= sizeof(val->u.value)) {
139 		data = &val->u.value;
140 		nloc = VAL_LOC_WORD;
141 	} else {
142 		data = malloc(size);
143 		if (data == NULL)
144 			return -1;
145 		nloc = VAL_LOC_COPY;
146 	}
147 
148 	if (umovebytes(val->inferior, val->u.inf_address, data, size) < size) {
149 		if (nloc == VAL_LOC_COPY)
150 			free(data);
151 		return -1;
152 	}
153 
154 	val->where = nloc;
155 	if (nloc == VAL_LOC_COPY)
156 		val->u.address = data;
157 
158 	return 0;
159 }
160 
161 unsigned char *
value_get_data(struct value * val,struct value_dict * arguments)162 value_get_data(struct value *val, struct value_dict *arguments)
163 {
164 	if (value_reify(val, arguments) < 0)
165 		return NULL;
166 	return value_get_raw_data(val);
167 }
168 
169 unsigned char *
value_get_raw_data(struct value * val)170 value_get_raw_data(struct value *val)
171 {
172 	switch (val->where) {
173 	case VAL_LOC_INFERIOR:
174 		abort();
175 	case VAL_LOC_NODATA:
176 		return NULL;
177 	case VAL_LOC_COPY:
178 	case VAL_LOC_SHARED:
179 		return val->u.address;
180 	case VAL_LOC_WORD:
181 		return val->u.buf;
182 	}
183 
184 	assert(!"Unexpected value of val->where");
185 	abort();
186 }
187 
188 int
value_clone(struct value * retp,const struct value * val)189 value_clone(struct value *retp, const struct value *val)
190 {
191 	*retp = *val;
192 
193 	if (val->own_type) {
194 		retp->type = malloc(sizeof(struct arg_type_info));
195 		if (type_clone (retp->type, val->type) < 0) {
196 			free(retp->type);
197 			return -1;
198 		}
199 	}
200 
201 	if (val->where == VAL_LOC_COPY) {
202 		assert(val->inferior != NULL);
203 		size_t size = type_sizeof(val->inferior, val->type);
204 		if (size == (size_t)-1) {
205 		fail:
206 			if (retp->own_type) {
207 				type_destroy(retp->type);
208 				free(retp->type);
209 			}
210 			return -1;
211 		}
212 
213 		retp->u.address = malloc(size);
214 		if (retp->u.address == NULL)
215 			goto fail;
216 
217 		memcpy(retp->u.address, val->u.address, size);
218 	}
219 
220 	return 0;
221 }
222 
223 size_t
value_size(struct value * val,struct value_dict * arguments)224 value_size(struct value *val, struct value_dict *arguments)
225 {
226 	if (val->size != (size_t)-1)
227 		return val->size;
228 
229 	if (val->type->type != ARGTYPE_ARRAY)
230 		return val->size = type_sizeof(val->inferior, val->type);
231 
232 	struct value length;
233 	if (expr_eval(val->type->u.array_info.length, val,
234 		      arguments, &length) < 0)
235 		return (size_t)-1;
236 
237 	size_t l;
238 	int o = value_extract_word(&length, (long *)&l, arguments);
239 	value_destroy(&length);
240 
241 	if (o < 0)
242 		return (size_t)-1;
243 
244 	size_t elt_size = type_sizeof(val->inferior,
245 				      val->type->u.array_info.elt_type);
246 	if (elt_size == (size_t)-1)
247 		return (size_t)-1;
248 
249 	return val->size = elt_size * l;
250 }
251 
252 int
value_init_element(struct value * ret_val,struct value * val,size_t element)253 value_init_element(struct value *ret_val, struct value *val, size_t element)
254 {
255 	size_t off = type_offsetof(val->inferior, val->type, element);
256 	if (off == (size_t)-1)
257 		return -1;
258 
259 	struct arg_type_info *e_info = type_element(val->type, element);
260 	if (e_info == NULL)
261 		return -1;
262 
263 	value_common_init(ret_val, val->inferior, val, e_info, 0);
264 
265 	switch (val->where) {
266 	case VAL_LOC_COPY:
267 	case VAL_LOC_SHARED:
268 		ret_val->u.address = val->u.address + off;
269 		ret_val->where = VAL_LOC_SHARED;
270 		return 0;
271 
272 	case VAL_LOC_WORD:
273 		ret_val->u.address = value_get_raw_data(val) + off;
274 		ret_val->where = VAL_LOC_SHARED;
275 		return 0;
276 
277 	case VAL_LOC_INFERIOR:
278 		ret_val->u.inf_address = val->u.inf_address + off;
279 		ret_val->where = VAL_LOC_INFERIOR;
280 		return 0;
281 
282 	case VAL_LOC_NODATA:
283 		assert(!"Can't offset NODATA.");
284 		abort();
285 	}
286 	abort();
287 }
288 
289 int
value_init_deref(struct value * ret_val,struct value * valp)290 value_init_deref(struct value *ret_val, struct value *valp)
291 {
292 	assert(valp->type->type == ARGTYPE_POINTER);
293 
294 	/* Note: extracting a pointer value should not need value_dict
295 	 * with function arguments.  */
296 	long l;
297 	if (value_extract_word(valp, &l, NULL) < 0)
298 		return -1;
299 
300 	/* We need "long" to be long enough to hold platform
301 	 * pointers.  */
302 	(void)sizeof(char[1 - 2*(sizeof(l) < sizeof(void *))]);
303 
304 	value_common_init(ret_val, valp->inferior, valp,
305 			  valp->type->u.ptr_info.info, 0);
306 	ret_val->u.value = l; /* Set the address.  */
307 	ret_val->where = VAL_LOC_INFERIOR;
308 	return 0;
309 }
310 
311 /* The functions value_extract_buf and value_extract_word assume that
312  * data in VALUE is stored at the start of the internal buffer.  For
313  * value_extract_buf in particular there's no other reasonable
314  * default.  If we need to copy out four bytes, they need to be the
315  * bytes pointed to by the buffer pointer.
316  *
317  * But actually the situation is similar for value_extract_word as
318  * well.  This function is used e.g. to extract characters from
319  * strings.  Those weren't stored by value_set_word, they might still
320  * be in client for all we know.  So value_extract_word has to assume
321  * that the whole of data is data is stored at the buffer pointer.
322  *
323  * This is a problem on big endian machines, where 2-byte quantity
324  * carried in 4- or 8-byte long is stored at the end of that long.
325  * (Though that quantity itself is still big endian.)  So we need to
326  * make a little dance to shift the value to the right part of the
327  * buffer.  */
328 
329 union word_data {
330 	uint8_t u8;
331 	uint16_t u16;
332 	uint32_t u32;
333 	uint64_t u64;
334 	long l;
335 	unsigned char buf[0];
336 } u;
337 
338 void
value_set_word(struct value * value,long word)339 value_set_word(struct value *value, long word)
340 {
341 	size_t sz = type_sizeof(value->inferior, value->type);
342 	assert(sz != (size_t)-1);
343 	assert(sz <= sizeof(value->u.value));
344 
345 	value->where = VAL_LOC_WORD;
346 
347 	union word_data u = {};
348 
349 	switch (sz) {
350 	case 0:
351 		u.l = 0;
352 		break;
353 	case 1:
354 		u.u8 = word;
355 		break;
356 	case 2:
357 		u.u16 = word;
358 		break;
359 	case 4:
360 		u.u32 = word;
361 		break;
362 	case 8:
363 		u.u64 = word;
364 		break;
365 	default:
366 		assert(sz != sz);
367 		abort();
368 	}
369 
370 	value->u.value = u.l;
371 }
372 
373 static int
value_extract_buf_sz(struct value * value,unsigned char * tgt,size_t sz,struct value_dict * arguments)374 value_extract_buf_sz(struct value *value, unsigned char *tgt, size_t sz,
375 		     struct value_dict *arguments)
376 {
377 	unsigned char *data = value_get_data(value, arguments);
378 	if (data == NULL)
379 		return -1;
380 
381 	memcpy(tgt, data, sz);
382 	return 0;
383 }
384 
385 int
value_extract_word(struct value * value,long * retp,struct value_dict * arguments)386 value_extract_word(struct value *value, long *retp,
387 		   struct value_dict *arguments)
388 {
389 	size_t sz = type_sizeof(value->inferior, value->type);
390 	if (sz == (size_t)-1)
391 		return -1;
392 	assert(sz <= sizeof(value->u.value));
393 
394 	if (sz == 0) {
395 		*retp = 0;
396 		return 0;
397 	}
398 
399 	union word_data u = {};
400 	if (value_extract_buf_sz(value, u.buf, sz, arguments) < 0)
401 		return -1;
402 
403 	switch (sz) {
404 	case 1:
405 		*retp = (long)u.u8;
406 		return 0;
407 	case 2:
408 		*retp = (long)u.u16;
409 		return 0;
410 	case 4:
411 		*retp = (long)u.u32;
412 		return 0;
413 	case 8:
414 		*retp = (long)u.u64;
415 		return 0;
416 	default:
417 		assert(sz != sz);
418 		abort();
419 	}
420 }
421 
422 int
value_extract_buf(struct value * value,unsigned char * tgt,struct value_dict * arguments)423 value_extract_buf(struct value *value, unsigned char *tgt,
424 		  struct value_dict *arguments)
425 {
426 	size_t sz = type_sizeof(value->inferior, value->type);
427 	if (sz == (size_t)-1)
428 		return -1;
429 
430 	return value_extract_buf_sz(value, tgt, sz, arguments);
431 }
432 
433 struct value *
value_get_parental_struct(struct value * val)434 value_get_parental_struct(struct value *val)
435 {
436 	struct value *parent;
437 	for (parent = val->parent; parent != NULL; parent = parent->parent)
438 		if (parent->type->type == ARGTYPE_STRUCT)
439 			return parent;
440 	return NULL;
441 }
442 
443 int
value_is_zero(struct value * val,struct value_dict * arguments)444 value_is_zero(struct value *val, struct value_dict *arguments)
445 {
446 	unsigned char *data = value_get_data(val, arguments);
447 	if (data == NULL)
448 		return -1;
449 	size_t sz = type_sizeof(val->inferior, val->type);
450 	if (sz == (size_t)-1)
451 		return -1;
452 
453 	int zero = 1;
454 	size_t j;
455 	for (j = 0; j < sz; ++j) {
456 		if (data[j] != 0) {
457 			zero = 0;
458 			break;
459 		}
460 	}
461 	return zero;
462 }
463 
464 int
value_equal(struct value * val1,struct value * val2,struct value_dict * arguments)465 value_equal(struct value *val1, struct value *val2,
466 	    struct value_dict *arguments)
467 {
468 	size_t sz1 = type_sizeof(val1->inferior, val1->type);
469 	size_t sz2 = type_sizeof(val2->inferior, val2->type);
470 	if (sz1 == (size_t)-1 || sz2 == (size_t)-1)
471 		return -1;
472 	if (sz1 != sz2)
473 		return 0;
474 
475 	unsigned char *data1 = value_get_data(val1, arguments);
476 	unsigned char *data2 = value_get_data(val2, arguments);
477 	if (data1 == NULL || data2 == NULL)
478 		return -1;
479 	return memcmp(data1, data2, sz1) == 0 ? 1 : 0;
480 }
481 
482 int
value_pass_by_reference(struct value * value)483 value_pass_by_reference(struct value *value)
484 {
485 	assert(value != NULL);
486 	assert(value->type->type == ARGTYPE_STRUCT);
487 
488 	struct arg_type_info *new_info = calloc(sizeof(*new_info), 1);
489 	if (new_info == NULL)
490 		return -1;
491 
492 	int own;
493 	struct arg_type_info *orig;
494 	value_take_type(value, &orig, &own);
495 	type_init_pointer(new_info, orig, own);
496 	new_info->lens = orig->lens;
497 	value_set_type(value, new_info, 1);
498 
499 	return 0;
500 }
501