ReactOS  0.4.10-dev-238-gc84f398
kdinit.c
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS Kernel
3  * LICENSE: GPL - See COPYING in the top level directory
4  * FILE: ntoskrnl/kd64/kdinit.c
5  * PURPOSE: KD64 Initialization Code
6  * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7  * Stefan Ginsberg (stefan.ginsberg@reactos.org)
8  */
9 
10 /* INCLUDES ******************************************************************/
11 
12 #include <ntoskrnl.h>
13 #include <reactos/buildno.h>
14 #define NDEBUG
15 #include <debug.h>
16 
17 /* UTILITY FUNCTIONS *********************************************************/
18 
19 /*
20  * Get the total size of the memory before
21  * Mm is initialized, by counting the number
22  * of physical pages. Useful for debug logging.
23  *
24  * Strongly inspired by:
25  * mm\ARM3\mminit.c : MiScanMemoryDescriptors(...)
26  *
27  * See also: kd\kdio.c
28  */
29 static SIZE_T
32 {
33  PLIST_ENTRY ListEntry;
35  SIZE_T NumberOfPhysicalPages = 0;
36 
37  /* Loop the memory descriptors */
38  for (ListEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
39  ListEntry != &LoaderBlock->MemoryDescriptorListHead;
40  ListEntry = ListEntry->Flink)
41  {
42  /* Get the descriptor */
43  Descriptor = CONTAINING_RECORD(ListEntry,
45  ListEntry);
46 
47  /* Check if this is invisible memory */
48  if ((Descriptor->MemoryType == LoaderFirmwarePermanent) ||
49  (Descriptor->MemoryType == LoaderSpecialMemory) ||
50  (Descriptor->MemoryType == LoaderHALCachedMemory) ||
51  (Descriptor->MemoryType == LoaderBBTMemory))
52  {
53  /* Skip this descriptor */
54  continue;
55  }
56 
57  /* Check if this is bad memory */
58  if (Descriptor->MemoryType != LoaderBad)
59  {
60  /* Count this in the total of pages */
61  NumberOfPhysicalPages += Descriptor->PageCount;
62  }
63  }
64 
65  return NumberOfPhysicalPages * PAGE_SIZE / 1024 / 1024;
66 }
67 
68 /* See also: kd\kdio.c */
69 static VOID
72 {
73  DPRINT1("-----------------------------------------------------\n");
74  DPRINT1("ReactOS " KERNEL_VERSION_STR " (Build " KERNEL_VERSION_BUILD_STR ") (Commit " KERNEL_VERSION_COMMIT_HASH ")\n");
75  DPRINT1("%u System Processor [%u MB Memory]\n", KeNumberProcessors, MemSizeMBs);
76 
77  if (KeLoaderBlock)
78  {
79  DPRINT1("Command Line: %s\n", KeLoaderBlock->LoadOptions);
81  }
82 }
83 
84 /* FUNCTIONS *****************************************************************/
85 
86 VOID
87 NTAPI
89 {
90  /* Update the KeUserCallbackDispatcher pointer */
93 }
94 
95 BOOLEAN
96 NTAPI
98  IN PDBGKD_DEBUG_DATA_HEADER64 DataHeader,
99  IN ULONG Size)
100 {
101  KIRQL OldIrql;
102  PLIST_ENTRY NextEntry;
103  PDBGKD_DEBUG_DATA_HEADER64 CurrentHeader;
104 
105  /* Acquire the Data Lock */
107 
108  /* Loop the debugger data list */
109  NextEntry = KdpDebuggerDataListHead.Flink;
110  while (NextEntry != &KdpDebuggerDataListHead)
111  {
112  /* Get the header for this entry */
113  CurrentHeader = CONTAINING_RECORD(NextEntry,
115  List);
116 
117  /* Move to the next one */
118  NextEntry = NextEntry->Flink;
119 
120  /* Check if we already have this data block */
121  if ((CurrentHeader == DataHeader) || (CurrentHeader->OwnerTag == Tag))
122  {
123  /* Release the lock and fail */
125  return FALSE;
126  }
127  }
128 
129  /* Setup the header */
130  DataHeader->OwnerTag = Tag;
131  DataHeader->Size = Size;
132 
133  /* Insert it into the list and release the lock */
134  InsertTailList(&KdpDebuggerDataListHead, (PLIST_ENTRY)&DataHeader->List);
136  return TRUE;
137 }
138 
139 BOOLEAN
140 NTAPI
142  IN PLOADER_PARAMETER_BLOCK LoaderBlock)
143 {
144  BOOLEAN EnableKd, DisableKdAfterInit = FALSE, BlockEnable;
145  LPSTR CommandLine, DebugLine, DebugOptionStart, DebugOptionEnd;
147  PLDR_DATA_TABLE_ENTRY LdrEntry;
148  PLIST_ENTRY NextEntry;
149  ULONG i, j, Length;
150  SIZE_T DebugOptionLength;
151  SIZE_T MemSizeMBs;
152  CHAR NameBuffer[256];
153  PWCHAR Name;
154 
155 #if defined(__GNUC__)
156  /* Make gcc happy */
157  BlockEnable = FALSE;
158 #endif
159 
160  /* Check if this is Phase 1 */
161  if (BootPhase)
162  {
163  /* Just query the performance counter */
165  return TRUE;
166  }
167 
168  /* Check if we already initialized once */
169  if (KdDebuggerEnabled) return TRUE;
170 
171  /* Set the Debug Routine as the Stub for now */
173 
174  /* Disable break after symbol load for now */
176 
177  /* Check if the Debugger Data Block was already initialized */
179  {
180  /* It wasn't...Initialize the KD Data Listhead */
182 
183  /* Register the Debugger Data Block */
186  sizeof(KdDebuggerDataBlock));
187 
188  /* Fill out the KD Version Block */
191 
192 #ifdef CONFIG_SMP
193  /* This is an MP Build */
195 #endif
196 
197  /* Save Pointers to Loaded Module List and Debugger Data */
200 
201  /* Set protocol limits */
206  KdVersionBlock.Unused[0] = 0;
207 
208  /* Link us in the KPCR */
209  KeGetPcr()->KdVersionBlock = &KdVersionBlock;
210  }
211 
212  /* Check if we have a loader block */
213  if (LoaderBlock)
214  {
215  /* Get the image entry */
216  LdrEntry = CONTAINING_RECORD(LoaderBlock->LoadOrderListHead.Flink,
218  InLoadOrderLinks);
219 
220  /* Save the Kernel Base */
221  PsNtosImageBase = (ULONG_PTR)LdrEntry->DllBase;
223 
224  /* Check if we have a command line */
225  CommandLine = LoaderBlock->LoadOptions;
226  if (CommandLine)
227  {
228  /* Upcase it */
229  _strupr(CommandLine);
230 
231  /* Assume we'll disable KD */
232  EnableKd = FALSE;
233 
234  /* Check for CRASHDEBUG, NODEBUG and just DEBUG */
235  if (strstr(CommandLine, "CRASHDEBUG"))
236  {
237  /* Don't enable KD now, but allow it to be enabled later */
239  }
240  else if (strstr(CommandLine, "NODEBUG"))
241  {
242  /* Don't enable KD and don't let it be enabled later */
244  }
245  else if ((DebugLine = strstr(CommandLine, "DEBUG")) != NULL)
246  {
247  /* Enable KD */
248  EnableKd = TRUE;
249 
250  /* Check if there are any options */
251  if (DebugLine[5] == '=')
252  {
253  /* Save pointers */
254  DebugOptionStart = DebugOptionEnd = &DebugLine[6];
255 
256  /* Scan the string for debug options */
257  for (;;)
258  {
259  /* Loop until we reach the end of the string */
260  while (*DebugOptionEnd != ANSI_NULL)
261  {
262  /* Check if this is a comma, a space or a tab */
263  if ((*DebugOptionEnd == ',') ||
264  (*DebugOptionEnd == ' ') ||
265  (*DebugOptionEnd == '\t'))
266  {
267  /*
268  * We reached the end of the option or
269  * the end of the string, break out
270  */
271  break;
272  }
273  else
274  {
275  /* Move on to the next character */
276  DebugOptionEnd++;
277  }
278  }
279 
280  /* Calculate the length of the current option */
281  DebugOptionLength = (DebugOptionEnd - DebugOptionStart);
282 
283  /*
284  * Break out if we reached the last option
285  * or if there were no options at all
286  */
287  if (!DebugOptionLength) break;
288 
289  /* Now check which option this is */
290  if ((DebugOptionLength == 10) &&
291  !(strncmp(DebugOptionStart, "AUTOENABLE", 10)))
292  {
293  /*
294  * Disable the debugger, but
295  * allow it to be reenabled
296  */
297  DisableKdAfterInit = TRUE;
298  BlockEnable = FALSE;
300  }
301  else if ((DebugOptionLength == 7) &&
302  !(strncmp(DebugOptionStart, "DISABLE", 7)))
303  {
304  /* Disable the debugger */
305  DisableKdAfterInit = TRUE;
306  BlockEnable = TRUE;
308  }
309  else if ((DebugOptionLength == 6) &&
310  !(strncmp(DebugOptionStart, "NOUMEX", 6)))
311  {
312  /* Ignore user mode exceptions */
314  }
315 
316  /*
317  * If there are more options then
318  * the next character should be a comma
319  */
320  if (*DebugOptionEnd != ',')
321  {
322  /* It isn't, break out */
323  break;
324  }
325 
326  /* Move on to the next option */
327  DebugOptionEnd++;
328  DebugOptionStart = DebugOptionEnd;
329  }
330  }
331  }
332  }
333  else
334  {
335  /* No command line options? Disable debugger by default */
337  EnableKd = FALSE;
338  }
339  }
340  else
341  {
342  /* Called from a bugcheck or a re-enable. Save the Kernel Base */
344 
345  /* Unconditionally enable KD */
346  EnableKd = TRUE;
347  }
348 
349  /* Set the Kernel Base in the Data Block */
351 
352  /* Initialize the debugger if requested */
353  if (EnableKd && (NT_SUCCESS(KdDebuggerInitialize0(LoaderBlock))))
354  {
355  /* Now set our real KD routine */
357 
358  /* Check if we've already initialized our structures */
360  {
361  /* Set the Debug Switch Routine and Retries */
364 
365  /* Initialize breakpoints owed flag and table */
367  for (i = 0; i < KD_BREAKPOINT_MAX; i++)
368  {
372  }
373 
374  /* Initialize the Time Slip DPC */
378 
379  /* First-time initialization done! */
381  }
382 
383  /* Initialize the timer */
385 
386  /* Officially enable KD */
389 
390  /* Let user-mode know that it's enabled as well */
391  SharedUserData->KdDebuggerEnabled = TRUE;
392 
393  /* Display separator + ReactOS version at start of the debug log */
394  MemSizeMBs = KdpGetMemorySizeInMBs(KeLoaderBlock);
395  KdpPrintBanner(MemSizeMBs);
396 
397  /* Check if the debugger should be disabled initially */
398  if (DisableKdAfterInit)
399  {
400  /* Disable it */
402 
403  /*
404  * Save the enable block state and return initialized
405  * (the debugger is active but disabled).
406  */
407  KdBlockEnable = BlockEnable;
408  return TRUE;
409  }
410 
411  /* Check if we have a loader block */
412  if (LoaderBlock)
413  {
414  /* Loop boot images */
415  NextEntry = LoaderBlock->LoadOrderListHead.Flink;
416  i = 0;
417  while ((NextEntry != &LoaderBlock->LoadOrderListHead) && (i < 2))
418  {
419  /* Get the image entry */
420  LdrEntry = CONTAINING_RECORD(NextEntry,
422  InLoadOrderLinks);
423 
424  /* Generate the image name */
425  Name = LdrEntry->FullDllName.Buffer;
426  Length = LdrEntry->FullDllName.Length / sizeof(WCHAR);
427  j = 0;
428  do
429  {
430  /* Do cheap Unicode to ANSI conversion */
431  NameBuffer[j++] = (CHAR)*Name++;
432  } while (j < Length);
433 
434  /* Null-terminate */
435  NameBuffer[j] = ANSI_NULL;
436 
437  /* Load symbols for image */
438  RtlInitString(&ImageName, NameBuffer);
439  DbgLoadImageSymbols(&ImageName,
440  LdrEntry->DllBase,
442 
443  /* Go to the next entry */
444  NextEntry = NextEntry->Flink;
445  i++;
446  }
447  }
448 
449  /* Check for incoming breakin and break on symbol load if we have it */
451  }
452  else
453  {
454  /* Disable debugger */
456  }
457 
458  /* Return initialized */
459  return TRUE;
460 }
NTSTATUS NTAPI KdDebuggerInitialize0(IN PLOADER_PARAMETER_BLOCK LoaderBlock OPTIONAL)
Definition: kdcom.c:147
#define IN
Definition: typedefs.h:38
LARGE_INTEGER NTAPI KeQueryPerformanceCounter(IN PLARGE_INTEGER PerformanceFreq)
Definition: timer.c:138
GLenum GLclampf GLint GLenum GLuint GLenum GLenum GLsizei GLenum const GLvoid GLfloat GLfloat GLfloat GLfloat GLclampd GLint GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean GLboolean GLboolean GLboolean GLint GLenum GLsizei const GLvoid GLenum GLint GLenum GLint GLint GLsizei GLint GLenum GLint GLint GLint GLint GLsizei GLenum GLsizei const GLuint GLboolean GLenum GLenum GLint GLsizei GLenum GLsizei GLenum const GLvoid GLboolean const GLboolean GLenum const GLdouble const GLfloat const GLdouble const GLfloat GLenum GLint GLint GLint GLint GLint GLint j
Definition: glfuncs.h:98
#define TRUE
Definition: types.h:120
DBGKD_GET_VERSION64 KdVersionBlock
Definition: kddata.c:371
PSTR ArcBootDeviceName
Definition: arc.h:503
BOOLEAN KdpDebuggerStructuresInitialized
Definition: kddata.c:88
#define DbgKdMaximumStateChange
Definition: windbgkd.h:62
PKDEBUG_ROUTINE KiDebugRoutine
Definition: kdmain.c:504
char * strstr(char *String1, char *String2)
Definition: utclib.c:653
char CHAR
Definition: xmlstorage.h:175
BOOLEAN KdAutoEnableOnEvent
Definition: kddata.c:84
BOOLEAN NTAPI KdpStub(IN PKTRAP_FRAME TrapFrame, IN PKEXCEPTION_FRAME ExceptionFrame, IN PEXCEPTION_RECORD ExceptionRecord, IN PCONTEXT ContextRecord, IN KPROCESSOR_MODE PreviousMode, IN BOOLEAN SecondChanceException)
Definition: kdtrap.c:271
BOOLEAN KdBlockEnable
Definition: kddata.c:85
uint16_t * PWCHAR
Definition: typedefs.h:54
#define InsertTailList(ListHead, Entry)
ULONG64 KernBase
Definition: wdbgexts.h:180
char * LPSTR
Definition: xmlstorage.h:182
BOOLEAN NTAPI KdInitSystem(ULONG BootPhase, PLOADER_PARAMETER_BLOCK LoaderBlock)
Definition: kdinit.c:174
#define WCHAR
Definition: msvc.h:43
PKDEBUG_SWITCH_ROUTINE KiDebugSwitchRoutine
Definition: kddata.c:75
#define KeGetPcr()
Definition: ke.h:25
uint32_t ULONG_PTR
Definition: typedefs.h:63
PVOID DllBase
Definition: btrfs_drv.h:1766
UCHAR KIRQL
Definition: env_spec_w32.h:591
TYPE_OF_MEMORY MemoryType
Definition: arc.h:193
LARGE_INTEGER KdTimerStart
Definition: kd64.h:548
#define DbgKdMaximumManipulate
Definition: windbgkd.h:117
GLenum GLclampf GLint i
Definition: glfuncs.h:14
PVOID KeUserCallbackDispatcher
Definition: ke.h:138
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
#define FALSE
Definition: types.h:117
#define ANSI_NULL
ULONG_PTR DirectoryTableBase
Definition: kd64.h:51
VOID NTAPI KdUpdateDataBlock(VOID)
Definition: kdinit.c:88
Definition: arc.h:130
LARGE_INTEGER KdPerformanceCounterRate
Definition: kddata.c:91
BOOLEAN KdpOweBreakpoint
Definition: kddata.c:98
ULONG_PTR PsNtosImageBase
Definition: sysldr.c:38
BOOLEAN NTAPI KdPollBreakIn(VOID)
Definition: kdmain.c:367
static SIZE_T INIT_FUNCTION KdpGetMemorySizeInMBs(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
Definition: kdinit.c:31
smooth NULL
Definition: ftsmooth.c:416
WORK_QUEUE_ITEM KdpTimeSlipWorkItem
Definition: kddata.c:118
BOOLEAN KdDebuggerEnabled
Definition: kdmain.c:16
VOID NTAPI KeInitializeTimer(OUT PKTIMER Timer)
Definition: timerobj.c:233
KSPIN_LOCK KdpDataSpinLock
Definition: kddata.c:366
static VOID INIT_FUNCTION KdpPrintBanner(IN SIZE_T MemSizeMBs)
Definition: kdinit.c:71
PLOADER_PARAMETER_BLOCK KeLoaderBlock
Definition: krnlinit.c:29
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
ULONG64 KeUserCallbackDispatcher
Definition: wdbgexts.h:188
KD_CONTEXT KdpContext
Definition: kdmain.c:23
UINTN Size
Definition: acefiex.h:555
ULONG Flags
Definition: kd64.h:50
#define KDBG_TAG
Definition: wdbgexts.h:28
struct _LIST_ENTRY * Flink
Definition: typedefs.h:119
unsigned char BOOLEAN
#define ExInitializeWorkItem(Item, Routine, Context)
Definition: exfuncs.h:265
LIST_ENTRY List
Definition: psmgr.c:57
if(!(yy_init))
Definition: macro.lex.yy.c:717
NTSTATUS NTAPI KdDisableDebuggerWithLock(IN BOOLEAN NeedLock)
Definition: kdapi.c:2035
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:24
LIST_ENTRY PsLoadedModuleList
Definition: sysldr.c:34
#define KeAcquireSpinLock(sl, irql)
Definition: env_spec_w32.h:609
int strncmp(const char *String1, const char *String2, ACPI_SIZE Count)
Definition: utclib.c:534
ULONG64 PsLoadedModuleList
Definition: wdbgexts.h:160
#define DbgKdMinimumManipulate
Definition: windbgkd.h:73
KDDEBUGGER_DATA64 * KdDebuggerDataBlock
Definition: kdpacket.c:21
USHORT Unused[1]
Definition: wdbgexts.h:158
ULONG NtBuildNumber
Definition: init.c:47
std::wstring STRING
Definition: fontsub.cpp:33
_In_ PUNICODE_STRING Name
Definition: mrx.h:218
unsigned __int64 ULONG64
Definition: imports.h:198
#define SharedUserData
static const char * ImageName
Definition: image.c:34
VOID UINTN Length
Definition: acefiex.h:744
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:803
Definition: btrfs_drv.h:1762
#define PAGE_SIZE
Definition: env_spec_w32.h:49
#define KD_BREAKPOINT_MAX
Definition: kd64.h:23
Definition: typedefs.h:117
CCHAR KeNumberProcessors
Definition: krnlinit.c:35
#define DbgKdMinimumStateChange
Definition: windbgkd.h:58
NTSYSAPI VOID NTAPI RtlInitString(PSTRING DestinationString, PCSZ SourceString)
BOOLEAN KdPitchDebugger
Definition: kdmain.c:21
KDPC KdpTimeSlipDpc
Definition: kddata.c:116
BOOLEAN NTAPI KdpTrap(IN PKTRAP_FRAME TrapFrame, IN PKEXCEPTION_FRAME ExceptionFrame, IN PEXCEPTION_RECORD ExceptionRecord, IN PCONTEXT ContextRecord, IN KPROCESSOR_MODE PreviousMode, IN BOOLEAN SecondChanceException)
Definition: kdtrap.c:135
ULONG_PTR SIZE_T
Definition: typedefs.h:78
_CRTIMP char *__cdecl _strupr(_Inout_z_ char *_String)
unsigned short USHORT
Definition: pedump.c:61
LIST_ENTRY KdpDebuggerDataListHead
Definition: kddata.c:365
#define DBGKD_VERS_FLAG_MP
Definition: wdbgexts.h:21
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
BOOLEAN KdIgnoreUmExceptions
Definition: kdmain.c:22
UNICODE_STRING FullDllName
Definition: btrfs_drv.h:1768
BREAKPOINT_ENTRY KdpBreakpointTable[KD_BREAKPOINT_MAX]
Definition: kddata.c:96
__int3264 LONG_PTR
Definition: mstsclib_h.h:276
HANDLE NTAPI PsGetCurrentProcessId(VOID)
Definition: process.c:1123
#define KeReleaseSpinLock(sl, irql)
Definition: env_spec_w32.h:627
VOID NTAPI KdpTimeSlipDpcRoutine(IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2)
Definition: kdapi.c:1785
VOID NTAPI KdpTimeSlipWork(IN PVOID Context)
Definition: kdapi.c:1811
VOID NTAPI DbgLoadImageSymbols(_In_ PSTRING Name, _In_ PVOID Base, _In_ ULONG_PTR ProcessId)
ULONG KdpDefaultRetries
Definition: windbgkd.h:226
#define DPRINT1
Definition: precomp.h:8
IN ULONG IN ULONG Tag
Definition: evtlib.h:159
PVOID Address
Definition: kd64.h:52
unsigned int ULONG
Definition: retypes.h:1
#define ULONG_PTR
Definition: config.h:101
BOOLEAN NTAPI KdpSwitchProcessor(IN PEXCEPTION_RECORD ExceptionRecord, IN OUT PCONTEXT ContextRecord, IN BOOLEAN SecondChanceException)
Definition: kdapi.c:1833
VOID NTAPI KeInitializeDpc(IN PKDPC Dpc, IN PKDEFERRED_ROUTINE DeferredRoutine, IN PVOID DeferredContext)
Definition: dpc.c:711
DBGKD_DEBUG_DATA_HEADER64 Header
Definition: wdbgexts.h:179
#define CHAR(Char)
KTIMER KdpTimeSlipTimer
Definition: kddata.c:117
BOOLEAN KdBreakAfterSymbolLoad
Definition: kdmain.c:19
BOOLEAN NTAPI KdRegisterDebuggerDataBlock(IN ULONG Tag, IN PDBGKD_DEBUG_DATA_HEADER64 DataHeader, IN ULONG Size)
Definition: kdinit.c:97
BOOLEAN KdDebuggerNotPresent
Definition: kdmain.c:18
ULONG64 DebuggerDataList
Definition: wdbgexts.h:161
#define LONG_PTR
Definition: generated.c:25
LONGLONG QuadPart
Definition: typedefs.h:112
#define INIT_FUNCTION
Definition: ntoskrnl.h:11
_In_ PSTORAGE_PROPERTY_ID _Outptr_ PSTORAGE_DESCRIPTOR_HEADER * Descriptor
Definition: classpnp.h:966