[Win32] Implementation of a debugger (eight) stepping

Source: Internet
Author: User

[Win32] Implementation of a debugger (eight) stepping

Zplutor
Source: http://www.cnblogs.com/zplutor/
This article copyright belongs to the author and the blog Garden altogether, welcome reprint. However, without the author's consent, this statement must be retained, and in the article page obvious location to the original link, otherwise reserves the right to pursue legal responsibility.

The last one explains how to implement the breakpoint function, which explains how to implement the single step function that is closely related to breakpoints. There are three types of stepping:stepin,stepover , and StepOut, which are more diversified to implement, and it's not difficult to implement them alone, but it's difficult to integrate them together. In particular, the logic of the program is more difficult to understand after adding a breakpoint function. This article begins by explaining the principles of each single step, and finally explains how to integrate them together. This is my personal implementation method, you can use for reference. (Note: The single-step execution described in this article is at the source level, not at the instruction level.) )

Stepin principle

Stepin is executed on an article-by-statement and enters the function when a function call is encountered. When the user releases the stepin command to the debugger, the debugger is implemented as follows:

① Gets the line information for the current instruction by debugging symbols and saves the line information.

② set the TF bit to start the CPU stepping.

③ Gets the line information for the current instruction when processing a single-step exception, compared to the row information saved in ①. If the same, the representation is still on the same line, go to ②, or, if not the same, indicate that a different line has been reached, ending stepin.

The line information can be obtained using the SymGetLineFromAddr64 function described in the previous article. The principle of Stepin is relatively simple, it is important to note that breakpoints are also used with the TF bit to achieve the purpose of re-setting, so you need to determine whether to reset the breakpoint when processing a single step exception. In addition, if there is a breakpoint in the line of code that Stepin , the debugger can simply restore the breakpoint, without notifying the user, if that line of code contains __asm {int 3}; statement, the debugger simply ignores it and does not need to notify the user.

Stepover principle

stepover is executed on an itemized statement and does not enter the function when a function call is encountered. When the user releases the stepover command to the debugger, the debugger is implemented as follows:

① Gets the line information for the current instruction by debugging symbols and saves the line information.

② checks whether the current instruction is a call command. If so, set a breakpoint on the next instruction, and then let the debugged process continue to run, or if not, set the TF bit, start stepping on the CPU , and jump to ④.

③ handles breakpoint exceptions, restores the contents of the first byte of the instruction where the breakpoint is located. The line information corresponding to the current instruction is then obtained, compared to the row information saved in ①, and if the same, jumps to ②; otherwise stops stepover.

④ handles a single-step exception, gets the line information for the current instruction, compared to the row information saved in ①. If same, jump to ②; otherwise stop stepover.

The principle of stepover and Stepin basically the same, the only difference is to encounter the call command skipped, skip the method is to set a breakpoint in the next instruction, and then the debugging process to execute at full speed, triggering the breakpoint and then set TF bit to perform a single step of the CPU . At full speed execution, the breakpoint set by the user and the breakpoint in the debugged process should not be ignored, and the user should be interrupted and notified as normal execution, and stepovershould be stopped at this time. When you perform a single step of the CPU , you should ignore the breakpoint like Stepin . stepover requires breakpoints to be implemented, so the breakpoints used by stepover should be distinguished from other types of breakpoints.

