diff -ruN --exclude=CVS --exclude=.svn --exclude='*~' /home/jimb/uberbaum/trace-base/gdb/ax-gdb.c /home/jimb/trace/trac/tracepoints/trunk/gdb/gdb/ax-gdb.c
--- /home/jimb/uberbaum/trace-base/gdb/ax-gdb.c	2007-02-27 14:41:44.000000000 -0800
+++ /home/jimb/trace/trac/tracepoints/trunk/gdb/gdb/ax-gdb.c	2007-03-02 11:40:21.000000000 -0800
@@ -321,15 +321,24 @@
 
       case axs_lvalue_memory:
 	{
-	  int length = TYPE_LENGTH (value->type);
+	  int length = TYPE_LENGTH (check_typedef (value->type));
 
-	  /* There's no point in trying to use a trace_quick bytecode
-	     here, since "trace_quick SIZE pop" is three bytes, whereas
-	     "const8 SIZE trace" is also three bytes, does the same
-	     thing, and the simplest code which generates that will also
-	     work correctly for objects with large sizes.  */
-	  ax_const_l (ax, length);
-	  ax_simple (ax, aop_trace);
+          /* Try to generate a trace_quick here if we can.  The
+             bytecode stream generated isn't any shorter ('quick <len>
+             pop' and 'const8 <len> trace' are both three bytes long),
+             but this simplifies agent expression evaluators that want
+             to be able to easily put an upper bound on the memory
+             that will be collected by an expression.  */
+          if (length < 1 << 16)
+            {
+              ax_trace_quick (ax, length);
+              ax_simple (ax, aop_pop);
+            }
+          else
+            {
+              ax_const_l (ax, length);
+              ax_simple (ax, aop_trace);
+            }
 	}
 	break;
 
@@ -650,7 +659,7 @@
 {
   ax_const_l (ax, k);
   value->kind = axs_rvalue;
-  value->type = type;
+  value->type = check_typedef (type);
 }
 
 
@@ -854,7 +863,7 @@
 	  ax_simple (ax, aop_swap);
 	}
 
-      value1->type = value2->type = target;
+      value1->type = value2->type = check_typedef (target);
     }
 }
 
@@ -907,7 +916,6 @@
          casting pointers we can do anything we like.  Is there any
          way for us to actually know what GCC actually does with a
          cast like this?  */
-      value->type = type;
       break;
 
     case TYPE_CODE_INT:
@@ -1810,6 +1818,29 @@
   return ax;
 }
 
+struct agent_expr *
+gen_trace_for_symbol (CORE_ADDR scope, struct symbol *sym)
+{
+  struct agent_expr *ax = new_agent_expr (scope);
+  struct cleanup *old_chain = make_cleanup_free_agent_expr (ax);
+  struct axs_value value;
+
+  trace_kludge = 1;
+  gen_var_ref (ax, &value, sym);
+
+  /* Make sure we record the final object, and get rid of it.  */
+  gen_traced_pop (ax, &value);
+
+  /* Oh, and terminate.  */
+  ax_simple (ax, aop_end);
+
+  /* We have successfully built the agent expr, so cancel the cleanup
+     request.  If we add more cleanups that we always want done, this
+     will have to get more complicated.  */
+  discard_cleanups (old_chain);
+  return ax;
+}
+
 static void
 agent_command (char *exp, int from_tty)
 {
diff -ruN --exclude=CVS --exclude=.svn --exclude='*~' /home/jimb/uberbaum/trace-base/gdb/ax-gdb.h /home/jimb/trace/trac/tracepoints/trunk/gdb/gdb/ax-gdb.h
--- /home/jimb/uberbaum/trace-base/gdb/ax-gdb.h	2007-02-27 14:41:40.000000000 -0800
+++ /home/jimb/trace/trac/tracepoints/trunk/gdb/gdb/ax-gdb.h	2007-03-02 11:40:17.000000000 -0800
@@ -110,4 +110,11 @@
    function to discover which registers the expression uses.  */
 extern struct agent_expr *gen_trace_for_expr (CORE_ADDR, struct expression *);
 
+/* Given a GDB symbol SYM, return bytecode to trace its value.
+   The result will use the `trace' and `trace_quick' bytecodes to
+   record the value of all memory touched by the expression, and leave
+   no values on the stack.  The caller can then use the ax_reqs
+   function to discover which registers the expression uses.  */
+extern struct agent_expr *gen_trace_for_symbol (CORE_ADDR, struct symbol *);
+
 #endif /* AX_GDB_H */
diff -ruN --exclude=CVS --exclude=.svn --exclude='*~' /home/jimb/uberbaum/trace-base/gdb/ax-general.c /home/jimb/trace/trac/tracepoints/trunk/gdb/gdb/ax-general.c
--- /home/jimb/uberbaum/trace-base/gdb/ax-general.c	2007-02-27 14:41:40.000000000 -0800
+++ /home/jimb/trace/trac/tracepoints/trunk/gdb/gdb/ax-general.c	2007-03-02 11:40:17.000000000 -0800
@@ -168,17 +168,29 @@
 }
 
 
-/* Append a trace_quick instruction to EXPR, to record N bytes.  */
+/* Append a trace_quick or trace16 instruction to EXPR, to record N bytes.  */
 void
 ax_trace_quick (struct agent_expr *x, int n)
 {
-  /* N must fit in a byte.  */
-  if (n < 0 || n > 255)
-    error (_("GDB bug: ax-general.c (ax_trace_quick): size out of range for trace_quick"));
-
-  grow_expr (x, 2);
-  x->buf[x->len++] = aop_trace_quick;
-  x->buf[x->len++] = n;
+  if (n < 0)
+    internal_error (__FILE__, __LINE__,
+                    _("ax_trace_quick: negative size"));
+  else if (n < (1 << 8))
+    {
+      grow_expr (x, 2);
+      x->buf[x->len++] = aop_trace_quick;
+      x->buf[x->len++] = n;
+    }
+  else if (n < (1 << 16))
+    {
+      grow_expr (x, 3);
+      x->buf[x->len++] = aop_trace16;
+      x->buf[x->len++] = n >> 8;
+      x->buf[x->len++] = n;
+    }
+  else
+    internal_error (__FILE__, __LINE__,
+                    _("ax_trace_quick: size out of range"));
 }
 
 
