Search code examples
iosxcodelldbsimulator

Setting breakpoint in dynamic loader on iOS simulator


I'm running into an issue where the dynamic loader is crashing in dyld_sim`memcmp. I'm trying to determine which library was loading at the time, but the stack seems corrupt (at least, the argument registers aren't available).

So I'm trying to set a breakpoint in the loader (further up the stack), but breakpoints in the dynamic loader don't seem to stick. I also tried setting symbolic breakpoints, but those don't trigger. I don't know if it's because I'm spelling it wrong (e.g. "dyld::load" didn't work).

Any ideas for what I can try?

dyld_sim`memcmp:
    0x107154afd <+0>:  pushq  %rbp
    0x107154afe <+1>:  movq   %rsp, %rbp
    0x107154b01 <+4>:  testq  %rdx, %rdx
    0x107154b04 <+7>:  je     0x107154b1e               ; <+33>
    0x107154b06 <+9>:  xorl   %ecx, %ecx
->  0x107154b08 <+11>: movzbl (%rdi,%rcx), %eax         ; Thread 1: EXC_BAD_ACCESS (code=50, address=0x1090fa000)
    0x107154b0c <+15>: movzbl (%rsi,%rcx), %r8d
    0x107154b11 <+20>: cmpb   %r8b, %al
    0x107154b14 <+23>: jne    0x107154b22               ; <+37>
    0x107154b16 <+25>: incq   %rcx
    0x107154b19 <+28>: cmpq   %rcx, %rdx
    0x107154b1c <+31>: jne    0x107154b08               ; <+11>
    0x107154b1e <+33>: xorl   %eax, %eax
    0x107154b20 <+35>: jmp    0x107154b25               ; <+40>
    0x107154b22 <+37>: subl   %r8d, %eax
    0x107154b25 <+40>: popq   %rbp
    0x107154b26 <+41>: retq   
#0  0x0000000107154b08 in memcmp ()
#1  0x0000000107144051 in ImageLoaderMachO::validateFirstPages(linkedit_data_command const*, int, unsigned char const*, unsigned long, long long, ImageLoader::LinkContext const&) ()
#2  0x0000000107147266 in ImageLoaderMachOCompressed::instantiateFromFile(char const*, int, unsigned char const*, unsigned long, unsigned long long, unsigned long long, stat const&, unsigned int, unsigned int, linkedit_data_command const*, encryption_info_command const*, ImageLoader::LinkContext const&) ()
#3  0x000000010714316f in ImageLoaderMachO::instantiateFromFile(char const*, int, unsigned char const*, unsigned long, unsigned long long, unsigned long long, stat const&, ImageLoader::LinkContext const&) ()
#4  0x00000001071356e1 in dyld::loadPhase6(int, stat const&, char const*, dyld::LoadContext const&) ()
#5  0x0000000107139ffd in dyld::loadPhase5(char const*, char const*, dyld::LoadContext const&, unsigned int&, std::__1::vector<char const*, std::__1::allocator<char const*> >*) ()
#6  0x0000000107139bbd in dyld::loadPhase4(char const*, char const*, dyld::LoadContext const&, unsigned int&, std::__1::vector<char const*, std::__1::allocator<char const*> >*) ()
#7  0x000000010713926a in dyld::loadPhase2(char const*, char const*, dyld::LoadContext const&, char const* const*, char const* const*, unsigned int&, std::__1::vector<char const*, std::__1::allocator<char const*> >*) ()
#8  0x000000010713912a in dyld::loadPhase1(char const*, char const*, dyld::LoadContext const&, unsigned int&, std::__1::vector<char const*, std::__1::allocator<char const*> >*) ()
#9  0x000000010713541c in dyld::loadPhase0(char const*, char const*, dyld::LoadContext const&, unsigned int&, std::__1::vector<char const*, std::__1::allocator<char const*> >*) ()
#10 0x00000001071350e6 in dyld::load(char const*, dyld::LoadContext const&, unsigned int&) ()
#11 0x000000010713a4ef in dyld::libraryLocator(char const*, bool, char const*, ImageLoader::RPathChain const*, bool, unsigned int&) ()
#12 0x0000000107140a2e in ImageLoader::recursiveLoadLibraries(ImageLoader::LinkContext const&, bool, ImageLoader::RPathChain const&, char const*) ()
#13 0x000000010713fc8a in ImageLoader::link(ImageLoader::LinkContext const&, bool, bool, bool, ImageLoader::RPathChain const&, char const*) ()
#14 0x0000000107136cc8 in dyld::link(ImageLoader*, bool, bool, ImageLoader::RPathChain const&, unsigned int) ()
#15 0x0000000107138123 in dyld::_main(macho_header const*, unsigned long, int, char const**, char const**, char const**, unsigned long*) ()
#16 0x0000000107133630 in start_sim ()
#17 0x00000001107168cc in dyld::useSimulatorDyld(int, macho_header const*, char const*, int, char const**, char const**, char const**, unsigned long*, unsigned long*) ()
#18 0x0000000110714575 in dyld::_main(macho_header const*, unsigned long, int, char const**, char const**, char const**, unsigned long*) ()
#19 0x000000011070f227 in dyldbootstrap::start(dyld3::MachOLoaded const*, int, char const**, dyld3::MachOLoaded const*, unsigned long*) ()
#20 0x000000011070f025 in _dyld_start ()

Solution

  • dyld has a copy of a bunch of functions in the C standard library (because it has to do work before the standard library gets loaded.) If we put breakpoints on these dyld versions, you would hit them frequently during startup, which in most circumstances is not what you want. So lldb keeps a list of libraries to avoid when resolving by-name breakpoints, and dyld is on that list on Darwin.

    You can force setting breakpoints on the dyld version of these functions in two ways. The easiest is to supply the shared library when you set the breakpoint, like:

    (lldb) break set -n memcmp -s dyld
    

    Since you specified the shared library, we assume you mean it and don't consult the avoid list.

    If you are going to be debugging dyld a lot, you can also disable the avoid list altogether by doing:

    (lldb) set set target.breakpoints-use-platform-avoid-list 0
    

    You can do that in a particular session or in your .lldbinit.