http://www.cnblogs.com/zqingnn/archive/2011/01/05/1926384.html
一个程序的完成过程一般是编码、编译、运行的过程,当然这是一个理想的过程,所有的开发几乎都不可能是一帆风顺的,总会有些意想不到的错误,这时便需要调试,良好的调试器应该每一个程序员的必备。
那么调试器使用的调试信息是从哪里来的呢?答案简单的很,是从编译后的文件中来的(注意这里编译的时候要使用特定的编译选项,如VC使用debug模式,GCC使用”-g”)。在编译的时候,编译器会从源文件中收集大量的信息,例如变量名、变量类型、变量所在行号、函数名、函数参数、函数的地址范围、行号和地址的对应关系等等,然后按照一种特定的格式写入到编译后的文件中。调试的时候,调试器便从文件中读取并解析这些信息,以产生人们可读性比较强的信息。简单的说,调试信息就是在机器码和对应的源代码之间建立一座桥梁,大大方便和提高了调试程序的能力。
调试信息一般都是按照什么样的格式存放的呢?主要有下面几种:stabs,COFF,PE-COFF,OMF,IEEE-695和DWARF。其中DWARF在Linux中被普遍使用,我们主要分析它。
DWARF的全称是"Debugging With Attributed Record Formats",遵从GNU FDL授权。现在已经有dwarf1,dwarf2,dwarf3三个版本。
Dwarf最初被贝尔实验室设计用来供Unix System V的sdb调试器使用,并且在1989年被Unix国际化部门的PLSIG (Programming Languages Special Interest Group)标准化成为dwarf1.0。但是dwarf1有着很多明显的缺点,于是PLSIG继续开发,改正了缺点,并加入了对C++等语言的支持,并在1990年正式公布了dwarf2的标准草案。但是稍后由于一些原因,PLSIG被解散,dwarf的开发陷入到多个并不合作的组织中间,造成dwarf2的一些实现细节要取决于特定的编译器。这种情况一直持续到1999年,开发工作受到了来自实现对HP/Inter IA-64架构提供较好支持的推动,成立了dwarf委员会,dwarf的原作者担任负责人,
开始了dwarf3的开发,并于2006年1月份推出dwarf3.0,同时为了解决分歧,dwarf委员会加入了自由标准组织,在自由标准组织与来自Linux基金会的OSDL(Open Source Development Labs)合并后,dwarf重返独立状态并创建了自己的网站:dwarfstd.org
这三个版本中,dwarf2对dwarf1的改变很大,dwarf3大多是对dwarf2的扩充。
现在dwarf已经是一种独立的标准,可以支持C、C++、JAVA、Fortran等语言。
在了解了dwarf的历史之后,来看一下如何查看dwarf所包含的调试信息内容,并在下一篇文章中介绍这些内容的具体意思。查看内容的工具常用的有四种:
1. readelf
GNU提供的二进制工具,功能很多,并不限于读dwarf信息
2. gdb
这个就不用多说了吧,^_^
3. drawfdump
是一个被打包在libdwarf内的程序
4. libdwarf
是一个封装好的C库API,用来读取dwarf信息
在这里我们主要使用readelf工具。
先写一个简单的C程序,如下:
1:  
2: int add(int, int);
3:  
4: int main()
5: ...{
6: int i, j;
7:  
8: for(i = 0; i < 100; i += 5, j = i * 5)
9: add(i, j);
10:  
11: return 0;
12: }
13:  
14: int add(int a, int b)
15: ...{
16: return a + b;
17: }
然后使用gcc –g hello.c –o hello编译。生成hello文件。
Hello文件是elf格式的,elf一般由多个节(section)组成,不熟悉的可以看前面两篇关于elf文件格式的文章。调试信息被包含在某几个节中,如果是用dwarf2格式编译的,这些节的名字一般是以.debug开头,如.debug_info,.debug_line,.debug_frame等,如果是用dwarf1格式编译的,这些节的名字一般是.debug,.line等。现在的编译器默认大多数是dwarf2格式编译,当然可以通过gcc的编译选项改变。
现在来看hello文件都包含了哪些调试信息。
首先来看都包含了哪些调试节,使用readelf –S hello命令,产生如下输出(已删一些无关内容):
[Nr] Name Type Addr Off Size 
  
