【问题标题】:Import class-dump info into LLDB将类转储信息导入 LLDB
【发布时间】:2014-06-15 14:17:51
【问题描述】:

这个问题基本上是Import class-dump info into GDB 的克隆,但使用的是 LLDB 而不是 GDB。


使用上述问题的答案中描述的方法,我可以创建包含名为test.stabs的符号的符号文件。

要在 LLDB 中导入和使用此信息,我尝试执行以下操作:

$ lldb test
(lldb) target module add test.stabs
(lldb) b +[TestClass randomNum]
Breakpoint 1: where = test.stabs`+[TestClass randomNum]:F(0,1), address = 0x0000000100000ed0

如您所见,LLDB 可以加载地址,但在实际运行目标时,LLDB 不会中断:

(lldb) r
Process 40430 launched: '/Users/Tyilo/test' (x86_64)
num: 4
Process 40430 exited with status = 0 (0x00000000)

你当然可以直接指定断点的地址:

(lldb) b -a 0x0000000100000ed0

它会起作用的。

有没有办法让b +[TestClass randomNum] 所在的断点在 LLDB 中工作?

【问题讨论】:

  • 坦率地说,如果 LLDB 还没有利用二进制文件中的有价值信息,那么这是一个应该针对 LLDB 提交的错误。应该没有理由“教”LLDB 类转储从二进制文件中获得的东西。

标签: objective-c lldb debug-symbols


【解决方案1】:

我制作了一个 python 函数,可以用来实现我想要的,但是它只有在程序运行时才有效。将下面的代码保存为break_message.py 并通过运行command script import break_message.py 将其导入lldb。现在你可以像这样使用它了:

$ lldb -p $(pgrep Finder)
(lldb) command script import break_message.py
(lldb) break_message -[TApplicationController cmdEmptyTrash:]
(lldb) continue

现在在 Finder 中打开您的废纸篓并清空它(如果它已经是空的,则将其放入其中)。断点将在 lldb 中命中。


import lldb
import re

def lldb_run(command):
    res = lldb.SBCommandReturnObject()
    lldb.debugger.GetCommandInterpreter().HandleCommand(command, res)
    return res

def lldb_call(command):
    res = lldb_run('call ' + command)
    out = res.GetOutput()
    r = re.compile(r'^[^=]*= (.*)\n$')
    m = r.search(out)
    return m.groups()[0]

def __lldb_init_module(debugger, internal_dict):
    lldb_run('command script add -f break_message.{0} {0}'.format('break_message'))

def break_message(debugger, command, result, internal_dict):
    r = re.compile(r'([+-])\s*\[\s*(\S+)\s+([^\]]+)\]')
    m = r.search(command)
    if not m:
        print 'Error in message format!'
        return

    typ, cls, sel = m.groups()
    sel = re.sub(r'\s+', '', sel)

    meta = typ == '+'

    clsptr = lldb_call('(id)objc_getClass("{}")'.format(cls))
    if clsptr == 'nil':
        print "Couldn't find class: " + cls
        return

    selptr = lldb_call('(id)sel_registerName("{}")'.format(sel))
    if selptr == 'nil':
        print "Couldn't register selector: " + sel
        return

    func = 'class_getClassMethod' if meta else 'class_getInstanceMethod'
    method = lldb_call('(id){}({}, {})'.format(func, clsptr, selptr))
    if method == 'nil':
        print "Couldn't find method for: " + sel
        return

    imp = lldb_call('(id)method_getImplementation({})'.format(method))

    lldb_run('breakpoint set -a {}'.format(imp))

【讨论】:

    【解决方案2】:

    lldb 认为你的方法名称是+[TestClass randomNum]:F(0,1)?你的文件名test.stabs 让我觉得它是用 stabs 调试信息构建的——看起来像 stabs。

    lldb 对 stabs 调试格式一无所知——你甚至不能用 clang 生成它——我们在 Mac OS X 和 iOS 上使用 DWARF。您可能会更成功地从您的二进制文件中完全剥离 stabs 调试信息(请参阅 strip(1))命令 - lldb 不会被它分心。

    【讨论】:

    • 尽管名称为test.stabs,但该文件实际上是一个空的dylib,其符号指向剥离后的可执行文件中的地址。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-11-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多