github.com/Rookout/GoSDK@v0.1.48/pkg/processor/namespaces/variable_namespace.go (about) 1 package namespaces 2 3 import ( 4 "fmt" 5 "go/constant" 6 "reflect" 7 "strconv" 8 "strings" 9 "time" 10 "unsafe" 11 12 "github.com/Rookout/GoSDK/pkg/config" 13 "github.com/Rookout/GoSDK/pkg/rookoutErrors" 14 "github.com/Rookout/GoSDK/pkg/services/collection" 15 "github.com/Rookout/GoSDK/pkg/services/collection/variable" 16 "github.com/Rookout/GoSDK/pkg/services/instrumentation/dwarf/godwarf" 17 ) 18 19 20 21 type ReferenceType struct{} 22 23 var ReferenceTypeInstance = &ReferenceType{} 24 25 26 27 type StructType struct{} 28 29 var StructTypeInstance = &StructType{} 30 31 type VariableNamespace struct { 32 Obj *variable.Variable 33 ObjectDumpConf config.ObjectDumpConfig 34 name string 35 CollectionService *collection.CollectionService 36 currentDepth int 37 } 38 39 func NewVariableNamespace(fullName string, o *variable.Variable, collectionService *collection.CollectionService) *VariableNamespace { 40 g := &VariableNamespace{ 41 Obj: o, 42 ObjectDumpConf: o.ObjectDumpConfig, 43 CollectionService: collectionService, 44 name: fullName, 45 currentDepth: 0, 46 } 47 48 return g 49 } 50 51 func (v *VariableNamespace) spawn(name string, obj *variable.Variable, checkMaxDepth bool) (*VariableNamespace, bool) { 52 if checkMaxDepth && v.currentDepth >= v.ObjectDumpConf.MaxDepth { 53 return nil, true 54 } 55 56 return &VariableNamespace{name: name, Obj: obj, ObjectDumpConf: obj.ObjectDumpConfig, CollectionService: v.CollectionService, currentDepth: v.currentDepth + 1}, false 57 } 58 59 func (v *VariableNamespace) GetSize(_ string, _ interface{}) Namespace { 60 switch v.Obj.Kind { 61 case reflect.Array, reflect.Map, reflect.Slice, reflect.String: 62 return NewGoObjectNamespace(v.Obj.Len) 63 } 64 return nil 65 } 66 67 func (v *VariableNamespace) CallMethod(name string, args string) (Namespace, rookoutErrors.RookoutError) { 68 switch name { 69 case "type": 70 return NewGoObjectNamespace(PrettyTypeName(v.Obj.DwarfType)), nil 71 case "size": 72 size := v.GetSize(name, args) 73 if size == nil { 74 return nil, rookoutErrors.NewObjectHasNoSizeException(v.GetObject()) 75 } 76 return size, nil 77 case "depth": 78 maxDepth, err := strconv.Atoi(args) 79 if err != nil { 80 return nil, rookoutErrors.NewRookInvalidMethodArguments("depth()", args) 81 } 82 v.ObjectDumpConf.MaxDepth = maxDepth 83 return v, nil 84 case "width": 85 maxWidth, err := strconv.Atoi(args) 86 if err != nil { 87 return nil, rookoutErrors.NewRookInvalidMethodArguments("width()", args) 88 } 89 v.ObjectDumpConf.MaxWidth = maxWidth 90 return v, nil 91 case "collection_dump": 92 maxCollectionDepth, err := strconv.Atoi(args) 93 if err != nil { 94 return nil, rookoutErrors.NewRookInvalidMethodArguments("collection_dump()", args) 95 } 96 v.ObjectDumpConf.MaxCollectionDepth = maxCollectionDepth 97 return v, nil 98 case "string": 99 maxString, err := strconv.Atoi(args) 100 if err != nil { 101 return nil, rookoutErrors.NewRookInvalidMethodArguments("string()", args) 102 } 103 v.ObjectDumpConf.MaxString = maxString 104 return v, nil 105 case "limit": 106 if objectDumpConfig, ok := config.GetObjectDumpConfig(strings.ToLower(args)); ok { 107 v.ObjectDumpConf = objectDumpConfig 108 return v, nil 109 } 110 return nil, rookoutErrors.NewRookInvalidMethodArguments("limit()", args) 111 112 default: 113 return nil, rookoutErrors.NewRookMethodNotFound(name) 114 } 115 } 116 117 func (v *VariableNamespace) ReadAttribute(name string) (Namespace, rookoutErrors.RookoutError) { 118 value := v.Obj 119 120 121 if value.Kind == reflect.Interface { 122 value = value.Children[0] 123 } 124 125 126 if value.Kind == reflect.Ptr && len(value.Children) == 1 && value.Children[0].Kind == reflect.Struct { 127 value = value.Children[0] 128 } 129 130 for _, child := range value.Children { 131 if name == child.Name { 132 attr, _ := v.spawn(v.name+"."+name, child, false) 133 return attr, nil 134 } 135 } 136 137 return nil, rookoutErrors.NewRookAttributeNotFoundException(name) 138 } 139 140 func (v *VariableNamespace) WriteAttribute(_ string, _ Namespace) rookoutErrors.RookoutError { 141 return rookoutErrors.NewNotImplemented() 142 } 143 144 func (v *VariableNamespace) readKeyFromArray(key int) (Namespace, rookoutErrors.RookoutError) { 145 name := v.name + "[" + strconv.Itoa(key) + "]" 146 147 if int(v.Obj.Len) <= key { 148 return nil, rookoutErrors.NewAgentKeyNotFoundException(v.name, key, nil) 149 } 150 151 var child *variable.Variable 152 if len(v.Obj.Children) > key { 153 child = v.Obj.Children[key] 154 } else { 155 156 var err error 157 child, err = v.Obj.LoadArrayValue(key) 158 if err == nil { 159 return nil, rookoutErrors.NewAgentKeyNotFoundException(v.name, key, err) 160 } 161 } 162 163 item, _ := v.spawn(name, child, false) 164 return item, nil 165 } 166 167 func (v *VariableNamespace) readKeyFromMap(key string) (Namespace, rookoutErrors.RookoutError) { 168 name := v.name + "[\"" + key + "\"]" 169 170 171 for i := 0; i < len(v.Obj.Children); i += 2 { 172 keyVar := v.Obj.Children[i] 173 if keyVar.Kind == reflect.Interface || keyVar.Kind == reflect.Ptr { 174 keyVar.ObjectDumpConfig.MaxCollectionDepth = 1 175 keyVar.LoadValue() 176 keyVar = keyVar.Children[0] 177 } 178 if keyVar.Kind != reflect.String { 179 continue 180 } 181 182 keyVar.LoadValue() 183 keyName := constant.StringVal(keyVar.Value) 184 if key == keyName { 185 v.Obj.Children[i+1].LoadValue() 186 item, _ := v.spawn(name, v.Obj.Children[i+1], false) 187 return item, nil 188 } 189 } 190 191 if int(v.Obj.Len) > len(v.Obj.Children)/2 { 192 193 value, err := v.Obj.LoadMapValue(key) 194 if err != nil { 195 return nil, rookoutErrors.NewAgentKeyNotFoundException(v.name, key, err) 196 } 197 item, _ := v.spawn(name, value, false) 198 return item, nil 199 } 200 201 return nil, rookoutErrors.NewAgentKeyNotFoundException(v.name, key, nil) 202 } 203 204 func (v *VariableNamespace) readKeyFromStruct(key string) (Namespace, rookoutErrors.RookoutError) { 205 name := v.name + "." + key 206 for _, child := range v.Obj.Children { 207 if key == child.Name { 208 item, _ := v.spawn(name, child, false) 209 return item, nil 210 } 211 } 212 213 if int(v.Obj.Len) > len(v.Obj.Children) { 214 215 obj, err := v.Obj.LoadStructValue(name) 216 if err != nil { 217 return nil, rookoutErrors.NewAgentKeyNotFoundException(v.name, key, err) 218 } 219 item, _ := v.spawn(name, obj, false) 220 return item, nil 221 } 222 223 return nil, rookoutErrors.NewAgentKeyNotFoundException(v.name, key, nil) 224 } 225 226 func (v *VariableNamespace) ReadKey(key interface{}) (Namespace, rookoutErrors.RookoutError) { 227 switch v.Obj.Kind { 228 case reflect.Array, reflect.Slice: 229 keyAsInt, ok := key.(int) 230 if !ok { 231 return nil, rookoutErrors.NewAgentKeyNotFoundException(v.name, key, nil) 232 } 233 return v.readKeyFromArray(keyAsInt) 234 235 case reflect.Map: 236 keyAsString, ok := key.(string) 237 if !ok { 238 return nil, rookoutErrors.NewAgentKeyNotFoundException(v.name, key, nil) 239 } 240 return v.readKeyFromMap(keyAsString) 241 242 case reflect.Struct: 243 keyAsString, ok := key.(string) 244 if !ok { 245 return nil, rookoutErrors.NewAgentKeyNotFoundException(v.name, key, nil) 246 } 247 return v.readKeyFromStruct(keyAsString) 248 249 case reflect.Interface, reflect.Ptr: 250 obj, _ := v.spawn(v.name, v.Obj.Children[0], false) 251 252 if v.Obj.Kind == obj.Obj.Kind { 253 return nil, rookoutErrors.NewInvalidInterfaceVariable(key) 254 } 255 return obj.ReadKey(key) 256 } 257 return nil, rookoutErrors.NewAgentKeyNotFoundException(v.name, key, nil) 258 } 259 260 func (v *VariableNamespace) GetObject() interface{} { 261 switch v.Obj.Kind { 262 case reflect.Bool: 263 return constant.BoolVal(v.Obj.Value) 264 case reflect.Float32: 265 float, _ := constant.Float32Val(v.Obj.Value) 266 return float 267 case reflect.Float64: 268 float, _ := constant.Float64Val(v.Obj.Value) 269 return float 270 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 271 number, _ := constant.Int64Val(v.Obj.Value) 272 switch v.Obj.Kind { 273 case reflect.Int: 274 return int(number) 275 case reflect.Int8: 276 return int8(number) 277 case reflect.Int16: 278 return int16(number) 279 case reflect.Int32: 280 return int32(number) 281 case reflect.Int64: 282 return int64(number) 283 } 284 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 285 number, _ := constant.Uint64Val(v.Obj.Value) 286 switch v.Obj.Kind { 287 case reflect.Uint: 288 return uint(number) 289 case reflect.Uint8: 290 return uint8(number) 291 case reflect.Uint16: 292 return uint16(number) 293 case reflect.Uint32: 294 return uint32(number) 295 case reflect.Uint64: 296 return uint64(number) 297 case reflect.Uintptr: 298 return uintptr(number) 299 } 300 case reflect.Complex64: 301 str := v.Obj.Value.ExactString() 302 str = strings.ReplaceAll(str, " ", "") 303 number, _ := strconv.ParseComplex(str, 64) 304 return complex64(number) 305 case reflect.Complex128: 306 str := v.Obj.Value.ExactString() 307 str = strings.ReplaceAll(str, " ", "") 308 number, _ := strconv.ParseComplex(str, 128) 309 return number 310 case reflect.String: 311 return constant.StringVal(v.Obj.Value) 312 case reflect.Array, reflect.Slice: 313 if v.Obj.IsNil() { 314 return nil 315 } 316 values := make([]interface{}, 0, len(v.Obj.Children)) 317 for i, child := range v.Obj.Children { 318 n, maxDepth := v.spawn(v.name+"["+strconv.Itoa(i)+"]", child, true) 319 if maxDepth { 320 return values 321 } 322 values = append(values, n.GetObject()) 323 } 324 return values 325 case reflect.Struct: 326 return StructTypeInstance 327 case reflect.Map, reflect.Chan, reflect.Interface, reflect.Ptr, reflect.Func: 328 if v.Obj.IsNil() { 329 return nil 330 } 331 return ReferenceTypeInstance 332 } 333 return constant.Val(v.Obj.Value) 334 } 335 336 func PrettyTypeName(typ godwarf.Type) string { 337 if typ == nil { 338 return "" 339 } 340 if typ.Common().Name != "" { 341 return typ.Common().Name 342 } 343 r := typ.String() 344 if r == "*void" { 345 return "unsafe.Pointer" 346 } 347 return r 348 } 349 350 func (v *VariableNamespace) Serialize(serializer Serializer) { 351 defer serializer.dumpOriginalType(PrettyTypeName(v.Obj.DwarfType)) 352 353 if v.Obj.Value != nil { 354 if cd := v.Obj.ConstDescr(); cd != "" { 355 i, _ := constant.Int64Val(constant.ToInt(v.Obj.Value)) 356 serializer.dumpEnum(cd, int(i), PrettyTypeName(v.Obj.DwarfType)) 357 return 358 } 359 360 var val interface{} 361 362 if v.Obj.Kind == reflect.Float32 || v.Obj.Kind == reflect.Float64 { 363 val, _ = constant.Float64Val(v.Obj.Value) 364 } else { 365 val = constant.Val(v.Obj.Value) 366 } 367 dumpInterface(serializer, val, v.ObjectDumpConf) 368 369 if v.Obj.Value.Kind() == constant.String { 370 serializer.dumpStringLen(int(v.Obj.Len)) 371 } 372 373 return 374 } 375 376 377 if v.Obj.DwarfType.Common().Name == "time.Time" { 378 timeValue := reflect.NewAt(reflect.TypeOf(time.Time{}), unsafe.Pointer(uintptr(v.Obj.Addr))) 379 dumpTimeValue(serializer, timeValue, v.ObjectDumpConf) 380 return 381 } 382 383 if v.Obj.Unreadable != nil { 384 dumpError(serializer, v.Obj.Unreadable) 385 } else { 386 switch v.Obj.Kind { 387 case reflect.Map: 388 getKeyValue := func(i int) (Namespace, Namespace, bool) { 389 keyIndex := i * 2 390 valueIndex := keyIndex + 1 391 392 key := v.Obj.Children[keyIndex] 393 keyNamespace, maxDepth := v.spawn(key.Name, key, true) 394 if maxDepth { 395 return nil, nil, false 396 } 397 398 value := v.Obj.Children[valueIndex] 399 valueNamespace, maxDepth := v.spawn(value.Name, value, true) 400 if maxDepth { 401 return nil, nil, false 402 } 403 404 return keyNamespace, valueNamespace, true 405 } 406 407 serializer.dumpMap(getKeyValue, len(v.Obj.Children)/2, v.ObjectDumpConf) 408 case reflect.Slice, reflect.Array, reflect.Chan: 409 410 if v.Obj.Base == 0 && v.Obj.Len == 0 { 411 serializer.dumpNil() 412 return 413 } 414 415 getElem := func(i int) (Namespace, bool) { 416 if i >= len(v.Obj.Children) { 417 return nil, false 418 } 419 420 child := v.Obj.Children[i] 421 spawned, maxDepth := v.spawn(child.Name, child, true) 422 if maxDepth { 423 return nil, false 424 } 425 return spawned, true 426 } 427 serializer.dumpArray(getElem, int(v.Obj.Len), v.ObjectDumpConf) 428 case reflect.Ptr: 429 if len(v.Obj.Children) == 0 || v.Obj.Children[0].Addr == 0 { 430 serializer.dumpNil() 431 } else if v.Obj.Children[0].OnlyAddr { 432 dumpUint(serializer, v.Obj.Children[0].Addr, v.ObjectDumpConf) 433 } else { 434 child, maxDepth := v.spawn(v.Obj.Name, v.Obj.Children[0], true) 435 if maxDepth { 436 return 437 } 438 child.Serialize(serializer) 439 } 440 case reflect.UnsafePointer: 441 if len(v.Obj.Children) == 0 { 442 serializer.dumpNil() 443 } 444 dumpUint(serializer, v.Obj.Children[0].Addr, v.ObjectDumpConf) 445 case reflect.Func: 446 serializer.dumpFunc(v.Obj.FunctionName, v.Obj.FileName, v.Obj.Line) 447 case reflect.Interface: 448 if v.Obj.Addr == 0 || len(v.Obj.Children) == 0 { 449 450 451 serializer.dumpNil() 452 return 453 } 454 455 data := v.Obj.Children[0] 456 if data.OnlyAddr { 457 dumpUint(serializer, data.Addr, v.ObjectDumpConf) 458 return 459 } 460 461 var child *VariableNamespace 462 if data.Addr == v.Obj.Addr { 463 464 var maxDepth bool 465 child, maxDepth = v.spawn(data.Name, data, true) 466 if maxDepth { 467 return 468 } 469 } else { 470 child, _ = v.spawn(data.Name, data, false) 471 child.currentDepth = v.currentDepth 472 } 473 474 child.Serialize(serializer) 475 serializer.dumpOriginalType(fmt.Sprintf("%s (%s)", PrettyTypeName(v.Obj.DwarfType), PrettyTypeName(child.Obj.DwarfType))) 476 case reflect.Struct: 477 getField := func(i int) (string, Namespace, bool) { 478 child := v.Obj.Children[i] 479 field, maxDepth := v.spawn(child.Name, child, true) 480 if maxDepth { 481 return "", nil, false 482 } 483 return child.Name, field, true 484 } 485 serializer.dumpStruct(getField, len(v.Obj.Children), v.ObjectDumpConf) 486 default: 487 serializer.dumpUnsupported() 488 } 489 } 490 } 491 492 func (v *VariableNamespace) GetObjectDumpConfig() config.ObjectDumpConfig { 493 return v.ObjectDumpConf 494 } 495 496 func (v *VariableNamespace) SetObjectDumpConfig(config config.ObjectDumpConfig) { 497 v.ObjectDumpConf = config 498 }