| /* C language support for compilation. |
| |
| Copyright (C) 2014-2016 Free Software Foundation, Inc. |
| |
| This file is part of GDB. |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
| |
| #include "defs.h" |
| #include "compile-internal.h" |
| #include "compile.h" |
| #include "gdb-dlfcn.h" |
| #include "c-lang.h" |
| #include "macrotab.h" |
| #include "macroscope.h" |
| #include "regcache.h" |
| |
| /* See compile-internal.h. */ |
| |
| const char * |
| c_get_mode_for_size (int size) |
| { |
| const char *mode = NULL; |
| |
| switch (size) |
| { |
| case 1: |
| mode = "QI"; |
| break; |
| case 2: |
| mode = "HI"; |
| break; |
| case 4: |
| mode = "SI"; |
| break; |
| case 8: |
| mode = "DI"; |
| break; |
| default: |
| internal_error (__FILE__, __LINE__, _("Invalid GCC mode size %d."), size); |
| } |
| |
| return mode; |
| } |
| |
| /* See compile-internal.h. */ |
| |
| char * |
| c_get_range_decl_name (const struct dynamic_prop *prop) |
| { |
| return xstrprintf ("__gdb_prop_%s", host_address_to_string (prop)); |
| } |
| |
| |
| |
| #define STR(x) #x |
| #define STRINGIFY(x) STR(x) |
| |
| /* Helper function for c_get_compile_context. Open the GCC front-end |
| shared library and return the symbol specified by the current |
| GCC_C_FE_CONTEXT. */ |
| |
| static gcc_c_fe_context_function * |
| load_libcc (void) |
| { |
| void *handle; |
| gcc_c_fe_context_function *func; |
| |
| /* gdb_dlopen will call error () on an error, so no need to check |
| value. */ |
| handle = gdb_dlopen (STRINGIFY (GCC_C_FE_LIBCC)); |
| func = (gcc_c_fe_context_function *) gdb_dlsym (handle, |
| STRINGIFY (GCC_C_FE_CONTEXT)); |
| |
| if (func == NULL) |
| error (_("could not find symbol %s in library %s"), |
| STRINGIFY (GCC_C_FE_CONTEXT), |
| STRINGIFY (GCC_C_FE_LIBCC)); |
| return func; |
| } |
| |
| /* Return the compile instance associated with the current context. |
| This function calls the symbol returned from the load_libcc |
| function. This will provide the gcc_c_context. */ |
| |
| struct compile_instance * |
| c_get_compile_context (void) |
| { |
| static gcc_c_fe_context_function *func; |
| |
| struct gcc_c_context *context; |
| |
| if (func == NULL) |
| { |
| func = load_libcc (); |
| gdb_assert (func != NULL); |
| } |
| |
| context = (*func) (GCC_FE_VERSION_0, GCC_C_FE_VERSION_0); |
| if (context == NULL) |
| error (_("The loaded version of GCC does not support the required version " |
| "of the API.")); |
| |
| return new_compile_instance (context); |
| } |
| |
| |
| |
| /* Write one macro definition. */ |
| |
| static void |
| print_one_macro (const char *name, const struct macro_definition *macro, |
| struct macro_source_file *source, int line, |
| void *user_data) |
| { |
| struct ui_file *file = (struct ui_file *) user_data; |
| |
| /* Don't print command-line defines. They will be supplied another |
| way. */ |
| if (line == 0) |
| return; |
| |
| /* None of -Wno-builtin-macro-redefined, #undef first |
| or plain #define of the same value would avoid a warning. */ |
| fprintf_filtered (file, "#ifndef %s\n# define %s", name, name); |
| |
| if (macro->kind == macro_function_like) |
| { |
| int i; |
| |
| fputs_filtered ("(", file); |
| for (i = 0; i < macro->argc; i++) |
| { |
| fputs_filtered (macro->argv[i], file); |
| if (i + 1 < macro->argc) |
| fputs_filtered (", ", file); |
| } |
| fputs_filtered (")", file); |
| } |
| |
| fprintf_filtered (file, " %s\n#endif\n", macro->replacement); |
| } |
| |
| /* Write macro definitions at PC to FILE. */ |
| |
| static void |
| write_macro_definitions (const struct block *block, CORE_ADDR pc, |
| struct ui_file *file) |
| { |
| struct macro_scope *scope; |
| |
| if (block != NULL) |
| scope = sal_macro_scope (find_pc_line (pc, 0)); |
| else |
| scope = default_macro_scope (); |
| if (scope == NULL) |
| scope = user_macro_scope (); |
| |
| if (scope != NULL && scope->file != NULL && scope->file->table != NULL) |
| macro_for_each_in_scope (scope->file, scope->line, print_one_macro, file); |
| } |
| |
| /* Helper function to construct a header scope for a block of code. |
| Takes a scope argument which selects the correct header to |
| insert into BUF. */ |
| |
| static void |
| add_code_header (enum compile_i_scope_types type, struct ui_file *buf) |
| { |
| switch (type) |
| { |
| case COMPILE_I_SIMPLE_SCOPE: |
| fputs_unfiltered ("void " |
| GCC_FE_WRAPPER_FUNCTION |
| " (struct " |
| COMPILE_I_SIMPLE_REGISTER_STRUCT_TAG |
| " *" |
| COMPILE_I_SIMPLE_REGISTER_ARG_NAME |
| ") {\n", |
| buf); |
| break; |
| case COMPILE_I_PRINT_ADDRESS_SCOPE: |
| case COMPILE_I_PRINT_VALUE_SCOPE: |
| /* <string.h> is needed for a memcpy call below. */ |
| fputs_unfiltered ("#include <string.h>\n" |
| "void " |
| GCC_FE_WRAPPER_FUNCTION |
| " (struct " |
| COMPILE_I_SIMPLE_REGISTER_STRUCT_TAG |
| " *" |
| COMPILE_I_SIMPLE_REGISTER_ARG_NAME |
| ", " |
| COMPILE_I_PRINT_OUT_ARG_TYPE |
| " " |
| COMPILE_I_PRINT_OUT_ARG |
| ") {\n", |
| buf); |
| break; |
| |
| case COMPILE_I_RAW_SCOPE: |
| break; |
| default: |
| gdb_assert_not_reached (_("Unknown compiler scope reached.")); |
| } |
| } |
| |
| /* Helper function to construct a footer scope for a block of code. |
| Takes a scope argument which selects the correct footer to |
| insert into BUF. */ |
| |
| static void |
| add_code_footer (enum compile_i_scope_types type, struct ui_file *buf) |
| { |
| switch (type) |
| { |
| case COMPILE_I_SIMPLE_SCOPE: |
| case COMPILE_I_PRINT_ADDRESS_SCOPE: |
| case COMPILE_I_PRINT_VALUE_SCOPE: |
| fputs_unfiltered ("}\n", buf); |
| break; |
| case COMPILE_I_RAW_SCOPE: |
| break; |
| default: |
| gdb_assert_not_reached (_("Unknown compiler scope reached.")); |
| } |
| } |
| |
| /* Generate a structure holding all the registers used by the function |
| we're generating. */ |
| |
| static void |
| generate_register_struct (struct ui_file *stream, struct gdbarch *gdbarch, |
| const unsigned char *registers_used) |
| { |
| int i; |
| int seen = 0; |
| |
| fputs_unfiltered ("struct " COMPILE_I_SIMPLE_REGISTER_STRUCT_TAG " {\n", |
| stream); |
| |
| if (registers_used != NULL) |
| for (i = 0; i < gdbarch_num_regs (gdbarch); ++i) |
| { |
| if (registers_used[i]) |
| { |
| struct type *regtype = check_typedef (register_type (gdbarch, i)); |
| char *regname = compile_register_name_mangled (gdbarch, i); |
| struct cleanup *cleanups = make_cleanup (xfree, regname); |
| |
| seen = 1; |
| |
| /* You might think we could use type_print here. However, |
| target descriptions often use types with names like |
| "int64_t", which may not be defined in the inferior |
| (and in any case would not be looked up due to the |
| #pragma business). So, we take a much simpler |
| approach: for pointer- or integer-typed registers, emit |
| the field in the most direct way; and for other |
| register types (typically flags or vectors), emit a |
| maximally-aligned array of the correct size. */ |
| |
| fputs_unfiltered (" ", stream); |
| switch (TYPE_CODE (regtype)) |
| { |
| case TYPE_CODE_PTR: |
| fprintf_filtered (stream, "__gdb_uintptr %s", regname); |
| break; |
| |
| case TYPE_CODE_INT: |
| { |
| const char *mode |
| = c_get_mode_for_size (TYPE_LENGTH (regtype)); |
| |
| if (mode != NULL) |
| { |
| if (TYPE_UNSIGNED (regtype)) |
| fputs_unfiltered ("unsigned ", stream); |
| fprintf_unfiltered (stream, |
| "int %s" |
| " __attribute__ ((__mode__(__%s__)))", |
| regname, |
| mode); |
| break; |
| } |
| } |
| |
| /* Fall through. */ |
| |
| default: |
| fprintf_unfiltered (stream, |
| " unsigned char %s[%d]" |
| " __attribute__((__aligned__(" |
| "__BIGGEST_ALIGNMENT__)))", |
| regname, |
| TYPE_LENGTH (regtype)); |
| } |
| fputs_unfiltered (";\n", stream); |
| |
| do_cleanups (cleanups); |
| } |
| } |
| |
| if (!seen) |
| fputs_unfiltered (" char " COMPILE_I_SIMPLE_REGISTER_DUMMY ";\n", |
| stream); |
| |
| fputs_unfiltered ("};\n\n", stream); |
| } |
| |
| /* Take the source code provided by the user with the 'compile' |
| command, and compute the additional wrapping, macro, variable and |
| register operations needed. INPUT is the source code derived from |
| the 'compile' command, GDBARCH is the architecture to use when |
| computing above, EXPR_BLOCK denotes the block relevant contextually |
| to the inferior when the expression was created, and EXPR_PC |
| indicates the value of $PC. */ |
| |
| char * |
| c_compute_program (struct compile_instance *inst, |
| const char *input, |
| struct gdbarch *gdbarch, |
| const struct block *expr_block, |
| CORE_ADDR expr_pc) |
| { |
| struct ui_file *buf, *var_stream = NULL; |
| char *code; |
| struct cleanup *cleanup; |
| struct compile_c_instance *context = (struct compile_c_instance *) inst; |
| |
| buf = mem_fileopen (); |
| cleanup = make_cleanup_ui_file_delete (buf); |
| |
| write_macro_definitions (expr_block, expr_pc, buf); |
| |
| /* Do not generate local variable information for "raw" |
| compilations. In this case we aren't emitting our own function |
| and the user's code may only refer to globals. */ |
| if (inst->scope != COMPILE_I_RAW_SCOPE) |
| { |
| unsigned char *registers_used; |
| int i; |
| |
| /* Generate the code to compute variable locations, but do it |
| before generating the function header, so we can define the |
| register struct before the function body. This requires a |
| temporary stream. */ |
| var_stream = mem_fileopen (); |
| make_cleanup_ui_file_delete (var_stream); |
| registers_used = generate_c_for_variable_locations (context, |
| var_stream, gdbarch, |
| expr_block, expr_pc); |
| make_cleanup (xfree, registers_used); |
| |
| fputs_unfiltered ("typedef unsigned int" |
| " __attribute__ ((__mode__(__pointer__)))" |
| " __gdb_uintptr;\n", |
| buf); |
| fputs_unfiltered ("typedef int" |
| " __attribute__ ((__mode__(__pointer__)))" |
| " __gdb_intptr;\n", |
| buf); |
| |
| /* Iterate all log2 sizes in bytes supported by c_get_mode_for_size. */ |
| for (i = 0; i < 4; ++i) |
| { |
| const char *mode = c_get_mode_for_size (1 << i); |
| |
| gdb_assert (mode != NULL); |
| fprintf_unfiltered (buf, |
| "typedef int" |
| " __attribute__ ((__mode__(__%s__)))" |
| " __gdb_int_%s;\n", |
| mode, mode); |
| } |
| |
| generate_register_struct (buf, gdbarch, registers_used); |
| } |
| |
| add_code_header (inst->scope, buf); |
| |
| if (inst->scope == COMPILE_I_SIMPLE_SCOPE |
| || inst->scope == COMPILE_I_PRINT_ADDRESS_SCOPE |
| || inst->scope == COMPILE_I_PRINT_VALUE_SCOPE) |
| { |
| ui_file_put (var_stream, ui_file_write_for_put, buf); |
| fputs_unfiltered ("#pragma GCC user_expression\n", buf); |
| } |
| |
| /* The user expression has to be in its own scope, so that "extern" |
| works properly. Otherwise gcc thinks that the "extern" |
| declaration is in the same scope as the declaration provided by |
| gdb. */ |
| if (inst->scope != COMPILE_I_RAW_SCOPE) |
| fputs_unfiltered ("{\n", buf); |
| |
| fputs_unfiltered ("#line 1 \"gdb command line\"\n", buf); |
| |
| switch (inst->scope) |
| { |
| case COMPILE_I_PRINT_ADDRESS_SCOPE: |
| case COMPILE_I_PRINT_VALUE_SCOPE: |
| fprintf_unfiltered (buf, |
| "__auto_type " COMPILE_I_EXPR_VAL " = %s;\n" |
| "typeof (%s) *" COMPILE_I_EXPR_PTR_TYPE ";\n" |
| "memcpy (" COMPILE_I_PRINT_OUT_ARG ", %s" COMPILE_I_EXPR_VAL ",\n" |
| "sizeof (*" COMPILE_I_EXPR_PTR_TYPE "));\n" |
| , input, input, |
| (inst->scope == COMPILE_I_PRINT_ADDRESS_SCOPE |
| ? "&" : "")); |
| break; |
| default: |
| fputs_unfiltered (input, buf); |
| break; |
| } |
| |
| fputs_unfiltered ("\n", buf); |
| |
| /* For larger user expressions the automatic semicolons may be |
| confusing. */ |
| if (strchr (input, '\n') == NULL) |
| fputs_unfiltered (";\n", buf); |
| |
| if (inst->scope != COMPILE_I_RAW_SCOPE) |
| fputs_unfiltered ("}\n", buf); |
| |
| add_code_footer (inst->scope, buf); |
| code = ui_file_xstrdup (buf, NULL); |
| do_cleanups (cleanup); |
| return code; |
| } |