デバッガヌの孊習、パヌト1

ハッキング゜フトりェアは、䞀郚の神秘的な「ハッカヌ」によっお実行されおいないこずを知っおいるず思いたす。この蚘事の読者の倧半ず同じプログラマヌによっお実行されたす。 同時に、゜フトりェア開発者自身ず同じツヌルを䜿甚したす。 もちろん、予玄に぀いおは、ほずんどの堎合ツヌルキットは非垞に具䜓的ですが、䜕らかの方法でデバッガヌを䜿甚しお゜フトりェアを分析するためです。



私の蚘事のほずんどは、゜フトりェアでセキュリティを䜿甚するこずに関心のある人を察象ずしおいるため、セキュリティコヌドの特定の郚分以前に公開されたものなどを含む資料を送信するだけで読者を混乱させるこずにしたした。 基本から始めお、すでに完成したベヌスでゆっくりず新しい玠材を提䟛する方がはるかに簡単です。



したがっお、この蚘事では、プログラマヌの基本ツヌルの1぀であるデバッガヌに぀いお説明したす。

蚘事の目的デバッガヌの基本的な操䜜方法を怜蚎し、その高床であたり䜿甚されない機胜を瀺し、䟋を䜿甚しおデバッガヌメカニズムの動䜜を理解し、特定の察抗手段を怜蚎したす。



蚘事のボリュヌムは予想倖に倧きかったため、3぀の郚分に分けたした。





実際に始めたしょう。





1.1。 ブレヌクポむントの䜿甚ずロヌカル倉数の倉曎



組み蟌みデバッガの最も䞀般的に䜿甚されるツヌルの1぀はブレヌクポむントBreakPoint-以降BPです。 BPのむンストヌル埌、プログラムはブレヌクポむントに到達するたで機胜し、その埌、䜜業が䞭断され、制埡がデバッガヌに転送されたす。



BPをむンストヌルおよび削陀する最も簡単な方法は、ホットキヌ「F5」たたはメニュヌの「デバッグ」->「ブレヌクポむントの切り替え」です。 他の方法もありたすが、それらに぀いおは埌で詳しく説明したす。



プログラムが停止した埌、アプリケヌションが停止されたプロシヌゞャのロヌカル倉数の倀を調べ、このプロシヌゞャの呌び出しに先行する呌び出しスタックを分析できたす。 ここで、これらの倉数の倀を倉曎できたす。



BPを眮く堎所-もちろん䞀般的な答えはありたせん。 本質的に、BPは、コヌドの動䜜、その正確性がわからない、たたは即座に怜出できない゚ラヌを明瀺的に含むコヌドの操䜜の孊習を促進するように蚭蚈されおいたす。



ブレヌクポむントを蚭定し、コヌドの各行を順番に実行する方が、同じコヌドを䜕時間もかけお、意図したものずは異なる動䜜を開始する堎所を芋぀けようずするよりもはるかに簡単です。



次の䟋を芋おみたしょう。



タスクがありたす。最初に無効にされた倉数の倀を5倍に123ず぀増やすコヌドを蚘述し、その埌、結果を10進数ず16進数の圢匏で衚瀺したす。 予想される倀は、128および00000080です。



コヌドが゚ラヌで曞かれおいるずしたしょう



var B: Integer = 123; procedure TForm1.FormCreate(Sender: TObject); var A: Integer; begin Inc(A); Inc(A); Inc(A, B); Inc(A); Inc(A); Inc(A); ShowMessage(IntToStr(A)); ShowMessage(IntToHex(A, 8)); end;
      
      







このコヌドは任意の倀を出力したすが、倉数「A」をれロで初期化しおいないため、必芁な倀は出力したせん。 たた、倉数「A」はロヌカルであるため、スタックに配眮されおいるこずを意味し、この手順の開始時にどの倀を取るかを予枬するこずはできたせん。 しかし、すでに営業日の終わりであり、本圓に疲れお目ががやけおいる、倉数の初期化を含む行を曞くのを忘れおいるず仮定したす。



その結果、䞍正な倀を衚瀺するコヌドがあり、この動䜜の理由をすばやく把握したいず考えおいたす。 BPをプロシヌゞャの本䜓に入れ、プログラムを実行しお実行したす。



画像



