* [rfc] dummy calls for hppa64-hpux
@ 2004-12-09 13:31 Randolph Chung
2004-12-10 19:04 ` Randolph Chung
0 siblings, 1 reply; 3+ messages in thread
From: Randolph Chung @ 2004-12-09 13:31 UTC (permalink / raw)
To: gdb-patches
this patch is not yet ready for inclusion, i'm only posting it for
comments because it's rather unorthodox.
there are two cases that i am trying to address:
1) on 32-bit hpux, we cannot do calls from gdb if the current space is
not the same space as __gcc_plt_call
2) on 64-bit hpux we don't have a suitable implementation of
push_dummy_code (64-bit hpux doesn't have __gcc_plt_call or
__d_plt_call)
the fundamental problem is that gdb cannot set pcsqh directly, the only
way to do it is to do an external branch to the target space. In old
versions of gdb (i.e. 5.x) this was done by temporarily overwriting the
insn at pc with a "bve" instruction, single step the inferior, and then
restoring the original instruction. this has obvious problems with
multithreaded apps. Dan also pointed out to me that the handling of
single stepping (as revived by the code below) will not handle
"unexpected" signals correctly. also there's no guarantee that we can
actually write to the memory space pointed to by pc.
I don't have any other good ideas of how to solve these problems, so
I've tried to reintroduce some of the hacks found in old versions of gdb
in as clean a way as possible. comments? is something like this ok?
randolph
Index: hppa-hpux-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/hppa-hpux-tdep.c,v
retrieving revision 1.29
diff -u -p -r1.29 hppa-hpux-tdep.c
--- hppa-hpux-tdep.c 8 Dec 2004 01:48:01 -0000 1.29
+++ hppa-hpux-tdep.c 9 Dec 2004 04:57:24 -0000
@@ -33,6 +33,8 @@
#include "infcall.h"
#include "observer.h"
#include "hppa-tdep.h"
+#include "solib-som.h"
+#include "solib-pa64.h"
#include <dl.h>
#include <machine/save_state.h>
@@ -53,6 +55,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
@@ -1228,8 +1246,84 @@ hppa_hpux_sigtramp_unwind_sniffer (struc
return NULL;
}
+static int
+hppa_hpux_try_to_set_pcsqh (ULONGEST target_addr)
+{
+ /* HACK! FIXME!
+ pcsqh cannot be written to directly; the only way to modify it is
+ to do an external branch to the new space. We do this by doing code
+ modification as well as single-stepping the inferior. This is
+ inheritently unsafe against signals and multithreaded applications,
+ but we have little alternative. */
+
+ unsigned int orig_insn[2];
+ unsigned int new_insn[2];
+ CORE_ADDR pcoqh, pcoqt;
+ ULONGEST r1, space;
+ struct target_waitstatus w;
+ int sid;
+
+ sid = (target_addr >> (register_size (current_gdbarch, 0) * 8 - 2)) & 3;
+
+ if (sid == 0)
+ space = read_register (HPPA_SR4_REGNUM);
+ else
+ space = read_register (HPPA_SR4_REGNUM + 4 + sid);
+
+ /* Don't do all this rather dangerous operation if we don't have to. */
+ if (space == read_register (HPPA_PCSQ_HEAD_REGNUM))
+ return 0;
+
+ pcoqh = read_register (HPPA_PCOQ_HEAD_REGNUM) & ~0x3;
+ pcoqt = read_register (HPPA_PCOQ_TAIL_REGNUM) & ~0x3;
+ r1 = read_register (1);
+
+ if (target_read_memory (pcoqh, (char *)&orig_insn[0], 4)
+ || target_read_memory (pcoqt, (char *)&orig_insn[1], 4))
+ return -1;
+
+ new_insn[0] = 0xe0202000 | (sid << 14); /* be 0(%srN,%r1) */
+ new_insn[1] = 0x08000240; /* nop */
+
+ if (target_write_memory (pcoqh, (char *)&new_insn[0], 4)
+ || target_write_memory (pcoqt, (char *)&new_insn[1], 4))
+ return -1;
+
+ write_register (1, target_addr);
+
+ target_resume (inferior_ptid, 1, 0);
+ registers_changed ();
+ target_wait (inferior_ptid, &w);
+ target_resume (inferior_ptid, 1, 0);
+ registers_changed ();
+ target_wait (inferior_ptid, &w);
+
+ if ((space & ~0x3ff) != (read_register (HPPA_PCSQ_HEAD_REGNUM) & ~0x3ff))
+ {
+ error ("Cannot set pcsqh correctly, got 0x%s instead of 0x%s\n",
+ paddr_nz (read_register (HPPA_PCSQ_HEAD_REGNUM)),
+ paddr_nz (space));
+ return -1;
+ }
+
+ if (target_write_memory (pcoqh, (char *)&orig_insn[0], 4)
+ || target_write_memory (pcoqt, (char *)&orig_insn[1], 4))
+ {
+ /* This error is noisy because we were able to overwrite the values
+ above, but we can't restore it now. */
+ error ("Cannot restore insns to pcoqh/pcoqt while setting pcsqh.\n");
+ return -1;
+ }
+
+ write_register (HPPA_PCOQ_HEAD_REGNUM, pcoqh);
+ write_register (HPPA_PCOQ_TAIL_REGNUM, pcoqt);
+ write_register (1, r1);
+
+ return 0;
+}
+
static CORE_ADDR
-hppa_hpux_som_find_global_pointer (struct value *function)
+hppa32_hpux_find_global_pointer (struct value *function)
{
CORE_ADDR faddr;
@@ -1248,15 +1342,15 @@ hppa_hpux_som_find_global_pointer (struc
return extract_unsigned_integer (buf, sizeof (buf));
}
- return som_solib_get_got_by_pc (faddr);
+ return gdbarch_tdep (current_gdbarch)->solib_get_got_by_pc (faddr);
}
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)
+hppa32_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)
{
/* 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
@@ -1327,6 +1421,12 @@ hppa_hpux_push_dummy_code (struct gdbarc
struct minimal_symbol *funsym, *stubsym;
CORE_ADDR stubaddr = 0;
+ if (hppa_hpux_try_to_set_pcsqh (SYMBOL_VALUE (sym)))
+ {
+ error ("Cannot do interspace function call from here.\n");
+ return sp;
+ }
+
funsym = lookup_minimal_symbol_by_pc (funcaddr);
if (!funsym)
error ("Unable to find symbol for target function.\n");
@@ -1415,6 +1515,91 @@ hppa_hpux_push_dummy_code (struct gdbarc
return sp;
}
+
+static CORE_ADDR
+hppa64_hpux_find_global_pointer (struct value *function)
+{
+ CORE_ADDR faddr;
+ char buf[32];
+
+ faddr = value_as_address (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);
+ }
+}
+
+static CORE_ADDR
+hppa64_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-hp-hpux does not have __gcc_plt_call; instead we have to do
+ everything ourselves using a stack trampoline. */
+
+ /* This is padded so it is a multiple of 8-bytes, so that if we write an
+ opd after the trampoline it will be properly aligned. */
+ static unsigned int trampoline[] = {
+ 0x0fdf12d1, /* std r31,-8(,sp) */
+ 0x50220020, /* ldd 10(r1),rp */
+ 0xe840f000, /* bve,l (rp),%r2 */
+ 0x503b0030, /* ldd 18(r1),dp */
+ 0x0fd110c2, /* ldd -8(,sp),rp */
+ 0xe840d002, /* bve,n (rp) */
+ 0x08000240, /* nop */
+ 0x08000240 /* nop */
+ };
+ unsigned long opd[] = { 0, 0, 0, 0 };
+ int opd_on_stack = 0;
+
+ if (hppa_hpux_try_to_set_pcsqh (sp))
+ {
+ error ("Cannot do interspace function call from here.\n");
+ return sp;
+ }
+
+ write_memory (sp, (char *)&trampoline, sizeof (trampoline));
+
+ if (!in_opd_section (funcaddr))
+ {
+ opd[2] = funcaddr;
+ opd[3] = gdbarch_tdep (gdbarch)->solib_get_got_by_pc (funcaddr);
+ if (opd[3] == 0)
+ opd[3] = read_register (27);
+
+ write_memory (sp + sizeof (trampoline), (char *)&opd, sizeof (opd));
+ regcache_cooked_write_unsigned (current_regcache, 1, sp + sizeof (trampoline));
+ opd_on_stack = 1;
+ }
+ else
+ regcache_cooked_write_unsigned (current_regcache, 1, funcaddr);
+
+ /* We set the breakpoint address and r31 to (close to) where the current
+ pc is; when the trampoline 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 the stub. */
+ *real_pc = sp;
+
+ if (opd_on_stack)
+ sp += sizeof(opd);
+ sp = gdbarch_frame_align (gdbarch, sp + sizeof (trampoline));
+
+ return sp;
+}
+
\f
/* Bit in the `ss_flag' member of `struct save_state' that indicates
@@ -1519,15 +1755,13 @@ hppa_hpux_init_abi (struct gdbarch_info
else
tdep->in_solib_call_trampoline = hppa64_hpux_in_solib_call_trampoline;
tdep->unwind_adjust_stub = hppa_hpux_unwind_adjust_stub;
+ tdep->unwind_stub_frame = hppa_hpux_unwind_stub_frame;
set_gdbarch_in_solib_return_trampoline (gdbarch,
hppa_hpux_in_solib_return_trampoline);
set_gdbarch_skip_trampoline_code (gdbarch, hppa_hpux_skip_trampoline_code);
- set_gdbarch_push_dummy_code (gdbarch, hppa_hpux_push_dummy_code);
- set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
-
set_gdbarch_read_pc (gdbarch, hppa_hpux_read_pc);
set_gdbarch_write_pc (gdbarch, hppa_hpux_write_pc);
set_gdbarch_unwind_pc (gdbarch, hppa_hpux_unwind_pc);
@@ -1544,8 +1779,13 @@ hppa_hpux_som_init_abi (struct gdbarch_i
tdep->is_elf = 0;
- tdep->find_global_pointer = hppa_hpux_som_find_global_pointer;
+ tdep->find_global_pointer = hppa32_hpux_find_global_pointer;
+
+ set_gdbarch_push_dummy_code (gdbarch, hppa32_hpux_push_dummy_code);
+ set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
+
hppa_hpux_init_abi (info, gdbarch);
+ som_solib_select (tdep);
}
static void
@@ -1554,7 +1794,13 @@ hppa_hpux_elf_init_abi (struct gdbarch_i
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
tdep->is_elf = 1;
+ tdep->find_global_pointer = hppa64_hpux_find_global_pointer;
+
+ set_gdbarch_push_dummy_code (gdbarch, hppa64_hpux_push_dummy_code);
+ set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
+
hppa_hpux_init_abi (info, gdbarch);
+ pa64_solib_select (tdep);
}
void
--
Randolph Chung
Debian GNU/Linux Developer, hppa/ia64 ports
http://www.tausq.org/
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [rfc] dummy calls for hppa64-hpux
2004-12-09 13:31 [rfc] dummy calls for hppa64-hpux Randolph Chung
@ 2004-12-10 19:04 ` Randolph Chung
2004-12-10 21:35 ` Daniel Jacobowitz
0 siblings, 1 reply; 3+ messages in thread
From: Randolph Chung @ 2004-12-10 19:04 UTC (permalink / raw)
To: gdb-patches
In reference to a message from Randolph Chung, dated Dec 08:
> this patch is not yet ready for inclusion, i'm only posting it for
> comments because it's rather unorthodox.
ok, here's another unfinished idea..... Dave Anglin suggested an
alternative scheme to me that seems more robust. I haven't written the
code for it yet, but here's a 50-line comment to explain it. Comments
before i try it? :)
/* 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. 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:
- in export stubs for shared libraries
- For 32-bit code, in the "noshlibs" routine in the main module
- For 64-bit code, in the "$START$" routine in the main module
(Note that we can cache the address of these sequences in
the objfile's private data.)
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 instruction (*)
- set the continuing address of the "dummy code" as the sequence.
(*) An additional twist is that, in order for us to restore the space
register to its starting state, we need the trampoline 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. */
Is this better? :)
randolph
--
Randolph Chung
Debian GNU/Linux Developer, hppa/ia64 ports
http://www.tausq.org/
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [rfc] dummy calls for hppa64-hpux
2004-12-10 19:04 ` Randolph Chung
@ 2004-12-10 21:35 ` Daniel Jacobowitz
0 siblings, 0 replies; 3+ messages in thread
From: Daniel Jacobowitz @ 2004-12-10 21:35 UTC (permalink / raw)
To: gdb-patches
On Fri, Dec 10, 2004 at 10:01:02AM -0800, Randolph Chung wrote:
> In reference to a message from Randolph Chung, dated Dec 08:
> > this patch is not yet ready for inclusion, i'm only posting it for
> > comments because it's rather unorthodox.
>
> ok, here's another unfinished idea..... Dave Anglin suggested an
> alternative scheme to me that seems more robust. I haven't written the
> code for it yet, but here's a 50-line comment to explain it. Comments
> before i try it? :)
I think this looks a whole lot better. If the space you're in can't
make inter-space calls, you probably won't need to do this anyway, so
issuing an error message is fine.
--
Daniel Jacobowitz
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2004-12-10 20:47 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-12-09 13:31 [rfc] dummy calls for hppa64-hpux Randolph Chung
2004-12-10 19:04 ` Randolph Chung
2004-12-10 21:35 ` Daniel Jacobowitz
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox