青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

Kisser Leon

這個kisser不太冷
posts - 100, comments - 102, trackbacks - 0, articles - 0

Finding crash information using the MAP file 2

Posted on 2007-04-10 11:27 kk 閱讀(962) 評論(0)  編輯 收藏 引用 所屬分類: IT
很奇怪,cppblog居然不能發表評論了,哭。。。所以就在發一篇了哦,呵呵。
Finding crash information using the MAP file
http://m.shnenglu.com/jacky2019/archive/2007/04/09/21527.html
上文中的關于小說明的第2點是有問題的

偶又試了一次,發現lines number可能是有問題的,而且也不是我的那種算法。不過函數名肯定是對的

在vckbase中又發現一篇好文,所以就又貼過來了。不過可惜的是,還是沒能解決dll的地址映射問題,無法track到dll內的信息,可惜了。

對“僅通過崩潰地址找出源代碼的出錯行”一文的補充與改進

作者:上海偉功通信 roc

下載源代碼

  讀了老羅的“僅通過崩潰地址找出源代碼的出錯行”(下稱"羅文")一文后,感覺該文還是可以學到不少東西的。不過文中尚存在有些說法不妥,以及有些操作太繁瑣的地方 。為此,本人在學習了此文后,在多次實驗實踐基礎上,把該文中的一些內容進行補充與改進,希望對大家調試程序,尤其是release版本的程序有幫助 。歡迎各位朋友批評指正。


一、該方法適用的范圍
  在windows程序中造成程序崩潰的原因很多,而文中所述的方法僅適用與:由一條語句當即引起的程序崩潰。如原文中舉的除數為零的崩潰例子。而筆者在實際工作中碰到更多的情況是:指針指向一非法地址 ,然后對指針的內容進行了,讀或寫的操作。例如:

void Crash1()
{
char * p =(char*)100;
*p=100;
}

  這些原因造成的崩潰,無論是debug版本,還是release版本的程序,使用該方法都可找到造成崩潰的函數或子程序中的語句行,具體方法的下面還會補充說明。 另外,實踐中另一種常見的造成程序崩潰的原因:函數或子程序中局部變量數組越界付值,造成函數或子程序返回地址遭覆蓋,從而造成函數或子程序返回時崩潰。例如:

#include 
void Crash2();
int main(int argc,char* argv[])
{
Crash2();
return 0;
}
void Crash2()
{
char p[1];
strcpy(p,"0123456789");
}

在vc中編譯運行此程序的release版本,會跳出如下的出錯提示框。


圖一 上面例子運行結果

  這里顯示的崩潰地址為:0x34333231。這種由前面語句造成的崩潰根源,在后續程序中方才顯現出來的情況,顯然用該文所述的方法就無能為力了。不過在此例中多少還有些蛛絲馬跡可尋找到崩潰的原因:函數Crash2中的局部數組p只有一個字節大小 ,顯然拷貝"0123456789"這個字符串會把超出長度的字符串拷貝到數組p的后面,即*(p+1)=''1'',*(p+2)=''2'',*(p+3)=''3'',*(p+4)=4。。。。。。而字符''1''的ASC碼的值為0x31,''2''為0x32,''3''為0x33,''4''為0x34。。。。。,由于intel的cpu中int型數據是低字節保存在低地址中 ,所以保存字符串''1234''的內存,顯示為一個4字節的int型數時就是0x34333231。顯然拷貝"0123456789"這個字符串時,"1234"這幾個字符把函數Crash2的返回地址給覆蓋 ,從而造成程序崩潰。對于類似的這種造成程序崩潰的錯誤朋友們還有其他方法排錯的話,歡迎一起交流討論。


