GDB (API)
|
00001 /* Xtensa GNU/Linux native support. 00002 00003 Copyright (C) 2007-2013 Free Software Foundation, Inc. 00004 00005 This file is part of GDB. 00006 00007 This program is free software; you can redistribute it and/or modify 00008 it under the terms of the GNU General Public License as published by 00009 the Free Software Foundation; either version 3 of the License, or 00010 (at your option) any later version. 00011 00012 This program is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 GNU General Public License for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 00019 00020 #include "defs.h" 00021 #include "gdb_string.h" 00022 #include "frame.h" 00023 #include "inferior.h" 00024 #include "gdbcore.h" 00025 #include "regcache.h" 00026 #include "gdb_assert.h" 00027 #include "target.h" 00028 #include "linux-nat.h" 00029 00030 #include <stdint.h> 00031 #include <sys/types.h> 00032 #include <signal.h> 00033 #include <sys/user.h> 00034 #include <sys/ioctl.h> 00035 #include "gdb_wait.h" 00036 #include <fcntl.h> 00037 #include <sys/procfs.h> 00038 #include <sys/ptrace.h> 00039 00040 #include "gregset.h" 00041 #include "xtensa-tdep.h" 00042 00043 /* Extended register set depends on hardware configs. 00044 Keeping these definitions separately allows to introduce 00045 hardware-specific overlays. */ 00046 #include "xtensa-xtregs.c" 00047 00048 static int 00049 get_thread_id (ptid_t ptid) 00050 { 00051 int tid = ptid_get_lwp (ptid); 00052 if (0 == tid) 00053 tid = ptid_get_pid (ptid); 00054 return tid; 00055 } 00056 #define GET_THREAD_ID(PTID) get_thread_id (PTID) 00057 00058 void 00059 fill_gregset (const struct regcache *regcache, 00060 gdb_gregset_t *gregsetp, int regnum) 00061 { 00062 int i; 00063 xtensa_elf_gregset_t *regs = (xtensa_elf_gregset_t *) gregsetp; 00064 struct gdbarch *gdbarch = get_regcache_arch (regcache); 00065 00066 if (regnum == gdbarch_pc_regnum (gdbarch) || regnum == -1) 00067 regcache_raw_collect (regcache, gdbarch_pc_regnum (gdbarch), ®s->pc); 00068 if (regnum == gdbarch_ps_regnum (gdbarch) || regnum == -1) 00069 regcache_raw_collect (regcache, gdbarch_ps_regnum (gdbarch), ®s->ps); 00070 00071 if (regnum == gdbarch_tdep (gdbarch)->wb_regnum || regnum == -1) 00072 regcache_raw_collect (regcache, 00073 gdbarch_tdep (gdbarch)->wb_regnum, 00074 ®s->windowbase); 00075 if (regnum == gdbarch_tdep (gdbarch)->ws_regnum || regnum == -1) 00076 regcache_raw_collect (regcache, 00077 gdbarch_tdep (gdbarch)->ws_regnum, 00078 ®s->windowstart); 00079 if (regnum == gdbarch_tdep (gdbarch)->lbeg_regnum || regnum == -1) 00080 regcache_raw_collect (regcache, 00081 gdbarch_tdep (gdbarch)->lbeg_regnum, 00082 ®s->lbeg); 00083 if (regnum == gdbarch_tdep (gdbarch)->lend_regnum || regnum == -1) 00084 regcache_raw_collect (regcache, 00085 gdbarch_tdep (gdbarch)->lend_regnum, 00086 ®s->lend); 00087 if (regnum == gdbarch_tdep (gdbarch)->lcount_regnum || regnum == -1) 00088 regcache_raw_collect (regcache, 00089 gdbarch_tdep (gdbarch)->lcount_regnum, 00090 ®s->lcount); 00091 if (regnum == gdbarch_tdep (gdbarch)->sar_regnum || regnum == -1) 00092 regcache_raw_collect (regcache, 00093 gdbarch_tdep (gdbarch)->sar_regnum, 00094 ®s->sar); 00095 if (regnum >=gdbarch_tdep (gdbarch)->ar_base 00096 && regnum < gdbarch_tdep (gdbarch)->ar_base 00097 + gdbarch_tdep (gdbarch)->num_aregs) 00098 regcache_raw_collect (regcache,regnum, 00099 ®s->ar[regnum - gdbarch_tdep (gdbarch)->ar_base]); 00100 else if (regnum == -1) 00101 { 00102 for (i = 0; i < gdbarch_tdep (gdbarch)->num_aregs; ++i) 00103 regcache_raw_collect (regcache, 00104 gdbarch_tdep (gdbarch)->ar_base + i, 00105 ®s->ar[i]); 00106 } 00107 } 00108 00109 void 00110 supply_gregset_reg (struct regcache *regcache, 00111 const gdb_gregset_t *gregsetp, int regnum) 00112 { 00113 int i; 00114 xtensa_elf_gregset_t *regs = (xtensa_elf_gregset_t *) gregsetp; 00115 00116 struct gdbarch *gdbarch = get_regcache_arch (regcache); 00117 00118 if (regnum == gdbarch_pc_regnum (gdbarch) || regnum == -1) 00119 regcache_raw_supply (regcache, gdbarch_pc_regnum (gdbarch), ®s->pc); 00120 if (regnum == gdbarch_ps_regnum (gdbarch) || regnum == -1) 00121 regcache_raw_supply (regcache, gdbarch_ps_regnum (gdbarch), ®s->ps); 00122 00123 if (regnum == gdbarch_tdep (gdbarch)->wb_regnum || regnum == -1) 00124 regcache_raw_supply (regcache, 00125 gdbarch_tdep (gdbarch)->wb_regnum, 00126 ®s->windowbase); 00127 if (regnum == gdbarch_tdep (gdbarch)->ws_regnum || regnum == -1) 00128 regcache_raw_supply (regcache, 00129 gdbarch_tdep (gdbarch)->ws_regnum, 00130 ®s->windowstart); 00131 if (regnum == gdbarch_tdep (gdbarch)->lbeg_regnum || regnum == -1) 00132 regcache_raw_supply (regcache, 00133 gdbarch_tdep (gdbarch)->lbeg_regnum, 00134 ®s->lbeg); 00135 if (regnum == gdbarch_tdep (gdbarch)->lend_regnum || regnum == -1) 00136 regcache_raw_supply (regcache, 00137 gdbarch_tdep (gdbarch)->lend_regnum, 00138 ®s->lend); 00139 if (regnum == gdbarch_tdep (gdbarch)->lcount_regnum || regnum == -1) 00140 regcache_raw_supply (regcache, 00141 gdbarch_tdep (gdbarch)->lcount_regnum, 00142 ®s->lcount); 00143 if (regnum == gdbarch_tdep (gdbarch)->sar_regnum || regnum == -1) 00144 regcache_raw_supply (regcache, 00145 gdbarch_tdep (gdbarch)->sar_regnum, 00146 ®s->sar); 00147 if (regnum >=gdbarch_tdep (gdbarch)->ar_base 00148 && regnum < gdbarch_tdep (gdbarch)->ar_base 00149 + gdbarch_tdep (gdbarch)->num_aregs) 00150 regcache_raw_supply (regcache,regnum, 00151 ®s->ar[regnum - gdbarch_tdep (gdbarch)->ar_base]); 00152 else if (regnum == -1) 00153 { 00154 for (i = 0; i < gdbarch_tdep (gdbarch)->num_aregs; ++i) 00155 regcache_raw_supply (regcache, 00156 gdbarch_tdep (gdbarch)->ar_base + i, 00157 ®s->ar[i]); 00158 } 00159 } 00160 00161 void 00162 supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregsetp) 00163 { 00164 supply_gregset_reg (regcache, gregsetp, -1); 00165 } 00166 00167 void 00168 fill_fpregset (const struct regcache *regcache, 00169 gdb_fpregset_t *fpregsetp, int regnum) 00170 { 00171 return; 00172 } 00173 00174 void 00175 supply_fpregset (struct regcache *regcache, 00176 const gdb_fpregset_t *fpregsetp) 00177 { 00178 return; 00179 } 00180 00181 /* Fetch greg-register(s) from process/thread TID 00182 and store value(s) in GDB's register array. */ 00183 00184 static void 00185 fetch_gregs (struct regcache *regcache, int regnum) 00186 { 00187 int tid = GET_THREAD_ID (inferior_ptid); 00188 const gdb_gregset_t regs; 00189 int areg; 00190 00191 if (ptrace (PTRACE_GETREGS, tid, 0, (long) ®s) < 0) 00192 { 00193 perror_with_name (_("Couldn't get registers")); 00194 return; 00195 } 00196 00197 supply_gregset_reg (regcache, ®s, regnum); 00198 } 00199 00200 /* Store greg-register(s) in GDB's register 00201 array into the process/thread specified by TID. */ 00202 00203 static void 00204 store_gregs (struct regcache *regcache, int regnum) 00205 { 00206 int tid = GET_THREAD_ID (inferior_ptid); 00207 gdb_gregset_t regs; 00208 int areg; 00209 00210 if (ptrace (PTRACE_GETREGS, tid, 0, (long) ®s) < 0) 00211 { 00212 perror_with_name (_("Couldn't get registers")); 00213 return; 00214 } 00215 00216 fill_gregset (regcache, ®s, regnum); 00217 00218 if (ptrace (PTRACE_SETREGS, tid, 0, (long) ®s) < 0) 00219 { 00220 perror_with_name (_("Couldn't write registers")); 00221 return; 00222 } 00223 } 00224 00225 static int xtreg_lo; 00226 static int xtreg_high; 00227 00228 /* Fetch/Store Xtensa TIE registers. Xtensa GNU/Linux PTRACE 00229 interface provides special requests for this. */ 00230 00231 static void 00232 fetch_xtregs (struct regcache *regcache, int regnum) 00233 { 00234 int tid = GET_THREAD_ID (inferior_ptid); 00235 const xtensa_regtable_t *ptr; 00236 char xtregs [XTENSA_ELF_XTREG_SIZE]; 00237 00238 if (ptrace (PTRACE_GETXTREGS, tid, 0, (long)&xtregs) < 0) 00239 perror_with_name (_("Couldn't get extended registers")); 00240 00241 for (ptr = xtensa_regmap_table; ptr->name; ptr++) 00242 if (regnum == ptr->gdb_regnum || regnum == -1) 00243 regcache_raw_supply (regcache, ptr->gdb_regnum, 00244 xtregs + ptr->ptrace_offset); 00245 } 00246 00247 static void 00248 store_xtregs (struct regcache *regcache, int regnum) 00249 { 00250 int tid = GET_THREAD_ID (inferior_ptid); 00251 const xtensa_regtable_t *ptr; 00252 char xtregs [XTENSA_ELF_XTREG_SIZE]; 00253 00254 if (ptrace (PTRACE_GETXTREGS, tid, 0, (long)&xtregs) < 0) 00255 perror_with_name (_("Couldn't get extended registers")); 00256 00257 for (ptr = xtensa_regmap_table; ptr->name; ptr++) 00258 if (regnum == ptr->gdb_regnum || regnum == -1) 00259 regcache_raw_collect (regcache, ptr->gdb_regnum, 00260 xtregs + ptr->ptrace_offset); 00261 00262 if (ptrace (PTRACE_SETXTREGS, tid, 0, (long)&xtregs) < 0) 00263 perror_with_name (_("Couldn't write extended registers")); 00264 } 00265 00266 void 00267 xtensa_linux_fetch_inferior_registers (struct target_ops *ops, 00268 struct regcache *regcache, int regnum) 00269 { 00270 if (regnum == -1) 00271 { 00272 fetch_gregs (regcache, regnum); 00273 fetch_xtregs (regcache, regnum); 00274 } 00275 else if ((regnum < xtreg_lo) || (regnum > xtreg_high)) 00276 fetch_gregs (regcache, regnum); 00277 else 00278 fetch_xtregs (regcache, regnum); 00279 } 00280 00281 void 00282 xtensa_linux_store_inferior_registers (struct target_ops *ops, 00283 struct regcache *regcache, int regnum) 00284 { 00285 if (regnum == -1) 00286 { 00287 store_gregs (regcache, regnum); 00288 store_xtregs (regcache, regnum); 00289 } 00290 else if ((regnum < xtreg_lo) || (regnum > xtreg_high)) 00291 store_gregs (regcache, regnum); 00292 else 00293 store_xtregs (regcache, regnum); 00294 } 00295 00296 void _initialize_xtensa_linux_nat (void); 00297 00298 void 00299 _initialize_xtensa_linux_nat (void) 00300 { 00301 struct target_ops *t; 00302 const xtensa_regtable_t *ptr; 00303 00304 /* Calculate the number range for extended registers. */ 00305 xtreg_lo = 1000000000; 00306 xtreg_high = -1; 00307 for (ptr = xtensa_regmap_table; ptr->name; ptr++) 00308 { 00309 if (ptr->gdb_regnum < xtreg_lo) 00310 xtreg_lo = ptr->gdb_regnum; 00311 if (ptr->gdb_regnum > xtreg_high) 00312 xtreg_high = ptr->gdb_regnum; 00313 } 00314 00315 /* Fill in the generic GNU/Linux methods. */ 00316 t = linux_target (); 00317 00318 /* Add our register access methods. */ 00319 t->to_fetch_registers = xtensa_linux_fetch_inferior_registers; 00320 t->to_store_registers = xtensa_linux_store_inferior_registers; 00321 00322 linux_nat_add_target (t); 00323 }