2004-12-17 Randolph Chung <tausq@debian.org>

* hppa-hpux-tdep.c (IS_32BIT_TARGET): New.
	(in_opd_section): New.
	(hppa32_hpux_find_global_pointer): Rename from
	hppa_hpux_som_find_global_pointer.
	(hppa64_hpux_find_global_pointer): New.
	(ldsid_pattern): New.
	(hppa_hpux_search_pattern): New.
	(hppa32_hpux_search_dummy_call_sequence): New.
	(hppa64_hpux_search_dummy_call_sequence): New.
	(hppa_hpux_find_import_stub_for_addr): New.
	(hppa_hpux_sr_for_addr): New.
	(hppa_hpux_find_dummy_bpaddr): New.
	(hppa_hpux_init_abi): Use IS_32BIT_TARGET predicate.
	(hppa_hpux_som_init_abi): Set find_global_pointer method to
	hppa32_hpux_find_global_pointer instead of
	hppa_hpux_som_find_global_pointer.
	(hppa_hpux_elf_init_abi): Set find_global_pointer method.
	* hppa-tdep.c (hppa_init_objfile_priv_data): New.
	(read_unwind_info): Use function to initialize objfile-private data.
	(hppa32_push_dummy_call): Don't automatically set the RP if there is
	a push_dummy_code method.
	(hppa64_push_dummy_call): Retrieve and set the global pointer.
	Don't automatically set the RP if there is a push_dummy_code method.
	* hppa-tdep.h (hppa_objfile_private): Add dummy_call_sequence_reg and
	dummy_call_sequence_addr members.
	(hppa_init_objfile_priv_data): New prototype.
This commit is contained in:
Randolph Chung 2004-12-17 19:09:53 +00:00
parent e3070fef41
commit 77d18ded6e
4 changed files with 531 additions and 143 deletions

View file

@ -1,3 +1,32 @@
2004-12-17 Randolph Chung <tausq@debian.org>
* hppa-hpux-tdep.c (IS_32BIT_TARGET): New.
(in_opd_section): New.
(hppa32_hpux_find_global_pointer): Rename from
hppa_hpux_som_find_global_pointer.
(hppa64_hpux_find_global_pointer): New.
(ldsid_pattern): New.
(hppa_hpux_search_pattern): New.
(hppa32_hpux_search_dummy_call_sequence): New.
(hppa64_hpux_search_dummy_call_sequence): New.
(hppa_hpux_find_import_stub_for_addr): New.
(hppa_hpux_sr_for_addr): New.
(hppa_hpux_find_dummy_bpaddr): New.
(hppa_hpux_init_abi): Use IS_32BIT_TARGET predicate.
(hppa_hpux_som_init_abi): Set find_global_pointer method to
hppa32_hpux_find_global_pointer instead of
hppa_hpux_som_find_global_pointer.
(hppa_hpux_elf_init_abi): Set find_global_pointer method.
* hppa-tdep.c (hppa_init_objfile_priv_data): New.
(read_unwind_info): Use function to initialize objfile-private data.
(hppa32_push_dummy_call): Don't automatically set the RP if there is
a push_dummy_code method.
(hppa64_push_dummy_call): Retrieve and set the global pointer.
Don't automatically set the RP if there is a push_dummy_code method.
* hppa-tdep.h (hppa_objfile_private): Add dummy_call_sequence_reg and
dummy_call_sequence_addr members.
(hppa_init_objfile_priv_data): New prototype.
2004-12-17 Joel Brobecker <brobecker@gnat.com>
* hppa-tdep.c (hppa_lookup_stub_minimal_symbol): New function.

View file

