add crash notes + symbolize tool + symbolized hook dll; README symbol build section
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
# MINT HOOK FAILED — Proton 崩溃分析
|
||||
|
||||
## 结论
|
||||
hook DLL 成功被 Proton 加载,但在**初始化阶段**(`DllMain` → `init` → `patch()`)发生
|
||||
`EXCEPTION_ACCESS_VIOLATION (0xc0000005)`,crash 落在 native `X3DAudio1_7.dll` 内部。
|
||||
不是缺 DLL、不是 WINEDLLOVERRIDES、不是 MinGW runtime 问题。
|
||||
|
||||
## 符号化结果(debug 构建 `hook-debug-symbolized.dll`,image base 0x180000000)
|
||||
|
||||
| RVA | 包含函数 | 含义 |
|
||||
|---|---|---|
|
||||
| `+0x521f15` | `std::thread::spawnhook::run_spawn_hooks` (+0x165) | **崩溃点**:首个线程 spawn 时的 std spawn-hooks 钩子,`usize::saturating_add` 内联叶子帧 |
|
||||
| `+0x57bff` | `repak::ext::ReadExt::read_array::<Block>`(`patch()` 里 `PakBuilder` 读 `mods_P.pak`) | 读 pak 阶段 |
|
||||
| `+0x54351` | `crossbeam_channel::Sender<tracing_appender::Msg>::drop` | tracing_appender **non_blocking 日志 worker** 的 channel 析构 |
|
||||
| `+0x15966` | `D3DPERF_QueryRepeatFrame`(proxy_dll 导出 thunk,hook/src/lib.rs:12) | DLL 导出面 |
|
||||
| `+0x2c221` | `tracing_subscriber::fmt::Timings` extension `get` | 日志 subscriber 初始化 |
|
||||
|
||||
## 指向
|
||||
5 个点全部落在**初始化序列**:`proxy_dll!([x3daudio1_7, d3d9], init)` 的 `init` →
|
||||
`patch()` → `mint_lib::setup_logging(bin_dir/mint_hook.log)`(`tracing_appender::non_blocking`)
|
||||
→ 读 `Content/Paks/mods_P.pak` → patternsleuth 解析 → `hooks::initialize()`。
|
||||
|
||||
崩溃点 `run_spawn_hooks` 说明:**hook 在 DllMain(LoadLibrary,持 loader lock)期间
|
||||
spawn 了线程**(tracing_appender 日志 worker,或 tokio/tokio-console 相关)。
|
||||
Windows/Proton 下 loader lock 内 spawn 线程是经典 AV/死锁源 —— 游戏主进程首次
|
||||
`LoadLibrary("x3daudio1_7")` 时触发 `init`,此时 spawn 线程在 Proton Experimental 下崩。
|
||||
|
||||
## 修复方向(按优先级)
|
||||
1. **延迟日志/线程初始化**:`patch()` 里不要在 `init`(DllMain 上下文)里
|
||||
`setup_logging`/spawn 任何线程;把 non_blocking guard 的创建挪到
|
||||
`hooks::initialize` 里真正进入游戏线程之后(如 `FEngineLoop::Init`/tick 钩子首次触发时)。
|
||||
2. 若 tokio 相关线程也在 init 期创建,同样挪出 DllMain 上下文。
|
||||
3. 上游 issue:https://github.com/trumank/mint/issues/307 (Linux 使用场景)。
|
||||
|
||||
## 复现符号化
|
||||
```bash
|
||||
# 带符号 DLL(本 release 附件 hook-debug-symbolized.dll,debug=2 构建,代码布局与发布版一致)
|
||||
x86_64-w64-mingw32-addr2line -Cfipe hook-debug-symbolized.dll \
|
||||
0x180521f15 0x180057bff 0x180054351 0x180015966 0x18002c221
|
||||
# 或用仓库里的通用脚本
|
||||
python3.12 symbolize_hook.py hook-debug-symbolized.dll 0x521f15 0x57bff 0x54351 0x15966 0x2c221
|
||||
```
|
||||
|
||||
## 临时恢复游戏
|
||||
```bash
|
||||
mv "/data/SteamLibrary/steamapps/common/Deep Rock Galactic/FSD/Binaries/Win64/x3daudio1_7.dll" \
|
||||
"/data/SteamLibrary/steamapps/common/Deep Rock Galactic/FSD/Binaries/Win64/x3daudio1_7.dll.disabled"
|
||||
# Steam 启动参数恢复 -disablemodding,去掉 WINEDLLOVERRIDES="x3daudio1_7=n,b"
|
||||
```
|
||||
@@ -17,7 +17,7 @@ Grab the tarball from the [latest release](https://gitea.mygoband.com/carrydela/
|
||||
check `sha256sum`, extract, put `mint` on your PATH:
|
||||
|
||||
```bash
|
||||
curl -fLO https://gitea.mygoband.com/carrydela/mint-linux/releases/download/v0.1.0/mint-linux-x86_64.tar.gz
|
||||
curl -fLO https://gitea.mygoband.com/carrydela/mint-linux/releases/download/v0.1.1/mint-linux-x86_64.tar.gz
|
||||
sha256sum -c mint-linux-x86_64.tar.gz.sha256 # download the .sha256 alongside
|
||||
tar -xzf mint-linux-x86_64.tar.gz
|
||||
install -m 0755 mint /usr/local/bin/
|
||||
@@ -52,6 +52,25 @@ the hook DLL is embedded into the Linux binary via Cargo artifact dependency
|
||||
itself to `FSD/Binaries/Win64/x3daudio1_7.dll` when installing mods.
|
||||
Binary is stripped.
|
||||
|
||||
## Symbol build (crash triage)
|
||||
|
||||
To resolve crash offsets (e.g. `X3DAudio1_7.dll + 0x521F15` from a Proton crash log)
|
||||
into Rust symbols, build the hook with debug info and symbolize:
|
||||
|
||||
```bash
|
||||
# one-off profile override (see [profile.release.package.hook] in Cargo.toml)
|
||||
cargo +nightly-2026-04-24 build --package mint --release
|
||||
|
||||
# symbolize RVAs against the debug hook.dll (image base 0x180000000)
|
||||
python3.12 symbolize_hook.py <hook.dll> 0x521f15 0x57bff 0x54351
|
||||
# or directly:
|
||||
x86_64-w64-mingw32-addr2line -Cfipe <hook.dll> 0x180521f15 0x180057bff 0x180054351
|
||||
```
|
||||
|
||||
A debug-symbolized DLL matching the shipped code layout is attached to the
|
||||
release as `hook-debug-symbolized.dll`. See `CRASH-NOTES.md` for the
|
||||
MINT HOOK FAILED analysis.
|
||||
|
||||
## Files
|
||||
|
||||
- `install.sh` — one-click installer (see above)
|
||||
|
||||
Executable
BIN
Binary file not shown.
@@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env python3.12
|
||||
"""Symbolize mint hook DLL crash RVAs.
|
||||
|
||||
Usage:
|
||||
python3.12 symbolize_hook.py <hook.dll> <rva> [rva ...]
|
||||
|
||||
RVAs are relative to the DLL's image base (e.g. from a wine/proton crash
|
||||
line "X3DAudio1_7.dll + 0x521F15"). The script prints the containing symbol
|
||||
for each RVA. Run it against a debug-symbol hook build (see README "Symbol
|
||||
build"), NOT the stripped release artifact.
|
||||
|
||||
Optional env:
|
||||
HOOK_IMAGE_BASE override base (default 0x180000000)
|
||||
"""
|
||||
import bisect, os, re, subprocess, sys
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 3:
|
||||
print(__doc__); sys.exit(1)
|
||||
dll = sys.argv[1]
|
||||
base = int(os.environ.get("HOOK_IMAGE_BASE", "0x180000000"), 16)
|
||||
rv = [int(x, 16) for x in sys.argv[2:]]
|
||||
|
||||
sym_out = subprocess.run(
|
||||
["x86_64-w64-mingw32-nm", "-n", "-C", dll],
|
||||
capture_output=True, text=True)
|
||||
syms = []
|
||||
for line in sym_out.stdout.splitlines():
|
||||
m = re.match(r"^([0-9a-f]+) [TtDdWw] (.+)$", line)
|
||||
if m:
|
||||
a = int(m.group(1), 16)
|
||||
if a >= base:
|
||||
syms.append((a, m.group(2).strip()))
|
||||
if not syms:
|
||||
print("no symbols found — is this a debug build? (see README)"); sys.exit(2)
|
||||
addrs = [a for a, _ in syms]
|
||||
syms.sort()
|
||||
|
||||
for r in rv:
|
||||
va = base + r
|
||||
i = bisect.bisect_right(addrs, va) - 1
|
||||
if i < 0:
|
||||
print(f"+{r:06x} NOT FOUND"); continue
|
||||
fa, name = syms[i]
|
||||
leaf = subprocess.run(
|
||||
["x86_64-w64-mingw32-addr2line", "-Cfie", dll, hex(va)],
|
||||
capture_output=True, text=True).stdout
|
||||
leaf_frames = [l for l in leaf.splitlines() if "at " in l]
|
||||
print(f"=== +{r:06x} (va {va:#x}) ===")
|
||||
print(f" container: {name[:160]}{'…' if len(name) > 160 else ''}")
|
||||
print(f" +{va - fa:#x} into symbol")
|
||||
if leaf_frames:
|
||||
print(f" leaf: {leaf_frames[0][:160]}")
|
||||
# outermost non-inlined frame
|
||||
if leaf_frames:
|
||||
print(f" outer: {leaf_frames[-1][:160]}")
|
||||
print()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user