X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=gdb%2Farch-utils.c;h=fad8ed1b366aa395dca43e88b260c19887ccb45e;hb=0ba6dca974b6df1fc1ac67608815cf5a2603856d;hp=19e35ffe4e522ae18148db04bb317a068f0faba8;hpb=68e9cc944cbd49fd6a7108caee8f77b924c2c40b;p=binutils-gdb.git diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c index 19e35ffe4e5..fad8ed1b366 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, 2003 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,8 +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" @@ -54,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); @@ -69,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); @@ -87,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) { @@ -111,7 +155,19 @@ generic_in_solib_call_trampoline (CORE_ADDR pc, char *name) return 0; } -char * +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 @@ -145,11 +201,7 @@ 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 @@ -157,7 +209,7 @@ generic_prologue_frameless_p (CORE_ADDR ip) int legacy_print_insn (bfd_vma vma, disassemble_info *info) { - return (*tm_print_insn) (vma, info); + return (*deprecated_tm_print_insn) (vma, info); } /* Helper functions for INNER_THAN */ @@ -187,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__, @@ -208,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__, @@ -234,13 +286,21 @@ 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 core_addr_identity (CORE_ADDR addr) { @@ -253,13 +313,6 @@ no_op_reg_to_regnum (int reg) return reg; } -/* For use by frame_args_address and frame_locals_address. */ -CORE_ADDR -default_frame_address (struct frame_info *fi) -{ - return fi->frame; -} - /* Default prepare_to_procced(). */ int default_prepare_to_proceed (int select_it) @@ -305,7 +358,7 @@ generic_prepare_to_proceed (int select_it) flush_cached_frames (); registers_changed (); stop_pc = wait_pc; - select_frame (get_current_frame (), 0); + 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 @@ -320,21 +373,34 @@ generic_prepare_to_proceed (int select_it) } -void +CORE_ADDR init_frame_pc_noop (int fromleaf, struct frame_info *prev) { - return; + /* Do nothing, implies return the same PC value. */ + return get_frame_pc (prev); } -void +CORE_ADDR init_frame_pc_default (int fromleaf, struct frame_info *prev) { - if (fromleaf) - prev->pc = SAVED_PC_AFTER_CALL (prev->next); - else if (prev->next != NULL) - prev->pc = FRAME_SAVED_PC (prev->next); + if (fromleaf && DEPRECATED_SAVED_PC_AFTER_CALL_P ()) + return DEPRECATED_SAVED_PC_AFTER_CALL (get_next_frame (prev)); + else if (get_next_frame (prev) != NULL) + return DEPRECATED_FRAME_SAVED_PC (get_next_frame (prev)); else - prev->pc = read_pc (); + return read_pc (); +} + +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 @@ -344,44 +410,107 @@ cannot_register_not (int regnum) } /* Legacy version of target_virtual_frame_pointer(). Assumes that - there is an FP_REGNUM and that it is the same, cooked or raw. */ + there is an DEPRECATED_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) { - gdb_assert (FP_REGNUM >= 0); - *frame_regnum = FP_REGNUM; + /* 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 (DEPRECATED_FP_REGNUM >= 0 && DEPRECATED_FP_REGNUM < NUM_REGS) + *frame_regnum = DEPRECATED_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); + if (gdbarch_register_type_p (current_gdbarch)) + return TYPE_LENGTH (gdbarch_register_type (current_gdbarch, regnum)); + else + /* FIXME: cagney/2003-03-01: Once all architectures implement + gdbarch_register_type(), this entire function can go away. It + is made obsolete by register_size(). */ + return TYPE_LENGTH (REGISTER_VIRTUAL_TYPE (regnum)); /* OK */ +} + +/* 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 += generic_register_size (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. */ -#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 */ -#endif /* ``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"; @@ -403,20 +532,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; } @@ -426,8 +551,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"); @@ -435,7 +560,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) @@ -444,8 +569,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"); @@ -453,7 +578,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 @@ -467,33 +592,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"); } @@ -623,7 +735,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__, @@ -655,7 +767,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"); @@ -692,7 +804,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 @@ -718,26 +830,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; @@ -745,12 +855,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) @@ -762,7 +872,13 @@ initialize_current_architecture (void) } } else - initialize_non_multiarch (); + { + /* 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. */ @@ -781,7 +897,7 @@ 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. */ @@ -791,6 +907,20 @@ initialize_current_architecture (void) } +/* 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; + info->osabi = GDB_OSABI_UNINITIALIZED; +} + /* */ extern initialize_file_ftype _initialize_gdbarch_utils; @@ -803,7 +933,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,