DWARF简析

  • sevaa/dwex: DWARF Explorer - a GUI utility for navigating the DWARF debug information (github.com)
  • eliben/pyelftools: Parsing ELF and DWARF in Python (github.com)
  • 8 调试信息标准: DWARF · GitBook (hitzhangjie.pro)

1.需求

通过elf获取到原文件中的相关数据定义,例如,c语言结构体,enmu,union等。

调查后可通过elf中的DWARF信息获取, DWARF信息在ELF的.debug_info段中。


2.DWARF简介

DWARF 是一种广泛使用的标准调试信息格式,最初DWARF的设计初衷是配合ELF格式使用,不过DWARF与具体的文件格式是没有依赖关系的。DWARF这个词是中世纪幻想小说中的用语,也没有什么官方含义,后来才提出 “Debugging With Attributed Record Formats” 这个术语来作为DWARF的另一种定义。

DWARF使用DIE(Debugging Information Entry)来描述变量、数据类型、代码等,DIE中包含了标签(Tag)一系列属性(Attributes)

DWARF还定义了一些关键的数据结构,如行号表(Line Number Table)调用栈信息(Call Frame Information)等,有了这些关键数据结构之后,开发者就可以在源码级别动态添加断点、显示完整的调用栈信息、查看调用栈中指定栈帧的信息。

CU - Compilation Unit

DIE - Debugging Information Entry

  • DW_TAG_xxxx: DIE的类型
  • DW_AT_XXX: DIE的属性
  • DIE也有父子关系,兄弟关系,例如:一个structure的成员变量就是structure DIE的子DIE.

3.如何解析

1.通过readelf tool

readelf -w xxx.elf

2. 通过python lib - pyelftools

使用示例:获取linux kernel module的各种structure定义。

import argparse
import json
import os
from collections import defaultdict
from typing import Optional

from elftools.dwarf.die import DIE
from elftools.elf.elffile import ELFFile
from loguru import logger

logger.add('test.log')

Map_TypePrefix = {
    'DW_TAG_base_type': '',
    'DW_TAG_structure_type': 'struct ',
    'DW_TAG_union_type': 'union ',
    'DW_TAG_pointer_type': 'pointer '
}

Map_AnonTypes = {
    'DW_TAG_subroutine_type': 'subroutine',
    'DW_TAG_pointer_type': 'pointer',
    'DW_TAG_union_type': 'union'
}


# recursive function to get type of a DIE node
def die_type_rec(die: DIE, prev: Optional[DIE]):
    t = die.attributes.get("DW_AT_type")
    if t is None:
        # logger.debug(die)
        prefix = '* ' if prev.tag == 'DW_TAG_pointer_type' else ''

        # got a type
        if die.attributes.get("DW_AT_name"):
            # common named type with prefix
            return prefix + Map_TypePrefix.get(die.tag, f'unknown: {die.tag}') \
                + die.attributes.get("DW_AT_name").value.decode()
        elif die.tag == 'DW_TAG_structure_type' and prev.tag == 'DW_TAG_typedef':
            # typedef-ed anonymous struct
            return prefix + 'struct ' + prev.attributes.get("DW_AT_name").value.decode()
        else:
            # no name types
            return prefix + Map_AnonTypes.get(die.tag, f'unknown: {die.tag}')
    elif t.form == 'DW_FORM_ref4':
        ref = t.value
        ref_die = dwarfinfo.get_DIE_from_refaddr(ref + die.cu.cu_offset)
        return die_type_rec(ref_die, die)


# recursive function to get all struct members
def die_info_rec(die: DIE, name=''):
    # logger.debug(die)
    if die.tag == 'DW_TAG_member' and die.attributes.get("DW_AT_name"):
        member_name = die.attributes.get("DW_AT_name").value.decode()
        member_type = die_type_rec(die, None)
        if die.attributes.get("DW_AT_data_member_location"):
            member_offset = die.attributes.get("DW_AT_data_member_location").value
            logger.debug('  > .{}, type: {}, offset: {}'.format(member_name, member_type, member_offset))
        elif die.attributes.get("DW_AT_bit_size") and die.attributes.get("DW_AT_data_bit_offset"):
            member_bit_size = die.attributes.get("DW_AT_bit_size").value
            member_bit_offset = die.attributes.get("DW_AT_data_bit_offset").value
            logger.debug('  > .{}, type: {}, bit_offset: {}, bit_size: {}'.format(member_name,
                                                                                  member_type, member_bit_size,
                                                                                  member_bit_offset))

        # save to return data
        if member_type.startswith('*'):
            # pointer member, change to *name -> type
            struct_data[name]['*' + member_name] = member_type[1:]
        else:
            struct_data[name][member_name] = member_type

    if die.tag == 'DW_TAG_structure_type' and die.attributes.get("DW_AT_name"):
        name = 'struct ' + die.attributes.get("DW_AT_name").value.decode()
        if die.attributes.get("DW_AT_declaration") and die.attributes.get("DW_AT_declaration").value == 1:
            logger.debug("struct {}: just a declaration".format(name))
            return

        size = die.attributes.get("DW_AT_byte_size").value
        logger.debug("{}, size:{}".format(name, size))

        # recursion into all children DIE
        for child in die.iter_children():
            die_info_rec(child, name)


