X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fhppa-tdep.c;h=46a7b080192ea63eebc796efe060d064688f059f;hb=ff644745cdc10d5dd58cb49c9968f971f72f6263;hp=52176ee68f3bb71f18a64d7ed147304cffbef79e;hpb=1b07b470630c522f6c6ee5d4522ca6d0a6ab2d89;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/hppa-tdep.c b/gdb/hppa-tdep.c index 52176ee68f..46a7b08019 100644 --- a/gdb/hppa-tdep.c +++ b/gdb/hppa-tdep.c @@ -64,11 +64,6 @@ const struct objfile_data *hppa_objfile_priv_data = NULL; #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 @@ -76,7 +71,6 @@ const struct objfile_data *hppa_objfile_priv_data = NULL; /* 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. */ @@ -267,6 +261,18 @@ hppa_extract_17 (unsigned word) 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; +} /* Compare the start address for two unwind entries returning 1 if @@ -332,6 +338,10 @@ internalize_unwinds (struct objfile *objfile, struct unwind_table_entry *table, 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); @@ -615,6 +625,44 @@ find_unwind_entry (CORE_ADDR pc) 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) { @@ -625,7 +673,7 @@ 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[] = { @@ -668,7 +716,7 @@ hppa32_register_name (int i) return names[i]; } -const char * +static const char * hppa64_register_name (int i) { static char *names[] = { @@ -713,8 +761,8 @@ hppa64_register_name (int i) 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) @@ -732,6 +780,12 @@ hppa32_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_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; @@ -745,7 +799,7 @@ hppa32_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_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)); /* The corresponding parameter that is pushed onto the stack, and [possibly] passed in a register. */ char param_val[8]; @@ -852,6 +906,11 @@ hppa32_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr, 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); @@ -874,8 +933,8 @@ hppa32_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_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) @@ -904,7 +963,7 @@ hppa64_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_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) @@ -984,6 +1043,22 @@ hppa64_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr, 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) { @@ -1001,42 +1076,31 @@ hppa64_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 @@ -1213,14 +1277,15 @@ inst_saves_fr (unsigned long inst) 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; @@ -1264,6 +1329,8 @@ restart: 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 @@ -1293,7 +1360,7 @@ restart: 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! */ @@ -1342,7 +1409,7 @@ restart: 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; @@ -1355,7 +1422,7 @@ restart: 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! */ @@ -1382,13 +1449,13 @@ restart: 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; @@ -1400,7 +1467,7 @@ restart: /* 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 @@ -1421,6 +1488,13 @@ restart: /* 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 @@ -1479,12 +1553,13 @@ after_prologue (CORE_ADDR pc) /* 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) @@ -1509,7 +1584,7 @@ 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 @@ -1528,6 +1603,7 @@ hppa_frame_cache (struct frame_info *next_frame, void **this_cache) long frame_size; struct unwind_table_entry *u; CORE_ADDR prologue_end; + int fp_in_r1 = 0; int i; if (hppa_debug) @@ -1546,7 +1622,7 @@ hppa_frame_cache (struct frame_info *next_frame, void **this_cache) 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) @@ -1591,12 +1667,24 @@ hppa_frame_cache (struct frame_info *next_frame, void **this_cache) 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) @@ -1604,7 +1692,7 @@ hppa_frame_cache (struct frame_info *next_frame, void **this_cache) 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)) @@ -1613,8 +1701,16 @@ hppa_frame_cache (struct frame_info *next_frame, void **this_cache) { 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); @@ -1626,6 +1722,11 @@ hppa_frame_cache (struct frame_info *next_frame, void **this_cache) 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; @@ -1641,6 +1742,10 @@ hppa_frame_cache (struct frame_info *next_frame, void **this_cache) 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); @@ -1749,8 +1854,6 @@ hppa_frame_cache (struct frame_info *next_frame, void **this_cache) 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. */ @@ -1765,10 +1868,9 @@ hppa_frame_cache (struct frame_info *next_frame, void **this_cache) 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. */ @@ -1777,29 +1879,17 @@ hppa_frame_cache (struct frame_info *next_frame, void **this_cache) 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); } @@ -1826,6 +1916,27 @@ hppa_frame_cache (struct frame_info *next_frame, void **this_cache) } } + /* 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; @@ -1836,6 +1947,19 @@ hppa_frame_cache (struct frame_info *next_frame, void **this_cache) } } + { + 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)); @@ -1846,8 +1970,14 @@ static void 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 @@ -1892,14 +2022,22 @@ static struct hppa_frame_cache * 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); @@ -1919,21 +2057,28 @@ hppa_fallback_frame_cache (struct frame_info *next_frame, void **this_cache) 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)) { @@ -1984,28 +2129,6 @@ hppa_fallback_unwind_sniffer (struct frame_info *next_frame) 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 { @@ -2058,7 +2181,11 @@ hppa_stub_frame_this_id (struct frame_info *next_frame, { 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 @@ -2070,8 +2197,13 @@ hppa_stub_frame_prev_register (struct frame_info *next_frame, { 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 = { @@ -2084,8 +2216,12 @@ static const struct 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; @@ -2099,10 +2235,49 @@ hppa_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame) 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 @@ -2141,9 +2316,11 @@ unwind_command (char *exp, int from_tty) 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); @@ -2176,30 +2353,31 @@ unwind_command (char *exp, int from_tty) 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 @@ -2230,18 +2408,6 @@ hppa_pc_requires_run_before_use (CORE_ADDR pc) 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. */ @@ -2293,7 +2459,7 @@ hppa_smash_text_address (CORE_ADDR addr) } /* 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) { @@ -2314,6 +2480,12 @@ hppa_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache, 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[], @@ -2321,20 +2493,53 @@ hppa_frame_prev_register_helper (struct frame_info *next_frame, 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); } + /* 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 @@ -2403,6 +2608,8 @@ hppa_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) 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) @@ -2434,6 +2641,8 @@ hppa_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) /* 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); @@ -2442,8 +2651,8 @@ hppa_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) 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); @@ -2462,6 +2671,8 @@ hppa_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) 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); @@ -2498,7 +2709,6 @@ hppa_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) 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; } @@ -2517,9 +2727,6 @@ void _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); @@ -2529,39 +2736,12 @@ _initialize_hppa_tdep (void) "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); } -