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