Home | History | Annotate | Download | only in GdbDebugAgent
      1 /** @file
      2   Private include file for GDB stub
      3 
      4   Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
      5 
      6   This program and the accompanying materials
      7   are licensed and made available under the terms and conditions of the BSD License
      8   which accompanies this distribution.  The full text of the license may be found at
      9   http://opensource.org/licenses/bsd-license.php
     10 
     11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #ifndef __GCC_DEBUG_AGENT_INTERNAL__
     17 #define __GCC_DEBUG_AGENT_INTERNAL__
     18 
     19 #include <Uefi.h>
     20 #include <Library/BaseLib.h>
     21 #include <Library/BaseMemoryLib.h>
     22 #include <Library/MemoryAllocationLib.h>
     23 #include <Library/DebugLib.h>
     24 #include <Library/PcdLib.h>
     25 #include <Library/GdbSerialLib.h>
     26 #include <Library/PrintLib.h>
     27 #include <Library/CacheMaintenanceLib.h>
     28 #include <Library/DebugAgentTimerLib.h>
     29 #include <Library/DebugAgentLib.h>
     30 
     31 #include <IndustryStandard/PeImage.h>
     32 #include <Protocol/DebugSupport.h>
     33 
     34 extern CONST CHAR8 mHexToStr[];
     35 
     36 // maximum size of input and output buffers
     37 // This value came from the show remote command of the gdb we tested against
     38 #define MAX_BUF_SIZE 2000
     39 
     40 // maximum size of address buffer
     41 #define MAX_ADDR_SIZE 32
     42 
     43 // maximum size of register number buffer
     44 #define MAX_REG_NUM_BUF_SIZE 32
     45 
     46 // maximum size of length buffer
     47 #define MAX_LENGTH_SIZE 32
     48 
     49 // maximum size of T signal members
     50 #define MAX_T_SIGNAL_SIZE 64
     51 
     52 // the mask used to clear all the cache
     53 #define TF_BIT 0x00000100
     54 
     55 
     56 //
     57 // GDB Signal definitions - generic names for interrupts
     58 //
     59 #define GDB_SIGINT      2  // Interrupt process via ctrl-c
     60 #define GDB_SIGILL      4  // Illegal instruction
     61 #define GDB_SIGTRAP     5  // Trace Trap (Breakpoint and SingleStep)
     62 #define GDB_SIGEMT      7  // Emulator Trap
     63 #define GDB_SIGFPE      8  // Floating point exception
     64 #define GDB_SIGSEGV     11 // Setgment violation, page fault
     65 
     66 
     67 //
     68 // GDB File I/O Error values, zero means no error
     69 // Includes all general GDB Unix like error values
     70 //
     71 #define GDB_EBADMEMADDRBUFSIZE   11  // the buffer that stores memory Address to be read from/written to is not the right size
     72 #define GDB_EBADMEMLENGBUFSIZE   12  // the buffer that stores Length is not the right size
     73 #define GDB_EBADMEMLENGTH        13  // Length, the given number of bytes to read or write, is not the right size
     74 #define GDB_EBADMEMDATA          14  // one of the bytes or nibbles of the memory is leess than 0
     75 #define GDB_EBADMEMDATASIZE      15  // the memory data, 'XX..', is too short or too long
     76 #define GDB_EBADBUFSIZE          21  // the buffer created is not the correct size
     77 #define GDB_EINVALIDARG          31  // argument is invalid
     78 #define GDB_ENOSPACE             41  //
     79 #define GDB_EINVALIDBRKPOINTTYPE 51  // the breakpoint type is not recognized
     80 #define GDB_EINVALIDREGNUM       61  // given register number is not valid: either <0 or >=Number of Registers
     81 #define GDB_EUNKNOWN             255 // unknown
     82 
     83 
     84 //
     85 // These devices are open by GDB so we can just read and write to them
     86 //
     87 #define GDB_STDIN   0x00
     88 #define GDB_STDOUT  0x01
     89 #define GDB_STDERR  0x02
     90 
     91 //
     92 //Define Register size for different architectures
     93 //
     94 #if defined (MDE_CPU_IA32)
     95 #define REG_SIZE  32
     96 #elif defined (MDE_CPU_X64)
     97 #define REG_SIZE  64
     98 #elif defined (MDE_CPU_ARM)
     99 #define REG_SIZE  32
    100 #endif
    101 
    102 
    103 typedef struct {
    104   EFI_EXCEPTION_TYPE  Exception;
    105   UINT8               SignalNo;
    106 } EFI_EXCEPTION_TYPE_ENTRY;
    107 
    108 
    109 #if defined (MDE_CPU_IA32) || defined (MDE_CPU_X64)
    110 
    111 //
    112 // Byte packed structure for DR6
    113 // 32-bits on IA-32
    114 // 64-bits on X64.  The upper 32-bits on X64 are reserved
    115 //
    116 typedef union {
    117   struct {
    118     UINT32  B0:1;           // Breakpoint condition detected
    119     UINT32  B1:1;           // Breakpoint condition detected
    120     UINT32  B2:1;           // Breakpoint condition detected
    121     UINT32  B3:1;           // Breakpoint condition detected
    122     UINT32  Reserved_1:9;   // Reserved
    123     UINT32  BD:1;           // Debug register access detected
    124     UINT32  BS:1;           // Single step
    125     UINT32  BT:1;           // Task switch
    126     UINT32  Reserved_2:16;  // Reserved
    127   } Bits;
    128   UINTN     UintN;
    129 } IA32_DR6;
    130 
    131 //
    132 // Byte packed structure for DR7
    133 // 32-bits on IA-32
    134 // 64-bits on X64.  The upper 32-bits on X64 are reserved
    135 //
    136 typedef union {
    137   struct {
    138     UINT32  L0:1;           // Local breakpoint enable
    139     UINT32  G0:1;           // Global breakpoint enable
    140     UINT32  L1:1;           // Local breakpoint enable
    141     UINT32  G1:1;           // Global breakpoint enable
    142     UINT32  L2:1;           // Local breakpoint enable
    143     UINT32  G2:1;           // Global breakpoint enable
    144     UINT32  L3:1;           // Local breakpoint enable
    145     UINT32  G3:1;           // Global breakpoint enable
    146     UINT32  LE:1;           // Local exact breakpoint enable
    147     UINT32  GE:1;           // Global exact breakpoint enable
    148     UINT32  Reserved_1:3;   // Reserved
    149     UINT32  GD:1;           // Global detect enable
    150     UINT32  Reserved_2:2;   // Reserved
    151     UINT32  RW0:2;          // Read/Write field
    152     UINT32  LEN0:2;         // Length field
    153     UINT32  RW1:2;          // Read/Write field
    154     UINT32  LEN1:2;         // Length field
    155     UINT32  RW2:2;          // Read/Write field
    156     UINT32  LEN2:2;         // Length field
    157     UINT32  RW3:2;          // Read/Write field
    158     UINT32  LEN3:2;         // Length field
    159   } Bits;
    160   UINTN     UintN;
    161 } IA32_DR7;
    162 
    163 #endif /* if defined (MDE_CPU_IA32) || defined (MDE_CPU_X64) */
    164 
    165 typedef enum {
    166   InstructionExecution,   //Hardware breakpoint
    167   DataWrite,              //watch
    168   DataRead,               //rwatch
    169   DataReadWrite,          //awatch
    170   SoftwareBreakpoint,     //Software breakpoint
    171   NotSupported
    172 } BREAK_TYPE;
    173 
    174 //
    175 // Array of exception types that need to be hooked by the debugger
    176 //
    177 extern EFI_EXCEPTION_TYPE_ENTRY gExceptionType[];
    178 
    179 //
    180 // If the periodic callback is called while we are processing an F packet we need
    181 // to let the callback know to not read from the serail stream as it could steal
    182 // characters from the F reponse packet
    183 //
    184 extern BOOLEAN gProcessingFPacket;
    185 
    186 
    187 /**
    188  Return the number of entries in the gExceptionType[]
    189 
    190  @retval    UINTN, the number of entries in the gExceptionType[] array.
    191  **/
    192 UINTN
    193 MaxEfiException (
    194   VOID
    195   );
    196 
    197 
    198 /**
    199  Check to see if the ISA is supported.
    200  ISA = Instruction Set Architecture
    201 
    202  @retval    TRUE if Isa is supported,
    203  FALSE otherwise.
    204  **/
    205 BOOLEAN
    206 CheckIsa (
    207   IN    EFI_INSTRUCTION_SET_ARCHITECTURE    Isa
    208   );
    209 
    210 
    211 /**
    212  Send the T signal with the given exception type (in gdb order) and possibly with n:r pairs related to the watchpoints
    213 
    214  @param  SystemContext        Register content at time of the exception
    215  @param  GdbExceptionType     GDB exception type
    216  **/
    217 
    218 VOID
    219 GdbSendTSignal (
    220   IN  EFI_SYSTEM_CONTEXT  SystemContext,
    221   IN  UINT8               GdbExceptionType
    222   );
    223 
    224 
    225 /**
    226  Translates the EFI mapping to GDB mapping
    227 
    228  @param     EFIExceptionType        EFI Exception that is being processed
    229  @retval    UINTN that corresponds to EFIExceptionType's GDB exception type number
    230  **/
    231 UINT8
    232 ConvertEFItoGDBtype (
    233   IN  EFI_EXCEPTION_TYPE EFIExceptionType
    234   );
    235 
    236 
    237 /**
    238  Empties the given buffer
    239  @param *Buf pointer to the first element in buffer to be emptied
    240  **/
    241 VOID
    242 EmptyBuffer (
    243   IN CHAR8  *Buf
    244   );
    245 
    246 
    247 /**
    248  Converts an 8-bit Hex Char into a INTN.
    249 
    250  @param     Char  - the hex character to be converted into UINTN
    251  @retval    a INTN, from 0 to 15, that corressponds to Char
    252  -1 if Char is not a hex character
    253  **/
    254 INTN
    255 HexCharToInt (
    256   IN  CHAR8 Char
    257   );
    258 
    259 
    260 /** 'E NN'
    261  Send an error with the given error number after converting to hex.
    262  The error number is put into the buffer in hex. '255' is the biggest errno we can send.
    263  ex: 162 will be sent as A2.
    264 
    265  @param   errno    the error number that will be sent
    266  **/
    267 VOID
    268 EFIAPI
    269 SendError (
    270   IN  UINT8     ErrorNum
    271   );
    272 
    273 
    274 /**
    275  Send 'OK' when the function is done executing successfully.
    276  **/
    277 VOID
    278 SendSuccess (
    279   VOID
    280   );
    281 
    282 
    283 /**
    284  Send empty packet to specify that particular command/functionality is not supported.
    285  **/
    286 VOID
    287 SendNotSupported (
    288   VOID
    289   );
    290 
    291 /** p n
    292  Reads the n-th register's value into an output buffer and sends it as a packet
    293  @param     SystemContext       Register content at time of the exception
    294  @param     InBuffer            This is the input buffer received from gdb server
    295  **/
    296 VOID
    297 ReadNthRegister (
    298   IN    EFI_SYSTEM_CONTEXT  SystemContext,
    299   IN    CHAR8               *InBuffer
    300   );
    301 
    302 
    303 /** g
    304  Reads the general registers into an output buffer  and sends it as a packet
    305  @param     SystemContext           Register content at time of the exception
    306  **/
    307 VOID
    308 ReadGeneralRegisters (
    309   IN    EFI_SYSTEM_CONTEXT  SystemContext
    310   );
    311 
    312 
    313 /** P n...=r...
    314  Writes the new value of n-th register received into the input buffer to the n-th register
    315  @param     SystemContext       Register content at time of the exception
    316  @param     InBuffer            This is the input buffer received from gdb server
    317  **/
    318 VOID
    319 WriteNthRegister (
    320   IN    EFI_SYSTEM_CONTEXT  SystemContext,
    321   IN    CHAR8               *InBuffer
    322   );
    323 
    324 
    325 /** G XX...
    326  Writes the new values received into the input buffer to the general registers
    327  @param     SystemContext               Register content at time of the exception
    328  @param     InBuffer                    Pointer to the input buffer received from gdb server
    329  **/
    330 
    331 VOID
    332 WriteGeneralRegisters (
    333   IN    EFI_SYSTEM_CONTEXT  SystemContext,
    334   IN    CHAR8               *InBuffer
    335   );
    336 
    337 
    338 /** m addr,length 
    339  Find the Length of the area to read and the start addres. Finally, pass them to
    340  another function, TransferFromMemToOutBufAndSend, that will read from that memory space and
    341  send it as a packet.
    342 
    343  @param  *PacketData  Pointer to Payload data for the packet
    344  **/
    345 VOID
    346 ReadFromMemory (
    347   IN  CHAR8  *PacketData
    348   );
    349 
    350 
    351 /** M addr,length :XX...
    352  Find the Length of the area in bytes to write and the start addres. Finally, pass them to
    353  another function, TransferFromInBufToMem, that will write to that memory space the info in
    354  the input buffer.
    355 
    356  @param   PacketData     Pointer to Payload data for the packet
    357  **/
    358 VOID
    359 WriteToMemory (
    360   IN CHAR8 *PacketData
    361   );
    362 
    363 
    364 /** c [addr ]
    365  Continue. addr is Address to resume. If addr is omitted, resume at current
    366  Address.
    367 
    368  @param SystemContext Register content at time of the exception
    369  @param *PacketData   Pointer to PacketData
    370  **/
    371 
    372 VOID
    373 ContinueAtAddress (
    374   IN  EFI_SYSTEM_CONTEXT   SystemContext,
    375   IN  CHAR8                *PacketData
    376   );
    377 
    378 
    379 /** s [addr ]
    380  Single step. addr is the Address at which to resume. If addr is omitted, resume
    381  at same Address.
    382 
    383  @param SystemContext   Register content at time of the exception
    384  @param PacketData      Pointer to Payload data for the packet
    385  **/
    386 VOID
    387 SingleStep (
    388   IN  EFI_SYSTEM_CONTEXT  SystemContext,
    389   IN  CHAR8               *PacketData
    390   );
    391 
    392 /**
    393  Insert Single Step in the SystemContext
    394 
    395  @param SystemContext   Register content at time of the exception
    396  **/
    397 VOID
    398 AddSingleStep (
    399   IN  EFI_SYSTEM_CONTEXT  SystemContext
    400   );
    401 
    402 /**
    403  Remove Single Step in the SystemContext
    404 
    405  @param SystemContext   Register content at time of the exception
    406  **/
    407 VOID
    408 RemoveSingleStep (
    409   IN  EFI_SYSTEM_CONTEXT  SystemContext
    410   );
    411 
    412 
    413 /**
    414   Z1, [addr], [length]
    415   Z2, [addr], [length]
    416   Z3, [addr], [length]
    417   Z4, [addr], [length]
    418 
    419   Insert hardware breakpoint/watchpoint at address addr of size length
    420 
    421   @param SystemContext  Register content at time of the exception
    422   @param *PacketData    Pointer to the Payload data for the packet
    423 
    424 **/
    425 VOID
    426 EFIAPI
    427 InsertBreakPoint(
    428   IN  EFI_SYSTEM_CONTEXT  SystemContext,
    429   IN  CHAR8               *PacketData
    430   );
    431 
    432 
    433 /**
    434   z1, [addr], [length]
    435   z2, [addr], [length]
    436   z3, [addr], [length]
    437   z4, [addr], [length]
    438 
    439   Remove hardware breakpoint/watchpoint at address addr of size length
    440 
    441   @param SystemContext  Register content at time of the exception
    442   @param *PacketData    Pointer to the Payload data for the packet
    443 
    444 **/
    445 VOID
    446 EFIAPI
    447 RemoveBreakPoint(
    448   IN  EFI_SYSTEM_CONTEXT  SystemContext,
    449   IN  CHAR8               *PacketData
    450   );
    451 
    452 
    453 /**
    454  Exception Hanldler for GDB. It will be called for all exceptions
    455  registered via the gExceptionType[] array.
    456 
    457  @param ExceptionType   Exception that is being processed
    458  @param SystemContext   Register content at time of the exception
    459 
    460  **/
    461 VOID
    462 EFIAPI
    463 GdbExceptionHandler (
    464   IN     EFI_EXCEPTION_TYPE  ExceptionType,
    465   IN OUT EFI_SYSTEM_CONTEXT  SystemContext
    466   );
    467 
    468 
    469 /**
    470  Periodic callback for GDB. This function is used to catch a ctrl-c or other
    471  break in type command from GDB.
    472 
    473  @param SystemContext           Register content at time of the call
    474 
    475  **/
    476 VOID
    477 EFIAPI
    478 GdbPeriodicCallBack (
    479   IN OUT EFI_SYSTEM_CONTEXT  SystemContext
    480   );
    481 
    482 
    483 /**
    484   Make two serail consoles: 1) StdIn and StdOut via GDB. 2) StdErr via GDB.
    485 
    486   These console show up on the remote system running GDB
    487 
    488 **/
    489 
    490 VOID
    491 GdbInitializeSerialConsole (
    492   VOID
    493   );
    494 
    495 
    496 /**
    497   Send a GDB Remote Serial Protocol Packet
    498 
    499   $PacketData#checksum PacketData is passed in and this function adds the packet prefix '$',
    500   the packet teminating character '#' and the two digit checksum.
    501 
    502   If an ack '+' is not sent resend the packet, but timeout eventually so we don't end up
    503   in an infinit loop. This is so if you unplug the debugger code just keeps running
    504 
    505   @param PacketData   Payload data for the packet
    506 
    507   @retval             Number of bytes of packet data sent.
    508 
    509 **/
    510 UINTN
    511 SendPacket (
    512   IN  CHAR8 *PacketData
    513   );
    514 
    515 
    516 /**
    517  Receive a GDB Remote Serial Protocol Packet
    518 
    519  $PacketData#checksum PacketData is passed in and this function adds the packet prefix '$',
    520  the packet teminating character '#' and the two digit checksum.
    521 
    522  If host re-starts sending a packet without ending the previous packet, only the last valid packet is processed.
    523  (In other words, if received packet is '$12345$12345$123456#checksum', only '$123456#checksum' will be processed.)
    524 
    525  If an ack '+' is not sent resend the packet
    526 
    527  @param PacketData   Payload data for the packet
    528 
    529  @retval             Number of bytes of packet data received.
    530 
    531  **/
    532 UINTN
    533 ReceivePacket (
    534  OUT  CHAR8 *PacketData,
    535  IN   UINTN PacketDataSize
    536  );
    537 
    538 
    539 /**
    540   Read data from a FileDescriptor. On success number of bytes read is returned. Zero indicates
    541   the end of a file. On error -1 is returned. If count is zero, GdbRead returns zero.
    542 
    543   @param  FileDescriptor   Device to talk to.
    544   @param  Buffer           Buffer to hold Count bytes that were read
    545   @param  Count            Number of bytes to transfer.
    546 
    547   @retval -1               Error
    548   @retval {other}          Number of bytes read.
    549 
    550 **/
    551 INTN
    552 GdbRead (
    553   IN  INTN    FileDescriptor,
    554   OUT VOID    *Buffer,
    555   IN  UINTN   Count
    556   );
    557 
    558 
    559 /**
    560   Write data to a FileDescriptor. On success number of bytes written is returned. Zero indicates
    561   nothing was written. On error -1 is returned.
    562 
    563   @param  FileDescriptor   Device to talk to.
    564   @param  Buffer           Buffer to hold Count bytes that are to be written
    565   @param  Count            Number of bytes to transfer.
    566 
    567   @retval -1               Error
    568   @retval {other}          Number of bytes written.
    569 
    570 **/
    571 INTN
    572 GdbWrite (
    573   IN  INTN          FileDescriptor,
    574   OUT CONST VOID    *Buffer,
    575   IN  UINTN         Count
    576   );
    577 
    578 UINTN *
    579 FindPointerToRegister (
    580   IN  EFI_SYSTEM_CONTEXT    SystemContext,
    581   IN  UINTN                 RegNumber
    582   );
    583 
    584 CHAR8 *
    585 BasicReadRegister (
    586   IN  EFI_SYSTEM_CONTEXT      SystemContext,
    587   IN  UINTN                   RegNumber,
    588   IN  CHAR8                   *OutBufPtr
    589   );
    590 
    591 VOID
    592 TransferFromInBufToMem (
    593   IN  UINTN   Length,
    594   IN  UINT8   *Address,
    595   IN  CHAR8   *NewData
    596   );
    597 
    598 VOID
    599 TransferFromMemToOutBufAndSend (
    600   IN  UINTN  Length,
    601   IN  UINT8  *Address
    602   );
    603 
    604 CHAR8 *
    605 BasicWriteRegister (
    606   IN  EFI_SYSTEM_CONTEXT    SystemContext,
    607   IN  UINTN                 RegNumber,
    608   IN  CHAR8                 *InBufPtr
    609   );
    610 
    611 VOID
    612 PrintReg (
    613   EFI_SYSTEM_CONTEXT SystemContext
    614   );
    615 
    616 UINTN
    617 ParseBreakpointPacket (
    618   IN  CHAR8 *PacketData,
    619   OUT UINTN *Type,
    620   OUT UINTN *Address,
    621   OUT UINTN *Length
    622   );
    623 
    624 UINTN
    625 GetBreakpointDataAddress (
    626   IN  EFI_SYSTEM_CONTEXT  SystemContext,
    627   IN  UINTN               BreakpointNumber
    628   );
    629 
    630 UINTN
    631 GetBreakpointDetected (
    632   IN  EFI_SYSTEM_CONTEXT  SystemContext
    633   );
    634 
    635 BREAK_TYPE
    636 GetBreakpointType (
    637   IN  EFI_SYSTEM_CONTEXT  SystemContext,
    638   IN  UINTN               BreakpointNumber
    639   );
    640 
    641 UINTN
    642 ConvertLengthData (
    643   IN  UINTN  Length
    644   );
    645 
    646 EFI_STATUS
    647 FindNextFreeDebugRegister (
    648   IN  EFI_SYSTEM_CONTEXT  SystemContext,
    649   OUT UINTN               *Register
    650   );
    651 
    652 EFI_STATUS
    653 EnableDebugRegister (
    654   IN  EFI_SYSTEM_CONTEXT  SystemContext,
    655   IN  UINTN               Register,
    656   IN  UINTN               Address,
    657   IN  UINTN               Length,
    658   IN  UINTN               Type
    659   );
    660 
    661 EFI_STATUS
    662 FindMatchingDebugRegister (
    663  IN  EFI_SYSTEM_CONTEXT  SystemContext,
    664  IN  UINTN               Address,
    665  IN  UINTN               Length,
    666  IN  UINTN               Type,
    667  OUT UINTN               *Register
    668  );
    669 
    670 EFI_STATUS
    671 DisableDebugRegister (
    672  IN  EFI_SYSTEM_CONTEXT  SystemContext,
    673  IN  UINTN               Register
    674  );
    675 
    676 VOID
    677 InitializeProcessor (
    678   VOID
    679   );
    680 
    681 /**
    682  Send the T signal with the given exception type (in gdb order) and possibly with n:r pairs related to the watchpoints
    683 
    684  @param  SystemContext        Register content at time of the exception
    685  @param  GdbExceptionType     GDB exception type
    686  **/
    687 VOID
    688 ProcessorSendTSignal (
    689   IN  EFI_SYSTEM_CONTEXT  SystemContext,
    690   IN  UINT8               GdbExceptionType,
    691   IN  OUT CHAR8           *TSignalPtr,
    692   IN  UINTN               SizeOfBuffer
    693   );
    694 
    695 /**
    696  Check to see if this exception is related to ctrl-c handling.
    697 
    698  @param ExceptionType     Exception that is being processed
    699  @param SystemContext     Register content at time of the exception
    700 
    701  @return  TRUE  This was a ctrl-c check that did not find a ctrl-c
    702  @return  FALSE This was not a ctrl-c check or some one hit ctrl-c
    703  **/
    704 BOOLEAN
    705 ProcessorControlC (
    706   IN  EFI_EXCEPTION_TYPE        ExceptionType,
    707   IN OUT EFI_SYSTEM_CONTEXT     SystemContext
    708   );
    709 
    710 
    711 /**
    712   Initialize debug agent.
    713 
    714   This function is used to set up debug enviroment. It may enable interrupts.
    715 
    716   @param[in] InitFlag   Init flag is used to decide initialize process.
    717   @param[in] Context    Context needed according to InitFlag, it was optional.
    718 
    719 **/
    720 VOID
    721 EFIAPI
    722 DebugAgentHookExceptions (
    723   IN UINT32                InitFlag,
    724   IN VOID                  *Context  OPTIONAL
    725   );
    726 
    727 
    728 #endif
    729