Phase A: consts extraction (11602), Hann window ID, DSP const map
This commit is contained in:
+171
@@ -0,0 +1,171 @@
|
|||||||
|
import ghidra.app.script.GhidraScript;
|
||||||
|
import ghidra.app.decompiler.DecompInterface;
|
||||||
|
import ghidra.app.decompiler.DecompileResults;
|
||||||
|
import ghidra.program.model.listing.Function;
|
||||||
|
import ghidra.program.model.listing.FunctionManager;
|
||||||
|
import ghidra.program.model.listing.Instruction;
|
||||||
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.address.AddressSpace;
|
||||||
|
import ghidra.program.model.address.AddressIterator;
|
||||||
|
import ghidra.program.model.symbol.Reference;
|
||||||
|
import ghidra.program.model.mem.Memory;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BFS-closure over the DSP call-graph starting from soothe2 DSP vtable slots and all
|
||||||
|
* FUN_* in decomp_dsp.txt. Decompiles every reachable function (if missing) and dumps
|
||||||
|
* all .data float constants referenced from instructions.
|
||||||
|
*/
|
||||||
|
public class DumpFuns extends GhidraScript {
|
||||||
|
|
||||||
|
final long LO = 0x180000000L;
|
||||||
|
final long HI = 0x182a00000L;
|
||||||
|
|
||||||
|
long parseAddr(String s) {
|
||||||
|
try {
|
||||||
|
return Long.parseLong(s.replaceAll("[^0-9a-fA-F]", ""), 16);
|
||||||
|
} catch (Exception e) { return -1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() throws Exception {
|
||||||
|
FunctionManager fm = currentProgram.getFunctionManager();
|
||||||
|
AddressSpace as = currentProgram.getAddressFactory().getDefaultAddressSpace();
|
||||||
|
|
||||||
|
// --- seeds from decomp_dsp.txt ---
|
||||||
|
Set<Long> seed = new LinkedHashSet<>();
|
||||||
|
BufferedReader br = new BufferedReader(new FileReader("/home/m/re-tools/decomp_dsp.txt"));
|
||||||
|
String line;
|
||||||
|
while ((line = br.readLine()) != null) {
|
||||||
|
int i = line.indexOf("FUN_");
|
||||||
|
while (i >= 0) {
|
||||||
|
int e = i + 4;
|
||||||
|
while (e < line.length() && "0123456789abcdefABCDEF".indexOf(line.charAt(e)) >= 0) e++;
|
||||||
|
long a = parseAddr(line.substring(i + 4, e));
|
||||||
|
if (a >= LO && a <= HI) seed.add(a);
|
||||||
|
i = line.indexOf("FUN_", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
br.close();
|
||||||
|
// --- seeds: vtable slots ---
|
||||||
|
long[] vts = {
|
||||||
|
0x1824abb90L, 0x1824ac7a8L, 0x1824ab7c0L, 0x1824ac638L, 0x1824ac5d8L,
|
||||||
|
0x1824be810L, 0x1824be228L, 0x1824be0a8L, 0x1824be7a0L, 0x1824ac210L,
|
||||||
|
0x1824ac248L, 0x1824b1ac8L, 0x1824b11c8L, 0x1824b0fd0L, 0x1824b1178L
|
||||||
|
};
|
||||||
|
for (long base : vts) {
|
||||||
|
for (int i = 0; i < 64; i++) {
|
||||||
|
try {
|
||||||
|
Address va = as.getAddress(base + i * 8L);
|
||||||
|
long tgt = currentProgram.getMemory().getLong(va);
|
||||||
|
if (tgt >= LO && tgt <= HI) seed.add(tgt);
|
||||||
|
} catch (Exception e) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- BFS closure (no decompile needed for called-functions graph) ---
|
||||||
|
Set<Long> done = new TreeSet<>();
|
||||||
|
Deque<Long> queue = new ArrayDeque<>(seed);
|
||||||
|
List<Long> order = new ArrayList<>();
|
||||||
|
int cap = 5000;
|
||||||
|
while (!queue.isEmpty() && order.size() < cap) {
|
||||||
|
long a = queue.poll();
|
||||||
|
if (!done.add(a)) continue;
|
||||||
|
order.add(a);
|
||||||
|
Function f = fm.getFunctionAt(as.getAddress(a));
|
||||||
|
if (f == null) continue;
|
||||||
|
try {
|
||||||
|
for (Function c : f.getCalledFunctions(monitor)) {
|
||||||
|
long ca = c.getEntryPoint().getOffset();
|
||||||
|
if (ca >= LO && ca <= HI && !done.contains(ca)) queue.add(ca);
|
||||||
|
}
|
||||||
|
} catch (Exception e) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- fun_map always written fresh ---
|
||||||
|
PrintWriter pm = new PrintWriter(new java.io.BufferedWriter(
|
||||||
|
new FileWriter("/home/m/re-tools/fun_map.txt", false)));
|
||||||
|
for (long a : order) {
|
||||||
|
Function f = fm.getFunctionAt(as.getAddress(a));
|
||||||
|
if (f == null) continue;
|
||||||
|
pm.println(Long.toHexString(a) + " " + f.getBody().getNumAddresses() + " " + f.getName());
|
||||||
|
}
|
||||||
|
pm.close();
|
||||||
|
|
||||||
|
// --- decompile missing ---
|
||||||
|
java.io.File df = new java.io.File("/home/m/re-tools/decomp_funs.txt");
|
||||||
|
boolean haveDec = df.exists() && df.length() > 100000;
|
||||||
|
DecompInterface di = null;
|
||||||
|
PrintWriter pw = null;
|
||||||
|
if (!haveDec) {
|
||||||
|
di = new DecompInterface();
|
||||||
|
di.openProgram(currentProgram);
|
||||||
|
pw = new PrintWriter(new java.io.BufferedWriter(new FileWriter(df)));
|
||||||
|
}
|
||||||
|
if (pw != null) {
|
||||||
|
int n = 0;
|
||||||
|
for (long a : order) {
|
||||||
|
Function f = fm.getFunctionAt(as.getAddress(a));
|
||||||
|
if (f == null) continue;
|
||||||
|
if (f.getBody().getNumAddresses() < 30) continue;
|
||||||
|
DecompileResults res = di.decompileFunction(f, 120, monitor);
|
||||||
|
if (res != null && res.getDecompiledFunction() != null) {
|
||||||
|
n++;
|
||||||
|
pw.println("############ FUN_ " + Long.toHexString(a) + " size=" +
|
||||||
|
f.getBody().getNumAddresses() + " ############");
|
||||||
|
pw.println(res.getDecompiledFunction().getC());
|
||||||
|
pw.println();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pw.close();
|
||||||
|
di.dispose();
|
||||||
|
println("DECOMP_DONE n=" + n);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- constants from instruction references ---
|
||||||
|
Map<Long,String> consts = new TreeMap<>();
|
||||||
|
Memory mem = currentProgram.getMemory();
|
||||||
|
AddressIterator it = mem.getLoadedAndInitializedAddressSet().getAddresses(true);
|
||||||
|
// iterate references: for data targets in range, collect functions referencing them
|
||||||
|
ghidra.program.model.symbol.ReferenceManager rm = currentProgram.getReferenceManager();
|
||||||
|
for (Function f : fm.getFunctions(true)) {
|
||||||
|
long fa = f.getEntryPoint().getOffset();
|
||||||
|
if (!order.contains(fa)) continue;
|
||||||
|
Iterator<Instruction> iit = currentProgram.getListing().getInstructions(f.getBody(), true);
|
||||||
|
while (iit.hasNext()) {
|
||||||
|
Instruction ins = iit.next();
|
||||||
|
for (Reference r : rm.getReferencesFrom(ins.getAddress())) {
|
||||||
|
long ta = r.getToAddress().getOffset();
|
||||||
|
if ((ta >= 0x1824c0000L && ta <= 0x182700000L) ||
|
||||||
|
(ta >= 0x180000000L && ta <= 0x181200000L)) {
|
||||||
|
consts.merge(ta, Long.toHexString(fa), (x, y) -> x + ";" + y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PrintWriter pc = new PrintWriter(new java.io.BufferedWriter(
|
||||||
|
new FileWriter("/home/m/re-tools/consts.txt", false)));
|
||||||
|
for (Map.Entry<Long,String> e : consts.entrySet()) {
|
||||||
|
try {
|
||||||
|
long ta = e.getKey();
|
||||||
|
int[] b = new int[8];
|
||||||
|
boolean ok = true;
|
||||||
|
for (int k = 0; k < 8; k++) {
|
||||||
|
Address a = as.getAddress(ta + k);
|
||||||
|
if (!mem.getLoadedAndInitializedAddressSet().contains(a)) { ok = false; break; }
|
||||||
|
b[k] = mem.getByte(a) & 0xff;
|
||||||
|
}
|
||||||
|
if (!ok) continue;
|
||||||
|
float f32 = Float.intBitsToFloat(b[0] | (b[1] << 8) | (b[2] << 16) | (b[3] << 24));
|
||||||
|
float f32b = Float.intBitsToFloat(b[4] | (b[5] << 8) | (b[6] << 16) | (b[7] << 24));
|
||||||
|
pc.println(Long.toHexString(ta) + " f32=" + f32 + " f32b=" + f32b + " refs=" + e.getValue());
|
||||||
|
} catch (Exception ex) { }
|
||||||
|
}
|
||||||
|
pc.close();
|
||||||
|
println("CONSTS_DONE nn=" + order.size() + " consts=" + consts.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
+11602
File diff suppressed because one or more lines are too long
@@ -0,0 +1,31 @@
|
|||||||
|
0x1824c3cd4 f32=0.115129 f32b=0 double=5.13266e-315 | 1/(20 log10 e) dB->lin
|
||||||
|
0x1824c3f70 f32=-1.0842e-19 f32b=1.45 double=0.1 | 0.1 pow base
|
||||||
|
0x1824c3e30 f32=-5.18969e+11 f32b=0.814 double=0.001 | 0.001
|
||||||
|
0x1824c4218 f32=3.37028e+12 f32b=2.1427 double=3.14159 | pi
|
||||||
|
0x1824c4248 f32=3.37028e+12 f32b=2.3927 double=6.28319 | 2pi
|
||||||
|
0x1824c4e00 f32=3.37028e+12 f32b=2.3927 double=6.28319 | 2pi
|
||||||
|
0x1824c4da0 f32=0 f32b=1.875 double=1 | 1.0
|
||||||
|
0x1824c4c90 f32=0 f32b=1.75 double=0.5 | 0.5
|
||||||
|
0x1824c4050 f32=0 f32b=1.75 double=0.5 | 0.5
|
||||||
|
0x1824c4140 f32=0 f32b=1.875 double=1 | 1.0
|
||||||
|
0x1824c41e8 f32=0 f32b=2 double=2 | 2.0
|
||||||
|
0x1824c4478 f32=30 f32b=31 double=6.44245e+09 | 30.0 dB map
|
||||||
|
0x1824c44d0 f32=90 f32b=96 double=3.51844e+13 | 90.0 dB map
|
||||||
|
0x1824c4704 f32=-6.90776 f32b=-7 double=-32768 | -6.907755=-ln(1000)
|
||||||
|
0x1824c45f8 f32=100000 f32b=100001 double=5.13466e+37 | 100000.0
|
||||||
|
0x1824c43d0 f32=0 f32b=7.76294 double=100000 | 100000.0
|
||||||
|
0x1824c42d8 f32=0 f32b=3.14062 double=50 | 50.0
|
||||||
|
0x1824c42b0 f32=0 f32b=2.8125 double=20 | 20.0
|
||||||
|
0x1824c4270 f32=0 f32b=2.5625 double=10 | 10.0
|
||||||
|
0x1824c40c0 f32=2.03538e+33 f32b=1.80175 double=0.707 | 0.707
|
||||||
|
0x1824c4060 f32=1.26662e-26 f32b=1.76 double=0.54 | 0.54
|
||||||
|
0x1824c4058 f32=-7.46298e-36 f32b=1.7525 double=0.51 | 0.51
|
||||||
|
0x1824c4410 f32=13.1 f32b=14 double=8.38861e+06 | 13.1
|
||||||
|
0x1824c43d8 f32=8 f32b=8.3 double=170394 | 8.3
|
||||||
|
0x1824c45ec f32=44100 f32b=60000 double=1.09557e+36 | 44100 base sr (f32)
|
||||||
|
0x1824c3ea4 f32=1 f32b=0 double=5.26354e-315 | 1.0
|
||||||
|
0x1824c3d8c f32=0.5 f32b=0 double=5.2221e-315 | 0.5
|
||||||
|
0x1824c3e00 f32=0.707 f32b=0.707107 double=0.00032073 | 0.707
|
||||||
|
0x1824c3c58 f32=0.001 f32b=0.002 double=1.972e-24 | 0.001 (f32)
|
||||||
|
0x1824c3d3c f32=0.25 f32b=0 double=5.18065e-315 | 0.25
|
||||||
|
0x1824c41e0 f32=2 f32b=0 double=5.30499e-315 | 2.0 f32?
|
||||||
+312047
File diff suppressed because it is too large
Load Diff
+2285
File diff suppressed because it is too large
Load Diff
+24
-3
@@ -21,6 +21,8 @@
|
|||||||
H=1/√(1+(Qeff·A)²), Qeff=1.54·q^1.33, sat(level), Q_notch=qn·(1−g)+1, per-frame env, WOLA-маска.
|
H=1/√(1+(Qeff·A)²), Qeff=1.54·q^1.33, sat(level), Q_notch=qn·(1−g)+1, per-frame env, WOLA-маска.
|
||||||
- LUT: depthcurve (207 float @0x1826170e8, `0.302+0.698·sin(π/2·x)^0.94`, r²=0.99999).
|
- LUT: depthcurve (207 float @0x1826170e8, `0.302+0.698·sin(π/2·x)^0.94`, r²=0.99999).
|
||||||
- Рендер-свипы в `/home/m/soothe-bt/` (506 wav + 609 rpp) — эталон для bit-exact.
|
- Рендер-свипы в `/home/m/soothe-bt/` (506 wav + 609 rpp) — эталон для bit-exact.
|
||||||
|
- BFS-замыкание call-graph от сидов: `fun_map.txt` (2035 функций), `decomp_funs.txt` (1640 декомпилировано,
|
||||||
|
312K), `consts.txt` (11602 констант) — после фикса `getInstructions()` в `DumpFuns.java`.
|
||||||
|
|
||||||
## Контракт из manual (`soothe2_ManualFAQ.pdf`, v1.0.0)
|
## Контракт из manual (`soothe2_ManualFAQ.pdf`, v1.0.0)
|
||||||
|
|
||||||
@@ -69,6 +71,22 @@
|
|||||||
- A.5. Найти oversample/resolution-путь (M6/M7): интерполяция сетки, период обновления.
|
- A.5. Найти oversample/resolution-путь (M6/M7): интерполяция сетки, период обновления.
|
||||||
- A.6. Сопоставить топологию с диаграммой (0.1) и stereo/link/balance (M8).
|
- A.6. Сопоставить топологию с диаграммой (0.1) и stereo/link/balance (M8).
|
||||||
|
|
||||||
|
### Статус фазы A (~40%)
|
||||||
|
- **A.2 константы — готово**: `consts.txt` (11602 из инструкций BFS-замыкания, 2670 в DSP-диапазоне
|
||||||
|
0x1824c0000–0x182700000) из повторного прогона `DumpFuns.java`. Точная double/f32-интерпретация —
|
||||||
|
`consts_double.txt` (чтение PE напрямую, `.data` vs `.rdata` через RVA).
|
||||||
|
- **A.3 ОКНО — найден**: `FUN_1805356f0` генерирует **Hann** `w(i)=0.5·(1−cos(2πi/N))`
|
||||||
|
(double 2π @0x1824c4e00/4248, 1.0 @4da0/4140, 0.5 @4c90/4050; хвост через `cos`, чётные пары через
|
||||||
|
SIMD `divpd`+`thunk_FUN_181a114e0(=cos)`). Размер N: `FUN_18052e130` →
|
||||||
|
`N = 2^floor(log2(sr/44100))·N0` (44100 @0x1824c45ec, 2.0 @41e8). **Нормализация окна** в
|
||||||
|
`FUN_18052df60`: сумма по окну → `scale=1/(mean/N)`, потом `/= (fsize @+0x1ac)`.
|
||||||
|
- **A.3 FFT — НЕ подтверждён для DSP**: найденный планировщик `FUN_181384180` (radix-4/8 стадии,
|
||||||
|
cos/sin twiddle, бит-реверс, log2(N)) — это **Vorbis-декодер** (строка `s_vorbis_1821e47fc`);
|
||||||
|
в DSP-пути не участвует. В бинарнике нет kissfft/fftw/MKL-FFT строк. DSP-STFT-FFT ищется дальше.
|
||||||
|
- **Константы детектора**: `10^((dB)/20)` через `expf((30·X−90)·0.115129255)`,
|
||||||
|
`0.115129255=1/(20·log10e)`, `−6.907755=−ln1000`, `0.707`/`0.51`/`0.54`/`0.001`,
|
||||||
|
маппинг резонанса `(x−0.707)·0.5+1` в `FUN_1805316e0`.
|
||||||
|
|
||||||
### Фаза B — Реконструкция C++ (bit-exact)
|
### Фаза B — Реконструкция C++ (bit-exact)
|
||||||
- B.1. Классы 1:1: `Soothe2FilterGraph::processBlock`, `FilterGraphGrid`, `DigitalFilter`,
|
- B.1. Классы 1:1: `Soothe2FilterGraph::processBlock`, `FilterGraphGrid`, `DigitalFilter`,
|
||||||
`SpectralProcessor` (STFT), `AudioProcessingModule`, `IIRFilterExtended`, env-модуль с
|
`SpectralProcessor` (STFT), `AudioProcessingModule`, `IIRFilterExtended`, env-модуль с
|
||||||
@@ -85,10 +103,13 @@
|
|||||||
- C.3. Итеративный цикл diff → локализация блока → фикс → повтор.
|
- C.3. Итеративный цикл diff → локализация блока → фикс → повтор.
|
||||||
|
|
||||||
## Риски
|
## Риски
|
||||||
- **FFT bit-exact**: если FFTW — нужна та же сборка; свой radix-2 — воспроизводим напрямую (A.3).
|
- **FFT bit-exact**: свой планировщик есть только у Vorbis-декодера; DSP-STFT-FFT ещё не найден (A.3) —
|
||||||
|
если свой radix-2 — воспроизводим напрямую; главный нерешённый риск фазы A.
|
||||||
- **Хост-зависимость**: уточнить точный размер буфера/фрейма (рендеры при разных RENDER_RANGE должны давать одинаковые байты).
|
- **Хост-зависимость**: уточнить точный размер буфера/фрейма (рендеры при разных RENDER_RANGE должны давать одинаковые байты).
|
||||||
- **Stereo**: все текущие свипы mono; для бит-exact графа M8 нужны стерео-рендеры (link/balance/ms).
|
- **Stereo**: все текущие свипы mono; для бит-exact графа M8 нужны стерео-рендеры (link/balance/ms).
|
||||||
|
|
||||||
## Открытые вопросы
|
## Открытые вопросы
|
||||||
1. Окна/oversample детали — из декомпиляции (A.6) или требуется доп. замеры.
|
1. Где реальный DSP-STFT FFT (не Vorbis/не внешний lib)? Искать большие функции с butterfly/стадиями
|
||||||
2. Стерео-верификация (M8) — приоритет mono-путь или сразу стерео-граф.
|
в 18052*/18053* или через трассировку вызовов от `processBlock` спектрального процессора.
|
||||||
|
2. Окна/oversample детали — из декомпиляции (A.6) или требуется доп. замеры.
|
||||||
|
3. Стерео-верификация (M8) — приоритет mono-путь или сразу стерео-граф.
|
||||||
|
|||||||
Reference in New Issue
Block a user