这里我们第一次碰到了 ptrace,它会在我们编写调试器的时刻经常碰到。ptrace 经由过程攫取存放器、内存、慢慢调试等让我们不雅察和控制另一个过程的履行。其 API 异常简单;你须要给这个简单函数供给一个列举值指定你想要进行的操作,然后是一些取决于你所供给的值可能会被应用也可能会被忽视的参数。函数原型看起来类似:
系列文┞仿索引
- long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);
request 是我们想对被跟踪过程进行的操作;pid 是被跟踪过程的过程 ID;addr 是一个内存地址,用于在一些调用中指定被跟踪法度榜样的地址;data 是 request 响应的资本。返回值平日是一些缺点信息,是以在你实际的代码中你也许应当检查返回值;为了简洁我这里就省略了。你可以查看 man 手册获取更多(关于 ptrace)的信息。
膳绫擎代码中我们发送的请求 PTRACE_TRACEME 表示这个过程应当许可父过程跟踪它。所有其它参数都邑被忽视,因为 API 设计并不是很重要,哈哈。
下一步,我们会调用 execl,这是很多诸多的 exec 函数格局之一。我们履行指定的法度榜样,经由过程敕令行参数传递它的名称,然后用一个 nullptr 终止列表。如不雅你愿意,你还可以传递其它履行你的法度榜样所需的参数。
在完成这些后,我们就会和子过程一路停止;在我们停止它之前它会一向履行。
添加调试轮回
如今我们已经启动了子过程,我们想要可以或许和它进行交互。为此,我们会创建一个 debugger 类,轮回监听用户输入,然后在我们父过程的 main 函数中启动它。
- else if (pid >= 1) {
- //parent
- debugger dbg{prog, pid};
- dbg.run();
- }
- class debugger {
- public:
- debugger (std::string prog_name, pid_t pid)
- : m_prog_name{std::move(prog_name)}, m_pid{pid} {}
- void run();
- private:
- std::string m_prog_name;
- pid_t m_pid;
- };
在 run 函数中,我们须要等待,直到子过程完成启动,然后一向大年夜 linenoise 获取输入直到收到 EOF(CTRL+D)。
- void debugger::run() {
- int wait_status;
- auto options = 0;
- waitpid(m_pid, &wait_status, options);
- char* line = nullptr;
- while((line = linenoise("minidbg> ")) != nullptr) {
- handle_command(line);
- linenoiseHistoryAdd(line);
- linenoiseFree(line);
- }
- }
我们将会支撑以下功能:
- 启动、暂停、持续履行
- 在不合处所设置断点
- 内存地址
- 源代码行
- 函数人口
- 读写存放器和内存
- 单步履行
- 指令
- 进入函数
- 彪炳函数
- 跳过函数
- 打印当前代码地址
- 打印函数调用栈
- 打印简单变量的值
当被跟踪的过程启动时,会发送一个 SIGTRAP 旌旗灯号给它,这是一个跟踪或者断点中断。我们可以应用 waitpid 函数等待这个旌旗灯号发送。
当我们知道过程可以被调试之后,我们监听用户输入。linenoise 函数它本身会用一个窗口显示和处理用户输入。这意味着我们不须要做太多的工作就会有一个支撑汗青记录和导航敕令的敕令行。当我们获取到输入时,我们把敕令发给我们写的小法度榜样 handle_command,然后我们把这个敕令添加到 linenoise 汗青并释放资本。
推荐阅读
人工智能与万物互联已成为智能化、网联化迈入纵深的使能技巧,为集成电路家当带来四大年夜计谋机会:形成计谋新需求、开辟技巧新偏向、构建研发新模式、塑造竞争新格局。我国正处于家当晋升的关键时代,应充分把握新形>>>详细阅读
本文标题:开发一个Linux调试器(一):准备环境
地址:http://www.17bianji.com/lsqh/35868.html
1/2 1

网友点评
精彩导读
科技快报
品牌展示