3 Copyright (c) 1998-2001 Klaus P. Gerlicher
11 setting, listing and removing breakpoints
25 15-Nov-2000: general cleanup of source files
29 This file may be distributed under the terms of the GNU Public License.
33 ////////////////////////////////////////////////////
39 ////////////////////////////////////////////////////
44 ULONG OldInt3Handler=0;
46 SW_BP aSwBreakpoints[64]={{0,0,0,0},};
48 //*************************************************************************
51 //*************************************************************************
52 PSW_BP FindSwBp(ULONG ulAddress)
56 for(i=0;i<DIM(aSwBreakpoints);i++)
58 if(aSwBreakpoints[i].ulAddress == ulAddress && aSwBreakpoints[i].bUsed==TRUE && aSwBreakpoints[i].bVirtual==FALSE)
59 return &aSwBreakpoints[i];
65 //*************************************************************************
66 // FindEmptySwBpSlot()
68 //*************************************************************************
69 PSW_BP FindEmptySwBpSlot(void)
73 for(i=0;i<(sizeof(aSwBreakpoints)/sizeof(SW_BP));i++)
75 if(aSwBreakpoints[i].bUsed == FALSE)
77 return &aSwBreakpoints[i];
84 //*************************************************************************
87 //*************************************************************************
88 PSW_BP FindVirtualSwBp(LPSTR ModName,LPSTR szFunctionName)
93 for(i=0;i<(sizeof(aSwBreakpoints)/sizeof(SW_BP));i++)
95 p = &aSwBreakpoints[i];
97 if(p->bUsed == TRUE &&
98 p->bVirtual == TRUE &&
99 PICE_strcmpi(p->szModName,ModName)==0 &&
100 PICE_strcmpi(p->szFunctionName,szFunctionName)==0)
109 //*************************************************************************
110 // IsSwBpAtAddressInstalled()
112 //*************************************************************************
113 BOOLEAN IsSwBpAtAddressInstalled(ULONG ulAddress)
117 for(i=0;i<DIM(aSwBreakpoints);i++)
119 if(aSwBreakpoints[i].ulAddress == ulAddress &&
120 aSwBreakpoints[i].bUsed == TRUE &&
121 aSwBreakpoints[i].bInstalled &&
122 aSwBreakpoints[i].bVirtual == FALSE)
129 //*************************************************************************
132 //*************************************************************************
133 BOOLEAN IsSwBpAtAddress(ULONG ulAddress)
137 for(i=0;i<DIM(aSwBreakpoints);i++)
139 if(aSwBreakpoints[i].ulAddress == ulAddress && aSwBreakpoints[i].bUsed==TRUE && aSwBreakpoints[i].bVirtual==FALSE)
146 //*************************************************************************
147 // NeedToReInstallSWBreakpoints()
149 //*************************************************************************
150 BOOLEAN NeedToReInstallSWBreakpoints(ULONG ulAddress,BOOLEAN bUseAddress)
153 BOOLEAN bResult = FALSE;
157 DPRINT((0,"NeedToReInstallSWBreakpoint() for %x (bUseAddress = %s)\n",ulAddress,bUseAddress?"TRUE":"FALSE"));
159 for(i=0;i<(sizeof(aSwBreakpoints)/sizeof(SW_BP));i++)
161 p = &aSwBreakpoints[i];
164 if(p->bUsed == TRUE && p->bInstalled == FALSE && p->ulAddress==ulAddress && p->bVirtual==FALSE)
166 if(IsAddressValid(p->ulAddress))
168 DPRINT((0,"NeedToReInstallSWBreakpoint(): [1] found BP\n"));
176 if(p->bUsed == TRUE && p->bInstalled == FALSE && p->bVirtual == FALSE)
178 if(IsAddressValid(p->ulAddress))
180 DPRINT((0,"NeedToReInstallSWBreakpoint(): [2] found BP\n"));
193 //*************************************************************************
194 // ReInstallSWBreakpoint()
196 //*************************************************************************
197 BOOLEAN ReInstallSWBreakpoint(ULONG ulAddress)
200 BOOLEAN bResult = FALSE;
204 DPRINT((0,"ReInstallSWBreakpoint()\n"));
206 for(i=0;i<(sizeof(aSwBreakpoints)/sizeof(SW_BP));i++)
208 p = &aSwBreakpoints[i];
209 if(p->bUsed == TRUE && p->bInstalled == FALSE && p->ulAddress == ulAddress && p->bVirtual == FALSE)
211 if(IsAddressValid(p->ulAddress))
215 if( !( isWriteable = IsAddressWriteable(p->ulAddress) ) )
216 SetAddressWriteable(p->ulAddress,TRUE);
217 *(PUCHAR)(p->ulAddress) = 0xCC;
219 SetAddressWriteable(p->ulAddress,FALSE);
220 p->bInstalled = TRUE;
232 //*************************************************************************
233 // InstallSWBreakpoint()
235 //*************************************************************************
236 BOOLEAN InstallSWBreakpoint(ULONG ulAddress,BOOLEAN bPermanent,void (*SWBreakpointCallback)(void))
239 BOOLEAN bResult = FALSE;
242 DPRINT((0,"InstallSWBreakpoint()\n"));
244 // check if page is present
245 // TODO: must also check if it's a writable page
246 if(IsAddressValid(ulAddress) )
248 DPRINT((0,"InstallSWBreakpoint(): %.8X is valid, writable? %d\n",ulAddress,IsAddressWriteable(ulAddress)));
249 DPRINT((0,"pde: %x, pte: %x\n", *(ADDR_TO_PDE(ulAddress)), *(ADDR_TO_PTE(ulAddress))));
250 if((p = FindSwBp(ulAddress))==NULL)
252 DPRINT((0,"InstallSWBreakpoint(): %.8X is free\n",ulAddress));
253 if( (p=FindEmptySwBpSlot()) )
256 DPRINT((0,"InstallSWBreakpoint(): found empty slot\n"));
257 DPRINT((0,"InstallSWBreakpoint(): %x value: %x", ulAddress, *(PUCHAR)ulAddress));
258 p->ucOriginalOpcode = *(PUCHAR)ulAddress;
259 //allow writing to page
260 if( !( isWriteable = IsAddressWriteable(ulAddress) ) )
261 SetAddressWriteable(ulAddress,TRUE);
262 DPRINT((0,"writing breakpoint\n"));
263 *(PUCHAR)ulAddress = 0xCC;
264 DPRINT((0,"restoring page access\n"));
266 SetAddressWriteable(ulAddress,FALSE);
268 p->bInstalled = TRUE;
270 p->ulAddress = ulAddress;
271 Disasm(&ulAddress,(PUCHAR)&tempBp);
272 p->ulNextInstr = ulAddress;
273 p->bPermanent = bPermanent;
275 p->Callback = SWBreakpointCallback;
283 DPRINT((0,"InstallSWBreakpoint(): %.8X is already used\n",ulAddress));
286 DPRINT((0,"InstallSWBreakpoint(): %.8X is a permanent breakpoint\n",ulAddress));
296 //*************************************************************************
297 // InstallVirtualSWBreakpoint()
299 //*************************************************************************
300 BOOLEAN InstallVirtualSWBreakpoint(LPSTR ModName,LPSTR FunctionName)
303 BOOLEAN bResult = FALSE;
306 DPRINT((0,"InstallVirtualSWBreakpoint(%s!%s)\n",ModName,FunctionName));
308 if( (p=FindEmptySwBpSlot()) )
310 DPRINT((0,"InstallVirtualSWBreakpoint(): found empty slot\n"));
313 p->bInstalled = TRUE;
316 PICE_strcpy(p->szModName,ModName);
317 PICE_strcpy(p->szFunctionName,FunctionName);
327 //*************************************************************************
328 // TryToInstallVirtualSWBreakpoints()
330 //*************************************************************************
331 void TryToInstallVirtualSWBreakpoints(void)
337 DPRINT((0,"TryToInstallVirtualSWBreakpoints()\n"));
339 for(i=0;i<(sizeof(aSwBreakpoints)/sizeof(SW_BP));i++)
341 p = &aSwBreakpoints[i];
342 if(p->bUsed == TRUE && p->bVirtual)
344 if((pMod = IsModuleLoaded(p->szModName)))
346 if((ulAddress = FindFunctionInModuleByName(p->szFunctionName,pMod)))
348 if((p = FindVirtualSwBp(p->szModName,p->szFunctionName)))
350 ULONG ulAddressWithOffset = ulAddress+p->ulAddress;
351 DPRINT((0,"TryToInstallVirtualSWBreakpoints(): ulAddressWithOffset = %x (offset = %x)\n",ulAddressWithOffset,p->ulAddress));
353 if(IsAddressValid(ulAddressWithOffset))
356 DPRINT((0,"TryToInstallVirtualSWBreakpoints(): installing...\n"));
357 p->ucOriginalOpcode = *(PUCHAR)ulAddressWithOffset;
358 //allow writing to page
359 if( !( isWriteable = IsAddressWriteable(ulAddressWithOffset) ) )
360 SetAddressWriteable(ulAddressWithOffset,TRUE);
361 *(PUCHAR)ulAddressWithOffset = 0xCC;
363 SetAddressWriteable(ulAddressWithOffset,FALSE);
365 p->bInstalled = TRUE;
368 p->ulAddress = ulAddressWithOffset;
369 Disasm(&ulAddressWithOffset,(PUCHAR)&tempBp);
370 p->ulNextInstr = ulAddressWithOffset;
371 p->bPermanent = FALSE;
376 DPRINT((0,"TryToInstallVirtualSWBreakpoints(): not valid address\n"));
377 PICE_memset(p,0,sizeof(*p));
387 //*************************************************************************
388 // RemoveSWBreakpoint()
390 // removes breakpoint from breakpoint list
391 //*************************************************************************
392 BOOLEAN RemoveSWBreakpoint(ULONG ulAddress)
395 BOOLEAN bResult = FALSE;
398 DPRINT((0,"RemoveSWBreakpoint()\n"));
400 if( (p = FindSwBp(ulAddress)) )
402 if(IsAddressValid(ulAddress) && p->bInstalled == TRUE && p->bVirtual==FALSE)
405 if( !( isWriteable = IsAddressWriteable(ulAddress) ) )
406 SetAddressWriteable(ulAddress,TRUE);
407 // restore original opcode
408 *(PUCHAR)(p->ulAddress) = p->ucOriginalOpcode;
410 SetAddressWriteable(ulAddress,FALSE);
413 PICE_memset(p,0,sizeof(*p));
424 //*************************************************************************
425 // DeInstallSWBreakpoint()
427 //*************************************************************************
428 BOOLEAN DeInstallSWBreakpoint(ULONG ulAddress)
431 BOOLEAN bResult = FALSE;
434 DPRINT((0,"DeInstallSWBreakpoint()\n"));
436 if( (p = FindSwBp(ulAddress)) )
438 if(IsAddressValid(ulAddress) && p->bInstalled == TRUE && p->bVirtual==FALSE)
441 if( !( isWriteable = IsAddressWriteable(ulAddress) ) )
442 SetAddressWriteable(ulAddress,TRUE);
443 // restore original opcode
444 *(PUCHAR)(p->ulAddress) = p->ucOriginalOpcode;
446 SetAddressWriteable(ulAddress,FALSE);
449 p->bInstalled = FALSE;
459 //*************************************************************************
460 // RemoveAllSWBreakpoints()
462 //*************************************************************************
463 BOOLEAN RemoveAllSWBreakpoints(BOOLEAN bEvenPermanents)
466 BOOLEAN bResult = FALSE;
470 DPRINT((0,"RemoveAllSWBreakpoint()\n"));
472 for(i=0;i<(sizeof(aSwBreakpoints)/sizeof(SW_BP));i++)
474 p = &aSwBreakpoints[i];
479 if(IsAddressValid(p->ulAddress) && p->bVirtual==FALSE)
482 if( !( isWriteable = IsAddressWriteable(p->ulAddress) ) )
483 SetAddressWriteable(p->ulAddress,TRUE);
484 *(PUCHAR)(p->ulAddress) = p->ucOriginalOpcode;
486 SetAddressWriteable(p->ulAddress,FALSE);
489 PICE_memset(p,0,sizeof(*p));
495 if(IsAddressValid(p->ulAddress) && p->bVirtual==FALSE)
498 if( !( isWriteable = IsAddressWriteable(p->ulAddress) ) )
499 SetAddressWriteable(p->ulAddress,TRUE);
500 *(PUCHAR)(p->ulAddress) = p->ucOriginalOpcode;
502 SetAddressWriteable(p->ulAddress,FALSE);
505 PICE_memset(p,0,sizeof(*p));
516 //*************************************************************************
517 // IsPermanentSWBreakpoint()
519 //*************************************************************************
520 PSW_BP IsPermanentSWBreakpoint(ULONG ulAddress)
526 DPRINT((0,"IsPermanentSWBreakpoint(%.8X)\n",ulAddress));
528 for(i=0;i<(sizeof(aSwBreakpoints)/sizeof(aSwBreakpoints[0]));i++)
530 p = &aSwBreakpoints[i];
531 if(p->ulAddress == ulAddress &&
533 p->bPermanent == TRUE)
545 //*************************************************************************
546 // ListSWBreakpoints()
548 //*************************************************************************
549 void ListSWBreakpoints(void)
557 DPRINT((0,"ListSWBreakpoints()\n"));
559 for(i=0;i<(sizeof(aSwBreakpoints)/sizeof(SW_BP));i++)
561 p = &aSwBreakpoints[i];
562 if(p->bUsed == TRUE && p->bVirtual == FALSE)
564 if((pSymbolName = FindFunctionByAddress(p->ulAddress,NULL,NULL)) )
566 pMod = FindModuleFromAddress(p->ulAddress);
567 PICE_sprintf(tempBp,"[%u] %.8X (%S!%s) %s\n",i,p->ulAddress,pMod->name,pSymbolName,p->bPermanent?"PERMANENT":"");
571 if(ScanExportsByAddress(&pSymbolName,p->ulAddress))
572 PICE_sprintf(tempBp,"[%u] %.8X (%s) %s\n",i,p->ulAddress,pSymbolName,p->bPermanent?"PERMANENT":"");
574 PICE_sprintf(tempBp,"[%u] %.8X (no symbol) %s\n",i,p->ulAddress,p->bPermanent?"PERMANENT":"");
576 Print(OUTPUT_WINDOW,tempBp);
578 else if(p->bUsed == TRUE)
580 PICE_sprintf(tempBp,"[%u] xxxxxxxx (%s!%s) VIRTUAL\n",i,p->szModName,p->szFunctionName);
581 Print(OUTPUT_WINDOW,tempBp);
588 //*************************************************************************
589 // RevirtualizeBreakpointsForModule()
591 //*************************************************************************
592 void RevirtualizeBreakpointsForModule(PDEBUG_MODULE pMod)
596 char temp[DEBUG_MODULE_NAME_LEN];
598 DPRINT((0,"RevirtualizeBreakpointsForModule(%x)\n",(ULONG)pMod));
600 if(IsRangeValid((ULONG)pMod,sizeof(DEBUG_MODULE)) )
602 start = (ULONG)pMod->BaseAddress;
603 end = (ULONG)pMod->BaseAddress+pMod->size;
605 DPRINT((0,"RevirtualizeBreakpointsForModule(): module %x (%x-%x)\n",(ULONG)pMod,start,end));
606 // go through all breakpoints
607 for(i=0;i<(sizeof(aSwBreakpoints)/sizeof(SW_BP));i++)
609 p = &aSwBreakpoints[i];
610 // if it's used and installed and not virtual
611 if(p->bUsed && p->bInstalled && p->bVirtual == FALSE)
613 // make sure we're in module's bound
614 if(p->ulAddress>=start && p->ulAddress<end)
617 ULONG ulFunctionAddress;
619 DPRINT((0,"RevirtualizeBreakpointsForModule(): module breakpoint %u\n",i));
620 // find the function in which this breakpoint resides
621 if(ScanExportsByAddress(&pFind,p->ulAddress))
623 // from now on it's virtual again
625 if(IsAddressValid(p->ulAddress) )
628 if( !( isWriteable = IsAddressWriteable(p->ulAddress) ) )
629 SetAddressWriteable(p->ulAddress,TRUE);
630 DPRINT((0,"RevirtualizeBreakpointsForModule(): restoring original opcode @ %x\n",p->ulAddress));
631 *(PUCHAR)(p->ulAddress) = p->ucOriginalOpcode;
633 SetAddressWriteable(p->ulAddress,FALSE);
637 DPRINT((0,"RevirtualizeBreakpointsForModule(): could not restore original opcode @ %x\n",p->ulAddress));
639 // skip past the module separator
640 while(*pFind!='!')pFind++;
642 // remember the function and the module for reinstallation
643 CopyWideToAnsi(temp,pMod->name);
644 PICE_strcpy(p->szModName,temp);
645 PICE_strcpy(p->szFunctionName,pFind);
646 DPRINT((0,"RevirtualizeBreakpointsForModule(): %s!%s\n",p->szModName,p->szFunctionName));
647 // if function name contains a '+' it's an offset
648 pFind = p->szFunctionName;
651 DPRINT((0,"RevirtualizeBreakpointsForModule(): [1] %s\n",pFind));
652 // found any offset to function
661 DPRINT((0,"RevirtualizeBreakpointsForModule(): [2] %s\n",p->szFunctionName));
662 if(ScanExports(p->szFunctionName,&ulFunctionAddress))
664 p->ulAddress -= ulFunctionAddress;
665 DPRINT((0,"RevirtualizeBreakpointsForModule(): [1] function @ %x offset = %x\n",ulFunctionAddress,p->ulAddress));
669 if((ulFunctionAddress = FindFunctionInModuleByName(p->szFunctionName,pMod)) )
671 p->ulAddress -= ulFunctionAddress;
672 DPRINT((0,"RevirtualizeBreakpointsForModule(): [2] function @ %x offset = %x\n",ulFunctionAddress,p->ulAddress));
676 DPRINT((0,"RevirtualizeBreakpointsForModule(): Breakpoint %u could not be virtualized properly!\n",i));
677 PICE_sprintf(tempBp,"Breakpoint %u could not be virtualized properly!\n",i);
678 Print(OUTPUT_WINDOW,tempBp);
684 DPRINT((0,"RevirtualizeBreakpointsForModule(): function for %x not found!\n",p->ulAddress));
685 PICE_memset(p,0,sizeof(*p));
693 //*************************************************************************
696 //*************************************************************************
698 NewInt3Handler:\n\t \
699 pushl $" STR(REASON_INT3) "\n\t \
700 // call debugger loop\n\t \
701 jmp NewInt31Handler\n\t \
705 //*************************************************************************
708 //*************************************************************************
709 void InstallInt3Hook(void)
711 ULONG LocalInt3Handler;
714 DPRINT((0,"enter InstallInt3Hook()...\n"));
719 PICE_memset(aSwBreakpoints,0,sizeof(aSwBreakpoints));
720 __asm__("mov $NewInt3Handler,%0"
721 :"=r" (LocalInt3Handler)
724 OldInt3Handler=SetGlobalInt(0x03,(ULONG)LocalInt3Handler);
728 DPRINT((0,"leave InstallInt3Hook()...\n"));
732 //*************************************************************************
733 // DeInstallInt3Hook()
735 //*************************************************************************
736 void DeInstallInt3Hook(void)
739 DPRINT((0,"enter DeInstallInt3Hook()...\n"));
744 RemoveAllSWBreakpoints(TRUE);
745 SetGlobalInt(0x03,(ULONG)OldInt3Handler);
750 DPRINT((0,"leave DeInstallInt3Hook()...\n"));