[Win32] Implementation of a debugger (vi) Display source code

Source: Internet
Author: User

[Win32] Implementation of a debugger (vi) Display source code

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 previous article introduced debug symbols and dbghelp loading and cleanup, which we used to implement a feature that shows the source code. The actual use of the feature is as follows:

This feature not only displays the source code, but also displays the address of each line of code. The following steps are probably required to implement this feature:

① gets the address of the next instruction to be executed.

② the debug symbol to get which line of the source file the address corresponds to.

③ for other rows, the corresponding address is obtained by the debug symbol.

The first step can be accomplished by acquiring the value of the EIP register, which is explained in the fourth article and is not repeated here. Here's how to implement a second and a third step.

Get source file and line number

In the debug symbol, the address of each line of source code is recorded. The Dbghelp SymGetLineFromAddr64 function allows you to get the source file path and line number from the address. The declaration of this function is as follows:

1 BOOL WINAPI SymGetLineFromAddr64 (
2 HANDLE hprocess,
3 DWORD64 dwaddr,
4 Pdword Pdwdisplacement,
5 Pimagehlp_line64 Line
6);

The hprocess parameter is the identifier of the symbol processor, and DWADDR is the address of the directive. Pdwdisplacement is an output parameter that gets the offset, in bytes, of the dwaddr relative to the start address of the row it is in. This parameter is required because one line of code may correspond to multiple assembly instructions, and it is possible to know where the next instruction to execute is located in this line of code. For example, int b = 3 * A + A; this line of code corresponds to the following assembly directives:

1 8B F8 mov eax,dword ptr [a]
2 6B C0 Imul eax,eax,3
3 F8 add Eax,dword ptr [a]
4. EC mov dword ptr [B],eax

If the SYMGETLINEFROMADDR64 function is called with the address of these four instructions respectively, then the values returned by Pdwdisplacement are 0,3,6 and 9, respectively.

The fourth parameter is a pointer to the IMAGEHLP_LINE64 struct, which is used to hold information about the row, which is declared as follows:

1 typedef struct _IMAGEHLP_LINE64 {
2 DWORD sizeofstruct;
3 PVOID Key;
4 DWORD linenumber;
5 Ptstr FileName;
6 DWORD64 Address;
7} imagehlp_line64, *pimagehlp_line64;

The Sizeofstruct field holds the size of the struct, and the field needs to be initialized before calling SymGetLineFromAddr64, or the function call will fail. The key field is reserved by the operating system and we do not need to use it. The filename and LineNumber fields are the absolute path and line number of the source file, respectively. Address is the start of the line.

Note that the filename field is a pointer to a string, and the storage space for the string does not need to be allocated by ourselves, and we do not need to release the memory that the pointer points to. In fact, this pointer points to somewhere inside the debug symbol, we can read the data, but we can't modify the data, and once the data is modified, other dbghelp functions may have strange problems. If you must modify the string, copy it to a different place before doing so. I wonder why this field is not a pctstr type, so you don't have to worry about the string being modified.

There are two success criteria for calling SymGetLineFromAddr64: one is that the module where the value of DWADDR is loaded into the symbol processor through the SYMLOADMODULE64 function The second is that the module contains the debug symbol information required by the SYMGETLINEFROMADDR64. If the first condition is not met, GetLastError returns 126, and if the second condition is not met, GetLastError returns 487.

Here is an example of calling SymGetLineFromAddr64:

1//Get EIP
2 context context;
3 Getdebuggeecontext (&context);
4
5//Get source files and line information
6 Imagehlp_line64 Lineinfo = {0};
7 lineinfo.sizeofstruct = sizeof (Lineinfo);
8 DWORD displacement = 0;
9
Ten if (SymGetLineFromAddr64 (
Getdebuggeehandle (),
The context. Eip
&displacement,
&lineinfo) = = FALSE) {
15
DWORD ErrorCode = GetLastError ();
17
Switch (errorCode) {
19
20//126 indicates that the module information has not yet been loaded via SymLoadModule64
Case 126:
Std::wcout << TEXT ("Debug info in current module have not loaded.") << Std::endl;
The return;
24
25//487 indicates that the module does not have debug symbols
Case 487:
Std::wcout << TEXT ("No debug info in current module.") << Std::endl;
return;
29
Default:
Std::wcout << TEXT ("SymGetLineFromAddr64 failed:") << errorCode << Std::endl;
return;
33}
34}

