GDBserver
/home/stan/gdb/src/gdb/gdbserver/linux-i386-ipa.c
Go to the documentation of this file.
00001 /* GNU/Linux/x86 specific low level interface, for the in-process
00002    agent library for GDB.
00003 
00004    Copyright (C) 2010-2013 Free Software Foundation, Inc.
00005 
00006    This file is part of GDB.
00007 
00008    This program is free software; you can redistribute it and/or modify
00009    it under the terms of the GNU General Public License as published by
00010    the Free Software Foundation; either version 3 of the License, or
00011    (at your option) any later version.
00012 
00013    This program is distributed in the hope that it will be useful,
00014    but WITHOUT ANY WARRANTY; without even the implied warranty of
00015    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016    GNU General Public License for more details.
00017 
00018    You should have received a copy of the GNU General Public License
00019    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
00020 
00021 #include "server.h"
00022 #include <stdint.h>
00023 #include <sys/mman.h>
00024 #include "tracepoint.h"
00025 
00026 /* GDB register numbers.  */
00027 
00028 enum i386_gdb_regnum
00029 {
00030   I386_EAX_REGNUM,              /* %eax */
00031   I386_ECX_REGNUM,              /* %ecx */
00032   I386_EDX_REGNUM,              /* %edx */
00033   I386_EBX_REGNUM,              /* %ebx */
00034   I386_ESP_REGNUM,              /* %esp */
00035   I386_EBP_REGNUM,              /* %ebp */
00036   I386_ESI_REGNUM,              /* %esi */
00037   I386_EDI_REGNUM,              /* %edi */
00038   I386_EIP_REGNUM,              /* %eip */
00039   I386_EFLAGS_REGNUM,           /* %eflags */
00040   I386_CS_REGNUM,               /* %cs */
00041   I386_SS_REGNUM,               /* %ss */
00042   I386_DS_REGNUM,               /* %ds */
00043   I386_ES_REGNUM,               /* %es */
00044   I386_FS_REGNUM,               /* %fs */
00045   I386_GS_REGNUM,               /* %gs */
00046   I386_ST0_REGNUM               /* %st(0) */
00047 };
00048 
00049 #define i386_num_regs 16
00050 
00051 /* Defined in auto-generated file i386-linux.c.  */
00052 void init_registers_i386_linux (void);
00053 extern const struct target_desc *tdesc_i386_linux;
00054 
00055 #define FT_CR_EAX 15
00056 #define FT_CR_ECX 14
00057 #define FT_CR_EDX 13
00058 #define FT_CR_EBX 12
00059 #define FT_CR_UESP 11
00060 #define FT_CR_EBP 10
00061 #define FT_CR_ESI 9
00062 #define FT_CR_EDI 8
00063 #define FT_CR_EIP 7
00064 #define FT_CR_EFL 6
00065 #define FT_CR_DS 5
00066 #define FT_CR_ES 4
00067 #define FT_CR_FS 3
00068 #define FT_CR_GS 2
00069 #define FT_CR_SS 1
00070 #define FT_CR_CS 0
00071 
00072 /* Mapping between the general-purpose registers in jump tracepoint
00073    format and GDB's register array layout.  */
00074 
00075 static const int i386_ft_collect_regmap[] =
00076 {
00077   FT_CR_EAX * 4, FT_CR_ECX * 4, FT_CR_EDX * 4, FT_CR_EBX * 4,
00078   FT_CR_UESP * 4, FT_CR_EBP * 4, FT_CR_ESI * 4, FT_CR_EDI * 4,
00079   FT_CR_EIP * 4, FT_CR_EFL * 4, FT_CR_CS * 4, FT_CR_SS * 4,
00080   FT_CR_DS * 4, FT_CR_ES * 4, FT_CR_FS * 4, FT_CR_GS * 4
00081 };
00082 
00083 void
00084 supply_fast_tracepoint_registers (struct regcache *regcache,
00085                                   const unsigned char *buf)
00086 {
00087   int i;
00088 
00089   for (i = 0; i < i386_num_regs; i++)
00090     {
00091       int regval;
00092 
00093       if (i >= I386_CS_REGNUM && i <= I386_GS_REGNUM)
00094         regval = *(short *) (((char *) buf) + i386_ft_collect_regmap[i]);
00095       else
00096         regval = *(int *) (((char *) buf) + i386_ft_collect_regmap[i]);
00097 
00098       supply_register (regcache, i, &regval);
00099     }
00100 }
00101 
00102 ULONGEST __attribute__ ((visibility("default"), used))
00103 gdb_agent_get_raw_reg (unsigned char *raw_regs, int regnum)
00104 {
00105   /* This should maybe be allowed to return an error code, or perhaps
00106      better, have the emit_reg detect this, and emit a constant zero,
00107      or something.  */
00108 
00109   if (regnum > i386_num_regs)
00110     return 0;
00111   else if (regnum >= I386_CS_REGNUM && regnum <= I386_GS_REGNUM)
00112     return *(short *) (raw_regs + i386_ft_collect_regmap[regnum]);
00113   else
00114     return *(int *) (raw_regs + i386_ft_collect_regmap[regnum]);
00115 }
00116 
00117 #ifdef HAVE_UST
00118 
00119 #include <ust/processor.h>
00120 
00121 /* "struct registers" is the UST object type holding the registers at
00122    the time of the static tracepoint marker call.  This doesn't
00123    contain EIP, but we know what it must have been (the marker
00124    address).  */
00125 
00126 #define ST_REGENTRY(REG)                        \
00127   {                                             \
00128     offsetof (struct registers, REG),           \
00129     sizeof (((struct registers *) NULL)->REG)   \
00130   }
00131 
00132 static struct
00133 {
00134   int offset;
00135   int size;
00136 } i386_st_collect_regmap[] =
00137   {
00138     ST_REGENTRY(eax),
00139     ST_REGENTRY(ecx),
00140     ST_REGENTRY(edx),
00141     ST_REGENTRY(ebx),
00142     ST_REGENTRY(esp),
00143     ST_REGENTRY(ebp),
00144     ST_REGENTRY(esi),
00145     ST_REGENTRY(edi),
00146     { -1, 0 }, /* eip */
00147     ST_REGENTRY(eflags),
00148     ST_REGENTRY(cs),
00149     ST_REGENTRY(ss),
00150   };
00151 
00152 #define i386_NUM_ST_COLLECT_GREGS \
00153   (sizeof (i386_st_collect_regmap) / sizeof (i386_st_collect_regmap[0]))
00154 
00155 void
00156 supply_static_tracepoint_registers (struct regcache *regcache,
00157                                     const unsigned char *buf,
00158                                     CORE_ADDR pc)
00159 {
00160   int i;
00161   unsigned int newpc = pc;
00162 
00163   supply_register (regcache, I386_EIP_REGNUM, &newpc);
00164 
00165   for (i = 0; i < i386_NUM_ST_COLLECT_GREGS; i++)
00166     if (i386_st_collect_regmap[i].offset != -1)
00167       {
00168         switch (i386_st_collect_regmap[i].size)
00169           {
00170           case 4:
00171             supply_register (regcache, i,
00172                              ((char *) buf)
00173                              + i386_st_collect_regmap[i].offset);
00174             break;
00175           case 2:
00176             {
00177               unsigned long reg
00178                 = * (short *) (((char *) buf)
00179                                + i386_st_collect_regmap[i].offset);
00180               reg &= 0xffff;
00181               supply_register (regcache, i, &reg);
00182             }
00183             break;
00184           default:
00185             internal_error (__FILE__, __LINE__, "unhandled register size: %d",
00186                             i386_st_collect_regmap[i].size);
00187           }
00188       }
00189 }
00190 
00191 #endif /* HAVE_UST */
00192 
00193 
00194 /* This is only needed because reg-i386-linux-lib.o references it.  We
00195    may use it proper at some point.  */
00196 const char *gdbserver_xmltarget;
00197 
00198 /* Attempt to allocate memory for trampolines in the first 64 KiB of
00199    memory to enable smaller jump patches.  */
00200 
00201 static void
00202 initialize_fast_tracepoint_trampoline_buffer (void)
00203 {
00204   const CORE_ADDR buffer_end = 64 * 1024;
00205   /* Ensure that the buffer will be at least 1 KiB in size, which is
00206      enough space for over 200 fast tracepoints.  */
00207   const int min_buffer_size = 1024;
00208   char buf[IPA_BUFSIZ];
00209   CORE_ADDR mmap_min_addr = buffer_end + 1;
00210   ULONGEST buffer_size;
00211   FILE *f = fopen ("/proc/sys/vm/mmap_min_addr", "r");
00212 
00213   if (!f)
00214     {    
00215       snprintf (buf, sizeof (buf), "mmap_min_addr open failed: %s",
00216                 strerror (errno));
00217       set_trampoline_buffer_space (0, 0, buf);
00218       return;
00219     }
00220 
00221   if (fgets (buf, IPA_BUFSIZ, f))
00222     sscanf (buf, "%llu", &mmap_min_addr);
00223       
00224   fclose (f);
00225       
00226   buffer_size = buffer_end - mmap_min_addr;
00227 
00228   if (buffer_size >= min_buffer_size)
00229     {
00230       if (mmap ((void *) (uintptr_t) mmap_min_addr, buffer_size,
00231                 PROT_READ | PROT_EXEC | PROT_WRITE,
00232                 MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
00233                 -1, 0)
00234           != MAP_FAILED)
00235         set_trampoline_buffer_space (mmap_min_addr, buffer_end, NULL);
00236       else
00237         {
00238           snprintf (buf, IPA_BUFSIZ, "low-64K-buffer mmap() failed: %s",
00239                     strerror (errno));
00240           set_trampoline_buffer_space (0, 0, buf);
00241         }
00242     }
00243   else
00244     {
00245       snprintf (buf, IPA_BUFSIZ, "mmap_min_addr is %d, must be %d or less",
00246                 (int) mmap_min_addr, (int) buffer_end - min_buffer_size);
00247       set_trampoline_buffer_space (0, 0, buf);
00248     }
00249 }
00250 
00251 void
00252 initialize_low_tracepoint (void)
00253 {
00254   init_registers_i386_linux ();
00255   ipa_tdesc = tdesc_i386_linux;
00256   initialize_fast_tracepoint_trampoline_buffer ();
00257 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Defines