#define MASK_14 0x3fff
#define MASK_21 0x1fffff
-/* Define offsets into the call dummy for the _sr4export address.
- See comments related to CALL_DUMMY for more info. */
-#define SR4EXPORT_LDIL_OFFSET (HPPA_INSTRUCTION_SIZE * 12)
-#define SR4EXPORT_LDO_OFFSET (HPPA_INSTRUCTION_SIZE * 13)
-
/* Sizes (in bytes) of the native unwind entries. */
#define UNWIND_ENTRY_SIZE 16
#define STUB_UNWIND_ENTRY_SIZE 8
/* FIXME: brobecker 2002-11-07: We will likely be able to make the
following functions static, once we hppa is partially multiarched. */
int hppa_pc_requires_run_before_use (CORE_ADDR pc);
-int hppa_instruction_nullified (void);
/* Handle 32/64-bit struct return conventions. */
hppa_get_field (word, 11, 15) << 11 |
(word & 0x1) << 16, 17) << 2;
}
+
+CORE_ADDR
+hppa_symbol_address(const char *sym)
+{
+ struct minimal_symbol *minsym;
+
+ minsym = lookup_minimal_symbol (sym, NULL, NULL);
+ if (minsym)
+ return SYMBOL_VALUE_ADDRESS (minsym);
+ else
+ return (CORE_ADDR)-1;
+}
\f
/* Compare the start address for two unwind entries returning 1 if
text_offset = low_text_segment_address;
}
+ else if (gdbarch_tdep (current_gdbarch)->solib_get_text_base)
+ {
+ text_offset = gdbarch_tdep (current_gdbarch)->solib_get_text_base (objfile);
+ }
bfd_get_section_contents (objfile->obfd, section, buf, 0, size);
return NULL;
}
+/* The epilogue is defined here as the area either on the `bv' instruction
+ itself or an instruction which destroys the function's stack frame.
+
+ We do not assume that the epilogue is at the end of a function as we can
+ also have return sequences in the middle of a function. */
+static int
+hppa_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ unsigned long status;
+ unsigned int inst;
+ char buf[4];
+ int off;
+
+ status = deprecated_read_memory_nobpt (pc, buf, 4);
+ if (status != 0)
+ return 0;
+
+ inst = extract_unsigned_integer (buf, 4);
+
+ /* The most common way to perform a stack adjustment ldo X(sp),sp
+ We are destroying a stack frame if the offset is negative. */
+ if ((inst & 0xffffc000) == 0x37de0000
+ && hppa_extract_14 (inst) < 0)
+ return 1;
+
+ /* ldw,mb D(sp),X or ldd,mb D(sp),X */
+ if (((inst & 0x0fc010e0) == 0x0fc010e0
+ || (inst & 0x0fc010e0) == 0x0fc010e0)
+ && hppa_extract_14 (inst) < 0)
+ return 1;
+
+ /* bv %r0(%rp) or bv,n %r0(%rp) */
+ if (inst == 0xe840c000 || inst == 0xe840c002)
+ return 1;
+
+ return 0;
+}
+
static const unsigned char *
hppa_breakpoint_from_pc (CORE_ADDR *pc, int *len)
{
/* Return the name of a register. */
-const char *
+static const char *
hppa32_register_name (int i)
{
static char *names[] = {
return names[i];
}
-const char *
+static const char *
hppa64_register_name (int i)
{
static char *names[] = {
We simply allocate the appropriate amount of stack space and put
arguments into their proper slots. */
-CORE_ADDR
-hppa32_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+static CORE_ADDR
+hppa32_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
struct regcache *regcache, CORE_ADDR bp_addr,
int nargs, struct value **args, CORE_ADDR sp,
int struct_return, CORE_ADDR struct_addr)
/* Two passes. First pass computes the location of everything,
second pass writes the bytes out. */
int write_pass;
+
+ /* Global pointer (r19) of the function we are trying to call. */
+ CORE_ADDR gp;
+
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
for (write_pass = 0; write_pass < 2; write_pass++)
{
CORE_ADDR struct_ptr = 0;
for (i = 0; i < nargs; i++)
{
struct value *arg = args[i];
- struct type *type = check_typedef (VALUE_TYPE (arg));
+ struct type *type = check_typedef (value_type (arg));
/* The corresponding parameter that is pushed onto the
stack, and [possibly] passed in a register. */
char param_val[8];
if (struct_return)
write_register (28, struct_addr);
+ gp = tdep->find_global_pointer (function);
+
+ if (gp != 0)
+ write_register (19, gp);
+
/* Set the return address. */
regcache_cooked_write_unsigned (regcache, HPPA_RP_REGNUM, bp_addr);
This ABI also requires that the caller provide an argument pointer
to the callee, so we do that too. */
-CORE_ADDR
-hppa64_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+static CORE_ADDR
+hppa64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
struct regcache *regcache, CORE_ADDR bp_addr,
int nargs, struct value **args, CORE_ADDR sp,
int struct_return, CORE_ADDR struct_addr)
for (i = 0; i < nargs; i++)
{
struct value *arg = args[i];
- struct type *type = check_typedef (VALUE_TYPE (arg));
+ struct type *type = check_typedef (value_type (arg));
if ((TYPE_CODE (type) == TYPE_CODE_INT
|| TYPE_CODE (type) == TYPE_CODE_ENUM)
&& TYPE_LENGTH (type) <= 8)
return param_end + 64;
}
+static CORE_ADDR
+hppa32_convert_from_func_ptr_addr (struct gdbarch *gdbarch,
+ CORE_ADDR addr,
+ struct target_ops *targ)
+{
+ if (addr & 2)
+ {
+ CORE_ADDR plabel;
+
+ plabel = addr & ~3;
+ target_read_memory(plabel, (char *)&addr, 4);
+ }
+
+ return addr;
+}
+
static CORE_ADDR
hppa32_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr)
{
return align_up (addr, 16);
}
-
-/* Get the PC from %r31 if currently in a syscall. Also mask out privilege
- bits. */
-
-static CORE_ADDR
-hppa_target_read_pc (ptid_t ptid)
+CORE_ADDR
+hppa_read_pc (ptid_t ptid)
{
- int flags = read_register_pid (HPPA_FLAGS_REGNUM, ptid);
+ ULONGEST ipsw;
+ CORE_ADDR pc;
- /* The following test does not belong here. It is OS-specific, and belongs
- in native code. */
- /* Test SS_INSYSCALL */
- if (flags & 2)
- return read_register_pid (31, ptid) & ~0x3;
+ ipsw = read_register_pid (HPPA_IPSW_REGNUM, ptid);
+ pc = read_register_pid (HPPA_PCOQ_HEAD_REGNUM, ptid);
- return read_register_pid (HPPA_PCOQ_HEAD_REGNUM, ptid) & ~0x3;
-}
+ /* If the current instruction is nullified, then we are effectively
+ still executing the previous instruction. Pretend we are still
+ there. This is needed when single stepping; if the nullified
+ instruction is on a different line, we don't want GDB to think
+ we've stepped onto that line. */
+ if (ipsw & 0x00200000)
+ pc -= 4;
-/* Write out the PC. If currently in a syscall, then also write the new
- PC value into %r31. */
+ return pc & ~0x3;
+}
-static void
-hppa_target_write_pc (CORE_ADDR v, ptid_t ptid)
+void
+hppa_write_pc (CORE_ADDR pc, ptid_t ptid)
{
- int flags = read_register_pid (HPPA_FLAGS_REGNUM, ptid);
-
- /* The following test does not belong here. It is OS-specific, and belongs
- in native code. */
- /* If in a syscall, then set %r31. Also make sure to get the
- privilege bits set correctly. */
- /* Test SS_INSYSCALL */
- if (flags & 2)
- write_register_pid (31, v | 0x3, ptid);
-
- write_register_pid (HPPA_PCOQ_HEAD_REGNUM, v, ptid);
- write_register_pid (HPPA_PCOQ_TAIL_REGNUM, v + 4, ptid);
+ write_register_pid (HPPA_PCOQ_HEAD_REGNUM, pc, ptid);
+ write_register_pid (HPPA_PCOQ_TAIL_REGNUM, pc + 4, ptid);
}
/* return the alignment of a type in bytes. Structures have the maximum
be in the prologue. */
-CORE_ADDR
-skip_prologue_hard_way (CORE_ADDR pc)
+static CORE_ADDR
+skip_prologue_hard_way (CORE_ADDR pc, int stop_before_branch)
{
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, restart_gr, restart_fr;
struct unwind_table_entry *u;
+ int final_iteration;
restart_gr = 0;
restart_fr = 0;
save_fr |= (1 << i);
save_fr &= ~restart_fr;
+ final_iteration = 0;
+
/* Loop until we find everything of interest or hit a branch.
For unoptimized GCC code and for any HP CC code this will never ever
old_save_sp = save_sp;
old_stack_remaining = stack_remaining;
- status = read_memory_nobpt (pc, buf, 4);
+ status = deprecated_read_memory_nobpt (pc, buf, 4);
inst = extract_unsigned_integer (buf, 4);
/* Yow! */
while (reg_num >= (TARGET_PTR_BIT == 64 ? 19 : 23) && reg_num <= 26)
{
pc += 4;
- status = read_memory_nobpt (pc, buf, 4);
+ status = deprecated_read_memory_nobpt (pc, buf, 4);
inst = extract_unsigned_integer (buf, 4);
if (status != 0)
return pc;
reg_num = inst_saves_fr (inst);
save_fr &= ~(1 << reg_num);
- status = read_memory_nobpt (pc + 4, buf, 4);
+ status = deprecated_read_memory_nobpt (pc + 4, buf, 4);
next_inst = extract_unsigned_integer (buf, 4);
/* Yow! */
while (reg_num >= 4 && reg_num <= (TARGET_PTR_BIT == 64 ? 11 : 7))
{
pc += 8;
- status = read_memory_nobpt (pc, buf, 4);
+ status = deprecated_read_memory_nobpt (pc, buf, 4);
inst = extract_unsigned_integer (buf, 4);
if (status != 0)
return pc;
if ((inst & 0xfc000000) != 0x34000000)
break;
- status = read_memory_nobpt (pc + 4, buf, 4);
+ status = deprecated_read_memory_nobpt (pc + 4, buf, 4);
next_inst = extract_unsigned_integer (buf, 4);
if (status != 0)
return pc;
/* Quit if we hit any kind of branch. This can happen if a prologue
instruction is in the delay slot of the first call/branch. */
- if (is_branch (inst))
+ if (is_branch (inst) && stop_before_branch)
break;
/* What a crock. The HP compilers set args_stored even if no
/* Bump the PC. */
pc += 4;
+
+ /* !stop_before_branch, so also look at the insn in the delay slot
+ of the branch. */
+ if (final_iteration)
+ break;
+ if (is_branch (inst))
+ final_iteration = 1;
}
/* We've got a tenative location for the end of the prologue. However
/* To skip prologues, I use this predicate. Returns either PC itself
if the code at PC does not look like a function prologue; otherwise
- returns an address that (if we're lucky) follows the prologue. If
- LENIENT, then we must skip everything which is involved in setting
- up the frame (it's OK to skip more, just so long as we don't skip
- anything which might clobber the registers which are being saved.
- Currently we must not skip more on the alpha, but we might the lenient
- stuff some day. */
+ returns an address that (if we're lucky) follows the prologue.
+
+ hppa_skip_prologue is called by gdb to place a breakpoint in a function.
+ It doesn't necessarily skips all the insns in the prologue. In fact
+ we might not want to skip all the insns because a prologue insn may
+ appear in the delay slot of the first branch, and we don't want to
+ skip over the branch in that case. */
static CORE_ADDR
hppa_skip_prologue (CORE_ADDR pc)
if (post_prologue_pc != 0)
return max (pc, post_prologue_pc);
else
- return (skip_prologue_hard_way (pc));
+ return (skip_prologue_hard_way (pc, 1));
}
struct hppa_frame_cache
long frame_size;
struct unwind_table_entry *u;
CORE_ADDR prologue_end;
+ int fp_in_r1 = 0;
int i;
if (hppa_debug)
cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
/* Yow! */
- u = find_unwind_entry (frame_func_unwind (next_frame));
+ u = find_unwind_entry (frame_pc_unwind (next_frame));
if (!u)
{
if (hppa_debug)
int looking_for_rp = u->Save_RP;
int fp_loc = -1;
- /* We have to use hppa_skip_prologue instead of just
+ /* We have to use skip_prologue_hard_way instead of just
skip_prologue_using_sal, in case we stepped into a function without
symbol information. hppa_skip_prologue also bounds the returned
pc by the passed in pc, so it will not return a pc in the next
- function. */
- prologue_end = hppa_skip_prologue (frame_func_unwind (next_frame));
+ function.
+
+ We used to call hppa_skip_prologue to find the end of the prologue,
+ but if some non-prologue instructions get scheduled into the prologue,
+ and the program is compiled with debug information, the "easy" way
+ in hppa_skip_prologue will return a prologue end that is too early
+ for us to notice any potential frame adjustments. */
+
+ /* We used to use frame_func_unwind () to locate the beginning of the
+ function to pass to skip_prologue (). However, when objects are
+ compiled without debug symbols, frame_func_unwind can return the wrong
+ function (or 0). We can do better than that by using unwind records. */
+
+ prologue_end = skip_prologue_hard_way (u->region_start, 0);
end_pc = frame_pc_unwind (next_frame);
if (prologue_end != 0 && end_pc > prologue_end)
frame_size = 0;
- for (pc = frame_func_unwind (next_frame);
+ for (pc = u->region_start;
((saved_gr_mask || saved_fr_mask
|| looking_for_sp || looking_for_rp
|| frame_size < (u->Total_frame_size << 3))
{
int reg;
char buf4[4];
- long status = read_memory_nobpt (pc, buf4, sizeof buf4);
- long inst = extract_unsigned_integer (buf4, sizeof buf4);
+ long inst;
+
+ if (!safe_frame_unwind_memory (next_frame, pc, buf4,
+ sizeof buf4))
+ {
+ error ("Cannot read instruction at 0x%s\n", paddr_nz (pc));
+ return (*this_cache);
+ }
+
+ inst = extract_unsigned_integer (buf4, sizeof buf4);
/* Note the interesting effects of this instruction. */
frame_size += prologue_inst_adjust_sp (inst);
looking_for_rp = 0;
cache->saved_regs[HPPA_RP_REGNUM].addr = -20;
}
+ else if (inst == 0x6bc23fd1) /* stw rp,-0x18(sr0,sp) */
+ {
+ looking_for_rp = 0;
+ cache->saved_regs[HPPA_RP_REGNUM].addr = -24;
+ }
else if (inst == 0x0fc212c1) /* std rp,-0x10(sr0,sp) */
{
looking_for_rp = 0;
looking_for_sp = 0;
cache->saved_regs[HPPA_FP_REGNUM].addr = 0;
}
+ else if (inst == 0x08030241) /* copy %r3, %r1 */
+ {
+ fp_in_r1 = 1;
+ }
/* Account for general and floating-point register saves. */
reg = inst_saves_gr (inst);
and saved on the stack, the Save_SP flag is set. We use this to
decide whether to use the frame pointer for unwinding.
- fp should never be zero here; checking just in case.
-
TODO: For the HP compiler, maybe we should use the alloca_frame flag
instead of Save_SP. */
fprintf_unfiltered (gdb_stdlog, " (base=0x%s) [frame pointer] }",
paddr_nz (cache->base));
}
- else if (frame_pc_unwind (next_frame) >= prologue_end)
+ else if (u->Save_SP
+ && trad_frame_addr_p (cache->saved_regs, HPPA_SP_REGNUM))
{
- if (u->Save_SP && trad_frame_addr_p (cache->saved_regs, HPPA_SP_REGNUM))
- {
/* Both we're expecting the SP to be saved and the SP has been
saved. The entry SP value is saved at this frame's SP
address. */
if (hppa_debug)
fprintf_unfiltered (gdb_stdlog, " (base=0x%s) [saved] }",
paddr_nz (cache->base));
- }
- else
- {
- /* The prologue has been slowly allocating stack space. Adjust
- the SP back. */
- cache->base = this_sp - frame_size;
- if (hppa_debug)
- fprintf_unfiltered (gdb_stdlog, " (base=0x%s) [unwind adjust] } ",
- paddr_nz (cache->base));
-
- }
}
else
{
- /* This frame has not yet been created. */
- cache->base = this_sp;
-
+ /* The prologue has been slowly allocating stack space. Adjust
+ the SP back. */
+ cache->base = this_sp - frame_size;
if (hppa_debug)
- fprintf_unfiltered (gdb_stdlog, " (base=0x%s) [before prologue] } ",
+ fprintf_unfiltered (gdb_stdlog, " (base=0x%s) [unwind adjust] } ",
paddr_nz (cache->base));
}
-
trad_frame_set_value (cache->saved_regs, HPPA_SP_REGNUM, cache->base);
}
}
}
+ /* If Save_SP is set, then we expect the frame pointer to be saved in the
+ frame. However, there is a one-insn window where we haven't saved it
+ yet, but we've already clobbered it. Detect this case and fix it up.
+
+ The prologue sequence for frame-pointer functions is:
+ 0: stw %rp, -20(%sp)
+ 4: copy %r3, %r1
+ 8: copy %sp, %r3
+ c: stw,ma %r1, XX(%sp)
+
+ So if we are at offset c, the r3 value that we want is not yet saved
+ on the stack, but it's been overwritten. The prologue analyzer will
+ set fp_in_r1 when it sees the copy insn so we know to get the value
+ from r1 instead. */
+ if (u->Save_SP && !trad_frame_addr_p (cache->saved_regs, HPPA_FP_REGNUM)
+ && fp_in_r1)
+ {
+ ULONGEST r1 = frame_unwind_register_unsigned (next_frame, 1);
+ trad_frame_set_value (cache->saved_regs, HPPA_FP_REGNUM, r1);
+ }
+
{
/* Convert all the offsets into addresses. */
int reg;
}
}
+ {
+ struct gdbarch *gdbarch;
+ struct gdbarch_tdep *tdep;
+
+ gdbarch = get_frame_arch (next_frame);
+ tdep = gdbarch_tdep (gdbarch);
+
+ if (tdep->unwind_adjust_stub)
+ {
+ tdep->unwind_adjust_stub (next_frame, cache->base, cache->saved_regs);
+ }
+ }
+
if (hppa_debug)
fprintf_unfiltered (gdb_stdlog, "base=0x%s }",
paddr_nz (((struct hppa_frame_cache *)*this_cache)->base));
hppa_frame_this_id (struct frame_info *next_frame, void **this_cache,
struct frame_id *this_id)
{
- struct hppa_frame_cache *info = hppa_frame_cache (next_frame, this_cache);
- (*this_id) = frame_id_build (info->base, frame_func_unwind (next_frame));
+ struct hppa_frame_cache *info;
+ CORE_ADDR pc = frame_pc_unwind (next_frame);
+ struct unwind_table_entry *u;
+
+ info = hppa_frame_cache (next_frame, this_cache);
+ u = find_unwind_entry (pc);
+
+ (*this_id) = frame_id_build (info->base, u->region_start);
}
static void
hppa_fallback_frame_cache (struct frame_info *next_frame, void **this_cache)
{
struct hppa_frame_cache *cache;
+ unsigned int frame_size;
+ int found_rp;
CORE_ADDR pc, start_pc, end_pc, cur_pc;
+ if (hppa_debug)
+ fprintf_unfiltered (gdb_stdlog, "{ hppa_fallback_frame_cache (frame=%d)-> ",
+ frame_relative_level(next_frame));
+
cache = FRAME_OBSTACK_ZALLOC (struct hppa_frame_cache);
(*this_cache) = cache;
cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
pc = frame_func_unwind (next_frame);
cur_pc = frame_pc_unwind (next_frame);
+ frame_size = 0;
+ found_rp = 0;
find_pc_partial_function (pc, NULL, &start_pc, &end_pc);
insn = read_memory_unsigned_integer (pc, 4);
+ frame_size += prologue_inst_adjust_sp (insn);
+
/* There are limited ways to store the return pointer into the
stack. */
if (insn == 0x6bc23fd9) /* stw rp,-0x14(sr0,sp) */
- {
- cache->saved_regs[HPPA_RP_REGNUM].addr = -20;
- break;
- }
+ {
+ cache->saved_regs[HPPA_RP_REGNUM].addr = -20;
+ found_rp = 1;
+ }
else if (insn == 0x0fc212c1) /* std rp,-0x10(sr0,sp) */
- {
- cache->saved_regs[HPPA_RP_REGNUM].addr = -16;
- break;
- }
+ {
+ cache->saved_regs[HPPA_RP_REGNUM].addr = -16;
+ found_rp = 1;
+ }
}
- cache->base = frame_unwind_register_unsigned (next_frame, HPPA_SP_REGNUM);
+ if (hppa_debug)
+ fprintf_unfiltered (gdb_stdlog, " frame_size = %d, found_rp = %d }\n",
+ frame_size, found_rp);
+
+ cache->base = frame_unwind_register_unsigned (next_frame, HPPA_SP_REGNUM) - frame_size;
+ trad_frame_set_value (cache->saved_regs, HPPA_SP_REGNUM, cache->base);
if (trad_frame_addr_p (cache->saved_regs, HPPA_RP_REGNUM))
{
return &hppa_fallback_frame_unwind;
}
-static CORE_ADDR
-hppa_frame_base_address (struct frame_info *next_frame,
- void **this_cache)
-{
- struct hppa_frame_cache *info = hppa_frame_cache (next_frame,
- this_cache);
- return info->base;
-}
-
-static const struct frame_base hppa_frame_base = {
- &hppa_frame_unwind,
- hppa_frame_base_address,
- hppa_frame_base_address,
- hppa_frame_base_address
-};
-
-static const struct frame_base *
-hppa_frame_base_sniffer (struct frame_info *next_frame)
-{
- return &hppa_frame_base;
-}
-
/* Stub frames, used for all kinds of call stubs. */
struct hppa_stub_unwind_cache
{
{
struct hppa_stub_unwind_cache *info
= hppa_stub_frame_unwind_cache (next_frame, this_prologue_cache);
- *this_id = frame_id_build (info->base, frame_pc_unwind (next_frame));
+
+ if (info)
+ *this_id = frame_id_build (info->base, frame_func_unwind (next_frame));
+ else
+ *this_id = null_frame_id;
}
static void
{
struct hppa_stub_unwind_cache *info
= hppa_stub_frame_unwind_cache (next_frame, this_prologue_cache);
- hppa_frame_prev_register_helper (next_frame, info->saved_regs, regnum,
- optimizedp, lvalp, addrp, realnump, valuep);
+
+ if (info)
+ hppa_frame_prev_register_helper (next_frame, info->saved_regs, regnum,
+ optimizedp, lvalp, addrp, realnump,
+ valuep);
+ else
+ error ("Requesting registers from null frame.\n");
}
static const struct frame_unwind hppa_stub_frame_unwind = {
hppa_stub_unwind_sniffer (struct frame_info *next_frame)
{
CORE_ADDR pc = frame_pc_unwind (next_frame);
+ struct gdbarch *gdbarch = get_frame_arch (next_frame);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- if (IN_SOLIB_CALL_TRAMPOLINE (pc, NULL)
+ if (pc == 0
+ || (tdep->in_solib_call_trampoline != NULL
+ && tdep->in_solib_call_trampoline (pc, NULL))
|| IN_SOLIB_RETURN_TRAMPOLINE (pc, NULL))
return &hppa_stub_frame_unwind;
return NULL;
frame_pc_unwind (next_frame));
}
-static CORE_ADDR
+CORE_ADDR
hppa_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
- return frame_unwind_register_signed (next_frame, HPPA_PCOQ_HEAD_REGNUM) & ~3;
+ ULONGEST ipsw;
+ CORE_ADDR pc;
+
+ ipsw = frame_unwind_register_unsigned (next_frame, HPPA_IPSW_REGNUM);
+ pc = frame_unwind_register_unsigned (next_frame, HPPA_PCOQ_HEAD_REGNUM);
+
+ /* If the current instruction is nullified, then we are effectively
+ still executing the previous instruction. Pretend we are still
+ there. This is needed when single stepping; if the nullified
+ instruction is on a different line, we don't want GDB to think
+ we've stepped onto that line. */
+ if (ipsw & 0x00200000)
+ pc -= 4;
+
+ return pc & ~0x3;
+}
+
+/* Return the minimal symbol whose name is NAME and stub type is STUB_TYPE.
+ Return NULL if no such symbol was found. */
+
+struct minimal_symbol *
+hppa_lookup_stub_minimal_symbol (const char *name,
+ enum unwind_stub_types stub_type)
+{
+ struct objfile *objfile;
+ struct minimal_symbol *msym;
+
+ ALL_MSYMBOLS (objfile, msym)
+ {
+ if (strcmp (SYMBOL_LINKAGE_NAME (msym), name) == 0)
+ {
+ struct unwind_table_entry *u;
+
+ u = find_unwind_entry (SYMBOL_VALUE (msym));
+ if (u != NULL && u->stub_unwind.stub_type == stub_type)
+ return msym;
+ }
+ }
+
+ return NULL;
}
/* Instead of this nasty cast, add a method pvoid() that prints out a
printf_unfiltered ("\tregion_start = ");
print_address (u->region_start, gdb_stdout);
+ gdb_flush (gdb_stdout);
printf_unfiltered ("\n\tregion_end = ");
print_address (u->region_end, gdb_stdout);
+ gdb_flush (gdb_stdout);
#define pif(FLD) if (u->FLD) printf_unfiltered (" "#FLD);
pin (Entry_FR);
pin (Entry_GR);
pin (Total_frame_size);
-}
-
-void
-hppa_skip_permanent_breakpoint (void)
-{
- /* 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 (HPPA_PCOQ_HEAD_REGNUM, read_register (HPPA_PCOQ_TAIL_REGNUM));
- write_register (HPPA_PCSQ_HEAD_REGNUM, read_register (HPPA_PCSQ_TAIL_REGNUM));
-
- write_register (HPPA_PCOQ_TAIL_REGNUM, read_register (HPPA_PCOQ_TAIL_REGNUM) + 4);
- /* We can leave the tail's space the same, since there's no jump. */
+ if (u->stub_unwind.stub_type)
+ {
+ printf_unfiltered ("\tstub type = ");
+ switch (u->stub_unwind.stub_type)
+ {
+ case LONG_BRANCH:
+ printf_unfiltered ("long branch\n");
+ break;
+ case PARAMETER_RELOCATION:
+ printf_unfiltered ("parameter relocation\n");
+ break;
+ case EXPORT:
+ printf_unfiltered ("export\n");
+ break;
+ case IMPORT:
+ printf_unfiltered ("import\n");
+ break;
+ case IMPORT_SHLIB:
+ printf_unfiltered ("import shlib\n");
+ break;
+ default:
+ printf_unfiltered ("unknown (%d)\n", u->stub_unwind.stub_type);
+ }
+ }
}
int
return (!target_has_stack && (pc & 0xFF000000));
}
-int
-hppa_instruction_nullified (void)
-{
- /* brobecker 2002/11/07: Couldn't we use a ULONGEST here? It would
- avoid the type cast. I'm leaving it as is for now as I'm doing
- semi-mechanical multiarching-related changes. */
- const int ipsw = (int) read_register (HPPA_IPSW_REGNUM);
- const int flags = (int) read_register (HPPA_FLAGS_REGNUM);
-
- return ((ipsw & 0x00200000) && !(flags & 0x2));
-}
-
/* Return the GDB type object for the "standard" data type of data
in register N. */
}
/* Get the ith function argument for the current function. */
-CORE_ADDR
+static CORE_ADDR
hppa_fetch_pointer_argument (struct frame_info *frame, int argi,
struct type *type)
{
store_unsigned_integer (buf, sizeof(tmp), tmp);
}
+static CORE_ADDR
+hppa_find_global_pointer (struct value *function)
+{
+ return 0;
+}
+
void
hppa_frame_prev_register_helper (struct frame_info *next_frame,
struct trad_frame_saved_reg saved_regs[],
enum lval_type *lvalp, CORE_ADDR *addrp,
int *realnump, void *valuep)
{
- int pcoqt = (regnum == HPPA_PCOQ_TAIL_REGNUM);
- struct gdbarch *gdbarch = get_frame_arch (next_frame);
- int regsize = register_size (gdbarch, HPPA_PCOQ_HEAD_REGNUM);
+ if (regnum == HPPA_PCOQ_TAIL_REGNUM)
+ {
+ if (valuep)
+ {
+ CORE_ADDR pc;
- if (pcoqt)
- regnum = HPPA_PCOQ_HEAD_REGNUM;
+ trad_frame_get_prev_register (next_frame, saved_regs,
+ HPPA_PCOQ_HEAD_REGNUM, optimizedp,
+ lvalp, addrp, realnump, valuep);
- trad_frame_prev_register (next_frame, saved_regs, regnum,
- optimizedp, lvalp, addrp, realnump, valuep);
+ pc = extract_unsigned_integer (valuep, 4);
+ store_unsigned_integer (valuep, 4, pc + 4);
+ }
- if (pcoqt)
- store_unsigned_integer (valuep, regsize,
- extract_unsigned_integer (valuep, regsize) + 4);
+ /* It's a computed value. */
+ *optimizedp = 0;
+ *lvalp = not_lval;
+ *addrp = 0;
+ *realnump = -1;
+ return;
+ }
+
+ /* Make sure the "flags" register is zero in all unwound frames.
+ The "flags" registers is a HP-UX specific wart, and only the code
+ in hppa-hpux-tdep.c depends on it. However, it is easier to deal
+ with it here. This shouldn't affect other systems since those
+ should provide zero for the "flags" register anyway. */
+ if (regnum == HPPA_FLAGS_REGNUM)
+ {
+ if (valuep)
+ store_unsigned_integer (valuep,
+ register_size (get_frame_arch (next_frame),
+ regnum),
+ 0);
+
+ /* It's a computed value. */
+ *optimizedp = 0;
+ *lvalp = not_lval;
+ *addrp = 0;
+ *realnump = -1;
+ return;
+ }
+
+ trad_frame_get_prev_register (next_frame, saved_regs, regnum,
+ optimizedp, lvalp, addrp, realnump, valuep);
}
+\f
/* Here is a table of C type sizes on hppa with various compiles
and options. I measured this on PA 9000/800 with HP-UX 11.11
else
tdep->bytes_per_address = 4;
+ tdep->find_global_pointer = hppa_find_global_pointer;
+
/* Some parts of the gdbarch vector depend on whether we are running
on a 32 bits or 64 bits target. */
switch (tdep->bytes_per_address)
/* The following gdbarch vector elements do not depend on the address
size, or in any other gdbarch element previously set. */
set_gdbarch_skip_prologue (gdbarch, hppa_skip_prologue);
+ set_gdbarch_in_function_epilogue_p (gdbarch,
+ hppa_in_function_epilogue_p);
set_gdbarch_inner_than (gdbarch, core_addr_greaterthan);
set_gdbarch_sp_regnum (gdbarch, HPPA_SP_REGNUM);
set_gdbarch_fp0_regnum (gdbarch, HPPA_FP0_REGNUM);
set_gdbarch_addr_bits_remove (gdbarch, hppa_smash_text_address);
set_gdbarch_smash_text_address (gdbarch, hppa_smash_text_address);
set_gdbarch_believe_pcc_promotion (gdbarch, 1);
- set_gdbarch_read_pc (gdbarch, hppa_target_read_pc);
- set_gdbarch_write_pc (gdbarch, hppa_target_write_pc);
+ set_gdbarch_read_pc (gdbarch, hppa_read_pc);
+ set_gdbarch_write_pc (gdbarch, hppa_write_pc);
/* Helper for function argument information. */
set_gdbarch_fetch_pointer_argument (gdbarch, hppa_fetch_pointer_argument);
case 4:
set_gdbarch_push_dummy_call (gdbarch, hppa32_push_dummy_call);
set_gdbarch_frame_align (gdbarch, hppa32_frame_align);
+ set_gdbarch_convert_from_func_ptr_addr
+ (gdbarch, hppa32_convert_from_func_ptr_addr);
break;
case 8:
set_gdbarch_push_dummy_call (gdbarch, hppa64_push_dummy_call);
frame_unwind_append_sniffer (gdbarch, hppa_stub_unwind_sniffer);
frame_unwind_append_sniffer (gdbarch, hppa_frame_unwind_sniffer);
frame_unwind_append_sniffer (gdbarch, hppa_fallback_unwind_sniffer);
- frame_base_append_sniffer (gdbarch, hppa_frame_base_sniffer);
return gdbarch;
}
_initialize_hppa_tdep (void)
{
struct cmd_list_element *c;
- void break_at_finish_command (char *arg, int from_tty);
- void tbreak_at_finish_command (char *arg, int from_tty);
- void break_at_finish_at_depth_command (char *arg, int from_tty);
gdbarch_register (bfd_arch_hppa, hppa_gdbarch_init, hppa_dump_tdep);
"Print unwind table entry at given address.",
&maintenanceprintlist);
- deprecate_cmd (add_com ("xbreak", class_breakpoint,
- break_at_finish_command,
- concat ("Set breakpoint at procedure exit. \n\
-Argument may be function name, or \"*\" and an address.\n\
-If function is specified, break at end of code for that function.\n\
-If an address is specified, break at the end of the function that contains \n\
-that exact address.\n",
- "With no arg, uses current execution address of selected stack frame.\n\
-This is useful for breaking on return to a stack frame.\n\
-\n\
-Multiple breakpoints at one place are permitted, and useful if conditional.\n\
-\n\
-Do \"help breakpoints\" for info on other commands dealing with breakpoints.", NULL)), NULL);
- deprecate_cmd (add_com_alias ("xb", "xbreak", class_breakpoint, 1), NULL);
- deprecate_cmd (add_com_alias ("xbr", "xbreak", class_breakpoint, 1), NULL);
- deprecate_cmd (add_com_alias ("xbre", "xbreak", class_breakpoint, 1), NULL);
- deprecate_cmd (add_com_alias ("xbrea", "xbreak", class_breakpoint, 1), NULL);
-
- deprecate_cmd (c = add_com ("txbreak", class_breakpoint,
- tbreak_at_finish_command,
-"Set temporary breakpoint at procedure exit. Either there should\n\
-be no argument or the argument must be a depth.\n"), NULL);
- set_cmd_completer (c, location_completer);
-
- if (xdb_commands)
- deprecate_cmd (add_com ("bx", class_breakpoint,
- break_at_finish_at_depth_command,
-"Set breakpoint at procedure exit. Either there should\n\
-be no argument or the argument must be a depth.\n"), NULL);
-
/* Debug this files internals. */
- add_show_from_set (add_set_cmd ("hppa", class_maintenance, var_zinteger,
- &hppa_debug, "Set hppa debugging.\n\
-When non-zero, hppa specific debugging is enabled.", &setdebuglist), &showdebuglist);
+ add_setshow_boolean_cmd ("hppa", class_maintenance, &hppa_debug, "\
+Set whether hppa target specific debugging information should be displayed.", "\
+Show whether hppa target specific debugging information is displayed.", "\
+This flag controls whether hppa target specific debugging information is\n\
+displayed. This information is particularly useful for debugging frame\n\
+unwinding problems.", "hppa debug flag is %s.",
+ NULL, NULL, &setdebuglist, &showdebuglist);
}
-