Automatic date update in version.in
[deliverable/binutils-gdb.git] / gdb / ax-gdb.c
index 601c7522a3bad68ef6f4412fdb5b9b3d6585557f..009c128c83c11e83405eb3c7137e58d8f2b46efe 100644 (file)
@@ -1,6 +1,6 @@
 /* GDB-specific functions for operating on agent expressions.
 
-   Copyright (C) 1998-2020 Free Software Foundation, Inc.
+   Copyright (C) 1998-2021 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -45,6 +45,7 @@
 #include "typeprint.h"
 #include "valprint.h"
 #include "c-lang.h"
+#include "expop.h"
 
 #include "gdbsupport/format.h"
 
 /* Prototypes for local functions.  */
 
 /* There's a standard order to the arguments of these functions:
-   union exp_element ** --- pointer into expression
    struct agent_expr * --- agent expression buffer to generate code into
    struct axs_value * --- describes value left on top of stack  */
 
-static struct value *const_var_ref (struct symbol *var);
-static struct value *const_expr (union exp_element **pc);
-static struct value *maybe_const_expr (union exp_element **pc);
-
 static void gen_traced_pop (struct agent_expr *, struct axs_value *);
 
 static void gen_sign_extend (struct agent_expr *, struct type *);
@@ -147,117 +143,13 @@ static void gen_struct_ref (struct agent_expr *ax,
                            const char *operand_name);
 static void gen_static_field (struct agent_expr *ax, struct axs_value *value,
                              struct type *type, int fieldno);
-static void gen_repeat (struct expression *exp, union exp_element **pc,
-                       struct agent_expr *ax, struct axs_value *value);
-static void gen_sizeof (struct expression *exp, union exp_element **pc,
-                       struct agent_expr *ax, struct axs_value *value,
-                       struct type *size_type);
 static void gen_expr_binop_rest (struct expression *exp,
-                                enum exp_opcode op, union exp_element **pc,
+                                enum exp_opcode op,
                                 struct agent_expr *ax,
                                 struct axs_value *value,
                                 struct axs_value *value1,
                                 struct axs_value *value2);
-\f
-
-/* Detecting constant expressions.  */
-
-/* If the variable reference at *PC is a constant, return its value.
-   Otherwise, return zero.
-
-   Hey, Wally!  How can a variable reference be a constant?
-
-   Well, Beav, this function really handles the OP_VAR_VALUE operator,
-   not specifically variable references.  GDB uses OP_VAR_VALUE to
-   refer to any kind of symbolic reference: function names, enum
-   elements, and goto labels are all handled through the OP_VAR_VALUE
-   operator, even though they're constants.  It makes sense given the
-   situation.
-
-   Gee, Wally, don'cha wonder sometimes if data representations that
-   subvert commonly accepted definitions of terms in favor of heavily
-   context-specific interpretations are really just a tool of the
-   programming hegemony to preserve their power and exclude the
-   proletariat?  */
-
-static struct value *
-const_var_ref (struct symbol *var)
-{
-  struct type *type = SYMBOL_TYPE (var);
-
-  switch (SYMBOL_CLASS (var))
-    {
-    case LOC_CONST:
-      return value_from_longest (type, (LONGEST) SYMBOL_VALUE (var));
-
-    case LOC_LABEL:
-      return value_from_pointer (type, (CORE_ADDR) SYMBOL_VALUE_ADDRESS (var));
-
-    default:
-      return 0;
-    }
-}
-
-
-/* If the expression starting at *PC has a constant value, return it.
-   Otherwise, return zero.  If we return a value, then *PC will be
-   advanced to the end of it.  If we return zero, *PC could be
-   anywhere.  */
-static struct value *
-const_expr (union exp_element **pc)
-{
-  enum exp_opcode op = (*pc)->opcode;
-  struct value *v1;
-
-  switch (op)
-    {
-    case OP_LONG:
-      {
-       struct type *type = (*pc)[1].type;
-       LONGEST k = (*pc)[2].longconst;
 
-       (*pc) += 4;
-       return value_from_longest (type, k);
-      }
-
-    case OP_VAR_VALUE:
-      {
-       struct value *v = const_var_ref ((*pc)[2].symbol);
-
-       (*pc) += 4;
-       return v;
-      }
-
-      /* We could add more operators in here.  */
-
-    case UNOP_NEG:
-      (*pc)++;
-      v1 = const_expr (pc);
-      if (v1)
-       return value_neg (v1);
-      else
-       return 0;
-
-    default:
-      return 0;
-    }
-}
-
-
-/* Like const_expr, but guarantee also that *PC is undisturbed if the
-   expression is not constant.  */
-static struct value *
-maybe_const_expr (union exp_element **pc)
-{
-  union exp_element *tentative_pc = *pc;
-  struct value *v = const_expr (&tentative_pc);
-
-  /* If we got a value, then update the real PC.  */
-  if (v)
-    *pc = tentative_pc;
-
-  return v;
-}
 \f
 
 /* Generating bytecode from GDB expressions: general assumptions */
@@ -1684,6 +1576,150 @@ gen_aggregate_elt_ref (struct agent_expr *ax, struct axs_value *value,
   return 0;
 }
 