@ -45,6 +45,9 @@
#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
#endif
#define IS_32BIT_TARGET(_gdbarch) \
((gdbarch_tdep (_gdbarch))->bytes_per_address == 4)
/* Forward declarations. */
extern void _initialize_hppa_hpux_tdep (void);
extern initialize_file_ftype _initialize_hppa_hpux_tdep;
@ -57,6 +60,20 @@ typedef struct
}
args_for_find_stub;
static int
in_opd_section (CORE_ADDR pc)
{
struct obj_section *s;
int retval = 0;
s = find_pc_section (pc);
retval = (s != NULL
&& s->the_bfd_section->name != NULL
&& strcmp (s->the_bfd_section->name, ".opd") == 0);
return (retval);
}
/* 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
@ -1229,7 +1246,7 @@ hppa_hpux_sigtramp_unwind_sniffer (struct frame_info *next_frame)
}
static CORE_ADDR
hppa_hpux_som_find_global_pointer (struct value *function)
hppa32_hpux_find_global_pointer (struct value *function)
{
CORE_ADDR faddr;
@ -1252,84 +1269,244 @@ hppa_hpux_som_find_global_pointer (struct value *function)
}
static CORE_ADDR
hppa_hpux_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp,
CORE_ADDR funcaddr, int using_gcc,
struct value **args, int nargs,
struct type *value_type,
CORE_ADDR *real_pc, CORE_ADDR *bp_addr)
hppa64_hpux_find_global_pointer (struct value *function)
{
/* FIXME: tausq/2004-06-09: This needs much more testing. It is broken
for pa64, but we should be able to get it to work with a little bit
of work. gdb-6.1 has a lot of code to handle various cases; I've tried to
simplify it and avoid compile-time conditionals. */
CORE_ADDR faddr;
char buf[32];
/* On HPUX, functions in the main executable and in libraries can be located
in different spaces. In order for us to be able to select the right
space for the function call, we need to go through an instruction seqeunce
to select the right space for the target function, call it, and then
restore the space on return.
faddr = value_as_address (function);
There are two helper routines that can be used for this task -- if
an application is linked with gcc, it will contain a __gcc_plt_call
helper function. __gcc_plt_call, when passed the entry point of an
import stub, will do the necessary space setting/restoration for the
target function.
if (in_opd_section (faddr))
{
target_read_memory (faddr, buf, sizeof (buf));
return extract_unsigned_integer (&buf[24], 8);
}
else
{
return gdbarch_tdep (current_gdbarch)->solib_get_got_by_pc (faddr);
}
}
For programs that are compiled/linked with the HP compiler, a similar
function called __d_plt_call exists; __d_plt_call expects a PLABEL instead
of an import stub as an argument.
static unsigned int ldsid_pattern[] = {
0x000010a0, /* ldsid (rX),rY */
0x00001820, /* mtsp rY,sr0 */
0xe0000000 /* be,n (sr0,rX) */
};
// *INDENT-OFF*
To summarize, the call flow is:
current function -> dummy frame -> __gcc_plt_call (import stub)
-> target function
or
current function -> dummy frame -> __d_plt_call (plabel)
-> target function
// *INDENT-ON*
static CORE_ADDR
hppa_hpux_search_pattern (CORE_ADDR start, CORE_ADDR end,
unsigned int *patterns, int count)
{
unsigned int *buf;
int offset, i;
int region, insns;
In general the "funcaddr" argument passed to push_dummy_code is the actual
entry point of the target function. For __gcc_plt_call, we need to
locate the import stub for the corresponding function. Failing that,
we construct a dummy "import stub" on the stack to pass as an argument.
For __d_plt_call, we similarly synthesize a PLABEL on the stack to
pass to the helper function.
region = end - start + 4;
insns = region / 4;
buf = (unsigned int *) alloca (region);
An additional twist is that, in order for us to restore the space register
to its starting state, we need __gcc_plt_call/__d_plt_call to return
to the instruction where we started the call. However, if we put
the breakpoint there, gdb will complain because it will find two
frames on the stack with the same (sp, pc) (with the dummy frame in
between). Currently, we set the return pointer to (pc - 4) of the
current function. FIXME: This is not an ideal solution; possibly if the
current pc is at the beginning of a page, this will cause a page fault.
Need to understand this better and figure out a better way to fix it. */
read_memory (start, (char *) buf, region);
struct minimal_symbol *sym;
for (i = 0; i < insns; i++)
buf[i] = extract_unsigned_integer (&buf[i], 4);
/* Nonzero if we will use GCC's PLT call routine. This routine must be
passed an import stub, not a PLABEL. It is also necessary to get %r19
before performing the call. (This is done by push_dummy_call.) */
int use_gcc_plt_call = 1;
for (offset = 0; offset <= insns - count; offset++)
{
for (i = 0; i < count; i++)
{
if ((buf[offset + i] & patterns[i]) != patterns[i])
break;
}
if (i == count)
break;
}
/* See if __gcc_plt_call is available; if not we will use the HP version
instead. */
sym = lookup_minimal_symbol ("__gcc_plt_call", NULL, NULL);
if (sym == NULL)
use_gcc_plt_call = 0;
if (offset <= insns - count)
return start + offset * 4;
else
return 0;
}
/* If using __gcc_plt_call, we need to make sure we pass in an import
stub. funcaddr can be pointing to an export stub or a real function,
so we try to resolve it to the import stub. */
if (use_gcc_plt_call)
static CORE_ADDR
hppa32_hpux_search_dummy_call_sequence (struct gdbarch *gdbarch, CORE_ADDR pc,
int *argreg)
{
struct objfile *obj;
struct obj_section *sec;
struct hppa_objfile_private *priv;
struct frame_info *frame;
struct unwind_table_entry *u;
CORE_ADDR addr, rp;
char buf[4];
unsigned int insn;
sec = find_pc_section (pc);
obj = sec->objfile;
priv = objfile_data (obj, hppa_objfile_priv_data);
if (!priv)
priv = hppa_init_objfile_priv_data (obj);
if (!priv)
error ("Internal error creating objfile private data.\n");
/* Use the cached value if we have one. */
if (priv->dummy_call_sequence_addr != 0)
{
*argreg = priv->dummy_call_sequence_reg;
return priv->dummy_call_sequence_addr;
}
/* First try a heuristic; if we are in a shared library call, our return
pointer is likely to point at an export stub. */
frame = get_current_frame ();
rp = frame_unwind_register_unsigned (frame, 2);
u = find_unwind_entry (rp);
if (u && u->stub_unwind.stub_type == EXPORT)
{
addr = hppa_hpux_search_pattern (u->region_start, u->region_end,
ldsid_pattern,
ARRAY_SIZE (ldsid_pattern));
if (addr)
goto found_pattern;
}
/* Next thing to try is to look for an export stub. */
if (priv->unwind_info)
{
int i;
for (i = 0; i < priv->unwind_info->last; i++)
{
struct unwind_table_entry *u;
u = &priv->unwind_info->table[i];
if (u->stub_unwind.stub_type == EXPORT)
{
addr = hppa_hpux_search_pattern (u->region_start, u->region_end,
ldsid_pattern,
ARRAY_SIZE (ldsid_pattern));
if (addr)
{
goto found_pattern;
}
}
}
}
/* Finally, if this is the main executable, try to locate a sequence
from noshlibs */
addr = hppa_symbol_address ("noshlibs");
sec = find_pc_section (addr);
if (sec && sec->objfile == obj)
{
CORE_ADDR start, end;
find_pc_partial_function (addr, NULL, &start, &end);
if (start != 0 && end != 0)
{
addr = hppa_hpux_search_pattern (start, end, ldsid_pattern,
ARRAY_SIZE (ldsid_pattern));
if (addr)
goto found_pattern;
}
}
/* Can't find a suitable sequence. */
return 0;
found_pattern:
target_read_memory (addr, buf, sizeof (buf));
insn = extract_unsigned_integer (buf, sizeof (buf));
priv->dummy_call_sequence_addr = addr;
priv->dummy_call_sequence_reg = (insn >> 21) & 0x1f;
*argreg = priv->dummy_call_sequence_reg;
return priv->dummy_call_sequence_addr;
}
static CORE_ADDR
hppa64_hpux_search_dummy_call_sequence (struct gdbarch *gdbarch, CORE_ADDR pc,
int *argreg)
{
struct objfile *obj;
struct obj_section *sec;
struct hppa_objfile_private *priv;
CORE_ADDR addr;
struct minimal_symbol *msym;
int i;
sec = find_pc_section (pc);
obj = sec->objfile;
priv = objfile_data (obj, hppa_objfile_priv_data);
if (!priv)
priv = hppa_init_objfile_priv_data (obj);
if (!priv)
error ("Internal error creating objfile private data.\n");
/* Use the cached value if we have one. */
if (priv->dummy_call_sequence_addr != 0)
{
*argreg = priv->dummy_call_sequence_reg;
return priv->dummy_call_sequence_addr;
}
/* FIXME: Without stub unwind information, locating a suitable sequence is
fairly difficult. For now, we implement a very naive and inefficient
scheme; try to read in blocks of code, and look for a "bve,n (rp)"
instruction. These are likely to occur at the end of functions, so
we only look at the last two instructions of each function. */
for (i = 0, msym = obj->msymbols; i < obj->minimal_symbol_count; i++, msym++)
{
CORE_ADDR begin, end;
char *name;
unsigned int insns[2];
int offset;
find_pc_partial_function (SYMBOL_VALUE_ADDRESS (msym), &name,
&begin, &end);
if (*name == 0 || begin == 0 || end == 0)
continue;
if (target_read_memory (end - sizeof (insns), (char *)insns, sizeof (insns)) == 0)
{
for (offset = 0; offset < ARRAY_SIZE (insns); offset++)
{
unsigned int insn;
insn = extract_unsigned_integer (&insns[offset], 4);
if (insn == 0xe840d002) /* bve,n (rp) */
{
addr = (end - sizeof (insns)) + (offset * 4);
goto found_pattern;
}
}
}
}
/* Can't find a suitable sequence. */
return 0;
found_pattern:
priv->dummy_call_sequence_addr = addr;
/* Right now we only look for a "bve,l (rp)" sequence, so the register is
always HPPA_RP_REGNUM. */
priv->dummy_call_sequence_reg = HPPA_RP_REGNUM;
*argreg = priv->dummy_call_sequence_reg;
return priv->dummy_call_sequence_addr;
}
static CORE_ADDR
hppa_hpux_find_import_stub_for_addr (CORE_ADDR funcaddr)
{
struct objfile *objfile;
struct minimal_symbol *funsym, *stubsym;
CORE_ADDR stubaddr = 0;
CORE_ADDR stubaddr;
funsym = lookup_minimal_symbol_by_pc (funcaddr);
if (!funsym)
error ("Unable to find symbol for target function.\n");
stubaddr = 0;
ALL_OBJFILES (objfile)
{
@ -1356,65 +1533,220 @@ hppa_hpux_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp,
}
}
if (stubaddr != 0)
return stubaddr;
}
static int
hppa_hpux_sr_for_addr (CORE_ADDR addr)
{
/* Argument to __gcc_plt_call is passed in r22. */
regcache_cooked_write_unsigned (current_regcache, 22, stubaddr);
int sr;
/* The space register to use is encoded in the top 2 bits of the address. */
sr = addr >> (gdbarch_tdep (current_gdbarch)->bytes_per_address * 8 - 2);
return sr + 4;
}
else
static CORE_ADDR
hppa_hpux_find_dummy_bpaddr (CORE_ADDR addr)
{
/* No import stub found; let's synthesize one. */
/* In order for us to restore the space register to its starting state,
we need the dummy trampoline to return to the an instruction address in
the same space as where we started the call. We used to place the
breakpoint near the current pc, however, this breaks nested dummy calls
as the nested call will hit the breakpoint address and terminate
prematurely. Instead, we try to look for an address in the same space to
put the breakpoint.
/* ldsid %r21, %r1 */
write_memory_unsigned_integer (sp, 4, 0x02a010a1);
/* mtsp %r1,%sr0 */
write_memory_unsigned_integer (sp + 4, 4, 0x00011820);
/* be 0(%sr0, %r21) */
write_memory_unsigned_integer (sp + 8, 4, 0xe2a00000);
/* nop */
write_memory_unsigned_integer (sp + 12, 4, 0x08000240);
This is similar in spirit to putting the breakpoint at the "entry point"
of an executable. */
regcache_cooked_write_unsigned (current_regcache, 21, funcaddr);
regcache_cooked_write_unsigned (current_regcache, 22, sp);
}
struct obj_section *sec;
struct unwind_table_entry *u;
struct minimal_symbol *msym;
CORE_ADDR func;
int i;
/* We set the breakpoint address and r31 to (close to) where the current
pc is; when __gcc_plt_call returns, it will restore pcsqh to the
current value based on this. The -4 is needed for frame unwinding
to work properly -- we need to land in a different function than
the current function. */
*bp_addr = (read_register (HPPA_PCOQ_HEAD_REGNUM) & ~3) - 4;
regcache_cooked_write_unsigned (current_regcache, 31, *bp_addr);
/* Continue from __gcc_plt_call. */
*real_pc = SYMBOL_VALUE (sym);
}
else
sec = find_pc_section (addr);
if (sec)
{
ULONGEST gp;
/* First try the lowest address in the section; we can use it as long
as it is "regular" code (i.e. not a stub) */
u = find_unwind_entry (sec->addr);
if (!u || u->stub_unwind.stub_type == 0)
return sec->addr;
/* Use __d_plt_call as a fallback; __d_plt_call expects to be called
with a plabel, so we need to build one. */
/* Otherwise, we need to find a symbol for a regular function. We
do this by walking the list of msymbols in the objfile. The symbol
we find should not be the same as the function that was passed in. */
sym = lookup_minimal_symbol ("__d_plt_call", NULL, NULL);
if (sym == NULL)
error("Can't find an address for __d_plt_call or __gcc_plt_call "
"trampoline\nSuggest linking executable with -g or compiling "
"with gcc.");
/* FIXME: this is broken, because we can find a function that will be
called by the dummy call target function, which will still not
work. */
gp = gdbarch_tdep (gdbarch)->find_global_pointer (funcaddr);
write_memory_unsigned_integer (sp, 4, funcaddr);
write_memory_unsigned_integer (sp + 4, 4, gp);
/* plabel is passed in r22 */
regcache_cooked_write_unsigned (current_regcache, 22, sp);
find_pc_partial_function (addr, NULL, &func, NULL);
for (i = 0, msym = sec->objfile->msymbols;
i < sec->objfile->minimal_symbol_count;
i++, msym++)
{
u = find_unwind_entry (SYMBOL_VALUE_ADDRESS (msym));
if (func != SYMBOL_VALUE_ADDRESS (msym)
&& (!u || u->stub_unwind.stub_type == 0))
return SYMBOL_VALUE_ADDRESS (msym);
}
}
/* Pushed one stack frame, which has to be 64-byte aligned. */
sp += 64;
warning ("Cannot find suitable address to place dummy breakpoint; nested "
"calls may fail.\n");
return addr - 4;
}
static CORE_ADDR
hppa_hpux_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp,
CORE_ADDR funcaddr, int using_gcc,
struct value **args, int nargs,
struct type *value_type,
CORE_ADDR *real_pc, CORE_ADDR *bp_addr)
{
CORE_ADDR pc, stubaddr;
int argreg;
pc = read_pc ();
/* Note: we don't want to pass a function descriptor here; push_dummy_call
fills in the PIC register for us. */
funcaddr = gdbarch_convert_from_func_ptr_addr (gdbarch, funcaddr, NULL);
/* The simple case is where we call a function in the same space that we are
currently in; in that case we don't really need to do anything. */
if (hppa_hpux_sr_for_addr (pc) == hppa_hpux_sr_for_addr (funcaddr))
{
/* Intraspace call. */
*bp_addr = hppa_hpux_find_dummy_bpaddr (pc);
*real_pc = funcaddr;
regcache_cooked_write_unsigned (current_regcache, HPPA_RP_REGNUM, *bp_addr);
return sp;
}
/* In order to make an interspace call, we need to go through a stub.
gcc supplies an appropriate stub called "__gcc_plt_call", however, if
an application is compiled with HP compilers then this stub is not
available. We used to fallback to "__d_plt_call", however that stub
is not entirely useful for us because it doesn't do an interspace
return back to the caller. Also, on hppa64-hpux, there is no
__gcc_plt_call available. In order to keep the code uniform, we
instead don't use either of these stubs, but instead write our own
onto the stack.
A problem arises since the stack is located in a different space than
code, so in order to branch to a stack stub, we will need to do an
interspace branch. Previous versions of gdb did this by modifying code
at the current pc and doing single-stepping to set the pcsq. Since this
is highly undesirable, we use a different scheme:
All we really need to do the branch to the stub is a short instruction
sequence like this:
PA1.1:
ldsid (rX),r1
mtsp r1,sr0
be,n (sr0,rX)
PA2.0:
bve,n (sr0,rX)
Instead of writing these sequences ourselves, we can find it in
the instruction stream that belongs to the current space. While this
seems difficult at first, we are actually guaranteed to find the sequences
in several places:
For 32-bit code:
- in export stubs for shared libraries
- in the "noshlibs" routine in the main module
For 64-bit code:
- at the end of each "regular" function
We cache the address of these sequences in the objfile's private data
since these operations can potentially be quite expensive.
So, what we do is:
- write a stack trampoline
- look for a suitable instruction sequence in the current space
- point the sequence at the trampoline
- set the return address of the trampoline to the current space
(see hppa_hpux_find_dummy_call_bpaddr)
- set the continuing address of the "dummy code" as the sequence.
*/
if (IS_32BIT_TARGET (gdbarch))
{
static unsigned int hppa32_tramp[] = {
0x0fdf1291, /* stw r31,-8(,sp) */
0x02c010a1, /* ldsid (,r22),r1 */
0x00011820, /* mtsp r1,sr0 */
0xe6c00000, /* be,l 0(sr0,r22),%sr0,%r31 */
0x081f0242, /* copy r31,rp */
0x0fd11082, /* ldw -8(,sp),rp */
0x004010a1, /* ldsid (,rp),r1 */
0x00011820, /* mtsp r1,sr0 */
0xe0400000, /* be 0(sr0,rp) */
0x08000240 /* nop */
};
/* for hppa32, we must call the function through a stub so that on
return it can return to the space of our trampoline. */
stubaddr = hppa_hpux_find_import_stub_for_addr (funcaddr);
if (stubaddr == 0)
error ("Cannot call external function not referenced by application "
"(no import stub).\n");
regcache_cooked_write_unsigned (current_regcache, 22, stubaddr);
write_memory (sp, (char *)&hppa32_tramp, sizeof (hppa32_tramp));
*bp_addr = hppa_hpux_find_dummy_bpaddr (pc);
regcache_cooked_write_unsigned (current_regcache, 31, *bp_addr);
*real_pc = hppa32_hpux_search_dummy_call_sequence (gdbarch, pc, &argreg);
if (*real_pc == 0)
error ("Cannot make interspace call from here.\n");
regcache_cooked_write_unsigned (current_regcache, argreg, sp);
sp += sizeof (hppa32_tramp);
}
else
{
static unsigned int hppa64_tramp[] = {
0xeac0f000, /* bve,l (r22),%r2 */
0x0fdf12d1, /* std r31,-8(,sp) */
0x0fd110c2, /* ldd -8(,sp),rp */
0xe840d002, /* bve,n (rp) */
0x08000240 /* nop */
};
/* for hppa64, we don't need to call through a stub; all functions
return via a bve. */
regcache_cooked_write_unsigned (current_regcache, 22, funcaddr);
write_memory (sp, (char *)&hppa64_tramp, sizeof (hppa64_tramp));
*bp_addr = pc - 4;
regcache_cooked_write_unsigned (current_regcache, 31, *bp_addr);
*real_pc = hppa64_hpux_search_dummy_call_sequence (gdbarch, pc, &argreg);
if (*real_pc == 0)
error ("Cannot make interspace call from here.\n");
regcache_cooked_write_unsigned (current_regcache, argreg, sp);
sp += sizeof (hppa64_tramp);
}
sp = gdbarch_frame_align (gdbarch, sp);
return sp;
}
/* Bit in the `ss_flag' member of `struct save_state' that indicates
@ -1656,7 +1988,7 @@ hppa_hpux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
if (tdep->bytes_per_address == 4)
if (IS_32BIT_TARGET (gdbarch))
tdep->in_solib_call_trampoline = hppa32_hpux_in_solib_call_trampoline;
else
tdep->in_solib_call_trampoline = hppa64_hpux_in_solib_call_trampoline;
@ -1689,7 +2021,8 @@ hppa_hpux_som_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
tdep->is_elf = 0;
tdep->find_global_pointer = hppa_hpux_som_find_global_pointer;
tdep->find_global_pointer = hppa32_hpux_find_global_pointer;
hppa_hpux_init_abi (info, gdbarch);
som_solib_select (tdep);
}
@ -1700,6 +2033,8 @@ hppa_hpux_elf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
tdep->is_elf = 1;
tdep->find_global_pointer = hppa64_hpux_find_global_pointer;
hppa_hpux_init_abi (info, gdbarch);
pa64_solib_select (tdep);
}

View file

@ -273,6 +273,20 @@ hppa_symbol_address(const char *sym)
else
return (CORE_ADDR)-1;
}
struct hppa_objfile_private *
hppa_init_objfile_priv_data (struct objfile *objfile)
{
struct hppa_objfile_private *priv;
priv = (struct hppa_objfile_private *)
obstack_alloc (&objfile->objfile_obstack,
sizeof (struct hppa_objfile_private));
set_objfile_data (objfile, hppa_objfile_priv_data, priv);
memset (priv, 0, sizeof (*priv));
return priv;
}
/* Compare the start address for two unwind entries returning 1 if
@ -529,15 +543,8 @@ read_unwind_info (struct objfile *objfile)
obj_private = (struct hppa_objfile_private *)
objfile_data (objfile, hppa_objfile_priv_data);
if (obj_private == NULL)
{
obj_private = (struct hppa_objfile_private *)
obstack_alloc (&objfile->objfile_obstack,
sizeof (struct hppa_objfile_private));
set_objfile_data (objfile, hppa_objfile_priv_data, obj_private);
obj_private->unwind_info = NULL;
obj_private->so_info = NULL;
obj_private->dp = 0;
}
obj_private = hppa_init_objfile_priv_data (objfile);
obj_private->unwind_info = ui;
}
@ -912,6 +919,7 @@ hppa32_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
write_register (19, gp);
/* Set the return address. */
if (!gdbarch_push_dummy_code_p (gdbarch))
regcache_cooked_write_unsigned (regcache, HPPA_RP_REGNUM, bp_addr);
/* Update the Stack Pointer. */
@ -952,6 +960,10 @@ hppa64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
been pushed. */
CORE_ADDR new_sp = 0;
/* Global pointer (r27) of the function we are trying to call. */
CORE_ADDR gp;
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
/* Two passes. First pass computes the location of everything,
second pass writes the bytes out. */
int write_pass;
@ -1033,7 +1045,13 @@ hppa64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
if (struct_return)
write_register (28, struct_addr);
gp = tdep->find_global_pointer (function);
if (gp != 0)
write_register (27, gp);
/* Set the return address. */
if (!gdbarch_push_dummy_code_p (gdbarch))
regcache_cooked_write_unsigned (regcache, HPPA_RP_REGNUM, bp_addr);
/* Update the Stack Pointer. */

View file

@ -204,6 +204,9 @@ struct hppa_objfile_private
struct hppa_unwind_info *unwind_info; /* a pointer */
struct so_list *so_info; /* a pointer */
CORE_ADDR dp;
int dummy_call_sequence_reg;
CORE_ADDR dummy_call_sequence_addr;
};
extern const struct objfile_data *hppa_objfile_priv_data;
@ -235,4 +238,7 @@ extern struct minimal_symbol *
hppa_lookup_stub_minimal_symbol (const char *name,
enum unwind_stub_types stub_type);
extern struct hppa_objfile_private *
hppa_init_objfile_priv_data (struct objfile *objfile);
#endif /* HPPA_TDEP_H */