value.c revision 642626096a694c6af279d25d2b1b2fba5b10ddfb
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
202struct value *
203value_string_to_charp(struct value *value)
204{
205	struct arg_type_info *info = malloc(sizeof(*info) * 2);
206	if (info == NULL) {
207	fail:
208		free(info);
209		return NULL;
210	}
211	type_init_array(&info[1], type_get_simple(ARGTYPE_CHAR), 0,
212			value->type->u.string_n_info.length, 0);
213	type_init_pointer(&info[0], &info[1], 0);
214
215	struct value *tmp = malloc(sizeof(*tmp));
216	if (tmp == NULL)
217		goto fail;
218
219	value_clone(tmp, value);
220	value_set_type(tmp, info, 1);
221	return tmp;
222}
223
224size_t
225value_size(struct value *val, struct value_dict *arguments)
226{
227	if (val->size != (size_t)-1)
228		return val->size;
229
230	if (val->type->type != ARGTYPE_ARRAY)
231		return val->size = type_sizeof(val->inferior, val->type);
232
233	struct value length;
234	if (expr_eval(val->type->u.array_info.length, val,
235		      arguments, &length) < 0)
236		return (size_t)-1;
237
238	size_t l;
239	int o = value_extract_word(&length, (long *)&l, arguments);
240	value_destroy(&length);
241
242	if (o < 0)
243		return (size_t)-1;
244
245	size_t elt_size = type_sizeof(val->inferior,
246				      val->type->u.array_info.elt_type);
247	if (elt_size == (size_t)-1)
248		return (size_t)-1;
249
250	return val->size = elt_size * l;
251}
252
253int
254value_init_element(struct value *ret_val, struct value *val, size_t element)
255{
256	size_t off = type_offsetof(val->inferior, val->type, element);
257	if (off == (size_t)-1)
258		return -1;
259
260	struct arg_type_info *e_info = type_element(val->type, element);
261	if (e_info == NULL)
262		return -1;
263
264	value_common_init(ret_val, val->inferior, val, e_info, 0);
265
266	switch (val->where) {
267	case VAL_LOC_COPY:
268	case VAL_LOC_SHARED:
269		ret_val->u.address = val->u.address + off;
270		ret_val->where = VAL_LOC_SHARED;
271		return 0;
272
273	case VAL_LOC_WORD:
274		ret_val->u.address = value_get_raw_data(val) + off;
275		ret_val->where = VAL_LOC_SHARED;
276		return 0;
277
278	case VAL_LOC_INFERIOR:
279		ret_val->u.address = val->u.address + off;
280		ret_val->where = VAL_LOC_INFERIOR;
281		return 0;
282
283	case VAL_LOC_NODATA:
284		assert(!"Can't offset NODATA.");
285		abort();
286	}
287	abort();
288}
289
290int
291value_init_deref(struct value *ret_val, struct value *valp)
292{
293	assert(valp->type->type == ARGTYPE_POINTER);
294
295	/* Note: extracting a pointer value should not need value_dict
296	 * with function arguments.  */
297	long l;
298	if (value_extract_word(valp, &l, NULL) < 0)
299		return -1;
300
301	/* We need "long" to be long enough to hold platform
302	 * pointers.  */
303	typedef char assert__long_enough_long[-(sizeof(l) < sizeof(void *))];
304
305	value_common_init(ret_val, valp->inferior, valp,
306			  valp->type->u.ptr_info.info, 0);
307	ret_val->u.value = l; /* Set the address.  */
308	ret_val->where = VAL_LOC_INFERIOR;
309	return 0;
310}
311
312int
313value_extract_word(struct value *value, long *retp, struct value_dict *arguments)
314{
315	union {
316		long val;
317		unsigned char buf[0];
318	} u;
319	memset(u.buf, 0, sizeof(u));
320	if (value_extract_buf(value, u.buf, arguments) < 0)
321		return -1;
322	*retp = u.val;
323	return 0;
324}
325
326int
327value_extract_buf(struct value *value, unsigned char *tgt,
328		  struct value_dict *arguments)
329{
330	unsigned char *data = value_get_data(value, arguments);
331	if (data == NULL)
332		return -1;
333
334	size_t sz = type_sizeof(value->inferior, value->type);
335	if (sz == (size_t)-1)
336		return -1;
337
338	memcpy(tgt, data, sz);
339	return 0;
340}
341
342struct value *
343value_get_parental_struct(struct value *val)
344{
345	struct value *parent;
346	for (parent = val->parent; parent != NULL; parent = parent->parent)
347		if (parent->type->type == ARGTYPE_STRUCT)
348			return parent;
349	return NULL;
350}
351
352int
353value_is_zero(struct value *val, struct value_dict *arguments)
354{
355	unsigned char *data = value_get_data(val, arguments);
356	if (data == NULL)
357		return -1;
358	size_t sz = type_sizeof(val->inferior, val->type);
359	if (sz == (size_t)-1)
360		return -1;
361
362	int zero = 1;
363	size_t j;
364	for (j = 0; j < sz; ++j) {
365		if (data[j] != 0) {
366			zero = 0;
367			break;
368		}
369	}
370	return zero;
371}
372