久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

Linux如何處理變量

159次閱讀
沒有評論

共計 5331 個字符,預計需要花費 14 分鐘才能閱讀完成。

這篇文章主要介紹了 Linux 如何處理變量,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓丸趣 TV 小編帶著大家一起了解一下。

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] lowpc=0x2e00 highpc=0x2e19 DW_OP_reg0

[1] lowpc=0x2e19 highpc=0x2e3f DW_OP_reg3

[2] lowpc=0x2ec4 highpc=0x2ec7 DW_OP_reg2

loclist with 3 entries follows

根據程序計數器的當前值,位置在寄存器之間移動的變量。

根據位置描述的種類,DW_AT_location 以三種不同的方式進行編碼。exprloc 編碼簡單和復合的位置描述。它們由一個字節長度組成,后跟一個  DWARF 表達式或位置描述。loclist 和 loclistptr 的編碼位置列表,它們在 .debug_loclists   部分中提供索引或偏移量,該部分描述了實際的位置列表。

DWARF 表達式

使用 DWARF 表達式計算變量的實際位置。這包括操作堆棧值的一系列操作。有很多 DWARF   操作可用,所以我不會詳細解釋它們。相反,我會從每一個表達式中給出一些例子,給你一個可用的東西。另外,不要害怕這些;libelfin   將為我們處理所有這些復雜性。

字面編碼

將無符號值壓入堆棧

將地址操作數壓入堆棧

將字面量壓入堆棧

DW_OP_lit0、DW_OP_lit1 hellip; hellip;DW_OP_lit31

DW_OP_addr addr

DW_OP_constu unsigned

寄存器值

將給定寄存器的內容加上給定的偏移量壓入堆棧

壓入在堆棧幀基址找到的值,偏移給定值

DW_OP_fbreg offset

DW_OP_breg0、DW_OP_breg1 hellip; hellip; DW_OP_breg31 offset

堆棧操作

將堆棧頂部視為內存地址,并將其替換為該地址的內容

復制堆棧頂部的值

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 offset

輸入轉化

將堆棧頂部的值轉換為不同的類型,它由給定偏移量的 DWARF 信息條目描述

DW_OP_convert DIE offset

特殊操作

什么都不做!

DW_OP_nop

DWARF 類型

DWARF   類型的表示需要足夠強大來為調試器用戶提供有用的變量表示。用戶經常希望能夠在應用程序級別進行調試,而不是在機器級別進行調試,并且他們需要了解他們的變量正在做什么。

DWARF 類型與大多數其他調試信息一起編碼在 DIE   中。它們可以具有指示其名稱、編碼、大小、字節等的屬性。無數的類型標簽可用于表示指針、數組、結構體、typedef 以及 C 或 C++   程序中可以看到的任何其他內容。

以這個簡單的結構體為例:

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

這個結構體的父 DIE 是這樣的:

 1 0x0000002a  DW_TAG_structure_type DW_AT_name  test  DW_AT_byte_size 0x000000b8 DW_AT_decl_file 0x00000001 test.cpp DW_AT_decl_line 0x00000001

上面說的是我們有一個叫做 test 的結構體,大小為 0xb8,在 test.cpp 的第 1 行聲明。接下來有許多描述成員的子 DIE。

 2 0x00000032  DW_TAG_member DW_AT_name  i  DW_AT_type  0x00000063  DW_AT_decl_file 0x00000001 test.cpp DW_AT_decl_line 0x00000002 DW_AT_data_member_location 0   2 0x0000003e  DW_TAG_member DW_AT_name  j  DW_AT_type  0x0000006a  DW_AT_decl_file 0x00000001 test.cpp DW_AT_decl_line 0x00000003 DW_AT_data_member_location 4   2 0x0000004a  DW_TAG_member DW_AT_name  k  DW_AT_type  0x00000071  DW_AT_decl_file 0x00000001 test.cpp DW_AT_decl_line 0x00000004 DW_AT_data_member_location 8   2 0x00000056  DW_TAG_member DW_AT_name  next  DW_AT_type  0x00000084  DW_AT_decl_file 0x00000001 test.cpp DW_AT_decl_line 0x00000005 DW_AT_data_member_location 176(as signed = -80)

每個成員都有一個名稱、一個類型(它是一個 DIE 偏移量)、一個聲明文件和行,以及一個指向其成員所在的結構體的字節偏移。其類型指向如下。

 1 0x00000063  DW_TAG_base_type DW_AT_name  int  DW_AT_encoding DW_ATE_signed DW_AT_byte_size 0x00000004   1 0x0000006a  DW_TAG_base_type DW_AT_name  float  DW_AT_encoding DW_ATE_float DW_AT_byte_size 0x00000004   1 0x00000071  DW_TAG_array_type DW_AT_type  0x00000063    2 0x00000076  DW_TAG_subrange_type DW_AT_type  0x0000007d  DW_AT_count 0x0000002a   1 0x0000007d  DW_TAG_base_type DW_AT_name  sizetype  DW_AT_byte_size 0x00000008 DW_AT_encoding DW_ATE_unsigned   1 0x00000084  DW_TAG_pointer_type DW_AT_type  0x0000002a

如你所見,我筆記本電腦上的 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 size return 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   at_name(die)     (0x    std::hex   result.value   ) =     value   std::endl; break; } case expr_result::type::reg: { auto value = get_register_value_from_dwarf_register(m_pid, result.value); std::cout   at_name(die)     (reg     result.value   ) =     value   std::endl; break; } default: throw std::runtime_error{Unhandled variable location  }

你可以看到,我根據變量的類型,打印輸出了值而沒有解釋。希望通過這個代碼,你可以看到如何支持編寫變量,或者用給定的名字搜索變量。

*** 我們可以將它添加到我們的命令解析器中:

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

感謝你能夠認真閱讀完這篇文章,希望丸趣 TV 小編分享的“Linux 如何處理變量”這篇文章對大家有幫助,同時也希望大家多多支持丸趣 TV,關注丸趣 TV 行業資訊頻道,更多相關知識等著你來學習!

正文完
 
丸趣
版權聲明:本站原創文章,由 丸趣 2023-08-25發表,共計5331字。
轉載說明:除特殊說明外本站除技術相關以外文章皆由網絡搜集發布,轉載請注明出處。
評論(沒有評論)
主站蜘蛛池模板: 上杭县| 大足县| 巴楚县| 来安县| 隆化县| 阿尔山市| 长葛市| 龙泉市| 淮安市| 西贡区| 若尔盖县| 鹤岗市| 新源县| 淮滨县| 墨江| 贺州市| 霍林郭勒市| 高淳县| 元阳县| 任丘市| 微山县| 渝北区| 明星| 宝应县| 靖安县| 新建县| 崇左市| 电白县| 尖扎县| 尼木县| 安康市| 林芝县| 龙川县| 莒南县| 宁蒗| 靖远县| 南阳市| 融水| 封丘县| 宝清县| 漯河市|