[ 0] NULL 00000000 000000 000000 
  
[ 1] .text PROGBITS 00008000 008000 0006c4 
  
[ 2] .ARM.exidx ARM_EXIDX 000086c4 0086c4 000008 
  
[ 3] .data PROGBITS 000086d0 0086d0 000520 
  
[ 4] .bss NOBITS 00008bf0 008bf0 000020 
  
[ 5] .debug_aranges PROGBITS 00000000 008bf0 000020 
  
[ 6] .debug_pubnames PROGBITS 00000000 008c10 000023 
  
[ 7] .debug_info PROGBITS 00000000 008c33 0000cc 
  
[ 8] .debug_abbrev PROGBITS 00000000 008cff 00006b 
  
[ 9] .debug_line PROGBITS 00000000 008d6a 00003e 
  
[10] .debug_frame PROGBITS 00000000 008da8 000188 
  
[11] .debug_loc PROGBITS 00000000 008f30 000054 
  
[12] .ARM.attributes ARM_ATTRIBUTES 00000000 008f84 000010 
  
[13] .comment PROGBITS 00000000 008f94 000032 
  
[14] .shstrtab STRTAB 00000000 008fc6 0000ad 
  
[15] .symtab SYMTAB 00000000 00931c 000780 
  
[16] .strtab STRTAB 00000000 009a9c 000416
  
可见一共包含了17个节,其中7个调试信息的节。
在来看一下各个调试信息节包含的内容,使用readelf –w* hello命令,*是调试节名的第一个字母,如-wi就是查看.debug_info节的内容,-wl就是查看.debug_line节的内容。
对于一个调试文件,.debug_info和.debug_line节是必须有的,其他的不见得。同时也可以自己写链接脚本实现对所有节(不局限于调试节)的控制,如指定每个节的基址等。
.debug_info基本包含了一个源文件内部的大部分信息,如函数、参数、变量、类型等等,我们看一下它的输出:
The section .debug_info contains:
  
Compilation Unit @ offset 0x0:
  
Length: 200
  
Version: 2
  
Abbrev Offset: 0
  
Pointer Size: 4
  
<0><b>: Abbrev Number: 1 (DW_TAG_compile_unit)
  
DW_AT_stmt_list : 0 
  
DW_AT_high_pc : 0x8248 
  
DW_AT_low_pc : 0x81ac 
  
DW_AT_producer : GNU C 4.1.1 
  
DW_AT_language : 1 (ANSI C)
  
DW_AT_name : hello.c 
  
DW_AT_comp_dir : C:\Program Files\CodeSourcery\Sourcery G++\bin 
  
<1><5c>: Abbrev Number: 2 (DW_TAG_subprogram)
  
DW_AT_sibling : <92> 
  
DW_AT_external : 1 
  
DW_AT_name : main 
  
DW_AT_decl_file : 1 
  
DW_AT_decl_line : 5 
  
DW_AT_type : <92> 
  
DW_AT_low_pc : 0x81ac 
  
DW_AT_high_pc : 0x8214 
  
DW_AT_frame_base : 0 (location list)
  
<2><79>: Abbrev Number: 3 (DW_TAG_variable)
  
DW_AT_name : i 
  
DW_AT_decl_file : 1 
  
DW_AT_decl_line : 6 
  
DW_AT_type : <92> 
  
DW_AT_location : 2 byte block: 91 68 (DW_OP_fbreg: -24)
  
<2><85>: Abbrev Number: 3 (DW_TAG_variable)
  
DW_AT_name : j 
  
DW_AT_decl_file : 1 
  
