关键词:vmlinux、strip、dump、_text、__end_rodata等等。linux
在平常的调试中,可能会在某些状况下踩到内核重要的数据,好比代码段或者rodata之类。spa
这种状况下,须要确认这些数据是否异常。调试
所谓的异常就是从DDR中读出的数据可否和vmlinux对上。code
原始的vmlinux文件,须要strip:blog
strip vmlinux -o vmlinux_stripped
而后去掉vmlinux的0x1000头部。ip
dd if=vmlinux_stripped of=vmlinux_stripped_noheader bs=4096 skip=1
最终获得的文件vmlinux_stripped_noheader就是加载到内核中运行的可执行文件。it
链接上JTAG,而后经过dump memory将DDR中数据导出。class
dump memory kernel.bin 0x8000000 0x809c7200
其中0x80000000是内核执行的起始地址,0x809c7200能够从System.map中获取,也即_end值。map
从下图能够看出,在内核启动以后不变的数据部分是代码段(_text <--> _etext)和只读数据段(__start_rodata <--> __end_data)。二进制
在System.map中找到以下几个关键地址:
... 80049000 T _text ... 806af4e8 T _etext ... 806b0000 R __start_rodata ... 80909000 R __end_rodata ...
在从_text到__end_rodata中间的数据,在整个运行期间是不会改变的。
获取上述符号对应地址的快捷方式:
grep -E " _text|_etext|__start_rodata|__end_rodata|__start_data_ro_after_init|__end_data_ro_after_init" System.map
可是存在一个特殊的RO_AFTER_INIT_DATA段,这部分数据在init初始化以后就不会改变。可是仍然和vmlinux是不同的。
#ifndef RO_AFTER_INIT_DATA #define RO_AFTER_INIT_DATA \ __start_data_ro_after_init = .; \ *(.data..ro_after_init) \ __end_data_ro_after_init = .; #endif
从DDR中导出_text到__end_rodata之间的数据:
dump memory kernel.bin 0x80049000 0x80909000
从stripped以后的vmlinux中截取_text到__end_rodata之间的数据:
dd if=vmlinux_stripped of=vmlinux_stripped_noheader bs=4096 skip=74 count=2240
0x8004900对应73个页面,可是还须要去掉1个页面的头,因此一共是74个页面。
0x80909000-0x8004900=0x8c000,即一共2240个页面。
在BeyondCompare中进行二进制比较以下: