This is transferred from "VC programming experience summary 7"
How to find the wrong code line by crash address
As programmers, what are we most worried about seeing? Is it a memory leak? Isn't the interface nice ... No! I believe no one will object to my opinion-that is, the program has crashed!
"The program has performed an illegal operation and will be closed soon. Please contact your software vendor. Hehe, this famous saying of M$ is probably what programmers are most worried about. Sometimes, your own program runs well on your own machine, but it crashes on someone else's machine; Sometimes in the process of writing and testing, I encounter illegal operations inexplicably, but I am not sure which line in the source code caused it ... Is it painful? Never mind, this article can help you out of this dilemma. You can even proudly ask users to tell you the crash address from now on, and then you can accurately locate the wrong line in the source code. (Isn't it amazing? Ha ha. )
First of all, I must emphasize that this method can be used on any compiler currently on the market. But I am only familiar with VC and MASM of M$, so the following part only introduces how to implement them in these two compilers, and readers can master the methods used in other compilers by themselves.
Okay, that's enough nonsense. Let's get started! :)
First, the mapping file of the program must be generated. What is a map file? Simply put, the mapping file is the only text representation of the global symbol, source file and code line number information of the program. It can be used anytime and anywhere without the support of additional programs. Moreover, this is the only savior who can find out where the program crashed.
Well, since the map file is so magical, how should it be generated? In VC, we can press Alt+F7 to open the "Project Settings" option page, select the C/C++ tab, enter: /Zd in the bottom project option, then select the Link tab, and enter: /mapinfo:lines and /map:PROJECT_NAME.map in the bottom project option. Finally, press F7 to compile and generate EXE executable files and mapping files.
In MASM, we need to set compilation and connection parameters, which 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 as makem.bat You can enter the makem file name at the command line, and compile and generate the EXE executable file and mapping file.
Let me explain the meaning of adding parameters first:
/Zd means generating row information at compile time.
/MAP[:filename] indicates the path and file name of the generated mapping file.
/MAPinfo:lines means adding line information when generating map files.
/MAPinfo:exports means to add the exported function when generating a mapping file (this option should be added if generating a DLL file).
Ok, through the above steps, we got the map file, so how do we use it?
Let's start with a simple example, please open your VC and create a new file like this:
0 1 file://* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *。
02 file:// Program name: Demonstrate how to find out the wrong source code line through crash address.
03 file://Author: Luo Cong
04 Document://Date: February 7, 2003
05 file://Source: (Lao Luo's colorful world)
06 file:// This program will generate "Divide by 0 Error", and the "Illegal Operation" dialog box will pop up.
07 file://"Divide by 0 error" will only be generated in the debugging version, in order to demonstrate this program as simple as possible.
08 Document://Note: If you need to reprint, please keep this program complete and indicate:
09 Document://Reprinted from Colorful World of Lao Luo ()
10 file:/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1 1
12 invalid crash (invalid)
13 {
14 int I = 1;
15 int j = 0;
16 I/= j;
17 }
18
19 empty main (empty)
20 {
2 1 crash ();
22 }
Obviously, this program has a "divide by 0 error", and if it is compiled in debugging mode, it will definitely produce "illegal operation" at runtime. Well, let's run it. Sure enough, the "Illegal Operation" dialog box appears. At this time, we click the "Details" button and record the address where the crash occurred-0x0040 104a on my machine.
Look at its map file again: (because the file content is too long, I omitted the useless part in the middle)
Collision demonstration
The timestamp is 3E430A76 (09: 23: 02 on February 7th, 2003).
The preferred loading address is 00400000.
Start length name category
000 1:00000000 0000de04H。 Text code
000 1:0000 de04 000 1000 ch。 Textbss code
0002:000000000000000 1346h。 Rdata
0002:0000 1346 0000000h。 Data data
0003:00000000000000 104h。 CRT$XCA data
0003:00000 104 00000 104h。 CRT$XCZ data
0003:00000208 00000 104H。 CRT$XIA data
0003:0000030c 00000 109H。 CRT$XIC data
0003:000004 18 00000 104h。 CRT$XIZ data
0003:000005 1c 00000 104h。 CRT$XPA data
0003:00000620 00000 104H。 CRT$XPX data
0003:00000724 00000 104H。 CRT$XPZ data
0003:00000828 00000 104H。 CRT$XTA data
0003:0000092c 0000 104h。 CRT$XTZ data
0003:00000a30 00000b93H。 Data data
0003:0000 15c 4 0000 1974h。 Bss data
0004:00000000 000000 14H。 Idata$2 data
0004:000000 14 000000 14H。 Idata$3 data
0004:00000028 00000 1 10H。 Idata$4 data
0004:00000 138 00000 1 10H。 Idata$5 data
0004:00000248 000004afH。 Idata$6 data
Publics is addressed by the value Rva+ base library: Object.
000 1:00000020 ? Crash @ @ yaxxz00401020fcrashdemo.obj
000 1:00000070 _ main 0040 1070 f crash demo . obj
0004:00000000 _ _ IMPORT _ DESCRIPTOR _ kernel 32 00424000 kernel 32:kernel 32 . dll
0004:000000 14 _ _ NULL _ IMPORT _ DESCRIPTOR 004240 14 kernel 32:kernel 32 . dll
0004:00000 138 _ _ imp _ _ GetCommandLineA @ 0 00424 138 kernel 32:kernel 32 . dll
0004:00000 13c _ _ imp _ _ GetVersion @ 0 00424 13c kernel 32:kernel 32 . dll
0004:00000 140 _ _ imp _ _ exit process @ 4 00424 140 kernel 32:kernel 32 . dll
0004:00000 144 _ _ imp _ _ debug break @ 0 00424 144 kernel 32:kernel 32 . dll
0004:00000 148 _ _ imp _ _ GetStdHandle @ 4 00424 148 kernel 32:kernel 32 . dll
0004:00000 14c _ _ imp _ _ WriteFile @ 20 00424 14c kernel 32:kernel 32 . dll
0004:00000 150 _ _ imp _ _ InterlockedDecrement @ 4 00424 150 kernel 32:kernel 32 . dll
0004:00000 154 _ _ imp _ _ OutputDebugStringA @ 4 00424 154 kernel 32:kernel 32 . dll
0004:00000 158 _ _ imp _ _ GetProcAddress @ 8 00424 158 kernel 32:kernel 32 . dll
0004:00000 15c _ _ imp _ _ loadlibrary a @ 4 00424 15c kernel 32:kernel 32 . dll
0004:00000 160 _ _ imp _ _ interlocked increment @ 4 00424 160 kernel 32:kernel 32 . dll
0004:00000 164 _ _ imp _ _ getmodulefilename a @ 12 00424 164 kernel 32:kernel 32 . dll
0004:00000 168 _ _ imp _ _ termin ate process @ 8 00424 168 kernel 32:kernel 32 . dll
0004:00000 16c _ _ imp _ _ GetCurrentProcess @ 0 00424 16c kernel 32:kernel 32 . dll
0004:00000 170 _ _ imp _ _ unhandledexception filter @ 4 00424 170 kernel 32:kernel 32 . dll
0004:00000 174 _ _ imp _ _ free environment stringsa @ 4 00424 174 kernel 32:kernel 32 . dll
0004:00000 178 _ _ imp _ _ free environment stringsw @ 4 00424 178 kernel 32:kernel 32 . dll
0004:00000 17c _ _ imp _ _ WideCharToMultiByte @ 32 00424 17c kernel 32:kernel 32 . dll
0004:00000 180 _ _ imp _ _ get environment strings @ 0 00424 180 kernel 32:kernel 32 . dll
0004:00000 184 _ _ imp _ _ GetEnvironmentStringsW @ 0 00424 184 kernel 32:kernel 32 . dll
0004:00000 188 _ _ imp _ _ SetHandleCount @ 4 00424 188 kernel 32:kernel 32 . dll
0004:00000 18c _ _ imp _ _ GetFileType @ 4 00424 18c kernel 32:kernel 32 . dll
0004:00000 190 _ _ imp _ _ GetStartupInfoA @ 4 00424 190 kernel 32:kernel 32 . dll
0004:00000 194 _ _ imp _ _ heap destroy @ 4 00424 194 kernel 32:kernel 32 . dll
0004:00000 198 _ _ imp _ _ heap create @ 12 00424 198 kernel 32:kernel 32 . dll
0004:00000 19c _ _ imp _ _ heap free @ 12 00424 19c kernel 32:kernel 32 . dll
0004:00000 1a 0 _ _ imp _ _ virtual free @ 12 00424 1a 0 kernel 32:kernel 32 . dll
0004:00000 1 a4 _ _ imp _ _ RtlUnwind @ 16 00424 1 a4 kernel 32:kernel 32 . dll
0004:00000 1 A8 _ _ imp _ _ GetLastError @ 0 00424 1 A8 kernel 32:kernel 32 . dll
0004:00000 1ac _ _ imp _ _ setconsolectlhandler @ 8 00424 1ac kernel 32:kernel 32 . dll
0004:00000 1b0 _ _ imp _ _ IsBadWritePtr @ 8 00424 1b0 kernel 32:kernel 32 . dll
0004:00000 1 B4 _ _ imp _ _ IsBadReadPtr @ 8 00424 1 B4 kernel 32:kernel 32 . dll
0004:00000 1b8 _ _ imp _ _ heap validate @ 12 00424 1b8 kernel 32:kernel 32 . dll
0004:00000 1bc _ _ imp _ _ GetCPInfo @ 8 00424 1bc kernel 32:kernel 32 . dll
0004:00000 1c 0 _ _ imp _ _ geta CP @ 0 00424 1c 0 kernel 32:kernel 32 . dll
0004:00000 1 C4 _ _ imp _ _ GetOEMCP @ 0 00424 1 C4 kernel 32:kernel 32 . dll
0004:00000 1 c8 _ _ imp _ _ HeapAlloc @ 12 00424 1 c8 kernel 32:kernel 32 . dll
0004:00000 1cc _ _ imp _ _ VirtualAlloc @ 16 00424 1cc kernel 32:kernel 32 . dll
0004:00000 1 d0 _ _ imp _ _ HeapReAlloc @ 16 00424 1 d0 kernel 32:kernel 32 . dll
0004:00000 1 D4 _ _ imp _ _ MultiByteToWideChar @ 24 00424 1 D4 kernel 32:kernel 32 . dll
0004:00000 1 D8 _ _ imp _ _ LCMapStringA @ 24 00424 1 D8 kernel 32:kernel 32 . dll
0004:00000 1dc _ _ imp _ _ LCMapStringW @ 24 00424 1dc kernel 32:kernel 32 . dll
0004:00000 1 E0 _ _ imp _ _ getstring typea @ 20 00424 1 E0 kernel 32:kernel 32 . dll
0004:00000 1 E4 _ _ imp _ _ getstring typew @ 16 00424 1 E4 kernel 32:kernel 32 . dll
0004:00000 1e 8 _ _ imp _ _ setfile pointer @ 16 00424 1e 8 kernel 32:kernel 32 . dll
0004:00000 1ec _ _ imp _ _ SetStdHandle @ 8 00424 1ec kernel 32:kernel 32 . dll
0004:00000 1f 0 _ _ imp _ _ FlushFileBuffers @ 4 00424 1f 0 kernel 32:kernel 32 . dll
0004:00000 1 F4 _ _ imp _ _ close handle @ 4 00424 1 F4 kernel 32:kernel 32 . dll
0004:00000 1 F8 \ 177 kernel 32 _ NULL _ THUNK _ DATA 00424 1 F8 kernel 32:kernel 32 . dll
The entry point is 000 1:000000f0.
The line number of. \ debug \ crashdemo.obj (d: \ msdev \ myprojects \ crashdemo \ crashdemo.cpp). text
13 000 1:00000020 14 000 1:00000038 15 000 1:0000003f 16 000 1:00000046
17 000 1:00000050 20 000 1:00000070 2 1:000 1:00000088 22 000 1:0000008d
If you carefully browse the Rva+Base column, you will find that the first function address greater than the crash address 0x0040 104a is 0x0040 1070, so the entry before address 0x0040 1070 is the function that caused the crash, that is, this line:
000 1:00000020 ? Crash @ @ yaxxz00401020fcrashdemo.obj
The function of the crash is. Crash @@YAXXZ, all function names starting with question marks are C++ decorated names. In our source program, it is also the subfunction Crash ().
Ok, now we know the name of the crash function easily. Are you excited? Hehe, don't be busy yet. Next, more powerful tricks will come out.
Notice the last part of the mapping file-line number information, which is displayed in the following form:
13 000 1:00000020
The first number represents the code line number in the source code, and the second number is the offset of the code line in the code segment to which it belongs.
If you want to find the code line number, you need to do some hexadecimal subtraction with the following formula:
Collapse line offset = collapse address)-image base address) -0x 1000.
Why are you doing this? Careful friends may have noticed the column Rva+Base. The crash addresses we get are all derived from Rva)+ base address, so the base address should be subtracted when calculating the line number. Usually, the value of the base address is 0x00400000. In addition, since the code segments of PE files usually start with the offset 0x 1000, 0x 1000 must also be subtracted.
Well, knowing this, we can do subtraction calculation in primary school:
Collapse line offset = 0x0040104a-0x00400000-0x1000 = 0x4a.
If you browse the code line information in the mapping file, you will see the number that does not exceed the calculation result, but the closest number is in the CrashDemo.cpp file:
16 000 1:00000046
That is 16 in the source code. Let's look at the source code:
16 I/= j;
Ha! ! ! It's really 16 line!
Excited? Me too! :)
The method is introduced. From now on, we can accurately locate the crash line in the source code, as long as the compiler can generate mapping files (including VC, MASM, VB, BCB, Delphi…… ...) ... We often complain about how poor the products of M$ are, but in fact M$ has provided us with a lot of valuable information intentionally or unintentionally, but we often don't know how to use it ... I believe so. You can even ask users to provide the crashed address, and then you can comfortably find the wrong line at home and correct it.