それは写真のようなものでなければなりたせん。 BPはラむンIncAにむンストヌルされたす。 巊䞋では、FormCreateプロシヌゞャのすべおのロヌカル倉数りィンドりは「ロヌカル倉数」ず呌ばれたすの倀、぀たりSelf倉数暗黙的に枡され、クラスメ゜ッドに垞に存圚したす、Senderパラメヌタヌ、およびロヌカル倉数「A」自䜓を確認できたす。 その倀は19079581です。「WatchList」の䞭倮の巊偎は、倉数「B」の倀です。



䞡方の倉数の倀ず完了した3行のコヌドを䞀目芋ただけでも、倉数 "A"の倀が予想ず䞀臎しないこずがわかりたす。 ナニットごずに2぀の増分ず123ず぀の増分が実行されるため、倉数「A」の倀125が衚瀺されるはずです。異なる倀があるため、これは1぀のこずしか意味したせん。倉数「A」の初期倀は本圓。



仮定の正しさを確認するために、倉数「A」の珟圚の倀を正しい倀に倉曎し、プロシヌゞャが返す結果が予期されたものであるかどうかを確認するためにプログラムを続けたしょう。



デバッガヌには、倉数の倀を倉曎するための2぀のツヌルが甚意されおいたす。



最初の「評䟡/倉曎」は、メニュヌたたはホットキヌ「Ctrl + F7」を介しお呌び出されたす。 これは最小限の機胜を備えた非垞にシンプルなツヌルであり、最もよく䜿甚されたす。



次のようになりたす。



画像



倉数の倀を倉曎するには、「新しい倀」フィヌルドに新しい倀を指定しお、「Enter」キヌたたは「倉曎」ボタンを抌したす。

2番目のツヌルである「怜査」は、「実行」メニュヌから、たたは「評䟡/倉曎」ダむアログから盎接䜿甚するこずもできたす。 これは、より高床なパラメヌタヌ゚ディタヌです。



倉数「A」の倀を倉曎した埌、ロヌカル倉数の倀のリストの倉曎に泚意しおください。



画像



倉数「A」は正しい倀を取り、「F9」を抌すかメニュヌから「実行」を遞択するこずで、アプリケヌションの実行を継続できたす。 デバッガの助けを借りたこのような介入の結果、プロシヌゞャは予想される数倀128ず00000080を提䟛したす。゚ラヌの原因を芋぀け、倉数「A」の正しく蚭定された倀で実行を確認したため、プロシヌゞャコヌドを安党に修正できたす



怜査に戻りたしょう。 瀺された2぀の呌び出し方法に加えお、右クリック時にコンテキストメニュヌを䜿甚するか、ホットキヌ「Alt + F5」を䜿甚しお、「ロヌカル倉数」りィンドりで倉数をダブルクリックするこずでも呌び出されたす。



これは、より「高床な」倉数プロパティ゚ディタヌですが、オブゞェクトのプロパティを倉曎するずきに䜿甚するのが劥圓です。 通垞の倉数を倉曎するのは倚少䞍䟿ですが、その理由は次のずおりです。



呌び出すず、最初に次のダむアログが衚瀺されたす。



画像



倉数の説明、メモリ内の䜍眮、および珟圚の倀を瀺したす。倉曎するには、再床省略ボタンを抌す必芁がありたす。その埌、远加のりィンドりが衚瀺されたす。



画像



通垞の倉数の倀を倉曎するような単玔な操䜜のための過床の䜓の動きは明らかに冗長です。 ただし、これを䜿甚しおオブゞェクトのプロパティを倉曎するず、画像が少し倉わりたす。



オブゞェクトのプロパティぞの「評䟡/倉曎」アクセスは、調査䞭のオブゞェクトに関する情報を盎接提䟛しないずいう点で倚少耇雑です。 たずえば、キャンバスフォヌムのハンドルを取埗するには、次のテキストを入力する必芁がありたす。「SForm as TForm1.Canvas.Handle」-封印するこずができ、このプロパティたたはそのプロパティの名前を忘れおしたうため、倚少䞍䟿です。



Inspectの堎合、このような問題は発生したせん。



たずえば、倉数「A」ではなく、倉数Selfに぀いお「Inspect」ダむアログを開きたしょう前述のように、これはオブゞェクトのすべおのメ゜ッドに察しお垞に暗黙的に存圚したす。



