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. > >> # *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 >>