【问题标题】:How to cast a function name to an address and add offset in LLDB?如何将函数名称转换为地址并在 LLDB 中添加偏移量?
【发布时间】:2020-02-20 02:14:33
【问题描述】:

说,我在 Mach-O 可执行文件中有两个相邻的函数 subfunc()main(),想反汇编从 subfunc()main()+0x10. 的所有指令

我知道我可以使用 `(void(*)())subfunc` 将函数转换为地址 - 没有更简单的方法吗?

我的尝试如下,但我收到以下错误消息:

dis -s `(void(*)())subfunc` -e `(void(*)())main+0x10` error: error: arithmetic on a pointer to the function type 'void ()'

我该如何解决这个问题?

【问题讨论】:

  • 如果你有调试信息,所以 lldb 知道这些是函数,有一种特殊情况,你不使用反引号,它会做正确的事情 -- dis -s subfunc -e main+16 -- 但我只是检查过,当 lldb 现在不知道这些是函数符号时,它看起来不起作用。显然,没有任何有效的 C 表达式可以为函数名称添加偏移量,因此 lldb 中有一些额外的技巧来允许这个(通常有用的)地址表达式。我不记得为什么它使用带有地址表达式而不是反引号的参数 eval r.n.
  • @JasonMolenda - 谢谢。地址表达式和反引号 eval 不是一回事吗?你能指点我这些东西的文档吗?
  • main+5 不是一个有效的 C 表达式,但它是一种非常方便的指定地址的方法。我们没有修改表达式解析器以接受这种形式(我们希望使表达式解析器与源语言保持准确),而是添加了“地址表达式”。他们首先尝试将他们的参数评估为表达式,如果失败,他们将解析形式为“symbolname+-offset”的简单表达式,“帮助地址表达式”是应该记录的地方,但是帮助字符串有点简洁。 ..
  • @JimIngham,在任何地方都没有关于地址表达式或反引号表达式的详细文档吗?如果<symbol>+-<offset> 有效,为什么main+5 无效? main 不是符号吗?

标签: macos debugging lldb


【解决方案1】:

这似乎是正确的语法:

dis --start-address `(void(*)())main` --end-address `(void(*)())main`+0x10

此语法与您尝试的变体之间非常小的区别是+0x10 偏移量在反引号字符之外,即偏移量在结束反引号之后 .

FWIW 这个变种似乎也能正常工作:

dis --start-address `(void(*)())main` --end-address 0x10+`(void(*)())main`

发现过程:

  • 我不熟悉您在原始问题中描述的“反引号”+ 函数转换,因此这是一个非常有用的起点。

    在我的情况下,我试图在共享库内的函数偏移处设置断点,并且在我的搜索让我找到你的问题之前就已经走到了这一步:

    breakpoint set --shlib libexample.dylib --address `((void*)some_function)+81`
    
    error: error: function 'some_function' with unknown type must be given a function type
    error: 1 errors parsing expression
    
  • 您的函数转换提示的使用符合错误消息中所述的“函数类型”要求,因此我接下来能够:

    print (void(*)())some_function
    
    (void (*)()) $38 = 0x00000001230094d0 (libexample.dylib`some_function)
    
  • 然后我尝试了似乎可以工作的反引号变体,但我希望该值以十六进制显示:

    print `(void(*)())some_function`
    (long) $2 = 4882207952
    
  • 但是当我尝试将-f hex 格式选项与打印一起使用时,我得到了一个错误:

    print -f hex `(void(*)())some_function`
    
    error: use of undeclared identifier 'f'
    error: 1 errors parsing expression
    
  • 最终,我注意到help print 输出底部的注释'print' is an abbreviation for 'expression --' 并意识到这意味着(显然?)不可能使用print 的替代显示格式,因为它被转换为expression -- -f hex ...语法无效。

  • 最终我找到了命令名称、显示格式和“--”所需的位置和组合,以使其按需要显示:

    expression -f hex -- `(void(*)())some_function`
    
    (long) $7 = 0x00000001230094d0
    
  • 没有什么特别的原因(我记得),正是在这一点上,我尝试将偏移量放在反引号之外,并且成功了!

    expression -f hex -- `(void(*)())some_function`+81
    
    (long) $12 = 0x0000000123009521
    
  • 当我尝试使用断点时它仍然有效:

    breakpoint set --shlib libexample.dylib --address `(void(*)())some_function`+81
    
    Breakpoint 6: where = libexample.dylib`some_function + 81, address = 0x0000000123009521
    
  • 然后我验证它也适用于您原始问题中的dis 命令:

    dis --start-address `(void(*)())some_function` --end-address `(void(*)())some_function`+81
    
  • 并确认裸函数名是不够的:

    dis --start-address some_function --end-address `(void(*)())some_function`+81
    
    error: address expression "some_function" evaluation failed
    
  • 我还再次确认反引号之间的偏移没有起作用:

    dis --start-address `(void(*)())some_function` --end-address `(void(*)())some_function+1`
    
    error: error: arithmetic on a pointer to the function type 'void ()'
    error: 1 errors parsing expression
    
  • 正是在这一点上,我意识到 能够解析 错误消息(大概是这样):

    [arithmetic on a pointer]  [to the function type]  ['void ()']
    

    根本问题是“指针算术”...

  • 进一步的研究表明,“函数类型指针未定义”都可以作为 gcc 扩展使用:

  • 这让我们回到了 @JasonMolenda 和 @JimIngham 的 cmets 以及函数指针算术解析是如何特殊情况的。

    在我看来,您收到的“错误:对指向函数类型的指针的算术......”消息充其量是糟糕的用户体验,最坏的情况是一个错误——考虑到 lldb 本身本质上以这种方式显示地址引用:

    0x1230094f9:  jle    0x123009cc2               ; some_function + 2034
    

    我对 libexample.dylib`some_function + 81 被显示但 AFAICT 没有被解析的感觉类似。

  • 总之,这种形式有效:

    `(void(*)())some_function`+0x10
    

    现在我只需要弄清楚为什么 some_function 没有做我认为应该做的事...... :)

【讨论】:

    猜你喜欢
    • 2018-03-24
    • 1970-01-01
    • 1970-01-01
    • 2015-03-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-20
    相关资源
    最近更新 更多