X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=gdb%2Frs6000-tdep.c;h=82c18c1dac2e9210aba04013c97ce9ce07724731;hb=1d9d99f32d861ae85dd59689ada801cc51d3ac91;hp=66cee5a2055c75f731fc96726c401d683e149601;hpb=fe794dc69d09f9a6fed65befc4597fd217fc449b;p=binutils-gdb.git diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c index 66cee5a2055..82c18c1dac2 100644 --- a/gdb/rs6000-tdep.c +++ b/gdb/rs6000-tdep.c @@ -1,5 +1,6 @@ /* Target-dependent code for GDB, the GNU debugger. - Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000 + Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, + 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This file is part of GDB. @@ -28,22 +29,17 @@ #include "gdbcmd.h" #include "symfile.h" #include "objfiles.h" -#include "xcoffsolib.h" #include "arch-utils.h" +#include "regcache.h" +#include "doublest.h" #include "bfd/libbfd.h" /* for bfd_default_set_arch_mach */ #include "coff/internal.h" /* for libcoff.h */ #include "bfd/libcoff.h" /* for xcoff_data */ -/* Some important register numbers. Keep these in the same order as in - /usr/mstsave.h `mstsave' structure, for easier processing. */ +#include "elf-bfd.h" -#define GP0_REGNUM 0 /* GPR register 0 */ -#define TOC_REGNUM 2 /* TOC register */ -#define PS_REGNUM 65 /* Processor (or machine) status (%msr) */ -#define CR_REGNUM 66 /* Condition register */ -#define LR_REGNUM 67 /* Link register */ -#define CTR_REGNUM 68 /* Count register */ +#include "ppc-tdep.h" /* If the kernel has to deliver a signal, it pushes a sigcontext structure on the stack and then calls the signal handler, passing @@ -89,6 +85,7 @@ struct reg struct gdbarch_tdep { int wordsize; /* size in bytes of fixed-point word */ + int osabi; /* OS / ABI from ELF header */ int *regoff; /* byte offsets in register arrays */ const struct reg *regs; /* from current variant */ }; @@ -123,7 +120,8 @@ void (*rs6000_set_host_arch_hook) (int) = NULL; static CORE_ADDR branch_dest (int opcode, int instr, CORE_ADDR pc, CORE_ADDR safety); -static CORE_ADDR skip_prologue (CORE_ADDR, struct rs6000_framedata *); +static CORE_ADDR skip_prologue (CORE_ADDR, CORE_ADDR, + struct rs6000_framedata *); static void frame_get_saved_regs (struct frame_info * fi, struct rs6000_framedata * fdatap); static CORE_ADDR frame_initial_stack_address (struct frame_info *); @@ -140,7 +138,7 @@ static CORE_ADDR rs6000_skip_prologue (CORE_ADDR pc) { struct rs6000_framedata frame; - pc = skip_prologue (pc, &frame); + pc = skip_prologue (pc, 0, &frame); return pc; } @@ -157,7 +155,7 @@ struct frame_extra_info CORE_ADDR initial_sp; /* initial stack pointer. */ }; -static void +void rs6000_init_extra_frame_info (int fromleaf, struct frame_info *fi) { fi->extra_info = (struct frame_extra_info *) @@ -182,7 +180,7 @@ rs6000_init_extra_frame_info (int fromleaf, struct frame_info *fi) not sure if it will be needed. The following function takes care of gpr's and fpr's only. */ -static void +void rs6000_frame_init_saved_regs (struct frame_info *fi) { frame_get_saved_regs (fi, NULL); @@ -205,7 +203,7 @@ rs6000_frame_args_address (struct frame_info *fi) static CORE_ADDR rs6000_saved_pc_after_call (struct frame_info *fi) { - return read_register (LR_REGNUM); + return read_register (PPC_LR_REGNUM); } /* Calculate the destination of a branch/jump. Return -1 if not a branch. */ @@ -243,7 +241,7 @@ branch_dest (int opcode, int instr, CORE_ADDR pc, CORE_ADDR safety) if (ext_op == 16) /* br conditional register */ { - dest = read_register (LR_REGNUM) & ~3; + dest = read_register (PPC_LR_REGNUM) & ~3; /* If we are about to return from a signal handler, dest is something like 0x3c90. The current frame is a signal handler @@ -262,13 +260,13 @@ branch_dest (int opcode, int instr, CORE_ADDR pc, CORE_ADDR safety) else if (ext_op == 528) /* br cond to count reg */ { - dest = read_register (CTR_REGNUM) & ~3; + dest = read_register (PPC_CTR_REGNUM) & ~3; /* If we are about to execute a system call, dest is something like 0x22fc or 0x3b00. Upon completion the system call will return to the address in the link register. */ if (dest < TEXT_SEGMENT_BASE) - dest = read_register (LR_REGNUM) & ~3; + dest = read_register (PPC_LR_REGNUM) & ~3; } else return -1; @@ -302,7 +300,8 @@ rs6000_breakpoint_from_pc (CORE_ADDR *bp_addr, int *bp_size) /* AIX does not support PT_STEP. Simulate it. */ void -rs6000_software_single_step (unsigned int signal, int insert_breakpoints_p) +rs6000_software_single_step (enum target_signal signal, + int insert_breakpoints_p) { #define INSNLEN(OPCODE) 4 @@ -385,11 +384,63 @@ rs6000_software_single_step (unsigned int signal, int insert_breakpoints_p) #define GET_SRC_REG(x) (((x) >> 21) & 0x1f) +/* Limit the number of skipped non-prologue instructions, as the examining + of the prologue is expensive. */ +static int max_skip_non_prologue_insns = 10; + +/* Given PC representing the starting address of a function, and + LIM_PC which is the (sloppy) limit to which to scan when looking + for a prologue, attempt to further refine this limit by using + the line data in the symbol table. If successful, a better guess + on where the prologue ends is returned, otherwise the previous + value of lim_pc is returned. */ static CORE_ADDR -skip_prologue (CORE_ADDR pc, struct rs6000_framedata *fdata) +refine_prologue_limit (CORE_ADDR pc, CORE_ADDR lim_pc) +{ + struct symtab_and_line prologue_sal; + + prologue_sal = find_pc_line (pc, 0); + if (prologue_sal.line != 0) + { + int i; + CORE_ADDR addr = prologue_sal.end; + + /* Handle the case in which compiler's optimizer/scheduler + has moved instructions into the prologue. We scan ahead + in the function looking for address ranges whose corresponding + line number is less than or equal to the first one that we + found for the function. (It can be less than when the + scheduler puts a body instruction before the first prologue + instruction.) */ + for (i = 2 * max_skip_non_prologue_insns; + i > 0 && (lim_pc == 0 || addr < lim_pc); + i--) + { + struct symtab_and_line sal; + + sal = find_pc_line (addr, 0); + if (sal.line == 0) + break; + if (sal.line <= prologue_sal.line + && sal.symtab == prologue_sal.symtab) + { + prologue_sal = sal; + } + addr = sal.end; + } + + if (lim_pc == 0 || prologue_sal.end < lim_pc) + lim_pc = prologue_sal.end; + } + return lim_pc; +} + + +static CORE_ADDR +skip_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct rs6000_framedata *fdata) { CORE_ADDR orig_pc = pc; - CORE_ADDR last_prologue_pc; + CORE_ADDR last_prologue_pc = pc; char buf[4]; unsigned long op; long offset = 0; @@ -399,6 +450,22 @@ skip_prologue (CORE_ADDR pc, struct rs6000_framedata *fdata) int framep = 0; int minimal_toc_loaded = 0; int prev_insn_was_prologue_insn = 1; + int num_skip_non_prologue_insns = 0; + + /* Attempt to find the end of the prologue when no limit is specified. + Note that refine_prologue_limit() has been written so that it may + be used to "refine" the limits of non-zero PC values too, but this + is only safe if we 1) trust the line information provided by the + compiler and 2) iterate enough to actually find the end of the + prologue. + + It may become a good idea at some point (for both performance and + accuracy) to unconditionally call refine_prologue_limit(). But, + until we can make a clear determination that this is beneficial, + we'll play it safe and only use it to obtain a limit when none + has been specified. */ + if (lim_pc == 0) + lim_pc = refine_prologue_limit (pc, lim_pc); memset (fdata, 0, sizeof (struct rs6000_framedata)); fdata->saved_gpr = -1; @@ -407,19 +474,22 @@ skip_prologue (CORE_ADDR pc, struct rs6000_framedata *fdata) fdata->frameless = 1; fdata->nosavedpc = 1; - pc -= 4; - for (;;) + for (;; pc += 4) { - pc += 4; - /* Sometimes it isn't clear if an instruction is a prologue instruction or not. When we encounter one of these ambiguous cases, we'll set prev_insn_was_prologue_insn to 0 (false). Otherwise, we'll assume that it really is a prologue instruction. */ if (prev_insn_was_prologue_insn) last_prologue_pc = pc; + + /* Stop scanning if we've hit the limit. */ + if (lim_pc != 0 && pc >= lim_pc) + break; + prev_insn_was_prologue_insn = 1; + /* Fetch the instruction and convert it to an integer. */ if (target_read_memory (pc, buf, 4)) break; op = extract_signed_integer (buf, 4); @@ -633,7 +703,31 @@ skip_prologue (CORE_ADDR pc, struct rs6000_framedata *fdata) } else { - break; + /* Not a recognized prologue instruction. + Handle optimizer code motions into the prologue by continuing + the search if we have no valid frame yet or if the return + address is not yet saved in the frame. */ + if (fdata->frameless == 0 + && (lr_reg == -1 || fdata->nosavedpc == 0)) + break; + + if (op == 0x4e800020 /* blr */ + || op == 0x4e800420) /* bctr */ + /* Do not scan past epilogue in frameless functions or + trampolines. */ + break; + if ((op & 0xf4000000) == 0x40000000) /* bxx */ + /* Never skip branches. */ + break; + + if (num_skip_non_prologue_insns++ > max_skip_non_prologue_insns) + /* Do not scan too many insns, scanning insns is expensive with + remote targets. */ + break; + + /* Continue scanning. */ + prev_insn_was_prologue_insn = 0; + continue; } } @@ -660,7 +754,7 @@ skip_prologue (CORE_ADDR pc, struct rs6000_framedata *fdata) function as well. */ tmp = find_pc_misc_function (pc); - if (tmp >= 0 && STREQ (misc_function_vector[tmp].name, "main")) + if (tmp >= 0 && STREQ (misc_function_vector[tmp].name, main_name ())) return pc + 8; } } @@ -676,8 +770,6 @@ skip_prologue (CORE_ADDR pc, struct rs6000_framedata *fdata) frames, etc. *************************************************************************/ -extern int stop_stack_dummy; - /* Pop the innermost frame, go back to the caller. */ @@ -692,7 +784,7 @@ rs6000_pop_frame (void) pc = read_pc (); sp = FRAME_FP (frame); - if (stop_stack_dummy) + if (PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame)) { generic_pop_dummy_frame (); flush_cached_frames (); @@ -707,7 +799,7 @@ rs6000_pop_frame (void) saved %pc value in the previous frame. */ addr = get_pc_function_start (frame->pc); - (void) skip_prologue (addr, &fdata); + (void) skip_prologue (addr, frame->pc, &fdata); wordsize = TDEP->wordsize; if (fdata.frameless) @@ -715,7 +807,7 @@ rs6000_pop_frame (void) else prev_sp = read_memory_addr (sp, wordsize); if (fdata.lr_offset == 0) - lr = read_register (LR_REGNUM); + lr = read_register (PPC_LR_REGNUM); else lr = read_memory_addr (prev_sp + fdata.lr_offset, wordsize); @@ -754,7 +846,7 @@ rs6000_pop_frame (void) static void rs6000_fix_call_dummy (char *dummyname, CORE_ADDR pc, CORE_ADDR fun, - int nargs, value_ptr *args, struct type *type, + int nargs, struct value **args, struct type *type, int gcc_p) { #define TOC_ADDR_OFFSET 20 @@ -766,7 +858,7 @@ rs6000_fix_call_dummy (char *dummyname, CORE_ADDR pc, CORE_ADDR fun, if (rs6000_find_toc_address_hook != NULL) { CORE_ADDR tocvalue = (*rs6000_find_toc_address_hook) (fun); - write_register (TOC_REGNUM, tocvalue); + write_register (PPC_TOC_REGNUM, tocvalue); } } @@ -787,7 +879,7 @@ rs6000_fix_call_dummy (char *dummyname, CORE_ADDR pc, CORE_ADDR fun, starting from r4. */ static CORE_ADDR -rs6000_push_arguments (int nargs, value_ptr *args, CORE_ADDR sp, +rs6000_push_arguments (int nargs, struct value **args, CORE_ADDR sp, int struct_return, CORE_ADDR struct_addr) { int ii; @@ -798,7 +890,7 @@ rs6000_push_arguments (int nargs, value_ptr *args, CORE_ADDR sp, int f_argno = 0; /* current floating point argno */ int wordsize = TDEP->wordsize; - value_ptr arg = 0; + struct value *arg = 0; struct type *type; CORE_ADDR saved_sp; @@ -917,7 +1009,7 @@ ran_out_of_registers_for_arguments: for (; jj < nargs; ++jj) { - value_ptr val = args[jj]; + struct value *val = args[jj]; space += ((TYPE_LENGTH (VALUE_TYPE (val))) + 3) & -4; } @@ -989,7 +1081,7 @@ ran_out_of_registers_for_arguments: static CORE_ADDR ppc_push_return_address (CORE_ADDR pc, CORE_ADDR sp) { - write_register (LR_REGNUM, CALL_DUMMY_ADDRESS ()); + write_register (PPC_LR_REGNUM, CALL_DUMMY_ADDRESS ()); return sp; } @@ -1041,19 +1133,55 @@ rs6000_extract_return_value (struct type *valtype, char *regbuf, char *valbuf) static CORE_ADDR rs6000_struct_return_address; -/* Indirect function calls use a piece of trampoline code to do context - switching, i.e. to set the new TOC table. Skip such code if we are on - its first instruction (as when we have single-stepped to here). - Also skip shared library trampoline code (which is different from +/* Return whether handle_inferior_event() should proceed through code + starting at PC in function NAME when stepping. + + The AIX -bbigtoc linker option generates functions @FIX0, @FIX1, etc. to + handle memory references that are too distant to fit in instructions + generated by the compiler. For example, if 'foo' in the following + instruction: + + lwz r9,foo(r2) + + is greater than 32767, the linker might replace the lwz with a branch to + somewhere in @FIX1 that does the load in 2 instructions and then branches + back to where execution should continue. + + GDB should silently step over @FIX code, just like AIX dbx does. + Unfortunately, the linker uses the "b" instruction for the branches, + meaning that the link register doesn't get set. Therefore, GDB's usual + step_over_function() mechanism won't work. + + Instead, use the IN_SOLIB_RETURN_TRAMPOLINE and SKIP_TRAMPOLINE_CODE hooks + in handle_inferior_event() to skip past @FIX code. */ + +int +rs6000_in_solib_return_trampoline (CORE_ADDR pc, char *name) +{ + return name && !strncmp (name, "@FIX", 4); +} + +/* Skip code that the user doesn't want to see when stepping: + + 1. Indirect function calls use a piece of trampoline code to do context + switching, i.e. to set the new TOC table. Skip such code if we are on + its first instruction (as when we have single-stepped to here). + + 2. Skip shared library trampoline code (which is different from indirect function call trampolines). + + 3. Skip bigtoc fixup code. + Result is desired PC to step until, or NULL if we are not in - trampoline code. */ + code that should be skipped. */ CORE_ADDR rs6000_skip_trampoline_code (CORE_ADDR pc) { register unsigned int ii, op; + int rel; CORE_ADDR solib_target_pc; + struct minimal_symbol *msymbol; static unsigned trampoline_code[] = { @@ -1067,6 +1195,21 @@ rs6000_skip_trampoline_code (CORE_ADDR pc) 0 }; + /* Check for bigtoc fixup code. */ + msymbol = lookup_minimal_symbol_by_pc (pc); + if (msymbol && rs6000_in_solib_return_trampoline (pc, SYMBOL_NAME (msymbol))) + { + /* Double-check that the third instruction from PC is relative "b". */ + op = read_memory_integer (pc + 8, 4); + if ((op & 0xfc000003) == 0x48000000) + { + /* Extract bits 6-29 as a signed 24-bit relative word address and + add it to the containing PC. */ + rel = ((int)(op << 6) >> 6); + return pc + 8 + rel; + } + } + /* If pc is in a shared library trampoline, return its target. */ solib_target_pc = find_solib_trampoline_target (pc); if (solib_target_pc) @@ -1085,7 +1228,7 @@ rs6000_skip_trampoline_code (CORE_ADDR pc) /* Determines whether the function FI has a frame on the stack or not. */ -static int +int rs6000_frameless_function_invocation (struct frame_info *fi) { CORE_ADDR func_start; @@ -1113,13 +1256,13 @@ rs6000_frameless_function_invocation (struct frame_info *fi) return 0; } - (void) skip_prologue (func_start, &fdata); + (void) skip_prologue (func_start, fi->pc, &fdata); return fdata.frameless; } /* Return the PC saved in a frame */ -static CORE_ADDR +CORE_ADDR rs6000_frame_saved_pc (struct frame_info *fi) { CORE_ADDR func_start; @@ -1139,7 +1282,7 @@ rs6000_frame_saved_pc (struct frame_info *fi) if (!func_start) return 0; - (void) skip_prologue (func_start, &fdata); + (void) skip_prologue (func_start, fi->pc, &fdata); if (fdata.lr_offset == 0 && fi->next != NULL) { @@ -1152,7 +1295,7 @@ rs6000_frame_saved_pc (struct frame_info *fi) } if (fdata.lr_offset == 0) - return read_register (LR_REGNUM); + return read_register (PPC_LR_REGNUM); return read_memory_addr (FRAME_CHAIN (fi) + fdata.lr_offset, wordsize); } @@ -1174,7 +1317,7 @@ frame_get_saved_regs (struct frame_info *fi, struct rs6000_framedata *fdatap) if (fdatap == NULL) { fdatap = &work_fdata; - (void) skip_prologue (get_pc_function_start (fi->pc), fdatap); + (void) skip_prologue (get_pc_function_start (fi->pc), fi->pc, fdatap); } frame_saved_regs_zalloc (fi); @@ -1223,12 +1366,12 @@ frame_get_saved_regs (struct frame_info *fi, struct rs6000_framedata *fdatap) /* If != 0, fdatap->cr_offset is the offset from the frame that holds the CR. */ if (fdatap->cr_offset != 0) - fi->saved_regs[CR_REGNUM] = frame_addr + fdatap->cr_offset; + fi->saved_regs[PPC_CR_REGNUM] = frame_addr + fdatap->cr_offset; /* If != 0, fdatap->lr_offset is the offset from the frame that holds the LR. */ if (fdatap->lr_offset != 0) - fi->saved_regs[LR_REGNUM] = frame_addr + fdatap->lr_offset; + fi->saved_regs[PPC_LR_REGNUM] = frame_addr + fdatap->lr_offset; } /* Return the address of a frame. This is the inital %sp value when the frame @@ -1250,7 +1393,7 @@ frame_initial_stack_address (struct frame_info *fi) /* find out if this function is using an alloca register.. */ - (void) skip_prologue (get_pc_function_start (fi->pc), &fdata); + (void) skip_prologue (get_pc_function_start (fi->pc), fi->pc, &fdata); /* if saved registers of this frame are not known yet, read and cache them. */ @@ -1313,7 +1456,7 @@ frame_initial_stack_address (struct frame_info *fi) /* In the case of the RS/6000, the frame's nominal address is the address of a 4-byte word containing the calling frame's address. */ -static CORE_ADDR +CORE_ADDR rs6000_frame_chain (struct frame_info *thisframe) { CORE_ADDR fp, fpp, lr; @@ -1338,7 +1481,7 @@ rs6000_frame_chain (struct frame_info *thisframe) else fp = read_memory_addr ((thisframe)->frame, wordsize); - lr = read_register (LR_REGNUM); + lr = read_register (PPC_LR_REGNUM); if (lr == entry_point_address ()) if (fp != 0 && (fpp = read_memory_addr (fp, wordsize)) != 0) if (PC_IN_CALL_DUMMY (lr, fpp, fpp)) @@ -1403,7 +1546,7 @@ rs6000_register_virtual_size (int n) of data in register N. */ static struct type * -rs6000_register_virtual_type (n) +rs6000_register_virtual_type (int n) { struct gdbarch_tdep *tdep = TDEP; const struct reg *reg = tdep->regs + n; @@ -1500,7 +1643,7 @@ rs6000_store_return_value (struct type *type, char *valbuf) TYPE_LENGTH (type)); else /* Everything else is returned in GPR3 and up. */ - write_register_bytes (REGISTER_BYTE (GP0_REGNUM + 3), valbuf, + write_register_bytes (REGISTER_BYTE (PPC_GP0_REGNUM + 3), valbuf, TYPE_LENGTH (type)); } @@ -1547,11 +1690,11 @@ rs6000_create_inferior (int pid) a function pointer would require allocation of a TOC entry in the inferior's memory space, with all its drawbacks. To be able to call C++ virtual methods in the inferior (which are called via - function pointers), find_function_addr uses this macro to get the + function pointers), find_function_addr uses this function to get the function address from a function pointer. */ -/* Return nonzero if ADDR (a function pointer) is in the data space and - is therefore a special function pointer. */ +/* Return real function address if ADDR (a function pointer) is in the data + space and is therefore a special function pointer. */ CORE_ADDR rs6000_convert_from_func_ptr_addr (CORE_ADDR addr) @@ -1909,6 +2052,85 @@ 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 @@ -1923,33 +2145,44 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) { struct gdbarch *gdbarch; struct gdbarch_tdep *tdep; - int wordsize, fromexec, power, i, off; + 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; - fromexec = info.abfd && info.abfd->format == bfd_object && + from_xcoff_exec = info.abfd && info.abfd->format == bfd_object && bfd_get_flavour (info.abfd) == bfd_target_xcoff_flavour; - /* Check word size. If INFO is from a binary file, infer it from that, - else use the previously-inferred size. */ - if (fromexec) + 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 + else if (from_elf_exec) { - tdep = TDEP; - if (tdep) - wordsize = tdep->wordsize; + 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); @@ -1960,7 +2193,7 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) 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) + if (tdep && tdep->wordsize == wordsize && tdep->osabi == osabi) return arches->gdbarch; } @@ -1972,9 +2205,9 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) - "set arch" trust blindly - GDB startup useless but harmless */ - if (!fromexec) + if (!from_xcoff_exec) { - arch = info.bfd_architecture; + arch = info.bfd_arch_info->arch; mach = info.bfd_arch_info->mach; } else @@ -1986,6 +2219,7 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) } tdep = xmalloc (sizeof (struct gdbarch_tdep)); tdep->wordsize = wordsize; + tdep->osabi = osabi; gdbarch = gdbarch_alloc (&info, tdep); power = arch == bfd_arch_rs6000; @@ -2051,6 +2285,7 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) 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); @@ -2060,16 +2295,17 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_register_convert_to_raw (gdbarch, rs6000_register_convert_to_raw); set_gdbarch_extract_return_value (gdbarch, rs6000_extract_return_value); - set_gdbarch_push_arguments (gdbarch, rs6000_push_arguments); + + 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_frame_init_saved_regs (gdbarch, rs6000_frame_init_saved_regs); - set_gdbarch_init_extra_frame_info (gdbarch, rs6000_init_extra_frame_info); - set_gdbarch_pop_frame (gdbarch, rs6000_pop_frame); set_gdbarch_skip_prologue (gdbarch, rs6000_skip_prologue); @@ -2081,10 +2317,36 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) /* Not sure on this. FIXMEmgo */ set_gdbarch_frame_args_skip (gdbarch, 8); - set_gdbarch_frameless_function_invocation (gdbarch, rs6000_frameless_function_invocation); - set_gdbarch_frame_chain (gdbarch, rs6000_frame_chain); set_gdbarch_frame_chain_valid (gdbarch, file_frame_chain_valid); - set_gdbarch_frame_saved_pc (gdbarch, rs6000_frame_saved_pc); + 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); @@ -2099,7 +2361,7 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) /* Initialization code. */ void -_initialize_rs6000_tdep () +_initialize_rs6000_tdep (void) { register_gdbarch_init (bfd_arch_rs6000, rs6000_gdbarch_init); register_gdbarch_init (bfd_arch_powerpc, rs6000_gdbarch_init);