aboutsummaryrefslogtreecommitdiff
path: root/gdb/hppa-tdep.c
diff options
context:
space:
mode:
authorJason Molenda <jmolenda@apple.com>1999-09-22 03:28:34 +0000
committerJason Molenda <jmolenda@apple.com>1999-09-22 03:28:34 +0000
commitc2c6d25f0d5eea4f834420870021a8c52db24018 (patch)
treef4b3d5e9e3207fa8118db4085f9c6a0cbc2bdaf6 /gdb/hppa-tdep.c
parent54af6ff67571ba569b94e26d558d02f9955e6844 (diff)
downloadgdb-c2c6d25f0d5eea4f834420870021a8c52db24018.zip
gdb-c2c6d25f0d5eea4f834420870021a8c52db24018.tar.gz
gdb-c2c6d25f0d5eea4f834420870021a8c52db24018.tar.bz2
import gdb-1999-09-21
Diffstat (limited to 'gdb/hppa-tdep.c')
-rw-r--r--gdb/hppa-tdep.c344
1 files changed, 271 insertions, 73 deletions
diff --git a/gdb/hppa-tdep.c b/gdb/hppa-tdep.c
index 5751b45..ffcbf32 100644
--- a/gdb/hppa-tdep.c
+++ b/gdb/hppa-tdep.c
@@ -341,8 +341,12 @@ internalize_unwinds (objfile, table, section, entries, size, text_offset)
low_text_segment_address = -1;
/* If addresses are 64 bits wide, then unwinds are supposed to
- be segment relative offsets instead of absolute addresses. */
- if (TARGET_PTR_BIT == 64)
+ be segment relative offsets instead of absolute addresses.
+
+ Note that when loading a shared library (text_offset != 0) the
+ unwinds are already relative to the text_offset that will be
+ passed in. */
+ if (TARGET_PTR_BIT == 64 && text_offset == 0)
{
bfd_map_over_sections (objfile->obfd,
record_text_segment_lowaddr, (PTR) NULL);
@@ -1102,6 +1106,12 @@ frame_chain (frame)
CORE_ADDR frame_base;
struct frame_info *tmp_frame;
+ /* A frame in the current frame list, or zero. */
+ struct frame_info *saved_regs_frame = 0;
+ /* Where the registers were saved in saved_regs_frame.
+ If saved_regs_frame is zero, this is garbage. */
+ struct frame_saved_regs saved_regs;
+
CORE_ADDR caller_pc;
struct minimal_symbol *min_frame_symbol;
@@ -1195,8 +1205,7 @@ frame_chain (frame)
We use information from unwind descriptors to determine if %r3
is saved into the stack (Entry_GR field has this information). */
- tmp_frame = frame;
- while (tmp_frame)
+ for (tmp_frame = frame; tmp_frame; tmp_frame = tmp_frame->next)
{
u = find_unwind_entry (tmp_frame->pc);
@@ -1216,14 +1225,25 @@ frame_chain (frame)
return (CORE_ADDR) 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
+ if (u->Save_SP
|| tmp_frame->signal_handler_caller
|| pc_in_interrupt_handler (tmp_frame->pc))
break;
- else
- tmp_frame = tmp_frame->next;
+
+ /* 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)
+ {
+ /* The unwind entry claims that r3 is saved here. However,
+ in optimized code, GCC often doesn't actually save r3.
+ We'll discover this if we look at the prologue. */
+ get_frame_saved_regs (tmp_frame, &saved_regs);
+ saved_regs_frame = tmp_frame;
+
+ /* If we have an address for r3, that's good. */
+ if (saved_regs.regs[FP_REGNUM])
+ break;
+ }
}
if (tmp_frame)
@@ -1239,8 +1259,6 @@ frame_chain (frame)
/* %r3 was saved somewhere in the stack. Dig it out. */
else
{
- struct frame_saved_regs saved_regs;
-
/* Sick.
For optimization purposes many kernels don't have the
@@ -1267,7 +1285,8 @@ frame_chain (frame)
fail miserably if the function which performs the
system call has a variable sized stack frame. */
- get_frame_saved_regs (tmp_frame, &saved_regs);
+ if (tmp_frame != saved_regs_frame)
+ get_frame_saved_regs (tmp_frame, &saved_regs);
/* Abominable hack. */
if (current_target.to_has_execution == 0
@@ -1296,14 +1315,14 @@ frame_chain (frame)
}
else
{
- struct frame_saved_regs saved_regs;
-
/* Get the innermost frame. */
tmp_frame = frame;
while (tmp_frame->next != NULL)
tmp_frame = tmp_frame->next;
- get_frame_saved_regs (tmp_frame, &saved_regs);
+ if (tmp_frame != saved_regs_frame)
+ get_frame_saved_regs (tmp_frame, &saved_regs);
+
/* Abominable hack. See above. */
if (current_target.to_has_execution == 0
&& ((saved_regs.regs[FLAGS_REGNUM]
@@ -1670,19 +1689,22 @@ restore_pc_queue (fsr)
return 1;
}
+
+#ifdef PA20W_CALLING_CONVENTIONS
+
/* This function pushes a stack frame with arguments as part of the
inferior function calling mechanism.
- For PAs the stack always grows to higher addresses. However the arguments
- may grow to either higher or lower addresses depending on which ABI is
- currently in use.
+ This is the version for the PA64, in which later arguments appear
+ at higher addresses. (The stack always grows towards higher
+ addresses.)
We simply allocate the appropriate amount of stack space and put
arguments into their proper slots. The call dummy code will copy
arguments into registers as needed by the ABI.
- Note for the PA64 ABI we load up the argument pointer since the caller
- must provide the argument pointer to the callee. */
+ This ABI also requires that the caller provide an argument pointer
+ to the callee, so we do that too. */
CORE_ADDR
hppa_push_arguments (nargs, args, sp, struct_return, struct_addr)
@@ -1716,30 +1738,137 @@ hppa_push_arguments (nargs, args, sp, struct_return, struct_addr)
/* Iterate over each argument provided by the user. */
for (i = 0; i < nargs; i++)
{
- lengths[i] = TYPE_LENGTH (VALUE_TYPE (args[i]));
+ struct type *arg_type = VALUE_TYPE (args[i]);
+
+ /* Integral scalar values smaller than a register are padded on
+ the left. We do this by promoting them to full-width,
+ although the ABI says to pad them with garbage. */
+ if (is_integral_type (arg_type)
+ && TYPE_LENGTH (arg_type) < REGISTER_SIZE)
+ {
+ args[i] = value_cast ((TYPE_UNSIGNED (arg_type)
+ ? builtin_type_unsigned_long
+ : builtin_type_long),
+ args[i]);
+ arg_type = VALUE_TYPE (args[i]);
+ }
+
+ lengths[i] = TYPE_LENGTH (arg_type);
/* Align the size of the argument to the word size for this
target. */
bytes_reserved = (lengths[i] + REGISTER_SIZE - 1) & -REGISTER_SIZE;
-#ifdef ARGS_GROW_DOWNWARD
- offset[i] = cum_bytes_reserved + lengths[i];
-#else
- /* If the arguments grow towards lower addresses, then we want
- offset[i] to point to the start of the argument rather than
- the end of the argument. */
offset[i] = cum_bytes_reserved;
- offset[i] += (lengths[i] < REGISTER_SIZE
- ? REGISTER_SIZE - lengths[i] : 0);
-#endif
+ /* Aggregates larger than eight bytes (the only types larger
+ than eight bytes we have) are aligned on a 16-byte boundary,
+ possibly padded on the right with garbage. This may leave an
+ empty word on the stack, and thus an unused register, as per
+ the ABI. */
+ if (bytes_reserved > 8)
+ {
+ /* Round up the offset to a multiple of two slots. */
+ int new_offset = ((offset[i] + 2*REGISTER_SIZE-1)
+ & -(2*REGISTER_SIZE));
- /* If the argument is a double word argument, then it needs to be
- double word aligned.
+ /* Note the space we've wasted, if any. */
+ bytes_reserved += new_offset - offset[i];
+ offset[i] = new_offset;
+ }
- ?!? I do not think this code is correct when !ARGS_GROW_DOWNWAR. */
+ cum_bytes_reserved += bytes_reserved;
+ }
+
+ /* CUM_BYTES_RESERVED already accounts for all the arguments
+ passed by the user. However, the ABIs mandate minimum stack space
+ allocations for outgoing arguments.
+
+ The ABIs also mandate minimum stack alignments which we must
+ preserve. */
+ cum_bytes_aligned = STACK_ALIGN (cum_bytes_reserved);
+ sp += max (cum_bytes_aligned, REG_PARM_STACK_SPACE);
+
+ /* Now write each of the args at the proper offset down the stack. */
+ for (i = 0; i < nargs; i++)
+ write_memory (orig_sp + offset[i], VALUE_CONTENTS (args[i]), lengths[i]);
+
+ /* If a structure has to be returned, set up register 28 to hold its
+ address */
+ if (struct_return)
+ write_register (28, struct_addr);
+
+ /* For the PA64 we must pass a pointer to the outgoing argument list.
+ The ABI mandates that the pointer should point to the first byte of
+ storage beyond the register flushback area.
+
+ However, the call dummy expects the outgoing argument pointer to
+ be passed in register %r4. */
+ write_register (4, orig_sp + REG_PARM_STACK_SPACE);
+
+ /* ?!? This needs further work. We need to set up the global data
+ pointer for this procedure. This assumes the same global pointer
+ for every procedure. The call dummy expects the dp value to
+ be passed in register %r6. */
+ write_register (6, read_register (27));
+
+ /* The stack will have 64 bytes of additional space for a frame marker. */
+ return sp + 64;
+}
+
+#else
+
+/* This function pushes a stack frame with arguments as part of the
+ inferior function calling mechanism.
+
+ This is the version of the function for the 32-bit PA machines, in
+ which later arguments appear at lower addresses. (The stack always
+ grows towards higher addresses.)
+
+ We simply allocate the appropriate amount of stack space and put
+ arguments into their proper slots. The call dummy code will copy
+ arguments into registers as needed by the ABI. */
+
+CORE_ADDR
+hppa_push_arguments (nargs, args, sp, struct_return, struct_addr)
+ int nargs;
+ value_ptr *args;
+ CORE_ADDR sp;
+ int struct_return;
+ CORE_ADDR struct_addr;
+{
+ /* array of arguments' offsets */
+ int *offset = (int *) alloca (nargs * sizeof (int));
+
+ /* array of arguments' lengths: real lengths in bytes, not aligned to
+ word size */
+ int *lengths = (int *) alloca (nargs * sizeof (int));
+
+ /* The number of stack bytes occupied by the current argument. */
+ int bytes_reserved;
+
+ /* The total number of bytes reserved for the arguments. */
+ int cum_bytes_reserved = 0;
+
+ /* Similarly, but aligned. */
+ int cum_bytes_aligned = 0;
+ int i;
+
+ /* Iterate over each argument provided by the user. */
+ for (i = 0; i < nargs; i++)
+ {
+ lengths[i] = TYPE_LENGTH (VALUE_TYPE (args[i]));
+
+ /* Align the size of the argument to the word size for this
+ target. */
+ bytes_reserved = (lengths[i] + REGISTER_SIZE - 1) & -REGISTER_SIZE;
+
+ offset[i] = cum_bytes_reserved + lengths[i];
+
+ /* If the argument is a double word argument, then it needs to be
+ double word aligned. */
if ((bytes_reserved == 2 * REGISTER_SIZE)
- && (offset[i] % 2 * REGISTER_SIZE))
+ && (offset[i] % 2 * REGISTER_SIZE))
{
int new_offset = 0;
/* BYTES_RESERVED is already aligned to the word, so we put
@@ -1761,55 +1890,31 @@ hppa_push_arguments (nargs, args, sp, struct_return, struct_addr)
}
- /* CUM_BYTES_RESERVED already accounts for all the arguments
- passed by the user. However, the ABIs mandate minimum stack space
+ /* CUM_BYTES_RESERVED already accounts for all the arguments passed
+ by the user. However, the ABI mandates minimum stack space
allocations for outgoing arguments.
- The ABIs also mandate minimum stack alignments which we must
+ The ABI also mandates minimum stack alignments which we must
preserve. */
cum_bytes_aligned = STACK_ALIGN (cum_bytes_reserved);
sp += max (cum_bytes_aligned, REG_PARM_STACK_SPACE);
/* Now write each of the args at the proper offset down the stack.
-
- The two ABIs write arguments in different directions using different
- starting points. What fun.
-
?!? We need to promote values to a full register instead of skipping
words in the stack. */
-#ifndef ARGS_GROW_DOWNWARD
- for (i = 0; i < nargs; i++)
- write_memory (orig_sp + offset[i], VALUE_CONTENTS (args[i]), lengths[i]);
-#else
for (i = 0; i < nargs; i++)
write_memory (sp - offset[i], VALUE_CONTENTS (args[i]), lengths[i]);
-#endif
/* If a structure has to be returned, set up register 28 to hold its
address */
if (struct_return)
write_register (28, struct_addr);
-#ifndef ARGS_GROW_DOWNWARD
- /* For the PA64 we must pass a pointer to the outgoing argument list.
- The ABI mandates that the pointer should point to the first byte of
- storage beyond the register flushback area.
-
- However, the call dummy expects the outgoing argument pointer to
- be passed in register %r4. */
- write_register (4, orig_sp + REG_PARM_STACK_SPACE);
-
- /* ?!? This needs further work. We need to set up the global data
- pointer for this procedure. This assumes the same global pointer
- for every procedure. The call dummy expects the dp value to
- be passed in register %r6. */
- write_register (6, read_register (27));
-#endif
-
/* The stack will have 32 bytes of additional space for a frame marker. */
return sp + 32;
}
+#endif
/* elz: this function returns a value which is built looking at the given address.
It is called from call_function_by_hand, in case we need to return a
@@ -1973,8 +2078,8 @@ hppa_fix_call_dummy (dummy, pc, fun, nargs, args, type, gcc_p)
CORE_ADDR solib_handle = 0;
/* Nonzero if we will use GCC's PLT call routine. This routine must be
- passed an import stub, not a PLABEL. It is also necessary to set %r19
- (the PIC register) before performing the call.
+ passed an import stub, not a PLABEL. It is also necessary to set %r19
+ (the PIC register) before performing the call.
If zero, then we are using __d_plt_call (HP's PLT call routine) or we
are calling the target directly. When using __d_plt_call we want to
@@ -2045,7 +2150,7 @@ hppa_fix_call_dummy (dummy, pc, fun, nargs, args, type, gcc_p)
write_register (5, fun);
/* We need to see if this objfile has a different DP value than our
- own (it could be a shared library for example. */
+ own (it could be a shared library for example). */
ALL_OBJFILES (objfile)
{
struct obj_section *s;
@@ -2822,8 +2927,73 @@ in_solib_call_trampoline (pc, name)
static CORE_ADDR dyncall = 0;
static CORE_ADDR sr4export = 0;
-/* FIXME XXX - dyncall and sr4export must be initialized whenever we get a
- new exec file */
+#ifdef GDB_TARGET_IS_HPPA_20W
+ /* PA64 has a completely different stub/trampoline scheme. Is it
+ better? Maybe. It's certainly harder to determine with any
+ certainty that we are in a stub because we can not refer to the
+ unwinders to help.
+
+ The heuristic is simple. Try to lookup the current PC value in th
+ minimal symbol table. If that fails, then assume we are not in a
+ stub and return.
+
+ Then see if the PC value falls within the section bounds for the
+ section containing the minimal symbol we found in the first
+ step. If it does, then assume we are not in a stub and return.
+
+ Finally peek at the instructions to see if they look like a stub. */
+ {
+ struct minimal_symbol *minsym;
+ asection *sec;
+ CORE_ADDR addr;
+ int insn, i;
+
+ minsym = lookup_minimal_symbol_by_pc (pc);
+ if (! minsym)
+ return 0;
+
+ sec = SYMBOL_BFD_SECTION (minsym);
+
+ if (sec->vma <= pc
+ && sec->vma + sec->_cooked_size < pc)
+ return 0;
+
+ /* We might be in a stub. Peek at the instructions. Stubs are 3
+ instructions long. */
+ insn = read_memory_integer (pc, 4);
+
+ /* Find out where we we think we are within the stub. */
+ if ((insn & 0xffffc00e) == 0x53610000)
+ addr = pc;
+ else if ((insn & 0xffffffff) == 0xe820d000)
+ addr = pc - 4;
+ else if ((insn & 0xffffc00e) == 0x537b0000)
+ addr = pc - 8;
+ else
+ return 0;
+
+ /* Now verify each insn in the range looks like a stub instruction. */
+ insn = read_memory_integer (addr, 4);
+ if ((insn & 0xffffc00e) != 0x53610000)
+ return 0;
+
+ /* Now verify each insn in the range looks like a stub instruction. */
+ insn = read_memory_integer (addr + 4, 4);
+ if ((insn & 0xffffffff) != 0xe820d000)
+ return 0;
+
+ /* Now verify each insn in the range looks like a stub instruction. */
+ insn = read_memory_integer (addr + 8, 4);
+ if ((insn & 0xffffc00e) != 0x537b0000)
+ return 0;
+
+ /* Looks like a stub. */
+ return 1;
+ }
+#endif
+
+ /* FIXME XXX - dyncall and sr4export must be initialized whenever we get a
+ new exec file */
/* First see if PC is in one of the two C-library trampolines. */
if (!dyncall)
@@ -2997,9 +3167,8 @@ skip_trampoline_code (pc, name)
struct minimal_symbol *msym;
struct unwind_table_entry *u;
-
-/* FIXME XXX - dyncall and sr4export must be initialized whenever we get a
- new exec file */
+ /* FIXME XXX - dyncall and sr4export must be initialized whenever we get a
+ new exec file */
if (!dyncall)
{
@@ -3829,16 +3998,21 @@ hppa_frame_find_saved_regs (frame_info, frame_saved_regs)
/* There are limited ways to store the return pointer into the
stack. */
- if (inst == 0x6bc23fd9 || inst == 0x0fc212c1)
+ if (inst == 0x6bc23fd9) /* stw rp,-0x14(sr0,sp) */
{
save_rp = 0;
frame_saved_regs->regs[RP_REGNUM] = frame_info->frame - 20;
}
+ else if (inst == 0x0fc212c1) /* std rp,-0x10(sr0,sp) */
+ {
+ save_rp = 0;
+ frame_saved_regs->regs[RP_REGNUM] = frame_info->frame - 16;
+ }
/* Note if we saved SP into the stack. This also happens to indicate
the location of the saved frame pointer. */
- if ((inst & 0xffffc000) == 0x6fc10000
- || (inst & 0xffffc00c) == 0x73c10008)
+ if ( (inst & 0xffffc000) == 0x6fc10000 /* stw,ma r1,N(sr0,sp) */
+ || (inst & 0xffffc00c) == 0x73c10008) /* std,ma r1,N(sr0,sp) */
{
frame_saved_regs->regs[FP_REGNUM] = frame_info->frame;
save_sp = 0;
@@ -4542,6 +4716,30 @@ hppa_prepare_to_proceed ()
#endif /* PREPARE_TO_PROCEED */
void
+hppa_skip_permanent_breakpoint ()
+{
+ /* To step over a breakpoint instruction on the PA takes some
+ fiddling with the instruction address queue.
+
+ When we stop at a breakpoint, the IA queue front (the instruction
+ we're executing now) points at the breakpoint instruction, and
+ the IA queue back (the next instruction to execute) points to
+ whatever instruction we would execute after the breakpoint, if it
+ were an ordinary instruction. This is the case even if the
+ breakpoint is in the delay slot of a branch instruction.
+
+ Clearly, to step past the breakpoint, we need to set the queue
+ front to the back. But what do we put in the back? What
+ instruction comes after that one? Because of the branch delay
+ slot, the next insn is always at the back + 4. */
+ write_register (PCOQ_HEAD_REGNUM, read_register (PCOQ_TAIL_REGNUM));
+ write_register (PCSQ_HEAD_REGNUM, read_register (PCSQ_TAIL_REGNUM));
+
+ write_register (PCOQ_TAIL_REGNUM, read_register (PCOQ_TAIL_REGNUM) + 4);
+ /* We can leave the tail's space the same, since there's no jump. */
+}
+
+void
_initialize_hppa_tdep ()
{
tm_print_insn = print_insn_hppa;