Source code of Windows XP (NT5)
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.

452 lines
13 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996-2000
  5. //
  6. // File: ciexcpt.cxx
  7. //
  8. // Contents: Macro package for C++ exception support
  9. //
  10. // Classes: CException -- The base for all exception classes
  11. // CExceptionContext -- Per-thread exception context.
  12. // CUnwindable -- Classes with destructors inherit
  13. // from this.
  14. //
  15. // History: 22-May-91 KyleP Created Interface.
  16. // 15-Aug-91 SethuR Included terminate(),unexpected()
  17. // set_unexpected(),set_terminate()
  18. // 18-Oct-91 KyleP Win32 try/except implementation
  19. // 19-Nov-91 KyleP Fix heap unwind, multiple inheritance
  20. // 14-May-92 BryanT Disable heapchk for FLAT builds.
  21. // 25-Apr-95 DwightKr Native C++ exception support
  22. // 30-Oct-98 KLam Translate in page error to disk full
  23. // when appropriate
  24. // 07-Jan-99 KLam Debug out when in page error occurs
  25. //
  26. // Notest: This file is a hack until C 9.x supports exceptions for
  27. // compilers on all platforms
  28. //
  29. //----------------------------------------------------------------------------
  30. #include <pch.cxx>
  31. #pragma hdrstop
  32. //#include <nulock.hxx>
  33. #if CIDBG == 1
  34. extern "C" {
  35. #include <imagehlp.h>
  36. #define MAX_TRANSLATED_LEN 80
  37. }
  38. #include "snapimg.hxx"
  39. void TranslateAddress(
  40. ULONG p,
  41. char *achBuffer,
  42. ULONG cchBuffer)
  43. {
  44. BYTE symbolInfo[sizeof(IMAGEHLP_SYMBOL) + MAX_TRANSLATED_LEN];
  45. PIMAGEHLP_SYMBOL psym = (PIMAGEHLP_SYMBOL) symbolInfo;
  46. DWORD_PTR dwDisplacement;
  47. psym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
  48. psym->MaxNameLength = MAX_TRANSLATED_LEN;
  49. HANDLE hProcess = GetCurrentProcess();
  50. if ( SnapToImageHlp( ) &&
  51. LocalSymGetSymFromAddr( hProcess,
  52. (ULONG_PTR)p,
  53. &dwDisplacement,
  54. psym )
  55. )
  56. {
  57. char * pszFormat = dwDisplacement ? "%s+0x%p\n" : "%s\n";
  58. char achTmpBuf[ MAX_TRANSLATED_LEN ];
  59. if ( LocalSymUnDName( psym, achTmpBuf, MAX_TRANSLATED_LEN ) )
  60. {
  61. _snprintf( achBuffer, cchBuffer,
  62. pszFormat,
  63. achTmpBuf,
  64. dwDisplacement );
  65. }
  66. else
  67. {
  68. _snprintf( achBuffer, cchBuffer,
  69. pszFormat,
  70. psym->Name,
  71. dwDisplacement );
  72. }
  73. }
  74. else
  75. {
  76. _snprintf( achBuffer, cchBuffer,
  77. "%px (symbolic name unavailable)",
  78. (ULONG_PTR)p );
  79. }
  80. }
  81. #endif // CIDBG
  82. //
  83. // If EXCEPT_TEST is defined, then the exception code can be compiled
  84. // without use the the 'Win4 environment'. This is only to facilitate
  85. // testing. When EXCEPT_TEST is defined debug messages are printed
  86. // to stdout instead of the debug terminal.
  87. //
  88. #if !defined( EXCEPT_TEST )
  89. # if CIDBG == 1
  90. DECLARE_DEBUG( ex )
  91. //
  92. // See ciexcpt.hxx for an explanation of why exInlineDebugOut isn't used.
  93. //
  94. void exInlineDebugOut2(unsigned long fDebugMask, char const *pszfmt, ...)
  95. {
  96. va_list ArgList;
  97. va_start(ArgList, pszfmt);
  98. if (exInfoLevel & fDebugMask)
  99. {
  100. vdprintf(fDebugMask, exInfoLevelString, (char const *) pszfmt, ArgList);
  101. }
  102. va_end(ArgList);
  103. }
  104. # endif // (CIDBG == 1)
  105. # if CIDBG == 1
  106. //
  107. // The default is to print exception messages to debug terminal.
  108. //
  109. unsigned long Win4ExceptionLevel = EXCEPT_MESSAGE;
  110. # if !defined( DECLARE_INFOLEVEL )
  111. extern EXTRNC unsigned long comp##InfoLevel = DEF_INFOLEVEL;
  112. extern EXTRNC char *comp##InfoLevelString = #comp;
  113. # else
  114. DECLARE_INFOLEVEL(ex)
  115. # endif
  116. # endif // (CIDBG == 1)
  117. //+---------------------------------------------------------------------------
  118. //
  119. // Function: SetWin4ExceptionLevel
  120. //
  121. // Synopsis: Sets global exception level
  122. //
  123. // History: 15-Sep-91 KevinRo Created
  124. //
  125. //----------------------------------------------------------------------------
  126. # if (CIDBG == 1)
  127. EXPORTIMP unsigned long APINOT
  128. SetWin4ExceptionLevel(
  129. unsigned long ulNewValue)
  130. {
  131. unsigned long ul;
  132. ul = Win4ExceptionLevel;
  133. Win4ExceptionLevel = ulNewValue;
  134. return(ul);
  135. }
  136. ULONG GetWin4ExceptionLevel(void)
  137. {
  138. return Win4ExceptionLevel;
  139. }
  140. # endif // (CIDBG == 1)
  141. #endif // !EXCEPT_TEST
  142. //
  143. // Heap checking can be turned on with this variable.
  144. // 0x00000001 = Always check new/delete
  145. // 0x00000002 = Check delete during unwind.
  146. //
  147. extern "C"
  148. {
  149. int newHeapCheck = 0;
  150. }
  151. //
  152. // In a multi-threaded (e.g. Win32) environment, we need one
  153. // exception context per thread.
  154. //
  155. enum Unwindability
  156. {
  157. NonUnwindable
  158. };
  159. void * __cdecl
  160. operator new ( size_t s, Unwindability dummy )
  161. {
  162. #if defined ( _AUTOCHECK_ )
  163. return RtlAllocateHeap( RtlProcessHeap(), 0, s );
  164. #else
  165. return(malloc(s));
  166. #endif // _AUTOCHECK_
  167. }
  168. //+-------------------------------------------------------------------------
  169. //
  170. // Function: GetScodeError, public
  171. //
  172. // Synopsis: Translates an NTSTATUS or HRESULT into an HRESULT (SCODE)
  173. //
  174. // Arguments: [e] -- The exception object
  175. //
  176. // Returns A SCODE equivalent
  177. //
  178. // History: 3-Feb-98 dlee Created
  179. //
  180. //--------------------------------------------------------------------------
  181. EXPORTIMP SCODE APINOT GetScodeError( CException & e )
  182. {
  183. //
  184. // This function normalizes NTSTATUS, HRESULTS, and Win32 error codes
  185. // into a Win32 error. Note that it is illegal in CI to throw Win32
  186. // error codes because they will be confused with HRESULT success codes
  187. //
  188. // n.b. A side effect is that this error is set in the thread's LastError
  189. //
  190. SCODE sc = e.GetErrorCode();
  191. // If it looks like an HRESULT already, just return it.
  192. if ( 0x80000000 == ( 0xC0000000 & sc ) )
  193. return sc;
  194. //
  195. // If it's a CI 0xC error, don't try to map it since it'll return
  196. // ERROR_MR_MID_NOT_FOUND (and DbgBreak on checked builds).
  197. //
  198. if ( 0xC0041000 == ( 0xC0041000 & sc ) )
  199. return sc;
  200. DWORD dwError = RtlNtStatusToDosError( sc );
  201. if ( ERROR_MR_MID_NOT_FOUND == dwError )
  202. {
  203. ciDebugOut(( DEB_WARN, "mr mid for error %#x\n", sc ));
  204. return sc;
  205. }
  206. return HRESULT_FROM_WIN32( dwError );
  207. } //GetScodeError
  208. //+-------------------------------------------------------------------------
  209. //
  210. // Method: IsOleError, public
  211. //
  212. // Synopsis: return TRUE if sc looks like an OLE SCODE.
  213. //
  214. // History: 19-Apr-95 BartoszM Created
  215. //
  216. //--------------------------------------------------------------------------
  217. inline BOOL IsOleError (NTSTATUS sc)
  218. {
  219. // if it's a win32 facility error in an hresult, only certain
  220. // instances are allowed returned by oledb. Map others to E_FAIL.
  221. if ( 0x80070000 == ( sc & 0x80070000 ) )
  222. {
  223. if ( E_OUTOFMEMORY == sc ||
  224. E_INVALIDARG == sc ||
  225. E_HANDLE == sc ||
  226. E_ACCESSDENIED == sc )
  227. return TRUE;
  228. else
  229. return FALSE;
  230. }
  231. else if ( 0x80030000 == ( sc & 0x80030000 ) )
  232. {
  233. // storage errors aren't allowed by ole-db
  234. return FALSE;
  235. }
  236. return ((sc & 0xFFF00000) == 0x80000000) ||
  237. (SUCCEEDED(sc) && (sc & 0xFFFFF000) != 0);
  238. } //IsOleError
  239. //+-------------------------------------------------------------------------
  240. //
  241. // Method: GetOleError, public
  242. //
  243. // History: 19-Apr-95 BartoszM Created
  244. // 26-Apr-95 DwightKr Converted from method to function
  245. // so that it can be independent from
  246. // the class CException which is now
  247. // part of the C++ run-time package.
  248. //
  249. //--------------------------------------------------------------------------
  250. EXPORTIMP SCODE APINOT GetOleError(CException & e)
  251. {
  252. NTSTATUS scError = e.GetErrorCode();
  253. if (IsOleError(scError))
  254. {
  255. return scError;
  256. }
  257. else if ( ( STATUS_NO_MEMORY == scError ) ||
  258. ( STATUS_COMMITMENT_LIMIT == scError ) ||
  259. ( STATUS_INSUFFICIENT_RESOURCES == scError ) ||
  260. ( HRESULT_FROM_WIN32( ERROR_COMMITMENT_LIMIT ) == scError ) ||
  261. ( HRESULT_FROM_WIN32( ERROR_NO_SYSTEM_RESOURCES ) == scError ) ||
  262. ( STG_E_TOOMANYOPENFILES == scError ) ||
  263. ( STG_E_INSUFFICIENTMEMORY == scError ) )
  264. {
  265. return E_OUTOFMEMORY;
  266. }
  267. else if ( STATUS_ACCESS_DENIED == scError )
  268. return E_ACCESSDENIED;
  269. else if ( STATUS_INVALID_HANDLE == scError )
  270. return E_HANDLE;
  271. else if ( STATUS_INVALID_PARAMETER == scError )
  272. return E_INVALIDARG;
  273. else
  274. {
  275. exDebugOut(( DEB_ITRACE, "GetOleError - mapping %08x to E_FAIL\n", scError));
  276. return E_FAIL;
  277. }
  278. }
  279. CException::CException()
  280. : _lError( HRESULT_FROM_WIN32( GetLastError() ) ),
  281. _dbgInfo( 0 )
  282. {
  283. } //CException
  284. #if CIDBG == 1
  285. //+---------------------------------------------------------------------------
  286. //
  287. // Function: ExceptionReport
  288. //
  289. // Synopsis: Outputs Exception messages based on the Win4ExceptionLevel
  290. // variable. Used by programs compiled with DEBUG defined
  291. //
  292. // History: 15-Sep-91 KevinRo Created
  293. //
  294. //----------------------------------------------------------------------------
  295. EXPORTIMP void APINOT
  296. ExceptionReport(
  297. unsigned int iLine,
  298. char *szFile,
  299. char *szMsg,
  300. long lError )
  301. {
  302. # if DBG
  303. if (Win4ExceptionLevel & EXCEPT_MESSAGE)
  304. {
  305. DWORD tid = GetCurrentThreadId();
  306. exDebugOut((DEB_FORCE,
  307. "%s - line: %u file: %s, thread id %x\n",
  308. szMsg, iLine, szFile, tid));
  309. if (lError != -1)
  310. exDebugOut((DEB_FORCE,"\terror code 0x%lx\n", lError ));
  311. }
  312. # endif
  313. if (Win4ExceptionLevel & EXCEPT_POPUP)
  314. {
  315. if(PopUpError(szMsg,iLine,szFile) == IDCANCEL)
  316. {
  317. DebugBreak();
  318. }
  319. }
  320. else
  321. {
  322. if (Win4ExceptionLevel & EXCEPT_BREAK)
  323. {
  324. DebugBreak();
  325. }
  326. }
  327. }
  328. #endif // CIDBG == 1
  329. //+-------------------------------------------------------------------------
  330. //
  331. // Setup the runtime package to translate system exceptions (i.e. those
  332. // usually processed by try / except blocks) into C++ exceptions (those
  333. // processed by try / catch blocks). This has no effect on try / except
  334. // blocks; as they will still continue to see the standard C exception.
  335. //
  336. // The translation is accomplished by telling the C run-time package to
  337. // call a user-specified function each time a system exception occurs. The
  338. // function translates the exception into a class and rethrows with the
  339. // class. If their is a following CATCH block, then the C++ class will
  340. // be caught. If there is a following except, then the original system
  341. // exception will be caught.
  342. //
  343. //--------------------------------------------------------------------------
  344. //
  345. // Convert system exceptions to a C++ exception.
  346. //
  347. void _cdecl SystemExceptionTranslator( unsigned int uiWhat,
  348. struct _EXCEPTION_POINTERS * pexcept )
  349. {
  350. //
  351. // Intentionally don't translate STATUS_PRIVILEGED_INSTRUCTION (see
  352. // Win4AssertEx for details.
  353. //
  354. //
  355. // In certain situations when a compressed or sparse file is mapped and we
  356. // run out of disk space the system can throw an in page error instead of
  357. // the appropriate error
  358. //
  359. // Throw the proper exception code so that the error can be handled correctly
  360. //
  361. if ( STATUS_IN_PAGE_ERROR == pexcept->ExceptionRecord->ExceptionCode &&
  362. pexcept->ExceptionRecord->NumberParameters >= 3 )
  363. {
  364. exDebugOut(( DEB_WARN, "SystemExceptionTranslator: Received In Page IO Error\n"));
  365. Win4Assert ( STATUS_IN_PAGE_ERROR == uiWhat );
  366. if ( STATUS_DISK_FULL == pexcept->ExceptionRecord->ExceptionInformation[2] ||
  367. STATUS_VOLUME_DISMOUNTED == pexcept->ExceptionRecord->ExceptionInformation[2] ||
  368. STATUS_INSUFFICIENT_RESOURCES == pexcept->ExceptionRecord->ExceptionInformation[2] )
  369. {
  370. exDebugOut(( DEB_WARN, "SystemExceptionTranslator: Translating In Page IO Error to 0x%x\n",
  371. (unsigned int) pexcept->ExceptionRecord->ExceptionInformation[2] ));
  372. uiWhat = (unsigned int) pexcept->ExceptionRecord->ExceptionInformation[2];
  373. pexcept->ExceptionRecord->ExceptionCode = (NTSTATUS) pexcept->ExceptionRecord->ExceptionInformation[2];
  374. }
  375. }
  376. #if CIDBG == 1
  377. if ( ASSRT_STRESSEXCEPTION != uiWhat )
  378. throw CException( uiWhat ) ;
  379. #else
  380. throw CException( uiWhat ) ;
  381. #endif
  382. } //SystemExceptionTranslator