画像



ご芧のずおり、この堎合、オブゞェクトのほずんどすべおのフィヌルドにアクセスできたすが、必芁に応じお倉曎できたす。プロパティの名前が混乱するこずはありたせん。



1.2。 トレヌス段階的なデバッグ



トレヌスの本質は、コヌドの各行をステップごずに実行するこずです。



以前にむンストヌルしたBPで停止し、コヌドを分析し、次の行に移動したいずしたす。 原則ずしお、BPを配眮しおプログラムを実行するこずもできたす。 そしお次の、そしおそれ以降の人々のために。

実際には、プロシヌゞャコヌドの各行にBPを蚭定しお、デバッガ自䜓が実行できるこずを手動でシミュレヌトしたす2番目のセクションで詳しく説明したす。



そしお圌は次のこずを知っおいたす。



  1. コマンド「Trace Into」「F7」-デバッガヌは珟圚のコヌド行のコヌドを実行し、次のコヌドで停止したす。 珟圚のコヌド行がプロシヌゞャを呌び出す堎合、次の行は呌び出されたプロシヌゞャの最初の行になりたす。
  2. 「Step Over」コマンド「F8」は最初のコマンドに䌌おいたすが、呌び出されたプロシヌゞャの本䜓ぞの゚ントリは発生したせん。
  3. 「次の゜ヌス行ぞのトレヌス」コマンド「Shift + F7」も最初のコマンドのほが完党な類䌌物ですが、「CPUビュヌ」りィンドりで䜿甚されたすこのデバッグモヌドはこの蚘事では考慮されおいたせん。
  4. 「Run to Cursor」「F4」コマンド-デバッガヌは、カヌ゜ルが珟圚䜍眮しおいる行たでプログラムコヌドを実行したす実行䞭に他のBPが発生しなかったずいう条件で。
  5. 「リタヌンたで実行」コマンド「Shift + F8」-デバッガヌは、珟圚のプロシヌゞャのコヌドを終了するたで実行したす。 倚くの堎合、誀っお抌された「F7」のカりンタヌずしお、たた実行䞭に他のBPが怜出されないずいう条件䞋で䜿甚されたした。
  6. Delphiの叀いバヌゞョンでは、「次のステヌトメントを蚭定」コマンドを䜿甚できたす。このコマンドを䜿甚しお、コヌドの任意の行を珟圚の行ずしお蚭定するこずにより、プログラムの進行状況を倉曎できたす。 この機胜は、珟圚アクティブな行を指す矢印を新しい䜍眮にドラッグできるコヌド゚ディタヌでも䜿甚できたす。


これらのチヌムは詳现な怜蚎を必芁ずしたせん。 「Trace Into」「F7」チヌムのみに泚目したしょう。



たずえば、次のコヌドを䜿甚したす。



 procedure TForm1.FormCreate(Sender: TObject); var S: TStringList; begin S := TStringList.Create; try S.Add('My value'); finally S.Free; end; end;
      
      







トレヌスを実行するずき、S.Addの行にいるずき、デバッガヌの反応には2぀のオプションがありたす。



  1. TStringList.Addメ゜ッド内に移動し、
  2. そこには入りたせん。


この動䜜は、コンパむラの蚭定が原因です。 事実、Delphiにはシステムモゞュヌル甚に2セットのDCUが付属しおいたす。 1぀はデバッグ情報あり、2぀目はデバッグ情報なし。 2番目のモゞュヌルが接続されおいる堎合、この堎合の「Trace Into」「F7」コマンドは「Step Over」「F8」ずしお機胜したす。 コンパむラヌ蚭定のモゞュヌル間の切り替えが構成されたす。



画像



たた、「デバッグDCUを䜿甚」パラメヌタヌがこの機胜を担圓したす。



1.3。 コンパむラヌ蚭定の詳现



コンパむラ蚭定のタブのオプションは、プロゞェクトをビルドするずきに生成されるコヌドに盎接圱響したす。 このタブのいずれかの項目を倉曎する堎合、倉曎を有効にするにはプロゞェクトの完党な再アセンブリ「プロゞェクト>ビルド」が必芁であるこずを忘れないでください。 これらの蚭定は、さたざたな状況でのコヌドの動䜜、およびプロゞェクトのデバッグ時に利甚可胜な情報の構成に盎接圱響したす。



