iis服务器助手广告
返回顶部
首页 > 资讯 > 操作系统 >Linux调试器中处理变量的过程是什么
  • 799
分享到

Linux调试器中处理变量的过程是什么

2023-06-28 02:06:33 799人浏览 安东尼
摘要

这篇文章主要讲解了“linux调试器中处理变量的过程是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Linux调试器中处理变量的过程是什么”吧!在开始之前,请确保你使用的 libelfi

这篇文章主要讲解了“linux调试器中处理变量的过程是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Linux调试器中处理变量的过程是什么”吧!

Linux调试器中处理变量的过程是什么

在开始之前,请确保你使用的 libelfin 版本是我分支上的 fbreg。这包含了一些 hack 来支持获取当前堆栈帧的基址并评估位置列表,这些都不是由原生的 libelfin 提供的。你可能需要给 GCC 传递 -gdwarf-2 参数使其生成兼容的 DWARF 信息。但是在实现之前,我将详细说明 DWARF 5 最新规范中的位置编码方式。

DWARF 位置

某一给定时刻的内存中变量的位置使用 DW_AT_location 属性编码在 DWARF 信息中。位置描述可以是单个位置描述、复合位置描述或位置列表。

  • 简单位置描述:描述了对象的一个连续的部分(通常是所有部分)的位置。简单位置描述可以描述可寻址存储器或寄存器中的位置,或缺少位置(具有或不具有已知值)。比如,DW_OP_fbreg -32: 一个整个存储的变量 – 从堆栈帧基址开始的32个字节。

  • 复合位置描述:根据片段描述对象,每个对象可以包含在寄存器的一部分中或存储在与其他片段无关的存储器位置中。比如, DW_OP_reg3 DW_OP_piece 4 DW_OP_reg10 DW_OP_piece 2:前四个字节位于寄存器 3 中,后两个字节位于寄存器 10 中的一个变量。

  • 位置列表:描述了具有有限生存期或在生存期内更改位置的对象。比如:

    • [ 0]DW_OP_reg0
    • [ 1]DW_OP_reg3
    • [ 2]DW_OP_reg2
  • 根据程序计数器的当前值,位置在寄存器之间移动的变量。

根据位置描述的种类,DW_AT_location 以三种不同的方式进行编码。exprloc 编码简单和复合的位置描述。它们由一个字节长度组成,后跟一个 DWARF 表达式或位置描述。loclist 和 loclistptr 的编码位置列表,它们在 .debug_loclists 部分中提供索引或偏移量,该部分描述了实际的位置列表。

DWARF 表达式

使用 DWARF 表达式计算变量的实际位置。这包括操作堆栈值的一系列操作。有很多 DWARF 操作可用,所以我不会详细解释它们。相反,我会从每一个表达式中给出一些例子,给你一个可用的东西。另外,不要害怕这些;libelfin将为我们处理所有这些复杂性。

  • 字面编码

    • 将无符号值压入堆栈
    • 将地址操作数压入堆栈
    • 将字面量压入堆栈
    • DW_OP_lit0、DW_OP_lit1……DW_OP_lit31
    • DW_OP_addr
    • DW_OP_constu
  • 寄存器值

    • 将给定寄存器的内容加上给定的偏移量压入堆栈
    • 压入在堆栈帧基址找到的值,偏移给定值
    • DW_OP_fbreg
    • DW_OP_breg0、DW_OP_breg1…… DW_OP_breg31
  • 堆栈操作

    • 将堆栈顶部视为内存地址,并将其替换为该地址的内容
    • 复制堆栈顶部的值
    • DW_OP_dup
    • DW_OP_deref
  • 算术和逻辑运算

    • 与 DW_OP_and 相同,但是会添加值
    • 弹出堆栈顶部的两个值,并压回它们的逻辑 AND
    • DW_OP_and
    • DW_OP_plus
  • 控制流操作

    • 条件分支:如果堆栈的顶部不是 0,则通过 offset 在表达式中向后或向后跳过
    • 弹出前两个值,比较它们,并且如果条件为真,则压入 1,否则为 0
    • DW_OP_le、DW_OP_eq、DW_OP_gt 等
    • DW_OP_bra
  • 输入转化

    • 将堆栈顶部的值转换为不同的类型,它由给定偏移量的 DWARF 信息条目描述
    • DW_OP_convert
  • 特殊操作

    • 什么都不做!
    • DW_OP_nop