diff -ruN --exclude=CVS --exclude=.svn --exclude='*~' /home/jimb/uberbaum/trace-base/gdb/ax.h /home/jimb/trace/trac/tracepoints/trunk/gdb/gdb/ax.h
--- /home/jimb/uberbaum/trace-base/gdb/ax.h	2007-02-27 14:41:40.000000000 -0800
+++ /home/jimb/trace/trac/tracepoints/trunk/gdb/gdb/ax.h	2007-03-02 11:40:14.000000000 -0800
@@ -159,7 +159,8 @@
 /* Append a zero-extension instruction to EXPR, to extend an N-bit value.  */
 extern void ax_zero_ext (struct agent_expr *EXPR, int N);
 
-/* Append a trace_quick instruction to EXPR, to record N bytes.  */
+/* Append a trace_quick or trace16 instruction to EXPR, to record N bytes.  
+   N must be less than 65536.  */
 extern void ax_trace_quick (struct agent_expr *EXPR, int N);
 
 /* Append a goto op to EXPR.  OP is the actual op (must be aop_goto or
diff -ruN --exclude=CVS --exclude=.svn --exclude='*~' /home/jimb/uberbaum/trace-base/gdb/config/i386/linux.mh /home/jimb/trace/trac/tracepoints/trunk/gdb/gdb/config/i386/linux.mh
--- /home/jimb/uberbaum/trace-base/gdb/config/i386/linux.mh	2007-02-27 14:41:40.000000000 -0800
+++ /home/jimb/trace/trac/tracepoints/trunk/gdb/gdb/config/i386/linux.mh	2007-03-02 11:40:19.000000000 -0800
@@ -4,7 +4,7 @@
 NATDEPFILES= inf-ptrace.o fork-child.o corelow.o \
 	core-aout.o i386-nat.o i386-linux-nat.o \
 	proc-service.o linux-thread-db.o gcore.o \
-	linux-nat.o linux-fork.o
+	linux-nat.o linux-fork.o linux-trace.o 
 
 # The dynamically loaded libthread_db needs access to symbols in the
 # gdb executable.
diff -ruN --exclude=CVS --exclude=.svn --exclude='*~' /home/jimb/uberbaum/trace-base/gdb/dwarf2-frame.c /home/jimb/trace/trac/tracepoints/trunk/gdb/gdb/dwarf2-frame.c
--- /home/jimb/uberbaum/trace-base/gdb/dwarf2-frame.c	2007-02-27 14:41:40.000000000 -0800
+++ /home/jimb/trace/trac/tracepoints/trunk/gdb/gdb/dwarf2-frame.c	2007-03-02 11:40:16.000000000 -0800
@@ -334,12 +334,14 @@
 	  else 
 	    fs->regs.reg[reg].how = DWARF2_FRAME_REG_UNSPECIFIED;
 
+#if 0
 	  if (fs->regs.reg[reg].how == DWARF2_FRAME_REG_UNSPECIFIED)
 	    complaint (&symfile_complaints, _("\
 incomplete CFI data; DW_CFA_restore unspecified\n\
 register %s (#%d) at 0x%s"),
 		       REGISTER_NAME(DWARF2_REG_TO_REGNUM(reg)),
 		       DWARF2_REG_TO_REGNUM(reg), paddr (fs->pc));
+#endif
 	}
       else
 	{
@@ -934,11 +936,13 @@
 	   DWARF2 register numbers.  */
 	if (fs->regs.reg[column].how == DWARF2_FRAME_REG_UNSPECIFIED)
 	  {
+#if 0
 	    if (cache->reg[regnum].how == DWARF2_FRAME_REG_UNSPECIFIED)
 	      complaint (&symfile_complaints, _("\
 incomplete CFI data; unspecified registers (e.g., %s) at 0x%s"),
 			 gdbarch_register_name (gdbarch, regnum),
 			 paddr_nz (fs->pc));
+#endif
 	  }
 	else
 	  cache->reg[regnum] = fs->regs.reg[column];
diff -ruN --exclude=CVS --exclude=.svn --exclude='*~' /home/jimb/uberbaum/trace-base/gdb/dwarf2loc.c /home/jimb/trace/trac/tracepoints/trunk/gdb/gdb/dwarf2loc.c
--- /home/jimb/uberbaum/trace-base/gdb/dwarf2loc.c	2007-02-27 14:41:40.000000000 -0800
+++ /home/jimb/trace/trac/tracepoints/trunk/gdb/gdb/dwarf2loc.c	2007-03-02 11:40:20.000000000 -0800
@@ -137,6 +137,35 @@
   read_memory (addr, buf, len);
 }
 
+
+/* Find the location expression describing the frame base for the code
+   address PC.  Return a pointer to it in *START, and its length in
+   *LENGTH.  */
+static void
+dwarf_frame_base_for_pc (CORE_ADDR pc, gdb_byte **start, size_t *length)
+{
+  struct symbol *framefunc = find_pc_function (pc);
+
+  if (SYMBOL_OPS (framefunc) == &dwarf2_loclist_funcs)
+    {
+      struct dwarf2_loclist_baton *symbaton
+        = SYMBOL_LOCATION_BATON (framefunc);    
+      *start = find_location_expression (symbaton, length, pc);
+    }
+  else
+    {
+      struct dwarf2_locexpr_baton *symbaton
+        = SYMBOL_LOCATION_BATON (framefunc);    
+      *length = symbaton->size;
+      *start = symbaton->data;
+    }
+
+  if (*start == NULL)
+    error (_("Could not find the frame base for \"%s\"."),
+	   SYMBOL_NATURAL_NAME (framefunc));
+}
+
+
 /* Using the frame specified in BATON, find the location expression
    describing the frame base.  Return a pointer to it in START and
    its length in LENGTH.  */
