From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 2055 invoked by alias); 27 Nov 2002 18:33:49 -0000 Mailing-List: contact rda-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Post: List-Help: , Sender: rda-owner@sources.redhat.com Received: (qmail 2019 invoked from network); 27 Nov 2002 18:33:47 -0000 Date: Wed, 27 Nov 2002 10:33:00 -0000 From: Kevin Buettner Message-Id: <1021127183338.ZM31443@localhost.localdomain> X-Mailer: Z-Mail (4.0.1 13Jan97 Caldera) To: rda@sources.redhat.com Subject: [RFC] Revise interfaces for *_bytes_{from,to}_reg() MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-SW-Source: 2002-q4/txt/msg00003.txt.bz2 I recently discovered that rda (on Linux/MIPS) didn't work correctly when the space allocated to hold a register for the remote protocol is larger than that required by the ptrace interface. (In a GDB configured for a mips64 target, I was seeing the (32-bit) register contents in the most significant 32-bits.) The patch below revises the gdbserv_{be,le,host}_bytes_{to,from}_reg() interfaces so that the correct padding/truncation occurs when the source and destination sizes differ. (I've thought about the problem of sign extension on MIPS, but I'm punting on it for now.) I'm not sure what the checkin policies are for RDA. I assume I need approval for gdbserv-utils.[hc]. In ChangeLog: * include/gdbserv-utils.h, lib/gdbserv-utils.c (gdbserv_be_bytes_to_reg, gdbserv_le_bytes_to_reg) (gdbserv_be_bytes_from_reg, gdbserv_le_bytes_from_reg) (gdbserv_host_bytes_to_reg, gdbserv_host_bytes_from_reg): Revise interfaces. In unix/ChangeLog: * linux-target.c (linux_get_reg, linux_set_reg, reg_from_regset) (reg_to_regset, get_regset, put_regset reg_from_gregset) (reg_to_gregset, reg_from_fpregset, reg_to_fpregset) (reg_from_xregset, reg_to_xregset): Adjust all calls to gdbserv_host_bytes_to_reg() and gdbserv_host_bytes_from_reg() to account for change in interface. Remove code which is no longer needed due to improvements in the aforementioned functions. Index: include/gdbserv-utils.h =================================================================== RCS file: /cvs/src/src/rda/include/gdbserv-utils.h,v retrieving revision 1.1 diff -u -p -r1.1 gdbserv-utils.h --- include/gdbserv-utils.h 28 Aug 2002 01:22:27 -0000 1.1 +++ include/gdbserv-utils.h 27 Nov 2002 17:57:17 -0000 @@ -60,42 +60,58 @@ extern void gdbserv_ulonglong_to_reg (st unsigned long long val, struct gdbserv_reg *reg); -/* Convert between a REG and a buffer representing a numeric type. - Handle big endian and little endian cases explicitly. */ +/* Convert between a REG and a buffer representing an unsigned numeric + type. Handle big endian and little endian cases explicitly. When + the source buffer is bigger than the destination buffer, the least + significant bytes (as appropriate for the endianess) are transferred. + When the source buffer is smaller than the destination, the most + significant bytes of the destination are padded with zeros. + + Note that gdbserv_be_bytes_from_reg() and gdbserv_le_bytes_from_reg() + have a buffer length parameter, but not a register length + parameter. This is because the register length was obtained from a + register packet sent by the debug client. On the other hand, + gdbserv_be_bytes_to_reg() and gdbserv_le_bytes_to_reg() take both a + buffer length and the register length. This is because we're + constructing a register (which will likely be sent to the client) + of a particular size. */ extern void gdbserv_be_bytes_to_reg (struct gdbserv *gdbserv, const void *buf, - int len, - struct gdbserv_reg *reg); + int buflen, + struct gdbserv_reg *reg, + int reglen); extern void gdbserv_le_bytes_to_reg (struct gdbserv *gdbserv, const void *buf, int len, - struct gdbserv_reg *reg); + struct gdbserv_reg *reg, + int reglen); extern void gdbserv_be_bytes_from_reg (struct gdbserv *gdbserv, void *buf, - int *lenp, + int buflen, const struct gdbserv_reg *reg); extern void gdbserv_le_bytes_from_reg (struct gdbserv *gdbserv, void *buf, - int *lenp, + int buflen, const struct gdbserv_reg *reg); -/* Convert between a REG and a buffer representing a native numeric - type. These are just wrappers for the routines above, but are - useful nonetheless since they free the caller from having to +/* Convert between a REG and a buffer representing a native unsigned + numeric type. These are just wrappers for the routines above, but + are useful nonetheless since they free the caller from having to worry about byte order issues. */ extern void gdbserv_host_bytes_to_reg (struct gdbserv *gdbserv, const void *buf, - int len, - struct gdbserv_reg *reg); + int buflen, + struct gdbserv_reg *reg, + int reglen); extern void gdbserv_host_bytes_from_reg (struct gdbserv *gdbserv, void *buf, - int *lenp, + int buflen, const struct gdbserv_reg *reg); #ifdef __cplusplus Index: lib/gdbserv-utils.c =================================================================== RCS file: /cvs/src/src/rda/lib/gdbserv-utils.c,v retrieving revision 1.1 diff -u -p -r1.1 gdbserv-utils.c --- lib/gdbserv-utils.c 28 Aug 2002 01:22:28 -0000 1.1 +++ lib/gdbserv-utils.c 27 Nov 2002 17:57:17 -0000 @@ -227,67 +227,129 @@ reverse_copy_bytes (void *dest, const vo void gdbserv_be_bytes_to_reg (struct gdbserv *gdbserv, const void *buf, - int len, - struct gdbserv_reg *reg) -{ + int buflen, + struct gdbserv_reg *reg, + int reglen) +{ + int bufoffset = 0; + int regoffset = 0; + int len = buflen; + reg->negative_p = 0; - reg->len = len; - memcpy (reg->buf, buf, len); + reg->len = reglen; + + if (reglen > buflen) + { + memset (reg->buf, 0, reglen - buflen); + regoffset = reglen - buflen; + } + + if (buflen > reglen) + { + bufoffset = buflen - reglen; + len = reglen; + } + + memcpy (reg->buf + regoffset, (char *)buf + bufoffset, len); } void gdbserv_be_bytes_from_reg (struct gdbserv *gdbserv, void *buf, - int *lenp, + int buflen, const struct gdbserv_reg *reg) { - *lenp = reg->len; - memcpy (buf, reg->buf, reg->len); + int bufoffset = 0; + int regoffset = 0; + int len = reg->len; + + if (reg->len > buflen) + { + regoffset = reg->len - buflen; + len = buflen; + } + + if (buflen > reg->len) + { + memset (buf, 0, buflen - reg->len); + bufoffset = buflen - reg->len; + } + + memcpy ((char *)buf + bufoffset, reg->buf + regoffset, len); } void gdbserv_le_bytes_to_reg (struct gdbserv *gdbserv, const void *buf, - int len, - struct gdbserv_reg *reg) + int buflen, + struct gdbserv_reg *reg, + int reglen) { + int regoffset = 0; + int len = buflen; + reg->negative_p = 0; - reg->len = len; - reverse_copy_bytes (reg->buf, buf, len); + reg->len = reglen; + + if (reglen > buflen) + { + memset (reg->buf, 0, reglen - buflen); + regoffset = reglen - buflen; + } + + if (buflen > reglen) + len = reglen; + + reverse_copy_bytes (reg->buf + regoffset, buf, len); } void gdbserv_le_bytes_from_reg (struct gdbserv *gdbserv, void *buf, - int *lenp, + int buflen, const struct gdbserv_reg *reg) { - *lenp = reg->len; - reverse_copy_bytes (buf, reg->buf, reg->len); + int bufoffset = 0; + int regoffset = 0; + int len = reg->len; + + if (reg->len > buflen) + { + regoffset = reg->len - buflen; + len = buflen; + } + + if (buflen > reg->len) + { + memset ((char *)buf + reg->len, 0, buflen - reg->len); + } + + reverse_copy_bytes (buf, reg->buf + regoffset, reg->len); } void gdbserv_host_bytes_to_reg (struct gdbserv *gdbserv, const void *buf, - int len, - struct gdbserv_reg *reg) + int buflen, + struct gdbserv_reg *reg, + int reglen) { #ifdef WORDS_BIGENDIAN - gdbserv_be_bytes_to_reg (gdbserv, buf, len, reg); + gdbserv_be_bytes_to_reg (gdbserv, buf, buflen, reg, reglen); #else - gdbserv_le_bytes_to_reg (gdbserv, buf, len, reg); + gdbserv_le_bytes_to_reg (gdbserv, buf, buflen, reg, reglen); #endif } void gdbserv_host_bytes_from_reg (struct gdbserv *gdbserv, void *buf, - int *lenp, + int buflen, const struct gdbserv_reg *reg) { #ifdef WORDS_BIGENDIAN - gdbserv_be_bytes_from_reg (gdbserv, buf, lenp, reg); + gdbserv_be_bytes_from_reg (gdbserv, buf, buflen, reg); #else - gdbserv_le_bytes_from_reg (gdbserv, buf, lenp, reg); + gdbserv_le_bytes_from_reg (gdbserv, buf, buflen, reg); #endif } Index: unix/linux-target.c =================================================================== RCS file: /cvs/src/src/rda/unix/linux-target.c,v retrieving revision 1.1 diff -u -p -r1.1 linux-target.c --- unix/linux-target.c 28 Aug 2002 01:22:28 -0000 1.1 +++ unix/linux-target.c 27 Nov 2002 17:57:19 -0000 @@ -922,8 +1065,6 @@ linux_get_reg (struct gdbserv *serv, int return -1; } - memset (tmp_buf, 0, reginfo[regno].proto_size); - if (reginfo[regno].whichregs != NOREGS) { /* Get the register value. */ @@ -931,9 +1072,12 @@ linux_get_reg (struct gdbserv *serv, int if (status < 0) return -1; /* fail */ } + else + memset (tmp_buf, 0, reginfo[regno].ptrace_size); /* Copy the bytes to the gdbserv_reg struct. */ - gdbserv_host_bytes_to_reg (serv, tmp_buf, reginfo[regno].proto_size, reg); + gdbserv_host_bytes_to_reg (serv, tmp_buf, reginfo[regno].ptrace_size, + reg, reginfo[regno].proto_size); return 0; /* success */ @@ -958,17 +1102,10 @@ linux_set_reg (struct gdbserv *serv, int struct child_process *process = gdbserv_target_data (serv); char tmp_buf[MAX_REG_SIZE]; int status; - int len; - - /* Clear out a temporary buffer into which to fetch the bytes that - we'll be setting. We do this in case ptrace_size != proto_size. */ - memset (tmp_buf, 0, reginfo[regno].ptrace_size); /* Copy the bytes from the gdbserv_reg struct to our temporary buffer. */ - gdbserv_host_bytes_from_reg (serv, tmp_buf, &len, reg); - - if (len != reginfo[regno].proto_size) - return -1; + gdbserv_host_bytes_from_reg (serv, tmp_buf, reginfo[regno].ptrace_size, + reg); /* Write the child's register. */ status = write_reg_bytes (process->pid, regno, tmp_buf); @@ -990,7 +1127,6 @@ reg_from_regset (struct gdbserv *serv, const void *regset, enum regset whichregs) { - char tmp_buf[MAX_REG_SIZE]; char *regbytes; if (regno < 0 || regno >= NUM_REGS @@ -1001,10 +1137,8 @@ reg_from_regset (struct gdbserv *serv, regbytes = ((char *) regset) + reginfo[regno].regset_field_offset; - memset (tmp_buf, 0, reginfo[regno].proto_size); - memcpy (tmp_buf, regbytes, reginfo[regno].regset_field_size); - - gdbserv_host_bytes_to_reg (serv, tmp_buf, reginfo[regno].proto_size, reg); + gdbserv_host_bytes_to_reg (serv, regbytes, reginfo[regno].regset_field_size, + reg, reginfo[regno].proto_size); return 0; } @@ -1020,9 +1154,7 @@ reg_to_regset (struct gdbserv *serv, void *regset, enum regset whichregs) { - char tmp_buf[MAX_REG_SIZE]; char *regbytes; - int len; if (regno < 0 || regno >= NUM_REGS || reginfo[regno].whichregs != whichregs) @@ -1030,15 +1162,10 @@ reg_to_regset (struct gdbserv *serv, return -1; } - memset (tmp_buf, 0, reginfo[regno].regset_field_size); - gdbserv_host_bytes_from_reg (serv, tmp_buf, &len, reg); - - if (len != reginfo[regno].proto_size) - return -1; - regbytes = ((char *) regset) + reginfo[regno].regset_field_offset; - memcpy (regbytes, tmp_buf, reginfo[regno].regset_field_size); + gdbserv_host_bytes_from_reg (serv, regbytes, reginfo[regno].regset_field_size, + reg); return 0; } @@ -1137,16 +1264,14 @@ get_regset (struct gdbserv *serv, int pi struct gdbserv_reg reg; int status; - memset (tmp_buf, 0, reginfo[regno].proto_size); - /* Get the register value. */ status = read_reg_bytes (pid, regno, tmp_buf); if (status < 0) return -1; /* fail */ /* Copy the bytes to the gdbserv_reg struct. */ - gdbserv_host_bytes_to_reg (serv, tmp_buf, - reginfo[regno].proto_size, ®); + gdbserv_host_bytes_to_reg (serv, tmp_buf, reginfo[regno].ptrace_size, + ®, reginfo[regno].proto_size); /* Now insert them into the regset. */ reg_to_regset (serv, ®, regno, regset, whichregs); @@ -1173,20 +1298,14 @@ put_regset (struct gdbserv *serv, { char tmp_buf[MAX_REG_SIZE]; struct gdbserv_reg reg; - int len; int status; /* Fetch the reg from the regset. */ reg_from_regset (serv, ®, regno, regset, whichregs); - /* Clear out a temporary buffer into which to put the bytes that - we'll be setting. We do this in case ptrace_size != proto_size. */ - memset (tmp_buf, 0, reginfo[regno].ptrace_size); - /* Copy the bytes from the gdbserv_reg struct to our temporary buffer. */ - gdbserv_host_bytes_from_reg (serv, tmp_buf, &len, ®); - if (len != reginfo[regno].proto_size) - return -1; + gdbserv_host_bytes_from_reg (serv, tmp_buf, + reginfo[regno].ptrace_size, ®); /* Write the child's register. */ status = write_reg_bytes (pid, regno, tmp_buf); @@ -1343,7 +1462,6 @@ linux_get_reg (struct gdbserv *serv, int elf_fpregset_t fpregs; void *fpxregs; char *buf; - char tmp_buf[MAX_REG_SIZE]; if (regno < 0 || regno >= NUM_REGS) { @@ -1394,14 +1512,9 @@ linux_get_reg (struct gdbserv *serv, int /* Adjust buf to point at the starting byte of the register. */ buf += reginfo[regno].offset; - /* We go through these memset / memcpy shenanigans in case - proto_size != ptrace_size. */ - memset (tmp_buf, 0, reginfo[regno].proto_size); - if (reginfo[regno].ptrace_size > 0) - memcpy (tmp_buf, buf, reginfo[regno].ptrace_size); - /* Copy the bytes to the gdbserv_reg struct. */ - gdbserv_host_bytes_to_reg (serv, tmp_buf, reginfo[regno].proto_size, reg); + gdbserv_host_bytes_to_reg (serv, buf, reginfo[regno].ptrace_size, + reg, reginfo[regno].proto_size); return 0; } @@ -1419,7 +1532,6 @@ linux_set_reg (struct gdbserv *serv, int void *fpxregs = NULL; char *buf; char tmp_buf[MAX_REG_SIZE]; - int len; if (regno < 0 || regno >= NUM_REGS) { @@ -1468,18 +1580,8 @@ linux_set_reg (struct gdbserv *serv, int /* Adjust buf to point at the starting byte of the register. */ buf += reginfo[regno].offset; - /* Clear out a temporary buffer into which to fetch the bytes that - we'll be setting. We do this in case ptrace_size != proto_size. */ - memset (tmp_buf, 0, reginfo[regno].ptrace_size); - /* Copy the bytes from the gdbserv_reg struct to our temporary buffer. */ - gdbserv_host_bytes_from_reg (serv, tmp_buf, &len, reg); - - if (len != reginfo[regno].proto_size) - return -1; - - /* Copy the bytes to the appropriate position in the ptrace struct. */ - memcpy (buf, tmp_buf, reginfo[regno].ptrace_size); + gdbserv_host_bytes_from_reg (serv, buf, reginfo[regno].ptrace_size, reg); /* Write the register set to the process. */ if (reginfo[regno].whichregs == GREGS) @@ -1521,7 +1623,6 @@ reg_from_gregset (struct gdbserv *serv, int regno, const GREGSET_T gregset) { - char tmp_buf[MAX_REG_SIZE]; char *regbytes; if (regno < 0 || regno >= NUM_REGS @@ -1532,10 +1633,8 @@ reg_from_gregset (struct gdbserv *serv, regbytes = ((char *) gregset) + reginfo[regno].offset; - memset (tmp_buf, 0, reginfo[regno].proto_size); - memcpy (tmp_buf, regbytes, reginfo[regno].ptrace_size); - - gdbserv_host_bytes_to_reg (serv, tmp_buf, reginfo[regno].proto_size, reg); + gdbserv_host_bytes_to_reg (serv, regbytes, reginfo[regno].ptrace_size, + reg, reginfo[regno].proto_size); return 0; } @@ -1550,9 +1649,7 @@ reg_to_gregset (struct gdbserv *serv, int regno, GREGSET_T gregset) { - char tmp_buf[MAX_REG_SIZE]; char *regbytes; - int len; if (regno < 0 || regno >= NUM_REGS || reginfo[regno].whichregs != GREGS) @@ -1562,13 +1659,7 @@ reg_to_gregset (struct gdbserv *serv, regbytes = ((char *) gregset) + reginfo[regno].offset; - memset (tmp_buf, 0, reginfo[regno].ptrace_size); - gdbserv_host_bytes_from_reg (serv, tmp_buf, &len, reg); - - if (len != reginfo[regno].proto_size) - return -1; - - memcpy (regbytes, tmp_buf, reginfo[regno].ptrace_size); + gdbserv_host_bytes_from_reg (serv, regbytes, reginfo[regno].ptrace_size, reg); return 0; } @@ -1583,7 +1674,6 @@ reg_from_fpregset (struct gdbserv *serv, int regno, const FPREGSET_T *fpregset) { - char tmp_buf[MAX_REG_SIZE]; char *regbytes; if (regno < 0 || regno >= NUM_REGS @@ -1594,10 +1684,8 @@ reg_from_fpregset (struct gdbserv *serv, regbytes = ((char *) fpregset) + reginfo[regno].offset; - memset (tmp_buf, 0, reginfo[regno].proto_size); - memcpy (tmp_buf, regbytes, reginfo[regno].ptrace_size); - - gdbserv_host_bytes_to_reg (serv, tmp_buf, reginfo[regno].proto_size, reg); + gdbserv_host_bytes_to_reg (serv, regbytes, reginfo[regno].ptrace_size, + reg, reginfo[regno].proto_size); return 0; } @@ -1612,9 +1700,7 @@ reg_to_fpregset (struct gdbserv *serv, int regno, FPREGSET_T *fpregset) { - char tmp_buf[MAX_REG_SIZE]; char *regbytes; - int len; if (regno < 0 || regno >= NUM_REGS || reginfo[regno].whichregs != FPREGS) @@ -1624,13 +1710,7 @@ reg_to_fpregset (struct gdbserv *serv, regbytes = ((char *) fpregset) + reginfo[regno].offset; - memset (tmp_buf, 0, reginfo[regno].ptrace_size); - gdbserv_host_bytes_from_reg (serv, tmp_buf, &len, reg); - - if (len != reginfo[regno].proto_size) - return -1; - - memcpy (regbytes, tmp_buf, reginfo[regno].ptrace_size); + gdbserv_host_bytes_from_reg (serv, regbytes, reginfo[regno].ptrace_size, reg); return 0; } @@ -1645,7 +1725,6 @@ reg_from_xregset (struct gdbserv *serv, int regno, const void *xregset) { - char tmp_buf[MAX_REG_SIZE]; char *regbytes; if (regno < 0 || regno >= NUM_REGS @@ -1656,10 +1735,8 @@ reg_from_xregset (struct gdbserv *serv, regbytes = ((char *) xregset) + reginfo[regno].offset; - memset (tmp_buf, 0, reginfo[regno].proto_size); - memcpy (tmp_buf, regbytes, reginfo[regno].ptrace_size); - - gdbserv_host_bytes_to_reg (serv, tmp_buf, reginfo[regno].proto_size, reg); + gdbserv_host_bytes_to_reg (serv, tmp_buf, reginfo[regno].ptrace_size, + reg, reginfo[regno].proto_size); return 0; } @@ -1674,9 +1751,7 @@ reg_to_xregset (struct gdbserv *serv, int regno, void *xregset) { - char tmp_buf[MAX_REG_SIZE]; char *regbytes; - int len; if (regno < 0 || regno >= NUM_REGS || reginfo[regno].whichregs != FPXREGS) @@ -1686,13 +1761,7 @@ reg_to_xregset (struct gdbserv *serv, regbytes = ((char *) xregset) + reginfo[regno].offset; - memset (tmp_buf, 0, reginfo[regno].ptrace_size); - gdbserv_host_bytes_from_reg (serv, tmp_buf, &len, reg); - - if (len != reginfo[regno].proto_size) - return -1; - - memcpy (regbytes, tmp_buf, reginfo[regno].ptrace_size); + gdbserv_host_bytes_from_reg (serv, regbytes, reginfo[regno].ptrace_size, reg); return 0; }