# Go程序异常结束

#### 定位思路

Go进程未按设计要求进行执行，出现异常结束的情况。通常会报诸如：unexpected fault address、signal SIGSEGV: segmentation violation code=0x32XXXX等报错信息。定位思路如图1所示。

图1 Go程序异常结束问题定位思路

1. 确认问题现象，是Go程序异常结束。
2. 使用go mod init {工程文件夹}生成go.mod文件。
3. 使用dlv调试工具，对Go程序进行调试，定位原因。
4. 修改代码，重新编译，验证。
5. 若验证通过，则确认合入代码，问题解决。
6. 若问题未解决，在代码中增加定位信息，重新编译，定位问题。


#### 案例：机器码差异导致异常结束

问题现象：

基于Go语言开发软件，在迁移到鲲鹏后进行测试，出现异常结束。

定位过程：

1. 查看报错日志，如下图所示。
  出现unexpected fault address报错，确认是程序异常退出问题。

2. 生成go.mod文件，后续dlv debug调试依赖工程文件夹下的go.mod文件。
  1 go mod init main

  其中main是工程文件夹。

3. 进入调试模式，设置断点，单步调试。
  1 dlv debug test.go

  其中test.go是源码文件。

4. 通过单步调试，定位在assembleJump函数处存在一段机器码，如下图所示。
5. 此处代码为合入开源社区的monkey补丁。该函数核心功能为实现函数的替换。
  例如：有两个函数A和B，经过monkey补丁的处理：monkey.patch(A, B)，最后在执行A函数的时候，实际上执行的是B函数。即A () à B ()。

6. 结合业务理解，该处机器码来源以下两条汇编语句。
  1 2 mov rdx, main.b.f; jmp [rdx];

  功能为main.b.f函数的地址赋予rdx寄存器，最后通过跳转指令jmp跳到rdx寄存器并执行。

7. 使用鲲鹏汇编指令，重构相关汇编语句，并翻译成机器码。
  1 2 3 mov x10, main.b.f; ldr x11, [x10] br x11;

8. 因为mov指令在鲲鹏上一次只能处理16位，x86平台一次能处理64位，main.b.f为64位立即数，因此需要分四次处理。
9. 重新编译验证通过。
10. 合入代码，问题解决。
