首页 > 其他分享 >Dwarf 调试

Dwarf 调试

时间:2024-12-28 10:30:20浏览次数:6  
标签:decl name DWARF member TAG DW 调试 Dwarf

什么是 DWARF?

DWARF(Debugging With Attributed Record Formats)是一种标准的调试信息格式,通常嵌入到二进制文件(如 ELF、Mach-O、PE 等)中。DWARF 由编译器生成,调试器使用它来提供源代码级别的调试信息,如变量名称、类型信息、源代码位置、函数调用栈等。

DWARF 格式并非特定于某一平台或架构,而是一种跨平台、跨架构的调试信息格式,广泛应用于许多操作系统和架构(如 Linux、macOS、FreeBSD、Windows 等)。

DWARF 的主要作用:

  1. 调试信息:DWARF 格式包含程序的调试信息,帮助调试器提供如下功能:

    • 显示程序的源代码和源行号。
    • 显示变量的名称、类型、作用域等信息。
    • 提供函数、类、结构体等符号的映射。
  2. 栈跟踪:DWARF 格式能描述函数调用堆栈,帮助调试器在崩溃或断点时回溯调用栈,显示程序运行过程中函数调用的关系。

  3. 程序反汇编:DWARF 也可以帮助调试器显示机器代码和源代码之间的对应关系,从而进行源代码级的调试,即使是在没有源代码的情况下,也能进行低级的调试。

DWARF 文件格式的结构:

DWARF 是基于 标签/值对 的结构,数据按块进行组织,主要包括以下几个部分:

  1. Debug Information Entries (DIEs):调试信息条目。每个 DIE 描述了程序中的一个符号(如变量、函数、类、类型等)。

  2. Attributes:每个 DIE 由多个属性(attributes)组成,属性提供了关于符号的详细信息,例如符号的名称、类型、大小等。

  3. Debug Sections:DWARF 信息存储在程序的不同段中。常见的段包括:

    • .debug_info:存储主调试信息。
    • .debug_abbrev:存储每个 DIE 所需的简略表示信息。
    • .debug_line:存储源代码的行号信息。
    • .debug_str:存储字符串(如变量名、函数名等)。
    • .debug_frame:用于描述堆栈帧信息,帮助栈展开。
  4. :DWARF 还可能包含其他类型的表,例如符号表、字符串表等,用于优化查找和存储。

如何使用 DWARF 信息?

调试器(如 GDB)通过读取二进制文件中的 DWARF 信息来执行源代码级调试。例如,使用 GDB 时,可以通过 DWARF 提供的源代码和变量信息,调试程序的执行。

例如,使用 GDB 进行调试时,GDB 会读取 DWARF 格式的调试信息,允许开发者进行以下操作:

  • 查看函数的调用栈。
  • 显示变量的值。
  • 在源代码级别单步调试。

Dwarf 示例

下面是一个简单的Dwarf示例:

首先,电脑中需要安装gcc, gcc的bin目录下一般会有objcopy, objdump这两个工具

写一个简单的C++代码,包含一个派生类,几个简单的变量

#include <stdio.h>

class CBase {
public:

    int MemberA;

    int MemberB;

    CBase() {
        MemberA = 0;
        MemberB = 0;
    }

    CBase(int a, int b) {
        MemberA = a;
        MemberB = b;
    }

};

class CDerived : public CBase {

public:

    int MemberC;

    CDerived(int a, int b, int c): CBase(a, b) {
        MemberC = c;      
    }
};

int main() {
    static CDerived d(1, 2, 3);
    int u1 = 1, u2 = 2;
    d.MemberC = (u1 + u2) * (d.MemberA - d.MemberB);
    printf("member c value: %d", d.MemberC);
    return 0;
}

用g++将它编译成exe或者elf

g++ main.cpp -o main.exe

可以用objdump命令打印它的Dwarf

objdump --dwarf=info main.exe > dump.txt

可以得到一份完整的dump文件,文件头如下所示,可以看到编译信息:

main.exe:     file format pei-x86-64

Contents of the .debug_info section:

  Compilation Unit @ offset 0:
   Length:        0x523 (32-bit)
   Version:       5
   Unit Type:     DW_UT_compile (1)
   Abbrev Offset: 0
   Pointer Size:  8
 <0><c>: Abbrev Number: 16 (DW_TAG_compile_unit)
    <d>   DW_AT_producer    : GNU C++17 14.2.0 -mtune=core2 -march=nocona -g
    <3c>   DW_AT_language    : 33	(C++14)
    <3d>   DW_AT_name        : (indirect line string, offset: 0): D:\Documents\TestDwarf\main.cpp
    <41>   DW_AT_comp_dir    : (indirect line string, offset: 0x20): D:\Documents\TestDwarf
    <45>   DW_AT_ranges      : 0xc
    <49>   DW_AT_low_pc      : 0
    <51>   DW_AT_stmt_list   : 0