二、設置編譯產生map文件的方法
  該文中產生map文件的方法是手工添加編譯參數來產生map文件。其實在vc6的IDE中有產生map文件的配置選項的。操作如下:先點擊菜單"Project"->"Settings。。。",彈出的屬性頁中選中"Link"頁 ,確保在"category"中選中"General",最后選中"Generate mapfile"的可選項。若要在在map文件中顯示Line numbers的信息的話 ,還需在project options 中加入/mapinfo:lines 。Line numbers信息對于"羅文"所用的方法來定位出錯源代碼行很重要 ,但筆者后面會介紹更加好的方法來定位出錯代碼行,那種方法不需要Line numbers信息。


圖二 設置產生MAP文件


三、定位崩潰語句位置的方法
  "羅文"所述的定位方法中,找到產生崩潰的函數位置的方法是正確的,即在map文件列出的每個函數的起始地址中,最近的且不大于崩潰地址的地址即為包含崩潰語句的函數的地址 。但之后的再進一步的定位出錯語句行的方法不是最妥當,因為那種方法前提是,假設基地址的值是 0x00400000 ,以及一般的 PE 文件的代碼段都是從 0x1000偏移開始的 。雖然這種情況很普遍,但在vc中還是可以基地址設置為其他數,比如設置為0x00500000,這時仍舊套用

 崩潰行偏移 = 崩潰地址 - 0x00400000 - 0x1000 

的公式顯然無法找到崩潰行偏移。 其實上述公式若改為

崩潰行偏移 = 崩潰地址 - 崩潰函數絕對地址 + 函數相對偏移

即可通用了。仍以"羅文"中的例子為例:"羅文"中提到的在其崩潰程序的對應map文件中,崩潰函數的編譯結果為

0001:00000020 ?Crash@@YAXXZ 00401020 f CrashDemo。obj 

對與上述結果,在使用我的公式時 ,"崩潰函數絕對地址"指00401020, 函數相對偏移指 00000020, 當崩潰地址= 0x0040104a時, 則 崩潰行偏移 = 崩潰地址 - 崩潰函數起始地址+ 函數相對偏移 = 0x0040104a - 0x00401020 + 0x00000020= 0x4a,結果與"羅文"計算結果相同 。但這個公式更通用。


四、更好的定位崩潰語句位置的方法。
  其實除了依靠map文件中的Line numbers信息最終定位出錯語句行外,在vc6中我們還可以通過編譯程序產生的對應的匯編語句,二進制碼,以及對應c/c++語句為一體的"cod"文件來定位出錯語句行 。先介紹一下產生這種包含了三種信息的"cod"文件的設置方法:先點擊菜單"Project"->"Settings。。。",彈出的屬性頁中選中"C/C++"頁 ,然后在"Category"中選則"Listing Files",再在"Listing file type"的組合框中選擇"Assembly,Machine code, and source"。接下去再通過一個具體的例子來說明這種方法的具體操作。


圖三 設置產生"cod"文件

準備步驟1)產生崩潰的程序如下:

01 //****************************************************************
02 //文件名稱:crash。cpp
03 //作用:    演示通過崩潰地址找出源代碼的出錯行新方法
04 //作者:   偉功通信 roc
05 //日期:   2005-5-16
06//****************************************************************
07 void Crash1();
08 int main(int argc,char* argv[])
09 {
10 Crash1();
11 return 0;
12 }
13
14 void Crash1()
15 {
16  char * p =(char*)100;
17  *p=100;
18 }

準備步驟2)按本文所述設置產生map文件(不需要產生Line numbers信息)。
準備步驟3)按本文所述設置產生cod文件。
準備步驟4)編譯。這里以debug版本為例(若是release版本需要將編譯選項改為不進行任何優化的選項,否則上述代碼會因為優化時看作廢代碼而不被編譯,從而看不到崩潰的結果),編譯后產生一個"exe"文件 ,一個"map"文件,一個"cod"文件。
運行此程序,產生如下如下崩潰提示:


圖四 上面例子運行結果

排錯步驟1)定位崩潰函數。可以查詢map文件獲得。我的機器編譯產生的map文件的部分如下:

 Crash
