zoukankan      html  css  js  c++  java
  • [整理]Breakpoint on arbitrary selector

    基本解释了最近在调试时遇到的一些疑问,接下来就是找解决方法了。

    //-- Begin: 1

    Sometimes when I'm debugging (OK, or hacking) something, a selector
    that I know is implemented by one of the classes in the target project
    is just not recognized by the debugger.  No tab-completion, etc.  Even
    the class is not recognized.  Yet looking up a class object by
    NSClassFromString and selector from NSSelectorFromString return
    reasonable looking values.

    Let's say I know a class "BobController" has a method "slackOff:" - I
    get a SEL from NSSelectorFromString(@"slackOff:").  It returns 111300.
    I examine memory at that location and sure enough, it looks like a
    selector!  I set a conditional breakpoint on objC_msgSend, to break
    whenever $r4==111300, and run the program.

    A very slow launch later, I perform a user action to provoke that
    method (in this case, a menu item that InterfaceBuilder shows as being
    targeted to "BobController" with an action of "slackOff:").  No
    breakpoint!

    Is it unrealistic for me to assume that all messages will get sent
    through objC_msgSend?  What is gdb doing when it sets a breakpoint on
    an Objective C method symbol?  I guess I could look it up in the
    source... any thoughts?

    Daniel

    //-- End

    ======================================================================================================

    //-- Begin: 2

    > Sometimes when I'm debugging (OK, or hacking) something, a selector
    > that I know is implemented by one of the classes in the target project
    > is just not recognized by the debugger.  No tab-completion, etc.  Even
    > the class is not recognized.  Yet looking up a class object by
    > NSClassFromString and selector from NSSelectorFromString return
    > reasonable looking values.


    the reason you're not able to break on an Objective-C symbol is most
    likely because the binary in question has been stripped of debugging
    symbols..  To see what I mean, compile your own Cocoa app, then run nm
    on it and notice that all the objective-c symbols are plainly visible.
    If you then run the strip command on the binary, then re-run nm,
    you'll see that all the objective-c symbol information has been
    removed.

    It's important to note that even when a binary has been stripped, the
    objective-c symbol information is still available from the objective-c
    segment.  Unfortunately, gdb only relies on the symtab segment for
    it's objective-c symbol parsing, so once this information has been
    stripped, gdb can't set a breakpoint on an objective-c method.

    You can, however, use otool to determine the method implementation
    addresses to manually set a breakpoint on methods whose symbols have
    been removed.  For example, to find the address of the method
    "addAppointment:", you can do something like this: "otool -ov
    <binaryname> | grep -A addAppointment:".  You'll then see something
    like "method_imp 0x00008518".  You can then set a breakpoint in gdb on
    this address.

    Mike

    //-- End

    ======================================================================================================

    //-- Begin: 3

    Thanks, Mike.  I will try the otool examination trick.

    I can appreciate that the symbols have been stripped.  That explains
    why gdb doesn't recognize the class or method names, but it doesn't
    explain to me why I can't set a breakpoint on objC_msgSend to catch the
    message, since that is unrelated to debugging symbols.

    Daniel

    //-- End

    ======================================================================================================

    //-- Begin: 4

    For anybody following along, there is a minor correction to make to
    Mike's excellent advice below.

    The "-A" option to grep requires an integer to specify how many lines
    of context to display. In this case, it looks like 3 is the right
    number to ask for if you want to see the method_imp entry:

    otool -ov <binaryname> | grep -A 3 <methodName>

    Thanks again, Mike!

    Daniel

    //-- End

    ======================================================================================================

    //-- Begin: 5

    There is an easy way to do this in the XCode debugger.  Bring up the
    breakpoints window and create a new breakpoint.  Type [BobController
    slackOff:].  Jonathan.

    //-- End

    ======================================================================================================

    //-- Begin: 6

    You must have missed the part in my original message that said I am
    working with methods that gdb doesn't recognize (no symbols).  That
    being the case, Xcode has as much trouble setting the breakpoint as I
    do.

    My real question is "Why doesn't a conditional breakpoint on
    objC_msgSend trap a method call with a particular SEL?"  The rest of
    the details were for context only. This question is sort of beyond the
    scope of Cocoa, I guess. I should probably raise it on the xcode list
    if I want gdb nerds to respond :)

    Daniel

    //-- End

    ======================================================================================================

    //-- Begin: 7

    Is there a way to import the output from class-dump into GDB?

    It’s possible to load a symbol file in gdb with the add-symbol-file command. The hardest part is to produce this symbol file.

    With the help of libMachObjC (which is part of class-dump), it’s very easy to dump all addresses and their corresponding Objective-C methods. I have written a small tool, objc-symbols which does exactly this.

    Let’s use Calendar.app as an example. If you try to list the symbols with the nm tool, you will notice that the Calendar app has been stripped:

    $ nm -U /Applications/Calendar.app/Contents/MacOS/Calendar0000000100000000 T __mh_execute_header
    0000000005614542-000000   OPT radr://5614542

    But with objc-symbols you can easily retrieve the addresses of all the missing Objective-C methods:

    $ objc-symbols /Applications/Calendar.app
    00000001000c774c+[CALCanvasAttributedText textWithPosition:size:text:]00000001000c8936-[CALCanvasAttributedText createTextureIfNeeded]00000001000c8886-[CALCanvasAttributedText bounds]00000001000c883b-[CALCanvasAttributedText updateBezierRepresentation]...00000001000309eb-[CALApplication applicationDidFinishLaunching:]...

    Then, with SymTabCreator you can create a symbol file, which is just actually an empty dylib with all the symbols.

    Using objc-symbols and SymTabCreator together is straightforward:

    $ objc-symbols /Applications/Calendar.app |SymTabCreator-o Calendar.stabs

    You can check that Calendar.stabs contains all the symbols:

    $ nm Calendar.stabs 
    000000010014a58b T +[APLCALSource printingCachedTextSize]000000010013e7c5 T +[APLColorSource alternateGenerator]000000010013e780 T +[APLColorSource defaultColorSource]000000010013e7bd T +[APLColorSource defaultGenerator]000000010011eb12 T +[APLConstraint constraintOfClass:withProperties:]...00000001000309eb T -[CALApplication applicationDidFinishLaunching:]...

    Now let’s see what happens in gdb:

    $ gdb --silent /Applications/Calendar.app
    Reading symbols for shared libraries ................................. done

    Without the symbol file:

    (gdb) b -[CALApplication applicationDidFinishLaunching:]Function"-[CALApplication applicationDidFinishLaunching:]" not defined.Make breakpoint pending on future shared library load?(y or [n]) n

    And after loading the symbol file:

    (gdb) add-symbol-file Calendar.stabs 
    add symbol table from file "Calendar.stabs"?(y or n) y
    Reading symbols from /Users/0xced/Calendar.stabs...done.(gdb) b -[CALApplication applicationDidFinishLaunching:]Breakpoint1 at 0x1000309f2

    You will notice that the breakpoint address does not exactly match the symbol address (0x1000309f2 vs 0x1000309eb, 7 bytes of difference), this is because gdb automatically recognizes the function prologue and sets the breakpoint just after.

    ====================

    I can't compile SymTabCreator, I get the error /Users/Tyilo/Downloads/SymTabCreator-master/SymTabCreator.m:80:54: Operand of type 'NSArray' where arithmetic or pointer type is required. – Tyilo Jul 25 at 17:07 

    @Tyilo: You need to upgrade your developer tools. Xcode has supported object subscripting since 4.4. developer.apple.com/library/mac/releasenotes/ObjectiveC/… – Peter Hosey Jul 25 at 17:16

    @PeterHosey Well I'm using Xcode 4.6, so there must be some build setting that prevents me from using objc subscripting. – Tyilo Jul 25 at 17:21

    @PeterHosey It works fine when building the Debug version, but it only happens with the Release version. – Tyilo Jul 25 at 17:25

     Hey! Really nice code :) Like it a lot. I've created a script that simplifies all this into a single line. See gist.github.com/nickskull/6083359 – Dominik Hadl Jul 25 at 20:23

    @Tyilo: I haven't looked, but it might be building both i386 and x86_64 architectures. The 64-bit build will succeed, on either configuration, but the 32-bit build will fail because subscripting (among other features) is 64-bit-only. Try unsetting the Architectures build setting. – Peter Hosey Jul 25 at 20:52

    @PeterHosey That fixed it, thanks. – Tyilo

    ====================

    //-- End

    ======================================================================================================

    //-- Begin: 8

    And now there is a way to do it... nice answer, 0xced!

    The DWARF file format is well documented, IIRC, and, as the lldb source is available, you have a working example of a parser.

    Since the source to class-dump is also available, it shouldn't be too hard to modify it to spew DWARF output that could then be loaded into the debugger.

    Obviously, you wouldn't be able to dump symbols with full fidelity, but this would probably be quite useful.

    ===================

    just to be clear … the original questioner was asking about gdb, but whether the original questioner ought to be more interested in lldb since that's what's current or else the original questioner really wants gdb, most of what is said here still stands … source to gdb can be retrieved from gnu.org/software/gdb/current if that's truly what's desired. –  john.k.doe Jul 21 at 17:35

    @john.k.doe Yes -- good point. Also, it appears that gdb can load DWARF, as well. –  bbum

    ===================

    //-- End

    ======================================================================================================

  • 相关阅读:
    Python学习——模块的基本知识
    Python学习-软件目录结构规范
    路径追踪的理论与实现:复合重要性采样
    路径追踪的理论与实现:渲染方程
    记一个C++随机数导致的bug
    Gamma矫正的原理和实现
    聊一聊Python的sort函数
    BVH树的构建与遍历
    Cocos动画系统
    Cocos事件分发系统
  • 原文地址:https://www.cnblogs.com/Proteas/p/3462335.html
Copyright © 2011-2022 走看看