Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

822 lines
19 KiB

  1. ; Copyright (c) 1995 Microsoft Corporation
  2. ;
  3. ; Module Name:
  4. ;
  5. ; thunk.s
  6. ;
  7. ; Abstract:
  8. ;
  9. ; Implements the API thunk that gets executed for all
  10. ; re-directed APIS.
  11. ;
  12. ; Author:
  13. ;
  14. ; Wesley Witt (wesw) 28-June-1995
  15. ;
  16. ; Environment:
  17. ;
  18. ; User Mode
  19. ;
  20. .386p
  21. include ks386.inc
  22. include callconv.inc
  23. TRACE equ 0
  24. EXTRNP _HandleDynamicDllLoadA,2
  25. EXTRNP _HandleDynamicDllLoadW,2
  26. EXTRNP _HandleDynamicDllFree,1
  27. EXTRNP _HandleGetProcAddress,1
  28. EXTRNP _HandleRegisterClassA,1
  29. EXTRNP _HandleRegisterClassW,1
  30. EXTRNP _HandleSetWindowLong,3
  31. EXTRNP _QueryPerformanceCounter,1
  32. EXTRNP _ApiTrace,9
  33. EXTRNP _GetApiInfo,4
  34. extrn _FastCounterAvail:DWORD
  35. extrn _ApiCounter:DWORD
  36. extrn _ApiTimingEnabled:DWORD
  37. extrn _ApiTraceEnabled:DWORD
  38. extrn _pTlsGetValue:DWORD
  39. extrn _pTlsSetValue:DWORD
  40. extrn _pGetLastError:DWORD
  41. extrn _pSetLastError:DWORD
  42. extrn _TlsReEnter:DWORD
  43. extrn _TlsStack:DWORD
  44. extrn _ThunkOverhead:DWORD
  45. extrn _ThunkCallOverhead:DWORD
  46. if TRACE
  47. extrn _dprintf:NEAR
  48. endif
  49. APITYPE_NORMAL equ 0
  50. APITYPE_LOADLIBRARYA equ 1
  51. APITYPE_LOADLIBRARYW equ 2
  52. APITYPE_FREELIBRARY equ 3
  53. APITYPE_REGISTERCLASSA equ 4
  54. APITYPE_REGISTERCLASSW equ 5
  55. APITYPE_GETPROCADDRESS equ 6
  56. APITYPE_SETWINDOWLONG equ 7
  57. APITYPE_WNDPROC equ 8
  58. APITYPE_INVALID equ 9
  59. DllEnabledOffset equ 52
  60. ApiInfoAddressOffset equ 4
  61. ApiInfoCountOffset equ 12
  62. ApiInfoTimeOffset equ 16
  63. ApiInfoCalleeTimeOffset equ 24
  64. ApiInfoNestCountOffset equ 32
  65. ApiInfoTraceEnabled equ 36
  66. ApiInfoTableOffset equ 40
  67. ApiTableCountOffset equ 8
  68. API_TRACE equ 1
  69. API_FULLTRACE equ 2
  70. LastErrorSave equ 0
  71. EdiSave equ 4
  72. EsiSave equ 8
  73. EdxSave equ 12
  74. EcxSave equ 16
  75. EbxSave equ 20
  76. EaxSave equ 24
  77. ApiFlagSave equ 28
  78. DllInfoSave equ 32
  79. ApiInfoSave equ 36
  80. RetAddrSave equ 40
  81. StackSize equ 44
  82. EbpFrm equ 0
  83. DllInfoFrm equ 4
  84. ApiInfoFrm equ 8
  85. ApiFlagFrm equ 12
  86. ApiBiasFrm equ 16
  87. RetAddrFrm equ 20
  88. LastErrorFrm equ 24
  89. Arg0Frm equ 28
  90. Arg1Frm equ 32
  91. Arg2Frm equ 36
  92. Arg3Frm equ 40
  93. Arg4Frm equ 44
  94. Arg5Frm equ 48
  95. Arg6Frm equ 52
  96. Arg7Frm equ 56
  97. OverheadTimeFrm equ 64
  98. FuncTimeFrm equ 72
  99. CalleeTimeFrm equ 80
  100. TempTimeFrm equ 88
  101. FrameSize equ 96
  102. ;
  103. ; Routine Description:
  104. ;
  105. ; This MACRO gets a performance counter value.
  106. ; If we are running on a uni-processor pentium
  107. ; then we can use the rdtsc instruction. Otherwise
  108. ; we must use the QueryPerformanceCounter API.
  109. ;
  110. ; Arguments:
  111. ;
  112. ; CounterOffset - the offset from ebp where the
  113. ; counter data is to be stored.
  114. ;
  115. ; Return Value:
  116. ;
  117. ; None.
  118. ;
  119. GET_PERFORMANCE_COUNTER macro CounterOffset
  120. local DoPentium,PentiumExit
  121. mov eax,[_FastCounterAvail]
  122. mov eax,[eax]
  123. or eax,eax
  124. jnz DoPentium
  125. mov eax,ebp
  126. add eax,CounterOffset
  127. push eax
  128. call _QueryPerformanceCounter@4
  129. jmp PentiumExit
  130. DoPentium:
  131. db 0fh,31h ; RDTSC instruction
  132. mov [ebp+CounterOffset],eax
  133. mov [ebp+CounterOffset+4],edx
  134. PentiumExit:
  135. endm
  136. _TEXT SEGMENT PARA PUBLIC 'CODE'
  137. ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
  138. if TRACE
  139. Msg1 db 'ApiMonThunk() 0x%08x',0ah,00
  140. Msg2 db 'ApiMonThunkComplete() 0x%08x',0ah,00
  141. endif
  142. ;
  143. ; Routine Description:
  144. ;
  145. ; This function is jumped to after a monitored
  146. ; API has completed. Here we do our cleanup
  147. ; and then branch to the caller's return address.
  148. ;
  149. ; Arguments:
  150. ;
  151. ; ebp - points to the api's frame on our parallel stack
  152. ; eax - return value
  153. ; edx - return value
  154. ;
  155. ; Return Value:
  156. ;
  157. ; None.
  158. ;
  159. cPublicProc _ApiMonThunkComplete,0
  160. ;
  161. ; save registers
  162. ;
  163. push eax
  164. push ebx
  165. push ecx
  166. push edx
  167. push esi
  168. push edi
  169. ;
  170. ; save the last error value
  171. ;
  172. call _pGetLastError
  173. push eax
  174. if TRACE
  175. ;
  176. ; trace the call
  177. ;
  178. mov eax,[ebp+ApiInfoFrm]
  179. mov eax,[eax+ApiInfoAddressOffset]
  180. push eax
  181. push offset FLAT:Msg2
  182. call _dprintf
  183. add esp,8
  184. endif
  185. ;
  186. ; check for counting enabled
  187. ;
  188. mov edx,[ebp+DllInfoFrm]
  189. mov eax,[edx+DllEnabledOffset]
  190. or eax,eax
  191. jz NoCounting
  192. ;
  193. ; decrement nesting count for this api
  194. ;
  195. mov eax,[ebp+ApiInfoFrm]
  196. dec dword ptr [eax+ApiInfoNestCountOffset]
  197. ;
  198. ; Compute total function time
  199. ;
  200. GET_PERFORMANCE_COUNTER TempTimeFrm
  201. mov eax,[ebp+TempTimeFrm]
  202. mov edx,[ebp+TempTimeFrm+4]
  203. sub eax,[ebp+FuncTimeFrm]
  204. sbb edx,[ebp+FuncTimeFrm+4]
  205. sub eax,_ThunkOverhead
  206. sbb edx,0
  207. mov [ebp+FuncTimeFrm],eax
  208. mov [ebp+FuncTimeFrm+4],edx
  209. ;
  210. ; Remove function time from our overhead time
  211. ; by adding advancing the overhead start time
  212. ;
  213. add [ebp+OverheadTimeFrm],eax
  214. adc [ebp+OverheadTimeFrm+4],edx
  215. ;
  216. ; accumulate function time for the API
  217. ;
  218. mov edi,[ebp+ApiInfoFrm]
  219. add [edi+ApiInfoTimeOffset],eax
  220. adc [edi+ApiInfoTimeOffset+4],edx
  221. ;
  222. ; add time to callee time of parent frame
  223. ;
  224. add [ebp - FrameSize + CalleeTimeFrm],eax
  225. adc [ebp - FrameSize + CalleeTimeFrm+4],edx
  226. ;
  227. ; accumulate own callee time for the API
  228. ;
  229. mov eax, [ebp+CalleeTimeFrm]
  230. mov edx, [ebp+CalleeTimeFrm+4]
  231. add [edi+ApiInfoCalleeTimeOffset],eax
  232. adc [edi+ApiInfoCalleeTimeOffset+4],edx
  233. NoCounting:
  234. ;
  235. ; handle load library and get process address specialy
  236. ;
  237. mov ecx,[ebp+ApiFlagFrm]
  238. or ecx,ecx
  239. jz ThunkNormal
  240. ;
  241. ; branch to the correct handler
  242. ;
  243. cmp ecx,APITYPE_LOADLIBRARYA
  244. jz DoLoadLibraryA
  245. cmp ecx,APITYPE_LOADLIBRARYW
  246. jz DoLoadLibraryW
  247. cmp ecx,APITYPE_FREELIBRARY
  248. jz DoFreeLibrary
  249. cmp ecx,APITYPE_GETPROCADDRESS
  250. jz DoGetProcAddress
  251. cmp ecx,APITYPE_WNDPROC ; no tracing for wnd procs yet
  252. jz NoTracing
  253. jmp ThunkNormal
  254. DoFreeLibrary:
  255. push [ebp+Arg0Frm]
  256. call _HandleDynamicDllFree@4
  257. jmp ThunkNormal
  258. DoLoadLibraryW:
  259. push [ebp+Arg0Frm]
  260. push [esp+EaxSave+4]
  261. call _HandleDynamicDllLoadW@8
  262. jmp ThunkNormal
  263. DoLoadLibraryA:
  264. push [ebp+Arg0Frm]
  265. push [esp+EaxSave+4]
  266. call _HandleDynamicDllLoadA@8
  267. jmp ThunkNormal
  268. DoGetProcAddress:
  269. push [esp+EaxSave]
  270. call _HandleGetProcAddress@4
  271. mov [esp+EaxSave],eax
  272. jmp ThunkNormal
  273. ThunkNormal:
  274. ;
  275. ; do the api tracing?
  276. ;
  277. mov eax,[_ApiTraceEnabled]
  278. mov eax,[eax]
  279. or eax, eax
  280. jz NoTracing
  281. mov eax,[ebp+DllInfoFrm]
  282. mov eax,[eax+DllEnabledOffset]
  283. or eax,eax
  284. jz NoTracing
  285. mov eax,[ebp+ApiInfoFrm]
  286. mov eax,[eax+ApiInfoTraceEnabled]
  287. or eax,eax
  288. jz NoTracing
  289. ;
  290. ; trace the api
  291. ;
  292. mov eax,[esp+EaxSave] ; get ret value
  293. push [esp+LastErrorSave] ; last error value
  294. push [ebp+FuncTimeFrm+4] ; function duration
  295. push [ebp+FuncTimeFrm]
  296. push [ebp+TempTimeFrm+4] ; exit time
  297. push [ebp+TempTimeFrm]
  298. push [ebp+RetAddrFrm] ; caller's address
  299. push eax ; return value
  300. lea eax,[ebp+Arg0Frm] ; parameter array
  301. push eax
  302. push [ebp+ApiInfoFrm] ; apiinfo pointer
  303. call _ApiTrace@36
  304. NoTracing:
  305. ;
  306. ; Compute our overhead time
  307. ;
  308. GET_PERFORMANCE_COUNTER TempTimeFrm
  309. mov eax,[ebp+TempTimeFrm]
  310. mov edx,[ebp+TempTimeFrm+4]
  311. sub eax,[ebp+OverheadTimeFrm]
  312. sbb edx,[ebp+OverheadTimeFrm+4]
  313. add eax,_ThunkCallOverhead
  314. adc edx,0
  315. ;
  316. ; Subtract from parent's function time
  317. ; by advancing the function start time
  318. ;
  319. add [ebp - FrameSize + FuncTimeFrm],eax
  320. adc [ebp - FrameSize + FuncTimeFrm+4],edx
  321. ;
  322. ; destroy the frame on the stack
  323. ;
  324. push _TlsStack
  325. call _pTlsGetValue
  326. mov [eax],ebp
  327. ;
  328. ; reset the last error value (already on the stack)
  329. ;
  330. call _pSetLastError
  331. ;
  332. ; restore the registers
  333. ;
  334. pop edi
  335. pop esi
  336. pop edx
  337. pop ecx
  338. pop ebx
  339. pop eax
  340. push [ebp+RetAddrFrm]
  341. mov ebp,[ebp]
  342. ;
  343. ; finally branch back to the caller
  344. ;
  345. ret
  346. stdENDP _ApiMonThunkComplete
  347. ;
  348. ; Routine Description:
  349. ;
  350. ; This function is the entry point for the api
  351. ; monitor thunk.
  352. ;
  353. ; Arguments:
  354. ;
  355. ; [esp+0] - API flag
  356. ; [esp+4] - DLLINFO pointer
  357. ; [esp+8] - APIINFO pointer
  358. ;
  359. ; Return Value:
  360. ;
  361. ; None.
  362. ;
  363. cPublicProc _ApiMonThunk,0
  364. ;
  365. ; save regs
  366. ;
  367. push eax
  368. push ebx
  369. push ecx
  370. push edx
  371. push esi
  372. push edi
  373. ;
  374. ; save the last error value
  375. ;
  376. call _pGetLastError
  377. push eax
  378. ;
  379. ; get the reentry flag
  380. ;
  381. push _TlsReEnter
  382. call _pTlsGetValue
  383. ;
  384. ; don't enter if disallow flag is set
  385. ;
  386. or eax,eax
  387. jz ThunkOk
  388. BadStack:
  389. ;
  390. ; replace ApiInfo pointer with Api address
  391. ; so we can ret to it
  392. ;
  393. mov ebx,[esp+ApiInfoSave]
  394. mov eax,dword ptr [ebx+ApiInfoAddressOffset]
  395. mov [esp+ApiInfoSave],eax
  396. ;
  397. ; reset the last error value
  398. ;
  399. call _pSetLastError
  400. ;
  401. ; restore the registers
  402. ;
  403. pop edi
  404. pop esi
  405. pop edx
  406. pop ecx
  407. pop ebx
  408. pop eax
  409. add sp,8 ; dump ApiFlag & DllInfo space
  410. ret ; jmp to real Api
  411. ThunkOk:
  412. ;
  413. ; get the parallel stack pointer
  414. ;
  415. push _TlsStack
  416. call _pTlsGetValue
  417. or eax,eax
  418. jz BadStack
  419. ;
  420. ; setup the frame pointer
  421. ;
  422. mov edx,[eax]
  423. mov [edx],ebp
  424. mov ebp,edx
  425. ;
  426. ; create a frame on the stack by advancing the pointer
  427. ;
  428. add edx,FrameSize
  429. mov [eax],edx
  430. ;
  431. ; clear ApiBias, entry from _penter uses bias
  432. ;
  433. mov [ebp+ApiBiasFrm],0
  434. Thunk_Middle:
  435. ;
  436. ; get the arguments from the mini-thunk
  437. ;
  438. mov eax,[esp+ApiFlagSave]
  439. mov [ebp+ApiFlagFrm],eax
  440. mov eax,[esp+DllInfoSave]
  441. mov [ebp+DllInfoFrm],eax
  442. mov eax,[esp+RetAddrSave]
  443. mov [ebp+RetAddrFrm],eax
  444. mov eax,[esp+ApiInfoSave]
  445. mov [ebp+ApiInfoFrm],eax
  446. ;
  447. ; save the real arguments
  448. ;
  449. mov eax,[esp+StackSize]
  450. mov [ebp+Arg0Frm],eax
  451. mov eax,[esp+StackSize+4]
  452. mov [ebp+Arg1Frm],eax
  453. mov eax,[esp+StackSize+8]
  454. mov [ebp+Arg2Frm],eax
  455. mov eax,[esp+StackSize+12]
  456. mov [ebp+Arg3Frm],eax
  457. mov eax,[esp+StackSize+16]
  458. mov [ebp+Arg4Frm],eax
  459. mov eax,[esp+StackSize+20]
  460. mov [ebp+Arg5Frm],eax
  461. mov eax,[esp+StackSize+24]
  462. mov [ebp+Arg6Frm],eax
  463. mov eax,[esp+StackSize+28]
  464. mov [ebp+Arg7Frm],eax
  465. ;
  466. ; zero the callee time
  467. ;
  468. mov [ebp+CalleeTimeFrm],0
  469. mov [ebp+CalleeTimeFrm+4],0
  470. ;
  471. ; start the overhead timer, because it is variable from here on
  472. ;
  473. GET_PERFORMANCE_COUNTER OverheadTimeFrm
  474. ;
  475. ; Do special API processing
  476. ;
  477. mov eax,[ebp+ApiFlagFrm]
  478. or eax,eax
  479. jz ThunkNotSpecial
  480. cmp eax,APITYPE_REGISTERCLASSA
  481. jz DoRegisterClassA
  482. cmp eax,APITYPE_REGISTERCLASSW
  483. jz DoRegisterClassW
  484. cmp eax,APITYPE_SETWINDOWLONG
  485. jz DoSetWindowLong
  486. jmp ThunkNotSpecial
  487. DoRegisterClassA:
  488. push [ebp+Arg0Frm]
  489. call _HandleRegisterClassA@4
  490. jmp ThunkNotSpecial
  491. DoRegisterClassW:
  492. push [ebp+Arg0Frm]
  493. call _HandleRegisterClassW@4
  494. jmp ThunkNotSpecial
  495. DoSetWindowLong:
  496. push [ebp+Arg2Frm]
  497. push [ebp+Arg1Frm]
  498. push [ebp+Arg0Frm]
  499. call _HandleSetWindowLong@12
  500. mov [esp+StackSize+8],eax ; Replace new long value parameter
  501. ThunkNotSpecial:
  502. ;
  503. ; change the return address to point to completion routine
  504. ;
  505. mov [esp+RetAddrSave],_ApiMonThunkComplete
  506. if TRACE
  507. ;
  508. ; trace the call
  509. ;
  510. mov eax,[ebp+ApiInfoFrm]
  511. mov eax,[eax+ApiInfoAddressOffset]
  512. push eax
  513. push offset FLAT:Msg1
  514. call _dprintf
  515. add esp,8
  516. endif
  517. ;
  518. ; check to see if api counting is enabled
  519. ; if not then bypass the counting code
  520. ;
  521. mov eax,[ebp+DllInfoFrm]
  522. mov eax,[eax+DllEnabledOffset]
  523. or eax, eax
  524. jz ThunkBypass
  525. ;
  526. ; increment the api's counters
  527. ;
  528. mov eax,[ebp+ApiInfoFrm]
  529. inc dword ptr [eax+ApiInfoCountOffset]
  530. inc dword ptr [eax+ApiInfoNestCountOffset]
  531. ;
  532. ; increment the global api counter
  533. ;
  534. mov eax,_ApiCounter
  535. inc dword ptr [eax]
  536. ThunkBypass:
  537. ;
  538. ; Replace ApiInfo pointer with ApiAddr (+bias)
  539. ;
  540. mov ebx,[ebp+ApiInfoFrm]
  541. mov eax,dword ptr [ebx+ApiInfoAddressOffset]
  542. mov ecx,[ebp+ApiBiasFrm]
  543. add eax,ecx
  544. mov [esp+ApiInfoSave],eax
  545. ;
  546. ; start the function timer here
  547. ;
  548. GET_PERFORMANCE_COUNTER FuncTimeFrm
  549. ;
  550. ; reset the last error value (already on stack)
  551. ;
  552. call _pSetLastError
  553. ;
  554. ; restore the registers
  555. ;
  556. pop edi
  557. pop esi
  558. pop edx
  559. pop ecx
  560. pop ebx
  561. pop eax
  562. add sp,8 ; dump ApiFlag & DllInfo from stack
  563. ret ; jump to Api
  564. stdENDP _ApiMonThunk
  565. ;
  566. ; Routine Description:
  567. ;
  568. ; This function is called when an application
  569. ; is compiled with -Gh. It performs the same
  570. ; function as ApiMonThunk does for non-instrumented
  571. ; code.
  572. ;
  573. ; Arguments:
  574. ;
  575. ; None.
  576. ;
  577. ; Return Value:
  578. ;
  579. ; None.
  580. ;
  581. align dword
  582. public __penter
  583. __penter proc
  584. ;
  585. ; allot space on stack for two api thunk parameters
  586. ; the third will replace the return address
  587. ;
  588. sub sp,8
  589. ;
  590. ; save regs
  591. ;
  592. push eax
  593. push ebx
  594. push ecx
  595. push edx
  596. push esi
  597. push edi
  598. ;
  599. ; save the last error value
  600. ;
  601. call _pGetLastError
  602. push eax
  603. ;
  604. ; get the parallel stack pointer
  605. ;
  606. push _TlsStack
  607. call _pTlsGetValue
  608. or eax,eax
  609. jnz Good_Stack
  610. ;
  611. ; reset the last error value
  612. ;
  613. call _pSetLastError
  614. ;
  615. ; restore the stack
  616. ;
  617. pop edi
  618. pop esi
  619. pop edx
  620. pop ecx
  621. pop ebx
  622. pop eax
  623. add sp,8
  624. ;
  625. ; jump to the real api
  626. ;
  627. ret
  628. Good_Stack:
  629. ;
  630. ; setup the frame pointer
  631. ;
  632. mov edx,[eax]
  633. mov [edx],ebp
  634. mov ebp,edx
  635. ;
  636. ; create a frame on the stack
  637. ;
  638. add edx,FrameSize
  639. mov [eax],edx
  640. ;
  641. ; get Api info from the return address, which is really
  642. ; the address of the function that is being profiled
  643. ;
  644. mov eax,[esp+ApiInfoSave] ; this is really the return to the Api
  645. mov [ebp+RetAddrFrm],eax ; save for exit in case Api not found
  646. lea ecx,[esp+ApiFlagSave]
  647. push eax
  648. push ecx
  649. add ecx,4
  650. push ecx
  651. add ecx,4
  652. push ecx
  653. call _GetApiInfo@16
  654. or eax,eax
  655. jz Api_NotFound
  656. mov [ebp+ApiBiasFrm],5
  657. jmp Thunk_Middle
  658. Api_NotFound:
  659. ;
  660. ; put back saved return address
  661. ;
  662. mov eax,[ebp+RetAddrFrm]
  663. mov [esp+ApiInfoSave],eax
  664. ;
  665. ; tear down this frame
  666. ;
  667. push _TlsStack
  668. call _pTlsGetValue
  669. mov [eax],ebp
  670. ;
  671. ; reset the last error value (already on the stack)
  672. ;
  673. call _pSetLastError
  674. ;
  675. ; restore the registers
  676. ;
  677. pop edi
  678. pop esi
  679. pop edx
  680. pop ecx
  681. pop ebx
  682. pop eax
  683. mov ebp,[ebp]
  684. ;
  685. ; discard unused api thunk space
  686. ;
  687. add esp,8
  688. ;
  689. ; jump to the real api
  690. ;
  691. ret
  692. __penter endp
  693. _TEXT ENDS
  694. end