test: dbgkproc.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# dbgkproc.c

Go to the documentation of this file.

    00001 /*++
    00002
    00003 Copyright (c) 1989  Microsoft Corporation
    00004
    00005 Module Name:
    00006
    00007     dbgkproc.c
    00008
    00009 Abstract:
    00010
    00011     This module implements process control primitives for the
    00012     Dbg component of NT
    00013
    00014 Author:
    00015
    00016     Mark Lucovsky (markl) 19-Jan-1990
    00017
    00018 Revision History:
    00019
    00020 --*/
    00021
    00022 #include "dbgkp.h"
    00023
    00024 #ifdef ALLOC_PRAGMA
    00025 #pragma alloc_text(PAGE, DbgkpSuspendProcess)
    00026 #pragma alloc_text(PAGE, DbgkpResumeProcess)
    00027 #pragma alloc_text(PAGE, DbgkpSectionHandleToFileHandle)
    00028 #pragma alloc_text(PAGE, DbgkCreateThread)
    00029 #pragma alloc_text(PAGE, DbgkExitThread)
    00030 #pragma alloc_text(PAGE, DbgkExitProcess)
    00031 #pragma alloc_text(PAGE, DbgkMapViewOfSection)
    00032 #pragma alloc_text(PAGE, DbgkUnMapViewOfSection)
    00033 #endif
    00034
    00035 VOID
    00036 DbgkpSuspendProcess(
    00037     IN BOOLEAN CreateDeleteLockHeld
    00038     )
    00039
    00040 /*++
    00041
    00042 Routine Description:
    00043
    00044     This function causes all threads in the calling process except for
    00045     the calling thread to suspend.
    00046
    00047 Arguments:
    00048
    00049     CreateDeleteLockHeld - Supplies a flag that specifies whether or not
    00050         the caller is holding the process create delete lock.  If the
    00051         caller holds the lock, than this function will not aquire the
    00052         lock before suspending the process.
    00053
    00054 Return Value:
    00055
    00056     None.
    00057
    00058 --*/
    00059
    00060 {
    00061     PEPROCESS Process;
    00062
    00063     PAGED_CODE();
    00064
    00065     Process = PsGetCurrentProcess();
    00066
    00067     //
    00068     // Freeze the execution of all threads in the current process, but
    00069     // the calling thread.
    00070     //
    00071     if ( !CreateDeleteLockHeld ) {
    00072         PsLockProcess(Process,KernelMode,PsLockWaitForever);
    00073         }
    00074
    00075     KeFreezeAllThreads();
    00076
    00077     if ( !CreateDeleteLockHeld ) {
    00078         PsUnlockProcess(Process);
    00079         }
    00080
    00081
    00082     return;
    00083 }
    00084
    00085 VOID
    00086 DbgkpResumeProcess(
    00087     IN BOOLEAN CreateDeleteLockHeld
    00088     )
    00089
    00090 /*++
    00091
    00092 Routine Description:
    00093
    00094     This function causes all threads in the calling process except for
    00095     the calling thread to resume.
    00096
    00097 Arguments:
    00098
    00099     CreateDeleteLockHeld - Supplies a flag that specifies whether or not
    00100         the caller is holding the process create delete lock.  If the
    00101         caller holds the lock, than this function will not aquire the
    00102         lock before suspending the process.
    00103
    00104 Return Value:
    00105
    00106     None.
    00107
    00108 --*/
    00109
    00110 {
    00111
    00112     PEPROCESS Process;
    00113
    00114     PAGED_CODE();
    00115
    00116     Process = PsGetCurrentProcess();
    00117     //
    00118     // Thaw the execution of all threads in the current process, but
    00119     // the calling thread.
    00120     //
    00121
    00122     if ( !CreateDeleteLockHeld ) {
    00123         PsLockProcess(Process,KernelMode,PsLockWaitForever);
    00124         }
    00125
    00126     KeThawAllThreads();
    00127
    00128     if ( !CreateDeleteLockHeld ) {
    00129         PsUnlockProcess(Process);
    00130         }
    00131
    00132     return;
    00133 }
    00134
    00135 HANDLE
    00136 DbgkpSectionHandleToFileHandle(
    00137     IN HANDLE SectionHandle
    00138     )
    00139
    00140 /*++
    00141
    00142 Routine Description:
    00143
    00144     This function Opens a handle to the file associated with the processes
    00145     section. The file is opened such that it can be dupped all the way to
    00146     the UI where the UI can either map the file or read the file to get
    00147     the debug info.
    00148
    00149 Arguments:
    00150
    00151     SectionHandle - Supplies a handle to the section whose associated file
    00152         is to be opened.
    00153
    00154 Return Value:
    00155
    00156     NULL - The file could not be opened.
    00157
    00158     NON-NULL - Returns a handle to the file associated with the specified
    00159         section.
    00160
    00161 --*/
    00162
    00163 {
    00164     NTSTATUS Status;
    00165     ANSI_STRING FileName;
    00166     UNICODE_STRING UnicodeFileName;
    00167     OBJECT_ATTRIBUTES Obja;
    00168     IO_STATUS_BLOCK IoStatusBlock;
    00169     HANDLE Handle;
    00170
    00171     PAGED_CODE();
    00172
    00173     Status = MmGetFileNameForSection(SectionHandle, (PSTRING)&FileName);
    00174     if ( !NT_SUCCESS(Status) ) {
    00175         return NULL;
    00176         }
    00177
    00178     Status = RtlAnsiStringToUnicodeString(&UnicodeFileName,&FileName,TRUE);
    00179     ExFreePool(FileName.Buffer);
    00180     if ( !NT_SUCCESS(Status) ) {
    00181         return NULL;
    00182         }
    00183
    00184     InitializeObjectAttributes(
    00185         &Obja,
    00186         &UnicodeFileName,
    00187         OBJ_CASE_INSENSITIVE,
    00188         NULL,
    00189         NULL
    00190         );
    00191
    00192     Status = ZwOpenFile(
    00193                 &Handle,
    00194                 (ACCESS_MASK)(GENERIC_READ | SYNCHRONIZE),
    00195                 &Obja,
    00196                 &IoStatusBlock,
    00197                 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
    00198                 FILE_SYNCHRONOUS_IO_NONALERT
    00199                 );
    00200     RtlFreeUnicodeString(&UnicodeFileName);
    00201     if ( !NT_SUCCESS(Status) ) {
    00202         return NULL;
    00203         }
    00204     else {
    00205         return Handle;
    00206         }
    00207 }
    00208
    00209
    00210 VOID
    00211 DbgkCreateThread(
    00212     PVOID StartAddress
    00213     )
    00214
    00215 /*++
    00216
    00217 Routine Description:
    00218
    00219     This function is called when a new thread begins to execute. If the
    00220     thread has an associated DebugPort, then a message is sent thru the
    00221     port.
    00222
    00223     If this thread is the first thread in the process, then this event
    00224     is translated into a CreateProcessInfo message.
    00225
    00226     If a message is sent, then while the thread is awaiting a reply,
    00227     all other threads in the process are suspended.
    00228
    00229 Arguments:
    00230
    00231     StartAddress - Supplies the start address for the thread that is
    00232         starting.
    00233
    00234 Return Value:
    00235
    00236     None.
    00237
    00238 --*/
    00239
    00240 {
    00241     PVOID Port;
    00242     DBGKM_APIMSG m;
    00243     PDBGKM_CREATE_THREAD CreateThreadArgs;
    00244     PDBGKM_CREATE_PROCESS CreateProcessArgs;
    00245     PETHREAD Thread;
    00246     PEPROCESS Process;
    00247     PDBGKM_LOAD_DLL LoadDllArgs;
    00248     NTSTATUS Status;
    00249     OBJECT_ATTRIBUTES Obja;
    00250     IO_STATUS_BLOCK IoStatusBlock;
    00251     PIMAGE_NT_HEADERS NtHeaders;
    00252
    00253     PAGED_CODE();
    00254
    00255     Process = PsGetCurrentProcess();
    00256
    00257     Port = PsGetCurrentThread()->HideFromDebugger ? NULL : Process->DebugPort;
    00258
    00259     if ( PsImageNotifyEnabled && !Process->Pcb.UserTime) {
    00260         IMAGE_INFO ImageInfo;
    00261         PIMAGE_NT_HEADERS NtHeaders;
    00262         ANSI_STRING FileName;
    00263         UNICODE_STRING UnicodeFileName;
    00264         PUNICODE_STRING pUnicodeFileName;
    00265
    00266         //
    00267         // notification of main .exe
    00268         //
    00269         ImageInfo.Properties = 0;
    00270         ImageInfo.ImageAddressingMode = IMAGE_ADDRESSING_MODE_32BIT;
    00271         ImageInfo.ImageBase = Process->SectionBaseAddress;
    00272         ImageInfo.ImageSize = 0;
    00273
    00274         try {
    00275             NtHeaders = RtlImageNtHeader(Process->SectionBaseAddress);
    00276
    00277             if ( NtHeaders ) {
    00278                 ImageInfo.ImageSize = NtHeaders->OptionalHeader.SizeOfImage;
    00279                 }
    00280             }
    00281         except(EXCEPTION_EXECUTE_HANDLER) {
    00282             ImageInfo.ImageSize = 0;
    00283         }
    00284         ImageInfo.ImageSelector = 0;
    00285         ImageInfo.ImageSectionNumber = 0;
    00286
    00287         pUnicodeFileName = NULL;
    00288         Status = MmGetFileNameForSection(Process->SectionHandle, (PSTRING)&FileName);
    00289         if ( NT_SUCCESS(Status) ) {
    00290             Status = RtlAnsiStringToUnicodeString(&UnicodeFileName,&FileName,TRUE);
    00291             ExFreePool(FileName.Buffer);
    00292             if ( NT_SUCCESS(Status) ) {
    00293                 pUnicodeFileName = &UnicodeFileName;
    00294                 }
    00295             }
    00296         PsCallImageNotifyRoutines(
    00297                     pUnicodeFileName,
    00298                     Process->UniqueProcessId,
    00299                     &ImageInfo
    00300                     );
    00301         if ( pUnicodeFileName ) {
    00302             RtlFreeUnicodeString(pUnicodeFileName);
    00303             }
    00304
    00305         //
    00306         // and of ntdll.dll
    00307         //
    00308         ImageInfo.Properties = 0;
    00309         ImageInfo.ImageAddressingMode = IMAGE_ADDRESSING_MODE_32BIT;
    00310         ImageInfo.ImageBase = PsSystemDllBase;
    00311         ImageInfo.ImageSize = 0;
    00312
    00313         try {
    00314             NtHeaders = RtlImageNtHeader(PsSystemDllBase);
    00315             if ( NtHeaders ) {
    00316                 ImageInfo.ImageSize = NtHeaders->OptionalHeader.SizeOfImage;
    00317                 }
    00318             }
    00319         except(EXCEPTION_EXECUTE_HANDLER) {
    00320             ImageInfo.ImageSize = 0;
    00321             }
    00322
    00323         ImageInfo.ImageSelector = 0;
    00324         ImageInfo.ImageSectionNumber = 0;
    00325
    00326         RtlInitUnicodeString(&UnicodeFileName,L"\\SystemRoot\\System32\\ntdll.dll");
    00327         PsCallImageNotifyRoutines(
    00328                     &UnicodeFileName,
    00329                     Process->UniqueProcessId,
    00330                     &ImageInfo
    00331                     );
    00332         }
    00333
    00334
    00335     if ( !Port ) {
    00336
    00337         return;
    00338     }
    00339
    00340     Thread = PsGetCurrentThread();
    00341
    00342     if ( Thread->DeadThread ) {
    00343         return;
    00344     }
    00345
    00346     //
    00347     // To determine if this should be turned into a create process,
    00348     // all threads in the process are suspended. The process list
    00349     // is then examined to see if the curent thread is the only thread
    00350     // on the list. If so, this becomes a create process message
    00351     //
    00352
    00353     PsLockProcess(Process,KernelMode,PsLockWaitForever);
    00354
    00355     //
    00356     // If we are doing a debug attach, then the create process has
    00357     // already occured. If this is the case, then the process has
    00358     // accumulated some time, so set reported to true
    00359     //
    00360
    00361     if ( Process->Pcb.UserTime ) {
    00362         Process->CreateProcessReported = TRUE;
    00363         }
    00364
    00365     if ( Process->CreateProcessReported == FALSE ) {
    00366
    00367         //
    00368         // This is a create process
    00369         //
    00370
    00371         Process->CreateProcessReported = TRUE;
    00372
    00373         CreateThreadArgs = &m.u.CreateProcessInfo.InitialThread;
    00374         CreateThreadArgs->SubSystemKey = 0;
    00375
    00376         CreateProcessArgs = &m.u.CreateProcessInfo;
    00377         CreateProcessArgs->SubSystemKey = 0;
    00378         CreateProcessArgs->FileHandle = DbgkpSectionHandleToFileHandle(
    00379                                             Process->SectionHandle
    00380                                             );
    00381         CreateProcessArgs->BaseOfImage = Process->SectionBaseAddress;
    00382         CreateThreadArgs->StartAddress = NULL;
    00383         CreateProcessArgs->DebugInfoFileOffset = 0;
    00384         CreateProcessArgs->DebugInfoSize = 0;
    00385
    00386         try {
    00387             NtHeaders = RtlImageNtHeader(Process->SectionBaseAddress);
    00388             if ( NtHeaders ) {
    00389                 CreateThreadArgs->StartAddress = (PVOID)(
    00390                     NtHeaders->OptionalHeader.ImageBase +
    00391                     NtHeaders->OptionalHeader.AddressOfEntryPoint);
    00392
    00393                 CreateProcessArgs->DebugInfoFileOffset = NtHeaders->FileHeader.PointerToSymbolTable;
    00394                 CreateProcessArgs->DebugInfoSize = NtHeaders->FileHeader.NumberOfSymbols;
    00395                 }
    00396             }
    00397         except(EXCEPTION_EXECUTE_HANDLER) {
    00398             CreateThreadArgs->StartAddress = NULL;
    00399             CreateProcessArgs->DebugInfoFileOffset = 0;
    00400             CreateProcessArgs->DebugInfoSize = 0;
    00401         }
    00402
    00403         DBGKM_FORMAT_API_MSG(m,DbgKmCreateProcessApi,sizeof(*CreateProcessArgs));
    00404
    00405         PsUnlockProcess(Process);
    00406
    00407         DbgkpSendApiMessage(&m,Port,FALSE);
    00408         ZwClose(CreateProcessArgs->FileHandle);
    00409
    00410         LoadDllArgs = &m.u.LoadDll;
    00411         LoadDllArgs->BaseOfDll = PsSystemDllBase;
    00412         LoadDllArgs->DebugInfoFileOffset = 0;
    00413         LoadDllArgs->DebugInfoSize = 0;
    00414
    00415         try {
    00416             NtHeaders = RtlImageNtHeader(PsSystemDllBase);
    00417             if ( NtHeaders ) {
    00418                 LoadDllArgs->DebugInfoFileOffset = NtHeaders->FileHeader.PointerToSymbolTable;
    00419                 LoadDllArgs->DebugInfoSize = NtHeaders->FileHeader.NumberOfSymbols;
    00420                 }
    00421             }
    00422         except(EXCEPTION_EXECUTE_HANDLER) {
    00423             LoadDllArgs->DebugInfoFileOffset = 0;
    00424             LoadDllArgs->DebugInfoSize = 0;
    00425         }
    00426
    00427         //
    00428         // Send load dll section for NT dll !
    00429         //
    00430
    00431         InitializeObjectAttributes(
    00432             &Obja,
    00433             &PsNtDllPathName,
    00434             OBJ_CASE_INSENSITIVE,
    00435             NULL,
    00436             NULL
    00437             );
    00438
    00439         Status = ZwOpenFile(
    00440                     &LoadDllArgs->FileHandle,
    00441                     (ACCESS_MASK)(GENERIC_READ | SYNCHRONIZE),
    00442                     &Obja,
    00443                     &IoStatusBlock,
    00444                     FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
    00445                     FILE_SYNCHRONOUS_IO_NONALERT
    00446                     );
    00447
    00448         if ( NT_SUCCESS(Status) ) {
    00449             DBGKM_FORMAT_API_MSG(m,DbgKmLoadDllApi,sizeof(*LoadDllArgs));
    00450             DbgkpSendApiMessage(&m,Port,TRUE);
    00451         }
    00452         ZwClose(LoadDllArgs->FileHandle);
    00453
    00454     } else {
    00455
    00456         CreateThreadArgs = &m.u.CreateThread;
    00457         CreateThreadArgs->SubSystemKey = 0;
    00458         CreateThreadArgs->StartAddress = StartAddress;
    00459
    00460         DBGKM_FORMAT_API_MSG(m,DbgKmCreateThreadApi,sizeof(*CreateThreadArgs));
    00461
    00462         PsUnlockProcess(Process);
    00463
    00464         DbgkpSendApiMessage(&m,Port,TRUE);
    00465     }
    00466
    00467
    00468 }
    00469
    00470 VOID
    00471 DbgkExitThread(
    00472     NTSTATUS ExitStatus
    00473     )
    00474
    00475 /*++
    00476
    00477 Routine Description:
    00478
    00479     This function is called when a new thread terminates. At this
    00480     point, the thread will no longer execute in user-mode. No other
    00481     exit processing has occured.
    00482
    00483     If a message is sent, then while the thread is awaiting a reply,
    00484     all other threads in the process are suspended.
    00485
    00486 Arguments:
    00487
    00488     ExitStatus - Supplies the ExitStatus of the exiting thread.
    00489
    00490 Return Value:
    00491
    00492     None.
    00493
    00494 --*/
    00495
    00496 {
    00497     PVOID Port;
    00498     DBGKM_APIMSG m;
    00499     PDBGKM_EXIT_THREAD args;
    00500     PEPROCESS Process;
    00501
    00502     PAGED_CODE();
    00503
    00504     Process = PsGetCurrentProcess();
    00505     Port = PsGetCurrentThread()->HideFromDebugger ? NULL : Process->DebugPort;
    00506
    00507     if ( !Port ) {
    00508         return;
    00509     }
    00510
    00511     if ( PsGetCurrentThread()->DeadThread ) {
    00512         return;
    00513     }
    00514
    00515     args = &m.u.ExitThread;
    00516     args->ExitStatus = ExitStatus;
    00517
    00518     DBGKM_FORMAT_API_MSG(m,DbgKmExitThreadApi,sizeof(*args));
    00519
    00520     DbgkpSuspendProcess(TRUE);
    00521
    00522     DbgkpSendApiMessage(&m,Port,FALSE);
    00523
    00524     DbgkpResumeProcess(TRUE);
    00525 }
    00526
    00527 VOID
    00528 DbgkExitProcess(
    00529     NTSTATUS ExitStatus
    00530     )
    00531
    00532 /*++
    00533
    00534 Routine Description:
    00535
    00536     This function is called when a process terminates. The address
    00537     space of the process is still intact, but no threads exist in
    00538     the process.
    00539
    00540 Arguments:
    00541
    00542     ExitStatus - Supplies the ExitStatus of the exiting process.
    00543
    00544 Return Value:
    00545
    00546     None.
    00547
    00548 --*/
    00549
    00550 {
    00551     PVOID Port;
    00552     DBGKM_APIMSG m;
    00553     PDBGKM_EXIT_PROCESS args;
    00554     PEPROCESS Process;
    00555
    00556     PAGED_CODE();
    00557
    00558     Process = PsGetCurrentProcess();
    00559     Port = PsGetCurrentThread()->HideFromDebugger ? NULL : Process->DebugPort;
    00560
    00561     if ( !Port ) {
    00562         return;
    00563     }
    00564
    00565     if ( PsGetCurrentThread()->DeadThread ) {
    00566         return;
    00567     }
    00568
    00569     //
    00570     // this ensures that other timed lockers of the process will bail
    00571     // since this call is done while holding the process lock, and lock duration
    00572     // is controlled by debugger
    00573     //
    00574     KeQuerySystemTime(&PsGetCurrentProcess()->ExitTime);
    00575
    00576     args = &m.u.ExitProcess;
    00577     args->ExitStatus = ExitStatus;
    00578
    00579     DBGKM_FORMAT_API_MSG(m,DbgKmExitProcessApi,sizeof(*args));
    00580
    00581     DbgkpSendApiMessage(&m,Port,FALSE);
    00582
    00583 }
    00584
    00585 VOID
    00586 DbgkMapViewOfSection(
    00587     IN HANDLE SectionHandle,
    00588     IN PVOID BaseAddress,
    00589     IN ULONG SectionOffset,
    00590     IN ULONG_PTR ViewSize
    00591     )
    00592
    00593 /*++
    00594
    00595 Routine Description:
    00596
    00597     This function is called when the current process successfully
    00598     maps a view of an image section. If the process has an associated
    00599     debug port, then a load dll message is sent.
    00600
    00601 Arguments:
    00602
    00603     SectionHandle - Supplies a handle to the section mapped by the
    00604         process.
    00605
    00606     BaseAddress - Supplies the base address of where the section is
    00607         mapped in the current process address space.
    00608
    00609     SectionOffset - Supplies the offset in the section where the
    00610         processes mapped view begins.
    00611
    00612     ViewSize - Supplies the size of the mapped view.
    00613
    00614 Return Value:
    00615
    00616     None.
    00617
    00618 --*/
    00619
    00620 {
    00621
    00622     PVOID Port;
    00623     DBGKM_APIMSG m;
    00624     PDBGKM_LOAD_DLL LoadDllArgs;
    00625     PEPROCESS Process;
    00626     PIMAGE_NT_HEADERS NtHeaders;
    00627
    00628     PAGED_CODE();
    00629
    00630     Process = PsGetCurrentProcess();
    00631
    00632     Port = PsGetCurrentThread()->HideFromDebugger ? NULL : Process->DebugPort;
    00633
    00634     if ( !Port || KeGetPreviousMode() == KernelMode ) {
    00635         return;
    00636     }
    00637
    00638     LoadDllArgs = &m.u.LoadDll;
    00639     LoadDllArgs->FileHandle = DbgkpSectionHandleToFileHandle(SectionHandle);
    00640     LoadDllArgs->BaseOfDll = BaseAddress;
    00641     LoadDllArgs->DebugInfoFileOffset = 0;
    00642     LoadDllArgs->DebugInfoSize = 0;
    00643
    00644     try {
    00645         NtHeaders = RtlImageNtHeader(BaseAddress);
    00646         if ( NtHeaders ) {
    00647             LoadDllArgs->DebugInfoFileOffset = NtHeaders->FileHeader.PointerToSymbolTable;
    00648             LoadDllArgs->DebugInfoSize = NtHeaders->FileHeader.NumberOfSymbols;
    00649             }
    00650         }
    00651     except(EXCEPTION_EXECUTE_HANDLER) {
    00652         LoadDllArgs->DebugInfoFileOffset = 0;
    00653         LoadDllArgs->DebugInfoSize = 0;
    00654     }
    00655
    00656     DBGKM_FORMAT_API_MSG(m,DbgKmLoadDllApi,sizeof(*LoadDllArgs));
    00657
    00658     DbgkpSendApiMessage(&m,Port,TRUE);
    00659     ZwClose(LoadDllArgs->FileHandle);
    00660
    00661 }
    00662
    00663 VOID
    00664 DbgkUnMapViewOfSection(
    00665     IN PVOID BaseAddress
    00666     )
    00667
    00668 /*++
    00669
    00670 Routine Description:
    00671
    00672     This function is called when the current process successfully
    00673     un maps a view of an image section. If the process has an associated
    00674     debug port, then an "unmap view of section" message is sent.
    00675
    00676 Arguments:
    00677
    00678     BaseAddress - Supplies the base address of the section being
    00679         unmapped.
    00680
    00681 Return Value:
    00682
    00683     None.
    00684
    00685 --*/
    00686
    00687 {
    00688
    00689     PVOID Port;
    00690     DBGKM_APIMSG m;
    00691     PDBGKM_UNLOAD_DLL UnloadDllArgs;
    00692     PEPROCESS Process;
    00693
    00694     PAGED_CODE();
    00695
    00696     Process = PsGetCurrentProcess();
    00697
    00698     Port = PsGetCurrentThread()->HideFromDebugger ? NULL : Process->DebugPort;
    00699
    00700     if ( !Port || KeGetPreviousMode() == KernelMode ) {
    00701         return;
    00702     }
    00703
    00704     UnloadDllArgs = &m.u.UnloadDll;
    00705     UnloadDllArgs->BaseAddress = BaseAddress;
    00706
    00707     DBGKM_FORMAT_API_MSG(m,DbgKmUnloadDllApi,sizeof(*UnloadDllArgs));
    00708
    00709     DbgkpSendApiMessage(&m,Port,TRUE);
    00710
    00711 }