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

     1  package tracee
     2  
     3  import (
     4  	"debug/dwarf"
     5  	"encoding/binary"
     6  	"fmt"
     7  	"math"
     8  	"strconv"
     9  	"strings"
    10  
    11  	"github.com/ks888/tgo/log"
    12  )
    13  
    14  const maxContainerItemsToPrint = 8
    15  
    16  type value interface {
    17  	String() string
    18  	Size() int64
    19  }
    20  
    21  type int8Value struct {
    22  	*dwarf.IntType
    23  	val int8
    24  }
    25  
    26  func (v int8Value) String() string {
    27  	return fmt.Sprintf("%d", v.val)
    28  }
    29  
    30  type int16Value struct {
    31  	*dwarf.IntType
    32  	val int16
    33  }
    34  
    35  func (v int16Value) String() string {
    36  	return fmt.Sprintf("%d", v.val)
    37  }
    38  
    39  type int32Value struct {
    40  	*dwarf.IntType
    41  	val int32
    42  }
    43  
    44  func (v int32Value) String() string {
    45  	return fmt.Sprintf("%d", v.val)
    46  }
    47  
    48  type int64Value struct {
    49  	*dwarf.IntType
    50  	val int64
    51  }
    52  
    53  func (v int64Value) String() string {
    54  	return fmt.Sprintf("%d", v.val)
    55  }
    56  
    57  type uint8Value struct {
    58  	*dwarf.UintType
    59  	val uint8
    60  }
    61  
    62  func (v uint8Value) String() string {
    63  	return fmt.Sprintf("%d", v.val)
    64  }
    65  
    66  type uint16Value struct {
    67  	*dwarf.UintType
    68  	val uint16
    69  }
    70  
    71  func (v uint16Value) String() string {
    72  	return fmt.Sprintf("%d", v.val)
    73  }
    74  
    75  type uint32Value struct {
    76  	*dwarf.UintType
    77  	val uint32
    78  }
    79  
    80  func (v uint32Value) String() string {
    81  	return fmt.Sprintf("%d", v.val)
    82  }
    83  
    84  type uint64Value struct {
    85  	*dwarf.UintType
    86  	val uint64
    87  }
    88  
    89  func (v uint64Value) String() string {
    90  	return fmt.Sprintf("%d", v.val)
    91  }
    92  
    93  type float32Value struct {
    94  	*dwarf.FloatType
    95  	val float32
    96  }
    97  
    98  func (v float32Value) String() string {
    99  	return fmt.Sprintf("%g", v.val)
   100  }
   101  
   102  type float64Value struct {
   103  	*dwarf.FloatType
   104  	val float64
   105  }
   106  
   107  func (v float64Value) String() string {
   108  	return fmt.Sprintf("%g", v.val)
   109  }
   110  
   111  type complex64Value struct {
   112  	*dwarf.ComplexType
   113  	val complex64
   114  }
   115  
   116  func (v complex64Value) String() string {
   117  	return fmt.Sprintf("%g", v.val)
   118  }
   119  
   120  type complex128Value struct {
   121  	*dwarf.ComplexType
   122  	val complex128
   123  }
   124  
   125  func (v complex128Value) String() string {
   126  	return fmt.Sprintf("%g", v.val)
   127  }
   128  
   129  type boolValue struct {
   130  	*dwarf.BoolType
   131  	val bool
   132  }
   133  
   134  func (v boolValue) String() string {
   135  	return fmt.Sprintf("%t", v.val)
   136  }
   137  
   138  type ptrValue struct {
   139  	*dwarf.PtrType
   140  	addr       uint64
   141  	pointedVal value
   142  }
   143  
   144  func (v ptrValue) String() string {
   145  	if v.pointedVal != nil {
   146  		return fmt.Sprintf("&%s", v.pointedVal)
   147  	}
   148  	return fmt.Sprintf("%#x", v.addr)
   149  }
   150  
   151  type funcValue struct {
   152  	*dwarf.FuncType
   153  	addr uint64
   154  }
   155  
   156  func (v funcValue) String() string {
   157  	return fmt.Sprintf("%#x", v.addr)
   158  }
   159  
   160  type stringValue struct {
   161  	*dwarf.StructType
   162  	val string
   163  }
   164  
   165  func (v stringValue) String() string {
   166  	return strconv.Quote(v.val)
   167  }
   168  
   169  type sliceValue struct {
   170  	*dwarf.StructType
   171  	val []value
   172  }
   173  
   174  func (v sliceValue) String() string {
   175  	if len(v.val) == 0 {
   176  		return "nil"
   177  	}
   178  
   179  	var vals []string
   180  	abbrev := false
   181  	for i, v := range v.val {
   182  		if i >= maxContainerItemsToPrint {
   183  			abbrev = true
   184  			break
   185  		}
   186  		vals = append(vals, v.String())
   187  	}
   188  
   189  	if abbrev {
   190  		return fmt.Sprintf("[]{%s, ...}", strings.Join(vals, ", "))
   191  	}
   192  	return fmt.Sprintf("[]{%s}", strings.Join(vals, ", "))
   193  }
   194  
   195  type structValue struct {
   196  	*dwarf.StructType
   197  	fields      map[string]value
   198  	abbreviated bool
   199  }
   200  
   201  func (v structValue) String() string {
   202  	if v.abbreviated {
   203  		return "{...}"
   204  	}
   205  	var vals []string
   206  	for name, val := range v.fields {
   207  		vals = append(vals, fmt.Sprintf("%s: %s", name, val))
   208  	}
   209  	return fmt.Sprintf("{%s}", strings.Join(vals, ", "))
   210  }
   211  
   212  type interfaceValue struct {
   213  	*dwarf.StructType
   214  	implType    dwarf.Type
   215  	implVal     value
   216  	abbreviated bool
   217  }
   218  
   219  func (v interfaceValue) String() string {
   220  	if v.abbreviated {
   221  		return "{...}"
   222  	}
   223  	if v.implType == nil {
   224  		return "nil"
   225  	}
   226  
   227  	typeName := v.implType.String()
   228  	const structPrefix = "struct "
   229  	if strings.HasPrefix(typeName, structPrefix) {
   230  		// just to make the logs cleaner
   231  		typeName = strings.TrimPrefix(typeName, structPrefix)
   232  	}
   233  	return fmt.Sprintf("%s(%s)", typeName, v.implVal)
   234  }
   235  
   236  type arrayValue struct {
   237  	*dwarf.ArrayType
   238  	val []value
   239  }
   240  
   241  func (v arrayValue) String() string {
   242  	var vals []string
   243  	abbrev := false
   244  	for i, v := range v.val {
   245  		if i >= maxContainerItemsToPrint {
   246  			abbrev = true
   247  			break
   248  		}
   249  		vals = append(vals, v.String())
   250  	}
   251  
   252  	if abbrev {
   253  		return fmt.Sprintf("[%d]{%s, ...}", len(vals), strings.Join(vals, ", "))
   254  	}
   255  	return fmt.Sprintf("[%d]{%s}", len(vals), strings.Join(vals, ", "))
   256  }
   257  
   258  type mapValue struct {
   259  	*dwarf.TypedefType
   260  	val map[value]value
   261  }
   262  
   263  func (v mapValue) String() string {
   264  	var vals []string
   265  	for k, v := range v.val {
   266  		vals = append(vals, fmt.Sprintf("%s: %s", k, v))
   267  	}
   268  	return fmt.Sprintf("{%s}", strings.Join(vals, ", "))
   269  }
   270  
   271  type voidValue struct {
   272  	dwarf.Type
   273  	val []byte
   274  }
   275  
   276  func (v voidValue) String() string {
   277  	return fmt.Sprintf("%v", v.val)
   278  }
   279  
   280  type valueParser struct {
   281  	reader         memoryReader
   282  	mapRuntimeType func(addr uint64) (dwarf.Type, error)
   283  }
   284  
   285  type memoryReader interface {
   286  	ReadMemory(addr uint64, out []byte) error
   287  }
   288  
   289  // parseValue parses the `value` using the specified `rawTyp`.
   290  // `remainingDepth` is the depth of parsing, and parser stops when the depth becomes negative.
   291  // It is decremented when the struct type value is parsed, though the structs used by builtin types, such as slice and map, are not considered.
   292  func (b valueParser) parseValue(rawTyp dwarf.Type, val []byte, remainingDepth int) value {
   293  	switch typ := rawTyp.(type) {
   294  	case *dwarf.IntType:
   295  		switch typ.Size() {
   296  		case 1:
   297  			return int8Value{IntType: typ, val: int8(val[0])}
   298  		case 2:
   299  			return int16Value{IntType: typ, val: int16(binary.LittleEndian.Uint16(val))}
   300  		case 4:
   301  			return int32Value{IntType: typ, val: int32(binary.LittleEndian.Uint32(val))}
   302  		case 8:
   303  			return int64Value{IntType: typ, val: int64(binary.LittleEndian.Uint64(val))}
   304  		}
   305  
   306  	case *dwarf.UintType:
   307  		switch typ.Size() {
   308  		case 1:
   309  			return uint8Value{UintType: typ, val: val[0]}
   310  		case 2:
   311  			return uint16Value{UintType: typ, val: binary.LittleEndian.Uint16(val)}
   312  		case 4:
   313  			return uint32Value{UintType: typ, val: binary.LittleEndian.Uint32(val)}
   314  		case 8:
   315  			return uint64Value{UintType: typ, val: binary.LittleEndian.Uint64(val)}
   316  		}
   317  
   318  	case *dwarf.FloatType:
   319  		switch typ.Size() {
   320  		case 4:
   321  			return float32Value{FloatType: typ, val: math.Float32frombits(binary.LittleEndian.Uint32(val))}
   322  		case 8:
   323  			return float64Value{FloatType: typ, val: math.Float64frombits(binary.LittleEndian.Uint64(val))}
   324  		}
   325  
   326  	case *dwarf.ComplexType:
   327  		switch typ.Size() {
   328  		case 8:
   329  			real := math.Float32frombits(binary.LittleEndian.Uint32(val[0:4]))
   330  			img := math.Float32frombits(binary.LittleEndian.Uint32(val[4:8]))
   331  			return complex64Value{ComplexType: typ, val: complex(real, img)}
   332  		case 16:
   333  			real := math.Float64frombits(binary.LittleEndian.Uint64(val[0:8]))
   334  			img := math.Float64frombits(binary.LittleEndian.Uint64(val[8:16]))
   335  			return complex128Value{ComplexType: typ, val: complex(real, img)}
   336  		}
   337  
   338  	case *dwarf.BoolType:
   339  		return boolValue{BoolType: typ, val: val[0] == 1}
   340  
   341  	case *dwarf.PtrType:
   342  		addr := binary.LittleEndian.Uint64(val)
   343  		if addr == 0 {
   344  			// nil pointer
   345  			return ptrValue{PtrType: typ}
   346  		}
   347  
   348  		if _, ok := typ.Type.(*dwarf.VoidType); ok {
   349  			// unsafe.Pointer
   350  			return ptrValue{PtrType: typ, addr: addr}
   351  		}
   352  
   353  		buff := make([]byte, typ.Type.Size())
   354  		if err := b.reader.ReadMemory(addr, buff); err != nil {
   355  			log.Debugf("failed to read memory (addr: %x): %v", addr, err)
   356  			// the value may not be initialized yet (or too large)
   357  			return ptrValue{PtrType: typ, addr: addr}
   358  		}
   359  		pointedVal := b.parseValue(typ.Type, buff, remainingDepth)
   360  		return ptrValue{PtrType: typ, addr: addr, pointedVal: pointedVal}
   361  
   362  	case *dwarf.FuncType:
   363  		// TODO: print the pointer to the actual function (and the variables in closure if possible).
   364  		addr := binary.LittleEndian.Uint64(val)
   365  		return funcValue{FuncType: typ, addr: addr}
   366  
   367  	case *dwarf.StructType:
   368  		switch {
   369  		case typ.StructName == "string":
   370  			return b.parseStringValue(typ, val)
   371  		case strings.HasPrefix(typ.StructName, "[]"):
   372  			return b.parseSliceValue(typ, val, remainingDepth)
   373  		case typ.StructName == "runtime.iface":
   374  			return b.parseInterfaceValue(typ, val, remainingDepth)
   375  		case typ.StructName == "runtime.eface":
   376  			return b.parseEmptyInterfaceValue(typ, val, remainingDepth)
   377  		default:
   378  			return b.parseStructValue(typ, val, remainingDepth)
   379  		}
   380  	case *dwarf.ArrayType:
   381  		if typ.Count == -1 {
   382  			break
   383  		}
   384  		var vals []value
   385  		stride := int(typ.Type.Size())
   386  		for i := 0; i < int(typ.Count); i++ {
   387  			vals = append(vals, b.parseValue(typ.Type, val[i*stride:(i+1)*stride], remainingDepth))
   388  		}
   389  		return arrayValue{ArrayType: typ, val: vals}
   390  	case *dwarf.TypedefType:
   391  		if strings.HasPrefix(typ.String(), "map[") {
   392  			return b.parseMapValue(typ, val, remainingDepth)
   393  		}
   394  
   395  		// In this case, virtually do nothing so far. So do not decrement `remainingDepth`.
   396  		return b.parseValue(typ.Type, val, remainingDepth)
   397  	}
   398  	return voidValue{Type: rawTyp, val: val}
   399  }
   400  
   401  func (b valueParser) parseStringValue(typ *dwarf.StructType, val []byte) stringValue {
   402  	addr := binary.LittleEndian.Uint64(val[:8])
   403  	len := int(binary.LittleEndian.Uint64(val[8:]))
   404  	buff := make([]byte, len)
   405  
   406  	if err := b.reader.ReadMemory(addr, buff); err != nil {
   407  		log.Debugf("failed to read memory (addr: %x): %v", addr, err)
   408  		return stringValue{StructType: typ}
   409  	}
   410  	return stringValue{StructType: typ, val: string(buff)}
   411  }
   412  
   413  func (b valueParser) parseSliceValue(typ *dwarf.StructType, val []byte, remainingDepth int) sliceValue {
   414  	// Values are wrapped by slice struct. So +1 here.
   415  	structVal := b.parseStructValue(typ, val, remainingDepth+1)
   416  	length := int(structVal.fields["len"].(int64Value).val)
   417  	if length == 0 {
   418  		return sliceValue{StructType: typ}
   419  	}
   420  
   421  	firstElem := structVal.fields["array"].(ptrValue)
   422  	sliceVal := sliceValue{StructType: typ, val: []value{firstElem.pointedVal}}
   423  
   424  	for i := 1; i < length; i++ {
   425  		addr := firstElem.addr + uint64(firstElem.pointedVal.Size())*uint64(i)
   426  		buff := make([]byte, 8)
   427  		binary.LittleEndian.PutUint64(buff, addr)
   428  		elem := b.parseValue(firstElem.PtrType, buff, remainingDepth).(ptrValue)
   429  		sliceVal.val = append(sliceVal.val, elem.pointedVal)
   430  	}
   431  
   432  	return sliceVal
   433  }
   434  
   435  func (b valueParser) parseInterfaceValue(typ *dwarf.StructType, val []byte, remainingDepth int) interfaceValue {
   436  	// Interface is represented by the iface and itab struct. So remainingDepth needs to be at least 2.
   437  	structVal := b.parseStructValue(typ, val, 2)
   438  	ptrToTab := structVal.fields["tab"].(ptrValue)
   439  	if ptrToTab.pointedVal == nil {
   440  		return interfaceValue{StructType: typ}
   441  	}
   442  	if b.mapRuntimeType == nil {
   443  		// Old go versions offer the different method to map the runtime type.
   444  		return interfaceValue{StructType: typ, abbreviated: true}
   445  	}
   446  
   447  	tab := ptrToTab.pointedVal.(structValue)
   448  	runtimeTypeAddr := tab.fields["_type"].(ptrValue).addr
   449  	implType, err := b.mapRuntimeType(runtimeTypeAddr)
   450  	if err != nil {
   451  		log.Debugf("failed to find the impl type (runtime type addr: %x): %v", runtimeTypeAddr, err)
   452  		return interfaceValue{StructType: typ}
   453  	}
   454  
   455  	data := structVal.fields["data"].(ptrValue)
   456  	if _, ok := implType.(*dwarf.PtrType); ok {
   457  		buff := make([]byte, 8)
   458  		binary.LittleEndian.PutUint64(buff, data.addr)
   459  		return interfaceValue{StructType: typ, implType: implType, implVal: b.parseValue(implType, buff, remainingDepth)}
   460  	}
   461  
   462  	// When the actual type is not pointer, we need the explicit dereference because data.addr is the pointer to the data.
   463  	dataBuff := make([]byte, implType.Size())
   464  	if err := b.reader.ReadMemory(data.addr, dataBuff); err != nil {
   465  		log.Debugf("failed to read memory (addr: %x): %v", data.addr, err)
   466  		return interfaceValue{StructType: typ}
   467  	}
   468  	return interfaceValue{StructType: typ, implType: implType, implVal: b.parseValue(implType, dataBuff, remainingDepth)}
   469  }
   470  
   471  func (b valueParser) parseEmptyInterfaceValue(typ *dwarf.StructType, val []byte, remainingDepth int) interfaceValue {
   472  	// Empty interface is represented by the eface struct. So remainingDepth needs to be at least 1.
   473  	structVal := b.parseStructValue(typ, val, 1)
   474  	data := structVal.fields["data"].(ptrValue)
   475  	if data.addr == 0 {
   476  		return interfaceValue{StructType: typ}
   477  	}
   478  	if b.mapRuntimeType == nil {
   479  		// Old go versions offer the different method to map the runtime type.
   480  		return interfaceValue{StructType: typ, abbreviated: true}
   481  	}
   482  
   483  	runtimeTypeAddr := structVal.fields["_type"].(ptrValue).addr
   484  	implType, err := b.mapRuntimeType(runtimeTypeAddr)
   485  	if err != nil {
   486  		log.Debugf("failed to find the impl type (runtime type addr: %x): %v", runtimeTypeAddr, err)
   487  		return interfaceValue{StructType: typ}
   488  	}
   489  
   490  	if _, ok := implType.(*dwarf.PtrType); ok {
   491  		buff := make([]byte, 8)
   492  		binary.LittleEndian.PutUint64(buff, data.addr)
   493  		return interfaceValue{StructType: typ, implType: implType, implVal: b.parseValue(implType, buff, remainingDepth)}
   494  	}
   495  
   496  	// When the actual type is not pointer, we need the explicit dereference because data.addr is the pointer to the data.
   497  	dataBuff := make([]byte, implType.Size())
   498  	if err := b.reader.ReadMemory(data.addr, dataBuff); err != nil {
   499  		log.Debugf("failed to read memory (addr: %x): %v", data.addr, err)
   500  		return interfaceValue{StructType: typ}
   501  	}
   502  
   503  	return interfaceValue{StructType: typ, implType: implType, implVal: b.parseValue(implType, dataBuff, remainingDepth)}
   504  }
   505  
   506  func (b valueParser) parseStructValue(typ *dwarf.StructType, val []byte, remainingDepth int) structValue {
   507  	if remainingDepth <= 0 {
   508  		return structValue{StructType: typ, abbreviated: true}
   509  	}
   510  
   511  	fields := make(map[string]value)
   512  	for _, field := range typ.Field {
   513  		fields[field.Name] = b.parseValue(field.Type, val[field.ByteOffset:field.ByteOffset+field.Type.Size()], remainingDepth-1)
   514  	}
   515  	return structValue{StructType: typ, fields: fields}
   516  }
   517  
   518  func (b valueParser) parseMapValue(typ *dwarf.TypedefType, val []byte, remainingDepth int) mapValue {
   519  	// Actual keys and values are wrapped by hmap struct and buckets struct. So +2 here.
   520  	ptrVal := b.parseValue(typ.Type, val, remainingDepth+2)
   521  	if ptrVal.(ptrValue).pointedVal == nil {
   522  		return mapValue{TypedefType: typ, val: nil}
   523  	}
   524  
   525  	hmapVal := ptrVal.(ptrValue).pointedVal.(structValue)
   526  	numBuckets := 1 << hmapVal.fields["B"].(uint8Value).val
   527  	ptrToBuckets := hmapVal.fields["buckets"].(ptrValue)
   528  	ptrToOldBuckets := hmapVal.fields["oldbuckets"].(ptrValue)
   529  	if ptrToOldBuckets.addr != 0 {
   530  		log.Debugf("Map values may be defective")
   531  	}
   532  
   533  	mapValues := make(map[value]value)
   534  	for i := 0; ; i++ {
   535  		mapValuesInBucket := b.parseBucket(ptrToBuckets, remainingDepth)
   536  		for k, v := range mapValuesInBucket {
   537  			mapValues[k] = v
   538  		}
   539  		if i+1 == numBuckets {
   540  			break
   541  		}
   542  
   543  		buckets := ptrToBuckets.pointedVal.(structValue)
   544  		nextBucketAddr := ptrToBuckets.addr + uint64(buckets.Size())
   545  		buff := make([]byte, 8)
   546  		binary.LittleEndian.PutUint64(buff, nextBucketAddr)
   547  		// Actual keys and values are wrapped by struct buckets. So +1 here.
   548  		ptrToBuckets = b.parseValue(ptrToBuckets.PtrType, buff, remainingDepth+1).(ptrValue)
   549  	}
   550  
   551  	return mapValue{TypedefType: typ, val: mapValues}
   552  }
   553  
   554  func (b valueParser) parseBucket(ptrToBucket ptrValue, remainingDepth int) map[value]value {
   555  	if ptrToBucket.addr == 0 {
   556  		return nil // initialized map may not have bucket
   557  	}
   558  
   559  	mapValues := make(map[value]value)
   560  	buckets := ptrToBucket.pointedVal.(structValue)
   561  	tophash := buckets.fields["tophash"].(arrayValue)
   562  	keys := buckets.fields["keys"].(arrayValue)
   563  	values := buckets.fields["values"].(arrayValue)
   564  
   565  	for j, hash := range tophash.val {
   566  		if hash.(uint8Value).val == 0 {
   567  			continue
   568  		}
   569  		mapValues[keys.val[j]] = values.val[j]
   570  	}
   571  
   572  	overflow := buckets.fields["overflow"].(ptrValue)
   573  	if overflow.addr == 0 {
   574  		return mapValues
   575  	}
   576  
   577  	buff := make([]byte, 8)
   578  	binary.LittleEndian.PutUint64(buff, overflow.addr)
   579  	// Actual keys and values are wrapped by struct buckets. So +1 here.
   580  	ptrToOverflowBucket := b.parseValue(ptrToBucket.PtrType, buff, remainingDepth+1).(ptrValue)
   581  	overflowedValues := b.parseBucket(ptrToOverflowBucket, remainingDepth)
   582  	for k, v := range overflowedValues {
   583  		mapValues[k] = v
   584  	}
   585  	return mapValues
   586  }