写一个错误的c程序
package dlsym
import "testing"
func Test_intercept(t *testing.T) { Intercept("gethostbyname\x00") }
package dlsym
// #cgo CFLAGS: -I.
// #include <stddef.h>
// #include "dlsym_wrapper.h" import "C" import "unsafe" func Intercept(symbol string) { ptr := unsafe.Pointer(&([]byte(symbol)[0])) C.intercept((*C.char)(ptr), C.size_t(len(symbol))) }
#include <dlfcn.h>
#include <stddef.h> #include <stdio.h> void intercept(char *symbol, size_t symbol_len) { symbol = NULL; // will cause SIGSEGV printf("%s\n", symbol); fflush(stdout); }
编译测试为可执行文件
go test -c github.com/taowen/go-lib c/dlsym
# will produce executable dlsym.test
这个是用于分析coredump的时候获得符号表使用的。
执行测试,获得coredump
GOTRACEBACK=crash ./dlsym.test
# produced /tmp/core_dlsym.test.29937
如果找不到coredump的位置,执行之前先设置好coredump的写出条件
echo '/tmp/core_%e.%p' | sudo tee /proc/sys/kernel/core_pattern
ulimit -c unlimited # coredump can be any large
用gdb分析coredump
gdb dlsym.test /tmp/core_dlsym.test /tmp/core_dlsym.test.29937
-
用
bt full
查看所有的frame -
用
frame <number>
查看指定的frame -
用
print <symbol>
查看指定的变量的值
通过cgo调用C语言库时会出现程序崩溃的情况,于是就希望能够生成core文件来查看程序崩溃时的堆栈信息。那么Golang程序如何在崩溃后生成core文件呢?答案就是GOTRACEBACK这个环境变量。
关于GOTRACEBACK环境变量的详细说明,可以参考官方 文档在
runtime一节的链接,这里仅列出文档中较为核心的说明如下(Golang版本为1.6)。根据文档的说明我们可以知道GOTRACEBACK的可选值为:none、single、all、system和crash,其中关于crash的说明就指出了在Unix系统上,程序崩溃会通过SIGABRT信号触发一次core dump。
GOTRACEBACK=none omits the goroutine stack traces entirely.
GOTRACEBACK=single (the default) behaves as described above.
GOTRACEBACK=all adds stack traces for all user-created goroutines.
GOTRACEBACK=system is like “all” but adds stack frames for run-time functions and shows goroutines created internally by the run-time.
GOTRACEBACK=crash is like “system” but crashes in an operating system-specific manner instead of exiting. For example, on Unix systems, the crash raises SIGABRT to trigger a core dump.
另外,虽然官方文档给出了GOTRACEBACK环境变量在不同选值下的行为说明,但看起来实在是有些不知所云,这里我们不妨通过一个简单的程序来验证一下,毕竟程序跑出来的效果才比较真实。以下是验证程序的代码,其功能非常简单,启动两个goroutine,一个正常跑10秒钟,一个睡5秒钟之后自行panic。
package main
import (
"fmt"
"time"
)