1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
|
TITLE "Capture Stack Back Trace"
;++
;
; Copyright (c) 1989 Microsoft Corporation
;
; Module Name:
;
; getcalr.s
;
; Abstract:
;
; This module implements the routine RtlCaptureStackBackTrace. It will
; walker the stack back trace and capture a portion of it.
;
; Author:
;
; Steve Wood (stevewo) 29-Jan-1992
;
; Environment:
;
; Any mode.
;
; Revision History:
;
;--
.386p
.xlist
include ks386.inc
include callconv.inc ; calling convention macros
.list
IFDEF NTOS_KERNEL_RUNTIME
EXTRNP _MmIsAddressValid,1
EXTRNP _KeGetCurrentIrql,0,IMPORT
ENDIF
_TEXT SEGMENT DWORD PUBLIC 'CODE'
ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
page ,132
subttl "RtlCaptureStackBackTrace"
;++
;
; USHORT
; RtlCaptureStackBackTrace(
; IN ULONG FramesToSkip,
; IN ULONG FramesToCapture,
; OUT PVOID *BackTrace,
; OUT PULONG BackTraceHash
; )
;
; Routine Description:
;
; This routine walks up the stack frames, capturing the return address from
; each frame requested.
;
;
; Arguments:
;
; OUT PVOID BackTrace (eps+0x10) - Returns the caller of the caller.
;
;
; Return Value:
;
; Number of return addresses returned in the BackTrace buffer.
;
;
;--
RcbtFramesToSkip EQU [ebp+08h]
RcbtFramesToCapture EQU [ebp+0Ch]
RcbtBackTrace EQU [ebp+010h]
RcbtBackTraceHash EQU [ebp+014h]
IFDEF NTOS_KERNEL_RUNTIME
RcbtInitialStack EQU [ebp-10h]
ENDIF
cPublicProc _RtlCaptureStackBackTrace ,4
IFDEF NTOS_KERNEL_RUNTIME
IF FPO
xor eax,eax
stdRET _RtlCaptureStackBackTrace
ENDIF
push ebp
mov ebp, esp
push ebx ; Save EBX
push esi ; Save ESI
push edi ; Save EDI
mov eax, PCR[PcPrcbData+PbCurrentThread] ; (eax)->current thread
push ThInitialStack[eax] ; RcbtInitialStack = base of kernel stack
mov esi,RcbtBackTraceHash ; (ESI) -> where to accumulate hash sum
mov edi,RcbtBackTrace ; (EDI) -> where to put backtrace
mov edx,ebp ; (EDX) = current frame pointer
mov ecx,RcbtFramesToSkip ; (ECX) = number of frames to skip
jecxz RcbtSkipLoopDone ; Done if nothing to skip
RcbtSkipLoop:
mov edx,[edx] ; (EDX) = next frame pointer
cmp edx,ebp ; If outside stack limits,
jbe RcbtCheckSkipU ; ...then exit
cmp edx,RcbtInitialStack
jae RcbtCheckSkipU
loop RcbtSkipLoop
RcbtSkipLoopDone:
mov ecx,RcbtFramesToCapture ; (ECX) = number of frames to capture
jecxz RcbtExit ; Bail out if nothing to capture
RcbtCaptureLoop:
mov eax,[edx].4 ; Get next return address
stosd ; Store it in the callers buffer
add [esi],eax ; Accumulate hash sum
mov edx,[edx] ; (EDX) = next frame pointer
cmp edx,ebp ; If outside stack limits,
jbe RcbtCheckCaptureU ; ...then exit
cmp edx,RcbtInitialStack
jae RcbtCheckCaptureU
loop RcbtCaptureLoop ; Otherwise get next frame
RcbtExit:
mov eax,edi ; (EAX) -> next unused dword in buffer
sub eax,RcbtBackTrace ; (EAX) = number of bytes stored
shr eax,2 ; (EAX) = number of dwords stored
pop edi ; discard RcbtInitialStack
pop edi ; Restore EDI
pop esi ; Restore ESI
pop ebx ; Restore EBX
pop ebp
stdRET _RtlCaptureStackBackTrace
RcbtCheckSkipU:
stdCall _KeGetCurrentIrql ; (al) = CurrentIrql
cmp al, 0 ; Bail out if not at IRQL 0
ja RcbtExit
mov ebx, PCR[PcPrcbData+PbCurrentThread] ; (ebx)->current thread
cmp byte ptr ThApcStateIndex[ebx],1 ; Bail out if attached.
je RcbtExit
mov ebx, ThTeb[ebx] ; (EBX) -> User mode TEB
or ebx, ebx
jnz @F
jmp short RcbtExit
RcbtSkipLoopU:
mov edx,[edx] ; (EDX) = next frame pointer
@@:
cmp edx,PcStackLimit[ebx] ; If outside stack limits,
jbe RcbtExit ; ...then exit
cmp edx,PcInitialStack[ebx]
jae RcbtExit
loop RcbtSkipLoopU
mov ecx,RcbtFramesToCapture ; (ECX) = number of frames to capture
jecxz RcbtExit ; Bail out if nothing to capture
RcbtCaptureLoopU:
mov eax,[edx].4 ; Get next return address
stosd ; Store it in the callers buffer
add [esi],eax ; Accumulate hash sum
mov edx,[edx] ; (EDX) = next frame pointer
@@:
cmp edx,PcStackLimit[ebx] ; If outside stack limits,
jbe RcbtExit ; ...then exit
cmp edx,PcInitialStack[ebx]
jae RcbtExit
loop RcbtCaptureLoopU ; Otherwise get next frame
jmp short RcbtExit
RcbtCheckCaptureU:
stdCall _KeGetCurrentIrql ; (al) = CurrentIrql
cmp al, 0 ; Bail out if not at IRQL 0
ja RcbtExit
mov ebx, PCR[PcPrcbData+PbCurrentThread] ; (ebx)->current thread
cmp byte ptr ThApcStateIndex[ebx],1 ; Bail out if attached.
je RcbtExit
mov ebx, ThTeb[ebx] ; (EBX) -> User mode TEB
or ebx, ebx
jnz @B
jmp RcbtExit ; Bail out if TEB == NULL
ELSE
;
; This is defined always for user mode code, although it can be
; unreliable if called from code compiled with FPO enabled.
;
push ebp
mov ebp, esp
push esi ; Save ESI
push edi ; Save EDI
mov esi,RcbtBackTraceHash ; (ESI) -> where to accumulate hash sum
mov edi,RcbtBackTrace ; (EDI) -> where to put backtrace
mov edx,ebp ; (EDX) = current frame pointer
mov ecx,RcbtFramesToSkip ; (ECX) = number of frames to skip
jecxz RcbtSkipLoopDone ; Done if nothing to skip
RcbtSkipLoop:
mov edx,[edx] ; (EDX) = next frame pointer
cmp edx,fs:PcStackLimit ; If outside stack limits,
jbe RcbtExit ; ...then exit
cmp edx,fs:PcInitialStack
jae RcbtExit
loop RcbtSkipLoop
RcbtSkipLoopDone:
mov ecx,RcbtFramesToCapture ; (ECX) = number of frames to capture
jecxz RcbtExit ; Bail out if nothing to capture
RcbtCaptureLoop:
mov eax,[edx].4 ; Get next return address
stosd ; Store it in the callers buffer
add [esi],eax ; Accumulate hash sum
mov edx,[edx] ; (EDX) = next frame pointer
cmp edx,fs:PcStackLimit ; If outside stack limits,
jbe RcbtExit ; ...then exit
cmp edx,fs:PcInitialStack
jae RcbtExit
loop RcbtCaptureLoop ; Otherwise get next frame
RcbtExit:
mov eax,edi ; (EAX) -> next unused dword in buffer
sub eax,RcbtBackTrace ; (EAX) = number of bytes stored
shr eax,2 ; (EAX) = number of dwords stored
pop edi ; Restore EDI
pop esi ; Restore ESI
pop ebp
stdRET _RtlCaptureStackBackTrace
ENDIF
stdENDP _RtlCaptureStackBackTrace
_TEXT ends
end
|