@@ -354,6 +383,8 @@
 			   struct axs_value *value, gdb_byte *data,
 			   int size)
 {
+  gdb_byte *buf_end;
+
   if (size == 0)
     error (_("Symbol \"%s\" has been optimized out."),
 	   SYMBOL_PRINT_NAME (symbol));
@@ -362,33 +393,46 @@
       && data[0] >= DW_OP_reg0
       && data[0] <= DW_OP_reg31)
     {
+      int reg = DWARF2_REG_TO_REGNUM (data[0] - DW_OP_reg0);
+      buf_end = data + 1;
+
       value->kind = axs_lvalue_register;
-      value->u.reg = data[0] - DW_OP_reg0;
+      value->u.reg = reg;
     }
   else if (data[0] == DW_OP_regx)
     {
       ULONGEST reg;
-      read_uleb128 (data + 1, data + size, &reg);
+      buf_end = read_uleb128 (data + 1, data + size, &reg);
+      reg = DWARF2_REG_TO_REGNUM (reg);
+
       value->kind = axs_lvalue_register;
       value->u.reg = reg;
     }
   else if (data[0] == DW_OP_fbreg)
     {
-      /* And this is worse than just minimal; we should honor the frame base
-	 as above.  */
-      int frame_reg;
       LONGEST frame_offset;
-      gdb_byte *buf_end;
+      gdb_byte *fb_start;
+      size_t fb_length;
 
       buf_end = read_sleb128 (data + 1, data + size, &frame_offset);
-      if (buf_end != data + size)
-	error (_("Unexpected opcode after DW_OP_fbreg for symbol \"%s\"."),
-	       SYMBOL_PRINT_NAME (symbol));
-
-      TARGET_VIRTUAL_FRAME_POINTER (ax->scope, &frame_reg, &frame_offset);
-      ax_reg (ax, frame_reg);
-      ax_const_l (ax, frame_offset);
-      ax_simple (ax, aop_add);
+
+      /* Find our frame base expression.  */
+      dwarf_frame_base_for_pc (ax->scope, &fb_start, &fb_length);
+
+      /* Recurse, to produce bytecode for the frame base.  */        
+      dwarf2_tracepoint_var_ref (symbol, ax, value, fb_start, fb_length);
+      
+      /* Frame base expressions may be register names; if this is the case, 
+         we need the actual register's value on the stack.  */
+      if (value->kind == axs_lvalue_register)
+        ax_reg (ax, value->u.reg);
+
+      /* Now add the constant operand of DW_OP_fbreg to that.  */
+      if (frame_offset != 0)
+        {
+          ax_const_l (ax, frame_offset);
+          ax_simple (ax, aop_add);
+        }
 
       value->kind = axs_lvalue_memory;
     }
@@ -397,23 +441,27 @@
     {
       unsigned int reg;
       LONGEST offset;
-      gdb_byte *buf_end;
 
-      reg = data[0] - DW_OP_breg0;
+      reg = DWARF2_REG_TO_REGNUM (data[0] - DW_OP_breg0);
       buf_end = read_sleb128 (data + 1, data + size, &offset);
-      if (buf_end != data + size)
-	error (_("Unexpected opcode after DW_OP_breg%u for symbol \"%s\"."),
-	       reg, SYMBOL_PRINT_NAME (symbol));
 
       ax_reg (ax, reg);
-      ax_const_l (ax, offset);
-      ax_simple (ax, aop_add);
+      if (offset != 0)
+        {
+          ax_const_l (ax, offset);
+          ax_simple (ax, aop_add);
+        }
 
       value->kind = axs_lvalue_memory;
     }
   else
     error (_("Unsupported DWARF opcode 0x%x in the location of \"%s\"."),
 	   data[0], SYMBOL_PRINT_NAME (symbol));
