//Read the first address from the file std::string addr; std::getline(map, addr, '-'); m_load_address = std::stoi(addr, 0, 16); } }
二、获取信息
通过一个 pc 怎么获取函数名呢?注意这个 pc 是一个 offset addr,传参的时候一定要转换。思路很简单,首先遍历所有的 cu,然后判断 cu 的 low_pc 和 high_pc,如果在这个 cu 符合,那么就通过 cu 拿到 cu.root。cu.root 是一个根 die,通过它可以遍历所有的 die。之后再判断 die的 tag 是不是一个函数,如果是且包含 pc,那么就是我们要找的函数。实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
dwarf::die Debugger::get_function_from_pc(std::intptr_t pc){ for (auto &cu : m_dwarf.compilation_units()) { // 循环遍历所有cu if (die_pc_range(cu.root()).contains(pc)) { for (constauto &die : cu.root()) { if (die.tag == dwarf::DW_TAG::subprogram) { if (die_pc_range(die).contains(pc)) { return die; } } } } } throw std::out_of_range{"Cannot find function"}; }
接着通过 pc 来获取 line entry:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
dwarf::line_table::iterator Debugger::get_line_entry_from_pc(uint64_t pc){ for (auto &cu : m_dwarf.compilation_units()) { if (die_pc_range(cu.root()).contains(pc)) { auto < = cu.get_line_table(); auto it = lt.find_address(pc); if (it == lt.end()) { throw std::out_of_range{"Cannot find line entry"}; } else { return it; } } }
throw std::out_of_range{"Cannot find line entry"}; }
接着我们打印源代码。思路是通过 debug info 中的源代码路径和 line table 来获取,好消息是,我们不必做更多的底层实现:
auto start_line = line <= n_lines_context ? 1 : line - n_lines_context; auto end_line = line + n_lines_context + (line < n_lines_context ? n_lines_context - line : 0) + 1;
char c{}; auto current_line = 1u; while (current_line != start_line && file.get(c)) { if (c == '\n') { ++current_line; } } std::cout << (current_line==line ? "> " : " ");