remove_breakpoint 是一个小的赞助函数:
这里我们在函数的返回地址处设置一个断点,正如彪炳 step_out。
你应当可以在 main 地址处设置一个断点,然后在全部法度榜样中跳入、跳过、彪炳函数。如不雅你测验测验彪炳 main 函数或者跳入任何动态链接库,就会出现料想之外的工作。
- void debugger::remove_breakpoint(std::intptr_t addr) {
- if (m_breakpoints.at(addr).is_enabled()) {
- m_breakpoints.at(addr).disable();
- }
- m_breakpoints.erase(addr);
- }
你可以在这里找到这篇博文的相干代码。下次我们会应用我们新的 DWARF 技能来实现源码级断点。
接下来是跳入 step_in。一个简单的算法是持续慢慢履行指令直到新的一行。
- void debugger::step_in() {
- auto line = get_line_entry_from_pc(get_pc())->line;
- while (get_line_entry_from_pc(get_pc())->line == line) {
- single_step_instruction_with_breakpoint_check();
- }
- auto line_entry = get_line_entry_from_pc(get_pc());
- print_source(line_entry->file->path, line_entry->line);
- }
跳过 step_over 对于我们来说是三个中最难的。理论上,解决办法就是鄙人一行源码中设置一个断点,但下一行源码是什么呢?它可能不是当前行后续的那一行,因为我们可能处于一个轮回、或者某种前提构造之中。真正的调试器一般会检查当前正在履行什么指令然后计算出所有可能的分支目标,然后在所有分支目标中设置断点。对于一个小的项目,我不计算实现或者集成一个 x86 指令模仿器,是以我们要想一个更简单的解决办法。有几个恐怖的选择,一个是一向慢慢履行直到当前函数新的一行,或者在当前函数的每一行都设置一个断点。如不雅我们是要跳过一个函数调用,前者将会相当的低效,因为我们须要慢慢履行那个调用图中的每个指令,是以我会采取第二种办法。
- void debugger::step_over() {
- auto func = get_function_from_pc(get_pc());
- auto func_entry = at_low_pc(func);
- auto func_end = at_high_pc(func);
- auto line = get_line_entry_from_pc(func_entry);
- auto start_line = get_line_entry_from_pc(get_pc());
- std::vector<std::intptr_t> to_delete{};
- while (line->address < func_end) {
- if (line->address != start_line->address && !m_breakpoints.count(line->address)) {
- set_breakpoint_at_address(line->address);
- to_delete.push_back(line->address);
- }
- ++line;
- }
- auto frame_pointer = get_register_value(m_pid, reg::rbp);
- auto return_address = read_memory(frame_pointer+8);
- if (!m_breakpoints.count(return_address)) {
- set_breakpoint_at_address(return_address);
- to_delete.push_back(return_address);
推荐阅读
run(getData) 在 JavaScript 的世比赛,所有代码都是单线程履行的,因为这个“缺点”,导致 JavaScript 的所有收集操作,浏览器事宜,都必须是异步履行。异步操作会在将来的某个>>>详细阅读
地址:http://www.17bianji.com/lsqh/36973.html
1/2 1

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