+
+  value->type = SYMBOL_TYPE (symbol);
+  if (buf_end != data + size)
+    error (_("Unexpected opcodes in location expression for symbol \"%s\"."),
+           SYMBOL_PRINT_NAME (symbol));
 }
 
 /* Return the value of SYMBOL in FRAME using the DWARF-2 expression
diff -ruN --exclude=CVS --exclude=.svn --exclude='*~' /home/jimb/uberbaum/trace-base/gdb/linux-trace.c /home/jimb/trace/trac/tracepoints/trunk/gdb/gdb/linux-trace.c
--- /home/jimb/uberbaum/trace-base/gdb/linux-trace.c	1969-12-31 16:00:00.000000000 -0800
+++ /home/jimb/trace/trac/tracepoints/trunk/gdb/gdb/linux-trace.c	2007-03-02 11:40:21.000000000 -0800
@@ -0,0 +1,365 @@
+/* Tracepoint support for the Linux Kernel.
+
+   Copyright (C) 2007 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#include "defs.h"
+
+#include <stdlib.h>
+
+#include "target.h"
+#include "frame.h"
+#include "regcache.h"
+
+static struct target_ops linux_trace_ops;
+
+/* The path of the kernel tracepoint control file.  */
+#define TRACEPOINT_CTRL_FILE "/proc/gdb-tracepoints"
+
+/* A file descriptor for TRACEPOINT_CTRL_FILE, or -1.  */
+static int trace_fd = -1;
+
+
+/* Trading packets with the tracepoint control file.  */
+
+static unsigned char response[1024];
+
+
+static void
+check_packet_error (char *response)
+{
+  if (response[0] == 'E')
+    {
+      char *end;
+      long n = strtol (response + 1, &end, 16);
+      if (*end == '\0')
+        error (_("Error response from kernel: %s"), safe_strerror (n));
+      else
+        error (_("Error response from kernel: %s"), response);
+    }
+}
+
+
+static void
+packet (char *request, int check)
+{
+  int request_len = strlen (request);
+  int len;
+
+  gdb_assert (trace_fd != -1);
+
+  if (remote_debug)
+    fprintf_unfiltered (gdb_stdlog, "request: '%s'\n", request);
+
+  len = write (trace_fd, request, request_len);
+  if (len < 0)
+    perror_with_name (TRACEPOINT_CTRL_FILE);
+  if (len < request_len)
+    error (_("Error sending linux-trace packet: partial write"));
+
+  len = read (trace_fd, response, sizeof (response) - 1);
+  if (len < 0)
+    {
+      response[0] = '\0';
+      perror_with_name (TRACEPOINT_CTRL_FILE);
+    }
+
+  response[len] = '\0';
+
+  if (remote_debug)
+    fprintf_unfiltered (gdb_stdlog, "reply:   '%s'\n", response);
+
+  if (check)
+    check_packet_error (response);
+}
+
+
+
+/* Opening and closing.  */
+
+
+static void
+linux_trace_init (void)
+{
+  packet ("QTinit", 1);
+}
+
+
+static void
+linux_trace_open (char *filename, int from_tty)
+{
+  if (filename
+      && filename[0])
+    error (_("The 'linux-trace' target doesn't take any arguments.\n"
+             "It always operates on the kernel it's running under.\n"));
+
+  target_preopen (from_tty);
+  unpush_target (&linux_trace_ops);
+
+  /* Try to open the kernel tracepoints control file.  */
+  trace_fd = open (TRACEPOINT_CTRL_FILE, O_RDWR);
+  if (trace_fd == -1)
+    {
+      if (errno == ENOENT)
+        error (_("Couldn't open %s.\n"
+                 "Have you loaded the tracepoint kernel module?"),
+                 TRACEPOINT_CTRL_FILE);
+      else
+        perror_with_name (TRACEPOINT_CTRL_FILE);
+    }
+
+  push_target (&linux_trace_ops);
+
+  puts_filtered ("Debugging with Linux kernel tracepoints.\n");
+
+  /* Start with a fresh slate.  */
+  linux_trace_init ();
+}
+ 
+
+static void
+linux_trace_close (int quitting)
+{
+  if (trace_fd != -1)
+    {
+      linux_trace_init ();
+      close (trace_fd);
+      trace_fd = -1;
+    }
+}
+
+
+static void
+linux_trace_detach (char *args, int from_tty)
+{
+  if (args)
+    error (_("When debugging with kernel tracepoints, "
+             "\"detach\" takes no arguments."));
+
+  unpush_target (&linux_trace_ops);
+  reinit_frame_cache ();
+
+  if (from_tty)
+    printf_filtered (_("No longer debugging Linux kernel via tracepoints.\n"));
+}
+
+
+
+/* Register access.  */
+
+
+static int
+hex_digit_value (char h)
+{
+  if ('0' <= h && h <= '9')
+    return h - '0';
+  else if ('a' <= h && h <= 'f')
+    return h - 'a' + 10;
+  else if ('A' <= h && h <= 'F')
+    return h - 'A' + 10;
+  else
+    return 0;
+}
+
+
+static void
+linux_trace_fetch_registers (int regno)
+{
+  size_t response_len;
+  int reg, byte;
+  size_t reg_size;
+
+  packet ("g", 0);
+
+  if (strcmp (response, "E03") == 0)
+    error ("No tracepoint hit is currently selected.");
+  else
+    check_packet_error (response);
+
+  response_len = strlen (response);
+
+  /* Sanity checks, with knowledge of the architecture.  */
+  if (REGISTER_BYTES_OK_P () && !REGISTER_BYTES_OK (response_len / 2))
+    error (_("Tracepoint 'g' packet reply is wrong length: '%s'"), response);
+
+  for (reg = 0, byte = 0; byte * 2 < response_len; reg++, byte += reg_size)
+    {
+      unsigned char buf[MAX_REGISTER_SIZE];
+      int i;
+
+      reg_size = register_size (current_gdbarch, reg);
+      for (i = 0; i < reg_size; i++)
+        buf[i] = ((hex_digit_value (response[(byte + i) * 2]) << 4)
+                  + hex_digit_value (response[(byte + i) * 2 + 1]));
+      regcache_raw_supply (current_regcache, reg, buf);
+    }
+
+  /* If we don't have enough bytes here, then mark this register
+     as unavailable.  */
+  if (regno >= reg)
+    {
+      regcache_raw_supply (current_regcache, regno, NULL);
+      set_register_cached (regno, -1);
+    }
+}
+
+
+static int
+linux_trace_has_registers_func (struct target_ops *ops)
+{
+  packet ("qTFrame", 1);
+  if (response[0] != 'F')
+    error ("linux-trace: unexpected reply to qTFrame: %s", response);
+  return response[1] == '1';
+}
+
+
+/* Memory access.  */
+
+static LONGEST
+linux_trace_xfer_partial (struct target_ops *ops,
+                          enum target_object object, const char *annex,
+                          gdb_byte *readbuf, const gdb_byte *writebuf,
+                          ULONGEST offset, LONGEST len)
+{
+  char request[100];
+  size_t response_len;
+  int i;
+
+  if (object != TARGET_OBJECT_MEMORY)
+    return -1;
+
+  /* It's not meaningful to write to a tracepoint hit.  */
+  if (writebuf)
+    return 0;
+  gdb_assert (readbuf);
+
+  sprintf (request, "m%llx,%llx",
+           (unsigned long long) offset, (unsigned long long) len);
+  packet (request, 0);
+  if (strcmp (response, "E03") == 0 /* no hit */
+      || strcmp (response, "E0e") == 0) /* address not logged */
+    return 0;                   /* fall through to executable */
+  else
+    check_packet_error (response);
+
+  response_len = strlen (response);
+  for (i = 0; i * 2 < response_len; i++)
+    readbuf[i] = ((hex_digit_value (response[i * 2]) << 4)
+                  + hex_digit_value (response[i * 2 + 1]));
+
+  return i;
+}
+
+
+
+/* Raw packet transfer.  */
+
+/* Really, the operations in tracepoints.c should get their own target
+   methods; passing remote protocol packets across the target boundary
+   is a crock.  But this is quicker.  */
+
+static void
+linux_trace_getpkt (char **buf, long *sizeof_buf, int forever)
+{
+  /* Our kludgy procfs interface requires us to read the whole
+     thing in one go.  But that makes this a bit simpler.  */
+  size_t len = read (trace_fd, response, sizeof (response));
+  if (len < 0)
+    {
+      response[0] = '\0';
+      perror_with_name (TRACEPOINT_CTRL_FILE);
+    }
+
+  if (*sizeof_buf < len + 1)
+    {
+      *sizeof_buf = len + 1;
+      *buf = xrealloc (*buf, *sizeof_buf);
+    }
+
+  memcpy (*buf, response, len);
+  (*buf)[len] = '\0';
+
+  if (remote_debug)
+    fprintf_unfiltered (gdb_stdlog, "reply: '%s'\n", *buf);
+}
+
+
+static int
+linux_trace_putpkt (char *buf)
+{
+  int buf_len, len;
+
+  buf_len = strlen (buf);
+  len = write (trace_fd, buf, buf_len);
+  if (len < 0)
+    perror_with_name (TRACEPOINT_CTRL_FILE);
+  if (len < buf_len)
+    error (_("Error sending linux-trace packet: partial write"));
+
+  if (remote_debug)
+    fprintf_unfiltered (gdb_stdlog, "sent:  '%s'\n", buf);
+
+  return 1;
+}
+
+
+
+/* Initialization.  */
+
+
+static int
+ignore (struct bp_target_info *bp_tgt)
+{
+  return 0;
+}
+
+
+static void
+init_linux_trace_ops ()
+{
+  struct target_ops *o = &linux_trace_ops;
+  o->to_shortname = "linux-trace";
+  o->to_longname = "Linux kernel tracepoints";
+  o->to_doc = "Debug the currently running Linux kernel using tracepoints.";
+  o->to_open = linux_trace_open;
+  o->to_close = linux_trace_close;
+  o->to_detach = linux_trace_detach;
+  o->to_fetch_registers = linux_trace_fetch_registers;
+  o->to_xfer_partial = linux_trace_xfer_partial;
+  o->to_insert_breakpoint = ignore;
+  o->to_remove_breakpoint = ignore;
+  o->to_getpkt = linux_trace_getpkt;
+  o->to_putpkt = linux_trace_putpkt;
+  o->to_stratum = core_stratum;
+  o->to_has_memory = 1;
+  o->to_has_stack = 1;
+  o->to_has_memory_func = linux_trace_has_registers_func;
+  o->to_has_stack_func = linux_trace_has_registers_func;  /* same as above */
+  o->to_has_registers_func = linux_trace_has_registers_func; /* same as above */
+  o->to_magic = OPS_MAGIC;
+}
+
+
+void
+_initialize_linux_trace (void)
+{
+  init_linux_trace_ops ();
+  add_target (&linux_trace_ops);
+}
diff -ruN --exclude=CVS --exclude=.svn --exclude='*~' /home/jimb/uberbaum/trace-base/gdb/Makefile.in /home/jimb/trace/trac/tracepoints/trunk/gdb/gdb/Makefile.in
--- /home/jimb/uberbaum/trace-base/gdb/Makefile.in	2007-02-27 14:41:40.000000000 -0800
+++ /home/jimb/trace/trac/tracepoints/trunk/gdb/gdb/Makefile.in	2007-03-02 11:40:17.000000000 -0800
@@ -542,6 +542,7 @@
 	interps.c \
 	jv-exp.y jv-lang.c jv-valprint.c jv-typeprint.c \
 	language.c linespec.c \