+\f
+
+namespace expr
+{
+
+void
+operation::generate_ax (struct expression *exp,
+                       struct agent_expr *ax,
+                       struct axs_value *value,
+                       struct type *cast_type)
+{
+  if (constant_p ())
+    {
+      struct value *v = evaluate (nullptr, exp, EVAL_AVOID_SIDE_EFFECTS);
+      ax_const_l (ax, value_as_long (v));
+      value->kind = axs_rvalue;
+      value->type = check_typedef (value_type (v));
+    }
+  else
+    {
+      do_generate_ax (exp, ax, value, cast_type);
+      if (cast_type != nullptr)
+       gen_cast (ax, value, cast_type);
+    }
+}
+
+void
+scope_operation::do_generate_ax (struct expression *exp,
+                                struct agent_expr *ax,
+                                struct axs_value *value,
+                                struct type *cast_type)
+{
+  struct type *type = std::get<0> (m_storage);
+  const std::string &name = std::get<1> (m_storage);
+  int found = gen_aggregate_elt_ref (ax, value, type, name.c_str ());
+  if (!found)
+    error (_("There is no field named %s"), name.c_str ());
+}
+
+void
+long_const_operation::do_generate_ax (struct expression *exp,
+                                     struct agent_expr *ax,
+                                     struct axs_value *value,
+                                     struct type *cast_type)
+{
+  gen_int_literal (ax, value, std::get<1> (m_storage),
+                  std::get<0> (m_storage));
+}
+
+void
+var_msym_value_operation::do_generate_ax (struct expression *exp,
+                                         struct agent_expr *ax,
+                                         struct axs_value *value,
+                                         struct type *cast_type)
+{
+  const bound_minimal_symbol &b = std::get<0> (m_storage);
+  gen_msym_var_ref (ax, value, b.minsym, b.objfile);
+
+  if (value->type->code () == TYPE_CODE_ERROR)
+    {
+      if (cast_type == nullptr)
+       error_unknown_type (b.minsym->linkage_name ());
+      value->type = cast_type;
+    }
+}
+
+void
+register_operation::do_generate_ax (struct expression *exp,
+                                   struct agent_expr *ax,
+                                   struct axs_value *value,
+                                   struct type *cast_type)
+{
+  const char *name = std::get<0> (m_storage).c_str ();
+  int len = std::get<0> (m_storage).size ();
+  int reg;
+
+  reg = user_reg_map_name_to_regnum (ax->gdbarch, name, len);
+  if (reg == -1)
+    internal_error (__FILE__, __LINE__,
+                   _("Register $%s not available"), name);
+  /* No support for tracing user registers yet.  */
+  if (reg >= gdbarch_num_cooked_regs (ax->gdbarch))
+    error (_("'%s' is a user-register; "
+            "GDB cannot yet trace user-register contents."),
+          name);
+  value->kind = axs_lvalue_register;
+  value->u.reg = reg;
+  value->type = register_type (ax->gdbarch, reg);
+}
+
+void
+internalvar_operation::do_generate_ax (struct expression *exp,
+                                      struct agent_expr *ax,
+                                      struct axs_value *value,
+                                      struct type *cast_type)
+{
+  struct internalvar *var = std::get<0> (m_storage);
+  const char *name = internalvar_name (var);
+  struct trace_state_variable *tsv;
+
+  tsv = find_trace_state_variable (name);
+  if (tsv)
+    {
+      ax_tsv (ax, aop_getv, tsv->number);
+      if (ax->tracing)
+       ax_tsv (ax, aop_tracev, tsv->number);
+      /* Trace state variables are always 64-bit integers.  */
+      value->kind = axs_rvalue;
+      value->type = builtin_type (ax->gdbarch)->builtin_long_long;
+    }
+  else if (! compile_internalvar_to_ax (var, ax, value))
+    error (_("$%s is not a trace state variable; GDB agent "
+            "expressions cannot use convenience variables."), name);
+}
+
+void
+ternop_cond_operation::do_generate_ax (struct expression *exp,
+                                      struct agent_expr *ax,
+                                      struct axs_value *value,
+                                      struct type *cast_type)
+{
+  struct axs_value value1, value2, value3;
+  int if1, end;
+
+  std::get<0> (m_storage)->generate_ax (exp, ax, &value1);
+  gen_usual_unary (ax, &value1);
+  /* For (A ? B : C), it's easiest to generate subexpression
+     bytecodes in order, but if_goto jumps on true, so we invert
+     the sense of A.  Then we can do B by dropping through, and
+     jump to do C.  */
+  gen_logical_not (ax, &value1, builtin_type (ax->gdbarch)->builtin_int);
+  if1 = ax_goto (ax, aop_if_goto);
+  std::get<1> (m_storage)->generate_ax (exp, ax, &value2);
+  gen_usual_unary (ax, &value2);
+  end = ax_goto (ax, aop_goto);
+  ax_label (ax, if1, ax->len);
+  std::get<2> (m_storage)->generate_ax (exp, ax, &value3);
+  gen_usual_unary (ax, &value3);
+  ax_label (ax, end, ax->len);
+  /* This is arbitrary - what if B and C are incompatible types? */
+  value->type = value2.type;
+  value->kind = value2.kind;
+}
+
 /* Generate code for GDB's magical `repeat' operator.
    LVALUE @ INT creates an array INT elements long, and whose elements
    have the same type as LVALUE, located in memory so that LVALUE is
@@ -1695,54 +1731,72 @@ gen_aggregate_elt_ref (struct agent_expr *ax, struct axs_value *value,
    without changing the type system, having values that occupy two
    stack slots, doing weird things with sizeof, etc.  So we require
    the right operand to be a constant expression.  */
-static void
-gen_repeat (struct expression *exp, union exp_element **pc,
-           struct agent_expr *ax, struct axs_value *value)
+void
+repeat_operation::do_generate_ax (struct expression *exp,
+                                 struct agent_expr *ax,
+                                 struct axs_value *value,
+                                 struct type *cast_type)
 {
   struct axs_value value1;
 
   /* We don't want to turn this into an rvalue, so no conversions
      here.  */
-  gen_expr (exp, pc, ax, &value1);
+  std::get<0> (m_storage)->generate_ax (exp, ax, &value1);
   if (value1.kind != axs_lvalue_memory)
     error (_("Left operand of `@' must be an object in memory."));
 
   /* Evaluate the length; it had better be a constant.  */
-  {
-    struct value *v = const_expr (pc);
-    int length;
-
-    if (!v)
-      error (_("Right operand of `@' must be a "
-              "constant, in agent expressions."));
-    if (value_type (v)->code () != TYPE_CODE_INT)
-      error (_("Right operand of `@' must be an integer."));
-    length = value_as_long (v);
-    if (length <= 0)
-      error (_("Right operand of `@' must be positive."));
-
-    /* The top of the stack is already the address of the object, so
-       all we need to do is frob the type of the lvalue.  */
-    {
-      /* FIXME-type-allocation: need a way to free this type when we are
-        done with it.  */
-      struct type *array
-       = lookup_array_range_type (value1.type, 0, length - 1);
+  if (!std::get<1> (m_storage)->constant_p ())
+    error (_("Right operand of `@' must be a "
+            "constant, in agent expressions."));
+
+  struct value *v
+    = std::get<1> (m_storage)->evaluate (nullptr, exp,
+                                        EVAL_AVOID_SIDE_EFFECTS);
+  if (value_type (v)->code () != TYPE_CODE_INT)
+    error (_("Right operand of `@' must be an integer."));
+  int length = value_as_long (v);
+  if (length <= 0)
+    error (_("Right operand of `@' must be positive."));
+
+  /* The top of the stack is already the address of the object, so
+     all we need to do is frob the type of the lvalue.  */
+  /* FIXME-type-allocation: need a way to free this type when we are
+     done with it.  */
+  struct type *array
+    = lookup_array_range_type (value1.type, 0, length - 1);
 
-      value->kind = axs_lvalue_memory;
-      value->type = array;
-    }
-  }
+  value->kind = axs_lvalue_memory;
+  value->type = array;
 }
 
+void
+comma_operation::do_generate_ax (struct expression *exp,
+                                struct agent_expr *ax,
+                                struct axs_value *value,
+                                struct type *cast_type)
+{
+  /* Note that we need to be a little subtle about generating code
+     for comma.  In C, we can do some optimizations here because
+     we know the left operand is only being evaluated for effect.
+     However, if the tracing kludge is in effect, then we always
+     need to evaluate the left hand side fully, so that all the
+     variables it mentions get traced.  */
+  struct axs_value value1;
+  std::get<0> (m_storage)->generate_ax (exp, ax, &value1);
+  /* Don't just dispose of the left operand.  We might be tracing,
+     in which case we want to emit code to trace it if it's an
+     lvalue.  */
+  gen_traced_pop (ax, &value1);
+  std::get<1> (m_storage)->generate_ax (exp, ax, value);
+  /* It's the consumer's responsibility to trace the right operand.  */
+}
 
-/* Emit code for the `sizeof' operator.
-   *PC should point at the start of the operand expression; we advance it
-   to the first instruction after the operand.  */
-static void
-gen_sizeof (struct expression *exp, union exp_element **pc,
-           struct agent_expr *ax, struct axs_value *value,
-           struct type *size_type)
+void
+unop_sizeof_operation::do_generate_ax (struct expression *exp,
+                                      struct agent_expr *ax,
+                                      struct axs_value *value,
+                                      struct type *cast_type)
 {
   /* We don't care about the value of the operand expression; we only
      care about its type.  However, in the current arrangement, the
@@ -1751,523 +1805,251 @@ gen_sizeof (struct expression *exp, union exp_element **pc,
      replacing it with code that simply pushes its size.  */
   int start = ax->len;
 
-  gen_expr (exp, pc, ax, value);
+  std::get<0> (m_storage)->generate_ax (exp, ax, value);
 
   /* Throw away the code we just generated.  */
   ax->len = start;
 
   ax_const_l (ax, TYPE_LENGTH (value->type));
   value->kind = axs_rvalue;
-  value->type = size_type;
+  value->type = builtin_type (ax->gdbarch)->builtin_int;
 }
-\f
-
-/* Generate bytecode for a cast to TO_TYPE.  Advance *PC over the
-   subexpression.  */
 
-static void
-gen_expr_for_cast (struct expression *exp, union exp_element **pc,
-                  struct agent_expr *ax, struct axs_value *value,
-                  struct type *to_type)
+void
+unop_cast_operation::do_generate_ax (struct expression *exp,
+                                    struct agent_expr *ax,
+                                    struct axs_value *value,
+                                    struct type *cast_type)
 {
-  enum exp_opcode op = (*pc)[0].opcode;
-
-  /* Don't let symbols be handled with gen_expr because that throws an
-     "unknown type" error for no-debug data symbols.  Instead, we want
-     the cast to reinterpret such symbols.  */
-  if (op == OP_VAR_MSYM_VALUE || op == OP_VAR_VALUE)
-    {
-      if (op == OP_VAR_VALUE)
-       {
-         gen_var_ref (ax, value, (*pc)[2].symbol);
-
-         if (value->optimized_out)
-           error (_("`%s' has been optimized out, cannot use"),
-                  (*pc)[2].symbol->print_name ());
-       }
-      else
-       gen_msym_var_ref (ax, value, (*pc)[2].msymbol, (*pc)[1].objfile);
-      if (value->type->code () == TYPE_CODE_ERROR)
-       value->type = to_type;
-      (*pc) += 4;
-    }
-  else
-    gen_expr (exp, pc, ax, value);
-  gen_cast (ax, value, to_type);
+  std::get<0> (m_storage)->generate_ax (exp, ax, value,
+                                       std::get<1> (m_storage));
 }
 
-/* Generating bytecode from GDB expressions: general recursive thingy  */
-
-/* XXX: i18n */
-/* A gen_expr function written by a Gen-X'er guy.
-   Append code for the subexpression of EXPR starting at *POS_P to AX.  */
 void
-gen_expr (struct expression *exp, union exp_element **pc,
-         struct agent_expr *ax, struct axs_value *value)
+unop_memval_operation::do_generate_ax (struct expression *exp,
+                                      struct agent_expr *ax,
+                                      struct axs_value *value,
+                                      struct type *cast_type)
 {
-  /* Used to hold the descriptions of operand expressions.  */
-  struct axs_value value1, value2, value3;
-  enum exp_opcode op = (*pc)[0].opcode, op2;
-  int if1, go1, if2, go2, end;
-  struct type *int_type = builtin_type (ax->gdbarch)->builtin_int;
-
-  /* If we're looking at a constant expression, just push its value.  */
-  {
-    struct value *v = maybe_const_expr (pc);
-
-    if (v)
-      {
-       ax_const_l (ax, value_as_long (v));
-       value->kind = axs_rvalue;
-       value->type = check_typedef (value_type (v));
-       return;
-      }
-  }
-
-  /* Otherwise, go ahead and generate code for it.  */
-  switch (op)
-    {
-      /* Binary arithmetic operators.  */
-    case BINOP_ADD:
-    case BINOP_SUB:
-    case BINOP_MUL:
-    case BINOP_DIV:
-    case BINOP_REM:
-    case BINOP_LSH:
-    case BINOP_RSH:
-    case BINOP_SUBSCRIPT:
-    case BINOP_BITWISE_AND:
-    case BINOP_BITWISE_IOR:
-    case BINOP_BITWISE_XOR:
-    case BINOP_EQUAL:
-    case BINOP_NOTEQUAL:
-    case BINOP_LESS:
-    case BINOP_GTR:
-    case BINOP_LEQ:
-    case BINOP_GEQ:
-      (*pc)++;
-      gen_expr (exp, pc, ax, &value1);
-      gen_usual_unary (ax, &value1);
-      gen_expr_binop_rest (exp, op, pc, ax, value, &value1, &value2);
-      break;
-
-    case BINOP_LOGICAL_AND:
-      (*pc)++;
-      /* Generate the obvious sequence of tests and jumps.  */
-      gen_expr (exp, pc, ax, &value1);
-      gen_usual_unary (ax, &value1);
-      if1 = ax_goto (ax, aop_if_goto);
-      go1 = ax_goto (ax, aop_goto);
-      ax_label (ax, if1, ax->len);
-      gen_expr (exp, pc, ax, &value2);
-      gen_usual_unary (ax, &value2);
-      if2 = ax_goto (ax, aop_if_goto);
-      go2 = ax_goto (ax, aop_goto);
-      ax_label (ax, if2, ax->len);
-      ax_const_l (ax, 1);
-      end = ax_goto (ax, aop_goto);
-      ax_label (ax, go1, ax->len);
-      ax_label (ax, go2, ax->len);
-      ax_const_l (ax, 0);
-      ax_label (ax, end, ax->len);
-      value->kind = axs_rvalue;
-      value->type = int_type;
-      break;
-
-    case BINOP_LOGICAL_OR:
-      (*pc)++;
-      /* Generate the obvious sequence of tests and jumps.  */
-      gen_expr (exp, pc, ax, &value1);
-      gen_usual_unary (ax, &value1);
-      if1 = ax_goto (ax, aop_if_goto);
-      gen_expr (exp, pc, ax, &value2);
-      gen_usual_unary (ax, &value2);
-      if2 = ax_goto (ax, aop_if_goto);
-      ax_const_l (ax, 0);
-      end = ax_goto (ax, aop_goto);
-      ax_label (ax, if1, ax->len);
-      ax_label (ax, if2, ax->len);
-      ax_const_l (ax, 1);
-      ax_label (ax, end, ax->len);
-      value->kind = axs_rvalue;
-      value->type = int_type;
-      break;
-
-    case TERNOP_COND:
-      (*pc)++;
-      gen_expr (exp, pc, ax, &value1);
-      gen_usual_unary (ax, &value1);
-      /* For (A ? B : C), it's easiest to generate subexpression
-        bytecodes in order, but if_goto jumps on true, so we invert
-        the sense of A.  Then we can do B by dropping through, and
-        jump to do C.  */
-      gen_logical_not (ax, &value1, int_type);
-      if1 = ax_goto (ax, aop_if_goto);
-      gen_expr (exp, pc, ax, &value2);
-      gen_usual_unary (ax, &value2);
-      end = ax_goto (ax, aop_goto);
-      ax_label (ax, if1, ax->len);
-      gen_expr (exp, pc, ax, &value3);
-      gen_usual_unary (ax, &value3);
-      ax_label (ax, end, ax->len);
-      /* This is arbitrary - what if B and C are incompatible types? */
-      value->type = value2.type;
-      value->kind = value2.kind;
-      break;
-
-    case BINOP_ASSIGN:
-      (*pc)++;
-      if ((*pc)[0].opcode == OP_INTERNALVAR)
-       {
-         const char *name = internalvar_name ((*pc)[1].internalvar);
-         struct trace_state_variable *tsv;
-
-         (*pc) += 3;
-         gen_expr (exp, pc, ax, value);
-         tsv = find_trace_state_variable (name);
-         if (tsv)
-           {
-             ax_tsv (ax, aop_setv, tsv->number);
-             if (ax->tracing)
-               ax_tsv (ax, aop_tracev, tsv->number);
-           }
-         else
-           error (_("$%s is not a trace state variable, "
-                    "may not assign to it"), name);
-       }
-      else
-       error (_("May only assign to trace state variables"));
-      break;
-
-    case BINOP_ASSIGN_MODIFY:
-      (*pc)++;
-      op2 = (*pc)[0].opcode;
-      (*pc)++;
-      (*pc)++;
-      if ((*pc)[0].opcode == OP_INTERNALVAR)
-       {
-         const char *name = internalvar_name ((*pc)[1].internalvar);
-         struct trace_state_variable *tsv;
-
-         (*pc) += 3;
-         tsv = find_trace_state_variable (name);
-         if (tsv)
-           {
-             /* The tsv will be the left half of the binary operation.  */
-             ax_tsv (ax, aop_getv, tsv->number);
-             if (ax->tracing)
-               ax_tsv (ax, aop_tracev, tsv->number);
-             /* Trace state variables are always 64-bit integers.  */
-             value1.kind = axs_rvalue;
-             value1.type = builtin_type (ax->gdbarch)->builtin_long_long;
-             /* Now do right half of expression.  */
-             gen_expr_binop_rest (exp, op2, pc, ax, value, &value1, &value2);
-             /* We have a result of the binary op, set the tsv.  */
-             ax_tsv (ax, aop_setv, tsv->number);
-             if (ax->tracing)
-               ax_tsv (ax, aop_tracev, tsv->number);
-           }
-         else
-           error (_("$%s is not a trace state variable, "
-                    "may not assign to it"), name);
-       }
-      else
-       error (_("May only assign to trace state variables"));
-      break;
-
-      /* Note that we need to be a little subtle about generating code
-        for comma.  In C, we can do some optimizations here because
-        we know the left operand is only being evaluated for effect.
-        However, if the tracing kludge is in effect, then we always
-        need to evaluate the left hand side fully, so that all the
-        variables it mentions get traced.  */
-    case BINOP_COMMA:
-      (*pc)++;
-      gen_expr (exp, pc, ax, &value1);
-      /* Don't just dispose of the left operand.  We might be tracing,
-        in which case we want to emit code to trace it if it's an
-        lvalue.  */
-      gen_traced_pop (ax, &value1);
-      gen_expr (exp, pc, ax, value);
-      /* It's the consumer's responsibility to trace the right operand.  */
-      break;
-
-    case OP_LONG:              /* some integer constant */
-      {
-       struct type *type = (*pc)[1].type;
-       LONGEST k = (*pc)[2].longconst;
-
-       (*pc) += 4;
-       gen_int_literal (ax, value, k, type);
-      }
-      break;
-
-    case OP_VAR_VALUE:
-      gen_var_ref (ax, value, (*pc)[2].symbol);
-
-      if (value->optimized_out)
-       error (_("`%s' has been optimized out, cannot use"),
-              (*pc)[2].symbol->print_name ());
-
-      if (value->type->code () == TYPE_CODE_ERROR)
-       error_unknown_type ((*pc)[2].symbol->print_name ());
-
-      (*pc) += 4;
-      break;
-
-    case OP_VAR_MSYM_VALUE:
-      gen_msym_var_ref (ax, value, (*pc)[2].msymbol, (*pc)[1].objfile);
-
-      if (value->type->code () == TYPE_CODE_ERROR)
-       error_unknown_type ((*pc)[2].msymbol->linkage_name ());
-
-      (*pc) += 4;
-      break;
-
-    case OP_REGISTER:
-      {
-       const char *name = &(*pc)[2].string;
-       int reg;
-
-       (*pc) += 4 + BYTES_TO_EXP_ELEM ((*pc)[1].longconst + 1);
-       reg = user_reg_map_name_to_regnum (ax->gdbarch, name, strlen (name));
-       if (reg == -1)
-         internal_error (__FILE__, __LINE__,
-                         _("Register $%s not available"), name);
-       /* No support for tracing user registers yet.  */
-       if (reg >= gdbarch_num_cooked_regs (ax->gdbarch))
-         error (_("'%s' is a user-register; "
-                  "GDB cannot yet trace user-register contents."),
-                name);
-       value->kind = axs_lvalue_register;
-       value->u.reg = reg;
-       value->type = register_type (ax->gdbarch, reg);
-      }
-      break;
-
-    case OP_INTERNALVAR:
-      {
-       struct internalvar *var = (*pc)[1].internalvar;
-       const char *name = internalvar_name (var);
-       struct trace_state_variable *tsv;
-
-       (*pc) += 3;
-       tsv = find_trace_state_variable (name);
-       if (tsv)
-         {
-           ax_tsv (ax, aop_getv, tsv->number);
-           if (ax->tracing)
-             ax_tsv (ax, aop_tracev, tsv->number);
-           /* Trace state variables are always 64-bit integers.  */
-           value->kind = axs_rvalue;
-           value->type = builtin_type (ax->gdbarch)->builtin_long_long;
-         }
-       else if (! compile_internalvar_to_ax (var, ax, value))
-         error (_("$%s is not a trace state variable; GDB agent "
-                  "expressions cannot use convenience variables."), name);
-      }
-      break;
-
-      /* Weirdo operator: see comments for gen_repeat for details.  */
-    case BINOP_REPEAT:
-      /* Note that gen_repeat handles its own argument evaluation.  */
-      (*pc)++;
-      gen_repeat (exp, pc, ax, value);
-      break;
-
-    case UNOP_CAST:
-      {
-       struct type *type = (*pc)[1].type;
-
-       (*pc) += 3;
-       gen_expr_for_cast (exp, pc, ax, value, type);
-      }
-      break;
-
-    case UNOP_CAST_TYPE:
-      {
-       int offset;
-       struct value *val;
-       struct type *type;
+  std::get<0> (m_storage)->generate_ax (exp, ax, value);
+  /* If we have an axs_rvalue or an axs_lvalue_memory, then we
+     already have the right value on the stack.  For
+     axs_lvalue_register, we must convert.  */
+  if (value->kind == axs_lvalue_register)
+    require_rvalue (ax, value);
+
+  value->type = std::get<1> (m_storage);
+  value->kind = axs_lvalue_memory;
+}
 
-       ++*pc;
-       offset = *pc - exp->elts;
-       val = evaluate_subexp (NULL, exp, &offset, EVAL_AVOID_SIDE_EFFECTS);
-       type = value_type (val);
-       *pc = &exp->elts[offset];
-       gen_expr_for_cast (exp, pc, ax, value, type);
-      }
-      break;
+void
+unop_memval_type_operation::do_generate_ax (struct expression *exp,
+                                           struct agent_expr *ax,
+                                           struct axs_value *value,
+                                           struct type *cast_type)
+{
+  struct value *val
+    = std::get<0> (m_storage)->evaluate (nullptr, exp,
+                                        EVAL_AVOID_SIDE_EFFECTS);
+  struct type *type = value_type (val);
 
-    case UNOP_MEMVAL:
-      {
-       struct type *type = check_typedef ((*pc)[1].type);
+  std::get<1> (m_storage)->generate_ax (exp, ax, value);
 
-       (*pc) += 3;
-       gen_expr (exp, pc, ax, value);
+  /* If we have an axs_rvalue or an axs_lvalue_memory, then we
+     already have the right value on the stack.  For
+     axs_lvalue_register, we must convert.  */
+  if (value->kind == axs_lvalue_register)
+    require_rvalue (ax, value);
 
-       /* If we have an axs_rvalue or an axs_lvalue_memory, then we
-          already have the right value on the stack.  For
-          axs_lvalue_register, we must convert.  */
-       if (value->kind == axs_lvalue_register)
-         require_rvalue (ax, value);
+  value->type = type;
+  value->kind = axs_lvalue_memory;
+}
 
-       value->type = type;
-       value->kind = axs_lvalue_memory;
-      }
-      break;
+void
+op_this_operation::do_generate_ax (struct expression *exp,
+                                  struct agent_expr *ax,
+                                  struct axs_value *value,
+                                  struct type *cast_type)
+{
+  struct symbol *sym, *func;
+  const struct block *b;
+  const struct language_defn *lang;
 
-    case UNOP_MEMVAL_TYPE:
-      {
-       int offset;
-       struct value *val;
-       struct type *type;
+  b = block_for_pc (ax->scope);
+  func = block_linkage_function (b);
+  lang = language_def (func->language ());
 
-       ++*pc;
-       offset = *pc - exp->elts;
-       val = evaluate_subexp (NULL, exp, &offset, EVAL_AVOID_SIDE_EFFECTS);
-       type = value_type (val);
-       *pc = &exp->elts[offset];
+  sym = lookup_language_this (lang, b).symbol;
+  if (!sym)
+    error (_("no `%s' found"), lang->name_of_this ());
 
-       gen_expr (exp, pc, ax, value);
+  gen_var_ref (ax, value, sym);
 
-       /* If we have an axs_rvalue or an axs_lvalue_memory, then we
-          already have the right value on the stack.  For
-          axs_lvalue_register, we must convert.  */
-       if (value->kind == axs_lvalue_register)
-         require_rvalue (ax, value);
+  if (value->optimized_out)
+    error (_("`%s' has been optimized out, cannot use"),
+          sym->print_name ());
+}
 
-       value->type = type;
-       value->kind = axs_lvalue_memory;
-      }
-      break;
+void
+assign_operation::do_generate_ax (struct expression *exp,
+                                 struct agent_expr *ax,
+                                 struct axs_value *value,
+                                 struct type *cast_type)
+{
+  operation *subop = std::get<0> (m_storage).get ();
+  if (subop->opcode () != OP_INTERNALVAR)
+    error (_("May only assign to trace state variables"));
 
-    case UNOP_PLUS:
-      (*pc)++;
-      /* + FOO is equivalent to 0 + FOO, which can be optimized.  */
-      gen_expr (exp, pc, ax, value);
-      gen_usual_unary (ax, value);
-      break;
-      
-    case UNOP_NEG:
-      (*pc)++;
-      /* -FOO is equivalent to 0 - FOO.  */
-      gen_int_literal (ax, &value1, 0,
-                      builtin_type (ax->gdbarch)->builtin_int);
-      gen_usual_unary (ax, &value1);   /* shouldn't do much */
-      gen_expr (exp, pc, ax, &value2);
-      gen_usual_unary (ax, &value2);
-      gen_usual_arithmetic (ax, &value1, &value2);
-      gen_binop (ax, value, &value1, &value2, aop_sub, aop_sub, 1, "negation");
-      break;
+  internalvar_operation *ivarop
+    = dynamic_cast<internalvar_operation *> (subop);
+  gdb_assert (ivarop != nullptr);
 
-    case UNOP_LOGICAL_NOT:
-      (*pc)++;
-      gen_expr (exp, pc, ax, value);
-      gen_usual_unary (ax, value);
-      gen_logical_not (ax, value, int_type);
-      break;
+  const char *name = internalvar_name (ivarop->get_internalvar ());
+  struct trace_state_variable *tsv;
 
-    case UNOP_COMPLEMENT:
-      (*pc)++;
-      gen_expr (exp, pc, ax, value);
-      gen_usual_unary (ax, value);
-      gen_integral_promotions (ax, value);
-      gen_complement (ax, value);
-      break;
+  std::get<1> (m_storage)->generate_ax (exp, ax, value);
+  tsv = find_trace_state_variable (name);
+  if (tsv)
+    {
+      ax_tsv (ax, aop_setv, tsv->number);
+      if (ax->tracing)
+       ax_tsv (ax, aop_tracev, tsv->number);
+    }
+  else
+    error (_("$%s is not a trace state variable, "
+            "may not assign to it"), name);
+}
 
-    case UNOP_IND:
-      (*pc)++;
-      gen_expr (exp, pc, ax, value);
-      gen_usual_unary (ax, value);
-      if (!pointer_type (value->type))
-       error (_("Argument of unary `*' is not a pointer."));
-      gen_deref (value);
-      break;
+void
+assign_modify_operation::do_generate_ax (struct expression *exp,
+                                        struct agent_expr *ax,
+                                        struct axs_value *value,
+                                        struct type *cast_type)
+{
+  operation *subop = std::get<1> (m_storage).get ();
+  if (subop->opcode () != OP_INTERNALVAR)
+    error (_("May only assign to trace state variables"));
 
-    case UNOP_ADDR:
-      (*pc)++;
-      gen_expr (exp, pc, ax, value);
-      gen_address_of (value);
-      break;
+  internalvar_operation *ivarop
+    = dynamic_cast<internalvar_operation *> (subop);
+  gdb_assert (ivarop != nullptr);
 
-    case UNOP_SIZEOF:
-      (*pc)++;
-      /* Notice that gen_sizeof handles its own operand, unlike most
-        of the other unary operator functions.  This is because we
-        have to throw away the code we generate.  */
-      gen_sizeof (exp, pc, ax, value,
-                 builtin_type (ax->gdbarch)->builtin_int);
-      break;
+  const char *name = internalvar_name (ivarop->get_internalvar ());
+  struct trace_state_variable *tsv;
 
-    case STRUCTOP_STRUCT:
-    case STRUCTOP_PTR:
-      {
-       int length = (*pc)[1].longconst;
-       const char *name = &(*pc)[2].string;
-
-       (*pc) += 4 + BYTES_TO_EXP_ELEM (length + 1);
-       gen_expr (exp, pc, ax, value);
-       if (op == STRUCTOP_STRUCT)
-         gen_struct_ref (ax, value, name, ".", "structure or union");
-       else if (op == STRUCTOP_PTR)
-         gen_struct_ref (ax, value, name, "->",
-                         "pointer to a structure or union");
-       else
-         /* If this `if' chain doesn't handle it, then the case list
-            shouldn't mention it, and we shouldn't be here.  */
-         internal_error (__FILE__, __LINE__,
-                         _("gen_expr: unhandled struct case"));
-      }
-      break;
-
-    case OP_THIS:
-      {
-       struct symbol *sym, *func;
-       const struct block *b;
-       const struct language_defn *lang;
+  tsv = find_trace_state_variable (name);
+  if (tsv)
+    {
+      /* The tsv will be the left half of the binary operation.  */
+      ax_tsv (ax, aop_getv, tsv->number);
+      if (ax->tracing)
+       ax_tsv (ax, aop_tracev, tsv->number);
+      /* Trace state variables are always 64-bit integers.  */
+      struct axs_value value1, value2;
+      value1.kind = axs_rvalue;
+      value1.type = builtin_type (ax->gdbarch)->builtin_long_long;
+      /* Now do right half of expression.  */
+      std::get<2> (m_storage)->generate_ax (exp, ax, &value2);
+      gen_expr_binop_rest (exp, std::get<0> (m_storage), ax,
+                          value, &value1, &value2);
+      /* We have a result of the binary op, set the tsv.  */
+      ax_tsv (ax, aop_setv, tsv->number);
+      if (ax->tracing)
+       ax_tsv (ax, aop_tracev, tsv->number);
+    }
+  else
+    error (_("$%s is not a trace state variable, "
+            "may not assign to it"), name);
+}
 
-       b = block_for_pc (ax->scope);
-       func = block_linkage_function (b);
-       lang = language_def (func->language ());
+void
+unop_cast_type_operation::do_generate_ax (struct expression *exp,
+                                         struct agent_expr *ax,
+                                         struct axs_value *value,
+                                         struct type *cast_type)
+{
+  struct value *val
+    = std::get<0> (m_storage)->evaluate (nullptr, exp,
+                                        EVAL_AVOID_SIDE_EFFECTS);
+  std::get<1> (m_storage)->generate_ax (exp, ax, value, value_type (val));
+}
 
-       sym = lookup_language_this (lang, b).symbol;
-       if (!sym)
-         error (_("no `%s' found"), lang->name_of_this ());
+void
+var_value_operation::do_generate_ax (struct expression *exp,
+                                    struct agent_expr *ax,
+                                    struct axs_value *value,
+                                    struct type *cast_type)
+{
+  gen_var_ref (ax, value, std::get<0> (m_storage).symbol);
 
-       gen_var_ref (ax, value, sym);
+  if (value->optimized_out)
+    error (_("`%s' has been optimized out, cannot use"),
+          std::get<0> (m_storage).symbol->print_name ());
 
-       if (value->optimized_out)
-         error (_("`%s' has been optimized out, cannot use"),
-                sym->print_name ());
+  if (value->type->code () == TYPE_CODE_ERROR)
+    {
+      if (cast_type == nullptr)
+       error_unknown_type (std::get<0> (m_storage).symbol->print_name ());
+      value->type = cast_type;
+    }
+}
 
-       (*pc) += 2;
-      }
-      break;
+void
+logical_and_operation::do_generate_ax (struct expression *exp,
+                                      struct agent_expr *ax,
+                                      struct axs_value *value,
+                                      struct type *cast_type)
+{
+  struct axs_value value1, value2;
+  int if1, go1, if2, go2, end;
 
-    case OP_SCOPE:
-      {
-       struct type *type = (*pc)[1].type;
-       int length = longest_to_int ((*pc)[2].longconst);
-       const char *name = &(*pc)[3].string;
-       int found;
-
-       found = gen_aggregate_elt_ref (ax, value, type, name);
-       if (!found)
-         error (_("There is no field named %s"), name);
-       (*pc) += 5 + BYTES_TO_EXP_ELEM (length + 1);
-      }
-      break;
+  /* Generate the obvious sequence of tests and jumps.  */
+  std::get<0> (m_storage)->generate_ax (exp, ax, &value1);
+  gen_usual_unary (ax, &value1);
+  if1 = ax_goto (ax, aop_if_goto);
+  go1 = ax_goto (ax, aop_goto);
+  ax_label (ax, if1, ax->len);
+  std::get<1> (m_storage)->generate_ax (exp, ax, &value2);
+  gen_usual_unary (ax, &value2);
+  if2 = ax_goto (ax, aop_if_goto);
+  go2 = ax_goto (ax, aop_goto);
+  ax_label (ax, if2, ax->len);
+  ax_const_l (ax, 1);
+  end = ax_goto (ax, aop_goto);
+  ax_label (ax, go1, ax->len);
+  ax_label (ax, go2, ax->len);
+  ax_const_l (ax, 0);
+  ax_label (ax, end, ax->len);
+  value->kind = axs_rvalue;
+  value->type = builtin_type (ax->gdbarch)->builtin_int;
+}
 
-    case OP_TYPE:
-    case OP_TYPEOF:
-    case OP_DECLTYPE:
-      error (_("Attempt to use a type name as an expression."));
+void
+logical_or_operation::do_generate_ax (struct expression *exp,
+                                     struct agent_expr *ax,
+                                     struct axs_value *value,
+                                     struct type *cast_type)
+{
+  struct axs_value value1, value2;
+  int if1, if2, end;
+
+  /* Generate the obvious sequence of tests and jumps.  */
+  std::get<0> (m_storage)->generate_ax (exp, ax, &value1);
+  gen_usual_unary (ax, &value1);
+  if1 = ax_goto (ax, aop_if_goto);
+  std::get<1> (m_storage)->generate_ax (exp, ax, &value2);
+  gen_usual_unary (ax, &value2);
+  if2 = ax_goto (ax, aop_if_goto);
+  ax_const_l (ax, 0);
+  end = ax_goto (ax, aop_goto);
+  ax_label (ax, if1, ax->len);
+  ax_label (ax, if2, ax->len);
+  ax_const_l (ax, 1);
+  ax_label (ax, end, ax->len);
+  value->kind = axs_rvalue;
+  value->type = builtin_type (ax->gdbarch)->builtin_int;
+}
 
-    default:
-      error (_("Unsupported operator %s (%d) in expression."),
-            op_name (exp, op), op);
-    }
 }
 
 /* This handles the middle-to-right-side of code generation for binary
@@ -2276,13 +2058,12 @@ gen_expr (struct expression *exp, union exp_element **pc,
 
 static void
 gen_expr_binop_rest (struct expression *exp,
-                    enum exp_opcode op, union exp_element **pc,
+                    enum exp_opcode op,
                     struct agent_expr *ax, struct axs_value *value,
                     struct axs_value *value1, struct axs_value *value2)
 {
   struct type *int_type = builtin_type (ax->gdbarch)->builtin_int;
 
-  gen_expr (exp, pc, ax, value2);
   gen_usual_unary (ax, value2);
   gen_usual_arithmetic (ax, value1, value2);
   switch (op)
@@ -2420,6 +2201,105 @@ gen_expr_binop_rest (struct expression *exp,
                      _("gen_expr: op case sets don't match"));
     }
 }
+
+/* A helper function that emits a binop based on two operations.  */
+
+void
+gen_expr_binop (struct expression *exp,
+               enum exp_opcode op,
+               expr::operation *lhs, expr::operation *rhs,
+               struct agent_expr *ax, struct axs_value *value)
+{
+  struct axs_value value1, value2;
+
+  lhs->generate_ax (exp, ax, &value1);
+  gen_usual_unary (ax, &value1);
+  rhs->generate_ax (exp, ax, &value2);
+  gen_expr_binop_rest (exp, op, ax, value, &value1, &value2);
+}
+
+/* A helper function that emits a structop based on an operation and a
+   member name.  */
+
+void
+gen_expr_structop (struct expression *exp,
+                  enum exp_opcode op,
+                  expr::operation *lhs,
+                  const char *name,
+                  struct agent_expr *ax, struct axs_value *value)
+{
+  lhs->generate_ax (exp, ax, value);
+  if (op == STRUCTOP_STRUCT)
+    gen_struct_ref (ax, value, name, ".", "structure or union");
+  else if (op == STRUCTOP_PTR)
+    gen_struct_ref (ax, value, name, "->",
+                   "pointer to a structure or union");
+  else
+    /* If this `if' chain doesn't handle it, then the case list
+       shouldn't mention it, and we shouldn't be here.  */
+    internal_error (__FILE__, __LINE__,
+                   _("gen_expr: unhandled struct case"));
+}
+
+/* A helper function that emits a unary operation.  */
+
+void
+gen_expr_unop (struct expression *exp,
+              enum exp_opcode op,
+              expr::operation *lhs,
+              struct agent_expr *ax, struct axs_value *value)
+{
+  struct axs_value value1, value2;
+
+  switch (op)
+    {
+    case UNOP_NEG:
+      gen_int_literal (ax, &value1, 0,
+                      builtin_type (ax->gdbarch)->builtin_int);
+      gen_usual_unary (ax, &value1);   /* shouldn't do much */
+      lhs->generate_ax (exp, ax, &value2);
+      gen_usual_unary (ax, &value2);
+      gen_usual_arithmetic (ax, &value1, &value2);
+      gen_binop (ax, value, &value1, &value2, aop_sub, aop_sub, 1, "negation");
+      break;
+
+    case UNOP_PLUS:
+      /* + FOO is equivalent to 0 + FOO, which can be optimized.  */
+      lhs->generate_ax (exp, ax, value);
+      gen_usual_unary (ax, value);
+      break;
+
+    case UNOP_LOGICAL_NOT:
+      lhs->generate_ax (exp, ax, value);
+      gen_usual_unary (ax, value);
+      gen_logical_not (ax, value,  builtin_type (ax->gdbarch)->builtin_int);
+      break;
+
+    case UNOP_COMPLEMENT:
+      lhs->generate_ax (exp, ax, value);
+      gen_usual_unary (ax, value);
+      gen_integral_promotions (ax, value);
+      gen_complement (ax, value);
+      break;
+
+    case UNOP_IND:
+      lhs->generate_ax (exp, ax, value);
+      gen_usual_unary (ax, value);
+      if (!pointer_type (value->type))
+       error (_("Argument of unary `*' is not a pointer."));
+      gen_deref (value);
+      break;
+
+    case UNOP_ADDR:
+      lhs->generate_ax (exp, ax, value);
+      gen_address_of (value);
+      break;
+
+    default:
+      gdb_assert_not_reached ("invalid case in gen_expr_unop");
+    }
+}
+
 \f
 
 /* Given a single variable and a scope, generate bytecodes to trace
@@ -2465,14 +2345,12 @@ gen_trace_for_expr (CORE_ADDR scope, struct expression *expr,
                    int trace_string)
 {
   agent_expr_up ax (new agent_expr (expr->gdbarch, scope));
-  union exp_element *pc;
   struct axs_value value;
 
-  pc = expr->elts;
   ax->tracing = 1;
   ax->trace_string = trace_string;
   value.optimized_out = 0;
-  gen_expr (expr, &pc, ax.get (), &value);
+  expr->op->generate_ax (expr, ax.get (), &value);
 
   /* Make sure we record the final object, and get rid of it.  */
   gen_traced_pop (ax.get (), &value);
