+ /* bfd_arch_info.mach corresponding to variant. */
+ unsigned long mach;
+
+ /* Table of register names; registers[R] is the name of the register
+ number R. */
+ int nregs;
+ const struct reg *regs;
+ };
+
+#define num_registers(list) (sizeof (list) / sizeof((list)[0]))
+
+
+/* Information in this table comes from the following web sites:
+ IBM: http://www.chips.ibm.com:80/products/embedded/
+ Motorola: http://www.mot.com/SPS/PowerPC/
+
+ I'm sure I've got some of the variant descriptions not quite right.
+ Please report any inaccuracies you find to GDB's maintainer.
+
+ If you add entries to this table, please be sure to allow the new
+ value as an argument to the --with-cpu flag, in configure.in. */
+
+static const struct variant variants[] =
+{
+ {"powerpc", "PowerPC user-level", bfd_arch_powerpc,
+ bfd_mach_ppc, num_registers (registers_powerpc), registers_powerpc},
+ {"power", "POWER user-level", bfd_arch_rs6000,
+ bfd_mach_rs6k, num_registers (registers_power), registers_power},
+ {"403", "IBM PowerPC 403", bfd_arch_powerpc,
+ bfd_mach_ppc_403, num_registers (registers_403), registers_403},
+ {"601", "Motorola PowerPC 601", bfd_arch_powerpc,
+ bfd_mach_ppc_601, num_registers (registers_601), registers_601},
+ {"602", "Motorola PowerPC 602", bfd_arch_powerpc,
+ bfd_mach_ppc_602, num_registers (registers_602), registers_602},
+ {"603", "Motorola/IBM PowerPC 603 or 603e", bfd_arch_powerpc,
+ bfd_mach_ppc_603, num_registers (registers_603), registers_603},
+ {"604", "Motorola PowerPC 604 or 604e", bfd_arch_powerpc,
+ 604, num_registers (registers_604), registers_604},
+ {"403GC", "IBM PowerPC 403GC", bfd_arch_powerpc,
+ bfd_mach_ppc_403gc, num_registers (registers_403GC), registers_403GC},
+ {"505", "Motorola PowerPC 505", bfd_arch_powerpc,
+ bfd_mach_ppc_505, num_registers (registers_505), registers_505},
+ {"860", "Motorola PowerPC 860 or 850", bfd_arch_powerpc,
+ bfd_mach_ppc_860, num_registers (registers_860), registers_860},
+ {"750", "Motorola/IBM PowerPC 750 or 740", bfd_arch_powerpc,
+ bfd_mach_ppc_750, num_registers (registers_750), registers_750},
+
+ /* FIXME: I haven't checked the register sets of the following. */
+ {"620", "Motorola PowerPC 620", bfd_arch_powerpc,
+ bfd_mach_ppc_620, num_registers (registers_powerpc), registers_powerpc},
+ {"a35", "PowerPC A35", bfd_arch_powerpc,
+ bfd_mach_ppc_a35, num_registers (registers_powerpc), registers_powerpc},
+ {"rs1", "IBM POWER RS1", bfd_arch_rs6000,
+ bfd_mach_rs6k_rs1, num_registers (registers_power), registers_power},
+ {"rsc", "IBM POWER RSC", bfd_arch_rs6000,
+ bfd_mach_rs6k_rsc, num_registers (registers_power), registers_power},
+ {"rs2", "IBM POWER RS2", bfd_arch_rs6000,
+ bfd_mach_rs6k_rs2, num_registers (registers_power), registers_power},
+
+ {0, 0, 0, 0}
+};
+
+#undef num_registers
+
+/* Look up the variant named NAME in the `variants' table. Return a
+ pointer to the struct variant, or null if we couldn't find it. */
+
+static const struct variant *
+find_variant_by_name (char *name)
+{
+ const struct variant *v;
+
+ for (v = variants; v->name; v++)
+ if (!strcmp (name, v->name))
+ return v;
+
+ return NULL;
+}
+
+/* Return the variant corresponding to architecture ARCH and machine number
+ MACH. If no such variant exists, return null. */
+
+static const struct variant *
+find_variant_by_arch (enum bfd_architecture arch, unsigned long mach)
+{
+ const struct variant *v;
+
+ for (v = variants; v->name; v++)
+ if (arch == v->arch && mach == v->mach)
+ return v;
+
+ return NULL;
+}
+
+
+
+\f
+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;
+}
+
+\f
+
+/* 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.
+
+ Called e.g. at program startup, when reading a core file, and when reading
+ a binary file. */
+
+static struct gdbarch *
+rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+ struct gdbarch *gdbarch;
+ struct gdbarch_tdep *tdep;
+ int wordsize, from_xcoff_exec, from_elf_exec, power, i, off;
+ struct reg *regs;
+ const struct variant *v;
+ enum bfd_architecture arch;
+ unsigned long mach;
+ bfd abfd;
+ int osabi, sysv_abi;
+
+ from_xcoff_exec = info.abfd && info.abfd->format == bfd_object &&
+ bfd_get_flavour (info.abfd) == bfd_target_xcoff_flavour;
+
+ from_elf_exec = info.abfd && info.abfd->format == bfd_object &&
+ bfd_get_flavour (info.abfd) == bfd_target_elf_flavour;
+
+ sysv_abi = info.abfd && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour;
+
+ osabi = get_elfosabi (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)
+ wordsize = 8;
+ else
+ wordsize = 4;
+ }
+ else if (from_elf_exec)
+ {
+ if (elf_elfheader (info.abfd)->e_ident[EI_CLASS] == ELFCLASS64)
+ wordsize = 8;
+ else
+ wordsize = 4;
+ }
+ else
+ {
+ wordsize = 4;
+ }
+
+ /* Find a candidate among extant architectures. */
+ for (arches = gdbarch_list_lookup_by_info (arches, &info);
+ arches != NULL;
+ arches = gdbarch_list_lookup_by_info (arches->next, &info))
+ {
+ /* Word size in the various PowerPC bfd_arch_info structs isn't
+ meaningful, because 64-bit CPUs can run in 32-bit mode. So, perform
+ separate word size check. */
+ tdep = gdbarch_tdep (arches->gdbarch);
+ if (tdep && tdep->wordsize == wordsize && tdep->osabi == osabi)
+ return arches->gdbarch;
+ }
+
+ /* None found, create a new architecture from INFO, whose bfd_arch_info
+ validity depends on the source:
+ - executable useless
+ - rs6000_host_arch() good
+ - core file good
+ - "set arch" trust blindly
+ - GDB startup useless but harmless */
+
+ if (!from_xcoff_exec)
+ {
+ arch = info.bfd_arch_info->arch;
+ mach = info.bfd_arch_info->mach;
+ }
+ else
+ {
+ arch = bfd_arch_powerpc;
+ mach = 0;
+ bfd_default_set_arch_mach (&abfd, arch, mach);
+ info.bfd_arch_info = bfd_get_arch_info (&abfd);
+ }
+ tdep = xmalloc (sizeof (struct gdbarch_tdep));
+ tdep->wordsize = wordsize;
+ tdep->osabi = osabi;
+ gdbarch = gdbarch_alloc (&info, tdep);
+ power = arch == bfd_arch_rs6000;
+
+ /* Select instruction printer. */
+ tm_print_insn = arch == power ? print_insn_rs6000 :
+ info.byte_order == BIG_ENDIAN ? print_insn_big_powerpc :
+ print_insn_little_powerpc;
+
+ /* Choose variant. */
+ v = find_variant_by_arch (arch, mach);
+ if (!v)
+ v = find_variant_by_name (power ? "power" : "powerpc");
+ tdep->regs = v->regs;
+
+ /* Calculate byte offsets in raw register array. */
+ tdep->regoff = xmalloc (v->nregs * sizeof (int));
+ for (i = off = 0; i < v->nregs; i++)
+ {
+ tdep->regoff[i] = off;
+ off += regsize (v->regs + i, wordsize);
+ }
+
+ set_gdbarch_read_pc (gdbarch, generic_target_read_pc);
+ set_gdbarch_write_pc (gdbarch, generic_target_write_pc);
+ set_gdbarch_read_fp (gdbarch, generic_target_read_fp);
+ set_gdbarch_write_fp (gdbarch, generic_target_write_fp);
+ set_gdbarch_read_sp (gdbarch, generic_target_read_sp);
+ set_gdbarch_write_sp (gdbarch, generic_target_write_sp);
+
+ set_gdbarch_num_regs (gdbarch, v->nregs);
+ set_gdbarch_sp_regnum (gdbarch, 1);
+ set_gdbarch_fp_regnum (gdbarch, 1);
+ set_gdbarch_pc_regnum (gdbarch, 64);
+ set_gdbarch_register_name (gdbarch, rs6000_register_name);
+ set_gdbarch_register_size (gdbarch, wordsize);
+ set_gdbarch_register_bytes (gdbarch, off);
+ 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, 8);
+ set_gdbarch_register_virtual_size (gdbarch, rs6000_register_virtual_size);
+ set_gdbarch_max_register_virtual_size (gdbarch, 8);
+ set_gdbarch_register_virtual_type (gdbarch, rs6000_register_virtual_type);
+
+ set_gdbarch_ptr_bit (gdbarch, wordsize * TARGET_CHAR_BIT);
+ set_gdbarch_short_bit (gdbarch, 2 * TARGET_CHAR_BIT);
+ set_gdbarch_int_bit (gdbarch, 4 * TARGET_CHAR_BIT);
+ set_gdbarch_long_bit (gdbarch, wordsize * TARGET_CHAR_BIT);
+ set_gdbarch_long_long_bit (gdbarch, 8 * TARGET_CHAR_BIT);
+ set_gdbarch_float_bit (gdbarch, 4 * TARGET_CHAR_BIT);
+ set_gdbarch_double_bit (gdbarch, 8 * TARGET_CHAR_BIT);
+ set_gdbarch_long_double_bit (gdbarch, 8 * TARGET_CHAR_BIT);
+
+ set_gdbarch_use_generic_dummy_frames (gdbarch, 1);
+ set_gdbarch_call_dummy_length (gdbarch, 0);
+ set_gdbarch_call_dummy_location (gdbarch, AT_ENTRY_POINT);
+ set_gdbarch_call_dummy_address (gdbarch, entry_point_address);
+ set_gdbarch_call_dummy_breakpoint_offset_p (gdbarch, 1);
+ set_gdbarch_call_dummy_breakpoint_offset (gdbarch, 0);
+ set_gdbarch_call_dummy_start_offset (gdbarch, 0);
+ set_gdbarch_pc_in_call_dummy (gdbarch, generic_pc_in_call_dummy);
+ set_gdbarch_call_dummy_p (gdbarch, 1);
+ set_gdbarch_call_dummy_stack_adjust_p (gdbarch, 0);
+ set_gdbarch_get_saved_register (gdbarch, generic_get_saved_register);
+ set_gdbarch_fix_call_dummy (gdbarch, rs6000_fix_call_dummy);
+ set_gdbarch_push_dummy_frame (gdbarch, generic_push_dummy_frame);
+ set_gdbarch_save_dummy_frame_tos (gdbarch, generic_save_dummy_frame_tos);
+ set_gdbarch_push_return_address (gdbarch, ppc_push_return_address);
+ set_gdbarch_believe_pcc_promotion (gdbarch, 1);
+ set_gdbarch_coerce_float_to_double (gdbarch, rs6000_coerce_float_to_double);
+
+ set_gdbarch_register_convertible (gdbarch, rs6000_register_convertible);
+ set_gdbarch_register_convert_to_virtual (gdbarch, rs6000_register_convert_to_virtual);
+ set_gdbarch_register_convert_to_raw (gdbarch, rs6000_register_convert_to_raw);
+
+ set_gdbarch_extract_return_value (gdbarch, rs6000_extract_return_value);
+
+ if (sysv_abi)
+ set_gdbarch_push_arguments (gdbarch, ppc_sysv_abi_push_arguments);
+ else
+ set_gdbarch_push_arguments (gdbarch, rs6000_push_arguments);
+
+ set_gdbarch_store_struct_return (gdbarch, rs6000_store_struct_return);
+ set_gdbarch_store_return_value (gdbarch, rs6000_store_return_value);
+ set_gdbarch_extract_struct_value_address (gdbarch, rs6000_extract_struct_value_address);
+ set_gdbarch_use_struct_convention (gdbarch, generic_use_struct_convention);
+
+ set_gdbarch_pop_frame (gdbarch, rs6000_pop_frame);
+
+ set_gdbarch_skip_prologue (gdbarch, rs6000_skip_prologue);
+ set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+ set_gdbarch_decr_pc_after_break (gdbarch, 0);
+ set_gdbarch_function_start_offset (gdbarch, 0);
+ set_gdbarch_breakpoint_from_pc (gdbarch, rs6000_breakpoint_from_pc);
+
+ /* Not sure on this. FIXMEmgo */
+ set_gdbarch_frame_args_skip (gdbarch, 8);
+
+ 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);
+ }
+ 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);
+
+ /* Handle RS/6000 function pointers. */
+ set_gdbarch_convert_from_func_ptr_addr (gdbarch,
+ rs6000_convert_from_func_ptr_addr);
+ }
+ set_gdbarch_frame_args_address (gdbarch, rs6000_frame_args_address);
+ set_gdbarch_frame_locals_address (gdbarch, rs6000_frame_args_address);
+ set_gdbarch_saved_pc_after_call (gdbarch, rs6000_saved_pc_after_call);
+
+ /* We can't tell how many args there are
+ now that the C compiler delays popping them. */
+ set_gdbarch_frame_num_args (gdbarch, frame_num_args_unknown);
+
+ return gdbarch;
+}
+
+/* Initialization code. */
+
+void
+_initialize_rs6000_tdep (void)
+{
+ register_gdbarch_init (bfd_arch_rs6000, rs6000_gdbarch_init);
+ register_gdbarch_init (bfd_arch_powerpc, rs6000_gdbarch_init);