+	linux-trace.c \
 	m2-exp.y m2-lang.c m2-typeprint.c m2-valprint.c \
 	macrotab.c macroexp.c macrocmd.c macroscope.c main.c maint.c \
 	mdebugread.c memattr.c mem-break.c minsyms.c mipsread.c memory-map.c \
@@ -1467,6 +1468,7 @@
 	infptrace.c inftarg.c irix5-nat.c \
 	libunwind-frame.c \
 	linux-fork.c \
+	linux-trace.c \
 	lynx-nat.c \
 	m68hc11-tdep.c \
 	m32r-tdep.c \
@@ -2255,6 +2257,7 @@
 linux-fork.o: linux-fork.c $(defs_h) $(inferior_h) $(regcache_h) $(gdbcmd_h) \
 	$(infcall_h) $(gdb_assert_h) $(gdb_string_h) $(linux_fork_h) \
 	$(linux_nat_h)
+linux-trace.o: linux-trace.c $(defs_h) $(target_h)
 linux-nat.o: linux-nat.c $(defs_h) $(inferior_h) $(target_h) $(gdb_string_h) \
 	$(gdb_wait_h) $(gdb_assert_h) $(linux_nat_h) $(gdbthread_h) \
 	$(gdbcmd_h) $(regcache_h) $(regset_h) $(inf_ptrace_h) $(auxv_h) \
diff -ruN --exclude=CVS --exclude=.svn --exclude='*~' /home/jimb/uberbaum/trace-base/gdb/remote.c /home/jimb/trace/trac/tracepoints/trunk/gdb/gdb/remote.c
--- /home/jimb/uberbaum/trace-base/gdb/remote.c	2007-02-27 14:41:41.000000000 -0800
+++ /home/jimb/trace/trac/tracepoints/trunk/gdb/gdb/remote.c	2007-03-02 11:40:20.000000000 -0800
@@ -191,6 +191,10 @@
 
 static int bin2hex (const gdb_byte *bin, char *hex, int count);
 
+static void getpkt (char **buf, long *sizeof_buf, int forever);
+
+static int putpkt (char *buf);
+
 static int putpkt_binary (char *buf, int cnt);
 
 static void check_binary_download (CORE_ADDR addr);
@@ -4553,7 +4557,7 @@
   puts_filtered ("\"");
 }
 
-int
+static int
 putpkt (char *buf)
 {
   return putpkt_binary (buf, strlen (buf));
@@ -4855,7 +4859,7 @@
    don't have to change all the calls to getpkt to deal with the
    return value, because at the moment I don't know what the right
    thing to do it for those.  */
-void
+static void
 getpkt (char **buf,
 	long *sizeof_buf,
 	int forever)
diff -ruN --exclude=CVS --exclude=.svn --exclude='*~' /home/jimb/uberbaum/trace-base/gdb/remote-fileio.c /home/jimb/trace/trac/tracepoints/trunk/gdb/gdb/remote-fileio.c
--- /home/jimb/uberbaum/trace-base/gdb/remote-fileio.c	2007-02-27 14:41:40.000000000 -0800
+++ /home/jimb/trace/trac/tracepoints/trunk/gdb/gdb/remote-fileio.c	2007-03-02 11:40:13.000000000 -0800
@@ -30,6 +30,7 @@
 #include "gdb_stat.h"
 #include "exceptions.h"
 #include "remote-fileio.h"
+#include "target.h"
 
 #include <fcntl.h>
 #include <sys/time.h>
@@ -538,7 +539,7 @@
         strcat (buf, ",C");
     }
   remote_fileio_sig_set (remote_fileio_ctrl_c_signal_handler);
-  putpkt (buf);
+  target_putpkt (buf);
 }
 
 static void
