github.com/ks888/tgo@v0.0.0-20190130135156-80bf89407292/tracee/process.go (about)

     1  package tracee
     2  
     3  import (
     4  	"debug/dwarf"
     5  	"encoding/binary"
     6  	"fmt"
     7  	"sort"
     8  	"strings"
     9  
    10  	"github.com/ks888/tgo/debugapi"
    11  	"github.com/ks888/tgo/log"
    12  	"golang.org/x/arch/x86/x86asm"
    13  )
    14  
    15  var breakpointInsts = []byte{0xcc}
    16  
    17  type breakpoint struct {
    18  	addr     uint64
    19  	orgInsts []byte
    20  }
    21  
    22  // Process represents the tracee process launched by or attached to this tracer.
    23  type Process struct {
    24  	debugapiClient *debugapi.Client
    25  	breakpoints    map[uint64]breakpoint
    26  	Binary         BinaryFile
    27  	GoVersion      GoVersion
    28  	moduleDataList []*moduleData
    29  	valueParser    valueParser
    30  }
    31  
    32  const countDisabled = -1
    33  
    34  // StackFrame describes the data in the stack frame and its associated function.
    35  type StackFrame struct {
    36  	Function        *Function
    37  	InputArguments  []Argument
    38  	OutputArguments []Argument
    39  	ReturnAddress   uint64
    40  }
    41  
    42  // Attributes specifies the set of tracee's attributes.
    43  type Attributes struct {
    44  	ProgramPath         string
    45  	CompiledGoVersion   string
    46  	FirstModuleDataAddr uint64
    47  }
    48  
    49  // LaunchProcess launches new tracee process.
    50  func LaunchProcess(name string, arg []string, attrs Attributes) (*Process, error) {
    51  	debugapiClient := debugapi.NewClient()
    52  	if err := debugapiClient.LaunchProcess(name, arg...); err != nil {
    53  		return nil, err
    54  	}
    55  
    56  	if attrs.ProgramPath == "" {
    57  		attrs.ProgramPath = name
    58  	}
    59  	proc, err := newProcess(debugapiClient, attrs)
    60  	if err != nil {
    61  		debugapiClient.DetachProcess()
    62  	}
    63  	return proc, err
    64  }
    65  
    66  // AttachProcess attaches to the existing tracee process.
    67  func AttachProcess(pid int, attrs Attributes) (*Process, error) {
    68  	debugapiClient := debugapi.NewClient()
    69  	err := debugapiClient.AttachProcess(pid)
    70  	if err != nil {
    71  		return nil, err
    72  	}
    73  
    74  	proc, err := newProcess(debugapiClient, attrs)
    75  	if err != nil {
    76  		debugapiClient.DetachProcess() // keep the attached process running
    77  	}
    78  	return proc, err
    79  }
    80  
    81  func newProcess(debugapiClient *debugapi.Client, attrs Attributes) (*Process, error) {
    82  	proc := &Process{debugapiClient: debugapiClient, breakpoints: make(map[uint64]breakpoint)}
    83  
    84  	proc.GoVersion = ParseGoVersion(attrs.CompiledGoVersion)
    85  	var err error
    86  	proc.Binary, err = OpenBinaryFile(attrs.ProgramPath, proc.GoVersion)
    87  	if err != nil {
    88  		return nil, err
    89  	}
    90  	proc.moduleDataList = parseModuleDataList(attrs.FirstModuleDataAddr, proc.Binary.moduleDataType(), debugapiClient)
    91  	proc.valueParser = valueParser{reader: debugapiClient, mapRuntimeType: proc.mapRuntimeType}
    92  	return proc, nil
    93  }
    94  
    95  func parseModuleDataList(firstModuleDataAddr uint64, moduleDataType dwarf.Type, reader memoryReader) (moduleDataList []*moduleData) {
    96  	moduleDataAddr := firstModuleDataAddr
    97  	for moduleDataAddr != 0 {
    98  		md := newModuleData(moduleDataAddr, moduleDataType)
    99  		moduleDataList = append(moduleDataList, md)
   100  
   101  		moduleDataAddr = md.next(reader)
   102  	}
   103  	return
   104  }
   105  
   106  func (p *Process) mapRuntimeType(runtimeTypeAddr uint64) (dwarf.Type, error) {
   107  	var md *moduleData
   108  	var reader memoryReader = p.debugapiClient
   109  	for _, candidate := range p.moduleDataList {
   110  		if candidate.types(reader) <= runtimeTypeAddr && runtimeTypeAddr < candidate.etypes(reader) {
   111  			md = candidate
   112  			break
   113  		}
   114  	}
   115  
   116  	return p.Binary.findDwarfTypeByAddr(runtimeTypeAddr - md.types(reader))
   117  }
   118  
   119  // Detach detaches from the tracee process. All breakpoints are cleared.
   120  func (p *Process) Detach() error {
   121  	for breakpointAddr := range p.breakpoints {
   122  		if err := p.ClearBreakpoint(breakpointAddr); err != nil {
   123  			// the process may have exited already
   124  			log.Debugf("failed to clear breakpoint at %#x: %v", breakpointAddr, err)
   125  		}
   126  	}
   127  
   128  	if err := p.debugapiClient.DetachProcess(); err != nil {
   129  		return err
   130  	}
   131  
   132  	return p.close()
   133  }
   134  
   135  func (p *Process) close() error {
   136  	return p.Binary.Close()
   137  }
   138  
   139  // ContinueAndWait continues the execution and waits until an event happens.
   140  // Note that the id of the stopped thread may be different from the id of the continued thread.
   141  func (p *Process) ContinueAndWait() (debugapi.Event, error) {
   142  	event, err := p.debugapiClient.ContinueAndWait()
   143  	if debugapi.IsExitEvent(event.Type) {
   144  		err = p.close()
   145  	}
   146  	return event, err
   147  }
   148  
   149  // SingleStep executes one instruction while clearing and setting breakpoints.
   150  // If not all the threads are stopped, there is some possibility that another thread
   151  // passes through the breakpoint while single-stepping.
   152  func (p *Process) SingleStep(threadID int, trappedAddr uint64) error {
   153  	if err := p.setPC(threadID, trappedAddr); err != nil {
   154  		return err
   155  	}
   156  
   157  	bp, bpSet := p.breakpoints[trappedAddr]
   158  	if bpSet {
   159  		if err := p.debugapiClient.WriteMemory(trappedAddr, bp.orgInsts); err != nil {
   160  			return err
   161  		}
   162  	}
   163  
   164  	if _, err := p.stepAndWait(threadID); err != nil {
   165  		unspecifiedError, ok := err.(debugapi.UnspecifiedThreadError)
   166  		if !ok {
   167  			return err
   168  		}
   169  
   170  		if err := p.singleStepUnspecifiedThreads(threadID, unspecifiedError); err != nil {
   171  			return err
   172  		}
   173  		return p.SingleStep(threadID, trappedAddr)
   174  	}
   175  
   176  	if bpSet {
   177  		return p.debugapiClient.WriteMemory(trappedAddr, breakpointInsts)
   178  	}
   179  	return nil
   180  }
   181  
   182  func (p *Process) setPC(threadID int, addr uint64) error {
   183  	regs, err := p.debugapiClient.ReadRegisters(threadID)
   184  	if err != nil {
   185  		return err
   186  	}
   187  
   188  	regs.Rip = addr
   189  	return p.debugapiClient.WriteRegisters(threadID, regs)
   190  }
   191  
   192  func (p *Process) stepAndWait(threadID int) (event debugapi.Event, err error) {
   193  	event, err = p.debugapiClient.StepAndWait(threadID)
   194  	if debugapi.IsExitEvent(event.Type) {
   195  		err = p.close()
   196  	}
   197  	return event, err
   198  }
   199  
   200  // SetBreakpoint sets the breakpoint at the specified address.
   201  func (p *Process) SetBreakpoint(addr uint64) error {
   202  	_, ok := p.breakpoints[addr]
   203  	if ok {
   204  		return nil
   205  	}
   206  
   207  	originalInsts := make([]byte, len(breakpointInsts))
   208  	if err := p.debugapiClient.ReadMemory(addr, originalInsts); err != nil {
   209  		return err
   210  	}
   211  	if err := p.debugapiClient.WriteMemory(addr, breakpointInsts); err != nil {
   212  		return err
   213  	}
   214  
   215  	p.breakpoints[addr] = breakpoint{addr, originalInsts}
   216  	return nil
   217  }
   218  
   219  // ClearBreakpoint clears the breakpoint at the specified address.
   220  func (p *Process) ClearBreakpoint(addr uint64) error {
   221  	bp, ok := p.breakpoints[addr]
   222  	if !ok {
   223  		return nil
   224  	}
   225  
   226  	if err := p.debugapiClient.WriteMemory(addr, bp.orgInsts); err != nil {
   227  		return err
   228  	}
   229  
   230  	delete(p.breakpoints, addr)
   231  	return nil
   232  }
   233  
   234  // ExistBreakpoint returns true if the the breakpoint is already set at the specified address.
   235  func (p *Process) ExistBreakpoint(addr uint64) bool {
   236  	_, ok := p.breakpoints[addr]
   237  	return ok
   238  }
   239  
   240  // StackFrameAt returns the stack frame to which the given rbp specified.
   241  // To get the correct stack frame, it assumes:
   242  // * rsp points to the return address.
   243  // * rsp+8 points to the beginning of the args list.
   244  //
   245  // To be accurate, we need to check the .debug_frame section to find the CFA and return address.
   246  // But we omit the check here because this function is called at only the beginning or end of the tracee's function call.
   247  func (p *Process) StackFrameAt(rsp, rip uint64) (*StackFrame, error) {
   248  	function, err := p.FindFunction(rip)
   249  	if err != nil {
   250  		return nil, err
   251  	}
   252  
   253  	buff := make([]byte, 8)
   254  	if err := p.debugapiClient.ReadMemory(rsp, buff); err != nil {
   255  		return nil, err
   256  	}
   257  	retAddr := binary.LittleEndian.Uint64(buff)
   258  
   259  	inputArgs, outputArgs, err := p.currentArgs(function.Parameters, rsp+8)
   260  	if err != nil {
   261  		return nil, err
   262  	}
   263  
   264  	return &StackFrame{
   265  		Function:        function,
   266  		ReturnAddress:   retAddr,
   267  		InputArguments:  inputArgs,
   268  		OutputArguments: outputArgs,
   269  	}, nil
   270  }
   271  
   272  // FindFunction finds the function to which pc specifies.
   273  func (p *Process) FindFunction(pc uint64) (*Function, error) {
   274  	function, err := p.Binary.FindFunction(pc)
   275  	if err == nil {
   276  		p.fillInOutputParameters(pc, function.Parameters)
   277  		p.fillInUnknownParameter(pc, function.Parameters)
   278  		return function, err
   279  	}
   280  
   281  	return p.findFunctionByModuleData(pc)
   282  }
   283  
   284  func (p *Process) fillInOutputParameters(pc uint64, params []Parameter) {
   285  	if !p.canFillInOutputParameters(pc, params) {
   286  		return
   287  	}
   288  
   289  	p.doFillInOutputParameters(pc, params)
   290  
   291  	sort.Slice(params, func(i, j int) bool { return params[i].Offset < params[j].Offset })
   292  	return
   293  }
   294  
   295  func (p *Process) canFillInOutputParameters(pc uint64, params []Parameter) bool {
   296  	for _, param := range params {
   297  		if param.IsOutput {
   298  			if param.Exist || !strings.HasPrefix(param.Name, "~r") {
   299  				return false
   300  			}
   301  		}
   302  	}
   303  
   304  	if !p.noPadding(pc, params) {
   305  		// It may be dangerous to fill in the parameter's location due to the alignment.
   306  		return false
   307  	}
   308  	return true
   309  }
   310  
   311  func (p *Process) doFillInOutputParameters(pc uint64, params []Parameter) {
   312  	var outputIndexes []int
   313  	var totalSize, totalOutputSize int
   314  	for i, param := range params {
   315  		if param.IsOutput {
   316  			outputIndexes = append(outputIndexes, i)
   317  			totalOutputSize += int(param.Typ.Size())
   318  		}
   319  		totalSize += int(param.Typ.Size())
   320  	}
   321  
   322  	sort.Slice(outputIndexes, func(i, j int) bool { return params[outputIndexes[i]].Name < params[outputIndexes[j]].Name })
   323  
   324  	currOffset := totalSize - totalOutputSize
   325  	for _, outputIndex := range outputIndexes {
   326  		params[outputIndex].Exist = true
   327  		params[outputIndex].Offset = currOffset
   328  		currOffset += int(params[outputIndex].Typ.Size())
   329  	}
   330  	return
   331  }
   332  
   333  func (p *Process) fillInUnknownParameter(pc uint64, params []Parameter) {
   334  	if !p.canFillInUnknownParameter(pc, params) {
   335  		return
   336  	}
   337  
   338  	unknownParamIndex := -1
   339  	for i, param := range params {
   340  		if !param.Exist {
   341  			unknownParamIndex = i
   342  			break
   343  		}
   344  	}
   345  
   346  	offset := p.calculateUnknownParameterOffset(params)
   347  	params[unknownParamIndex].Exist = true
   348  	params[unknownParamIndex].Offset = offset
   349  
   350  	sort.Slice(params, func(i, j int) bool { return params[i].Offset < params[j].Offset })
   351  	return
   352  }
   353  
   354  func (p *Process) canFillInUnknownParameter(pc uint64, params []Parameter) bool {
   355  	numNonExistParams := 0
   356  	for _, param := range params {
   357  		if !param.Exist {
   358  			numNonExistParams++
   359  		}
   360  	}
   361  	if numNonExistParams != 1 {
   362  		// 0: no need to fill in.
   363  		// 1>: we can not fill in the parameter's location in decisive way.
   364  		return false
   365  	}
   366  
   367  	if !p.noPadding(pc, params) {
   368  		// It may be dangerous to fill in the parameter's location due to the alignment.
   369  		return false
   370  	}
   371  	return true
   372  }
   373  
   374  func (p *Process) noPadding(pc uint64, params []Parameter) bool {
   375  	expectedArgsSize, err := p.findFunctionArgsSize(pc)
   376  	if err != nil {
   377  		log.Debugf("failed to find function args size: %v", err)
   378  		return false
   379  	}
   380  
   381  	actualArgsSize := 0
   382  	for _, param := range params {
   383  		actualArgsSize += int(param.Typ.Size())
   384  	}
   385  	return actualArgsSize == expectedArgsSize
   386  }
   387  
   388  func (p *Process) findFunctionArgsSize(pc uint64) (int, error) {
   389  	md := p.findModuleDataByPC(pc)
   390  	if md == nil {
   391  		return 0, fmt.Errorf("no moduledata found for pc %#x", pc)
   392  	}
   393  
   394  	funcTypeVal, _, err := p.findFuncType(md, pc)
   395  	if err != nil {
   396  		return 0, err
   397  	}
   398  
   399  	for _, field := range _funcType.Field {
   400  		if field.Name == "args" {
   401  			rawData := funcTypeVal[field.ByteOffset : field.ByteOffset+field.Type.Size()]
   402  			return int(binary.LittleEndian.Uint32(rawData)), nil
   403  		}
   404  	}
   405  	return 0, fmt.Errorf("failed to find args size at %#x", pc)
   406  }
   407  
   408  func (p *Process) calculateUnknownParameterOffset(params []Parameter) int {
   409  	argsSize := 0
   410  	for _, param := range params {
   411  		argsSize += int(param.Typ.Size())
   412  	}
   413  
   414  	params = append(params, Parameter{Offset: argsSize, Exist: true} /* sentinel */)
   415  	for i := 0; i < len(params)-1; i++ {
   416  		if !params[i].Exist {
   417  			continue
   418  		}
   419  		j := i + 1
   420  		if !params[j].Exist {
   421  			j++
   422  		}
   423  
   424  		nextOffset := params[i].Offset + int(params[i].Typ.Size())
   425  		if nextOffset != params[j].Offset {
   426  			return nextOffset
   427  		}
   428  	}
   429  	return 0
   430  }
   431  
   432  var findfuncbucketType = &dwarf.StructType{
   433  	CommonType: dwarf.CommonType{ByteSize: 20},
   434  	StructName: "runtime.findfuncbucket",
   435  	Field: []*dwarf.StructField{
   436  		&dwarf.StructField{
   437  			Name:       "idx",
   438  			Type:       &dwarf.UintType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 4}}},
   439  			ByteOffset: 0,
   440  		},
   441  		&dwarf.StructField{
   442  			Name: "subbuckets",
   443  			Type: &dwarf.ArrayType{
   444  				CommonType:    dwarf.CommonType{ByteSize: 16},
   445  				Type:          &dwarf.UintType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 1}}},
   446  				StrideBitSize: 0,
   447  				Count:         16,
   448  			},
   449  			ByteOffset: 4,
   450  		},
   451  	},
   452  }
   453  
   454  // Assume this dwarf.Type represents a subset of the _func type in the case DWARF is not available.
   455  var _funcType = &dwarf.StructType{
   456  	StructName: "runtime._func",
   457  	CommonType: dwarf.CommonType{ByteSize: 40},
   458  	Field: []*dwarf.StructField{
   459  		&dwarf.StructField{
   460  			Name:       "entry",
   461  			Type:       &dwarf.UintType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 8}}},
   462  			ByteOffset: 0,
   463  		},
   464  		&dwarf.StructField{
   465  			Name:       "nameoff",
   466  			Type:       &dwarf.IntType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 4}}},
   467  			ByteOffset: 8,
   468  		},
   469  		&dwarf.StructField{
   470  			Name:       "args",
   471  			Type:       &dwarf.IntType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 4}}},
   472  			ByteOffset: 12,
   473  		},
   474  	},
   475  }
   476  
   477  // findFunctionByModuleData has the same logic as the runtime.findfunc.
   478  func (p *Process) findFunctionByModuleData(pc uint64) (*Function, error) {
   479  	md := p.findModuleDataByPC(pc)
   480  	if md == nil {
   481  		return nil, fmt.Errorf("no moduledata found for pc %#x", pc)
   482  	}
   483  
   484  	funcTypeVal, endAddr, err := p.findFuncType(md, pc)
   485  	if err != nil {
   486  		return nil, err
   487  	}
   488  
   489  	var entry uint64
   490  	var nameoff int32
   491  	var args int32
   492  	for _, field := range _funcType.Field {
   493  		rawData := funcTypeVal[field.ByteOffset : field.ByteOffset+field.Type.Size()]
   494  		switch field.Name {
   495  		case "entry":
   496  			entry = binary.LittleEndian.Uint64(rawData)
   497  		case "nameoff":
   498  			nameoff = int32(binary.LittleEndian.Uint32(rawData))
   499  		case "args":
   500  			args = int32(binary.LittleEndian.Uint32(rawData))
   501  			if args < 0 {
   502  				// In Go's Assembler, the args size declared in the TEXT directive can be omitted.
   503  				// In that case, `args` here may be negative.
   504  				args = 0
   505  			}
   506  		}
   507  	}
   508  
   509  	funcName, err := p.resolveNameoff(md, int(nameoff))
   510  	if err != nil {
   511  		return nil, err
   512  	}
   513  
   514  	numParams := int(args) / 8 // the actual number of params is unknown. Assumes the each parameter has 1 ptr size.
   515  	params := make([]Parameter, 0, numParams)
   516  	for i := 0; i < numParams; i++ {
   517  		param := Parameter{
   518  			Typ:    &dwarf.PtrType{CommonType: dwarf.CommonType{ByteSize: 8}, Type: &dwarf.VoidType{}},
   519  			Offset: i * 8,
   520  			Exist:  true,
   521  		}
   522  		params = append(params, param)
   523  	}
   524  
   525  	return &Function{Name: funcName, StartAddr: entry, EndAddr: endAddr, Parameters: params}, nil
   526  }
   527  
   528  func (p *Process) findModuleDataByPC(pc uint64) *moduleData {
   529  	for _, moduleData := range p.moduleDataList {
   530  		if moduleData.minpc(p.debugapiClient) <= pc && pc < moduleData.maxpc(p.debugapiClient) {
   531  			return moduleData
   532  		}
   533  	}
   534  	return nil
   535  }
   536  
   537  const (
   538  	// must be same as the values defined in runtime package
   539  	minfunc      = 16            // minimum function size
   540  	pcbucketsize = 256 * minfunc // size of bucket in the pc->func lookup table
   541  )
   542  
   543  // findFuncType implements the core logic to find the func type using pc.
   544  // The logic is essentially same as the one used in the runtime.findfunc().
   545  // It involves 2 tables and linear search and has 4 steps (if the only 1 table is there, it must be huge!).
   546  // (1) Find the bucket. `findfunctab` points to the array of the buckets.
   547  //     The index is pc / (1 bucket region, typically 4096 bytes), so it uses the first 20 bits of the pc
   548  //     (assuming the pc can be represented in 32 bits).
   549  // (2) Find the subbucket. Each bucket contains the 16 subbuckets.
   550  //     The index is pc % 1 bucket region / (1 subbucket region, typically 256), so it uses the
   551  //     next 4 bits of the pc.
   552  // (3) Find the functab. `functab` points to the array of the functabs.
   553  //     We can find out the rough index using the index the bucket holds + sub-index the subbucket holds.
   554  //     But it may not be correct, because 1 subbucket region is typically 256 and may contain multiple functions.
   555  //     So do the linear search to find the correct index.
   556  // (4) Finally, get the func type using the funcoff field in functab, the pointer to the func type embedded in the pcln table.
   557  //     Note that the pcln table contains not only func type, but other data like function name.
   558  func (p *Process) findFuncType(md *moduleData, pc uint64) ([]byte, uint64, error) {
   559  	ftabIdx, err := p.findFtabIndex(md, pc)
   560  	if err != nil {
   561  		return nil, 0, err
   562  	}
   563  
   564  	ftabIdx = p.adjustFtabIndex(md, pc, ftabIdx)
   565  	endAddr := p.findEndAddr(md, ftabIdx)
   566  	_, funcoff := md.functab(p.debugapiClient, ftabIdx)
   567  
   568  	funcTypePtr := md.pclntable(p.debugapiClient, int(funcoff))
   569  	buff := make([]byte, _funcType.Size())
   570  	if err := p.debugapiClient.ReadMemory(funcTypePtr, buff); err != nil {
   571  		return nil, 0, err
   572  	}
   573  
   574  	return buff, endAddr, nil
   575  }
   576  
   577  func (p *Process) findFtabIndex(md *moduleData, pc uint64) (int, error) {
   578  	var idxField, subbucketsField *dwarf.StructField
   579  	for _, field := range findfuncbucketType.Field {
   580  		switch field.Name {
   581  		case "idx":
   582  			idxField = field
   583  		case "subbuckets":
   584  			subbucketsField = field
   585  		}
   586  	}
   587  
   588  	x := pc - md.minpc(p.debugapiClient)
   589  	bucketIndex := x / pcbucketsize
   590  	subbucketIndex := int(x % pcbucketsize / (pcbucketsize / uint64(subbucketsField.Type.Size())))
   591  
   592  	ptrToFindFuncBucket := md.findfunctab(p.debugapiClient) + bucketIndex*uint64(findfuncbucketType.Size())
   593  	buff := make([]byte, findfuncbucketType.Size())
   594  	if err := p.debugapiClient.ReadMemory(ptrToFindFuncBucket, buff); err != nil {
   595  		return 0, err
   596  	}
   597  
   598  	ftabIdx := int(binary.LittleEndian.Uint32(buff[idxField.ByteOffset : idxField.ByteOffset+idxField.Type.Size()]))
   599  	ftabIdx += int(buff[int(subbucketsField.ByteOffset)+subbucketIndex])
   600  	return ftabIdx, nil
   601  }
   602  
   603  func (p *Process) adjustFtabIndex(md *moduleData, pc uint64, ftabIdx int) int {
   604  	ftabLen := md.ftabLen(p.debugapiClient)
   605  	if ftabIdx >= ftabLen {
   606  		ftabIdx = ftabLen - 1
   607  	}
   608  
   609  	entry, _ := md.functab(p.debugapiClient, ftabIdx)
   610  	if pc < entry {
   611  		for entry > pc && ftabIdx > 0 {
   612  			ftabIdx--
   613  			entry, _ = md.functab(p.debugapiClient, ftabIdx)
   614  		}
   615  		if ftabIdx == 0 {
   616  			panic("bad findfunctab entry idx")
   617  		}
   618  	} else {
   619  		// linear search to find func with pc >= entry.
   620  		nextEntry, _ := md.functab(p.debugapiClient, ftabIdx+1)
   621  		for nextEntry <= pc {
   622  			ftabIdx++
   623  			nextEntry, _ = md.functab(p.debugapiClient, ftabIdx+1)
   624  		}
   625  	}
   626  	return ftabIdx
   627  }
   628  
   629  func (p *Process) findEndAddr(md *moduleData, ftabIdx int) uint64 {
   630  	ftabLen := md.ftabLen(p.debugapiClient)
   631  	if ftabIdx+1 >= ftabLen {
   632  		return 0
   633  	}
   634  	entry, _ := md.functab(p.debugapiClient, ftabIdx+1)
   635  	return entry
   636  }
   637  
   638  func (p *Process) resolveNameoff(md *moduleData, nameoff int) (string, error) {
   639  	ptrToFuncname := md.pclntable(p.debugapiClient, nameoff)
   640  	var rawFuncname []byte
   641  	for {
   642  		buff := make([]byte, 16)
   643  		if err := p.debugapiClient.ReadMemory(ptrToFuncname, buff); err != nil {
   644  			return "", err
   645  		}
   646  
   647  		for i := 0; i < len(buff); i++ {
   648  			if buff[i] == 0 {
   649  				return string(append(rawFuncname, buff[0:i]...)), nil
   650  			}
   651  		}
   652  
   653  		rawFuncname = append(rawFuncname, buff...)
   654  		ptrToFuncname += uint64(len(buff))
   655  	}
   656  }
   657  
   658  func (p *Process) currentArgs(params []Parameter, addrBeginningOfArgs uint64) (inputArgs []Argument, outputArgs []Argument, err error) {
   659  	for _, param := range params {
   660  		param := param // without this, all the closures point to the last param.
   661  		parseValue := func(depth int) value {
   662  			if !param.Exist {
   663  				return nil
   664  			}
   665  
   666  			size := param.Typ.Size()
   667  			buff := make([]byte, size)
   668  			if err = p.debugapiClient.ReadMemory(addrBeginningOfArgs+uint64(param.Offset), buff); err != nil {
   669  				log.Debugf("failed to read the '%s' value: %v", param.Name, err)
   670  				return nil
   671  			}
   672  			return p.valueParser.parseValue(param.Typ, buff, depth)
   673  		}
   674  
   675  		arg := Argument{Name: param.Name, Typ: param.Typ, parseValue: parseValue}
   676  		if param.IsOutput {
   677  			outputArgs = append(outputArgs, arg)
   678  		} else {
   679  			inputArgs = append(inputArgs, arg)
   680  		}
   681  	}
   682  	return
   683  }
   684  
   685  // ReadInstructions reads the instructions of the specified function from memory.
   686  func (p *Process) ReadInstructions(f *Function) ([]x86asm.Inst, error) {
   687  	if f.EndAddr == 0 {
   688  		return nil, fmt.Errorf("the end address of the function %s is unknown", f.Name)
   689  	}
   690  
   691  	buff := make([]byte, f.EndAddr-f.StartAddr)
   692  	if err := p.debugapiClient.ReadMemory(f.StartAddr, buff); err != nil {
   693  		return nil, err
   694  	}
   695  
   696  	for addr, bp := range p.breakpoints {
   697  		if f.StartAddr <= addr && addr < f.EndAddr {
   698  			copy(buff[addr-f.StartAddr:], bp.orgInsts)
   699  		}
   700  	}
   701  
   702  	var pos int
   703  	var insts []x86asm.Inst
   704  	for pos < len(buff) {
   705  		inst, err := x86asm.Decode(buff[pos:len(buff)], 64)
   706  		if err != nil {
   707  			log.Debugf("decode error at %#x: %v", pos, err)
   708  		} else {
   709  			insts = append(insts, inst)
   710  		}
   711  
   712  		pos += inst.Len
   713  	}
   714  
   715  	return insts, nil
   716  }
   717  
   718  // GoRoutineInfo describes the various info of the go routine like pc.
   719  type GoRoutineInfo struct {
   720  	ID                int64
   721  	UsedStackSize     uint64
   722  	CurrentPC         uint64
   723  	CurrentStackAddr  uint64
   724  	NextDeferFuncAddr uint64
   725  	Panicking         bool
   726  	PanicHandler      *PanicHandler
   727  }
   728  
   729  // PanicHandler holds the function info which (will) handles panic.
   730  type PanicHandler struct {
   731  	// UsedStackSizeAtDefer and PCAtDefer are the function info which register this handler by 'defer'.
   732  	UsedStackSizeAtDefer uint64
   733  	PCAtDefer            uint64
   734  }
   735  
   736  // CurrentGoRoutineInfo returns the go routine info associated with the go routine which hits the breakpoint.
   737  func (p *Process) CurrentGoRoutineInfo(threadID int) (GoRoutineInfo, error) {
   738  	gAddr, err := p.debugapiClient.ReadTLS(threadID, p.offsetToG())
   739  	if err != nil {
   740  		unspecifiedError, ok := err.(debugapi.UnspecifiedThreadError)
   741  		if !ok {
   742  			return GoRoutineInfo{}, err
   743  		}
   744  
   745  		if err := p.singleStepUnspecifiedThreads(threadID, unspecifiedError); err != nil {
   746  			return GoRoutineInfo{}, err
   747  		}
   748  		return p.CurrentGoRoutineInfo(threadID)
   749  	}
   750  
   751  	_, idRawVal, err := p.findFieldInStruct(gAddr, p.Binary.runtimeGType(), "goid")
   752  	if err != nil {
   753  		return GoRoutineInfo{}, err
   754  	}
   755  	id := int64(binary.LittleEndian.Uint64(idRawVal))
   756  
   757  	stackType, stackRawVal, err := p.findFieldInStruct(gAddr, p.Binary.runtimeGType(), "stack")
   758  	if err != nil {
   759  		return GoRoutineInfo{}, err
   760  	}
   761  	stackVal := p.valueParser.parseValue(stackType, stackRawVal, 1)
   762  	stackHi := stackVal.(structValue).fields["hi"].(uint64Value).val
   763  
   764  	regs, err := p.debugapiClient.ReadRegisters(threadID)
   765  	if err != nil {
   766  		return GoRoutineInfo{}, err
   767  	}
   768  	usedStackSize := stackHi - regs.Rsp
   769  
   770  	_, panicRawVal, err := p.findFieldInStruct(gAddr, p.Binary.runtimeGType(), "_panic")
   771  	if err != nil {
   772  		return GoRoutineInfo{}, err
   773  	}
   774  	panicAddr := binary.LittleEndian.Uint64(panicRawVal)
   775  	panicking := panicAddr != 0
   776  
   777  	panicHandler, err := p.findPanicHandler(gAddr, panicAddr, stackHi)
   778  	if err != nil {
   779  		return GoRoutineInfo{}, err
   780  	}
   781  
   782  	nextDeferFuncAddr, err := p.findNextDeferFuncAddr(gAddr)
   783  	if err != nil {
   784  		return GoRoutineInfo{}, err
   785  	}
   786  
   787  	return GoRoutineInfo{ID: id, UsedStackSize: usedStackSize, CurrentPC: regs.Rip, CurrentStackAddr: regs.Rsp, NextDeferFuncAddr: nextDeferFuncAddr, Panicking: panicking, PanicHandler: panicHandler}, nil
   788  }
   789  
   790  func (p *Process) singleStepUnspecifiedThreads(threadID int, err debugapi.UnspecifiedThreadError) error {
   791  	for _, unspecifiedThread := range err.ThreadIDs {
   792  		if unspecifiedThread == threadID {
   793  			continue
   794  		}
   795  
   796  		regs, err := p.debugapiClient.ReadRegisters(unspecifiedThread)
   797  		if err != nil {
   798  			return err
   799  		}
   800  		if err := p.SingleStep(unspecifiedThread, regs.Rip-1); err != nil {
   801  			return err
   802  		}
   803  	}
   804  	return nil
   805  }
   806  
   807  func (p *Process) findNextDeferFuncAddr(gAddr uint64) (uint64, error) {
   808  	ptrToDeferType, rawVal, err := p.findFieldInStruct(gAddr, p.Binary.runtimeGType(), "_defer")
   809  	if err != nil {
   810  		return 0, err
   811  	}
   812  	deferAddr := binary.LittleEndian.Uint64(rawVal)
   813  	if deferAddr == 0x0 {
   814  		return 0x0, nil
   815  	}
   816  
   817  	deferType := ptrToDeferType.(*dwarf.PtrType).Type
   818  	_, rawVal, err = p.findFieldInStruct(deferAddr, deferType, "fn")
   819  	if err != nil {
   820  		return 0, err
   821  	}
   822  	ptrToFuncAddr := binary.LittleEndian.Uint64(rawVal)
   823  
   824  	buff := make([]byte, 8)
   825  	if err := p.debugapiClient.ReadMemory(ptrToFuncAddr, buff); err != nil {
   826  		return 0, fmt.Errorf("failed to read memory at %#x: %v", ptrToFuncAddr, err)
   827  	}
   828  	return binary.LittleEndian.Uint64(buff), nil
   829  }
   830  
   831  func (p *Process) findFieldInStruct(structAddr uint64, structType dwarf.Type, fieldName string) (dwarf.Type, []byte, error) {
   832  	for {
   833  		typedefType, ok := structType.(*dwarf.TypedefType)
   834  		if !ok {
   835  			break
   836  		}
   837  		structType = typedefType.Type
   838  	}
   839  
   840  	for _, field := range structType.(*dwarf.StructType).Field {
   841  		if field.Name != fieldName {
   842  			continue
   843  		}
   844  
   845  		buff := make([]byte, field.Type.Size())
   846  		addr := structAddr + uint64(field.ByteOffset)
   847  		if err := p.debugapiClient.ReadMemory(addr, buff); err != nil {
   848  			return nil, nil, fmt.Errorf("failed to read memory at %#x: %v", addr, err)
   849  		}
   850  		return field.Type, buff, nil
   851  	}
   852  	return nil, nil, fmt.Errorf("field %s not found", fieldName)
   853  }
   854  
   855  func (p *Process) findPanicHandler(gAddr, panicAddr, stackHi uint64) (*PanicHandler, error) {
   856  	ptrToDeferType, rawVal, err := p.findFieldInStruct(gAddr, p.Binary.runtimeGType(), "_defer")
   857  	if err != nil {
   858  		return nil, err
   859  	}
   860  	deferAddr := binary.LittleEndian.Uint64(rawVal)
   861  	deferType := ptrToDeferType.(*dwarf.PtrType).Type
   862  
   863  	for deferAddr != 0 {
   864  		_, rawVal, err := p.findFieldInStruct(deferAddr, deferType, "_panic")
   865  		if err != nil {
   866  			return nil, err
   867  		}
   868  		panicInDefer := binary.LittleEndian.Uint64(rawVal)
   869  		if panicInDefer == panicAddr {
   870  			break
   871  		}
   872  
   873  		_, rawVal, err = p.findFieldInStruct(deferAddr, deferType, "link")
   874  		if err != nil {
   875  			return nil, err
   876  		}
   877  		deferAddr = binary.LittleEndian.Uint64(rawVal)
   878  	}
   879  
   880  	if deferAddr == 0 {
   881  		return nil, nil
   882  	}
   883  
   884  	_, rawVal, err = p.findFieldInStruct(deferAddr, deferType, "sp")
   885  	if err != nil {
   886  		return nil, err
   887  	}
   888  	stackAddress := binary.LittleEndian.Uint64(rawVal)
   889  	usedStackSizeAtDefer := stackHi - stackAddress
   890  
   891  	_, rawVal, err = p.findFieldInStruct(deferAddr, deferType, "pc")
   892  	if err != nil {
   893  		return nil, err
   894  	}
   895  	pc := binary.LittleEndian.Uint64(rawVal)
   896  
   897  	return &PanicHandler{UsedStackSizeAtDefer: usedStackSizeAtDefer, PCAtDefer: pc}, nil
   898  }
   899  
   900  // ThreadInfo describes the various info of thread.
   901  type ThreadInfo struct {
   902  	ID               int
   903  	CurrentPC        uint64
   904  	CurrentStackAddr uint64
   905  }
   906  
   907  // CurrentThreadInfo returns the thread info of the specified thread ID.
   908  func (p *Process) CurrentThreadInfo(threadID int) (ThreadInfo, error) {
   909  	regs, err := p.debugapiClient.ReadRegisters(threadID)
   910  	if err != nil {
   911  		return ThreadInfo{}, err
   912  	}
   913  	return ThreadInfo{ID: threadID, CurrentPC: regs.Rip, CurrentStackAddr: regs.Rsp}, nil
   914  }
   915  
   916  // Argument represents the value passed to the function.
   917  type Argument struct {
   918  	Name string
   919  	Typ  dwarf.Type
   920  	// parseValue lazily parses the value. The parsing every time is not only wasting resource, but the value may not be initialized yet.
   921  	parseValue func(int) value
   922  }
   923  
   924  // ParseValue parses the arg value and returns string representation.
   925  // The `depth` option specifies to the depth of the parsing.
   926  func (arg Argument) ParseValue(depth int) string {
   927  	val := arg.parseValue(depth)
   928  	var valStr string
   929  	if val == nil {
   930  		valStr = "-"
   931  	} else {
   932  		valStr = val.String()
   933  	}
   934  
   935  	if arg.Name == "" {
   936  		return valStr
   937  	}
   938  	return fmt.Sprintf("%s = %s", arg.Name, valStr)
   939  }