Home System Tutorial LINUX Prepare environment registers and memory Elves and dwarves source code and signal source code level for step-by-step execution

Prepare environment registers and memory Elves and dwarves source code and signal source code level for step-by-step execution

Jun 02, 2024 am 09:10 AM

Setting breakpoints on video memory addresses seems good, but it does not provide the most user-friendly tool. We hope to also be able to set breakpoints on source code lines and function entry addresses so that we can debug at the same level of concreteness as the code.

This article will add source-level breakpoints to our debugger. With all the features we already support, this is much easier than it sounds at first. We'll also add a command to get the type and address of a symbol, which is useful for locating code or data and understanding linking concepts.

Series Index

With the release of previous articles, this link will gradually take effect.

Design environment breakpoint register and video memory Elves and dwarves source code and signal source code level to execute the source code level breakpoint call stack and read the following steps of variables

Breakpoint

DWARF

Elves and dwarves This article describes how DWARF debugging information works and how to use it to map machine code to high-level source code. Recall that DWARF contains the address range of a function and a line table that allows you to convert code locations between representational layers. We will use this functionality to implement our breakpoints.

linux vector 头文件_头文件vector报错_头文件vector

Function Entry

If you consider Linux operating system principles such as overloading, member functions, etc., setting breakpoints on function names can be a bit complicated, and we will traverse all compilation units and search for functions that match the name we are looking for . The DWARF information is as follows:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

DW_TAG_compile_unit

DW_AT_producerclang version 3.9.1 (tags/RELEASE_391/final)

DW_AT_languageDW_LANG_C_plus_plus

DW_AT_name/super/secret/path/MiniDbg/examples/variable.cpp

DW_AT_stmt_list 0x00000000

DW_AT_comp_dir/super/secret/path/MiniDbg/build

DW_AT_low_pc0x00400670

DW_AT_high_pc 0x0040069c

LOCAL_SYMBOLS:

DW_TAG_subprogram

DW_AT_low_pc0x00400670

DW_AT_high_pc 0x0040069c

DW_AT_namefoo

...

...

DW_TAG_subprogram

DW_AT_low_pc0x00400700

DW_AT_high_pc 0x004007a0

DW_AT_namebar

...

Copy after login

We want to match the DW_AT_name and use DW_AT_low_pc (the starting address of the function) to set our breakpoint.

1

2

3

4

5

6

7

8

9

10

11

12

void debugger::set_breakpoint_at_function(const std::string& name) {

for (const auto& cu : m_dwarf.compilation_units()) {

for (const auto& die : cu.root()) {

if (die.has(dwarf::DW_AT::name) && at_name(die) == name) {

auto low_pc = at_low_pc(die);

auto entry = get_line_entry_from_pc(low_pc);

++entry; //skip prologue

set_breakpoint_at_address(entry->address);

}

}

}

}

Copy after login

The only thing that looks a little strange about this code is ++entry. The problem is that the DW_AT_low_pc of the function does not point to the start address of the user code for the function, it points to the start of the prologue. The compiler generally outputs the prologue and epilogue of a function, which are used to save and restore the stack, operate the stack table pointer, etc. This isn't very useful to us, so we increment the entry line by one to get the first line of user code instead of the prologue. The DWARF line table actually has some functionality for marking the entry as the first line after the function prologue, but not all compilers output it, so I used the original way.

Source code lines

头文件vector报错_头文件vector_linux vector 头文件

To set a breakpoint on a high-level source code line, we need to convert this line number into an address in DWARF. We will iterate through the compilation units, looking for one whose name matches the given file, and then look for the entry corresponding to the given line.

DWARF looks a bit like this:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

.debug_line: line number info for a single cu

Source lines (from CU-DIE at .debug_info offset 0x0000000b):

NS new statement, BB new basic block, ET end of text sequence

PE prologue end, EB epilogue begin

IS=val ISA number, DI=val discriminator value

[lno,col] NS BB ET PE EB IS= DI= uri: "filepath"

0x004004a7 [ 1, 0] NS uri: "/super/secret/path/a.hpp"

0x004004ab [ 2, 0] NS

0x004004b2 [ 3, 0] NS

0x004004b9 [ 4, 0] NS

0x004004c1 [ 5, 0] NS

0x004004c3 [ 1, 0] NS uri: "/super/secret/path/b.hpp"

0x004004c7 [ 2, 0] NS

0x004004ce [ 3, 0] NS

0x004004d5 [ 4, 0] NS

0x004004dd [ 5, 0] NS

0x004004df [ 4, 0] NS uri: "/super/secret/path/ab.cpp"

0x004004e3 [ 5, 0] NS

0x004004e8 [ 6, 0] NS

0x004004ed [ 7, 0] NS

0x004004f4 [ 7, 0] NS ET