Timestamp is 42881a01 (Mon May 16 11:56:49 2005)
Preferred load address is 00400000
Start Length Name Class
0001:00000000 0000ddf1H .text CODE
0001:0000ddf1 0001000fH .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$XTZ DATA
0003:00000a30 00000b93H .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 _main 00401020 f Crash.obj
0001:00000060 ?Crash1@@YAXXZ 00401060 f Crash.obj
0001:000000a0 __chkesp 004010a0 f LIBCD:chkesp.obj
0001:000000e0 _mainCRTStartup 004010e0 f LIBCD:crt0.obj
0001:00000210 __amsg_exit 00401210 f LIBCD:crt0.obj
0001:00000270 __CrtDbgBreak 00401270 f LIBCD:dbgrpt.obj
...

對于崩潰地址0x00401082而言,小于此地址中最接近的地址(Rva+Base中的地址)為00401060,其對應的函數名為?Crash1@@YAXXZ,由于所有以問號開頭的函數名稱都是 C++ 修飾的名稱 ,"@@YAXXZ"則為區別重載函數而加的后綴,所以?Crash1@@YAXXZ就是我們的源程序中,Crash1() 這個函數。
排錯步驟2)定位出錯行。打開編譯生成的"cod"文件,我機器上生成的文件內容如下:

 TITLE E:\Crash\Crash。cpp
.386P
include listing.inc
if @Version gt 510
.model FLAT
else
_TEXT SEGMENT PARA USE32 PUBLIC ''CODE''
_TEXT ENDS
_DATA SEGMENT DWORD USE32 PUBLIC ''DATA''
_DATA ENDS
CONST SEGMENT DWORD USE32 PUBLIC ''CONST''
CONST ENDS
_BSS SEGMENT DWORD USE32 PUBLIC ''BSS''
_BSS ENDS
$$SYMBOLS SEGMENT BYTE USE32 ''DEBSYM''
$$SYMBOLS ENDS
$$TYPES SEGMENT BYTE USE32 ''DEBTYP''
$$TYPES ENDS
_TLS SEGMENT DWORD USE32 PUBLIC ''TLS''
_TLS ENDS
; COMDAT _main
_TEXT SEGMENT PARA USE32 PUBLIC ''CODE''
_TEXT ENDS
; COMDAT ?Crash1@@YAXXZ
_TEXT SEGMENT PARA USE32 PUBLIC ''CODE''
_TEXT ENDS
FLAT GROUP _DATA, CONST, _BSS
ASSUME CS: FLAT, DS: FLAT, SS: FLAT
endif
PUBLIC ?Crash1@@YAXXZ     ; Crash1
PUBLIC _main
EXTRN __chkesp:NEAR
; COMDAT _main
_TEXT SEGMENT
_main PROC NEAR     ; COMDAT
; 9    : {
00000 55   push  ebp
00001 8b ec   mov  ebp, esp
00003 83 ec 40  sub  esp, 64   ; 00000040H
00006 53   push  ebx
00007 56   push  esi
00008 57   push  edi
00009 8d 7d c0  lea  edi, DWORD PTR [ebp-64]
0000c b9 10 00 00 00  mov  ecx, 16   ; 00000010H
00011 b8 cc cc cc cc  mov  eax, -858993460  ; ccccccccH
00016 f3 ab   rep stosd
; 10   :  Crash1();
00018 e8 00 00 00 00  call  ?Crash1@@YAXXZ  ; Crash1
; 11   :  return 0;
0001d 33 c0   xor  eax, eax
; 12   : }
0001f 5f   pop  edi
00020 5e   pop  esi
00021 5b   pop  ebx
00022 83 c4 40  add  esp, 64   ; 00000040H
00025 3b ec   cmp  ebp, esp
00027 e8 00 00 00 00  call  __chkesp
0002c 8b e5   mov  esp, ebp
0002e 5d   pop  ebp
0002f c3   ret  0
_main ENDP
_TEXT ENDS
; COMDAT ?Crash1@@YAXXZ
_TEXT SEGMENT
_p$ = -4
?Crash1@@YAXXZ PROC NEAR    ; Crash1, COMDAT
; 15   : {
00000 55   push  ebp
00001 8b ec   mov  ebp, esp
00003 83 ec 44  sub  esp, 68   ; 00000044H
00006 53   push  ebx
00007 56   push  esi
00008 57   push  edi
00009 8d 7d bc  lea  edi, DWORD PTR [ebp-68]
0000c b9 11 00 00 00  mov  ecx, 17   ; 00000011H
00011 b8 cc cc cc cc  mov  eax, -858993460  ; ccccccccH
00016 f3 ab   rep stosd
; 16   :  char * p =(char*)100;
00018 c7 45 fc 64 00
00 00   mov  DWORD PTR _p$[ebp], 100 ; 00000064H
; 17   :  *p=100;
0001f 8b 45 fc  mov  eax, DWORD PTR _p$[ebp]
00022 c6 00 64  mov  BYTE PTR [eax], 100 ; 00000064H
; 18   : }
00025 5f   pop  edi
00026 5e   pop  esi
00027 5b   pop  ebx
00028 8b e5   mov  esp, ebp
0002a 5d   pop  ebp
0002b c3   ret  0
?Crash1@@YAXXZ ENDP     ; Crash1
_TEXT ENDS
END

