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.

442 lines
11 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. result.h
  5. Abstract:
  6. Author:
  7. Hakki T. Bostanci (hakkib) 06-Apr-2000
  8. Revision History:
  9. --*/
  10. #ifndef RESULT_H
  11. #define RESULT_H
  12. #ifndef ASSERT
  13. #define ASSERT assert
  14. #endif
  15. #ifndef PCTSTR
  16. #define PCTSTR LPCTSTR
  17. #endif //PCTSTR
  18. #if defined(_X86_)
  19. #define CURRENT_MACHINE_TYPE IMAGE_FILE_MACHINE_I386
  20. #elif defined(_MIPS_)
  21. #define CURRENT_MACHINE_TYPE IMAGE_FILE_MACHINE_R4000
  22. #elif defined(_ALPHA_)
  23. #define CURRENT_MACHINE_TYPE IMAGE_FILE_MACHINE_ALPHA
  24. #elif defined(_PPC_)
  25. #define CURRENT_MACHINE_TYPE IMAGE_FILE_MACHINE_POWERPC
  26. #elif defined(_AXP64_)
  27. #define CURRENT_MACHINE_TYPE IMAGE_FILE_MACHINE_ALPHA64
  28. #elif defined(_IA64_)
  29. #define CURRENT_MACHINE_TYPE IMAGE_FILE_MACHINE_IA64
  30. #ifndef CONTEXT_CONTROL
  31. #pragma message("CONTEXT_CONTROL was not defined!!!")
  32. #define CONTEXT_CONTROL CONTEXT86_CONTROL
  33. #endif CONTEXT_CONTROL
  34. #else
  35. #undef CURRENT_MACHINE_TYPE
  36. #endif
  37. //
  38. // The CHECK() macro can be used to evaluate the result of APIs that use
  39. // LastError. These APIs typically return a non-zero value if there is
  40. // no error and if there is an error, they return zero and SetLastError()
  41. // with the extended error information.
  42. //
  43. #define CHECK(Expression) \
  44. { \
  45. if ((Expression) == 0) { \
  46. \
  47. throw CError(GetLastError() STAMP(_T(#Expression))); \
  48. } \
  49. } \
  50. //
  51. // CHECK0 macro deals with the API functions that do not use the LastError
  52. // value. Typically registry APIs fall into this category, they directly
  53. // return the error code, or ERROR_SUCCESS if there is no error.
  54. //
  55. #define CHECK_REG(Expression) \
  56. { \
  57. DWORD __dwResult = (DWORD) (Expression); \
  58. \
  59. if (__dwResult != ERROR_SUCCESS) { \
  60. \
  61. throw CError(__dwResult STAMP(_T(#Expression))); \
  62. } \
  63. } \
  64. //
  65. // CHECK0 macro deals with the API functions that do not use the LastError
  66. // value. Typically registry APIs fall into this category, they directly
  67. // return the error code, or ERROR_SUCCESS if there is no error.
  68. //
  69. #define CHECK_HR(Expression) \
  70. { \
  71. HRESULT __hr = Expression; \
  72. \
  73. if (__hr != S_OK) \
  74. { \
  75. throw CError(__hr STAMP(_T(#Expression))); \
  76. } \
  77. } \
  78. //
  79. // CHECK_LSA macro deals with the LSA API functions.
  80. //
  81. #define CHECK_LSA(Expression) \
  82. { \
  83. DWORD __dwResult = (DWORD) (Expression); \
  84. \
  85. if (__dwResult != ERROR_SUCCESS) \
  86. { \
  87. __dwResult = LsaNtStatusToWinError(__dwResult); \
  88. \
  89. throw CError(__dwResult STAMP(_T(#Expression))); \
  90. } \
  91. } \
  92. //
  93. // On DEBUG builds, we include the location STAMP on the error message popup,
  94. // i.e. we display the expression that raised the error, the module name and
  95. // the line number
  96. //
  97. #ifdef _CONSOLE
  98. #define ENDL _T("\n")
  99. #else //_CONSOLE
  100. #define ENDL _T(", ")
  101. #endif //_CONSOLE
  102. #if defined(DEBUG) || defined(_DEBUG) || defined(DBG)
  103. #define STAMP(pExpr) , pExpr, _T(__FILE__), __LINE__
  104. #define STAMP_DECL , PCTSTR pExpr = _T(""), PCTSTR pFile = _T(""), INT nLine = 0
  105. #define STAMP_INIT , m_pExpr(pExpr), m_pFile(pFile), m_nLine(nLine)
  106. #define STAMP_ARGS , m_pExpr, m_pFile, (PCTSTR) m_nLine
  107. #define STAMP_DEFINE PCTSTR m_pExpr; PCTSTR m_pFile; INT m_nLine; mutable CONTEXT m_Context;
  108. #define STAMP_FORMAT _T("%s") ENDL _T("%s: %d") ENDL
  109. #define STAMP_IOS << std::endl << rhs.m_pExpr << std::endl << rhs.m_pFile << _T(": ") << rhs.m_nLine
  110. #define STAMP_LENGTH _tcslen(pExpr) + _tcslen(pFile) + 8
  111. #else //DEBUG
  112. #define STAMP(pExpr)
  113. #define STAMP_DECL
  114. #define STAMP_INIT
  115. #define STAMP_ARGS
  116. #define STAMP_DEFINE
  117. #define STAMP_FORMAT
  118. #define STAMP_IOS
  119. #define STAMP_LENGTH 0
  120. #endif //DEBUG
  121. inline PTSTR _tcsdupl(LPCTSTR pStrSource)
  122. {
  123. if (!pStrSource) {
  124. pStrSource = _T("");
  125. }
  126. PTSTR pStrDest = (PTSTR) ::LocalAlloc(
  127. LMEM_FIXED,
  128. (_tcslen(pStrSource) + 1) * sizeof(TCHAR)
  129. );
  130. if (pStrDest) {
  131. _tcscpy(pStrDest, pStrSource);
  132. }
  133. return pStrDest;
  134. }
  135. inline PTSTR FormatMessageFromSystem(DWORD nNum)
  136. {
  137. PTSTR pText = 0;
  138. DWORD dwResult = ::FormatMessage(
  139. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  140. FORMAT_MESSAGE_FROM_SYSTEM |
  141. FORMAT_MESSAGE_IGNORE_INSERTS |
  142. FORMAT_MESSAGE_MAX_WIDTH_MASK,
  143. 0,
  144. nNum,
  145. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  146. (PTSTR) &pText,
  147. 0,
  148. 0
  149. );
  150. if (pText == 0) {
  151. pText = _tcsdupl(_T("Unknown Error"));
  152. }
  153. return pText;
  154. }
  155. #ifdef _IOSTREAM_
  156. // workaround for VC6 compiler bug (Q192539)
  157. class CError;
  158. std::ostream &operator <<(std::ostream &os, const CError &rhs);
  159. #endif //_IOSTREAM_
  160. //////////////////////////////////////////////////////////////////////////
  161. //
  162. // CError
  163. //
  164. class CError
  165. {
  166. public:
  167. CError(
  168. PTSTR pText
  169. STAMP_DECL
  170. ) :
  171. m_nNum(0),
  172. m_pText(pText),
  173. m_bFree(false)
  174. STAMP_INIT
  175. {
  176. #if (defined(DEBUG) || defined(_DEBUG) || defined(DBG)) && defined(CURRENT_MACHINE_TYPE)
  177. m_Context.ContextFlags = CONTEXT_CONTROL;
  178. GetThreadContext(GetCurrentThread(), &m_Context);
  179. #endif
  180. }
  181. CError(
  182. DWORD nNum
  183. STAMP_DECL
  184. ) :
  185. m_nNum(nNum),
  186. m_pText(0),
  187. m_bFree(false)
  188. STAMP_INIT
  189. {
  190. #if (defined(DEBUG) || defined(_DEBUG) || defined(DBG)) && defined(CURRENT_MACHINE_TYPE)
  191. m_Context.ContextFlags = CONTEXT_CONTROL;
  192. GetThreadContext(GetCurrentThread(), &m_Context);
  193. #endif
  194. }
  195. ~CError()
  196. {
  197. if (m_bFree) {
  198. LocalFree(m_pText);
  199. }
  200. }
  201. DWORD
  202. Num() const
  203. {
  204. return m_nNum;
  205. }
  206. PCTSTR
  207. Text() const
  208. {
  209. if (!m_pText) {
  210. m_pText = FormatMessageFromSystem(m_nNum);
  211. m_bFree = true;
  212. }
  213. return m_pText;
  214. }
  215. static
  216. void
  217. AskDebugBreak()
  218. {
  219. if (MessageBox(
  220. 0,
  221. _T("Do you want to break into the debugger?"),
  222. 0,
  223. MB_ICONQUESTION | MB_YESNO
  224. ) == IDYES) {
  225. DebugBreak();
  226. }
  227. }
  228. #if (defined(DEBUG) || defined(_DEBUG) || defined(DBG)) && defined(CURRENT_MACHINE_TYPE) && defined(_IMAGEHLP_)
  229. #define MAX_STACK_DEPTH 32
  230. #define MAX_SYMBOL_LENGTH 256
  231. template <int N>
  232. struct CImagehlpSymbol : public IMAGEHLP_SYMBOL
  233. {
  234. CImagehlpSymbol()
  235. {
  236. ZeroMemory(this, sizeof(*this));
  237. SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
  238. MaxNameLength = N;
  239. }
  240. private:
  241. CHAR NameData[N-1];
  242. };
  243. struct CImagehlpLine : public IMAGEHLP_LINE
  244. {
  245. CImagehlpLine()
  246. {
  247. ZeroMemory(this, sizeof(*this));
  248. SizeOfStruct = sizeof(IMAGEHLP_LINE);
  249. }
  250. };
  251. struct CImagehlpModule : public IMAGEHLP_MODULE
  252. {
  253. CImagehlpModule()
  254. {
  255. ZeroMemory(this, sizeof(*this));
  256. SizeOfStruct = sizeof(IMAGEHLP_MODULE);
  257. }
  258. };
  259. void DumpStack(FILE *fout = stdout) const
  260. {
  261. PCONTEXT pContext = &m_Context;
  262. HANDLE hProcess = GetCurrentProcess();
  263. HANDLE hThread = GetCurrentThread();
  264. SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES);
  265. SymInitialize(hProcess, 0, TRUE);
  266. STACKFRAME StackFrame = { 0 };
  267. #if defined(_X86_)
  268. StackFrame.AddrPC.Offset = pContext->Eip;
  269. StackFrame.AddrFrame.Offset = pContext->Ebp;
  270. StackFrame.AddrStack.Offset = pContext->Esp;
  271. #elif defined(_MIPS_)
  272. StackFrame.AddrPC.Offset = pContext->Fir;
  273. StackFrame.AddrFrame.Offset = pContext->IntS6;
  274. StackFrame.AddrStack.Offset = pContext->IntSp;
  275. #elif defined(_ALPHA_)
  276. StackFrame.AddrPC.Offset = pContext->Fir;
  277. StackFrame.AddrFrame.Offset = pContext->IntFp;
  278. StackFrame.AddrStack.Offset = pContext->IntSp;
  279. #elif defined(_PPC_)
  280. StackFrame.AddrPC.Offset = pContext->Iar;
  281. StackFrame.AddrFrame.Offset = pContext->IntFp;
  282. StackFrame.AddrStack.Offset = pContext->Gpr1;
  283. #endif
  284. StackFrame.AddrPC.Mode = AddrModeFlat;
  285. StackFrame.AddrFrame.Mode = AddrModeFlat;
  286. StackFrame.AddrStack.Mode = AddrModeFlat;
  287. for (
  288. int nStackWalkLevel = 0;
  289. nStackWalkLevel < MAX_STACK_DEPTH &&
  290. StackWalk(
  291. CURRENT_MACHINE_TYPE,
  292. hProcess,
  293. hThread,
  294. &StackFrame,
  295. pContext,
  296. 0,
  297. SymFunctionTableAccess,
  298. SymGetModuleBase,
  299. 0
  300. );
  301. ++nStackWalkLevel
  302. ) {
  303. CImagehlpModule Module;
  304. SymGetModuleInfo(hProcess, StackFrame.AddrPC.Offset, &Module);
  305. DWORD dwDisplacement = 0;
  306. CImagehlpSymbol<MAX_SYMBOL_LENGTH> Symbol;
  307. SymGetSymFromAddr(hProcess, StackFrame.AddrPC.Offset, &dwDisplacement, &Symbol);
  308. CHAR szUnDSymbol[MAX_SYMBOL_LENGTH] = "";
  309. SymUnDName(&Symbol, szUnDSymbol, sizeof(szUnDSymbol));
  310. DWORD dwLineDisplacement = 0;
  311. CImagehlpLine Line;
  312. SymGetLineFromAddr(hProcess, StackFrame.AddrPC.Offset, &dwLineDisplacement, &Line);
  313. fprintf(
  314. fout,
  315. "%08x %08x %08x %08x %s!%s+0x%x (%s:%d)\n",
  316. StackFrame.Params[0],
  317. StackFrame.Params[1],
  318. StackFrame.Params[2],
  319. StackFrame.Params[3],
  320. Module.ModuleName,
  321. szUnDSymbol,
  322. dwDisplacement,
  323. Line.FileName,
  324. Line.LineNumber
  325. );
  326. }
  327. SymCleanup(hProcess);
  328. }
  329. #else
  330. void
  331. DumpStack(PVOID pVoid = 0) const
  332. {
  333. }
  334. #endif
  335. template <class F>
  336. int
  337. Print(F OutputFunction) const
  338. {
  339. OutputFunction(
  340. _T("Error 0x%08x: %s") ENDL STAMP_FORMAT,
  341. Num(),
  342. Text()
  343. STAMP_ARGS
  344. );
  345. return 1;
  346. }
  347. #ifdef _IOSTREAM_
  348. friend std::ostream &operator <<(std::ostream &os, const CError &rhs)
  349. {
  350. return os <<
  351. _T("Error ") << rhs.Num() << _T(": ") << rhs.Text()
  352. STAMP_IOS << std::endl;
  353. }
  354. #endif //_IOSTREAM_
  355. private:
  356. DWORD m_nNum;
  357. mutable PTSTR m_pText;
  358. mutable bool m_bFree;
  359. STAMP_DEFINE;
  360. };
  361. #endif //RESULT_H