xcode反汇编调试iOS模拟器程序(五)调试objc_msgSend函数

原创 2013年04月03日 15:23:08

反汇编调试objective-c,遇到最多的就是objc_msgSend这函数了,本节主要讲讲它的实现以及调试过程的一些技巧。

以UIWebView为例子,看看它在loadRequest时做了什么。

首先必须明白,原始代码中调用

[uiWebViewInstance loadRequest:request]
的实质是调用了
objc_msgSend(uiWebViewInstance, "loadRequest:"的selector, request)

编写一个用到UIWebView的demo,主要功能是打开一个网页。

在main函数加断点,触发后,在命令行输入:

b -[UIWebView loadRequest:]
然后continue,直到触发断点,如下图:


用step over跑到第17行,或直接在那加个断点continue到那。旁边的注释已经显示,call的是存储了objc_msgSend这个函数的偏移地址的代码位置。

17行的前三行,可以看出其动作是往栈上传参数,这三个参数原本是放在edx,ecx,eax的,所以如果参数不多,也可以不用esp为基址来查参数。

在当前的命令行输入

register read
来查看各寄存器的值。lldb会把当前值的意义也输出来。但gdb不会,gdb对应的命令是
info registers

结果如下图:


从ecx的内容可以看出,要call的selector的名字同样是loadRequest:,后面会验证。

接着,step into,可以看到:

那里只有一个跳转命令,继续step into,跳到objc_msgSend真正的地址,看到下图所示的代码:


简单点说,这些代码做了这些事:

1. 先判断传来的对象是否nil,是的话,把返回值(esp+4)置0就返回了,不是就进行下一步。即使是void型的函数,也是被当做有返回值的,只是没用。

2. 查找这个method有没有被cache,有就jmpl到cache了的IMP地址;没有就以selector代表的字符串从这个类的method list里找出method来(第13到20行的循环),cache后再jmpl。如果找不到method就抛出异常然后程序崩溃了。

一个小技巧是,如果想省去点好多次step over来跳过查找的步骤,可以在两个jmpl *%eax的地方加断点,然后run到那里(图中的第31行和38行)。如果传来的对象不是nil,最后都会到这来。此时eax里保存的是函数的地址,即objective-c运行时库定义的IMP(指向函数的指针),jump过去就能到目标函数里了。

另外,在调试反汇编时,step over和step into不要用快捷键,要用调试工具栏上的按钮。不知道为什么按快捷键都等于run了……

接着,在jmpl处step into,就到真实的函数了:


证实了刚才ecx是传了selector名字。


在lldb中搜索