其中

?Crash1@@YAXXZ PROC NEAR    ; Crash1, COMDAT

為Crash1匯編代碼的起始行。產生崩潰的代碼便在其后的某個位置。接下去的一行為:

; 15   : {

冒號后的"{"表示源文件中的語句,冒號前的"15"表示該語句在源文件中的行數。 這之后顯示該語句匯編后的偏移地址,二進制碼,匯編代碼。如

00000 55   push  ebp

其中"0000"表示相對于函數開始地址后的偏移,"55"為編譯后的機器代碼," push ebp"為匯編代碼。從"cod"文件中我們可以看出,一條(c/c++)語句通常需要編譯成數條匯編語句 。此外有些匯編語句太長則會分兩行顯示如:

00018 c7 45 fc 64 00
00 00   mov  DWORD PTR _p$[ebp], 100 ; 00000064H

其中"0018"表示相對偏移,在debug版本中,這個數據為相對于函數起始地址的偏移(此時每個函數第一條語句相對偏移為0000);release版本中為相對于代碼段第一條語句的偏移(即代碼段第一條語句相對偏移為0000,而以后的每個函數第一條語句相對偏移就不為0000了)。"c7 45 fc 64 00 00 00 "為編譯后的機器代碼 ,"mov DWORD PTR _p$[ebp], 100"為匯編代碼, 匯編語言中";"后的內容為注釋,所以";00000064H",是個注釋這里用來說明100轉換成16進制時為"00000064H"。
接下去,我們開始來定位產生崩潰的語句。
第一步,計算崩潰地址相對于崩潰函數的偏移,在本例中已經知道了崩潰語句的地址(0x00401082),和對應函數的起始地址(0x00401060),所以崩潰地址相對函數起始地址的偏移就很容易計算了:

  崩潰偏移地址 = 崩潰語句地址 - 崩潰函數的起始地址 = 0x00401082 - 0x00401060 = 0x22。

第二步,計算出錯的匯編語句在cod文件中的相對偏移。我們可以看到函數Crash1()在cod文件中的相對偏移地址為0000,則

崩潰語句在cod文件中的相對偏移 =  崩潰函數在cod文件中相對偏移 + 崩潰偏移地址 = 0x0000 + 0x22 = 0x22

第三步,我們看Crash1函數偏移0x22除的代碼是什么?結果如下

 00022 c6 00 64  mov  BYTE PTR [eax], 100 ; 00000064H

這句匯編語句表示將100這個數保存到寄存器eax所指的內存單元中去,保存空間大小為1個字節(byte)。程序正是執行這條命令時產生了崩潰,顯然這里eax中的為一個非法地址 ,所以程序崩潰了!
第四步,再查看該匯編語句在其前面幾行的其對應的源代碼,結果如下:

; 17   :  *p=100;

其中17表示該語句位于源文件中第17行,而“*p=100;”這正是源文件中產生崩潰的語句。
至此我們僅從崩潰地址就查找出了造成崩潰的源代碼語句和該語句所在源文件中的確切位置,甚至查找到了造成崩潰的編譯后的確切匯編代碼!
怎么樣,是不是感覺更爽啊?


五、小節

1、新方法同樣要注意可以適用的范圍,即程序由一條語句當即引起的崩潰。另外我不知道除了VC6外,是否還有其他的編譯器能夠產生類似的"cod"文件。
2、我們可以通過比較 新方法產生的debug和releae版本的"cod"文件,查找那些僅release版本(或debug版本)有另一個版本沒有的bug(或其他性狀)。例如"羅文"中所舉的那個用例 ,只要打開release版本的"cod"文件,就明白了為啥debug版本會產生崩潰而release版本卻沒有:原來release版本中產生崩潰的語句其實根本都沒有編譯 。同樣本例中的release版本要看到崩潰的效果,需要將編譯選項改為為不優化的配置。

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲视频第一页| 欧美有码在线视频| 中文国产亚洲喷潮| 亚洲精品一区在线观看香蕉| 一区在线影院| 精品1区2区3区4区| 尤物九九久久国产精品的特点| 国产精品系列在线播放| 国产一本一道久久香蕉| 国产精品一区二区黑丝| 国产亚洲精久久久久久| 激情久久久久久久| 亚洲茄子视频| 亚洲午夜精品| 欧美自拍丝袜亚洲| 免费亚洲一区二区| 99成人精品| 久久精品亚洲乱码伦伦中文 | 久久久久久久久蜜桃| 美女免费视频一区| 国产精品乱码久久久久久| 韩国成人福利片在线播放| 一区二区日韩精品| 久久亚洲视频| 亚洲男人的天堂在线| 欧美成人精品在线播放| 国产午夜精品久久| 亚洲欧美国产制服动漫| 亚洲国产经典视频| 国产一区高清视频| 亚洲女同同性videoxma| 亚洲黄色在线观看| 久久偷窥视频| 极品少妇一区二区三区精品视频| 亚洲欧美一区二区原创| 亚洲精品一级| 一区二区三区四区五区精品视频| 国产精品成人一区二区| 久久蜜桃精品| 一区二区三区日韩精品| 久久亚洲精品欧美| 久久久久久网站| 欧美视频一区二区三区| 亚洲一级网站| 欧美电影资源| 欧美ed2k| 亚洲精品在线免费观看视频| 久久久精品动漫| 午夜激情综合网| 国产精品久久久久久久久久三级| 亚洲精品国产日韩| 韩国av一区二区三区| 午夜国产精品视频| 日韩亚洲在线| 国产精品v欧美精品v日韩精品| 日韩一级视频免费观看在线| 欧美电影免费观看高清| 免费成人网www| 亚洲精品欧美专区| 中文一区字幕| 欧美福利视频网站| 久久综合久久综合九色| 国产精品综合色区在线观看| 亚洲国产精品成人久久综合一区| 欧美日韩一区二区三区在线看| 久久久久久久999精品视频| 欧美日韩国产在线一区| 欧美va亚洲va国产综合| 国产精品视频成人| 欧美激情亚洲自拍| 亚洲国产精品久久久久| 午夜精彩视频在线观看不卡| 亚洲人成精品久久久久| 欧美在线综合| 久久国产一区二区三区| 国产欧美高清| 欧美一区二区黄色| 欧美在线高清视频| 国产欧美一区二区在线观看| 亚洲永久免费精品| 欧美一区二区在线播放| 国产精品午夜在线| 欧美一级理论片| 欧美国产日韩xxxxx| 一区二区三区三区在线| 在线精品观看| 亚洲激情一区二区| 国产精品a久久久久久| 亚洲欧美中文日韩v在线观看| 亚洲高清av在线| 在线观看国产日韩| **性色生活片久久毛片| 亚洲国产精品久久久久秋霞影院| 欧美亚男人的天堂| 欧美 日韩 国产一区二区在线视频 | 久久一区二区三区国产精品| 亚洲第一精品电影| 欧美日韩一区不卡| 欧美在线播放| 一道本一区二区| 久久青草福利网站| 欧美一级专区免费大片| 99国产精品久久久久老师| 国产日韩欧美在线| 国产精品久久一级| 欧美日韩一区二区三区在线| 久久亚洲欧美国产精品乐播| 这里只有精品视频| 一本色道久久88综合日韩精品| 欧美国产日产韩国视频| 亚洲国产精品第一区二区| 欧美黄色成人网| 欧美二区乱c少妇| 久久综合狠狠综合久久综合88 | 黄色成人av| 国产精品综合av一区二区国产馆| 国产精品视频专区| 国产精品免费电影| 国产精品视频久久| 黑丝一区二区| 亚洲激情六月丁香| 亚洲精品日日夜夜| 日韩亚洲欧美中文三级| 亚洲欧美另类在线观看| 香蕉国产精品偷在线观看不卡| 亚洲午夜在线观看| 久久精品国产77777蜜臀| 麻豆久久精品| 欧美日韩亚洲一区二区| 国产精品视频一二三| 影音先锋日韩资源| 亚洲尤物影院| 欧美 日韩 国产 一区| 日韩午夜中文字幕| 久久午夜色播影院免费高清| 欧美日韩色综合| 一区二区在线不卡| 欧美亚洲免费电影| 亚洲第一网站免费视频| 亚洲男人的天堂在线| 欧美日韩精品| 一区二区三区四区五区精品| 欧美成人自拍视频| 欧美成人dvd在线视频| 伊人婷婷欧美激情| 亚洲国产小视频在线观看| 欧美成人四级电影| 亚洲无线观看| 久久精品国产亚洲高清剧情介绍| 国产亚洲成人一区| 久久永久免费| 欧美日韩中文字幕| 欧美中文在线视频| 欧美成人一区二区三区在线观看| 国产精品福利在线| 国产日韩欧美日韩大片| 有坂深雪在线一区| 久久久久久电影| 久久爱www久久做| 欧美视频免费在线| 一本一本久久a久久精品综合妖精 一本一本久久a久久精品综合麻豆 | 亚洲无线一线二线三线区别av| 欧美96在线丨欧| 艳女tv在线观看国产一区| 国产一区二区三区在线观看免费视频| 亚洲嫩草精品久久| 久久精品99国产精品日本 | 欧美日韩国产999| 欧美一区二区黄色| 美女黄毛**国产精品啪啪| 日韩视频在线观看| 亚洲男人的天堂在线aⅴ视频| 国内成人精品2018免费看| 亚洲国产欧美日韩精品| 欧美日韩高清在线| 久久综合色婷婷| 欧美大片18| 久久人人爽人人爽爽久久| 欧美久久婷婷综合色| 久久精品国产视频| 国产精品户外野外| 亚洲国产精品成人| 国产综合久久| 亚洲欧美日韩国产综合在线| 亚洲片在线观看| 久久综合给合| 久久嫩草精品久久久精品| 国产精品爽爽爽| 亚洲精品久久久久| 日韩午夜电影在线观看| 另类欧美日韩国产在线| 久久综合久久久久88| 国语自产精品视频在线看一大j8 | 亚洲一区二区视频在线| 欧美福利视频在线观看| 亚洲精品亚洲人成人网| 91久久精品日日躁夜夜躁欧美| 另类图片国产| 一本久久a久久精品亚洲| 亚洲一区二区在线|