github.com/Rookout/GoSDK@v0.1.48/pkg/services/collection/variable/variable_locator.go (about)

     1  // The MIT License (MIT)
     2  
     3  // Copyright (c) 2014 Derek Parker
     4  
     5  // Permission is hereby granted, free of charge, to any person obtaining a copy of
     6  // this software and associated documentation files (the "Software"), to deal in
     7  // the Software without restriction, including without limitation the rights to
     8  // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
     9  // the Software, and to permit persons to whom the Software is furnished to do so,
    10  // subject to the following conditions:
    11  
    12  // The above copyright notice and this permission notice shall be included in all
    13  // copies or substantial portions of the Software.
    14  
    15  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    16  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
    17  // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
    18  // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
    19  // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
    20  // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    21  
    22  package variable
    23  
    24  import (
    25  	"debug/dwarf"
    26  	"errors"
    27  	"strings"
    28  
    29  	"github.com/Rookout/GoSDK/pkg/config"
    30  	"github.com/Rookout/GoSDK/pkg/logger"
    31  	"github.com/Rookout/GoSDK/pkg/rookoutErrors"
    32  	"github.com/Rookout/GoSDK/pkg/services/assembler"
    33  	"github.com/Rookout/GoSDK/pkg/services/collection/memory"
    34  	"github.com/Rookout/GoSDK/pkg/services/collection/registers"
    35  	"github.com/Rookout/GoSDK/pkg/services/instrumentation/binary_info"
    36  	"github.com/Rookout/GoSDK/pkg/services/instrumentation/dwarf/frame"
    37  	"github.com/Rookout/GoSDK/pkg/services/instrumentation/dwarf/godwarf"
    38  	"github.com/Rookout/GoSDK/pkg/services/instrumentation/dwarf/op"
    39  )
    40  
    41  func GetVariableLocators(pc uint64, line int, function *binary_info.Function, binaryInfo *binary_info.BinaryInfo) ([]*VariableLocator, error) {
    42  	root, err := godwarf.LoadTree(function.Offset, binaryInfo.Dwarf, binaryInfo.Images[0].StaticBase)
    43  	if err != nil {
    44  		return nil, err
    45  	}
    46  
    47  	variableLocators := getVariableLocators(root, 0, pc, line, function, binaryInfo)
    48  	return variableLocators, nil
    49  }
    50  
    51  func getVariableLocators(root *godwarf.Tree, depth int, pc uint64, line int, function *binary_info.Function, binaryInfo *binary_info.BinaryInfo) []*VariableLocator {
    52  	switch root.Tag {
    53  	case dwarf.TagInlinedSubroutine, dwarf.TagLexDwarfBlock, dwarf.TagSubprogram:
    54  		var variables []*VariableLocator
    55  		if root.ContainsPC(pc) {
    56  			for _, child := range root.Children {
    57  				variables = append(variables, getVariableLocators(child, depth+1, pc, line, function, binaryInfo)...)
    58  			}
    59  		}
    60  		return variables
    61  	case dwarf.TagFormalParameter, dwarf.TagVariable:
    62  		if name := root.Val(dwarf.AttrName).(string); strings.HasPrefix(name, "~") {
    63  			return nil
    64  		}
    65  		if root.Tag != dwarf.TagFormalParameter {
    66  			
    67  			
    68  			
    69  			declLine, ok := root.Val(dwarf.AttrDeclLine).(int64)
    70  			if ok && line < int(declLine)+1 {
    71  				return nil
    72  			}
    73  		}
    74  		newVar, err := NewVariableLocator(root, function, pc, binaryInfo)
    75  		if err != nil {
    76  			return nil
    77  		}
    78  		return []*VariableLocator{newVar}
    79  	}
    80  
    81  	return nil
    82  }
    83  
    84  type VariableLocator struct {
    85  	VariableName string
    86  	variableType godwarf.Type
    87  	locator      *op.DwarfLocator
    88  	binaryInfo   *binary_info.BinaryInfo
    89  	function     *binary_info.Function
    90  	pc           uint64
    91  }
    92  
    93  func NewVariableLocator(entry *godwarf.Tree, function *binary_info.Function, pc uint64, binaryInfo *binary_info.BinaryInfo) (*VariableLocator, error) {
    94  	name, varType, err := binaryInfo.ReadVariableEntry(entry)
    95  	if err != nil {
    96  		return nil, err
    97  	}
    98  
    99  	instr, _, err := binaryInfo.LocationExpr(entry.Entry, dwarf.AttrLocation, pc)
   100  	if err != nil {
   101  		return nil, err
   102  	}
   103  
   104  	locator, err := op.NewDwarfLocator(instr, binaryInfo.PointerSize)
   105  	if err != nil {
   106  		return nil, err
   107  	}
   108  
   109  	v := &VariableLocator{VariableName: name, variableType: varType, locator: locator, binaryInfo: binaryInfo, function: function, pc: pc}
   110  	return v, nil
   111  }
   112  
   113  func (v *VariableLocator) Locate(regs registers.Registers, dictAddr uint64, variablesCache *VariablesCache, objectDumpConfig config.ObjectDumpConfig) *Variable {
   114  	var mem memory.MemoryReader = &memory.ProcMemory{}
   115  	var addr int64
   116  	var pieces []op.Piece
   117  
   118  	dwarfRegs, err := v.advanceRegs(regs)
   119  	if err != nil {
   120  		logger.Logger().WithError(err).Warningf("Failed to advance regs")
   121  	} else {
   122  		addr, pieces, err = v.locator.Locate(&dwarfRegs)
   123  		if err != nil {
   124  			logger.Logger().WithError(err).Warningf("Failed to locate %s", v.VariableName)
   125  		}
   126  		if pieces != nil {
   127  			addr = memory.FakeAddress
   128  			var cmem *memory.CompositeMemory
   129  			cmem, err = memory.NewCompositeMemory(mem, dwarfRegs, pieces, v.binaryInfo.PointerSize)
   130  			if cmem != nil {
   131  				mem = cmem
   132  			}
   133  		}
   134  	}
   135  
   136  	newVar := NewVariable(v.VariableName, uint64(addr), v.variableType, mem, v.binaryInfo, objectDumpConfig, dictAddr, variablesCache)
   137  	if pieces != nil {
   138  		newVar.Flags |= VariableFakeAddress
   139  	}
   140  	if err != nil {
   141  		newVar.Unreadable = err
   142  	}
   143  	return newVar
   144  }
   145  
   146  func (v *VariableLocator) GetRegsUsed() ([]assembler.Reg, rookoutErrors.RookoutError) {
   147  	tracker := newRegTracker()
   148  
   149  	_, pieces, err := v.locator.Locate(tracker)
   150  	if err != nil {
   151  		return nil, rookoutErrors.NewFailedToLocate(v.VariableName, err)
   152  	}
   153  
   154  	return tracker.ResolveRegsUsed(v.variableType, pieces)
   155  }
   156  
   157  func (v *VariableLocator) advanceRegs(regs registers.Registers) (op.DwarfRegisters, error) {
   158  	dwarfRegs := binary_info.RegistersToDwarfRegisters(0, regs)
   159  	fde, err := v.binaryInfo.FrameEntries.FDEForPC(v.pc) 
   160  	var framectx *frame.FrameContext
   161  	if _, nofde := err.(*frame.ErrNoFDEForPC); nofde {
   162  		framectx = binary_info.FixFrameUnwindContext(nil, v.pc, v.binaryInfo)
   163  	} else {
   164  		framectx = binary_info.FixFrameUnwindContext(fde.EstablishFrame(v.pc), v.pc, v.binaryInfo)
   165  	}
   166  
   167  	cfareg, err := executeFrameRegRule(0, framectx.CFA, 0, dwarfRegs, v.binaryInfo)
   168  	if err != nil {
   169  		return op.DwarfRegisters{}, err
   170  	}
   171  	if cfareg == nil {
   172  		return op.DwarfRegisters{}, errors.New("no cfareg")
   173  	}
   174  
   175  	callimage := v.binaryInfo.PCToImage(v.pc)
   176  
   177  	dwarfRegs.SetStaticBase(callimage.StaticBase)
   178  	dwarfRegs.SetCFA(int64(cfareg.Uint64Val))
   179  	dwarfRegs.SetFrameBase(v.frameBase(dwarfRegs))
   180  
   181  	
   182  	
   183  	
   184  	
   185  	
   186  	
   187  	
   188  	dwarfRegs.AddReg(dwarfRegs.SPRegNum, cfareg)
   189  
   190  	for i, regRule := range framectx.Regs {
   191  		reg, err := executeFrameRegRule(i, regRule, dwarfRegs.CFA(), dwarfRegs, v.binaryInfo)
   192  		dwarfRegs.AddReg(i, reg)
   193  		if i == framectx.RetAddrReg {
   194  			if reg == nil {
   195  				if err == nil {
   196  					return op.DwarfRegisters{}, err
   197  				}
   198  			}
   199  		}
   200  	}
   201  	return dwarfRegs, nil
   202  }
   203  
   204  func executeFrameRegRule(regnum uint64, rule frame.DWRule, cfa int64, dwarfRegs op.DwarfRegisters, binaryInfo *binary_info.BinaryInfo) (*op.DwarfRegister, error) {
   205  	switch rule.Rule {
   206  	default:
   207  		fallthrough
   208  	case frame.RuleUndefined:
   209  		return nil, nil
   210  	case frame.RuleSameVal:
   211  		if dwarfRegs.Reg(regnum) == nil {
   212  			return nil, nil
   213  		}
   214  		reg := *dwarfRegs.Reg(regnum)
   215  		return &reg, nil
   216  	case frame.RuleOffset:
   217  		return readRegisterAt(regnum, uint64(cfa+rule.Offset))
   218  	case frame.RuleValOffset:
   219  		return op.DwarfRegisterFromUint64(uint64(cfa + rule.Offset)), nil
   220  	case frame.RuleRegister:
   221  		return dwarfRegs.Reg(rule.Reg), nil
   222  	case frame.RuleExpression:
   223  		v, _, err := op.ExecuteStackProgram(&dwarfRegs, rule.Expression, binaryInfo.PointerSize)
   224  		if err != nil {
   225  			return nil, err
   226  		}
   227  		return readRegisterAt(regnum, uint64(v))
   228  	case frame.RuleValExpression:
   229  		v, _, err := op.ExecuteStackProgram(&dwarfRegs, rule.Expression, binaryInfo.PointerSize)
   230  		if err != nil {
   231  			return nil, err
   232  		}
   233  		return op.DwarfRegisterFromUint64(uint64(v)), nil
   234  	case frame.RuleArchitectural:
   235  		return nil, errors.New("architectural frame rules are unsupported")
   236  	case frame.RuleCFA:
   237  		if dwarfRegs.Reg(rule.Reg) == nil {
   238  			return nil, nil
   239  		}
   240  		return op.DwarfRegisterFromUint64(uint64(int64(dwarfRegs.Uint64Val(rule.Reg)) + rule.Offset)), nil
   241  	case frame.RuleFramePointer:
   242  		curReg := dwarfRegs.Reg(rule.Reg)
   243  		if curReg == nil {
   244  			return nil, nil
   245  		}
   246  		if curReg.Uint64Val <= uint64(cfa) {
   247  			return readRegisterAt(regnum, curReg.Uint64Val)
   248  		}
   249  		newReg := *curReg
   250  		return &newReg, nil
   251  	}
   252  }
   253  
   254  func readRegisterAt(regnum uint64, addr uint64) (*op.DwarfRegister, error) {
   255  	buf := make([]byte, binary_info.RegSize(regnum))
   256  	memReader := memory.ProcMemory{}
   257  	_, err := memReader.ReadMemory(buf, addr)
   258  	if err != nil {
   259  		return nil, err
   260  	}
   261  	return op.DwarfRegisterFromBytes(buf), nil
   262  }
   263  
   264  func (v *VariableLocator) frameBase(regs op.DwarfRegisters) int64 {
   265  	dwarfTree, err := v.binaryInfo.Images[0].GetDwarfTree(v.function.Offset)
   266  	if err != nil {
   267  		return 0
   268  	}
   269  	fb, _, _, _ := v.binaryInfo.Location(dwarfTree.Entry, dwarf.AttrFrameBase, v.pc, regs)
   270  	return fb
   271  }