2004-04-22 Randolph Chung <tausq@debian.org>
* hppa-tdep.h (find_unwind_entry, hppa_get_field, hppa_extract_5_load) (hppa_extract_5R_store, hppa_extract_5r_store, hppa_extract_17) (hppa_extract_21, hppa_extract_14, hppa_low_sign_extend) (hppa_sign_extend): Add prototype. * hppa-tdep.c (get_field, extract_5_load, extract_5R_store) (extract_5r_store, extract_17, extract_21, extract_14, low_sign_extend) (sign_extend): Rename with hppa_ prefix and make non-static. Other hppa targets will also use these functions. (find_unwind_entry): Remove prototype (moved to hppa-tdep.h). (hppa_in_solib_call_trampoline, hppa_in_solib_return_trampoline) (hppa_skip_trampoline_code): Move to hppa-hpux-tdep.c (hppa_gdbarch_init): Remove gdbarch setting of skip_trampoline_code, in_solib_call_trampoline and in_solib_return_trampoline. * hppa-hpux-tdep.c (hppa32_hpux_in_solib_call_trampoline) (hppa64_hpux_in_solib_call_trampoline): New functions, split from hppa_in_solib_call_trampoline. (hppa_hpux_in_solib_return_trampoline, hppa_hpux_skip_trampoline_code): Moved from hppa-tdep.c. (hppa_hpux_init_abi): Set gdbarch for skip_trampoline_code, in_solib_call_trampoline and in_solib_return_trampoline.
This commit is contained in:
parent
369aa52037
commit
abc485a155
@ -1,3 +1,27 @@
|
|||||||
|
2004-04-22 Randolph Chung <tausq@debian.org>
|
||||||
|
|
||||||
|
* hppa-tdep.h (find_unwind_entry, hppa_get_field, hppa_extract_5_load)
|
||||||
|
(hppa_extract_5R_store, hppa_extract_5r_store, hppa_extract_17)
|
||||||
|
(hppa_extract_21, hppa_extract_14, hppa_low_sign_extend)
|
||||||
|
(hppa_sign_extend): Add prototype.
|
||||||
|
* hppa-tdep.c (get_field, extract_5_load, extract_5R_store)
|
||||||
|
(extract_5r_store, extract_17, extract_21, extract_14, low_sign_extend)
|
||||||
|
(sign_extend): Rename with hppa_ prefix and make non-static. Other
|
||||||
|
hppa targets will also use these functions.
|
||||||
|
(find_unwind_entry): Remove prototype (moved to hppa-tdep.h).
|
||||||
|
(hppa_in_solib_call_trampoline, hppa_in_solib_return_trampoline)
|
||||||
|
(hppa_skip_trampoline_code): Move to hppa-hpux-tdep.c
|
||||||
|
(hppa_gdbarch_init): Remove gdbarch setting of
|
||||||
|
skip_trampoline_code, in_solib_call_trampoline and
|
||||||
|
in_solib_return_trampoline.
|
||||||
|
* hppa-hpux-tdep.c (hppa32_hpux_in_solib_call_trampoline)
|
||||||
|
(hppa64_hpux_in_solib_call_trampoline): New functions, split from
|
||||||
|
hppa_in_solib_call_trampoline.
|
||||||
|
(hppa_hpux_in_solib_return_trampoline, hppa_hpux_skip_trampoline_code):
|
||||||
|
Moved from hppa-tdep.c.
|
||||||
|
(hppa_hpux_init_abi): Set gdbarch for skip_trampoline_code,
|
||||||
|
in_solib_call_trampoline and in_solib_return_trampoline.
|
||||||
|
|
||||||
2004-04-22 Randolph Chung <tausq@debian.org>
|
2004-04-22 Randolph Chung <tausq@debian.org>
|
||||||
|
|
||||||
* hppa-tdep.c (hppa_debug): New variable.
|
* hppa-tdep.c (hppa_debug): New variable.
|
||||||
|
@ -164,6 +164,515 @@ hppa64_hpux_frame_find_saved_regs_in_sigtramp (struct frame_info *fi,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return one if PC is in the call path of a trampoline, else return zero.
|
||||||
|
|
||||||
|
Note we return one for *any* call trampoline (long-call, arg-reloc), not
|
||||||
|
just shared library trampolines (import, export). */
|
||||||
|
|
||||||
|
static int
|
||||||
|
hppa32_hpux_in_solib_call_trampoline (CORE_ADDR pc, char *name)
|
||||||
|
{
|
||||||
|
struct minimal_symbol *minsym;
|
||||||
|
struct unwind_table_entry *u;
|
||||||
|
static CORE_ADDR dyncall = 0;
|
||||||
|
static CORE_ADDR sr4export = 0;
|
||||||
|
|
||||||
|
/* FIXME XXX - dyncall and sr4export must be initialized whenever we get a
|
||||||
|
new exec file */
|
||||||
|
|
||||||
|
/* First see if PC is in one of the two C-library trampolines. */
|
||||||
|
if (!dyncall)
|
||||||
|
{
|
||||||
|
minsym = lookup_minimal_symbol ("$$dyncall", NULL, NULL);
|
||||||
|
if (minsym)
|
||||||
|
dyncall = SYMBOL_VALUE_ADDRESS (minsym);
|
||||||
|
else
|
||||||
|
dyncall = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sr4export)
|
||||||
|
{
|
||||||
|
minsym = lookup_minimal_symbol ("_sr4export", NULL, NULL);
|
||||||
|
if (minsym)
|
||||||
|
sr4export = SYMBOL_VALUE_ADDRESS (minsym);
|
||||||
|
else
|
||||||
|
sr4export = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pc == dyncall || pc == sr4export)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
minsym = lookup_minimal_symbol_by_pc (pc);
|
||||||
|
if (minsym && strcmp (DEPRECATED_SYMBOL_NAME (minsym), ".stub") == 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* Get the unwind descriptor corresponding to PC, return zero
|
||||||
|
if no unwind was found. */
|
||||||
|
u = find_unwind_entry (pc);
|
||||||
|
if (!u)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* If this isn't a linker stub, then return now. */
|
||||||
|
if (u->stub_unwind.stub_type == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* By definition a long-branch stub is a call stub. */
|
||||||
|
if (u->stub_unwind.stub_type == LONG_BRANCH)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* The call and return path execute the same instructions within
|
||||||
|
an IMPORT stub! So an IMPORT stub is both a call and return
|
||||||
|
trampoline. */
|
||||||
|
if (u->stub_unwind.stub_type == IMPORT)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* Parameter relocation stubs always have a call path and may have a
|
||||||
|
return path. */
|
||||||
|
if (u->stub_unwind.stub_type == PARAMETER_RELOCATION
|
||||||
|
|| u->stub_unwind.stub_type == EXPORT)
|
||||||
|
{
|
||||||
|
CORE_ADDR addr;
|
||||||
|
|
||||||
|
/* Search forward from the current PC until we hit a branch
|
||||||
|
or the end of the stub. */
|
||||||
|
for (addr = pc; addr <= u->region_end; addr += 4)
|
||||||
|
{
|
||||||
|
unsigned long insn;
|
||||||
|
|
||||||
|
insn = read_memory_integer (addr, 4);
|
||||||
|
|
||||||
|
/* Does it look like a bl? If so then it's the call path, if
|
||||||
|
we find a bv or be first, then we're on the return path. */
|
||||||
|
if ((insn & 0xfc00e000) == 0xe8000000)
|
||||||
|
return 1;
|
||||||
|
else if ((insn & 0xfc00e001) == 0xe800c000
|
||||||
|
|| (insn & 0xfc000000) == 0xe0000000)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Should never happen. */
|
||||||
|
warning ("Unable to find branch in parameter relocation stub.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unknown stub type. For now, just return zero. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hppa64_hpux_in_solib_call_trampoline (CORE_ADDR pc, char *name)
|
||||||
|
{
|
||||||
|
/* PA64 has a completely different stub/trampoline scheme. Is it
|
||||||
|
better? Maybe. It's certainly harder to determine with any
|
||||||
|
certainty that we are in a stub because we can not refer to the
|
||||||
|
unwinders to help.
|
||||||
|
|
||||||
|
The heuristic is simple. Try to lookup the current PC value in th
|
||||||
|
minimal symbol table. If that fails, then assume we are not in a
|
||||||
|
stub and return.
|
||||||
|
|
||||||
|
Then see if the PC value falls within the section bounds for the
|
||||||
|
section containing the minimal symbol we found in the first
|
||||||
|
step. If it does, then assume we are not in a stub and return.
|
||||||
|
|
||||||
|
Finally peek at the instructions to see if they look like a stub. */
|
||||||
|
struct minimal_symbol *minsym;
|
||||||
|
asection *sec;
|
||||||
|
CORE_ADDR addr;
|
||||||
|
int insn, i;
|
||||||
|
|
||||||
|
minsym = lookup_minimal_symbol_by_pc (pc);
|
||||||
|
if (! minsym)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
sec = SYMBOL_BFD_SECTION (minsym);
|
||||||
|
|
||||||
|
if (bfd_get_section_vma (sec->owner, sec) <= pc
|
||||||
|
&& pc < (bfd_get_section_vma (sec->owner, sec)
|
||||||
|
+ bfd_section_size (sec->owner, sec)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* We might be in a stub. Peek at the instructions. Stubs are 3
|
||||||
|
instructions long. */
|
||||||
|
insn = read_memory_integer (pc, 4);
|
||||||
|
|
||||||
|
/* Find out where we think we are within the stub. */
|
||||||
|
if ((insn & 0xffffc00e) == 0x53610000)
|
||||||
|
addr = pc;
|
||||||
|
else if ((insn & 0xffffffff) == 0xe820d000)
|
||||||
|
addr = pc - 4;
|
||||||
|
else if ((insn & 0xffffc00e) == 0x537b0000)
|
||||||
|
addr = pc - 8;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Now verify each insn in the range looks like a stub instruction. */
|
||||||
|
insn = read_memory_integer (addr, 4);
|
||||||
|
if ((insn & 0xffffc00e) != 0x53610000)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Now verify each insn in the range looks like a stub instruction. */
|
||||||
|
insn = read_memory_integer (addr + 4, 4);
|
||||||
|
if ((insn & 0xffffffff) != 0xe820d000)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Now verify each insn in the range looks like a stub instruction. */
|
||||||
|
insn = read_memory_integer (addr + 8, 4);
|
||||||
|
if ((insn & 0xffffc00e) != 0x537b0000)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Looks like a stub. */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return one if PC is in the return path of a trampoline, else return zero.
|
||||||
|
|
||||||
|
Note we return one for *any* call trampoline (long-call, arg-reloc), not
|
||||||
|
just shared library trampolines (import, export). */
|
||||||
|
|
||||||
|
static int
|
||||||
|
hppa_hpux_in_solib_return_trampoline (CORE_ADDR pc, char *name)
|
||||||
|
{
|
||||||
|
struct unwind_table_entry *u;
|
||||||
|
|
||||||
|
/* Get the unwind descriptor corresponding to PC, return zero
|
||||||
|
if no unwind was found. */
|
||||||
|
u = find_unwind_entry (pc);
|
||||||
|
if (!u)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* If this isn't a linker stub or it's just a long branch stub, then
|
||||||
|
return zero. */
|
||||||
|
if (u->stub_unwind.stub_type == 0 || u->stub_unwind.stub_type == LONG_BRANCH)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* The call and return path execute the same instructions within
|
||||||
|
an IMPORT stub! So an IMPORT stub is both a call and return
|
||||||
|
trampoline. */
|
||||||
|
if (u->stub_unwind.stub_type == IMPORT)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* Parameter relocation stubs always have a call path and may have a
|
||||||
|
return path. */
|
||||||
|
if (u->stub_unwind.stub_type == PARAMETER_RELOCATION
|
||||||
|
|| u->stub_unwind.stub_type == EXPORT)
|
||||||
|
{
|
||||||
|
CORE_ADDR addr;
|
||||||
|
|
||||||
|
/* Search forward from the current PC until we hit a branch
|
||||||
|
or the end of the stub. */
|
||||||
|
for (addr = pc; addr <= u->region_end; addr += 4)
|
||||||
|
{
|
||||||
|
unsigned long insn;
|
||||||
|
|
||||||
|
insn = read_memory_integer (addr, 4);
|
||||||
|
|
||||||
|
/* Does it look like a bl? If so then it's the call path, if
|
||||||
|
we find a bv or be first, then we're on the return path. */
|
||||||
|
if ((insn & 0xfc00e000) == 0xe8000000)
|
||||||
|
return 0;
|
||||||
|
else if ((insn & 0xfc00e001) == 0xe800c000
|
||||||
|
|| (insn & 0xfc000000) == 0xe0000000)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Should never happen. */
|
||||||
|
warning ("Unable to find branch in parameter relocation stub.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unknown stub type. For now, just return zero. */
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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.
|
||||||
|
|
||||||
|
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. */
|
||||||
|
|
||||||
|
static CORE_ADDR
|
||||||
|
hppa_hpux_skip_trampoline_code (CORE_ADDR pc)
|
||||||
|
{
|
||||||
|
long orig_pc = pc;
|
||||||
|
long prev_inst, curr_inst, loc;
|
||||||
|
static CORE_ADDR dyncall = 0;
|
||||||
|
static CORE_ADDR dyncall_external = 0;
|
||||||
|
static CORE_ADDR sr4export = 0;
|
||||||
|
struct minimal_symbol *msym;
|
||||||
|
struct unwind_table_entry *u;
|
||||||
|
|
||||||
|
/* FIXME XXX - dyncall and sr4export must be initialized whenever we get a
|
||||||
|
new exec file */
|
||||||
|
|
||||||
|
if (!dyncall)
|
||||||
|
{
|
||||||
|
msym = lookup_minimal_symbol ("$$dyncall", NULL, NULL);
|
||||||
|
if (msym)
|
||||||
|
dyncall = SYMBOL_VALUE_ADDRESS (msym);
|
||||||
|
else
|
||||||
|
dyncall = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dyncall_external)
|
||||||
|
{
|
||||||
|
msym = lookup_minimal_symbol ("$$dyncall_external", NULL, NULL);
|
||||||
|
if (msym)
|
||||||
|
dyncall_external = SYMBOL_VALUE_ADDRESS (msym);
|
||||||
|
else
|
||||||
|
dyncall_external = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sr4export)
|
||||||
|
{
|
||||||
|
msym = lookup_minimal_symbol ("_sr4export", NULL, NULL);
|
||||||
|
if (msym)
|
||||||
|
sr4export = SYMBOL_VALUE_ADDRESS (msym);
|
||||||
|
else
|
||||||
|
sr4export = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Addresses passed to dyncall may *NOT* be the actual address
|
||||||
|
of the function. So we may have to do something special. */
|
||||||
|
if (pc == dyncall)
|
||||||
|
{
|
||||||
|
pc = (CORE_ADDR) read_register (22);
|
||||||
|
|
||||||
|
/* 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, TARGET_PTR_BIT / 8);
|
||||||
|
}
|
||||||
|
if (pc == dyncall_external)
|
||||||
|
{
|
||||||
|
pc = (CORE_ADDR) read_register (22);
|
||||||
|
pc = (CORE_ADDR) read_memory_integer (pc & ~0x3, TARGET_PTR_BIT / 8);
|
||||||
|
}
|
||||||
|
else if (pc == sr4export)
|
||||||
|
pc = (CORE_ADDR) (read_register (22));
|
||||||
|
|
||||||
|
/* Get the unwind descriptor corresponding to PC, return zero
|
||||||
|
if no unwind was found. */
|
||||||
|
u = find_unwind_entry (pc);
|
||||||
|
if (!u)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* If this isn't a linker stub, then return now. */
|
||||||
|
/* elz: attention here! (FIXME) because of a compiler/linker
|
||||||
|
error, some stubs which should have a non zero stub_unwind.stub_type
|
||||||
|
have unfortunately a value of zero. So this function would return here
|
||||||
|
as if we were not in a trampoline. To fix this, we go look at the partial
|
||||||
|
symbol information, which reports this guy as a stub.
|
||||||
|
(FIXME): Unfortunately, we are not that lucky: it turns out that the
|
||||||
|
partial symbol information is also wrong sometimes. This is because
|
||||||
|
when it is entered (somread.c::som_symtab_read()) it can happen that
|
||||||
|
if the type of the symbol (from the som) is Entry, and the symbol is
|
||||||
|
in a shared library, then it can also be a trampoline. This would
|
||||||
|
be OK, except that I believe the way they decide if we are ina shared library
|
||||||
|
does not work. SOOOO..., even if we have a regular function w/o trampolines
|
||||||
|
its minimal symbol can be assigned type mst_solib_trampoline.
|
||||||
|
Also, if we find that the symbol is a real stub, then we fix the unwind
|
||||||
|
descriptor, and define the stub type to be EXPORT.
|
||||||
|
Hopefully this is correct most of the times. */
|
||||||
|
if (u->stub_unwind.stub_type == 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* elz: NOTE (FIXME!) once the problem with the unwind information is fixed
|
||||||
|
we can delete all the code which appears between the lines */
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
msym = lookup_minimal_symbol_by_pc (pc);
|
||||||
|
|
||||||
|
if (msym == NULL || MSYMBOL_TYPE (msym) != mst_solib_trampoline)
|
||||||
|
return orig_pc == pc ? 0 : pc & ~0x3;
|
||||||
|
|
||||||
|
else if (msym != NULL && MSYMBOL_TYPE (msym) == mst_solib_trampoline)
|
||||||
|
{
|
||||||
|
struct objfile *objfile;
|
||||||
|
struct minimal_symbol *msymbol;
|
||||||
|
int function_found = 0;
|
||||||
|
|
||||||
|
/* go look if there is another minimal symbol with the same name as
|
||||||
|
this one, but with type mst_text. This would happen if the msym
|
||||||
|
is an actual trampoline, in which case there would be another
|
||||||
|
symbol with the same name corresponding to the real function */
|
||||||
|
|
||||||
|
ALL_MSYMBOLS (objfile, msymbol)
|
||||||
|
{
|
||||||
|
if (MSYMBOL_TYPE (msymbol) == mst_text
|
||||||
|
&& DEPRECATED_STREQ (DEPRECATED_SYMBOL_NAME (msymbol), DEPRECATED_SYMBOL_NAME (msym)))
|
||||||
|
{
|
||||||
|
function_found = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (function_found)
|
||||||
|
/* the type of msym is correct (mst_solib_trampoline), but
|
||||||
|
the unwind info is wrong, so set it to the correct value */
|
||||||
|
u->stub_unwind.stub_type = EXPORT;
|
||||||
|
else
|
||||||
|
/* the stub type info in the unwind is correct (this is not a
|
||||||
|
trampoline), but the msym type information is wrong, it
|
||||||
|
should be mst_text. So we need to fix the msym, and also
|
||||||
|
get out of this function */
|
||||||
|
{
|
||||||
|
MSYMBOL_TYPE (msym) = mst_text;
|
||||||
|
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) == 0x20200000)
|
||||||
|
return (hppa_extract_21 (prev_inst) + hppa_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 a be 0(sr0,%r21)? OR
|
||||||
|
Does it look like a be, n 0(sr0,%r21)? OR
|
||||||
|
Does it look like a bve (r21)? (this is on PA2.0)
|
||||||
|
Does it look like a bve, n(r21)? (this is also on PA2.0)
|
||||||
|
That's the branch from an
|
||||||
|
import stub to an export stub.
|
||||||
|
|
||||||
|
It is impossible to determine the target of the branch via
|
||||||
|
simple examination of instructions and/or data (consider
|
||||||
|
that the address in the plabel may be the address of the
|
||||||
|
bind-on-reference routine in the dynamic loader).
|
||||||
|
|
||||||
|
So we have try an alternative approach.
|
||||||
|
|
||||||
|
Get the name of the symbol at our current location; it should
|
||||||
|
be a stub symbol with the same name as the symbol in the
|
||||||
|
shared library.
|
||||||
|
|
||||||
|
Then lookup a minimal symbol with the same name; we should
|
||||||
|
get the minimal symbol for the target routine in the shared
|
||||||
|
library as those take precedence of import/export stubs. */
|
||||||
|
if ((curr_inst == 0xe2a00000) ||
|
||||||
|
(curr_inst == 0xe2a00002) ||
|
||||||
|
(curr_inst == 0xeaa0d000) ||
|
||||||
|
(curr_inst == 0xeaa0d002))
|
||||||
|
{
|
||||||
|
struct minimal_symbol *stubsym, *libsym;
|
||||||
|
|
||||||
|
stubsym = lookup_minimal_symbol_by_pc (loc);
|
||||||
|
if (stubsym == NULL)
|
||||||
|
{
|
||||||
|
warning ("Unable to find symbol for 0x%lx", loc);
|
||||||
|
return orig_pc == pc ? 0 : pc & ~0x3;
|
||||||
|
}
|
||||||
|
|
||||||
|
libsym = lookup_minimal_symbol (DEPRECATED_SYMBOL_NAME (stubsym), NULL, NULL);
|
||||||
|
if (libsym == NULL)
|
||||||
|
{
|
||||||
|
warning ("Unable to find library symbol for %s\n",
|
||||||
|
DEPRECATED_SYMBOL_NAME (stubsym));
|
||||||
|
return orig_pc == pc ? 0 : pc & ~0x3;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SYMBOL_VALUE (libsym);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Does it look like bl X,%rp or bl X,%r0? Another way to do a
|
||||||
|
branch from the stub to the actual function. */
|
||||||
|
/*elz */
|
||||||
|
else if ((curr_inst & 0xffe0e000) == 0xe8400000
|
||||||
|
|| (curr_inst & 0xffe0e000) == 0xe8000000
|
||||||
|
|| (curr_inst & 0xffe0e000) == 0xe800A000)
|
||||||
|
return (loc + hppa_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) */
|
||||||
|
else if ((curr_inst & 0xffe0f000) == 0xe840c000)
|
||||||
|
{
|
||||||
|
/* Yup. See if the previous instruction loaded
|
||||||
|
rp from sp - 8. */
|
||||||
|
if (prev_inst == 0x4bc23ff1)
|
||||||
|
return (read_memory_integer
|
||||||
|
(read_register (HPPA_SP_REGNUM) - 8, 4)) & ~0x3;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
warning ("Unable to find restore of %%rp before bv (%%rp).");
|
||||||
|
return orig_pc == pc ? 0 : pc & ~0x3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* elz: added this case to capture the new instruction
|
||||||
|
at the end of the return part of an export stub used by
|
||||||
|
the PA2.0: BVE, n (rp) */
|
||||||
|
else if ((curr_inst & 0xffe0f000) == 0xe840d000)
|
||||||
|
{
|
||||||
|
return (read_memory_integer
|
||||||
|
(read_register (HPPA_SP_REGNUM) - 24, TARGET_PTR_BIT / 8)) & ~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 (HPPA_SP_REGNUM) - 24, TARGET_PTR_BIT / 8)) & ~0x3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Haven't found the branch yet, but we're still in the stub.
|
||||||
|
Keep looking. */
|
||||||
|
loc += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Exception handling support for the HP-UX ANSI C++ compiler.
|
/* Exception handling support for the HP-UX ANSI C++ compiler.
|
||||||
The compiler (aCC) provides a callback for exception events;
|
The compiler (aCC) provides a callback for exception events;
|
||||||
GDB can set a breakpoint on this callback and find out what
|
GDB can set a breakpoint on this callback and find out what
|
||||||
@ -716,7 +1225,20 @@ child_get_current_exception_event (void)
|
|||||||
static void
|
static void
|
||||||
hppa_hpux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
|
hppa_hpux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
|
||||||
{
|
{
|
||||||
|
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
|
||||||
|
|
||||||
set_gdbarch_deprecated_pc_in_sigtramp (gdbarch, hppa_hpux_pc_in_sigtramp);
|
set_gdbarch_deprecated_pc_in_sigtramp (gdbarch, hppa_hpux_pc_in_sigtramp);
|
||||||
|
|
||||||
|
if (tdep->bytes_per_address == 4)
|
||||||
|
set_gdbarch_in_solib_call_trampoline (gdbarch,
|
||||||
|
hppa32_hpux_in_solib_call_trampoline);
|
||||||
|
else
|
||||||
|
set_gdbarch_in_solib_call_trampoline (gdbarch,
|
||||||
|
hppa64_hpux_in_solib_call_trampoline);
|
||||||
|
|
||||||
|
set_gdbarch_in_solib_return_trampoline (gdbarch,
|
||||||
|
hppa_hpux_in_solib_return_trampoline);
|
||||||
|
set_gdbarch_skip_trampoline_code (gdbarch, hppa_hpux_skip_trampoline_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
625
gdb/hppa-tdep.c
625
gdb/hppa-tdep.c
@ -88,28 +88,8 @@ const struct objfile_data *hppa_objfile_priv_data = NULL;
|
|||||||
#define UNWIND_ENTRY_SIZE 16
|
#define UNWIND_ENTRY_SIZE 16
|
||||||
#define STUB_UNWIND_ENTRY_SIZE 8
|
#define STUB_UNWIND_ENTRY_SIZE 8
|
||||||
|
|
||||||
static int get_field (unsigned word, int from, int to);
|
|
||||||
|
|
||||||
static int extract_5_load (unsigned int);
|
|
||||||
|
|
||||||
static unsigned extract_5R_store (unsigned int);
|
|
||||||
|
|
||||||
static unsigned extract_5r_store (unsigned int);
|
|
||||||
|
|
||||||
struct unwind_table_entry *find_unwind_entry (CORE_ADDR);
|
|
||||||
|
|
||||||
static int extract_17 (unsigned int);
|
|
||||||
|
|
||||||
static int extract_21 (unsigned);
|
|
||||||
|
|
||||||
static int extract_14 (unsigned);
|
|
||||||
|
|
||||||
static void unwind_command (char *, int);
|
static void unwind_command (char *, int);
|
||||||
|
|
||||||
static int low_sign_extend (unsigned int, unsigned int);
|
|
||||||
|
|
||||||
static int sign_extend (unsigned int, unsigned int);
|
|
||||||
|
|
||||||
static int hppa_alignof (struct type *);
|
static int hppa_alignof (struct type *);
|
||||||
|
|
||||||
static int prologue_inst_adjust_sp (unsigned long);
|
static int prologue_inst_adjust_sp (unsigned long);
|
||||||
@ -246,16 +226,16 @@ hppa64_return_value (struct gdbarch *gdbarch,
|
|||||||
/* This assumes that no garbage lies outside of the lower bits of
|
/* This assumes that no garbage lies outside of the lower bits of
|
||||||
value. */
|
value. */
|
||||||
|
|
||||||
static int
|
int
|
||||||
sign_extend (unsigned val, unsigned bits)
|
hppa_sign_extend (unsigned val, unsigned bits)
|
||||||
{
|
{
|
||||||
return (int) (val >> (bits - 1) ? (-1 << bits) | val : val);
|
return (int) (val >> (bits - 1) ? (-1 << bits) | val : val);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For many immediate values the sign bit is the low bit! */
|
/* For many immediate values the sign bit is the low bit! */
|
||||||
|
|
||||||
static int
|
int
|
||||||
low_sign_extend (unsigned val, unsigned bits)
|
hppa_low_hppa_sign_extend (unsigned val, unsigned bits)
|
||||||
{
|
{
|
||||||
return (int) ((val & 0x1 ? (-1 << (bits - 1)) : 0) | val >> 1);
|
return (int) ((val & 0x1 ? (-1 << (bits - 1)) : 0) | val >> 1);
|
||||||
}
|
}
|
||||||
@ -263,74 +243,74 @@ low_sign_extend (unsigned val, unsigned bits)
|
|||||||
/* Extract the bits at positions between FROM and TO, using HP's numbering
|
/* Extract the bits at positions between FROM and TO, using HP's numbering
|
||||||
(MSB = 0). */
|
(MSB = 0). */
|
||||||
|
|
||||||
static int
|
int
|
||||||
get_field (unsigned word, int from, int to)
|
hppa_get_field (unsigned word, int from, int to)
|
||||||
{
|
{
|
||||||
return ((word) >> (31 - (to)) & ((1 << ((to) - (from) + 1)) - 1));
|
return ((word) >> (31 - (to)) & ((1 << ((to) - (from) + 1)) - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* extract the immediate field from a ld{bhw}s instruction */
|
/* extract the immediate field from a ld{bhw}s instruction */
|
||||||
|
|
||||||
static int
|
int
|
||||||
extract_5_load (unsigned word)
|
hppa_extract_5_load (unsigned word)
|
||||||
{
|
{
|
||||||
return low_sign_extend (word >> 16 & MASK_5, 5);
|
return hppa_low_hppa_sign_extend (word >> 16 & MASK_5, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* extract the immediate field from a break instruction */
|
/* extract the immediate field from a break instruction */
|
||||||
|
|
||||||
static unsigned
|
unsigned
|
||||||
extract_5r_store (unsigned word)
|
hppa_extract_5r_store (unsigned word)
|
||||||
{
|
{
|
||||||
return (word & MASK_5);
|
return (word & MASK_5);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* extract the immediate field from a {sr}sm instruction */
|
/* extract the immediate field from a {sr}sm instruction */
|
||||||
|
|
||||||
static unsigned
|
unsigned
|
||||||
extract_5R_store (unsigned word)
|
hppa_extract_5R_store (unsigned word)
|
||||||
{
|
{
|
||||||
return (word >> 16 & MASK_5);
|
return (word >> 16 & MASK_5);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* extract a 14 bit immediate field */
|
/* extract a 14 bit immediate field */
|
||||||
|
|
||||||
static int
|
int
|
||||||
extract_14 (unsigned word)
|
hppa_extract_14 (unsigned word)
|
||||||
{
|
{
|
||||||
return low_sign_extend (word & MASK_14, 14);
|
return hppa_low_hppa_sign_extend (word & MASK_14, 14);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* extract a 21 bit constant */
|
/* extract a 21 bit constant */
|
||||||
|
|
||||||
static int
|
int
|
||||||
extract_21 (unsigned word)
|
hppa_extract_21 (unsigned word)
|
||||||
{
|
{
|
||||||
int val;
|
int val;
|
||||||
|
|
||||||
word &= MASK_21;
|
word &= MASK_21;
|
||||||
word <<= 11;
|
word <<= 11;
|
||||||
val = get_field (word, 20, 20);
|
val = hppa_get_field (word, 20, 20);
|
||||||
val <<= 11;
|
val <<= 11;
|
||||||
val |= get_field (word, 9, 19);
|
val |= hppa_get_field (word, 9, 19);
|
||||||
val <<= 2;
|
val <<= 2;
|
||||||
val |= get_field (word, 5, 6);
|
val |= hppa_get_field (word, 5, 6);
|
||||||
val <<= 5;
|
val <<= 5;
|
||||||
val |= get_field (word, 0, 4);
|
val |= hppa_get_field (word, 0, 4);
|
||||||
val <<= 2;
|
val <<= 2;
|
||||||
val |= get_field (word, 7, 8);
|
val |= hppa_get_field (word, 7, 8);
|
||||||
return sign_extend (val, 21) << 11;
|
return hppa_sign_extend (val, 21) << 11;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* extract a 17 bit constant from branch instructions, returning the
|
/* extract a 17 bit constant from branch instructions, returning the
|
||||||
19 bit signed value. */
|
19 bit signed value. */
|
||||||
|
|
||||||
static int
|
int
|
||||||
extract_17 (unsigned word)
|
hppa_extract_17 (unsigned word)
|
||||||
{
|
{
|
||||||
return sign_extend (get_field (word, 19, 28) |
|
return hppa_sign_extend (hppa_get_field (word, 19, 28) |
|
||||||
get_field (word, 29, 29) << 10 |
|
hppa_get_field (word, 29, 29) << 10 |
|
||||||
get_field (word, 11, 15) << 11 |
|
hppa_get_field (word, 11, 15) << 11 |
|
||||||
(word & 0x1) << 16, 17) << 2;
|
(word & 0x1) << 16, 17) << 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1099,515 +1079,6 @@ hppa_alignof (struct type *type)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return one if PC is in the call path of a trampoline, else return zero.
|
|
||||||
|
|
||||||
Note we return one for *any* call trampoline (long-call, arg-reloc), not
|
|
||||||
just shared library trampolines (import, export). */
|
|
||||||
|
|
||||||
static int
|
|
||||||
hppa_in_solib_call_trampoline (CORE_ADDR pc, char *name)
|
|
||||||
{
|
|
||||||
struct minimal_symbol *minsym;
|
|
||||||
struct unwind_table_entry *u;
|
|
||||||
static CORE_ADDR dyncall = 0;
|
|
||||||
static CORE_ADDR sr4export = 0;
|
|
||||||
|
|
||||||
#ifdef GDB_TARGET_IS_HPPA_20W
|
|
||||||
/* PA64 has a completely different stub/trampoline scheme. Is it
|
|
||||||
better? Maybe. It's certainly harder to determine with any
|
|
||||||
certainty that we are in a stub because we can not refer to the
|
|
||||||
unwinders to help.
|
|
||||||
|
|
||||||
The heuristic is simple. Try to lookup the current PC value in th
|
|
||||||
minimal symbol table. If that fails, then assume we are not in a
|
|
||||||
stub and return.
|
|
||||||
|
|
||||||
Then see if the PC value falls within the section bounds for the
|
|
||||||
section containing the minimal symbol we found in the first
|
|
||||||
step. If it does, then assume we are not in a stub and return.
|
|
||||||
|
|
||||||
Finally peek at the instructions to see if they look like a stub. */
|
|
||||||
{
|
|
||||||
struct minimal_symbol *minsym;
|
|
||||||
asection *sec;
|
|
||||||
CORE_ADDR addr;
|
|
||||||
int insn, i;
|
|
||||||
|
|
||||||
minsym = lookup_minimal_symbol_by_pc (pc);
|
|
||||||
if (! minsym)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
sec = SYMBOL_BFD_SECTION (minsym);
|
|
||||||
|
|
||||||
if (bfd_get_section_vma (sec->owner, sec) <= pc
|
|
||||||
&& pc < (bfd_get_section_vma (sec->owner, sec)
|
|
||||||
+ bfd_section_size (sec->owner, sec)))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* We might be in a stub. Peek at the instructions. Stubs are 3
|
|
||||||
instructions long. */
|
|
||||||
insn = read_memory_integer (pc, 4);
|
|
||||||
|
|
||||||
/* Find out where we think we are within the stub. */
|
|
||||||
if ((insn & 0xffffc00e) == 0x53610000)
|
|
||||||
addr = pc;
|
|
||||||
else if ((insn & 0xffffffff) == 0xe820d000)
|
|
||||||
addr = pc - 4;
|
|
||||||
else if ((insn & 0xffffc00e) == 0x537b0000)
|
|
||||||
addr = pc - 8;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Now verify each insn in the range looks like a stub instruction. */
|
|
||||||
insn = read_memory_integer (addr, 4);
|
|
||||||
if ((insn & 0xffffc00e) != 0x53610000)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Now verify each insn in the range looks like a stub instruction. */
|
|
||||||
insn = read_memory_integer (addr + 4, 4);
|
|
||||||
if ((insn & 0xffffffff) != 0xe820d000)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Now verify each insn in the range looks like a stub instruction. */
|
|
||||||
insn = read_memory_integer (addr + 8, 4);
|
|
||||||
if ((insn & 0xffffc00e) != 0x537b0000)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Looks like a stub. */
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* FIXME XXX - dyncall and sr4export must be initialized whenever we get a
|
|
||||||
new exec file */
|
|
||||||
|
|
||||||
/* First see if PC is in one of the two C-library trampolines. */
|
|
||||||
if (!dyncall)
|
|
||||||
{
|
|
||||||
minsym = lookup_minimal_symbol ("$$dyncall", NULL, NULL);
|
|
||||||
if (minsym)
|
|
||||||
dyncall = SYMBOL_VALUE_ADDRESS (minsym);
|
|
||||||
else
|
|
||||||
dyncall = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!sr4export)
|
|
||||||
{
|
|
||||||
minsym = lookup_minimal_symbol ("_sr4export", NULL, NULL);
|
|
||||||
if (minsym)
|
|
||||||
sr4export = SYMBOL_VALUE_ADDRESS (minsym);
|
|
||||||
else
|
|
||||||
sr4export = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pc == dyncall || pc == sr4export)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
minsym = lookup_minimal_symbol_by_pc (pc);
|
|
||||||
if (minsym && strcmp (DEPRECATED_SYMBOL_NAME (minsym), ".stub") == 0)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
/* Get the unwind descriptor corresponding to PC, return zero
|
|
||||||
if no unwind was found. */
|
|
||||||
u = find_unwind_entry (pc);
|
|
||||||
if (!u)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* If this isn't a linker stub, then return now. */
|
|
||||||
if (u->stub_unwind.stub_type == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* By definition a long-branch stub is a call stub. */
|
|
||||||
if (u->stub_unwind.stub_type == LONG_BRANCH)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
/* The call and return path execute the same instructions within
|
|
||||||
an IMPORT stub! So an IMPORT stub is both a call and return
|
|
||||||
trampoline. */
|
|
||||||
if (u->stub_unwind.stub_type == IMPORT)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
/* Parameter relocation stubs always have a call path and may have a
|
|
||||||
return path. */
|
|
||||||
if (u->stub_unwind.stub_type == PARAMETER_RELOCATION
|
|
||||||
|| u->stub_unwind.stub_type == EXPORT)
|
|
||||||
{
|
|
||||||
CORE_ADDR addr;
|
|
||||||
|
|
||||||
/* Search forward from the current PC until we hit a branch
|
|
||||||
or the end of the stub. */
|
|
||||||
for (addr = pc; addr <= u->region_end; addr += 4)
|
|
||||||
{
|
|
||||||
unsigned long insn;
|
|
||||||
|
|
||||||
insn = read_memory_integer (addr, 4);
|
|
||||||
|
|
||||||
/* Does it look like a bl? If so then it's the call path, if
|
|
||||||
we find a bv or be first, then we're on the return path. */
|
|
||||||
if ((insn & 0xfc00e000) == 0xe8000000)
|
|
||||||
return 1;
|
|
||||||
else if ((insn & 0xfc00e001) == 0xe800c000
|
|
||||||
|| (insn & 0xfc000000) == 0xe0000000)
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Should never happen. */
|
|
||||||
warning ("Unable to find branch in parameter relocation stub.\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Unknown stub type. For now, just return zero. */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return one if PC is in the return path of a trampoline, else return zero.
|
|
||||||
|
|
||||||
Note we return one for *any* call trampoline (long-call, arg-reloc), not
|
|
||||||
just shared library trampolines (import, export). */
|
|
||||||
|
|
||||||
static int
|
|
||||||
hppa_in_solib_return_trampoline (CORE_ADDR pc, char *name)
|
|
||||||
{
|
|
||||||
struct unwind_table_entry *u;
|
|
||||||
|
|
||||||
/* Get the unwind descriptor corresponding to PC, return zero
|
|
||||||
if no unwind was found. */
|
|
||||||
u = find_unwind_entry (pc);
|
|
||||||
if (!u)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* If this isn't a linker stub or it's just a long branch stub, then
|
|
||||||
return zero. */
|
|
||||||
if (u->stub_unwind.stub_type == 0 || u->stub_unwind.stub_type == LONG_BRANCH)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* The call and return path execute the same instructions within
|
|
||||||
an IMPORT stub! So an IMPORT stub is both a call and return
|
|
||||||
trampoline. */
|
|
||||||
if (u->stub_unwind.stub_type == IMPORT)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
/* Parameter relocation stubs always have a call path and may have a
|
|
||||||
return path. */
|
|
||||||
if (u->stub_unwind.stub_type == PARAMETER_RELOCATION
|
|
||||||
|| u->stub_unwind.stub_type == EXPORT)
|
|
||||||
{
|
|
||||||
CORE_ADDR addr;
|
|
||||||
|
|
||||||
/* Search forward from the current PC until we hit a branch
|
|
||||||
or the end of the stub. */
|
|
||||||
for (addr = pc; addr <= u->region_end; addr += 4)
|
|
||||||
{
|
|
||||||
unsigned long insn;
|
|
||||||
|
|
||||||
insn = read_memory_integer (addr, 4);
|
|
||||||
|
|
||||||
/* Does it look like a bl? If so then it's the call path, if
|
|
||||||
we find a bv or be first, then we're on the return path. */
|
|
||||||
if ((insn & 0xfc00e000) == 0xe8000000)
|
|
||||||
return 0;
|
|
||||||
else if ((insn & 0xfc00e001) == 0xe800c000
|
|
||||||
|| (insn & 0xfc000000) == 0xe0000000)
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Should never happen. */
|
|
||||||
warning ("Unable to find branch in parameter relocation stub.\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Unknown stub type. For now, just return zero. */
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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.
|
|
||||||
|
|
||||||
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. */
|
|
||||||
|
|
||||||
static CORE_ADDR
|
|
||||||
hppa_skip_trampoline_code (CORE_ADDR pc)
|
|
||||||
{
|
|
||||||
long orig_pc = pc;
|
|
||||||
long prev_inst, curr_inst, loc;
|
|
||||||
static CORE_ADDR dyncall = 0;
|
|
||||||
static CORE_ADDR dyncall_external = 0;
|
|
||||||
static CORE_ADDR sr4export = 0;
|
|
||||||
struct minimal_symbol *msym;
|
|
||||||
struct unwind_table_entry *u;
|
|
||||||
|
|
||||||
/* FIXME XXX - dyncall and sr4export must be initialized whenever we get a
|
|
||||||
new exec file */
|
|
||||||
|
|
||||||
if (!dyncall)
|
|
||||||
{
|
|
||||||
msym = lookup_minimal_symbol ("$$dyncall", NULL, NULL);
|
|
||||||
if (msym)
|
|
||||||
dyncall = SYMBOL_VALUE_ADDRESS (msym);
|
|
||||||
else
|
|
||||||
dyncall = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!dyncall_external)
|
|
||||||
{
|
|
||||||
msym = lookup_minimal_symbol ("$$dyncall_external", NULL, NULL);
|
|
||||||
if (msym)
|
|
||||||
dyncall_external = SYMBOL_VALUE_ADDRESS (msym);
|
|
||||||
else
|
|
||||||
dyncall_external = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!sr4export)
|
|
||||||
{
|
|
||||||
msym = lookup_minimal_symbol ("_sr4export", NULL, NULL);
|
|
||||||
if (msym)
|
|
||||||
sr4export = SYMBOL_VALUE_ADDRESS (msym);
|
|
||||||
else
|
|
||||||
sr4export = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Addresses passed to dyncall may *NOT* be the actual address
|
|
||||||
of the function. So we may have to do something special. */
|
|
||||||
if (pc == dyncall)
|
|
||||||
{
|
|
||||||
pc = (CORE_ADDR) read_register (22);
|
|
||||||
|
|
||||||
/* 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, TARGET_PTR_BIT / 8);
|
|
||||||
}
|
|
||||||
if (pc == dyncall_external)
|
|
||||||
{
|
|
||||||
pc = (CORE_ADDR) read_register (22);
|
|
||||||
pc = (CORE_ADDR) read_memory_integer (pc & ~0x3, TARGET_PTR_BIT / 8);
|
|
||||||
}
|
|
||||||
else if (pc == sr4export)
|
|
||||||
pc = (CORE_ADDR) (read_register (22));
|
|
||||||
|
|
||||||
/* Get the unwind descriptor corresponding to PC, return zero
|
|
||||||
if no unwind was found. */
|
|
||||||
u = find_unwind_entry (pc);
|
|
||||||
if (!u)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* If this isn't a linker stub, then return now. */
|
|
||||||
/* elz: attention here! (FIXME) because of a compiler/linker
|
|
||||||
error, some stubs which should have a non zero stub_unwind.stub_type
|
|
||||||
have unfortunately a value of zero. So this function would return here
|
|
||||||
as if we were not in a trampoline. To fix this, we go look at the partial
|
|
||||||
symbol information, which reports this guy as a stub.
|
|
||||||
(FIXME): Unfortunately, we are not that lucky: it turns out that the
|
|
||||||
partial symbol information is also wrong sometimes. This is because
|
|
||||||
when it is entered (somread.c::som_symtab_read()) it can happen that
|
|
||||||
if the type of the symbol (from the som) is Entry, and the symbol is
|
|
||||||
in a shared library, then it can also be a trampoline. This would
|
|
||||||
be OK, except that I believe the way they decide if we are ina shared library
|
|
||||||
does not work. SOOOO..., even if we have a regular function w/o trampolines
|
|
||||||
its minimal symbol can be assigned type mst_solib_trampoline.
|
|
||||||
Also, if we find that the symbol is a real stub, then we fix the unwind
|
|
||||||
descriptor, and define the stub type to be EXPORT.
|
|
||||||
Hopefully this is correct most of the times. */
|
|
||||||
if (u->stub_unwind.stub_type == 0)
|
|
||||||
{
|
|
||||||
|
|
||||||
/* elz: NOTE (FIXME!) once the problem with the unwind information is fixed
|
|
||||||
we can delete all the code which appears between the lines */
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
msym = lookup_minimal_symbol_by_pc (pc);
|
|
||||||
|
|
||||||
if (msym == NULL || MSYMBOL_TYPE (msym) != mst_solib_trampoline)
|
|
||||||
return orig_pc == pc ? 0 : pc & ~0x3;
|
|
||||||
|
|
||||||
else if (msym != NULL && MSYMBOL_TYPE (msym) == mst_solib_trampoline)
|
|
||||||
{
|
|
||||||
struct objfile *objfile;
|
|
||||||
struct minimal_symbol *msymbol;
|
|
||||||
int function_found = 0;
|
|
||||||
|
|
||||||
/* go look if there is another minimal symbol with the same name as
|
|
||||||
this one, but with type mst_text. This would happen if the msym
|
|
||||||
is an actual trampoline, in which case there would be another
|
|
||||||
symbol with the same name corresponding to the real function */
|
|
||||||
|
|
||||||
ALL_MSYMBOLS (objfile, msymbol)
|
|
||||||
{
|
|
||||||
if (MSYMBOL_TYPE (msymbol) == mst_text
|
|
||||||
&& DEPRECATED_STREQ (DEPRECATED_SYMBOL_NAME (msymbol), DEPRECATED_SYMBOL_NAME (msym)))
|
|
||||||
{
|
|
||||||
function_found = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (function_found)
|
|
||||||
/* the type of msym is correct (mst_solib_trampoline), but
|
|
||||||
the unwind info is wrong, so set it to the correct value */
|
|
||||||
u->stub_unwind.stub_type = EXPORT;
|
|
||||||
else
|
|
||||||
/* the stub type info in the unwind is correct (this is not a
|
|
||||||
trampoline), but the msym type information is wrong, it
|
|
||||||
should be mst_text. So we need to fix the msym, and also
|
|
||||||
get out of this function */
|
|
||||||
{
|
|
||||||
MSYMBOL_TYPE (msym) = mst_text;
|
|
||||||
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) == 0x20200000)
|
|
||||||
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 a be 0(sr0,%r21)? OR
|
|
||||||
Does it look like a be, n 0(sr0,%r21)? OR
|
|
||||||
Does it look like a bve (r21)? (this is on PA2.0)
|
|
||||||
Does it look like a bve, n(r21)? (this is also on PA2.0)
|
|
||||||
That's the branch from an
|
|
||||||
import stub to an export stub.
|
|
||||||
|
|
||||||
It is impossible to determine the target of the branch via
|
|
||||||
simple examination of instructions and/or data (consider
|
|
||||||
that the address in the plabel may be the address of the
|
|
||||||
bind-on-reference routine in the dynamic loader).
|
|
||||||
|
|
||||||
So we have try an alternative approach.
|
|
||||||
|
|
||||||
Get the name of the symbol at our current location; it should
|
|
||||||
be a stub symbol with the same name as the symbol in the
|
|
||||||
shared library.
|
|
||||||
|
|
||||||
Then lookup a minimal symbol with the same name; we should
|
|
||||||
get the minimal symbol for the target routine in the shared
|
|
||||||
library as those take precedence of import/export stubs. */
|
|
||||||
if ((curr_inst == 0xe2a00000) ||
|
|
||||||
(curr_inst == 0xe2a00002) ||
|
|
||||||
(curr_inst == 0xeaa0d000) ||
|
|
||||||
(curr_inst == 0xeaa0d002))
|
|
||||||
{
|
|
||||||
struct minimal_symbol *stubsym, *libsym;
|
|
||||||
|
|
||||||
stubsym = lookup_minimal_symbol_by_pc (loc);
|
|
||||||
if (stubsym == NULL)
|
|
||||||
{
|
|
||||||
warning ("Unable to find symbol for 0x%lx", loc);
|
|
||||||
return orig_pc == pc ? 0 : pc & ~0x3;
|
|
||||||
}
|
|
||||||
|
|
||||||
libsym = lookup_minimal_symbol (DEPRECATED_SYMBOL_NAME (stubsym), NULL, NULL);
|
|
||||||
if (libsym == NULL)
|
|
||||||
{
|
|
||||||
warning ("Unable to find library symbol for %s\n",
|
|
||||||
DEPRECATED_SYMBOL_NAME (stubsym));
|
|
||||||
return orig_pc == pc ? 0 : pc & ~0x3;
|
|
||||||
}
|
|
||||||
|
|
||||||
return SYMBOL_VALUE (libsym);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Does it look like bl X,%rp or bl X,%r0? Another way to do a
|
|
||||||
branch from the stub to the actual function. */
|
|
||||||
/*elz */
|
|
||||||
else if ((curr_inst & 0xffe0e000) == 0xe8400000
|
|
||||||
|| (curr_inst & 0xffe0e000) == 0xe8000000
|
|
||||||
|| (curr_inst & 0xffe0e000) == 0xe800A000)
|
|
||||||
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) */
|
|
||||||
else if ((curr_inst & 0xffe0f000) == 0xe840c000)
|
|
||||||
{
|
|
||||||
/* Yup. See if the previous instruction loaded
|
|
||||||
rp from sp - 8. */
|
|
||||||
if (prev_inst == 0x4bc23ff1)
|
|
||||||
return (read_memory_integer
|
|
||||||
(read_register (HPPA_SP_REGNUM) - 8, 4)) & ~0x3;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
warning ("Unable to find restore of %%rp before bv (%%rp).");
|
|
||||||
return orig_pc == pc ? 0 : pc & ~0x3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* elz: added this case to capture the new instruction
|
|
||||||
at the end of the return part of an export stub used by
|
|
||||||
the PA2.0: BVE, n (rp) */
|
|
||||||
else if ((curr_inst & 0xffe0f000) == 0xe840d000)
|
|
||||||
{
|
|
||||||
return (read_memory_integer
|
|
||||||
(read_register (HPPA_SP_REGNUM) - 24, TARGET_PTR_BIT / 8)) & ~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 (HPPA_SP_REGNUM) - 24, TARGET_PTR_BIT / 8)) & ~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
|
/* For the given instruction (INST), return any adjustment it makes
|
||||||
to the stack pointer or zero for no adjustment.
|
to the stack pointer or zero for no adjustment.
|
||||||
|
|
||||||
@ -1621,11 +1092,11 @@ prologue_inst_adjust_sp (unsigned long inst)
|
|||||||
|
|
||||||
/* The most common way to perform a stack adjustment ldo X(sp),sp */
|
/* The most common way to perform a stack adjustment ldo X(sp),sp */
|
||||||
if ((inst & 0xffffc000) == 0x37de0000)
|
if ((inst & 0xffffc000) == 0x37de0000)
|
||||||
return extract_14 (inst);
|
return hppa_extract_14 (inst);
|
||||||
|
|
||||||
/* stwm X,D(sp) */
|
/* stwm X,D(sp) */
|
||||||
if ((inst & 0xffe00000) == 0x6fc00000)
|
if ((inst & 0xffe00000) == 0x6fc00000)
|
||||||
return extract_14 (inst);
|
return hppa_extract_14 (inst);
|
||||||
|
|
||||||
/* std,ma X,D(sp) */
|
/* std,ma X,D(sp) */
|
||||||
if ((inst & 0xffe00008) == 0x73c00008)
|
if ((inst & 0xffe00008) == 0x73c00008)
|
||||||
@ -1635,16 +1106,16 @@ prologue_inst_adjust_sp (unsigned long inst)
|
|||||||
save high bits in save_high21 for later use. */
|
save high bits in save_high21 for later use. */
|
||||||
if ((inst & 0xffe00000) == 0x28200000)
|
if ((inst & 0xffe00000) == 0x28200000)
|
||||||
{
|
{
|
||||||
save_high21 = extract_21 (inst);
|
save_high21 = hppa_extract_21 (inst);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((inst & 0xffff0000) == 0x343e0000)
|
if ((inst & 0xffff0000) == 0x343e0000)
|
||||||
return save_high21 + extract_14 (inst);
|
return save_high21 + hppa_extract_14 (inst);
|
||||||
|
|
||||||
/* fstws as used by the HP compilers. */
|
/* fstws as used by the HP compilers. */
|
||||||
if ((inst & 0xffffffe0) == 0x2fd01220)
|
if ((inst & 0xffffffe0) == 0x2fd01220)
|
||||||
return extract_5_load (inst);
|
return hppa_extract_5_load (inst);
|
||||||
|
|
||||||
/* No adjustment. */
|
/* No adjustment. */
|
||||||
return 0;
|
return 0;
|
||||||
@ -1693,17 +1164,17 @@ inst_saves_gr (unsigned long inst)
|
|||||||
|| (inst >> 26) == 0x1f
|
|| (inst >> 26) == 0x1f
|
||||||
|| ((inst >> 26) == 0x1f
|
|| ((inst >> 26) == 0x1f
|
||||||
&& ((inst >> 6) == 0xa)))
|
&& ((inst >> 6) == 0xa)))
|
||||||
return extract_5R_store (inst);
|
return hppa_extract_5R_store (inst);
|
||||||
|
|
||||||
/* Does it look like a std? */
|
/* Does it look like a std? */
|
||||||
if ((inst >> 26) == 0x1c
|
if ((inst >> 26) == 0x1c
|
||||||
|| ((inst >> 26) == 0x03
|
|| ((inst >> 26) == 0x03
|
||||||
&& ((inst >> 6) & 0xf) == 0xb))
|
&& ((inst >> 6) & 0xf) == 0xb))
|
||||||
return extract_5R_store (inst);
|
return hppa_extract_5R_store (inst);
|
||||||
|
|
||||||
/* Does it look like a stwm? GCC & HPC may use this in prologues. */
|
/* Does it look like a stwm? GCC & HPC may use this in prologues. */
|
||||||
if ((inst >> 26) == 0x1b)
|
if ((inst >> 26) == 0x1b)
|
||||||
return extract_5R_store (inst);
|
return hppa_extract_5R_store (inst);
|
||||||
|
|
||||||
/* Does it look like sth or stb? HPC versions 9.0 and later use these
|
/* Does it look like sth or stb? HPC versions 9.0 and later use these
|
||||||
too. */
|
too. */
|
||||||
@ -1711,7 +1182,7 @@ inst_saves_gr (unsigned long inst)
|
|||||||
|| ((inst >> 26) == 0x3
|
|| ((inst >> 26) == 0x3
|
||||||
&& (((inst >> 6) & 0xf) == 0x8
|
&& (((inst >> 6) & 0xf) == 0x8
|
||||||
|| (inst >> 6) & 0xf) == 0x9))
|
|| (inst >> 6) & 0xf) == 0x9))
|
||||||
return extract_5R_store (inst);
|
return hppa_extract_5R_store (inst);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1729,14 +1200,14 @@ inst_saves_fr (unsigned long inst)
|
|||||||
{
|
{
|
||||||
/* is this an FSTD ? */
|
/* is this an FSTD ? */
|
||||||
if ((inst & 0xfc00dfc0) == 0x2c001200)
|
if ((inst & 0xfc00dfc0) == 0x2c001200)
|
||||||
return extract_5r_store (inst);
|
return hppa_extract_5r_store (inst);
|
||||||
if ((inst & 0xfc000002) == 0x70000002)
|
if ((inst & 0xfc000002) == 0x70000002)
|
||||||
return extract_5R_store (inst);
|
return hppa_extract_5R_store (inst);
|
||||||
/* is this an FSTW ? */
|
/* is this an FSTW ? */
|
||||||
if ((inst & 0xfc00df80) == 0x24001200)
|
if ((inst & 0xfc00df80) == 0x24001200)
|
||||||
return extract_5r_store (inst);
|
return hppa_extract_5r_store (inst);
|
||||||
if ((inst & 0xfc000002) == 0x7c000000)
|
if ((inst & 0xfc000002) == 0x7c000000)
|
||||||
return extract_5R_store (inst);
|
return hppa_extract_5R_store (inst);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2172,7 +1643,7 @@ hppa_frame_cache (struct frame_info *next_frame, void **this_cache)
|
|||||||
&& (!u->Save_SP || reg != HPPA_FP_REGNUM))
|
&& (!u->Save_SP || reg != HPPA_FP_REGNUM))
|
||||||
{
|
{
|
||||||
saved_gr_mask &= ~(1 << reg);
|
saved_gr_mask &= ~(1 << reg);
|
||||||
if ((inst >> 26) == 0x1b && extract_14 (inst) >= 0)
|
if ((inst >> 26) == 0x1b && hppa_extract_14 (inst) >= 0)
|
||||||
/* stwm with a positive displacement is a _post_
|
/* stwm with a positive displacement is a _post_
|
||||||
_modify_. */
|
_modify_. */
|
||||||
cache->saved_regs[reg].addr = 0;
|
cache->saved_regs[reg].addr = 0;
|
||||||
@ -2186,9 +1657,9 @@ hppa_frame_cache (struct frame_info *next_frame, void **this_cache)
|
|||||||
if ((inst >> 26) == 0x1c)
|
if ((inst >> 26) == 0x1c)
|
||||||
offset = (inst & 0x1 ? -1 << 13 : 0) | (((inst >> 4) & 0x3ff) << 3);
|
offset = (inst & 0x1 ? -1 << 13 : 0) | (((inst >> 4) & 0x3ff) << 3);
|
||||||
else if ((inst >> 26) == 0x03)
|
else if ((inst >> 26) == 0x03)
|
||||||
offset = low_sign_extend (inst & 0x1f, 5);
|
offset = hppa_low_hppa_sign_extend (inst & 0x1f, 5);
|
||||||
else
|
else
|
||||||
offset = extract_14 (inst);
|
offset = hppa_extract_14 (inst);
|
||||||
|
|
||||||
/* Handle code with and without frame pointers. */
|
/* Handle code with and without frame pointers. */
|
||||||
if (u->Save_SP)
|
if (u->Save_SP)
|
||||||
@ -2210,7 +1681,7 @@ hppa_frame_cache (struct frame_info *next_frame, void **this_cache)
|
|||||||
/* ldo X(%r3),%r1 or ldo X(%r30),%r1. */
|
/* ldo X(%r3),%r1 or ldo X(%r30),%r1. */
|
||||||
if ((inst & 0xffffc000) == 0x34610000
|
if ((inst & 0xffffc000) == 0x34610000
|
||||||
|| (inst & 0xffffc000) == 0x37c10000)
|
|| (inst & 0xffffc000) == 0x37c10000)
|
||||||
fp_loc = extract_14 (inst);
|
fp_loc = hppa_extract_14 (inst);
|
||||||
|
|
||||||
reg = inst_saves_fr (inst);
|
reg = inst_saves_fr (inst);
|
||||||
if (reg >= 12 && reg <= 21)
|
if (reg >= 12 && reg <= 21)
|
||||||
@ -2690,10 +2161,6 @@ hppa_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
|
|||||||
/* The following gdbarch vector elements do not depend on the address
|
/* The following gdbarch vector elements do not depend on the address
|
||||||
size, or in any other gdbarch element previously set. */
|
size, or in any other gdbarch element previously set. */
|
||||||
set_gdbarch_skip_prologue (gdbarch, hppa_skip_prologue);
|
set_gdbarch_skip_prologue (gdbarch, hppa_skip_prologue);
|
||||||
set_gdbarch_skip_trampoline_code (gdbarch, hppa_skip_trampoline_code);
|
|
||||||
set_gdbarch_in_solib_call_trampoline (gdbarch, hppa_in_solib_call_trampoline);
|
|
||||||
set_gdbarch_in_solib_return_trampoline (gdbarch,
|
|
||||||
hppa_in_solib_return_trampoline);
|
|
||||||
set_gdbarch_inner_than (gdbarch, core_addr_greaterthan);
|
set_gdbarch_inner_than (gdbarch, core_addr_greaterthan);
|
||||||
set_gdbarch_sp_regnum (gdbarch, HPPA_SP_REGNUM);
|
set_gdbarch_sp_regnum (gdbarch, HPPA_SP_REGNUM);
|
||||||
set_gdbarch_fp0_regnum (gdbarch, HPPA_FP0_REGNUM);
|
set_gdbarch_fp0_regnum (gdbarch, HPPA_FP0_REGNUM);
|
||||||
|
@ -104,6 +104,8 @@ enum unwind_stub_types
|
|||||||
IMPORT_SHLIB = 12,
|
IMPORT_SHLIB = 12,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct unwind_table_entry *find_unwind_entry (CORE_ADDR);
|
||||||
|
|
||||||
/* We use the objfile->obj_private pointer for two things:
|
/* We use the objfile->obj_private pointer for two things:
|
||||||
* 1. An unwind table;
|
* 1. An unwind table;
|
||||||
*
|
*
|
||||||
@ -134,4 +136,14 @@ struct hppa_objfile_private
|
|||||||
|
|
||||||
extern const struct objfile_data *hppa_objfile_priv_data;
|
extern const struct objfile_data *hppa_objfile_priv_data;
|
||||||
|
|
||||||
|
int hppa_get_field (unsigned word, int from, int to);
|
||||||
|
int hppa_extract_5_load (unsigned int);
|
||||||
|
unsigned hppa_extract_5R_store (unsigned int);
|
||||||
|
unsigned hppa_extract_5r_store (unsigned int);
|
||||||
|
int hppa_extract_17 (unsigned int);
|
||||||
|
int hppa_extract_21 (unsigned);
|
||||||
|
int hppa_extract_14 (unsigned);
|
||||||
|
int hppa_low_sign_extend (unsigned int, unsigned int);
|
||||||
|
int hppa_sign_extend (unsigned int, unsigned int);
|
||||||
|
|
||||||
#endif /* HPPA_TDEP_H */
|
#endif /* HPPA_TDEP_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user