#include "osabi.h"
#include "gdb_string.h"
#include "frame.h"
+#include "frame-unwind.h"
+#include "trad-frame.h"
#include "symtab.h"
#include "objfiles.h"
#include "inferior.h"
#include "infcall.h"
+#include "hppa-tdep.h"
#include <dl.h>
#include <machine/save_state.h>
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
+#endif
+
/* Forward declarations. */
extern void _initialize_hppa_hpux_tdep (void);
extern initialize_file_ftype _initialize_hppa_hpux_tdep;
}
args_for_find_stub;
-/* FIXME: brobecker 2002-12-25. The following functions will eventually
- become static, after the multiarching conversion is done. */
-int hppa_hpux_pc_in_sigtramp (CORE_ADDR pc, char *name);
-void hppa32_hpux_frame_saved_pc_in_sigtramp (struct frame_info *fi,
- CORE_ADDR *tmp);
-void hppa32_hpux_frame_base_before_sigtramp (struct frame_info *fi,
- CORE_ADDR *tmp);
-void hppa32_hpux_frame_find_saved_regs_in_sigtramp (struct frame_info *fi,
- CORE_ADDR *fsr);
-void hppa64_hpux_frame_saved_pc_in_sigtramp (struct frame_info *fi,
- CORE_ADDR *tmp);
-void hppa64_hpux_frame_base_before_sigtramp (struct frame_info *fi,
- CORE_ADDR *tmp);
-void hppa64_hpux_frame_find_saved_regs_in_sigtramp (struct frame_info *fi,
- CORE_ADDR *fsr);
+/* Return one if PC is in the call path of a trampoline, else return zero.
-int
-hppa_hpux_pc_in_sigtramp (CORE_ADDR pc, char *name)
+ 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)
{
- /* Actually, for a PA running HPUX the kernel calls the signal handler
- without an intermediate trampoline. Luckily the kernel always sets
- the return pointer for the signal handler to point to _sigreturn. */
- return (name && (strcmp ("_sigreturn", name) == 0));
-}
+ struct minimal_symbol *minsym;
+ struct unwind_table_entry *u;
+ static CORE_ADDR dyncall = 0;
+ static CORE_ADDR sr4export = 0;
-/* For hppa32_hpux_frame_saved_pc_in_sigtramp,
- hppa32_hpux_frame_base_before_sigtramp and
- hppa32_hpux_frame_find_saved_regs_in_sigtramp:
+ /* FIXME XXX - dyncall and sr4export must be initialized whenever we get a
+ new exec file */
- The signal context structure pointer is always saved at the base
- of the frame which "calls" the signal handler. We only want to find
- the hardware save state structure, which lives 10 32bit words into
- sigcontext structure.
+ /* 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;
+ }
- Within the hardware save state structure, registers are found in the
- same order as the register numbers in GDB.
+ if (!sr4export)
+ {
+ minsym = lookup_minimal_symbol ("_sr4export", NULL, NULL);
+ if (minsym)
+ sr4export = SYMBOL_VALUE_ADDRESS (minsym);
+ else
+ sr4export = -1;
+ }
- At one time we peeked at %r31 rather than the PC queues to determine
- what instruction took the fault. This was done on purpose, but I don't
- remember why. Looking at the PC queues is really the right way, and
- I don't remember why that didn't work when this code was originally
- written. */
+ if (pc == dyncall || pc == sr4export)
+ return 1;
-void
-hppa32_hpux_frame_saved_pc_in_sigtramp (struct frame_info *fi, CORE_ADDR *tmp)
-{
- *tmp = read_memory_integer (get_frame_base (fi) + (43 * 4), 4);
+ 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;
}
-void
-hppa32_hpux_frame_base_before_sigtramp (struct frame_info *fi,
- CORE_ADDR *tmp)
+static int
+hppa64_hpux_in_solib_call_trampoline (CORE_ADDR pc, char *name)
{
- *tmp = read_memory_integer (get_frame_base (fi) + (40 * 4), 4);
+ /* 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;
}
-void
-hppa32_hpux_frame_find_saved_regs_in_sigtramp (struct frame_info *fi,
- CORE_ADDR *fsr)
+/* 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)
{
- int i;
- const CORE_ADDR tmp = get_frame_base (fi) + (10 * 4);
+ struct unwind_table_entry *u;
- for (i = 0; i < NUM_REGS; i++)
+ /* 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)
{
- if (i == SP_REGNUM)
- fsr[SP_REGNUM] = read_memory_integer (tmp + SP_REGNUM * 4, 4);
- else
- fsr[i] = tmp + i * 4;
+ 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;
+
}
-/* For hppa64_hpux_frame_saved_pc_in_sigtramp,
- hppa64_hpux_frame_base_before_sigtramp and
- hppa64_hpux_frame_find_saved_regs_in_sigtramp:
+/* 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.
- These functions are the PA64 ABI equivalents of the 32bits counterparts
- above. See the comments there.
+ Simple code examination probably is not a good idea since the code
+ sequences in trampolines can also appear in user code.
- For PA64, the save_state structure is at an offset of 24 32-bit words
- from the sigcontext structure. The 64 bit general registers are at an
- offset of 640 bytes from the beginning of the save_state structure,
- and the floating pointer register are at an offset of 256 bytes from
- the beginning of the save_state structure. */
+ 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.
-void
-hppa64_hpux_frame_saved_pc_in_sigtramp (struct frame_info *fi, CORE_ADDR *tmp)
-{
- *tmp = read_memory_integer
- (get_frame_base (fi) + (24 * 4) + 640 + (33 * 8), 8);
-}
+ 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. */
-void
-hppa64_hpux_frame_base_before_sigtramp (struct frame_info *fi,
- CORE_ADDR *tmp)
+static CORE_ADDR
+hppa_hpux_skip_trampoline_code (CORE_ADDR pc)
{
- *tmp = read_memory_integer
- (get_frame_base (fi) + (24 * 4) + 640 + (30 * 8), 8);
-}
+ 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;
+ }
-void
-hppa64_hpux_frame_find_saved_regs_in_sigtramp (struct frame_info *fi,
- CORE_ADDR *fsr)
-{
- int i;
- const CORE_ADDR tmp1 = get_frame_base (fi) + (24 * 4) + 640;
- const CORE_ADDR tmp2 = get_frame_base (fi) + (24 * 4) + 256;
+ if (!dyncall_external)
+ {
+ msym = lookup_minimal_symbol ("$$dyncall_external", NULL, NULL);
+ if (msym)
+ dyncall_external = SYMBOL_VALUE_ADDRESS (msym);
+ else
+ dyncall_external = -1;
+ }
- for (i = 0; i < NUM_REGS; i++)
+ if (!sr4export)
{
- if (i == SP_REGNUM)
- fsr[SP_REGNUM] = read_memory_integer (tmp1 + SP_REGNUM * 8, 8);
- else if (i >= FP0_REGNUM)
- fsr[i] = tmp2 + (i - FP0_REGNUM) * 8;
+ msym = lookup_minimal_symbol ("_sr4export", NULL, NULL);
+ if (msym)
+ sr4export = SYMBOL_VALUE_ADDRESS (msym);
else
- fsr[i] = tmp1 + i * 8;
+ 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.
The compiler (aCC) provides a callback for exception events;
GDB can set a breakpoint on this callback and find out what
1. event kind catch or throw
2. the target address if known
3. a flag -- not sure what this is. pai/1997-07-17 */
- event_kind = read_register (ARG0_REGNUM);
- catch_addr = read_register (ARG1_REGNUM);
+ event_kind = read_register (HPPA_ARG0_REGNUM);
+ catch_addr = read_register (HPPA_ARG1_REGNUM);
/* Now go down to a user frame */
/* For a throw, __d_eh_break is called by
return ¤t_ex_event;
}
+/* Signal frames. */
+struct hppa_hpux_sigtramp_unwind_cache
+{
+ CORE_ADDR base;
+ struct trad_frame_saved_reg *saved_regs;
+};
+
+static int hppa_hpux_tramp_reg[] = {
+ HPPA_SAR_REGNUM,
+ HPPA_PCOQ_HEAD_REGNUM,
+ HPPA_PCSQ_HEAD_REGNUM,
+ HPPA_PCOQ_TAIL_REGNUM,
+ HPPA_PCSQ_TAIL_REGNUM,
+ HPPA_EIEM_REGNUM,
+ HPPA_IIR_REGNUM,
+ HPPA_ISR_REGNUM,
+ HPPA_IOR_REGNUM,
+ HPPA_IPSW_REGNUM,
+ -1,
+ HPPA_SR4_REGNUM,
+ HPPA_SR4_REGNUM + 1,
+ HPPA_SR4_REGNUM + 2,
+ HPPA_SR4_REGNUM + 3,
+ HPPA_SR4_REGNUM + 4,
+ HPPA_SR4_REGNUM + 5,
+ HPPA_SR4_REGNUM + 6,
+ HPPA_SR4_REGNUM + 7,
+ HPPA_RCR_REGNUM,
+ HPPA_PID0_REGNUM,
+ HPPA_PID1_REGNUM,
+ HPPA_CCR_REGNUM,
+ HPPA_PID2_REGNUM,
+ HPPA_PID3_REGNUM,
+ HPPA_TR0_REGNUM,
+ HPPA_TR0_REGNUM + 1,
+ HPPA_TR0_REGNUM + 2,
+ HPPA_CR27_REGNUM
+};
+
+static struct hppa_hpux_sigtramp_unwind_cache *
+hppa_hpux_sigtramp_frame_unwind_cache (struct frame_info *next_frame,
+ void **this_cache)
+
+{
+ struct gdbarch *gdbarch = get_frame_arch (next_frame);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ struct hppa_hpux_sigtramp_unwind_cache *info;
+ unsigned int flag;
+ CORE_ADDR sp, scptr;
+ int i, incr, off, szoff;
+
+ if (*this_cache)
+ return *this_cache;
+
+ info = FRAME_OBSTACK_ZALLOC (struct hppa_hpux_sigtramp_unwind_cache);
+ *this_cache = info;
+ info->saved_regs = trad_frame_alloc_saved_regs (next_frame);
+
+ sp = frame_unwind_register_unsigned (next_frame, HPPA_SP_REGNUM);
+
+ scptr = sp - 1352;
+ off = scptr;
+
+ /* See /usr/include/machine/save_state.h for the structure of the save_state_t
+ structure. */
+
+ flag = read_memory_unsigned_integer(scptr, 4);
+
+ if (!(flag & 0x40))
+ {
+ /* Narrow registers. */
+ off = scptr + offsetof (save_state_t, ss_narrow);
+ incr = 4;
+ szoff = 0;
+ }
+ else
+ {
+ /* Wide registers. */
+ off = scptr + offsetof (save_state_t, ss_wide) + 8;
+ incr = 8;
+ szoff = (tdep->bytes_per_address == 4 ? 4 : 0);
+ }
+
+ for (i = 1; i < 32; i++)
+ {
+ info->saved_regs[HPPA_R0_REGNUM + i].addr = off + szoff;
+ off += incr;
+ }
+
+ for (i = 0;
+ i < sizeof(hppa_hpux_tramp_reg) / sizeof(hppa_hpux_tramp_reg[0]);
+ i++)
+ {
+ if (hppa_hpux_tramp_reg[i] > 0)
+ info->saved_regs[hppa_hpux_tramp_reg[i]].addr = off + szoff;
+ off += incr;
+ }
+
+ /* TODO: fp regs */
+
+ info->base = frame_unwind_register_unsigned (next_frame, HPPA_SP_REGNUM);
+
+ return info;
+}
+
+static void
+hppa_hpux_sigtramp_frame_this_id (struct frame_info *next_frame,
+ void **this_prologue_cache,
+ struct frame_id *this_id)
+{
+ struct hppa_hpux_sigtramp_unwind_cache *info
+ = hppa_hpux_sigtramp_frame_unwind_cache (next_frame, this_prologue_cache);
+ *this_id = frame_id_build (info->base, frame_pc_unwind (next_frame));
+}
+
+static void
+hppa_hpux_sigtramp_frame_prev_register (struct frame_info *next_frame,
+ void **this_prologue_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp,
+ CORE_ADDR *addrp,
+ int *realnump, void *valuep)
+{
+ struct hppa_hpux_sigtramp_unwind_cache *info
+ = hppa_hpux_sigtramp_frame_unwind_cache (next_frame, this_prologue_cache);
+ hppa_frame_prev_register_helper (next_frame, info->saved_regs, regnum,
+ optimizedp, lvalp, addrp, realnump, valuep);
+}
+
+static const struct frame_unwind hppa_hpux_sigtramp_frame_unwind = {
+ SIGTRAMP_FRAME,
+ hppa_hpux_sigtramp_frame_this_id,
+ hppa_hpux_sigtramp_frame_prev_register
+};
+
+static const struct frame_unwind *
+hppa_hpux_sigtramp_unwind_sniffer (struct frame_info *next_frame)
+{
+ CORE_ADDR pc = frame_pc_unwind (next_frame);
+ char *name;
+
+ find_pc_partial_function (pc, &name, NULL, NULL);
+
+ if (name && strcmp(name, "_sigreturn") == 0)
+ return &hppa_hpux_sigtramp_frame_unwind;
+
+ return NULL;
+}
+
static void
hppa_hpux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
- set_gdbarch_deprecated_pc_in_sigtramp (gdbarch, hppa_hpux_pc_in_sigtramp);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ 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);
+
+ frame_unwind_append_sniffer (gdbarch, hppa_hpux_sigtramp_unwind_sniffer);
}
static void
hppa_hpux_som_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ tdep->is_elf = 0;
hppa_hpux_init_abi (info, gdbarch);
}
static void
hppa_hpux_elf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ tdep->is_elf = 1;
hppa_hpux_init_abi (info, gdbarch);
}