对于基类,可以在dwarf信息看到类的定义,及其成员和地址偏移量

 <1><1d0>: Abbrev Number: 19 (DW_TAG_class_type)
    <1d1>   DW_AT_name        : CBase
    <1d7>   DW_AT_byte_size   : 8
    <1d8>   DW_AT_decl_file   : 2
    <1d9>   DW_AT_decl_line   : 5
    <1da>   DW_AT_decl_column : 7
    <1db>   DW_AT_sibling     : <0x253>
 <2><1df>: Abbrev Number: 9 (DW_TAG_member)
    <1e0>   DW_AT_name        : MemberA
    <1e8>   DW_AT_decl_file   : 2
    <1e8>   DW_AT_decl_line   : 8
    <1e9>   DW_AT_decl_column : 9
    <1e9>   DW_AT_type        : <0xe2>
    <1ed>   DW_AT_data_member_location: 0
    <1ee>   DW_AT_accessibility: 1	(public)
 <2><1ee>: Abbrev Number: 9 (DW_TAG_member)
    <1ef>   DW_AT_name        : MemberB
    <1f7>   DW_AT_decl_file   : 2
    <1f7>   DW_AT_decl_line   : 10
    <1f8>   DW_AT_decl_column : 9
    <1f8>   DW_AT_type        : <0xe2>
    <1fc>   DW_AT_data_member_location: 4

对于派生类,可以看到继承信息,派生类成员的地址偏移量会在基类后面

 <1><25d>: Abbrev Number: 22 (DW_TAG_class_type)
    <25e>   DW_AT_name        : (indirect string, offset: 0): CDerived
    <262>   DW_AT_byte_size   : 12
    <263>   DW_AT_decl_file   : 2
    <264>   DW_AT_decl_line   : 25
    <265>   DW_AT_decl_column : 7
    <266>   DW_AT_sibling     : <0x2b6>
 <2><26a>: Abbrev Number: 23 (DW_TAG_inheritance)
    <26b>   DW_AT_type        : <0x1d0>
    <26f>   DW_AT_data_member_location: 0
    <270>   DW_AT_accessibility: 1	(public)
 <2><271>: Abbrev Number: 9 (DW_TAG_member)
    <272>   DW_AT_name        : MemberC
    <27a>   DW_AT_decl_file   : 2
    <27a>   DW_AT_decl_line   : 29
    <27b>   DW_AT_decl_column : 9
    <27b>   DW_AT_type        : <0xe2>
    <27f>   DW_AT_data_member_location: 8
    <280>   DW_AT_accessibility: 1	(public)

对于变量,可以看到分配的地址,调试时通过地址+类型信息,可以得到变量的值
通过decl信息,则可以得到源代码的位置

 <2><381>: Abbrev Number: 11 (DW_TAG_variable)
    <382>   DW_AT_name        : d
    <384>   DW_AT_decl_file   : 2
    <384>   DW_AT_decl_line   : 38
    <385>   DW_AT_decl_column : 21
    <386>   DW_AT_type        : <0x25d>
    <38a>   DW_AT_location    : 9 byte block: 3 30 c0 0 40 1 0 0 0 	(DW_OP_addr: 14000c030)
 <2><394>: Abbrev Number: 11 (DW_TAG_variable)
    <395>   DW_AT_name        : u1
    <398>   DW_AT_decl_file   : 2
    <398>   DW_AT_decl_line   : 41
    <399>   DW_AT_decl_column : 9
    <39a>   DW_AT_type        : <0xe2>
    <39e>   DW_AT_location    : 2 byte block: 91 6c 	(DW_OP_fbreg: -20)
 <2><3a1>: Abbrev Number: 11 (DW_TAG_variable)
    <3a2>   DW_AT_name        : u2
    <3a5>   DW_AT_decl_file   : 2
    <3a5>   DW_AT_decl_line   : 41
    <3a6>   DW_AT_decl_column : 17
    <3a7>   DW_AT_type        : <0xe2>
    <3ab>   DW_AT_location    : 2 byte block: 91 68 	(DW_OP_fbreg: -24)

对更详细的dwarf信息解释,可以看官方文档

Dwarf 解析示例

某些语言的库有dwarf解析的相关sdk,如python有pyelftools用来解析Dwarf

示例代码

from elftools.elf.elffile import ELFFile
from elftools.dwarf.dwarf import DWARFError

