diff options
-rw-r--r-- | gdb/ChangeLog | 31 | ||||
-rw-r--r-- | gdb/Makefile.in | 4 | ||||
-rw-r--r-- | gdb/arm-linux-nat.c | 318 | ||||
-rw-r--r-- | gdb/arm-linux-tdep.c | 219 | ||||
-rw-r--r-- | gdb/arm-linux-tdep.h | 62 | ||||
-rw-r--r-- | gdb/arm-tdep.h | 6 | ||||
-rw-r--r-- | gdb/config/arm/linux.mh | 3 | ||||
-rw-r--r-- | gdb/config/arm/linux.mt | 5 |
8 files changed, 356 insertions, 292 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 5294e28..22d2bb0 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,34 @@ +2006-07-12 Daniel Jacobowitz <dan@codesourcery.com> + + * Makefile.in (arm_linux_tdep_h): New variable. + (arm-linux-nat.o, arm-linux-tdep.o): Update. + * arm-linux-nat.c: Include "arm-linux-tdep.h". + (typeNone, typeSingle, typeDouble, typeExtended) + (FPWORDS, ARM_CPSR_REGNUM, FPREG, FPA11) + (fetch_nwfpe_single, fetch_nwfpe_double, fetch_nwfpe_none) + (fetch_nwfpe_extended, fetch_nwfpe_register, store_nwfpe_single) + (store_nwfpe_double, store_nwfpe_extended, store_nwfpe_register): + Delete. + (fetch_fpregister, fetch_fpregs, store_fpregister, store_fpregs): + Use gdb_byte buffers, NWFPE_FPSR_OFFSET, supply_nwfpe_register, + and collect_nwfpe_register. + (fill_gregset, supply_gregset, fill_fpregset, supply_fpregset): Use + new regset functions. + * arm-linux-tdep.c: Include "regset.h" and "arm-linux-tdep.h". + (arm_apcs_32): New declaration. + (ARM_LINUX_SIZEOF_GREGSET, arm_linux_supply_gregset) + (arm_linux_collect_gregset, typeNone, typeSingle, typeDouble) + (typeExtended, supply_nwfpe_register, collect_nwfpe_register) + (arm_linux_supply_nwfpe, arm_linux_collect_nwfpe) + (arm_linux_regset_from_core_section): New. + (arm_linux_init_abi): Register arm_linux_regset_from_core_section. + * arm-linux-tdep.h: New file. + * arm-tdep.h (struct regset): Declare. + (struct gdbarch_tdep): Add gregset, fpregset members. + * config/arm/linux.mh (NATDEPFILES): Remove corelow.o and + core-regset.o. + * config/arm/linux.mt (TDEPFILES): Add corelow.o. + 2006-07-12 Jan Kratochvil <lace@jankratochvil.net> * infrun.c (handle_inferior_event): Fixed typos in printf. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 21eeb50..f19935b 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -639,6 +639,7 @@ amd64_nat_h = amd64-nat.h amd64_tdep_h = amd64-tdep.h $(i386_tdep_h) annotate_h = annotate.h $(symtab_h) $(gdbtypes_h) arch_utils_h = arch-utils.h +arm_linux_tdep_h = arm-linux-tdep.h arm_tdep_h = arm-tdep.h auxv_h = auxv.h ax_gdb_h = ax-gdb.h @@ -1772,10 +1773,11 @@ arch-utils.o: arch-utils.c $(defs_h) $(arch_utils_h) $(buildsym_h) \ $(floatformat_h) arm-linux-nat.o: arm-linux-nat.c $(defs_h) $(inferior_h) $(gdbcore_h) \ $(gdb_string_h) $(regcache_h) $(arm_tdep_h) $(gregset_h) \ - $(target_h) $(linux_nat_h) $(gdb_proc_service_h) + $(target_h) $(linux_nat_h) $(gdb_proc_service_h) $(arm_linux_tdep_h) arm-linux-tdep.o: arm-linux-tdep.c $(defs_h) $(target_h) $(value_h) \ $(gdbtypes_h) $(floatformat_h) $(gdbcore_h) $(frame_h) $(regcache_h) \ $(doublest_h) $(solib_svr4_h) $(osabi_h) $(arm_tdep_h) \ + $(regset_h) $(arm_linux_tdep_h) \ $(glibc_tdep_h) $(trad_frame_h) $(tramp_frame_h) $(gdb_string_h) armnbsd-nat.o: armnbsd-nat.c $(defs_h) $(gdbcore_h) $(inferior_h) \ $(regcache_h) $(target_h) $(gdb_string_h) $(arm_tdep_h) $(inf_ptrace_h) diff --git a/gdb/arm-linux-nat.c b/gdb/arm-linux-nat.c index 0cfec20..5111510 100644 --- a/gdb/arm-linux-nat.c +++ b/gdb/arm-linux-nat.c @@ -28,6 +28,7 @@ #include "linux-nat.h" #include "arm-tdep.h" +#include "arm-linux-tdep.h" #include <sys/user.h> #include <sys/ptrace.h> @@ -46,32 +47,6 @@ extern int arm_apcs_32; -#define typeNone 0x00 -#define typeSingle 0x01 -#define typeDouble 0x02 -#define typeExtended 0x03 -#define FPWORDS 28 -#define ARM_CPSR_REGNUM 16 - -typedef union tagFPREG - { - unsigned int fSingle; - unsigned int fDouble[2]; - unsigned int fExtended[3]; - } -FPREG; - -typedef struct tagFPA11 - { - FPREG fpreg[8]; /* 8 floating point registers */ - unsigned int fpsr; /* floating point status register */ - unsigned int fpcr; /* floating point control register */ - unsigned char fType[8]; /* type of floating point value held in - floating point registers. */ - int initflag; /* NWFPE initialization flag. */ - } -FPA11; - /* The following variables are used to determine the version of the underlying GNU/Linux operating system. Examples: @@ -104,132 +79,6 @@ get_thread_id (ptid_t ptid) } #define GET_THREAD_ID(PTID) get_thread_id ((PTID)); -static void -fetch_nwfpe_single (unsigned int fn, FPA11 * fpa11) -{ - unsigned int mem[3]; - - mem[0] = fpa11->fpreg[fn].fSingle; - mem[1] = 0; - mem[2] = 0; - regcache_raw_supply (current_regcache, ARM_F0_REGNUM + fn, (char *) &mem[0]); -} - -static void -fetch_nwfpe_double (unsigned int fn, FPA11 * fpa11) -{ - unsigned int mem[3]; - - mem[0] = fpa11->fpreg[fn].fDouble[1]; - mem[1] = fpa11->fpreg[fn].fDouble[0]; - mem[2] = 0; - regcache_raw_supply (current_regcache, ARM_F0_REGNUM + fn, (char *) &mem[0]); -} - -static void -fetch_nwfpe_none (unsigned int fn) -{ - unsigned int mem[3] = - {0, 0, 0}; - - regcache_raw_supply (current_regcache, ARM_F0_REGNUM + fn, (char *) &mem[0]); -} - -static void -fetch_nwfpe_extended (unsigned int fn, FPA11 * fpa11) -{ - unsigned int mem[3]; - - mem[0] = fpa11->fpreg[fn].fExtended[0]; /* sign & exponent */ - mem[1] = fpa11->fpreg[fn].fExtended[2]; /* ls bits */ - mem[2] = fpa11->fpreg[fn].fExtended[1]; /* ms bits */ - regcache_raw_supply (current_regcache, ARM_F0_REGNUM + fn, (char *) &mem[0]); -} - -static void -fetch_nwfpe_register (int regno, FPA11 * fpa11) -{ - int fn = regno - ARM_F0_REGNUM; - - switch (fpa11->fType[fn]) - { - case typeSingle: - fetch_nwfpe_single (fn, fpa11); - break; - - case typeDouble: - fetch_nwfpe_double (fn, fpa11); - break; - - case typeExtended: - fetch_nwfpe_extended (fn, fpa11); - break; - - default: - fetch_nwfpe_none (fn); - } -} - -static void -store_nwfpe_single (unsigned int fn, FPA11 *fpa11) -{ - unsigned int mem[3]; - - regcache_raw_collect (current_regcache, ARM_F0_REGNUM + fn, - (char *) &mem[0]); - fpa11->fpreg[fn].fSingle = mem[0]; - fpa11->fType[fn] = typeSingle; -} - -static void -store_nwfpe_double (unsigned int fn, FPA11 *fpa11) -{ - unsigned int mem[3]; - - regcache_raw_collect (current_regcache, ARM_F0_REGNUM + fn, - (char *) &mem[0]); - fpa11->fpreg[fn].fDouble[1] = mem[0]; - fpa11->fpreg[fn].fDouble[0] = mem[1]; - fpa11->fType[fn] = typeDouble; -} - -void -store_nwfpe_extended (unsigned int fn, FPA11 *fpa11) -{ - unsigned int mem[3]; - - regcache_raw_collect (current_regcache, ARM_F0_REGNUM + fn, - (char *) &mem[0]); - fpa11->fpreg[fn].fExtended[0] = mem[0]; /* sign & exponent */ - fpa11->fpreg[fn].fExtended[2] = mem[1]; /* ls bits */ - fpa11->fpreg[fn].fExtended[1] = mem[2]; /* ms bits */ - fpa11->fType[fn] = typeDouble; -} - -void -store_nwfpe_register (int regno, FPA11 * fpa11) -{ - if (register_cached (regno)) - { - unsigned int fn = regno - ARM_F0_REGNUM; - switch (fpa11->fType[fn]) - { - case typeSingle: - store_nwfpe_single (fn, fpa11); - break; - - case typeDouble: - store_nwfpe_double (fn, fpa11); - break; - - case typeExtended: - store_nwfpe_extended (fn, fpa11); - break; - } - } -} - - /* Get the value of a particular register from the floating point state of the process and store it into regcache. */ @@ -237,13 +86,13 @@ static void fetch_fpregister (int regno) { int ret, tid; - FPA11 fp; + gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE]; /* Get the thread id for the ptrace call. */ tid = GET_THREAD_ID (inferior_ptid); /* Read the floating point state. */ - ret = ptrace (PT_GETFPREGS, tid, 0, &fp); + ret = ptrace (PT_GETFPREGS, tid, 0, fp); if (ret < 0) { warning (_("Unable to fetch floating point register.")); @@ -252,31 +101,12 @@ fetch_fpregister (int regno) /* Fetch fpsr. */ if (ARM_FPS_REGNUM == regno) - regcache_raw_supply (current_regcache, ARM_FPS_REGNUM, (char *) &fp.fpsr); + regcache_raw_supply (current_regcache, ARM_FPS_REGNUM, + fp + NWFPE_FPSR_OFFSET); /* Fetch the floating point register. */ if (regno >= ARM_F0_REGNUM && regno <= ARM_F7_REGNUM) - { - int fn = regno - ARM_F0_REGNUM; - - switch (fp.fType[fn]) - { - case typeSingle: - fetch_nwfpe_single (fn, &fp); - break; - - case typeDouble: - fetch_nwfpe_double (fn, &fp); - break; - - case typeExtended: - fetch_nwfpe_extended (fn, &fp); - break; - - default: - fetch_nwfpe_none (fn); - } - } + supply_nwfpe_register (current_regcache, regno, fp); } /* Get the whole floating point state of the process and store it @@ -286,13 +116,13 @@ static void fetch_fpregs (void) { int ret, regno, tid; - FPA11 fp; + gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE]; /* Get the thread id for the ptrace call. */ tid = GET_THREAD_ID (inferior_ptid); /* Read the floating point state. */ - ret = ptrace (PT_GETFPREGS, tid, 0, &fp); + ret = ptrace (PT_GETFPREGS, tid, 0, fp); if (ret < 0) { warning (_("Unable to fetch the floating point registers.")); @@ -300,31 +130,12 @@ fetch_fpregs (void) } /* Fetch fpsr. */ - regcache_raw_supply (current_regcache, ARM_FPS_REGNUM, (char *) &fp.fpsr); + regcache_raw_supply (current_regcache, ARM_FPS_REGNUM, + fp + NWFPE_FPSR_OFFSET); /* Fetch the floating point registers. */ for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++) - { - int fn = regno - ARM_F0_REGNUM; - - switch (fp.fType[fn]) - { - case typeSingle: - fetch_nwfpe_single (fn, &fp); - break; - - case typeDouble: - fetch_nwfpe_double (fn, &fp); - break; - - case typeExtended: - fetch_nwfpe_extended (fn, &fp); - break; - - default: - fetch_nwfpe_none (fn); - } - } + supply_nwfpe_register (current_regcache, regno, fp); } /* Save a particular register into the floating point state of the @@ -334,13 +145,13 @@ static void store_fpregister (int regno) { int ret, tid; - FPA11 fp; + gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE]; /* Get the thread id for the ptrace call. */ tid = GET_THREAD_ID (inferior_ptid); /* Read the floating point state. */ - ret = ptrace (PT_GETFPREGS, tid, 0, &fp); + ret = ptrace (PT_GETFPREGS, tid, 0, fp); if (ret < 0) { warning (_("Unable to fetch the floating point registers.")); @@ -349,15 +160,14 @@ store_fpregister (int regno) /* Store fpsr. */ if (ARM_FPS_REGNUM == regno && register_cached (ARM_FPS_REGNUM)) - regcache_raw_collect (current_regcache, ARM_FPS_REGNUM, (char *) &fp.fpsr); + regcache_raw_collect (current_regcache, ARM_FPS_REGNUM, + fp + NWFPE_FPSR_OFFSET); /* Store the floating point register. */ if (regno >= ARM_F0_REGNUM && regno <= ARM_F7_REGNUM) - { - store_nwfpe_register (regno, &fp); - } + collect_nwfpe_register (current_regcache, regno, fp); - ret = ptrace (PTRACE_SETFPREGS, tid, 0, &fp); + ret = ptrace (PTRACE_SETFPREGS, tid, 0, fp); if (ret < 0) { warning (_("Unable to store floating point register.")); @@ -372,13 +182,13 @@ static void store_fpregs (void) { int ret, regno, tid; - FPA11 fp; + gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE]; /* Get the thread id for the ptrace call. */ tid = GET_THREAD_ID (inferior_ptid); /* Read the floating point state. */ - ret = ptrace (PT_GETFPREGS, tid, 0, &fp); + ret = ptrace (PT_GETFPREGS, tid, 0, fp); if (ret < 0) { warning (_("Unable to fetch the floating point registers.")); @@ -387,15 +197,15 @@ store_fpregs (void) /* Store fpsr. */ if (register_cached (ARM_FPS_REGNUM)) - regcache_raw_collect (current_regcache, ARM_FPS_REGNUM, (char *) &fp.fpsr); + regcache_raw_collect (current_regcache, ARM_FPS_REGNUM, + fp + NWFPE_FPSR_OFFSET); /* Store the floating point registers. */ for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++) - { - fetch_nwfpe_register (regno, &fp); - } + if (register_cached (regno)) + collect_nwfpe_register (current_regcache, regno, fp); - ret = ptrace (PTRACE_SETFPREGS, tid, 0, &fp); + ret = ptrace (PTRACE_SETFPREGS, tid, 0, fp); if (ret < 0) { warning (_("Unable to store floating point registers.")); @@ -597,83 +407,25 @@ arm_linux_store_inferior_registers (int regno) } } -/* Fill register regno (if it is a general-purpose register) in - *gregsetp with the appropriate value from GDB's register array. - If regno is -1, do this for all registers. */ +/* Wrapper functions for the standard regset handling, used by + thread debugging. */ void fill_gregset (gdb_gregset_t *gregsetp, int regno) { - if (-1 == regno) - { - int regnum; - for (regnum = ARM_A1_REGNUM; regnum <= ARM_PC_REGNUM; regnum++) - regcache_raw_collect (current_regcache, regnum, - (char *) &(*gregsetp)[regnum]); - } - else if (regno >= ARM_A1_REGNUM && regno <= ARM_PC_REGNUM) - regcache_raw_collect (current_regcache, regno, - (char *) &(*gregsetp)[regno]); - - if (ARM_PS_REGNUM == regno || -1 == regno) - { - if (arm_apcs_32) - regcache_raw_collect (current_regcache, ARM_PS_REGNUM, - (char *) &(*gregsetp)[ARM_CPSR_REGNUM]); - else - regcache_raw_collect (current_regcache, ARM_PC_REGNUM, - (char *) &(*gregsetp)[ARM_PC_REGNUM]); - } + arm_linux_collect_gregset (NULL, current_regcache, regno, gregsetp, 0); } -/* Fill GDB's register array with the general-purpose register values - in *gregsetp. */ - void supply_gregset (gdb_gregset_t *gregsetp) { - int regno, reg_pc; - - for (regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++) - regcache_raw_supply (current_regcache, regno, - (char *) &(*gregsetp)[regno]); - - if (arm_apcs_32) - regcache_raw_supply (current_regcache, ARM_PS_REGNUM, - (char *) &(*gregsetp)[ARM_CPSR_REGNUM]); - else - regcache_raw_supply (current_regcache, ARM_PS_REGNUM, - (char *) &(*gregsetp)[ARM_PC_REGNUM]); - - reg_pc = ADDR_BITS_REMOVE ((CORE_ADDR)(*gregsetp)[ARM_PC_REGNUM]); - regcache_raw_supply (current_regcache, ARM_PC_REGNUM, (char *) ®_pc); + arm_linux_supply_gregset (NULL, current_regcache, -1, gregsetp, 0); } -/* Fill register regno (if it is a floating-point register) in - *fpregsetp with the appropriate value from GDB's register array. - If regno is -1, do this for all registers. */ - void fill_fpregset (gdb_fpregset_t *fpregsetp, int regno) { - FPA11 *fp = (FPA11 *) fpregsetp; - - if (-1 == regno) - { - int regnum; - for (regnum = ARM_F0_REGNUM; regnum <= ARM_F7_REGNUM; regnum++) - store_nwfpe_register (regnum, fp); - } - else if (regno >= ARM_F0_REGNUM && regno <= ARM_F7_REGNUM) - { - store_nwfpe_register (regno, fp); - return; - } - - /* Store fpsr. */ - if (ARM_FPS_REGNUM == regno || -1 == regno) - regcache_raw_collect (current_regcache, ARM_FPS_REGNUM, - (char *) &fp->fpsr); + arm_linux_collect_nwfpe (NULL, current_regcache, regno, fpregsetp, 0); } /* Fill GDB's register array with the floating-point register values @@ -682,17 +434,7 @@ fill_fpregset (gdb_fpregset_t *fpregsetp, int regno) void supply_fpregset (gdb_fpregset_t *fpregsetp) { - int regno; - FPA11 *fp = (FPA11 *) fpregsetp; - - /* Fetch fpsr. */ - regcache_raw_supply (current_regcache, ARM_FPS_REGNUM, (char *) &fp->fpsr); - - /* Fetch the floating point registers. */ - for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++) - { - fetch_nwfpe_register (regno, fp); - } + arm_linux_supply_nwfpe (NULL, current_regcache, -1, fpregsetp, 0); } int diff --git a/gdb/arm-linux-tdep.c b/gdb/arm-linux-tdep.c index 95d422a..52daada 100644 --- a/gdb/arm-linux-tdep.c +++ b/gdb/arm-linux-tdep.c @@ -31,14 +31,18 @@ #include "doublest.h" #include "solib-svr4.h" #include "osabi.h" +#include "regset.h" #include "trad-frame.h" #include "tramp-frame.h" #include "arm-tdep.h" +#include "arm-linux-tdep.h" #include "glibc-tdep.h" #include "gdb_string.h" +extern int arm_apcs_32; + /* Under ARM GNU/Linux the traditional way of performing a breakpoint is to execute a particular software interrupt, rather than use a particular undefined instruction to provoke a trap. Upon exection @@ -378,6 +382,217 @@ static struct tramp_frame arm_eabi_linux_rt_sigreturn_tramp_frame = { arm_linux_rt_sigreturn_init }; +/* Core file and register set support. */ + +#define ARM_LINUX_SIZEOF_GREGSET (18 * INT_REGISTER_SIZE) + +void +arm_linux_supply_gregset (const struct regset *regset, + struct regcache *regcache, + int regnum, const void *gregs_buf, size_t len) +{ + const gdb_byte *gregs = gregs_buf; + int regno; + CORE_ADDR reg_pc; + gdb_byte pc_buf[INT_REGISTER_SIZE]; + + for (regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++) + if (regnum == -1 || regnum == regno) + regcache_raw_supply (regcache, regno, + gregs + INT_REGISTER_SIZE * regno); + + if (regnum == ARM_PS_REGNUM || regnum == -1) + { + if (arm_apcs_32) + regcache_raw_supply (regcache, ARM_PS_REGNUM, + gregs + INT_REGISTER_SIZE * ARM_CPSR_REGNUM); + else + regcache_raw_supply (regcache, ARM_PS_REGNUM, + gregs + INT_REGISTER_SIZE * ARM_PC_REGNUM); + } + + if (regnum == ARM_PC_REGNUM || regnum == -1) + { + reg_pc = extract_unsigned_integer (gregs + + INT_REGISTER_SIZE * ARM_PC_REGNUM, + INT_REGISTER_SIZE); + reg_pc = ADDR_BITS_REMOVE (reg_pc); + store_unsigned_integer (pc_buf, INT_REGISTER_SIZE, reg_pc); + regcache_raw_supply (regcache, ARM_PC_REGNUM, pc_buf); + } +} + +void +arm_linux_collect_gregset (const struct regset *regset, + const struct regcache *regcache, + int regnum, void *gregs_buf, size_t len) +{ + gdb_byte *gregs = gregs_buf; + int regno; + + for (regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++) + if (regnum == -1 || regnum == regno) + regcache_raw_collect (regcache, regno, + gregs + INT_REGISTER_SIZE * regno); + + if (regnum == ARM_PS_REGNUM || regnum == -1) + { + if (arm_apcs_32) + regcache_raw_collect (regcache, ARM_PS_REGNUM, + gregs + INT_REGISTER_SIZE * ARM_CPSR_REGNUM); + else + regcache_raw_collect (regcache, ARM_PS_REGNUM, + gregs + INT_REGISTER_SIZE * ARM_PC_REGNUM); + } + + if (regnum == ARM_PC_REGNUM || regnum == -1) + regcache_raw_collect (regcache, ARM_PC_REGNUM, + gregs + INT_REGISTER_SIZE * ARM_PC_REGNUM); +} + +/* Support for register format used by the NWFPE FPA emulator. */ + +#define typeNone 0x00 +#define typeSingle 0x01 +#define typeDouble 0x02 +#define typeExtended 0x03 + +void +supply_nwfpe_register (struct regcache *regcache, int regno, + const gdb_byte *regs) +{ + const gdb_byte *reg_data; + gdb_byte reg_tag; + gdb_byte buf[FP_REGISTER_SIZE]; + + reg_data = regs + (regno - ARM_F0_REGNUM) * FP_REGISTER_SIZE; + reg_tag = regs[(regno - ARM_F0_REGNUM) + NWFPE_TAGS_OFFSET]; + memset (buf, 0, FP_REGISTER_SIZE); + + switch (reg_tag) + { + case typeSingle: + memcpy (buf, reg_data, 4); + break; + case typeDouble: + memcpy (buf, reg_data + 4, 4); + memcpy (buf + 4, reg_data, 4); + break; + case typeExtended: + /* We want sign and exponent, then least significant bits, + then most significant. NWFPE does sign, most, least. */ + memcpy (buf, reg_data, 4); + memcpy (buf + 4, reg_data + 8, 4); + memcpy (buf + 8, reg_data + 4, 4); + break; + default: + break; + } + + regcache_raw_supply (regcache, regno, buf); +} + +void +collect_nwfpe_register (const struct regcache *regcache, int regno, + gdb_byte *regs) +{ + gdb_byte *reg_data; + gdb_byte reg_tag; + gdb_byte buf[FP_REGISTER_SIZE]; + + regcache_raw_collect (regcache, regno, buf); + + /* NOTE drow/2006-06-07: This code uses the tag already in the + register buffer. I've preserved that when moving the code + from the native file to the target file. But this doesn't + always make sense. */ + + reg_data = regs + (regno - ARM_F0_REGNUM) * FP_REGISTER_SIZE; + reg_tag = regs[(regno - ARM_F0_REGNUM) + NWFPE_TAGS_OFFSET]; + + switch (reg_tag) + { + case typeSingle: + memcpy (reg_data, buf, 4); + break; + case typeDouble: + memcpy (reg_data, buf + 4, 4); + memcpy (reg_data + 4, buf, 4); + break; + case typeExtended: + memcpy (reg_data, buf, 4); + memcpy (reg_data + 4, buf + 8, 4); + memcpy (reg_data + 8, buf + 4, 4); + break; + default: + break; + } +} + +void +arm_linux_supply_nwfpe (const struct regset *regset, + struct regcache *regcache, + int regnum, const void *regs_buf, size_t len) +{ + const gdb_byte *regs = regs_buf; + int regno; + + if (regnum == ARM_FPS_REGNUM || regnum == -1) + regcache_raw_supply (regcache, ARM_FPS_REGNUM, + regs + NWFPE_FPSR_OFFSET); + + for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++) + if (regnum == -1 || regnum == regno) + supply_nwfpe_register (regcache, regno, regs); +} + +void +arm_linux_collect_nwfpe (const struct regset *regset, + const struct regcache *regcache, + int regnum, void *regs_buf, size_t len) +{ + gdb_byte *regs = regs_buf; + int regno; + + for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++) + if (regnum == -1 || regnum == regno) + collect_nwfpe_register (regcache, regno, regs); + + if (regnum == ARM_FPS_REGNUM || regnum == -1) + regcache_raw_collect (regcache, ARM_FPS_REGNUM, + regs + INT_REGISTER_SIZE * ARM_FPS_REGNUM); +} + +/* Return the appropriate register set for the core section identified + by SECT_NAME and SECT_SIZE. */ + +static const struct regset * +arm_linux_regset_from_core_section (struct gdbarch *gdbarch, + const char *sect_name, size_t sect_size) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + if (strcmp (sect_name, ".reg") == 0 + && sect_size == ARM_LINUX_SIZEOF_GREGSET) + { + if (tdep->gregset == NULL) + tdep->gregset = regset_alloc (gdbarch, arm_linux_supply_gregset, + arm_linux_collect_gregset); + return tdep->gregset; + } + + if (strcmp (sect_name, ".reg2") == 0 + && sect_size == ARM_LINUX_SIZEOF_NWFPE) + { + if (tdep->fpregset == NULL) + tdep->fpregset = regset_alloc (gdbarch, arm_linux_supply_nwfpe, + arm_linux_collect_nwfpe); + return tdep->fpregset; + } + + return NULL; +} + static void arm_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) @@ -432,6 +647,10 @@ arm_linux_init_abi (struct gdbarch_info info, &arm_eabi_linux_sigreturn_tramp_frame); tramp_frame_prepend_unwinder (gdbarch, &arm_eabi_linux_rt_sigreturn_tramp_frame); + + /* Core file support. */ + set_gdbarch_regset_from_core_section (gdbarch, + arm_linux_regset_from_core_section); } void diff --git a/gdb/arm-linux-tdep.h b/gdb/arm-linux-tdep.h new file mode 100644 index 0000000..31d6ba0 --- /dev/null +++ b/gdb/arm-linux-tdep.h @@ -0,0 +1,62 @@ +/* GNU/Linux on ARM target support, prototypes. + + Copyright (C) 2006 + Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +struct regset; +struct regcache; + +#define ARM_CPSR_REGNUM 16 + +#define ARM_LINUX_SIZEOF_NWFPE (8 * FP_REGISTER_SIZE \ + + 2 * INT_REGISTER_SIZE \ + + 8 + INT_REGISTER_SIZE) + +/* Support for register format used by the NWFPE FPA emulator. Each + register takes three words, where either the first one, two, or + three hold a single, double, or extended precision value (depending + on the corresponding tag). The register set is eight registers, + followed by the fpsr and fpcr, followed by eight tag bytes, and a + final word flag which indicates whether NWFPE has been + initialized. */ + +#define NWFPE_FPSR_OFFSET (8 * FP_REGISTER_SIZE) +#define NWFPE_FPCR_OFFSET (NWFPE_FPSR_OFFSET + INT_REGISTER_SIZE) +#define NWFPE_TAGS_OFFSET (NWFPE_FPCR_OFFSET + INT_REGISTER_SIZE) +#define NWFPE_INITFLAG_OFFSET (NWFPE_TAGS_OFFSET + 8) + +void arm_linux_supply_gregset (const struct regset *regset, + struct regcache *regcache, + int regnum, const void *gregs_buf, size_t len); +void arm_linux_collect_gregset (const struct regset *regset, + const struct regcache *regcache, + int regnum, void *gregs_buf, size_t len); + +void supply_nwfpe_register (struct regcache *regcache, int regno, + const gdb_byte *regs); +void collect_nwfpe_register (const struct regcache *regcache, int regno, + gdb_byte *regs); + +void arm_linux_supply_nwfpe (const struct regset *regset, + struct regcache *regcache, + int regnum, const void *regs_buf, size_t len); +void arm_linux_collect_nwfpe (const struct regset *regset, + const struct regcache *regcache, + int regnum, void *regs_buf, size_t len); diff --git a/gdb/arm-tdep.h b/gdb/arm-tdep.h index 3141052..f6dc635 100644 --- a/gdb/arm-tdep.h +++ b/gdb/arm-tdep.h @@ -18,6 +18,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +/* Forward declarations. */ +struct regset; + /* Register numbers of various important registers. Note that some of these values are "real" register numbers, and correspond to the general registers of the machine, and some are "phony" register @@ -143,6 +146,9 @@ struct gdbarch_tdep If this is negative, longjmp support will be disabled. */ size_t jb_elt_size; /* And the size of each entry in the buf. */ + + /* Cached core file helpers. */ + struct regset *gregset, *fpregset; }; #ifndef LOWEST_PC diff --git a/gdb/config/arm/linux.mh b/gdb/config/arm/linux.mh index 32181a4..7de2327 100644 --- a/gdb/config/arm/linux.mh +++ b/gdb/config/arm/linux.mh @@ -1,8 +1,7 @@ # Host: ARM based machine running GNU/Linux NAT_FILE= nm-linux.h -NATDEPFILES= inf-ptrace.o fork-child.o corelow.o \ - core-regset.o arm-linux-nat.o gcore.o \ +NATDEPFILES= inf-ptrace.o fork-child.o arm-linux-nat.o gcore.o \ proc-service.o linux-thread-db.o linux-nat.o linux-fork.o LOADLIBES= -ldl -rdynamic diff --git a/gdb/config/arm/linux.mt b/gdb/config/arm/linux.mt index 6521a0b..49e65a0 100644 --- a/gdb/config/arm/linux.mt +++ b/gdb/config/arm/linux.mt @@ -1,3 +1,6 @@ # Target: ARM based machine running GNU/Linux DEPRECATED_TM_FILE= tm-linux.h -TDEPFILES= arm-tdep.o arm-linux-tdep.o glibc-tdep.o solib.o solib-svr4.o solib-legacy.o symfile-mem.o +TDEPFILES= arm-tdep.o arm-linux-tdep.o glibc-tdep.o solib.o \ + solib-svr4.o solib-legacy.o symfile-mem.o \ + corelow.o + |