[原创]修正lldb-310及以后版本的Thumb反汇编问题
此方法仅仅是临时修改方案!
This is just a dirty fix!
前提
1.ARMv7s程序
2.使用Thumb2指令集
3.无完整符号信息
问题
lldb执行反汇编时需要确定该地址的指令集,lldb会利用FunctionStarts中的地址生成符号信息。这样即使没有完整调试符号,使用lldb也进行基本的汇编级调试。如果某一个地址查询不到任何符号,那么lldb将默认以ARM指令集去处理后续工作。符号解析过程需要主程序的节表中的一些信息,空节表会导致无法正常完成符号解析过程。
跟踪解析符号可以发现其中用到了LINKEDIT段的地址。这一数据就是从节表中查询得来的,如果节表为空,将返回无效地址(-1)。但符号解析相关的代码直接使用了查询结果,并未判断此地址是否有效。
在lldb-310中,由于意外的清空了节表, 导致后续的符号解析过程出错,从而损失了本应存在的符号信息。这就是lldb-310以后没有完整调试符号时无法反汇编及追踪使用Thumb2指令集的代码块的原因。
解决方法
修改源代码
找到Source/Target/Target.cpp
将Target::SetExecutableModule做如下修改
void
Target::SetExecutableModule (ModuleSP& executable_sp, bool get_dependent_files)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TARGET));
//ClearModules(false);
ModulesDidUnload (m_images, false);
//m_section_load_history.Clear();
m_images.Clear();
m_scratch_ast_context_ap.reset();
m_scratch_ast_source_ap.reset();
m_ast_importer_ap.reset();
if (executable_sp.get())
{ ... }
}
修改的目的是保留当前主程序的节信息。lldb-310引入了节加载与卸载的历史纪录,这个功能正是由这个SectionHistory对象实现的。修改后此段逻辑与lldb-300同样片段一致,目前看上去不清理SectionHistory不影响后续使用。这个问题应该是lldb-310引入的缺陷. 由于绝大部分使用lldb的场合都有完整符号支持, 所以不会暴露出这个缺陷。
如果不想自己编译lldb, 也可修改文件跳过Target::ClearModules中m_section_load_history.Clear()这条语句即可。一般情况不会有显著的副作用。
稍后将此问题向lldb社区反馈。希望能在未来版本得到修正。正式的修复方案应该会更加严密。
---------------------------------------------------------------------------------------------------
A Short English Version
Fixing Thumb Disassemble Issue of LLDB-310 and Later
Symptoms
The lldb-310 and later revisions couldn't disassemble and trace thumb code block correctly without full debug symbols.
Analyse
It's must be a defect brought by the lldb-310, because the lldb-300 could handle thumb code block correctly without full debug symbols. It's done by utilising the FunctionStarts data embedded in a modern MachO file. the symbol parsing phase needs section list of the executable which maintained by Target:m_section_load_history. An empty section list will leads to misinterpreting some data, one of them is the FunctionStarts data.
Resolution
Modify the code of Target::SetExecutableModule in Source/Target/Target.cpp in LLDB source tree. Do not clear the m_section_load_history.
like this:
void
Target::SetExecutableModule (ModuleSP& executable_sp, bool get_dependent_files)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TARGET));
//ClearModules(false);
ModulesDidUnload (m_images, false);
//m_section_load_history.Clear();
m_images.Clear();
m_scratch_ast_context_ap.reset();
m_scratch_ast_source_ap.reset();
m_ast_importer_ap.reset();
if (executable_sp.get())
{ ... }
}
