github.com/podhmo/reflect-shape@v0.4.3/metadata/internal/unsaferuntime/api.go (about)

     1  package unsaferuntime
     2  
     3  import (
     4  	"fmt"
     5  	"runtime"
     6  	"strings"
     7  	"unsafe"
     8  )
     9  
    10  type Accessor struct {
    11  	// TODO: cache
    12  	// fmPCtoPC map[uintptr]uintptr
    13  }
    14  
    15  func New() *Accessor {
    16  	return &Accessor{}
    17  }
    18  
    19  func (a *Accessor) FuncForPC(pc uintptr) *runtime.Func {
    20  	rfunc := runtime.FuncForPC(pc)
    21  	if !strings.HasSuffix(rfunc.Name(), "-fm") {
    22  		return rfunc
    23  	}
    24  	target := strings.TrimSuffix(rfunc.Name(), "-fm")
    25  
    26  	var prevs []*moduledata
    27  	findDepth := 1
    28  	for datap := &runtime_firstmoduledata; datap != nil; datap = datap.next {
    29  		if datap.minpc <= pc && pc < datap.maxpc {
    30  			m := datap
    31  			for _, functab := range m.ftab {
    32  				//	fmt.Printf("functab: %x, %x\n", functab.entryoff, functab.funcoff)
    33  				funcoff := functab.funcoff
    34  				rfunc := (*runtime.Func)(unsafe.Pointer(&m.pclntable[funcoff]))
    35  				if rfunc.Name() == target {
    36  					return rfunc
    37  				}
    38  			}
    39  			// find prev
    40  			if len(prevs) > 0 {
    41  				m := prevs[len(prevs)-findDepth]
    42  				for _, functab := range m.ftab {
    43  					//	fmt.Printf("functab: %x, %x\n", functab.entryoff, functab.funcoff)
    44  					funcoff := functab.funcoff
    45  					rfunc := (*runtime.Func)(unsafe.Pointer(&m.pclntable[funcoff]))
    46  					if rfunc.Name() == target {
    47  						return rfunc
    48  					}
    49  				}
    50  				findDepth++
    51  			}
    52  			// find next
    53  			continue
    54  		}
    55  		prevs = append(prevs, datap)
    56  	}
    57  	return nil
    58  }
    59  
    60  func Print(pc uintptr, pkg string) error {
    61  	prefix := strings.TrimSuffix(pkg, ".") + "."
    62  
    63  	for datap := &runtime_firstmoduledata; datap != nil; datap = datap.next {
    64  		if datap.minpc <= pc && pc < datap.maxpc {
    65  			m := datap
    66  			for _, functab := range m.ftab {
    67  				//	fmt.Printf("functab: %x, %x\n", functab.entryoff, functab.funcoff)
    68  				funcoff := functab.funcoff
    69  				rfunc := (*runtime.Func)(unsafe.Pointer(&m.pclntable[funcoff]))
    70  
    71  				if strings.Contains(rfunc.Name(), prefix) {
    72  					filename, lineno := rfunc.FileLine(rfunc.Entry())
    73  					fmt.Printf("* %s\t%v:%v\n", rfunc.Name(), filename, lineno)
    74  				}
    75  			}
    76  		}
    77  	}
    78  
    79  	return nil
    80  }