X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Frs6000-tdep.c;h=f91de78898d356b20e7d458606b3644f4f12f16d;hb=7b112f9c0c091098e7b67fbd4b15c445effebfb4;hp=72e1fbd3c7852f19df8510478ab1ca66c3740a6c;hpb=5d57ee30b32f18261ff10f664e5b5f8c9e5052e9;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c index 72e1fbd3c7..f91de78898 100644 --- a/gdb/rs6000-tdep.c +++ b/gdb/rs6000-tdep.c @@ -38,6 +38,8 @@ #include "libbfd.h" /* for bfd_default_set_arch_mach */ #include "coff/internal.h" /* for libcoff.h */ #include "libcoff.h" /* for xcoff_data */ +#include "coff/xcoff.h" +#include "libxcoff.h" #include "elf-bfd.h" @@ -280,7 +282,7 @@ branch_dest (int opcode, int instr, CORE_ADDR pc, CORE_ADDR safety) #define BIG_BREAKPOINT { 0x7d, 0x82, 0x10, 0x08 } #define LITTLE_BREAKPOINT { 0x08, 0x10, 0x82, 0x7d } -static unsigned char * +const static unsigned char * rs6000_breakpoint_from_pc (CORE_ADDR *bp_addr, int *bp_size) { static unsigned char big_breakpoint[] = BIG_BREAKPOINT; @@ -301,7 +303,7 @@ rs6000_software_single_step (enum target_signal signal, { CORE_ADDR dummy; int breakp_sz; - char *breakp = rs6000_breakpoint_from_pc (&dummy, &breakp_sz); + const char *breakp = rs6000_breakpoint_from_pc (&dummy, &breakp_sz); int ii, insn; CORE_ADDR loc; CORE_ADDR breaks[2]; @@ -1144,6 +1146,7 @@ static void rs6000_extract_return_value (struct type *valtype, char *regbuf, char *valbuf) { int offset = 0; + struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); if (TYPE_CODE (valtype) == TYPE_CODE_FLT) { @@ -1165,6 +1168,13 @@ rs6000_extract_return_value (struct type *valtype, char *regbuf, char *valbuf) memcpy (valbuf, &ff, sizeof (float)); } } + else if (TYPE_CODE (valtype) == TYPE_CODE_ARRAY + && TYPE_LENGTH (valtype) == 16 + && TYPE_VECTOR (valtype)) + { + memcpy (valbuf, regbuf + REGISTER_BYTE (tdep->ppc_vr0_regnum + 2), + TYPE_LENGTH (valtype)); + } else { /* return value is copied starting from r3. */ @@ -1319,7 +1329,8 @@ rs6000_frame_saved_pc (struct frame_info *fi) { CORE_ADDR func_start; struct rs6000_framedata fdata; - int wordsize = TDEP->wordsize; + struct gdbarch_tdep *tdep = TDEP; + int wordsize = tdep->wordsize; if (fi->signal_handler_caller) return read_memory_addr (fi->frame + SIG_FRAME_PC_OFFSET, wordsize); @@ -1342,7 +1353,7 @@ rs6000_frame_saved_pc (struct frame_info *fi) return read_memory_addr (fi->next->frame + SIG_FRAME_LR_OFFSET, wordsize); else - return read_memory_addr (FRAME_CHAIN (fi) + DEFAULT_LR_SAVE, + return read_memory_addr (FRAME_CHAIN (fi) + tdep->lr_frame_offset, wordsize); } @@ -1387,10 +1398,13 @@ frame_get_saved_regs (struct frame_info *fi, struct rs6000_framedata *fdatap) && fdatap->cr_offset == 0 && fdatap->vr_offset == 0) frame_addr = 0; - else if (fi->prev && fi->prev->frame) - frame_addr = fi->prev->frame; else - frame_addr = read_memory_addr (fi->frame, wordsize); + /* NOTE: cagney/2002-04-14: The ->frame points to the inner-most + address of the current frame. Things might be easier if the + ->frame pointed to the outer-most address of the frame. In the + mean time, the address of the prev frame is used as the base + address of this frame. */ + frame_addr = FRAME_CHAIN (fi); /* if != -1, fdatap->saved_fpr is the smallest number of saved_fpr. All fpr's from saved_fpr to fp31 are saved. */ @@ -1487,41 +1501,22 @@ frame_initial_stack_address (struct frame_info *fi) return fi->extra_info->initial_sp; } - /* This function has an alloca register. If this is the top-most frame - (with the lowest address), the value in alloca register is good. */ - - if (!fi->next) - return fi->extra_info->initial_sp = read_register (fdata.alloca_reg); - - /* Otherwise, this is a caller frame. Callee has usually already saved - registers, but there are exceptions (such as when the callee - has no parameters). Find the address in which caller's alloca - register is saved. */ - - for (callee_fi = fi->next; callee_fi; callee_fi = callee_fi->next) - { - - if (!callee_fi->saved_regs) - frame_get_saved_regs (callee_fi, NULL); - - /* this is the address in which alloca register is saved. */ - - tmpaddr = callee_fi->saved_regs[fdata.alloca_reg]; - if (tmpaddr) - { - fi->extra_info->initial_sp = - read_memory_addr (tmpaddr, TDEP->wordsize); - return fi->extra_info->initial_sp; - } - - /* Go look into deeper levels of the frame chain to see if any one of - the callees has saved alloca register. */ - } - - /* If alloca register was not saved, by the callee (or any of its callees) - then the value in the register is still good. */ - - fi->extra_info->initial_sp = read_register (fdata.alloca_reg); + /* There is an alloca register, use its value, in the current frame, + as the initial stack pointer. */ + { + char *tmpbuf = alloca (MAX_REGISTER_RAW_SIZE); + if (frame_register_read (fi, fdata.alloca_reg, tmpbuf)) + { + fi->extra_info->initial_sp + = extract_unsigned_integer (tmpbuf, + REGISTER_RAW_SIZE (fdata.alloca_reg)); + } + else + /* NOTE: cagney/2002-04-17: At present the only time + frame_register_read will fail is when the register isn't + available. If that does happen, use the frame. */ + fi->extra_info->initial_sp = fi->frame; + } return fi->extra_info->initial_sp; } @@ -1729,7 +1724,7 @@ rs6000_do_altivec_registers (int regnum) print_spaces_filtered (15 - strlen (REGISTER_NAME (i)), gdb_stdout); /* Get the data in raw format. */ - if (read_relative_register_raw_bytes (i, raw_buffer)) + if (!frame_register_read (selected_frame, i, raw_buffer)) { printf_filtered ("*value not available*\n"); continue; @@ -1826,7 +1821,7 @@ rs6000_do_registers_info (int regnum, int fpregs) print_spaces_filtered (15 - strlen (REGISTER_NAME (i)), gdb_stdout); /* Get the data in raw format. */ - if (read_relative_register_raw_bytes (i, raw_buffer)) + if (!frame_register_read (selected_frame, i, raw_buffer)) { printf_filtered ("*value not available*\n"); continue; @@ -1858,19 +1853,16 @@ rs6000_do_registers_info (int regnum, int fpregs) } else { - /* Print as integer in hex and in decimal. */ + /* Print the register in hex. */ + val_print (REGISTER_VIRTUAL_TYPE (i), virtual_buffer, 0, 0, + gdb_stdout, 'x', 1, 0, Val_pretty_default); + /* If not a vector register, print it also in decimal. */ if (!altivec_register_p (i)) { - val_print (REGISTER_VIRTUAL_TYPE (i), virtual_buffer, 0, 0, - gdb_stdout, 'x', 1, 0, Val_pretty_default); printf_filtered ("\t"); val_print (REGISTER_VIRTUAL_TYPE (i), virtual_buffer, 0, 0, gdb_stdout, 0, 1, 0, Val_pretty_default); } - else - /* Print as integer in hex only. */ - val_print (REGISTER_VIRTUAL_TYPE (i), virtual_buffer, 0, 0, - gdb_stdout, 'x', 1, 0, Val_pretty_default); } printf_filtered ("\n"); } @@ -1924,6 +1916,8 @@ rs6000_store_struct_return (CORE_ADDR addr, CORE_ADDR sp) static void rs6000_store_return_value (struct type *type, char *valbuf) { + struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); + if (TYPE_CODE (type) == TYPE_CODE_FLT) /* Floating point values are returned starting from FPR1 and up. @@ -1932,6 +1926,13 @@ rs6000_store_return_value (struct type *type, char *valbuf) write_register_bytes (REGISTER_BYTE (FP0_REGNUM + 1), valbuf, TYPE_LENGTH (type)); + else if (TYPE_CODE (type) == TYPE_CODE_ARRAY) + { + if (TYPE_LENGTH (type) == 16 + && TYPE_VECTOR (type)) + write_register_bytes (REGISTER_BYTE (tdep->ppc_vr0_regnum + 2), + valbuf, TYPE_LENGTH (type)); + } else /* Everything else is returned in GPR3 and up. */ write_register_bytes (REGISTER_BYTE (gdbarch_tdep (current_gdbarch)->ppc_gp0_regnum + 3), @@ -2022,7 +2023,21 @@ rs6000_convert_from_func_ptr_addr (CORE_ADDR addr) Most of these register groups aren't anything formal. I arrived at them by looking at the registers that occurred in more than one - processor. */ + processor. + + Note: kevinb/2002-04-30: Support for the fpscr register was added + during April, 2002. Slot 70 is being used for PowerPC and slot 71 + for Power. For PowerPC, slot 70 was unused and was already in the + PPC_UISA_SPRS which is ideally where fpscr should go. For Power, + slot 70 was being used for "mq", so the next available slot (71) + was chosen. It would have been nice to be able to make the + register numbers the same across processor cores, but this wasn't + possible without either 1) renumbering some registers for some + processors or 2) assigning fpscr to a really high slot that's + larger than any current register number. Doing (1) is bad because + existing stubs would break. Doing (2) is undesirable because it + would introduce a really large gap between fpscr and the rest of + the registers for most processors. */ /* Convenience macros for populating register arrays. */ @@ -2073,6 +2088,17 @@ rs6000_convert_from_func_ptr_addr (CORE_ADDR addr) /* 56 */ F(f24),F(f25),F(f26),F(f27),F(f28),F(f29),F(f30),F(f31), \ /* 64 */ R(pc), R(ps) +#define COMMON_UISA_NOFP_REGS \ + /* 0 */ R(r0), R(r1), R(r2), R(r3), R(r4), R(r5), R(r6), R(r7), \ + /* 8 */ R(r8), R(r9), R(r10),R(r11),R(r12),R(r13),R(r14),R(r15), \ + /* 16 */ R(r16),R(r17),R(r18),R(r19),R(r20),R(r21),R(r22),R(r23), \ + /* 24 */ R(r24),R(r25),R(r26),R(r27),R(r28),R(r29),R(r30),R(r31), \ + /* 32 */ R0, R0, R0, R0, R0, R0, R0, R0, \ + /* 40 */ R0, R0, R0, R0, R0, R0, R0, R0, \ + /* 48 */ R0, R0, R0, R0, R0, R0, R0, R0, \ + /* 56 */ R0, R0, R0, R0, R0, R0, R0, R0, \ + /* 64 */ R(pc), R(ps) + /* UISA-level SPRs for PowerPC. */ #define PPC_UISA_SPRS \ /* 66 */ R4(cr), R(lr), R(ctr), R4(xer), R4(fpscr) @@ -2122,6 +2148,14 @@ static const struct reg registers_powerpc[] = PPC_ALTIVEC_REGS }; +/* PowerPC UISA - a PPC processor as viewed by user-level + code, but without floating point registers. */ +static const struct reg registers_powerpc_nofp[] = +{ + COMMON_UISA_NOFP_REGS, + PPC_UISA_SPRS +}; + /* IBM PowerPC 403. */ static const struct reg registers_403[] = { @@ -2368,88 +2402,7 @@ find_variant_by_arch (enum bfd_architecture arch, unsigned long mach) return NULL; } - - - -static void -process_note_abi_tag_sections (bfd *abfd, asection *sect, void *obj) -{ - int *os_ident_ptr = obj; - const char *name; - unsigned int sectsize; - - name = bfd_get_section_name (abfd, sect); - sectsize = bfd_section_size (abfd, sect); - if (strcmp (name, ".note.ABI-tag") == 0 && sectsize > 0) - { - unsigned int name_length, data_length, note_type; - char *note = alloca (sectsize); - - bfd_get_section_contents (abfd, sect, note, - (file_ptr) 0, (bfd_size_type) sectsize); - - name_length = bfd_h_get_32 (abfd, note); - data_length = bfd_h_get_32 (abfd, note + 4); - note_type = bfd_h_get_32 (abfd, note + 8); - - if (name_length == 4 && data_length == 16 && note_type == 1 - && strcmp (note + 12, "GNU") == 0) - { - int os_number = bfd_h_get_32 (abfd, note + 16); - - /* The case numbers are from abi-tags in glibc */ - switch (os_number) - { - case 0 : - *os_ident_ptr = ELFOSABI_LINUX; - break; - case 1 : - *os_ident_ptr = ELFOSABI_HURD; - break; - case 2 : - *os_ident_ptr = ELFOSABI_SOLARIS; - break; - default : - internal_error (__FILE__, __LINE__, - "process_note_abi_sections: unknown OS number %d", - os_number); - break; - } - } - } -} - -/* Return one of the ELFOSABI_ constants for BFDs representing ELF - executables. If it's not an ELF executable or if the OS/ABI couldn't - be determined, simply return -1. */ - -static int -get_elfosabi (bfd *abfd) -{ - int elfosabi = -1; - - if (abfd != NULL && bfd_get_flavour (abfd) == bfd_target_elf_flavour) - { - elfosabi = elf_elfheader (abfd)->e_ident[EI_OSABI]; - - /* When elfosabi is 0 (ELFOSABI_NONE), this is supposed to indicate - that we're on a SYSV system. However, GNU/Linux uses a note section - to record OS/ABI info, but leaves e_ident[EI_OSABI] zero. So we - have to check the note sections too. */ - if (elfosabi == 0) - { - bfd_map_over_sections (abfd, - process_note_abi_tag_sections, - &elfosabi); - } - } - - return elfosabi; -} - - - /* Initialize the current architecture based on INFO. If possible, re-use an architecture from ARCHES, which is a list of architectures already created during this debugging session. @@ -2468,7 +2421,8 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) enum bfd_architecture arch; unsigned long mach; bfd abfd; - int osabi, sysv_abi; + int sysv_abi; + enum gdb_osabi osabi = GDB_OSABI_UNKNOWN; gdbarch_print_insn_ftype *print_insn; from_xcoff_exec = info.abfd && info.abfd->format == bfd_object && @@ -2479,13 +2433,14 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) sysv_abi = info.abfd && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour; - osabi = get_elfosabi (info.abfd); + if (info.abfd) + osabi = gdbarch_lookup_osabi (info.abfd); /* Check word size. If INFO is from a binary file, infer it from that, else choose a likely default. */ if (from_xcoff_exec) { - if (xcoff_data (info.abfd)->xcoff64) + if (bfd_xcoff_is_xcoff64 (info.abfd)) wordsize = 8; else wordsize = 4; @@ -2499,7 +2454,11 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) } else { - wordsize = 4; + if (info.bfd_arch_info != NULL && info.bfd_arch_info->bits_per_word != 0) + wordsize = info.bfd_arch_info->bits_per_word / + info.bfd_arch_info->bits_per_byte; + else + wordsize = 4; } /* Find a candidate among extant architectures. */ @@ -2581,7 +2540,15 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) break; } - /* Calculate byte offsets in raw register array. */ + /* Set lr_frame_offset. */ + if (wordsize == 8) + tdep->lr_frame_offset = 16; + else if (sysv_abi) + tdep->lr_frame_offset = 4; + else + tdep->lr_frame_offset = 8; + + /* Calculate byte offsets in raw register array. */ tdep->regoff = xmalloc (v->nregs * sizeof (int)); for (i = off = 0; i < v->nregs; i++) { @@ -2614,7 +2581,7 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_register_byte (gdbarch, rs6000_register_byte); set_gdbarch_register_raw_size (gdbarch, rs6000_register_raw_size); set_gdbarch_max_register_raw_size (gdbarch, 16); - set_gdbarch_register_virtual_size (gdbarch, generic_register_virtual_size); + set_gdbarch_register_virtual_size (gdbarch, generic_register_size); set_gdbarch_max_register_virtual_size (gdbarch, 16); set_gdbarch_register_virtual_type (gdbarch, rs6000_register_virtual_type); set_gdbarch_do_registers_info (gdbarch, rs6000_do_registers_info); @@ -2654,7 +2621,14 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_extract_return_value (gdbarch, rs6000_extract_return_value); - if (sysv_abi) + /* Note: kevinb/2002-04-12: I'm not convinced that rs6000_push_arguments() + is correct for the SysV ABI when the wordsize is 8, but I'm also + fairly certain that ppc_sysv_abi_push_arguments() will give even + worse results since it only works for 32-bit code. So, for the moment, + we're better off calling rs6000_push_arguments() since it works for + 64-bit code. At some point in the future, this matter needs to be + revisited. */ + if (sysv_abi && wordsize == 4) set_gdbarch_push_arguments (gdbarch, ppc_sysv_abi_push_arguments); else set_gdbarch_push_arguments (gdbarch, rs6000_push_arguments); @@ -2673,56 +2647,27 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) /* Not sure on this. FIXMEmgo */ set_gdbarch_frame_args_skip (gdbarch, 8); - /* Until November 2001, gcc was not complying to the SYSV ABI for - returning structures less than or equal to 8 bytes in size. It was - returning everything in memory. When this was corrected, it wasn't - fixed for native platforms. */ if (sysv_abi) - { - if (osabi == ELFOSABI_LINUX - || osabi == ELFOSABI_NETBSD - || osabi == ELFOSABI_FREEBSD) - set_gdbarch_use_struct_convention (gdbarch, - generic_use_struct_convention); - else - set_gdbarch_use_struct_convention (gdbarch, - ppc_sysv_abi_use_struct_convention); - } + set_gdbarch_use_struct_convention (gdbarch, + ppc_sysv_abi_use_struct_convention); else - { - set_gdbarch_use_struct_convention (gdbarch, - generic_use_struct_convention); - } + set_gdbarch_use_struct_convention (gdbarch, + generic_use_struct_convention); set_gdbarch_frame_chain_valid (gdbarch, file_frame_chain_valid); - if (osabi == ELFOSABI_LINUX) - { - set_gdbarch_frameless_function_invocation (gdbarch, - ppc_linux_frameless_function_invocation); - set_gdbarch_frame_chain (gdbarch, ppc_linux_frame_chain); - set_gdbarch_frame_saved_pc (gdbarch, ppc_linux_frame_saved_pc); - - set_gdbarch_frame_init_saved_regs (gdbarch, - ppc_linux_frame_init_saved_regs); - set_gdbarch_init_extra_frame_info (gdbarch, - ppc_linux_init_extra_frame_info); - - set_gdbarch_memory_remove_breakpoint (gdbarch, - ppc_linux_memory_remove_breakpoint); - set_solib_svr4_fetch_link_map_offsets - (gdbarch, ppc_linux_svr4_fetch_link_map_offsets); - } - else - { - set_gdbarch_frameless_function_invocation (gdbarch, - rs6000_frameless_function_invocation); - set_gdbarch_frame_chain (gdbarch, rs6000_frame_chain); - set_gdbarch_frame_saved_pc (gdbarch, rs6000_frame_saved_pc); - set_gdbarch_frame_init_saved_regs (gdbarch, rs6000_frame_init_saved_regs); - set_gdbarch_init_extra_frame_info (gdbarch, rs6000_init_extra_frame_info); + set_gdbarch_frameless_function_invocation (gdbarch, + rs6000_frameless_function_invocation); + set_gdbarch_frame_chain (gdbarch, rs6000_frame_chain); + set_gdbarch_frame_saved_pc (gdbarch, rs6000_frame_saved_pc); - /* Handle RS/6000 function pointers. */ + set_gdbarch_frame_init_saved_regs (gdbarch, rs6000_frame_init_saved_regs); + set_gdbarch_init_extra_frame_info (gdbarch, rs6000_init_extra_frame_info); + + if (!sysv_abi) + { + /* Handle RS/6000 function pointers (which are really function + descriptors). */ set_gdbarch_convert_from_func_ptr_addr (gdbarch, rs6000_convert_from_func_ptr_addr); } @@ -2734,9 +2679,24 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) now that the C compiler delays popping them. */ set_gdbarch_frame_num_args (gdbarch, frame_num_args_unknown); + /* Hook in ABI-specific overrides, if they have been registered. */ + gdbarch_init_osabi (info, gdbarch, osabi); + return gdbarch; } +static void +rs6000_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); + + if (tdep == NULL) + return; + + fprintf_unfiltered (file, "rs6000_dump_tdep: OS ABI = %s\n", + gdbarch_osabi_name (tdep->osabi)); +} + static struct cmd_list_element *info_powerpc_cmdlist = NULL; static void @@ -2750,8 +2710,8 @@ rs6000_info_powerpc_command (char *args, int from_tty) void _initialize_rs6000_tdep (void) { - register_gdbarch_init (bfd_arch_rs6000, rs6000_gdbarch_init); - register_gdbarch_init (bfd_arch_powerpc, rs6000_gdbarch_init); + gdbarch_register (bfd_arch_rs6000, rs6000_gdbarch_init, rs6000_dump_tdep); + gdbarch_register (bfd_arch_powerpc, rs6000_gdbarch_init, rs6000_dump_tdep); /* Add root prefix command for "info powerpc" commands */ add_prefix_cmd ("powerpc", class_info, rs6000_info_powerpc_command, @@ -2761,5 +2721,4 @@ _initialize_rs6000_tdep (void) add_cmd ("altivec", class_info, rs6000_altivec_registers_info, "Display the contents of the AltiVec registers.", &info_powerpc_cmdlist); - }