GDB (API)
|
00001 /* Target-dependent code for FreeBSD/i386. 00002 00003 Copyright (C) 2003-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 "arch-utils.h" 00022 #include "gdbcore.h" 00023 #include "osabi.h" 00024 #include "regcache.h" 00025 00026 #include "gdb_assert.h" 00027 00028 #include "i386-tdep.h" 00029 #include "i387-tdep.h" 00030 #include "bsd-uthread.h" 00031 #include "solib-svr4.h" 00032 00033 /* FreeBSD 3.0-RELEASE or later. */ 00034 00035 /* From <machine/reg.h>. */ 00036 static int i386fbsd_r_reg_offset[] = 00037 { 00038 9 * 4, 8 * 4, 7 * 4, 6 * 4, /* %eax, %ecx, %edx, %ebx */ 00039 15 * 4, 4 * 4, /* %esp, %ebp */ 00040 3 * 4, 2 * 4, /* %esi, %edi */ 00041 12 * 4, 14 * 4, /* %eip, %eflags */ 00042 13 * 4, 16 * 4, /* %cs, %ss */ 00043 1 * 4, 0 * 4, -1, -1 /* %ds, %es, %fs, %gs */ 00044 }; 00045 00046 /* Sigtramp routine location. */ 00047 CORE_ADDR i386fbsd_sigtramp_start_addr = 0xbfbfdf20; 00048 CORE_ADDR i386fbsd_sigtramp_end_addr = 0xbfbfdff0; 00049 00050 /* From <machine/signal.h>. */ 00051 int i386fbsd_sc_reg_offset[] = 00052 { 00053 8 + 14 * 4, /* %eax */ 00054 8 + 13 * 4, /* %ecx */ 00055 8 + 12 * 4, /* %edx */ 00056 8 + 11 * 4, /* %ebx */ 00057 8 + 0 * 4, /* %esp */ 00058 8 + 1 * 4, /* %ebp */ 00059 8 + 10 * 4, /* %esi */ 00060 8 + 9 * 4, /* %edi */ 00061 8 + 3 * 4, /* %eip */ 00062 8 + 4 * 4, /* %eflags */ 00063 8 + 7 * 4, /* %cs */ 00064 8 + 8 * 4, /* %ss */ 00065 8 + 6 * 4, /* %ds */ 00066 8 + 5 * 4, /* %es */ 00067 8 + 15 * 4, /* %fs */ 00068 8 + 16 * 4 /* %gs */ 00069 }; 00070 00071 /* From /usr/src/lib/libc/i386/gen/_setjmp.S. */ 00072 static int i386fbsd_jmp_buf_reg_offset[] = 00073 { 00074 -1, /* %eax */ 00075 -1, /* %ecx */ 00076 -1, /* %edx */ 00077 1 * 4, /* %ebx */ 00078 2 * 4, /* %esp */ 00079 3 * 4, /* %ebp */ 00080 4 * 4, /* %esi */ 00081 5 * 4, /* %edi */ 00082 0 * 4 /* %eip */ 00083 }; 00084 00085 static void 00086 i386fbsd_supply_uthread (struct regcache *regcache, 00087 int regnum, CORE_ADDR addr) 00088 { 00089 gdb_byte buf[4]; 00090 int i; 00091 00092 gdb_assert (regnum >= -1); 00093 00094 for (i = 0; i < ARRAY_SIZE (i386fbsd_jmp_buf_reg_offset); i++) 00095 { 00096 if (i386fbsd_jmp_buf_reg_offset[i] != -1 00097 && (regnum == -1 || regnum == i)) 00098 { 00099 read_memory (addr + i386fbsd_jmp_buf_reg_offset[i], buf, 4); 00100 regcache_raw_supply (regcache, i, buf); 00101 } 00102 } 00103 } 00104 00105 static void 00106 i386fbsd_collect_uthread (const struct regcache *regcache, 00107 int regnum, CORE_ADDR addr) 00108 { 00109 gdb_byte buf[4]; 00110 int i; 00111 00112 gdb_assert (regnum >= -1); 00113 00114 for (i = 0; i < ARRAY_SIZE (i386fbsd_jmp_buf_reg_offset); i++) 00115 { 00116 if (i386fbsd_jmp_buf_reg_offset[i] != -1 00117 && (regnum == -1 || regnum == i)) 00118 { 00119 regcache_raw_collect (regcache, i, buf); 00120 write_memory (addr + i386fbsd_jmp_buf_reg_offset[i], buf, 4); 00121 } 00122 } 00123 } 00124 00125 static void 00126 i386fbsdaout_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) 00127 { 00128 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); 00129 00130 /* Obviously FreeBSD is BSD-based. */ 00131 i386bsd_init_abi (info, gdbarch); 00132 00133 /* FreeBSD has a different `struct reg', and reserves some space for 00134 its FPU emulator in `struct fpreg'. */ 00135 tdep->gregset_reg_offset = i386fbsd_r_reg_offset; 00136 tdep->gregset_num_regs = ARRAY_SIZE (i386fbsd_r_reg_offset); 00137 tdep->sizeof_gregset = 18 * 4; 00138 tdep->sizeof_fpregset = 176; 00139 00140 /* FreeBSD uses -freg-struct-return by default. */ 00141 tdep->struct_return = reg_struct_return; 00142 00143 /* FreeBSD uses a different memory layout. */ 00144 tdep->sigtramp_start = i386fbsd_sigtramp_start_addr; 00145 tdep->sigtramp_end = i386fbsd_sigtramp_end_addr; 00146 00147 /* FreeBSD has a more complete `struct sigcontext'. */ 00148 tdep->sc_reg_offset = i386fbsd_sc_reg_offset; 00149 tdep->sc_num_regs = ARRAY_SIZE (i386fbsd_sc_reg_offset); 00150 00151 /* FreeBSD provides a user-level threads implementation. */ 00152 bsd_uthread_set_supply_uthread (gdbarch, i386fbsd_supply_uthread); 00153 bsd_uthread_set_collect_uthread (gdbarch, i386fbsd_collect_uthread); 00154 } 00155 00156 static void 00157 i386fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) 00158 { 00159 /* It's almost identical to FreeBSD a.out. */ 00160 i386fbsdaout_init_abi (info, gdbarch); 00161 00162 /* Except that it uses ELF. */ 00163 i386_elf_init_abi (info, gdbarch); 00164 00165 /* FreeBSD ELF uses SVR4-style shared libraries. */ 00166 set_solib_svr4_fetch_link_map_offsets 00167 (gdbarch, svr4_ilp32_fetch_link_map_offsets); 00168 } 00169 00170 /* FreeBSD 4.0-RELEASE or later. */ 00171 00172 /* From <machine/reg.h>. */ 00173 static int i386fbsd4_r_reg_offset[] = 00174 { 00175 10 * 4, 9 * 4, 8 * 4, 7 * 4, /* %eax, %ecx, %edx, %ebx */ 00176 16 * 4, 5 * 4, /* %esp, %ebp */ 00177 4 * 4, 3 * 4, /* %esi, %edi */ 00178 13 * 4, 15 * 4, /* %eip, %eflags */ 00179 14 * 4, 17 * 4, /* %cs, %ss */ 00180 2 * 4, 1 * 4, 0 * 4, 18 * 4 /* %ds, %es, %fs, %gs */ 00181 }; 00182 00183 /* From <machine/signal.h>. */ 00184 int i386fbsd4_sc_reg_offset[] = 00185 { 00186 20 + 11 * 4, /* %eax */ 00187 20 + 10 * 4, /* %ecx */ 00188 20 + 9 * 4, /* %edx */ 00189 20 + 8 * 4, /* %ebx */ 00190 20 + 17 * 4, /* %esp */ 00191 20 + 6 * 4, /* %ebp */ 00192 20 + 5 * 4, /* %esi */ 00193 20 + 4 * 4, /* %edi */ 00194 20 + 14 * 4, /* %eip */ 00195 20 + 16 * 4, /* %eflags */ 00196 20 + 15 * 4, /* %cs */ 00197 20 + 18 * 4, /* %ss */ 00198 20 + 3 * 4, /* %ds */ 00199 20 + 2 * 4, /* %es */ 00200 20 + 1 * 4, /* %fs */ 00201 20 + 0 * 4 /* %gs */ 00202 }; 00203 00204 static void 00205 i386fbsd4_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) 00206 { 00207 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); 00208 00209 /* Inherit stuff from older releases. We assume that FreeBSD 00210 4.0-RELEASE always uses ELF. */ 00211 i386fbsd_init_abi (info, gdbarch); 00212 00213 /* FreeBSD 4.0 introduced a new `struct reg'. */ 00214 tdep->gregset_reg_offset = i386fbsd4_r_reg_offset; 00215 tdep->gregset_num_regs = ARRAY_SIZE (i386fbsd4_r_reg_offset); 00216 tdep->sizeof_gregset = 19 * 4; 00217 00218 /* FreeBSD 4.0 introduced a new `struct sigcontext'. */ 00219 tdep->sc_reg_offset = i386fbsd4_sc_reg_offset; 00220 tdep->sc_num_regs = ARRAY_SIZE (i386fbsd4_sc_reg_offset); 00221 } 00222 00223 00224 /* Provide a prototype to silence -Wmissing-prototypes. */ 00225 void _initialize_i386fbsd_tdep (void); 00226 00227 void 00228 _initialize_i386fbsd_tdep (void) 00229 { 00230 gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_FREEBSD_AOUT, 00231 i386fbsdaout_init_abi); 00232 gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_FREEBSD_ELF, 00233 i386fbsd4_init_abi); 00234 }