Title: Find the wrong bank only by the crash address (11 thousand words) Sender: Lao Luo Time: 2003-2-7 14:01:56 Detailed information:
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, I must 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 want to set compilation and connection parameters, I usually do: 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 into makename to enter Makem FileName in the command line to compile generation EXE executive files and Map files.
Here, I will first explain the meaning of the join parameters: / zd means generating row information / map [: filename] when compiling, indicating that the path and file name / mapinfo: Lines indicate to generate the MAP file, add row information. / mapInfo: Exports When generating a map file, add Exported Functions (if the DLL file is generated, this option is plus) OK, through the above steps, we have got the map file, then how should we take it? Let us start from simple instances, please open your VC, create such a file: 01 // *************************** ************************************ 02 // Program Name: Demonstrate how to find the source by crash address the offending line of code 03 // author: Luo Cong 04 // date: 2003-2-705 // source: http: //www.luocong.com (Luo colorful world) 06 // this program will have a " Except for 0 errors, "illegal operation" dialog box pops up. 07 // "Except 0 Error" will only be generated under the Debug version, this program is as simple as possible for demos. 08 // Notes: If you want to reprint, keep the procedure complete, and indicate: 09 // Reprinted from "Lao Luo" (http://www.luoocong.com) 10 // *** *********************************************************** *********** 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} It is clear that 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: (Since the content is too long, some of the middle barters I have omitted) CrashDemo TimeStamp IS 3E430A76 (Fri Feb 07 09:23:02 2003) Preferred Load Address IS 00400000 Start Length Name Class 0001 : 00000000 0000de04H .text CODE 0001: 0000de04 0001000cH .textbss CODE 0002: 00000000 00001346H .rdata DATA 0002: 00001346 00000000H .edata DATA 0003: 00000000 00000104H .CRT $ XCA DATA 0003: 00000104 00000104H .CRT $ XCZ DATA 0003: 00000208 00000104H. CRT $ XIA DATA 0003: 0000030c 00000109H .CRT $ XIC DATA 0003: 00000418 00000104H .CRT $ XIZ DATA 0003: 0000051c 00000104H .CRT $ XPA DATA 0003: 00000620 00000104H .CRT $ XPX DATA 0003: 00000724 00000104H .CRT $ XPZ DATA 0003 : 00000828 00000104H .CRT $ Xta Data 0003: 0000092C 00000104H .CRT $ x x d d 0003: 00000a30 000000b93h .data data 0003: 000015c4 00001974H .bss DATA 0004: 00000000 00000014H .idata $ 2 DATA 0004: 00000014 00000014H .idata $ 3 DATA 0004: 00000028 00000110H .idata $ 4 DATA 0004: 00000138 00000110H .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 0042413c 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 0042414c 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: K ERNEL32.dll 0004: 0000015c __imp__LoadLibraryA @ 4 0042415c 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 0042416c 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 0042417c 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 0042418c 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 0042419c kernel32: KERNEL32.dll 0004: 000001a0 __imp__VirtualFree @ 12 004241a0 kernel32: KERNEL32.dll 0004: 000001a4 __imp__RtlUnwind @ 16 004241a4 kernel32: KERNEL32.dll 0004: 000001a8 __imp__GetLastError @ 0 004241a8 kernel3 2: KERNEL32.dll 0004: 000001ac __imp__SetConsoleCtrlHandler @ 8 004241ac kernel32: KERNEL32.dll 0004: 000001b0 __imp__IsBadWritePtr @ 8 004241b0 kernel32: KERNEL32.dll 0004: 000001b4 __imp__IsBadReadPtr @ 8 004241b4 kernel32: KERNEL32.dll 0004: 000001b8 __imp__HeapValidate @ 12 004241b8 kernel32: KERNEL32.dll 0004: 000001bc __imp__GetCPInfo @ 8 004241bc kernel32: KERNEL32.dll 0004: 000001c0 __imp__GetACP @ 0 004241c0 kernel32: KERNEL32.dll 0004: 000001c4 __imp__GetOEMCP @ 0 004241c4 kernel32: KERNEL32.dll 0004: 000001c8 __imp__HeapAlloc @
12 004241c8 kernel32: KERNEL32.dll 0004: 000001cc __imp__VirtualAlloc @ 16 004241cc kernel32: KERNEL32.dll 0004: 000001d0 __imp__HeapReAlloc @ 16 004241d0 kernel32: KERNEL32.dll 0004: 000001d4 __imp__MultiByteToWideChar @ 24 004241d4 kernel32: KERNEL32.dll 0004: 000001d8 __imp__LCMapStringA @ 24 004241d8 kernel32: KERNEL32.dll 0004: 000001dc __imp__LCMapStringW @ 24 004241dc kernel32: KERNEL32.dll 0004: 000001e0 __imp__GetStringTypeA @ 20 004241e0 kernel32: KERNEL32.dll 0004: 000001e4 __imp__GetStringTypeW @ 16 004241e4 kernel32: KERNEL32.dll 0004: 000001e8 __imp__SetFilePointer @ 16 004241e8 kernel32: KERNEL32.dll 0004: 000001ec __imp__SetStdHandle @ 8 004241ec kernel32: KERNEL32.dll 0004: 000001f0 __imp__FlushFileBuffers @ 4 004241f0 kernel32: KERNEL32.dll 0004: 000001f4 __imp__CloseHandle @ 4 004241f4 kernel32: KERNEL32.dll 0004: 000001f8 / 177KERNEL32_NULL_THUNK_DATA 004241f8 kernel32 : KERNEL32.dll entry 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: 00000046 17 0001: 00000050 21 0001: 00000070 21 0001: 00000088 22 0001: 0000008D If you carefully browse the RVA Base this column, you will find the first function address of the first than the crash address 0x0040104a is 0x00401070, so at 0x00401070 The previous entrance is a function that creates a crash, that is, this line: 0001: 00000020? Crash @@ yaxxz 00401020 f crashDemo.obj Therefore, a function of crash is? Crash @@ yaxxz, all the function names starting with the question mark C modified name. 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 code line is in the offset 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 operation: crash offset = crash address - the base address - 0x1000 Why do you want 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 the code line information of the map file will see, it will see the calculation result, but the most The approach is the crashdemo.cpp file: 16 0001: 00000046 is the 16th line in the source code, let us take a look at the source code: 16 I / = j; Ha! ! ! Sure enough, it is the 16th line! Excited? me too! :) The method has been introduced. From now, we can accurately position the collapse line in the source code, and as long as the compiler can generate the MAP file (including VC, MASM, VB, BCB, Delphi ...), this method It is suitable. 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. Is it very cool? :) Lao Luo 2003-2-7Copyright © 2000-2003 Watching the Snow Academy (www.pediy.com) All Rights Reserved.