Skip to content
MachoCacheResolve

MachoCacheResolve

Description

Resolve runtime_ip to a function name.

Parameters

Name Direction Description
self in,out Cache. Grows on first sight of module_path.
module_path in Path to the loaded Mach-O on disk.
slide in ASLR slide as reported by _dyld_get_image_vmaddr_slide – the offset added to the binary’s on-disk vmaddrs to get its runtime addresses. runtime_ip - slide is the file-relative VA.
runtime_ip in Address to resolve.
out_name out On success, pointer to the function name (borrowed from the cached Mach-O / DWARF strings; valid until MachoCacheDeinit).
out_offset out On success, byte offset from the function start.

Success

Returns true.

Failure

Returns false if the module can’t be opened or the IP falls outside any symbol / function.

Usage example (Cross-references)

Usage examples (Cross-references)
            u64 slide = 0;
            if (cache_ok && dyld_image_for_ip(frames[i].ip, &mod_path, &slide)) {
                if (MachoCacheResolve(&cache, mod_path, slide, ip, &sym_name, &sym_off)) {
                    named = true;
                }
        Zstr       name     = NULL;
        u32        offset   = 0;
        bool       resolved = MachoCacheResolve(&cache, bin_path, 0, low + 0x20, &name, &offset);
        ok                  = ok && resolved && name && ZstrCompare(name, fn_name) == 0 && offset == 0x20;
        Zstr name1 = NULL;
        u32  off1  = 0;
        ok         = ok && MachoCacheResolve(&cache, bin_path, 0, low + 0x10, &name1, &off1);
        ok         = ok && name1 && ZstrCompare(name1, fn_name) == 0 && off1 == 0x10;
        Zstr name2 = NULL;
        u32  off2  = 0;
        ok         = ok && MachoCacheResolve(&cache, bin_path, 0, low + 0x30, &name2, &off2);
        ok         = ok && name2 && ZstrCompare(name2, fn_name) == 0 && off2 == 0x30;
        ok         = ok && VecLen(&cache.entries) == 1;
        Zstr       name     = NULL;
        u32        offset   = 0;
        bool       resolved = MachoCacheResolve(&cache, bin_path, 0, low + 0x14, &name, &offset);
        ok                  = ok && resolved && name && ZstrCompare(name, fn_name) == 0 && offset == 0x14;
        ok                  = ok && DebugAllocatorLiveCount(&dbg) > baseline;
        Zstr      name       = NULL;
        u32       offset     = 0;
        bool      ok         = MachoCacheResolve(&cache, bin_path, slide, runtime_ip, &name, &offset);
        ok                   = ok && name && ZstrCompare(name, "real_main_proc") == 0 && offset == 0x10;
        Zstr      name       = NULL;
        u32       offset     = 0;
        bool      ok         = MachoCacheResolve(&cache, bin_path, slide, runtime_ip, &name, &offset);
        ok                   = ok && name && ZstrCompare(name, "dsym_only_fn") == 0 && offset == 0x8;
    
        Zstr name = NULL;
        bool ok   = !MachoCacheResolve(&cache, bin_path, 0, 0x100000208ull, &name, NULL);
    
        MachoCacheDeinit(&cache);
        const u64  slide      = 0x100;
        const u64  runtime_ip = 0x100000100ull + 0x10 + slide;
        bool       resolved   = MachoCacheResolve(&cache, bin_path, slide, runtime_ip, &name, &offset);
        ok                    = ok && resolved && name && ZstrCompare(name, "real_main_proc") == 0 && offset == 0x10;
    
        // Resolve module A then module B: two distinct entries (0 and 1).
        ok             = ok && MachoCacheResolve(&cache, bin_a, 0, 0x100000110ull, &name, &off);
        ok             = ok && VecLen(&cache.entries) == 1;
        ok             = ok && MachoCacheResolve(&cache, bin_b, 0, 0x100000110ull, &name, &off);
        ok             = ok && MachoCacheResolve(&cache, bin_a, 0, 0x100000110ull, &name, &off);
        ok             = ok && VecLen(&cache.entries) == 1;
        ok             = ok && MachoCacheResolve(&cache, bin_b, 0, 0x100000110ull, &name, &off);
        ok             = ok && VecLen(&cache.entries) == 2;
        size after_two = DebugAllocatorLiveCount(&dbg);
        // mis-matches entry 0 first. Either way the cache HIT breaks: the
        // entries vector grows and the live count rises.
        ok = ok && MachoCacheResolve(&cache, bin_b, 0, 0x100000110ull, &name, &off);
        ok = ok && VecLen(&cache.entries) == 2;
        ok = ok && DebugAllocatorLiveCount(&dbg) == after_two;
    
        // Re-resolve module A (index 0) too: still a hit, no growth.
        ok = ok && MachoCacheResolve(&cache, bin_a, 0, 0x100000110ull, &name, &off);
        ok = ok && VecLen(&cache.entries) == 2;
        ok = ok && DebugAllocatorLiveCount(&dbg) == after_two;
        Zstr       name     = NULL;
        u32        offset   = 0;
        bool       resolved = MachoCacheResolve(&cache, bin_path, 0, 0x100000208ull, &name, &offset);
        ok                  = ok && resolved && name && ZstrCompare(name, "dsym_only_fn") == 0 && offset == 0x8;
        ok                  = ok && DebugAllocatorLiveCount(&dbg) > baseline;
        Zstr       name  = NULL;
        // Resolve must fail: stripped main + UUID-mismatched dSYM.
        ok = ok && !MachoCacheResolve(&cache, bin_path, 0, 0x100000208ull, &name, NULL);
    
        MachoCacheDeinit(&cache);
        u32        offset = 0;
        // file-relative VA low+0x20 -> 0x20 into the function.
        bool resolved = MachoCacheResolve(&cache, bin_path, 0, low + 0x20, &name, &offset);
        ok            = ok && resolved && name && ZstrCompare(name, fn_name) == 0 && offset == 0x20;
        ok            = ok && DebugAllocatorLiveCount(&dbg) > baseline;
    
        // runtime_ip strictly below slide -> reject (both `<` and `<=`).
        ok = ok && !MachoCacheResolve(&cache, bin_path, 0x200, 0x100, &name, &off);
    
        // runtime_ip == slide: file-relative VA 0 must resolve. The mutant
        off          = 0;
        const u64 eq = 0x9000;
        ok           = ok && MachoCacheResolve(&cache, bin_path, eq, eq, &name, &off);
        ok           = ok && name && ZstrCompare(name, "fn_at_zero") == 0 && off == 0;
        u32  off  = 0;
        // Str overload -> macho_cache_resolve_str -> macho_cache_resolve_zstr.
        ok = ok && MachoCacheResolve(&cache, &mod, 0, 0x100000110ull, &name, &off);
        ok = ok && name && ZstrCompare(name, "str_fn") == 0 && off == 0x10;
        name = NULL;
        off  = 0;
        ok   = ok && !MachoCacheResolve(&cache, &mod, 0, 0xdeadbeefull, &name, &off);
    
        StrDeinit(&mod);
Last updated on