Copy after login

So if we want to set a breakpoint on line 5 of ab.cpp, we will look for the entry related to line (0x004004e3) and set a breakpoint.

1

2

3

4

5

6

7

8

9

10

11

12

13

void debugger::set_breakpoint_at_source_line(const std::string& file, unsigned line) {

for (const auto& cu : m_dwarf.compilation_units()) {

if (is_suffix(file, at_name(cu.root()))) {

const auto& lt = cu.get_line_table();

for (const auto& entry : lt) {

if (entry.is_stmt && entry.line == line) {

set_breakpoint_at_address(entry.address);

return;

}

}

}

}

}

Copy after login

我这儿做了is_suffixhack,这样你可以输入c.cpp代表a/b/c.cpp。其实你实际上应当使用大小写敏感路径处理库或则其它东西,而且我比较懒。entry.is_stmt是检测行表入口是否被标记为一个句子的开头,这是由编译器按照它觉得是断点的最佳目标的地址设置的。

符号查找

头文件vector报错_头文件vector_linux vector 头文件

当我们在对象文件层时,符号是王者。函数用符号命名红旗linux系统,全局变量用符号命名,你得到一个符号,我们得到一个符号,每位人都得到一个符号。在给定的对象文件中linux vector 头文件,一些符号可能引用其他对象文件或共享库,链接器将从符号引用创建一个可执行程序。

可以在正确命名的符号表中查找符号,它储存在二补码文件的ELF部份中。辛运的是,libelfin有一个不错的插口来做这件事,所以我们不须要自己处理所有的ELF的事情。为了让你晓得我们在处理哪些,下边是一个二补码文件的.symtab部份的轮询,它由readelf生成:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

Num: Value Size Type Bind Vis Ndx Name

0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND

1: 0000000000400238 0 SECTION LOCAL DEFAULT 1

2: 0000000000400254 0 SECTION LOCAL DEFAULT 2

3: 0000000000400278 0 SECTION LOCAL DEFAULT 3

4: 00000000004002c8 0 SECTION LOCAL DEFAULT 4

5: 0000000000400430 0 SECTION LOCAL DEFAULT 5

6: 00000000004004e4 0 SECTION LOCAL DEFAULT 6

7: 0000000000400508 0 SECTION LOCAL DEFAULT 7

8: 0000000000400528 0 SECTION LOCAL DEFAULT 8

9: 0000000000400558 0 SECTION LOCAL DEFAULT 9

10: 0000000000400570 0 SECTION LOCAL DEFAULT 10

11: 0000000000400714 0 SECTION LOCAL DEFAULT 11

12: 0000000000400720 0 SECTION LOCAL DEFAULT 12

13: 0000000000400724 0 SECTION LOCAL DEFAULT 13

14: 0000000000400750 0 SECTION LOCAL DEFAULT 14

15: 0000000000600e18 0 SECTION LOCAL DEFAULT 15

16: 0000000000600e20 0 SECTION LOCAL DEFAULT 16

17: 0000000000600e28 0 SECTION LOCAL DEFAULT 17

18: 0000000000600e30 0 SECTION LOCAL DEFAULT 18

19: 0000000000600ff0 0 SECTION LOCAL DEFAULT 19

20: 0000000000601000 0 SECTION LOCAL DEFAULT 20

21: 0000000000601018 0 SECTION LOCAL DEFAULT 21

22: 0000000000601028 0 SECTION LOCAL DEFAULT 22

23: 0000000000000000 0 SECTION LOCAL DEFAULT 23

24: 0000000000000000 0 SECTION LOCAL DEFAULT 24

25: 0000000000000000 0 SECTION LOCAL DEFAULT 25

26: 0000000000000000 0 SECTION LOCAL DEFAULT 26

27: 0000000000000000 0 SECTION LOCAL DEFAULT 27

28: 0000000000000000 0 SECTION LOCAL DEFAULT 28

29: 0000000000000000 0 SECTION LOCAL DEFAULT 29

30: 0000000000000000 0 SECTION LOCAL DEFAULT 30

31: 0000000000000000 0 FILE LOCAL DEFAULT ABS init.c

32: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c

33: 0000000000600e28 0 OBJECT LOCAL DEFAULT 17 __JCR_LIST__

34: 00000000004005a0 0 FUNC LOCAL DEFAULT 10 deregister_tm_clones

35: 00000000004005e0 0 FUNC LOCAL DEFAULT 10 register_tm_clones

36: 0000000000400620 0 FUNC LOCAL DEFAULT 10 __do_global_dtors_aux

37: 0000000000601028 1 OBJECT LOCAL DEFAULT 22 completed.6917

38: 0000000000600e20 0 OBJECT LOCAL DEFAULT 16 __do_global_dtors_aux_fin

