zoukankan      html  css  js  c++  java
  • 通过JTAG对比内核启动后text/rodata段内容

    关键词:vmlinux、strip、dump、_text、__end_rodata等等。

    在日常的调试中,可能会在某些情况下踩到内核重要的数据,比如代码段或者rodata之类。

    这种情况下,需要确认这些数据是否异常。

    所谓的异常就是从DDR中读出的数据能否和vmlinux对上。

    1. 准备vmlinux数据

    原始的vmlinux文件,需要strip:

    $(CROSS_COMPILE_PREFIX)strip vmlinux -o vmlinux_stripped

    然后去掉vmlinux的0x1000头部,即一个页面。

    dd if=vmlinux_stripped of=vmlinux_stripped_noheader bs=4096 skip=1

    最终得到的文件vmlinux_stripped_noheader就是加载到内核中运行的可执行文件。

    2. 从DDR中导出数据

    连接上JTAG,然后通过dump memory将DDR中数据导出。

    dump memory kernel.bin 0x8000000 0x809c7200

     其中0x80000000是内核执行的起始地址,0x809c7200可以从System.map中获取,也即_end值。

    3. 对比数据

    3.1 确定各段数据起始和结束地址

    从下图可以看出,在内核启动之后不变的数据部分是代码段(_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

    得到的结果是:

    8026f000 T _text----------------------------------------------dump起始地址
    80629a20 T _etext---------------------------------------------text结束地址
    8062a000 R __start_rodata-------------------------------------rodata起始地址
    8077eac8 R __start_data_ro_after_init-------------------------init过程中可能改变区域起始地址
    8077eb40 R __end_data_ro_after_init---------------------------init过程中可能改变区域结束地址。
    807a6000 R __end_rodata---------------------------------------dump结束地址

    3.2 从运行设备导出text和rodata段地址

    从DDR中导出_text到__end_rodata之间的数据:

    dump memory kernel.bin 0x8026f000 0x807a6000

    3.3 从vmlinux导出源数据(text和rodata)

    从stripped之后的vmlinux中截取_text到__end_rodata之间的数据:

    dd if=vmlinux_stripped of=vmlinux_stripped_text_and_rodata bs=4096 skip=624 count=1335

    由于vmlinux还包含一个页面的头,之后才是加载到0x80000000地址的内容,所以需要从vmlinux多strip一个页面。所以dd skip数量为:

    (_text - 0x8000000)/0x1000 + 1 = (0x8026f000 - 0x80000000)/0x1000 + 1 =  0x26f + 1= 623 + 1 = 624个页面,所以共需要strip掉624个页面。

    (__end_rodata - _text)/PAGE_SIZE = (0x807a6000-0x8026f00)/0x1000 = 0x537000/0x1000 = 0x537 = 1335,所以一共需要截取1335个页面。

    4. 实际比较

    在BeyondCompare中进行二进制比较,找出异常点。

    根据BeyondCompare结果,可以看出有那几处异常,异常起始地址和结束地址是多少。

    根据BeyondComapre异常点的位置,可以倒推出vmlinux中位置,进而找到对应的符号表。

     

     上面函数resume_userspace()异常点,也和实际现场的PC指向一致。那么问题就定位为DDR数据异常。

  • 相关阅读:
    Bootstrap3 formテキストフィールド横幅の指定の仕方
    HTML豆ちしき
    iMac Termanel命令まとめ
    ちょっとした難しい言葉まとめ①
    即使痛苦,绝不止步
    Bower —— 一个Web的包管理工具
    词汇
    8.3.2018 1 Quick and dirty 快而脏的快餐
    7.26 5 优化浪漫 恋爱中的经济学
    7.26 4 印度旅馆阿鲁沙之家
  • 原文地址:https://www.cnblogs.com/arnoldlu/p/10932267.html
Copyright © 2011-2022 走看看