diff -ruN --exclude=CVS --exclude=.svn --exclude='*~' /home/jimb/uberbaum/trace-base/gdb/remote.h /home/jimb/trace/trac/tracepoints/trunk/gdb/gdb/remote.h
--- /home/jimb/uberbaum/trace-base/gdb/remote.h	2007-02-27 14:41:46.000000000 -0800
+++ /home/jimb/trace/trac/tracepoints/trunk/gdb/gdb/remote.h	2007-03-02 11:40:22.000000000 -0800
@@ -26,22 +26,6 @@
 
 /* FIXME?: move this interface down to tgt vector) */
 
-/* Read a packet from the remote machine, with error checking, and
-   store it in *BUF.  Resize *BUF using xrealloc if necessary to hold
-   the result, and update *SIZEOF_BUF.  If FOREVER, wait forever
-   rather than timing out; this is used (in synchronous mode) to wait
-   for a target that is is executing user code to stop.  */
-
-extern void getpkt (char **buf, long *sizeof_buf, int forever);
-
-/* Send a packet to the remote machine, with error checking.  The data
-   of the packet is in BUF.  The string in BUF can be at most PBUFSIZ
-   - 5 to account for the $, # and checksum, and for a possible /0 if
-   we are debugging (remote_debug) and want to print the sent packet
-   as a string */
-
-extern int putpkt (char *buf);
-
 /* Send HEX encoded string to the target console. (gdb_stdtarg) */
 
 extern void remote_console_output (char *);
diff -ruN --exclude=CVS --exclude=.svn --exclude='*~' /home/jimb/uberbaum/trace-base/gdb/target.c /home/jimb/trace/trac/tracepoints/trunk/gdb/gdb/target.c
--- /home/jimb/uberbaum/trace-base/gdb/target.c	2007-02-27 14:41:43.000000000 -0800
+++ /home/jimb/trace/trac/tracepoints/trunk/gdb/gdb/target.c	2007-03-02 11:40:21.000000000 -0800
@@ -362,6 +362,24 @@
   target_create_inferior (exec, args, env, from_tty);
 }
 
+static int
+get_has_memory_flag (struct target_ops *ops)
+{
+  return ops->to_has_memory;
+}
+
+static int
+get_has_stack_flag (struct target_ops *ops)
+{
+  return ops->to_has_stack;
+}
+
+static int
+get_has_registers_flag (struct target_ops *ops)
+{
+  return ops->to_has_registers;
+}
+
 /* Go through the target stack from top to bottom, copying over zero
    entries in current_target, then filling in still empty entries.  In
    effect, we are doing class inheritance through the pushed target
@@ -446,14 +464,19 @@
       INHERIT (to_stop, t);
       /* Do not inherit to_xfer_partial.  */
       INHERIT (to_rcmd, t);
+      INHERIT (to_getpkt, t);
+      INHERIT (to_putpkt, t);
       INHERIT (to_enable_exception_callback, t);
       INHERIT (to_get_current_exception_event, t);
       INHERIT (to_pid_to_exec_file, t);
       INHERIT (to_stratum, t);
       INHERIT (to_has_all_memory, t);
       INHERIT (to_has_memory, t);
+      INHERIT (to_has_memory_func, t);
       INHERIT (to_has_stack, t);
+      INHERIT (to_has_stack_func, t);
       INHERIT (to_has_registers, t);
+      INHERIT (to_has_registers_func, t);
       INHERIT (to_has_execution, t);
       INHERIT (to_has_thread_control, t);
       INHERIT (to_sections, t);
@@ -625,6 +648,12 @@
   de_fault (to_rcmd,
 	    (void (*) (char *, struct ui_file *))
 	    tcomplain);
+  de_fault (to_getpkt,
+	    (void (*) (char **, long *, int))
+	    tcomplain);
+  de_fault (to_putpkt,
+	    (int (*) (char *))
+	    tcomplain);
   de_fault (to_enable_exception_callback,
 	    (struct symtab_and_line * (*) (enum exception_event_kind, int))
 	    nosupport_runtime);
@@ -643,6 +672,10 @@
   de_fault (to_async,
 	    (void (*) (void (*) (enum inferior_event_type, void*), void*))
 	    tcomplain);
+  de_fault (to_has_memory_func, get_has_memory_flag);
+  de_fault (to_has_stack_func, get_has_stack_flag);
+  de_fault (to_has_registers_func, get_has_registers_flag);
+            
   current_target.to_read_description = NULL;
 #undef de_fault
 
@@ -2660,6 +2693,22 @@
   fprintf_unfiltered (gdb_stdlog, "target_rcmd (%s, ...)\n", command);
 }
 
+static void
+debug_to_getpkt (char **buf, long *sizeof_buf, int forever)
+{
+  debug_target.to_getpkt (buf, sizeof_buf, forever);
+  fprintf_unfiltered (gdb_stdlog, "target_getpkt (&\"%s\", &%ld, %d)",
+                      *buf, *sizeof_buf, forever);
+}
+
+static int
+debug_to_putpkt (char *buf)
+{
+  int result = debug_target.to_putpkt (buf);
+  fprintf_unfiltered (gdb_stdlog, "target_putpkt (\"%s\")", buf);
+  return result;
+}
+
 static struct symtab_and_line *
 debug_to_enable_exception_callback (enum exception_event_kind kind, int enable)
 {
@@ -2693,6 +2742,36 @@
   return exec_file;
 }
 
+static int
+debug_to_has_memory_func (struct target_ops *ops)
+{
+  int has_mem = debug_target.to_has_memory_func (ops);
+
+  fprintf_unfiltered (gdb_stdlog, "target_has_memory_func (ops) = %d\n",
+                      has_mem);
+  return has_mem;
+}
+
+static int
+debug_to_has_stack_func (struct target_ops *ops)
+{
+  int has_stack = debug_target.to_has_stack_func (ops);
+
+  fprintf_unfiltered (gdb_stdlog, "target_has_stack_func (ops) = %d\n",
+                      has_stack);
+  return has_stack;
+}
+
+static int
+debug_to_has_registers_func (struct target_ops *ops)
+{
+  int has_regs = debug_target.to_has_registers_func (ops);
+
+  fprintf_unfiltered (gdb_stdlog, "target_has_registers_func (ops) = %d\n",
+                      has_regs);
+  return has_regs;
+}
+
 static void
 setup_target_debug (void)
 {
@@ -2747,9 +2826,14 @@
   current_target.to_find_new_threads = debug_to_find_new_threads;
   current_target.to_stop = debug_to_stop;
   current_target.to_rcmd = debug_to_rcmd;
+  current_target.to_getpkt = debug_to_getpkt;
+  current_target.to_putpkt = debug_to_putpkt;
   current_target.to_enable_exception_callback = debug_to_enable_exception_callback;
   current_target.to_get_current_exception_event = debug_to_get_current_exception_event;
   current_target.to_pid_to_exec_file = debug_to_pid_to_exec_file;
+  current_target.to_has_memory_func = debug_to_has_memory_func;
+  current_target.to_has_stack_func = debug_to_has_stack_func;
+  current_target.to_has_registers_func = debug_to_has_registers_func;
 }
 
 
