* hppa-tdep.c (saved_pc_after_call): If the saved PC is in a

linker stub, then return the address the stub will return to.
	(frame_saved_pc): Correctly restart the search for the saved
	pc when a linker stub is encountered.

	* hppa-tdep.c (inst_saves_gr): Handle 16 and 8 bit instruction
	register stores emitted by the version 9 HP compilers.
	(inst_saves_fr): Relax test for a specific base register (%r1);
	this avoids losing with the version 9 HP compilers.
	(skip_prologue): Try to skip argument stores emitted by the HP
	compilers.  It's not perfect, but it's better than before.
This commit is contained in:
Jeff Law 1994-08-01 07:49:59 +00:00
parent 58bbba79a2
commit edd86fb0da
2 changed files with 149 additions and 16 deletions

View File

@ -1,3 +1,17 @@
Mon Aug 1 01:36:13 1994 Jeff Law (law@snake.cs.utah.edu)
* hppa-tdep.c (saved_pc_after_call): If the saved PC is in a
linker stub, then return the address the stub will return to.
(frame_saved_pc): Correctly restart the search for the saved
pc when a linker stub is encountered.
* hppa-tdep.c (inst_saves_gr): Handle 16 and 8 bit instruction
register stores emitted by the version 9 HP compilers.
(inst_saves_fr): Relax test for a specific base register (%r1);
this avoids losing with the version 9 HP compilers.
(skip_prologue): Try to skip argument stores emitted by the HP
compilers. It's not perfect, but it's better than before.
Fri Jul 29 23:20:30 1994 Stu Grossman (grossman@cygnus.com)
* findvar.c (write_pc write_pc_pid): Remove casts to long when

View File

