vault backup: 2026-05-04 23:28:37
This commit is contained in:
@@ -1 +1 @@
|
|||||||
{"要解决这个问题,得对记忆进行合理规划与维护:":{"要解决这个问题,得对记忆进行合理规划与维护:":{"currentFile":{"count":1,"lastUpdated":1774938677236}}},"Openclaw-workspace":{"Openclaw-workspace":{"currentFile":{"count":1,"lastUpdated":1774938879095}}},"workflow":{"workflow":{"currentFile":{"count":1,"lastUpdated":1775020352083}}},"\\AI\\Skill\\MatrixAITA-POPODocs-Skill、D":{"\\AI\\Skill\\MatrixAITA-POPODocs-Skill、D":{"currentFile":{"count":1,"lastUpdated":1776242568663}}},"推荐加在仓库内已有的标准元数据文件中,例如:":{"推荐加在仓库内已有的标准元数据文件中,例如:":{"currentFile":{"count":1,"lastUpdated":1776242909075}}},"推荐加在仓库内已有的标准元数据文件中,":{"推荐加在仓库内已有的标准元数据文件中,":{"currentFile":{"count":1,"lastUpdated":1776242914868}}},"Screenshots":{"Screenshots":{"currentFile":{"count":1,"lastUpdated":1776309732196}}},"WorkSpace":{"WorkSpace":{"currentFile":{"count":1,"lastUpdated":1776315471938}}},"VPS账号 以及PS4 DNS":{"VPS账号 以及PS4 DNS":{"internalLink":{"count":1,"lastUpdated":1776322449307}}},"G37、G37":{"G37、G37":{"currentFile":{"count":1,"lastUpdated":1776416826672}}},"GIt&SVN简报":{"GIt&SVN简报":{"internalLink":{"count":1,"lastUpdated":1776661549625}}},"redoc":{"redoc":{"currentFile":{"count":1,"lastUpdated":1776854054282}}},"的访问权限":{"的访问权限":{"currentFile":{"count":1,"lastUpdated":1776939597742}}}}
|
{"\\AI\\Skill\\MatrixAITA-POPODocs-Skill、D":{"\\AI\\Skill\\MatrixAITA-POPODocs-Skill、D":{"currentFile":{"count":1,"lastUpdated":1776242568663}}},"推荐加在仓库内已有的标准元数据文件中,例如:":{"推荐加在仓库内已有的标准元数据文件中,例如:":{"currentFile":{"count":1,"lastUpdated":1776242909075}}},"推荐加在仓库内已有的标准元数据文件中,":{"推荐加在仓库内已有的标准元数据文件中,":{"currentFile":{"count":1,"lastUpdated":1776242914868}}},"Screenshots":{"Screenshots":{"currentFile":{"count":1,"lastUpdated":1776309732196}}},"WorkSpace":{"WorkSpace":{"currentFile":{"count":1,"lastUpdated":1776315471938}}},"VPS账号 以及PS4 DNS":{"VPS账号 以及PS4 DNS":{"internalLink":{"count":1,"lastUpdated":1776322449307}}},"G37、G37":{"G37、G37":{"currentFile":{"count":1,"lastUpdated":1776416826672}}},"GIt&SVN简报":{"GIt&SVN简报":{"internalLink":{"count":1,"lastUpdated":1776661549625}}},"redoc":{"redoc":{"currentFile":{"count":1,"lastUpdated":1776854054282}}},"的访问权限":{"的访问权限":{"currentFile":{"count":1,"lastUpdated":1776939597742}}},"SDK\\bin\\amd64\\msdia140.dll":{"SDK\\bin\\amd64\\msdia140.dll":{"currentFile":{"count":1,"lastUpdated":1777906125383}}}}
|
||||||
304
03-UnrealEngine/Gameplay/Debug/UE5编辑器开启ASAN.md
Normal file
304
03-UnrealEngine/Gameplay/Debug/UE5编辑器开启ASAN.md
Normal file
@@ -0,0 +1,304 @@
|
|||||||
|
---
|
||||||
|
title: UE5编辑器开启ASAN
|
||||||
|
date: 2026-05-04 22:45:02
|
||||||
|
excerpt:
|
||||||
|
tags:
|
||||||
|
rating: ⭐
|
||||||
|
---
|
||||||
|
UE5的编辑器直接开启ASAN会因为有全局变量初始化依赖问题导致误报阻塞。
|
||||||
|
|
||||||
|
虽然网上以及有人探究过底层原因以及解决方式:[https://zhuanlan.zhihu.com/p/14576791261](https://zhuanlan.zhihu.com/p/14576791261)
|
||||||
|
但是此解法需要修改大量代码而且容易因为UE的升级导致有新代码需要修改,非常不灵活。
|
||||||
|
后面公司的UE交流群里有同事列出更好的解决方式,就是在引擎启动后主动调用DLL的ASAN初始化函数。
|
||||||
|
以下是此修改方式是具体落地修改:
|
||||||
|
## 1. 修改Core.Build.cs
|
||||||
|
|
||||||
|
Core.Build.cs添加DIA SDK依赖
|
||||||
|
```cpp
|
||||||
|
// DIA SDK
|
||||||
|
if (Target.Platform == UnrealTargetPlatform.Win64)
|
||||||
|
{
|
||||||
|
string DiaSdkDir = Target.WindowsPlatform.DiaSdkDir;
|
||||||
|
if (DiaSdkDir == null)
|
||||||
|
{
|
||||||
|
throw new System.Exception("Unable to find DIA SDK directory");
|
||||||
|
}
|
||||||
|
|
||||||
|
string ToolChainDir = Target.WindowsPlatform.ToolChainDir;
|
||||||
|
string ToolChainArch = (Target.Architecture == UnrealArch.Arm64) ? "arm64" : "x64";
|
||||||
|
PrivateIncludePaths.Add(Path.Combine(ToolChainDir, "atlmfc", "include"));
|
||||||
|
PublicAdditionalLibraries.Add(Path.Combine(ToolChainDir, "atlmfc", "lib", ToolChainArch, "atls.lib"));
|
||||||
|
|
||||||
|
string DiaArch = (Target.Architecture == UnrealArch.Arm64) ? "arm64" : "amd64";
|
||||||
|
PrivateIncludePaths.Add(Path.Combine(DiaSdkDir, "include"));
|
||||||
|
PublicAdditionalLibraries.Add(Path.Combine(DiaSdkDir, "lib", DiaArch, "diaguids.lib"));
|
||||||
|
RuntimeDependencies.Add("$(TargetOutputDir)/msdia140.dll", Path.Combine(DiaSdkDir, "bin", DiaArch, "msdia140.dll"));
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2.新建下面文件到此路径里编译 [Engine/Source/Runtime/Core/Private/Windows/](https://km.netease.com/v4/detail/blog/254722),命名随意,如AsanInitializer.cpp
|
||||||
|
```cpp
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <tchar.h>
|
||||||
|
#include <psapi.h>
|
||||||
|
#include <dia2.h>
|
||||||
|
#include <debugapi.h>
|
||||||
|
#include <cassert>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Debug Print Utility
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
template<typename ...TArgs, size_t size>
|
||||||
|
static void DebugPrint(const TCHAR(&format)[size], TArgs&&... args)
|
||||||
|
{
|
||||||
|
TCHAR msg[1024] = {};
|
||||||
|
int written = _stprintf_s(msg, format, std::forward<TArgs>(args)...);
|
||||||
|
if (written <= 0)
|
||||||
|
return;
|
||||||
|
OutputDebugString(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Symbol Resolution using DIA SDK
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
class SimpleDiaCallback : public IDiaLoadCallback2
|
||||||
|
{
|
||||||
|
LONG m_refCount = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID rid, void** ppUnk) override
|
||||||
|
{
|
||||||
|
if (!ppUnk) return E_INVALIDARG;
|
||||||
|
|
||||||
|
if (rid == __uuidof(IDiaLoadCallback2) ||
|
||||||
|
rid == __uuidof(IDiaLoadCallback) ||
|
||||||
|
rid == __uuidof(IUnknown))
|
||||||
|
{
|
||||||
|
*ppUnk = this;
|
||||||
|
AddRef();
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
*ppUnk = nullptr;
|
||||||
|
return E_NOINTERFACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG STDMETHODCALLTYPE AddRef() override { return ++m_refCount; }
|
||||||
|
ULONG STDMETHODCALLTYPE Release() override
|
||||||
|
{
|
||||||
|
auto count = --m_refCount;
|
||||||
|
if (count == 0) delete this;
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 实现必要的回调方法
|
||||||
|
HRESULT STDMETHODCALLTYPE NotifyDebugDir(BOOL, DWORD, BYTE*) override { return S_OK; }
|
||||||
|
HRESULT STDMETHODCALLTYPE NotifyOpenDBG(LPCOLESTR, HRESULT) override { return S_OK; }
|
||||||
|
HRESULT STDMETHODCALLTYPE NotifyOpenPDB(LPCOLESTR, HRESULT) override { return S_OK; }
|
||||||
|
HRESULT STDMETHODCALLTYPE RestrictRegistryAccess() override { return S_OK; }
|
||||||
|
HRESULT STDMETHODCALLTYPE RestrictSymbolServerAccess() override { return S_OK; }
|
||||||
|
HRESULT STDMETHODCALLTYPE RestrictOriginalPathAccess() override { return S_OK; }
|
||||||
|
HRESULT STDMETHODCALLTYPE RestrictReferencePathAccess() override { return S_OK; }
|
||||||
|
HRESULT STDMETHODCALLTYPE RestrictDBGAccess() override { return S_OK; }
|
||||||
|
HRESULT STDMETHODCALLTYPE RestrictSystemRootAccess() override { return S_OK; }
|
||||||
|
};
|
||||||
|
|
||||||
|
static DWORD GetSymbolOffset(HMODULE hModule, const wchar_t* name)
|
||||||
|
{
|
||||||
|
wchar_t moduleName[MAX_PATH] = {};
|
||||||
|
GetModuleFileNameW(hModule, moduleName, MAX_PATH);
|
||||||
|
|
||||||
|
HRESULT hr = CoInitialize(nullptr);
|
||||||
|
bool needUninitialize = SUCCEEDED(hr);
|
||||||
|
|
||||||
|
IDiaDataSource* diaDataSource = nullptr;
|
||||||
|
hr = CoCreateInstance(__uuidof(DiaSource), nullptr, CLSCTX_INPROC_SERVER,
|
||||||
|
__uuidof(IDiaDataSource), (void**)&diaDataSource);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
if (needUninitialize) CoUninitialize();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleDiaCallback* callback = new SimpleDiaCallback();
|
||||||
|
callback->AddRef();
|
||||||
|
|
||||||
|
hr = diaDataSource->loadDataForExe(moduleName, nullptr, callback);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
callback->Release();
|
||||||
|
diaDataSource->Release();
|
||||||
|
if (needUninitialize) CoUninitialize();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
IDiaSession* session = nullptr;
|
||||||
|
hr = diaDataSource->openSession(&session);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
callback->Release();
|
||||||
|
diaDataSource->Release();
|
||||||
|
if (needUninitialize) CoUninitialize();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
IDiaSymbol* globalSymbol = nullptr;
|
||||||
|
hr = session->get_globalScope(&globalSymbol);
|
||||||
|
|
||||||
|
DWORD result = 0;
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
IDiaEnumSymbols* enumSymbols = nullptr;
|
||||||
|
if (SUCCEEDED(globalSymbol->findChildren(SymTagFunction, name, nsRegularExpression, &enumSymbols)))
|
||||||
|
{
|
||||||
|
IDiaSymbol* symbol = nullptr;
|
||||||
|
ULONG count = 0;
|
||||||
|
while (SUCCEEDED(enumSymbols->Next(1, &symbol, &count)) && count == 1)
|
||||||
|
{
|
||||||
|
wchar_t* symbolName = nullptr;
|
||||||
|
if (SUCCEEDED(symbol->get_name(&symbolName)) && wcscmp(symbolName, name) == 0)
|
||||||
|
{
|
||||||
|
symbol->get_relativeVirtualAddress(&result);
|
||||||
|
}
|
||||||
|
symbol->Release();
|
||||||
|
}
|
||||||
|
enumSymbols->Release();
|
||||||
|
}
|
||||||
|
globalSymbol->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
session->Release();
|
||||||
|
callback->Release();
|
||||||
|
diaDataSource->Release();
|
||||||
|
if (needUninitialize) CoUninitialize();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FARPROC MyGetSymbolAddress(HMODULE hModule, const wchar_t* name)
|
||||||
|
{
|
||||||
|
DWORD offset = GetSymbolOffset(hModule, name);
|
||||||
|
if (offset == 0)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return (FARPROC)((char*)hModule + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// ASAN Pre-Initialization
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
static int ExecInitializeClonedVariables(HMODULE hModule)
|
||||||
|
{
|
||||||
|
using InitializeClonedVariablesFunc = int();
|
||||||
|
auto InitializeClonedVariables = (InitializeClonedVariablesFunc*)MyGetSymbolAddress(hModule, L"__asan_initialize_cloned_variables");
|
||||||
|
if (!InitializeClonedVariables)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TCHAR moduleName[MAX_PATH] = {};
|
||||||
|
if (GetModuleFileName(hModule, moduleName, MAX_PATH) > 0)
|
||||||
|
{
|
||||||
|
DebugPrint(_T("AsanPreInit: Call InitializeClonedVariables on %s\n"), moduleName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return InitializeClonedVariables();
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<HMODULE> GetModules(HANDLE hProcess)
|
||||||
|
{
|
||||||
|
size_t count = 2048;
|
||||||
|
std::vector<HMODULE> modHandles;
|
||||||
|
DWORD cbNeeded;
|
||||||
|
size_t loadedCount = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
modHandles.resize(count);
|
||||||
|
size_t size = modHandles.size() * sizeof(HMODULE);
|
||||||
|
assert(size < MAXDWORD);
|
||||||
|
if (!EnumProcessModules(hProcess, modHandles.data(), (DWORD)size, &cbNeeded))
|
||||||
|
{
|
||||||
|
DebugPrint(_T("EnumProcessModules failed: %d\n"), GetLastError());
|
||||||
|
}
|
||||||
|
loadedCount = cbNeeded / sizeof(HMODULE);
|
||||||
|
if (loadedCount < modHandles.size())
|
||||||
|
{
|
||||||
|
modHandles.resize(loadedCount);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
count *= 2;
|
||||||
|
} while (loadedCount <= 10000);
|
||||||
|
return modHandles;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::unordered_set<std::string> GetMainBinaries()
|
||||||
|
{
|
||||||
|
TCHAR executable[1024] = {};
|
||||||
|
GetModuleFileName(nullptr, executable, sizeof(executable));
|
||||||
|
fs::path execPath(executable);
|
||||||
|
std::unordered_set<std::string> binaries;
|
||||||
|
for (auto& entry : fs::directory_iterator(execPath.parent_path()))
|
||||||
|
{
|
||||||
|
auto filename = entry.path().filename();
|
||||||
|
if (filename.extension() == ".dll")
|
||||||
|
{
|
||||||
|
binaries.emplace(filename.string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return binaries;
|
||||||
|
}
|
||||||
|
|
||||||
|
__declspec(dllexport) bool AsanPreInit_Setup()
|
||||||
|
{
|
||||||
|
auto modules = GetModules(GetCurrentProcess());
|
||||||
|
auto binaries = GetMainBinaries();
|
||||||
|
HANDLE process = GetCurrentProcess();
|
||||||
|
for (auto& mod : modules)
|
||||||
|
{
|
||||||
|
if (!mod)
|
||||||
|
continue;
|
||||||
|
if (mod == (HMODULE)&__ImageBase)
|
||||||
|
continue;
|
||||||
|
char baseName[MAX_PATH] = {};
|
||||||
|
GetModuleBaseNameA(process, mod, baseName, sizeof(baseName));
|
||||||
|
// 简单过滤下除当前执行文件目录外的动态库
|
||||||
|
if (!binaries.count(baseName))
|
||||||
|
continue;
|
||||||
|
ExecInitializeClonedVariables(mod);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
class AsanPreInit
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AsanPreInit() { AsanPreInit_Setup(); }
|
||||||
|
};
|
||||||
|
static AsanPreInit g_Init;
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3.正常运行
|
||||||
|
首次运行可能会有DIA报错,按照下图方式修复
|
||||||
|
|
||||||
|
根本原因
|
||||||
|
系统注册表中找不到 DiaSource 的 CLSID,即msdia140.d11(或对应版本)没有被注册到 Windows COM 注册表中。
|
||||||
|
|
||||||
|
解决方案一:注册msdia*.dll (需要管理员权限)
|
||||||
|
以管理员身份运行 CMD,执行以下命令(根据你的 VS 版本选择):
|
||||||
|
1. VS2022
|
||||||
|
1. regsvr32 "C:\Program Files\Microsoft Visual Studio\2022\Professional\DIA SDK\bin\amd64\msdia140.dll"
|
||||||
|
2. VS2019
|
||||||
|
1. regsvr32 "C:\Program Files (x86) \Microsoft Visual Studio\2019\Professional\DIA SDK\bin\amd64\msdia140.dll"
|
||||||
|
3. VS2017
|
||||||
|
1. regsvr32 "C:\Program Files (x86) \Microsoft Visual Studio\2017\Professional\DIA SDK\bin\amd64\msdia140.dll"
|
||||||
|
注册成功后再运行代码即可
|
||||||
15
07-Other/AI/AI Agent/Renderdoc/Renderdoc.md
Normal file
15
07-Other/AI/AI Agent/Renderdoc/Renderdoc.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
title: "AI一键生成完整截帧分析 RenderDocWorkflow-网易KM"
|
||||||
|
source: "https://km.netease.com/v4/detail/blog/264805"
|
||||||
|
author:
|
||||||
|
published:
|
||||||
|
created: 2026-05-04
|
||||||
|
description:
|
||||||
|
tags:
|
||||||
|
- "clippings"
|
||||||
|
---
|
||||||
|
- 文章
|
||||||
|
- AI一键生成完整截帧分析 RenderDocWorkflow https://km.netease.com/v4/detail/blog/264805
|
||||||
|
- 相关仓库
|
||||||
|
- RenderDocMCP:http://git-internal.nie.netease.com/mcpanalyzer/RenderDocMCP
|
||||||
|
- RenderDocWorkflow:http://git-internal.nie.netease.com/mcpanalyzer/RenderDocWorkflow
|
||||||
@@ -10,16 +10,56 @@
|
|||||||
- UnrealMcp
|
- UnrealMcp
|
||||||
- Puerts
|
- Puerts
|
||||||
- Puerts Editor
|
- Puerts Editor
|
||||||
- uecli
|
- **uecli**
|
||||||
- Readme的材质都是agent调用uecli做的 帮我生产材质 排版材质节点 帮我场景截图,帮我材质蓝图截图 帮我写readme 帮我提交仓库。 https://github.com/wlxklyh/UECLI
|
- Readme的材质都是agent调用uecli做的 帮我生产材质 排版材质节点 帮我场景截图,帮我材质蓝图截图 帮我写readme 帮我提交仓库。 https://github.com/wlxklyh/UECLI
|
||||||
- 通过蓝图转c++功能,让AI读懂蓝图
|
- **通过蓝图转c++功能,让AI读懂蓝图**
|
||||||
- IDE Debug MCP
|
|
||||||
|
- Debug
|
||||||
|
- 雷火MCP**IDE Debug MCP**
|
||||||
- https://km.netease.com/v4/section/aigc/detail/blog/263683
|
- https://km.netease.com/v4/section/aigc/detail/blog/263683
|
||||||
- cpp-debugger-cli
|
- cpp-debugger-cli
|
||||||
|
- 互娱
|
||||||
|
- **从 ASAN 到 AI 的“接力排查”** https://km.netease.com/v4/detail/blog/256465
|
||||||
|
- **1. 借助 ASAN 把“指针变野”的时间点钉住**
|
||||||
|
- 第一步是启用 ASAN(AddressSanitizer)来辅助定位:
|
||||||
|
- 在 UE5 编辑器环境启用 ASAN,本身需要做一些额外工作:[https://km.netease.com/v4/detail/blog/254722](https://km.netease.com/v4/detail/blog/254722)
|
||||||
|
- 这些环境搭建细节本文不展开,只强调结论:ASAN 成功启用,可以看到完整的分配 / 释放栈。
|
||||||
|
- https://km.netease.com/v4/detail/blog/260127
|
||||||
|
- [RiderDebugMcp](http://git-internal.nie.netease.com/mcpanalyzer/RiderDebugMcp)
|
||||||
|
- [VSDebugMCP](http://git-internal.nie.netease.com/mcpanalyzer/VSDebugMCP)
|
||||||
|
- [UnrealMCP](http://git-internal.nie.netease.com/mcpanalyzer/UnrealMCP)
|
||||||
|
- [ue-reference-diagnostic-mcp](http://git-internal.nie.netease.com/mcpanalyzer/ue-reference-diagnostic-mcp)
|
||||||
|
- LLDB MCP https://lldb.llvm.org/use/mcp.html
|
||||||
|
- 其他仓库
|
||||||
|
- https://github.com/akiselev/debugger-cli
|
||||||
- Docker
|
- Docker
|
||||||
- Gitea:工单以及版本管理。
|
- Gitea:工单以及版本管理。
|
||||||
- OpenClaw:子节点部署,通过父节点进行控制。
|
- ~~OpenClaw:子节点部署,通过父节点进行控制。~~
|
||||||
- SMB服务。
|
- SMB服务。
|
||||||
- Obsidian Cli:文档管理。
|
- Obsidian Cli:文档管理。
|
||||||
|
|
||||||
## UE测试技术
|
## UE测试技术
|
||||||
|
- 可视化日志
|
||||||
|
- 自动测试框架
|
||||||
|
|
||||||
|
## LLDB
|
||||||
|
#### 1. 安装与环境配置
|
||||||
|
首先,你需要确保本地安装了 LLDB,并为 Claude Code 配置 MCP 服务。
|
||||||
|
- **方案 A:使用官方/社区 LLDB-MCP (推荐)** 在终端中运行以下命令添加 MCP 调试服务:
|
||||||
|
```
|
||||||
|
# 使用 uvx 或 npx 自动安装并运行 lldb-mcp-server
|
||||||
|
claude mcp add lldb-debugger -- command "uvx" --args "lldb-mcp-server"
|
||||||
|
```
|
||||||
|
可能是https://github.com/stass/lldb-mcp
|
||||||
|
|
||||||
|
- **方案 B:开启 LLDB 2026 原生 MCP 支持** 现代版本的 LLDB(v19+)已内置 MCP 协议支持。你可以在项目目录下启动它:
|
||||||
|
```
|
||||||
|
lldb --protocol-server start --port 59999
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2. 安装调试“技能” (Skill)
|
||||||
|
为了让 Claude 具备系统化的调试思维(而不只是乱试命令),你需要从 **Skills.sh** 或 GitHub 安装技能包:
|
||||||
|
```
|
||||||
|
# 安装通用的调试技能包
|
||||||
|
claude skill install AlmogBaku/debug-skill
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user