diff -ruN --exclude=CVS --exclude=.svn --exclude='*~' /home/jimb/uberbaum/trace-base/gdb/target.h /home/jimb/trace/trac/tracepoints/trunk/gdb/gdb/target.h
--- /home/jimb/uberbaum/trace-base/gdb/target.h	2007-02-27 14:41:40.000000000 -0800
+++ /home/jimb/trace/trac/tracepoints/trunk/gdb/gdb/target.h	2007-03-02 11:40:13.000000000 -0800
@@ -395,6 +395,8 @@
     char *(*to_extra_thread_info) (struct thread_info *);
     void (*to_stop) (void);
     void (*to_rcmd) (char *command, struct ui_file *output);
+    void (*to_getpkt) (char **buf, long *sizeof_buf, int forever);
+    int (*to_putpkt) (char *buf);
     struct symtab_and_line *(*to_enable_exception_callback) (enum
 							     exception_event_kind,
 							     int);
@@ -403,8 +405,11 @@
     enum strata to_stratum;
     int to_has_all_memory;
     int to_has_memory;
+    int (*to_has_memory_func) (struct target_ops *);
     int to_has_stack;
+    int (*to_has_stack_func) (struct target_ops *);
     int to_has_registers;
+    int (*to_has_registers_func) (struct target_ops *);
     int to_has_execution;
     int to_has_thread_control;	/* control thread execution */
     struct section_table
@@ -934,6 +939,21 @@
 #define target_rcmd(command, outbuf) \
      (*current_target.to_rcmd) (command, outbuf)
 
+/* Read a packet from the remote machine, with error checking, and
+   store it in *BUF.  Resize *BUF using xrealloc if necessary to hold
+   the result, and update *SIZEOF_BUF.  If FOREVER, wait forever
+   rather than timing out; this is used (in synchronous mode) to wait
+   for a target that is is executing user code to stop.  */
+#define target_getpkt(buf, sizeof_buf, forever) \
+  (*current_target.to_getpkt) ((buf), (sizeof_buf), (forever))
+
+/* Send a packet to the remote machine, with error checking.  The data
+   of the packet is in BUF.  The string in BUF can be at most PBUFSIZ
+   - 5 to account for the $, # and checksum, and for a possible /0 if
+   we are debugging (remote_debug) and want to print the sent packet
+   as a string */
+#define target_putpkt(buf) \
+     (*current_target.to_putpkt) (buf)
 
 /* Get the symbol information for a breakpointable routine called when
    an exception event occurs.
@@ -960,18 +980,18 @@
 /* Does the target include memory?  (Dummy targets don't.)  */
 
 #define	target_has_memory	\
-     (current_target.to_has_memory)
+     ((*current_target.to_has_memory_func) (&current_target))
 
 /* Does the target have a stack?  (Exec files don't, VxWorks doesn't, until
    we start a process.)  */
 
 #define	target_has_stack	\
-     (current_target.to_has_stack)
+     ((*current_target.to_has_stack_func) (&current_target))
 
 /* Does the target have registers?  (Exec files don't.)  */
 
 #define	target_has_registers	\
-     (current_target.to_has_registers)
+     ((*current_target.to_has_registers_func) (&current_target))
 
 /* Does the target have execution?  Can we make it jump (through
    hoops), or pop its stack a few times?  This means that the current
diff -ruN --exclude=CVS --exclude=.svn --exclude='*~' /home/jimb/uberbaum/trace-base/gdb/tracepoint.c /home/jimb/trace/trac/tracepoints/trunk/gdb/gdb/tracepoint.c
--- /home/jimb/uberbaum/trace-base/gdb/tracepoint.c	2007-02-27 14:41:40.000000000 -0800
+++ /home/jimb/trace/trac/tracepoints/trunk/gdb/gdb/tracepoint.c	2007-03-02 13:47:22.000000000 -0800
@@ -164,7 +164,8 @@
 {
   if (current_target.to_shortname &&
       (strcmp (current_target.to_shortname, "remote") == 0
-       || strcmp (current_target.to_shortname, "extended-remote") == 0))
+       || strcmp (current_target.to_shortname, "extended-remote") == 0
+       || strcmp (current_target.to_shortname, "linux-trace") == 0))
     return 1;
   else
     return 0;
@@ -200,7 +201,7 @@
     {
       char *buf;
       QUIT;			/* allow user to bail out with ^C */
-      getpkt (buf_p, sizeof_buf, 0);
+      target_getpkt (buf_p, sizeof_buf, 0);
       buf = *buf_p;
       if (buf[0] == 0)
 	error (_("Target does not support this command."));
@@ -1203,6 +1204,7 @@
 static void
 collect_symbol (struct collection_list *collect, 
 		struct symbol *sym,
+                CORE_ADDR scope_pc,
 		long frame_regno, long frame_offset)
 {
   unsigned long len;
@@ -1310,6 +1312,13 @@
       printf_filtered ("%s has been optimized out of existence.\n",
 		       DEPRECATED_SYMBOL_NAME (sym));
       break;
+    case LOC_COMPUTED:
+    case LOC_COMPUTED_ARG:
+      {
+        struct agent_expr *aexpr = gen_trace_for_symbol (scope_pc, sym);
+        add_aexpr (collect, aexpr);
+      }
+      break;
     }
 }
 
@@ -1338,10 +1347,11 @@
 	    case LOC_STATIC:
 	    case LOC_REGISTER:
 	    case LOC_BASEREG:
