töréspontok és lépés révén

programok hibakeresése

A legtöbb programozónak nem veszik észre, hogy debuggers általánosan használt töréspont „színfalak mögött”, hogy a hibakereső, hogy ellenőrizzék a fő beosztottak. Bár lehetséges, hogy hozzanak egy töréspont nem közvetlenül hibakereső telepíti őket, így kezelni azokat a feladatokat, lépésre (átlépve) a hívott függvény. Debugger is használja töréspont, ahol szükség van, hogy végre egy programot az említett forrás file vonal és megáll. Végül a hibakereső beállítja a töréspontot, hogy lépjen a gyengébb hibakereső parancs (például úgy, hogy a kiválasztás a menüpont Debug Break WDBG).

Listing 4-4 ​​ábra SetBreakpoint funkció kódot. Kód olvasása, tartsd észben, hogy DBG_ funkció * LOCALASSIST.DLL tartozik a könyvtár és segít elkülöníteni a különböző rutinok manipulálni a folyamatot, így könnyebben hozzá WDBG távoli hibakeresés funkciót. SetBreakpoint szemlélteti feldolgozási funkciót (lásd korábban ebben a fejezetben) módosításához szükséges memória védelem felvétel közben is.

Listing 4-4. Funkció SetBreakepoint a 1386CPUHELP.C

int CPUHELP_DLLINTERFACE _stdcall

