X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Ffindvar.c;h=8f1960890fd8a0c12e04a1b0b7ffae456419ca5b;hb=e8475ad46302c0439093e9e25d631e56331f20e4;hp=c743d80976de5307a0fec409f0e0d7fe9614d7db;hpb=ade40d3153e344521d48bddf744bc2b8a1792d06;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/findvar.c b/gdb/findvar.c index c743d80976..8f1960890f 100644 --- a/gdb/findvar.c +++ b/gdb/findvar.c @@ -1,21 +1,23 @@ /* Find a variable's value in memory, for GDB, the GNU debugger. - Copyright 1986, 1987, 1989, 1991 Free Software Foundation, Inc. + Copyright 1986, 87, 89, 91, 94, 95, 96, 1998 + Free Software Foundation, Inc. -This file is part of GDB. + 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 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. + 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ + 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ #include "defs.h" #include "symtab.h" @@ -25,6 +27,27 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "gdbcore.h" #include "inferior.h" #include "target.h" +#include "gdb_string.h" +#include "floatformat.h" +#include "symfile.h" /* for overlay functions */ + +/* This is used to indicate that we don't know the format of the floating point + number. Typically, this is useful for native ports, where the actual format + is irrelevant, since no conversions will be taking place. */ + +const struct floatformat floatformat_unknown; + +/* Registers we shouldn't try to store. */ +#if !defined (CANNOT_STORE_REGISTER) +#define CANNOT_STORE_REGISTER(regno) 0 +#endif + +void write_register_gen PARAMS ((int, char *)); + +static int +read_relative_register_raw_bytes_for_frame PARAMS ((int regnum, + char *myaddr, + struct frame_info *frame)); /* Basic byte-swapping routines. GDB has needed these for a long time... All extract a target-format integer at ADDR which is LEN bytes long. */ @@ -34,141 +57,341 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ assume it throughout all these swapping routines. If we had to deal with 9 bit characters, we would need to make len be in bits and would have to re-write these routines... */ - you lose +you lose #endif LONGEST -extract_signed_integer (addr, len) - PTR addr; - int len; +extract_signed_integer (void *addr, int len) { LONGEST retval; unsigned char *p; - unsigned char *startaddr = (unsigned char *)addr; + unsigned char *startaddr = (unsigned char *) addr; unsigned char *endaddr = startaddr + len; - if (len > sizeof (LONGEST)) + if (len > (int) sizeof (LONGEST)) error ("\ That operation is not available on integers of more than %d bytes.", sizeof (LONGEST)); /* Start at the most significant end of the integer, and work towards the least significant. */ -#if TARGET_BYTE_ORDER == BIG_ENDIAN - p = startaddr; -#else - p = endaddr - 1; -#endif - /* Do the sign extension once at the start. */ - retval = (*p ^ 0x80) - 0x80; -#if TARGET_BYTE_ORDER == BIG_ENDIAN - for (++p; p < endaddr; ++p) -#else - for (--p; p >= startaddr; --p) -#endif + if (TARGET_BYTE_ORDER == BIG_ENDIAN) + { + p = startaddr; + /* Do the sign extension once at the start. */ + retval = ((LONGEST) * p ^ 0x80) - 0x80; + for (++p; p < endaddr; ++p) + retval = (retval << 8) | *p; + } + else { - retval = (retval << 8) | *p; + p = endaddr - 1; + /* Do the sign extension once at the start. */ + retval = ((LONGEST) * p ^ 0x80) - 0x80; + for (--p; p >= startaddr; --p) + retval = (retval << 8) | *p; } return retval; } -unsigned LONGEST -extract_unsigned_integer (addr, len) - PTR addr; - int len; +ULONGEST +extract_unsigned_integer (void *addr, int len) { - unsigned LONGEST retval; + ULONGEST retval; unsigned char *p; - unsigned char *startaddr = (unsigned char *)addr; + unsigned char *startaddr = (unsigned char *) addr; unsigned char *endaddr = startaddr + len; - if (len > sizeof (unsigned LONGEST)) + if (len > (int) sizeof (ULONGEST)) error ("\ That operation is not available on integers of more than %d bytes.", - sizeof (unsigned LONGEST)); + sizeof (ULONGEST)); /* Start at the most significant end of the integer, and work towards the least significant. */ retval = 0; -#if TARGET_BYTE_ORDER == BIG_ENDIAN - for (p = startaddr; p < endaddr; ++p) -#else - for (p = endaddr - 1; p >= startaddr; --p) -#endif + if (TARGET_BYTE_ORDER == BIG_ENDIAN) + { + for (p = startaddr; p < endaddr; ++p) + retval = (retval << 8) | *p; + } + else { - retval = (retval << 8) | *p; + for (p = endaddr - 1; p >= startaddr; --p) + retval = (retval << 8) | *p; } return retval; } +/* Sometimes a long long unsigned integer can be extracted as a + LONGEST value. This is done so that we can print these values + better. If this integer can be converted to a LONGEST, this + function returns 1 and sets *PVAL. Otherwise it returns 0. */ + +int +extract_long_unsigned_integer (void *addr, int orig_len, LONGEST *pval) +{ + char *p, *first_addr; + int len; + + len = orig_len; + if (TARGET_BYTE_ORDER == BIG_ENDIAN) + { + for (p = (char *) addr; + len > (int) sizeof (LONGEST) && p < (char *) addr + orig_len; + p++) + { + if (*p == 0) + len--; + else + break; + } + first_addr = p; + } + else + { + first_addr = (char *) addr; + for (p = (char *) addr + orig_len - 1; + len > (int) sizeof (LONGEST) && p >= (char *) addr; + p--) + { + if (*p == 0) + len--; + else + break; + } + } + + if (len <= (int) sizeof (LONGEST)) + { + *pval = (LONGEST) extract_unsigned_integer (first_addr, + sizeof (LONGEST)); + return 1; + } + + return 0; +} + + +/* Treat the LEN bytes at ADDR as a target-format address, and return + that address. ADDR is a buffer in the GDB process, not in the + inferior. + + This function should only be used by target-specific code. It + assumes that a pointer has the same representation as that thing's + address represented as an integer. Some machines use word + addresses, or similarly munged things, for certain types of + pointers, so that assumption doesn't hold everywhere. + + Common code should use extract_typed_address instead, or something + else based on POINTER_TO_ADDRESS. */ + CORE_ADDR -extract_address (addr, len) - PTR addr; - int len; +extract_address (void *addr, int len) { /* Assume a CORE_ADDR can fit in a LONGEST (for now). Not sure whether we want this to be true eventually. */ - return extract_unsigned_integer (addr, len); + return (CORE_ADDR) extract_unsigned_integer (addr, len); +} + + +/* Treat the bytes at BUF as a pointer of type TYPE, and return the + address it represents. */ +CORE_ADDR +extract_typed_address (void *buf, struct type *type) +{ + if (TYPE_CODE (type) != TYPE_CODE_PTR + && TYPE_CODE (type) != TYPE_CODE_REF) + internal_error ("findvar.c (extract_typed_address): " + "type is not a pointer or reference"); + + return POINTER_TO_ADDRESS (type, buf); } + void -store_signed_integer (addr, len, val) - PTR addr; - int len; - LONGEST val; +store_signed_integer (void *addr, int len, LONGEST val) { unsigned char *p; - unsigned char *startaddr = (unsigned char *)addr; + unsigned char *startaddr = (unsigned char *) addr; unsigned char *endaddr = startaddr + len; /* Start at the least significant end of the integer, and work towards the most significant. */ -#if TARGET_BYTE_ORDER == BIG_ENDIAN - for (p = endaddr - 1; p >= startaddr; --p) -#else - for (p = startaddr; p < endaddr; ++p) -#endif + if (TARGET_BYTE_ORDER == BIG_ENDIAN) { - *p = val & 0xff; - val >>= 8; + for (p = endaddr - 1; p >= startaddr; --p) + { + *p = val & 0xff; + val >>= 8; + } + } + else + { + for (p = startaddr; p < endaddr; ++p) + { + *p = val & 0xff; + val >>= 8; + } } } void -store_unsigned_integer (addr, len, val) - PTR addr; - int len; - unsigned LONGEST val; +store_unsigned_integer (void *addr, int len, ULONGEST val) { unsigned char *p; - unsigned char *startaddr = (unsigned char *)addr; + unsigned char *startaddr = (unsigned char *) addr; unsigned char *endaddr = startaddr + len; /* Start at the least significant end of the integer, and work towards the most significant. */ -#if TARGET_BYTE_ORDER == BIG_ENDIAN - for (p = endaddr - 1; p >= startaddr; --p) -#else - for (p = startaddr; p < endaddr; ++p) -#endif + if (TARGET_BYTE_ORDER == BIG_ENDIAN) + { + for (p = endaddr - 1; p >= startaddr; --p) + { + *p = val & 0xff; + val >>= 8; + } + } + else { - *p = val & 0xff; - val >>= 8; + for (p = startaddr; p < endaddr; ++p) + { + *p = val & 0xff; + val >>= 8; + } } } +/* Store the address VAL as a LEN-byte value in target byte order at + ADDR. ADDR is a buffer in the GDB process, not in the inferior. + + This function should only be used by target-specific code. It + assumes that a pointer has the same representation as that thing's + address represented as an integer. Some machines use word + addresses, or similarly munged things, for certain types of + pointers, so that assumption doesn't hold everywhere. + + Common code should use store_typed_address instead, or something else + based on ADDRESS_TO_POINTER. */ void -store_address (addr, len, val) - PTR addr; - int len; - CORE_ADDR val; +store_address (void *addr, int len, LONGEST val) { - /* Assume a CORE_ADDR can fit in a LONGEST (for now). Not sure - whether we want this to be true eventually. */ - store_unsigned_integer (addr, len, (LONGEST)val); + store_unsigned_integer (addr, len, val); +} + + +/* Store the address ADDR as a pointer of type TYPE at BUF, in target + form. */ +void +store_typed_address (void *buf, struct type *type, CORE_ADDR addr) +{ + if (TYPE_CODE (type) != TYPE_CODE_PTR + && TYPE_CODE (type) != TYPE_CODE_REF) + internal_error ("findvar.c (store_typed_address): " + "type is not a pointer or reference"); + + ADDRESS_TO_POINTER (type, buf, addr); +} + + + + +/* Extract a floating-point number from a target-order byte-stream at ADDR. + Returns the value as type DOUBLEST. + + If the host and target formats agree, we just copy the raw data into the + appropriate type of variable and return, letting the host increase precision + as necessary. Otherwise, we call the conversion routine and let it do the + dirty work. */ + +DOUBLEST +extract_floating (void *addr, int len) +{ + DOUBLEST dretval; + + if (len * TARGET_CHAR_BIT == TARGET_FLOAT_BIT) + { + if (HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT) + { + float retval; + + memcpy (&retval, addr, sizeof (retval)); + return retval; + } + else + floatformat_to_doublest (TARGET_FLOAT_FORMAT, addr, &dretval); + } + else if (len * TARGET_CHAR_BIT == TARGET_DOUBLE_BIT) + { + if (HOST_DOUBLE_FORMAT == TARGET_DOUBLE_FORMAT) + { + double retval; + + memcpy (&retval, addr, sizeof (retval)); + return retval; + } + else + floatformat_to_doublest (TARGET_DOUBLE_FORMAT, addr, &dretval); + } + else if (len * TARGET_CHAR_BIT == TARGET_LONG_DOUBLE_BIT) + { + if (HOST_LONG_DOUBLE_FORMAT == TARGET_LONG_DOUBLE_FORMAT) + { + DOUBLEST retval; + + memcpy (&retval, addr, sizeof (retval)); + return retval; + } + else + floatformat_to_doublest (TARGET_LONG_DOUBLE_FORMAT, addr, &dretval); + } + else + { + error ("Can't deal with a floating point number of %d bytes.", len); + } + + return dretval; +} + +void +store_floating (void *addr, int len, DOUBLEST val) +{ + if (len * TARGET_CHAR_BIT == TARGET_FLOAT_BIT) + { + if (HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT) + { + float floatval = val; + + memcpy (addr, &floatval, sizeof (floatval)); + } + else + floatformat_from_doublest (TARGET_FLOAT_FORMAT, &val, addr); + } + else if (len * TARGET_CHAR_BIT == TARGET_DOUBLE_BIT) + { + if (HOST_DOUBLE_FORMAT == TARGET_DOUBLE_FORMAT) + { + double doubleval = val; + + memcpy (addr, &doubleval, sizeof (doubleval)); + } + else + floatformat_from_doublest (TARGET_DOUBLE_FORMAT, &val, addr); + } + else if (len * TARGET_CHAR_BIT == TARGET_LONG_DOUBLE_BIT) + { + if (HOST_LONG_DOUBLE_FORMAT == TARGET_LONG_DOUBLE_FORMAT) + memcpy (addr, &val, sizeof (val)); + else + floatformat_from_doublest (TARGET_LONG_DOUBLE_FORMAT, &val, addr); + } + else + { + error ("Can't deal with a floating point number of %d bytes.", len); + } } -#if !defined (GET_SAVED_REGISTER) /* Return the address in which frame FRAME's value of register REGNUM has been saved in memory. Or return zero if it has not been saved. @@ -177,16 +400,13 @@ store_address (addr, len, val) CORE_ADDR find_saved_register (frame, regnum) - FRAME frame; + struct frame_info *frame; int regnum; { - struct frame_info *fi; - struct frame_saved_regs saved_regs; - - register FRAME frame1 = 0; + register struct frame_info *frame1 = NULL; register CORE_ADDR addr = 0; - if (frame == 0) /* No regs saved if want current frame */ + if (frame == NULL) /* No regs saved if want current frame */ return 0; #ifdef HAVE_REGISTER_WINDOWS @@ -205,22 +425,20 @@ find_saved_register (frame, regnum) callers to this routine asking for the stack pointer want the stack pointer saved for *this* frame; this is returned from the next frame. */ - - if (REGISTER_IN_WINDOW_P(regnum)) + if (REGISTER_IN_WINDOW_P (regnum)) { frame1 = get_next_frame (frame); - if (!frame1) return 0; /* Registers of this frame are - active. */ - + if (!frame1) + return 0; /* Registers of this frame are active. */ + /* Get the SP from the next frame in; it will be this - current frame. */ + current frame. */ if (regnum != SP_REGNUM) - frame1 = frame; - - fi = get_frame_info (frame1); - get_frame_saved_regs (fi, &saved_regs); - return saved_regs.regs[regnum]; /* ... which might be zero */ + frame1 = frame; + + FRAME_INIT_SAVED_REGS (frame1); + return frame1->saved_regs[regnum]; /* ... which might be zero */ } #endif /* HAVE_REGISTER_WINDOWS */ @@ -234,10 +452,9 @@ find_saved_register (frame, regnum) frame1 = get_prev_frame (frame1); if (frame1 == 0 || frame1 == frame) break; - fi = get_frame_info (frame1); - get_frame_saved_regs (fi, &saved_regs); - if (saved_regs.regs[regnum]) - addr = saved_regs.regs[regnum]; + FRAME_INIT_SAVED_REGS (frame1); + if (frame1->saved_regs[regnum]) + addr = frame1->saved_regs[regnum]; } return addr; @@ -259,15 +476,19 @@ find_saved_register (frame, regnum) The argument RAW_BUFFER must point to aligned memory. */ void -get_saved_register (raw_buffer, optimized, addrp, frame, regnum, lval) +default_get_saved_register (raw_buffer, optimized, addrp, frame, regnum, lval) char *raw_buffer; int *optimized; CORE_ADDR *addrp; - FRAME frame; + struct frame_info *frame; int regnum; enum lval_type *lval; { CORE_ADDR addr; + + if (!target_has_registers) + error ("No registers."); + /* Normal systems don't optimize out things with register numbers. */ if (optimized != NULL) *optimized = 0; @@ -281,7 +502,8 @@ get_saved_register (raw_buffer, optimized, addrp, frame, regnum, lval) if (raw_buffer != NULL) { /* Put it back in target format. */ - store_address (raw_buffer, REGISTER_RAW_SIZE (regnum), addr); + store_address (raw_buffer, REGISTER_RAW_SIZE (regnum), + (LONGEST) addr); } if (addrp != NULL) *addrp = 0; @@ -301,60 +523,115 @@ get_saved_register (raw_buffer, optimized, addrp, frame, regnum, lval) if (addrp != NULL) *addrp = addr; } -#endif /* GET_SAVED_REGISTER. */ -/* Copy the bytes of register REGNUM, relative to the current stack frame, +#if !defined (GET_SAVED_REGISTER) +#define GET_SAVED_REGISTER(raw_buffer, optimized, addrp, frame, regnum, lval) \ + default_get_saved_register(raw_buffer, optimized, addrp, frame, regnum, lval) +#endif +void +get_saved_register (raw_buffer, optimized, addrp, frame, regnum, lval) + char *raw_buffer; + int *optimized; + CORE_ADDR *addrp; + struct frame_info *frame; + int regnum; + enum lval_type *lval; +{ + GET_SAVED_REGISTER (raw_buffer, optimized, addrp, frame, regnum, lval); +} + +/* Copy the bytes of register REGNUM, relative to the input stack frame, into our memory at MYADDR, in target byte order. The number of bytes copied is REGISTER_RAW_SIZE (REGNUM). Returns 1 if could not be read, 0 if could. */ -int -read_relative_register_raw_bytes (regnum, myaddr) +static int +read_relative_register_raw_bytes_for_frame (regnum, myaddr, frame) int regnum; char *myaddr; + struct frame_info *frame; { int optim; - if (regnum == FP_REGNUM && selected_frame) + if (regnum == FP_REGNUM && frame) { - /* Put it back in target format. */ - store_address (myaddr, REGISTER_RAW_SIZE(FP_REGNUM), - FRAME_FP(selected_frame)); + /* Put it back in target format. */ + store_address (myaddr, REGISTER_RAW_SIZE (FP_REGNUM), + (LONGEST) FRAME_FP (frame)); + return 0; } - get_saved_register (myaddr, &optim, (CORE_ADDR *) NULL, selected_frame, - regnum, (enum lval_type *)NULL); + get_saved_register (myaddr, &optim, (CORE_ADDR *) NULL, frame, + regnum, (enum lval_type *) NULL); + + if (register_valid[regnum] < 0) + return 1; /* register value not available */ + return optim; } +/* Copy the bytes of register REGNUM, relative to the current stack frame, + into our memory at MYADDR, in target byte order. + The number of bytes copied is REGISTER_RAW_SIZE (REGNUM). + + Returns 1 if could not be read, 0 if could. */ + +int +read_relative_register_raw_bytes (regnum, myaddr) + int regnum; + char *myaddr; +{ + return read_relative_register_raw_bytes_for_frame (regnum, myaddr, + selected_frame); +} + /* Return a `value' with the contents of register REGNUM in its virtual format, with the type specified by - REGISTER_VIRTUAL_TYPE. */ + REGISTER_VIRTUAL_TYPE. -value + NOTE: returns NULL if register value is not available. + Caller will check return value or die! */ + +value_ptr value_of_register (regnum) int regnum; { CORE_ADDR addr; int optim; - register value val; + register value_ptr reg_val; char raw_buffer[MAX_REGISTER_RAW_SIZE]; - char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE]; enum lval_type lval; get_saved_register (raw_buffer, &optim, &addr, selected_frame, regnum, &lval); - REGISTER_CONVERT_TO_VIRTUAL (regnum, raw_buffer, virtual_buffer); - val = allocate_value (REGISTER_VIRTUAL_TYPE (regnum)); - memcpy (VALUE_CONTENTS_RAW (val), virtual_buffer, - REGISTER_VIRTUAL_SIZE (regnum)); - VALUE_LVAL (val) = lval; - VALUE_ADDRESS (val) = addr; - VALUE_REGNO (val) = regnum; - VALUE_OPTIMIZED_OUT (val) = optim; - return val; + if (register_valid[regnum] < 0) + return NULL; /* register value not available */ + + reg_val = allocate_value (REGISTER_VIRTUAL_TYPE (regnum)); + + /* Convert raw data to virtual format if necessary. */ + + if (REGISTER_CONVERTIBLE (regnum)) + { + REGISTER_CONVERT_TO_VIRTUAL (regnum, REGISTER_VIRTUAL_TYPE (regnum), + raw_buffer, VALUE_CONTENTS_RAW (reg_val)); + } + else if (REGISTER_RAW_SIZE (regnum) == REGISTER_VIRTUAL_SIZE (regnum)) + memcpy (VALUE_CONTENTS_RAW (reg_val), raw_buffer, + REGISTER_RAW_SIZE (regnum)); + else + internal_error ("Register \"%s\" (%d) has conflicting raw (%d) and virtual (%d) size", + REGISTER_NAME (regnum), + regnum, + REGISTER_RAW_SIZE (regnum), + REGISTER_VIRTUAL_SIZE (regnum)); + VALUE_LVAL (reg_val) = lval; + VALUE_ADDRESS (reg_val) = addr; + VALUE_REGNO (reg_val) = regnum; + VALUE_OPTIMIZED_OUT (reg_val) = optim; + return reg_val; } /* Low level examining and depositing of registers. @@ -364,21 +641,41 @@ value_of_register (regnum) or it will get garbage. (a change from GDB version 3, in which the caller got the value from the last stop). */ -/* Contents of the registers in target byte order. - We allocate some extra slop since we do a lot of memcpy's around `registers', - and failing-soft is better than failing hard. */ -char registers[REGISTER_BYTES + /* SLOP */ 256]; +/* Contents and state of the registers (in target byte order). */ + +char *registers; + +/* VALID_REGISTER is non-zero if it has been fetched, -1 if the + register value was not available. */ -/* Nonzero if that register has been fetched. */ -char register_valid[NUM_REGS]; +signed char *register_valid; + +/* The thread/process associated with the current set of registers. For now, + -1 is special, and means `no current process'. */ +int registers_pid = -1; /* Indicate that registers may have changed, so invalidate the cache. */ + void registers_changed () { int i; - for (i = 0; i < NUM_REGS; i++) + int numregs = ARCH_NUM_REGS; + + registers_pid = -1; + + /* Force cleanup of any alloca areas if using C alloca instead of + a builtin alloca. This particular call is used to clean up + areas allocated by low level target code which may build up + during lengthy interactions between gdb and the target before + gdb gives control to the user (ie watchpoints). */ + alloca (0); + + for (i = 0; i < numregs; i++) register_valid[i] = 0; + + if (registers_changed_hook) + registers_changed_hook (); } /* Indicate that all registers have been fetched, so mark them all valid. */ @@ -386,30 +683,77 @@ void registers_fetched () { int i; - for (i = 0; i < NUM_REGS; i++) + int numregs = ARCH_NUM_REGS; + for (i = 0; i < numregs; i++) register_valid[i] = 1; } -/* Copy LEN bytes of consecutive data from registers - starting with the REGBYTE'th byte of register data +/* read_register_bytes and write_register_bytes are generally a *BAD* + idea. They are inefficient because they need to check for partial + updates, which can only be done by scanning through all of the + registers and seeing if the bytes that are being read/written fall + inside of an invalid register. [The main reason this is necessary + is that register sizes can vary, so a simple index won't suffice.] + It is far better to call read_register_gen and write_register_gen + if you want to get at the raw register contents, as it only takes a + regno as an argument, and therefore can't do a partial register + update. + + Prior to the recent fixes to check for partial updates, both read + and write_register_bytes always checked to see if any registers + were stale, and then called target_fetch_registers (-1) to update + the whole set. This caused really slowed things down for remote + targets. */ + +/* Copy INLEN bytes of consecutive data from registers + starting with the INREGBYTE'th byte of register data into memory at MYADDR. */ void -read_register_bytes (regbyte, myaddr, len) - int regbyte; +read_register_bytes (inregbyte, myaddr, inlen) + int inregbyte; char *myaddr; - int len; + int inlen; { - /* Fetch all registers. */ - int i; - for (i = 0; i < NUM_REGS; i++) - if (!register_valid[i]) - { - target_fetch_registers (-1); - break; - } + int inregend = inregbyte + inlen; + int regno; + + if (registers_pid != inferior_pid) + { + registers_changed (); + registers_pid = inferior_pid; + } + + /* See if we are trying to read bytes from out-of-date registers. If so, + update just those registers. */ + + for (regno = 0; regno < NUM_REGS; regno++) + { + int regstart, regend; + + if (register_valid[regno]) + continue; + + if (REGISTER_NAME (regno) == NULL || *REGISTER_NAME (regno) == '\0') + continue; + + regstart = REGISTER_BYTE (regno); + regend = regstart + REGISTER_RAW_SIZE (regno); + + if (regend <= inregbyte || inregend <= regstart) + /* The range the user wants to read doesn't overlap with regno. */ + continue; + + /* We've found an invalid register where at least one byte will be read. + Update it from the target. */ + target_fetch_registers (regno); + + if (!register_valid[regno]) + error ("read_register_bytes: Couldn't update register %d.", regno); + } + if (myaddr != NULL) - memcpy (myaddr, ®isters[regbyte], len); + memcpy (myaddr, ®isters[inregbyte], inlen); } /* Read register REGNO into memory at MYADDR, which must be large enough @@ -421,27 +765,114 @@ read_register_gen (regno, myaddr) int regno; char *myaddr; { + if (registers_pid != inferior_pid) + { + registers_changed (); + registers_pid = inferior_pid; + } + if (!register_valid[regno]) target_fetch_registers (regno); memcpy (myaddr, ®isters[REGISTER_BYTE (regno)], REGISTER_RAW_SIZE (regno)); } -/* Copy LEN bytes of consecutive data from memory at MYADDR - into registers starting with the REGBYTE'th byte of register data. */ +/* Write register REGNO at MYADDR to the target. MYADDR points at + REGISTER_RAW_BYTES(REGNO), which must be in target byte-order. */ + +void +write_register_gen (regno, myaddr) + int regno; + char *myaddr; +{ + int size; + + /* On the sparc, writing %g0 is a no-op, so we don't even want to change + the registers array if something writes to this register. */ + if (CANNOT_STORE_REGISTER (regno)) + return; + + if (registers_pid != inferior_pid) + { + registers_changed (); + registers_pid = inferior_pid; + } + + size = REGISTER_RAW_SIZE (regno); + + /* If we have a valid copy of the register, and new value == old value, + then don't bother doing the actual store. */ + + if (register_valid[regno] + && memcmp (®isters[REGISTER_BYTE (regno)], myaddr, size) == 0) + return; + + target_prepare_to_store (); + + memcpy (®isters[REGISTER_BYTE (regno)], myaddr, size); + + register_valid[regno] = 1; + + target_store_registers (regno); +} + +/* Copy INLEN bytes of consecutive data from memory at MYADDR + into registers starting with the MYREGSTART'th byte of register data. */ void -write_register_bytes (regbyte, myaddr, len) - int regbyte; +write_register_bytes (myregstart, myaddr, inlen) + int myregstart; char *myaddr; - int len; + int inlen; { - /* Make sure the entire registers array is valid. */ - read_register_bytes (0, (char *)NULL, REGISTER_BYTES); - memcpy (®isters[regbyte], myaddr, len); - target_store_registers (-1); + int myregend = myregstart + inlen; + int regno; + + target_prepare_to_store (); + + /* Scan through the registers updating any that are covered by the range + myregstart<=>myregend using write_register_gen, which does nice things + like handling threads, and avoiding updates when the new and old contents + are the same. */ + + for (regno = 0; regno < NUM_REGS; regno++) + { + int regstart, regend; + + regstart = REGISTER_BYTE (regno); + regend = regstart + REGISTER_RAW_SIZE (regno); + + /* Is this register completely outside the range the user is writing? */ + if (myregend <= regstart || regend <= myregstart) + /* do nothing */ ; + + /* Is this register completely within the range the user is writing? */ + else if (myregstart <= regstart && regend <= myregend) + write_register_gen (regno, myaddr + (regstart - myregstart)); + + /* The register partially overlaps the range being written. */ + else + { + char regbuf[MAX_REGISTER_RAW_SIZE]; + /* What's the overlap between this register's bytes and + those the caller wants to write? */ + int overlapstart = max (regstart, myregstart); + int overlapend = min (regend, myregend); + + /* We may be doing a partial update of an invalid register. + Update it from the target before scribbling on it. */ + read_register_gen (regno, regbuf); + + memcpy (registers + overlapstart, + myaddr + (overlapstart - myregstart), + overlapend - overlapstart); + + target_store_registers (regno); + } + } } + /* Return the raw contents of register REGNO, regarding it as an integer. */ /* This probably should be returning LONGEST rather than CORE_ADDR. */ @@ -449,24 +880,48 @@ CORE_ADDR read_register (regno) int regno; { + if (registers_pid != inferior_pid) + { + registers_changed (); + registers_pid = inferior_pid; + } + if (!register_valid[regno]) target_fetch_registers (regno); - return extract_address (®isters[REGISTER_BYTE (regno)], - REGISTER_RAW_SIZE(regno)); + return ((CORE_ADDR) + extract_unsigned_integer (®isters[REGISTER_BYTE (regno)], + REGISTER_RAW_SIZE (regno))); } -/* Registers we shouldn't try to store. */ -#if !defined (CANNOT_STORE_REGISTER) -#define CANNOT_STORE_REGISTER(regno) 0 -#endif +CORE_ADDR +read_register_pid (regno, pid) + int regno, pid; +{ + int save_pid; + CORE_ADDR retval; + + if (pid == inferior_pid) + return read_register (regno); + + save_pid = inferior_pid; + + inferior_pid = pid; + + retval = read_register (regno); + + inferior_pid = save_pid; + + return retval; +} -/* Store VALUE, into the raw contents of register number REGNO. */ -/* FIXME: The val arg should probably be a LONGEST. */ +/* Store VALUE, into the raw contents of register number REGNO. + This should probably write a LONGEST rather than a CORE_ADDR */ void write_register (regno, val) - int regno, val; + int regno; + LONGEST val; { PTR buf; int size; @@ -476,69 +931,367 @@ write_register (regno, val) if (CANNOT_STORE_REGISTER (regno)) return; - size = REGISTER_RAW_SIZE(regno); + if (registers_pid != inferior_pid) + { + registers_changed (); + registers_pid = inferior_pid; + } + + size = REGISTER_RAW_SIZE (regno); buf = alloca (size); store_signed_integer (buf, size, (LONGEST) val); /* If we have a valid copy of the register, and new value == old value, then don't bother doing the actual store. */ - if (register_valid [regno]) - { - if (memcmp (®isters[REGISTER_BYTE (regno)], buf, size) == 0) - return; - } - + if (register_valid[regno] + && memcmp (®isters[REGISTER_BYTE (regno)], buf, size) == 0) + return; + target_prepare_to_store (); memcpy (®isters[REGISTER_BYTE (regno)], buf, size); - register_valid [regno] = 1; + register_valid[regno] = 1; target_store_registers (regno); } +void +write_register_pid (regno, val, pid) + int regno; + CORE_ADDR val; + int pid; +{ + int save_pid; + + if (pid == inferior_pid) + { + write_register (regno, val); + return; + } + + save_pid = inferior_pid; + + inferior_pid = pid; + + write_register (regno, val); + + inferior_pid = save_pid; +} + /* Record that register REGNO contains VAL. This is used when the value is obtained from the inferior or core dump, - so there is no need to store the value there. */ + so there is no need to store the value there. + + If VAL is a NULL pointer, then it's probably an unsupported register. We + just set it's value to all zeros. We might want to record this fact, and + report it to the users of read_register and friends. + */ void supply_register (regno, val) int regno; char *val; { +#if 1 + if (registers_pid != inferior_pid) + { + registers_changed (); + registers_pid = inferior_pid; + } +#endif + register_valid[regno] = 1; - memcpy (®isters[REGISTER_BYTE (regno)], val, REGISTER_RAW_SIZE (regno)); + if (val) + memcpy (®isters[REGISTER_BYTE (regno)], val, REGISTER_RAW_SIZE (regno)); + else + memset (®isters[REGISTER_BYTE (regno)], '\000', REGISTER_RAW_SIZE (regno)); /* On some architectures, e.g. HPPA, there are a few stray bits in some registers, that the rest of the code would like to ignore. */ #ifdef CLEAN_UP_REGISTER_VALUE - CLEAN_UP_REGISTER_VALUE(regno, ®isters[REGISTER_BYTE(regno)]); + CLEAN_UP_REGISTER_VALUE (regno, ®isters[REGISTER_BYTE (regno)]); +#endif +} + + +/* This routine is getting awfully cluttered with #if's. It's probably + time to turn this into READ_PC and define it in the tm.h file. + Ditto for write_pc. + + 1999-06-08: The following were re-written so that it assumes the + existance of a TARGET_READ_PC et.al. macro. A default generic + version of that macro is made available where needed. + + Since the ``TARGET_READ_PC'' et.al. macro is going to be controlled + by the multi-arch framework, it will eventually be possible to + eliminate the intermediate read_pc_pid(). The client would call + TARGET_READ_PC directly. (cagney). */ + +#ifndef TARGET_READ_PC +#define TARGET_READ_PC generic_target_read_pc +#endif + +CORE_ADDR +generic_target_read_pc (int pid) +{ +#ifdef PC_REGNUM + if (PC_REGNUM >= 0) + { + CORE_ADDR pc_val = ADDR_BITS_REMOVE ((CORE_ADDR) read_register_pid (PC_REGNUM, pid)); + return pc_val; + } +#endif + internal_error ("generic_target_read_pc"); + return 0; +} + +CORE_ADDR +read_pc_pid (pid) + int pid; +{ + int saved_inferior_pid; + CORE_ADDR pc_val; + + /* In case pid != inferior_pid. */ + saved_inferior_pid = inferior_pid; + inferior_pid = pid; + + pc_val = TARGET_READ_PC (pid); + + inferior_pid = saved_inferior_pid; + return pc_val; +} + +CORE_ADDR +read_pc () +{ + return read_pc_pid (inferior_pid); +} + +#ifndef TARGET_WRITE_PC +#define TARGET_WRITE_PC generic_target_write_pc +#endif + +void +generic_target_write_pc (pc, pid) + CORE_ADDR pc; + int pid; +{ +#ifdef PC_REGNUM + if (PC_REGNUM >= 0) + write_register_pid (PC_REGNUM, pc, pid); + if (NPC_REGNUM >= 0) + write_register_pid (NPC_REGNUM, pc + 4, pid); + if (NNPC_REGNUM >= 0) + write_register_pid (NNPC_REGNUM, pc + 8, pid); +#else + internal_error ("generic_target_write_pc"); +#endif +} + +void +write_pc_pid (pc, pid) + CORE_ADDR pc; + int pid; +{ + int saved_inferior_pid; + + /* In case pid != inferior_pid. */ + saved_inferior_pid = inferior_pid; + inferior_pid = pid; + + TARGET_WRITE_PC (pc, pid); + + inferior_pid = saved_inferior_pid; +} + +void +write_pc (pc) + CORE_ADDR pc; +{ + write_pc_pid (pc, inferior_pid); +} + +/* Cope with strage ways of getting to the stack and frame pointers */ + +#ifndef TARGET_READ_SP +#define TARGET_READ_SP generic_target_read_sp +#endif + +CORE_ADDR +generic_target_read_sp () +{ +#ifdef SP_REGNUM + if (SP_REGNUM >= 0) + return read_register (SP_REGNUM); +#endif + internal_error ("generic_target_read_sp"); +} + +CORE_ADDR +read_sp () +{ + return TARGET_READ_SP (); +} + +#ifndef TARGET_WRITE_SP +#define TARGET_WRITE_SP generic_target_write_sp +#endif + +void +generic_target_write_sp (val) + CORE_ADDR val; +{ +#ifdef SP_REGNUM + if (SP_REGNUM >= 0) + { + write_register (SP_REGNUM, val); + return; + } +#endif + internal_error ("generic_target_write_sp"); +} + +void +write_sp (val) + CORE_ADDR val; +{ + TARGET_WRITE_SP (val); +} + +#ifndef TARGET_READ_FP +#define TARGET_READ_FP generic_target_read_fp +#endif + +CORE_ADDR +generic_target_read_fp () +{ +#ifdef FP_REGNUM + if (FP_REGNUM >= 0) + return read_register (FP_REGNUM); +#endif + internal_error ("generic_target_read_fp"); +} + +CORE_ADDR +read_fp () +{ + return TARGET_READ_FP (); +} + +#ifndef TARGET_WRITE_FP +#define TARGET_WRITE_FP generic_target_write_fp +#endif + +void +generic_target_write_fp (val) + CORE_ADDR val; +{ +#ifdef FP_REGNUM + if (FP_REGNUM >= 0) + { + write_register (FP_REGNUM, val); + return; + } #endif + internal_error ("generic_target_write_fp"); +} + +void +write_fp (val) + CORE_ADDR val; +{ + TARGET_WRITE_FP (val); +} + + +/* Given a pointer of type TYPE in target form in BUF, return the + address it represents. */ +CORE_ADDR +generic_pointer_to_address (struct type *type, char *buf) +{ + return extract_address (buf, TYPE_LENGTH (type)); +} + + +/* Given an address, store it as a pointer of type TYPE in target + format in BUF. */ +void +generic_address_to_pointer (struct type *type, char *buf, CORE_ADDR addr) +{ + store_address (buf, TYPE_LENGTH (type), addr); } + +/* Will calling read_var_value or locate_var_value on SYM end + up caring what frame it is being evaluated relative to? SYM must + be non-NULL. */ +int +symbol_read_needs_frame (sym) + struct symbol *sym; +{ + switch (SYMBOL_CLASS (sym)) + { + /* All cases listed explicitly so that gcc -Wall will detect it if + we failed to consider one. */ + case LOC_REGISTER: + case LOC_ARG: + case LOC_REF_ARG: + case LOC_REGPARM: + case LOC_REGPARM_ADDR: + case LOC_LOCAL: + case LOC_LOCAL_ARG: + case LOC_BASEREG: + case LOC_BASEREG_ARG: + case LOC_THREAD_LOCAL_STATIC: + return 1; + + case LOC_UNDEF: + case LOC_CONST: + case LOC_STATIC: + case LOC_INDIRECT: + case LOC_TYPEDEF: + + case LOC_LABEL: + /* Getting the address of a label can be done independently of the block, + even if some *uses* of that address wouldn't work so well without + the right frame. */ + + case LOC_BLOCK: + case LOC_CONST_BYTES: + case LOC_UNRESOLVED: + case LOC_OPTIMIZED_OUT: + return 0; + } + return 1; +} + /* Given a struct symbol for a variable, and a stack frame id, read the value of the variable and return a (pointer to a) struct value containing the value. If the variable cannot be found, return a zero pointer. If FRAME is NULL, use the selected_frame. */ -value +value_ptr read_var_value (var, frame) register struct symbol *var; - FRAME frame; + struct frame_info *frame; { - register value v; - struct frame_info *fi; + register value_ptr v; struct type *type = SYMBOL_TYPE (var); CORE_ADDR addr; register int len; v = allocate_value (type); VALUE_LVAL (v) = lval_memory; /* The most likely possibility. */ + VALUE_BFD_SECTION (v) = SYMBOL_BFD_SECTION (var); + len = TYPE_LENGTH (type); - if (frame == 0) frame = selected_frame; + if (frame == NULL) + frame = selected_frame; switch (SYMBOL_CLASS (var)) { @@ -551,7 +1304,16 @@ read_var_value (var, frame) case LOC_LABEL: /* Put the constant back in target format. */ - store_address (VALUE_CONTENTS_RAW (v), len, SYMBOL_VALUE_ADDRESS (var)); + if (overlay_debugging) + { + CORE_ADDR addr + = symbol_overlayed_address (SYMBOL_VALUE_ADDRESS (var), + SYMBOL_BFD_SECTION (var)); + store_typed_address (VALUE_CONTENTS_RAW (v), type, addr); + } + else + store_typed_address (VALUE_CONTENTS_RAW (v), type, + SYMBOL_VALUE_ADDRESS (var)); VALUE_LVAL (v) = not_lval; return v; @@ -565,30 +1327,42 @@ read_var_value (var, frame) } case LOC_STATIC: + if (overlay_debugging) + addr = symbol_overlayed_address (SYMBOL_VALUE_ADDRESS (var), + SYMBOL_BFD_SECTION (var)); + else + addr = SYMBOL_VALUE_ADDRESS (var); + break; + + case LOC_INDIRECT: + /* The import slot does not have a real address in it from the + dynamic loader (dld.sl on HP-UX), if the target hasn't begun + execution yet, so check for that. */ + if (!target_has_execution) + error ("\ +Attempt to access variable defined in different shared object or load module when\n\ +addresses have not been bound by the dynamic loader. Try again when executable is running."); + addr = SYMBOL_VALUE_ADDRESS (var); + addr = read_memory_unsigned_integer + (addr, TARGET_PTR_BIT / TARGET_CHAR_BIT); break; case LOC_ARG: - fi = get_frame_info (frame); - if (fi == NULL) + if (frame == NULL) return 0; - addr = FRAME_ARGS_ADDRESS (fi); + addr = FRAME_ARGS_ADDRESS (frame); if (!addr) - { - return 0; - } + return 0; addr += SYMBOL_VALUE (var); break; case LOC_REF_ARG: - fi = get_frame_info (frame); - if (fi == NULL) + if (frame == NULL) return 0; - addr = FRAME_ARGS_ADDRESS (fi); + addr = FRAME_ARGS_ADDRESS (frame); if (!addr) - { - return 0; - } + return 0; addr += SYMBOL_VALUE (var); addr = read_memory_unsigned_integer (addr, TARGET_PTR_BIT / TARGET_CHAR_BIT); @@ -596,10 +1370,9 @@ read_var_value (var, frame) case LOC_LOCAL: case LOC_LOCAL_ARG: - fi = get_frame_info (frame); - if (fi == NULL) + if (frame == NULL) return 0; - addr = FRAME_LOCALS_ADDRESS (fi); + addr = FRAME_LOCALS_ADDRESS (frame); addr += SYMBOL_VALUE (var); break; @@ -613,13 +1386,28 @@ read_var_value (var, frame) addr += SYMBOL_VALUE (var); break; } - + + case LOC_THREAD_LOCAL_STATIC: + { + char buf[MAX_REGISTER_RAW_SIZE]; + + get_saved_register (buf, NULL, NULL, frame, SYMBOL_BASEREG (var), + NULL); + addr = extract_address (buf, REGISTER_RAW_SIZE (SYMBOL_BASEREG (var))); + addr += SYMBOL_VALUE (var); + break; + } + case LOC_TYPEDEF: error ("Cannot look up value of a typedef"); break; case LOC_BLOCK: - VALUE_ADDRESS (v) = BLOCK_START (SYMBOL_BLOCK_VALUE (var)); + if (overlay_debugging) + VALUE_ADDRESS (v) = symbol_overlayed_address + (BLOCK_START (SYMBOL_BLOCK_VALUE (var)), SYMBOL_BFD_SECTION (var)); + else + VALUE_ADDRESS (v) = BLOCK_START (SYMBOL_BLOCK_VALUE (var)); return v; case LOC_REGISTER: @@ -627,20 +1415,48 @@ read_var_value (var, frame) case LOC_REGPARM_ADDR: { struct block *b; + int regno = SYMBOL_VALUE (var); + value_ptr regval; if (frame == NULL) return 0; b = get_frame_block (frame); - - v = value_from_register (type, SYMBOL_VALUE (var), frame); if (SYMBOL_CLASS (var) == LOC_REGPARM_ADDR) { - addr = *(CORE_ADDR *)VALUE_CONTENTS (v); + regval = value_from_register (lookup_pointer_type (type), + regno, + frame); + + if (regval == NULL) + error ("Value of register variable not available."); + + addr = value_as_pointer (regval); VALUE_LVAL (v) = lval_memory; } else - return v; + { + regval = value_from_register (type, regno, frame); + + if (regval == NULL) + error ("Value of register variable not available."); + return regval; + } + } + break; + + case LOC_UNRESOLVED: + { + struct minimal_symbol *msym; + + msym = lookup_minimal_symbol (SYMBOL_NAME (var), NULL, NULL); + if (msym == NULL) + return 0; + if (overlay_debugging) + addr = symbol_overlayed_address (SYMBOL_VALUE_ADDRESS (msym), + SYMBOL_BFD_SECTION (msym)); + else + addr = SYMBOL_VALUE_ADDRESS (msym); } break; @@ -660,24 +1476,33 @@ read_var_value (var, frame) } /* Return a value of type TYPE, stored in register REGNUM, in frame - FRAME. */ + FRAME. -value + NOTE: returns NULL if register value is not available. + Caller will check return value or die! */ + +value_ptr value_from_register (type, regnum, frame) struct type *type; int regnum; - FRAME frame; + struct frame_info *frame; { - char raw_buffer [MAX_REGISTER_RAW_SIZE]; - char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE]; + char raw_buffer[MAX_REGISTER_RAW_SIZE]; CORE_ADDR addr; int optim; - value v = allocate_value (type); - int len = TYPE_LENGTH (type); + value_ptr v = allocate_value (type); char *value_bytes = 0; int value_bytes_copied = 0; int num_storage_locs; enum lval_type lval; + int len; + + CHECK_TYPEDEF (type); + len = TYPE_LENGTH (type); + + /* Pointers on D10V are really only 16 bits, but we lie to gdb elsewhere... */ + if (GDB_TARGET_IS_D10V && TYPE_CODE (type) == TYPE_CODE_PTR) + len = 2; VALUE_REGNO (v) = regnum; @@ -689,15 +1514,15 @@ value_from_register (type, regnum, frame) #ifdef GDB_TARGET_IS_H8500 || TYPE_CODE (type) == TYPE_CODE_PTR #endif - ) + ) { /* Value spread across multiple storage locations. */ - + int local_regnum; int mem_stor = 0, reg_stor = 0; int mem_tracking = 1; CORE_ADDR last_addr = 0; - CORE_ADDR first_addr; + CORE_ADDR first_addr = 0; value_bytes = (char *) alloca (len + MAX_REGISTER_RAW_SIZE); @@ -718,13 +1543,18 @@ value_from_register (type, regnum, frame) switch (regnum) { - case R0_REGNUM: case R1_REGNUM: case R2_REGNUM: case R3_REGNUM: + case R0_REGNUM: + case R1_REGNUM: + case R2_REGNUM: + case R3_REGNUM: page_regnum = SEG_D_REGNUM; break; - case R4_REGNUM: case R5_REGNUM: + case R4_REGNUM: + case R5_REGNUM: page_regnum = SEG_E_REGNUM; break; - case R6_REGNUM: case R7_REGNUM: + case R6_REGNUM: + case R7_REGNUM: page_regnum = SEG_T_REGNUM; break; } @@ -737,6 +1567,9 @@ value_from_register (type, regnum, frame) page_regnum, &lval); + if (register_valid[page_regnum] == -1) + return NULL; /* register value not available */ + if (lval == lval_register) reg_stor++; else @@ -751,6 +1584,9 @@ value_from_register (type, regnum, frame) regnum, &lval); + if (register_valid[regnum] == -1) + return NULL; /* register value not available */ + if (lval == lval_register) reg_stor++; else @@ -761,7 +1597,7 @@ value_from_register (type, regnum, frame) last_addr = addr; } else -#endif /* GDB_TARGET_IS_H8500 */ +#endif /* GDB_TARGET_IS_H8500 */ for (local_regnum = regnum; value_bytes_copied < len; (value_bytes_copied += REGISTER_RAW_SIZE (local_regnum), @@ -774,6 +1610,9 @@ value_from_register (type, regnum, frame) local_regnum, &lval); + if (register_valid[local_regnum] == -1) + return NULL; /* register value not available */ + if (regnum == local_regnum) first_addr = addr; if (lval == lval_register) @@ -781,7 +1620,7 @@ value_from_register (type, regnum, frame) else { mem_stor++; - + mem_tracking = (mem_tracking && (regnum == local_regnum @@ -810,14 +1649,14 @@ value_from_register (type, regnum, frame) VALUE_ADDRESS (v) = first_addr; } else - fatal ("value_from_register: Value not stored anywhere!"); + internal_error ("value_from_register: Value not stored anywhere!"); VALUE_OPTIMIZED_OUT (v) = optim; /* Any structure stored in more than one register will always be - an integral number of registers. Otherwise, you'd need to do - some fiddling with the last register copied here for little - endian machines. */ + an integral number of registers. Otherwise, you'd need to do + some fiddling with the last register copied here for little + endian machines. */ /* Copy into the contents section of the value. */ memcpy (VALUE_CONTENTS_RAW (v), value_bytes, len); @@ -825,7 +1664,7 @@ value_from_register (type, regnum, frame) /* Finally do any conversion necessary when extracting this type from more than one register. */ #ifdef REGISTER_CONVERT_TO_TYPE - REGISTER_CONVERT_TO_TYPE(regnum, type, VALUE_CONTENTS_RAW(v)); + REGISTER_CONVERT_TO_TYPE (regnum, type, VALUE_CONTENTS_RAW (v)); #endif return v; } @@ -835,49 +1674,57 @@ value_from_register (type, regnum, frame) read the data in raw format. */ get_saved_register (raw_buffer, &optim, &addr, frame, regnum, &lval); + + if (register_valid[regnum] == -1) + return NULL; /* register value not available */ + VALUE_OPTIMIZED_OUT (v) = optim; VALUE_LVAL (v) = lval; VALUE_ADDRESS (v) = addr; - - /* Convert the raw contents to virtual contents. - (Just copy them if the formats are the same.) */ - - REGISTER_CONVERT_TO_VIRTUAL (regnum, raw_buffer, virtual_buffer); - + + /* Convert raw data to virtual format if necessary. */ + if (REGISTER_CONVERTIBLE (regnum)) { - /* When the raw and virtual formats differ, the virtual format - corresponds to a specific data type. If we want that type, - copy the data into the value. - Otherwise, do a type-conversion. */ - - if (type != REGISTER_VIRTUAL_TYPE (regnum)) - { - /* eg a variable of type `float' in a 68881 register - with raw type `extended' and virtual type `double'. - Fetch it as a `double' and then convert to `float'. */ - v = allocate_value (REGISTER_VIRTUAL_TYPE (regnum)); - memcpy (VALUE_CONTENTS_RAW (v), virtual_buffer, len); - v = value_cast (type, v); - } - else - memcpy (VALUE_CONTENTS_RAW (v), virtual_buffer, len); + REGISTER_CONVERT_TO_VIRTUAL (regnum, type, + raw_buffer, VALUE_CONTENTS_RAW (v)); } else { /* Raw and virtual formats are the same for this register. */ -#if TARGET_BYTE_ORDER == BIG_ENDIAN - if (len < REGISTER_RAW_SIZE (regnum)) + if (TARGET_BYTE_ORDER == BIG_ENDIAN && len < REGISTER_RAW_SIZE (regnum)) { - /* Big-endian, and we want less than full size. */ + /* Big-endian, and we want less than full size. */ VALUE_OFFSET (v) = REGISTER_RAW_SIZE (regnum) - len; } -#endif - memcpy (VALUE_CONTENTS_RAW (v), virtual_buffer + VALUE_OFFSET (v), len); + memcpy (VALUE_CONTENTS_RAW (v), raw_buffer + VALUE_OFFSET (v), len); } - + + if (GDB_TARGET_IS_D10V + && TYPE_CODE (type) == TYPE_CODE_PTR + && TYPE_TARGET_TYPE (type) + && (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_FUNC)) + { + /* pointer to function */ + unsigned long num; + unsigned short snum; + snum = (unsigned short) extract_unsigned_integer (VALUE_CONTENTS_RAW (v), 2); + num = D10V_MAKE_IADDR (snum); + store_address (VALUE_CONTENTS_RAW (v), 4, num); + } + else if (GDB_TARGET_IS_D10V + && TYPE_CODE (type) == TYPE_CODE_PTR) + { + /* pointer to data */ + unsigned long num; + unsigned short snum; + snum = (unsigned short) extract_unsigned_integer (VALUE_CONTENTS_RAW (v), 2); + num = D10V_MAKE_DADDR (snum); + store_address (VALUE_CONTENTS_RAW (v), 4, num); + } + return v; } @@ -886,14 +1733,14 @@ value_from_register (type, regnum, frame) return a (pointer to a) struct value containing the properly typed address. */ -value +value_ptr locate_var_value (var, frame) register struct symbol *var; - FRAME frame; + struct frame_info *frame; { CORE_ADDR addr = 0; struct type *type = SYMBOL_TYPE (var); - value lazy_value; + value_ptr lazy_value; /* Evaluate it first; if the result is a memory address, we're fine. Lazy evaluation pays off here. */ @@ -905,12 +1752,16 @@ locate_var_value (var, frame) if (VALUE_LAZY (lazy_value) || TYPE_CODE (type) == TYPE_CODE_FUNC) { + value_ptr val; + addr = VALUE_ADDRESS (lazy_value); - return value_from_longest (lookup_pointer_type (type), (LONGEST) addr); + val = value_from_pointer (lookup_pointer_type (type), addr); + VALUE_BFD_SECTION (val) = VALUE_BFD_SECTION (lazy_value); + return val; } /* Not a memory address; check what the problem was. */ - switch (VALUE_LVAL (lazy_value)) + switch (VALUE_LVAL (lazy_value)) { case lval_register: case lval_reg_frame_relative: @@ -923,5 +1774,31 @@ locate_var_value (var, frame) SYMBOL_SOURCE_NAME (var)); break; } - return 0; /* For lint -- never reached */ + return 0; /* For lint -- never reached */ +} + + +static void build_findvar PARAMS ((void)); +static void +build_findvar () +{ + /* We allocate some extra slop since we do a lot of memcpy's around + `registers', and failing-soft is better than failing hard. */ + int sizeof_registers = REGISTER_BYTES + /* SLOP */ 256; + int sizeof_register_valid = NUM_REGS * sizeof (*register_valid); + registers = xmalloc (sizeof_registers); + memset (registers, 0, sizeof_registers); + register_valid = xmalloc (sizeof_register_valid); + memset (register_valid, 0, sizeof_register_valid); +} + +void _initialize_findvar PARAMS ((void)); +void +_initialize_findvar () +{ + build_findvar (); + + register_gdbarch_swap (®isters, sizeof (registers), NULL); + register_gdbarch_swap (®ister_valid, sizeof (register_valid), NULL); + register_gdbarch_swap (NULL, 0, build_findvar); }