image lookup -r -s objc_msgSend
可以看到:
13 symbols match the regular expression 'objc_msgSend' in /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator6.1.sdk/usr/lib/libobjc.A.dylib:
        Address: libobjc.A.dylib[0x0001708c] (libobjc.A.dylib.__TEXT.__text + 90252)
        Summary: libobjc.A.dylib`objc_msgSend        Address: libobjc.A.dylib[0x00017104] (libobjc.A.dylib.__TEXT.__text + 90372)
        Summary: libobjc.A.dylib`objc_msgSendSuper        Address: libobjc.A.dylib[0x0001716c] (libobjc.A.dylib.__TEXT.__text + 90476)
        Summary: libobjc.A.dylib`objc_msgSendSuper2        Address: libobjc.A.dylib[0x00017468] (libobjc.A.dylib.__TEXT.__text + 91240)
        Summary: libobjc.A.dylib`objc_msgSendSuper2_debug        Address: libobjc.A.dylib[0x00017338] (libobjc.A.dylib.__TEXT.__text + 90936)
        Summary: libobjc.A.dylib`objc_msgSendSuper2_stret        Address: libobjc.A.dylib[0x00017478] (libobjc.A.dylib.__TEXT.__text + 91256)
        Summary: libobjc.A.dylib`objc_msgSendSuper2_stret_debug        Address: libobjc.A.dylib[0x000172c8] (libobjc.A.dylib.__TEXT.__text + 90824)
        Summary: libobjc.A.dylib`objc_msgSendSuper_stret        Address: libobjc.A.dylib[0x00017460] (libobjc.A.dylib.__TEXT.__text + 91232)
        Summary: libobjc.A.dylib`objc_msgSend_debug        Address: libobjc.A.dylib[0x000171dc] (libobjc.A.dylib.__TEXT.__text + 90588)
        Summary: libobjc.A.dylib`objc_msgSend_fpret        Address: libobjc.A.dylib[0x00017480] (libobjc.A.dylib.__TEXT.__text + 91264)
        Summary: libobjc.A.dylib`objc_msgSend_fpret_debug        Address: libobjc.A.dylib[0x00017488] (libobjc.A.dylib.__TEXT.__text + 91272)
        Summary: libobjc.A.dylib`objc_msgSend_noarg        Address: libobjc.A.dylib[0x00017254] (libobjc.A.dylib.__TEXT.__text + 90708)
        Summary: libobjc.A.dylib`objc_msgSend_stret        Address: libobjc.A.dylib[0x00017470] (libobjc.A.dylib.__TEXT.__text + 91248)
        Summary: libobjc.A.dylib`objc_msgSend_stret_debug
objc_msgSend会有好多个版本:

objc_msgSend是普通调用,返回值为void、id、指针、int等32bit能表示的数据的objective-c函数会用到它。

objc_msgSend_stret在返回值为结构体时用到,stret表示structure return。值得一提的是,C++类也算是结构体哦。

objc_msgSend_fpret在返回值为浮点数时用到,fpret表示floating point return

带Super的表示调用父类的函数。


如上节所说,在obj_msgSend的第一行加自动断点 p (char*)*(SEL*)($esp+8) 就会打印多到你不想看的selector名字。注意这个地方不能去po对象,因为po的实质是调用对象的description,这个会再调用obj_msgSend,无限递归就挂了。


转载请注明出处:http://blog.csdn.net/hursing

xcode反汇编调试iOS模拟器程序
(一)查看反汇编
(二)看懂反汇编
(三)查看Objective-C函数与参数
(四)自动断点应用之NSNotificationCenter
(五)调试objc_msgSend函数
(六)函数出入口处的处理与局部变量
(七)Debug与Release的区别

(八)反汇编自己的代码来掌握规则

版权声明:转载请注明出处:http://blog.csdn.net/hursing

相关文章推荐

Effective Objective-C(第11-14条)动态绑定、objc_msgSend、消息转发机制

第11条:理解objc_msgSend的作用     在对象上调用方法是Objective-C中经常使用的功能。用Objective-C术语来说这叫做:“传递消息”(pass a message)。消...
  • hherima
  • hherima
  • 2014年08月10日 15:06
  • 2629

理解 objc_msgSend 的角色

对象调用方法,这个在Objective-C里面叫做传递信息(passing a message)。信息有名称,有方法,接收参数,还可能有返回值。 由于Objective-C是C的一个延展,那么我们首...

iOS中消息分发 objc_msgSend的作用

转自:http://book.51cto.com/art/201403/432144.htm 第11条:理解objc_msgSend的作用 在对象上调用方法是Objective...

runtime objc_msgSend

原文出自:标哥的技术博客 前言想要通过runtime发送消息,就必须要掌握runtime如何发送消息,是调用哪个函数?又是如何调用的?本篇文章只是记录笔者学习objc_msgSend函数的使用笔记,若...

[ios]关于objc_msgSend的学习

最近项目需要,所以使用了objc-c的
  • yxh265
  • yxh265
  • 2014年08月18日 10:29
  • 3707

为什么程序会在objc_msgSend() 崩溃

问题产生的原因 程序崩溃在objc_msgSend(),最有可能的原因是向一个已经释放的对象发送消息。 其他的原因如下: 1.也许你的指针是完全正确的,但是别的缺胳膊少腿的对象的内容可能是溢出在附...

ios objc_msgSend简单使用

引入头文件 #import #import 1. 以前未使用objc_msgSend时,我们是这样调用testRuntime函数的 - (void)runTimeClicked { [...

理解objc_msgSend的作用

在对象上调用方法是Objective-C中经常使用的功能。用Objective-C的术语来说,这叫做“传递消息”(pass a message)。消息有“名称”(name)或“选择子”(selecto...

深入分析 objc_msgSend

原文:http://vagase.me/blog/dig-objc-msgsend/ 在Objective-C中,所有的[receiver message]都会转换为objc_msgSend...
  • zhchaoo
  • zhchaoo
  • 2013年03月27日 13:47
  • 7715

【iOS/Mac OS】程序崩在objc_msgSend(),怎么办?

程序崩在objc_msgSend(),怎么办?   最可能的原因是,当你向一个已经释放的对象发送消息时,或者虽然指针是正确的,却被别的对象破坏了内容(比如内存越界),再或者使用了悬摆指针(dang...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:xcode反汇编调试iOS模拟器程序(五)调试objc_msgSend函数
举报原因:
原因补充:

(最多只允许输入30个字)