DWARF 类型

DWARF 类型的表示需要足够强大来为调试器用户提供有用的变量表示。用户经常希望能够在应用程序级别进行调试,而不是在机器级别进行调试,并且他们需要了解他们的变量正在做什么。

DWARF 类型与大多数其他调试信息一起编码在 DIE 中。它们可以具有指示其名称、编码、大小、字节等的属性。无数的类型标签可用于表示指针、数组、结构体、typedef 以及 C 或 c++ 程序中可以看到的任何其他内容。

以这个简单的结构体为例:

struct test{int i;float j;int k[42];test* next;};

这个结构体的父 DIE 是这样的:

 DW_TAG_structure_typeDW_AT_name "test"DW_AT_byte_size 0x000000b8DW_AT_decl_file 0x00000001 test.cppDW_AT_decl_line 0x00000001

上面说的是我们有一个叫做 test 的结构体,大小为 0xb8,在 test.cpp 的第 1 行声明。接下来有许多描述成员的子 DIE。

 DW_TAG_memberDW_AT_name "i"DW_AT_type DW_AT_decl_file 0x00000001 test.cppDW_AT_decl_line 0x00000002DW_AT_data_member_location 0 DW_TAG_memberDW_AT_name "j"DW_AT_type DW_AT_decl_file 0x00000001 test.cppDW_AT_decl_line 0x00000003DW_AT_data_member_location 4 DW_TAG_memberDW_AT_name "k"DW_AT_type DW_AT_decl_file 0x00000001 test.cppDW_AT_decl_line 0x00000004DW_AT_data_member_location 8 DW_TAG_memberDW_AT_name "next"DW_AT_type DW_AT_decl_file 0x00000001 test.cppDW_AT_decl_line 0x00000005DW_AT_data_member_location 176(as signed = -80)

每个成员都有一个名称、一个类型(它是一个 DIE 偏移量)、一个声明文件和行,以及一个指向其成员所在的结构体的字节偏移。其类型指向如下。

 DW_TAG_base_typeDW_AT_name "int"DW_AT_encoding DW_ATE_signedDW_AT_byte_size 0x00000004 DW_TAG_base_typeDW_AT_name "float"DW_AT_encoding DW_ATE_floatDW_AT_byte_size 0x00000004 DW_TAG_array_typeDW_AT_type  DW_TAG_subrange_typeDW_AT_type DW_AT_count 0x0000002a DW_TAG_base_typeDW_AT_name "sizetype"DW_AT_byte_size 0x00000008DW_AT_encoding DW_ATE_unsigned DW_TAG_pointer_typeDW_AT_type

如你所见,我笔记本电脑上的 int 是一个 4 字节的有符号整数类型,float是一个 4 字节的浮点数。整数数组类型通过指向 int 类型作为其元素类型,sizetype(可以认为是 size_t)作为索引类型,它具有 2a 个元素。 test * 类型是 DW_TAG_pointer_type,它引用 test DIE。

实现简单的变量读取器

如上所述,libelfin 将为我们处理大部分复杂性。但是,它并没有实现用于表示可变位置的所有方法,并且在我们的代码中处理这些将变得非常复杂。因此,我现在选择只支持 exprloc。请根据需要添加对更多类型表达式的支持。如果你真的有勇气,请提交补丁到 libelfin 中来帮助完成必要的支持!

处理变量主要是将不同部分定位在存储器或寄存器中,读取或写入与之前一样。为了简单起见,我只会告诉你如何实现读取。

