Rename gdb exception types
[deliverable/binutils-gdb.git] / gdb / compile / compile-c-support.c
index 39f06c6b752704d8176354921ea4d6701715ec3a..d1947da6570bc655f578e3eb87d98d462dd5ede0 100644 (file)
@@ -1,6 +1,6 @@
-/* C language support for compilation.
+/* C/C++ language support for compilation.
 
-   Copyright (C) 2014-2015 Free Software Foundation, Inc.
+   Copyright (C) 2014-2019 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 
 #include "defs.h"
 #include "compile-internal.h"
+#include "compile-c.h"
+#include "compile-cplus.h"
 #include "compile.h"
 #include "gdb-dlfcn.h"
 #include "c-lang.h"
 #include "macrotab.h"
 #include "macroscope.h"
 #include "regcache.h"
+#include "common/function-view.h"
+#include "common/preprocessor.h"
 
 /* See compile-internal.h.  */
 
@@ -56,63 +60,88 @@ c_get_mode_for_size (int size)
 
 /* See compile-internal.h.  */
 
-char *
+std::string
 c_get_range_decl_name (const struct dynamic_prop *prop)
 {
-  return xstrprintf ("__gdb_prop_%s", host_address_to_string (prop));
+  return string_printf ("__gdb_prop_%s", host_address_to_string (prop));
 }
 
 \f
 
-#define STR(x) #x
-#define STRINGIFY(x) STR(x)
+/* Load the plug-in library FE_LIBCC and return the initialization function
+   FE_CONTEXT.  */
 
-/* Helper function for c_get_compile_context.  Open the GCC front-end
-   shared library and return the symbol specified by the current
-   GCC_C_FE_CONTEXT.  */
-
-static gcc_c_fe_context_function *
-load_libcc (void)
+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.  */
+  gdb_dlhandle_up 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);
+
+  /* Leave the library open.  */
+  handle.release ();
   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_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_instance *
+c_get_compile_context ()
+{
+  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);
+}
+
+/* A C++-language implementation of get_compile_context.  */
+
+compile_instance *
+cplus_get_compile_context ()
+{
+  return get_compile_context
+    <compile_cplus_instance, gcc_cp_fe_context_function, gcc_cp_context,
+     gcc_base_api_version, gcc_cp_api_version>
+    (STRINGIFY (GCC_CP_FE_LIBCC), STRINGIFY (GCC_CP_FE_CONTEXT),
+     GCC_FE_VERSION_0, GCC_CP_FE_VERSION_0);
 }
 
 \f