DW_AT_decl_line : 6 
  
DW_AT_type : <92> 
  
DW_AT_location : 2 byte block: 91 6c (DW_OP_fbreg: -20)
  
<1><92>: Abbrev Number: 4 (DW_TAG_base_type)
  
DW_AT_name : int 
  
DW_AT_byte_size : 4 
  
DW_AT_encoding : 5 (signed)
  
<1><99>: Abbrev Number: 5 (DW_TAG_subprogram)
  
DW_AT_external : 1 
  
DW_AT_name : add 
  
DW_AT_decl_file : 1 
  
DW_AT_decl_line : 15 
  
DW_AT_prototyped : 1 
  
DW_AT_type : <92> 
  
DW_AT_low_pc : 0x8214 
  
DW_AT_high_pc : 0x8248 
  
DW_AT_frame_base : 0x2a (location list)
  
<2><b2>: Abbrev Number: 6 (DW_TAG_formal_parameter)
  
DW_AT_name : a 
  
DW_AT_decl_file : 1 
  
DW_AT_decl_line : 14 
  
DW_AT_type : <92> 
  
DW_AT_location : 2 byte block: 91 6c (DW_OP_fbreg: -20)
  
<2><be>: Abbrev Number: 6 (DW_TAG_formal_parameter)
  
DW_AT_name : b 
  
DW_AT_decl_file : 1 
  
DW_AT_decl_line : 14 
  
DW_AT_type : <92> 
  
DW_AT_location : 2 byte block: 91 68 (DW_OP_fbreg: -24)
.debug_line包含了所有地址和源文件行的对应信息,内容如下:
Dump of debug contents of section .debug_line:
  
Length: 58
  
DWARF Version: 2
  
Prologue Length: 30
  
Minimum Instruction Length: 2
  
Initial value of '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 Directory Table is empty.
  
The File Name Table:
  
Entry Dir Time Size Name
  
1 0 0 0 hello.c
  
Line Number Statements:
  
Extended opcode 2: set Address to 0x81ac
  
Special opcode 9: advance Address by 0 to 0x81ac and Line by 4 to 5
  
Special opcode 120: advance Address by 16 to 0x81bc and Line by 3 to 8
  
Special opcode 90: advance Address by 12 to 0x81c8 and Line by 1 to 9
  
Special opcode 88: advance Address by 12 to 0x81d4 and Line by -1 to 8
  
Advance PC by constant 34 to 0x81f6
  
Special opcode 78: advance Address by 10 to 0x8200 and Line by 3 to 11
  
Special opcode 34: advance Address by 4 to 0x8204 and Line by 1 to 12
  
Special opcode 120: advance Address by 16 to 0x8214 and Line by 3 to 15
  
Special opcode 174: advance Address by 24 to 0x822c and Line by 1 to 16
  
Special opcode 90: advance Address by 12 to 0x8238 and Line by 1 to 17
  
Advance PC by 16 to 0x8248
  
Extended opcode 1: End of Sequence

