prototype.c revision ebc56a70e20ca0b3fc49c0eb5fc83e56c5e1fa5b
1/*
2 * This file is part of ltrace.
3 * Copyright (C) 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 <stdlib.h>
22#include <string.h>
23
24#include "prototype.h"
25#include "callback.h"
26#include "param.h"
27#include "type.h"
28
29struct protolib g_prototypes;
30
31void
32prototype_init(struct prototype *proto)
33{
34	VECT_INIT(&proto->params, struct param);
35
36	proto->return_info = NULL;
37	proto->own_return_info = 0;
38}
39
40static void
41param_destroy_cb(struct param *param, void *data)
42{
43	param_destroy(param);
44}
45
46void
47prototype_destroy(struct prototype *proto)
48{
49	if (proto == NULL)
50		return;
51	if (proto->own_return_info) {
52		type_destroy(proto->return_info);
53		free(proto->return_info);
54	}
55
56	VECT_DESTROY(&proto->params, struct param, &param_destroy_cb, NULL);
57}
58
59int
60prototype_push_param(struct prototype *proto, struct param *param)
61{
62	return VECT_PUSHBACK(&proto->params, param);
63}
64
65size_t
66prototype_num_params(struct prototype *proto)
67{
68	return vect_size(&proto->params);
69}
70
71void
72prototype_destroy_nth_param(struct prototype *proto, size_t n)
73{
74	assert(n < prototype_num_params(proto));
75	VECT_ERASE(&proto->params, struct param, n, n+1,
76		   &param_destroy_cb, NULL);
77}
78
79struct param *
80prototype_get_nth_param(struct prototype *proto, size_t n)
81{
82	assert(n < prototype_num_params(proto));
83	return VECT_ELEMENT(&proto->params, struct param, n);
84}
85
86struct each_param_data {
87	struct prototype *proto;
88	enum callback_status (*cb)(struct prototype *, struct param *, void *);
89	void *data;
90};
91
92static enum callback_status
93each_param_cb(struct param *param, void *data)
94{
95	struct each_param_data *cb_data = data;
96	return (cb_data->cb)(cb_data->proto, param, cb_data->data);
97}
98
99struct param *
100prototype_each_param(struct prototype *proto, struct param *start_after,
101		     enum callback_status (*cb)(struct prototype *,
102						struct param *, void *),
103		     void *data)
104{
105	struct each_param_data cb_data = { proto, cb, data };
106	return VECT_EACH(&proto->params, struct param, start_after,
107			 &each_param_cb, &cb_data);
108}
109
110void
111named_type_destroy(struct named_type *named)
112{
113	if (named->owned) {
114		type_destroy(named->info);
115		free(named->info);
116	}
117}
118
119int
120protolib_init(struct protolib *plib)
121{
122	plib->prototypes = dict_init(&dict_key2hash_string,
123				     &dict_key_cmp_string);
124	if (plib->prototypes == NULL)
125		return -1;
126
127	plib->named_types = dict_init(&dict_key2hash_string,
128				      &dict_key_cmp_string);
129	if (plib->named_types == NULL) {
130		dict_clear(plib->prototypes);
131		return -1;
132	}
133
134	VECT_INIT(&plib->imports, struct protolib *);
135	return 0;
136}
137
138static void
139prototype_entry_destroy(void *key, void *val, void *data)
140{
141	char *name = key;
142	struct prototype *proto = val;
143	free(name);
144	prototype_destroy(proto);
145}
146
147static void
148named_type_entry_destroy(void *key, void *val, void *data)
149{
150	char *name = key;
151	struct named_type *named = val;
152	free(name);
153	named_type_destroy(named);
154}
155
156void
157protolib_destroy(struct protolib *plib)
158{
159	VECT_DESTROY(&plib->imports, struct prototype *, NULL, NULL);
160
161	dict_apply_to_all(plib->prototypes, prototype_entry_destroy, NULL);
162	dict_clear(plib->prototypes);
163
164	dict_apply_to_all(plib->named_types, named_type_entry_destroy, NULL);
165	dict_clear(plib->named_types);
166}
167
168static struct protolib **
169each_import(struct protolib *plib, struct protolib **start_after,
170	    enum callback_status (*cb)(struct protolib **, void *), void *data)
171{
172	return VECT_EACH(&plib->imports, struct protolib *,
173			 start_after, cb, data);
174}
175
176static enum callback_status
177is_or_imports(struct protolib **plibp, void *data)
178{
179	struct protolib *import = data;
180	if (*plibp == import
181	    || each_import(*plibp, NULL, &is_or_imports, import) != NULL)
182		return CBS_STOP;
183	else
184		return CBS_CONT;
185}
186
187int
188protolib_add_import(struct protolib *plib, struct protolib *import)
189{
190	if (is_or_imports(&plib, import) == CBS_STOP)
191		return -2;
192
193	return VECT_PUSHBACK(&plib->imports, import) < 0 ? -1 : 0;
194}
195
196static int
197enroll(struct dict *dict, const char *name, int own_name, void *value)
198{
199	assert(name != NULL);
200
201	if (!own_name) {
202		name = strdup(name);
203		if (name == NULL)
204			return -1;
205	}
206
207	if (dict_enter(dict, (void *)name, value) < 0) {
208		if (own_name)
209			free((void *)name);
210		return -1;
211	}
212	return 0;
213}
214
215int
216protolib_add_prototype(struct protolib *plib, const char *name, int own_name,
217		       struct prototype *proto)
218{
219	return enroll(plib->prototypes, name, own_name, proto);
220}
221
222int
223protolib_add_named_type(struct protolib *plib, const char *name, int own_name,
224			struct named_type *named)
225{
226	return enroll(plib->named_types, name, own_name, named);
227}
228
229struct lookup {
230	const char *name;
231	void *result;
232};
233
234static enum callback_status
235lookup_prototype_rec(struct protolib **plibp, void *data)
236{
237	struct lookup *lookup = data;
238
239	lookup->result = dict_find_entry((*plibp)->prototypes, lookup->name);
240	if (lookup->result != NULL)
241		return CBS_STOP;
242
243	if (each_import(*plibp, NULL, &lookup_prototype_rec, lookup) != NULL) {
244		assert(lookup->result != NULL);
245		return CBS_STOP;
246	}
247
248	return CBS_CONT;
249}
250
251struct prototype *
252protolib_lookup_prototype(struct protolib *plib, const char *name)
253{
254	struct lookup lookup = { name, NULL };
255	if (lookup_prototype_rec(&plib, &lookup) == CBS_STOP)
256		assert(lookup.result != NULL);
257	else
258		assert(lookup.result == NULL);
259	return lookup.result;
260}
261
262struct named_type *
263protolib_lookup_type(struct protolib *plib, const char *name);
264