+            case LOC_COMPUTED:
 	      if (type == 'L')	/* collecting Locals */
 		{
 		  count++;
-		  collect_symbol (collect, sym, frame_regno, 
+		  collect_symbol (collect, sym, pc, frame_regno, 
 				  frame_offset);
 		}
 	      break;
@@ -1351,10 +1361,11 @@
 	    case LOC_REGPARM:
 	    case LOC_REGPARM_ADDR:
 	    case LOC_BASEREG_ARG:
+            case LOC_COMPUTED_ARG:
 	      if (type == 'A')	/* collecting Arguments */
 		{
 		  count++;
-		  collect_symbol (collect, sym, frame_regno, 
+		  collect_symbol (collect, sym, pc, frame_regno, 
 				  frame_offset);
 		}
 	    }
@@ -1618,6 +1629,7 @@
 		    case OP_VAR_VALUE:
 		      collect_symbol (collect,
 				      exp->elts[2].symbol,
+                                      t->address,
 				      frame_reg,
 				      frame_offset);
 		      break;
@@ -1717,7 +1729,7 @@
   extern bfd *exec_bfd;
   asection *s;
   bfd_size_type size;
-  bfd_vma lma;
+  bfd_vma vma;
   int anysecs = 0;
 
   if (!exec_bfd)
@@ -1728,23 +1740,26 @@
     {
       char tmp1[40], tmp2[40];
 
-      if ((s->flags & SEC_LOAD) == 0 ||
-      /* (s->flags & SEC_CODE)     == 0 || */
-	  (s->flags & SEC_READONLY) == 0)
+      if ((s->flags & SEC_LOAD) == 0
+          /* || (s->flags & SEC_CODE)     == 0 */
+	  || (s->flags & SEC_READONLY) == 0
+          /* These sections are freed by the Linux kernel after startup.  */
+          || strcmp (s->name, ".init.text") == 0
+          || strcmp (s->name, ".init.data") == 0)
 	continue;
 
       anysecs = 1;
-      lma = s->lma;
+      vma = s->vma;
       size = bfd_get_section_size (s);
-      sprintf_vma (tmp1, lma);
-      sprintf_vma (tmp2, lma + size);
+      sprintf_vma (tmp1, vma);
+      sprintf_vma (tmp2, vma + size);
       sprintf (target_buf + strlen (target_buf), 
 	       ":%s,%s", tmp1, tmp2);
     }
   if (anysecs)
     {
-      putpkt (target_buf);
-      getpkt (&target_buf, &target_buf_size, 0);
+      target_putpkt (target_buf);
+      target_getpkt (&target_buf, &target_buf_size, 0);
     }
 }
 
@@ -1769,7 +1784,7 @@
 
   if (target_is_remote ())
     {
-      putpkt ("QTinit");
+      target_putpkt ("QTinit");
       remote_get_noisy_reply (&target_buf, &target_buf_size);
       if (strcmp (target_buf, "OK"))
 	error (_("Target does not support this command."));
@@ -1786,7 +1801,7 @@
 
 	if (t->actions)
 	  strcat (buf, "-");
-	putpkt (buf);
+	target_putpkt (buf);
 	remote_get_noisy_reply (&target_buf, &target_buf_size);
 	if (strcmp (target_buf, "OK"))
 	  error (_("Target does not support tracepoints."));
@@ -1810,7 +1825,7 @@
 			     tdp_actions[ndx],
 			     ((tdp_actions[ndx + 1] || stepping_actions)
 			      ? '-' : 0));
-		    putpkt (buf);
+		    target_putpkt (buf);
 		    remote_get_noisy_reply (&target_buf,
 					    &target_buf_size);
 		    if (strcmp (target_buf, "OK"))
@@ -1827,7 +1842,7 @@
 			     ((ndx == 0) ? "S" : ""),
 			     stepping_actions[ndx],
 			     (stepping_actions[ndx + 1] ? "-" : ""));
-		    putpkt (buf);
+		    target_putpkt (buf);
 		    remote_get_noisy_reply (&target_buf,
 					    &target_buf_size);
 		    if (strcmp (target_buf, "OK"))
@@ -1841,7 +1856,7 @@
       /* Tell target to treat text-like sections as transparent.  */
       remote_set_transparent_ranges ();
       /* Now insert traps and begin collecting data.  */
-      putpkt ("QTStart");
+      target_putpkt ("QTStart");
       remote_get_noisy_reply (&target_buf, &target_buf_size);
       if (strcmp (target_buf, "OK"))
 	error (_("Bogus reply from target: %s"), target_buf);
@@ -1863,7 +1878,7 @@
 {
   if (target_is_remote ())
     {
-      putpkt ("QTStop");
+      target_putpkt ("QTStop");
       remote_get_noisy_reply (&target_buf, &target_buf_size);
       if (strcmp (target_buf, "OK"))
 	error (_("Bogus reply from target: %s"), target_buf);
@@ -1883,7 +1898,7 @@
 {
   if (target_is_remote ())
     {
-      putpkt ("qTStatus");
+      target_putpkt ("qTStatus");
       remote_get_noisy_reply (&target_buf, &target_buf_size);
 
       if (target_buf[0] != 'T' ||
@@ -1904,14 +1919,21 @@
 		      int from_tty)
 {
   int target_frameno = -1, target_tracept = -1;
-  CORE_ADDR old_frame_addr;
+  CORE_ADDR old_frame_addr = 0;
   struct symbol *old_func;
   char *reply;
 
-  old_frame_addr = get_frame_base (get_current_frame ());
-  old_func = find_pc_function (read_pc ());
+  /* The linux-trace target actually changes whether it has stack or
+     not, depending on whether there's a selected trace frame.  */
+  if (target_has_stack)
+    {
+      old_frame_addr = get_frame_base (get_current_frame ());
+      old_func = find_pc_function (read_pc ());
+    }
+  else
+    old_func = NULL;
 
-  putpkt (*msg);
+  target_putpkt (*msg);
   reply = remote_get_noisy_reply (msg, sizeof_msg);
 
   while (reply && *reply)
@@ -2580,7 +2602,7 @@
      to the tracepoint PC.  If not, then the current frame was
      collected during single-stepping.  */
 
-  stepping_frame = (t->address != (read_pc () - DECR_PC_AFTER_BREAK));
+  stepping_frame = (t->address != read_pc ());
 
   for (action = t->actions; action; action = action->next)
     {