dwarf调试信息格式入门的更多相关文章

  1. DWARF调试格式的简介

    DWARF调试格式的简介 Michael J. Eager, Eager Consulting Feb, 2007 翻译:吴晖 2012年2月 如果我们可以编写确保能正确工作且永远不需要调试的程序,这 ...

  2. 探索 DWARF 调试格式信息

    https://www.ibm.com/developerworks/cn/aix/library/au-dwarf-debug-format/ 简介 DWARF(使用有属性的记录格式进行调试 )是许 ...

  3. 051 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 13 Eclipse下程序调试——debug入门1

    051 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 13 Eclipse下程序调试--debug入门1 本文知识点: 程序调试--debug入门1 程序 ...

  4. 摄像头 ISP 调试的入门之谈(经验总结)

    在讲述本文之前,我尽量以一个什么也不清楚的初学到入门的用词来阐述什么是 ISP 调试,以及为什么需要调试. 如果你从来都没有接触过什么是摄像头 ISP 调试,我想这个文章可以给你一些启发和关键词. 因 ...

  5. Google Chrome调试js入门

    平常在开发过程中,经常会接触到前端页面.那么对于js的调试那可是家常便饭,不必多说.最近一直在用火狐的Firebug,但是不知道怎么的不好使了.网上找找说法,都说重新安装狐火浏览器就可以了,但是我安装 ...

  6. Qualcomm平台camera调试移植入门

    1  camera基本代码架构 高通平台对于camera的代码组织,大体上还是遵循Android的框架:即上层应用和HAL层交互,高通平台在HAL层里面实现自己的一套管理策略:在kernel中实现se ...

  7. 在 Chrome DevTools 中调试 JavaScript 入门

    第 1 步:重现错误 找到一系列可一致重现错误的操作始终是调试的第一步. 点击 Open Demo. 演示页面随即在新标签中打开. OPEN DEMO 在 Number 1 文本框中输入 5. 在 N ...

  8. GDB调试-从入门到实践

    你好,我是雨乐! 在上篇文章中,我们分析了线上coredump产生的原因,其中用到了coredump分析工具gdb,这几天一直有读者在问,能不能写一篇关于gdb调试方面的文章,今天借助此文,分享一些工 ...

  9. gdb调试快速入门

    编译指令 gcc test.c -o test -g -g是加入调试信息,加入源码信息 启动gdb调试 gdb test 进入gdb中 设置参数 set args 10 20 显示参数show age ...

随机推荐

  1. Clover启动mbr的win7/win8

    对以传统bios安装在mbr分区的win7/WIN8也可以使用EFI引导直接进入win.首先进win提取EFI引导文件,以管理员员身份运行cmd,输入如下命令 bcdboot c:\windows / ...

  2. 一段式fsm

    //1-paragraph method to decribe FSM //Describe state transition, state output, state input condition ...

  3. LeetCode 673. Number of Longest Increasing Subsequence

    Given an unsorted array of integers, find the number of longest increasing subsequence. Example 1: I ...

  4. js request学习

    SP的内置对象在JSP页面中无须声明就可以直接使用,其内置对象常用的有Request,response,session,application,out,config,pageCOntext reque ...

  5. Linux下二进制文件安装MySQL

    MySQL 下载地址:https://dev.mysql.com/downloads/mysql/ 并按如下方式选择来下载安装包. 1. 设置配置文件/etc/my.cnmore /etc/my.cn ...

  6. vim第五章 命令行模式

    vim第五章命令行模式 技巧 27 结识vim的命令行模式 在命令行模式中执行的命令有被称作ex命令    在按/调出查找提示符或者<C-r>=访问表示寄存器时 命令行模式也被激活     ...

  7. 神经网络的BP推导过程

    神经网络的BP推导过程 下面我们从一个简单的例子入手考虑如何从数学上计算代价函数的梯度,考虑如下简单的神经网络,该神经网络有三层神经元,对应的两个权重矩阵,为了计算梯度我们只需要计算两个偏导数即可: ...

  8. Leetcode 396.旋转函数

    旋转函数 给定一个长度为 n 的整数数组 A . 假设 Bk 是数组 A 顺时针旋转 k 个位置后的数组,我们定义 A 的"旋转函数" F 为: F(k) = 0 * Bk[0] ...

  9. 【bzoj3689】异或之 可持久化Trie树+堆

    题目描述 给定n个非负整数A[1], A[2], ……, A[n].对于每对(i, j)满足1 <= i < j <= n,得到一个新的数A[i] xor A[j],这样共有n*(n ...

  10. BZOJ 2431: [HAOI2009]逆序对数列【dp】

    Description 对于一个数列{ai},如果有i<j且ai>aj,那么我们称ai与aj为一对逆序对数.若对于任意一个由1~n自然数组成的数列,可以很容易求出有多少个逆序对数.那么逆序 ...