sizes), and this is simpler.)  */
 \f
 
-/* Generating bytecode from GDB expressions: the `trace' kludge  */
-
-/* The compiler in this file is a general-purpose mechanism for
-   translating GDB expressions into bytecode.  One ought to be able to
-   find a million and one uses for it.
-
-   However, at the moment it is HOPELESSLY BRAIN-DAMAGED for the sake
-   of expediency.  Let he who is without sin cast the first stone.
-
-   For the data tracing facility, we need to insert `trace' bytecodes
-   before each data fetch; this records all the memory that the
-   expression touches in the course of evaluation, so that memory will
-   be available when the user later tries to evaluate the expression
-   in GDB.
-
-   This should be done (I think) in a post-processing pass, that walks
-   an arbitrary agent expression and inserts `trace' operations at the
-   appropriate points.  But it's much faster to just hack them
-   directly into the code.  And since we're in a crunch, that's what
-   I've done.
-
-   Setting the flag trace_kludge to non-zero enables the code that
-   emits the trace bytecodes at the appropriate points.  */
-int trace_kludge;
-
-/* Inspired by trace_kludge, this indicates that pointers to chars
-   should get an added tracenz bytecode to record nonzero bytes, up to
-   a length that is the value of trace_string_kludge.  */
-int trace_string_kludge;
-
 /* Scan for all static fields in the given class, including any base
    classes, and generate tracing bytecodes for each.  */
 
                struct agent_expr *ax, struct axs_value *value)
 {
   int string_trace = 0;
-  if (trace_string_kludge
+  if (ax->trace_string
       && TYPE_CODE (value->type) == TYPE_CODE_PTR
       && c_textual_element_type (check_typedef (TYPE_TARGET_TYPE (value->type)),
                                 's'))
     string_trace = 1;
 
-  if (trace_kludge)
+  if (ax->tracing)
     switch (value->kind)
       {
       case axs_rvalue:
        if (string_trace)
          {
-           ax_const_l (ax, trace_string_kludge);
+           ax_const_l (ax, ax->trace_string);
            ax_simple (ax, aop_tracenz);
          }
        else
          if (string_trace)
            {
              ax_simple (ax, aop_ref32);
-             ax_const_l (ax, trace_string_kludge);
+             ax_const_l (ax, ax->trace_string);
              ax_simple (ax, aop_tracenz);
            }
        }
        if (string_trace)
          {
            ax_reg (ax, value->u.reg);
-           ax_const_l (ax, trace_string_kludge);
+           ax_const_l (ax, ax->trace_string);
            ax_simple (ax, aop_tracenz);
          }
        break;
     ax_simple (ax, aop_pop);
 
   /* To trace C++ classes with static fields stored elsewhere.  */
-  if (trace_kludge
+  if (ax->tracing
       && (TYPE_CODE (value->type) == TYPE_CODE_STRUCT
          || TYPE_CODE (value->type) == TYPE_CODE_UNION))
     gen_trace_static_fields (gdbarch, ax, value->type);
 static void
 gen_fetch (struct agent_expr *ax, struct type *type)
 {
-  if (trace_kludge)
+  if (ax->tracing)
     {
       /* Record the area of memory we're about to fetch.  */
       ax_trace_quick (ax, TYPE_LENGTH (type));
          /* Add the offset.  */
          gen_offset (ax, offset / TARGET_CHAR_BIT);
 
-         if (trace_kludge)
+         if (ax->tracing)
            {
              /* Record the area of memory we're about to fetch.  */
              ax_trace_quick (ax, op_size / TARGET_CHAR_BIT);
          if (tsv)
            {
              ax_tsv (ax, aop_setv, tsv->number);
-             if (trace_kludge)
+             if (ax->tracing)
                ax_tsv (ax, aop_tracev, tsv->number);
            }
          else
            {
              /* The tsv will be the left half of the binary operation.  */
              ax_tsv (ax, aop_getv, tsv->number);
-             if (trace_kludge)
+             if (ax->tracing)
                ax_tsv (ax, aop_tracev, tsv->number);
              /* Trace state variables are always 64-bit integers.  */
              value1.kind = axs_rvalue;
              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 (trace_kludge)
+             if (ax->tracing)
                ax_tsv (ax, aop_tracev, tsv->number);
            }
          else
        if (tsv)
          {
            ax_tsv (ax, aop_getv, tsv->number);
-           if (trace_kludge)
+           if (ax->tracing)
              ax_tsv (ax, aop_tracev, tsv->number);
            /* Trace state variables are always 64-bit integers.  */
            value->kind = axs_rvalue;
 
 struct agent_expr *
 gen_trace_for_var (CORE_ADDR scope, struct gdbarch *gdbarch,
-                  struct symbol *var)
+                  struct symbol *var, int trace_string)
 {
   struct cleanup *old_chain = 0;
   struct agent_expr *ax = new_agent_expr (gdbarch, scope);
 
   old_chain = make_cleanup_free_agent_expr (ax);
 
-  trace_kludge = 1;
+  ax->tracing = 1;
+  ax->trace_string = trace_string;
   gen_var_ref (gdbarch, ax, &value, var);
 
   /* If there is no actual variable to trace, flag it by returning
    caller can then use the ax_reqs function to discover which
    registers it relies upon.  */
 struct agent_expr *
-gen_trace_for_expr (CORE_ADDR scope, struct expression *expr)
+gen_trace_for_expr (CORE_ADDR scope, struct expression *expr,
+                   int trace_string)
 {
   struct cleanup *old_chain = 0;
   struct agent_expr *ax = new_agent_expr (expr->gdbarch, scope);
   old_chain = make_cleanup_free_agent_expr (ax);
 
   pc = expr->elts;
-  trace_kludge = 1;
+  ax->tracing = 1;
+  ax->trace_string = trace_string;
   value.optimized_out = 0;
   gen_expr (expr, &pc, ax, &value);
 
   old_chain = make_cleanup_free_agent_expr (ax);
 
   pc = expr->elts;
-  trace_kludge = 0;
+  ax->tracing = 0;
   value.optimized_out = 0;
   gen_expr (expr, &pc, ax, &value);
 
 }
 
 struct agent_expr *
-gen_trace_for_return_address (CORE_ADDR scope, struct gdbarch *gdbarch)
+gen_trace_for_return_address (CORE_ADDR scope, struct gdbarch *gdbarch,
+                             int trace_string)
 {
   struct cleanup *old_chain = 0;
   struct agent_expr *ax = new_agent_expr (gdbarch, scope);
 
   old_chain = make_cleanup_free_agent_expr (ax);
 
-  trace_kludge = 1;
+  ax->tracing = 1;
+  ax->trace_string = trace_string;
 
   gdbarch_gen_return_address (gdbarch, ax, &value, scope);
 
 
   old_chain = make_cleanup_free_agent_expr (ax);
 
+  /* We're computing values, not doing side effects.  */
+  ax->tracing = 0;
+
   /* Evaluate and push the args on the stack in reverse order,
      for simplicity of collecting them on the target side.  */
   for (tem = nargs - 1; tem >= 0; --tem)
     {
       pc = exprs[tem]->elts;
-      /* We're computing values, not doing side effects.  */
-      trace_kludge = 0;
       value.optimized_out = 0;
       gen_expr (exprs[tem], &pc, ax, &value);
       require_rvalue (ax, &value);
   struct expression *expr;
   struct agent_expr *agent;
   const char *arg;
+  int trace_string = 0;
 
   if (!eval)
     {
-      trace_string_kludge = 0;
       if (*exp == '/')
-        exp = decode_agent_options (exp);
+        exp = decode_agent_options (exp, &trace_string);
     }
 
   arg = exp;
   if (!eval && strcmp (arg, "$_ret") == 0)
     {
-      agent = gen_trace_for_return_address (pc, get_current_arch ());
+      agent = gen_trace_for_return_address (pc, get_current_arch (),
+                                           trace_string);
       old_chain = make_cleanup_free_agent_expr (agent);
     }
   else
       expr = parse_exp_1 (&arg, pc, block_for_pc (pc), 0);
       old_chain = make_cleanup (free_current_contents, &expr);
       if (eval)
-       agent = gen_eval_for_expr (pc, expr);
+       {
+         gdb_assert (trace_string == 0);
+         agent = gen_eval_for_expr (pc, expr);
+       }
       else
-       agent = gen_trace_for_expr (pc, expr);
+       agent = gen_trace_for_expr (pc, expr, trace_string);
       make_cleanup_free_agent_expr (agent);
     }
 
 
 /* Parse any collection options, such as /s for strings.  */
 
 const char *
-decode_agent_options (const char *exp)
+decode_agent_options (const char *exp, int *trace_string)
 {
   struct value_print_options opts;
 
+  *trace_string = 0;
+
   if (*exp != '/')
     return exp;
 
          /* Allow an optional decimal number giving an explicit maximum
             string length, defaulting it to the "print elements" value;
             so "collect/s80 mystr" gets at most 80 bytes of string.  */
-         trace_string_kludge = opts.print_max;
+         *trace_string = opts.print_max;
          exp++;
          if (*exp >= '0' && *exp <= '9')
-           trace_string_kludge = atoi (exp);
+           *trace_string = atoi (exp);
          while (*exp >= '0' && *exp <= '9')
            exp++;
        }
 
   if (cmd_cfunc_eq (c, collect_pseudocommand))
     {
-      trace_string_kludge = 0;
+      int trace_string = 0;
+
       if (*p == '/')
-       p = decode_agent_options (p);
+       p = decode_agent_options (p, &trace_string);
 
       do
        {                       /* Repeat over a comma-separated list.  */
              /* We have something to collect, make sure that the expr to
                 bytecode translator can handle it and that it's not too
                 long.  */
-             aexpr = gen_trace_for_expr (loc->address, exp);
+             aexpr = gen_trace_for_expr (loc->address, exp, trace_string);
              make_cleanup_free_agent_expr (aexpr);
 
              if (aexpr->len > MAX_AGENT_EXPR_LEN)
                struct symbol *sym,
                struct gdbarch *gdbarch,
                long frame_regno, long frame_offset,
-               CORE_ADDR scope)
+               CORE_ADDR scope,
+               int trace_string)
 {
   unsigned long len;
   unsigned int reg;
       struct agent_expr *aexpr;
       struct cleanup *old_chain1 = NULL;
 
-      aexpr = gen_trace_for_var (scope, gdbarch, sym);
+      aexpr = gen_trace_for_var (scope, gdbarch, sym, trace_string);
 
       /* It can happen that the symbol is recorded as a computed
         location, but it's been optimized away and doesn't actually
   long frame_regno;
   long frame_offset;
   int count;
+  int trace_string;
 };
 
 /* The callback for the locals and args iterators.  */
   struct add_local_symbols_data *p = cb_data;
 
   collect_symbol (p->collect, sym, p->gdbarch, p->frame_regno,
-                 p->frame_offset, p->pc);
+                 p->frame_offset, p->pc, p->trace_string);
   p->count++;
 }
 
 static void
 add_local_symbols (struct collection_list *collect,
                   struct gdbarch *gdbarch, CORE_ADDR pc,
-                  long frame_regno, long frame_offset, int type)
+                  long frame_regno, long frame_offset, int type,
+                  int trace_string)
 {
   struct block *block;
   struct add_local_symbols_data cb_data;
   cb_data.frame_regno = frame_regno;
   cb_data.frame_offset = frame_offset;
   cb_data.count = 0;
+  cb_data.trace_string = trace_string;
 
   if (type == 'L')
     {
 
       if (cmd_cfunc_eq (cmd, collect_pseudocommand))
        {
-         trace_string_kludge = 0;
+         int trace_string = 0;
+
          if (*action_exp == '/')
-           action_exp = decode_agent_options (action_exp);
+           action_exp = decode_agent_options (action_exp, &trace_string);
 
          do
            {                   /* Repeat over a comma-separated list.  */
                                     tloc->address,
                                     frame_reg,
                                     frame_offset,
-                                    'A');
+                                    'A',
+                                    trace_string);
                  action_exp = strchr (action_exp, ',');        /* more? */
                }
              else if (0 == strncasecmp ("$loc", action_exp, 4))
                                     tloc->address,
                                     frame_reg,
                                     frame_offset,
-                                    'L');
+                                    'L',
+                                    trace_string);
                  action_exp = strchr (action_exp, ',');        /* more? */
                }
              else if (0 == strncasecmp ("$_ret", action_exp, 5))
                  struct cleanup *old_chain1 = NULL;
 
                  aexpr = gen_trace_for_return_address (tloc->address,
-                                                       tloc->gdbarch);
+                                                       tloc->gdbarch,
+                                                       trace_string);
 
                  old_chain1 = make_cleanup_free_agent_expr (aexpr);
 
                                      tloc->gdbarch,
                                      frame_reg,
                                      frame_offset,
-                                     tloc->address);
+                                     tloc->address,
+                                     trace_string);
                      break;
 
                    default:    /* Full-fledged expression.  */
-                     aexpr = gen_trace_for_expr (tloc->address, exp);
+                     aexpr = gen_trace_for_expr (tloc->address, exp,
+                                                 trace_string);
 
                      old_chain1 = make_cleanup_free_agent_expr (aexpr);
 
              char *cmd = NULL;
              struct cleanup *old_chain
                = make_cleanup (free_current_contents, &cmd);
+             int trace_string = 0;
 
              if (*action_exp == '/')
-               action_exp = decode_agent_options (action_exp);
+               action_exp = decode_agent_options (action_exp, &trace_string);
 
              do
                {               /* Repeat over a comma-separated list.  */