From 29709017e835906e3e95bc230d393331636234e1 Mon Sep 17 00:00:00 2001 From: Daniel Jacobowitz Date: Tue, 28 Nov 2006 22:14:31 +0000 Subject: [PATCH] * Makefile.in (mips-tdep.o, target-descriptions.o): Update. * target-descriptions.c (struct property): New. (struct target_desc): Add properties member. (tdesc_property, set_tdesc_property): New. * target-descriptions.h (tdesc_property, set_tdesc_property): Declare. * mips-tdep.c (PROPERTY_GP32, PROPERTY_GP64): New constants. (struct gdbarch_tdep): Add register_size_valid_p and register_size. (mips_isa_regsize): Use them. (mips_register_g_packet_guesses): New. (mips_gdbarch_init): Call it. If a target description is supplied, check for internal properties. Check for register size mismatches. * remote.c (send_g_packet, process_g_packet): New functions, split out from fetch_registers_using_g. (fetch_registers_using_g): Use them. (struct remote_g_packet_guess, remote_g_packet_guess_s) (struct remote_g_packet_data, remote_g_packet_data_handle) (remote_g_packet_data_init, register_remote_g_packet_guess) (remote_read_description): New. (init_remote_ops, init_remote_async_ops): Set to_read_description. (_initialize_remote): Register remote_g_packet_data_handle. * remote.h (register_remote_g_packet_guess): Declare. --- gdb/ChangeLog | 25 +++++++ gdb/Makefile.in | 4 +- gdb/mips-tdep.c | 81 ++++++++++++++++++++++ gdb/remote.c | 137 +++++++++++++++++++++++++++++++++----- gdb/remote.h | 5 ++ gdb/target-descriptions.c | 47 +++++++++++++ gdb/target-descriptions.h | 9 +++ 7 files changed, 289 insertions(+), 19 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index ab8040e89c..96f8c93891 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,28 @@ +2006-11-28 Daniel Jacobowitz + + * Makefile.in (mips-tdep.o, target-descriptions.o): Update. + * target-descriptions.c (struct property): New. + (struct target_desc): Add properties member. + (tdesc_property, set_tdesc_property): New. + * target-descriptions.h (tdesc_property, set_tdesc_property): + Declare. + * mips-tdep.c (PROPERTY_GP32, PROPERTY_GP64): New constants. + (struct gdbarch_tdep): Add register_size_valid_p and register_size. + (mips_isa_regsize): Use them. + (mips_register_g_packet_guesses): New. + (mips_gdbarch_init): Call it. If a target description is supplied, + check for internal properties. Check for register size mismatches. + * remote.c (send_g_packet, process_g_packet): New functions, split + out from fetch_registers_using_g. + (fetch_registers_using_g): Use them. + (struct remote_g_packet_guess, remote_g_packet_guess_s) + (struct remote_g_packet_data, remote_g_packet_data_handle) + (remote_g_packet_data_init, register_remote_g_packet_guess) + (remote_read_description): New. + (init_remote_ops, init_remote_async_ops): Set to_read_description. + (_initialize_remote): Register remote_g_packet_data_handle. + * remote.h (register_remote_g_packet_guess): Declare. + 2006-11-28 Daniel Jacobowitz * Makefile.in (SFILES): Add new and missed files. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index c98e5b94c4..695a3a77a5 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -2382,7 +2382,7 @@ mips-tdep.o: mips-tdep.c $(defs_h) $(gdb_string_h) $(gdb_assert_h) \ $(block_h) $(reggroups_h) $(opcode_mips_h) $(elf_mips_h) \ $(elf_bfd_h) $(symcat_h) $(sim_regno_h) $(dis_asm_h) \ $(frame_unwind_h) $(frame_base_h) $(trad_frame_h) $(infcall_h) \ - $(floatformat_h) + $(floatformat_h) $(remote_h) $(target_descriptions_h) mipsv4-nat.o: mipsv4-nat.c $(defs_h) $(inferior_h) $(gdbcore_h) $(target_h) \ $(regcache_h) $(gregset_h) memory-map.o: memory-map.c $(defs_h) $(memory_map_h) $(xml_support_h) \ @@ -2780,7 +2780,7 @@ target.o: target.c $(defs_h) $(gdb_string_h) $(target_h) $(gdbcmd_h) \ $(gdb_wait_h) $(dcache_h) $(regcache_h) $(gdb_assert_h) $(gdbcore_h) \ $(exceptions_h) $(target_descriptions_h) target-descriptions.o: target-descriptions.c $(defs_h) $(arch_utils_h) \ - $(target_h) $(target_descriptions_h) $(gdb_assert_h) + $(target_h) $(target_descriptions_h) $(vec_h) $(gdb_assert_h) target-memory.o: target-memory.c $(defs_h) $(vec_h) $(target_h) \ $(memory_map_h) $(gdb_assert_h) thread.o: thread.c $(defs_h) $(symtab_h) $(frame_h) $(inferior_h) \ diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c index 19f0e0dfa8..8b3ddb8870 100644 --- a/gdb/mips-tdep.c +++ b/gdb/mips-tdep.c @@ -55,6 +55,8 @@ #include "trad-frame.h" #include "infcall.h" #include "floatformat.h" +#include "remote.h" +#include "target-descriptions.h" static const struct objfile_data *mips_pdr_data; @@ -119,6 +121,11 @@ static enum mips_fpu_type mips_fpu_type = MIPS_DEFAULT_FPU_TYPE; static int mips_debug = 0; +/* Properties (for struct target_desc) describing the g/G packet + layout. */ +#define PROPERTY_GP32 "internal: transfers-32bit-registers" +#define PROPERTY_GP64 "internal: transfers-64bit-registers" + /* MIPS specific per-architecture information */ struct gdbarch_tdep { @@ -141,6 +148,13 @@ struct gdbarch_tdep const struct mips_regnum *regnum; /* Register names table for the current register set. */ const char **mips_processor_reg_names; + + /* The size of register data available from the target, if known. + This doesn't quite obsolete the manual + mips64_transfers_32bit_regs_p, since that is documented to force + left alignment even for big endian (very strange). */ + int register_size_valid_p; + int register_size; }; static int @@ -245,6 +259,13 @@ mips_abi (struct gdbarch *gdbarch) int mips_isa_regsize (struct gdbarch *gdbarch) { + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + /* If we know how big the registers are, use that size. */ + if (tdep->register_size_valid_p) + return tdep->register_size; + + /* Fall back to the previous behavior. */ return (gdbarch_bfd_arch_info (gdbarch)->bits_per_word / gdbarch_bfd_arch_info (gdbarch)->bits_per_byte); } @@ -4711,6 +4732,37 @@ global_mips_abi (void) internal_error (__FILE__, __LINE__, _("unknown ABI string")); } +static void +mips_register_g_packet_guesses (struct gdbarch *gdbarch) +{ + static struct target_desc *tdesc_gp32, *tdesc_gp64; + + if (tdesc_gp32 == NULL) + { + /* Create feature sets with the appropriate properties. The values + are not important. */ + + tdesc_gp32 = allocate_target_description (); + set_tdesc_property (tdesc_gp32, PROPERTY_GP32, ""); + + tdesc_gp64 = allocate_target_description (); + set_tdesc_property (tdesc_gp64, PROPERTY_GP64, ""); + } + + /* If the size matches the set of 32-bit or 64-bit integer registers, + assume that's what we've got. */ + register_remote_g_packet_guess (gdbarch, 38 * 4, tdesc_gp32); + register_remote_g_packet_guess (gdbarch, 38 * 8, tdesc_gp64); + + /* If the size matches the full set of registers GDB traditionally + knows about, including floating point, for either 32-bit or + 64-bit, assume that's what we've got. */ + register_remote_g_packet_guess (gdbarch, 90 * 4, tdesc_gp32); + register_remote_g_packet_guess (gdbarch, 90 * 8, tdesc_gp64); + + /* Otherwise we don't have a useful guess. */ +} + static struct gdbarch * mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) { @@ -4855,6 +4907,16 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) fprintf_unfiltered (gdb_stdlog, "mips_gdbarch_init: fpu_type = %d\n", fpu_type); + /* Check for blatant incompatibilities. */ + + /* If we have only 32-bit registers, then we can't debug a 64-bit + ABI. */ + if (info.target_desc + && tdesc_property (info.target_desc, PROPERTY_GP32) != NULL + && mips_abi != MIPS_ABI_EABI32 + && mips_abi != MIPS_ABI_O32) + return NULL; + /* try to find a pre-existing architecture */ for (arches = gdbarch_list_lookup_by_info (arches, &info); arches != NULL; @@ -4885,6 +4947,23 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) tdep->found_abi = found_abi; tdep->mips_abi = mips_abi; tdep->mips_fpu_type = fpu_type; + tdep->register_size_valid_p = 0; + tdep->register_size = 0; + + if (info.target_desc) + { + /* Some useful properties can be inferred from the target. */ + if (tdesc_property (info.target_desc, PROPERTY_GP32) != NULL) + { + tdep->register_size_valid_p = 1; + tdep->register_size = 4; + } + else if (tdesc_property (info.target_desc, PROPERTY_GP64) != NULL) + { + tdep->register_size_valid_p = 1; + tdep->register_size = 8; + } + } /* Initially set everything according to the default ABI/ISA. */ set_gdbarch_short_bit (gdbarch, 16); @@ -5152,6 +5231,8 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_single_step_through_delay (gdbarch, mips_single_step_through_delay); + mips_register_g_packet_guesses (gdbarch); + /* Hook in OS ABI-specific overrides, if they have been registered. */ gdbarch_init_osabi (info, gdbarch); diff --git a/gdb/remote.c b/gdb/remote.c index e758412fe2..69bc65bd16 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -3535,11 +3535,10 @@ fetch_register_using_p (struct packet_reg *reg) /* Fetch the registers included in the target's 'g' packet. */ -static void -fetch_registers_using_g (void) +static int +send_g_packet (void) { struct remote_state *rs = get_remote_state (); - struct remote_arch_state *rsa = get_remote_arch_state (); int i, buf_len; char *p; char *regs; @@ -3547,11 +3546,41 @@ fetch_registers_using_g (void) sprintf (rs->buf, "g"); remote_send (&rs->buf, &rs->buf_size); + /* We can get out of synch in various cases. If the first character + in the buffer is not a hex character, assume that has happened + and try to fetch another packet to read. */ + while ((rs->buf[0] < '0' || rs->buf[0] > '9') + && (rs->buf[0] < 'A' || rs->buf[0] > 'F') + && (rs->buf[0] < 'a' || rs->buf[0] > 'f') + && rs->buf[0] != 'x') /* New: unavailable register value. */ + { + if (remote_debug) + fprintf_unfiltered (gdb_stdlog, + "Bad register packet; fetching a new packet\n"); + getpkt (&rs->buf, &rs->buf_size, 0); + } + buf_len = strlen (rs->buf); /* Sanity check the received packet. */ if (buf_len % 2 != 0) error (_("Remote 'g' packet reply is of odd length: %s"), rs->buf); + + return buf_len / 2; +} + +static void +process_g_packet (void) +{ + struct remote_state *rs = get_remote_state (); + struct remote_arch_state *rsa = get_remote_arch_state (); + int i, buf_len; + char *p; + char *regs; + + buf_len = strlen (rs->buf); + + /* Further sanity checks, with knowledge of the architecture. */ if (REGISTER_BYTES_OK_P () && !REGISTER_BYTES_OK (buf_len / 2)) error (_("Remote 'g' packet reply is wrong length: %s"), rs->buf); if (buf_len > 2 * rsa->sizeof_g_packet) @@ -3588,20 +3617,6 @@ fetch_registers_using_g (void) /* Unimplemented registers read as all bits zero. */ memset (regs, 0, rsa->sizeof_g_packet); - /* We can get out of synch in various cases. If the first character - in the buffer is not a hex character, assume that has happened - and try to fetch another packet to read. */ - while ((rs->buf[0] < '0' || rs->buf[0] > '9') - && (rs->buf[0] < 'A' || rs->buf[0] > 'F') - && (rs->buf[0] < 'a' || rs->buf[0] > 'f') - && rs->buf[0] != 'x') /* New: unavailable register value. */ - { - if (remote_debug) - fprintf_unfiltered (gdb_stdlog, - "Bad register packet; fetching a new packet\n"); - getpkt (&rs->buf, &rs->buf_size, 0); - } - /* Reply describes registers byte by byte, each byte encoded as two hex characters. Suck them all up, then supply them to the register cacheing/storage mechanism. */ @@ -3648,6 +3663,13 @@ fetch_registers_using_g (void) } } +static void +fetch_registers_using_g (void) +{ + send_g_packet (); + process_g_packet (); +} + static void remote_fetch_registers (int regnum) { @@ -6052,6 +6074,83 @@ remote_get_thread_local_address (ptid_t ptid, CORE_ADDR lm, CORE_ADDR offset) return 0; } +/* Support for inferring a target description based on the current + architecture and the size of a 'g' packet. While the 'g' packet + can have any size (since optional registers can be left off the + end), some sizes are easily recognizable given knowledge of the + approximate architecture. */ + +struct remote_g_packet_guess +{ + int bytes; + const struct target_desc *tdesc; +}; +typedef struct remote_g_packet_guess remote_g_packet_guess_s; +DEF_VEC_O(remote_g_packet_guess_s); + +struct remote_g_packet_data +{ + VEC(remote_g_packet_guess_s) *guesses; +}; + +static struct gdbarch_data *remote_g_packet_data_handle; + +static void * +remote_g_packet_data_init (struct obstack *obstack) +{ + return OBSTACK_ZALLOC (obstack, struct remote_g_packet_data); +} + +void +register_remote_g_packet_guess (struct gdbarch *gdbarch, int bytes, + const struct target_desc *tdesc) +{ + struct remote_g_packet_data *data + = gdbarch_data (gdbarch, remote_g_packet_data_handle); + struct remote_g_packet_guess new_guess, *guess; + int ix; + + gdb_assert (tdesc != NULL); + + for (ix = 0; + VEC_iterate (remote_g_packet_guess_s, data->guesses, ix, guess); + ix++) + if (guess->bytes == bytes) + internal_error (__FILE__, __LINE__, + "Duplicate g packet description added for size %d", + bytes); + + new_guess.bytes = bytes; + new_guess.tdesc = tdesc; + VEC_safe_push (remote_g_packet_guess_s, data->guesses, &new_guess); +} + +static const struct target_desc * +remote_read_description (struct target_ops *target) +{ + struct remote_g_packet_data *data + = gdbarch_data (current_gdbarch, remote_g_packet_data_handle); + + if (!VEC_empty (remote_g_packet_guess_s, data->guesses)) + { + struct remote_g_packet_guess *guess; + int ix; + int bytes = send_g_packet (); + + for (ix = 0; + VEC_iterate (remote_g_packet_guess_s, data->guesses, ix, guess); + ix++) + if (guess->bytes == bytes) + return guess->tdesc; + + /* We discard the g packet. A minor optimization would be to + hold on to it, and fill the register cache once we have selected + an architecture, but it's too tricky to do safely. */ + } + + return NULL; +} + static void init_remote_ops (void) { @@ -6103,6 +6202,7 @@ Specify the serial device it is connected to\n\ remote_ops.to_memory_map = remote_memory_map; remote_ops.to_flash_erase = remote_flash_erase; remote_ops.to_flash_done = remote_flash_done; + remote_ops.to_read_description = remote_read_description; } /* Set up the extended remote vector by making a copy of the standard @@ -6235,6 +6335,7 @@ Specify the serial device it is connected to (e.g. /dev/ttya)."; remote_async_ops.to_memory_map = remote_memory_map; remote_async_ops.to_flash_erase = remote_flash_erase; remote_async_ops.to_flash_done = remote_flash_done; + remote_ops.to_read_description = remote_read_description; } /* Set up the async extended remote vector by making a copy of the standard @@ -6326,6 +6427,8 @@ _initialize_remote (void) /* architecture specific data */ remote_gdbarch_data_handle = gdbarch_data_register_post_init (init_remote_state); + remote_g_packet_data_handle = + gdbarch_data_register_pre_init (remote_g_packet_data_init); /* Old tacky stuff. NOTE: This comes after the remote protocol so that the remote protocol has been initialized. */ diff --git a/gdb/remote.h b/gdb/remote.h index fd84a91bdb..50f1a86147 100644 --- a/gdb/remote.h +++ b/gdb/remote.h @@ -21,6 +21,8 @@ #ifndef REMOTE_H #define REMOTE_H +struct target_desc; + /* FIXME?: move this interface down to tgt vector) */ /* Read a packet from the remote machine, with error checking, and @@ -63,4 +65,7 @@ extern int remote_read_bytes (CORE_ADDR memaddr, gdb_byte *myaddr, int len); extern void (*deprecated_target_resume_hook) (void); extern void (*deprecated_target_wait_loop_hook) (void); +void register_remote_g_packet_guess (struct gdbarch *gdbarch, int bytes, + const struct target_desc *tdesc); + #endif diff --git a/gdb/target-descriptions.c b/gdb/target-descriptions.c index 041d72be15..ffee104b97 100644 --- a/gdb/target-descriptions.c +++ b/gdb/target-descriptions.c @@ -26,13 +26,23 @@ #include "arch-utils.h" #include "target.h" #include "target-descriptions.h" +#include "vec.h" #include "gdb_assert.h" /* Types. */ +typedef struct property +{ + const char *key; + const char *value; +} property_s; +DEF_VEC_O(property_s); + struct target_desc { + /* Any architecture-specific properties specified by the target. */ + VEC(property_s) *properties; }; /* Global state. These variables are associated with the current @@ -122,6 +132,23 @@ target_current_description (void) return NULL; } +/* Return the string value of a property named KEY, or NULL if the + property was not specified. */ + +const char * +tdesc_property (const struct target_desc *target_desc, const char *key) +{ + struct property *prop; + int ix; + + for (ix = 0; VEC_iterate (property_s, target_desc->properties, ix, prop); + ix++) + if (strcmp (prop->key, key) == 0) + return prop->value; + + return NULL; +} + /* Methods for constructing a target description. */ struct target_desc * @@ -129,3 +156,23 @@ allocate_target_description (void) { return XZALLOC (struct target_desc); } + +void +set_tdesc_property (struct target_desc *target_desc, + const char *key, const char *value) +{ + struct property *prop, new_prop; + int ix; + + gdb_assert (key != NULL && value != NULL); + + for (ix = 0; VEC_iterate (property_s, target_desc->properties, ix, prop); + ix++) + if (strcmp (prop->key, key) == 0) + internal_error (__FILE__, __LINE__, + _("Attempted to add duplicate property \"%s\""), key); + + new_prop.key = key; + new_prop.value = value; + VEC_safe_push (property_s, target_desc->properties, &new_prop); +} diff --git a/gdb/target-descriptions.h b/gdb/target-descriptions.h index bbcf879a86..74f59833d9 100644 --- a/gdb/target-descriptions.h +++ b/gdb/target-descriptions.h @@ -45,8 +45,17 @@ const struct target_desc *target_current_description (void); /* Accessors for target descriptions. */ +/* Return the string value of a property named KEY, or NULL if the + property was not specified. */ + +const char *tdesc_property (const struct target_desc *, + const char *key); + /* Methods for constructing a target description. */ struct target_desc *allocate_target_description (void); +void set_tdesc_property (struct target_desc *, + const char *key, const char *value); + #endif /* TARGET_DESCRIPTIONS_H */