Go程序异常结束
定位思路
Go进程未按设计要求进行执行,出现异常结束的情况。往往会报诸如:unexpected fault address、signal SIGSEGV: segmentation violation code=0x32XXXX等报错信息。定位思路如图1所示。
- 确认问题现象,是Go程序异常结束。
- 使用go mod init {工程文件夹}生成go.mod文件。
- 使用dlv调试工具,对Go程序进行调试,定位原因。
- 修改代码,重新编译,验证。
- 若验证通过,则确认合入代码,问题解决。
- 若问题未解决,在代码中增加定位信息,重新编译,定位问题。
案例:机器码差异导致异常结束
问题现象:
基于Go语言开发软件,在迁移到鲲鹏后进行测试,出现异常结束。
定位过程:
- 查看报错日志,如下图所示。
出现unexpected fault address报错,确认是程序异常退出问题。
- 生成go.mod文件,后续dlv debug调试依赖工程文件夹下的go.mod文件。
1
go mod init main
其中main是工程文件夹。
- 进入调试模式,设置断点,单步调试。
1
dlv debug test.go
其中test.go是源码文件。
- 通过单步调试,定位在assembleJump函数处存在一段机器码,如下图所示。
- 此处代码为合入开源社区的monkey补丁。该函数核心功能为实现函数的替换。
例如:有两个函数A和B,经过monkey补丁的处理:monkey.patch(A, B),最后在执行A函数的时候,实际上执行的是B函数。即A () à B ()。
- 结合业务理解,该处机器码来源以下两条汇编语句。
1 2
mov rdx, main.b.f; jmp [rdx];
功能为main.b.f函数的地址赋予rdx寄存器,最后通过跳转指令jmp跳到rdx寄存器并执行。
- 使用鲲鹏汇编指令,重构相关汇编语句,并翻译成机器码。
1 2 3
mov x10, main.b.f; ldr x11, [x10] br x11;
- 因为mov指令在鲲鹏上一次只能处理16位,x86平台一次能处理64位,main.b.f为64位立即数,因此需要分四次处理。
- 重新编译验证通过。
- 合入代码,问题解决。
父主题: 疑难问题