@@ -122,10 +151,8 @@ c_get_compile_context (void)
 static void
 print_one_macro (const char *name, const struct macro_definition *macro,
                 struct macro_source_file *source, int line,
-                void *user_data)
+                ui_file *file)
 {
-  struct ui_file *file = user_data;
-
   /* Don't print command-line defines.  They will be supplied another
      way.  */
   if (line == 0)
@@ -158,7 +185,7 @@ static void
 write_macro_definitions (const struct block *block, CORE_ADDR pc,
                         struct ui_file *file)
 {
-  struct macro_scope *scope;
+  gdb::unique_xmalloc_ptr<struct macro_scope> scope;
 
   if (block != NULL)
     scope = sal_macro_scope (find_pc_line (pc, 0));
@@ -168,71 +195,15 @@ write_macro_definitions (const struct block *block, CORE_ADDR pc,
     scope = user_macro_scope ();
 
   if (scope != NULL && scope->file != NULL && scope->file->table != NULL)
-    macro_for_each_in_scope (scope->file, scope->line, print_one_macro, file);
-}
-
-/* Helper function to construct a header scope for a block of code.
-   Takes a scope argument which selects the correct header to
-   insert into BUF.  */
-
-static void
-add_code_header (enum compile_i_scope_types type, struct ui_file *buf)
-{
-  switch (type)
-    {
-    case COMPILE_I_SIMPLE_SCOPE:
-      fputs_unfiltered ("void "
-                       GCC_FE_WRAPPER_FUNCTION
-                       " (struct "
-                       COMPILE_I_SIMPLE_REGISTER_STRUCT_TAG
-                       " *"
-                       COMPILE_I_SIMPLE_REGISTER_ARG_NAME
-                       ") {\n",
-                       buf);
-      break;
-    case COMPILE_I_PRINT_ADDRESS_SCOPE:
-    case COMPILE_I_PRINT_VALUE_SCOPE:
-      /* <string.h> is needed for a memcpy call below.  */
-      fputs_unfiltered ("#include <string.h>\n"
-                       "void "
-                       GCC_FE_WRAPPER_FUNCTION
-                       " (struct "
-                       COMPILE_I_SIMPLE_REGISTER_STRUCT_TAG
-                       " *"
-                       COMPILE_I_SIMPLE_REGISTER_ARG_NAME
-                       ", "
-                       COMPILE_I_PRINT_OUT_ARG_TYPE
-                       " "
-                       COMPILE_I_PRINT_OUT_ARG
-                       ") {\n",
-                       buf);
-      break;
-
-    case COMPILE_I_RAW_SCOPE:
-      break;
-    default:
-      gdb_assert_not_reached (_("Unknown compiler scope reached."));
-    }
-}
-
-/* Helper function to construct a footer scope for a block of code.
-   Takes a scope argument which selects the correct footer to
-   insert into BUF.  */
-
-static void
-add_code_footer (enum compile_i_scope_types type, struct ui_file *buf)
-{
-  switch (type)
     {
-    case COMPILE_I_SIMPLE_SCOPE:
-    case COMPILE_I_PRINT_ADDRESS_SCOPE:
-    case COMPILE_I_PRINT_VALUE_SCOPE:
-      fputs_unfiltered ("}\n", buf);
-      break;
-    case COMPILE_I_RAW_SCOPE:
-      break;
-    default:
-      gdb_assert_not_reached (_("Unknown compiler scope reached."));
+      macro_for_each_in_scope (scope->file, scope->line,
+                              [&] (const char *name,
+                                   const macro_definition *macro,
+                                   macro_source_file *source,
+                                   int line)
+       {
+         print_one_macro (name, macro, source, line, file);
+       });
     }
 }
 
@@ -255,8 +226,7 @@ generate_register_struct (struct ui_file *stream, struct gdbarch *gdbarch,
        if (registers_used[i])
          {
            struct type *regtype = check_typedef (register_type (gdbarch, i));
-           char *regname = compile_register_name_mangled (gdbarch, i);
-           struct cleanup *cleanups = make_cleanup (xfree, regname);
+           std::string regname = compile_register_name_mangled (gdbarch, i);
 
            seen = 1;
 
@@ -274,7 +244,8 @@ generate_register_struct (struct ui_file *stream, struct gdbarch *gdbarch,
            switch (TYPE_CODE (regtype))
              {
              case TYPE_CODE_PTR:
-               fprintf_filtered (stream, "__gdb_uintptr %s", regname);
+               fprintf_filtered (stream, "__gdb_uintptr %s",
+                                 regname.c_str ());
                break;
 
              case TYPE_CODE_INT:
@@ -289,7 +260,7 @@ generate_register_struct (struct ui_file *stream, struct gdbarch *gdbarch,
                      fprintf_unfiltered (stream,
                                          "int %s"
                                          " __attribute__ ((__mode__(__%s__)))",
-                                         regname,
+                                         regname.c_str (),
                                          mode);
                      break;
                    }
@@ -299,15 +270,13 @@ generate_register_struct (struct ui_file *stream, struct gdbarch *gdbarch,
 
              default:
                fprintf_unfiltered (stream,
-                                   "  unsigned char %s[%d]"
+                                   "  unsigned char %s[%s]"
                                    " __attribute__((__aligned__("
                                    "__BIGGEST_ALIGNMENT__)))",
-                                   regname,
-                                   TYPE_LENGTH (regtype));
+                                   regname.c_str (),
+                                   pulongest (TYPE_LENGTH (regtype)));
              }
            fputs_unfiltered (";\n", stream);
-
-           do_cleanups (cleanups);
          }
       }
 
@@ -318,124 +287,405 @@ 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.  */
 
-char *
-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;
-  char *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);
+  }
+};
 