One difficulty with Stepover is how to know whether the current instruction is a call command, and how long it takes to get it. This is a difficult issue and requires some knowledge of the instruction format, which can be consulted on how many ways the call command is written (http://blog.ftofficer.com/2010/04/ N-forms-of-call-instructions) article. At the end of this article we provide a table of call instructions, and we only need to follow this table to write the code to judge.

StepOut principle

StepOut jumps out of the currently executing function and immediately returns to the previous layer function. When the user releases the StepOut command to the debugger, the debugger is implemented as follows:

① gets the address of the RET instruction for the current function, and sets a breakpoint on the instruction to allow the debug process to continue execution.

② the first byte of the instruction in which the breakpoint is restored when processing a breakpoint exception. Gets the return address from the top of the line stacks, sets a breakpoint at that address, and then lets the debugged process continue execution.

③ handles the breakpoint exception again, restores the first byte of the instruction that contains the breakpoint, and ends the StepOut.

StepOut has two difficulties: one is how to get the address of the RET instruction, and the second is how to get the return address of the function. For the first question, you can use the symfromaddr function to get information about a function. The role of the symfromaddr function is to obtain the information of the corresponding symbol by the address, which can be a variable or a function. The statement is as follows:

1 BOOL WINAPI symfromaddr (
2 HANDLE hprocess,
3 DWORD64 Address,
4 PDWORD64 Displacement,
5 Psymbol_info Symbol
6);

The first parameter is the identifier of the symbol processor. The second parameter is an address. The third parameter is the output parameter, which returns the offset of the address relative to the symbol start address after the function call succeeds. The fourth parameter is a pointer to the symbol_info struct, and the symbol-related information is stored in the struct when the function call succeeds. The definition of the struct has been mentioned in the previous article.

The argument address can be an arbitrary address, and if the address belongs to a variable, the function returns the symbolic information of the variable, and if the address belongs to a function, the symbolic information of the function is returned, and if the address does not correspond to any symbol, the function returns FALSE.

We can put the current debug processEIPPass it as an addresssymfromaddrTo get the information for the current function.Symbol_infoOfAddressfield holds the address of the first instruction of the function,SizeThe field holds the byte length of all instructions in the function, becauseRETAn instruction is the last instruction of a function, soAddressPlusSizeand subtractRETThe length of the instruction isRETThe address of the instruction. So the next question is to getRETThe length of the instruction.RETInstruction ratioPagerInstruction is much simpler, with only two forms, one byte long and the hexadecimal value0xC3Or0xCB; the other has three bytes long, and the hexadecimal value of the first byte is0xC2Or0xCA, followed by two bytes isESPThe value that will be added.

The second difficulty is getting the return address of a function. If you are familiar with the process of calling a function, you know that at the time the RET instruction is about to be executed, the top of the line stacks, the memory location referred to by ESP , must be the return address of the function. This is the purpose of setting breakpoints in the RET directive.

When StepOut is performed, the other breakpoints cannot be ignored because the debug process is running at full speed, and the breakpoint that is used when the breakpoint is triggered is canceled StepOut . Also, the breakpoints used by StepOut are distinguished from other types of breakpoints.

Integration

The three steps described above require breakpoints and the support of CPU stepping, which means that their processing logic is concentrated in the breakpoint exception and the single step exception handler, which makes the logic of the Code complex and difficult to understand. Here I try to figure out this idea, so that you have a better understanding of the sample code.

The previous article divided the breakpoints into the following three types:

Initial Breakpoint

Breakpoints in the process being debugged

Breakpoints set by the debugger

In addition to the initial breakpoint, the other two breakpoints are collectively referred to as normal breakpoints. After you have added the functionality of stepping, you have added two types of breakpoints:

stepover Breakpoint

StepOut Breakpoint

The addition of the breakpoint type complicates the handling of the breakpoint exception, so it is necessary to reduce the complexity by placing all of the breakpoint's processing on the first receive breakpoint exception, so you will need to manually subtract 1 from the EIP at this point.

As stated above, all normal breakpoints should be ignored when the debug process is executed one-by-one, ignoring the meaning of not notifying the user. In order to do this, you need to save the execution state of the debugged process (full-speed or one-point execution), and then check those states.

Is the process of breakpoint exception:

is a single-step exception handling process:

In the above two flowcharts, the processing of thestepover Breakpoint and the handling of the single-step exception have the same logic, and the common logic should be extracted into a function when implemented.

Sample code

In this Minidebugger , three commands were added, as follows:

In Stepin

Over Stepover

Out StepOut

Http://files.cnblogs.com/zplutor/MiniDebugger8.rar

[Win32] Implementation of a debugger (eight) stepping

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.