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 ui_file *buf, *var_stream = NULL;
- std::string code;
- struct cleanup *cleanup;
- 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);
+ }
+};
- buf = mem_fileopen ();
- cleanup = make_cleanup_ui_file_delete (buf);
+/* 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. */
- var_stream = mem_fileopen ();
- make_cleanup_ui_file_delete (var_stream);
- registers_used = generate_c_for_variable_locations (context,
- var_stream, gdbarch,
- expr_block, expr_pc);
- make_cleanup (xfree, registers_used);
-
- fputs_unfiltered ("typedef unsigned int"
- " __attribute__ ((__mode__(__pointer__)))"
- " __gdb_uintptr;\n",
- buf);
- fputs_unfiltered ("typedef int"
- " __attribute__ ((__mode__(__pointer__)))"
- " __gdb_intptr;\n",
- buf);
+/* 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. */
- /* Iterate all log2 sizes in bytes supported by c_get_mode_for_size. */
- for (i = 0; i < 4; ++i)
- {
- const char *mode = c_get_mode_for_size (1 << i);
-
- gdb_assert (mode != NULL);
- fprintf_unfiltered (buf,
- "typedef int"
- " __attribute__ ((__mode__(__%s__)))"
- " __gdb_int_%s;\n",
- mode, mode);
- }
+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)
- {
- ui_file_put (var_stream, ui_file_write_for_put, buf);
- fputs_unfiltered ("#pragma GCC user_expression\n", buf);
- }
+/* C-language policy to emit the user code snippet INPUT into BUF based on the
+ scope TYPE. */
+
+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);
+ }
+};
+
+/* C++-language policy to emit a push user expression pragma into
+ BUF. */
+
+struct cplus_push_user_expression
+{
+ void push_user_expression (struct ui_file *buf)
+ {
+ fputs_unfiltered ("#pragma GCC push_user_expression\n", buf);
+ }
+};
- /* The user expression has to be in its own scope, so that "extern"
- works properly. Otherwise gcc thinks that the "extern"
- declaration is in the same scope as the declaration provided by
- gdb. */
- if (inst->scope != COMPILE_I_RAW_SCOPE)
- fputs_unfiltered ("{\n", buf);
+/* C++-language policy to emit a pop user expression pragma into BUF. */
- fputs_unfiltered ("#line 1 \"gdb command line\"\n", buf);
+struct cplus_pop_user_expression
+{
+ void pop_user_expression (struct ui_file *buf)
+ {
+ fputs_unfiltered ("#pragma GCC pop_user_expression\n", buf);
+ }
+};
+
+/* 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. */
- switch (inst->scope)
+struct cplus_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:
- fprintf_unfiltered (buf,
-"__auto_type " COMPILE_I_EXPR_VAL " = %s;\n"
-"typeof (%s) *" COMPILE_I_EXPR_PTR_TYPE ";\n"
-"memcpy (" COMPILE_I_PRINT_OUT_ARG ", %s" COMPILE_I_EXPR_VAL ",\n"
- "sizeof (*" COMPILE_I_EXPR_PTR_TYPE "));\n"
- , input, input,
- (inst->scope == COMPILE_I_PRINT_ADDRESS_SCOPE
- ? "&" : ""));
+ fputs_unfiltered (
+ "#include <cstring>\n"
+ "#include <bits/move.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;
- default:
- fputs_unfiltered (input, buf);
+
+ case COMPILE_I_RAW_SCOPE:
break;
+
+ default:
+ gdb_assert_not_reached (_("Unknown compiler scope reached."));
}
- void add_input (enum compile_i_scope_types type,
- const char *input, struct ui_file *buf)
+ }
+};
+
+/* C++-language policy to emit the user code snippet INPUT into BUF based on
+ the scope TYPE. */
+
+struct cplus_add_input
+{
- char *compute (const char *input, const struct block *expr_block,
- CORE_ADDR expr_pc)
++ 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 " COMPILE_I_EXPR_VAL " = %s;\n"
+ "decltype (" COMPILE_I_EXPR_VAL ") *" COMPILE_I_EXPR_PTR_TYPE ";\n"
+ "std::memcpy (" COMPILE_I_PRINT_OUT_ARG ", %s ("
+ COMPILE_I_EXPR_VAL "),\n"
+ "sizeof (" COMPILE_I_EXPR_VAL "));\n"
+ ,input,
+ (type == COMPILE_I_PRINT_ADDRESS_SCOPE
+ ? "std::__addressof" : ""));
+ break;
+
+ default:
+ fputs_unfiltered (input, buf);
+ break;
+ }
+ fputs_unfiltered ("\n", buf);
+ }
+};
+
+/* A host class representing a compile program.
+
+ 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)
+ {
+ struct ui_file *var_stream = NULL;
+ struct ui_file *buf = mem_fileopen ();
+ struct cleanup *cleanup = make_cleanup_ui_file_delete (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. */
+ var_stream = mem_fileopen ();
+ make_cleanup_ui_file_delete (var_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);
+
+ fputs_unfiltered ("typedef unsigned int"
+ " __attribute__ ((__mode__(__pointer__)))"
+ " __gdb_uintptr;\n",
+ buf);
+ fputs_unfiltered ("typedef int"
+ " __attribute__ ((__mode__(__pointer__)))"
+ " __gdb_intptr;\n",
+ buf);
+
+ /* Iterate all log2 sizes in bytes supported by c_get_mode_for_size. */
+ for (int i = 0; i < 4; ++i)
+ {
+ const char *mode = c_get_mode_for_size (1 << i);
+
+ gdb_assert (mode != NULL);
+ fprintf_unfiltered (buf,
+ "typedef int"
+ " __attribute__ ((__mode__(__%s__)))"
+ " __gdb_int_%s;\n",
+ mode, mode);
+ }
+
+ generate_register_struct (buf, 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)
+ {
+ ui_file_put (var_stream, ui_file_write_for_put, buf);
+ 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)
+ fputs_unfiltered ("{\n", buf);
+
+ fputs_unfiltered ("#line 1 \"gdb command line\"\n", buf);
+
+ add_input (m_instance->scope (), input, buf);
+
+ /* For larger user expressions the automatic semicolons may be
+ confusing. */
+ if (strchr (input, '\n') == NULL)
+ fputs_unfiltered (";\n", buf);
- fputs_unfiltered ("\n", buf);
+ if (m_instance->scope () != COMPILE_I_RAW_SCOPE)
+ fputs_unfiltered ("}\n", 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)
+ pop_user_expression (buf);
+
+ add_code_footer (m_instance->scope (), buf);
- char *code = ui_file_xstrdup (buf, NULL);
++ std::string code = ui_file_as_string (buf);
+ do_cleanups (cleanup);
+ return code;
+ }
+
+private:
+
+ /* The compile instance to be used for compilation and
+ type-conversion. */
+ CompileInstanceType *m_instance;
+
+ /* The architecture to be used. */
+ struct gdbarch *m_arch;
+};
- /* For larger user expressions the automatic semicolons may be
- confusing. */
- if (strchr (input, '\n') == NULL)
- fputs_unfiltered (";\n", buf);
+/* The types used for C and C++ program computations. */
+
+typedef compile_program<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;
+
+typedef compile_program<compile::compile_cplus_instance,
+ cplus_push_user_expression, cplus_pop_user_expression,
+ cplus_add_code_header, c_add_code_footer,
+ cplus_add_input> cplus_compile_program;
+
+/* The la_compute_program method for C. */
+
- char *
++std::string
+c_compute_program (struct compile_instance *inst,
+ const char *input,
+ struct gdbarch *gdbarch,
+ const struct block *expr_block,
+ CORE_ADDR expr_pc)
+{
+ compile_c_instance *c_inst = static_cast<compile_c_instance *> (inst);
+ c_compile_program program (c_inst, gdbarch);
+
+ return program.compute (input, expr_block, expr_pc);
+}
+
+/* The la_compute_program method for C++. */
+
- char *
++std::string
+cplus_compute_program (struct 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)
- fputs_unfiltered ("}\n", buf);
+ compile_cplus_instance *cplus_inst
+ = static_cast<compile_cplus_instance *> (inst);
+ cplus_compile_program program (cplus_inst, gdbarch);
- add_code_footer (inst->scope, buf);
- code = ui_file_as_string (buf);
- do_cleanups (cleanup);
- return code;
+ return program.compute (input, expr_block, expr_pc);
}