Skip to content

Commit

Permalink
fix #15, support inline function on traceback
Browse files Browse the repository at this point in the history
  • Loading branch information
pkujhd committed Jun 15, 2020
1 parent ea16ec7 commit 70df881
Show file tree
Hide file tree
Showing 10 changed files with 262 additions and 20 deletions.
2 changes: 2 additions & 0 deletions const.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const (
_FuncSize = int(unsafe.Sizeof(_func{}))
ItabSize = int(unsafe.Sizeof(itab{}))
FindFuncBucketSize = int(unsafe.Sizeof(findfuncbucket{}))
InlinedCallSize = int(unsafe.Sizeof(inlinedCall{}))
INVALID_HANDLE_VALUE = ^uintptr(0)
INVALID_OFFSET = int(-1)
)
Expand Down Expand Up @@ -49,4 +50,5 @@ const (
ITAB_PREFIX = "go.itab."
RUNTIME_PREFIX = "runtime."
STKOBJ_SUFFIX = ".stkobj"
INLINETREE_SUFFIX = ".inlinetree"
)
31 changes: 30 additions & 1 deletion dymcode.1.12.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@

package goloader

import (
"cmd/objfile/goobj"
)

const (
R_PCREL = 15
// R_TLS_LE, used on 386, amd64, and ARM, resolves to the offset of the
Expand Down Expand Up @@ -51,10 +55,35 @@ const (
// Update cmd/link/internal/sym/AbiSymKindToSymKind for new SymKind values.
)

// inlinedCall is the encoding of entries in the FUNCDATA_InlTree table.
type inlinedCall struct {
parent int16 // index of parent in the inltree, or < 0
funcID funcID // type of the called function
_ byte
file int32 // fileno index into filetab
line int32 // line number of the call site
func_ int32 // offset into pclntab for name of called function
parentPc int32 // position of an instruction whose source position is the call site (offset from entry)
}

func initInlinedCall(codereloc *CodeReloc, inl goobj.InlinedCall, _func *_func) inlinedCall {
return inlinedCall{
parent: int16(inl.Parent),
funcID: _func.funcID,
file: int32(findFileTab(codereloc, inl.File)),
line: int32(inl.Line),
func_: int32(findFuncNameOff(codereloc, inl.Func.Name)),
parentPc: int32(inl.ParentPC)}
}

func addInlineTree(codereloc *CodeReloc, _func *_func, funcdata *[]uintptr, pcdata *[]uint32, inlineOffset uint32) (err error) {
return _addInlineTree(codereloc, _func, funcdata, pcdata, inlineOffset)
}

func addStackObject(codereloc *CodeReloc, funcname string, symbolMap map[string]uintptr) (err error) {
return _addStackObject(codereloc, funcname, symbolMap)
}

func addDeferReturn(codereloc *CodeReloc, _func *_func, funcname string) (err error) {
func addDeferReturn(codereloc *CodeReloc, _func *_func) (err error) {
return nil
}
29 changes: 28 additions & 1 deletion dymcode.1.14.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package goloader

import (
"cmd/objfile/goobj"
"errors"
"fmt"
)
Expand Down Expand Up @@ -59,11 +60,37 @@ const (

)

// inlinedCall is the encoding of entries in the FUNCDATA_InlTree table.
type inlinedCall struct {
parent int16 // index of parent in the inltree, or < 0
funcID funcID // type of the called function
_ byte
file int32 // fileno index into filetab
line int32 // line number of the call site
func_ int32 // offset into pclntab for name of called function
parentPc int32 // position of an instruction whose source position is the call site (offset from entry)
}

func initInlinedCall(codereloc *CodeReloc, inl goobj.InlinedCall, _func *_func) inlinedCall {
return inlinedCall{
parent: int16(inl.Parent),
funcID: _func.funcID,
file: int32(findFileTab(codereloc, inl.File)),
line: int32(inl.Line),
func_: int32(findFuncNameOff(codereloc, inl.Func.Name)),
parentPc: int32(inl.ParentPC)}
}

func addInlineTree(codereloc *CodeReloc, _func *_func, funcdata *[]uintptr, pcdata *[]uint32, inlineOffset uint32) (err error) {
return _addInlineTree(codereloc, _func, funcdata, pcdata, inlineOffset)
}

func addStackObject(codereloc *CodeReloc, funcname string, symbolMap map[string]uintptr) (err error) {
return _addStackObject(codereloc, funcname, symbolMap)
}

func addDeferReturn(codereloc *CodeReloc, _func *_func, funcname string) (err error) {
func addDeferReturn(codereloc *CodeReloc, _func *_func) (err error) {
funcname := gostringnocopy(&codereloc.pclntable[_func.nameoff])
Func := codereloc.symMap[funcname].Func
if Func != nil && len(Func.FuncData) > _FUNCDATA_OpenCodedDeferInfo {
sym := codereloc.symMap[funcname]
Expand Down
8 changes: 7 additions & 1 deletion dymcode.1.8.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,16 @@ const (
SDWARFINFO
)

type inlinedCall struct{}

func addInlineTree(codereloc *CodeReloc, _func *_func, funcdata *[]uintptr, pcdata *[]uint32, inlineOffset uint32) (err error) {
return nil
}

func addStackObject(codereloc *CodeReloc, funcname string, symbolMap map[string]uintptr) (err error) {
return nil
}

func addDeferReturn(codereloc *CodeReloc, _func *_func, funcname string) (err error) {
func addDeferReturn(codereloc *CodeReloc, _func *_func) (err error) {
return nil
}
26 changes: 25 additions & 1 deletion dymcode.1.9.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@

package goloader

import (
"cmd/objfile/goobj"
)

const (
R_PCREL = 15
// R_TLS_LE, used on 386, amd64, and ARM, resolves to the offset of the
Expand Down Expand Up @@ -44,10 +48,30 @@ const (
// Update cmd/link/internal/sym/AbiSymKindToSymKind for new SymKind values.
)

// inlinedCall is the encoding of entries in the FUNCDATA_InlTree table.
type inlinedCall struct {
parent int32 // index of parent in the inltree, or < 0
file int32 // fileno index into filetab
line int32 // line number of the call site
func_ int32 // offset into pclntab for name of called function
}

func initInlinedCall(codereloc *CodeReloc, inl goobj.InlinedCall, _func *_func) inlinedCall {
return inlinedCall{
parent: int32(inl.Parent),
file: int32(findFileTab(codereloc, inl.File)),
line: int32(inl.Line),
func_: int32(findFuncNameOff(codereloc, inl.Func.Name))}
}

func addInlineTree(codereloc *CodeReloc, _func *_func, funcdata *[]uintptr, pcdata *[]uint32, inlineOffset uint32) (err error) {
return _addInlineTree(codereloc, _func, funcdata, pcdata, inlineOffset)
}

func addStackObject(codereloc *CodeReloc, funcname string, symbolMap map[string]uintptr) (err error) {
return nil
}

func addDeferReturn(codereloc *CodeReloc, _func *_func, funcname string) (err error) {
func addDeferReturn(codereloc *CodeReloc, _func *_func) (err error) {
return nil
}
31 changes: 18 additions & 13 deletions dymcode.go
Original file line number Diff line number Diff line change
Expand Up @@ -435,36 +435,41 @@ func addFuncTab(module *moduledata, index int, pclnOff *int, codereloc *CodeRelo
_func := codereloc._func[index]
_func.entry = module.ftab[index].entry

data := make([]uintptr, len(Func.FuncData))
funcdata := make([]uintptr, len(Func.FuncData))
for k, symbol := range Func.FuncData {
if codereloc.stkmaps[symbol.Sym.Name] != nil {
data[k] = (uintptr)(unsafe.Pointer(&(codereloc.stkmaps[symbol.Sym.Name][0])))
funcdata[k] = (uintptr)(unsafe.Pointer(&(codereloc.stkmaps[symbol.Sym.Name][0])))
} else {
data[k] = (uintptr)(0)
funcdata[k] = (uintptr)(0)
}
}

pcdata := []uint32{}
pcln := uint32(_func.pcln) + uint32(Func.PCLine.Size)
for k := 0; k < len(Func.PCData); k++ {
pcdata = append(pcdata, pcln)
pcln += uint32(Func.PCData[k].Size)
}
if err = addInlineTree(codereloc, &_func, &funcdata, &pcdata, pcln); err != nil {
return err
}
if err = addStackObject(codereloc, funcname, symbolMap); err != nil {
return err
}
if err = addDeferReturn(codereloc, &_func, funcname); err != nil {
if err = addDeferReturn(codereloc, &_func); err != nil {
return err
}

copy2Slice(module.pclntable[offset:], uintptr(unsafe.Pointer(&_func)), _FuncSize)
offset += _FuncSize

pcln := uint32(_func.pcln) + uint32(Func.PCLine.Size)
for k := 0; k < len(Func.PCData); k++ {
binary.LittleEndian.PutUint32(module.pclntable[offset:], pcln)
pcln += uint32(Func.PCData[k].Size)
offset += Uint32Size
if len(pcdata) > 0 {
copy2Slice(module.pclntable[offset:], uintptr(unsafe.Pointer(&(pcdata[0]))), Uint32Size*len(pcdata))
offset += Uint32Size * len(pcdata)
}

offset = alignof(offset, PtrSize)
funcDataSize := int(PtrSize * _func.nfuncdata)
copy2Slice(module.pclntable[offset:], uintptr(unsafe.Pointer(&data[0])), funcDataSize)
offset += funcDataSize
copy2Slice(module.pclntable[offset:], uintptr(unsafe.Pointer(&funcdata[0])), int(PtrSize*_func.nfuncdata))
offset += int(PtrSize * _func.nfuncdata)

*pclnOff = offset
return err
Expand Down
59 changes: 59 additions & 0 deletions inlinetree.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// +build go1.9
// +build !go1.15

package goloader

import (
"cmd/objfile/goobj"
"strings"
"unsafe"
)

func readPCInline(codeReloc *CodeReloc, symbol *goobj.Sym, fd *readAtSeeker) {
fd.ReadAtWithSize(&(codeReloc.pclntable), symbol.Func.PCInline.Size, symbol.Func.PCInline.Offset)
}

func findFuncNameOff(codereloc *CodeReloc, funcname string) int32 {
for index, _ := range codereloc._func {
name := gostringnocopy(&codereloc.pclntable[codereloc._func[index].nameoff])
if name == funcname {
return codereloc._func[index].nameoff
}
}
return -1
}

func findFileTab(codereloc *CodeReloc, filename string) int32 {
tab := codereloc.fileMap[strings.TrimLeft(filename, FILE_SYM_PREFIX)]
for index, value := range codereloc.filetab {
if uint32(tab) == value {
return int32(index)
}
}
return -1
}

func _addInlineTree(codereloc *CodeReloc, _func *_func, funcdata *[]uintptr, pcdata *[]uint32, inlineOffset uint32) (err error) {
funcname := gostringnocopy(&codereloc.pclntable[_func.nameoff])
Func := codereloc.symMap[funcname].Func
if Func != nil && len(Func.InlTree) != 0 {
name := funcname + INLINETREE_SUFFIX
bytes := make([]byte, len(Func.InlTree)*InlinedCallSize)
for k, inl := range Func.InlTree {
inlinedcall := initInlinedCall(codereloc, inl, _func)
copy2Slice(bytes[k*InlinedCallSize:], uintptr(unsafe.Pointer(&inlinedcall)), InlinedCallSize)
}
codereloc.stkmaps[name] = bytes
for _func.nfuncdata <= _FUNCDATA_InlTree {
*funcdata = append(*funcdata, uintptr(0))
_func.nfuncdata++
}
(*funcdata)[_FUNCDATA_InlTree] = (uintptr)(unsafe.Pointer(&(codereloc.stkmaps[name][0])))
for _func.npcdata <= _PCDATA_InlTreeIndex {
*pcdata = append(*pcdata, uint32(0))
_func.npcdata++
}
(*pcdata)[_PCDATA_InlTreeIndex] = inlineOffset
}
return err
}
7 changes: 4 additions & 3 deletions module.1.8.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// +build go1.8
// +build !go1.10,!go1.11,!go1.12,!go1.13,!go1.14,!go1.15
// +build !go1.9,!go1.10,!go1.11,!go1.12,!go1.13,!go1.14,!go1.15

package goloader

Expand All @@ -12,10 +12,8 @@ import (
// See funcdata.h and ../cmd/internal/obj/funcdata.go.
const (
_PCDATA_StackMapIndex = 0
_PCDATA_InlTreeIndex = 1
_FUNCDATA_ArgsPointerMaps = 0
_FUNCDATA_LocalsPointerMaps = 1
_FUNCDATA_InlTree = 2
_ArgsSizeUnknown = -0x80000000
)

Expand Down Expand Up @@ -85,3 +83,6 @@ func init_func(symbol *goobj.Sym, nameOff, spOff, pcfileOff, pclnOff int) _func
}
return fdata
}

func readPCInline(codeReloc *CodeReloc, symbol *goobj.Sym, fd *readAtSeeker) {
}
87 changes: 87 additions & 0 deletions module.1.9.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// +build go1.9
// +build !go1.10,!go1.11,!go1.12,!go1.13,!go1.14,!go1.15

package goloader

import (
"cmd/objfile/goobj"
)

// PCDATA and FUNCDATA table indexes.
//
// See funcdata.h and ../cmd/internal/obj/funcdata.go.
const (
_PCDATA_StackMapIndex = 0
_PCDATA_InlTreeIndex = 1
_FUNCDATA_ArgsPointerMaps = 0
_FUNCDATA_LocalsPointerMaps = 1
_FUNCDATA_InlTree = 2
_ArgsSizeUnknown = -0x80000000
)

// moduledata records information about the layout of the executable
// image. It is written by the linker. Any changes here must be
// matched changes to the code in cmd/internal/ld/symtab.go:symtab.
// moduledata is stored in read-only memory; none of the pointers here
// are visible to the garbage collector.
type moduledata struct {
pclntable []byte
ftab []functab
filetab []uint32
findfunctab uintptr
minpc, maxpc uintptr

text, etext uintptr
noptrdata, enoptrdata uintptr
data, edata uintptr
bss, ebss uintptr
noptrbss, enoptrbss uintptr
end, gcdata, gcbss uintptr
types, etypes uintptr

textsectmap []textsect
typelinks []int32 // offsets from types
itablinks []*itab

ptab []ptabEntry

pluginpath string
pkghashes []modulehash

modulename string
modulehashes []modulehash

gcdatamask, gcbssmask bitvector

typemap map[typeOff]uintptr // offset to *_rtype in previous module

next *moduledata
}

type _func struct {
entry uintptr // start pc
nameoff int32 // function name

args int32 // in/out args size
_ int32 // previously legacy frame size; kept for layout compatibility

pcsp int32
pcfile int32
pcln int32
npcdata int32
nfuncdata int32
}

func init_func(symbol *goobj.Sym, nameOff, spOff, pcfileOff, pclnOff int) _func {
fdata := _func{
entry: uintptr(0),
nameoff: int32(nameOff),
args: int32(symbol.Func.Args),
pcsp: int32(spOff),
pcfile: int32(pcfileOff),
pcln: int32(pclnOff),
npcdata: int32(len(symbol.Func.PCData)),
nfuncdata: int32(len(symbol.Func.FuncData)),
}
return fdata
}
Loading

0 comments on commit 70df881

Please sign in to comment.