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