/* Target-dependent code for the ALPHA architecture, for GDB, the GNU Debugger.
- Copyright 1993, 1994 Free Software Foundation, Inc.
+ Copyright 1993, 1994, 1995, 1996, 1997 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "defs.h"
#include "frame.h"
#include "dis-asm.h"
#include "symfile.h"
#include "objfiles.h"
+#include "gdb_string.h"
/* FIXME: Some of this code should perhaps be merged with mips-tdep.c. */
/* Forward declarations. */
-static CORE_ADDR
-read_next_frame_reg PARAMS ((FRAME, int));
+static alpha_extra_func_info_t push_sigtramp_desc PARAMS ((CORE_ADDR low_addr));
-static CORE_ADDR
-heuristic_proc_start PARAMS ((CORE_ADDR));
+static CORE_ADDR read_next_frame_reg PARAMS ((struct frame_info *, int));
-static alpha_extra_func_info_t
-heuristic_proc_desc PARAMS ((CORE_ADDR, CORE_ADDR, FRAME));
+static CORE_ADDR heuristic_proc_start PARAMS ((CORE_ADDR));
-static alpha_extra_func_info_t
-find_proc_desc PARAMS ((CORE_ADDR, FRAME));
+static alpha_extra_func_info_t heuristic_proc_desc PARAMS ((CORE_ADDR,
+ CORE_ADDR,
+ struct frame_info *));
-static int
-alpha_in_lenient_prologue PARAMS ((CORE_ADDR, CORE_ADDR));
+static alpha_extra_func_info_t find_proc_desc PARAMS ((CORE_ADDR,
+ struct frame_info *));
-static void
-reinit_frame_cache_sfunc PARAMS ((char *, int, struct cmd_list_element *));
+#if 0
+static int alpha_in_lenient_prologue PARAMS ((CORE_ADDR, CORE_ADDR));
+#endif
+
+static void reinit_frame_cache_sfunc PARAMS ((char *, int,
+ struct cmd_list_element *));
static CORE_ADDR after_prologue PARAMS ((CORE_ADDR pc,
alpha_extra_func_info_t proc_desc));
-static int in_prologue PARAMS ((CORE_ADDR pc,
+static int alpha_in_prologue PARAMS ((CORE_ADDR pc,
alpha_extra_func_info_t proc_desc));
/* Heuristic_proc_start may hunt through the text section for a long
} *linked_proc_desc_table = NULL;
\f
-/* Guaranteed to set fci->saved_regs to some values (it never leaves it
+/* Under GNU/Linux, signal handler invocations can be identified by the
+ designated code sequence that is used to return from a signal
+ handler. In particular, the return address of a signal handler
+ points to the following sequence (the first instruction is quadword
+ aligned):
+
+ bis $30,$30,$16
+ addq $31,0x67,$0
+ call_pal callsys
+
+ Each instruction has a unique encoding, so we simply attempt to
+ match the instruction the pc is pointing to with any of the above
+ instructions. If there is a hit, we know the offset to the start
+ of the designated sequence and can then check whether we really are
+ executing in a designated sequence. If not, -1 is returned,
+ otherwise the offset from the start of the desingated sequence is
+ returned.
+
+ There is a slight chance of false hits: code could jump into the
+ middle of the designated sequence, in which case there is no
+ guarantee that we are in the middle of a sigreturn syscall. Don't
+ think this will be a problem in praxis, though.
+*/
+
+long
+alpha_linux_sigtramp_offset (CORE_ADDR pc)
+{
+ unsigned int i[3], w;
+ long off;
+
+ if (read_memory_nobpt(pc, (char *) &w, 4) != 0)
+ return -1;
+
+ off = -1;
+ switch (w)
+ {
+ case 0x47de0410: off = 0; break; /* bis $30,$30,$16 */
+ case 0x43ecf400: off = 4; break; /* addq $31,0x67,$0 */
+ case 0x00000083: off = 8; break; /* call_pal callsys */
+ default: return -1;
+ }
+ pc -= off;
+ if (pc & 0x7)
+ {
+ /* designated sequence is not quadword aligned */
+ return -1;
+ }
+
+ if (read_memory_nobpt(pc, (char *) i, sizeof(i)) != 0)
+ return -1;
+
+ if (i[0] == 0x47de0410 && i[1] == 0x43ecf400 && i[2] == 0x00000083)
+ return off;
+
+ return -1;
+}
+
+\f
+/* Under OSF/1, the __sigtramp routine is frameless and has a frame
+ size of zero, but we are able to backtrace through it. */
+CORE_ADDR
+alpha_osf_skip_sigtramp_frame (frame, pc)
+ struct frame_info *frame;
+ CORE_ADDR pc;
+{
+ char *name;
+ find_pc_partial_function (pc, &name, (CORE_ADDR *)NULL, (CORE_ADDR *)NULL);
+ if (IN_SIGTRAMP (pc, name))
+ return frame->frame;
+ else
+ return 0;
+}
+
+\f
+/* Dynamically create a signal-handler caller procedure descriptor for
+ the signal-handler return code starting at address LOW_ADDR. The
+ descriptor is added to the linked_proc_desc_table. */
+
+static alpha_extra_func_info_t
+push_sigtramp_desc (low_addr)
+ CORE_ADDR low_addr;
+{
+ struct linked_proc_info *link;
+ alpha_extra_func_info_t proc_desc;
+
+ link = (struct linked_proc_info *)
+ xmalloc (sizeof (struct linked_proc_info));
+ link->next = linked_proc_desc_table;
+ linked_proc_desc_table = link;
+
+ proc_desc = &link->info;
+
+ proc_desc->numargs = 0;
+ PROC_LOW_ADDR (proc_desc) = low_addr;
+ PROC_HIGH_ADDR (proc_desc) = low_addr + 3 * 4;
+ PROC_DUMMY_FRAME (proc_desc) = 0;
+ PROC_FRAME_OFFSET (proc_desc) = 0x298; /* sizeof(struct sigcontext_struct) */
+ PROC_FRAME_REG (proc_desc) = SP_REGNUM;
+ PROC_REG_MASK (proc_desc) = 0xffff;
+ PROC_FREG_MASK (proc_desc) = 0xffff;
+ PROC_PC_REG (proc_desc) = 26;
+ PROC_LOCALOFF (proc_desc) = 0;
+ SET_PROC_DESC_IS_DYN_SIGTRAMP (proc_desc);
+ return (proc_desc);
+}
+
+\f
+/* Guaranteed to set frame->saved_regs to some values (it never leaves it
NULL). */
void
-alpha_find_saved_regs (fci)
- FRAME fci;
+alpha_find_saved_regs (frame)
+ struct frame_info *frame;
{
int ireg;
CORE_ADDR reg_position;
alpha_extra_func_info_t proc_desc;
int returnreg;
- fci->saved_regs = (struct frame_saved_regs *)
+ frame->saved_regs = (struct frame_saved_regs *)
obstack_alloc (&frame_cache_obstack, sizeof(struct frame_saved_regs));
- memset (fci->saved_regs, 0, sizeof (struct frame_saved_regs));
+ memset (frame->saved_regs, 0, sizeof (struct frame_saved_regs));
+
+ /* If it is the frame for __sigtramp, the saved registers are located
+ in a sigcontext structure somewhere on the stack. __sigtramp
+ passes a pointer to the sigcontext structure on the stack.
+ If the stack layout for __sigtramp changes, or if sigcontext offsets
+ change, we might have to update this code. */
+#ifndef SIGFRAME_PC_OFF
+#define SIGFRAME_PC_OFF (2 * 8)
+#define SIGFRAME_REGSAVE_OFF (4 * 8)
+#define SIGFRAME_FPREGSAVE_OFF (SIGFRAME_REGSAVE_OFF + 32 * 8 + 8)
+#endif
+ if (frame->signal_handler_caller)
+ {
+ CORE_ADDR sigcontext_addr;
- proc_desc = fci->proc_desc;
+ sigcontext_addr = SIGCONTEXT_ADDR (frame);
+ for (ireg = 0; ireg < 32; ireg++)
+ {
+ reg_position = sigcontext_addr + SIGFRAME_REGSAVE_OFF + ireg * 8;
+ frame->saved_regs->regs[ireg] = reg_position;
+ }
+ for (ireg = 0; ireg < 32; ireg++)
+ {
+ reg_position = sigcontext_addr + SIGFRAME_FPREGSAVE_OFF + ireg * 8;
+ frame->saved_regs->regs[FP0_REGNUM + ireg] = reg_position;
+ }
+ frame->saved_regs->regs[PC_REGNUM] = sigcontext_addr + SIGFRAME_PC_OFF;
+ return;
+ }
+
+ proc_desc = frame->proc_desc;
if (proc_desc == NULL)
/* I'm not sure how/whether this can happen. Normally when we can't
find a proc_desc, we "synthesize" one using heuristic_proc_desc
/* Fill in the offsets for the registers which gen_mask says
were saved. */
- reg_position = fci->frame + PROC_REG_OFFSET (proc_desc);
+ reg_position = frame->frame + PROC_REG_OFFSET (proc_desc);
mask = PROC_REG_MASK (proc_desc);
returnreg = PROC_PC_REG (proc_desc);
- /* Note that RA is always saved first, regardless of it's actual
+ /* Note that RA is always saved first, regardless of its actual
register number. */
if (mask & (1 << returnreg))
{
- fci->saved_regs->regs[returnreg] = reg_position;
+ frame->saved_regs->regs[returnreg] = reg_position;
reg_position += 8;
mask &= ~(1 << returnreg); /* Clear bit for RA so we
don't save again later. */
for (ireg = 0; ireg <= 31 ; ++ireg)
if (mask & (1 << ireg))
{
- fci->saved_regs->regs[ireg] = reg_position;
+ frame->saved_regs->regs[ireg] = reg_position;
reg_position += 8;
}
/* Fill in the offsets for the registers which float_mask says
were saved. */
- reg_position = fci->frame + PROC_FREG_OFFSET (proc_desc);
+ reg_position = frame->frame + PROC_FREG_OFFSET (proc_desc);
mask = PROC_FREG_MASK (proc_desc);
for (ireg = 0; ireg <= 31 ; ++ireg)
if (mask & (1 << ireg))
{
- fci->saved_regs->regs[FP0_REGNUM+ireg] = reg_position;
+ frame->saved_regs->regs[FP0_REGNUM+ireg] = reg_position;
reg_position += 8;
}
- fci->saved_regs->regs[PC_REGNUM] = fci->saved_regs->regs[returnreg];
+ frame->saved_regs->regs[PC_REGNUM] = frame->saved_regs->regs[returnreg];
}
static CORE_ADDR
read_next_frame_reg(fi, regno)
- FRAME fi;
+ struct frame_info *fi;
int regno;
{
- /* If it is the frame for sigtramp we have a pointer to the sigcontext
- on the stack.
- If the stack layout for __sigtramp changes or if sigcontext offsets
- change we might have to update this code. */
-#ifndef SIGFRAME_PC_OFF
-#define SIGFRAME_PC_OFF (2 * 8)
-#define SIGFRAME_REGSAVE_OFF (4 * 8)
-#endif
for (; fi; fi = fi->next)
{
- if (fi->signal_handler_caller)
- {
- int offset;
- CORE_ADDR sigcontext_addr = read_memory_integer(fi->frame, 8);
-
- if (regno == PC_REGNUM)
- offset = SIGFRAME_PC_OFF;
- else if (regno < 32)
- offset = SIGFRAME_REGSAVE_OFF + regno * 8;
- else
- return 0;
- return read_memory_integer(sigcontext_addr + offset, 8);
- }
- else if (regno == SP_REGNUM)
+ /* We have to get the saved sp from the sigcontext
+ if it is a signal handler frame. */
+ if (regno == SP_REGNUM && !fi->signal_handler_caller)
return fi->frame;
else
{
CORE_ADDR
alpha_frame_saved_pc(frame)
- FRAME frame;
+ struct frame_info *frame;
{
alpha_extra_func_info_t proc_desc = frame->proc_desc;
/* We have to get the saved pc from the sigcontext
if it is a signal handler frame. */
- int pcreg = frame->signal_handler_caller ? PC_REGNUM
- : (proc_desc ? PROC_PC_REG(proc_desc) : RA_REGNUM);
+ int pcreg = frame->signal_handler_caller ? PC_REGNUM : frame->pc_reg;
if (proc_desc && PROC_DESC_IS_DUMMY(proc_desc))
return read_memory_integer(frame->frame - 8, 8);
CORE_ADDR
alpha_saved_pc_after_call (frame)
- FRAME frame;
+ struct frame_info *frame;
{
- alpha_extra_func_info_t proc_desc = find_proc_desc (frame->pc, frame->next);
- int pcreg = proc_desc ? PROC_PC_REG (proc_desc) : RA_REGNUM;
+ CORE_ADDR pc = frame->pc;
+ CORE_ADDR tmp;
+ alpha_extra_func_info_t proc_desc;
+ int pcreg;
+
+ /* Skip over shared library trampoline if necessary. */
+ tmp = SKIP_TRAMPOLINE_CODE (pc);
+ if (tmp != 0)
+ pc = tmp;
- return read_register (pcreg);
+ proc_desc = find_proc_desc (pc, frame->next);
+ pcreg = proc_desc ? PROC_PC_REG (proc_desc) : RA_REGNUM;
+
+ if (frame->signal_handler_caller)
+ return alpha_frame_saved_pc (frame);
+ else
+ return read_register (pcreg);
}
static alpha_extra_func_info_t
heuristic_proc_desc(start_pc, limit_pc, next_frame)
CORE_ADDR start_pc, limit_pc;
- FRAME next_frame;
+ struct frame_info *next_frame;
{
- CORE_ADDR sp = next_frame ? next_frame->frame : read_register (SP_REGNUM);
+ CORE_ADDR sp = read_next_frame_reg (next_frame, SP_REGNUM);
CORE_ADDR cur_pc;
int frame_size;
int has_frame_reg = 0;
unsigned long reg_mask = 0;
+ int pcreg = -1;
if (start_pc == 0)
return NULL;
- memset(&temp_proc_desc, '\0', sizeof(temp_proc_desc));
- memset(&temp_saved_regs, '\0', sizeof(struct frame_saved_regs));
- PROC_LOW_ADDR(&temp_proc_desc) = start_pc;
+ memset (&temp_proc_desc, '\0', sizeof(temp_proc_desc));
+ memset (&temp_saved_regs, '\0', sizeof(struct frame_saved_regs));
+ PROC_LOW_ADDR (&temp_proc_desc) = start_pc;
if (start_pc + 200 < limit_pc)
limit_pc = start_pc + 200;
word = extract_unsigned_integer (buf, 4);
if ((word & 0xffff0000) == 0x23de0000) /* lda $sp,n($sp) */
- frame_size += (-word) & 0xffff;
+ {
+ if (word & 0x8000)
+ frame_size += (-word) & 0xffff;
+ else
+ /* Exit loop if a positive stack adjustment is found, which
+ usually means that the stack cleanup code in the function
+ epilogue is reached. */
+ break;
+ }
else if ((word & 0xfc1f0000) == 0xb41e0000 /* stq reg,n($sp) */
&& (word & 0xffff0000) != 0xb7fe0000) /* reg != $zero */
{
int reg = (word & 0x03e00000) >> 21;
reg_mask |= 1 << reg;
temp_saved_regs.regs[reg] = sp + (short)word;
+
+ /* Starting with OSF/1-3.2C, the system libraries are shipped
+ without local symbols, but they still contain procedure
+ descriptors without a symbol reference. GDB is currently
+ unable to find these procedure descriptors and uses
+ heuristic_proc_desc instead.
+ As some low level compiler support routines (__div*, __add*)
+ use a non-standard return address register, we have to
+ add some heuristics to determine the return address register,
+ or stepping over these routines will fail.
+ Usually the return address register is the first register
+ saved on the stack, but assembler optimization might
+ rearrange the register saves.
+ So we recognize only a few registers (t7, t9, ra) within
+ the procedure prologue as valid return address registers.
+ If we encounter a return instruction, we extract the
+ the return address register from it.
+
+ FIXME: Rewriting GDB to access the procedure descriptors,
+ e.g. via the minimal symbol table, might obviate this hack. */
+ if (pcreg == -1
+ && cur_pc < (start_pc + 80)
+ && (reg == T7_REGNUM || reg == T9_REGNUM || reg == RA_REGNUM))
+ pcreg = reg;
}
+ else if ((word & 0xffe0ffff) == 0x6be08001) /* ret zero,reg,1 */
+ pcreg = (word >> 16) & 0x1f;
else if (word == 0x47de040f) /* bis sp,sp fp */
has_frame_reg = 1;
}
+ if (pcreg == -1)
+ {
+ /* If we haven't found a valid return address register yet,
+ keep searching in the procedure prologue. */
+ while (cur_pc < (limit_pc + 80) && cur_pc < (start_pc + 80))
+ {
+ char buf[4];
+ unsigned long word;
+
+ if (read_memory_nobpt (cur_pc, buf, 4))
+ break;
+ cur_pc += 4;
+ word = extract_unsigned_integer (buf, 4);
+
+ if ((word & 0xfc1f0000) == 0xb41e0000 /* stq reg,n($sp) */
+ && (word & 0xffff0000) != 0xb7fe0000) /* reg != $zero */
+ {
+ int reg = (word & 0x03e00000) >> 21;
+ if (reg == T7_REGNUM || reg == T9_REGNUM || reg == RA_REGNUM)
+ {
+ pcreg = reg;
+ break;
+ }
+ }
+ else if ((word & 0xffe0ffff) == 0x6be08001) /* ret zero,reg,1 */
+ {
+ pcreg = (word >> 16) & 0x1f;
+ break;
+ }
+ }
+ }
+
if (has_frame_reg)
PROC_FRAME_REG(&temp_proc_desc) = GCC_FP_REGNUM;
else
PROC_FRAME_REG(&temp_proc_desc) = SP_REGNUM;
PROC_FRAME_OFFSET(&temp_proc_desc) = frame_size;
PROC_REG_MASK(&temp_proc_desc) = reg_mask;
- PROC_PC_REG(&temp_proc_desc) = RA_REGNUM;
+ PROC_PC_REG(&temp_proc_desc) = (pcreg == -1) ? RA_REGNUM : pcreg;
PROC_LOCALOFF(&temp_proc_desc) = 0; /* XXX - bogus */
return &temp_proc_desc;
}
CORE_ADDR pc;
alpha_extra_func_info_t proc_desc;
{
- struct block *b;
struct symtab_and_line sal;
CORE_ADDR func_addr, func_end;
if (proc_desc)
{
+ if (PROC_DESC_IS_DYN_SIGTRAMP (proc_desc))
+ return PROC_LOW_ADDR (proc_desc); /* "prologue" is in kernel */
+
/* If function is frameless, then we need to do it the hard way. I
strongly suspect that frameless always means prologueless... */
if (PROC_FRAME_REG (proc_desc) == SP_REGNUM
}
/* Return non-zero if we *might* be in a function prologue. Return zero if we
- are definatly *not* in a function prologue. */
+ are definitively *not* in a function prologue. */
static int
-in_prologue (pc, proc_desc)
+alpha_in_prologue (pc, proc_desc)
CORE_ADDR pc;
alpha_extra_func_info_t proc_desc;
{
}
static alpha_extra_func_info_t
-find_proc_desc(pc, next_frame)
+find_proc_desc (pc, next_frame)
CORE_ADDR pc;
- FRAME next_frame;
+ struct frame_info *next_frame;
{
alpha_extra_func_info_t proc_desc;
struct block *b;
if (PC_IN_CALL_DUMMY (pc, 0, 0))
{
struct linked_proc_info *link;
- CORE_ADDR sp = next_frame ? next_frame->frame : read_register (SP_REGNUM);
+ CORE_ADDR sp = read_next_frame_reg (next_frame, SP_REGNUM);
alpha_extra_func_info_t found_proc_desc = NULL;
long min_distance = LONG_MAX;
0, NULL);
}
+ /* If we never found a PDR for this function in symbol reading, then
+ examine prologues to find the information. */
+ if (sym && ((mips_extra_func_info_t) SYMBOL_VALUE (sym))->pdr.framereg == -1)
+ sym = NULL;
+
if (sym)
{
/* IF this is the topmost frame AND
proc_desc = (alpha_extra_func_info_t)SYMBOL_VALUE(sym);
if (next_frame == NULL)
{
- if (PROC_DESC_IS_DUMMY (proc_desc) || in_prologue (pc, proc_desc))
+ if (PROC_DESC_IS_DUMMY (proc_desc) || alpha_in_prologue (pc, proc_desc))
{
alpha_extra_func_info_t found_heuristic =
heuristic_proc_desc (PROC_LOW_ADDR (proc_desc),
pc, next_frame);
- PROC_LOCALOFF (found_heuristic) = PROC_LOCALOFF (proc_desc);
if (found_heuristic)
- proc_desc = found_heuristic;
+ {
+ PROC_LOCALOFF (found_heuristic) =
+ PROC_LOCALOFF (proc_desc);
+ PROC_PC_REG (found_heuristic) = PROC_PC_REG (proc_desc);
+ proc_desc = found_heuristic;
+ }
}
}
}
else
{
+ long offset;
+
/* Is linked_proc_desc_table really necessary? It only seems to be used
by procedure call dummys. However, the procedures being called ought
to have their own proc_descs, and even if they don't,
&& PROC_HIGH_ADDR(&link->info) > pc)
return &link->info;
- if (startaddr == 0)
+ /* If PC is inside a dynamically generated sigtramp handler,
+ create and push a procedure descriptor for that code: */
+ offset = DYNAMIC_SIGTRAMP_OFFSET (pc);
+ if (offset >= 0)
+ return push_sigtramp_desc (pc - offset);
+
+ /* If heuristic_fence_post is non-zero, determine the procedure
+ start address by examining the instructions.
+ This allows us to find the start address of static functions which
+ have no symbolic information, as startaddr would have been set to
+ the preceding global function start address by the
+ find_pc_partial_function call above. */
+ if (startaddr == 0 || heuristic_fence_post != 0)
startaddr = heuristic_proc_start (pc);
proc_desc =
alpha_extra_func_info_t cached_proc_desc;
-FRAME_ADDR
+CORE_ADDR
alpha_frame_chain(frame)
- FRAME frame;
+ struct frame_info *frame;
{
alpha_extra_func_info_t proc_desc;
CORE_ADDR saved_pc = FRAME_SAVED_PC(frame);
/* Fetch the frame pointer for a dummy frame from the procedure
descriptor. */
if (PROC_DESC_IS_DUMMY(proc_desc))
- return (FRAME_ADDR) PROC_DUMMY_FRAME(proc_desc);
+ return (CORE_ADDR) PROC_DUMMY_FRAME(proc_desc);
/* If no frame pointer and frame size is zero, we must be at end
of stack (or otherwise hosed). If we don't check frame size,
/* The previous frame from a sigtramp frame might be frameless
and have frame size zero. */
&& !frame->signal_handler_caller)
- {
- /* The alpha __sigtramp routine is frameless and has a frame size
- of zero, but we are able to backtrace through it. */
- char *name;
- find_pc_partial_function (saved_pc, &name,
- (CORE_ADDR *)NULL, (CORE_ADDR *)NULL);
- if (IN_SIGTRAMP (saved_pc, name))
- return frame->frame;
- else
- return 0;
- }
+ return FRAME_PAST_SIGTRAMP_FRAME (frame, saved_pc);
else
return read_next_frame_reg(frame, PROC_FRAME_REG(proc_desc))
+ PROC_FRAME_OFFSET(proc_desc);
}
void
-init_extra_frame_info(fci)
- struct frame_info *fci;
+init_extra_frame_info (frame)
+ struct frame_info *frame;
{
/* Use proc_desc calculated in frame_chain */
alpha_extra_func_info_t proc_desc =
- fci->next ? cached_proc_desc : find_proc_desc(fci->pc, fci->next);
+ frame->next ? cached_proc_desc : find_proc_desc(frame->pc, frame->next);
- fci->saved_regs = NULL;
- fci->proc_desc =
- proc_desc == &temp_proc_desc ? 0 : proc_desc;
+ frame->saved_regs = NULL;
+ frame->localoff = 0;
+ frame->pc_reg = RA_REGNUM;
+ frame->proc_desc = proc_desc == &temp_proc_desc ? 0 : proc_desc;
if (proc_desc)
{
- /* Get the locals offset from the procedure descriptor, it is valid
- even if we are in the middle of the prologue. */
- fci->localoff = PROC_LOCALOFF(proc_desc);
+ /* Get the locals offset and the saved pc register from the
+ procedure descriptor, they are valid even if we are in the
+ middle of the prologue. */
+ frame->localoff = PROC_LOCALOFF(proc_desc);
+ frame->pc_reg = PROC_PC_REG(proc_desc);
/* Fixup frame-pointer - only needed for top frame */
/* Fetch the frame pointer for a dummy frame from the procedure
descriptor. */
if (PROC_DESC_IS_DUMMY(proc_desc))
- fci->frame = (FRAME_ADDR) PROC_DUMMY_FRAME(proc_desc);
+ frame->frame = (CORE_ADDR) PROC_DUMMY_FRAME(proc_desc);
/* This may not be quite right, if proc has a real frame register.
Get the value of the frame relative sp, procedure might have been
interrupted by a signal at it's very start. */
- else if (fci->pc == PROC_LOW_ADDR (proc_desc) && !PROC_DESC_IS_DUMMY (proc_desc))
- fci->frame = read_next_frame_reg (fci->next, SP_REGNUM);
+ else if (frame->pc == PROC_LOW_ADDR (proc_desc)
+ && !PROC_DESC_IS_DYN_SIGTRAMP (proc_desc))
+ frame->frame = read_next_frame_reg (frame->next, SP_REGNUM);
else
- fci->frame = read_next_frame_reg (fci->next, PROC_FRAME_REG (proc_desc))
- + PROC_FRAME_OFFSET (proc_desc);
+ frame->frame = read_next_frame_reg (frame->next, PROC_FRAME_REG (proc_desc))
+ + PROC_FRAME_OFFSET (proc_desc);
if (proc_desc == &temp_proc_desc)
{
- fci->saved_regs = (struct frame_saved_regs*)
- obstack_alloc (&frame_cache_obstack,
- sizeof (struct frame_saved_regs));
- *fci->saved_regs = temp_saved_regs;
- fci->saved_regs->regs[PC_REGNUM] = fci->saved_regs->regs[RA_REGNUM];
+ char *name;
+
+ /* Do not set the saved registers for a sigtramp frame,
+ alpha_find_saved_registers will do that for us.
+ We can't use frame->signal_handler_caller, it is not yet set. */
+ find_pc_partial_function (frame->pc, &name,
+ (CORE_ADDR *)NULL,(CORE_ADDR *)NULL);
+ if (!IN_SIGTRAMP (frame->pc, name))
+ {
+ frame->saved_regs = (struct frame_saved_regs*)
+ obstack_alloc (&frame_cache_obstack,
+ sizeof (struct frame_saved_regs));
+ *frame->saved_regs = temp_saved_regs;
+ frame->saved_regs->regs[PC_REGNUM]
+ = frame->saved_regs->regs[RA_REGNUM];
+ }
}
}
}
cache. This allows the rest of info frame to extract the important
arguments without difficulty. */
-FRAME
+struct frame_info *
setup_arbitrary_frame (argc, argv)
int argc;
- FRAME_ADDR *argv;
+ CORE_ADDR *argv;
{
if (argc != 2)
error ("ALPHA frame specifications require two arguments: sp and pc");
for (i = 0, m_arg = alpha_args; i < nargs; i++, m_arg++)
{
- value_ptr arg = value_arg_coerce (args[i]);
+ value_ptr arg = args[i];
+ struct type *arg_type = check_typedef (VALUE_TYPE (arg));
/* Cast argument to long if necessary as the compiler does it too. */
- if (TYPE_LENGTH (VALUE_TYPE (arg)) < TYPE_LENGTH (builtin_type_long))
- arg = value_cast (builtin_type_long, arg);
- m_arg->len = TYPE_LENGTH (VALUE_TYPE (arg));
+ switch (TYPE_CODE (arg_type))
+ {
+ case TYPE_CODE_INT:
+ case TYPE_CODE_BOOL:
+ case TYPE_CODE_CHAR:
+ case TYPE_CODE_RANGE:
+ case TYPE_CODE_ENUM:
+ if (TYPE_LENGTH (arg_type) < TYPE_LENGTH (builtin_type_long))
+ {
+ arg_type = builtin_type_long;
+ arg = value_cast (arg_type, arg);
+ }
+ break;
+ default:
+ break;
+ }
+ m_arg->len = TYPE_LENGTH (arg_type);
m_arg->offset = accumulate_size;
accumulate_size = (accumulate_size + m_arg->len + 7) & ~7;
m_arg->contents = VALUE_CONTENTS(arg);
alpha_pop_frame()
{
register int regnum;
- FRAME frame = get_current_frame ();
+ struct frame_info *frame = get_current_frame ();
CORE_ADDR new_sp = frame->frame;
alpha_extra_func_info_t proc_desc = frame->proc_desc;
}
write_register (SP_REGNUM, new_sp);
flush_cached_frames ();
- /* We let init_extra_frame_info figure out the frame pointer */
- set_current_frame (create_new_frame (0, read_pc ()));
- if (proc_desc && PROC_DESC_IS_DUMMY(proc_desc))
+ if (proc_desc && (PROC_DESC_IS_DUMMY(proc_desc)
+ || PROC_DESC_IS_DYN_SIGTRAMP (proc_desc)))
{
struct linked_proc_info *pi_ptr, *prev_ptr;
unsigned long inst;
int offset;
CORE_ADDR post_prologue_pc;
+ char buf[4];
+
+#ifdef GDB_TARGET_HAS_SHARED_LIBS
+ /* Silently return the unaltered pc upon memory errors.
+ This could happen on OSF/1 if decode_line_1 tries to skip the
+ prologue for quickstarted shared library functions when the
+ shared library is not yet mapped in.
+ Reading target memory is slow over serial lines, so we perform
+ this check only if the target has shared libraries. */
+ if (target_read_memory (pc, buf, 4))
+ return pc;
+#endif
/* See if we can determine the end of the prologue via the symbol table.
If so, then return either PC, or the PC after the prologue, whichever
or in the gcc frame. */
for (offset = 0; offset < 100; offset += 4)
{
- char buf[4];
int status;
status = read_memory_nobpt (pc + offset, buf, 4);
return pc + offset;
}
+#if 0
/* Is address PC in the prologue (loosely defined) for function at
STARTADDR? */
CORE_ADDR end_prologue = alpha_skip_prologue (startaddr, 1);
return pc >= startaddr && pc < end_prologue;
}
+#endif
/* The alpha needs a conversion between register and memory format if
the register is a floating point register and
}
else if (TYPE_CODE (valtype) == TYPE_CODE_INT && TYPE_LENGTH (valtype) <= 4)
{
- unsigned LONGEST l;
+ ULONGEST l;
l = extract_unsigned_integer (raw_buffer, REGISTER_RAW_SIZE (regnum));
l = ((l >> 32) & 0xc0000000) | ((l >> 29) & 0x3fffffff);
store_unsigned_integer (virtual_buffer, TYPE_LENGTH (valtype), l);
}
else if (TYPE_CODE (valtype) == TYPE_CODE_INT && TYPE_LENGTH (valtype) <= 4)
{
- unsigned LONGEST l;
+ ULONGEST l;
if (TYPE_UNSIGNED (valtype))
l = extract_unsigned_integer (virtual_buffer, TYPE_LENGTH (valtype));
else
/* Given a return value in `regbuf' with a type `valtype',
extract and copy its value into `valbuf'. */
+
void
alpha_extract_return_value (valtype, regbuf, valbuf)
struct type *valtype;
char regbuf[REGISTER_BYTES];
char *valbuf;
{
- int regnum;
-
- regnum = TYPE_CODE (valtype) == TYPE_CODE_FLT ? FP0_REGNUM : V0_REGNUM;
-
- memcpy (valbuf, regbuf + REGISTER_BYTE (regnum), TYPE_LENGTH (valtype));
+ if (TYPE_CODE (valtype) == TYPE_CODE_FLT)
+ alpha_register_convert_to_virtual (FP0_REGNUM, valtype,
+ regbuf + REGISTER_BYTE (FP0_REGNUM),
+ valbuf);
+ else
+ memcpy (valbuf, regbuf + REGISTER_BYTE (V0_REGNUM), TYPE_LENGTH (valtype));
}
/* Given a return value in `regbuf' with a type `valtype',
write its value into the appropriate register. */
+
void
alpha_store_return_value (valtype, valbuf)
struct type *valtype;
char *valbuf;
{
- int regnum;
char raw_buffer[MAX_REGISTER_RAW_SIZE];
+ int regnum = V0_REGNUM;
+ int length = TYPE_LENGTH (valtype);
- regnum = TYPE_CODE (valtype) == TYPE_CODE_FLT ? FP0_REGNUM : V0_REGNUM;
- memcpy(raw_buffer, valbuf, TYPE_LENGTH (valtype));
-
- write_register_bytes(REGISTER_BYTE (regnum), raw_buffer, TYPE_LENGTH (valtype));
-}
-
-/* Print the instruction at address MEMADDR in debugged memory,
- on STREAM. Returns length of the instruction, in bytes. */
-
-int
-print_insn (memaddr, stream)
- CORE_ADDR memaddr;
- GDB_FILE *stream;
-{
- disassemble_info info;
-
- GDB_INIT_DISASSEMBLE_INFO(info, stream);
+ if (TYPE_CODE (valtype) == TYPE_CODE_FLT)
+ {
+ regnum = FP0_REGNUM;
+ length = REGISTER_RAW_SIZE (regnum);
+ alpha_register_convert_to_raw (valtype, regnum, valbuf, raw_buffer);
+ }
+ else
+ memcpy (raw_buffer, valbuf, length);
- return print_insn_alpha (memaddr, &info);
+ write_register_bytes (REGISTER_BYTE (regnum), raw_buffer, length);
}
/* Just like reinit_frame_cache, but with the right arguments to be
callable as an sfunc. */
+
static void
reinit_frame_cache_sfunc (args, from_tty, c)
char *args;
if (entry != 0)
return entry;
- sym = lookup_minimal_symbol ("_Prelude", symfile_objfile);
+ sym = lookup_minimal_symbol ("_Prelude", NULL, symfile_objfile);
if (!sym || MSYMBOL_TYPE (sym) != mst_text)
return 0;
{
struct cmd_list_element *c;
+ tm_print_insn = print_insn_alpha;
+
/* Let the user set the fence post for heuristic_proc_start. */
/* We really would like to have both "0" and "unlimited" work, but