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