Beispiel #1
0
// Trap a particular thread
BOOL
TrapThread(DWORD dwProcessId, DWORD dwThreadId)
{
    PPROCESS_INFO pProcessInfo;
    PTHREAD_INFO pThreadInfo;
    HANDLE hProcess;
    HANDLE hThread;

    /* FIXME: synchronize access to globals */

    pProcessInfo = &g_Processes[dwProcessId];
    hProcess = pProcessInfo->hProcess;
    assert(hProcess);

    pThreadInfo = &pProcessInfo->Threads[dwThreadId];
    hThread = pThreadInfo->hThread;
    assert(hThread);

    DWORD dwRet = SuspendThread(hThread);
    if (dwRet != (DWORD)-1) {
        CONTEXT Context;
        if (getThreadContext(hProcess, hThread, &Context)) {
            dumpStack(hProcess, hThread, &Context);
        }
        writeDump(dwProcessId, pProcessInfo, nullptr);

        // TODO: Flag fTerminating

        exit(3);
    }

    TerminateProcess(hProcess, 3);

    return TRUE;
}
Beispiel #2
0
afs_int32
writeDatabase(struct ubik_trans *ut, int fid)
{
    dbadr dbAddr, dbAppAddr;
    struct dump diskDump, apDiskDump;
    dbadr tapeAddr;
    struct tape diskTape;
    dbadr volFragAddr;
    struct volFragment diskVolFragment;
    struct volInfo diskVolInfo;
    int length, hash;
    int old = 0;
    int entrySize;
    afs_int32 code = 0, tcode;
    afs_int32 appDumpAddrs[MAXAPPENDS], numaddrs, appcount, j;

    struct memoryHashTable *mht;

    LogDebug(4, "writeDatabase:\n");

    /* write out a header identifying this database etc */
    tcode = writeDbHeader(fid);
    if (tcode) {
	LogError(tcode, "writeDatabase: Can't write Header\n");
	ERROR(tcode);
    }

    /* write out the tree of dump structures */

    mht = ht_GetType(HT_dumpIden_FUNCTION, &entrySize);
    if (!mht) {
	LogError(tcode, "writeDatabase: Can't get dump type\n");
	ERROR(BUDB_BADARGUMENT);
    }

    for (old = 0; old <= 1; old++) {
	/*oldnew */
	/* only two states, old or not old */
	length = (old ? mht->oldLength : mht->length);
	if (!length)
	    continue;

	for (hash = 0; hash < length; hash++) {
	    /*hashBuckets */
	    /* dump all the dumps in this hash bucket
	     */
	    for (dbAddr = ht_LookupBucket(ut, mht, hash, old); dbAddr; dbAddr = ntohl(diskDump.idHashChain)) {	/*initialDumps */
		/* now check if this dump had any errors/inconsistencies.
		 * If so, don't dump it
		 */
		if (badEntry(dbAddr)) {
		    LogError(0,
			     "writeDatabase: Damaged dump entry at addr 0x%x\n",
			     dbAddr);
		    Log("     Skipping remainder of dumps on hash chain %d\n",
			hash);
		    break;
		}

		tcode =
		    cdbread(ut, dump_BLOCK, dbAddr, &diskDump,
			    sizeof(diskDump));
		if (tcode) {
		    LogError(tcode,
			     "writeDatabase: Can't read dump entry (addr 0x%x)\n",
			     dbAddr);
		    Log("     Skipping remainder of dumps on hash chain %d\n",
			hash);
		    break;
		}

		/* Skip appended dumps, only start with initial dumps */
		if (diskDump.initialDumpID != 0)
		    continue;

		/* Skip appended dumps, only start with initial dumps. Then
		 * follow the appended dump chain so they are in order for restore.
		 */
		appcount = numaddrs = 0;
		for (dbAppAddr = dbAddr; dbAppAddr;
		     dbAppAddr = ntohl(apDiskDump.appendedDumpChain)) {
		    /*appendedDumps */
		    /* Check to see if we have a circular loop of appended dumps */
		    for (j = 0; j < numaddrs; j++) {
			if (appDumpAddrs[j] == dbAppAddr)
			    break;	/* circular loop */
		    }
		    if (j < numaddrs) {	/* circular loop */
			Log("writeDatabase: Circular loop found in appended dumps\n");
			Log("Skipping rest of appended dumps of dumpID %u\n",
			    ntohl(diskDump.id));
			break;
		    }
		    if (numaddrs >= MAXAPPENDS)
			numaddrs = MAXAPPENDS - 1;	/* don't overflow */
		    appDumpAddrs[numaddrs] = dbAppAddr;
		    numaddrs++;

		    /* If we dump a 1000 appended dumps, assume a loop */
		    if (appcount >= 5 * MAXAPPENDS) {
			Log("writeDatabase: Potential circular loop of appended dumps\n");
			Log("Skipping rest of appended dumps of dumpID %u. Dumped %d\n", ntohl(diskDump.id), appcount);
			break;
		    }
		    appcount++;

		    /* Read the dump entry */
		    if (dbAddr == dbAppAddr) {
			/* First time through, don't need to read the dump entry again */
			memcpy(&apDiskDump, &diskDump, sizeof(diskDump));
		    } else {
			if (badEntry(dbAppAddr)) {
			    LogError(0,
				     "writeDatabase: Damaged appended dump entry at addr 0x%x\n",
				     dbAddr);
			    Log("     Skipping this and remainder of appended dumps of initial DumpID %u\n", ntohl(diskDump.id));
			    break;
			}

			tcode =
			    cdbread(ut, dump_BLOCK, dbAppAddr, &apDiskDump,
				    sizeof(apDiskDump));
			if (tcode) {
			    LogError(tcode,
				     "writeDatabase: Can't read appended dump entry (addr 0x%x)\n",
				     dbAppAddr);
			    Log("     Skipping this and remainder of appended dumps of initial DumpID %u\n", ntohl(diskDump.id));
			    break;
			}

			/* Verify that this appended dump points to the initial dump */
			if (ntohl(apDiskDump.initialDumpID) !=
			    ntohl(diskDump.id)) {
			    LogError(0,
				     "writeDatabase: Appended dumpID %u does not reference initial dumpID %u\n",
				     ntohl(apDiskDump.id),
				     ntohl(diskDump.id));
			    Log("     Skipping this appended dump\n");
			    continue;
			}
		    }

		    /* Save the dump entry */
		    tcode = writeDump(fid, &apDiskDump);
		    if (tcode) {
			LogError(tcode,
				 "writeDatabase: Can't write dump entry\n");
			ERROR(tcode);
		    }

		    /* For each tape on this dump
		     */
		    for (tapeAddr = ntohl(apDiskDump.firstTape); tapeAddr; tapeAddr = ntohl(diskTape.nextTape)) {	/*tapes */
			/* read the tape entry */
			tcode =
			    cdbread(ut, tape_BLOCK, tapeAddr, &diskTape,
				    sizeof(diskTape));
			if (tcode) {
			    LogError(tcode,
				     "writeDatabase: Can't read tape entry (addr 0x%x) of dumpID %u\n",
				     tapeAddr, ntohl(apDiskDump.id));
			    Log("     Skipping this and remaining tapes in the dump (and all their volumes)\n");
			    break;
			}

			/* Save the tape entry */
			tcode =
			    writeTape(fid, &diskTape, ntohl(apDiskDump.id));
			if (tcode) {
			    LogError(tcode,
				     "writeDatabase: Can't write tape entry\n");
			    ERROR(tcode);
			}

			/* For each volume on this tape.
			 */
			for (volFragAddr = ntohl(diskTape.firstVol); volFragAddr; volFragAddr = ntohl(diskVolFragment.sameTapeChain)) {	/*volumes */
			    /* Read the volume Fragment entry */
			    tcode =
				cdbread(ut, volFragment_BLOCK, volFragAddr,
					&diskVolFragment,
					sizeof(diskVolFragment));
			    if (tcode) {
				LogError(tcode,
					 "writeDatabase: Can't read volfrag entry (addr 0x%x) of dumpID %u\n",
					 volFragAddr, ntohl(apDiskDump.id));
				Log("     Skipping this and remaining volumes on tape '%s'\n", diskTape.name);
				break;
			    }

			    /* Read the volume Info entry */
			    tcode =
				cdbread(ut, volInfo_BLOCK,
					ntohl(diskVolFragment.vol),
					&diskVolInfo, sizeof(diskVolInfo));
			    if (tcode) {
				LogError(tcode,
					 "writeDatabase: Can't read volinfo entry (addr 0x%x) of dumpID %u\n",
					 ntohl(diskVolFragment.vol),
					 ntohl(apDiskDump.id));
				Log("     Skipping volume on tape '%s'\n",
				    diskTape.name);
				continue;
			    }

			    /* Save the volume entry */
			    tcode =
				writeVolume(ut, fid, &diskVolFragment,
					    &diskVolInfo,
					    ntohl(apDiskDump.id),
					    diskTape.name);
			    if (tcode) {
				LogError(tcode,
					 "writeDatabase: Can't write volume entry\n");
				ERROR(tcode);
			    }
			}	/*volumes */
		    }		/*tapes */
		}		/*appendedDumps */
	    }			/*initialDumps */
	}			/*hashBuckets */
    }				/*oldnew */

    /* write out the textual configuration information */
    tcode = writeText(ut, fid, TB_DUMPSCHEDULE);
    if (tcode) {
	LogError(tcode, "writeDatabase: Can't write dump schedule\n");
	ERROR(tcode);
    }
    tcode = writeText(ut, fid, TB_VOLUMESET);
    if (tcode) {
	LogError(tcode, "writeDatabase: Can't write volume set\n");
	ERROR(tcode);
    }
    tcode = writeText(ut, fid, TB_TAPEHOSTS);
    if (tcode) {
	LogError(tcode, "writeDatabase: Can't write tape hosts\n");
	ERROR(tcode);
    }

    tcode = writeStructHeader(fid, SD_END);
    if (tcode) {
	LogError(tcode, "writeDatabase: Can't write end savedb\n");
	ERROR(tcode);
    }

  error_exit:
    doneWriting(code);
    return (code);
}
Beispiel #3
0
void runTest(unsigned int startFreq, unsigned int targetFreq, unsigned int coreID)
{
   double startBenchTime=0;
   double targetBenchTime=0;
   unsigned long lowBoundTime=0;
   unsigned long highBoundTime=0;
   unsigned long time =0;
   
   unsigned long startLoopTime = 0;
   unsigned long lateStartLoopTime = 0;
   unsigned long endLoopTime = 0;

   /* Build the confidence interval of the sample mean */    
   double startBenchSD=0;
   double targetBenchSD=0;
   unsigned long startLowBoundTime=0;
   unsigned long startHighBoundTime=0;
   unsigned long targetLowBoundTime=0;
   unsigned long targetHighBoundTime=0;
   unsigned long targetQ1=0;
   unsigned long targetQ3=0;

   setFreq(coreID,targetFreq);
   waitCurFreq(coreID,targetFreq);
   targetBenchTime = measureLoop(NB_BENCH_META_REPET);
   fprintf(stdout,"Bench %d %.2f\n",targetFreq, targetBenchTime); 
   targetBenchSD = sd(NB_BENCH_META_REPET, targetBenchTime, times);

   // Build the inter-quartile range for the target frequency
   interQuartileRange(NB_BENCH_META_REPET, times, 
		&targetQ1, &targetQ3);
   
   setFreq(coreID,startFreq);
   waitCurFreq(coreID,startFreq);
   startBenchTime = measureLoop(NB_BENCH_META_REPET);  
   fprintf(stdout,"Bench %d %.2f\n",startFreq, startBenchTime);
   startBenchSD = sd(NB_BENCH_META_REPET, startBenchTime, times);
   

   // Build the confidence interval for the target frequency
   confidenceInterval(NB_BENCH_META_REPET, targetBenchTime, targetBenchSD,
		&targetLowBoundTime, &targetHighBoundTime);

   fprintf(stdout,"targetLowbound : %lu ; targetHighbound : %lu\n",
			targetLowBoundTime,targetHighBoundTime);
   fprintf(stdout,"targetQ1 : %lu ; targetQ3 : %lu\n",
			targetQ1, targetQ3);


   // Build the confidence interval for the start frequency
   confidenceInterval(NB_BENCH_META_REPET, startBenchTime, startBenchSD,
		&startLowBoundTime, &startHighBoundTime);
   fprintf(stdout,"startLowbound : %lu ; startHighbound : %lu\n",
			startLowBoundTime,startHighBoundTime);

   // Check if the confidence intervals overlap
   if ( startLowBoundTime >= targetHighBoundTime || targetLowBoundTime >= startHighBoundTime )
   {
   		fprintf(stdout,"Confidence intervals do not overlap, alternatives are statistically different with selected confidence level\n");
   }
   else if( startLowBoundTime < targetHighBoundTime || targetLowBoundTime > startHighBoundTime )
   {
		if( ( startBenchTime >= targetLowBoundTime && startBenchTime <= targetHighBoundTime ) ||
		    ( targetBenchTime >= startLowBoundTime && targetBenchTime <= startHighBoundTime ) )
		{
   			fprintf(stdout,"Warning: confidence intervals overlap considerably, alternatives are equal with selected confidence level\n");
			return;
		}else
		{
   			fprintf(stdout,"Warning: confidence intervals overlap, we can not state any thing, need to do the t-test\n");
		}
   }

   //lowBoundTime  = targetLowBoundTime ;
   //highBoundTime = targetHighBoundTime;

   // Now we use the inter-quartile range
   lowBoundTime  = targetQ1;
   highBoundTime = targetQ3;

   sync();
   loop();
   warmup_cpuid();

   {
      unsigned int i = 0;
      unsigned int j = 0;
      unsigned int it = 0;
      unsigned int niters = 0;
      char validated = 0;
      double validateBenchTime=0;
      double validateBenchSD=0;
      unsigned long validateLowBoundTime=0;
      unsigned long validateHighBoundTime=0;

      for (it=0;it<NB_REPORT_TIMES;it++){
      do
      {
         startLoopTime = 0;
         lateStartLoopTime = 0;
         endLoopTime = 0;
         niters = 0;
         
#ifdef _DUMP
         resetDump();
#endif

         sync_rdtsc1(startLoopTime);
         setFreq(coreID,targetFreq);
         sync_rdtsc1(lateStartLoopTime);
         do
         {
            time = loop();
#ifdef _DUMP
            writeDump(time);
#endif
         } while ( ( time < lowBoundTime || time > highBoundTime ) && ++niters < NB_TRY_REPET_LOOP );

         sync_rdtsc2(endLoopTime);

         // Validation
         validated = 1;
         times[0] = time;
         measurements[it]= endLoopTime - startLoopTime;
         measurements_late[it]= endLoopTime - lateStartLoopTime;
         measurements_timestamps[it]= endLoopTime ;

         for ( i = 1 ; i < NB_VALIDATION_REPET ; i++ )
         {
            times[i] = loop();
#ifdef _DUMP
            writeDump(times[i]);
#endif            
         }

         // Build a confidence interval for the new time value
         validateBenchTime = average(NB_VALIDATION_REPET, times); 
         validateBenchSD   = sd(NB_VALIDATION_REPET, validateBenchTime, times);
         confidenceInterval(NB_VALIDATION_REPET, validateBenchTime, validateBenchSD,
                            &validateLowBoundTime, &validateHighBoundTime);

         if ( validateHighBoundTime < targetLowBoundTime  || validateLowBoundTime > targetHighBoundTime )
         {
            validated = 0;
            if (j%20==19)
            {
               setFreq(coreID,targetFreq);
               waitCurFreq(coreID,targetFreq);
               targetBenchTime = measureLoop(NB_BENCH_META_REPET);
               targetBenchSD = sd(NB_BENCH_META_REPET, targetBenchTime, times);

               // Build the inter-quartile range for the target frequency
               interQuartileRange(NB_BENCH_META_REPET, times,
                                       &targetQ1, &targetQ3);
               confidenceInterval(NB_BENCH_META_REPET, targetBenchTime, targetBenchSD,
                                 &targetLowBoundTime, &targetHighBoundTime);
               lowBoundTime  = targetQ1;  
               highBoundTime = targetQ3;  
            }
         }

         setFreq(coreID,startFreq);
         waitCurFreq(coreID,startFreq);
         wait(NB_WAIT_US);

      }while(!validated && ++j < NB_TRY_REPET);

      if ( j >= NB_TRY_REPET || validated == 0 ){
         it--;
      }
#if NB_REPORT_TIMES == 1
      fprintf(stdout,"Number of iterations to solution : %d ;  Number of attempts : %d\n", niters, j+1);
      if ( j >= NB_TRY_REPET || validated == 0 )
         fprintf(stdout,"Warning: The computed change time may not be accurate\n"); 

      fprintf(stdout,"LastTime : %lu ; validateLowbound : %lu ; validateHighbound : %lu\n",
              time, validateLowBoundTime,validateHighBoundTime);
#endif
   }}
   
#if NB_REPORT_TIMES == 1
   fprintf(stdout,"Change time (with write) : %lu\n" ,endLoopTime-startLoopTime);
   fprintf(stdout,"Change time : %lu\n" ,endLoopTime-lateStartLoopTime);
   fprintf(stdout,"Write cost : : %lu\n" ,lateStartLoopTime-startLoopTime);
#else
   int i=0; 
   for (i=0;i<NB_REPORT_TIMES;i++){
     fprintf(stdout,"%lu\t%llu\t%lu\n",measurements[i],measurements_timestamps[i]-measurements_timestamps[0],measurements_late[i]);
   }
#endif
}
Beispiel #4
0
 void icqv8_processChannel2(HICQ icq, ICQV8 *cfg, int sz, SNAC *snac)
 {
    static const struct snacproc snacs[] = {    { 0x01, icqv8_snac01_table },
                                                { 0x02, icqv8_snac02_table },
                                                { 0x03, icqv8_snac03_table },
                                                { 0x04, icqv8_snac04_table },
                                                { 0x09, icqv8_snac09_table },
                                                { 0x0B, icqv8_snac0B_table },
                                                { 0x13, icqv8_snac13_table },
                                                { 0x15, icqv8_snac15_table },
                                                { 0x00, NULL               }
                                           };

    const SNAC_CMD              *ptr;
    const struct snacproc       *sproc;
    int                         rc;

    snac->family  = SHORT_VALUE(snac->family);
    snac->subType = SHORT_VALUE(snac->subType);

//    DBGTracex(snac->family);
//    DBGTracex(snac->subType);

    for(sproc = snacs;sproc->tbl && sproc->id != snac->family;sproc++);

    ptr = sproc->tbl;

//    DBGMessage("***********************************************************************");
//    DBGTracex(ptr);
//    DBGTracex(&icqv8_snac13_table);

//    CHKPoint();

    while(ptr && ptr->subType)
    {
//       DBGTracex(ptr->subType);

       if(ptr->subType == snac->subType)
       {
//          CHKPoint();

          rc = ptr->exec(icq, cfg, sz-sizeof(SNAC), snac->request, (void *) (snac+1));

          if(rc)
             logError(icq,rc,snac->family,snac->subType,sz,snac);

          return;
       }
       ptr++;
    }

//    DBGTracex(ptr->subType);


//    if(icqPacket(icq, 7, pkt, sz, 0, 0))
//      return;

    writeDump(icq,sz,snac);

//    DBGMessage("***********************************************************************");

 }
