value.c revision 4767187d0d7924bfe5028fe3e29e3b018bc9c99b
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
30static void
31value_common_init(struct value *valp, struct Process *inferior,
32		  struct value *parent, struct arg_type_info *type,
33		  int own_type)
34{
35	valp->type = type;
36	valp->own_type = own_type;
37	valp->inferior = inferior;
38	memset(&valp->u, 0, sizeof(valp->u));
39	valp->where = VAL_LOC_NODATA;
40	valp->parent = parent;
41	valp->size = (size_t)-1;
42}
43
44void
45value_init(struct value *valp, struct Process *inferior, struct value *parent,
46	   struct arg_type_info *type, int own_type)
47{
48	assert(inferior != NULL);
49	value_common_init(valp, inferior, parent, type, own_type);
50}
51
52void
53value_init_detached(struct value *valp, struct value *parent,
54		    struct arg_type_info *type, int own_type)
55{
56	value_common_init(valp, NULL, parent, type, own_type);
57}
58
59void
60value_set_type(struct value *value, struct arg_type_info *type, int own_type)
61{
62	if (value->own_type)
63		type_destroy(value->type);
64	value->type = type;
65	value->own_type = own_type;
66}
67
68void
69value_take_type(struct value *value, struct arg_type_info **type,
70		int *own_type)
71{
72	*type = value->type;
73	*own_type = value->own_type;
74	value->own_type = 0;
75}
76
77void
78value_release(struct value *val)
79{
80	if (val == NULL)
81		return;
82	if (val->where == VAL_LOC_COPY) {
83		free(val->u.address);
84		val->where = VAL_LOC_NODATA;
85	}
86}
87
88void
89value_destroy(struct value *val)
90{
91	if (val == NULL)
92		return;
93	value_release(val);
94	value_set_type(val, NULL, 0);
95}
96
97void
98value_set_long(struct value *valp, long value)
99{
100	valp->where = VAL_LOC_WORD;
101	valp->u.value = value;
102}
103
104unsigned char *
105value_reserve(struct value *valp, size_t size)
106{
107	if (size <= sizeof(valp->u.value)) {
108		value_set_long(valp, 0);
109	} else {
110		valp->where = VAL_LOC_COPY;
111		valp->u.address = calloc(size, 1);
112		if (valp->u.address == 0)
113			return NULL;
114	}
115	return value_get_raw_data(valp);
116}
117
118int
119value_reify(struct value *val, struct value_dict *arguments)
120{
121	if (val->where != VAL_LOC_INFERIOR)
122		return 0;
123	assert(val->inferior != NULL);
124
125	size_t size = value_size(val, arguments);
126	if (size == (size_t)-1)
127		return -1;
128
129	void *data;
130	enum value_location_t nloc;
131	if (size <= sizeof(val->u.value)) {
132		data = &val->u.value;
133		nloc = VAL_LOC_WORD;
134	} else {
135		data = malloc(size);
136		if (data == NULL)
137			return -1;
138		nloc = VAL_LOC_COPY;
139	}
140
141	if (umovebytes(val->inferior, val->u.address, data, size) < size) {
142		if (nloc == VAL_LOC_COPY)
143			free(data);
144		return -1;
145	}
146
147	val->where = nloc;
148	if (nloc == VAL_LOC_COPY)
149		val->u.address = data;
150
151	return 0;
152}
153
154unsigned char *
155value_get_data(struct value *val, struct value_dict *arguments)
156{
157	if (value_reify(val, arguments) < 0)
158		return NULL;
159	return value_get_raw_data(val);
160}
161
162unsigned char *
163value_get_raw_data(struct value *val)
164{
165	switch (val->where) {
166	case VAL_LOC_INFERIOR:
167		abort();
168	case VAL_LOC_NODATA:
169		return NULL;
170	case VAL_LOC_COPY:
171	case VAL_LOC_SHARED:
172		return val->u.address;
173	case VAL_LOC_WORD:
174		return val->u.buf;
175	}
176
177	assert(!"Unexpected value of val->where");
178	abort();
179}
180
181int
182value_clone(struct value *retp, struct value *val)
183{
184	*retp = *val;
185	if (val->where == VAL_LOC_COPY) {
186		assert(val->inferior != NULL);
187		size_t size = type_sizeof(val->inferior, val->type);
188		if (size == (size_t)-1)
189			return -1;
190
191		retp->u.address = malloc(size);
192		if (retp->u.address == NULL)
193			return -1;
194
195		memcpy(retp->u.address, val->u.address, size);
196	}
197
198	return 0;
199}
200
201struct value *
202value_string_to_charp(struct value *value)
203{
204	struct arg_type_info *info = malloc(sizeof(*info) * 2);
205	if (info == NULL) {
206	fail:
207		free(info);
208		return NULL;
209	}
210	type_init_array(&info[1], type_get_simple(ARGTYPE_CHAR), 0,
211			value->type->u.string_n_info.length, 0);
212	type_init_pointer(&info[0], &info[1], 0);
213
214	struct value *tmp = malloc(sizeof(*tmp));
215	if (tmp == NULL)
216		goto fail;
217
218	value_clone(tmp, value);
219	value_set_type(tmp, info, 1);
220	return tmp;
221}
222
223size_t
224value_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
252int
253value_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.address = val->u.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
289int
290value_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	typedef char assert__long_enough_long[-(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
311int
312value_extract_word(struct value *value, long *retp, struct value_dict *arguments)
313{
314	union {
315		long val;
316		unsigned char buf[0];
317	} u;
318	memset(u.buf, 0, sizeof(u));
319	if (value_extract_buf(value, u.buf, arguments) < 0)
320		return -1;
321	*retp = u.val;
322	return 0;
323}
324
325int
326value_extract_buf(struct value *value, unsigned char *tgt,
327		  struct value_dict *arguments)
328{
329	unsigned char *data = value_get_data(value, arguments);
330	if (data == NULL)
331		return -1;
332
333	size_t sz = type_sizeof(value->inferior, value->type);
334	if (sz == (size_t)-1)
335		return -1;
336
337	memcpy(tgt, data, sz);
338	return 0;
339}
340
341struct value *
342value_get_parental_struct(struct value *val)
343{
344	struct value *parent;
345	for (parent = val->parent; parent != NULL; parent = parent->parent)
346		if (parent->type->type == ARGTYPE_STRUCT)
347			return parent;
348	return NULL;
349}
350
351int
352value_is_zero(struct value *val, struct value_dict *arguments)
353{
354	unsigned char *data = value_get_data(val, arguments);
355	if (data == NULL)
356		return -1;
357	size_t sz = type_sizeof(val->inferior, val->type);
358	if (sz == (size_t)-1)
359		return -1;
360
361	int zero = 1;
362	size_t j;
363	for (j = 0; j < sz; ++j) {
364		if (data[j] != 0) {
365			zero = 0;
366			break;
367		}
368	}
369	return zero;
370}
371