max at bruningsystems.com ??: > Hi Brian, > > Brian Xu - Sun Microsystems - Beijing China wrote: > >> max at bruningsystems.com ??: >> >>> Hi Brian, >>> >>> Brian Xu - Sun Microsystems - Beijing China wrote: >>> >>> >>>> Hi, >>>> I have a question: how the cmd '::findstack -v' in mdb works? >>>> >>>> Likewise in sparc, since at any time only the current register window >>>> can be accessed, so if we want to backtrace the stack, we can only >>>> access the fp(i6) and args(i0-i5) of the function's father, and how we >>>> can access those of the grandfather, great grandfather, etc? >>>> >>>> >>>> >>> |SPARC uses register windows for most argument passing. Basically, >>> if a function executes the "save" instruction at or near the beginning >>> and the "restore" instruction at the end, there is a save area for >>> registers >>> on the stack. When a thread switch occurs, or a window spill trap >>> occurs (a save executed, but no more windows), the register window(s) >>> that need to be saved are placed in the save area on the stack. >>> If a function does not use save/restore, arguments are in the output >>> registers. There are six registers used for argument passing. If a >>> function takes more than 6 arguments, the additional arguments are >>> placed >>> in the caller's frame at a fixed location from the top. >>> >>> >> Thanks for the info. >> >> I have a question about the meaning of 'when a thread switch occurs'. >> Here the thread means which thread, the current thread? >> > Yes, the current thread. During a switch on SPARC, in resume() the FLUSHW > instruction is executed for the thread being switched out. This instruction > will save all register windows (that need to be saved) in the > appropriate register > window save area in the stack of the thread being switched out. (I just > now see > you mention flushw below). > >> If there is no window spill, and we set a breakpoint in a thread, when >> the thread stops at the breakpoint, since the thread switch occurs, >> then $c will list the values of the args of each function on the >> stack, right? (we also consider the STOP as a thread state transition) >> > That should be correct. > >> Another question is(it also my original question), even the trap >> handler can only access the current register window, how it can put >> the registers of other window in the save area? Here I think it is the >> trap handler or the swtch that put the value of registers in the save >> area. >> I think the handler execute the 'flushw' instruction or repeat execute >> the 'restore' instruction. right? >> > Yes. > >>> The following shows an example. Note that for 64-bit SPARC, the >>> stack pointer (%sp) and the frame pointer (%fp) are adjusted by 0x7ff >>> (the ABI-Bias). The bias is there for two reasons. First, it allows >>> trap handling code to quickly determine if it needs to save 32-bit >>> or 64-bit values (with the bias, 64-bit stack pointer is always an odd >>> number (lowest bit set)). Second, it allows more space to be >>> accessed using "immediate" addressing (for example, "ld [%fp+offset], >>> %l0"). >>> "offset" is an immediate value and is a signed, 13-bit value. By >>> using the >>> abi-bias, the range of stack addresses that can be accessed with >>> immediate >>> addressing is increased. Let me know if you want more information on >>> this. >>> >>> >> then the 'save' function at the beginning of a function should be, >> save %sp, xx, %sp >> where xx=0x7ff + 24(the size of the register window) + 'extra area for >> local variables' for 64bit and xx=24 + 'extra area for local >> variables' for 32bit, right? >> > Well, not quite. The save area is 0xB0 bytes for 64-bit apps/kernel, > and 0x5c bytes > for 32-bit apps. Take a look at the comment in > http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/uts/sparc/sys/stack.h > which describes both 32-bit and 64-bit stacks. > Here is an example.
#*if* *defined*(__sparcv9 <http://src.opensolaris.org/source/s?defs=__sparcv9>) 79 /* 80 * The 64-bit C ABI uses a stack frame that looks like: 81 * 82 * | | 83 * |-------------------------------| 84 * | Locals, temps, saved floats | 85 * |-------------------------------| 86 * | outgoing parameters past 6 | 87 * |-------------------------------|-\ 88 * | outgoing parameters thru 6 | | 89 * |-------------------------------| > minimum stack frame 90 * | 16 xwords to save IN and | | 91 * | LOCAL register on overflow | | 92 * |-------------------------------|-/-\ 93 * | | | 94 * | | > v9 abi bias 95 * | | | 96 * %sp->|-------------------------------|---/ 97 */ [0]> ddi_regs_map_setup::dis ddi_regs_map_setup: save %sp, -0xe0, %sp ddi_regs_map_setup+4: ldx [%fp + 0x8af], %l0 >>>>> 0x8af = 0x7ff + 0xb0, access the Locals here. ddi_regs_map_setup+8: clr %o0 ddi_regs_map_setup+0xc: mov 0x1, %l1 ddi_regs_map_setup+0x10: call -0x2400cc <impl_acc_hdl_alloc> ddi_regs_map_setup+0x14: clr %o1 ddi_regs_map_setup+0x18: call -0x2400dc <impl_acc_hdl_get> ddi_regs_map_setup+0x1c: stx %o0, [%l0] ddi_regs_map_setup+0x20: st %l1, [%o0] ddi_regs_map_setup+0x24: mov 0x3, %l5 ddi_regs_map_setup+0x28: mov 0x2, %l4 ddi_regs_map_setup+0x2c: stx %i0, [%o0 + 0x18] ddi_regs_map_setup+0x30: mov %o0, %l2 ddi_regs_map_setup+0x34: add %fp, 0x7cf, %o1 ... My questions: 1. when the bias 0x7ff is subtracted from %sp? implicitly by the 'save'? 2. the bias area can also be used as Locals, temps, then when it is used? and when the explicitly allocated area is used? Thanks, Brian >>> # *mdb -k* >>> >>> *::threadlist* *-v* /<-- stack backtrace for all kernel threads/ >>> /< output truncated >/ >>> ============== thread_id 30000aa5500 0x30000b2ced9: >>> process args /usr/sbin/inetd -s /<-- inetd / >>> 0x30000aa5610: lwp procp wchan >>> 30000b4dba0 30000b2ca48 300007fe87a >>> 0x30000aa5538: pc sp >>> cv_wait_sig_swap+0x184 2a1003650a1 <-- stack pointer >>> is odd (i.e., has ABI-bias)// >>> cv_waituntil_sig+0x14(300007fe87a, 300007fe840, 0, 0, 3b, 20) >>> poll+0x424(ffbff5f8, 30000998d08, 3000004ec48, ffffffffffffffff, 0, 188) >>> syscall_trap32+0xa8(ffbff5f8, 31, ffffffffffffffff, 0, 1c, 40) >>> /< output truncated >/ >>> >>> >>> *30000aa5500::print kthread_t t_pcb* /<-- get the pc and sp from the >>> thread of inetd/ >>> { >>> t_pcb.val = [ 0x107bd1c, 0x2a1003650a1 ] >>> } >>> >>> *107bd1c/ai* /<-- same pc as threadlist shows/ >>> cv_wait_sig_swap+0x184: >>> cv_wait_sig_swap+0x184: call -0x3aeb4 >>> | >>> >>> The following shows the register save areas for each stack frame for >>> |inetd|. >>> >>> | >>> >>> *2a1003650a1+7ff,10/K* /<-- must add V9 bias, display 16 64-bit >>> hex values/ >>> 0x2a1003658a0: 30000b4dba0 30000b2ca48 0 >>> 300007fe87a /<-- %l0-%l3/ >>> 938 0 30000aa5500 >>> fffd /<-- %l4-%l7/ >>> 0 300007fe840 20 >>> 3000004edce /<-- %i0-%i3/ >>> 2a100365a00 0 2a100365151 >>> 107c14c /<-- %i4-%i7/ >>> >>> *107c14c/ai* /<-- %i7 is saved program counter/ >>> cv_waituntil_sig+0x14: >>> cv_waituntil_sig+0x14: call -0x5b4 >>> *2a100365151+7ff,10/K* /<-- %i6 is saved frame pointer, use to get >>> previous frame/ >>> 0x2a100365950: 0 3000004ec48 3b 0 >>> 30000c05798 30 300007fe840 >>> 30000bbb600 >>> 300007fe87a 300007fe840 0 0 >>> 3b 20 2a100365211 10bb378 >>> >>> *10bb378/ai* /<-- and repeat.../ >>> poll+0x424: poll+0x424: call -0x3f240 >>> *2a100365211+7ff,10/K* >>> 0x2a100365a10: 30000998d48 300007fe840 0 31 >>> 30000998d58 0 0 0 >>> ffbff5f8 30000998d08 3000004ec48 >>> ffffffffffffffff 0 188 >>> 2a1003652f1 10343fc >>> *10343fc/ai* /<-- and again.../ >>> >>> > > >>> In the above output, each frame's window save area is displayed. Hope >>> this helps. For 32-bit programs, the technique is the same, only you >>> don't >>> add 7ff, since the ABI-bias is not used. >>> Basically, ::findstack does the same walk that I am doing by hand in >>> the above output. >>> >>> >> very detailed info, impressive! >> > Thank you. > >> Thanks, >> Brian >> >>> max >>> >>> > > _______________________________________________ > mdb-discuss mailing list > mdb-discuss at opensolaris.org >