libunwind-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [libunwind] unwinding through dynamically modified code?


From: Todd L Miller
Subject: Re: [libunwind] unwinding through dynamically modified code?
Date: Wed, 24 Mar 2004 13:05:41 -0600 (CST)

        A code fragment, with accompanying guesses and questions.

        regionZero->insn_count = 0;
        regionZero->op_count = 2;
        _U_dyn_op_alias(& regionZero->op[0], _U_QP_TRUE, 0,
                        <address of jump to 0x60000ffffffe9f80> );
        _U_dyn_op_stop( & regionZero->op[1] );

        /* The unw_dyn_info_t which points to regionZero (whose 'next' is
           regionOne) has a start_ip of 0x60000ffffffe9f80. */

0x60000ffffffe9f80:     [MLX]       nop.m 0x0
0x60000ffffffe9f81:                 brl.few 0x60000ffffffea1e0;;

        /* This jump is because this code fragment is currently configured
           not to do anything; it will be later replaced with a bundle
           of no-ops. */

0x60000ffffffe9f90:     [MII]       alloc r43=ar.pfs,61,53,0
0x60000ffffffe9f91:                 nop.i 0x0
0x60000ffffffe9f92:                 nop.i 0x0;;

        /* op_count was initialized to 0, and insn_count is 3. */
        _U_dyn_op_save_reg( & regionOne->op[ regionOne->op_count++ ],
                        _U_QP_TRUE, regionOne->insn_count++,
                        UNW_IA64_AR_PFS, UNW_IA64_GR + 43 );

0x60000ffffffe9fa0:     [MII]       mov r44=r1

        /* Is this still superflous if I later change the gp to make a
           function call? */
        _U_dyn_op_save_reg( & regionOne->op[ regionOne->op_count++ ],
                        _U_QP_TRUE, regionOne->insn_count++,
                        UNW_IA64_GR + 1, UNW_IA64_GR + 44 );

0x60000ffffffe9fa1:                 mov r45=r2
0x60000ffffffe9fa2:                 mov r46=r3
... // the other unstacked scratch registers
0x60000ffffffea020:     [MII]       mov r68=r31
0x60000ffffffea021:                 nop.i 0x0
0x60000ffffffea022:                 nop.i 0x0
0x60000ffffffea030:     [MMI]       mov.m r69=ar.ccv
0x60000ffffffea031:                 mov.m r70=ar25
0x60000ffffffea032:                 mov r72=b0
0x60000ffffffea040:     [MII]       mov.m r71=ar26
0x60000ffffffea041:                 mov r73=b6
0x60000ffffffea042:                 mov r74=b7
0x60000ffffffea050:     [MII]       nop.m 0x0
0x60000ffffffea051:                 mov r75=pr

        _U_dyn_op_save_reg( & regionOne->op[ regionOne->op_count++ ],
                        _U_QP_TRUE, regionOne->insn_count++,
                        UNW_IA64_PR, UNW_IA64_GR + 75 );

0x60000ffffffea052:                 nop.i 0x0
0x60000ffffffea060:     [MII]       nop.m 0x0
0x60000ffffffea061:                 mov r76=r12

        _U_dyn_op_save_reg( & regionOne->op[ regionOne->op_count++ ],
                        _U_QP_TRUE, regionOne->insn_count++,
                        UNW_IA64_SP, UNW_IA64_GR + 76 );

0x60000ffffffea062:                 adds r12=-32,r12;;
... // do some other stuff, including function calls
0x60000ffffffea100:     [MII]       mov r1=r44
0x60000ffffffea101:                 mov r2=r45
0x60000ffffffea102:                 mov r3=r46
... // the other scratch unstacked registers
0x60000ffffffea180:     [MII]       mov r31=r68
0x60000ffffffea181:                 nop.i 0x0
0x60000ffffffea182:                 nop.i 0x0
0x60000ffffffea190:     [MMI]       mov.m ar.ccv=r69
0x60000ffffffea191:                 mov.m ar25=r70
0x60000ffffffea192:                 mov.sptk b0=r72,0x60000ffffffea190
0x60000ffffffea1a0:     [MII]       mov.m ar26=r71
0x60000ffffffea1a1:                 mov.sptk b6=r73,0x60000ffffffea1a0
0x60000ffffffea1a2:                 mov.sptk b7=r74,0x60000ffffffea1a0
0x60000ffffffea1b0:     [MII]       nop.m 0x0
0x60000ffffffea1b1:                 mov pr=r75,0xfffffffffffffffe
0x60000ffffffea1b2:                 mov r12=r76
0x60000ffffffea1c0:     [MII]       nop.m 0x0
0x60000ffffffea1c1:                 mov.i ar.pfs=r43
0x60000ffffffea1c2:                 nop.i 0x0;;
0x60000ffffffea1d0:     [MII]       alloc r43=ar.pfs,12,3,0

        /* At this point, the machine state, excepting the extra output
           register and the pc, is the same as it was before the jump
           to this code fragment.  After this bundle finishes its
           nops, */

0x60000ffffffea1d1:                 nop.i 0x0
0x60000ffffffea1d2:                 nop.i 0x0;;

        /* I can safely emulate the instructions we overwrote to insert
           the jump to this code.  In some cases, those instructons will
           alter the frame/unwind state, but I don't see any reasonable
           way of telling libunwind about them if they do. */

        /* More importantly, however, after this alloc, the registers
           in which I'd been preserving ar.pfs, the gp, the stack pointer,
           and the predicate registers are no longer accessible.

           Given that my code fragment is only half-way done, do I insert
           another alias operation, or _U_dyn_op_stop() the current region
           and start another one?  Immediately after the emulated instructions,
           I insert another large alloc and repeat the entire process.  If
           I used more than two regions, would the third be an aliased
           region covering the emulated instruction(s), and then the
           fourth effectively a duplicate of the second?  Or do the label
           state/copy state operations come into play here? */

0x60000ffffffe9f90:     [MII]       alloc r43=ar.pfs,61,53,0
0x60000ffffffe9f91:                 nop.i 0x0
0x60000ffffffe9f92:                 nop.i 0x0;;
.. // repeat above
0x60000ffffffea440:     [MII]       alloc r43=ar.pfs,12,3,0

        /* I do the save/do stuff/restore routine twice because the
           project I'm working on requires the ability to distinguish
           before and after individual instructions.  (So that I may have
           emulated instructions before the first nop in this email, as
           well.)  Anyway, at this point, the same questions as above
           arise: the registers in which I preserved state are no longer
           accessible, and I have several trailing instructions. */

0x60000ffffffea441:                 nop.i 0x0
0x60000ffffffea442:                 nop.i 0x0;;

... // emulated instructions

0x60000ffffffea470:     [MLX]       nop.m 0x0
0x60000ffffffea471:                 brl.few 0x60000fffffeb32d0;;

        /* This is the jump back to the function from whence it came.
           (If the address looks odd, it's because all of this was
           actually disassembled out of a buffer in the local process
           before I copied it to the remote process; assume any addresses
           I gave were altered appropriately.)  At this point,
           I _U_dyn_op_stop the current region and am done (as far as
           constructing the dynamic information goes). */

        /* The unw_dyn_info_t has an end_ip of 0x60000ffffffea480. */


        I then have to copy the unw_dyn_info_t and its linked list of
regions into the remote process (diddling the pointers as I go) and link
it into the dynamic unwind information list there.

        Thank you for your time.

- Todd L Miller


reply via email to

[Prev in Thread] Current Thread [Next in Thread]