首先我们需要告诉 libelfin 如何从我们的进程中读取寄存器。我们创建一个继承自 expr_context 的类并使用 ptrace 来处理所有内容:

class ptrace_expr_context : public dwarf::expr_context {public:ptrace_expr_context (pid_t pid) : m_pid{pid} {}dwarf::taddr reg (unsigned regnum) override {return get_reGISter_value_from_dwarf_register(m_pid, regnum);}dwarf::taddr pc() override {struct user_regs_struct regs;ptrace(PTRACE_GETREGS, m_pid, nullptr, &regs);return regs.rip;}dwarf::taddr deref_size (dwarf::taddr address, unsigned size) override {//TODO take into account sizereturn ptrace(PTRACE_PEEKDATA, m_pid, address, nullptr);}private:pid_t m_pid;};

读取将由我们 debugger 类中的 read_variables 函数处理:

void debugger::read_variables() {using namespace dwarf;auto func = get_function_from_pc(get_pc());//...}

我们上面做的第一件事是找到我们目前进入的函数,然后我们需要循环访问该函数中的条目来寻找变量:

for (const auto& die : func) {if (die.tag == DW_TAG::variable) {//...}}

我们通过查找 DIE 中的 DW_AT_location 条目获取位置信息:

auto loc_val = die[DW_AT::location];

接着我们确保它是一个 exprloc,并请求 libelfin 来评估我们的表达式:

if (loc_val.get_type() == value::type::exprloc) {ptrace_expr_context context {m_pid};auto result = loc_val.as_exprloc().evaluate(&context);

现在我们已经评估了表达式,我们需要读取变量的内容。它可以在内存或寄存器中,因此我们将处理这两种情况:

switch (result.location_type) {case expr_result::type::address:{auto value = read_memory(result.value);std::cout " (0x" ") = "break;}case expr_result::type::reg:{auto value = get_register_value_from_dwarf_register(m_pid, result.value);std::cout " (reg " ") = "break;}default:throw std::runtime_error{"Unhandled variable location"};}

你可以看到,我根据变量的类型,打印输出了值而没有解释。希望通过这个代码,你可以看到如何支持编写变量,或者用给定的名字搜索变量。

最后我们可以将它添加到我们的命令解析器中:

else if(is_prefix(command, "variables")) {read_variables();}

测试一下

编写一些具有一些变量的小功能,不用优化并带有调试信息编译它,然后查看是否可以读取变量的值。尝试写入存储变量的内存地址,并查看程序改变的行为。

感谢各位的阅读,以上就是“Linux调试器中处理变量的过程是什么”的内容了,经过本文的学习后,相信大家对Linux调试器中处理变量的过程是什么这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!

--结束END--

本文标题: Linux调试器中处理变量的过程是什么

本文链接: https://www.lsjlt.com/news/315676.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Linux调试器中处理变量的过程是什么
    这篇文章主要讲解了“Linux调试器中处理变量的过程是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Linux调试器中处理变量的过程是什么”吧!在开始之前,请确保你使用的 libelfi...
    99+
    2023-06-28
  • sql存储过程调试的方法是什么
    调试SQL存储过程的方法可以有以下几种:1. 使用PRINT语句:在存储过程中插入PRINT语句,将变量的值或执行的步骤输出到消息窗...
    99+
    2023-08-28
    sql
  • db2存储过程调试的方法是什么
    要调试db2存储过程,可以使用以下方法: 使用db2的调试工具:db2提供了一些调试工具,可以帮助开发人员调试存储过程。其中包括...
    99+
    2024-04-09
    db2
  • mysql存储过程调试的方法是什么
    MySQL存储过程调试的方法有以下几种: 使用PRINT或SELECT语句输出变量值:在存储过程中可以使用PRINT或SELEC...
    99+
    2024-04-09
    mysql
  • PostgreSQL中GetSnapshotData的处理过程是什么
    这篇文章主要讲解了“PostgreSQL中GetSnapshotData的处理过程是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“PostgreSQL中...
    99+
    2024-04-02
  • Emacs调试中GUD调试器的特性是什么
    Emacs调试中GUD调试器的特性是什么,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。下面简短地对 Emacs 的调试工具 GUD 的特性进行了探索。如果你是一...
    99+
    2023-06-16
  • python中什么是调试器
    这期内容当中小编将会给大家带来有关python中什么是调试器,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。python有哪些常用库python常用的库:1.requesuts;2.scrapy;3.pil...
    99+
    2023-06-14
  • python调试过程中多颜色输出的方法是什么
    本篇内容主要讲解“python调试过程中多颜色输出的方法是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“python调试过程中多颜色输出的方法是什么”吧!主要语法主要是通过一个固定格式的字符...
    99+
    2023-07-05
  • JavaScript 错误处理中的源映射:简化调试过程
    ...
    99+
    2024-04-02
  • Linux中变量参数$的含义是什么
    本篇文章为大家展示了Linux中变量参数$的含义是什么,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。Linux变量参数$的含义   我们先写一个简单的脚本,执行以后再解释各个变量的意义 # touc...
    99+
    2023-06-13
  • mysql存储过程中给变量赋值的方法是什么
    这篇文章主要介绍“mysql存储过程中给变量赋值的方法是什么”,在日常操作中,相信很多人在mysql存储过程中给变量赋值的方法是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解...
    99+
    2024-04-02
  • java中volatile变量的原理是什么
    这篇文章给大家介绍java中volatile变量的原理是什么,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。Java可以用来干什么Java主要应用于:1. web开发;2. Android开发;3. 客户端开发;4. 网...
    99+
    2023-06-14
  • 仅在处理程序内有效的变量是什么意思
    问题内容 在 go-optical 文档中他们说: as a rule of thumb, you must only use context values within the h...
    99+
    2024-02-05
  • Java中ThreadLocal线程变量的实现原理是什么
    这篇文章主要介绍了Java中ThreadLocal线程变量的实现原理是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Java中ThreadLocal线程变量的实现原理是什么文章都会有所收获,下面我们一起来看...
    99+
    2023-07-02
  • linux中环境变量是什么意思
    小编给大家分享一下linux中环境变量是什么意思,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!在linux中,环境变量指的是系统预定义的参数;它相当于全局变量,存在于所有的Shell中,具有继承性,可存储有关shell会话...
    99+
    2023-06-21
  • linux主机中病毒处理过程是怎么样的
    这期内容当中小编将会给大家带来有关linux主机中病毒处理过程是怎么样的,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。问题现象服务器一直往外大量发包,占用流量和cpu,导致服务器响应很慢甚至无响应,怀疑是...
    99+
    2023-06-05
  • linux中Path环境变量的作用是什么
    在Linux操作系统中,Path环境变量的作用是指定可执行程序的搜索路径。当用户在命令行中输入一个可执行程序的名称时,操作系统会按照...
    99+
    2023-09-14
    linux Path
  • PostgreSQL的查询处理过程是什么
    这篇文章主要讲解了“PostgreSQL的查询处理过程是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“PostgreSQL的查询处理过程是什么”吧!一、...
    99+
    2024-04-02
  • javascript事件处理的过程是什么
    本文小编为大家详细介绍“javascript事件处理的过程是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“javascript事件处理的过程是什么”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,...
    99+
    2024-04-02
  • 云服务器的演变过程是什么
    云服务器是一种虚拟化计算平台,它的演变过程可以分为以下几个阶段: 早期云服务器 早期的云服务器是通过传统服务器的形式创建的。它们提供了大量的计算资源,通常包括大型计算机、服务器和网络设备。 云主机 云主机是一种虚拟化计算平台,可以通过互...
    99+
    2023-10-27
    过程 服务器
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作