2015-03-13 30 views
1

目標陣列在answer on a sister site的大小,我試圖從Linux內核陣列[email protected]/unix/af_unix.c其定義爲轉儲信息:得到了SystemTap

struct hlist_head unix_socket_table[2 * UNIX_HASH_SIZE]; 

就目前而言,我是硬編碼我的stp腳本中的陣列大小:

 
for (i = 0; i < 512; i++) 

我怎麼能避免這種情況?該信息(數組的大小)存儲在調試信息中。 gdb能告訴我:

$ gdb --batch --ex 'whatis unix_socket_table' "/usr/lib/debug/boot/vmlinux-$(uname -r)" 
type = struct hlist_head [512] 
$ gdb --batch --ex 'p sizeof(unix_socket_table)/sizeof(*unix_socket_table)' "/usr/lib/debug/boot/vmlinux-$(uname -r)" 
$1 = 512 

但我會怎麼做它systemtap? AFAICT,systemtap沒有sizeof()運營商。

回答

3

非常感謝@fche for pointing me in the right direction。正如他所說,systemtapsymdata()函數可用於檢索包含大小的給定地址處的符號信息。因此,我們可以寫我們自己的sizeof()功能解析它以提取尺寸爲:

function sizeof(address:long) { 
    tokenize(symdata(address), "/"); 
    return strtol(tokenize("",""),16); 
} 

如果我們看那個symdata()函數的定義,我們可以看到,它本身就是一個systemtap功能,它利用了_stp_snprint_addr()的C函數,它自己調用_stp_kallsyms_lookup()來檢索數據。這意味着我們也可以直接使用stp_kallsyms_lookup()定義我們自己sizeof()

function sizeof:long (addr:long) %{ /* pure */ /* pragma:symbols */ 
    STAP_RETVALUE = -1; 
    _stp_kallsyms_lookup(STAP_ARG_addr, (unsigned long*)&(STAP_RETVALUE), NULL, NULL, NULL); 
%} 

(注意,我們需要-g大師)這裏我們使用嵌入式C)。

現在,要獲得數組大小,我們需要數組元素的大小。一種方法可以是使用數組的2個元素之間的地址偏移量。因此,我們可以定義我們array_size()功能:

function array_size(first:long, second:long) { 
    return sizeof(first)/(second - first); 
} 

(其中sizeof()是一個或另一個的上面定義的函數)。

,並調用它爲:

probe begin { 
    printf("%d\n", array_size(
    &@var("[email protected]/unix/af_unix.c")[0], 
    &@var("[email protected]/unix/af_unix.c")[1])); 
    exit(); 
} 

這讓我們512預期。

對於sizeof(),另一種方法可以是使用C sizeof()操作者:

$ sudo stap -ge ' 
%{ #include <net/af_unix.h> %} 
probe begin { 
    printf("%d\n", %{ sizeof(unix_socket_table)/sizeof(unix_socket_table[0]) %}); 
    exit(); 
}' 
512 

(也需要-g),但是然後被從內核源代碼(頭文件)檢索到的信息,而不是調試信息,所以雖然這對於在頭文件中定義的內核數組來說很有效,但這種方法對於所有數組都不是必需的。

5

如果它是一個類型,@cast運營商可以使用:

size=&@cast(0,"$TYPENAME")[1] 

但很可惜,unix_socket_table不是一個類型。因此,計劃B,在變量上使用symdata(在附近的任何舊內核函數的範圍內)。

probe begin /* kernel.function("*@net/unix/af_unix.c") */ { 
    println(symdata(& @var("unix_socket_table"))) 
    exit() 
} 

結果這裏:

unix_socket_table+0x0/0x1000 [kernel] 

第二十六進制數是符號尺寸,如從在腳本處理時間的ELF符號表,相當於4096圖這裏計算:

% readelf -s /usr/lib/debug/lib/modules/`uname -r`/vmlinux | grep unix_socket_table 
71901: ffffffff82023dc0 4096 OBJECT GLOBAL DEFAULT 28 unix_socket_table 

您可以通過例如獲得數:

probe begin { 
    tokenize(symdata(@var("[email protected]/unix/af_unix.c")),"/"); 
    printf("%d\n", strtol(tokenize("",""), 16)); 
    exit() 
}