それらをより詳现に怜蚎したしょう。



コヌド生成グルヌプ



画像



最適化パラメヌタヌ



このパラメヌタヌは、コヌドの最適化に盎接圱響したす。パラメヌタヌがオンの堎合、コヌドはサむズず実行速床の䞡方を考慮しお、最適な方法で生成されたす。 コヌドの最適化により、BPで䞭断した時点で既にメモリから削陀されおいる可胜性があるため、これにより、䞀郚のロヌカル倉数ぞのアクセスが読み取りでもアクセスできなくなる可胜性がありたす。



䟋ずしお、最初の章のコヌドを取り䞊げ、同じBPに぀いお説明したすが、最適化はオンになっおいたす。



画像



ご芧のずおり、以前に䜿甚可胜なSelfおよびSender倉数の倀は䜿甚できなくなりたした。 たた、「デバッグDCUを䜿甚」パラメヌタヌが無効になっおいるため、「コヌルスタック」りィンドりで劇的な倉曎が発生し、以前はコヌルリストに関する詳现情報が衚瀺されおいたした。

さらに、InspectツヌルはSelfオブゞェクトの操䜜も拒吊し、次の゚ラヌを発生させたす。



画像



スタックフレヌムずPentiom-safe FDIVオプション



これらのパラメヌタヌの説明はスキップしたす-デバッグ段階では、これらのパラメヌタヌはおもしろくありたせん。 芁するに、1぀目はスタックの自己分析に圹立ち、2぀目は数孊的コプロセッサヌで䜜業する際のニュアンスの原因ずなりたす。 誰かがニュアンスに興味がある堎合は、プロファむルでのコミュニケヌションの私の座暙。



レコヌドフィヌルドの䜍眮合わせパラメヌタヌ



パックされおいないレコヌドのグロヌバルアラむンメント。ディレクティブ「{$ Align x}」たたは「{$ A x}」を䜿甚しおモゞュヌル内でロヌカルに倉曎できたす。



たずえば、次のコヌドを怜蚎しおください。



 type T = record a: Int64; b: Byte; c: Integer; d: Byte; end;
      
      







SizeOfTを介しお取埗できるこのレコヌドのサむズは、アラむメント蚭定ごずに異なりたす。



{$ Align 1} = 14

{$ Align 2} = 16

{$ Align 4} = 20

{$ Align 8} = 24



構文オプショングルヌプ



画像



䜕も觊らない方がいいです 詊しおみるず、暙準VCLでのアセンブルを拒吊するこずもできたす。



私は「Complete boolen eval」パラメヌタに぀いおのみ説明したす。それらのいく぀かは時々それをオンにするからです。 次のコヌドを実行するず゚ラヌが発生したす。



 function IsListDataPresent(Value: TList): Boolean; begin Result := (Value <> nil) and (Value.Count > 0); end; procedure TForm1.FormCreate(Sender: TObject); begin if IsListDataPresent(nil) then ShowMessage('boo...'); end;
      
      







この蚭定をオンにするず、ブヌル匏党䜓がチェックされるため、最初のチェックでValueパラメヌタヌが無効化されおいるず刀断されたにもかかわらず、Value.Countにアクセスするず゚ラヌが発生したす。 たた、たずえば「拡匵構文」パラメヌタヌを有効にするず、このコヌドは、宣蚀されおいないResult倉数に぀いお䞍平を蚀っおも収集されたせん。



ランタむム゚ラヌグルヌプ



画像



範囲確認パラメヌタヌ



これは、アプリケヌションのデバッグ時に最も芁求されるパラメヌタヌの1぀です。 圌は、デヌタ配列にアクセスするずきに境界をチェックする責任がありたす。



最も単玔な堎合、このコヌドを実行するず䟋倖がスロヌされたす。



 const A: array [0..1] of Char = ('A', 'B'); procedure TForm1.FormCreate(Sender: TObject); var I: Integer; begin for I := 0 to 100 do Caption := Caption + A[I]; end;
      
      







ここでは、単に配列の芁玠にアクセスしようずしおいたすが、原則ずしお、「範囲チェック」オプションを無効にしお、割り圓おられたメモリを超えない堎合、このコヌドはフォヌムヘッダヌに奇劙な行があるず脅したす。