-  /* 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 push user expression pragma into
+   BUF.  */
 
-  fputs_unfiltered ("#line 1 \"gdb command line\"\n", buf);
+struct cplus_push_user_expression
+{
+  void push_user_expression (struct ui_file *buf)
+  {
+    fputs_unfiltered ("#pragma GCC push_user_expression\n", buf);
+  }
+};
+
+/* C++-language policy to emit a pop user expression pragma into 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."));
     }
+  }
+};
 
-  fputs_unfiltered ("\n", buf);
+/* C++-language policy to emit the user code snippet INPUT into BUF based on
+   the scope TYPE.  */
 
-  /* For larger user expressions the automatic semicolons may be
-     confusing.  */
-  if (strchr (input, '\n') == NULL)
-    fputs_unfiltered (";\n", buf);
+struct cplus_add_input
+{
+  void add_input (enum compile_i_scope_types type, const char *input,
+                 struct ui_file *buf)
+  {
+    switch (type)
+      {
+      case COMPILE_I_PRINT_VALUE_SCOPE:
+      case COMPILE_I_PRINT_ADDRESS_SCOPE:
+       fprintf_unfiltered
+         (buf,
+          /* "auto" strips ref- and cv- qualifiers, so we need to also strip
+             those from COMPILE_I_EXPR_PTR_TYPE.  */
+          "auto " COMPILE_I_EXPR_VAL " = %s;\n"
+          "typedef "
+            "std::add_pointer<std::remove_cv<decltype (%s)>::type>::type "
+            " __gdb_expr_ptr;\n"
+          "__gdb_expr_ptr " COMPILE_I_EXPR_PTR_TYPE ";\n"
+          "std::memcpy (" COMPILE_I_PRINT_OUT_ARG ", %s ("
+          COMPILE_I_EXPR_VAL "),\n"
+          "\tsizeof (*" COMPILE_I_EXPR_PTR_TYPE "));\n"
+          ,input, input,
+          (type == COMPILE_I_PRINT_ADDRESS_SCOPE
+           ? "__builtin_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
+   language.
+
+   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
+{
+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.  */
+  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.  */
+       gdb::unique_xmalloc_ptr<unsigned char> registers_used
+         = generate_c_for_variable_locations (m_instance, &var_stream, m_arch,
+                                              expr_block, expr_pc);
+
+       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.get ());
+      }
+
+    AddCodeHeaderPolicy::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 ());
+       PushUserExpressionPolicy::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");
+
+    AddInputPolicy::add_input (m_instance->scope (), input, &buf);
 
-  if (inst->scope != COMPILE_I_RAW_SCOPE)
-    fputs_unfiltered ("}\n", 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)
+      PopUserExpressionPolicy::pop_user_expression (&buf);
+
+    AddCodeFooterPolicy::add_code_footer (m_instance->scope (), &buf);
+    return buf.string ();
+  }
+
+private:
+
+  /* The compile instance to be used for compilation and
+     type-conversion.  */
+  CompileInstanceType *m_instance;
+
+  /* The architecture to be used.  */
+  struct gdbarch *m_arch;
+};
+
+/* 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_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.  */
+
+std::string
+c_compute_program (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++.  */
+
+std::string
+cplus_compute_program (compile_instance *inst,
+                      const char *input,
+                      struct gdbarch *gdbarch,
+                      const struct block *expr_block,
+                      CORE_ADDR expr_pc)
+{
+  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_xstrdup (buf, NULL);
-  do_cleanups (cleanup);
-  return code;
+  return program.compute (input, expr_block, expr_pc);
 }
This page took 0.033539 seconds and 4 git commands to generate.