@@ -2494,13 +2372,11 @@ agent_expr_up
 gen_eval_for_expr (CORE_ADDR scope, struct expression *expr)
 {
   agent_expr_up ax (new agent_expr (expr->gdbarch, scope));
-  union exp_element *pc;
   struct axs_value value;
 
-  pc = expr->elts;
   ax->tracing = 0;
   value.optimized_out = 0;
-  gen_expr (expr, &pc, ax.get (), &value);
+  expr->op->generate_ax (expr, ax.get (), &value);
 
   require_rvalue (ax.get (), &value);
 
@@ -2542,7 +2418,6 @@ gen_printf (CORE_ADDR scope, struct gdbarch *gdbarch,
            int nargs, struct expression **exprs)
 {
   agent_expr_up ax (new agent_expr (gdbarch, scope));
-  union exp_element *pc;
   struct axs_value value;
   int tem;
 
@@ -2553,9 +2428,8 @@ gen_printf (CORE_ADDR scope, struct gdbarch *gdbarch,
      for simplicity of collecting them on the target side.  */
   for (tem = nargs - 1; tem >= 0; --tem)
     {
-      pc = exprs[tem]->elts;
       value.optimized_out = 0;
-      gen_expr (exprs[tem], &pc, ax.get (), &value);
+      exprs[tem]->op->generate_ax (exprs[tem], ax.get (), &value);
       require_rvalue (ax.get (), &value);
     }
 
This page took 0.038967 seconds and 4 git commands to generate.