# GLThread 1371(29457) SIGSEGV(SEGV_MAPERR)
#00 pc 0000000000aa3f58 split_config.arm64_v8a.apk
#01 pc 0000000000aafb84 split_config.arm64_v8a.apk
在之前的2篇教程里面,我们已经了解了split_confing.arm64_v8a.apk, SIGSEGV(SEGV_MAPERR)的相关基础知识,本节教程就来详细聊一聊这个崩溃地址pc 0000000000xxxxxx相关的知识。
ndk 与 so库
使用游戏引擎开发游戏,一定是会和c++打交道,而在安卓上编译c++游戏引擎,我们使用的ndk(Native Development Kit)构建so库,一般来说如果崩溃发生在我们的so库,在崩溃日志里面,我们都会看些携带崩溃so库以及行号等信息,如下:

但也有个别情况,我们的崩溃信息没有任何so库相关的信息,如下所示,仅仅指向了apk,没有更多的信息了,这种情况不在本节的讨论范围之内。
#00 pc 0000000000aa3f58 split_config.arm64_v8a.apk
函数修饰名
在上边的举例中,我们会发现一串我们可能会认识的类似函数的字符串
_Z26lua_cocos2dx_Node_addChildP9lua_State+340
我们可以分为2部分理解:
_Z 26 lua_cocos2dx_Node_addChild P 9 lua_State
这是编译器对函数的修饰,不同的编译器对函数的修饰结果也不同,一般都是以_Z开头,26表示函数名字的长度,紧接着P表示第一个参数是个指针类型,9表示函数参数类型名字长度,所以从以上信息,我们就能推理出函数原型为:
lua_cocos2dx_Node_addChild( lua_State* )
为什么要有函数名修饰这玩意?
因为大部分的编译语言都支持函数重载(函数名相同,但参数个数/类型不同),在链接时为了区分,所以对每个函数作了修饰,当然还有更多的原因,但我们只需要这么多足矣。
其实我们在链接c++程序遇到报错时,经常会遇到函数修饰名称,当我们在c++代码里面调用c代码时,经常会用到extern关键字,其背后的原因都和这个函数名称修饰有关系。
340
这个是基于函数地址的偏移量,我们观察so的反汇编代码,能够看到非常多的函数名+偏移量的调用,我们代码层面的if/goto/break/continue/函数调用等逻辑的跳转,在汇编的角度看来,都是地址的跳转,如下图的汇编指令:
-
b: 跳转到指定的目标地址执行代码。
-
b.ne / b.eq : 根据条件进行跳转。

思考
了解完毕以上的基础知识后,我们简单思考下:
_Z26lua_cocos2dx_Node_addChildP9lua_State+340的目标位置是addChild+340,这个位置一般来说是落在addChild的函数实现内部,所以我们通过这个偏移量是能够很明确的知道具体崩溃在函数的具体行数以及位置。
bugly会自动帮我们计算这些信息,前提是需要我们上传符号表文件,没错,这些信息就是在符号表文件里面。
接下来
本节暂时介绍这么多,涉及的内容有点偏底层、偏原理,下一节我们会实际动手操作验证下:
崩溃地址、函数修饰名、函数偏移量,三者之间的关系
提前剧透下,我们会详细介绍
-
符号表 -
readelf读取 ELF(可执行和可链接的格式)文件信息 -
addr2line:崩溃地址获得函数的行号 -
objdump:反汇编so文件

被折叠的 条评论
为什么被折叠?



