static int restore_pc_queue PARAMS ((struct frame_saved_regs *fsr));
static int hppa_alignof PARAMS ((struct type *arg));
+static FRAME_ADDR dig_fp_from_stack PARAMS ((FRAME frame,
+ struct unwind_table_entry *u));
CORE_ADDR frame_saved_pc PARAMS ((FRAME frame));
\f
int flags;
int framesize;
- if (frame->next) /* Only do this for outermost frame */
+ if (frame->next && !fromleaf)
return;
+ /* If the next frame represents a frameless function invocation
+ then we have to do some adjustments that are normally done by
+ FRAME_CHAIN. (FRAME_CHAIN is not called in this case.) */
+ if (fromleaf)
+ {
+ /* Find the framesize of *this* frame without peeking at the PC
+ in the current frame structure (it isn't set yet). */
+ framesize = find_proc_framesize (FRAME_SAVED_PC (get_next_frame (frame)));
+
+ /* Now adjust our base frame accordingly. If we have a frame pointer
+ use it, else subtract the size of this frame from the current
+ frame. (we always want frame->frame to point at the lowest address
+ in the frame). */
+ if (framesize == -1)
+ frame->frame = read_register (FP_REGNUM);
+ else
+ frame->frame -= framesize;
+ return;
+ }
+
flags = read_register (FLAGS_REGNUM);
if (flags & 2) /* In system call? */
frame->pc = read_register (31) & ~0x3;
- /* The outermost frame is always derived from PC-framesize */
+ /* The outermost frame is always derived from PC-framesize
+
+ One might think frameless innermost frames should have
+ a frame->frame that is the same as the parent's frame->frame.
+ That is wrong; frame->frame in that case should be the *high*
+ address of the parent's frame. It's complicated as hell to
+ explain, but the parent *always* creates some stack space for
+ the child. So the child actually does have a frame of some
+ sorts, and its base is the high address in its parent's frame. */
framesize = find_proc_framesize(frame->pc);
if (framesize == -1)
frame->frame = read_register (FP_REGNUM);
else
frame->frame = read_register (SP_REGNUM) - framesize;
-
- if (!frameless_function_invocation (frame)) /* Frameless? */
- return; /* No, quit now */
-
- /* For frameless functions, we need to look at the caller's frame */
- framesize = find_proc_framesize(FRAME_SAVED_PC(frame));
- if (framesize != -1)
- frame->frame -= framesize;
}
\f
+/* Given a GDB frame, determine the address of the calling function's frame.
+ This will be used to create a new GDB frame struct, and then
+ INIT_EXTRA_FRAME_INFO and INIT_FRAME_PC will be called for the new frame.
+
+ This may involve searching through prologues for several functions
+ at boundaries where GCC calls HP C code, or where code which has
+ a frame pointer calls code without a frame pointer. */
+
+
FRAME_ADDR
frame_chain (frame)
struct frame_info *frame;
{
- int framesize;
+ int my_framesize, caller_framesize;
+ struct unwind_table_entry *u;
+
+ /* Get frame sizes for the current frame and the frame of the
+ caller. */
+ my_framesize = find_proc_framesize (frame->pc);
+ caller_framesize = find_proc_framesize (FRAME_SAVED_PC(frame));
+
+ /* If caller does not have a frame pointer, then its frame
+ can be found at current_frame - caller_framesize. */
+ if (caller_framesize != -1)
+ return frame->frame - caller_framesize;
+
+ /* Both caller and callee have frame pointers and are GCC compiled
+ (SAVE_SP bit in unwind descriptor is on for both functions.
+ The previous frame pointer is found at the top of the current frame. */
+ if (caller_framesize == -1 && my_framesize == -1)
+ return read_memory_integer (frame->frame, 4);
+
+ /* Caller has a frame pointer, but callee does not. This is a little
+ more difficult as GCC and HP C lay out locals and callee register save
+ areas very differently.
+
+ The previous frame pointer could be in a register, or in one of
+ several areas on the stack.
+
+ Walk from the current frame to the innermost frame examining
+ unwind descriptors to determine if %r3 ever gets saved into the
+ stack. If so return whatever value got saved into the stack.
+ If it was never saved in the stack, then the value in %r3 is still
+ valid, so use it.
- framesize = find_proc_framesize(FRAME_SAVED_PC(frame));
+ We use information from unwind descriptors to determine if %r3
+ is saved into the stack (Entry_GR field has this information). */
- if (framesize != -1)
- return frame->frame - framesize;
+ while (frame)
+ {
+ u = find_unwind_entry (frame->pc);
+
+ if (!u)
+ {
+ /* We could find this information by examining prologues. I don't
+ think anyone has actually written any tools (not even "strip")
+ which leave them out of an executable, so maybe this is a moot
+ point. */
+ warning ("Unable to find unwind for PC 0x%x -- Help!", frame->pc);
+ return 0;
+ }
+
+ /* Entry_GR specifies the number of callee-saved general registers
+ saved in the stack. It starts at %r3, so %r3 would be 1. */
+ if (u->Entry_GR >= 1 || u->Save_SP)
+ break;
+ else
+ frame = frame->next;
+ }
- return read_memory_integer (frame->frame, 4);
+ if (frame)
+ {
+ /* We may have walked down the chain into a function with a frame
+ pointer. */
+ if (u->Save_SP)
+ return read_memory_integer (frame->frame, 4);
+ /* %r3 was saved somewhere in the stack. Dig it out. */
+ else
+ return dig_fp_from_stack (frame, u);
+ }
+ else
+ {
+ /* The value in %r3 was never saved into the stack (thus %r3 still
+ holds the value of the previous frame pointer). */
+ return read_register (FP_REGNUM);
+ }
}
+
+/* Given a frame and an unwind descriptor return the value for %fr (aka fp)
+ which was saved into the stack. FIXME: Why can't we just use the standard
+ saved_regs stuff? */
+
+static FRAME_ADDR
+dig_fp_from_stack (frame, u)
+ FRAME frame;
+ struct unwind_table_entry *u;
+{
+ CORE_ADDR pc = u->region_start;
+
+ /* Search the function for the save of %r3. */
+ while (pc != u->region_end)
+ {
+ char buf[4];
+ unsigned long inst;
+ int status;
+
+ /* We need only look for the standard stw %r3,X(%sp) instruction,
+ the other variants (eg stwm) are only used on the first register
+ save (eg %r3). */
+ status = target_read_memory (pc, buf, 4);
+ inst = extract_unsigned_integer (buf, 4);
+
+ if (status != 0)
+ memory_error (status, pc);
+
+ /* Check for stw %r3,X(%sp). */
+ if ((inst & 0xffffc000) == 0x6bc30000)
+ {
+ /* Found the instruction which saves %r3. The offset (relative
+ to this frame) is framesize + immed14 (derived from the
+ store instruction). */
+ int offset = (u->Total_frame_size << 3) + extract_14 (inst);
+
+ return read_memory_integer (frame->frame + offset, 4);
+ }
+
+ /* Keep looking. */
+ pc += 4;
+ }
+
+ warning ("Unable to find %%r3 in stack.\n");
+ return 0;
+}
+
\f
/* To see if a frame chain is valid, see if the caller looks like it
was compiled with gcc. */
write_register (SAR_REGNUM,
read_memory_integer (fsr.regs[SAR_REGNUM], 4));
+ /* If the PC was explicitly saved, then just restore it. */
if (fsr.regs[PCOQ_TAIL_REGNUM])
write_register (PCOQ_TAIL_REGNUM,
read_memory_integer (fsr.regs[PCOQ_TAIL_REGNUM], 4));
+ /* Else use the value in %rp to set the new PC. */
+ else
+ target_write_pc (read_register (RP_REGNUM));
+
write_register (FP_REGNUM, read_memory_integer (fp, 4));
if (fsr.regs[IPSW_REGNUM]) /* call dummy */
CORE_ADDR pc = read_pc ();
CORE_ADDR new_pc = read_memory_integer (fsr->regs[PCOQ_HEAD_REGNUM], 4);
int pid;
- WAITTYPE w;
+ struct target_waitstatus w;
int insn_count;
/* Advance past break instruction in the call dummy. */
for (insn_count = 0; insn_count < 3; insn_count++)
{
+ /* FIXME: What if the inferior gets a signal right now? Want to
+ merge this into wait_for_inferior (as a special kind of
+ watchpoint? By setting a breakpoint at the end? Is there
+ any other choice? Is there *any* way to do this stuff with
+ ptrace() or some equivalent?). */
resume (1, 0);
- target_wait(&w);
+ target_wait (inferior_pid, &w);
- if (!WIFSTOPPED (w))
+ if (w.kind == TARGET_WAITKIND_SIGNALLED)
{
- stop_signal = WTERMSIG (w);
+ stop_signal = w.value.sig;
terminal_ours_for_output ();
- printf ("\nProgram terminated with signal %d, %s\n",
- stop_signal, safe_strsignal (stop_signal));
- fflush (stdout);
+ printf_unfiltered ("\nProgram terminated with signal %s, %s.\n",
+ target_signal_to_name (stop_signal),
+ target_signal_to_string (stop_signal));
+ gdb_flush (gdb_stdout);
return 0;
}
}
+ target_terminal_ours ();
fetch_inferior_registers (-1);
return 1;
}
CORE_ADDR
hppa_fix_call_dummy (dummy, pc, fun, nargs, args, type, gcc_p)
- REGISTER_TYPE *dummy;
+ char *dummy;
CORE_ADDR pc;
CORE_ADDR fun;
int nargs;
{
CORE_ADDR dyncall_addr, sr4export_addr;
struct minimal_symbol *msymbol;
+ int flags = read_register (FLAGS_REGNUM);
msymbol = lookup_minimal_symbol ("$$dyncall", (struct objfile *) NULL);
if (msymbol == NULL)
sr4export_addr = SYMBOL_VALUE_ADDRESS (msymbol);
- dummy[9] = deposit_21 (fun >> 11, dummy[9]);
- dummy[10] = deposit_14 (fun & MASK_11, dummy[10]);
- dummy[12] = deposit_21 (sr4export_addr >> 11, dummy[12]);
- dummy[13] = deposit_14 (sr4export_addr & MASK_11, dummy[13]);
+ store_unsigned_integer
+ (&dummy[9*REGISTER_SIZE],
+ REGISTER_SIZE,
+ deposit_21 (fun >> 11,
+ extract_unsigned_integer (&dummy[9*REGISTER_SIZE],
+ REGISTER_SIZE)));
+ store_unsigned_integer
+ (&dummy[10*REGISTER_SIZE],
+ REGISTER_SIZE,
+ deposit_14 (fun & MASK_11,
+ extract_unsigned_integer (&dummy[10*REGISTER_SIZE],
+ REGISTER_SIZE)));
+ store_unsigned_integer
+ (&dummy[12*REGISTER_SIZE],
+ REGISTER_SIZE,
+ deposit_21 (sr4export_addr >> 11,
+ extract_unsigned_integer (&dummy[12*REGISTER_SIZE],
+ REGISTER_SIZE)));
+ store_unsigned_integer
+ (&dummy[13*REGISTER_SIZE],
+ REGISTER_SIZE,
+ deposit_14 (sr4export_addr & MASK_11,
+ extract_unsigned_integer (&dummy[13*REGISTER_SIZE],
+ REGISTER_SIZE)));
write_register (22, pc);
- return dyncall_addr;
+ /* If we are in a syscall, then we should call the stack dummy
+ directly. $$dyncall is not needed as the kernel sets up the
+ space id registers properly based on the value in %r31. In
+ fact calling $$dyncall will not work because the value in %r22
+ will be clobbered on the syscall exit path. */
+ if (flags & 2)
+ return pc;
+ else
+ return dyncall_addr;
+
+}
+
+/* Get the PC from %r31 if currently in a syscall. Also mask out privilege
+ bits. */
+CORE_ADDR
+target_read_pc ()
+{
+ int flags = read_register (FLAGS_REGNUM);
+
+ if (flags & 2)
+ return read_register (31) & ~0x3;
+ return read_register (PC_REGNUM) & ~0x3;
+}
+
+/* Write out the PC. If currently in a syscall, then also write the new
+ PC value into %r31. */
+void
+target_write_pc (v)
+ CORE_ADDR v;
+{
+ int flags = read_register (FLAGS_REGNUM);
+
+ /* If in a syscall, then set %r31. Also make sure to get the
+ privilege bits set correctly. */
+ if (flags & 2)
+ write_register (31, (long) (v | 0x3));
+
+ write_register (PC_REGNUM, (long) v);
+ write_register (NPC_REGNUM, (long) v + 4);
}
/* return the alignment of a type in bytes. Structures have the maximum
if (regnum == -1)
pa_print_registers (raw_regs, regnum, fpregs);
else if (regnum < FP0_REGNUM)
- printf ("%s %x\n", reg_names[regnum], *(long *)(raw_regs +
+ printf_unfiltered ("%s %x\n", reg_names[regnum], *(long *)(raw_regs +
REGISTER_BYTE (regnum)));
else
pa_print_fp_reg (regnum);
int i;
for (i = 0; i < 18; i++)
- printf ("%8.8s: %8x %8.8s: %8x %8.8s: %8x %8.8s: %8x\n",
+ printf_unfiltered ("%8.8s: %8x %8.8s: %8x %8.8s: %8x %8.8s: %8x\n",
reg_names[i],
*(int *)(raw_regs + REGISTER_BYTE (i)),
reg_names[i + 18],
{
unsigned char raw_buffer[MAX_REGISTER_RAW_SIZE];
unsigned char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE];
- REGISTER_TYPE val;
- /* Get the data in raw format, then convert also to virtual format. */
+ /* Get the data in raw format. */
read_relative_register_raw_bytes (i, raw_buffer);
- REGISTER_CONVERT_TO_VIRTUAL (i, raw_buffer, virtual_buffer);
- fputs_filtered (reg_names[i], stdout);
- print_spaces_filtered (15 - strlen (reg_names[i]), stdout);
+ /* Convert raw data to virtual format if necessary. */
+#ifdef REGISTER_CONVERTIBLE
+ if (REGISTER_CONVERTIBLE (i))
+ {
+ REGISTER_CONVERT_TO_VIRTUAL (i, REGISTER_VIRTUAL_TYPE (i),
+ raw_buffer, virtual_buffer);
+ }
+ else
+#endif
+ memcpy (virtual_buffer, raw_buffer,
+ REGISTER_VIRTUAL_SIZE (i));
+
+ fputs_filtered (reg_names[i], gdb_stdout);
+ print_spaces_filtered (15 - strlen (reg_names[i]), gdb_stdout);
- val_print (REGISTER_VIRTUAL_TYPE (i), virtual_buffer, 0, stdout, 0,
+ val_print (REGISTER_VIRTUAL_TYPE (i), virtual_buffer, 0, gdb_stdout, 0,
1, 0, Val_pretty_default);
printf_filtered ("\n");
}
if (inst == 0x6BC23FD9) /* stw rp,-20(sp) */
{
- if (read_memory_integer (pc + 4, 4) == 0x8040241) /* copy r4,r1 */
+ if (read_memory_integer (pc + 4, 4) == 0x8030241) /* copy r3,r1 */
pc += 16;
- else if ((read_memory_integer (pc + 4, 4) & ~MASK_14) == 0x68810000) /* stw r1,(r4) */
+ else if ((read_memory_integer (pc + 4, 4) & ~MASK_14) == 0x68710000) /* stw r1,(r3) */
pc += 8;
}
- else if (read_memory_integer (pc, 4) == 0x8040241) /* copy r4,r1 */
+ else if (read_memory_integer (pc, 4) == 0x8030241) /* copy r3,r1 */
pc += 12;
- else if ((read_memory_integer (pc, 4) & ~MASK_14) == 0x68810000) /* stw r1,(r4) */
+ else if ((read_memory_integer (pc, 4) & ~MASK_14) == 0x68710000) /* stw r1,(r3) */
pc += 4;
return pc;
if (!xxx.u)
{
- printf ("Can't find unwind table entry for PC 0x%x\n", address);
+ printf_unfiltered ("Can't find unwind table entry for PC 0x%x\n", address);
return;
}
- printf ("%08x\n%08X\n%08X\n%08X\n", xxx.foo[0], xxx.foo[1], xxx.foo[2],
+ printf_unfiltered ("%08x\n%08X\n%08X\n%08X\n", xxx.foo[0], xxx.foo[1], xxx.foo[2],
xxx.foo[3]);
}
+#endif /* MAINTENANCE_CMDS */
void
_initialize_hppa_tdep ()
{
+#ifdef MAINTENANCE_CMDS
add_cmd ("unwind", class_maintenance, unwind_command,
"Print unwind table entry at given address.",
&maintenanceprintlist);
-}
-
#endif /* MAINTENANCE_CMDS */
+}