windows-nt/Source/XPSP1/NT/base/mvdm/wow16/toolhelp/stack2.asm
2020-09-26 16:20:57 +08:00

179 lines
7.5 KiB
NASM

;**************************************************************************
;* STACK2.ASM
;*
;* Assembly support code for stack tracing.
;*
;**************************************************************************
INCLUDE TOOLPRIV.INC
INCLUDE TDB.INC
;** External functions
externNP HelperVerifySeg
externNP HelperHandleToSel
;** Functions
sBegin CODE
assumes CS,CODE
; StackFrameFirst
; Returns information about the first stack frame and checks it
; for validity as much as possible. The first stack frame is found
; by getting the information from the TDB. If this task is active,
; or if the task was changed in an unusual way, this information
; may be incorrect. If it is, the user must set up the first
; CS, IP, and BP, and BPNext in the user structure, log it as the
; first stack trace and call StackTraceNext directly.
cProc StackFrameFirst, <NEAR,PUBLIC>, <si,di,ds>
parmD lpStack
parmW hTDB
cBegin
;** Verify that we have a good TDB first
;** Start by verifying the selector
mov ax,hTDB ;Get the selector
cCall HelperHandleToSel, <ax> ;Convert it to a selector
push ax ;Save it
mov bx,TDBSize
cCall HelperVerifySeg, <ax,bx>
pop bx ;Get selector back
or ax,ax ;FALSE return?
jnz SHORT SF_SelOk ;Selector's OK
xor ax,ax ;Return FALSE
jmp SHORT SF_End
SF_SelOk:
;** Verify that the TDB signature matches
mov ds,bx ;Point with DS
cmp ds:[TDB_sig],TDB_SIGNATURE ;Is this really a TDB?
jz SF_SigOk ;Must be
xor ax,ax ;Return FALSE
jmp SHORT SF_End
SF_SigOk:
;** Get the BP value from the task stack and store in structure
les di,lpStack ;Get a pointer to the user struct
mov ax,ds:[TDB_taskSS] ;Get the SS value
mov bx,ds:[TDB_taskSP] ;Get the max segment offset we need
add bx,Task_CS + 2
cCall HelperVerifySeg, <ax,bx> ;Make sure we can read all this
or ax,ax ;Error?
jz SF_End ;Yes, can't do walk
lds bx,DWORD PTR ds:[TDB_taskSP] ;Get the SS:SP value
mov si,ds:[bx].Task_BP ;Get the BP value from the stack
and si,NOT 1 ;Clear the FAR frame bit, if any
mov es:[di].st_wBP,si ;Store the BP value
mov ax,ds:[bx].Task_IP ;Store initial IP
mov es:[di].st_wIP,ax
mov ax,ds:[bx].Task_CS ;Store the initial CS
mov es:[di].st_wCS,ax
;** Return as much info as possible about this first frame
mov ax,hTDB ;Get the TDB handle
mov es:[di].st_hTask,ax ;Save in structure
mov es:[di].st_wSS,ds ;Save the SS value
mov es:[di].st_wFlags,FRAME_FAR ;Force a FAR frame this time
;** Try to verify this stuff
xor ax,ax ;In case we need to exit
or si,si ;End of the line?
jz SF_End ;Nope
cmp si,ds:[0ah] ;Compare against stack top
jb SF_End ;Fine with top
cmp si,ds:[0eh] ;Check against stack bottom
jae SF_End ;OK with bottom too
mov ax,1 ;Return TRUE
SF_End:
cEnd
; StackFrameNext
; Returns information in a public structure about the stack frame
; pointed to by the BP value passed in. Returns TRUE if the
; information seems valid, or FALSE if information could not be
; returned.
cProc StackFrameNext, <NEAR,PUBLIC>, <si,di,ds>
parmD lpStack
cBegin
;** Get pointers to the frame
les di,lpStack ;Get a pointer to the structure
mov ax,es:[di].st_wSS ;Get the stack segment
mov ds,ax ;Point with DS
;** Get the next stack frame
mov si,es:[di].st_wBP ;Get the current BP value
lea ax,[si + 6] ;Get the max stack probe
cmp ax,si ;No stack wraparound allowed
jb SN_End ;If below, we have wrapped
cCall HelperVerifySeg, <ds,ax> ;Make sure the stack is OK
or ax,ax ;OK?
jnz @F ;Yes.
jmp SHORT SN_End ;Return FALSE
@@: mov dx,ds:[si+4] ;DX:CX is the return address
mov cx,ds:[si+2]
mov bx,ds:[si] ;Get next BP value
;** Zero BP is end of chain
xor ax,ax ;In case we need to exit
or bx,bx ;End of the line?
jz SN_End ;Nope
;** If the new BP is higher on the stack than the old, it's invalid
cmp bx,si ;New BP <= Old BP?
jbe SN_End ;OK.
;** Make sure we're still on the stack (variables from KDATA.ASM)
cmp bx,ds:[0ah] ;Compare against stack top
jb SN_End ;Fine with top
cmp bx,ds:[0eh] ;Check against stack bottom
jae SN_End ;OK with bottom too
;** Return what we can about the frame
mov es:[di].st_wSS,ds ;Save the SS value
mov es:[di].st_wBP,si ; and the BP value
test bx,1 ;Far or near frame?
jnz SN_FarFrame ;For sure far if BP is odd
;** Even when BP is not odd, we may have a far frame
mov ax,cs ;Get our RPL bits
and al,3 ;Mask RPL bits
mov ah,dl ;Get frame's RPL bits
and ah,3 ;Mask RPL bits
cmp al,ah ;If CS is a handle, they won't match
jne SN_NearFrame ;Bits don't match
lar ax,dx ;Get the access bits
test ax,800h ;Is this a code segment?
jz SN_NearFrame ;No. MUST be near frame
lsl ax,dx ;Get the limit
cmp ax,cx ;Inside limit?
jbe SN_NearFrame ;No. MUST be near
;** Otherwise, probably is a far frame. It may not be, of course,
;** because this may be a code seg parameter
SN_FarFrame:
mov es:[di].st_wIP,cx ;Save the offset
mov es:[di].st_wCS,dx ; and selector value
mov ax,FRAME_FAR ;Tell the user what we did
and bx,NOT 1 ;Clear the far frame bit
jmp SHORT SN_20 ;Skip near section
;** Must be a near frame
SN_NearFrame:
mov es:[di].st_wIP,cx ;Save the offset
;Leave the old CS value in
mov ax,FRAME_NEAR ;Tell the user what we did
SN_20: mov es:[di].st_wFlags,ax ;Save in the structure
mov es:[di].st_wBP,bx ;Save BP in the structure
mov ax,1 ;Return TRUE
SN_End:
cEnd
sEnd
END