/* Target-dependent code for GDB, the GNU debugger.
- Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996,
- 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software
- Foundation, Inc.
+ Copyright (C) 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996,
+ 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
This file is part of GDB.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
#include "defs.h"
#include "frame.h"
#include "frame-base.h"
#include "reggroups.h"
+#include "rs6000-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
struct reg
{
char *name; /* name of register */
- unsigned char sz32; /* size on 32-bit arch, 0 if nonextant */
- unsigned char sz64; /* size on 64-bit arch, 0 if nonextant */
+ unsigned char sz32; /* size on 32-bit arch, 0 if nonexistent */
+ unsigned char sz64; /* size on 64-bit arch, 0 if nonexistent */
unsigned char fpr; /* whether register is floating-point */
unsigned char pseudo; /* whether register is pseudo */
int spr_num; /* PowerPC SPR number, or -1 if not an SPR.
return pc;
}
+static int
+insn_changes_sp_or_jumps (unsigned long insn)
+{
+ int opcode = (insn >> 26) & 0x03f;
+ int sd = (insn >> 21) & 0x01f;
+ int a = (insn >> 16) & 0x01f;
+ int subcode = (insn >> 1) & 0x3ff;
+
+ /* Changes the stack pointer. */
+
+ /* NOTE: There are many ways to change the value of a given register.
+ The ways below are those used when the register is R1, the SP,
+ in a funtion's epilogue. */
+
+ if (opcode == 31 && subcode == 444 && a == 1)
+ return 1; /* mr R1,Rn */
+ if (opcode == 14 && sd == 1)
+ return 1; /* addi R1,Rn,simm */
+ if (opcode == 58 && sd == 1)
+ return 1; /* ld R1,ds(Rn) */
+
+ /* Transfers control. */
+
+ if (opcode == 18)
+ return 1; /* b */
+ if (opcode == 16)
+ return 1; /* bc */
+ if (opcode == 19 && subcode == 16)
+ return 1; /* bclr */
+ if (opcode == 19 && subcode == 528)
+ return 1; /* bcctr */
+
+ return 0;
+}
+
+/* Return true if we are in the function's epilogue, i.e. after the
+ instruction that destroyed the function's stack frame.
+
+ 1) scan forward from the point of execution:
+ a) If you find an instruction that modifies the stack pointer
+ or transfers control (except a return), execution is not in
+ an epilogue, return.
+ b) Stop scanning if you find a return instruction or reach the
+ end of the function or reach the hard limit for the size of
+ an epilogue.
+ 2) scan backward from the point of execution:
+ a) If you find an instruction that modifies the stack pointer,
+ execution *is* in an epilogue, return.
+ b) Stop scanning if you reach an instruction that transfers
+ control or the beginning of the function or reach the hard
+ limit for the size of an epilogue. */
+
+static int
+rs6000_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ bfd_byte insn_buf[PPC_INSN_SIZE];
+ CORE_ADDR scan_pc, func_start, func_end, epilogue_start, epilogue_end;
+ unsigned long insn;
+ struct frame_info *curfrm;
+
+ /* Find the search limits based on function boundaries and hard limit. */
+
+ if (!find_pc_partial_function (pc, NULL, &func_start, &func_end))
+ return 0;
+
+ epilogue_start = pc - PPC_MAX_EPILOGUE_INSTRUCTIONS * PPC_INSN_SIZE;
+ if (epilogue_start < func_start) epilogue_start = func_start;
+
+ epilogue_end = pc + PPC_MAX_EPILOGUE_INSTRUCTIONS * PPC_INSN_SIZE;
+ if (epilogue_end > func_end) epilogue_end = func_end;
+
+ curfrm = get_current_frame ();
+
+ /* Scan forward until next 'blr'. */
+
+ for (scan_pc = pc; scan_pc < epilogue_end; scan_pc += PPC_INSN_SIZE)
+ {
+ if (!safe_frame_unwind_memory (curfrm, scan_pc, insn_buf, PPC_INSN_SIZE))
+ return 0;
+ insn = extract_signed_integer (insn_buf, PPC_INSN_SIZE);
+ if (insn == 0x4e800020)
+ break;
+ if (insn_changes_sp_or_jumps (insn))
+ return 0;
+ }
+
+ /* Scan backward until adjustment to stack pointer (R1). */
+
+ for (scan_pc = pc - PPC_INSN_SIZE;
+ scan_pc >= epilogue_start;
+ scan_pc -= PPC_INSN_SIZE)
+ {
+ if (!safe_frame_unwind_memory (curfrm, scan_pc, insn_buf, PPC_INSN_SIZE))
+ return 0;
+ insn = extract_signed_integer (insn_buf, PPC_INSN_SIZE);
+ if (insn_changes_sp_or_jumps (insn))
+ return 1;
+ }
+
+ return 0;
+}
+
/* Fill in fi->saved_regs */
remember just the first one, but skip over additional
ones. */
- if (lr_reg < 0)
+ if (lr_reg == -1)
lr_reg = (op & 0x03e00000);
if (lr_reg == 0)
r0_contains_arg = 0;
continue;
}
+ else if ((op & 0xfe80ffff) == 0x42800005 && lr_reg != -1)
+ {
+ /* bcl 20,xx,.+4 is used to get the current PC, with or without
+ prediction bits. If the LR has already been saved, we can
+ skip it. */
+ continue;
+ }
else if (op == 0x48000005)
{ /* bl .+4 used in
-mrelocatable */
regcache_raw_write_signed (regcache, SP_REGNUM, sp);
/* Set back chain properly. */
- store_unsigned_integer (tmp_buffer, 4, saved_sp);
- write_memory (sp, tmp_buffer, 4);
+ store_unsigned_integer (tmp_buffer, wordsize, saved_sp);
+ write_memory (sp, tmp_buffer, wordsize);
/* Point the inferior function call's return address at the dummy's
breakpoint. */
|| (tdep->ppc_ev0_regnum >= 0
&& regnum >= tdep->ppc_ev0_regnum
&& regnum < tdep->ppc_ev0_regnum + 32)
+ || regnum == tdep->ppc_vrsave_regnum - 1 /* vscr */
|| regnum == tdep->ppc_vrsave_regnum
|| regnum == tdep->ppc_acc_regnum
|| regnum == tdep->ppc_spefscr_regnum);
Usually a function pointer's representation is simply the address
of the function. On the RS/6000 however, a function pointer is
- represented by a pointer to a TOC entry. This TOC entry contains
+ represented by a pointer to an OPD entry. This OPD entry contains
three words, the first word is the address of the function, the
second word is the TOC pointer (r2), and the third word is the
static chain value. Throughout GDB it is currently assumed that a
function pointer contains the address of the function, which is not
easy to fix. In addition, the conversion of a function address to
- a function pointer would require allocation of a TOC entry in the
+ a function pointer would require allocation of an OPD 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 function to get the
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
struct rs6000_framedata fdata;
int wordsize = tdep->wordsize;
+ CORE_ADDR func, pc;
if ((*this_cache) != NULL)
return (*this_cache);
(*this_cache) = cache;
cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
- skip_prologue (frame_func_unwind (next_frame), frame_pc_unwind (next_frame),
- &fdata);
-
- /* If there were any saved registers, figure out parent's stack
- pointer. */
- /* The following is true only if the frame doesn't have a call to
- alloca(), FIXME. */
-
- if (fdata.saved_fpr == 0
- && fdata.saved_gpr == 0
- && fdata.saved_vr == 0
- && fdata.saved_ev == 0
- && fdata.lr_offset == 0
- && fdata.cr_offset == 0
- && fdata.vr_offset == 0
- && fdata.ev_offset == 0)
- cache->base = frame_unwind_register_unsigned (next_frame, SP_REGNUM);
- else
+ func = frame_func_unwind (next_frame);
+ pc = frame_pc_unwind (next_frame);
+ skip_prologue (func, pc, &fdata);
+
+ /* Figure out the parent's stack pointer. */
+
+ /* 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. */
+ cache->base = frame_unwind_register_unsigned (next_frame, SP_REGNUM);
+
+ /* If the function appears to be frameless, check a couple of likely
+ indicators that we have simply failed to find the frame setup.
+ Two common cases of this are missing symbols (i.e.
+ frame_func_unwind returns the wrong address or 0), and assembly
+ stubs which have a fast exit path but set up a frame on the slow
+ path.
+
+ If the LR appears to return to this function, then presume that
+ we have an ABI compliant frame that we failed to find. */
+ if (fdata.frameless && fdata.lr_offset == 0)
{
- /* 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. */
- cache->base = frame_unwind_register_unsigned (next_frame, SP_REGNUM);
- if (!fdata.frameless)
- /* Frameless really means stackless. */
- cache->base = read_memory_addr (cache->base, wordsize);
+ CORE_ADDR saved_lr;
+ int make_frame = 0;
+
+ saved_lr = frame_unwind_register_unsigned (next_frame,
+ tdep->ppc_lr_regnum);
+ if (func == 0 && saved_lr == pc)
+ make_frame = 1;
+ else if (func != 0)
+ {
+ CORE_ADDR saved_func = get_pc_function_start (saved_lr);
+ if (func == saved_func)
+ make_frame = 1;
+ }
+
+ if (make_frame)
+ {
+ fdata.frameless = 0;
+ fdata.lr_offset = wordsize;
+ }
}
+
+ if (!fdata.frameless)
+ /* Frameless really means stackless. */
+ cache->base = read_memory_addr (cache->base, wordsize);
+
trad_frame_set_value (cache->saved_regs, SP_REGNUM, cache->base);
/* if != -1, fdata.saved_fpr is the smallest number of saved_fpr.
_("rs6000_gdbarch_init: "
"received unexpected BFD 'arch' value"));
+ set_gdbarch_have_nonsteppable_watchpoint (gdbarch, 1);
+
/* Sanity check on registers. */
gdb_assert (strcmp (tdep->regs[tdep->ppc_gp0_regnum].name, "r0") == 0);
set_gdbarch_deprecated_extract_struct_value_address (gdbarch, rs6000_extract_struct_value_address);
set_gdbarch_skip_prologue (gdbarch, rs6000_skip_prologue);
+ set_gdbarch_in_function_epilogue_p (gdbarch, rs6000_in_function_epilogue_p);
+
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
set_gdbarch_breakpoint_from_pc (gdbarch, rs6000_breakpoint_from_pc);
switch (info.osabi)
{
+ case GDB_OSABI_LINUX:
+ /* FIXME: pgilliam/2005-10-21: Assume all PowerPC 64-bit linux systems
+ have altivec registers. If not, ptrace will fail the first time it's
+ called to access one and will not be called again. This wart will
+ be removed when Daniel Jacobowitz's proposal for autodetecting target
+ registers is implemented. */
+ if ((v->arch == bfd_arch_powerpc) && ((v->mach)== bfd_mach_ppc64))
+ {
+ tdep->ppc_vr0_regnum = 71;
+ tdep->ppc_vrsave_regnum = 104;
+ }
+ /* Fall Thru */
case GDB_OSABI_NETBSD_AOUT:
case GDB_OSABI_NETBSD_ELF:
case GDB_OSABI_UNKNOWN:
- case GDB_OSABI_LINUX:
set_gdbarch_unwind_pc (gdbarch, rs6000_unwind_pc);
frame_unwind_append_sniffer (gdbarch, rs6000_frame_sniffer);
set_gdbarch_unwind_dummy_id (gdbarch, rs6000_unwind_dummy_id);
frame_base_append_sniffer (gdbarch, rs6000_frame_base_sniffer);
}
- if (from_xcoff_exec)
- {
- /* NOTE: jimix/2003-06-09: This test should really check for
- GDB_OSABI_AIX when that is defined and becomes
- available. (Actually, once things are properly split apart,
- the test goes away.) */
- /* RS6000/AIX does not support PT_STEP. Has to be simulated. */
- set_gdbarch_software_single_step (gdbarch, rs6000_software_single_step);
- }
-
init_sim_regno_table (gdbarch);
return gdbarch;
/* FIXME: Dump gdbarch_tdep. */
}
-static struct cmd_list_element *info_powerpc_cmdlist = NULL;
-
-static void
-rs6000_info_powerpc_command (char *args, int from_tty)
-{
- help_list (info_powerpc_cmdlist, "info powerpc ", class_info, gdb_stdout);
-}
-
/* Initialization code. */
extern initialize_file_ftype _initialize_rs6000_tdep; /* -Wmissing-prototypes */
{
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,
- _("Various POWERPC info specific commands."),
- &info_powerpc_cmdlist, "info powerpc ", 0, &infolist);
}