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 }