/* Target-dependent code for the HP PA architecture, for GDB.
- Copyright 1986, 1987, 1989, 1990, 1991, 1992, 1993, 1994, 1995
+ Copyright 1986, 1987, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996
Free Software Foundation, Inc.
Contributed by the Center for Software Science at the
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"
static int pc_in_linker_stub PARAMS ((CORE_ADDR));
-static int compare_unwind_entries PARAMS ((const struct unwind_table_entry *,
- const struct unwind_table_entry *));
+static int compare_unwind_entries PARAMS ((const void *, const void *));
static void read_unwind_info PARAMS ((struct objfile *));
larger than the first, and zero if they are equal. */
static int
-compare_unwind_entries (a, b)
- const struct unwind_table_entry *a;
- const struct unwind_table_entry *b;
+compare_unwind_entries (arg1, arg2)
+ const void *arg1;
+ const void *arg2;
{
+ const struct unwind_table_entry *a = arg1;
+ const struct unwind_table_entry *b = arg2;
+
if (a->region_start > b->region_start)
return 1;
else if (a->region_start < b->region_start)
contains a sorted list of struct unwind_table_entry. Since we do a binary
search of the unwind tables, we depend upon them to be sorted. */
-static struct unwind_table_entry *
+struct unwind_table_entry *
find_unwind_entry(pc)
CORE_ADDR pc;
{
}
/* If PC is inside a linker stub, then dig out the address the stub
- will return to. */
+ will return to.
+
+ Don't do this for long branch stubs. Why? For some unknown reason
+ _start is marked as a long branch stub in hpux10. */
u = find_unwind_entry (pc);
- if (u && u->stub_type != 0)
+ if (u && u->stub_type != 0
+ && u->stub_type != LONG_BRANCH)
{
unsigned int insn;
/* Abominable hack. */
if (current_target.to_has_execution == 0
- && saved_regs.regs[FLAGS_REGNUM]
- && (read_memory_integer (saved_regs.regs[FLAGS_REGNUM], 4) & 0x2))
+ && ((saved_regs.regs[FLAGS_REGNUM]
+ && (read_memory_integer (saved_regs.regs[FLAGS_REGNUM], 4)
+ & 0x2))
+ || (saved_regs.regs[FLAGS_REGNUM] == 0
+ && read_register (FLAGS_REGNUM) & 0x2)))
{
u = find_unwind_entry (FRAME_SAVED_PC (frame));
if (!u)
}
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);
+ /* Abominable hack. See above. */
+ if (current_target.to_has_execution == 0
+ && ((saved_regs.regs[FLAGS_REGNUM]
+ && (read_memory_integer (saved_regs.regs[FLAGS_REGNUM], 4)
+ & 0x2))
+ || (saved_regs.regs[FLAGS_REGNUM] == 0
+ && read_register (FLAGS_REGNUM) & 0x2)))
+ {
+ u = find_unwind_entry (FRAME_SAVED_PC (frame));
+ if (!u)
+ return read_memory_integer (saved_regs.regs[FP_REGNUM], 4);
+ else
+ return frame_base - (u->Total_frame_size << 3);
+ }
+
/* 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);
&& SYMBOL_VALUE_ADDRESS (msym_us) == SYMBOL_VALUE_ADDRESS (msym_start))
return 0;
+ /* Grrrr. Some new idiot decided that they don't want _start for the
+ PRO configurations; $START$ calls main directly.... Deal with it. */
+ msym_start = lookup_minimal_symbol ("$START$", NULL, NULL);
+ if (msym_us
+ && msym_start
+ && SYMBOL_VALUE_ADDRESS (msym_us) == SYMBOL_VALUE_ADDRESS (msym_start))
+ return 0;
+
next = get_next_frame (thisframe);
if (next)
next_u = find_unwind_entry (next->pc);
old_chain = make_cleanup (delete_breakpoint, breakpoint);
/* Start up the inferior. */
+ clear_proceed_status ();
proceed_to_finish = 1;
proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0);
alignment required by their fields. */
static int
-hppa_alignof (arg)
- struct type *arg;
+hppa_alignof (type)
+ struct type *type;
{
int max_align, align, i;
- switch (TYPE_CODE (arg))
+ CHECK_TYPEDEF (type);
+ switch (TYPE_CODE (type))
{
case TYPE_CODE_PTR:
case TYPE_CODE_INT:
case TYPE_CODE_FLT:
- return TYPE_LENGTH (arg);
+ return TYPE_LENGTH (type);
case TYPE_CODE_ARRAY:
- return hppa_alignof (TYPE_FIELD_TYPE (arg, 0));
+ return hppa_alignof (TYPE_FIELD_TYPE (type, 0));
case TYPE_CODE_STRUCT:
case TYPE_CODE_UNION:
max_align = 2;
- for (i = 0; i < TYPE_NFIELDS (arg); i++)
+ for (i = 0; i < TYPE_NFIELDS (type); i++)
{
/* Bit fields have no real alignment. */
- if (!TYPE_FIELD_BITPOS (arg, i))
+ if (!TYPE_FIELD_BITPOS (type, i))
{
- align = hppa_alignof (TYPE_FIELD_TYPE (arg, i));
+ align = hppa_alignof (TYPE_FIELD_TYPE (type, i));
max_align = max (max_align, align);
}
}
CORE_ADDR pc;
{
char buf[4];
+ CORE_ADDR orig_pc = pc;
unsigned long inst, stack_remaining, save_gr, save_fr, save_rp, save_sp;
- unsigned long args_stored, status, i;
+ unsigned long args_stored, status, i, restart_gr, restart_fr;
struct unwind_table_entry *u;
+ restart_gr = 0;
+ restart_fr = 0;
+
+restart:
u = find_unwind_entry (pc);
if (!u)
return pc;
/* An indication that args may be stored into the stack. Unfortunately
the HPUX compilers tend to set this in cases where no args were
stored too!. */
- args_stored = u->Args_stored;
+ args_stored = 1;
/* Turn the Entry_GR field into a bitmask. */
save_gr = 0;
save_gr |= (1 << i);
}
+ save_gr &= ~restart_gr;
/* Turn the Entry_FR field into a bitmask too. */
save_fr = 0;
for (i = 12; i < u->Entry_FR + 12; i++)
save_fr |= (1 << i);
+ save_fr &= ~restart_fr;
/* Loop until we find everything of interest or hit a branch.
pc += 4;
}
+ /* We've got a tenative location for the end of the prologue. However
+ because of limitations in the unwind descriptor mechanism we may
+ have went too far into user code looking for the save of a register
+ that does not exist. So, if there registers we expected to be saved
+ but never were, mask them out and restart.
+
+ This should only happen in optimized code, and should be very rare. */
+ if (save_gr || save_fr
+ && ! (restart_fr || restart_gr))
+ {
+ pc = orig_pc;
+ restart_gr = save_gr;
+ restart_fr = save_fr;
+ goto restart;
+ }
+
return pc;
}