crash log
bugly上报的日志如下,方便观察我换行整理了下:
通过addr2line/objdump定位函数基址
提示是_Z26lua_cocos2dx_Node_addChildP9lua_State
函数的问题,通过addr2line,可以得到0x7577cc
对应的地方的确是addChild逻辑
从objdump
的反汇编中找到addChild的相关调用,注意这里都是基址+偏移
,类似if/goto/break/continue
反汇编之后会变成这样的反汇编代码
所以我们可以通过左边减右边就是addChild的基址
实际计算也验证了这个逻辑:
7698040=0x757678
,就是addChild的基址。
通过ida定位函数基址
这种方式需要我们知道函数的签名,才能定位。
_Z26lua_cocos2dx_Node_addChildP9lua_State
这个是编译器对函数的签名。
在ida的Disassemyly窗口中
我们使用jump to address
当然你也可以使用快捷键G
打开下边的面板
这里我们输入_Z26lua_cocos2dx_Node_addChildP9lua_State
,如果成功,ida会跳转到这个函数定义的位置
注意左侧的地址,ida会详细的展示这个函数的细节信息。
函数基址为0x757678,和我们通过objdump算出来的基址是一致的。
通过偏移精确定位代码位置
看到bugly提示偏移为340
通过手动计算0x757678+0x340=0x7579b8
,从objdump的结果中也能看到对应的反汇编代码,执行到str处崩溃的
在ida中更方便,我们可以直接输入
ida会自动跳转到计算后的位置
这两种方式结果是一致的,在ida中按下F5
得到的对应反汇编代码为:
观察反汇编,所以问题应该出在4364行,比addr2line的结果更加精细
template <class T> bool luaval_to_object(lua_State* L, int lo, const char* type, T** ret, const char* funcName = "") { if(nullptr == L || lua_gettop(L) < lo) // 对应的源码 return false; if (!luaval_is_usertype(L, lo, type, 0)) return false; *ret = static_cast<T*>(tolua_tousertype(L, lo, 0)); if (nullptr == *ret){ CCLOG("Warning: %s argument %d is invalid native object(nullptr)", funcName, lo); logLuaCallStack(L); } return true; }
至此这个问题追查到这里,都是一些非常基础的底层实现,如果还没有答案,那么这个问题多半就不太好解决了,有可能跟多线程有关系,也有可能lua虚拟机出现了异常,不是非常好确定。