[gdbserver] Fix IPA build.
[deliverable/binutils-gdb.git] / gdb / gdbserver / linux-i386-ipa.c
index 69f67495a7e5e129f428e54f07cc107e51ba0c16..68d65ac92a4439b9d7267b36bb686a2271a7b92b 100644 (file)
@@ -1,7 +1,7 @@
 /* GNU/Linux/x86 specific low level interface, for the in-process
    agent library for GDB.
 
-   Copyright (C) 2010 Free Software Foundation, Inc.
+   Copyright (C) 2010-2013 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -19,6 +19,9 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "server.h"
+#include <stdint.h>
+#include <sys/mman.h>
+#include "tracepoint.h"
 
 /* GDB register numbers.  */
 
@@ -47,6 +50,7 @@ enum i386_gdb_regnum
 
 /* Defined in auto-generated file i386-linux.c.  */
 void init_registers_i386_linux (void);
+extern const struct target_desc *tdesc_i386_linux;
 
 #define FT_CR_EAX 15
 #define FT_CR_ECX 14
@@ -95,12 +99,159 @@ supply_fast_tracepoint_registers (struct regcache *regcache,
     }
 }
 
+ULONGEST __attribute__ ((visibility("default"), used))
+gdb_agent_get_raw_reg (unsigned char *raw_regs, int regnum)
+{
+  /* This should maybe be allowed to return an error code, or perhaps
+     better, have the emit_reg detect this, and emit a constant zero,
+     or something.  */
+
+  if (regnum > i386_num_regs)
+    return 0;
+  else if (regnum >= I386_CS_REGNUM && regnum <= I386_GS_REGNUM)
+    return *(short *) (raw_regs + i386_ft_collect_regmap[regnum]);
+  else
+    return *(int *) (raw_regs + i386_ft_collect_regmap[regnum]);
+}
+
+#ifdef HAVE_UST
+
+#include <ust/processor.h>
+
+/* "struct registers" is the UST object type holding the registers at
+   the time of the static tracepoint marker call.  This doesn't
+   contain EIP, but we know what it must have been (the marker
+   address).  */
+
+#define ST_REGENTRY(REG)                       \
+  {                                            \
+    offsetof (struct registers, REG),          \
+    sizeof (((struct registers *) NULL)->REG)  \
+  }
+
+static struct
+{
+  int offset;
+  int size;
+} i386_st_collect_regmap[] =
+  {
+    ST_REGENTRY(eax),
+    ST_REGENTRY(ecx),
+    ST_REGENTRY(edx),
+    ST_REGENTRY(ebx),
+    ST_REGENTRY(esp),
+    ST_REGENTRY(ebp),
+    ST_REGENTRY(esi),
+    ST_REGENTRY(edi),
+    { -1, 0 }, /* eip */
+    ST_REGENTRY(eflags),
+    ST_REGENTRY(cs),
+    ST_REGENTRY(ss),
+  };
+
+#define i386_NUM_ST_COLLECT_GREGS \
+  (sizeof (i386_st_collect_regmap) / sizeof (i386_st_collect_regmap[0]))
+
+void
+supply_static_tracepoint_registers (struct regcache *regcache,
+                                   const unsigned char *buf,
+                                   CORE_ADDR pc)
+{
+  int i;
+  unsigned int newpc = pc;
+
+  supply_register (regcache, I386_EIP_REGNUM, &newpc);
+
+  for (i = 0; i < i386_NUM_ST_COLLECT_GREGS; i++)
+    if (i386_st_collect_regmap[i].offset != -1)
+      {
+       switch (i386_st_collect_regmap[i].size)
+         {
+         case 4:
+           supply_register (regcache, i,
+                            ((char *) buf)
+                            + i386_st_collect_regmap[i].offset);
+           break;
+         case 2:
+           {
+             unsigned long reg
+               = * (short *) (((char *) buf)
+                              + i386_st_collect_regmap[i].offset);
+             reg &= 0xffff;
+             supply_register (regcache, i, &reg);
+           }
+           break;
+         default:
+           internal_error (__FILE__, __LINE__, "unhandled register size: %d",
+                           i386_st_collect_regmap[i].size);
+         }
+      }
+}
+
+#endif /* HAVE_UST */
+
+
 /* This is only needed because reg-i386-linux-lib.o references it.  We
    may use it proper at some point.  */
 const char *gdbserver_xmltarget;
 
+/* Attempt to allocate memory for trampolines in the first 64 KiB of
+   memory to enable smaller jump patches.  */
+
+static void
+initialize_fast_tracepoint_trampoline_buffer (void)
+{
+  const CORE_ADDR buffer_end = 64 * 1024;
+  /* Ensure that the buffer will be at least 1 KiB in size, which is
+     enough space for over 200 fast tracepoints.  */
+  const int min_buffer_size = 1024;
+  char buf[IPA_BUFSIZ];
+  CORE_ADDR mmap_min_addr = buffer_end + 1;
+  ULONGEST buffer_size;
+  FILE *f = fopen ("/proc/sys/vm/mmap_min_addr", "r");
+
+  if (!f)
+    {    
+      snprintf (buf, sizeof (buf), "mmap_min_addr open failed: %s",
+               strerror (errno));
+      set_trampoline_buffer_space (0, 0, buf);
+      return;
+    }
+
+  if (fgets (buf, IPA_BUFSIZ, f))
+    sscanf (buf, "%llu", &mmap_min_addr);
+      
+  fclose (f);
+      
+  buffer_size = buffer_end - mmap_min_addr;
+
+  if (buffer_size >= min_buffer_size)
+    {
+      if (mmap ((void *) (uintptr_t) mmap_min_addr, buffer_size,
+               PROT_READ | PROT_EXEC | PROT_WRITE,
+               MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
+               -1, 0)
+         != MAP_FAILED)
+       set_trampoline_buffer_space (mmap_min_addr, buffer_end, NULL);
+      else
+       {
+         snprintf (buf, IPA_BUFSIZ, "low-64K-buffer mmap() failed: %s",
+                   strerror (errno));
+         set_trampoline_buffer_space (0, 0, buf);
+       }
+    }
+  else
+    {
+      snprintf (buf, IPA_BUFSIZ, "mmap_min_addr is %d, must be %d or less",
+               (int) mmap_min_addr, (int) buffer_end - min_buffer_size);
+      set_trampoline_buffer_space (0, 0, buf);
+    }
+}
+
 void
 initialize_low_tracepoint (void)
 {
   init_registers_i386_linux ();
+  ipa_tdesc = tdesc_i386_linux;
+  initialize_fast_tracepoint_trampoline_buffer ();
 }
This page took 0.029005 seconds and 4 git commands to generate.