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  }