How to Use the map file to find out which line of the source code is abnormal when the program crashes

Source: Internet
Author: User

 

(Reprinted)

As a programmer, what do we worry most about? 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 .", Well, I am afraid this M $ famous saying is something programmers are most worried about. Sometimes, your program runs well on your machine, but it crashes on another machine; sometimes you may encounter illegal operations while writing and testing, but you cannot determine which line of the source code is the cause ...... Is it painful? It doesn't matter. This article can help you out of this dilemma, and even you can proudly ask the user to tell you the address of the crash, 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. Moreover, this is the only savior that can find the place where the program crashes.

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 DLL file is generated, 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 identify the source code error line through the crash address
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 "Old Luo's colorful world" (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 0020.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 0020.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 0020.1bc Kernel32: kernel32.dll
0004: 000001c0 _ imp _ getacp @ 0 001_1c0 Kernel32: kernel32.dll
0004: 000001c4 _ imp _ getoemcp @ 0 0000001c4 Kernel32: kernel32.dll
0004: 000001c8 _ imp _ heapalloc @ 12 001_1c8 Kernel32: kernel32.dll
0004: 000001cc _ imp _ virtualalloc @ 16 0020.1cc 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 RVA + base column, you will find that the first function address is 0x00401070 larger than the crashed address 0x0040104a, so the entry before the address 0x00401070 is the function that generates the 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-base address (imagebase address)-0x1000

Why? Careful friends may be aware of the RVA + base column. The crash address we get is 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? :)

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.