From fc0c74b114ec869ce89d12a282a1cbcb6ab7e6e8 Mon Sep 17 00:00:00 2001 From: Andrew Cagney Date: Mon, 15 Oct 2001 18:18:30 +0000 Subject: [PATCH] Add INTEGER_TO_ADDRESS to hadle nasty harvard architectures that do funnies to integer to address conversions. --- gdb/ChangeLog | 18 ++++++++++ gdb/config/mips/tm-mips.h | 4 --- gdb/d10v-tdep.c | 16 +++++++++ gdb/doc/ChangeLog | 7 ++++ gdb/doc/gdbint.texinfo | 25 +++++++++++++- gdb/gdbarch.c | 38 +++++++++++++++++++++ gdb/gdbarch.h | 37 ++++++++++++++++++++ gdb/gdbarch.sh | 1 + gdb/mips-tdep.c | 17 +++++++++ gdb/values.c | 72 +++++++++++++++++++++++---------------- 10 files changed, 201 insertions(+), 34 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index aa84f1dcaba..a3d4087de7c 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,21 @@ +2001-10-15 Andrew Cagney + + * mips-tdep.c (mips_integer_to_address): New function. + (mips_gdbarch_init): Initialize pointer_to_address, + address_to_pointer and integer_to_address. + + * config/mips/tm-mips.h (POINTER_TO_ADDRESS): Delete + (ADDRESS_TO_POINTER): Delete. + + * d10v-tdep.c (d10v_integer_to_address): New function. + (d10v_gdbarch_init): Initialize integer_to_address. + + * values.c (value_as_pointer): Use INTEGER_TO_ADDRESS when + available. + + * gdbarch.sh (INTEGER_TO_ADDRESS): New predicate and function. + * gdbarch.h, gdbarch.c: Regenerate. + 2001-10-14 Mark Kettenis * config/s390/nm-linux.h: Don't include . diff --git a/gdb/config/mips/tm-mips.h b/gdb/config/mips/tm-mips.h index a865e96223d..f89d7abe108 100644 --- a/gdb/config/mips/tm-mips.h +++ b/gdb/config/mips/tm-mips.h @@ -499,9 +499,5 @@ typedef unsigned long t_inst; /* Integer big enough to hold an instruction */ extern void mips_set_processor_type_command (char *, int); -/* MIPS sign extends addresses */ -#define POINTER_TO_ADDRESS(TYPE,BUF) (signed_pointer_to_address (TYPE, BUF)) -#define ADDRESS_TO_POINTER(TYPE,BUF,ADDR) (address_to_signed_pointer (TYPE, BUF, ADDR)) - /* Single step based on where the current instruction will take us. */ extern void mips_software_single_step (enum target_signal, int); diff --git a/gdb/d10v-tdep.c b/gdb/d10v-tdep.c index b0dd3bcac18..e9c926995b0 100644 --- a/gdb/d10v-tdep.c +++ b/gdb/d10v-tdep.c @@ -419,6 +419,21 @@ d10v_pointer_to_address (struct type *type, void *buf) return d10v_make_daddr (addr); } +static CORE_ADDR +d10v_integer_to_address (struct type *type, void *buf) +{ + LONGEST val; + val = unpack_long (type, buf); + if (TYPE_CODE (type) == TYPE_CODE_INT + && TYPE_LENGTH (type) <= TYPE_LENGTH (builtin_type_void_data_ptr)) + /* Convert small integers that would would be directly copied into + a pointer variable into an address pointing into data space. */ + return d10v_make_daddr (val & 0xffff); + else + /* The value is too large to fit in a pointer. Assume this was + intentional and that the user in fact specified a raw address. */ + return val; +} /* Store the address of the place in which to copy the structure the subroutine will return. This is called from call_function. @@ -1478,6 +1493,7 @@ d10v_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_addr_bit (gdbarch, 32); set_gdbarch_address_to_pointer (gdbarch, d10v_address_to_pointer); set_gdbarch_pointer_to_address (gdbarch, d10v_pointer_to_address); + set_gdbarch_integer_to_address (gdbarch, d10v_integer_to_address); set_gdbarch_short_bit (gdbarch, 2 * TARGET_CHAR_BIT); set_gdbarch_int_bit (gdbarch, 2 * TARGET_CHAR_BIT); set_gdbarch_long_bit (gdbarch, 4 * TARGET_CHAR_BIT); diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index 66300bb8ffb..9466bd210b3 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,10 @@ +2001-10-15 Andrew Cagney + + * gdbint.texinfo (Target Architecture Definition): Default + POINTER_TO_ADDRESS functions assume unsigned addresses. + (INTEGER_TO_ADDRESS): Document. Derive pragmatics section from a + posting by Jim Blandy. + 2001-10-12 Jim Blandy * Makefile.in (MAKEHTMLFLAGS): Remove -glossary; the most recent diff --git a/gdb/doc/gdbint.texinfo b/gdb/doc/gdbint.texinfo index 46778f8995c..3c867fef761 100644 --- a/gdb/doc/gdbint.texinfo +++ b/gdb/doc/gdbint.texinfo @@ -2489,7 +2489,7 @@ appropriate way for the current architecture. If you can, use Here are some macros which architectures can define to indicate the relationship between pointers and addresses. These have default definitions, appropriate for architectures on which all pointers are -simple byte addresses. +simple unsigned byte addresses. @deftypefn {Target Macro} CORE_ADDR POINTER_TO_ADDRESS (struct type *@var{type}, char *@var{buf}) Assume that @var{buf} holds a pointer of type @var{type}, in the @@ -3141,6 +3141,29 @@ function. A zero value indicates that it is not important or necessary to set a breakpoint to get through the dynamic linker and that single stepping will suffice. +@item INTEGER_TO_ADDRESS (@var{type}, @var{buf}) +@findex INTEGER_TO_ADDRESS +@cindex converting integers to addresses +Define this when the architecture needs to handle non-pointer to address +conversions specially. Converts that value to an address according to +the current architectures conventions. + +@emph{Pragmatics: When the user copies a well defined expression from +their source code and passes it, as a parameter, to @value{GDBN}'s +@code{print} command, they should get the same value as would have been +computed by the target program. Any deviation from this rule can cause +major confusion and annoyance, and needs to be justified carefully. In +other words, @value{GDBN} doesn't really have the freedom to do these +conversions in clever and useful ways. It has, however, been pointed +out that users aren't complaining about how @value{GDBN} casts integers +to pointers; they are complaining that they can't take an address from a +disassembly listing and give it to @code{x/i}. Adding an architecture +method like @code{INTEGER_TO_ADDRESS} certainly makes it possible for +@value{GDBN} to ``get it right'' in all circumstances.} + +@xref{Target Architecture Definition, , Pointers Are Not Always +Addresses}. + @item IS_TRAPPED_INTERNALVAR (@var{name}) @findex IS_TRAPPED_INTERNALVAR This is an ugly hook to allow the specification of special actions that diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c index 2517ebaf7b7..4dceeac2cdc 100644 --- a/gdb/gdbarch.c +++ b/gdb/gdbarch.c @@ -207,6 +207,7 @@ struct gdbarch gdbarch_store_pseudo_register_ftype *store_pseudo_register; gdbarch_pointer_to_address_ftype *pointer_to_address; gdbarch_address_to_pointer_ftype *address_to_pointer; + gdbarch_integer_to_address_ftype *integer_to_address; gdbarch_return_value_on_stack_ftype *return_value_on_stack; gdbarch_extract_return_value_ftype *extract_return_value; gdbarch_push_arguments_ftype *push_arguments; @@ -387,6 +388,7 @@ struct gdbarch startup_gdbarch = 0, 0, 0, + 0, /* startup_gdbarch() */ }; @@ -679,6 +681,7 @@ verify_gdbarch (struct gdbarch *gdbarch) /* Skip verify of store_pseudo_register, invalid_p == 0 */ /* Skip verify of pointer_to_address, invalid_p == 0 */ /* Skip verify of address_to_pointer, invalid_p == 0 */ + /* Skip verify of integer_to_address, has predicate */ /* Skip verify of return_value_on_stack, invalid_p == 0 */ if ((GDB_MULTI_ARCH >= 2) && (gdbarch->extract_return_value == 0)) @@ -1312,6 +1315,17 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) (long) current_gdbarch->inner_than /*INNER_THAN ()*/); #endif +#ifdef INTEGER_TO_ADDRESS + fprintf_unfiltered (file, + "gdbarch_dump: %s # %s\n", + "INTEGER_TO_ADDRESS(type, buf)", + XSTRING (INTEGER_TO_ADDRESS (type, buf))); + if (GDB_MULTI_ARCH) + fprintf_unfiltered (file, + "gdbarch_dump: INTEGER_TO_ADDRESS = 0x%08lx\n", + (long) current_gdbarch->integer_to_address + /*INTEGER_TO_ADDRESS ()*/); +#endif #ifdef MAX_REGISTER_RAW_SIZE fprintf_unfiltered (file, "gdbarch_dump: MAX_REGISTER_RAW_SIZE # %s\n", @@ -3393,6 +3407,30 @@ set_gdbarch_address_to_pointer (struct gdbarch *gdbarch, gdbarch->address_to_pointer = address_to_pointer; } +int +gdbarch_integer_to_address_p (struct gdbarch *gdbarch) +{ + return gdbarch->integer_to_address != 0; +} + +CORE_ADDR +gdbarch_integer_to_address (struct gdbarch *gdbarch, struct type *type, void *buf) +{ + if (gdbarch->integer_to_address == 0) + internal_error (__FILE__, __LINE__, + "gdbarch: gdbarch_integer_to_address invalid"); + if (gdbarch_debug >= 2) + fprintf_unfiltered (gdb_stdlog, "gdbarch_integer_to_address called\n"); + return gdbarch->integer_to_address (type, buf); +} + +void +set_gdbarch_integer_to_address (struct gdbarch *gdbarch, + gdbarch_integer_to_address_ftype integer_to_address) +{ + gdbarch->integer_to_address = integer_to_address; +} + int gdbarch_return_value_on_stack (struct gdbarch *gdbarch, struct type *type) { diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h index 29ed0208567..7e709176793 100644 --- a/gdb/gdbarch.h +++ b/gdb/gdbarch.h @@ -1239,6 +1239,43 @@ extern void set_gdbarch_address_to_pointer (struct gdbarch *gdbarch, gdbarch_add #endif #endif +#if defined (INTEGER_TO_ADDRESS) +/* Legacy for systems yet to multi-arch INTEGER_TO_ADDRESS */ +#if !defined (INTEGER_TO_ADDRESS_P) +#define INTEGER_TO_ADDRESS_P() (1) +#endif +#endif + +/* Default predicate for non- multi-arch targets. */ +#if (!GDB_MULTI_ARCH) && !defined (INTEGER_TO_ADDRESS_P) +#define INTEGER_TO_ADDRESS_P() (0) +#endif + +extern int gdbarch_integer_to_address_p (struct gdbarch *gdbarch); +#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (INTEGER_TO_ADDRESS_P) +#error "Non multi-arch definition of INTEGER_TO_ADDRESS" +#endif +#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (INTEGER_TO_ADDRESS_P) +#define INTEGER_TO_ADDRESS_P() (gdbarch_integer_to_address_p (current_gdbarch)) +#endif + +/* Default (function) for non- multi-arch platforms. */ +#if (!GDB_MULTI_ARCH) && !defined (INTEGER_TO_ADDRESS) +#define INTEGER_TO_ADDRESS(type, buf) ( (type, buf)) +#endif + +typedef CORE_ADDR (gdbarch_integer_to_address_ftype) (struct type *type, void *buf); +extern CORE_ADDR gdbarch_integer_to_address (struct gdbarch *gdbarch, struct type *type, void *buf); +extern void set_gdbarch_integer_to_address (struct gdbarch *gdbarch, gdbarch_integer_to_address_ftype *integer_to_address); +#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (INTEGER_TO_ADDRESS) +#error "Non multi-arch definition of INTEGER_TO_ADDRESS" +#endif +#if GDB_MULTI_ARCH +#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (INTEGER_TO_ADDRESS) +#define INTEGER_TO_ADDRESS(type, buf) (gdbarch_integer_to_address (current_gdbarch, type, buf)) +#endif +#endif + /* Default (function) for non- multi-arch platforms. */ #if (!GDB_MULTI_ARCH) && !defined (RETURN_VALUE_ON_STACK) #define RETURN_VALUE_ON_STACK(type) (generic_return_value_on_stack_not (type)) diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh index a1d5962b5b9..cdb9e201490 100755 --- a/gdb/gdbarch.sh +++ b/gdb/gdbarch.sh @@ -472,6 +472,7 @@ f:2:STORE_PSEUDO_REGISTER:void:store_pseudo_register:int regnum:regnum:::0::0 # f:2:POINTER_TO_ADDRESS:CORE_ADDR:pointer_to_address:struct type *type, void *buf:type, buf:::unsigned_pointer_to_address::0 f:2:ADDRESS_TO_POINTER:void:address_to_pointer:struct type *type, void *buf, CORE_ADDR addr:type, buf, addr:::unsigned_address_to_pointer::0 +F:2:INTEGER_TO_ADDRESS:CORE_ADDR:integer_to_address:struct type *type, void *buf:type, buf # f:2:RETURN_VALUE_ON_STACK:int:return_value_on_stack:struct type *type:type:::generic_return_value_on_stack_not::0 f:2:EXTRACT_RETURN_VALUE:void:extract_return_value:struct type *type, char *regbuf, char *valbuf:type, regbuf, valbuf::0:0 diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c index a6e06bbf394..df2bc3ba839 100644 --- a/gdb/mips-tdep.c +++ b/gdb/mips-tdep.c @@ -3950,6 +3950,20 @@ mips_ecoff_reg_to_regnum (int num) return num + FP0_REGNUM - 32; } +/* Convert an integer into an address. By first converting the value + into a pointer and then extracting it signed, the address is + guarenteed to be correctly sign extended. */ + +static CORE_ADDR +mips_integer_to_address (struct type *type, void *buf) +{ + char *tmp = alloca (TYPE_LENGTH (builtin_type_void_data_ptr)); + LONGEST val = unpack_long (type, buf); + store_signed_integer (tmp, TYPE_LENGTH (builtin_type_void_data_ptr), val); + return extract_signed_integer (tmp, + TYPE_LENGTH (builtin_type_void_data_ptr)); +} + static struct gdbarch * mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) @@ -4259,6 +4273,9 @@ mips_gdbarch_init (struct gdbarch_info info, set_gdbarch_skip_prologue (gdbarch, mips_skip_prologue); set_gdbarch_saved_pc_after_call (gdbarch, mips_saved_pc_after_call); + set_gdbarch_pointer_to_address (gdbarch, signed_pointer_to_address); + set_gdbarch_address_to_pointer (gdbarch, address_to_signed_pointer); + set_gdbarch_integer_to_address (gdbarch, mips_integer_to_address); return gdbarch; } diff --git a/gdb/values.c b/gdb/values.c index ededf9d368f..bf032af358f 100644 --- a/gdb/values.c +++ b/gdb/values.c @@ -572,35 +572,49 @@ value_as_pointer (value_ptr val) return ADDR_BITS_REMOVE (value_as_long (val)); #else COERCE_ARRAY (val); - /* In converting VAL to an address (CORE_ADDR), any small integers - are first cast to a generic pointer. The function unpack_long - will then correctly convert that pointer into a canonical address - (using POINTER_TO_ADDRESS). - - Without the cast, the MIPS gets: 0xa0000000 -> (unsigned int) - 0xa0000000 -> (LONGEST) 0x00000000a0000000 - - With the cast, the MIPS gets: 0xa0000000 -> (unsigned int) - 0xa0000000 -> (void*) 0xa0000000 -> (LONGEST) 0xffffffffa0000000. - - If the user specifies an integer that is larger than the target - pointer type, it is assumed that it was intentional and the value - is converted directly into an ADDRESS. This ensures that no - information is discarded. - - NOTE: The cast operation may eventualy be converted into a TARGET - method (see POINTER_TO_ADDRESS() and ADDRESS_TO_POINTER()) so - that the TARGET ISA/ABI can apply an arbitrary conversion. - - NOTE: In pure harvard architectures function and data pointers - can be different and may require different integer to pointer - conversions. */ - if (TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_INT - && (TYPE_LENGTH (VALUE_TYPE (val)) - <= TYPE_LENGTH (builtin_type_void_data_ptr))) - { - val = value_cast (builtin_type_void_data_ptr, val); - } + + /* Some architectures (e.g. Harvard), map instruction and data + addresses onto a single large unified address space. For + instance: An architecture may consider a large integer in the + range 0x10000000 .. 0x1000ffff to already represent a data + addresses (hence not need a pointer to address conversion) while + a small integer would still need to be converted integer to + pointer to address. Just assume such architectures handle all + integer conversions in a single function. */ + + /* JimB writes: + + I think INTEGER_TO_ADDRESS is a good idea as proposed --- but we + must admonish GDB hackers to make sure its behavior matches the + compiler's, whenever possible. + + In general, I think GDB should evaluate expressions the same way + the compiler does. When the user copies an expression out of + their source code and hands it to a `print' command, they should + get the same value the compiler would have computed. Any + deviation from this rule can cause major confusion and annoyance, + and needs to be justified carefully. In other words, GDB doesn't + really have the freedom to do these conversions in clever and + useful ways. + + AndrewC pointed out that users aren't complaining about how GDB + casts integers to pointers; they are complaining that they can't + take an address from a disassembly listing and give it to `x/i'. + This is certainly important. + + Adding an architecture method like INTEGER_TO_ADDRESS certainly + makes it possible for GDB to "get it right" in all circumstances + --- the target has complete control over how things get done, so + people can Do The Right Thing for their target without breaking + anyone else. The standard doesn't specify how integers get + converted to pointers; usually, the ABI doesn't either, but + ABI-specific code is a more reasonable place to handle it. */ + + if (TYPE_CODE (VALUE_TYPE (val)) != TYPE_CODE_PTR + && TYPE_CODE (VALUE_TYPE (val)) != TYPE_CODE_REF + && INTEGER_TO_ADDRESS_P ()) + return INTEGER_TO_ADDRESS (VALUE_TYPE (val), VALUE_CONTENTS (val)); + return unpack_long (VALUE_TYPE (val), VALUE_CONTENTS (val)); #endif } -- 2.30.2