强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

LLVM 开发指南 / 第 16 章:LLDB 调试器

第 16 章:LLDB 调试器

“好的调试器让你看见程序运行的真相。”


16.1 LLDB 概述

LLDB 是 LLVM 项目的调试器,基于 LLVM 和 Clang 构建。

特性说明
高性能使用 LLVM 反汇编器和 Clang 表达式解析
模块化基于库设计,可嵌入
Python 脚本完整的 Python 脚本化 API
兼容 GDB兼容大部分 GDB 命令
跨平台macOS, Linux, Windows, FreeBSD

16.2 基础命令

# 启动 LLDB
lldb ./program
lldb -c core           # 分析 core dump
lldb -p <pid>          # 附加到进程

# GDB 兼容模式
lldb --no-use-colors ./program

16.2.1 常用命令

# 启动和运行
(lldb) run                          # 运行程序
(lldb) run arg1 arg2                # 带参数运行
(lldb) process launch -- arg1       # 另一种方式
(lldb) quit                         # 退出

# 断点
(lldb) break set -n main            # 函数断点
(lldb) break set -f test.c -l 10    # 文件行断点
(lldb) break set -n foo -c 'x > 5'  # 条件断点
(lldb) break set -a 0x1234          # 地址断点
(lldb) break set -n foo --count 5   # 忽略前 5 次
(lldb) break list                   # 列出断点
(lldb) break delete 1               # 删除断点
(lldb) break disable 1              # 禁用断点
(lldb) break enable 1               # 启用断点

# 执行控制
(lldb) step                         # 单步进入 (s)
(lldb) next                         # 单步跳过 (n)
(lldb) stepi                        # 指令级单步
(lldb) nexti                        # 指令级跳过
(lldb) continue                     # 继续执行 (c)
(lldb) finish                       # 运行到函数返回

# 查看变量
(lldb) frame variable               # 当前帧变量
(lldb) frame variable x             # 特定变量
(lldb) frame variable -r 3          # 递归 3 层展开
(lldb) expression x                 # 表达式求值
(lldb) expression x = 42            # 修改变量
(lldb) po x                         # 打印对象 (ObjC/Swift)
(lldb) p x                          # 打印值

# 调用栈
(lldb) bt                           # 回溯 (backtrace)
(lldb) frame select 3               # 选择栈帧
(lldb) thread list                  # 线程列表
(lldb) thread select 2              # 选择线程

# 内存和寄存器
(lldb) memory read 0x1234           # 读内存
(lldb) memory read -fx -c 64 $rsp   # 读栈
(lldb) register read                # 读寄存器
(lldb) register read $rax           # 读特定寄存器

# 断点命令
(lldb) watch set var x              # 变量监视
(lldb) watch set expression -- *(int*)0x1234  # 地址监视

16.3 Python 脚本化

16.3.1 Python 命令

# my_script.py — 自定义 LLDB 命令
import lldb

def print_registers(debugger, command, result, internal_dict):
    """打印所有通用寄存器"""
    target = debugger.GetSelectedTarget()
    process = target.GetProcess()
    thread = process.GetSelectedThread()
    frame = thread.GetSelectedFrame()
    
    regs = ["rax", "rbx", "rcx", "rdx", "rsi", "rdi", 
            "rbp", "rsp", "r8", "r9", "r10", "r11",
            "r12", "r13", "r14", "r15", "rip"]
    
    for reg_name in regs:
        reg = frame.FindRegister(reg_name)
        if reg.IsValid():
            print(f"  {reg_name}: {reg.GetValue()}")

def my_backtrace(debugger, command, result, internal_dict):
    """自定义回溯"""
    target = debugger.GetSelectedTarget()
    process = target.GetProcess()
    thread = process.GetSelectedThread()
    
    print(f"线程 {thread.GetIndexID()}: {thread.GetName()}")
    for frame in thread:
        name = frame.GetFunctionName()
        line = frame.GetLineEntry().GetLine()
        file = frame.GetLineEntry().GetFileSpec().GetFilename()
        print(f"  #{frame.GetFrameID()} {name} at {file}:{line}")

