func foreach_symbol_callback(symname *C.char, addr C.uint64_t) {
	symbolCache.cache[symbolCache.currentModule] =
		append(symbolCache.cache[symbolCache.currentModule], &symbolAddress{C.GoString(symname), (uint64)(addr)})
}
foreach_symbol_callback is a gateway function that will be exported to C
so that it can be referenced as a function pointer
export foreach_symbol_callback
package bcc
import (
	"fmt"
	"regexp"
	"sync"
	"unsafe"
)
import "C"
type symbolAddress struct {
	name string
	addr uint64
}
var symbolCache = struct {
	cache         map[string][]*symbolAddress
	currentModule string
	lock          *sync.Mutex
}{
	cache:         map[string][]*symbolAddress{},
	currentModule: "",
	lock:          &sync.Mutex{},
}
type bccSymbol struct {
	name         *C.char
	demangleName *C.char
	module       *C.char
	offset       C.ulonglong
}
type bccSymbolOption struct {
	useDebugFile      int
	checkDebugFileCrc int
	useSymbolType     uint32
}
func resolveSymbolPath(module string, symname string, addr uint64, pid int) (string, uint64, error) {
	if pid == -1 {
		pid = 0
	}
	modname, offset, err := bccResolveSymname(module, symname, addr, pid)
	if err != nil {
		return "", 0, fmt.Errorf("unable to locate symbol %s in module %s: %v", symname, module, err)
	}
	return modname, offset, nil
}
func bccResolveSymname(module string, symname string, addr uint64, pid int) (string, uint64, error) {
	symbol := &bccSymbol{}
	symbolC := (*C.struct_bcc_symbol)(unsafe.Pointer(symbol))
	moduleCS := C.CString(module)
	defer C.free(unsafe.Pointer(moduleCS))
	symnameCS := C.CString(symname)
	defer C.free(unsafe.Pointer(symnameCS))
	res, err := C.bcc_resolve_symname(moduleCS, symnameCS, (C.uint64_t)(addr), C.int(pid), nil, symbolC)
	if res < 0 {
		return "", 0, fmt.Errorf("unable to locate symbol %s in module %s: %v", symname, module, err)
	}
	return C.GoString(symbolC.module), (uint64)(symbolC.offset), nil
}
func bccResolveName(module, symname string, pid int) (uint64, error) {
	symbol := &bccSymbolOption{}
	symbolC := (*C.struct_bcc_symbol_option)(unsafe.Pointer(symbol))
	pidC := C.int(pid)
	cache := C.bcc_symcache_new(pidC, symbolC)
	moduleCS := C.CString(module)
	defer C.free(unsafe.Pointer(moduleCS))
	nameCS := C.CString(symname)
	defer C.free(unsafe.Pointer(nameCS))
	var addr uint64
	addrC := C.uint64_t(addr)
	res := C.bcc_symcache_resolve_name(cache, moduleCS, nameCS, &addrC)
	if res < 0 {
		return 0, fmt.Errorf("unable to locate symbol %s in module %s", symname, module)
	}
	return addr, nil
}
func getUserSymbolsAndAddresses(module string) ([]*symbolAddress, error) {
	symbolCache.lock.Lock()
	defer symbolCache.lock.Unlock()
	if _, ok := symbolCache.cache[module]; ok {
		return symbolCache.cache[module], nil
	}
	symbolCache.cache[module] = []*symbolAddress{}
	symbolCache.currentModule = module
	if err := bccForeachSymbol(module); err != nil {
		return nil, err
	}
	return symbolCache.cache[module], nil
}
func matchUserSymbols(module, match string) ([]*symbolAddress, error) {
	r, err := regexp.Compile(match)
	if err != nil {
		return nil, fmt.Errorf("invalid regex %s : %s", match, err)
	}
	matchedSymbols := []*symbolAddress{}
	symbols, err := getUserSymbolsAndAddresses(module)
	if err != nil {
		return nil, err
	}
	for _, sym := range symbols {
		if r.MatchString(sym.name) {
			matchedSymbols = append(matchedSymbols, sym)
		}
	}
	return matchedSymbols, nil
}