/* Target-dependent code for the SPARC for GDB, the GNU debugger.
- Copyright 1986, 1987, 1989, 1991, 1992 Free Software Foundation, Inc.
+ Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994
+ Free Software Foundation, Inc.
This file is part of GDB.
#include "inferior.h"
#include "obstack.h"
#include "target.h"
-#include "ieee-float.h"
+#include "value.h"
+
+#include "symfile.h" /* for objfiles.h */
+#include "objfiles.h" /* for find_pc_section */
#ifdef USE_PROC_FS
#include <sys/procfs.h>
-#else
-#include <sys/ptrace.h>
#endif
#include "gdbcore.h"
/* From infrun.c */
extern int stop_after_trap;
+/* We don't store all registers immediately when requested, since they
+ get sent over in large chunks anyway. Instead, we accumulate most
+ of the changes and send them over once. "deferred_stores" keeps
+ track of which sets of registers we have locally-changed copies of,
+ so we only need send the groups that have changed. */
+
+int deferred_stores = 0; /* Cumulates stores we want to do eventually. */
+
typedef enum
{
Error, not_branch, bicc, bicca, ba, baa, ticc, ta
npc4 = next_pc + 4; /* branch not taken */
target_insert_breakpoint (next_pc, break_mem[0]);
- /* printf ("set break at %x\n",next_pc); */
+ /* printf_unfiltered ("set break at %x\n",next_pc); */
pc = read_register (PC_REGNUM);
pc_instruction = read_memory_integer (pc, sizeof(pc_instruction));
}
}
\f
-#define FRAME_SAVED_L0 0 /* Byte offset from SP */
-#define FRAME_SAVED_I0 32 /* Byte offset from SP */
-
CORE_ADDR
sparc_frame_chain (thisframe)
FRAME thisframe;
{
- CORE_ADDR retval;
+ char buf[MAX_REGISTER_RAW_SIZE];
int err;
CORE_ADDR addr;
addr = thisframe->frame + FRAME_SAVED_I0 +
- REGISTER_RAW_SIZE(FP_REGNUM) * (FP_REGNUM - I0_REGNUM);
- err = target_read_memory (addr, (char *) &retval, sizeof (CORE_ADDR));
+ REGISTER_RAW_SIZE (FP_REGNUM) * (FP_REGNUM - I0_REGNUM);
+ err = target_read_memory (addr, buf, REGISTER_RAW_SIZE (FP_REGNUM));
if (err)
return 0;
- SWAP_TARGET_AND_HOST (&retval, sizeof (retval));
- return retval;
+ return extract_address (buf, REGISTER_RAW_SIZE (FP_REGNUM));
}
CORE_ADDR
sparc_extract_struct_value_address (regbuf)
char regbuf[REGISTER_BYTES];
{
- /* FIXME, handle byte swapping */
return read_memory_integer (((int *)(regbuf))[SP_REGNUM]+(16*4),
- sizeof (CORE_ADDR));
+ TARGET_PTR_BIT / TARGET_CHAR_BIT);
}
/* Find the pc saved in frame FRAME. */
CORE_ADDR
-frame_saved_pc (frame)
+sparc_frame_saved_pc (frame)
FRAME frame;
{
- CORE_ADDR prev_pc;
+ char buf[MAX_REGISTER_RAW_SIZE];
+ CORE_ADDR addr;
- if (get_current_frame () == frame) /* FIXME, debug check. Remove >=gdb-4.6 */
+ if (frame->signal_handler_caller)
{
- if (read_register (SP_REGNUM) != frame->bottom) abort();
- }
+ /* This is the signal trampoline frame.
+ Get the saved PC from the sigcontext structure. */
- read_memory ((CORE_ADDR) (frame->bottom + FRAME_SAVED_I0 +
- REGISTER_RAW_SIZE(I7_REGNUM) * (I7_REGNUM - I0_REGNUM)),
- (char *) &prev_pc,
- sizeof (CORE_ADDR));
+#ifndef SIGCONTEXT_PC_OFFSET
+#define SIGCONTEXT_PC_OFFSET 12
+#endif
- SWAP_TARGET_AND_HOST (&prev_pc, sizeof (prev_pc));
- return PC_ADJUST (prev_pc);
+ CORE_ADDR sigcontext_addr;
+ char scbuf[TARGET_PTR_BIT / HOST_CHAR_BIT];
+ int saved_pc_offset = SIGCONTEXT_PC_OFFSET;
+ char *name = NULL;
+
+ /* Solaris2 ucbsigvechandler passes a pointer to a sigcontext
+ as the third parameter. The offset to the saved pc is 12. */
+ find_pc_partial_function (frame->pc, &name,
+ (CORE_ADDR *)NULL,(CORE_ADDR *)NULL);
+ if (name && STREQ (name, "ucbsigvechandler"))
+ saved_pc_offset = 12;
+
+ /* The sigcontext address is contained in register O2. */
+ get_saved_register (buf, (int *)NULL, (CORE_ADDR *)NULL,
+ frame, O0_REGNUM + 2, (enum lval_type *)NULL);
+ sigcontext_addr = extract_address (buf, REGISTER_RAW_SIZE (O0_REGNUM));
+
+ /* Don't cause a memory_error when accessing sigcontext in case the
+ stack layout has changed or the stack is corrupt. */
+ target_read_memory (sigcontext_addr + saved_pc_offset,
+ scbuf, sizeof (scbuf));
+ return extract_address (scbuf, sizeof (scbuf));
+ }
+ addr = (frame->bottom + FRAME_SAVED_I0 +
+ REGISTER_RAW_SIZE (I7_REGNUM) * (I7_REGNUM - I0_REGNUM));
+ read_memory (addr, buf, REGISTER_RAW_SIZE (I7_REGNUM));
+ return PC_ADJUST (extract_address (buf, REGISTER_RAW_SIZE (I7_REGNUM)));
}
/*
* difficulty.
*/
FRAME
-setup_arbitrary_frame (frame, stack)
- FRAME_ADDR frame, stack;
+setup_arbitrary_frame (argc, argv)
+ int argc;
+ FRAME_ADDR *argv;
{
- FRAME fid = create_new_frame (frame, 0);
+ FRAME fid;
+
+ if (argc != 2)
+ error ("Sparc frame specifications require two arguments: fp and sp");
+
+ fid = create_new_frame (argv[0], 0);
if (!fid)
fatal ("internal: create_new_frame returned invalid frame id");
- fid->bottom = stack;
+ fid->bottom = argv[1];
fid->pc = FRAME_SAVED_PC (fid);
return fid;
}
-/* This code was written by Gary Beihl (beihl@mcc.com).
- It was modified by Michael Tiemann (tiemann@corto.inria.fr). */
-
-/*
- * This routine appears to be passed a size by which to increase the
- * stack. It then executes a save instruction in the inferior to
- * increase the stack by this amount. Only the register window system
- * should be affected by this; the program counter & etc. will not be.
- *
- * This instructions used for this purpose are:
- *
- * sethi %hi(0x0),g1 *
- * add g1,0x1ee0,g1 *
- * save sp,g1,sp
- * sethi %hi(0x0),g1 *
- * add g1,0x1ee0,g1 *
- * t g0,0x1,o0
- * sethi %hi(0x0),g0 (nop)
- *
- * I presume that these set g1 to be the negative of the size, do a
- * save (putting the stack pointer at sp - size) and restore the
- * original contents of g1. A * indicates that the actual value of
- * the instruction is modified below.
- */
-static int save_insn_opcodes[] = {
- 0x03000000, 0x82007ee0, 0x9de38001, 0x03000000,
- 0x82007ee0, 0x91d02001, 0x01000000 };
-
-/* Neither do_save_insn or do_restore_insn save stack configuration
- (current_frame, etc),
- since the stack is in an indeterminate state through the call to
- each of them. That responsibility of the routine which calls them. */
-
-static void
-do_save_insn (size)
- int size;
-{
- int g1 = read_register (G1_REGNUM);
- CORE_ADDR sp = read_register (SP_REGNUM);
- CORE_ADDR pc = read_register (PC_REGNUM);
- CORE_ADDR npc = read_register (NPC_REGNUM);
- CORE_ADDR fake_pc = sp - sizeof (save_insn_opcodes);
- struct inferior_status inf_status;
-
- save_inferior_status (&inf_status, 0); /* Don't restore stack info */
- /*
- * See above.
- */
- save_insn_opcodes[0] = 0x03000000 | ((-size >> 10) & 0x3fffff);
- save_insn_opcodes[1] = 0x82006000 | (-size & 0x3ff);
- save_insn_opcodes[3] = 0x03000000 | ((g1 >> 10) & 0x3fffff);
- save_insn_opcodes[4] = 0x82006000 | (g1 & 0x3ff);
- write_memory (fake_pc, (char *)save_insn_opcodes, sizeof (save_insn_opcodes));
-
- clear_proceed_status ();
- stop_after_trap = 1;
- proceed (fake_pc, 0, 0);
-
- write_register (PC_REGNUM, pc);
- write_register (NPC_REGNUM, npc);
- restore_inferior_status (&inf_status);
-}
-
-/*
- * This routine takes a program counter value. It restores the
- * register window system to the frame above the current one.
- * THIS ROUTINE CLOBBERS PC AND NPC IN THE TARGET!
- */
-
-/* The following insns translate to:
-
- restore %g0,%g0,%g0
- t %g0,1
- sethi %hi(0),%g0 */
-
-static int restore_insn_opcodes[] = { 0x81e80000, 0x91d02001, 0x01000000 };
-
-static void
-do_restore_insn ()
-{
- CORE_ADDR sp = read_register (SP_REGNUM);
- CORE_ADDR fake_pc = sp - sizeof (restore_insn_opcodes);
- struct inferior_status inf_status;
-
- save_inferior_status (&inf_status, 0); /* Don't restore stack info */
-
- write_memory (fake_pc, (char *)restore_insn_opcodes,
- sizeof (restore_insn_opcodes));
-
- clear_proceed_status ();
- stop_after_trap = 1;
- proceed (fake_pc, 0, 0);
-
- restore_inferior_status (&inf_status);
-}
-
/* Given a pc value, skip it forward past the function prologue by
disassembling instructions that appear to be a prologue.
struct frame_saved_regs *saved_regs_addr;
{
register int regnum;
- FRAME_ADDR frame = read_register (FP_REGNUM);
+ FRAME_ADDR frame = FRAME_FP(fi);
FRAME fid = FRAME_INFO_ID (fi);
if (!fid)
fatal ("Bad frame info struct in FRAME_FIND_SAVED_REGS");
- (void) memset (saved_regs_addr, 0, sizeof (*saved_regs_addr));
-
- /* Old test.
- if (fi->pc >= frame - CALL_DUMMY_LENGTH - 0x140
- && fi->pc <= frame) */
+ memset (saved_regs_addr, 0, sizeof (*saved_regs_addr));
if (fi->pc >= (fi->bottom ? fi->bottom :
read_register (SP_REGNUM))
/* Push an empty stack frame, and record in it the current PC, regs, etc.
- Note that the write's are of registers in the context of the newly
- pushed frame. Thus the the fp*'s, the g*'s, the i*'s, and
- the randoms, of the new frame, are being saved. The locals and outs
+ We save the non-windowed registers and the ins. The locals and outs
are new; they don't need to be saved. The i's and l's of
- the last frame were saved by the do_save_insn in the register
- file (now on the stack, since a context switch happended imm after).
-
- The return pointer register %i7 does not have
- the pc saved into it (return from this frame will be accomplished
- by a POP_FRAME). In fact, we must leave it unclobbered, since we
- must preserve it in the calling routine except across call instructions. */
+ the last frame were already saved on the stack. */
/* Definitely see tm-sparc.h for more doc of the frame format here. */
void
sparc_push_dummy_frame ()
{
- CORE_ADDR fp;
- char register_temp[REGISTER_BYTES];
+ CORE_ADDR sp, old_sp;
+ char register_temp[0x140];
+
+ old_sp = sp = read_register (SP_REGNUM);
- do_save_insn (0x140); /* FIXME where does this value come from? */
- fp = read_register (FP_REGNUM);
+ /* Y, PS, WIM, TBR, PC, NPC, FPS, CPS regs */
+ read_register_bytes (REGISTER_BYTE (Y_REGNUM), ®ister_temp[0],
+ REGISTER_RAW_SIZE (Y_REGNUM) * 8);
- read_register_bytes (REGISTER_BYTE (FP0_REGNUM), register_temp, 32 * 4);
- write_memory (fp - 0x80, register_temp, 32 * 4);
+ read_register_bytes (REGISTER_BYTE (O0_REGNUM), ®ister_temp[8 * 4],
+ REGISTER_RAW_SIZE (O0_REGNUM) * 8);
- read_register_bytes (REGISTER_BYTE (G0_REGNUM), register_temp, 8 * 4);
- write_memory (fp - 0xa0, register_temp, 8 * 4);
+ read_register_bytes (REGISTER_BYTE (G0_REGNUM), ®ister_temp[16 * 4],
+ REGISTER_RAW_SIZE (G0_REGNUM) * 8);
- read_register_bytes (REGISTER_BYTE (I0_REGNUM), register_temp, 8 * 4);
- write_memory (fp - 0xc0, register_temp, 8 * 4);
+ read_register_bytes (REGISTER_BYTE (FP0_REGNUM), ®ister_temp[24 * 4],
+ REGISTER_RAW_SIZE (FP0_REGNUM) * 32);
- /* Y, PS, WIM, TBR, PC, NPC, FPS, CPS regs */
- read_register_bytes (REGISTER_BYTE (Y_REGNUM), register_temp, 8 * 4);
- write_memory (fp - 0xe0, register_temp, 8 * 4);
+ sp -= 0x140;
+
+ write_register (SP_REGNUM, sp);
+
+ write_memory (sp + 0x60, ®ister_temp[0], (8 + 8 + 8 + 32) * 4);
+
+ write_register (FP_REGNUM, old_sp);
+
+ /* Set return address register for the call dummy to the current PC. */
+ write_register (I7_REGNUM, read_pc() - 8);
}
/* Discard from the stack the innermost frame, restoring all saved registers.
fi = get_frame_info (frame);
get_frame_saved_regs (fi, &fsr);
- do_restore_insn ();
if (fsr.regs[FP0_REGNUM])
{
read_memory (fsr.regs[FP0_REGNUM], raw_buffer, 32 * 4);
write_register_bytes (REGISTER_BYTE (FP0_REGNUM), raw_buffer, 32 * 4);
}
+ if (fsr.regs[FPS_REGNUM])
+ {
+ read_memory (fsr.regs[FPS_REGNUM], raw_buffer, 4);
+ write_register_bytes (REGISTER_BYTE (FPS_REGNUM), raw_buffer, 4);
+ }
+ if (fsr.regs[CPS_REGNUM])
+ {
+ read_memory (fsr.regs[CPS_REGNUM], raw_buffer, 4);
+ write_register_bytes (REGISTER_BYTE (CPS_REGNUM), raw_buffer, 4);
+ }
if (fsr.regs[G1_REGNUM])
{
read_memory (fsr.regs[G1_REGNUM], raw_buffer, 7 * 4);
}
if (fsr.regs[I0_REGNUM])
{
+ CORE_ADDR sp;
+
+ char reg_temp[REGISTER_BYTES];
+
read_memory (fsr.regs[I0_REGNUM], raw_buffer, 8 * 4);
- write_register_bytes (REGISTER_BYTE (O0_REGNUM), raw_buffer, 8 * 4);
+
+ /* Get the ins and locals which we are about to restore. Just
+ moving the stack pointer is all that is really needed, except
+ store_inferior_registers is then going to write the ins and
+ locals from the registers array, so we need to muck with the
+ registers array. */
+ sp = fsr.regs[SP_REGNUM];
+ read_memory (sp, reg_temp, REGISTER_RAW_SIZE (L0_REGNUM) * 16);
+
+ /* Restore the out registers.
+ Among other things this writes the new stack pointer. */
+ write_register_bytes (REGISTER_BYTE (O0_REGNUM), raw_buffer,
+ REGISTER_RAW_SIZE (O0_REGNUM) * 8);
+
+ write_register_bytes (REGISTER_BYTE (L0_REGNUM), reg_temp,
+ REGISTER_RAW_SIZE (L0_REGNUM) * 16);
}
if (fsr.regs[PS_REGNUM])
write_register (PS_REGNUM, read_memory_integer (fsr.regs[PS_REGNUM], 4));
sparc_pc_adjust(pc)
CORE_ADDR pc;
{
- long insn;
+ unsigned long insn;
+ char buf[4];
int err;
- err = target_read_memory (pc + 8, (char *)&insn, sizeof(long));
- SWAP_TARGET_AND_HOST (&insn, sizeof(long));
+ err = target_read_memory (pc + 8, buf, sizeof(long));
+ insn = extract_unsigned_integer (buf, 4);
if ((err == 0) && (insn & 0xfffffe00) == 0)
return pc+12;
else
return pc+8;
}
-
-
-/* Structure of SPARC extended floating point numbers.
- This information is not currently used by GDB, since no current SPARC
- implementations support extended float. */
-
-const struct ext_format ext_format_sparc = {
-/* tot sbyte smask expbyte manbyte */
- 16, 0, 0x80, 0,1, 4,8, /* sparc */
-};
\f
#ifdef USE_PROC_FS /* Target dependent support for /proc */
supply_gregset (gregsetp)
prgregset_t *gregsetp;
{
- register int regno;
+ register int regi;
register prgreg_t *regp = (prgreg_t *) gregsetp;
/* GDB register numbers for Gn, On, Ln, In all match /proc reg numbers. */
- for (regno = G0_REGNUM ; regno <= I7_REGNUM ; regno++)
+ for (regi = G0_REGNUM ; regi <= I7_REGNUM ; regi++)
{
- supply_register (regno, (char *) (regp + regno));
+ supply_register (regi, (char *) (regp + regi));
}
/* These require a bit more care. */
{
if ((regno == -1) || (regno == regi))
{
- *(regp + regno) = *(int *) ®isters[REGISTER_BYTE (regi)];
+ *(regp + regi) = *(int *) ®isters[REGISTER_BYTE (regi)];
}
}
if ((regno == -1) || (regno == PS_REGNUM))
{
from = (char *) ®isters[REGISTER_BYTE (regi)];
to = (char *) &fpregsetp->pr_fr.pr_regs[regi-FP0_REGNUM];
- bcopy (from, to, REGISTER_RAW_SIZE (regno));
+ memcpy (to, from, REGISTER_RAW_SIZE (regi));
}
}
if ((regno == -1) || (regno == FPS_REGNUM))
CORE_ADDR *pc;
{
CORE_ADDR jb_addr;
+#define LONGJMP_TARGET_SIZE 4
+ char buf[LONGJMP_TARGET_SIZE];
jb_addr = read_register(O0_REGNUM);
- if (target_read_memory(jb_addr + JB_PC * JB_ELEMENT_SIZE, (char *) pc,
- sizeof(CORE_ADDR)))
+ if (target_read_memory(jb_addr + JB_PC * JB_ELEMENT_SIZE, buf,
+ LONGJMP_TARGET_SIZE))
return 0;
- SWAP_TARGET_AND_HOST(pc, sizeof(CORE_ADDR));
+ *pc = extract_address (buf, LONGJMP_TARGET_SIZE);
return 1;
}
#endif /* GET_LONGJMP_TARGET */
+
+/* So far used only for sparc solaris. In sparc solaris, we recognize
+ a trampoline by it's section name. That is, if the pc is in a
+ section named ".plt" then we are in a trampline. */
+
+int
+in_solib_trampoline(pc, name)
+ CORE_ADDR pc;
+ char *name;
+{
+ struct obj_section *s;
+ int retval = 0;
+
+ s = find_pc_section(pc);
+
+ retval = (s != NULL
+ && s->the_bfd_section->name != NULL
+ && STREQ (s->the_bfd_section->name, ".plt"));
+ return(retval);
+}
+