CLI-Anything 之 LLDB 调试 Harness 规范:把 LLDB 变成 Agent 原生、可脚本化的有状态调试后端

发布时间:2026/9/10 9:25:45
CLI-Anything 之 LLDB 调试 Harness 规范:把 LLDB 变成 Agent 原生、可脚本化的有状态调试后端 CLI-Anything 之 LLDB 调试 Harness 规范把 LLDB 变成 Agent 原生、可脚本化的有状态调试后端【免费下载链接】CLI-AnythingCLI-Anything: Making ALL Software Agent-Native -- CLI-Hub: https://clianything.cc/项目地址: https://gitcode.com/GitHub_Trending/cl/CLI-Anything本指南解析 CLI-Anything 仓库中 LLDB 工具族的官方 Harness 规范HARNESS.md它定义了如何用LLDB Python API而非脆弱的子进程文本解析构建出面向 AI Agent 与脚本的两条正式入口JSON CLI/REPL 工具cli-anything-lldb与 stdio Debug Adapter ProtocolDAP服务器cli-anything-lldb-dap。读完本文你将掌握该 harness 的架构布局、全部命令组、持久化调试会话机制、DAP 协议实现要点以及其背后八条可复用的设计模式并能在 macOS/Linux/Windows 上完成安装、运行、JSON 工作流与 DAP 对接。概览两个入口一个状态内核HARNESS.md 明确了lldb/agent-harness的定位将 LLDB Python API 包装为 Click 驱动的 CLI 工具与调试适配器。与“通过lldb -b -o ...子进程抓取文本”的脆弱方案不同该 harness 选择进程内直接import lldb的原生集成路线从而获得完整、无妥协的专业能力这也是 CLI-Anything 的一贯原则见 LLDB.md。对外暴露两个 Agent 可用的入口由 setup.py 中的console_scripts声明入口场景说明cli-anything-lldbJSON CLI / REPL 工作流命令式、可单条执行的调试控制底层复用持久会话cli-anything-lldb-dapstdio DAP 客户端面向编辑器与 AI 调试客户端的正式单会话 DAP 服务器核心能力包括直接import lldb集成、面向 JSON 模式的结构化 dict 输出、带持久调试会话的交互式 REPL、以及正式的单会话 DAP 服务器。会话对象LLDBSession拥有 debugger/target/process 的完整生命周期命令与 DAP 两条路径共享同一套有状态内核核心实现见 core/session.py。架构与模块布局规范给出了模块结构。以仓库根目录为基准完整布局如下lldb/ ├── agent-harness/ │ ├── HARNESS.md # 本文所讲的 Harness 规范 │ ├── LLDB.md # 后端接入笔记为何用 LLDB Python API │ ├── setup.py # 打包与两个 console_scripts 入口 │ └── cli_anything/lldb/ │ ├── lldb_cli.py # Click CLI 根组与全部命令组 │ ├── __main__.py │ ├── dap.py # stdio DAP 服务器LLDBDebugAdapter │ ├── core/ │ │ ├── session.py # LLDBSession有状态会话封装 │ │ ├── breakpoints.py # 断点相关核心逻辑 │ │ ├── inspect.py # 检查类逻辑 │ │ └── threads.py # 线程相关核心逻辑 │ ├── utils/ │ │ ├── lldb_backend.py # import lldb 的惰性加载与路径发现 │ │ ├── output.py # JSON/人类友好双输出 │ │ ├── errors.py # 结构化错误负载 │ │ ├── repl_skin.py # REPL 皮肤 │ │ ├── session_client.py # 持久会话客户端本地 JSON socket │ │ └── session_server.py # 持久会话守护进程 │ ├── skills/SKILL.md │ ├── README.md │ └── tests/ │ ├── test_core.py │ ├── test_full_e2e.py │ └── TEST.md从源码结构看分层意图非常清晰core/封装 LLDB SB 系列对象的操作并返回纯 dictutils/解决“能否 import 到 lldb”“如何输出”“出错如何表达”“会话放哪里”等横切问题lldb_cli.py与dap.py是两个对外消费层。全局选项cli-anything-lldb在根组声明了四项全局选项实现见 lldb_cli.py--json机器可读输出。所有核心方法返回 JSON 可序列化的 dict/list直接映射为 JSON 输出供 Agent 工作流消费--debug出错时在错误信息中包含 traceback--session-file显式指定持久 CLI 会话状态文件的路径--version显示包版本。在 CLI 层这些选项被写入ctx.obj并由_output()在 JSON 与人类友好格式化之间切换、由_handle_exc()把异常转成结构化错误负载。命令组总览Harness 用 12 个命令组覆盖目标、进程、断点、线程、栈帧、单步、表达式、内存、Core dump、DAP、会话与 REPL命令组子命令 / 用法语义targetcreate --exe PATH [--arch]/info创建或查看调试目标processlaunch [--arg --env --cwd --stop-at-entry]、attach [--pid\|--name\|--wait-for]、continue、interrupt、detach、info进程生命周期管理breakpointset [--file --line\|--function] [--condition] [--allow-pending]、list、delete --id、enable --id、disable --id断点操作threadlist、select --id、backtrace [--limit]、info线程操作frameselect --index、info、locals栈帧操作stepover、into、out单步执行exprexpr expression在当前帧求值表达式memoryread --address --size、find needle --start --size内存读写/搜索coreload --path加载 Core dumpdap[--log-file] [--profile]运行 stdio DAP 服务器sessioninfo、close持久 CLI 会话生命周期repl默认模式交互式会话命令级详细参数见 LLDB.md 同级 README 的命令组清单CLI 组件的 Click 定义集中在 lldb_cli.py。依赖模型与安装LLDB 是必需后端依赖README 与 HARNESS.md 均给出# macOS xcode-select --install # Ubuntu sudo apt install lldb python3-lldb # Windows winget install LLVM.LLVM安装并确保lldb在PATH上后harness 通过lldb -P自动发现 LLDB Python 绑定目录lldb -P随后安装包本身仓库内路径执行cd lldb/agent-harness pip install -e .安装后即可使用cli-anything-lldb与cli-anything-lldb-dap两个命令包依赖click8.0、prompt-toolkit3.0Python 要求3.10参见 setup.py。绑定自动发现的实现细节utils/lldb_backend.py实现了规范的集成策略见 lldb_backend.py先尝试普通import lldb失败时运行lldb -P探测 LLDB Python 模块目录把发现的路径前置插入sys.path重试导入。若lldb可执行文件都不存在会抛出带安装提示的RuntimeErrormacOS/Ubuntu/Windows 三条安装命令被内置在_install_hint()中若路径存在但绑定仍导入失败则提示检查 LLDB 安装与 Python 版本兼容性。这条“先直连、失败再探测”的路径在首次真正需要会话时才触发——这正是“LLDB 惰性导入”模式的落地。快速开始JSON CLI 有状态工作流非 REPL 命令默认共享一个自动维持的持久 LLDB 会话因此target create、breakpoint set、process launch与后续检查命令可以分成多次独立的 CLI 调用执行却命中同一个活跃调试器状态。完整工作流如下# 查看帮助 cli-anything-lldb --help # 创建目标 cli-anything-lldb --json target create --exe /path/to/executable # 启动进程并传入参数 cli-anything-lldb --json process launch --arg foo --arg bar # 在用户代码执行前停在进程入口 cli-anything-lldb --json process launch --stop-at-entry # 按函数设置断点 cli-anything-lldb --json breakpoint set --function main # 挂起断点必须显式声明 cli-anything-lldb --json breakpoint set --function PluginEntry --allow-pending # 继续与检查 cli-anything-lldb --json process continue cli-anything-lldb --json process interrupt cli-anything-lldb --json thread backtrace cli-anything-lldb --json frame locals # 在当前帧求值表达式 cli-anything-lldb --json expr argc # 结束持久会话 cli-anything-lldb --json session close # 直接进入交互式 REPL默认模式无子命令即触发 cli-anything-lldb会话状态文件与安全约束默认会话状态文件位于每个用户的专属应用目录而非全局临时目录。当 Agent 需要显式路径时可用--session-file path或环境变量CLI_ANYTHING_LLDB_SESSION_FILE指定用完后运行session close清理。CLI 侧通过utils/session_client.py的resolve_session_file解析会话路径见 lldb_cli.py。会话守护进程的持久化由utils/session_server.py承担CLI 会话鉴权状态被写入按用户隔离的目录并施加严格权限RPC 分发使用显式方法白名单。README 说明持久会话守护进程现在走 localhost JSON socket 协议会话令牌存放在 owner 专属的状态文件中——这两点正对应 HARNESS 模式的第 7 条“安全持久守护进程”。诚实断点状态honest breakpoint state默认情况下breakpoint set若在 LLDB 中创建的是没有任何已解析位置的挂起断点命令将失败只有在预期目标或符号稍后才加载时才应使用--allow-pending。断点负载包含resolved与location_details字段Agent 可据此判断某个 stop 是否真实可达。底层实现位于 session.py创建断点后调用_breakpoint_payload()统计解析位置若resolved为假且未传allow_pending会先BreakpointDelete再抛出明确错误。负载里除resolved外还包括id、hits、locations数量、location_details每个位置的地址/文件/行/列/函数/启用状态/命中次数、enabled、condition。数据模型全部返回纯字典HARNESS 与 LLDB.md 共同确定了数据契约——所有核心操作返回普通 dict进程信息pid、state、num_threads停止信息reason、description、module、function、frame帧信息function、file、line、address断点id、locations、condition表达式结果type、value、summary、error这与--json输出模式一一对应LLDB.md 的 “Data Model” 一节。进程状态由 session.py 中的_STATE_NAMES映射为字符串invalid/unloaded/connected/attaching/launching/stopped/running/stepping/crashed/detached/exited/suspended停止原因_stop_reason_name把 LLDB 枚举归一化为breakpoint、watchpoint、signal、exception、step、entry等可读值命中断点 ID 由_hit_breakpoint_ids从GetStopReasonDataAtIndex成对解析。会话生命周期遵循规范LLDB.mdSBDebugger.Initialize后SBDebugger.Create创建调试器同步模式SetAsync(False)保证确定性命令行为见 session.py会话关闭时destroy()按process_originattached 则 Detach、launched 则 Kill清理进程再SBDebugger.Destroy与Terminate。Debug Adapter Protocol 服务器cli-anything-lldb-dap是stdio DAP 服务器。关键约束它拥有一个进程内LLDBSession不使用持久 CLI 守护进程stdout 上只允许出现 DAP 的Content-Length帧诊断信息一律走 stderr 或--log-fileDAP 启动期间被调试程序的 stdout/stderr 会被抑制以免污染协议帧。DAP 消息编解码在 dap.pyencode_message组装Content-Length头与紧凑 JSON 体read_message解析头与按长度读取正文畸形头/缺Content-Length/EOF 截断都会抛DAPProtocolError。支持的请求v1生命周期initialize、launch、attach、configurationDone、disconnect断点setBreakpoints、setFunctionBreakpoints检查threads、stackTrace、scopes、variables、setVariable、evaluate、source、loadedSources、readMemory、modules、exceptionInfo、disassemble执行continue、pause、next、stepIn、stepOutDAP 使用协议原生的挂起断点语义启动时未解析的断点返回verified: false启动后若 LLDB 解析成功则以断点事件上报更新。变量引用variable references为适配器本地概念在每次继续执行后重置——这保证了对 AI Agent 暴露的停驻帧状态是真实可信的避免继续执行后复用陈旧的 LLDBSBValue对象。对长运行 GUI 目标的异步控制README 补充了适配器的并发细节对长时间运行的 GUI 目标DAP 的continue在阻塞式SBProcess.Continue()完成前即先行响应再由后台线程等待下一次 stoppause走SBProcess.SendAsyncInterrupt()因此调试对象运行中适配器依然可响应。若在 continue 进行中收到setBreakpoints/setFunctionBreakpoints适配器先请求异步中断、等待 continue 线程观察到停止状态才真正修改断点若进程未及时停下请求会明确失败而不是挂死 DAP 事件循环。Stop 规则与结构化停止分类面对嘈杂的 GUI 调试对象launch/attach接受非标准的停止规则控制参数autoContinueInternalBreakpoints兼容性布尔开关启用内置规则以跳过 NVIDIA__jit_debug_register_code/jit-debug-register以及 Windows 在ntdll.dllDbgBreakPoint处的Exception 0x80000003等常见内部陷阱stopRules内联结构化规则可选字段name、actionstop或continue、origin、reason、module、function、regex。每条规则必须至少包含一个匹配器防止规则意外归类所有停止事件stopRuleProfile/stopProfile/profile为该 launch/attach 请求加载的外部 JSON profile 路径。Profile 也可以从三个位置整体加载cli-anything-lldb-dap --profile PATH、cli-anything-lldb dap --profile PATH、或 launch/attach 参数。规范中的 JSON 示例{ autoContinueInternalBreakpoints: true, stopRules: [ { name: c4d-nvidia-jit, action: continue, origin: internalTrap, module: nvgpucomp64.dll, function: __jit_debug_register_code } ] }每个 DAPstopped事件都带有body.cliAnythingStop.origin扩展客户端可以据此区分手动暂停manualPause、调试器内部陷阱internalTrap与普通调试对象停止debuggee并附带 LLDB 停止原因、module/function/frame 元数据与命中的规则。源码实现位于 dap.pyStopRule.from_mapping校验action只能取stop|continue、预编译regex、并强制“至少一个匹配器”matches()按结构化停止上下文精确匹配其中 module 匹配允许 basename 比较、function 匹配允许Class::func/Modulefunc这类符号后缀。运行中的 DAP 进程不会热加载代码或 profile——新规则/代码内容要生效必须重启适配器后重新 attach/launch。运行时参数解析差异CLI 侧运行 DAP 采用 Click 参数--log-file、--profile见 lldb_cli.py独立入口cli-anything-lldb-dap则用 argparse 风格处理相同参数。两者最终都进入LLDBDebugAdapter主循环。可复用的设计模式HARNESS.md 总结了八条模式可与源码一一对照LLDB 惰性导入绑定只在命令真正需要会话时才导入——session.py构造时才调用ensure_lldb_importable()CLI 层则在_get_session()内按需创建RemoteLLDBSessionProxy会话对象LLDBSession拥有 debugger/target/process 生命周期初始化、同步模式、销毁清理都封装在内Dict-first API核心方法返回可 JSON 序列化的 dict/list天然适配--json诚实断点状态断点负载含resolved与location_detailsCLI 未显式--allow-pending时未解析断点直接失败双输出模式_output()按--json决定走 JSON 还是人类友好格式化utils/output.py 提供output_json边界错误命令层把异常转换为结构化错误负载utils/errors.py 的handle_error--debug时附带 traceback安全持久守护进程CLI 会话鉴权状态写入 per-user 目录并限制权限RPC 分发采用显式方法白名单结构化停止分类DAP 停止处理用 profile 驱动的规则替代临时子串检查同时保留autoContinueInternalBreakpoints作为 NVIDIA/Windows 常见内部陷阱的兼容快捷方式。关键实现约束与当前限制工程化细节决定了 Agent 使用边界内存查找的工程上限find_memory以 64 KiB 分块扫描、单次请求上限 1 MiB常量定义在 session.py块与块之间保留重叠字节以覆盖跨块命中非法 needle/负 size/超限 size 都会得到明确错误。CLI 帮助文本同样标注了max 1048576 bytes的上限见 lldb_cli.py无状态入口的状态约束target create之后才允许breakpoint set/process launchprocess launch/attach/core load之后才有continue/step/expr等操作CLI 的_require_target()/_require_process()会在顺序错误时给出“Run: ...”的修正提示LLDB.md 记录的限制尚无高级 watchpoint 支持内存搜索是对已抓取范围内的朴素字节扫描多目标工作流尚未实现当前为单一活跃 target/session。测试与验证Harness 自带单元与端到端测试README “Testing”一节cd lldb/agent-harness pytest cli_anything/lldb/tests/test_core.py -v pytest cli_anything/lldb/tests/test_full_e2e.py -v pytest cli_anything/lldb/tests -qE2E 测试要求本机具备可用的 C 编译器clang、gcc或cc以便现场构建小型调试辅助程序默认套件无需额外环境变量LLDB_TEST_CORE仅在你希望把负路径的 core 加载检查指向特定本地文件时使用。测试目录内另有 TEST.md 说明测试设计。对 Agent 而言skills/SKILL.md 还提供了供 Agent 直接引用的技能说明与 HARNESS/README 共同构成“规范 使用手册 技能卡”的完整文档链。整个lldb/agent-harness是 CLI-Anything 生态“所有软件 Agent 原生化”主张的调试领域范本原生后端集成、结构化契约、诚实状态语义与可审计的 DAP 扩展四者共同让 LLDB 既适合人用也适合机器用。【免费下载链接】CLI-AnythingCLI-Anything: Making ALL Software Agent-Native -- CLI-Hub: https://clianything.cc/项目地址: https://gitcode.com/GitHub_Trending/cl/CLI-Anything创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考