画像



これは䞍快ですが、プログラムの実行には重芁ではありたせん。 ブロックに曞き蟌もうずしたずきにブロックの境界を間違えた堎合、さらに悪いこずになりたす。この堎合、アプリケヌションのメモリが砎壊される可胜性がありたす。



この䟋を怜蚎し、最適化を無効にしたす。



 type TMyEnum1 = (en1, en2, en3, en4, en5); TMyEnum2 = en1..en3; procedure TForm1.FormCreate(Sender: TObject); var I: TMyEnum1; HazardVariable: Integer; Buff: array [TMyEnum2] of Integer; begin HazardVariable := 100; for I := Low(I) to High(I) do Buff[I] := Integer(I); ShowMessage(IntToStr(HazardVariable)); end;
      
      







このコヌドの実行埌、HazardVariableの数倀はどうなるず思いたすか 反埩子のタむプを遞択するずきにミスをしお、TMyEnum2ではなくTMyEnum1を蚘述したため、配列の境界の範囲を超え、スタック䞊のデヌタが倱われ、それに栌玍されおいるロヌカル倉数の倀が倉曎されたした。



最適化を有効にするず、状況はさらに悪化したす。 次の゚ラヌが衚瀺されたす。



画像



この説明によれば、゚ラヌテキストに蚘茉されおいるアドレスはアプリケヌションのメモリに属しおいないため、䟋倖がどこで発生したのか、なぜ発生したのか掚枬するこずもできたせん。説明できたせん。



したがっお、原則ずしおそれを受け入れたす-アプリケヌションのデバッグは、垞に「範囲チェック」蚭定をオンにしお行う必芁がありたす



たた、このパラメヌタヌは、倉数の倀を倉曎する際の蚱容倀の超過を制埡したす。 たずえば、負の倀をCardinal / DWORDなどの笊号なしの型に割り圓おようずした堎合、たたはこの型の倉数が含むこずができる倀よりも倧きい倀を割り圓おようずした堎合、たずえばByte型の倉数に500を割り圓おた堎合などに、䟋倖が発生したす



パラメヌタ「I / O cheking」



Pascalスタむルのファむルを操䜜する堎合、I / Oの結果を確認する必芁がありたす。



このアプロヌチを䜿甚する゜フトりェアがただあるかどうかはわかりたせんが、Append / Assign / Rewriteなどを突然䜿甚する堎合は、アプリケヌションのデバッグ時にこのオプションを有効にしおください。



オヌバヌフロヌチェックオプション



算術挔算の結果を制埡し、結果が倉数の範囲倖にある堎合に䟋倖を発生させたす。



このパラメヌタヌず「範囲チェック」の違いを理解しやすくするために、次のコヌドを怜蚎しおください。



 procedure TForm1.FormCreate(Sender: TObject); var C: Cardinal; B: Byte; I: Integer; begin I := -1; B := I; C := I; ShowMessage(IntToStr(C - B)); end;
      
      







「オヌバヌフロヌチェック」オプションが有効になっおいる堎合、このコヌドは䟋倖を発生させたせん。 ここでは受け入れられない倀が倉数に割り圓おられおいたすが、それらに察しお数孊的挔算は実行されたせん。 ただし、「範囲チェック」オプションが有効になっおいる堎合、䟋倖が発生したす。



次に、コヌドの2番目のバヌゞョンを怜蚎したす。



 procedure TForm1.FormCreate(Sender: TObject); var C: Cardinal; B: Byte; begin B := 255; Inc(B); C := 0; C := C - 1; ShowMessage(IntToStr(C - B)); end;
      
      







「範囲チェック」パラメヌタヌからの反応はなくなりたすが、算術挔算の結果ができないため、IncBおよびC= C-1の行で「Overflow cheking」が原因のEIntegerOverflow䟋倖が発生したす。察応する倉数に保存されたす。

したがっお、倉数を䜿甚する堎合、䞡方のパラメヌタヌは互いに補完したす。



オヌバヌフロヌチェックは、範囲チェックほど重芁ではありたせんが、アプリケヌションをデバッグするずきは、オンのたたにしおおくこずをお勧めしたす。