Get the address of a row

The source file and line number of the instruction can be obtained through SymGetLineFromAddr64, then can we get the address of the line according to the source file path and line number? Of course, the SYMGETLINEFROMNAME64 function is used for this purpose. The declaration of this function is as follows:

1 BOOL WINAPI SymGetLineFromName64 (
2 HANDLE hprocess,
3 Pctstr ModuleName,
4 Pctstr FileName,
5 DWORD Dwlinenumber,
6 Plong Lpdisplacement,
7 Pimagehlp_line64 Line
8);

This function is similar to SYMGETLINEFROMADDR64, which returns the information of the row through the imagehlp_line64 struct, and has a displacement output parameter, but the meaning of this parameter in two functions is very different, the following will be described in detail. First look at the meaning of the other parameters.

The modulename is used to specify the name of the module, and the ModuleName parameter mentioned in the previous article explaining the SYMLOADMODULE64 function can be used in this place (oddly, the modulename parameter of SymLoadModule64 is the PCSTR type , while SymGetLineFromName64 's modulename parameter is the PCTSTR type). When the filename parameter specifies only a file name, and multiple modules contain a source file with the same name, SYMGETLINEFROMNAME64 uses this parameter to determine which module's source file to use. If each module does not have a source file with the same name, or if filename specifies an absolute path, this parameter is not necessary and is specified as null.

The filename and Dwlinenumber parameters specify the source file and line number, respectively. FileName can be either a file name or an absolute path, as described above. Dwlinenumber is any non-0 value, even if the line number does not exist in the source file, even if it is negative, SYMGETLINEFROMNAME64 will return true! So how do we know if the specified line number is valid? Just check the value of the displacement. In most cases, displacement represents the difference between a specified row and the line number of a valid row closest to the row, and the line number of the valid row is less than or equal to the line number of the specified row. You can use the following expression (the variable in the formula uses the name of the function parameter):

*lpdisplacement = Dwline-line->linenumber (dwline >= line->linenumber)

The so-called valid line is the ability to generate assembly instruction line (can produce assembly instructions to have the corresponding address), such as int a = 1 + 1, is a valid row, and int A; and a blank line is not a valid row. Use the following code as an example to illustrate:

1 int wmain (int argc, wchar_t** argv) {
2
3 int a = 1 + 1;
4
5
6
7 int b = 2 + 2;
8
9 return 0;
10}

①dwline = 2 o'clock, Line->linenumber = 1,*lpdisplacement = 1.

②dwline = 4, 5, 6 o'clock, line->linenumber = 3,*lpdisplacement = 1, 2, 3.

③dwline = 7 o'clock, Line->linenumber = 7,*lpdisplacement = 0.

④dwline = 12 o'clock, Line->linenumber = 10,*lpdisplacement = 2.

As can be seen from the fourth example, if the specified line number is greater than the number of rows in the source file, the function returns the information for the last row of valid rows, displacement the difference between the specified line number and the valid line number, as well as the above formula.

If Dwline is 0, then SymGetLineFromName64 returns False,getlasterror returns 1168. Oddly, Dwline can also be called successfully for negative numbers, when the function returns information for the last row of valid rows, displacement is Int_max + dwline.

In summary, to determine whether the specified row is a valid row, just check whether displacement is 0.

Sample code

Well, you know how to get the line number and the address of the line can be implemented to display the source code, detailed methods refer to the sample code. When using this feature, be aware that the source file must be synchronized with the debugger and debug symbols, and if you modify the source code without recompiling the link, the displayed code is definitely wrong.

Now a command is added to the Minidebugger:

l [after] [before]

Displays the line that is currently executing and the code that is nearby. After specifies how many lines are displayed after the current line of code, before specifies how many lines in front of the current line of code are displayed. If omitted, the default value is 10.

If you execute the L command immediately after the Execute S command starts the debug process, you get the error message "SymGetLineFromAddr64 Failed:6" because the symbol processor is not created at this time. You can use the L command only after you have executed the G command at least once.

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

[Win32] Implementation of a debugger (vi) Display source code

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.