Files
ipsw/pkg/signature/kernel_cpp_test.go
blacktop 196d77de6f feat: add kernel C++ parsing to symbolicate cmds and APIs
Add API endpoints and CLI support for discovering C++ classes and symbolication of kernelcaches, refactor Mach-O handling, and improve symbol collection.

- API: add /kernel/cpp and /kernel/symbolicate routes, request param structs, response types, and openKernel helper. Use cpp scanner and signature parsing to return classes and symbol maps.
- CLI: wire scanner LogStats flag, refactor kernel symbolicate command (schema writer helper, improved signature parsing, and symbol matching logic). Add tests for symbolicator schema and kernel symbol matching.
- Signature pkg: add kernel C++ symbol extraction (pkg/signature/kernel_cpp.go) and SymbolicateMachO to symbolicate already-open Mach-Os; integrate C++ symbols into symbol map and update signature matching/logging behavior.
- Internal: refactor in-memory DB lookups (findMachOByUUID, findSymbolByAddr) to reduce duplication. Improve symbols collection for kernel Mach-Os (collectKernelMachoSymbols, extra kernel symbols from signature/C++), add helpers to append symbols.
- Kernelcache CPP: add LogStats option and conditional logging of scan stats.
- Crashlog/ips: update wording to reflect kernel symbols are from kernel analysis and store KernelSymbols earlier in processing; parse signatures only when configured.

Also add unit tests for new symbolication helpers and kernel C++ signature handling. Overall this consolidates kernel symbol discovery, improves reuse, and surfaces C++-derived symbols in symbol maps.
2026-03-10 12:20:12 -06:00

70 lines
1.9 KiB
Go

package signature
import (
"testing"
"github.com/blacktop/ipsw/pkg/kernelcache/cpp"
)
func TestCPPClassSymbols(t *testing.T) {
t.Parallel()
symbols := cppClassSymbols(cpp.Class{
Name: "IOService",
Ctor: 0xfffffe0001234000,
MetaPtr: 0xfffffe0001235000,
MetaVtableAddr: 0xfffffe0001236000,
VtableAddr: 0xfffffe0001237000,
})
if len(symbols) != 4 {
t.Fatalf("cppClassSymbols returned %d symbols, want 4", len(symbols))
}
want := map[uint64]string{
0xfffffe0001234000: "IOService::IOService",
0xfffffe0001235000: "IOService::gMetaClass",
0xfffffe0001236000: "vtable for IOService::MetaClass",
0xfffffe0001237000: "vtable for IOService",
}
for _, symbol := range symbols {
if got, ok := want[symbol.addr]; !ok || got != symbol.name {
t.Fatalf("unexpected symbol %#x => %q", symbol.addr, symbol.name)
}
}
}
func TestAddKernelCPPClassesSkipsConflicts(t *testing.T) {
t.Parallel()
sm := NewSymbolMap()
if err := sm.Add(0xfffffe0001234000, "ExistingCtor"); err != nil {
t.Fatalf("failed to seed symbol map: %v", err)
}
added := sm.addKernelCPPClasses([]cpp.Class{{
Name: "IOService",
Ctor: 0xfffffe0001234000,
MetaPtr: 0xfffffe0001235000,
MetaVtableAddr: 0xfffffe0001236000,
VtableAddr: 0xfffffe0001237000,
}})
if added != 3 {
t.Fatalf("addKernelCPPClasses added %d symbols, want 3", added)
}
if got := sm[0xfffffe0001234000]; got != "ExistingCtor" {
t.Fatalf("constructor symbol was overwritten: got %q", got)
}
if got := sm[0xfffffe0001235000]; got != "IOService::gMetaClass" {
t.Fatalf("meta class symbol = %q, want IOService::gMetaClass", got)
}
if got := sm[0xfffffe0001236000]; got != "vtable for IOService::MetaClass" {
t.Fatalf("meta vtable symbol = %q, want vtable for IOService::MetaClass", got)
}
if got := sm[0xfffffe0001237000]; got != "vtable for IOService" {
t.Fatalf("vtable symbol = %q, want vtable for IOService", got)
}
}