def parse_top_die_by_cu(dwarfinfo):
    j = 0
    for CU in dwarfinfo.iter_CUs():
        j = j + 1
        logger.debug('  Found a compile unit at offset %s, length %s' % (CU.cu_offset, CU['unit_length']))

        # Start with the top DIE, the root for this CU's DIE tree
        top_DIE = CU.get_top_DIE()

        logger.debug("------------------------Top Die[{}] start-----------------------------------------".format(j))
        logger.debug(top_DIE)

        # Display DIEs recursively starting with top_DIE
        i = 0
        for child in top_DIE.iter_children():
            # for child in CU.iter_DIEs():
            i = i + 1
            logger.debug("Top Die[{}]->child[{}]:", j, i)
            die_info_rec(child)

        logger.debug("------------------------Top Die[{}] end-----------------------------------------".format(j))


# dict for all struct members
struct_data = defaultdict(dict)

elf_file = ".\\test.ko"

print('Processing file:', elf_file)
f = open(elf_file, 'rb')
elffile = ELFFile(f)

if not elffile.has_dwarf_info():
    print(f'ERROR: input file {elf_file} has no DWARF info')
    exit(1)

dwarfinfo = elffile.get_dwarf_info()

parse_top_die_by_cu(dwarfinfo)

f.close()

运行结果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/516832.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode-热题100:2. 两数相加

题目描述 给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。 请你将两个数相加,并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外,这两个数都…

金融贷款批准预测项目

注意:本文引用自专业人工智能社区Venus AI 更多AI知识请参考原站 ([www.aideeplearning.cn]) 在金融服务行业,贷款审批是一项关键任务,它不仅关系到资金的安全,还直接影响到金融机构的运营效率和风险管理…

【Java笔记】多线程0:JVM线程是用户态还是内核态?Java 线程与OS线程的联系

文章目录 JVM线程是用户态线程还是内核态线程什么是用户态线程与内核态线程绿色线程绿色线程的缺点 线程映射稍微回顾下线程映射模型JVM线程映射 线程状态操作系统的线程状态JVM的线程状态JVM线程与OS线程的状态关系 Reference 今天复盘一下Java中,JVM线程与实际操作…

面试算法-140-接雨水

