1 1.1 christos /* Convert symbols from GDB to GCC 2 1.1 christos 3 1.1.1.4 christos Copyright (C) 2014-2024 Free Software Foundation, Inc. 4 1.1 christos 5 1.1 christos This file is part of GDB. 6 1.1 christos 7 1.1 christos This program is free software; you can redistribute it and/or modify 8 1.1 christos it under the terms of the GNU General Public License as published by 9 1.1 christos the Free Software Foundation; either version 3 of the License, or 10 1.1 christos (at your option) any later version. 11 1.1 christos 12 1.1 christos This program is distributed in the hope that it will be useful, 13 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of 14 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 1.1 christos GNU General Public License for more details. 16 1.1 christos 17 1.1 christos You should have received a copy of the GNU General Public License 18 1.1 christos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 19 1.1 christos 20 1.1 christos 21 1.1 christos #include "compile-internal.h" 22 1.1 christos #include "compile-cplus.h" 23 1.1.1.2 christos #include "gdbsupport/gdb_assert.h" 24 1.1 christos #include "symtab.h" 25 1.1 christos #include "parser-defs.h" 26 1.1 christos #include "block.h" 27 1.1 christos #include "objfiles.h" 28 1.1 christos #include "compile.h" 29 1.1 christos #include "value.h" 30 1.1 christos #include "exceptions.h" 31 1.1 christos #include "gdbtypes.h" 32 1.1.1.2 christos #include "dwarf2/loc.h" 33 1.1 christos #include "cp-support.h" 34 1.1.1.4 christos #include "cli/cli-cmds.h" 35 1.1 christos #include "compile-c.h" 36 1.1.1.4 christos #include "inferior.h" 37 1.1 christos 38 1.1 christos /* Convert a given symbol, SYM, to the compiler's representation. 39 1.1 christos INSTANCE is the compiler instance. IS_GLOBAL is true if the 40 1.1 christos symbol came from the global scope. IS_LOCAL is true if the symbol 41 1.1 christos came from a local scope. (Note that the two are not strictly 42 1.1 christos inverses because the symbol might have come from the static 43 1.1 christos scope.) */ 44 1.1 christos 45 1.1 christos static void 46 1.1 christos convert_one_symbol (compile_cplus_instance *instance, 47 1.1 christos struct block_symbol sym, bool is_global, bool is_local) 48 1.1 christos { 49 1.1 christos /* Squash compiler warning. */ 50 1.1 christos gcc_type sym_type = 0; 51 1.1.1.3 christos const char *filename = sym.symbol->symtab ()->filename; 52 1.1.1.4 christos unsigned int line = sym.symbol->line (); 53 1.1 christos 54 1.1 christos instance->error_symbol_once (sym.symbol); 55 1.1 christos 56 1.1.1.3 christos if (sym.symbol->aclass () == LOC_LABEL) 57 1.1 christos sym_type = 0; 58 1.1 christos else 59 1.1.1.3 christos sym_type = instance->convert_type (sym.symbol->type ()); 60 1.1 christos 61 1.1.1.3 christos if (sym.symbol->domain () == STRUCT_DOMAIN) 62 1.1 christos { 63 1.1 christos /* Nothing to do. */ 64 1.1 christos } 65 1.1 christos else 66 1.1 christos { 67 1.1 christos /* Squash compiler warning. */ 68 1.1 christos gcc_cp_symbol_kind_flags kind = GCC_CP_FLAG_BASE; 69 1.1 christos CORE_ADDR addr = 0; 70 1.1 christos std::string name; 71 1.1 christos gdb::unique_xmalloc_ptr<char> symbol_name; 72 1.1 christos 73 1.1.1.3 christos switch (sym.symbol->aclass ()) 74 1.1 christos { 75 1.1 christos case LOC_TYPEDEF: 76 1.1.1.3 christos if (sym.symbol->type ()->code () == TYPE_CODE_TYPEDEF) 77 1.1 christos kind = GCC_CP_SYMBOL_TYPEDEF; 78 1.1.1.3 christos else if (sym.symbol->type ()->code () == TYPE_CODE_NAMESPACE) 79 1.1 christos return; 80 1.1 christos break; 81 1.1 christos 82 1.1 christos case LOC_LABEL: 83 1.1 christos kind = GCC_CP_SYMBOL_LABEL; 84 1.1.1.3 christos addr = sym.symbol->value_address (); 85 1.1 christos break; 86 1.1 christos 87 1.1 christos case LOC_BLOCK: 88 1.1 christos { 89 1.1 christos kind = GCC_CP_SYMBOL_FUNCTION; 90 1.1.1.3 christos addr = sym.symbol->value_block()->start (); 91 1.1.1.3 christos if (is_global && sym.symbol->type ()->is_gnu_ifunc ()) 92 1.1.1.4 christos addr = gnu_ifunc_resolve_addr (current_inferior ()->arch (), 93 1.1.1.4 christos addr); 94 1.1 christos } 95 1.1 christos break; 96 1.1 christos 97 1.1 christos case LOC_CONST: 98 1.1.1.3 christos if (sym.symbol->type ()->code () == TYPE_CODE_ENUM) 99 1.1 christos { 100 1.1 christos /* Already handled by convert_enum. */ 101 1.1 christos return; 102 1.1 christos } 103 1.1 christos instance->plugin ().build_constant 104 1.1.1.2 christos (sym_type, sym.symbol->natural_name (), 105 1.1.1.3 christos sym.symbol->value_longest (), filename, line); 106 1.1 christos return; 107 1.1 christos 108 1.1 christos case LOC_CONST_BYTES: 109 1.1 christos error (_("Unsupported LOC_CONST_BYTES for symbol \"%s\"."), 110 1.1.1.2 christos sym.symbol->print_name ()); 111 1.1 christos 112 1.1 christos case LOC_UNDEF: 113 1.1.1.3 christos internal_error (_("LOC_UNDEF found for \"%s\"."), 114 1.1.1.2 christos sym.symbol->print_name ()); 115 1.1 christos 116 1.1 christos case LOC_COMMON_BLOCK: 117 1.1 christos error (_("Fortran common block is unsupported for compilation " 118 1.1 christos "evaluaton of symbol \"%s\"."), 119 1.1.1.2 christos sym.symbol->print_name ()); 120 1.1 christos 121 1.1 christos case LOC_OPTIMIZED_OUT: 122 1.1 christos error (_("Symbol \"%s\" cannot be used for compilation evaluation " 123 1.1 christos "as it is optimized out."), 124 1.1.1.2 christos sym.symbol->print_name ()); 125 1.1 christos 126 1.1 christos case LOC_COMPUTED: 127 1.1 christos if (is_local) 128 1.1 christos goto substitution; 129 1.1 christos /* Probably TLS here. */ 130 1.1 christos warning (_("Symbol \"%s\" is thread-local and currently can only " 131 1.1 christos "be referenced from the current thread in " 132 1.1 christos "compiled code."), 133 1.1.1.2 christos sym.symbol->print_name ()); 134 1.1.1.4 christos [[fallthrough]]; 135 1.1 christos case LOC_UNRESOLVED: 136 1.1 christos /* 'symbol_name' cannot be used here as that one is used only for 137 1.1 christos local variables from compile_dwarf_expr_to_c. 138 1.1 christos Global variables can be accessed by GCC only by their address, not 139 1.1 christos by their name. */ 140 1.1 christos { 141 1.1 christos struct value *val; 142 1.1.1.3 christos frame_info_ptr frame = nullptr; 143 1.1 christos 144 1.1 christos if (symbol_read_needs_frame (sym.symbol)) 145 1.1 christos { 146 1.1 christos frame = get_selected_frame (nullptr); 147 1.1 christos if (frame == nullptr) 148 1.1 christos error (_("Symbol \"%s\" cannot be used because " 149 1.1 christos "there is no selected frame"), 150 1.1.1.2 christos sym.symbol->print_name ()); 151 1.1 christos } 152 1.1 christos 153 1.1 christos val = read_var_value (sym.symbol, sym.block, frame); 154 1.1.1.4 christos if (val->lval () != lval_memory) 155 1.1 christos error (_("Symbol \"%s\" cannot be used for compilation " 156 1.1 christos "evaluation as its address has not been found."), 157 1.1.1.2 christos sym.symbol->print_name ()); 158 1.1 christos 159 1.1 christos kind = GCC_CP_SYMBOL_VARIABLE; 160 1.1.1.4 christos addr = val->address (); 161 1.1 christos } 162 1.1 christos break; 163 1.1 christos 164 1.1 christos 165 1.1 christos case LOC_REGISTER: 166 1.1 christos case LOC_ARG: 167 1.1 christos case LOC_REF_ARG: 168 1.1 christos case LOC_REGPARM_ADDR: 169 1.1 christos case LOC_LOCAL: 170 1.1 christos substitution: 171 1.1 christos kind = GCC_CP_SYMBOL_VARIABLE; 172 1.1 christos symbol_name = c_symbol_substitution_name (sym.symbol); 173 1.1 christos break; 174 1.1 christos 175 1.1 christos case LOC_STATIC: 176 1.1 christos kind = GCC_CP_SYMBOL_VARIABLE; 177 1.1.1.3 christos addr = sym.symbol->value_address (); 178 1.1 christos break; 179 1.1 christos 180 1.1 christos case LOC_FINAL_VALUE: 181 1.1 christos default: 182 1.1 christos gdb_assert_not_reached ("Unreachable case in convert_one_symbol."); 183 1.1 christos } 184 1.1 christos 185 1.1 christos /* Don't emit local variable decls for a raw expression. */ 186 1.1 christos if (instance->scope () != COMPILE_I_RAW_SCOPE || symbol_name == nullptr) 187 1.1 christos { 188 1.1 christos /* For non-local symbols, create/push a new scope so that the 189 1.1 christos symbol is properly scoped to the plug-in. */ 190 1.1 christos if (!is_local) 191 1.1 christos { 192 1.1 christos compile_scope scope 193 1.1.1.2 christos = instance->new_scope (sym.symbol->natural_name (), 194 1.1.1.3 christos sym.symbol->type ()); 195 1.1 christos if (scope.nested_type () != GCC_TYPE_NONE) 196 1.1 christos { 197 1.1 christos /* We found a symbol for this type that was defined inside 198 1.1.1.2 christos some other symbol, e.g., a class typedef defined. */ 199 1.1 christos return; 200 1.1 christos } 201 1.1 christos 202 1.1 christos instance->enter_scope (std::move (scope)); 203 1.1 christos } 204 1.1 christos 205 1.1 christos /* Get the `raw' name of the symbol. */ 206 1.1.1.2 christos if (name.empty () && sym.symbol->natural_name () != nullptr) 207 1.1 christos name = compile_cplus_instance::decl_name 208 1.1.1.2 christos (sym.symbol->natural_name ()).get (); 209 1.1 christos 210 1.1 christos /* Define the decl. */ 211 1.1 christos instance->plugin ().build_decl 212 1.1.1.3 christos ("variable", name.c_str (), kind.raw (), sym_type, 213 1.1 christos symbol_name.get (), addr, filename, line); 214 1.1 christos 215 1.1 christos /* Pop scope for non-local symbols. */ 216 1.1 christos if (!is_local) 217 1.1 christos instance->leave_scope (); 218 1.1 christos } 219 1.1 christos } 220 1.1 christos } 221 1.1 christos 222 1.1 christos /* Convert a full symbol to its gcc form. CONTEXT is the compiler to 223 1.1 christos use, IDENTIFIER is the name of the symbol, SYM is the symbol 224 1.1 christos itself, and DOMAIN is the domain which was searched. */ 225 1.1 christos 226 1.1 christos static void 227 1.1 christos convert_symbol_sym (compile_cplus_instance *instance, 228 1.1 christos const char *identifier, struct block_symbol sym, 229 1.1.1.4 christos domain_search_flags domain) 230 1.1 christos { 231 1.1 christos /* If we found a symbol and it is not in the static or global 232 1.1 christos scope, then we should first convert any static or global scope 233 1.1 christos symbol of the same name. This lets this unusual case work: 234 1.1 christos 235 1.1 christos int x; // Global. 236 1.1 christos int func(void) 237 1.1 christos { 238 1.1 christos int x; 239 1.1 christos // At this spot, evaluate "extern int x; x" 240 1.1 christos } 241 1.1 christos */ 242 1.1 christos 243 1.1.1.4 christos const struct block *static_block = nullptr; 244 1.1.1.4 christos if (sym.block != nullptr) 245 1.1.1.4 christos static_block = sym.block->static_block (); 246 1.1 christos /* STATIC_BLOCK is NULL if FOUND_BLOCK is the global block. */ 247 1.1 christos bool is_local_symbol = (sym.block != static_block && static_block != nullptr); 248 1.1 christos if (is_local_symbol) 249 1.1 christos { 250 1.1 christos struct block_symbol global_sym; 251 1.1 christos 252 1.1 christos global_sym = lookup_symbol (identifier, nullptr, domain, nullptr); 253 1.1 christos /* If the outer symbol is in the static block, we ignore it, as 254 1.1 christos it cannot be referenced. */ 255 1.1 christos if (global_sym.symbol != nullptr 256 1.1.1.4 christos && global_sym.block != global_sym.block->static_block ()) 257 1.1 christos { 258 1.1 christos if (compile_debug) 259 1.1.1.3 christos gdb_printf (gdb_stdlog, 260 1.1.1.3 christos "gcc_convert_symbol \"%s\": global symbol\n", 261 1.1.1.3 christos identifier); 262 1.1 christos convert_one_symbol (instance, global_sym, true, false); 263 1.1 christos } 264 1.1 christos } 265 1.1 christos 266 1.1 christos if (compile_debug) 267 1.1.1.3 christos gdb_printf (gdb_stdlog, 268 1.1.1.3 christos "gcc_convert_symbol \"%s\": local symbol\n", 269 1.1.1.3 christos identifier); 270 1.1 christos convert_one_symbol (instance, sym, false, is_local_symbol); 271 1.1 christos } 272 1.1 christos 273 1.1 christos /* Convert a minimal symbol to its gcc form. CONTEXT is the compiler 274 1.1 christos to use and BMSYM is the minimal symbol to convert. */ 275 1.1 christos 276 1.1 christos static void 277 1.1 christos convert_symbol_bmsym (compile_cplus_instance *instance, 278 1.1 christos struct bound_minimal_symbol bmsym) 279 1.1 christos { 280 1.1 christos struct minimal_symbol *msym = bmsym.minsym; 281 1.1 christos struct objfile *objfile = bmsym.objfile; 282 1.1 christos struct type *type; 283 1.1 christos gcc_cp_symbol_kind_flags kind; 284 1.1 christos gcc_type sym_type; 285 1.1 christos CORE_ADDR addr; 286 1.1 christos 287 1.1.1.3 christos addr = msym->value_address (objfile); 288 1.1 christos 289 1.1 christos /* Conversion copied from write_exp_msymbol. */ 290 1.1.1.3 christos switch (msym->type ()) 291 1.1 christos { 292 1.1 christos case mst_text: 293 1.1 christos case mst_file_text: 294 1.1 christos case mst_solib_trampoline: 295 1.1.1.4 christos type = builtin_type (objfile)->nodebug_text_symbol; 296 1.1 christos kind = GCC_CP_SYMBOL_FUNCTION; 297 1.1 christos break; 298 1.1 christos 299 1.1 christos case mst_text_gnu_ifunc: 300 1.1 christos /* nodebug_text_gnu_ifunc_symbol would cause: 301 1.1 christos function return type cannot be function */ 302 1.1.1.4 christos type = builtin_type (objfile)->nodebug_text_symbol; 303 1.1 christos kind = GCC_CP_SYMBOL_FUNCTION; 304 1.1.1.4 christos addr = gnu_ifunc_resolve_addr (current_inferior ()->arch (), addr); 305 1.1 christos break; 306 1.1 christos 307 1.1 christos case mst_data: 308 1.1 christos case mst_file_data: 309 1.1 christos case mst_bss: 310 1.1 christos case mst_file_bss: 311 1.1.1.4 christos type = builtin_type (objfile)->nodebug_data_symbol; 312 1.1 christos kind = GCC_CP_SYMBOL_VARIABLE; 313 1.1 christos break; 314 1.1 christos 315 1.1 christos case mst_slot_got_plt: 316 1.1.1.4 christos type = builtin_type (objfile)->nodebug_got_plt_symbol; 317 1.1 christos kind = GCC_CP_SYMBOL_FUNCTION; 318 1.1 christos break; 319 1.1 christos 320 1.1 christos default: 321 1.1.1.4 christos type = builtin_type (objfile)->nodebug_unknown_symbol; 322 1.1 christos kind = GCC_CP_SYMBOL_VARIABLE; 323 1.1 christos break; 324 1.1 christos } 325 1.1 christos 326 1.1 christos sym_type = instance->convert_type (type); 327 1.1 christos instance->plugin ().push_namespace (""); 328 1.1 christos instance->plugin ().build_decl 329 1.1.1.3 christos ("minsym", msym->natural_name (), kind.raw (), sym_type, nullptr, addr, 330 1.1 christos nullptr, 0); 331 1.1 christos instance->plugin ().pop_binding_level (""); 332 1.1 christos } 333 1.1 christos 334 1.1 christos /* See compile-cplus.h. */ 335 1.1 christos 336 1.1 christos void 337 1.1 christos gcc_cplus_convert_symbol (void *datum, 338 1.1 christos struct gcc_cp_context *gcc_context, 339 1.1 christos enum gcc_cp_oracle_request request, 340 1.1 christos const char *identifier) 341 1.1 christos { 342 1.1 christos if (compile_debug) 343 1.1.1.3 christos gdb_printf (gdb_stdlog, 344 1.1.1.3 christos "got oracle request for \"%s\"\n", identifier); 345 1.1 christos 346 1.1 christos bool found = false; 347 1.1 christos compile_cplus_instance *instance = (compile_cplus_instance *) datum; 348 1.1 christos 349 1.1.1.2 christos try 350 1.1 christos { 351 1.1 christos /* Symbol searching is a three part process unfortunately. */ 352 1.1 christos 353 1.1 christos /* First do a "standard" lookup, converting any found symbols. 354 1.1 christos This will find variables in the current scope. */ 355 1.1 christos 356 1.1 christos struct block_symbol sym 357 1.1.1.4 christos = lookup_symbol (identifier, instance->block (), SEARCH_VFT, nullptr); 358 1.1 christos 359 1.1 christos if (sym.symbol != nullptr) 360 1.1 christos { 361 1.1 christos found = true; 362 1.1.1.4 christos convert_symbol_sym (instance, identifier, sym, SEARCH_VFT); 363 1.1 christos } 364 1.1 christos 365 1.1 christos /* Then use linespec.c's multi-symbol search. This should find 366 1.1 christos all non-variable symbols for which we have debug info. */ 367 1.1 christos 368 1.1 christos symbol_searcher searcher; 369 1.1 christos searcher.find_all_symbols (identifier, current_language, 370 1.1.1.4 christos SEARCH_ALL_DOMAINS, nullptr, nullptr); 371 1.1 christos 372 1.1 christos /* Convert any found symbols. */ 373 1.1 christos for (const auto &it : searcher.matching_symbols ()) 374 1.1 christos { 375 1.1 christos /* Don't convert the symbol found above, if any, twice! */ 376 1.1 christos if (it.symbol != sym.symbol) 377 1.1 christos { 378 1.1 christos found = true; 379 1.1 christos convert_symbol_sym (instance, identifier, it, 380 1.1.1.4 christos to_search_flags (it.symbol->domain ())); 381 1.1 christos } 382 1.1 christos } 383 1.1 christos 384 1.1 christos /* Finally, if no symbols have been found, fall back to minsyms. */ 385 1.1 christos if (!found) 386 1.1 christos { 387 1.1 christos for (const auto &it : searcher.matching_msymbols ()) 388 1.1 christos { 389 1.1 christos found = true; 390 1.1 christos convert_symbol_bmsym (instance, it); 391 1.1 christos } 392 1.1 christos } 393 1.1 christos } 394 1.1.1.2 christos catch (const gdb_exception &e) 395 1.1 christos { 396 1.1 christos /* We can't allow exceptions to escape out of this callback. Safest 397 1.1 christos is to simply emit a gcc error. */ 398 1.1.1.2 christos instance->plugin ().error (e.what ()); 399 1.1 christos } 400 1.1 christos 401 1.1 christos if (compile_debug && !found) 402 1.1.1.3 christos gdb_printf (gdb_stdlog, 403 1.1.1.3 christos "gcc_convert_symbol \"%s\": lookup_symbol failed\n", 404 1.1.1.3 christos identifier); 405 1.1 christos 406 1.1 christos if (compile_debug) 407 1.1 christos { 408 1.1 christos if (found) 409 1.1.1.3 christos gdb_printf (gdb_stdlog, "found type for %s\n", identifier); 410 1.1 christos else 411 1.1 christos { 412 1.1.1.3 christos gdb_printf (gdb_stdlog, "did not find type for %s\n", 413 1.1.1.3 christos identifier); 414 1.1 christos } 415 1.1 christos } 416 1.1 christos 417 1.1 christos return; 418 1.1 christos } 419 1.1 christos 420 1.1 christos /* See compile-cplus.h. */ 421 1.1 christos 422 1.1 christos gcc_address 423 1.1 christos gcc_cplus_symbol_address (void *datum, struct gcc_cp_context *gcc_context, 424 1.1 christos const char *identifier) 425 1.1 christos { 426 1.1 christos compile_cplus_instance *instance = (compile_cplus_instance *) datum; 427 1.1 christos gcc_address result = 0; 428 1.1 christos int found = 0; 429 1.1 christos 430 1.1 christos if (compile_debug) 431 1.1.1.3 christos gdb_printf (gdb_stdlog, 432 1.1.1.3 christos "got oracle request for address of %s\n", identifier); 433 1.1 christos 434 1.1 christos /* We can't allow exceptions to escape out of this callback. Safest 435 1.1 christos is to simply emit a gcc error. */ 436 1.1.1.2 christos try 437 1.1 christos { 438 1.1 christos struct symbol *sym 439 1.1.1.4 christos = lookup_symbol (identifier, nullptr, SEARCH_FUNCTION_DOMAIN, 440 1.1.1.4 christos nullptr).symbol; 441 1.1 christos 442 1.1.1.4 christos if (sym != nullptr) 443 1.1 christos { 444 1.1 christos if (compile_debug) 445 1.1.1.3 christos gdb_printf (gdb_stdlog, 446 1.1.1.3 christos "gcc_symbol_address \"%s\": full symbol\n", 447 1.1.1.3 christos identifier); 448 1.1.1.3 christos result = sym->value_block ()->start (); 449 1.1.1.3 christos if (sym->type ()->is_gnu_ifunc ()) 450 1.1.1.4 christos result = gnu_ifunc_resolve_addr (current_inferior ()->arch (), 451 1.1.1.4 christos result); 452 1.1 christos found = 1; 453 1.1 christos } 454 1.1 christos else 455 1.1 christos { 456 1.1 christos struct bound_minimal_symbol msym; 457 1.1 christos 458 1.1 christos msym = lookup_bound_minimal_symbol (identifier); 459 1.1 christos if (msym.minsym != nullptr) 460 1.1 christos { 461 1.1 christos if (compile_debug) 462 1.1.1.3 christos gdb_printf (gdb_stdlog, 463 1.1.1.3 christos "gcc_symbol_address \"%s\": minimal " 464 1.1.1.3 christos "symbol\n", 465 1.1.1.3 christos identifier); 466 1.1.1.3 christos result = msym.value_address (); 467 1.1.1.3 christos if (msym.minsym->type () == mst_text_gnu_ifunc) 468 1.1.1.4 christos result = gnu_ifunc_resolve_addr (current_inferior ()->arch (), 469 1.1.1.4 christos result); 470 1.1 christos found = 1; 471 1.1 christos } 472 1.1 christos } 473 1.1 christos } 474 1.1 christos 475 1.1.1.2 christos catch (const gdb_exception_error &e) 476 1.1 christos { 477 1.1.1.2 christos instance->plugin ().error (e.what ()); 478 1.1 christos } 479 1.1 christos 480 1.1 christos if (compile_debug && !found) 481 1.1.1.3 christos gdb_printf (gdb_stdlog, 482 1.1.1.3 christos "gcc_symbol_address \"%s\": failed\n", 483 1.1.1.3 christos identifier); 484 1.1 christos 485 1.1 christos if (compile_debug) 486 1.1 christos { 487 1.1 christos if (found) 488 1.1.1.3 christos gdb_printf (gdb_stdlog, "found address for %s!\n", identifier); 489 1.1 christos else 490 1.1.1.3 christos gdb_printf (gdb_stdlog, 491 1.1.1.3 christos "did not find address for %s\n", identifier); 492 1.1 christos } 493 1.1 christos 494 1.1 christos return result; 495 1.1 christos } 496