Beispiel #5
0
BOOL
DebugMainLoop(void)
{
    BOOL fFinished = FALSE;
    BOOL fTerminating = FALSE;

    while (!fFinished) {
        DEBUG_EVENT DebugEvent;            // debugging event information
        DWORD dwContinueStatus = DBG_CONTINUE;    // exception continuation
        PPROCESS_INFO pProcessInfo;
        PTHREAD_INFO pThreadInfo;

        // Wait for a debugging event to occur. The second parameter indicates
        // that the function does not return until a debugging event occurs.
        if(!WaitForDebugEvent(&DebugEvent, INFINITE))
        {
            OutputDebug("WaitForDebugEvent: 0x%08lx", GetLastError());

            return FALSE;
        }

        // Process the debugging event code.
        switch (DebugEvent.dwDebugEventCode) {
        case EXCEPTION_DEBUG_EVENT: {
            PEXCEPTION_RECORD pExceptionRecord = &DebugEvent.u.Exception.ExceptionRecord;
            NTSTATUS ExceptionCode = pExceptionRecord->ExceptionCode;

            // Process the exception code. When handling
            // exceptions, remember to set the continuation
            // status parameter (dwContinueStatus). This value
            // is used by the ContinueDebugEvent function.
            if (debugOptions.verbose_flag) {
                lprintf("EXCEPTION PID=%lu TID=%lu ExceptionCode=0x%lx dwFirstChance=%lu\n",
                        DebugEvent.dwProcessId,
                        DebugEvent.dwThreadId,
                        pExceptionRecord->ExceptionCode,
                        DebugEvent.u.Exception.dwFirstChance
                );
            }

            // Find the process in the process list
            pProcessInfo = &g_Processes[DebugEvent.dwProcessId];

            dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;

            if (DebugEvent.u.Exception.dwFirstChance) {
                if (pExceptionRecord->ExceptionCode == (DWORD)STATUS_BREAKPOINT) {
                    // Signal the aedebug event
                    if (!pProcessInfo->fBreakpointSignalled) {
                        pProcessInfo->fBreakpointSignalled = TRUE;

                        if (debugOptions.hEvent) {
                            SetEvent(debugOptions.hEvent);
                            CloseHandle(debugOptions.hEvent);
                        }

                        if (debugOptions.dwThreadId) {
                            DWORD dwThreadId = debugOptions.dwThreadId;
                            const DWORD dwFailed = (DWORD)-1;
                            DWORD dwRet = dwFailed;
                            pThreadInfo = &pProcessInfo->Threads[dwThreadId];
                            HANDLE hThread = pThreadInfo->hThread;
                            if (hThread != NULL) {
                                dwRet = ResumeThread(hThread);
                            }
                            if (dwRet == dwFailed) {
                                lprintf("error: failed to resume thread %lu\n", dwThreadId);
                            }
                        }

                        /*
                         * We ignore first-chance breakpoints by default.
                         *
                         * We get one of these whenever we attach to a process.
                         * But in some cases, we never get a second-chance, e.g.,
                         * when we're attached through MSVCRT's abort().
                         */
                        if (!debugOptions.breakpoint_flag) {
                            dwContinueStatus = DBG_CONTINUE;
                            break;
                        }
                    }
                }

                if (ExceptionCode == STATUS_WX86_BREAKPOINT) {
                    if (!pProcessInfo->fWowBreakpointSignalled) {
                        pProcessInfo->fWowBreakpointSignalled = TRUE;
                        dwContinueStatus = DBG_CONTINUE;
                        break;
                    }
                }

               /*
                 * Ignore thread naming exception.
                 *
                 * http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
                 *
                 * TODO: Note down the thread name
                 */
                if (ExceptionCode == 0x406d1388) {
                    dwContinueStatus = DBG_CONTINUE;
                    break;
                }

                if (ExceptionCode == DBG_CONTROL_C ||
                    ExceptionCode == DBG_CONTROL_BREAK) {
                    dwContinueStatus = DBG_CONTINUE;
                } else if (!debugOptions.first_chance) {
                    // Ignore other first change exceptions
                    break;
                }
            }

            dumpException(pProcessInfo->hProcess,
                          &DebugEvent.u.Exception.ExceptionRecord);

            // Find the thread in the thread list
            THREAD_INFO_LIST::const_iterator it;
            for (it = pProcessInfo->Threads.begin(); it != pProcessInfo->Threads.end(); ++it) {
                DWORD dwThreadId = it->first;
                HANDLE hThread = it->second.hThread;
                if (dwThreadId != DebugEvent.dwThreadId &&
                    ExceptionCode != STATUS_BREAKPOINT &&
                    ExceptionCode != STATUS_WX86_BREAKPOINT &&
                    ExceptionCode != DBG_CONTROL_C &&
                    ExceptionCode != DBG_CONTROL_BREAK) {
                    continue;
                }

                CONTEXT Context;
                if (!getThreadContext(pProcessInfo->hProcess, hThread, &Context)) {
                    continue;
                }

                dumpStack(pProcessInfo->hProcess, hThread, &Context);

                if (!DebugEvent.u.Exception.dwFirstChance) {
                    EXCEPTION_POINTERS ExceptionPointers;
                    ExceptionPointers.ExceptionRecord = pExceptionRecord;
                    ExceptionPointers.ContextRecord = &Context;

                    MINIDUMP_EXCEPTION_INFORMATION ExceptionParam;
                    ExceptionParam.ThreadId = DebugEvent.dwThreadId;
                    ExceptionParam.ExceptionPointers = &ExceptionPointers;
                    ExceptionParam.ClientPointers = FALSE;

                    writeDump(DebugEvent.dwProcessId, pProcessInfo, &ExceptionParam);
                }
            }

            if (!DebugEvent.u.Exception.dwFirstChance) {
                /*
                 * Terminate the process. As continuing would cause the JIT debugger
                 * to be invoked again.
                 */
                fTerminating = TRUE;
                TerminateProcess(pProcessInfo->hProcess, (UINT)ExceptionCode);
            }

            break;
        }

        case CREATE_THREAD_DEBUG_EVENT:
            if (debugOptions.verbose_flag) {
                lprintf("CREATE_THREAD PID=%lu TID=%lu\n",
                        DebugEvent.dwProcessId,
                        DebugEvent.dwThreadId
                );
            }

            // Add the thread to the thread list
            pProcessInfo = &g_Processes[DebugEvent.dwProcessId];
            pThreadInfo = &pProcessInfo->Threads[DebugEvent.dwThreadId];
            pThreadInfo->hThread = DebugEvent.u.CreateThread.hThread;
            break;

        case CREATE_PROCESS_DEBUG_EVENT: {
            HANDLE hFile = DebugEvent.u.CreateProcessInfo.hFile;

            char szImageName[MAX_PATH];
            char *lpImageName = NULL;
            if (hFile && GetFileNameFromHandle(hFile, szImageName, _countof(szImageName))) {
                lpImageName = szImageName;
            }

            if (debugOptions.verbose_flag) {
                PCSTR lpModuleName = lpImageName ? getBaseName(lpImageName) : "";

                lprintf("CREATE_PROCESS PID=%lu TID=%lu lpBaseOfImage=%p %s\n",
                        DebugEvent.dwProcessId,
                        DebugEvent.dwThreadId,
                        DebugEvent.u.CreateProcessInfo.lpBaseOfImage,
                        lpModuleName
                );
            }

            HANDLE hProcess = DebugEvent.u.CreateProcessInfo.hProcess;

            pProcessInfo = &g_Processes[DebugEvent.dwProcessId];
            pProcessInfo->hProcess = hProcess;
            pProcessInfo->fDumpWritten = !debugOptions.minidump;

            pThreadInfo = &pProcessInfo->Threads[DebugEvent.dwThreadId];
            pThreadInfo->hThread = DebugEvent.u.CreateProcessInfo.hThread;

            if (!InitializeSym(hProcess, FALSE)) {
                OutputDebug("error: SymInitialize failed: 0x%08lx\n", GetLastError());
                exit(EXIT_FAILURE);
            }

            SymRegisterCallback64(hProcess, &symCallback, 0);

            loadModule(hProcess, hFile, lpImageName, DebugEvent.u.CreateProcessInfo.lpBaseOfImage);

            break;
        }

        case EXIT_THREAD_DEBUG_EVENT:
            if (debugOptions.verbose_flag) {
                lprintf("EXIT_THREAD PID=%lu TID=%lu dwExitCode=0x%lx\n",
                        DebugEvent.dwProcessId,
                        DebugEvent.dwThreadId,
                        DebugEvent.u.ExitThread.dwExitCode
                );
            }

            // Remove the thread from the thread list
            pProcessInfo = &g_Processes[DebugEvent.dwProcessId];

            // Dump the stack on abort()
            if (!fTerminating && isAbnormalExitCode(DebugEvent.u.ExitThread.dwExitCode)) {
                pThreadInfo = &pProcessInfo->Threads[DebugEvent.dwThreadId];
                HANDLE hProcess = pProcessInfo->hProcess;
                HANDLE hThread = pThreadInfo->hThread;
                CONTEXT Context;
                if (getThreadContext(hProcess, hThread, &Context)) {
                    dumpStack(hProcess, hThread, &Context);
                }
            }

            pProcessInfo->Threads.erase(DebugEvent.dwThreadId);
            break;

        case EXIT_PROCESS_DEBUG_EVENT: {
            if (debugOptions.verbose_flag) {
                lprintf("EXIT_PROCESS PID=%lu TID=%lu dwExitCode=0x%lx\n",
                        DebugEvent.dwProcessId,
                        DebugEvent.dwThreadId,
                        DebugEvent.u.ExitProcess.dwExitCode
                );
            }

            pProcessInfo = &g_Processes[DebugEvent.dwProcessId];

            // Dump the stack on abort()
            if (!fTerminating && isAbnormalExitCode(DebugEvent.u.ExitThread.dwExitCode)) {
                pThreadInfo = &pProcessInfo->Threads[DebugEvent.dwThreadId];
                HANDLE hProcess = pProcessInfo->hProcess;
                HANDLE hThread = pThreadInfo->hThread;
                CONTEXT Context;
                if (getThreadContext(hProcess, hThread, &Context)) {
                    dumpStack(hProcess, hThread, &Context);
                }

                writeDump(DebugEvent.dwProcessId, pProcessInfo, nullptr);
            }

            // Remove the process from the process list
            g_Processes.erase(DebugEvent.dwProcessId);

            if (!SymCleanup(pProcessInfo->hProcess)) {
                OutputDebug("SymCleanup failed with 0x%08lx\n", GetLastError());
            }

            if (g_Processes.empty()) {
                fFinished = TRUE;
            }

            break;
        }

        case LOAD_DLL_DEBUG_EVENT: {
            HANDLE hFile = DebugEvent.u.LoadDll.hFile;

            char szImageName[MAX_PATH];
            char *lpImageName = NULL;
            if (hFile && GetFileNameFromHandle(hFile, szImageName, _countof(szImageName))) {
                lpImageName = szImageName;
            }

            if (debugOptions.verbose_flag) {
                PCSTR lpModuleName = lpImageName ? getBaseName(lpImageName) : "";

                lprintf("LOAD_DLL PID=%lu TID=%lu lpBaseOfDll=%p %s\n",
                        DebugEvent.dwProcessId,
                        DebugEvent.dwThreadId,
                        DebugEvent.u.LoadDll.lpBaseOfDll,
                        lpModuleName
                );
            }

            pProcessInfo = &g_Processes[DebugEvent.dwProcessId];

            loadModule(pProcessInfo->hProcess, hFile, lpImageName, DebugEvent.u.LoadDll.lpBaseOfDll);

            break;
        }

        case UNLOAD_DLL_DEBUG_EVENT:
            if (debugOptions.verbose_flag) {
                lprintf("UNLOAD_DLL PID=%lu TID=%lu lpBaseOfDll=%p\n",
                        DebugEvent.dwProcessId,
                        DebugEvent.dwThreadId,
                        DebugEvent.u.UnloadDll.lpBaseOfDll
                );
            }

            pProcessInfo = &g_Processes[DebugEvent.dwProcessId];

            SymUnloadModule64(pProcessInfo->hProcess, (UINT_PTR)DebugEvent.u.UnloadDll.lpBaseOfDll);

            break;

        case OUTPUT_DEBUG_STRING_EVENT: {
            if (debugOptions.verbose_flag) {
                lprintf("OUTPUT_DEBUG_STRING PID=%lu TID=%lu\n",
                        DebugEvent.dwProcessId,
                        DebugEvent.dwThreadId
                );
            }

            pProcessInfo = &g_Processes[DebugEvent.dwProcessId];

            assert(!DebugEvent.u.DebugString.fUnicode);

            LPSTR lpDebugStringData = readProcessString(pProcessInfo->hProcess,
                                                        DebugEvent.u.DebugString.lpDebugStringData,
                                                        DebugEvent.u.DebugString.nDebugStringLength);

            lprintf("%s", lpDebugStringData);

            free(lpDebugStringData);
            break;
        }

        case RIP_EVENT:
            if (debugOptions.verbose_flag) {
                lprintf("RIP PID=%lu TID=%lu\n",
                        DebugEvent.dwProcessId,
                        DebugEvent.dwThreadId
                );
            }
            break;

        default:
            if (debugOptions.verbose_flag) {
                lprintf("EVENT%lu PID=%lu TID=%lu\n",
                    DebugEvent.dwDebugEventCode,
                    DebugEvent.dwProcessId,
                    DebugEvent.dwThreadId
                );
            }
            break;
        }

        // Resume executing the thread that reported the debugging event.
        ContinueDebugEvent(
            DebugEvent.dwProcessId,
            DebugEvent.dwThreadId,
            dwContinueStatus
        );
    }

    return TRUE;
}