小さなニュアンス暗号アルゎリズムを突然実装した堎合、原則ずしお、オヌバヌフロヌ操䜜は暙準です。 このような状況では、コヌドを別のモゞュヌルに転送し、モゞュヌルの先頭に「{$ OVERFLOWCHECKS OFF}」ディレクティブを蚘述しお、珟圚のモゞュヌルのオヌバヌフロヌチェックを無効にしたす。



デバッググルヌプ



画像



このタブでは、すべおが非垞に簡単です。 「アサヌション」パラメヌタヌを陀くすべおのパラメヌタヌは、アプリケヌションの最終コヌドに圱響を䞎えたせん。 特定のパラメヌタのアクティビティに応じお、各モゞュヌルのDCUファむル内のデバッグ情報の完党性が倉わりたす。 この情報に基づいお、デバッガヌは、プログラムのアセンブラヌリストをプログラマヌによっお実装された実際のコヌドず同期し、ロヌカル倉数などを認識したす。アプリケヌションをコンパむルするずき、このデバッグ情報はアプリケヌションの本䜓に収たりたせん。

唯䞀の䟋倖は「Assertions」パラメヌタヌです-Assertプロシヌゞャの操䜜を担圓したす。 このパラメヌタヌが無効になっおいる堎合、Assertは実行されたせん;それ以倖の堎合、実行され、そのコヌドもコンパむル段階でアプリケヌション本䜓に配眮されたす。



たずめたす。



アプリケヌションのデバッグの段階では、「ランタむム゚ラヌ」グルヌプず「デバッグ」グルヌプのすべおのパラメヌタヌを有効にし、リリヌスアプリケヌションの最終コンパむル䞭は無効にするこずをお勧めしたす。 Delphi 7以前では、これは手動で行う必芁がありたすが、Delphi 2005以降では、プロゞェクトビルドの通垞のサポヌトが登堎したした。このビルドでは、これらのフラグの組み合わせをアセンブリの皮類ごずに個別に指定できたす。



1.4。 呌び出しスタックりィンドり



アプリケヌションのデバッグ時にBPがメむンツヌルである堎合、Call Stackが2番目に重芁です。



このりィンドりは次のようになりたす。



画像



デバッガヌがむンストヌルされたBPでプログラムの実行を䞭断するたたぱラヌのために停止する前に行われた呌び出しの完党な説明が含たれおいたす。 たずえば、スクリヌンショットは、フォヌム䞊のボタンをクリックしたずきに発生した呌び出しのスタックを瀺しおいたす。 TWinControl.DefaultHandlerプロシヌゞャにWM_COMMAND273メッセヌゞが到着したこずから始たりたした。



このリストを手元に眮いお、ダブルクリックしおたたは「゜ヌスを衚瀺」メニュヌを䜿甚しおコヌルをすばやく切り替え、各コヌルのロヌカル倉数のリストを衚瀺「ロヌカルを衚瀺」し、コヌルでBPを蚭定したす。



もちろん、倚くの可胜性はありたせんが、ほずんどの堎合、゚ラヌが発生した堎所をすばやくロヌカラむズできるため、デバッグ䞭の䜜業が倧幅に容易になりたす。



たずえば、EAbstractError゚ラヌが発生するず、呌び出しスタックは次のようになりたす。



画像



この堎合、゚ラヌがその䞭にある可胜性が高いず蚀うためには、Delphiシステムモゞュヌルにコヌドが配眮されおいない最初の呌び出しを芋぀けるだけで十分です。 このような呌び出しはUnit1.TForm1.Button1Clickです。これは、次のコヌドが実行されたButton1ボタンハンドラヌです。



 procedure TForm1.Button1Click(Sender: TObject); begin TStrings.Create.Add('qwe'); end;
      
      







別の䜿甚䟋は、特定の関数の呌び出しをトレヌスするこずです。 たずえば、非垞に倧きなアプリケヌションコヌドがあり、その内郚のどこかにMessageBoxが呌び出されおいたすが、このMessageBoxの呌び出しの堎所をロヌカラむズするためのヒッチのあるこの堎所を芋぀けるこずはできたせん。 これを行うには、次の方法を䜿甚できたす。

  1. 察象の関数の呌び出しが宣蚀されおいるモゞュヌルこの堎合はwindows.pasに移動したす。
  2. その宣蚀青いドット関数MessageBoxを持぀行;倖郚user32 ...、
  3. この行にBPをむンストヌルし、プログラムを実行したす。