39: 0000000000400640 0 FUNC LOCAL DEFAULT 10 frame_dummy

40: 0000000000600e18 0 OBJECT LOCAL DEFAULT 15 __frame_dummy_init_array_

41: 0000000000000000 0 FILE LOCAL DEFAULT ABS /super/secret/path/MiniDbg/

42: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c

43: 0000000000400818 0 OBJECT LOCAL DEFAULT 14 __FRAME_END__

44: 0000000000600e28 0 OBJECT LOCAL DEFAULT 17 __JCR_END__

45: 0000000000000000 0 FILE LOCAL DEFAULT ABS

46: 0000000000400724 0 NOTYPE LOCAL DEFAULT 13 __GNU_EH_FRAME_HDR

47: 0000000000601000 0 OBJECT LOCAL DEFAULT 20 _GLOBAL_OFFSET_TABLE_

48: 0000000000601028 0 OBJECT LOCAL DEFAULT 21 __TMC_END__

49: 0000000000601020 0 OBJECT LOCAL DEFAULT 21 __dso_handle

50: 0000000000600e20 0 NOTYPE LOCAL DEFAULT 15 __init_array_end

51: 0000000000600e18 0 NOTYPE LOCAL DEFAULT 15 __init_array_start

52: 0000000000600e30 0 OBJECT LOCAL DEFAULT 18 _DYNAMIC

53: 0000000000601018 0 NOTYPE WEAK DEFAULT 21 data_start

54: 0000000000400710 2 FUNC GLOBAL DEFAULT 10 __libc_csu_fini

55: 0000000000400570 43 FUNC GLOBAL DEFAULT 10 _start

56: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__

57: 0000000000400714 0 FUNC GLOBAL DEFAULT 11 _fini

58: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@@GLIBC_

59: 0000000000400720 4 OBJECT GLOBAL DEFAULT 12 _IO_stdin_used

60: 0000000000601018 0 NOTYPE GLOBAL DEFAULT 21 __data_start

61: 00000000004006a0 101 FUNC GLOBAL DEFAULT 10 __libc_csu_init

62: 0000000000601028 0 NOTYPE GLOBAL DEFAULT 22 __bss_start

63: 0000000000601030 0 NOTYPE GLOBAL DEFAULT 22 _end

64: 0000000000601028 0 NOTYPE GLOBAL DEFAULT 21 _edata

65: 0000000000400670 44 FUNC GLOBAL DEFAULT 10 main

66: 0000000000400558 0 FUNC GLOBAL DEFAULT 9 _init

Copy after login

你可以在对象文件中见到用于设置环境的好多符号,最后还可以见到main符号。

我们对符号的类型、名称和值(地址)感兴趣。我们有一个该类型的symbol_type枚举,并使用一个std::string作为名称,std::uintptr_t作为地址:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

enum class symbol_type {

notype, // No type (e.g., absolute symbol)

object, // Data object

func, // Function entry point

section, // Symbol is associated with a section

file, // Source file associated with the

}; // object file

std::string to_string (symbol_type st) {

switch (st) {

case symbol_type::notype: return "notype";

case symbol_type::object: return "object";

case symbol_type::func: return "func";

case symbol_type::section: return "section";

case symbol_type::file: return "file";

}

}

struct symbol {

symbol_type type;

std::string name;

std::uintptr_t addr;

};

Copy after login

我们须要将从libelfin获得的符号类型映射到我们的枚举,由于我们不希望依赖关系破环这个插口。辛运的是,我为所有的东西选了同样的名子,所以这样很简单:

1

2

3

4

5

6

7

8

9

10

symbol_type to_symbol_type(elf::stt sym) {

switch (sym) {

case elf::stt::notype: return symbol_type::notype;

case elf::stt::object: return symbol_type::object;

case elf::stt::func: return symbol_type::func;

case elf::stt::section: return symbol_type::section;

case elf::stt::file: return symbol_type::file;

default: return symbol_type::notype;

}

};

Copy after login

最后我们要查找符号。为了说明的目的,我循环查找符号表的ELF部份,之后搜集我在其中找到的任意符号到std::vector中。更智能的实现可以构建从名称到符号的映射,这样你只须要查看一次数据就行了。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

std::vector debugger::lookup_symbol(const std::string& name) {

std::vector syms;

for (auto &sec : m_elf.sections()) {

if (sec.get_hdr().type != elf::sht::symtab && sec.get_hdr().type != elf::sht::dynsym)

continue;

for (auto sym : sec.as_symtab()) {

if (sym.get_name() == name) {

auto &d = sym.get_data();

syms.push_back(symbol{to_symbol_type(d.type()), sym.get_name(), d.value});

}

}

}

return syms;

}

Copy after login

添加命令

