ReactOS  0.4.15-dev-507-g90aff8d
pseh3.h
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS system libraries
3  * LICENSE: GNU GPL - See COPYING in the top level directory
4  * PURPOSE: Header for PSEH3
5  * PROGRAMMER: Timo Kreuzer (timo.kreuzer@reactos.org)
6  */
7 
8 /* For additional information see pseh3.c in the related library. */
9 
10 #pragma once
11 #define _PSEH3_H_
12 
13 #include <excpt.h>
14 
15 #ifdef __cplusplus
16 extern "C" {
17 #endif
18 
19 /* CLANG must safe non-volatiles, because it uses a return-twice algorithm */
20 #if defined(__clang__) && !defined(_SEH3$_FRAME_ALL_NONVOLATILES)
21 #define _SEH3$_FRAME_ALL_NONVOLATILES 1
22 #endif
23 
24 enum
25 {
29 #ifdef __clang__
31 #elif defined(__cplusplus)
33 #else
35 #endif
36 };
37 
38 typedef struct _SEH3$_SCOPE_TABLE
39 {
40  void *Target;
41  void *Filter;
42  unsigned char TryLevel;
43  unsigned char HandlerType;
44 } SEH3$_SCOPE_TABLE, *PSEH3$_SCOPE_TABLE;
45 
47 {
51 
53 {
54  /* First the Windows base record. Don't move this! */
56  void *Handler;
57 
58  /* Points to the end of the internal registration chain */
60 
61  /* Pointer to the static scope table */
63 
64  /* Except handler stores pointer to exception pointers here */
66 
67  /* Except handler stores the exception code here */
68  unsigned long ExceptionCode;
69 
70  /* Registers that we need to save */
71  unsigned long Esp;
72  unsigned long Ebp;
73 
74  char* AllocaFrame;
75 #ifdef _SEH3$_FRAME_ALL_NONVOLATILES
76  unsigned long Ebx;
77  unsigned long Esi;
78  unsigned long Edi;
79 #endif
80 #ifdef __clang__
81  void *ReturnAddress;
82 #endif
84 
85 /* Prevent gcc from inlining functions that use SEH. */
86 static inline __attribute__((always_inline)) __attribute__((returns_twice)) void _SEH3$_PreventInlining() {}
87 
88 /* Unregister the root frame */
89 extern inline __attribute__((always_inline,gnu_inline))
90 void _SEH3$_UnregisterFrame(volatile SEH3$_REGISTRATION_FRAME *RegistrationFrame)
91 {
92  asm volatile ("movl %k[NewHead], %%fs:0"
93  : : [NewHead] "ir" (RegistrationFrame->Next) : "memory");
94 }
95 
96 /* Unregister a trylevel frame */
97 extern inline __attribute__((always_inline,gnu_inline))
98 void _SEH3$_UnregisterTryLevel(
99  volatile SEH3$_REGISTRATION_FRAME *TrylevelFrame)
100 {
101  volatile SEH3$_REGISTRATION_FRAME *RegistrationFrame;
102  asm volatile ("movl %%fs:0, %k[RegistrationFrame]"
103  : [RegistrationFrame] "=r" (RegistrationFrame) : );
104  RegistrationFrame->EndOfChain = TrylevelFrame->Next;
105 }
106 
107 enum
108 {
110 };
111 
112 #ifndef __clang__
113 /* These are global dummy definitions, that get overwritten in the local context of __finally / __except blocks */
114 int __cdecl __attribute__((error ("Can only be used inside a __finally block."))) _abnormal_termination(void);
115 unsigned long __cdecl __attribute__((error("Can only be used inside an exception filter or __except block."))) _exception_code(void);
116 void * __cdecl __attribute__((error("Can only be used inside an exception filter."))) _exception_info(void);
117 #endif
118 
119 /* This attribute allows automatic cleanup of the registered frames */
120 #define _SEH3$_AUTO_CLEANUP __attribute__((cleanup(_SEH3$_AutoCleanup)))
121 
122 int
123 __attribute__((regparm(3)))
124 __attribute__((returns_twice))
125 _SEH3$_RegisterFrameWithNonVolatiles(
126  volatile SEH3$_REGISTRATION_FRAME* RegistrationFrame,
128  void* AllocaFrame);
129 
130 int
131 __attribute__((regparm(3)))
132 __attribute__((returns_twice))
133 _SEH3$_RegisterTryLevelWithNonVolatiles(
134  volatile SEH3$_REGISTRATION_FRAME* RegistrationFrame,
136  void* AllocaFrame);
137 
138 /* CLANG specific definitions! */
139 #ifdef __clang__
140 
141 /* CLANG thinks it is smart and optimizes the alloca away if it is 0 and with it the use of a frame register */
142 #define _SEH3$_EnforceFramePointer() asm volatile ("#\n" : : "m"(*(char*)__builtin_alloca(4)) : "%esp", "memory")
143 
144 /* CLANG doesn't have asm goto! */
145 #define _SEH3$_ASM_GOTO(...)
146 
147 #define _SEH3$_RegisterFrame_(_TrylevelFrame, _DataTable) \
148  do { \
149  int result = _SEH3$_RegisterFrameWithNonVolatiles(_TrylevelFrame, _DataTable, __builtin_alloca(0)); \
150  if (__builtin_expect(result != 0, 0)) \
151  { \
152  if (result == 1) goto _SEH3$_l_FilterOrFinally; \
153  if (result == 2) goto _SEH3$_l_HandlerTarget; \
154  goto _SEH3$_l_BeforeFilterOrFinally; \
155  } \
156  } while(0)
157 
158 #define _SEH3$_RegisterTryLevel_(_TrylevelFrame, _DataTable) \
159  do { \
160  int result = _SEH3$_RegisterTryLevelWithNonVolatiles(_TrylevelFrame, _DataTable, __builtin_alloca(0)); \
161  if (__builtin_expect(result != 0, 0)) \
162  { \
163  if (result == 1) goto _SEH3$_l_FilterOrFinally; \
164  if (result == 2) goto _SEH3$_l_HandlerTarget; \
165  goto _SEH3$_l_BeforeFilterOrFinally; \
166  } \
167  } while(0)
168 
169 #define _SEH3$_SCARE_GCC()
170 
171 #else /* !__clang__ */
172 
173 /* This will make GCC use ebp, even if it was disabled by -fomit-frame-pointer */
174 #define _SEH3$_EnforceFramePointer() asm volatile ("#\n" : : "m"(*(char*)__builtin_alloca(0)) : "%esp", "memory")
175 
176 #define _SEH3$_ASM_GOTO(...) asm goto ("#\n" : : : "memory" : __VA_ARGS__)
177 
178 #ifdef __cplusplus
179 #define _SEH3$_CALL_WRAPPER(_Function, _TrylevelFrame, _DataTable) \
180  asm goto ("leal %0, %%eax\n\t" \
181  "leal %1, %%edx\n\t" \
182  "call " #_Function "WithStackLayout" \
183  : \
184  : "m" (*(_TrylevelFrame)), "m" (*(_DataTable)), "c" (__builtin_alloca(0)), "p" (_SEH3$_RegisterFrameWithNonVolatiles) \
185  : "eax", "edx", "memory" \
186  : _SEH3$_l_BeforeTry, _SEH3$_l_HandlerTarget, _SEH3$_l_OnException, _SEH3$_l_BeforeFilterOrFinally, _SEH3$_l_FilterOrFinally)
187 
188 #else
189 #define _SEH3$_CALL_WRAPPER(_Function, _TrylevelFrame, _DataTable) \
190  asm goto ("leal %0, %%eax\n\t" \
191  "leal %1, %%edx\n\t" \
192  "call " #_Function \
193  : \
194  : "m" (*(_TrylevelFrame)), "m" (*(_DataTable)), "p" (_SEH3$_RegisterFrameWithNonVolatiles) \
195  : "eax", "edx", "ecx", "memory" \
196  : _SEH3$_l_BeforeTry, _SEH3$_l_HandlerTarget, _SEH3$_l_OnException, _SEH3$_l_BeforeFilterOrFinally, _SEH3$_l_FilterOrFinally)
197 #endif
198 
199 /* This is an asm wrapper around _SEH3$_RegisterFrame */
200 #define _SEH3$_RegisterFrame_(_TrylevelFrame, _DataTable) \
201  _SEH3$_CALL_WRAPPER(__SEH3$_RegisterFrame, _TrylevelFrame, _DataTable)
202 
203 /* This is an asm wrapper around _SEH3$_RegisterTryLevel */
204 #define _SEH3$_RegisterTryLevel_(_TrylevelFrame, _DataTable) \
205  _SEH3$_CALL_WRAPPER(__SEH3$_RegisterTryLevel, _TrylevelFrame, _DataTable)
206 
207 /* This construct scares GCC so much, that it will stop moving code
208  around into places that are never executed. */
209 #define _SEH3$_SCARE_GCC() \
210  void *plabel; \
211  _SEH3$_ASM_GOTO(_SEH3$_l_BeforeTry, _SEH3$_l_HandlerTarget, _SEH3$_l_OnException, _SEH3$_l_BeforeFilterOrFinally, _SEH3$_l_FilterOrFinally); \
212  asm volatile ("#" : "=a"(plabel) : "p"(&&_SEH3$_l_BeforeTry), "p"(&&_SEH3$_l_HandlerTarget), "p"(&&_SEH3$_l_OnException), "p"(&&_SEH3$_l_FilterOrFinally) \
213  : "ebx", "ecx", "edx", "esi", "edi", "flags", "memory" ); \
214  goto _SEH3$_l_OnException;
215 
216 #endif /* __clang__ */
217 
218 /* Neither CLANG nor C++ support nested functions */
219 #if defined(__cplusplus) || defined(__clang__)
220 
221 /* Use the global unregister function */
222 void
223 __attribute__((regparm(1)))
224 _SEH3$_AutoCleanup(
225  volatile SEH3$_REGISTRATION_FRAME *Frame);
226 
227 /* These are only dummies here */
228 #define _SEH3$_DECLARE_CLEANUP_FUNC(_Name)
229 #define _SEH3$_DEFINE_CLEANUP_FUNC(_Name)
230 #define _SEH3$_DECLARE_FILTER_FUNC(_Name)
231 #define _SEH3$_DEFINE_DUMMY_FINALLY(_Name)
232 
233 /* On invocation, the AllocaFrame field is loaded with the return esp value */
234 #define _SEH3$_NESTED_FUNC_RETURN(_Result) \
235  /* Restore esp and return to the caller */ \
236  asm volatile ("movl %[FixedEsp], %%esp\n\tret" \
237  : : "a" (_Result), [FixedEsp] "m" (_SEH3$_TrylevelFrame.AllocaFrame) : "ebx", "ecx", "edx", "esi", "edi", "flags", "memory")
238 
239 /* The filter "function" */
240 #define _SEH3$_DEFINE_FILTER_FUNC(_Name, expression) \
241  { \
242  /* Evaluate and return the filter expression */ \
243  asm volatile ("#\n" : : : "eax", "ebx", "ecx", "edx", "esi", "edi", "flags", "memory"); \
244  _SEH3$_NESTED_FUNC_RETURN((expression)); \
245  }
246 
247 #define _SEH3$_FINALLY_FUNC_OPEN(_Name) \
248  { \
249  asm volatile ("#\n" : : : "eax", "ebx", "ecx", "edx", "esi", "edi", "flags", "memory"); \
250  /* This construct makes sure that the finally function returns */ \
251  /* a proper value at the end */ \
252  for (; ; (void)({_SEH3$_NESTED_FUNC_RETURN(0); 0;}))
253 
254 #define _SEH3$_FILTER(_Filter, _FilterExpression) (&&_SEH3$_l_FilterOrFinally)
255 #define _SEH3$_FINALLY(_Finally) (&&_SEH3$_l_FilterOrFinally)
256 
257 #define _SEH3$_DECLARE_EXCEPT_INTRINSICS()
258 
259 /* Since we cannot use nested functions, we declare these globally as macros */
260 #define _abnormal_termination() (_SEH3$_TrylevelFrame.ExceptionPointers != 0)
261 #define _exception_code() (_SEH3$_TrylevelFrame.ExceptionCode)
262 #define _exception_info() (_SEH3$_TrylevelFrame.ExceptionPointers)
263 
264 #else /* __cplusplus || __clang__ */
265 
266 #define _SEH3$_DECLARE_EXCEPT_INTRINSICS() \
267  inline __attribute__((always_inline, gnu_inline)) \
268  unsigned long _exception_code() { return _SEH3$_TrylevelFrame.ExceptionCode; }
269 
270 /* On GCC the filter function is a nested function with __fastcall calling
271  convention. The eax register contains a base address the function uses
272  to address the callers stack frame. __fastcall is chosen, because it gives
273  us an effective was of passing one argument to the function, that we need
274  to tell the function in a first pass to return informtion about the frame
275  base address. Since this is something GCC chooses arbitrarily, we call
276  the function with an arbitrary base address in eax first and then use the
277  result to calculate the correct address for a second call to the function. */
278 #define _SEH3$_DECLARE_FILTER_FUNC(_Name) \
279  auto int __fastcall _Name(int Action)
280 
281 #define _SEH3$_NESTED_FUNC_OPEN(_Name) \
282  int __fastcall _Name(int Action) \
283  { \
284  /* This is a fancy way to get information about the frame layout */ \
285  if (Action == 0) return (int)&_SEH3$_TrylevelFrame;
286 
287 #define _SEH3$_DEFINE_FILTER_FUNC(_Name, expression) \
288  _SEH3$_NESTED_FUNC_OPEN(_Name) \
289  /* Declare the intrinsics for exception filters */ \
290 _Pragma("GCC diagnostic push") \
291 _Pragma("GCC diagnostic ignored \"-Wshadow\"") \
292  inline __attribute__((always_inline, gnu_inline)) \
293  unsigned long _exception_code() { return _SEH3$_TrylevelFrame.ExceptionCode; } \
294  inline __attribute__((always_inline, gnu_inline)) \
295  void * _exception_info() { return _SEH3$_TrylevelFrame.ExceptionPointers; } \
296 _Pragma("GCC diagnostic pop") \
297 \
298  /* Now handle the actual filter expression */ \
299  return (expression); \
300  }
301 
302 #define _SEH3$_FINALLY_FUNC_OPEN(_Name) \
303  _SEH3$_NESTED_FUNC_OPEN(_Name) \
304  /* Declare the intrinsics for the finally function */ \
305  inline __attribute__((always_inline, gnu_inline)) \
306  int _abnormal_termination() { return (_SEH3$_TrylevelFrame.ExceptionPointers != 0); } \
307 \
308  /* This construct makes sure that the finally function returns */ \
309  /* a proper value at the end */ \
310  for (; ; (void)({return 0; 0;}))
311 
312 #define _SEH3$_FILTER(_Filter, _FilterExpression) \
313  (__builtin_constant_p(_FilterExpression) ? (void*)(unsigned long)(unsigned char)(unsigned long)(_FilterExpression) : _Filter)
314 
315 #define _SEH3$_FINALLY(_Finally) (_Finally)
316 
317 #define _SEH3$_DEFINE_DUMMY_FINALLY(_Name) \
318  auto inline __attribute__((always_inline,gnu_inline)) int _Name(int Action) { (void)Action; return 0; }
319 
320 #define _SEH3$_DECLARE_CLEANUP_FUNC(_Name) \
321  auto inline __attribute__((always_inline,gnu_inline)) void _Name(volatile SEH3$_REGISTRATION_FRAME *p)
322 
323 #define _SEH3$_DEFINE_CLEANUP_FUNC(_Name) \
324  _SEH3$_DECLARE_CLEANUP_FUNC(_Name) \
325  { \
326  (void)p; \
327  /* Unregister the frame */ \
328  if (_SEH3$_TryLevel == 1) _SEH3$_UnregisterFrame(&_SEH3$_TrylevelFrame); \
329  else _SEH3$_UnregisterTryLevel(&_SEH3$_TrylevelFrame); \
330 \
331  /* Invoke the finally function (an inline dummy in the __except case) */ \
332  _SEH3$_FinallyFunction(1); \
333  }
334 
335 #endif /* __cplusplus || __clang__ */
336 
337 
338 
339 #define _SEH3_TRY \
340  _SEH3$_PreventInlining(); \
341  /* Enter the outer scope */ \
342  if (1) { \
343  /* Declare local labels */ \
344  __label__ _SEH3$_l_BeforeTry; \
345  __label__ _SEH3$_l_DoTry; \
346  __label__ _SEH3$_l_AfterTry; \
347  __label__ _SEH3$_l_EndTry; \
348  __label__ _SEH3$_l_HandlerTarget; \
349  __label__ _SEH3$_l_OnException; \
350  __label__ _SEH3$_l_BeforeFilterOrFinally; \
351  __label__ _SEH3$_l_FilterOrFinally; \
352  (void)&&_SEH3$_l_OnException; \
353  (void)&&_SEH3$_l_BeforeFilterOrFinally; \
354  (void)&&_SEH3$_l_FilterOrFinally; \
355 \
356  /* Count the try level. Outside of any __try, _SEH3$_TryLevel is 0 */ \
357  enum { \
358  _SEH3$_PreviousTryLevel = _SEH3$_TryLevel, \
359  _SEH3$_TryLevel = _SEH3$_PreviousTryLevel + 1, \
360  }; \
361 \
362  /* Forward declaration of the auto cleanup function */ \
363  _SEH3$_DECLARE_CLEANUP_FUNC(_SEH3$_AutoCleanup); \
364 \
365  /* Allocate a registration frame */ \
366  volatile SEH3$_REGISTRATION_FRAME _SEH3$_AUTO_CLEANUP _SEH3$_TrylevelFrame; \
367 \
368  goto _SEH3$_l_BeforeTry; \
369  /* Silence warning */ goto _SEH3$_l_AfterTry; \
370 \
371  _SEH3$_l_DoTry: \
372  if (1)
373 
374 
375 #define _SEH3_EXCEPT(...) \
376  /* End of the try block */ \
377  _SEH3$_l_AfterTry: (void)0; \
378  goto _SEH3$_l_EndTry; \
379 \
380  _SEH3$_l_BeforeTry: (void)0; \
381  _SEH3$_ASM_GOTO(_SEH3$_l_OnException); \
382 \
383  /* Forward declaration of the filter function */ \
384  _SEH3$_DECLARE_FILTER_FUNC(_SEH3$_FilterFunction); \
385 \
386  /* Create a static data table that contains the jump target and filter function */ \
387  static const SEH3$_SCOPE_TABLE _SEH3$_ScopeTable = { &&_SEH3$_l_HandlerTarget, _SEH3$_FILTER(&_SEH3$_FilterFunction, (__VA_ARGS__)), _SEH3$_TryLevel, _SEH3$_HANDLER_TYPE }; \
388 \
389  /* Register the registration record. */ \
390  if (_SEH3$_TryLevel == 1) _SEH3$_RegisterFrame_(&_SEH3$_TrylevelFrame, &_SEH3$_ScopeTable); \
391  else _SEH3$_RegisterTryLevel_(&_SEH3$_TrylevelFrame, &_SEH3$_ScopeTable); \
392 \
393  /* Define an empty inline finally function */ \
394  _SEH3$_DEFINE_DUMMY_FINALLY(_SEH3$_FinallyFunction) \
395 \
396  /* Allow intrinsics for __except to be used */ \
397  _SEH3$_DECLARE_EXCEPT_INTRINSICS(); \
398 \
399  goto _SEH3$_l_DoTry; \
400 \
401  _SEH3$_l_BeforeFilterOrFinally: (void)0; \
402  /* Make sure the filter function doesn't use esp */ \
403  _SEH3$_EnforceFramePointer(); \
404 \
405  _SEH3$_l_FilterOrFinally: (void)0; \
406  /* Emit the filter function */ \
407  _SEH3$_DEFINE_FILTER_FUNC(_SEH3$_FilterFunction, (__VA_ARGS__)) \
408 \
409  _SEH3$_l_HandlerTarget: (void)0; \
410  _SEH3$_EnforceFramePointer(); \
411 \
412  if (1) \
413  { \
414  /* Prevent this block from being optimized away */ \
415  asm volatile ("#\n"); \
416  if (1)
417 
418 
419 #define _SEH3_FINALLY \
420  /* End of the try block */ \
421  _SEH3$_l_AfterTry: (void)0; \
422  /* Set ExceptionPointers to 0, this is used by _abnormal_termination() */ \
423  _SEH3$_TrylevelFrame.ExceptionPointers = 0; \
424 \
425  goto _SEH3$_l_EndTry; \
426 \
427  _SEH3$_l_BeforeTry: (void)0; \
428  _SEH3$_ASM_GOTO(_SEH3$_l_OnException); \
429 \
430  /* Forward declaration of the finally function */ \
431  _SEH3$_DECLARE_FILTER_FUNC(_SEH3$_FinallyFunction); \
432 \
433  /* Create a static data table that contains the finally function */ \
434  static const SEH3$_SCOPE_TABLE _SEH3$_ScopeTable = { 0, _SEH3$_FINALLY(&_SEH3$_FinallyFunction), _SEH3$_TryLevel, _SEH3$_HANDLER_TYPE }; \
435 \
436  /* Register the registration record. */ \
437  if (_SEH3$_TryLevel == 1) _SEH3$_RegisterFrame_(&_SEH3$_TrylevelFrame, &_SEH3$_ScopeTable); \
438  else _SEH3$_RegisterTryLevel_(&_SEH3$_TrylevelFrame, &_SEH3$_ScopeTable); \
439  _SEH3$_TrylevelFrame.ExceptionPointers = (PSEH3$_EXCEPTION_POINTERS)1; \
440 \
441  goto _SEH3$_l_DoTry; \
442 \
443  _SEH3$_l_HandlerTarget: (void)0; \
444  _SEH3$_EnforceFramePointer(); \
445 \
446  _SEH3$_l_BeforeFilterOrFinally: (void)0; \
447  _SEH3$_EnforceFramePointer(); \
448  _SEH3$_l_FilterOrFinally: (void)0; \
449  _SEH3$_FINALLY_FUNC_OPEN(_SEH3$_FinallyFunction)
450 
451 
452 #define _SEH3_END \
453  }; \
454  goto _SEH3$_l_EndTry; \
455 \
456  _SEH3$_l_OnException: (void)0; \
457  /* Force GCC to create proper code pathes */ \
458  _SEH3$_SCARE_GCC(); \
459 \
460  _SEH3$_l_EndTry:(void)0; \
461  _SEH3$_ASM_GOTO(_SEH3$_l_OnException); \
462 \
463  /* Implementation of the auto cleanup function */ \
464  _SEH3$_DEFINE_CLEANUP_FUNC(_SEH3$_AutoCleanup); \
465 \
466  /* Close the outer scope */ \
467  }
468 
469 #define _SEH3_LEAVE goto _SEH3$_l_AfterTry
470 
471 #define _SEH3_VOLATILE volatile
472 
473 
474 #ifdef __cplusplus
475 }; // extern "C"
476 #endif
static unsigned int block
Definition: xmlmemory.c:118
void * Filter
Definition: pseh3.h:41
int const SEH3 $_SCOPE_TABLE * ScopeTable
Definition: pseh3.h:127
#define error(str)
Definition: mkdosfs.c:1605
#define __cdecl
Definition: accygwin.h:79
unsigned long Esp
Definition: pseh3.h:71
void * Handler
Definition: pseh3.h:56
PSEH3 $_SCOPE_TABLE ScopeTable
Definition: pseh3.h:62
static __attribute__((always_inline)) __attribute__((returns_twice)) void _SEH3 $_PreventInlining()
Definition: pseh3.h:86
struct _SEH3 $_REGISTRATION_FRAME * EndOfChain
Definition: pseh3.h:59
unsigned long Ebp
Definition: pseh3.h:72
struct _CONTEXT * ContextRecord
Definition: pseh3.h:49
#define _SEH3
Definition: pseh3.h:323
struct _SEH3 $_REGISTRATION_FRAME * Next
Definition: pseh3.h:55
c used
Definition: write.c:2857
#define volatile
Definition: prototyp.h:117
HRESULT Next([in] ULONG celt, [out, size_is(celt), length_is(*pceltFetched)] STATPROPSETSTG *rgelt, [out] ULONG *pceltFetched)
unsigned char HandlerType
Definition: pseh3.h:43
int const SEH3 $_SCOPE_TABLE void * AllocaFrame
Definition: pseh3.h:127
unsigned long ExceptionCode
Definition: pseh3.h:68
PSEH3 $_EXCEPTION_POINTERS volatile ExceptionPointers
Definition: pseh3.h:65
void * Target
Definition: pseh3.h:40
struct _EXCEPTION_RECORD * ExceptionRecord
Definition: pseh3.h:48
void _abnormal_termination()
Definition: stubs.c:222
unsigned char TryLevel
Definition: pseh3.h:42
char * AllocaFrame
Definition: pseh3.h:74
#define const
Definition: zconf.h:230
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition: glext.h:7005