From: Keith Seitz Date: Tue, 21 Feb 2017 21:32:58 +0000 (-0800) Subject: C++-ify compile/. X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=8e4430c2ec07ca8cc824b87da8a9c0cc917ad686;p=thirdparty%2Fbinutils-gdb.git C++-ify compile/. --- diff --git a/gdb/c-lang.h b/gdb/c-lang.h index c4b19ecfef6..58a81b01fce 100644 --- a/gdb/c-lang.h +++ b/gdb/c-lang.h @@ -150,7 +150,7 @@ extern int c_textual_element_type (struct type *, char); exception on failure. This is suitable for use as the la_get_compile_instance language method. */ -extern struct compile_instance *c_get_compile_context (void); +extern compile::compile_instance *c_get_compile_context (void); /* This takes the user-supplied text and returns a new bit of code to compile. @@ -158,7 +158,7 @@ extern struct compile_instance *c_get_compile_context (void); This is used as the la_compute_program language method; see that for a description of the arguments. */ -extern std::string c_compute_program (struct compile_instance *inst, +extern std::string c_compute_program (compile::compile_instance *inst, const char *input, struct gdbarch *gdbarch, const struct block *expr_block, diff --git a/gdb/compile/compile-c-support.c b/gdb/compile/compile-c-support.c index 7ad0a872f23..ead2bddf210 100644 --- a/gdb/compile/compile-c-support.c +++ b/gdb/compile/compile-c-support.c @@ -19,6 +19,7 @@ #include "defs.h" #include "compile-internal.h" +#include "compile-c.h" #include "compile.h" #include "gdb-dlfcn.h" #include "c-lang.h" @@ -62,57 +63,71 @@ 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. */ +/* Load the plug-in library FE_LIBCC and return the initialization function + FE_CONTEXT. */ -static gcc_c_fe_context_function * -load_libcc (void) +template +FUNCTYPE * +load_libcompile (const char *fe_libcc, const char *fe_context) { void *handle; - gcc_c_fe_context_function *func; + FUNCTYPE *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)); + /* gdb_dlopen will call error () on an error, so no need to check + value. */ + handle = gdb_dlopen (fe_libcc); + func = (FUNCTYPE *) (gdb_dlsym (handle, fe_context)); if (func == NULL) - error (_("could not find symbol %s in library %s"), - STRINGIFY (GCC_C_FE_CONTEXT), - STRINGIFY (GCC_C_FE_LIBCC)); + error (_("could not find symbol %s in library %s"), fe_context, 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) + This function calls the symbol returned from the load_libcompile + function. FE_LIBCC is the library to load. BASE_VERSION is the + base compile plug-in version we support. API_VERSION is the + API version supported. */ + +template +compile::compile_instance * +get_compile_context (const char *fe_libcc, const char *fe_context, + BASE_VERSION_TYPE base_version, + API_VERSION_TYPE api_version) { - static gcc_c_fe_context_function *func; - - struct gcc_c_context *context; + static FUNCTYPE *func; + static CTXTYPE *context; if (func == NULL) { - func = load_libcc (); + func = load_libcompile (fe_libcc, fe_context); gdb_assert (func != NULL); } - context = (*func) (GCC_FE_VERSION_0, GCC_C_FE_VERSION_0); + context = (*func) (base_version, api_version); if (context == NULL) error (_("The loaded version of GCC does not support the required version " "of the API.")); - return new_compile_instance (context); + return new INSTTYPE (context); +} + +/* A C-language implementation of get_compile_context. */ + +compile::compile_instance * +c_get_compile_context (void) +{ + using namespace compile; + + return get_compile_context + + (STRINGIFY (GCC_C_FE_LIBCC), STRINGIFY (GCC_C_FE_CONTEXT), + GCC_FE_VERSION_0, GCC_C_FE_VERSION_0); } @@ -171,71 +186,6 @@ write_macro_definitions (const struct block *block, CORE_ADDR pc, 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: - /* is needed for a memcpy call below. */ - fputs_unfiltered ("#include \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. */ @@ -318,114 +268,289 @@ generate_register_struct (struct ui_file *stream, struct gdbarch *gdbarch, 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. */ +/* C-language policy to emit a push user expression pragma into BUF. */ -std::string -c_compute_program (struct compile_instance *inst, - const char *input, - struct gdbarch *gdbarch, - const struct block *expr_block, - CORE_ADDR expr_pc) +struct c_push_user_expression { - struct compile_c_instance *context = (struct compile_c_instance *) inst; + void push_user_expression (struct ui_file *buf) + { + fputs_unfiltered ("#pragma GCC user_expression\n", buf); + } +}; - string_file buf; - string_file var_stream; +/* C-language policy to emit a pop user expression pragma into BUF. + For C, this is a nop. */ - write_macro_definitions (expr_block, expr_pc, &buf); +struct pop_user_expression_nop +{ + void pop_user_expression (struct ui_file *buf) + { + /* Nothing to do. */ + } +}; + +/* C-language policy to construct a code header for a block of code. + Takes a scope TYPE argument which selects the correct header to + insert into 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; +struct c_add_code_header +{ + 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: + /* is needed for a memcpy call below. */ + fputs_unfiltered ("#include \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.")); + } + } +}; - /* 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. */ - registers_used = generate_c_for_variable_locations (context, - var_stream, gdbarch, - expr_block, expr_pc); - make_cleanup (xfree, registers_used); - - buf.puts ("typedef unsigned int" - " __attribute__ ((__mode__(__pointer__)))" - " __gdb_uintptr;\n"); - buf.puts ("typedef int" - " __attribute__ ((__mode__(__pointer__)))" - " __gdb_intptr;\n"); - - /* 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); +/* C-language policy to construct a code footer for a block of code. + Takes a scope TYPE which selects the correct footer to insert into BUF. */ - gdb_assert (mode != NULL); - buf.printf ("typedef int" - " __attribute__ ((__mode__(__%s__)))" - " __gdb_int_%s;\n", - mode, mode); - } +struct c_add_code_footer +{ + 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; - generate_register_struct (&buf, gdbarch, registers_used); - } + case COMPILE_I_RAW_SCOPE: + break; - add_code_header (inst->scope, &buf); + default: + gdb_assert_not_reached (_("Unknown compiler scope reached.")); + } + } +}; - if (inst->scope == COMPILE_I_SIMPLE_SCOPE - || inst->scope == COMPILE_I_PRINT_ADDRESS_SCOPE - || inst->scope == COMPILE_I_PRINT_VALUE_SCOPE) - { - buf.write (var_stream.c_str (), var_stream.size ()); - buf.puts ("#pragma GCC user_expression\n"); - } +/* C-language policy to emit the user code snippet INPUT into BUF based on the + scope TYPE. */ - /* 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) - buf.puts ("{\n"); +struct c_add_input +{ + void add_input (enum compile_i_scope_types type, const char *input, + struct ui_file *buf) + { + switch (type) + { + 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, + (type == COMPILE_I_PRINT_ADDRESS_SCOPE + ? "&" : "")); + break; + + default: + fputs_unfiltered (input, buf); + break; + } + fputs_unfiltered ("\n", buf); + } +}; - buf.puts ("#line 1 \"gdb command line\"\n"); +/* A host class representing a compile program. - switch (inst->scope) - { - case COMPILE_I_PRINT_ADDRESS_SCOPE: - case COMPILE_I_PRINT_VALUE_SCOPE: - buf.printf ( -"__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: - buf.puts (input); - break; - } + CompileInstanceType is the type of the compile_instance for the + langauge. + + PushUserExpressionPolicy and PopUserExpressionPolicy are used to + push and pop user expression pragmas to the compile plug-in. + + AddCodeHeaderPolicy and AddCodeFooterPolicy are used to add the appropriate + code header and footer, respectively. + + AddInputPolicy adds the actual user code. */ + +template +class compile_program + : private PushUserExpressionPolicy, private PopUserExpressionPolicy, + private AddCodeHeaderPolicy, private AddCodeFooterPolicy, + private AddInputPolicy +{ + using PushUserExpressionPolicy::push_user_expression; + using PopUserExpressionPolicy::pop_user_expression; + using AddCodeHeaderPolicy::add_code_header; + using AddCodeFooterPolicy::add_code_footer; + using AddInputPolicy::add_input; + +public: + + /* Construct a compile_program using the compiler instance INST + using the architecture given by GDBARCH. */ + + compile_program (CompileInstanceType *inst, struct gdbarch *gdbarch) + : m_instance (inst), m_arch (gdbarch) + { + } + + /* 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, EXPR_BLOCK denotes the block relevant contextually + to the inferior when the expression was created, and EXPR_PC + indicates the value of $PC. + + Returns the text of the program to compile. This must be free'd by + the caller. */ + + std::string compute (const char *input, const struct block *expr_block, + CORE_ADDR expr_pc) + { + string_file var_stream; + string_file 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 (m_instance->scope () != COMPILE_I_RAW_SCOPE) + { + /* 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. */ + unsigned char *registers_used + = generate_c_for_variable_locations (m_instance, var_stream, m_arch, + expr_block, expr_pc); + make_cleanup (xfree, registers_used); + + buf.puts ("typedef unsigned int" + " __attribute__ ((__mode__(__pointer__)))" + " __gdb_uintptr;\n"); + buf.puts ("typedef int" + " __attribute__ ((__mode__(__pointer__)))" + " __gdb_intptr;\n"); + + /* Iterate all log2 sizes in bytes supported by c_get_mode_for_size. */ + for (int i = 0; i < 4; ++i) + { + const char *mode = c_get_mode_for_size (1 << i); + + gdb_assert (mode != NULL); + buf.printf ("typedef int" + " __attribute__ ((__mode__(__%s__)))" + " __gdb_int_%s;\n", + mode, mode); + } + + generate_register_struct (&buf, m_arch, registers_used); + } + + add_code_header (m_instance->scope (), &buf); + + if (m_instance->scope () == COMPILE_I_SIMPLE_SCOPE + || m_instance->scope () == COMPILE_I_PRINT_ADDRESS_SCOPE + || m_instance->scope () == COMPILE_I_PRINT_VALUE_SCOPE) + { + buf.write (var_stream.c_str (), var_stream.size ()); + push_user_expression (&buf); + } + + write_macro_definitions (expr_block, expr_pc, &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 (m_instance->scope () != COMPILE_I_RAW_SCOPE) + buf.puts ("{\n"); + + buf.puts ("#line 1 \"gdb command line\"\n"); + + add_input (m_instance->scope (), input, &buf); + + /* For larger user expressions the automatic semicolons may be + confusing. */ + if (strchr (input, '\n') == NULL) + buf.puts (";\n"); + + if (m_instance->scope () != COMPILE_I_RAW_SCOPE) + buf.puts ("}\n"); + + if (m_instance->scope () == COMPILE_I_SIMPLE_SCOPE + || m_instance->scope () == COMPILE_I_PRINT_ADDRESS_SCOPE + || m_instance->scope () == COMPILE_I_PRINT_VALUE_SCOPE) + pop_user_expression (&buf); - buf.puts ("\n"); + add_code_footer (m_instance->scope (), &buf); + return std::move (buf.string ()); + } - /* For larger user expressions the automatic semicolons may be - confusing. */ - if (strchr (input, '\n') == NULL) - buf.puts (";\n"); +private: + + /* The compile instance to be used for compilation and + type-conversion. */ + CompileInstanceType *m_instance; + + /* The architecture to be used. */ + struct gdbarch *m_arch; +}; + +/* Type used for C program computations. */ + +typedef compile_program c_compile_program; + +/* The la_compute_program method for C. */ + +std::string +c_compute_program (compile::compile_instance *inst, + const char *input, + struct gdbarch *gdbarch, + const struct block *expr_block, + CORE_ADDR expr_pc) +{ + using namespace compile; - if (inst->scope != COMPILE_I_RAW_SCOPE) - buf.puts ("}\n"); + compile_c_instance *c_inst = static_cast (inst); + c_compile_program program (c_inst, gdbarch); - add_code_footer (inst->scope, &buf); - return std::move (buf.string ()); + return program.compute (input, expr_block, expr_pc); } diff --git a/gdb/compile/compile-c-symbols.c b/gdb/compile/compile-c-symbols.c index 9282cfc0251..e5023af7281 100644 --- a/gdb/compile/compile-c-symbols.c +++ b/gdb/compile/compile-c-symbols.c @@ -20,6 +20,7 @@ #include "defs.h" #include "compile-internal.h" +#include "compile-c.h" #include "symtab.h" #include "parser-defs.h" #include "block.h" @@ -32,104 +33,12 @@ -/* Object of this type are stored in the compiler's symbol_err_map. */ +using namespace compile; -struct symbol_error -{ - /* The symbol. */ - - const struct symbol *sym; - - /* The error message to emit. This is malloc'd and owned by the - hash table. */ +/* See description in compile-c.h. */ - char *message; -}; - -/* Hash function for struct symbol_error. */ - -static hashval_t -hash_symbol_error (const void *a) -{ - const struct symbol_error *se = (const struct symbol_error *) a; - - return htab_hash_pointer (se->sym); -} - -/* Equality function for struct symbol_error. */ - -static int -eq_symbol_error (const void *a, const void *b) -{ - const struct symbol_error *sea = (const struct symbol_error *) a; - const struct symbol_error *seb = (const struct symbol_error *) b; - - return sea->sym == seb->sym; -} - -/* Deletion function for struct symbol_error. */ - -static void -del_symbol_error (void *a) -{ - struct symbol_error *se = (struct symbol_error *) a; - - xfree (se->message); - xfree (se); -} - -/* Associate SYMBOL with some error text. */ - -static void -insert_symbol_error (htab_t hash, const struct symbol *sym, const char *text) -{ - struct symbol_error e; - void **slot; - - e.sym = sym; - slot = htab_find_slot (hash, &e, INSERT); - if (*slot == NULL) - { - struct symbol_error *e = XNEW (struct symbol_error); - - e->sym = sym; - e->message = xstrdup (text); - *slot = e; - } -} - -/* Emit the error message corresponding to SYM, if one exists, and - arrange for it not to be emitted again. */ - -static void -error_symbol_once (struct compile_c_instance *context, - const struct symbol *sym) -{ - struct symbol_error search; - struct symbol_error *err; - char *message; - - if (context->symbol_err_map == NULL) - return; - - search.sym = sym; - err = (struct symbol_error *) htab_find (context->symbol_err_map, &search); - if (err == NULL || err->message == NULL) - return; - - message = err->message; - err->message = NULL; - make_cleanup (xfree, message); - error (_("%s"), message); -} - - - -/* Compute the name of the pointer representing a local symbol's - address. */ - -static char * -symbol_substitution_name (struct symbol *sym) +char * +c_symbol_substitution_name (struct symbol *sym) { return concat ("__", SYMBOL_NATURAL_NAME (sym), "_ptr", (char *) NULL); } @@ -142,7 +51,7 @@ symbol_substitution_name (struct symbol *sym) scope.) */ static void -convert_one_symbol (struct compile_c_instance *context, +convert_one_symbol (compile_c_instance *context, struct block_symbol sym, int is_global, int is_local) @@ -151,19 +60,18 @@ convert_one_symbol (struct compile_c_instance *context, const char *filename = symbol_symtab (sym.symbol)->filename; unsigned short line = SYMBOL_LINE (sym.symbol); - error_symbol_once (context, sym.symbol); + context->error_symbol_once (sym.symbol); if (SYMBOL_CLASS (sym.symbol) == LOC_LABEL) sym_type = 0; else - sym_type = convert_type (context, SYMBOL_TYPE (sym.symbol)); + sym_type = context->convert_type (SYMBOL_TYPE (sym.symbol)); if (SYMBOL_DOMAIN (sym.symbol) == STRUCT_DOMAIN) { /* Binding a tag, so we don't need to build a decl. */ - C_CTX (context)->c_ops->tagbind (C_CTX (context), - SYMBOL_NATURAL_NAME (sym.symbol), - sym_type, filename, line); + context->tagbind (SYMBOL_NATURAL_NAME (sym.symbol), + sym_type, filename, line); } else { @@ -196,9 +104,8 @@ convert_one_symbol (struct compile_c_instance *context, /* Already handled by convert_enum. */ return; } - C_CTX (context)->c_ops->build_constant - (C_CTX (context), - sym_type, SYMBOL_NATURAL_NAME (sym.symbol), + context->build_constant + (sym_type, SYMBOL_NATURAL_NAME (sym.symbol), SYMBOL_VALUE (sym.symbol), filename, line); return; @@ -267,7 +174,7 @@ convert_one_symbol (struct compile_c_instance *context, case LOC_LOCAL: substitution: kind = GCC_C_SYMBOL_VARIABLE; - symbol_name = symbol_substitution_name (sym.symbol); + symbol_name = c_symbol_substitution_name (sym.symbol); break; case LOC_STATIC: @@ -282,18 +189,17 @@ convert_one_symbol (struct compile_c_instance *context, } /* Don't emit local variable decls for a raw expression. */ - if (context->base.scope != COMPILE_I_RAW_SCOPE + if (context->scope () != COMPILE_I_RAW_SCOPE || symbol_name == NULL) { - decl = C_CTX (context)->c_ops->build_decl - (C_CTX (context), - SYMBOL_NATURAL_NAME (sym.symbol), + decl = context->build_decl + (SYMBOL_NATURAL_NAME (sym.symbol), kind, sym_type, symbol_name, addr, filename, line); - C_CTX (context)->c_ops->bind (C_CTX (context), decl, is_global); + context->bind (decl, is_global); } xfree (symbol_name); @@ -305,7 +211,7 @@ convert_one_symbol (struct compile_c_instance *context, itself, and DOMAIN is the domain which was searched. */ static void -convert_symbol_sym (struct compile_c_instance *context, const char *identifier, +convert_symbol_sym (compile_c_instance *context, const char *identifier, struct block_symbol sym, domain_enum domain) { const struct block *static_block; @@ -355,7 +261,7 @@ convert_symbol_sym (struct compile_c_instance *context, const char *identifier, to use and BMSYM is the minimal symbol to convert. */ static void -convert_symbol_bmsym (struct compile_c_instance *context, +convert_symbol_bmsym (compile_c_instance *context, struct bound_minimal_symbol bmsym) { struct minimal_symbol *msym = bmsym.minsym; @@ -405,12 +311,10 @@ convert_symbol_bmsym (struct compile_c_instance *context, break; } - sym_type = convert_type (context, type); - decl = C_CTX (context)->c_ops->build_decl (C_CTX (context), - MSYMBOL_NATURAL_NAME (msym), - kind, sym_type, NULL, addr, - NULL, 0); - C_CTX (context)->c_ops->bind (C_CTX (context), decl, 1 /* is_global */); + sym_type = context->convert_type (type); + decl = context->build_decl (MSYMBOL_NATURAL_NAME (msym), + kind, sym_type, NULL, addr, NULL, 0); + context->bind (decl, true /* is_global */); } /* See compile-internal.h. */ @@ -421,7 +325,7 @@ gcc_convert_symbol (void *datum, enum gcc_c_oracle_request request, const char *identifier) { - struct compile_c_instance *context = (struct compile_c_instance *) datum; + compile_c_instance *context = static_cast (datum); domain_enum domain; int found = 0; @@ -446,7 +350,7 @@ gcc_convert_symbol (void *datum, { struct block_symbol sym; - sym = lookup_symbol (identifier, context->base.block, domain, NULL); + sym = lookup_symbol (identifier, context->block (), domain, NULL); if (sym.symbol != NULL) { convert_symbol_sym (context, identifier, sym, domain); @@ -467,7 +371,7 @@ gcc_convert_symbol (void *datum, CATCH (e, RETURN_MASK_ALL) { - C_CTX (context)->c_ops->error (C_CTX (context), e.message); + context->error (e.message); } END_CATCH @@ -484,7 +388,7 @@ gcc_address gcc_symbol_address (void *datum, struct gcc_c_context *gcc_context, const char *identifier) { - struct compile_c_instance *context = (struct compile_c_instance *) datum; + compile_c_instance *context = static_cast (datum); gcc_address result = 0; int found = 0; @@ -529,7 +433,7 @@ gcc_symbol_address (void *datum, struct gcc_c_context *gcc_context, CATCH (e, RETURN_MASK_ERROR) { - C_CTX (context)->c_ops->error (C_CTX (context), e.message); + context->error (e.message); } END_CATCH @@ -583,7 +487,7 @@ symbol_seen (htab_t hashtab, struct symbol *sym) /* Generate C code to compute the length of a VLA. */ static void -generate_vla_size (struct compile_c_instance *compiler, +generate_vla_size (compile_instance *compiler, string_file &stream, struct gdbarch *gdbarch, unsigned char *registers_used, @@ -639,7 +543,7 @@ generate_vla_size (struct compile_c_instance *compiler, /* Generate C code to compute the address of SYM. */ static void -generate_c_for_for_one_variable (struct compile_c_instance *compiler, +generate_c_for_for_one_variable (compile_instance *compiler, string_file &stream, struct gdbarch *gdbarch, unsigned char *registers_used, @@ -663,7 +567,7 @@ generate_c_for_for_one_variable (struct compile_c_instance *compiler, if (SYMBOL_COMPUTED_OPS (sym) != NULL) { - char *generated_name = symbol_substitution_name (sym); + char *generated_name = c_symbol_substitution_name (sym); struct cleanup *cleanup = make_cleanup (xfree, generated_name); /* We need to emit to a temporary buffer in case an error occurs in the middle. */ @@ -702,22 +606,15 @@ generate_c_for_for_one_variable (struct compile_c_instance *compiler, CATCH (e, RETURN_MASK_ERROR) { - if (compiler->symbol_err_map == NULL) - compiler->symbol_err_map = htab_create_alloc (10, - hash_symbol_error, - eq_symbol_error, - del_symbol_error, - xcalloc, - xfree); - insert_symbol_error (compiler->symbol_err_map, sym, e.message); + compiler->insert_symbol_error (sym, e.message); } END_CATCH } -/* See compile-internal.h. */ +/* See compile-c.h. */ unsigned char * -generate_c_for_variable_locations (struct compile_c_instance *compiler, +generate_c_for_variable_locations (compile_instance *compiler, string_file &stream, struct gdbarch *gdbarch, const struct block *block, diff --git a/gdb/compile/compile-c-types.c b/gdb/compile/compile-c-types.c index 5ce4cdef06a..47a1925b1ac 100644 --- a/gdb/compile/compile-c-types.c +++ b/gdb/compile/compile-c-types.c @@ -21,103 +21,36 @@ #include "defs.h" #include "gdbtypes.h" #include "compile-internal.h" -/* An object that maps a gdb type to a gcc type. */ +#include "compile-c.h" -struct type_map_instance -{ - /* The gdb type. */ - - struct type *type; - - /* The corresponding gcc type handle. */ - - gcc_type gcc_type_handle; -}; - -/* Hash a type_map_instance. */ - -static hashval_t -hash_type_map_instance (const void *p) -{ - const struct type_map_instance *inst = (const struct type_map_instance *) p; - - return htab_hash_pointer (inst->type); -} - -/* Check two type_map_instance objects for equality. */ - -static int -eq_type_map_instance (const void *a, const void *b) -{ - const struct type_map_instance *insta = (const struct type_map_instance *) a; - const struct type_map_instance *instb = (const struct type_map_instance *) b; - - return insta->type == instb->type; -} - - - -/* Insert an entry into the type map associated with CONTEXT that maps - from the gdb type TYPE to the gcc type GCC_TYPE. It is ok for a - given type to be inserted more than once, provided that the exact - same association is made each time. This simplifies how type - caching works elsewhere in this file -- see how struct type caching - is handled. */ - -static void -insert_type (struct compile_c_instance *context, struct type *type, - gcc_type gcc_type) -{ - struct type_map_instance inst, *add; - void **slot; - - inst.type = type; - inst.gcc_type_handle = gcc_type; - slot = htab_find_slot (context->type_map, &inst, INSERT); - - add = (struct type_map_instance *) *slot; - /* The type might have already been inserted in order to handle - recursive types. */ - if (add != NULL && add->gcc_type_handle != gcc_type) - error (_("Unexpected type id from GCC, check you use recent enough GCC.")); - - if (add == NULL) - { - add = XNEW (struct type_map_instance); - *add = inst; - *slot = add; - } -} +using namespace compile; /* Convert a pointer type to its gcc representation. */ static gcc_type -convert_pointer (struct compile_c_instance *context, struct type *type) +convert_pointer (compile_c_instance *context, struct type *type) { - gcc_type target = convert_type (context, TYPE_TARGET_TYPE (type)); + gcc_type target = context->convert_type (TYPE_TARGET_TYPE (type)); - return C_CTX (context)->c_ops->build_pointer_type (C_CTX (context), - target); + return context->build_pointer_type (target); } /* Convert an array type to its gcc representation. */ static gcc_type -convert_array (struct compile_c_instance *context, struct type *type) +convert_array (compile_c_instance *context, struct type *type) { gcc_type element_type; struct type *range = TYPE_INDEX_TYPE (type); - element_type = convert_type (context, TYPE_TARGET_TYPE (type)); + element_type = context->convert_type (TYPE_TARGET_TYPE (type)); if (TYPE_LOW_BOUND_KIND (range) != PROP_CONST) - return C_CTX (context)->c_ops->error (C_CTX (context), - _("array type with non-constant" - " lower bound is not supported")); + return context->error (_("array type with non-constant" + " lower bound is not supported")); if (TYPE_LOW_BOUND (range) != 0) - return C_CTX (context)->c_ops->error (C_CTX (context), - _("cannot convert array type with " - "non-zero lower bound to C")); + return context->error (_("cannot convert array type with " + "non-zero lower bound to C")); if (TYPE_HIGH_BOUND_KIND (range) == PROP_LOCEXPR || TYPE_HIGH_BOUND_KIND (range) == PROP_LOCLIST) @@ -126,14 +59,11 @@ convert_array (struct compile_c_instance *context, struct type *type) char *upper_bound; if (TYPE_VECTOR (type)) - return C_CTX (context)->c_ops->error (C_CTX (context), - _("variably-sized vector type" - " is not supported")); + return context->error (_("variably-sized vector type" + " is not supported")); upper_bound = c_get_range_decl_name (&TYPE_RANGE_DATA (range)->high); - result = C_CTX (context)->c_ops->build_vla_array_type (C_CTX (context), - element_type, - upper_bound); + result = context->build_vla_array_type (element_type, upper_bound); xfree (upper_bound); return result; } @@ -150,18 +80,15 @@ convert_array (struct compile_c_instance *context, struct type *type) } if (TYPE_VECTOR (type)) - return C_CTX (context)->c_ops->build_vector_type (C_CTX (context), - element_type, - count); - return C_CTX (context)->c_ops->build_array_type (C_CTX (context), - element_type, count); + return context->build_vector_type (element_type, count); + return context->build_array_type (element_type, count); } } /* Convert a struct or union type to its gcc representation. */ static gcc_type -convert_struct_or_union (struct compile_c_instance *context, struct type *type) +convert_struct_or_union (compile_c_instance *context, struct type *type) { int i; gcc_type result; @@ -169,63 +96,53 @@ convert_struct_or_union (struct compile_c_instance *context, struct type *type) /* First we create the resulting type and enter it into our hash table. This lets recursive types work. */ if (TYPE_CODE (type) == TYPE_CODE_STRUCT) - result = C_CTX (context)->c_ops->build_record_type (C_CTX (context)); + result = context->build_record_type (); else { gdb_assert (TYPE_CODE (type) == TYPE_CODE_UNION); - result = C_CTX (context)->c_ops->build_union_type (C_CTX (context)); + result = context->build_union_type (); } - insert_type (context, type, result); + context->insert_type (type, result); for (i = 0; i < TYPE_NFIELDS (type); ++i) { gcc_type field_type; unsigned long bitsize = TYPE_FIELD_BITSIZE (type, i); - field_type = convert_type (context, TYPE_FIELD_TYPE (type, i)); + field_type = context->convert_type (TYPE_FIELD_TYPE (type, i)); if (bitsize == 0) bitsize = 8 * TYPE_LENGTH (TYPE_FIELD_TYPE (type, i)); - C_CTX (context)->c_ops->build_add_field (C_CTX (context), result, - TYPE_FIELD_NAME (type, i), - field_type, - bitsize, - TYPE_FIELD_BITPOS (type, i)); + context->build_add_field (result, TYPE_FIELD_NAME (type, i), + field_type, bitsize, + TYPE_FIELD_BITPOS (type, i)); } - C_CTX (context)->c_ops->finish_record_or_union (C_CTX (context), result, - TYPE_LENGTH (type)); + context->finish_record_or_union (result, TYPE_LENGTH (type)); return result; } /* Convert an enum type to its gcc representation. */ static gcc_type -convert_enum (struct compile_c_instance *context, struct type *type) +convert_enum (compile_c_instance *context, struct type *type) { gcc_type int_type, result; int i; - struct gcc_c_context *ctx = C_CTX (context); - if (C_CTX (context)->c_ops->c_version >= GCC_C_FE_VERSION_1) - int_type = ctx->c_ops->int_type (ctx, - TYPE_UNSIGNED (type), - TYPE_LENGTH (type), - NULL); + if (context->c_version () >= GCC_C_FE_VERSION_1) + int_type = context->int_type (TYPE_UNSIGNED (type), TYPE_LENGTH (type), + NULL); else - int_type = ctx->c_ops->int_type_v0 (ctx, - TYPE_UNSIGNED (type), - TYPE_LENGTH (type)); + int_type = context->int_type (TYPE_UNSIGNED (type), TYPE_LENGTH (type)); - result = ctx->c_ops->build_enum_type (ctx, int_type); + result = context->build_enum_type (int_type); for (i = 0; i < TYPE_NFIELDS (type); ++i) { - ctx->c_ops->build_add_enum_constant (ctx, - result, - TYPE_FIELD_NAME (type, i), - TYPE_FIELD_ENUMVAL (type, i)); + context->build_add_enum_constant (result, TYPE_FIELD_NAME (type, i), + TYPE_FIELD_ENUMVAL (type, i)); } - ctx->c_ops->finish_enum_type (ctx, result); + context->finish_enum_type (result); return result; } @@ -233,7 +150,7 @@ convert_enum (struct compile_c_instance *context, struct type *type) /* Convert a function type to its gcc representation. */ static gcc_type -convert_func (struct compile_c_instance *context, struct type *type) +convert_func (compile_c_instance *context, struct type *type) { int i; gcc_type result, return_type; @@ -242,16 +159,14 @@ convert_func (struct compile_c_instance *context, struct type *type) /* This approach means we can't make self-referential function types. Those are impossible in C, though. */ - return_type = convert_type (context, TYPE_TARGET_TYPE (type)); + return_type = context->convert_type (TYPE_TARGET_TYPE (type)); array.n_elements = TYPE_NFIELDS (type); array.elements = XNEWVEC (gcc_type, TYPE_NFIELDS (type)); for (i = 0; i < TYPE_NFIELDS (type); ++i) - array.elements[i] = convert_type (context, TYPE_FIELD_TYPE (type, i)); + array.elements[i] = context->convert_type (TYPE_FIELD_TYPE (type, i)); - result = C_CTX (context)->c_ops->build_function_type (C_CTX (context), - return_type, - &array, is_varargs); + result = context->build_function_type (return_type, &array, is_varargs); xfree (array.elements); return result; @@ -260,66 +175,59 @@ convert_func (struct compile_c_instance *context, struct type *type) /* Convert an integer type to its gcc representation. */ static gcc_type -convert_int (struct compile_c_instance *context, struct type *type) +convert_int (compile_c_instance *context, struct type *type) { - if (C_CTX (context)->c_ops->c_version >= GCC_C_FE_VERSION_1) + if (context->c_version () >= GCC_C_FE_VERSION_1) { if (TYPE_NOSIGN (type)) { gdb_assert (TYPE_LENGTH (type) == 1); - return C_CTX (context)->c_ops->char_type (C_CTX (context)); + return context->char_type (); } - return C_CTX (context)->c_ops->int_type (C_CTX (context), - TYPE_UNSIGNED (type), - TYPE_LENGTH (type), - TYPE_NAME (type)); + return context->int_type (TYPE_UNSIGNED (type), TYPE_LENGTH (type), + TYPE_NAME (type)); } else - return C_CTX (context)->c_ops->int_type_v0 (C_CTX (context), - TYPE_UNSIGNED (type), - TYPE_LENGTH (type)); + return context->int_type (TYPE_UNSIGNED (type), TYPE_LENGTH (type)); } /* Convert a floating-point type to its gcc representation. */ static gcc_type -convert_float (struct compile_c_instance *context, struct type *type) +convert_float (compile_c_instance *context, struct type *type) { - if (C_CTX (context)->c_ops->c_version >= GCC_C_FE_VERSION_1) - return C_CTX (context)->c_ops->float_type (C_CTX (context), - TYPE_LENGTH (type), - TYPE_NAME (type)); + if (context->c_version () >= GCC_C_FE_VERSION_1) + return context->float_type (TYPE_LENGTH (type), TYPE_NAME (type)); else - return C_CTX (context)->c_ops->float_type_v0 (C_CTX (context), - TYPE_LENGTH (type)); + return context->float_type (TYPE_LENGTH (type)); } /* Convert the 'void' type to its gcc representation. */ static gcc_type -convert_void (struct compile_c_instance *context, struct type *type) +convert_void (compile_c_instance *context, struct type *type) { - return C_CTX (context)->c_ops->void_type (C_CTX (context)); + return context->void_type (); } /* Convert a boolean type to its gcc representation. */ static gcc_type -convert_bool (struct compile_c_instance *context, struct type *type) +convert_bool (compile_c_instance *context, struct type *type) { - return C_CTX (context)->c_ops->bool_type (C_CTX (context)); + return context->bool_type (); } /* Convert a qualified type to its gcc representation. */ static gcc_type -convert_qualified (struct compile_c_instance *context, struct type *type) +convert_qualified (compile_c_instance *context, struct type *type) { struct type *unqual = make_unqualified_type (type); gcc_type unqual_converted; gcc_qualifiers_flags quals = 0; - unqual_converted = convert_type (context, unqual); + unqual_converted = context->convert_type (unqual); if (TYPE_CONST (type)) quals |= GCC_QUALIFIER_CONST; @@ -328,19 +236,17 @@ convert_qualified (struct compile_c_instance *context, struct type *type) if (TYPE_RESTRICT (type)) quals |= GCC_QUALIFIER_RESTRICT; - return C_CTX (context)->c_ops->build_qualified_type (C_CTX (context), - unqual_converted, - quals); + return context->build_qualified_type (unqual_converted, quals); } /* Convert a complex type to its gcc representation. */ static gcc_type -convert_complex (struct compile_c_instance *context, struct type *type) +convert_complex (compile_c_instance *context, struct type *type) { - gcc_type base = convert_type (context, TYPE_TARGET_TYPE (type)); + gcc_type base = context->convert_type (TYPE_TARGET_TYPE (type)); - return C_CTX (context)->c_ops->build_complex_type (C_CTX (context), base); + return context->build_complex_type (base); } /* A helper function which knows how to convert most types from their @@ -349,7 +255,7 @@ convert_complex (struct compile_c_instance *context, struct type *type) returns the gcc type. */ static gcc_type -convert_type_basic (struct compile_c_instance *context, struct type *type) +convert_type_basic (compile_c_instance *context, struct type *type) { /* If we are converting a qualified type, first convert the unqualified type and then apply the qualifiers. */ @@ -392,70 +298,219 @@ convert_type_basic (struct compile_c_instance *context, struct type *type) return convert_complex (context, type); } - return C_CTX (context)->c_ops->error (C_CTX (context), - _("cannot convert gdb type " - "to gcc type")); + return context->error (_("cannot convert gdb type to gcc type")); } -/* See compile-internal.h. */ +/* Default compile flags for C. */ + +const char *compile_c_instance::m_default_cflags = "-std=gnu11" + /* Otherwise the .o file may need + "_Unwind_Resume" and + "__gcc_personality_v0". */ + " -fno-exceptions" + " -Wno-implicit-function-declaration"; gcc_type -convert_type (struct compile_c_instance *context, struct type *type) +compile_c_instance::convert_type (struct type *type) { - struct type_map_instance inst, *found; - gcc_type result; - /* We don't ever have to deal with typedefs in this code, because those are only needed as symbols by the C compiler. */ type = check_typedef (type); - inst.type = type; - found = (struct type_map_instance *) htab_find (context->type_map, &inst); - if (found != NULL) - return found->gcc_type_handle; + type_map_t::iterator pos = m_type_map.find (type); + if (pos != m_type_map.end ()) + return pos->second; - result = convert_type_basic (context, type); - insert_type (context, type, result); + gcc_type result = convert_type_basic (this, type); + insert_type (type, result); return result; } - +#define FORWARD(OP,...) (m_context->c_ops->OP (m_context, ##__VA_ARGS__)) + +unsigned int +compile_c_instance::c_version () const +{ + return m_context->c_ops->c_version; +} + +bool +compile_c_instance::tagbind (const char *name, gcc_type tagged_type, + const char *filename, unsigned int line_number) +{ + return FORWARD (tagbind, name, tagged_type, filename, line_number); +} + +bool +compile_c_instance::build_constant (gcc_type type, const char *name, + unsigned long value, const char *filename, + unsigned int line_number) +{ + return FORWARD (build_constant, type, name, value, filename, line_number); +} + +gcc_decl +compile_c_instance::build_decl (const char *name, + enum gcc_c_symbol_kind sym_kind, + gcc_type sym_type, + const char *substitution_name, + gcc_address address, const char *filename, + unsigned int line_number) +{ + return FORWARD (build_decl, name, sym_kind, sym_type, substitution_name, + address, filename, line_number); +} + +bool +compile_c_instance::bind (gcc_decl decl, bool is_global) +{ + return FORWARD (bind, decl, is_global); +} + +gcc_type +compile_c_instance::error (const char *message) +{ + return FORWARD (error, message); +} + +gcc_type +compile_c_instance::build_pointer_type (gcc_type base_type) +{ + return FORWARD (build_pointer_type, base_type); +} + +gcc_type +compile_c_instance::build_vla_array_type (gcc_type element_type, + const char *upper_bound_name) +{ + return FORWARD (build_vla_array_type, element_type, upper_bound_name); +} + +gcc_type +compile_c_instance::build_vector_type (gcc_type element_type, int num_elements) +{ + return FORWARD (build_vector_type, element_type, num_elements); +} + +gcc_type +compile_c_instance::build_array_type (gcc_type element_type, int num_elements) +{ + return FORWARD (build_array_type, element_type, num_elements); +} -/* Delete the compiler instance C. */ +gcc_type +compile_c_instance::build_record_type () +{ + return FORWARD (build_record_type); +} -static void -delete_instance (struct compile_instance *c) +gcc_type +compile_c_instance::build_union_type () { - struct compile_c_instance *context = (struct compile_c_instance *) c; + return FORWARD (build_union_type); +} - context->base.fe->ops->destroy (context->base.fe); - htab_delete (context->type_map); - if (context->symbol_err_map != NULL) - htab_delete (context->symbol_err_map); - xfree (context); +bool +compile_c_instance::build_add_field (gcc_type record_or_union_type, + const char *field_name, + gcc_type field_type, unsigned long bitsize, + unsigned long bitpos) +{ + return FORWARD (build_add_field, record_or_union_type, field_name, + field_type, bitsize, bitpos); } -/* See compile-internal.h. */ +bool +compile_c_instance::finish_record_or_union (gcc_type record_or_union_type, + unsigned long size_in_bytes) +{ + return FORWARD (finish_record_or_union, record_or_union_type, size_in_bytes); +} -struct compile_instance * -new_compile_instance (struct gcc_c_context *fe) +gcc_type +compile_c_instance::int_type (bool is_unsigned, unsigned long size_in_bytes, + const char *builtin_name) { - struct compile_c_instance *result = XCNEW (struct compile_c_instance); + return FORWARD (int_type, is_unsigned, size_in_bytes, builtin_name); +} - result->base.fe = &fe->base; - result->base.destroy = delete_instance; - result->base.gcc_target_options = ("-std=gnu11" - /* Otherwise the .o file may need - "_Unwind_Resume" and - "__gcc_personality_v0". */ - " -fno-exceptions"); +gcc_type +compile_c_instance::int_type (bool is_unsigned, unsigned long size_in_bytes) +{ + return FORWARD (int_type_v0, is_unsigned, size_in_bytes); +} + +gcc_type +compile_c_instance::build_enum_type (gcc_type underlying_int_type) +{ + return FORWARD (build_enum_type, underlying_int_type); +} - result->type_map = htab_create_alloc (10, hash_type_map_instance, - eq_type_map_instance, - xfree, xcalloc, xfree); +bool +compile_c_instance::build_add_enum_constant (gcc_type enum_type, + const char *name, + unsigned long value) +{ + return FORWARD (build_add_enum_constant, enum_type, name, value); +} - fe->c_ops->set_callbacks (fe, gcc_convert_symbol, - gcc_symbol_address, result); +bool +compile_c_instance::finish_enum_type (gcc_type enum_type) +{ + return FORWARD (finish_enum_type, enum_type); +} - return &result->base; +gcc_type +compile_c_instance::build_function_type (gcc_type return_value, + const struct gcc_type_array *argument_types, + bool is_varargs) +{ + return FORWARD (build_function_type, return_value, argument_types, + is_varargs); } + +gcc_type +compile_c_instance::char_type () +{ + return FORWARD (char_type); +} + +gcc_type +compile_c_instance::float_type (unsigned long size_in_bytes, + const char *builtin_name) +{ + return FORWARD (float_type, size_in_bytes, builtin_name); +} + +gcc_type +compile_c_instance::float_type (unsigned long size_in_bytes) +{ + return FORWARD (float_type_v0, size_in_bytes); +} + +gcc_type +compile_c_instance::void_type () +{ + return FORWARD (void_type); +} + +gcc_type +compile_c_instance::bool_type () +{ + return FORWARD (bool_type); +} + +gcc_type +compile_c_instance::build_qualified_type (gcc_type unqualified_type, + enum gcc_qualifiers qualifiers) +{ + return FORWARD (build_qualified_type, unqualified_type, qualifiers); +} + +gcc_type +compile_c_instance::build_complex_type (gcc_type element_type) +{ + return FORWARD (build_complex_type, element_type); +} + +#undef FORWARD diff --git a/gdb/compile/compile-c.h b/gdb/compile/compile-c.h new file mode 100644 index 00000000000..fd2b380c057 --- /dev/null +++ b/gdb/compile/compile-c.h @@ -0,0 +1,176 @@ +/* Header file for GDB compile C-language support. + Copyright (C) 2014-2017 Free Software Foundation, Inc. + + 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 . */ + +#ifndef GDB_COMPILE_C_H +#define GDB_COMPILE_C_H + +#include "common/enum-flags.h" + +/* enum-flags wrapper. */ +DEF_ENUM_FLAGS_TYPE (enum gcc_qualifiers, gcc_qualifiers_flags); + +/* A callback suitable for use as the GCC C symbol oracle. */ + +extern gcc_c_oracle_function gcc_convert_symbol; + +/* A callback suitable for use as the GCC C address oracle. */ + +extern gcc_c_symbol_address_function gcc_symbol_address; + +namespace compile +{ + + /* A subclass of compile_instance that is specific to the C front + end. */ + + class compile_c_instance + : public compile_instance + { + public: + + compile_c_instance (struct gcc_base_context *base, const char *options) + : compile_instance (base, options) + { + } + + explicit compile_c_instance (struct gcc_c_context *gcc_c) + : compile_instance (&gcc_c->base, m_default_cflags), m_context (gcc_c) + { + m_context->c_ops->set_callbacks (m_context, gcc_convert_symbol, + gcc_symbol_address, this); + } + + ~compile_c_instance () + { + m_gcc_fe->ops->destroy (m_gcc_fe); + } + + /* Convert a gdb type, TYPE, to a GCC type. + + The new GCC type is returned. */ + + gcc_type convert_type (struct type *type); + + /* Plug-in forwards */ + + unsigned int c_version () const; + + bool tagbind (const char *name, gcc_type tagged_type, const char *filename, + unsigned int line_number); + + bool build_constant (gcc_type type, const char *name, unsigned long value, + const char *filename, unsigned int line_number); + + gcc_decl build_decl (const char *name, enum gcc_c_symbol_kind sym_kind, + gcc_type sym_type, const char *substitution_name, + gcc_address address, const char *filename, + unsigned int line_number); + + bool bind (gcc_decl decl, bool is_global); + + gcc_type error (const char *message); + + gcc_type build_pointer_type (gcc_type base_type); + + gcc_type build_vla_array_type (gcc_type element_type, + const char *upper_bound_name); + + gcc_type build_vector_type (gcc_type element_type, int num_elements); + + gcc_type build_array_type (gcc_type element_type, int num_elements); + + gcc_type build_record_type (); + + gcc_type build_union_type (); + + bool build_add_field (gcc_type record_or_union_type, const char *field_name, + gcc_type field_type, unsigned long bitsize, + unsigned long bitpos); + + bool finish_record_or_union (gcc_type record_or_union_type, + unsigned long size_in_bytes); + + gcc_type int_type (bool is_unsigned, unsigned long size_in_bytes, + const char *builtin_name); + + gcc_type int_type (bool is_unsigned, unsigned long size_in_bytes); + + gcc_type build_enum_type (gcc_type underlying_int_type); + + bool build_add_enum_constant (gcc_type enum_type, const char *name, + unsigned long value); + + bool finish_enum_type (gcc_type enum_type); + + gcc_type build_function_type (gcc_type return_value, + const struct gcc_type_array *argument_types, + bool is_varargs); + + gcc_type char_type (); + + gcc_type float_type (unsigned long size_in_bytes, const char *builtin_name); + + gcc_type float_type (unsigned long size_in_bytes); + + gcc_type void_type (); + + gcc_type bool_type (); + + gcc_type build_qualified_type (gcc_type unqualified_type, + enum gcc_qualifiers qualifiers); + + gcc_type build_complex_type (gcc_type element_type); + + private: + + /* Default compiler flags for C. */ + static const char *m_default_cflags; + + /* The GCC C context. */ + struct gcc_c_context *m_context; + }; +}; + +/* Emit code to compute the address for all the local variables in + scope at PC in BLOCK. Returns a malloc'd vector, indexed by gdb + register number, where each element indicates if the corresponding + register is needed to compute a local variable. */ + +extern unsigned char *generate_c_for_variable_locations + (compile::compile_instance *compiler, + string_file &stream, + struct gdbarch *gdbarch, + const struct block *block, + CORE_ADDR pc); + +/* Get the GCC mode attribute value for a given type size. */ + +extern const char *c_get_mode_for_size (int size); + +/* Given a dynamic property, return an xmallocd name that is used to + represent its size. The result must be freed by the caller. The + contents of the resulting string will be the same each time for + each call with the same argument. */ + +struct dynamic_prop; +extern char *c_get_range_decl_name (const struct dynamic_prop *prop); + +/* Compute the name of the pointer representing a local symbol's + address. */ + +extern char *c_symbol_substitution_name (struct symbol *sym); + +#endif /* GDB_COMPILE_C_H */ diff --git a/gdb/compile/compile-internal.h b/gdb/compile/compile-internal.h index 0c53f8c4432..292282e6550 100644 --- a/gdb/compile/compile-internal.h +++ b/gdb/compile/compile-internal.h @@ -17,12 +17,11 @@ #ifndef GDB_COMPILE_INTERNAL_H #define GDB_COMPILE_INTERNAL_H -#include "hashtab.h" +#include "defs.h" #include "gcc-c-interface.h" -#include "common/enum-flags.h" -/* enum-flags wrapper. */ -DEF_ENUM_FLAGS_TYPE (enum gcc_qualifiers, gcc_qualifiers_flags); +#include +#include /* Debugging flag for the "compile" family of commands. */ @@ -30,57 +29,153 @@ extern int compile_debug; struct block; -/* An object of this type holds state associated with a given - compilation job. */ - -struct compile_instance +namespace compile { - /* The GCC front end. */ + /* An object of this type holds state associated with a given + compilation job. */ - struct gcc_base_context *fe; + class compile_instance + { + public: - /* The "scope" of this compilation. */ + compile_instance (struct gcc_base_context *gcc_fe, const char *options) + : m_gcc_fe (gcc_fe), m_gcc_target_options (options) + { + } - enum compile_i_scope_types scope; + virtual ~compile_instance () + { + } - /* The block in which an expression is being parsed. */ + /* Returns the GCC options to be passed during compilation. */ - const struct block *block; + const std::string &gcc_target_options () const + { + return m_gcc_target_options; + } - /* Specify "-std=gnu11", "-std=gnu++11" or similar. These options are put - after CU's DW_AT_producer compilation options to override them. */ + /* Insert GCC_TYPE into the type cache for TYPE. - const char *gcc_target_options; + It is ok for a given type to be inserted more than once, provided that + the exact same association is made each time. */ - /* How to destroy this object. */ + void insert_type (struct type *type, gcc_type gcc_type); - void (*destroy) (struct compile_instance *); -}; + /* Associate SYMBOL with some error text. */ -/* A subclass of compile_instance that is specific to the C front - end. */ -struct compile_c_instance -{ - /* Base class. Note that the base class vtable actually points to a - gcc_c_fe_vtable. */ + void insert_symbol_error (const struct symbol *sym, std::string text); - struct compile_instance base; + /* Emit the error message corresponding to SYM, if one exists, and + arrange for it not to be emitted again. */ - /* Map from gdb types to gcc types. */ + void error_symbol_once (const struct symbol *sym); - htab_t type_map; + /* These currently just forward to the underlying ops + vtable. */ - /* Map from gdb symbols to gcc error messages to emit. */ + /* Set the plug-in print callback. */ - htab_t symbol_err_map; -}; + void set_print_callback (void (*print_function) (void *, const char *), + void *datum); + + /* Return the plug-in's front-end version. */ + + unsigned int version () const; + + /* Set the plug-in's verbosity level. */ + + void set_verbose (int level); + + /* Set the plug-in driver program. */ + + void set_driver_filename (const char *filename); + + /* Set the regular expression used to match the configury triplet + prefix to the compiler. */ + + void set_triplet_regexp (const char *regexp); + + /* Set compilation arguments. */ + + char *set_arguments (int argc, char **argv); + + /* As above for protocol version 0. */ + + char *set_arguments (const char *regexp, int argc, char **argv); + + /* Set the filename of the program to compile. */ + + void set_source_file (const char *filename); + + /* Compile the previously specified source file to FILENAME. */ + + bool compile (const char *filename); + + /* Same as above, but for earlier protocol versions. */ + + bool compile (const char *filename, int verbose_level); + + /* Set the scope type for this compile. */ + + void set_scope (enum compile_i_scope_types scope) + { + m_scope = scope; + } + + /* Return the scope type. */ + + enum compile_i_scope_types scope () const + { + return m_scope; + } + + /* Set the block to be used for symbol searches. */ -/* A helper macro that takes a compile_c_instance and returns its - corresponding gcc_c_context. */ + void set_block (const struct block *block) + { + m_block = block; + } -#define C_CTX(I) ((struct gcc_c_context *) ((I)->base.fe)) + /* Return the search block. */ -/* Define header and footers for different scopes. */ + const struct block *block () const + { + return m_block; + } + + protected: + + /* Map types used by the compile instance for caching type conversions. + and error tracking. */ + + typedef std::pair type_map_item_t; + typedef std::unordered_map type_map_t; + typedef std::pair symbol_err_map_item_t; + typedef std::unordered_map + symbol_err_map_t; + + /* The GCC front end. */ + struct gcc_base_context *m_gcc_fe; + + /* The "scope" of this compilation. */ + enum compile_i_scope_types m_scope; + + /* The block in which an expression is being parsed. */ + const struct block *m_block; + + /* Specify "-std=gnu11", "-std=gnu++11" or similar. These options are put + after CU's DW_AT_producer compilation options to override them. */ + std::string m_gcc_target_options; + + /* Map from gdb types to gcc types. */ + type_map_t m_type_map; + + /* Map from gdb symbols to gcc error messages to emit. */ + symbol_err_map_t m_symbol_err_map; + }; +}; + +/* Define the headers and footers for different scopes. */ /* A simple scope just declares a function named "_gdb_expr", takes no arguments and returns no value. */ @@ -93,6 +188,10 @@ struct compile_c_instance #define COMPILE_I_EXPR_VAL "__gdb_expr_val" #define COMPILE_I_EXPR_PTR_TYPE "__gdb_expr_ptr_type" +/* A "type" to indicate a NULL type. */ + +const gcc_type GCC_TYPE_NONE = (gcc_type) -1; + /* Call gdbarch_register_name (GDBARCH, REGNUM) and convert its result to a form suitable for the compiler source. The register names should not clash with inferior defined macros. Returned pointer is @@ -108,50 +207,6 @@ extern char *compile_register_name_mangled (struct gdbarch *gdbarch, extern int compile_register_name_demangle (struct gdbarch *gdbarch, const char *reg_name); -/* Convert a gdb type, TYPE, to a GCC type. CONTEXT is used to do the - actual conversion. The new GCC type is returned. */ - -struct type; -extern gcc_type convert_type (struct compile_c_instance *context, - struct type *type); - -/* A callback suitable for use as the GCC C symbol oracle. */ - -extern gcc_c_oracle_function gcc_convert_symbol; - -/* A callback suitable for use as the GCC C address oracle. */ - -extern gcc_c_symbol_address_function gcc_symbol_address; - -/* Instantiate a GDB object holding state for the GCC context FE. The - new object is returned. */ - -extern struct compile_instance *new_compile_instance (struct gcc_c_context *fe); - -/* Emit code to compute the address for all the local variables in - scope at PC in BLOCK. Returns a malloc'd vector, indexed by gdb - register number, where each element indicates if the corresponding - register is needed to compute a local variable. */ - -extern unsigned char *generate_c_for_variable_locations - (struct compile_c_instance *compiler, - string_file &stream, - struct gdbarch *gdbarch, - const struct block *block, - CORE_ADDR pc); - -/* Get the GCC mode attribute value for a given type size. */ - -extern const char *c_get_mode_for_size (int size); - -/* Given a dynamic property, return an xmallocd name that is used to - represent its size. The result must be freed by the caller. The - contents of the resulting string will be the same each time for - each call with the same argument. */ - -struct dynamic_prop; -extern char *c_get_range_decl_name (const struct dynamic_prop *prop); - /* Type used to hold and pass around the source and object file names to use for compilation. */ class compile_file_names diff --git a/gdb/compile/compile-loc2c.c b/gdb/compile/compile-loc2c.c index f1296e8304e..aab50e93571 100644 --- a/gdb/compile/compile-loc2c.c +++ b/gdb/compile/compile-loc2c.c @@ -24,6 +24,7 @@ #include "ui-file.h" #include "utils.h" #include "compile-internal.h" +#include "compile-c.h" #include "compile.h" #include "block.h" #include "dwarf2-frame.h" diff --git a/gdb/compile/compile.c b/gdb/compile/compile.c index 8d57cc98084..b9a3d3419f9 100644 --- a/gdb/compile/compile.c +++ b/gdb/compile/compile.c @@ -420,8 +420,8 @@ filter_args (int *argcp, char **argv) generated above. */ static void -get_args (const struct compile_instance *compiler, struct gdbarch *gdbarch, - int *argcp, char ***argvp) +get_args (const compile::compile_instance *compiler, + struct gdbarch *gdbarch, int *argcp, char ***argvp) { const char *cs_producer_options; int argc_compiler; @@ -442,7 +442,7 @@ get_args (const struct compile_instance *compiler, struct gdbarch *gdbarch, freeargv (argv_producer); } - build_argc_argv (compiler->gcc_target_options, + build_argc_argv (compiler->gcc_target_options ().c_str (), &argc_compiler, &argv_compiler); append_args (argcp, argvp, argc_compiler, argv_compiler); freeargv (argv_compiler); @@ -450,14 +450,15 @@ get_args (const struct compile_instance *compiler, struct gdbarch *gdbarch, append_args (argcp, argvp, compile_args_argc, compile_args_argv); } -/* A cleanup function to destroy a gdb_gcc_instance. */ +/* A cleanup function to destroy a compile_instance. */ static void cleanup_compile_instance (void *arg) { - struct compile_instance *inst = (struct compile_instance *) arg; + compile::compile_instance *inst + = static_cast (arg); - inst->destroy (inst); + delete inst; } /* A cleanup function to unlink a file. */ @@ -487,16 +488,16 @@ static compile_file_names compile_to_object (struct command_line *cmd, const char *cmd_string, enum compile_i_scope_types scope) { - struct compile_instance *compiler; + compile::compile_instance *compiler; struct cleanup *cleanup, *inner_cleanup; const struct block *expr_block; CORE_ADDR trash_pc, expr_pc; int argc; char **argv; - int ok; + bool ok; FILE *src; struct gdbarch *gdbarch = get_current_arch (); - char *triplet_rx; + char *triplet_rx = NULL; char *error_message; if (!target_has_execution) @@ -513,10 +514,9 @@ compile_to_object (struct command_line *cmd, const char *cmd_string, compiler = current_language->la_get_compile_instance (); cleanup = make_cleanup (cleanup_compile_instance, compiler); - compiler->fe->ops->set_print_callback (compiler->fe, print_callback, NULL); - - compiler->scope = scope; - compiler->block = expr_block; + compiler->set_print_callback (print_callback, NULL); + compiler->set_scope (scope); + compiler->set_block (expr_block); /* From the provided expression, build a scope to pass to the compiler. */ @@ -547,16 +547,16 @@ compile_to_object (struct command_line *cmd, const char *cmd_string, if (compile_debug) fprintf_unfiltered (gdb_stdlog, "debug output:\n\n%s", code.c_str ()); - if (compiler->fe->ops->version >= GCC_FE_VERSION_1) - compiler->fe->ops->set_verbose (compiler->fe, compile_debug); + if (compiler->version () >= GCC_FE_VERSION_1) + compiler->set_verbose (compile_debug); if (compile_gcc[0] != 0) { - if (compiler->fe->ops->version < GCC_FE_VERSION_1) + if (compiler->version () < GCC_FE_VERSION_1) error (_("Command 'set compile-gcc' requires GCC version 6 or higher " "(libcc1 interface version 1 or higher)")); - compiler->fe->ops->set_driver_filename (compiler->fe, compile_gcc); + compiler->set_driver_filename (compile_gcc); } else { @@ -567,19 +567,18 @@ compile_to_object (struct command_line *cmd, const char *cmd_string, triplet_rx = concat (arch_rx, "(-[^-]*)?-", os_rx, (char *) NULL); make_cleanup (xfree, triplet_rx); - if (compiler->fe->ops->version >= GCC_FE_VERSION_1) - compiler->fe->ops->set_triplet_regexp (compiler->fe, triplet_rx); + if (compiler->version () >= GCC_FE_VERSION_1) + compiler->set_triplet_regexp (triplet_rx); } /* Set compiler command-line arguments. */ get_args (compiler, gdbarch, &argc, &argv); make_cleanup_freeargv (argv); - if (compiler->fe->ops->version >= GCC_FE_VERSION_1) - error_message = compiler->fe->ops->set_arguments (compiler->fe, argc, argv); + if (compiler->version ()>= GCC_FE_VERSION_1) + error_message = compiler->set_arguments (argc, argv); else - error_message = compiler->fe->ops->set_arguments_v0 (compiler->fe, triplet_rx, - argc, argv); + error_message = compiler->set_arguments (triplet_rx, argc, argv); if (error_message != NULL) { make_cleanup (xfree, error_message); @@ -612,13 +611,12 @@ compile_to_object (struct command_line *cmd, const char *cmd_string, fnames.source_file ()); /* Call the compiler and start the compilation process. */ - compiler->fe->ops->set_source_file (compiler->fe, fnames.source_file ()); + compiler->set_source_file (fnames.source_file ()); - if (compiler->fe->ops->version >= GCC_FE_VERSION_1) - ok = compiler->fe->ops->compile (compiler->fe, fnames.object_file ()); + if (compiler->version () >= GCC_FE_VERSION_1) + ok = compiler->compile (fnames.object_file ()); else - ok = compiler->fe->ops->compile_v0 (compiler->fe, fnames.object_file (), - compile_debug); + ok = compiler->compile (fnames.object_file (), compile_debug); if (!ok) error (_("Compilation failed.")); @@ -697,6 +695,140 @@ compile_register_name_demangle (struct gdbarch *gdbarch, error (_("Cannot find gdbarch register \"%s\"."), regname); } +/* See description in compile-internal.h. */ + +void +compile::compile_instance::insert_type (struct type *type, gcc_type gcc_type) +{ + type_map_t::iterator pos = m_type_map.find (type); + + if (pos != m_type_map.end ()) + { + /* The type might have already been inserted in order to handle + recursive types. */ + if (pos->second != gcc_type) + error (_("Unexpected type id from GCC, check you use recent " + "enough GCC.")); + } + else + m_type_map.insert (std::make_pair (type, gcc_type)); +} + +/* See description in compile-internal.h. */ + +void +compile::compile_instance::insert_symbol_error (const struct symbol *sym, + std::string text) +{ + symbol_err_map_t::iterator pos = m_symbol_err_map.find (sym); + + if (pos == m_symbol_err_map.end ()) + m_symbol_err_map.insert (std::make_pair (sym, text)); +} + +/* See description in compile-internal.h. */ + +void +compile::compile_instance::error_symbol_once (const struct symbol *sym) +{ + symbol_err_map_t::iterator pos = m_symbol_err_map.find (sym); + if (pos == m_symbol_err_map.end () || pos->second.length () == 0) + return; + + std::string message (pos->second); + pos->second.clear (); + ::error (_("%s"), message.c_str ()); +} + +/* Forwards to the plug-in. */ + +#define FORWARD(OP,...) (m_gcc_fe->ops->OP (m_gcc_fe, ##__VA_ARGS__)) + +/* Set the plug-in print callback. */ + +void +compile::compile_instance::set_print_callback + (void (*print_function) (void *, const char *), void *datum) +{ + FORWARD (set_print_callback, print_function, datum); +} + +/* Return the plug-in's front-end version. */ + +unsigned int +compile::compile_instance::version () const +{ + return m_gcc_fe->ops->version; +} + +/* Set the plug-in's verbosity level. */ + +void +compile::compile_instance::set_verbose (int level) +{ + FORWARD (set_verbose, level); +} + +/* Set the plug-in driver program. */ + +void +compile::compile_instance::set_driver_filename (const char *filename) +{ + FORWARD (set_driver_filename, filename); +} + +/* Set the regular expression used to match the configury triplet + prefix to the compiler. */ + +void +compile::compile_instance::set_triplet_regexp (const char *regexp) +{ + FORWARD (set_triplet_regexp, regexp); +} + +/* Set compilation arguments. */ + +char * +compile::compile_instance::set_arguments (int argc, char **argv) +{ + return FORWARD (set_arguments, argc, argv); +} + +/* As above, for protocol version 0. */ + +char * +compile::compile_instance::set_arguments (const char *regexp, int argc, char + **argv) +{ + return FORWARD (set_arguments_v0, regexp, argc, argv); +} + +/* Set the filename of the program to compile. */ + +void +compile::compile_instance::set_source_file (const char *filename) +{ + FORWARD (set_source_file, filename); +} + +/* Compile the previously specified source file to FILENAME. */ + +bool +compile::compile_instance::compile (const char *filename) +{ + return FORWARD (compile, filename); +} + +/* As above, but for an earlier compile protocol. */ + +bool +compile::compile_instance::compile (const char *filename, int verbose_level) +{ + return FORWARD (compile_v0, filename, verbose_level); +} + +#undef FORWARD + extern initialize_file_ftype _initialize_compile; void diff --git a/gdb/language.h b/gdb/language.h index 2bf677c43e7..4c4468d52b8 100644 --- a/gdb/language.h +++ b/gdb/language.h @@ -35,7 +35,11 @@ struct value_print_options; struct type_print_options; struct lang_varobj_ops; struct parser_state; -struct compile_instance; + +namespace compile +{ + class compile_instance; +}; #define MAX_FORTRAN_DIMS 7 /* Maximum number of F77 array dims. */ @@ -400,7 +404,7 @@ struct language_defn instance is owned by its caller and must be deallocated by calling its 'destroy' method. */ - struct compile_instance *(*la_get_compile_instance) (void); + compile::compile_instance *(*la_get_compile_instance) (void); /* This method must be defined if 'la_get_gcc_context' is defined. If 'la_get_gcc_context' is not defined, then this method is @@ -416,7 +420,7 @@ struct language_defn parsed. EXPR_PC is the PC at which the expression is being parsed. */ - std::string (*la_compute_program) (struct compile_instance *inst, + std::string (*la_compute_program) (compile::compile_instance *inst, const char *input, struct gdbarch *gdbarch, const struct block *expr_block,