debug_line中包含的是地址和源文件行之間的關系
我今天想搞清楚的是文件的C代碼和匯編代碼之間的關系:
對這塊之前一直是迷迷糊糊的,發現這個問題已經嚴重影響到bug的定位了.
之前感覺C和匯編不能一一對應起來,但是太模糊了! 什么叫做不能一一對應,到底是C能對應到某一部分的匯編,還是匯編能對應到某一部分的C,能不能說得清楚一些?
希望看到的一種現象是: 能夠從dwarf中看到, 說這部分匯編代碼就是對應的C語言中的第幾行到第幾行!~
addr2line的貌似可以解答我的疑惑.
addr2line輸入一個虛擬地址,然后addr2line會根據這個地址報告我說這個地址對應的虛擬地址是多少
[疑惑: 對於inline的函數會怎么處理呢?]
具體用法:
an accurate picture of the source program
x29在arm64中是棧幀寄存器
發現棧幀中根本就沒有!
arm64的ret指令是會改變寄存器的
b和ret,跳轉指令會改變寄存器,ret指令也會改變寄存器. 但是改變的都是x30寄存器吧? 還包括狀態寄存器!
可能CPU會
arm64的處理規范是:caller把所有的變量給准備好,按照x0到x7的方式准備好[],如果超過8個參數,會把參數放到堆棧中去,那個一個棧幀到底是指什么?
下面這段代碼用來考察arm64的棧幀:(該代碼很簡單,但是包含了傳參的復雜場景,包括形參多於8個,此時會涉及到寄存器不夠用的情況.並且涉及到返回值很大)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct big{
char buf[64];
int i;
};
int func(int a, int b, int c, int d, int e,
int f, int g, int h, int i, int j) {
return a+b+c+d+e+f+g+h+i+j;
}
struct big funb() {
struct big big_buf;
big_buf.i = func(1,2,3,4,5,6,7,8,9,10);
return big_buf;
}
int funa(int a)
{
return a+1;
}
int fun(int a)
{
int b, c;
b = a+2;
c = funa(1);
return a+b+c;
}
int main()
{
int i;
struct big big_buf;
big_buf = funb();
i = big_buf.i;
return fun(i);
}
debug_line中的信息, 一臉蒙.這個段說是C與匯編的對應, 但是根本就沒看出來呀!
Raw dump of debug contents of section .debug_line: Offset: 0x0 長度: 62 DWARF 版本: 2 Prologue Length: 29 最小指令長度: 1 “is_stmt”的初始值: 1 Line Base: -5 Line Range: 14 Opcode Base: 13 Opcodes: Opcode 1 has 0 args Opcode 2 has 1 args Opcode 3 has 1 args Opcode 4 has 1 args Opcode 5 has 1 args Opcode 6 has 0 args Opcode 7 has 0 args Opcode 8 has 0 args Opcode 9 has 1 args Opcode 10 has 0 args Opcode 11 has 0 args Opcode 12 has 1 args 目錄表為空。 The File Name Table (offset 0x1c): 條目 目錄 時間 大小 名稱 1 0 0 0 test.c Line Number Statements: [0x00000027] Extended opcode 2: set Address to 0x4004f6 [0x00000032] Special opcode 10: advance Address by 0 to 0x4004f6 and Line by 5 to 6 [0x00000033] Special opcode 104: advance Address by 7 to 0x4004fd and Line by 1 to 7 [0x00000034] Special opcode 90: advance Address by 6 to 0x400503 and Line by 1 to 8 [0x00000035] Special opcode 35: advance Address by 2 to 0x400505 and Line by 2 to 10 [0x00000036] Special opcode 161: advance Address by 11 to 0x400510 and Line by 2 to 12 [0x00000037] Special opcode 132: advance Address by 9 to 0x400519 and Line by 1 to 13 [0x00000038] Special opcode 188: advance Address by 13 to 0x400526 and Line by 1 to 14 [0x00000039] Special opcode 188: advance Address by 13 to 0x400533 and Line by 1 to 15 [0x0000003a] Special opcode 35: advance Address by 2 to 0x400535 and Line by 2 to 17 [0x0000003b] Special opcode 119: advance Address by 8 to 0x40053d and Line by 2 to 19 [0x0000003c] Special opcode 147: advance Address by 10 to 0x400547 and Line by 2 to 21 [0x0000003d] Advance PC by 2 to 0x400549 [0x0000003f] Extended opcode 1: 序列結束
dwarf 只記錄整個匯編代碼中最關機的部分,
什么是最關鍵的部分呢? 其實匯編代碼大部分和C代碼是無關的,比如說寄存器現場的保存, 變量的讀取等, 都不是最核心的代碼, 什么是最核心的代碼?
核心的代碼是要能和C語言對應起來的代碼! 想想dwarf的出現真是牛逼!
因為dwarf能從另一個角度看C代碼: 變量的聲明與定義這個與我們平常定位問題是無關的, 所謂的匯編與C對應, 其實就是可執行代碼!
可執行代碼包括:賦值與計算! 應該就這么兩類了!(突然感覺層次好高~~~)
那么這里就涉及到一個難題, 通常C代碼的一行可能對應着匯編代碼的多行,這個在dwarf中是怎么處理的?
突然感覺dwarf做了一件很人工智能的事情, 意義不亞於谷歌翻譯!
從匯編到C語言代碼段的翻譯,不簡單!
如果類比成谷歌翻譯, 那么就是概率性的問題了, dwarf翻譯出來的結果也是概率性的嗎?
發現這樣一個規律 debug_line中只針對這樣幾處C代碼:
1) 是計算的部分; 2)函數頭函數尾 ||| 也就是過濾掉了變量的聲明的部分! 真是一個天大的發現
可以好好研究一下dwarf翻譯的算法:
