X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Farch-utils.c;h=de3d284a8c801b38a453e1e400806834f337c091;hb=9b700aad366dceee82141afc69b6ee69802b90c9;hp=004d3aeb10d46b50f0c4cc31e1e634fd20cad43d;hpb=3172dc307bfd4eca0675c7343aa94eae02eb40e2;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c index 004d3aeb10..de3d284a8c 100644 --- a/gdb/arch-utils.c +++ b/gdb/arch-utils.c @@ -1,5 +1,7 @@ /* Dynamic architecture support for GDB, the GNU debugger. - Copyright 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + + Copyright 1998, 1999, 2000, 2001, 2002 Free Software Foundation, + Inc. This file is part of GDB. @@ -21,12 +23,12 @@ #include "defs.h" #if GDB_MULTI_ARCH +#include "arch-utils.h" #include "gdbcmd.h" #include "inferior.h" /* enum CALL_DUMMY_LOCATION et.al. */ #else /* Just include everything in sight so that the every old definition of macro is visible. */ -#include "gdb_string.h" #include "symtab.h" #include "frame.h" #include "inferior.h" @@ -37,6 +39,10 @@ #include "target.h" #include "annotate.h" #endif +#include "gdb_string.h" +#include "regcache.h" +#include "gdb_assert.h" +#include "sim-regno.h" #include "version.h" @@ -52,14 +58,14 @@ and optionally adjust the pc to point to the correct memory location for inserting the breakpoint. */ -unsigned char * +const unsigned char * legacy_breakpoint_from_pc (CORE_ADDR * pcptr, int *lenptr) { /* {BIG_,LITTLE_}BREAKPOINT is the sequence of bytes we insert for a breakpoint. On some machines, breakpoints are handled by the target environment and we don't have to worry about them here. */ #ifdef BIG_BREAKPOINT - if (TARGET_BYTE_ORDER == BIG_ENDIAN) + if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) { static unsigned char big_break_insn[] = BIG_BREAKPOINT; *lenptr = sizeof (big_break_insn); @@ -67,7 +73,7 @@ legacy_breakpoint_from_pc (CORE_ADDR * pcptr, int *lenptr) } #endif #ifdef LITTLE_BREAKPOINT - if (TARGET_BYTE_ORDER != BIG_ENDIAN) + if (TARGET_BYTE_ORDER != BFD_ENDIAN_BIG) { static unsigned char little_break_insn[] = LITTLE_BREAKPOINT; *lenptr = sizeof (little_break_insn); @@ -85,6 +91,46 @@ legacy_breakpoint_from_pc (CORE_ADDR * pcptr, int *lenptr) return NULL; } +/* Implementation of extract return value that grubs around in the + register cache. */ +void +legacy_extract_return_value (struct type *type, struct regcache *regcache, + void *valbuf) +{ + char *registers = deprecated_grub_regcache_for_registers (regcache); + bfd_byte *buf = valbuf; + DEPRECATED_EXTRACT_RETURN_VALUE (type, registers, buf); /* OK */ +} + +/* Implementation of store return value that grubs the register cache. + Takes a local copy of the buffer to avoid const problems. */ +void +legacy_store_return_value (struct type *type, struct regcache *regcache, + const void *buf) +{ + bfd_byte *b = alloca (TYPE_LENGTH (type)); + gdb_assert (regcache == current_regcache); + memcpy (b, buf, TYPE_LENGTH (type)); + DEPRECATED_STORE_RETURN_VALUE (type, b); +} + + +int +legacy_register_sim_regno (int regnum) +{ + /* Only makes sense to supply raw registers. */ + gdb_assert (regnum >= 0 && regnum < NUM_REGS); + /* NOTE: cagney/2002-05-13: The old code did it this way and it is + suspected that some GDB/SIM combinations may rely on this + behavour. The default should be one2one_register_sim_regno + (below). */ + if (REGISTER_NAME (regnum) != NULL + && REGISTER_NAME (regnum)[0] != '\0') + return regnum; + else + return LEGACY_SIM_REGNO_IGNORE; +} + int generic_frameless_function_invocation_not (struct frame_info *fi) { @@ -97,7 +143,31 @@ generic_return_value_on_stack_not (struct type *type) return 0; } -char * +CORE_ADDR +generic_skip_trampoline_code (CORE_ADDR pc) +{ + return 0; +} + +int +generic_in_solib_call_trampoline (CORE_ADDR pc, char *name) +{ + return 0; +} + +int +generic_in_solib_return_trampoline (CORE_ADDR pc, char *name) +{ + return 0; +} + +int +generic_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc) +{ + return 0; +} + +const char * legacy_register_name (int i) { #ifdef REGISTER_NAMES @@ -131,13 +201,16 @@ generic_remote_translate_xfer_address (CORE_ADDR gdb_addr, int gdb_len, int generic_prologue_frameless_p (CORE_ADDR ip) { -#ifdef SKIP_PROLOGUE_FRAMELESS_P - return ip == SKIP_PROLOGUE_FRAMELESS_P (ip); -#else return ip == SKIP_PROLOGUE (ip); -#endif } +/* New/multi-arched targets should use the correct gdbarch field + instead of using this global pointer. */ +int +legacy_print_insn (bfd_vma vma, disassemble_info *info) +{ + return (*tm_print_insn) (vma, info); +} /* Helper functions for INNER_THAN */ @@ -166,9 +239,9 @@ default_float_format (struct gdbarch *gdbarch) #endif switch (byte_order) { - case BIG_ENDIAN: + case BFD_ENDIAN_BIG: return &floatformat_ieee_single_big; - case LITTLE_ENDIAN: + case BFD_ENDIAN_LITTLE: return &floatformat_ieee_single_little; default: internal_error (__FILE__, __LINE__, @@ -187,9 +260,9 @@ default_double_format (struct gdbarch *gdbarch) #endif switch (byte_order) { - case BIG_ENDIAN: + case BFD_ENDIAN_BIG: return &floatformat_ieee_double_big; - case LITTLE_ENDIAN: + case BFD_ENDIAN_LITTLE: return &floatformat_ieee_double_little; default: internal_error (__FILE__, __LINE__, @@ -213,15 +286,23 @@ generic_register_convertible_not (int num) } -int -default_register_sim_regno (int num) +/* Under some ABI's that specify the `struct convention' for returning + structures by value, by the time we've returned from the function, + the return value is sitting there in the caller's buffer, but GDB + has no way to find the address of that buffer. + + On such architectures, use this function as your + extract_struct_value_address method. When asked to a struct + returned by value in this fashion, GDB will print a nice error + message, instead of garbage. */ +CORE_ADDR +generic_cannot_extract_struct_value_address (char *dummy) { - return num; + return 0; } - CORE_ADDR -default_convert_from_func_ptr_addr (CORE_ADDR addr) +core_addr_identity (CORE_ADDR addr) { return addr; } @@ -232,39 +313,197 @@ no_op_reg_to_regnum (int reg) return reg; } -/* For use by frame_args_address and frame_locals_address. */ +/* Default prepare_to_procced(). */ +int +default_prepare_to_proceed (int select_it) +{ + return 0; +} + +/* Generic prepare_to_proceed(). This one should be suitable for most + targets that support threads. */ +int +generic_prepare_to_proceed (int select_it) +{ + ptid_t wait_ptid; + struct target_waitstatus wait_status; + + /* Get the last target status returned by target_wait(). */ + get_last_target_status (&wait_ptid, &wait_status); + + /* Make sure we were stopped either at a breakpoint, or because + of a Ctrl-C. */ + if (wait_status.kind != TARGET_WAITKIND_STOPPED + || (wait_status.value.sig != TARGET_SIGNAL_TRAP && + wait_status.value.sig != TARGET_SIGNAL_INT)) + { + return 0; + } + + if (!ptid_equal (wait_ptid, minus_one_ptid) + && !ptid_equal (inferior_ptid, wait_ptid)) + { + /* Switched over from WAIT_PID. */ + CORE_ADDR wait_pc = read_pc_pid (wait_ptid); + + if (wait_pc != read_pc ()) + { + if (select_it) + { + /* Switch back to WAIT_PID thread. */ + inferior_ptid = wait_ptid; + + /* FIXME: This stuff came from switch_to_thread() in + thread.c (which should probably be a public function). */ + flush_cached_frames (); + registers_changed (); + stop_pc = wait_pc; + select_frame (get_current_frame ()); + } + /* We return 1 to indicate that there is a breakpoint here, + so we need to step over it before continuing to avoid + hitting it straight away. */ + if (breakpoint_here_p (wait_pc)) + { + return 1; + } + } + } + return 0; + +} + CORE_ADDR -default_frame_address (struct frame_info *fi) +init_frame_pc_noop (int fromleaf, struct frame_info *prev) { - return fi->frame; + /* Do nothing, implies return the same PC value. */ + return get_frame_pc (prev); } -/* Functions to manipulate the endianness of the target. */ +CORE_ADDR +init_frame_pc_default (int fromleaf, struct frame_info *prev) +{ + if (fromleaf) + return SAVED_PC_AFTER_CALL (get_next_frame (prev)); + else if (get_next_frame (prev) != NULL) + return FRAME_SAVED_PC (get_next_frame (prev)); + else + return read_pc (); +} -#ifdef TARGET_BYTE_ORDER_SELECTABLE -/* compat - Catch old targets that expect a selectable byte-order to - default to BIG_ENDIAN */ -#ifndef TARGET_BYTE_ORDER_DEFAULT -#define TARGET_BYTE_ORDER_DEFAULT BIG_ENDIAN -#endif -#endif -#if !TARGET_BYTE_ORDER_SELECTABLE_P -#ifndef TARGET_BYTE_ORDER_DEFAULT -/* compat - Catch old non byte-order selectable targets that do not - define TARGET_BYTE_ORDER_DEFAULT and instead expect - TARGET_BYTE_ORDER to be used as the default. For targets that - defined neither TARGET_BYTE_ORDER nor TARGET_BYTE_ORDER_DEFAULT the - below will get a strange compiler warning. */ -#define TARGET_BYTE_ORDER_DEFAULT TARGET_BYTE_ORDER -#endif -#endif -#ifndef TARGET_BYTE_ORDER_DEFAULT -#define TARGET_BYTE_ORDER_DEFAULT BIG_ENDIAN /* arbitrary */ +void +default_elf_make_msymbol_special (asymbol *sym, struct minimal_symbol *msym) +{ + return; +} + +void +default_coff_make_msymbol_special (int val, struct minimal_symbol *msym) +{ + return; +} + +int +cannot_register_not (int regnum) +{ + return 0; +} + +/* Legacy version of target_virtual_frame_pointer(). Assumes that + there is an FP_REGNUM and that it is the same, cooked or raw. */ + +void +legacy_virtual_frame_pointer (CORE_ADDR pc, + int *frame_regnum, + LONGEST *frame_offset) +{ + /* FIXME: cagney/2002-09-13: This code is used when identifying the + frame pointer of the current PC. It is assuming that a single + register and an offset can determine this. I think it should + instead generate a byte code expression as that would work better + with things like Dwarf2's CFI. */ + if (FP_REGNUM >= 0 && FP_REGNUM < NUM_REGS) + *frame_regnum = FP_REGNUM; + else if (SP_REGNUM >= 0 && SP_REGNUM < NUM_REGS) + *frame_regnum = SP_REGNUM; + else + /* Should this be an internal error? I guess so, it is reflecting + an architectural limitation in the current design. */ + internal_error (__FILE__, __LINE__, "No virtual frame pointer available"); + *frame_offset = 0; +} + +/* Assume the world is sane, every register's virtual and real size + is identical. */ + +int +generic_register_size (int regnum) +{ + gdb_assert (regnum >= 0 && regnum < NUM_REGS + NUM_PSEUDO_REGS); + return TYPE_LENGTH (REGISTER_VIRTUAL_TYPE (regnum)); +} + +/* Assume all registers are adjacent. */ + +int +generic_register_byte (int regnum) +{ + int byte; + int i; + gdb_assert (regnum >= 0 && regnum < NUM_REGS + NUM_PSEUDO_REGS); + byte = 0; + for (i = 0; i < regnum; i++) + { + byte += TYPE_LENGTH (REGISTER_VIRTUAL_TYPE (i)); + } + return byte; +} + + +int +legacy_pc_in_sigtramp (CORE_ADDR pc, char *name) +{ +#if !defined (IN_SIGTRAMP) + if (SIGTRAMP_START_P ()) + return (pc) >= SIGTRAMP_START (pc) && (pc) < SIGTRAMP_END (pc); + else + return name && strcmp ("_sigtramp", name) == 0; +#else + return IN_SIGTRAMP (pc, name); #endif +} + +int +legacy_convert_register_p (int regnum) +{ + return REGISTER_CONVERTIBLE (regnum); +} + +void +legacy_register_to_value (int regnum, struct type *type, + char *from, char *to) +{ + REGISTER_CONVERT_TO_VIRTUAL (regnum, type, from, to); +} + +void +legacy_value_to_register (struct type *type, int regnum, + char *from, char *to) +{ + REGISTER_CONVERT_TO_RAW (type, regnum, from, to); +} + + +/* Functions to manipulate the endianness of the target. */ + /* ``target_byte_order'' is only used when non- multi-arch. - Multi-arch targets obtain the current byte order using - TARGET_BYTE_ORDER which is controlled by gdbarch.*. */ -int target_byte_order = TARGET_BYTE_ORDER_DEFAULT; + Multi-arch targets obtain the current byte order using the + TARGET_BYTE_ORDER gdbarch method. + + The choice of initial value is entirely arbitrary. During startup, + the function initialize_current_architecture() updates this value + based on default byte-order information extracted from BFD. */ +int target_byte_order = BFD_ENDIAN_BIG; int target_byte_order_auto = 1; static const char endian_big[] = "big"; @@ -286,20 +525,16 @@ show_endian (char *args, int from_tty) { if (TARGET_BYTE_ORDER_AUTO) printf_unfiltered ("The target endianness is set automatically (currently %s endian)\n", - (TARGET_BYTE_ORDER == BIG_ENDIAN ? "big" : "little")); + (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? "big" : "little")); else printf_unfiltered ("The target is assumed to be %s endian\n", - (TARGET_BYTE_ORDER == BIG_ENDIAN ? "big" : "little")); + (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? "big" : "little")); } static void set_endian (char *ignore_args, int from_tty, struct cmd_list_element *c) { - if (!TARGET_BYTE_ORDER_SELECTABLE_P) - { - printf_unfiltered ("Byte order is not selectable."); - } - else if (set_endian_string == endian_auto) + if (set_endian_string == endian_auto) { target_byte_order_auto = 1; } @@ -309,8 +544,8 @@ set_endian (char *ignore_args, int from_tty, struct cmd_list_element *c) if (GDB_MULTI_ARCH) { struct gdbarch_info info; - memset (&info, 0, sizeof info); - info.byte_order = LITTLE_ENDIAN; + gdbarch_info_init (&info); + info.byte_order = BFD_ENDIAN_LITTLE; if (! gdbarch_update_p (info)) { printf_unfiltered ("Little endian target not supported by GDB\n"); @@ -318,7 +553,7 @@ set_endian (char *ignore_args, int from_tty, struct cmd_list_element *c) } else { - target_byte_order = LITTLE_ENDIAN; + target_byte_order = BFD_ENDIAN_LITTLE; } } else if (set_endian_string == endian_big) @@ -327,8 +562,8 @@ set_endian (char *ignore_args, int from_tty, struct cmd_list_element *c) if (GDB_MULTI_ARCH) { struct gdbarch_info info; - memset (&info, 0, sizeof info); - info.byte_order = BIG_ENDIAN; + gdbarch_info_init (&info); + info.byte_order = BFD_ENDIAN_BIG; if (! gdbarch_update_p (info)) { printf_unfiltered ("Big endian target not supported by GDB\n"); @@ -336,7 +571,7 @@ set_endian (char *ignore_args, int from_tty, struct cmd_list_element *c) } else { - target_byte_order = BIG_ENDIAN; + target_byte_order = BFD_ENDIAN_BIG; } } else @@ -350,33 +585,20 @@ set_endian (char *ignore_args, int from_tty, struct cmd_list_element *c) static void set_endian_from_file (bfd *abfd) { + int want; if (GDB_MULTI_ARCH) internal_error (__FILE__, __LINE__, "set_endian_from_file: not for multi-arch"); - if (TARGET_BYTE_ORDER_SELECTABLE_P) - { - int want; - - if (bfd_big_endian (abfd)) - want = BIG_ENDIAN; - else - want = LITTLE_ENDIAN; - if (TARGET_BYTE_ORDER_AUTO) - target_byte_order = want; - else if (TARGET_BYTE_ORDER != want) - warning ("%s endian file does not match %s endian target.", - want == BIG_ENDIAN ? "big" : "little", - TARGET_BYTE_ORDER == BIG_ENDIAN ? "big" : "little"); - } + if (bfd_big_endian (abfd)) + want = BFD_ENDIAN_BIG; else - { - if (bfd_big_endian (abfd) - ? TARGET_BYTE_ORDER != BIG_ENDIAN - : TARGET_BYTE_ORDER == BIG_ENDIAN) - warning ("%s endian file does not match %s endian target.", - bfd_big_endian (abfd) ? "big" : "little", - TARGET_BYTE_ORDER == BIG_ENDIAN ? "big" : "little"); - } + want = BFD_ENDIAN_LITTLE; + if (TARGET_BYTE_ORDER_AUTO) + target_byte_order = want; + else if (TARGET_BYTE_ORDER != want) + warning ("%s endian file does not match %s endian target.", + want == BFD_ENDIAN_BIG ? "big" : "little", + TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? "big" : "little"); } @@ -506,7 +728,7 @@ set_architecture (char *ignore_args, int from_tty, struct cmd_list_element *c) else if (GDB_MULTI_ARCH) { struct gdbarch_info info; - memset (&info, 0, sizeof info); + gdbarch_info_init (&info); info.bfd_arch_info = bfd_scan_arch (set_architecture_string); if (info.bfd_arch_info == NULL) internal_error (__FILE__, __LINE__, @@ -529,40 +751,6 @@ set_architecture (char *ignore_args, int from_tty, struct cmd_list_element *c) show_architecture (NULL, from_tty); } -/* Called if the user enters ``info architecture'' without an argument. */ - -static void -info_architecture (char *args, int from_tty) -{ - printf_filtered ("Available architectures are:\n"); - if (GDB_MULTI_ARCH) - { - const char **arches = gdbarch_printable_names (); - const char **arch; - for (arch = arches; *arch != NULL; arch++) - { - printf_filtered (" %s", *arch); - } - xfree (arches); - } - else - { - enum bfd_architecture a; - for (a = bfd_arch_obscure + 1; a < bfd_arch_last; a++) - { - const struct bfd_arch_info *ap; - for (ap = bfd_lookup_arch (a, 0); - ap != NULL; - ap = ap->next) - { - printf_filtered (" %s", ap->printable_name); - ap = ap->next; - } - } - } - printf_filtered ("\n"); -} - /* Set the dynamic target-system-dependent parameters (architecture, byte-order) using information found in the BFD */ @@ -572,7 +760,7 @@ set_gdbarch_from_file (bfd *abfd) if (GDB_MULTI_ARCH) { struct gdbarch_info info; - memset (&info, 0, sizeof info); + gdbarch_info_init (&info); info.abfd = abfd; if (! gdbarch_update_p (info)) error ("Architecture of file not recognized.\n"); @@ -609,7 +797,7 @@ initialize_current_architecture (void) /* determine a default architecture and byte order. */ struct gdbarch_info info; - memset (&info, 0, sizeof (info)); + gdbarch_info_init (&info); /* Find a default architecture. */ if (info.bfd_arch_info == NULL @@ -635,26 +823,24 @@ initialize_current_architecture (void) "initialize_current_architecture: Arch not found"); } - /* take several guesses at a byte order. */ - /* NB: can't use TARGET_BYTE_ORDER_DEFAULT as its definition is - forced above. */ - if (info.byte_order == 0 + /* Take several guesses at a byte order. */ + if (info.byte_order == BFD_ENDIAN_UNKNOWN && default_bfd_vec != NULL) { /* Extract BFD's default vector's byte order. */ switch (default_bfd_vec->byteorder) { case BFD_ENDIAN_BIG: - info.byte_order = BIG_ENDIAN; + info.byte_order = BFD_ENDIAN_BIG; break; case BFD_ENDIAN_LITTLE: - info.byte_order = LITTLE_ENDIAN; + info.byte_order = BFD_ENDIAN_LITTLE; break; default: break; } } - if (info.byte_order == 0) + if (info.byte_order == BFD_ENDIAN_UNKNOWN) { /* look for ``*el-*'' in the target name. */ const char *chp; @@ -662,12 +848,12 @@ initialize_current_architecture (void) if (chp != NULL && chp - 2 >= target_name && strncmp (chp - 2, "el", 2) == 0) - info.byte_order = LITTLE_ENDIAN; + info.byte_order = BFD_ENDIAN_LITTLE; } - if (info.byte_order == 0) + if (info.byte_order == BFD_ENDIAN_UNKNOWN) { /* Wire it to big-endian!!! */ - info.byte_order = BIG_ENDIAN; + info.byte_order = BFD_ENDIAN_BIG; } if (GDB_MULTI_ARCH) @@ -678,6 +864,14 @@ initialize_current_architecture (void) "initialize_current_architecture: Selection of initial architecture failed"); } } + else + { + /* If the multi-arch logic comes up with a byte-order (from BFD) + use it for the non-multi-arch case. */ + if (info.byte_order != BFD_ENDIAN_UNKNOWN) + target_byte_order = info.byte_order; + initialize_non_multiarch (); + } /* Create the ``set architecture'' command appending ``auto'' to the list of architectures. */ @@ -696,19 +890,29 @@ initialize_current_architecture (void) arches, &set_architecture_string, "Set architecture of target.", &setlist); - c->function.sfunc = set_architecture; + set_cmd_sfunc (c, set_architecture); add_alias_cmd ("processor", "architecture", class_support, 1, &setlist); /* Don't use set_from_show - need to print both auto/manual and current setting. */ add_cmd ("architecture", class_support, show_architecture, "Show the current target architecture", &showlist); - c = add_cmd ("architecture", class_support, info_architecture, - "List supported target architectures", &infolist); - deprecate_cmd (c, "set architecture"); } } +/* Initialize a gdbarch info to values that will be automatically + overridden. Note: Originally, this ``struct info'' was initialized + using memset(0). Unfortunatly, that ran into problems, namely + BFD_ENDIAN_BIG is zero. An explicit initialization function that + can explicitly set each field to a well defined value is used. */ + +void +gdbarch_info_init (struct gdbarch_info *info) +{ + memset (info, 0, sizeof (struct gdbarch_info)); + info->byte_order = BFD_ENDIAN_UNKNOWN; +} + /* */ extern initialize_file_ftype _initialize_gdbarch_utils; @@ -721,7 +925,7 @@ _initialize_gdbarch_utils (void) endian_enum, &set_endian_string, "Set endianness of target.", &setlist); - c->function.sfunc = set_endian; + set_cmd_sfunc (c, set_endian); /* Don't use set_from_show - need to print both auto/manual and current setting. */ add_cmd ("endian", class_support, show_endian,