题目 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 示例 1: 输入:height [0,1,0,2,1,0,1,3,2,1,2,1] 输出:6 解释:上面是由数组 [0,1,0,2,1,0,1,3,2…

Java web第一次作业

1.学会用记事本编写jsp文件&#xff0c;并放进tomcat的相关目录下&#xff0c;运行。 源代码&#xff1a; <% page contentType"text/html;charsetUTF-8" language"java" %> <html> <head> <title>我的第一个JSP页面</ti…

在深度学习模型中引入先验

当面对复杂问题的时候&#xff0c;在深度学习模型提取特征的过程中完全抛弃知识是非常不明智的策略。虽然有很多研究者在深度网络处理数据之前&#xff0c;利用具有某种知识的模型驱动方法对数据进行预处理&#xff0c;但是这种方法没有进行实质性地改造深度网络&#xff0c;且…

组合总和 II-java

题目描述: 给定一个候选人编号的集合 candidates 和一个目标数 target &#xff0c;找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的每个数字在每个组合中只能使用 一次 。 注意&#xff1a;解集不能包含重复的组合。 解题思想: 回溯法 剪枝 : …

PWM技术的应用

目录 PWM技术简介 PWM重要参数 PWM实现呼吸灯 脉宽调制波形 PWM案例 电路图 keil文件 直流电机 直流电机的控制 直流电机的驱动芯片L293D L293D引脚图 L293D功能表 直流电机案例 电路图 keil文件 步进电机 步进电机特点 步进电机驱动芯片L298 L298引脚图 L…

【Canvas与艺术】绘制黑白纹章,内嵌陶渊明南山诗

【效果图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>用Canvas绘制黑白纹章</title><style type"text/css…

Doris实践——信贷系统日志分析场景的实践应用

目录 前言 一、早期架构演进 1.1 架构1.0 基于Kettle MySQL离线数仓 1.2 架构2.0 基于 Presto / Trino统一查询 二、基于Doris的新一代架构 三、新数仓架构搭建经验 3.1 并发查询加速 3.2 数仓底座建设 四、Doris助力信DolphinScheduler 和 Shell 贷业务场景落地 4.…

QT----opencv4.8.0编译cuda版本,QTcreater使用

目录 1 编译opencv4.8.02 验证能否加载GPU cuda12.1 opencv4.8.0 vs2019 cmake3.29 1 编译opencv4.8.0 打开cmake&#xff0c;选择opencv480路径&#xff0c;build路径随意 点击configure后&#xff0c;选择这些选项&#xff0c;opencv_word&#xff0c;cuda全选&#xff0c;…

一款功能强大且易于使用的视频剪辑应用程序

一款功能强大且易于使用的视频剪辑应用程序&#xff0c;它提供了丰富多样的转场特效和滤镜&#xff0c;让用户能够轻松地为视频添加各种炫酷的效果。与其他视频编辑软件相比&#xff0c;剪映国际版的最大亮点在于其完全免费使用。首先&#xff0c;剪映国际版为用户提供了丰富的…

pth转onnx,同时使用onnx进行部署

当像我一样的菜鸡在使用开源的深度学习代码时&#xff0c;对于输出的pth模型文件&#xff0c;在预测时使用开源的predict.py文件进行部署&#xff0c;但是使用pth文件有一个问题&#xff0c;就是每次他都要重新加载一次模型&#xff0c;而且不方便移植&#xff0c;所以&#xf…

Java 面向对象(基础)

1、面向对象的概述及两大要素&#xff1a;类与对象 1. 面向对象内容的三条主线&#xff1a; - Java类及类的成员&#xff1a;&#xff08;重点&#xff09;属性、方法、构造器&#xff1b;&#xff08;熟悉&#xff09;代码块、内部类 - 面向对象的特征&#xff1a;封装、继承…

31-数据流:通过iam-authz-server设计,看数据流服务的设计

IAM数据流服务iam-authz-server的设计和实现。 iam-authz-server的功能介绍 iam-authz-server目前的唯一功能&#xff0c;是通过提供 /v1/authz RESTful API接口完成资源授权。 /v1/authz 接口是通过github.com/ory/ladon来完成资源授权的。 因为iam-authz-server承载了数据流…

ES6展开运算符

1.展开可迭代对象&#xff08;简单理解为数组和伪数组&#xff09;&#xff0c;如数组、 NodeList 、arguments。 可以通过展开运算符把一个伪数组转换为数组 const a [...document.body.children]; console.log(a); console.log(Array.isArray(a));2.实现数组的浅拷贝 cons…

51单片机入门之独立按键

目录 1.按键简介 2.独立按键控制LED亮灭 3.独立按键控制LED移位 1.按键简介 在生活中&#xff0c;我们常常会见到各种按键&#xff0c;我们的开发板上也有按键&#xff0c;就在左下角有四个按键&#xff0c;我们把它们叫做独立按键。 独立按键的原理比较简单&…

【三十三】【算法分析与设计】回溯(1),46. 全排列,78. 子集,没有树结构,但是依旧模拟树结构,回溯,利用全局变量+递归函数模拟树结构

46. 全排列 给定一个不含重复数字的数组 nums &#xff0c;返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 示例 1&#xff1a; 输入&#xff1a;nums [1&#xff0c;2&#xff0c;3] 输出&#xff1a;[[1&#xff0c;2&#xff0c;3]&#xff0c;[1&#xff0c;3&a…

WPF中通过自定义Panel实现控件拖动

背景 看到趋时软件的公众号文章&#xff08;WPF自定义Panel&#xff1a;让拖拽变得更简单&#xff09;&#xff0c;发现可以不通过Drag的方法来实现ListBox控件的拖动&#xff0c;而是通过对控件的坐标相加减去实现控件的位移等判断&#xff0c;因此根据文章里面的代码,边理解边…

考题抄错会做也白搭--模版方法模式

1.1 选择题不会做&#xff0c;蒙呗&#xff01; "题目抄错了&#xff0c;那就不是考试题目了&#xff0c;而考试试卷最大的好处就是&#xff0c;大家都是一样的题目&#xff0c;特别是标准化的考试&#xff0c;比如全是选择或判断的题目&#xff0c;那就最大化地限制了答题…