From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 16876 invoked by alias); 8 Jun 2006 15:24:45 -0000 Received: (qmail 16862 invoked by uid 22791); 8 Jun 2006 15:24:42 -0000 X-Spam-Check-By: sourceware.org Received: from nevyn.them.org (HELO nevyn.them.org) (66.93.172.17) by sourceware.org (qpsmtpd/0.31.1) with ESMTP; Thu, 08 Jun 2006 15:24:38 +0000 Received: from drow by nevyn.them.org with local (Exim 4.54) id 1FoMN6-0005OX-HL; Thu, 08 Jun 2006 11:24:32 -0400 Date: Thu, 08 Jun 2006 15:24:00 -0000 From: Daniel Jacobowitz To: gdb-patches@sourceware.org Cc: Richard Earnshaw Subject: [rfa] Cross corefile support for ARM Message-ID: <20060608152432.GA20630@nevyn.them.org> Mail-Followup-To: gdb-patches@sourceware.org, Richard Earnshaw MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.5.11+cvs20060403 X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2006-06/txt/msg00071.txt.bz2 I've reimplemented ARM Linux corefile support to use the new interfaces, and work for cross-debuggers. I needed this last week to track down a problem in an EABI binary and I didn't have an EABI native GDB available. I've tested it manually in both cross and native configurations; it actually fixes FPA (NWFPE) support for core files, which had gotten broken at some point in the past when ARM stopped providing FP0_REGNUM. This whole story is a bit of an embarrassment. I've implemented this at least twice in the past but never cleaned it up enough to submit it. And Girish Shilamkar submitted something similar in February, although I didn't notice at the time that (A) he didn't remove the existing core file support in arm-linux-nat.c, which would probably break native ARM gdbs, and (B) the FP support was bogus and didn't match any core dump layout I'm famliar with. And I never heard back about TimeSys's copyright assignment, so that's been sitting in limbo. Look OK? -- Daniel Jacobowitz CodeSourcery 2006-06-08 Daniel Jacobowitz * 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. Index: src/gdb/Makefile.in =================================================================== --- src.orig/gdb/Makefile.in 2006-06-08 11:02:11.000000000 -0400 +++ src/gdb/Makefile.in 2006-06-08 11:12:48.000000000 -0400 @@ -641,6 +641,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 @@ -1769,10 +1770,11 @@ arch-utils.o: arch-utils.c $(defs_h) $(a $(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) Index: src/gdb/arm-linux-nat.c =================================================================== --- src.orig/gdb/arm-linux-nat.c 2006-06-08 11:02:11.000000000 -0400 +++ src/gdb/arm-linux-nat.c 2006-06-08 11:08:17.000000000 -0400 @@ -28,6 +28,7 @@ #include "linux-nat.h" #include "arm-tdep.h" +#include "arm-linux-tdep.h" #include #include @@ -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 } } -/* 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 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 Index: src/gdb/arm-linux-tdep.c =================================================================== --- src.orig/gdb/arm-linux-tdep.c 2006-06-08 11:02:11.000000000 -0400 +++ src/gdb/arm-linux-tdep.c 2006-06-08 11:08:17.000000000 -0400 @@ -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 @@ -329,6 +333,217 @@ static struct tramp_frame arm_eabi_linux 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) @@ -383,6 +598,10 @@ arm_linux_init_abi (struct gdbarch_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 Index: src/gdb/arm-linux-tdep.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ src/gdb/arm-linux-tdep.h 2006-06-08 11:08:17.000000000 -0400 @@ -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); Index: src/gdb/arm-tdep.h =================================================================== --- src.orig/gdb/arm-tdep.h 2006-06-08 11:02:11.000000000 -0400 +++ src/gdb/arm-tdep.h 2006-06-08 11:08:17.000000000 -0400 @@ -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 Index: src/gdb/config/arm/linux.mh =================================================================== --- src.orig/gdb/config/arm/linux.mh 2006-06-08 11:02:11.000000000 -0400 +++ src/gdb/config/arm/linux.mh 2006-06-08 11:08:17.000000000 -0400 @@ -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 Index: src/gdb/config/arm/linux.mt =================================================================== --- src.orig/gdb/config/arm/linux.mt 2006-06-08 11:02:11.000000000 -0400 +++ src/gdb/config/arm/linux.mt 2006-06-08 11:08:17.000000000 -0400 @@ -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 +