# 注册命令
def __lldb_init_module(debugger, internal_dict):
    debugger.HandleCommand(
        'command script add -f my_script.print_registers regs')
    debugger.HandleCommand(
        'command script add -f my_script.my_backtrace mybt')
    print("自定义命令已加载: regs, mybt")
# 在 LLDB 中加载脚本
(lldb) command script import my_script.py
(lldb) regs
(lldb) mybt

16.3.2 条件断点脚本

# 在断点触发时执行 Python 代码
def breakpoint_handler(frame, bp_loc, dict):
    """断点命中时打印调用参数"""
    func = frame.GetFunctionName()
    args = frame.GetFunction().GetArguments()
    
    print(f"=== 命中断点: {func} ===")
    for arg in args:
        print(f"  {arg.GetName()}: {arg.GetValue()}")
    
    return True  # 继续执行

# 在 LLDB 中使用
(lldb) break set -n my_function
(lldb) break command add -F my_script.breakpoint_handler 1

16.3.3 自定义数据格式化

# 为自定义类型定义显示格式
class MyVectorSyntheticProvider:
    """显示 std::vector 内容"""
    
    def __init__(self, valobj, dict):
        self.valobj = valobj
        self.update()
    
    def update(self):
        self.start = self.valobj.GetChildMemberWithName('_start')
        self.finish = self.valobj.GetChildMemberWithName('_finish')
    
    def num_children(self):
        start_addr = self.start.GetValueAsUnsigned()
        finish_addr = self.finish.GetValueAsUnsigned()
        return int((finish_addr - start_addr) / 4)  # sizeof(int)
    
    def get_child_at_index(self, index):
        offset = index * 4
        return self.start.CreateChildAtOffset(
            f'[{index}]', offset, self.start.GetType())
    
    def get_child_index(self, name):
        return int(name.strip('[]'))

def __lldb_init_module(debugger, internal_dict):
    debugger.HandleCommand(
        'type synthetic add -l my_script.MyVectorSyntheticProvider MyVector')

16.4 与 GDB 对比

特性LLDBGDB
表达式解析Clang(支持 C++17+)内置解析器
脚本语言PythonPython
架构模块化、库化单体
macOS原生支持有限
Rust通过插件通过插件
启动速度
社区Apple/LLVMGNU

16.5 LLDB 扩展

16.5.1 自定义 LLDB 插件

// MyLLDBPlugin.cpp
#include "lldb/API/LLDB.h"
#include "lldb/API/SBDebugger.h"
#include "lldb/API/SBCommandInterpreter.h"

class MyPlugin : public lldb::SBCommandPluginInterface {
public:
    bool DoExecute(lldb::SBDebugger debugger, char **command,
                   lldb::SBCommandReturnObject &result) override {
        result.AppendMessage("Hello from MyPlugin!");
        result.SetStatus(lldb::eReturnStatusSuccessFinishResult);
        return true;
    }
};

16.5.2 core dump 分析

# 生成 core dump
ulimit -c unlimited
./program  # 崩溃后生成 core

# 分析 core dump
lldb -c core ./program
(lldb) bt
(lldb) frame variable
(lldb) thread list
(lldb) image list  # 加载的模块

16.6 本章小结

概念要点
基础命令run, break, step, next, bt, frame
Python 脚本command script add/import
断点处理-F 回调函数
数据格式化type synthetic add
GDB 兼容大部分 GDB 命令可直接使用

扩展阅读

  1. LLDB Documentation — LLDB 官方文档
  2. LLDB Python Reference — Python API
  3. LLDB Tutorial — 教程
  4. GDB to LLDB — GDB 命令映射

下一章: 第 17 章:MLIR — 学习 MLIR 多级 IR 框架。