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
>   


Reply via email to