SetBreakpoint (PDEBUGPACKET dp.

DWORD dwReadWrite = 0;

BYTE bTempOp = BREAK_OPCODE;

ASSERT (FALSE == IsBadReadPtr (dp, sizeof (DEBUGPACKET)));

ASSERT (FALSE == IsBadWritePtr (pOpCode, sizeof (OPCODE)));

if ((TRUE == IsBadReadPtr (dp, sizeof (DEBUGPACKET))) ||

(TRUE == IsBadWritePtr (pOpCode, sizeof (OPCODE))))

TRACE0 ( "SetBreakpoint érvénytelen paraméter \ n.!");

// nagyobb, mint 2 GB, tegye a visszatérítést,

if ((HAMIS = ISNT ()) (UlAddr> = 0x80000000))

bReadMem = DBG_ReadProcessMemory (DP-> hProcess.

(LPCVOID) ulAddr, SbTempOp. sizeof (bájt), SdwReadWrite);

ASSERT (HAMIS = bReadMem!);

ASSERT (sizeof (BYTE) = dwReadWrite);

if ((HAMIS = bReadMem) ||

(Sizeof (BYTE)! = DwReadWrite))

// ha ez készül egy új töréspontot átírni

// opkód meglévő töréspontot?

ha (BREAKJDPCODE = bTempOp)

// Az oldalas tulajdonságai alatta debugger.

// Fordítás rosszabb hibakereső mód

if (HAMIS == DBG_VirtualProtectEx (DP> hProcess.

Assert ( "VirtualProtectEx .failed !!".);

// Mentse el a kódot cserélhető működését.

// A műveleti kód lett mentve, így most

// kell állítania egy töréspont.

bWriteMem = DBG_WriteProcessMemory (DP-> hProcess.

ASSERT (HAMIS = bWriteMem!);

ASSERT (sizeof (BYTE) == dwReadWrite);

if ((HAMIS == bWriteMem) ||

(Sizeof (BYTE)! = DwReadWrite))

// Vissza az állam védelme, amely megelőzte

// beállítása töréspont

// módosítása védelme vissza mi volt azelőtt

// I átkozott thebreakpoint az.

Igazolni (DBG_VirtualProtectEx (DP> hProcess.

// visszaállítása az utasítás cache, ha a memória volt a CPU cache

bFlush = DBG_FlushInstructionCache (DP-> hProcess.

ASSERT (IGAZ = bFlush);

Kérdés: hogyan lehet visszaállítani a töréspont, hogy képes legyen újra megáll ezen a helyen? Ha a CPU támogat egyetlen lépésben végrehajtás, visszaállítási pont triviális megszakításokkal. A lépésről lépésre üzemmódban a CPU végrehajtja egyetlen utasítást, és létrehoz egy másik fajta kivételével - EXCEPTION_SINGLE_STEP (0x80000004). Szerencsére az összes CPU, hogy fut a Windows 32-bit, támogat egyetlen lépésben végrehajtását. Belépni egy-léptető üzemmódban Intel Pentium processzorok telepítéséhez szükséges (egyetlen állam) 8. bit zászlók regisztráljon. Útmutató Intel nevezi bit trap - csapda Rag (TF vagy trace flag). Listing 4-5 mutatja Setsingiestep funkció és a szükséges lépéseket, hogy telepítse kicsit TF. Cseréje után a töréspont forráskód debugger működését megállapítja a belső állapotban, hogy elvárja, egyetlen léptető, a CPU beállítja a megfelelő módot, majd folytassa a folyamatot.

Listing 4-5. SetSingleStep funkciója 1386CPUHELP. C

BOOL CPUHELP_DLLIMNTERFACE _stdcall

SetSingleStep (PDEBUGPACKET dp)

ASSERT (FALSE == IsBadReadPtr (dp, sizeof (DEBUGPACKET)));

ha (IGAZ = IsBadReadPtr (dp, sizeof (DEBUGPACKET)))

FŰTŐTT ( "SetSingleStep érvénytelen paraméter \ n.!");

// i386, egyszerűen telepíthető a TF-bit.

bSetContext = DBG_SetThreadContext (DP-> hThread,

ASSERT (HAMIS = bSetContext!);

Miután a hibakereső felszabadítja a fő folyamat okozza ContinueDebugEvent funkció, a folyamat minden végrehajtása után egyetlen utasítást azonnal generál lépés kivétel. Annak érdekében, hogy azt várták lépés kivételével, a hibakereső ellenőrzi a belső állapotát. Mivel a hibakereső várható ilyen kivétel, hogy „tudja”, hogy a töréspont újra kell telepíteni. Minden lépésnél a jelen eljárásban a utasítás mutató mozog olyan helyzetbe megelőző kezdeti töréspontot. Ezért a hibakereső meghatározhat egy töréspont műveleti kódot vissza az eredeti helyére. Minden alkalommal, amikor van egy kivétel típusú EXCEPTION_ SINGLE_STEP. Az operációs rendszer automatikusan visszaállítja bit TF, így nincs szükség a visszaállításához a debugger. A beállítás után a fő hibakereső töréspont kinyitja szolga, és az egyik folytatódik.

Minden feldolgozási töréspontok végrehajtja CWDBGProjDOC módszer. -andieBreakpoint. amely megtalálható WDBGPROJDOC.CPP fájlt a mellékelt CD-ROM-on. Sami töréspontok azonosított fájlok és töréspontok BREAKPOINT.CPP. Ezek a fájlok egy pár osztályok, amelyek kezelik a töréspontok a különböző stílusokat. WDBG töréspontok párbeszédablak lehetővé teszi, hogy töréspont, amikor a gyengébb hibakereső ugyanúgy ahogy az a debugger, a Visual C ++. Képesek létrehozni „on the fly” töréspontot, akkor azt kell gondosan megőrizni a következő állapotot, és az állam a másodlagos hibakereső töréspont. Részletek a feldolgozás és kikapcsolása töréspontokat szerint alárendeltsége megtalálható a módszer leírását CBreakpointsDig :: Önök a BREAKPOINTSDLG.CPP fájlt a mellékelt CD-ROM-on.

Az egyik legelegánsabb tulajdonságok értékesített WDBG társított tétel Debug szünet menüben. A gond az, hogy míg a gyengébb hibakereső végezzük, ez bármikor lehetséges, hogy gyorsan be a fő debugger.

Töréspontok beállítása végrehajtásakor Debug töréspontok kissé eltérnek használt WDBG. Ezeket nevezik egyszeri (one-shot) töréspont, mert azonnal el kell távolítani, amint a ravaszt. Fogadása egy sor töréspontok van némi érdeklődés. Teljes kép nyerhető működésének elemzésével CWDBGProj Doc. OnDebugBreak a WDBGPROJDOC.CPP. és itt csak néhány tanulságos részleteket. Listing 4-6 funkcióját mutatja CWDBGProj Doc. OnDebugBreak a WDBGPROJDOC.CPP. További információ az egyszeri töréspontok mutatjuk be a szakasz „Operation Step Into, átlépni u lépéssel Out” ebben a fejezetben.

Listing 4-5. Feldolgozás Debug breake a WDBGPROJDOC.CPP

void CWDBGProjDoc. OnDebugBreak ()

ASSERT (m_vDbgThreads.size ()> 0);

// Itt az ötlet, hogy függessze fel minden szála

// rosszabb hibakereső és állítsa a mutatót az aktuális utasítás

// mindegyikre, hogy a megszakítási. Így tudok

// biztosítja, hogy legalább az egyik az adatfolyamok lesz

// fogni eldobható töréspont. Az egyik esetben,

// ahol beállítás töréspontok minden patak nem fog

// függvény fordul elő, amikor a „lógó” alkalmazást. mert

// nincs vissza áramlás, töréspontok soha nem hívott.

// Hogy a munkát a patthelyzet, azt kellett

// az alábbi algoritmus: "

// 1. Állítsa be a töréspontot ez a funkció.

// 2. Állítsa állapotjelző jelzi, hogy elvárom

// pont Debug szünet szakítja.

// 3. Állítsa be az időzítőt a háttérben várja a töréspont.

// 4. Ha az egyik töréspont eltűnik, a számláló.

5. // Ha az időzítő nullázódik, a „lógó” alkalmazást.

// 6. Miután az időzítő beállításához utasítás mutató az egyik

// 7. újraindítja az áramlást.

// 8. Ha ezek a konkrét töréspont működik, megtisztítása

// töréspont és állítsa vissza a utasításszámláló

// vissza az eredeti helyére.

// emelni a prioritása a menet, így

// beállítási átmenni ezen töréspontok a lehető

// gyorsabb, és megakadályoznak minden áramlást az inferior hibakereső

FOGANTYÚ hThisThread = GetCurrentThread ();

int iOldPriority = GetThreadPriority (hThisThread);

SetThreadPriority (hThisThread, THREAD_BASE_PRIORITY_LOWRT);

FOGANTYÚ hProc = GetDebuggeeProcessHandle ();

DBGTHREADVECT :: bejáró i; for (i = m_vDbgThreads.begin ();

// Szünet az áramlás. Ha már van egy számláló

// szuszpenzió, én tulajdonképpen nem aggódik. azaz

// így töréspontok és telepített minden patak

// rosszabb hibakereső. Találok aktív szál

// végül baleset.

// szál van függesztve, akkor kap a kontextusban.

// Mióta használja ASSERT, ez a téma kiemelt

// meghatározott valós időben, és a számítógép

// „lefagy” a levéltábla, így a ha-utasítás lehet

// adja meg a hiba csak a segítségével a nyom operátor.

if (HAMIS! = DBG_GetThreadContext (i-> m_hThread, CTX))

DWORD dwAddr = ReturnlnstructionPointer ( CTX);

// beállítása töréspont.

if (TRUE == cBP.ArmBreakpoint (hProc))

// hozzáadása a töréspont Debug megtörni a listán,

// ha a töréspont volt sikeres

// aktiválódik. Inferior debugger tudott könnyedén

// több áramlások, az azonos

// csak egy töréspont. m_aDebugBreakBPs.Add (CBP);

TRACE ( "GetThreadContext sikertelen! Last Error = Ox% 08X \ n",

// Mivel a függvény GetThreadContext nem sikerült,

// kéne megnézni, mi történt. ezért

// adja meg hibakeresőjének WDBG debugger.

// Bár WDBG szál fut

// prioritás a valós idejű, a hívás DebugBreak

// azonnal eltávolítja az áramlás a működési ütemező

// rendszer, így a prioritás csökken. DebugBreak ();

// Minden folyamok beállított töréspont. Most

// indítsa újra az összes őket, és küldje mindenki egy üzenetet, inline.

// Az ok küldésére ilyen üzenetek egyszerű. Ha a slave

// debugger fog reagálni üzenetek vagy más módon feldolgozó, akkor

// azonnal megszakad. Azonban, ha ez csak egy üres ciklus

// üzeneteket, meg kell kényszeríteni, hogy cselekvésre.

// Mivel van egy azonosítója (ID) áramlási egyszerűen Levél

// patak üzenet WM_NULL. Azt feltételezik, hogy ez a sima

// az üzenetet, úgy, hogy nem rontja el a gyengébb debugger.

// Ha a szál nem egy üzenetet sorban, ez a funkció egyszerűen tolerálni

// rossz egy ilyen áramlás, anélkül, hogy bármilyen kárt,

for (i = m_vDbgThreads.begin ();

// Legyen ez az áramlás továbbra is végrehajtja

// amíg a következő töréspont

PostThreadMessage (i-> m_dwTID, WM_NULL, 0, 0);

// Most kisebb a prioritása a régi értékeket.

SetThreadPriority (hThisThread, iOldPriority);

Annak érdekében, hogy állítsa le az alsóbbrendű debugger, akkor kell kezelni a „squeeze” a töréspont a CPU utasítás áramot úgy, hogy lehetséges, hogy hagyja abba a debugger. Ha a szál fut, akkor kap az ismert pont használhatja az API-funkció suspendThread. felfüggesztő. Ezután aktiválja az API-funkció GetThreadContext. meghatározza a mutató a jelenlegi csapat. Ezzel a mutató, akkor visszatér a telepítése egyszerű töréspont. Ha beállít egy töréspont, meg kell hívni az API-funkció ResumeThread. hogy az áramlás, hogy továbbra is fut, és győződjön meg arról, hogy azért jött, hogy ezt a pontot.

Bár beavatkozni a debugger nagyon egyszerű, meg kell gondolni többet egy pár kérdés. Az első az, hogy a töréspont nem működik. Ha az alsó hibakereső feldolgozza az üzenetet vagy nem más munkát, akkor megszakad. Azonban, ha a gyengébb debugger, hogy ilyen állapotban, várja az érkezését az üzenet, a töréspont nem indul, amíg a gyengébb debugger nem kapja meg az üzenetet. Bár lehet, hogy a felhasználónak, hogy az egeret a gyengébb debugger, hogy létrehoz egy üzenetet. _MOUSEMOVE. de a felhasználó nem kap izgatott ilyen követelmény.

Annak érdekében, hogy a gyengébb hibakereső eléri a töréspontot, meg kell, hogy küldjön neki egy üzenetet. Ha minden van egy patak leíró kiadott hibakeresés API, nem világos, hogyan kell bekapcsolni a fogantyút a megfelelő kilincs (HWND)? Sajnos, nem lehet csinálni. Azonban, miután egy szál fogantyú, akkor mindig hívja a funkció PostThreadMessage. ami küld egy üzenetet minden in-line üzeneteket. Mivel HWND-üzenet feldolgozása alkalmazzák-line az üzenet tetején sorban, a hívás PostThreadMessage csinálni, amire szüksége van.

Továbbra is megérteni, milyen üzenetet kell küldeni? Nem tud üzenetet küldeni, hogy okozhat rosszabb debugger köze valódi feldolgozás, lehetővé téve így a fő hibakereső változtatni a viselkedését a gyengébb debugger. Például, elküldi a WM_CREATE üzenetet. Valószínűleg nem lenne jó ötlet. Szerencsére van egy megfelelő üzenet - WM_NULL. akkor valószínű, hogy használni, mint egy hibakereső eszköz, ha változik az üzeneteket. Üzenetek küldésére használja WM_NULL PostThreadMessage nem jár semmilyen kárt, akkor is, ha a téma nincs üzenet sorban, és a kérelem egy konzolt. Mivel konzolos alkalmazások mindig a futó állapotban, akkor is, ha a várható legfontosabb parancsok, töréspont az éppen futó parancs hatására egy megszakítást.

Kapcsolatos másik probléma multi-threading. Ha megy, hogy függessze fel csak egy szál, és több szálon alkalmazás, meg kell tudni, hogy melyik szál fel kell függeszteni? Ha megszakítja egy alkalmazás végrehajtása, meg egy töréspont a rossz menet, mondjuk, hogy ez le van zárva állapotban vár egy esemény, a jel a szállított csak, mint például a háttérben folyó nyomtatás közben a pontot nem működik megszakítás amíg a felhasználó kiválasztja valamit majd nyomtatni. Az egyetlen biztos módja megszakítani többszálú alkalmazás felfüggesztésére minden szálat, és beállít egy töréspont mindegyikre.

Ez a technika jól működik olyan alkalmazás, amely csak két szál. Azonban, ha egy csomó folyik, a probléma továbbra is nyitott. Felfüggesztése A minden szolga áramlási debugger, hogy megváltoztatja az állam a kérelem, fennáll annak a veszélye, hogy a meghajtó, hogy zsákutca. Ahhoz, hogy függessze fel az összes szálat, töréspont és önéletrajz folyik, minden gond nélkül, a hibakereső kell emelni a prioritást a saját téma. Prioritás növelése THREAD_BASE_PRIORITY_LOWRT. így a hibakereső tudja tervezni a patak folyik a gyengébb debugger nem végzik, ha az alapvető hibakereső manipulálja őket.

Míg többszálú alkalmazások szakítsa algoritmus ésszerűen hangzik. Ahhoz azonban, hogy egy pont Debug szünet teljesen működő, meg kell oldani egy utolsó probléma. Ha telepítette a teljes készlet töréspontok minden patakok és ezen folyamok megújítják, akkor is lehetséges helyzet, amelyben nem lesz megszakítás. Azáltal töréspont, akkor hivatkozhat a teljesítménye legalább az egyik patakok okoznak kivétel töréspont. Mi történne, ha a folyamat olyan patthelyzet? Semmi sem történik - nincs téma nem teljesülnek, és a gondosan elhelyezett a töréspont nem dob kivételt.

Tudtad, hogy a megfigyelők - olyan műveletek, melyek a érve a megfelelő típusú objektumot, és visszaad egy eleme egy más típusú, használják őket, hogy információt szerezzenek az objektumot. Ezek közé tartozik, például, méret-típusú művelet.

Hírek Fórum
Knights-éter elmélet