一如往常,我们须要添加一些更多的命令来向用户曝露功能。对于断点,我使用GDB风格的插口linux vector 头文件,其中断点类型是通过你传递的参数推论的,而不用要求显式切换:

1

2

3

4

5

6

7

8

9

10

11

12

13

else if(is_prefix(command, "break")) {

if (args[1][0] == '0' && args[1][1] == 'x') {

std::string addr {args[1], 2};

set_breakpoint_at_address(std::stol(addr, 0, 16));

}

else if (args[1].find(':') != std::string::npos) {

auto file_and_line = split(args[1], ':');

set_breakpoint_at_source_line(file_and_line[0], std::stoi(file_and_line[1]));

}

else {

set_breakpoint_at_function(args[1]);

}

}

Copy after login

对于符号,我们将查找符号并复印出我们发觉的任何匹配项:

1

2

3

4

5

6

else if(is_prefix(command, "symbol")) {

auto syms = lookup_symbol(args[1]);

for (auto&& s : syms) {

std::cout << s.name << &#039; &#039; << to_string(s.type) << " 0x" << std::hex << s.addr << std::endl;

}

}

Copy after login

测试一下

在一个简单的二补码文件上启动调试器,并设置源代码级别的断点。在一些foo函数上设置一个断点,见到我的调试器停在它前面是我这个项目最有价值的时刻之一。

符号查找可以通过在程序中添加一些函数或全局变量并查找它们的名称来进行测试。请注意,假若你正在编译C++代码,你还须要考虑名称重整。

The above is the detailed content of Prepare environment registers and memory Elves and dwarves source code and signal source code level for step-by-step execution. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

What is the Linux best used for? What is the Linux best used for? Apr 03, 2025 am 12:11 AM

Linux is best used as server management, embedded systems and desktop environments. 1) In server management, Linux is used to host websites, databases, and applications, providing stability and reliability. 2) In embedded systems, Linux is widely used in smart home and automotive electronic systems because of its flexibility and stability. 3) In the desktop environment, Linux provides rich applications and efficient performance.

What are the 5 basic components of Linux? What are the 5 basic components of Linux? Apr 06, 2025 am 12:05 AM

The five basic components of Linux are: 1. The kernel, managing hardware resources; 2. The system library, providing functions and services; 3. Shell, the interface for users to interact with the system; 4. The file system, storing and organizing data; 5. Applications, using system resources to implement functions.

What is basic Linux administration? What is basic Linux administration? Apr 02, 2025 pm 02:09 PM

Linux system management ensures the system stability, efficiency and security through configuration, monitoring and maintenance. 1. Master shell commands such as top and systemctl. 2. Use apt or yum to manage the software package. 3. Write automated scripts to improve efficiency. 4. Common debugging errors such as permission problems. 5. Optimize performance through monitoring tools.

What is the most use of Linux? What is the most use of Linux? Apr 09, 2025 am 12:02 AM

Linux is widely used in servers, embedded systems and desktop environments. 1) In the server field, Linux has become an ideal choice for hosting websites, databases and applications due to its stability and security. 2) In embedded systems, Linux is popular for its high customization and efficiency. 3) In the desktop environment, Linux provides a variety of desktop environments to meet the needs of different users.

How to learn Linux basics? How to learn Linux basics? Apr 10, 2025 am 09:32 AM

The methods for basic Linux learning from scratch include: 1. Understand the file system and command line interface, 2. Master basic commands such as ls, cd, mkdir, 3. Learn file operations, such as creating and editing files, 4. Explore advanced usage such as pipelines and grep commands, 5. Master debugging skills and performance optimization, 6. Continuously improve skills through practice and exploration.

How much does Linux cost? How much does Linux cost? Apr 04, 2025 am 12:01 AM

Linuxisfundamentallyfree,embodying"freeasinfreedom"whichallowsuserstorun,study,share,andmodifythesoftware.However,costsmayarisefromprofessionalsupport,commercialdistributions,proprietaryhardwaredrivers,andlearningresources.Despitethesepoten

What is a Linux device? What is a Linux device? Apr 05, 2025 am 12:04 AM

Linux devices are hardware devices running Linux operating systems, including servers, personal computers, smartphones and embedded systems. They take advantage of the power of Linux to perform various tasks such as website hosting and big data analytics.

What are the disadvantages of Linux? What are the disadvantages of Linux? Apr 08, 2025 am 12:01 AM

The disadvantages of Linux include user experience, software compatibility, hardware support, and learning curve. 1. The user experience is not as friendly as Windows or macOS, and it relies on the command line interface. 2. The software compatibility is not as good as other systems and lacks native versions of many commercial software. 3. Hardware support is not as comprehensive as Windows, and drivers may be compiled manually. 4. The learning curve is steep, and mastering command line operations requires time and patience.

See all articles