@ -703,10 +703,19 @@ saved_pc_after_call (frame)
FRAME frame;
{
int ret_regnum;
CORE_ADDR pc;
struct unwind_table_entry *u;
ret_regnum = find_return_regnum (get_frame_pc (frame));
return read_register (ret_regnum) & ~0x3;
pc = read_register (ret_regnum) & ~0x3;
/* If PC is in a linker stub, then we need to dig the address
the stub will return to out of the stack. */
u = find_unwind_entry (pc);
if (u && u->stub_type != 0)
return frame_saved_pc (frame);
else
return pc;
}
CORE_ADDR
@ -731,7 +740,6 @@ frame_saved_pc (frame)
return rp;
}
restart:
if (frameless_function_invocation (frame))
{
int ret_regnum;
@ -761,8 +769,10 @@ restart:
}
else
{
int rp_offset = rp_saved (pc);
int rp_offset;
restart:
rp_offset = rp_saved (pc);
/* Similar to code in frameless function case. If the next
frame is a signal or interrupt handler, then dig the right
information out of the saved register info. */
@ -1741,10 +1751,7 @@ is_branch (inst)
}
/* Return the register number for a GR which is saved by INST or
zero it INST does not save a GR.
Note we only care about full 32bit register stores (that's the only
kind of stores the prologue will use). */
zero it INST does not save a GR. */
static int
inst_saves_gr (inst)
@ -1754,10 +1761,15 @@ inst_saves_gr (inst)
if ((inst >> 26) == 0x1a)
return extract_5R_store (inst);
/* Does it look like a stwm? */
/* Does it look like a stwm? GCC & HPC may use this in prologues. */
if ((inst >> 26) == 0x1b)
return extract_5R_store (inst);
/* Does it look like sth or stb? HPC versions 9.0 and later use these
too. */
if ((inst >> 26) == 0x19 || (inst >> 26) == 0x18)
return extract_5R_store (inst);
return 0;
}
@ -1765,13 +1777,15 @@ inst_saves_gr (inst)
zero it INST does not save a FR.
Note we only care about full 64bit register stores (that's the only
kind of stores the prologue will use). */
kind of stores the prologue will use).
FIXME: What about argument stores with the HP compiler in ANSI mode? */
static int
inst_saves_fr (inst)
unsigned long inst;
{
if ((inst & 0xfc1fffe0) == 0x2c101220)
if ((inst & 0xfc00dfc0) == 0x2c001200)
return extract_5r_store (inst);
return 0;
}
@ -1788,7 +1802,7 @@ skip_prologue (pc)
{
char buf[4];
unsigned long inst, stack_remaining, save_gr, save_fr, save_rp, save_sp;
int status, i;
unsigned long args_stored, status, i;
struct unwind_table_entry *u;
u = find_unwind_entry (pc);
@ -1806,6 +1820,11 @@ skip_prologue (pc)
save_rp = u->Save_RP;
save_sp = u->Save_SP;
/* 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;
/* Turn the Entry_GR field into a bitmask. */
save_gr = 0;
for (i = 3; i < u->Entry_GR + 3; i++)
@ -1836,11 +1855,24 @@ skip_prologue (pc)
Some unexpected things are expected with debugging optimized code, so
we allow this routine to walk past user instructions in optimized
GCC code. */
while (save_gr || save_fr || save_rp || save_sp || stack_remaining > 0)
while (save_gr || save_fr || save_rp || save_sp || stack_remaining > 0
|| args_stored)
{
unsigned int reg_num;
unsigned long old_stack_remaining, old_save_gr, old_save_fr;
unsigned long old_save_rp, old_save_sp, old_args_stored, next_inst;
/* Save copies of all the triggers so we can compare them later
(only for HPC). */
old_save_gr = save_gr;
old_save_fr = save_fr;
old_save_rp = save_rp;
old_save_sp = save_sp;
old_stack_remaining = stack_remaining;
status = target_read_memory (pc, buf, 4);
inst = extract_unsigned_integer (buf, 4);
/* Yow! */
if (status != 0)
return pc;
@ -1858,14 +1890,101 @@ skip_prologue (pc)
save_sp = 0;
/* Account for general and floating-point register saves. */
save_gr &= ~(1 << inst_saves_gr (inst));
save_fr &= ~(1 << inst_saves_fr (inst));
reg_num = inst_saves_gr (inst);
save_gr &= ~(1 << reg_num);
/* Ugh. Also account for argument stores into the stack.
Unfortunately args_stored only tells us that some arguments
where stored into the stack. Not how many or what kind!
This is a kludge as on the HP compiler sets this bit and it
never does prologue scheduling. So once we see one, skip past
all of them. We have similar code for the fp arg stores below.
FIXME. Can still die if we have a mix of GR and FR argument
stores! */
if (reg_num >= 23 && reg_num <= 26)
{
while (reg_num >= 23 && reg_num <= 26)
{
pc += 4;
status = target_read_memory (pc, buf, 4);
inst = extract_unsigned_integer (buf, 4);
if (status != 0)
return pc;
reg_num = inst_saves_gr (inst);
}
args_stored = 0;
continue;
}
reg_num = inst_saves_fr (inst);
save_fr &= ~(1 << reg_num);
status = target_read_memory (pc + 4, buf, 4);
next_inst = extract_unsigned_integer (buf, 4);
/* Yow! */
if (status != 0)
return pc;
/* We've got to be read to handle the ldo before the fp register
save. */
if ((inst & 0xfc000000) == 0x34000000
&& inst_saves_fr (next_inst) >= 4
&& inst_saves_fr (next_inst) <= 7)
{
/* So we drop into the code below in a reasonable state. */
reg_num = inst_saves_fr (next_inst);
pc -= 4;
}
/* Ugh. Also account for argument stores into the stack.
This is a kludge as on the HP compiler sets this bit and it
never does prologue scheduling. So once we see one, skip past
all of them. */
if (reg_num >= 4 && reg_num <= 7)
{
while (reg_num >= 4 && reg_num <= 7)
{
pc += 8;
status = target_read_memory (pc, buf, 4);
inst = extract_unsigned_integer (buf, 4);
if (status != 0)
return pc;
if ((inst & 0xfc000000) != 0x34000000)
break;
status = target_read_memory (pc + 4, buf, 4);
next_inst = extract_unsigned_integer (buf, 4);
if (status != 0)
return pc;
reg_num = inst_saves_fr (next_inst);
}
args_stored = 0;
continue;
}
/* 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))
break;
/* What a crock. The HP compilers set args_stored even if no
arguments were stored into the stack (boo hiss). This could
cause this code to then skip a bunch of user insns (up to the
first branch).
To combat this we try to identify when args_stored was bogusly
set and clear it. We only do this when args_stored is nonzero,
all other resources are accounted for, and nothing changed on
this pass. */
if (args_stored
&& ! (save_gr || save_fr || save_rp || save_sp || stack_remaining > 0)
&& old_save_gr == save_gr && old_save_fr == save_fr
&& old_save_rp == save_rp && old_save_sp == save_sp
&& old_stack_remaining == stack_remaining)
break;
/* Bump the PC. */
pc += 4;
}