This is transferred from "VC Programming Experience Summary 7"
Borrowing the flowers - how to find an error by crash address
As a programmer, what do we usually have to see? Is it a memory leak? Is it a look at the interface? ...... wrong! I believe that my opinion is that there will be no objection - that is, the program has crashed!
"The program performs illegal operations, which is about to be closed. Please contact your software supplier.", Huh, this sentence "famous saying", I am afraid that the programmer is the most worried thing. Sometimes, your own procedure runs well on his own machine, but it has collapsed on the machine's machine; sometimes he is illegally operated in the process of writing and testing, but it can't be determined. Where is the source code ... isn't it very painful? Don't matter, this article can help you get out of this dilemma, or even you can proudly ask the user to tell you the crash address, then you can accurately locate the error in the source code. (Very magical? Oh.)
First of all, I have to emphasize that this method can be used on any compiler on the current market. But I am only familiar with the M $ VC and MASM, so the following sections only describe how to implement in these two compilers, and the readers will be able to integrate through and master the methods used on other compilers.
Well, nonsense, let us start! :)
First, you must generate the MAP file of the program. What is a MAP file? Simply put, the Map file is the unique text representation method for the global symbol of the program, the source file, and the code line number information, which can be used anywhere, using, no need for additional programs. Moreover, this is the only residence that can find out where the program crashes.
Ok, since the Map file is so amazing, how should we generate it? In the VC, we can press Alt F7, open the "Project Settings" option page, select the C / C tab, and enter: / zd in the bottom Project Options, then select the Link tab, at the bottom Inside the Project Options input: / mapinfo: lines and /map:project_name.map. Finally press F7 to compile generation EXE executive files and MAP files.
In Masm, we have to set compilation and connection parameters, I usually do this:
RC% 1.rcml / c / coff / zd% 1.asmlink / subsystem: windows / mapinfo: exports / mapinfo: lines / map:%1.map% 1.obj% 1.RES
To save it as makem.bat, you can enter Makem FileName on the command line to compile the generation EXE executive file and the Map file.
Here, I will explain the meaning of the join parameters:
/ Zd indicates that the row information / map [: filename] represents the path and file name / mapinfo: Lines represents the MAP file when it is generated, when the MAP file is generated, add the MAP file when adding the MAP file when adding the MAP file when generating the MAP file. Functions (if the DLL file is generated, this option is added)
OK, through the above steps, we have already got a map file, then how should we take it?
Let us start from simple instances, please open your VC, create such a file: 01 file: // ************************* *********************************************** 02 file: // Program Name: Demonstrate how to crash address to find out the source of the offending line 03 file: // author: Luo Cong 04 file: // date: 2003-2-705 file: // source: http: //www.luocong.com (Luo colorful world 06 File: // This program generates "except 0 errors" to pop up the "illegal operation" dialog box. 07 file: // "Except 0 Error" will only be generated under the Debug version, and this program is as simple as possible for demonstration. 08 File: // Notes: If you want to reprint, keep the procedure complete, and indicate: 09 file: // Reprinted from "Lao Luo" (http://www.luocong.com) 10 File : // **************************************************************** ***************** 11 12 Void Crash (void) 13 {14 I = 1; 15 INT J = 0; 16 I / = J; 17} 18 19 Void Main (void) 20 {21 Crash (); 22}
Obviously, this program has "except 0 errors", compiled in the debug mode, will definitely generate "illegal operation" when running. Ok, let's run it. Sure enough, the "illegal operation" dialog appears. At this time, we click the "Details" button to record the address that generates crash - 0x0040104a on my machine.
Take a look at its MAP file: (because the content is too long, the part is not used in the middle, I will omit)
CrashDemo
TimeStamp Is 3e430a76 (Fri Feb 07 09:23:02 2003)
Preferred Load Address IS 00400000
Start Length Name Class0001: 00000000 0000de04H .text CODE0001: 0000de04 0001000cH .textbss CODE0002: 00000000 00001346H .rdata DATA0002: 00001346 00000000H .edata DATA0003: 00000000 00000104H .CRT $ XCA DATA0003: 00000104 00000104H .CRT $ XCZ DATA0003: 00000208 00000104H .CRT $ XIA DATA0003: 0000030c 00000109H .CRT $ XIC DATA0003: 00000418 00000104H .CRT $ XIZ DATA0003: 0000051c 00000104H .CRT $ XPA DATA0003: 00000620 00000104H .CRT $ XPX DATA0003: 00000724 00000104H .CRT $ XPZ DATA0003: 00000828 00000104H .CRT $ XTA DATA0003 : 0000092c 00000104H .CRT $ XTZ DATA0003: 00000a30 00000b93H .data DATA0003: 000015c4 00001974H .bss DATA0004: 00000000 00000014H .idata $ 2 DATA0004: 00000014 00000014H .idata $ 3 DATA0004: 00000028 00000110H .idata $ 4 DATA0004: 00000138 00000110H .idata $ 5 DATA0004: 00000248 000004afh .idata $ 6 DataAddress Publics by Value RVA Base Lib: Object
0001: 00000020 Crash @@ YAXXZ 00401020 f CrashDemo.obj0001:? 00000070 _main 00401070 f CrashDemo.obj0004: 00000000 __IMPORT_DESCRIPTOR_KERNEL32 00424000 kernel32: KERNEL32.dll0004: 00000014 __NULL_IMPORT_DESCRIPTOR 00424014 kernel32: KERNEL32.dll0004: 00000138 __imp__GetCommandLineA @ 0 00424138 kernel32: KERNEL32.dll0004 : 0000013c __imp__GetVersion @ 0 0042413c kernel32: KERNEL32.dll0004: 00000140 __imp__ExitProcess @ 4 00424140 kernel32: KERNEL32.dll0004: 00000144 __imp__DebugBreak @ 0 00424144 kernel32: KERNEL32.dll0004: 00000148 __imp__GetStdHandle @ 4 00424148 kernel32: KERNEL32.dll0004: 0000014c __imp__WriteFile @ 20 0042414c kernel32: KERNEL32.dll0004: 00000150 __imp__InterlockedDecrement @ 4 00424150 kernel32: KERNEL32.dll0004: 00000154 __imp__OutputDebugStringA @ 4 00424154 kernel32: KERNEL32.dll0004: 00000158 __imp__GetProcAddress @ 8 00424158 kernel32: KERNEL32.dll0004: 0000015c __imp__LoadLibraryA @ 4 0042415c kernel32: KERNEL32.dll0004: 00000160 __Imp__interlockedIncrement @ 4 00424160 Kernel32: kernel32.dll0004: 00000164 __ imp__GetModuleFileNameA @ 12 00424164 kernel32: KERNEL32.dll0004: 00000168 __imp__TerminateProcess @ 8 00424168 kernel32: KERNEL32.dll0004: 0000016c __imp__GetCurrentProcess @ 0 0042416c kernel32: KERNEL32.dll0004: 00000170 __imp__UnhandledExceptionFilter @ 4 00424170 kernel32: KERNEL32.dll0004: 00000174 __imp__FreeEnvironmentStringsA @ 4 00424174 kernel32: KERNEL32.dll0004: 00000178 __imp__FreeEnvironmentStringsW @ 4 00424178 kernel32: KERNEL32.dll0004: 0000017c __imp__WideCharToMultiByte @ 32 0042417c kernel32: KERNEL32.dll0004: 00000180 __imp__GetEnvironmentStrings @ 0 00424180 kernel32: KERNEL32.dll0004: 00000184 __imp__GetEnvironmentStringsW @
0 00424184 kernel32: KERNEL32.dll0004: 00000188 __imp__SetHandleCount @ 4 00424188 kernel32: KERNEL32.dll0004: 0000018c __imp__GetFileType @ 4 0042418c kernel32: KERNEL32.dll0004: 00000190 __imp__GetStartupInfoA @ 4 00424190 kernel32: KERNEL32.dll0004: 00000194 __imp__HeapDestroy @ 4 00424194 kernel32: KERNEL32. dll0004: 00000198 __imp__HeapCreate @ 12 00424198 kernel32: KERNEL32.dll0004: 0000019c __imp__HeapFree @ 12 0042419c kernel32: KERNEL32.dll0004: 000001a0 __imp__VirtualFree @ 12 004241a0 kernel32: KERNEL32.dll0004: 000001a4 __imp__RtlUnwind @ 16 004241a4 kernel32: KERNEL32.dll0004: 000001a8 __imp__GetLastError @ 0 004241a8 kernel32: KERNEL32.dll0004: 000001ac __imp__SetConsoleCtrlHandler @ 8 004241ac kernel32: KERNEL32.dll0004: 000001b0 __imp__IsBadWritePtr @ 8 004241b0 kernel32: KERNEL32.dll0004: 000001b4 __imp__IsBadReadPtr @ 8 004241b4 kernel32: KERNEL32.dll0004: 000001b8 __imp__HeapValidate @ 12 004241b8 kernel32: KERNEL32.dll0004 : 000001BC __IMP__GETCPINFO @ 8 004241BC KERNEL32: KERNEL32.DLL0004: 000001C0 __IMP__GETACP @ 0 004241C0 kernel32: KERNEL32.dll0004: 000001c4 __imp__GetOEMCP @ 0 004241c4 kernel32: KERNEL32.dll0004: 000001c8 __imp__HeapAlloc @ 12 004241c8 kernel32: KERNEL32.dll0004: 000001cc __imp__VirtualAlloc @ 16 004241cc kernel32: KERNEL32.dll0004: 000001d0 __imp__HeapReAlloc @ 16 004241d0 kernel32: KERNEL32.dll0004: 000001d4 __imp__MultiByteToWideChar @ 24 004241d4 kernel32: KERNEL32.dll0004: 000001d8 __imp__LCMapStringA @ 24 004241d8 kernel32: KERNEL32.dll0004: 000001dc __imp__LCMapStringW @ 24 004241dc kernel32: KERNEL32.dll0004: 000001e0 __imp__GetStringTypeA @ 20 004241e0 kernel32: KERNEL32.dll0004: 000001e4 __imp__GetStringTypeW @
16 004241e4 kernel32: KERNEL32.dll0004: 000001e8 __imp__SetFilePointer @ 16 004241e8 kernel32: KERNEL32.dll0004: 000001ec __imp__SetStdHandle @ 8 004241ec kernel32: KERNEL32.dll0004: 000001f0 __imp__FlushFileBuffers @ 4 004241f0 kernel32: KERNEL32.dll0004: 000001f4 __imp__CloseHandle @ 4 004241f4 kernel32: KERNEL32. DLL0004: 000001F8 / 17KERNEL32_NULL_THUNK_DATA 004241F8 KERNEL32: KERNEL32.DLLENTRY POINT AT 0001: 000000F0
Line NumBers for ./debug/crashdemo.obj (D:/msdev/myprojects/crashdemo/crashdemo.cpp) Segment .text
13 0001: 00000020 14 0001: 00000038 15 0001: 0000003F 16 0001: 0000004617 0001: 00000050 20 0001: 00000070 21 0001: 00000088 22 0001: 0000008D
If you carefully browse the RVA Base column, you will find that the first function address is 0x00401070 than the crash address 0x0040104a, so the entry before the address of this 0x00401070 is the function of crash, that is, this line:
0001: 00000020? Crash @@ yaxxz 00401020 f crashdemo.obj
Therefore, the function that crashes is what the Crash @@ yaxxz, all the function names starting with the question mark are the name of C modified. In our source program, it is a Crash () this sub function.
OK, now we will easily know the name of the function of crash, are you very exciting? Oh, don't be busy, next, the more powerful tricks will appear.
Note the last part of the Map file - line number information, which is displayed in this form:
13 0001: 00000020
The first number represents the code line number in the source code, the second number is the offset of the code line in the code segment.
If you want to find the code line number, you need to use the following formula to do some hexadecimal subtraction operations:
Crash offset = crash address - IMAGEBASE Address - 0x1000
Why do you do this? Careful friends may pay attention to the RVA Base this column, and the crash address we get is based on the offset address (RVA) base address (BASE), so the base address is reduced when the line number is calculated. Go, in general, the value of the base address is 0x00400000. In addition, since the code segment of the general PE file is started from the 0x1000 offset, the 0x1000 must also be subtracted.
Ok, I understand this, we can come to the primary school subtraction:
Crash offset = 0x0040104A - 0x00400000 - 0x1000 = 0x4a
If you browse the code row information of the map file, you will see that you don't exceed the calculation result, but the closest number is in the CrashDemo.cpp file: 16 0001: 00000046
That is, in the 16th line of the source code, let's take a look at the source code:
16 I / = j;
what! ! ! Sure enough, it is the 16th line!
Excited? me too! :)
The method has been described. From now on, we can accurately position the collapse of the source code, and as long as the compiler can generate the MAP file (including VC, MASM, VB, BCB, Delphi ...), this method is Applicable. We often complain how the products of M $ are poor, but in fact, M $ still has no intention to provide a lot of valuable information to us, but we often don't know how to use it ... I believe this, you can Confum way to face the "illegal operation" prompt. You can even ask the user to provide the address of the crash, then you can sit in the home comfortably to find the wrong line and make a correction.