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, ¶m_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 ¶m_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