github.com/undoio/delve@v1.9.0/pkg/proc/moduledata.go (about)

     1  package proc
     2  
     3  import (
     4  	"go/constant"
     5  	"unsafe"
     6  )
     7  
     8  // delve counterpart to runtime.moduledata
     9  type moduleData struct {
    10  	text, etext   uint64
    11  	types, etypes uint64
    12  	typemapVar    *Variable
    13  }
    14  
    15  func loadModuleData(bi *BinaryInfo, mem MemoryReadWriter) ([]moduleData, error) {
    16  	// +rtype -var firstmoduledata moduledata
    17  	// +rtype -field moduledata.text uintptr
    18  	// +rtype -field moduledata.types uintptr
    19  
    20  	scope := globalScope(nil, bi, bi.Images[0], mem)
    21  	var md *Variable
    22  	md, err := scope.findGlobal("runtime", "firstmoduledata")
    23  	if err != nil {
    24  		return nil, err
    25  	}
    26  
    27  	r := []moduleData{}
    28  
    29  	for md.Addr != 0 {
    30  		const (
    31  			typesField   = "types"
    32  			etypesField  = "etypes"
    33  			textField    = "text"
    34  			etextField   = "etext"
    35  			nextField    = "next"
    36  			typemapField = "typemap"
    37  		)
    38  		vars := map[string]*Variable{}
    39  
    40  		for _, fieldName := range []string{typesField, etypesField, textField, etextField, nextField, typemapField} {
    41  			var err error
    42  			vars[fieldName], err = md.structMember(fieldName)
    43  			if err != nil {
    44  				return nil, err
    45  			}
    46  
    47  		}
    48  
    49  		var err error
    50  
    51  		touint := func(name string) (ret uint64) {
    52  			if err == nil {
    53  				var n uint64
    54  				n, err = vars[name].asUint()
    55  				ret = n
    56  			}
    57  			return ret
    58  		}
    59  
    60  		r = append(r, moduleData{
    61  			types: touint(typesField), etypes: touint(etypesField),
    62  			text: touint(textField), etext: touint(etextField),
    63  			typemapVar: vars[typemapField],
    64  		})
    65  		if err != nil {
    66  			return nil, err
    67  		}
    68  
    69  		md = vars[nextField].maybeDereference()
    70  		if md.Unreadable != nil {
    71  			return nil, md.Unreadable
    72  		}
    73  	}
    74  
    75  	return r, nil
    76  }
    77  
    78  func findModuleDataForType(bi *BinaryInfo, mds []moduleData, typeAddr uint64, mem MemoryReadWriter) *moduleData {
    79  	for i := range mds {
    80  		if typeAddr >= mds[i].types && typeAddr < mds[i].etypes {
    81  			return &mds[i]
    82  		}
    83  	}
    84  	return nil
    85  }
    86  
    87  func resolveTypeOff(bi *BinaryInfo, mds []moduleData, typeAddr, off uint64, mem MemoryReadWriter) (*Variable, error) {
    88  	// See runtime.(*_type).typeOff in $GOROOT/src/runtime/type.go
    89  	md := findModuleDataForType(bi, mds, typeAddr, mem)
    90  
    91  	rtyp, err := bi.findType("runtime._type")
    92  	if err != nil {
    93  		return nil, err
    94  	}
    95  
    96  	if md == nil {
    97  		v, err := reflectOffsMapAccess(bi, off, mem)
    98  		if err != nil {
    99  			return nil, err
   100  		}
   101  		v.loadValue(LoadConfig{false, 1, 0, 0, -1, 0})
   102  		addr, _ := constant.Int64Val(v.Value)
   103  		return v.newVariable(v.Name, uint64(addr), rtyp, mem), nil
   104  	}
   105  
   106  	if t, _ := md.typemapVar.mapAccess(newConstant(constant.MakeUint64(uint64(off)), mem)); t != nil {
   107  		return t, nil
   108  	}
   109  
   110  	res := md.types + off
   111  
   112  	return newVariable("", uint64(res), rtyp, bi, mem), nil
   113  }
   114  
   115  func resolveNameOff(bi *BinaryInfo, mds []moduleData, typeAddr, off uint64, mem MemoryReadWriter) (name, tag string, pkgpathoff int32, err error) {
   116  	// See runtime.resolveNameOff in $GOROOT/src/runtime/type.go
   117  	for _, md := range mds {
   118  		if typeAddr >= md.types && typeAddr < md.etypes {
   119  			return loadName(bi, md.types+off, mem)
   120  		}
   121  	}
   122  
   123  	v, err := reflectOffsMapAccess(bi, off, mem)
   124  	if err != nil {
   125  		return "", "", 0, err
   126  	}
   127  
   128  	resv := v.maybeDereference()
   129  	if resv.Unreadable != nil {
   130  		return "", "", 0, resv.Unreadable
   131  	}
   132  
   133  	return loadName(bi, resv.Addr, mem)
   134  }
   135  
   136  func reflectOffsMapAccess(bi *BinaryInfo, off uint64, mem MemoryReadWriter) (*Variable, error) {
   137  	scope := globalScope(nil, bi, bi.Images[0], mem)
   138  	reflectOffs, err := scope.findGlobal("runtime", "reflectOffs")
   139  	if err != nil {
   140  		return nil, err
   141  	}
   142  
   143  	reflectOffsm, err := reflectOffs.structMember("m")
   144  	if err != nil {
   145  		return nil, err
   146  	}
   147  
   148  	return reflectOffsm.mapAccess(newConstant(constant.MakeUint64(uint64(off)), mem))
   149  }
   150  
   151  const (
   152  	// flags for the name struct (see 'type name struct' in $GOROOT/src/reflect/type.go)
   153  	nameflagExported = 1 << 0
   154  	nameflagHasTag   = 1 << 1
   155  	nameflagHasPkg   = 1 << 2
   156  )
   157  
   158  func loadName(bi *BinaryInfo, addr uint64, mem MemoryReadWriter) (name, tag string, pkgpathoff int32, err error) {
   159  	off := addr
   160  	namedata := make([]byte, 3)
   161  	_, err = mem.ReadMemory(namedata, off)
   162  	off += 3
   163  	if err != nil {
   164  		return "", "", 0, err
   165  	}
   166  
   167  	namelen := uint16(namedata[1])<<8 | uint16(namedata[2])
   168  
   169  	rawstr := make([]byte, int(namelen))
   170  	_, err = mem.ReadMemory(rawstr, off)
   171  	off += uint64(namelen)
   172  	if err != nil {
   173  		return "", "", 0, err
   174  	}
   175  
   176  	name = string(rawstr)
   177  
   178  	if namedata[0]&nameflagHasTag != 0 {
   179  		taglendata := make([]byte, 2)
   180  		_, err = mem.ReadMemory(taglendata, off)
   181  		off += 2
   182  		if err != nil {
   183  			return "", "", 0, err
   184  		}
   185  		taglen := uint16(taglendata[0])<<8 | uint16(taglendata[1])
   186  
   187  		rawstr := make([]byte, int(taglen))
   188  		_, err = mem.ReadMemory(rawstr, off)
   189  		off += uint64(taglen)
   190  		if err != nil {
   191  			return "", "", 0, err
   192  		}
   193  
   194  		tag = string(rawstr)
   195  	}
   196  
   197  	if namedata[0]&nameflagHasPkg != 0 {
   198  		pkgdata := make([]byte, 4)
   199  		_, err = mem.ReadMemory(pkgdata, off)
   200  		if err != nil {
   201  			return "", "", 0, err
   202  		}
   203  
   204  		// see func pkgPath in $GOROOT/src/reflect/type.go
   205  		copy((*[4]byte)(unsafe.Pointer(&pkgpathoff))[:], pkgdata)
   206  	}
   207  
   208  	return name, tag, pkgpathoff, nil
   209  }