Usage of Map Files (resend)
When I read "deep understanding of computer systems", I always see the map file, but I never understand it. Today I see a piece of relatedArticle. After all, sometimes our ide prompts that the information is not clear enough. Using map files is a good helper for debugging.
Only passCrash addressFindSource codeError line
AsProgramWhat do we worry most about seeing at ordinary times? Is memory leakage? Is the interface hard to see ?...... Wrong! I believe that there will be no objection in my opinion-that is, the program has crashed!
"This program has performed illegal operations and is about to be closed. Please contact your software supplier .", Haha, this M $"Famous saying", I'm afraid it's what programmers are most worried about. Sometimes, your program runs well on your machine, but it crashes on another machine; sometimes you encounter illegal operations while writing and testing, but you cannot determine whether the operation is the source.CodeWhich line in ...... Is it painful? It doesn't matter. This article can help you out of this dilemma, and even you can proudly ask usersCrash addressTell you, then you can precisely locate the line with errors in the source code. (Amazing, right? Haha .)
First of all, I must emphasize that this method can be used on any compiler on the market. However, I am only familiar with the VC and MASM of M $, so the subsequent sections only introduce how to implement them in these two compilers. please familiarize yourself with the methods used in other compilers.
Well, let's get started! :)
First, the map file of the program must be generated. What is a map file? In short, a map file is the unique text representation of the program's global symbols, source files, and code line numbers. It can be used anywhere and anytime, no additional programs are required. Besides, this is the only one that can findProgram crash.
Well, since the map file is so amazing, how should we generate it? In VC, we can press Alt + F7 to open the "Project Settings" option page, select the C/C ++ tab, and enter/ZD in the following project options, select the link tab and enter:/MapInfo: lines and/map: project_name.map in the following project options. Finally, press F7 to compile and generate the EXE executable file and map file.
In MASM, we need to set compilation and connection parameters. I usually do this:
RC % 1.rc
ML/C/COFF/ZD % 1.asm
Link/subsystem: Windows/MapInfo: exports/MapInfo: lines/map: % 1.map % 1.obj % 1.res
Save it as makem. bat, and you can input makem filename in the command line to compile and generate the EXE executable file and map file.
Here I will explain the meaning of the added parameters:
/ZD indicates generating row information during compilation
/Map [: Filename] indicates the path and file name of the generated map file
/MapInfo: lines indicates that line information is added when a map file is generated.
/MapInfo: exports indicates that exported functions is added when the map file is generated (if the generatedDLLFile, this option must be added)
OK. We have obtained the map file through the above steps. How can we use it?
Let's start with a simple instance. Open your VC and create a new file:
01 //************************************* ***************************
02 // program name: demonstrate how to use Crash address Find the source code error line
03 // Author: Luo Cong
04 // Date: 2003-2-7
05 // Source: Http://www.luocong.com (Laoluo's colorful world)
06 // This program will generate an "except 0 error", so that the "invalid operation" dialog box will pop up.
07 // "except 0 errors" will only be generated in the debug version. This program is simplified as much as possible for demonstration.
08 // Note: If you want to reprint it, please keep the program complete and note:
09 // reposted from "the colorful world of Lao Luo "( Http://www.luocong.com )
10 //************************************* ***************************
11
12 Void crash (void)
13 {
14 int I = 1;
15 Int J = 0;
16 I/= J;
17}
18
19 void main (void)
20 {
21 crash ();
22}
Obviously, this program has a "Division by 0 error". If it is compiled in debug mode, it will certainly produce "invalid operations" during runtime ". Okay. Let's run it. The "invalid operation" dialog box appears. Then, click "details, record the address that caused the crash -- on my machine it is 0x0040104a.
Let's take a look at its map file: (because the file content is too long, I omitted useless parts in the middle)
Crashdemo
Timestamp is 3e0000a76 (Fri Feb 07 09:23:02 2003)
Preferred load address is 00400000
Start length name class
0001:00000000 0000de04h. Text code
0001: include04 0001000ch. textbss code
000:00000000 00001346 H. RDATA
000:00001346 00000000 H. edata
0003:00000000 00000104 H. CRT $ xca data
0003:00000104 00000104 H. CRT $ xcz data
0003:00000208 00000104 H. CRT $ Xia data
0003: 0000030c 00000109 H. CRT $ xic data
0003:00000418 00000104 H. CRT $ xiz data
0003: 0000051c 00000104 H. CRT $ xpa data
0003: 00000620 00000104 H. CRT $ xpx data
0003: 00000724 00000104 H. CRT $ xpz data
0003: 00000828 00000104 H. CRT $ xta data
0003: 0000092c 00000104 H. CRT $ xtz data
0003: 00000a30 00000b93h. Data data
0003: 201715c4 00001974 H. BSS data
0004:00000000 00000014 H. idata $2 Data
0004:00000014 00000014 H. idata $3 data
0004:00000028 00000110 H. idata $4 Data
0004:00000138 00000110 H. idata $5 Data
0004:00000248 000004afh. idata $6 data
Address publics by value RVA + base Lib: Object
0001:00000020? Crash @ yaxxz 00401020 F crashdemo. OBJ
0001: 00000070 _ main 00401070 F crashdemo. OBJ
0004:00000000 _ import_descriptor_kernel32 00424000 Kernel32: kernel32. DLL
0004:00000014 _ null_import_descriptor 00424014 Kernel32: kernel32. DLL
0004:00000138 _ imp _ getcommandlinea @ 0 00424138 Kernel32: kernel32.DLL
0004: 0000013c _ imp _ getversion @ 0 0020.13c Kernel32: kernel32. DLL
0004:00000140 _ imp _ exitprocess @ 4 00424140 Kernel32: kernel32. DLL
0004:00000144 _ imp _ debugbreak @ 0 00424144 Kernel32: kernel32. DLL
0004:00000148 _ imp _ getstdhandle @ 4 00424148 Kernel32: kernel32. DLL
0004: 0000014c _ imp _ writefile @ 20 0020.14c Kernel32: kernel32. DLL
0004:00000150 _ imp _ interlockeddecrement @ 4 00424150 Kernel32: kernel32. DLL
0004:00000154 _ imp _ outputdebugstringa @ 4 00424154 Kernel32: kernel32.DLL
0004:00000158 _ imp _ getprocaddress @ 8 00424158 Kernel32: kernel32. DLL
0004: 0000015c _ imp _ loadlibrarya @ 4 001_15c Kernel32: kernel32. DLL
0004: 00000160 _ imp _ interlockedincrement @ 4 00424160 Kernel32: kernel32. DLL
0004: 00000164 _ imp _ getmodulefilenamea @ 12 00424164 Kernel32: kernel32. DLL
0004: 00000168 _ imp _ terminateprocess @ 8 00424168 Kernel32: kernel32. DLL
0004: 0000016c _ imp _ getcurrentprocess @ 0 0020.16c Kernel32: kernel32. DLL
0004: 00000170 _ imp _ unhandledexceptionfilter @ 4 00424170 Kernel32: kernel32.DLL
0004: 00000174 _ imp _ freeenvironmentstringsa @ 4 00424174 Kernel32: kernel32. DLL
0004: 00000178 _ imp _ freeenvironmentstringsw @ 4 00424178 Kernel32: kernel32. DLL
0004: 0000017c _ imp _ widechartomultibyte @ 32 0020.17c Kernel32: kernel32. DLL
0004: 00000180 _ imp _ getenvironmentstrings @ 0 00424180 Kernel32: kernel32. DLL
0004: 00000184 _ imp _ getenvironmentstringsw @ 0 00424184 Kernel32: kernel32. DLL
0004: 00000188 _ imp _ sethandlecount @ 4 00424188 Kernel32: kernel32. DLL
0004: 0000018c _ imp _ getfiletype @ 4 0020.18c Kernel32: kernel32.DLL
0004: 00000190 _ imp _ getstartupinfoa @ 4 00424190 Kernel32: kernel32. DLL
0004: 00000194 _ imp _ heapdestroy @ 4 00424194 Kernel32: kernel32. DLL
0004: 00000198 _ imp _ heapcreate @ 12 00424198 Kernel32: kernel32. DLL
0004: 0000019c _ imp _ heapfree @ 12 001_19c Kernel32: kernel32. DLL
0004: 000001a0 _ imp _ virtualfree @ 12 001_1a0 Kernel32: kernel32. DLL
0004: 000001a4 _ imp _ rtlunwind @ 16 0020.1a4 Kernel32: kernel32. DLL
0004: 000001a8 _ imp _ getlasterror @ 0 001_1a8 Kernel32: kernel32. DLL
0004: 000001ac _ imp _ setconsolectrlhandler @ 8 001_1ac Kernel32: kernel32. DLL
0004: 000001b0 _ imp _ isbadwriteptr @ 8 001_1b0 Kernel32: kernel32. DLL
0004: 000001b4 _ imp _ isbadreadptr @ 8 001_1b4 Kernel32: kernel32.DLL
0004: 000001b8 _ imp _ heapvalidate @ 12 001_1b8 Kernel32: kernel32. DLL
0004: 000001bc _ imp _ getcpinfo @ 8 001_1bc Kernel32: kernel32. DLL
0004: 000001c0 _ imp _ getacp @ 0 001_1c0 Kernel32: kernel32. DLL
0004: 000001c4 _ imp _ getoemcp @ 0 001_1c4 Kernel32: kernel32. DLL
0004: 000001c8 _ imp _ heapalloc @ 12 001_1c8 Kernel32: kernel32. DLL
0004: 000001cc _ imp _ virtualalloc @ 16 0000001cc Kernel32: kernel32. DLL
0004: 000001d0 _ imp _ heaprealloc @ 16 001_1d0 Kernel32: kernel32. DLL
0004: 000001d4 _ imp _ multibytetowidechar @ 24 0000001d4 Kernel32: kernel32. DLL
0004: 000001d8 _ imp _ lcmapstringa @ 24 001_1d8 Kernel32: kernel32. DLL
0004: 000001dc _ imp _ lcmapstringw @ 24 001_1dc Kernel32: kernel32.DLL
0004: 000001e0 _ imp _ getstringtypea @ 20 001_1e0 Kernel32: kernel32. DLL
0004: 000001e4 _ imp _ getstringtypew @ 16 001_1e4 Kernel32: kernel32. DLL
0004: 000001e8 _ imp _ setfilepointer @ 16 001_1e8 Kernel32: kernel32. DLL
0004: 000001ec _ imp _ setstdhandle @ 8 001_1ec Kernel32: kernel32. DLL
0004: 000001f0 _ imp _ flushfilebuffers @ 4 001_1f0 Kernel32: kernel32. DLL
0004: 000001f4 _ imp _ closehandle @ 4 0000001f4 Kernel32: kernel32. DLL
0004: 000001f8 \ 177kernel32_null_thunk_data 001_1f8 Kernel32: kernel32.DLL
Entry point at 0001: 000000f0
Line numbers for. \ debug \ crashdemo. OBJ (D: \ msdev \ myprojects \ crashdemo. cpp) segment. Text
13 0001:00000020 14 0001:00000038 15 0001: 0000003f 16 0001:00000046
17 0001:00000050 20 0001: 00000070 21 0001: 00000088 22 0001: 0000008d
If you carefully read the column RVA + base, you will find the firstCrash address0x0040104a the function address is 0x00401070, so the entry before the address 0x00401070 is a function with a crash, that is, this line:
0001:00000020? Crash @ yaxxz 00401020 F crashdemo. OBJ
So what is the function that crashes? Crash @ yaxxz. All function names starting with question marks are c ++ modified names. In our source program, this is the crash () subfunction.
OK. Now we can easily see the name of the function that crashed. Are you very excited? Well, don't be busy first. Next, more advanced moves will be available.
Pay attention to line numbers information, the last part of the map file, which is displayed in this form:
13 0001:00000020
The first number indicates the code line number in the source code, and the second number indicates the offset of the code line in the code segment to which it belongs.
To find the code row number, use the following formula to perform hexadecimal subtraction:
Crash line offset =Crash address(Crash address)-base address (imagebase address)-0x1000
Why? Careful friends may notice the column RVA + base. What we getCrash addressAll are obtained from the offset address (RVA) + base address (base). Therefore, when calculating the row number, subtract the base address. Generally, the base address value is 0x00400000. In addition, because the code segments of a PE file generally start from 0x1000 offset, 0x1000 must be subtracted.
Now that we understand this, we can perform the primary subtraction calculation:
Crash line offset = 0x0040104a-0x00400000-0x1000 = 0x4a
If you browse the code line information of the map file, you will see that the calculation result is no more than, but the nearest number is in the crashdemo. cpp file:
16 0001:00000046
That is to say, in the source code of line 16th, let's look at the source code:
16 I/= J;
Ha !!! That's exactly 16th lines!
Excited? The same is true for me! :)
The method has been introduced. From now on, we can precisely locate the crash line in the source code, and as long as the compiler can generate Map Files (including VC, MASM, VB, BCB, Delphi ......), This method is applicable. We often complain about how the product of M $ is poor, but in fact M $ still intentionally or unintentionally provides a lot of valuable information to us, but we often don't know how to use it ...... I believe that in this way, you will be more comfortable with the "illegal operations" prompt. You can even ask the user to provide the address for the crash, and then you can sit at home and comfortably find the wrong line and make corrections.
Is it nice? :)