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 ®, 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 }