GDBserver
/home/stan/gdb/src/gdb/gdbserver/linux-xtensa-low.c
Go to the documentation of this file.
00001 /* GNU/Linux/Xtensa specific low level interface, for the remote server for GDB.
00002    Copyright (C) 2007-2013 Free Software Foundation, Inc.
00003 
00004    This file is part of GDB.
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 3 of the License, or
00009    (at your option) any later version.
00010 
00011    This program is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014    GNU General Public License for more details.
00015 
00016    You should have received a copy of the GNU General Public License
00017    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
00018 
00019 
00020 #include "server.h"
00021 #include "linux-low.h"
00022 
00023 /* Defined in auto-generated file reg-xtensa.c.  */
00024 void init_registers_xtensa (void);
00025 extern const struct target_desc *tdesc_xtensa;
00026 
00027 #include <sys/ptrace.h>
00028 #include <xtensa-config.h>
00029 
00030 #include "xtensa-xtregs.c"
00031 
00032 enum regnum {
00033         R_PC=0, R_PS,
00034         R_LBEG, R_LEND, R_LCOUNT,
00035         R_SAR,
00036         R_WS, R_WB,
00037         R_A0 = 64
00038 };
00039 
00040 static void
00041 xtensa_fill_gregset (struct regcache *regcache, void *buf)
00042 {
00043   elf_greg_t* rset = (elf_greg_t*)buf;
00044   const struct target_desc *tdesc = regcache->tdesc;
00045   int ar0_regnum;
00046   char *ptr;
00047   int i;
00048 
00049   /* Take care of AR registers.  */
00050 
00051   ar0_regnum = find_regno (tdesc, "ar0");
00052   ptr = (char*)&rset[R_A0];
00053 
00054   for (i = ar0_regnum; i < ar0_regnum + XCHAL_NUM_AREGS; i++)
00055     {
00056       collect_register (regcache, i, ptr);
00057       ptr += register_size (tdesc, i);
00058     }
00059 
00060   /* Loop registers, if hardware has it.  */
00061 
00062 #if XCHAL_HAVE_LOOP
00063   collect_register_by_name (regcache, "lbeg", (char*)&rset[R_LBEG]);
00064   collect_register_by_name (regcache, "lend", (char*)&rset[R_LEND]);
00065   collect_register_by_name (regcache, "lcount", (char*)&rset[R_LCOUNT]);
00066 #endif
00067 
00068   collect_register_by_name (regcache, "sar", (char*)&rset[R_SAR]);
00069   collect_register_by_name (regcache, "pc", (char*)&rset[R_PC]);
00070   collect_register_by_name (regcache, "ps", (char*)&rset[R_PS]);
00071   collect_register_by_name (regcache, "windowbase", (char*)&rset[R_WB]);
00072   collect_register_by_name (regcache, "windowstart", (char*)&rset[R_WS]);
00073 }
00074 
00075 static void
00076 xtensa_store_gregset (struct regcache *regcache, const void *buf)
00077 {
00078   const elf_greg_t* rset = (const elf_greg_t*)buf;
00079   const struct target_desc *tdesc = regcache->tdesc;
00080   int ar0_regnum;
00081   char *ptr;
00082   int i;
00083 
00084   /* Take care of AR registers.  */
00085 
00086   ar0_regnum = find_regno (tdesc, "ar0");
00087   ptr = (char *)&rset[R_A0];
00088 
00089   for (i = ar0_regnum; i < ar0_regnum + XCHAL_NUM_AREGS; i++)
00090     {
00091       supply_register (regcache, i, ptr);
00092       ptr += register_size (tdesc, i);
00093     }
00094 
00095   /* Loop registers, if hardware has it.  */
00096 
00097 #if XCHAL_HAVE_LOOP
00098   supply_register_by_name (regcache, "lbeg", (char*)&rset[R_LBEG]);
00099   supply_register_by_name (regcache, "lend", (char*)&rset[R_LEND]);
00100   supply_register_by_name (regcache, "lcount", (char*)&rset[R_LCOUNT]);
00101 #endif
00102 
00103   supply_register_by_name (regcache, "sar", (char*)&rset[R_SAR]);
00104   supply_register_by_name (regcache, "pc", (char*)&rset[R_PC]);
00105   supply_register_by_name (regcache, "ps", (char*)&rset[R_PS]);
00106   supply_register_by_name (regcache, "windowbase", (char*)&rset[R_WB]);
00107   supply_register_by_name (regcache, "windowstart", (char*)&rset[R_WS]);
00108 }
00109 
00110 /* Xtensa GNU/Linux PTRACE interface includes extended register set.  */
00111 
00112 static void
00113 xtensa_fill_xtregset (struct regcache *regcache, void *buf)
00114 {
00115   const xtensa_regtable_t *ptr;
00116 
00117   for (ptr = xtensa_regmap_table; ptr->name; ptr++)
00118     {
00119       collect_register_by_name (regcache, ptr->name,
00120                                 (char*)buf + ptr->ptrace_offset);
00121     }
00122 }
00123 
00124 static void
00125 xtensa_store_xtregset (struct regcache *regcache, const void *buf)
00126 {
00127   const xtensa_regtable_t *ptr;
00128 
00129   for (ptr = xtensa_regmap_table; ptr->name; ptr++)
00130     {
00131       supply_register_by_name (regcache, ptr->name,
00132                                 (char*)buf + ptr->ptrace_offset);
00133     }
00134 }
00135 
00136 static struct regset_info xtensa_regsets[] = {
00137   { PTRACE_GETREGS, PTRACE_SETREGS, 0, sizeof (elf_gregset_t),
00138     GENERAL_REGS,
00139     xtensa_fill_gregset, xtensa_store_gregset },
00140   { PTRACE_GETXTREGS, PTRACE_SETXTREGS, 0, XTENSA_ELF_XTREG_SIZE,
00141     EXTENDED_REGS,
00142     xtensa_fill_xtregset, xtensa_store_xtregset },
00143   { 0, 0, 0, -1, -1, NULL, NULL }
00144 };
00145 
00146 #if XCHAL_HAVE_BE
00147 #define XTENSA_BREAKPOINT {0xd2,0x0f}
00148 #else
00149 #define XTENSA_BREAKPOINT {0x2d,0xf0}
00150 #endif
00151 
00152 static const unsigned char xtensa_breakpoint[] = XTENSA_BREAKPOINT;
00153 #define xtensa_breakpoint_len 2
00154 
00155 static CORE_ADDR
00156 xtensa_get_pc (struct regcache *regcache)
00157 {
00158   unsigned long pc;
00159 
00160   collect_register_by_name (regcache, "pc", &pc);
00161   return pc;
00162 }
00163 
00164 static void
00165 xtensa_set_pc (struct regcache *regcache, CORE_ADDR pc)
00166 {
00167   unsigned long newpc = pc;
00168   supply_register_by_name (regcache, "pc", &newpc);
00169 }
00170 
00171 static int
00172 xtensa_breakpoint_at (CORE_ADDR where)
00173 {
00174     unsigned long insn;
00175 
00176     (*the_target->read_memory) (where, (unsigned char *) &insn,
00177                                 xtensa_breakpoint_len);
00178     return memcmp((char *) &insn,
00179                   xtensa_breakpoint, xtensa_breakpoint_len) == 0;
00180 }
00181 
00182 static struct regsets_info xtensa_regsets_info =
00183   {
00184     xtensa_regsets, /* regsets */
00185     0, /* num_regsets */
00186     NULL, /* disabled_regsets */
00187   };
00188 
00189 static struct usrregs_info xtensa_usrregs_info =
00190   {
00191     xtensa_num_regs,
00192     xtensa_regmap,
00193   };
00194 
00195 static struct regs_info regs_info =
00196   {
00197     NULL, /* regset_bitmap */
00198     &xtensa_usrregs_info,
00199     &xtensa_regsets_info
00200   };
00201 
00202 static void
00203 xtensa_arch_setup (void)
00204 {
00205   current_process ()->tdesc = tdesc_xtensa;
00206 }
00207 
00208 static const struct regs_info *
00209 xtensa_regs_info (void)
00210 {
00211   return &regs_info;
00212 }
00213 
00214 struct linux_target_ops the_low_target = {
00215   xtensa_arch_setup,
00216   xtensa_regs_info,
00217   0,
00218   0,
00219   NULL, /* fetch_register */
00220   xtensa_get_pc,
00221   xtensa_set_pc,
00222   xtensa_breakpoint,
00223   xtensa_breakpoint_len,
00224   NULL,
00225   0,
00226   xtensa_breakpoint_at,
00227 };
00228 
00229 
00230 void
00231 initialize_low_arch (void)
00232 {
00233   /* Initialize the Linux target descriptions.  */
00234   init_registers_xtensa ();
00235 
00236   initialize_regsets_info (&xtensa_regsets_info);
00237 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Defines