dwarf调试信息格式入门
一个程序的完成过程一般是编码、编译、运行的过程,当然这是一个理想的过程,所有的开发几乎都不可能是一帆风顺的,总会有些意想不到的错误,这时便需要调试,良好的调试器应该每一个程序员的必备。
那么调试器使用的调试信息是从哪里来的呢?答案简单的很,是从编译后的文件中来的(注意这里编译的时候要使用特定的编译选项,如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调试信息格式入门的更多相关文章
- DWARF调试格式的简介
DWARF调试格式的简介 Michael J. Eager, Eager Consulting Feb, 2007 翻译:吴晖 2012年2月 如果我们可以编写确保能正确工作且永远不需要调试的程序,这 ...
- 探索 DWARF 调试格式信息
https://www.ibm.com/developerworks/cn/aix/library/au-dwarf-debug-format/ 简介 DWARF(使用有属性的记录格式进行调试 )是许 ...
- 051 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 13 Eclipse下程序调试——debug入门1
051 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 13 Eclipse下程序调试--debug入门1 本文知识点: 程序调试--debug入门1 程序 ...
- 摄像头 ISP 调试的入门之谈(经验总结)
在讲述本文之前,我尽量以一个什么也不清楚的初学到入门的用词来阐述什么是 ISP 调试,以及为什么需要调试. 如果你从来都没有接触过什么是摄像头 ISP 调试,我想这个文章可以给你一些启发和关键词. 因 ...
- Google Chrome调试js入门
平常在开发过程中,经常会接触到前端页面.那么对于js的调试那可是家常便饭,不必多说.最近一直在用火狐的Firebug,但是不知道怎么的不好使了.网上找找说法,都说重新安装狐火浏览器就可以了,但是我安装 ...
- Qualcomm平台camera调试移植入门
1 camera基本代码架构 高通平台对于camera的代码组织,大体上还是遵循Android的框架:即上层应用和HAL层交互,高通平台在HAL层里面实现自己的一套管理策略:在kernel中实现se ...
- 在 Chrome DevTools 中调试 JavaScript 入门
第 1 步:重现错误 找到一系列可一致重现错误的操作始终是调试的第一步. 点击 Open Demo. 演示页面随即在新标签中打开. OPEN DEMO 在 Number 1 文本框中输入 5. 在 N ...
- GDB调试-从入门到实践
你好,我是雨乐! 在上篇文章中,我们分析了线上coredump产生的原因,其中用到了coredump分析工具gdb,这几天一直有读者在问,能不能写一篇关于gdb调试方面的文章,今天借助此文,分享一些工 ...
- gdb调试快速入门
编译指令 gcc test.c -o test -g -g是加入调试信息,加入源码信息 启动gdb调试 gdb test 进入gdb中 设置参数 set args 10 20 显示参数show age ...
随机推荐
- hihoCoder-1097-Prim
这题就是prim的板子题,不过如果用end每次初始化为-1的话,我们就不需要对于每次选中的下一个点进行判断是否选中了,因为每次外层循环第一次进入都是可以的. 然后还很 (i=1:i<=n;i++ ...
- cache支持三种pre-fetch方式:normal/pre-fetch1/pre-fetch2-way1/pre-fetch-way2
1.normal fetch ----fetch 1 cache line once 2. pre-fetch mode one ---- fetch 3 cache line once 3.pre ...
- 绑定用户id,用户权限认证
上面这个就是为了把user_id与文章关联起来 文章需要跟用户关联,所以要去文章模型中加以关联 这样就可以直接在模板中进行关联处理 权限认证 首先要创建policy php artisan make: ...
- laravel中migrate的使用
migration的使用是大大提高了我们开发的效率,数据库迁移大大的方便了我们.今天我就来给大家分享下migration 首先: laravel提供了我们一些基本的建表的规范: 表名:通常用名词+s的 ...
- (转)python之禅
凡是用过 Python的人,基本上都知道在交互式解释器中输入 import this 就会显示 Tim Peters 的 The Zen of Python,但它那偈语般的语句有点令人费解,所以我想分 ...
- 杭电 5748 Bellovin
Description Peter has a sequence and he define a function on the sequence -- , where is the length ...
- cs229_part6
part 6 接下来就是无监督学习算法了. k均值聚类 问题背景 样本集描述: \[ x\in D, x\in R^n \] 之前的有监督学习问题中,所有的x都有对应的y.但是如果我们的x没有对应的y ...
- python基础——9(迭代器、生成器)
一.迭代器 1.概念 器:包含了多个值的容器 迭代:循环反馈(一次从容器中取出一个值) 迭代器:从装有多个值的容器中一次取出一个值给外界 s = 'abcdef' ls = [1,2,3,4,5] 遍 ...
- Java-确定字符串是否包含子字符串
利用String自带的函数和正则来实现 package com.tj; public class MyClass implements Cloneable { public static void m ...
- angular controller与directive相互引用
/** * Created by Administrator on 2017/8/28. */ var app =angular.module('app',[]); app.directive('fo ...