プログラム内の任意の堎所からMessageBox呌び出しが行われるずすぐに、BPが機胜し、呌び出しスタックデヌタに基づいお呌び出しの正確な堎所を芋぀けるこずができたす。



1.5。 高床なブレヌクポむントプロパティの操䜜



, , , , , , , .



. BP .



画像



«Breakpoint list» BP.



画像



:



画像



«Condition» .

「パスカりント」パラメヌタヌは、BPがアクティブになる前にそのような条件をいく぀スキップする必芁があるかを瀺し、「条件」パラメヌタヌの倀を考慮しお、操䜜の数が最初からカりントされたす。



抜象的な䟋を考えおみたしょう



 procedure TForm1.FormCreate(Sender: TObject); var I, RandomValue: Integer; begin RandomValue := Random(100); for I := 1 to 100 do RandomValue := RandomValue + I; ShowMessage(IntToStr(RandomValue)); end;
      
      







, (RandomValue := ...). , 100 . «Pass count» 10. , «I» .



, 75 , «Condition»: I > 75. : , «I» 85, , 95.



:



, , , . . «Pass count», , , «Pass count». ( ).



«Condition», . ., «I» 75, , . , , «Pass count» , «I» 85.



, , «I» 75, «Pass count» .



.



.



, , . ぀たり ( ), , , 100 , , .



: (, ), .



:



 procedure TForm1.FormCreate(Sender: TObject); var I, RandomValue: Integer; begin RandomValue := Random(100); for I := 1 to 10000 do RandomValue := RandomValue + I; ShowMessage(IntToStr(RandomValue)); end;
      
      







同じ7行目にBPを蚭定し、パラメヌタヌ「Condition」に倀I = 9999を指定したす。このような小さなサむクルであっおも、3〜5秒の範囲で状態が機胜するのを埅぀必芁がありたす。もちろん、これは䟿利ではありたせん。このような堎合、次のようにコヌドを倉曎する方が簡単です。



 procedure TForm1.FormCreate(Sender: TObject); var I, RandomValue: Integer; begin RandomValue := Random(100); for I := 1 to 10000 do begin RandomValue := RandomValue + I; {$IFDEF DEBUG} if I = 9999 then Beep; {$ENDIF} end; ShowMessage(IntToStr(RandomValue)); end;
      
      








 Beep, . .

( DEBUG , , , Beep-. )



«» , (SEH), Delphi try..finally..except. SEH «» . , :



 function Test1(var Value: Integer): Cardinal; var I: Integer; begin Result := GetTickCount; for I := 1 to 100000000 do Inc(Value); Result := GetTickCount - Result; end; function Test2(var Value: Integer): Cardinal; var I: Integer; begin Result := GetTickCount; for I := 1 to 100000000 do try Inc(Value); finally end; Result := GetTickCount - Result; end; procedure TForm1.FormCreate(Sender: TObject); var A: Integer; begin A := 0; ShowMessage(IntToStr(Test1(A))); A := 0; ShowMessage(IntToStr(Test2(A))); end;
      
      







Test1 Test2 100 .



210 , – , – try..finally.



, «» – , 




«Group», BP . – , , , , BP, .



:



画像



: «Enable group» – , «Disable group» – .



«Break», . , .

– .



– , .



, .



䟋をコンパむルする前に、コンパむラヌ蚭定で「オヌバヌフロヌチェック」オプションを有効にし、最適化を無効にしおください。



 function Level3(Value: Integer): Integer; var I: Integer; begin Result := Value; for I := 0 to 9 do Inc(Result); end; function Level2(Value: Integer): Integer; var I: Integer; begin Result := Value; for I := 0 to 9 do Inc(Result, Level3(Result) shr 1); end; function Level1(Value: Integer): Integer; var I: Integer; begin Result := Value; for I := 0 to 9 do Inc(Result, Level2(Result) shr 3); end; procedure TForm1.FormCreate(Sender: TObject); begin ShowMessage(IntToStr(Level1(0))); end;
      
      







このコヌドを実行するず、16行目に䟋倖が発生したす



 Inc(Result, Level3(Result) shr 1);.
      
      







, , , , . : , , , «F9» , .



, , , , .



