日常調(diào)試中經(jīng)常碰到異常死機(jī)或者程序異常退出,大部分情況下依靠或者打印的異常棧,再結(jié)合異常環(huán)境下的匯編代碼匯編語言轉(zhuǎn)換成機(jī)器碼,就能解決問題。
不過如果碰到只有異常打印,以及異常PC附近的 dump,而無法找到和它對(duì)應(yīng)的匯編代碼的時(shí)候,該怎么辦呢?比如以下幾種常見情況:
幸運(yùn)的是,gcc工具鏈提供了反匯編二進(jìn)制文件的功能。我們可以借助這個(gè)功能,結(jié)合工具,來將異常棧中PC附近的機(jī)器碼轉(zhuǎn)換成匯編代碼。
?????1、提取PC附近的機(jī)器碼文本?
?
下圖是異常在ARMv8處理器上,函數(shù)里面的一個(gè)異常棧,并且dump出了內(nèi)存中PC前后各128字節(jié)的機(jī)器碼、。們可以使用文本編輯工具,將紅框里面的機(jī)器碼保存為一個(gè)文件,比如命名為inode.txt。
注意只能保留機(jī)器碼,打印log中前邊的時(shí)間戳以及PC 不能保存,否則會(huì)被后續(xù)步驟的hex工具當(dāng)做機(jī)器碼處理,造成錯(cuò)誤的結(jié)果。
2、用xxd命令將其轉(zhuǎn)換成bin文件
xxd是Linux下一個(gè)常用的hex工具。可以使用如下參數(shù)將保存的文本文件轉(zhuǎn)換成bin文件:
xxd -r -ps inode.txt inode.bin
命令中輸入為之前保存的inode.txt文件,輸出為inode.bin文件。完成上述操作之后,用hex工具打開生成的inode.bin,可以看到bin文件的內(nèi)容和inode.txt的內(nèi)容大致相似:
細(xì)心的你一定發(fā)現(xiàn)不對(duì)勁的地方了:xxd生成的bin是將text文本中的內(nèi)容按照大端格式轉(zhuǎn)換的,實(shí)際hex中dump的機(jī)器碼是小端格式,xxd命令的一個(gè)缺陷就是無法支持端格式識(shí)別,默認(rèn)只能按照大端格式去處理數(shù)據(jù)。因?yàn)锳RMv8架構(gòu)妖孽的地方在于它的指令只能是小端格式的。顯然,按照大端格式去反匯編的話,也得不到想要的結(jié)果。這個(gè)時(shí)候,我們可以再次借用命令和xxd命令,實(shí)現(xiàn)bin文件的端結(jié)構(gòu)轉(zhuǎn)換。相關(guān)操作命令如下:
-e '4 "x"' inode.bin > .txt
xxd -r -ps .txt > .bin
第一個(gè)命令使用了-e參數(shù),并且格式對(duì)是4 x的形式,將前面生成的inode.bin文件每4個(gè)字節(jié)讀入然后以16進(jìn)制的形式轉(zhuǎn)成了文本輸出,生成了.txt文件。其實(shí)這一步生成的文本文件就實(shí)現(xiàn)了端結(jié)構(gòu)的轉(zhuǎn)換。第二條xxd和前面一樣,將數(shù)據(jù)位交換了的文本文件再次轉(zhuǎn)換到.bin文件中。這樣我們得到的.bin文件就和文本文件一樣是小端格式了:
3、用工具將bin文件反匯編
得到了正確格式的bin文件匯編語言轉(zhuǎn)換成機(jī)器碼,接下來就可以使用工具來反匯編它了。命令如下:
-linux-gnu- -D -b -m .bin
就可以得到如下的匯編代碼了:
.bin: file
of .data:
00000 :
0: addx0, x19, #0x88
4: ,
8: , x19, #0x440
c:
10: , x19, #0x40
...
6c: nop
70: , [x23]
74: , 0x98
78: , x19, #0xd8
7c: b.
80: ldrx4, [x19,#40]
84: cmpx4, x20
88: b.
8c: ldrx4, [x19,#216]
90: , x4, #0xd8
94: , 0x7c
98: movx0, #0x0 // #0
...
再結(jié)合異常棧,異常時(shí)候pc的機(jī)器碼是,即上面反匯編0x80處偏移的指令,是ldr x4, [x19, #40]。即從x19寄存器加上40的偏移量去取數(shù)據(jù),x19的值是01f28,加上40之后是01f50,和異常fault地址匹配。到了這里,自然就可以愉快的分析下去了。
Tips?
ARM系列的工具支持參數(shù) -EB、-EL,所以如果異常發(fā)生在ARMv7及以前的架構(gòu)上時(shí),是可以省略掉用和xxd命令做二次端結(jié)構(gòu)轉(zhuǎn)換的操作的。直接在的命令中加上-EB或者-EL參數(shù)就能正確識(shí)別指令。
另外,命令默認(rèn)以ARM指令集來反匯編bin文件。對(duì)于crash在thumb或者指令集的代碼中的異常棧,可以在的時(shí)候增加參數(shù)--thumb,來強(qiáng)制命令使用thumb指令集反匯編bin文件。