zoukankan      html  css  js  c++  java
  • dwarf格式解析

    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个,此时会涉及到寄存器不够用的情况.并且涉及到返回值很大)

    stp x29,x30,[sp, 0x8]!
    先修改寄存器的值, 再做
    #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翻译的算法:

  • 相关阅读:
    动态传参
    函数的介绍
    文件的操作
    send email with formatted table
    minimize and close window with customed winform
    python algorithm
    something important about docker
    book list
    which language is suitable for what to do
    Find Duplicate Items in list fast
  • 原文地址:https://www.cnblogs.com/honpey/p/5990604.html
Copyright © 2011-2022 走看看