:



  1. «level2BP».
  2. , . FormCreate ShowMessage «Disable group» «level2BP». , «Break».
  3. Level1 №25. , .
  4. , 9 ( I ). , 8 , , «level2BP». «Condition» I=8, «Break» «Enable group» «level2BP».
  5. , Level2, – . F9, , , , I 5. «Condition» I=5, .
  6. , .




— , :

rouse.drkb.ru/blog/bp3.mp4 (17 ).

( , , , , )



, , .



«Pass Count», «Condition»? , «Pass Count» . (. . «Condition») , .



.



«Ignore subsequent exceptions» , .



«Handle subsequent exceptions» , .



, :



 procedure TForm1.Button1Click(Sender: TObject); begin ShowMessage('All exceptions ignored'); end; procedure TForm1.Button2Click(Sender: TObject); begin PInteger(0)^ := 123; end; procedure TForm1.Button3Click(Sender: TObject); var S: TStrings; begin S := TStrings.Create; try S.Add('abstract') finally S.Free; end; end; procedure TForm1.Button4Click(Sender: TObject); begin ShowMessage('All exceptions handled'); end;
      
      







ShowMessage , , «Break», «Ignore subsequent exceptions».



ShowMessage , «Handle subsequent exceptions».



:



  1. Button1
  2. Button2
  3. Button3
  4. Button4
  5. Button2
  6. Button3


, Button2 Button3 , 2 3 , 5 6 , Button4.



2 :



«Log message» – , .



«Eval expression» – , ( «Log result») . , «123 * 2».



1.6。 «Data breakpoint», «Watch List» «Call Stack»



, , «Source Breakpoint». . . , .



, , (, , ) BP , , «Data breakpoint».



«Watch List» ( Delphi) «Breakpoint List» «Add Breakpoint->Data Breakpoint», , , , . , ( ) .



問題は、アプリケヌションを起動するたびに倉数が配眮されるアドレスが毎回異なるため、この倀の取埗が非垞に難しいこずです。



– . , , , «Data breakpoint» . , , , . . – , , , , , , . «Data breakpoint» , .



, , «Data breakpoint» – «Memory Breakpoint».



, Delphi , «Memory Breakpoint» , .



, .



:



 type TTest = class Data: array [0..10] of Char; Caption: string; Description: string; procedure ShowCaption; procedure ShowDescription; procedure ShowData; end; TForm1 = class(TForm) procedure FormCreate(Sender: TObject); private FT: TTest; procedure InitData(Value: PChar); end; var Form1: TForm1; implementation {$R *.DFM} { TTest } procedure TTest.ShowCaption; begin ShowMessage(Caption); end; procedure TTest.ShowData; begin ShowMessage(PChar(@Data[0])); end; procedure TTest.ShowDescription; begin ShowMessage(Description); end; { TForm1 } procedure TForm1.FormCreate(Sender: TObject); begin FT := TTest.Create; try FT.Caption := 'Test caption'; FT.Description := 'Test Description'; InitData(@FT.Data[0]); FT.ShowCaption; FT.ShowDescription; FT.ShowData; finally FT.Free; end; end; procedure TForm1.InitData(Value: PChar); const ValueData = 'Test data value'; var I: Integer; begin for I := 1 to Length(ValueData) do begin Value^ := ValueData[I]; Inc(Value); end; end;
      
      







, :



画像



«Break», - «system»:



画像



, , , «Call Stack», , ShowCaption .

BP , , , Caption, :



画像



, - Caption. «Data breakpoint».



  1. Caption, FT.Description := 'Test Description';.
  2. , FP.Caption «Watch List» «Break When Changed». (, Delphi 2010 ), «Data breakpoint» . «Breakpoint List» «Add->Data Breakpoint», FP.Caption .
  3. .




, №68 – Inc(Value). «Data breakpoint» , , , , FP.Caption, – Value^ := ValueData[I].



, , . , ValueData, Data, , - , Caption Description.



1.7. 結論ずしお



. , : , .., .

«CPU-View» Address Breakpoint. , .. , CPU-View :)



, . , BreakPoint, Data Breakpoint, Delphi, ( , TF GUARD ), Hardware Breakpoint, Delphi.



« » , aka Inovet, aka Palladin aka .



(Rouse_)

, 2012



All Articles