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.
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,
#include "defs.h"
#include "compile-internal.h"
+#include "compile-c.h"
#include "compile.h"
#include "gdb-dlfcn.h"
#include "c-lang.h"
return xstrprintf ("__gdb_prop_%s", host_address_to_string (prop));
}
-\f
-
#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 <typename FUNCTYPE>
+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 <typename INSTTYPE, typename FUNCTYPE, typename CTXTYPE,
+ typename BASE_VERSION_TYPE, typename API_VERSION_TYPE>
+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<FUNCTYPE> (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
+ <compile_c_instance, gcc_c_fe_context_function, gcc_c_context,
+ gcc_base_api_version, gcc_c_api_version>
+ (STRINGIFY (GCC_C_FE_LIBCC), STRINGIFY (GCC_C_FE_CONTEXT),
+ GCC_FE_VERSION_0, GCC_C_FE_VERSION_0);
}
\f
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. */
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:
+ /* <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."));
+ }
+ }
+};
- /* 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 CompileInstanceType, class PushUserExpressionPolicy,
+ class PopUserExpressionPolicy, class AddCodeHeaderPolicy,
+ class AddCodeFooterPolicy, class AddInputPolicy>
+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<compile::compile_c_instance, c_push_user_expression,
+ pop_user_expression_nop, c_add_code_header,
+ c_add_code_footer,
+ c_add_input> 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<compile_c_instance *> (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);
}
#include "defs.h"
#include "compile-internal.h"
+#include "compile-c.h"
#include "symtab.h"
#include "parser-defs.h"
#include "block.h"
\f
-/* 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);
-}
-
-\f
-
-/* 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);
}
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)
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
{
/* 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;
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:
}
/* 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);
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;
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;
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. */
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<compile_c_instance *> (datum);
domain_enum domain;
int found = 0;
{
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);
CATCH (e, RETURN_MASK_ALL)
{
- C_CTX (context)->c_ops->error (C_CTX (context), e.message);
+ context->error (e.message);
}
END_CATCH
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<compile_c_instance *> (datum);
gcc_address result = 0;
int found = 0;
CATCH (e, RETURN_MASK_ERROR)
{
- C_CTX (context)->c_ops->error (C_CTX (context), e.message);
+ context->error (e.message);
}
END_CATCH
/* 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,
/* 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,
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. */
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,
#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;
-}
-
-\f
-
-/* 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)
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;
}
}
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;
/* 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;
}
/* 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;
/* 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;
/* 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;
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
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. */
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;
}
-\f
+#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
--- /dev/null
+/* 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 <http://www.gnu.org/licenses/>. */
+
+#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 */
#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 <string>
+#include <unordered_map>
/* Debugging flag for the "compile" family of commands. */
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<struct type *, gcc_type> type_map_item_t;
+ typedef std::unordered_map<struct type *, gcc_type> type_map_t;
+ typedef std::pair<const struct symbol *, std::string> symbol_err_map_item_t;
+ typedef std::unordered_map<const struct symbol *, std::string>
+ 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. */
#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
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
#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"
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;
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);
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<compile::compile_instance *> (arg);
- inst->destroy (inst);
+ delete inst;
}
/* A cleanup function to unlink a file. */
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)
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. */
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
{
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);
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."));
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
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. */
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
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,