* hppa-tdep.c (skip_prologue): Do nothing if not at the beginning
of a function. (skip_trampoline_code): Rewrite and add support for argument relocation stubs stubs, import/export stubs, calls through "_sr4export" and cascaded trampolines.
This commit is contained in:
parent
277c24a1f0
commit
de48213858
|
@ -12,6 +12,12 @@ Fri Mar 25 12:40:41 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
|
|||
|
||||
Fri Mar 25 10:14:03 1994 Jeffrey A. Law (law@snake.cs.utah.edu)
|
||||
|
||||
* hppa-tdep.c (skip_prologue): Do nothing if not at the beginning
|
||||
of a function.
|
||||
(skip_trampoline_code): Rewrite and add support for argument
|
||||
relocation stubs stubs, import/export stubs, calls through
|
||||
"_sr4export" and cascaded trampolines.
|
||||
|
||||
* hppa-tdep.c (skip_prologue): Return "pc" not zero
|
||||
if no unwind descriptor is found.
|
||||
|
||||
|
|
147
gdb/hppa-tdep.c
147
gdb/hppa-tdep.c
|
@ -1256,24 +1256,37 @@ pa_print_fp_reg (i)
|
|||
}
|
||||
}
|
||||
|
||||
/* Function calls that pass into a new compilation unit must pass through a
|
||||
small piece of code that does long format (`external' in HPPA parlance)
|
||||
jumps. We figure out where the trampoline is going to end up, and return
|
||||
the PC of the final destination. If we aren't in a trampoline, we just
|
||||
return NULL.
|
||||
/* Figure out if PC is in a trampoline, and if so find out where
|
||||
the trampoline will jump to. If not in a trampoline, return zero.
|
||||
|
||||
For computed calls, we just extract the new PC from r22. */
|
||||
Simple code examination probably is not a good idea since the code
|
||||
sequences in trampolines can also appear in user code.
|
||||
|
||||
We use unwinds and information from the minimal symbol table to
|
||||
determine when we're in a trampoline. This won't work for ELF
|
||||
(yet) since it doesn't create stub unwind entries. Whether or
|
||||
not ELF will create stub unwinds or normal unwinds for linker
|
||||
stubs is still being debated.
|
||||
|
||||
This should handle simple calls through dyncall or sr4export,
|
||||
long calls, argument relocation stubs, and dyncall/sr4export
|
||||
calling an argument relocation stub. It even handles some stubs
|
||||
used in dynamic executables. */
|
||||
|
||||
CORE_ADDR
|
||||
skip_trampoline_code (pc, name)
|
||||
CORE_ADDR pc;
|
||||
char *name;
|
||||
{
|
||||
long inst0, inst1;
|
||||
long orig_pc = pc;
|
||||
long prev_inst, curr_inst, loc;
|
||||
static CORE_ADDR dyncall = 0;
|
||||
static CORE_ADDR sr4export = 0;
|
||||
struct minimal_symbol *msym;
|
||||
struct unwind_table_entry *u;
|
||||
|
||||
/* FIXME XXX - dyncall 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)
|
||||
{
|
||||
|
@ -1284,19 +1297,113 @@ skip_trampoline_code (pc, name)
|
|||
dyncall = -1;
|
||||
}
|
||||
|
||||
if (!sr4export)
|
||||
{
|
||||
msym = lookup_minimal_symbol ("_sr4export", NULL);
|
||||
if (msym)
|
||||
sr4export = SYMBOL_VALUE_ADDRESS (msym);
|
||||
else
|
||||
sr4export = -1;
|
||||
}
|
||||
|
||||
/* Addresses passed to dyncall may *NOT* be the actual address
|
||||
of the funtion. So we may have to do something special. */
|
||||
if (pc == dyncall)
|
||||
return (CORE_ADDR)(read_register (22) & ~0x3);
|
||||
{
|
||||
pc = (CORE_ADDR) read_register (22);
|
||||
|
||||
inst0 = read_memory_integer (pc, 4);
|
||||
inst1 = read_memory_integer (pc+4, 4);
|
||||
/* If bit 30 (counting from the left) is on, then pc is the address of
|
||||
the PLT entry for this function, not the address of the function
|
||||
itself. Bit 31 has meaning too, but only for MPE. */
|
||||
if (pc & 0x2)
|
||||
pc = (CORE_ADDR) read_memory_integer (pc & ~0x3, 4);
|
||||
}
|
||||
else if (pc == sr4export)
|
||||
pc = (CORE_ADDR) (read_register (22));
|
||||
|
||||
if ( (inst0 & 0xffe00000) == 0x20200000 /* ldil xxx, r1 */
|
||||
&& (inst1 & 0xffe0e002) == 0xe0202002) /* be,n yyy(sr4, r1) */
|
||||
pc = extract_21 (inst0) + extract_17 (inst1);
|
||||
else
|
||||
pc = (CORE_ADDR)NULL;
|
||||
/* Get the unwind descriptor corresponding to PC, return zero
|
||||
if no unwind was found. */
|
||||
u = find_unwind_entry (pc);
|
||||
if (!u)
|
||||
return 0;
|
||||
|
||||
return pc;
|
||||
/* If this isn't a linker stub, then return now. */
|
||||
if (u->stub_type == 0)
|
||||
return orig_pc == pc ? 0 : pc & ~0x3;
|
||||
|
||||
/* It's a stub. Search for a branch and figure out where it goes.
|
||||
Note we have to handle multi insn branch sequences like ldil;ble.
|
||||
Most (all?) other branches can be determined by examining the contents
|
||||
of certain registers and the stack. */
|
||||
loc = pc;
|
||||
curr_inst = 0;
|
||||
prev_inst = 0;
|
||||
while (1)
|
||||
{
|
||||
/* Make sure we haven't walked outside the range of this stub. */
|
||||
if (u != find_unwind_entry (loc))
|
||||
{
|
||||
warning ("Unable to find branch in linker stub");
|
||||
return orig_pc == pc ? 0 : pc & ~0x3;
|
||||
}
|
||||
|
||||
prev_inst = curr_inst;
|
||||
curr_inst = read_memory_integer (loc, 4);
|
||||
|
||||
/* Does it look like a branch external using %r1? Then it's the
|
||||
branch from the stub to the actual function. */
|
||||
if ((curr_inst & 0xffe0e000) == 0xe0202000)
|
||||
{
|
||||
/* Yup. See if the previous instruction loaded
|
||||
a value into %r1. If so compute and return the jump address. */
|
||||
if ((prev_inst & 0xffe00000) == 0x20202000)
|
||||
return (extract_21 (prev_inst) + extract_17 (curr_inst)) & ~0x3;
|
||||
else
|
||||
{
|
||||
warning ("Unable to find ldil X,%%r1 before ble Y(%%sr4,%%r1).");
|
||||
return orig_pc == pc ? 0 : pc & ~0x3;
|
||||
}
|
||||
}
|
||||
|
||||
/* Does it look like bl X,rp? Another way to do a branch from the
|
||||
stub to the actual function. */
|
||||
else if ((curr_inst & 0xffe0e000) == 0xe8400000)
|
||||
return (loc + extract_17 (curr_inst) + 8) & ~0x3;
|
||||
|
||||
/* Does it look like bv (rp)? Note this depends on the
|
||||
current stack pointer being the same as the stack
|
||||
pointer in the stub itself! This is a branch on from the
|
||||
stub back to the original caller. */
|
||||
else if ((curr_inst & 0xffe0e000) == 0xe840c000)
|
||||
{
|
||||
/* Yup. See if the previous instruction loaded
|
||||
rp from sp - 8. */
|
||||
if (prev_inst == 0x4bc23ff1)
|
||||
return (read_memory_integer
|
||||
(read_register (SP_REGNUM) - 8, 4)) & ~0x3;
|
||||
else
|
||||
{
|
||||
warning ("Unable to find restore of %%rp before bv (%%rp).");
|
||||
return orig_pc == pc ? 0 : pc & ~0x3;
|
||||
}
|
||||
}
|
||||
|
||||
/* What about be,n 0(sr0,%rp)? It's just another way we return to
|
||||
the original caller from the stub. Used in dynamic executables. */
|
||||
else if (curr_inst == 0xe0400002)
|
||||
{
|
||||
/* The value we jump to is sitting in sp - 24. But that's
|
||||
loaded several instructions before the be instruction.
|
||||
I guess we could check for the previous instruction being
|
||||
mtsp %r1,%sr0 if we want to do sanity checking. */
|
||||
return (read_memory_integer
|
||||
(read_register (SP_REGNUM) - 24, 4)) & ~0x3;
|
||||
}
|
||||
|
||||
/* Haven't found the branch yet, but we're still in the stub.
|
||||
Keep looking. */
|
||||
loc += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/* For the given instruction (INST), return any adjustment it makes
|
||||
|
@ -1411,7 +1518,7 @@ inst_saves_fr (inst)
|
|||
be in the prologue. */
|
||||
|
||||
CORE_ADDR
|
||||
skip_prologue(pc)
|
||||
skip_prologue (pc)
|
||||
CORE_ADDR pc;
|
||||
{
|
||||
char buf[4];
|
||||
|
@ -1423,6 +1530,10 @@ skip_prologue(pc)
|
|||
if (!u)
|
||||
return pc;
|
||||
|
||||
/* If we are not at the beginning of a function, then return now. */
|
||||
if ((pc & ~0x3) != u->region_start)
|
||||
return pc;
|
||||
|
||||
/* This is how much of a frame adjustment we need to account for. */
|
||||
stack_remaining = u->Total_frame_size << 3;
|
||||
|
||||
|
|
Loading…
Reference in New Issue