def parse_dwarf(filename):
    # 打开 ELF 文件
    with open(filename, 'rb') as f:
        elf = ELFFile(f)

        # 查找 DWARF 部分
        if not elf.has_dwarf_info():
            print("No DWARF information found.")
            return
        
        dwarf_info = elf.get_dwarf_info()

        # 遍历 DWARF 信息
        for cu in dwarf_info.iter_CUs():  # 遍历编译单元(Compilation Unit)
            print(f"Compilation Unit: {cu.get_name()}")
            
            # 遍历调试信息条目(DIE)
            for die in cu.iter_DIEs():
                try:
                    # 打印 DIE 的类型和名称
                    if die.tag == 'DW_TAG_class_type':
                        class_name = die.attributes.get('DW_AT_name')
                        print(f"Class found: {class_name}")

                        # 打印类的成员变量(DW_TAG_member)
                        for member in die.iter_children():
                            if member.tag == 'DW_TAG_member':
                                member_name = member.attributes.get('DW_AT_name')
                                print(f"  Member: {member_name}")
                except DWARFError as e:
                    print(f"Error processing DIE: {e}")

if __name__ == "__main__":
    # 解析 DWARF 信息,假设可执行文件名为 program
    parse_dwarf('program')

运行程序后,输出如下所示:

Compilation Unit: /path/to/program
Class found: CBase
Member: MemberA
Member: MemberB
Class found: CDerived
Member: MemberC

标签:decl,name,DWARF,member,TAG,DW,调试,Dwarf
From: https://www.cnblogs.com/Asp1rant/p/18637238

相关文章

  • WireShark4.4.2浏览器网络调试指南:捕获实时流量(四)
    概述在当今高度互联的世界中,网络流量的监控和分析至关重要。随着企业网络和互联网应用的复杂性增加,IT专业人员和网络管理员需要准确的工具来评估和优化网络性能。Wireshark作为全球使用最广泛的网络协议分析工具,提供了捕获和分析实时网络流量的综合解决方案。捕获流量2.1......
  • WireShark4.4.2浏览器网络调试指南:过滤实时流量上(五)
    概述随着互联网在现代生活中的作用不断增强,网络流量的实时分析与监控已经成为保护网络安全和优化网络性能的关键环节。网络管理员和IT专业人员常常需要分析大量网络数据,以检测潜在问题或优化网络配置。Wireshark作为全球广泛使用的网络协议分析工具,其强大的数据捕获和分析功能......
  • ssm停车场管理系统8zk28(程序+源码+数据库+调试部署+开发环境)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容一、研究背景与意义随着城市化进程的加速和汽车保有量的不断增加,停车场管理面临着越来越大的挑战。传统的停车场管理方式存在效率低下、资源浪费、......
  • ssm蔬菜水果销售网站1y6qd--(程序+源码+数据库+调试部署+开发环境)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容一、项目背景与意义随着健康饮食观念的普及和互联网技术的快速发展,线上购买蔬菜水果已成为消费者的新选择。然而,当前市场上蔬菜水果销售网站众多,但......
  • ssm社区再就业管理信息系统z6zw3(程序+源码+数据库+调试部署+开发环境)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容一、课题背景与意义随着社会对就业问题的日益关注,社区再就业管理信息系统的建设变得尤为重要。该系统旨在提高再就业管理的效率,为失业人员提供更便......
  • 嵌入式系统 第五讲 开发环境和调试技术
    •5.1交叉开发模式概述•交叉开发模式:宿主机(PC机:VMware下的Ubuntu)-目标板(FS3399M4实验箱:超级终端Xshell)•GNU软件:        ①Shell:Shell基本上是一个命令解释器,类似于DOS下的command        ②glibc:glibc是GNU发布的libc库,即c运行库       ......
  • ssm体检中心管理系统vahdr(程序+源码+数据库+调试部署+开发环境)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容一、项目背景随着人们生活水平的提高和健康意识的增强,体检已成为现代人关注健康的重要方式。然而,传统的体检中心管理方式存在诸多不足,如流程繁琐、......
  • ssm实验室设备管理系统sg01u(程序+源码+数据库+调试部署+开发环境)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容一、项目背景与意义随着科技的不断进步,实验室在科研、教学等领域的作用日益凸显。然而,传统的实验室设备管理方式存在诸多不足,如设备信息记录不完整......
  • 【K8s】专题十五(6):Kubernetes 网络之 Pod 网络调试
    本文内容均来自个人笔记并重新梳理,如有错误欢迎指正!如果对您有帮助,烦请点赞、关注、转发、订阅专栏!专栏订阅入口| 精选文章 | Kubernetes |Docker|Linux |羊毛资源 | 工具推荐 |往期精彩文章【Docker】(全网首发)KylinV10下MySQL容器内存占用异常的解决......
  • TCP-UDP调试工具推荐:Socket通信测试教程(附详细图解)
    前言在网络编程与应用开发中,调试始终是一项不可忽视的重要环节。尤其是在涉及TCP/IP、UDP等底层网络通信协议时,如何确保数据能够准确无误地在不同节点间传输,是许多开发者关注的核心问题。调试的难点不仅在于定位连接建立、数据流控制及错误处理等问题,还在于快速、高效地解决这些......