github.com/Rookout/GoSDK@v0.1.48/pkg/services/collection/variable/types.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 "bytes" 26 "errors" 27 "fmt" 28 "go/constant" 29 "reflect" 30 "strings" 31 "unsafe" 32 33 "github.com/Rookout/GoSDK/pkg/config" 34 "github.com/Rookout/GoSDK/pkg/services/collection/memory" 35 "github.com/Rookout/GoSDK/pkg/services/instrumentation/binary_info" 36 "github.com/Rookout/GoSDK/pkg/services/instrumentation/dwarf/godwarf" 37 "github.com/Rookout/GoSDK/pkg/services/instrumentation/module" 38 ) 39 40 41 42 43 44 45 46 47 48 49 func runtimeTypeToDIE(_type *Variable, dataAddr uint64) (typ godwarf.Type, kind int64, err error) { 50 bi := _type.bi 51 52 _type = _type.MaybeDereference() 53 54 // go 1.11 implementation: use extended attribute in debug_info 55 56 md := module.FindModuleDataForType(_type.Addr) 57 if md != nil { 58 so := imageOfPC(bi, md.GetFirstPC()) 59 if so != nil { 60 if rtdie, ok := so.RuntimeTypeToDIE[_type.Addr-md.GetTypesAddr()]; ok { 61 typ, err := godwarf.ReadType(so.Dwarf, so.Index, rtdie.Offset, &so.TypeCache) 62 if err != nil { 63 return nil, 0, fmt.Errorf("invalid interface type: %v", err) 64 } 65 if rtdie.Kind == -1 { 66 kindField := _type.loadFieldNamed("kind") 67 if kindField == nil || kindField.Value == nil { 68 kindField = _type.loadFieldNamed("Kind_") 69 if kindField == nil || kindField.Value == nil { 70 return typ, rtdie.Kind, nil 71 } 72 } 73 rtdie.Kind, _ = constant.Int64Val(kindField.Value) 74 } 75 return typ, rtdie.Kind, nil 76 } 77 } 78 } 79 80 // go1.7 to go1.10 implementation: convert runtime._type structs to type names 81 82 if binary_info.GoVersionAfterOrEqual(1, 17) { 83 84 85 86 87 88 return nil, 0, fmt.Errorf("could not resolve interface type") 89 } 90 91 typename, kind, err := nameOfRuntimeType(_type) 92 if err != nil { 93 return nil, 0, fmt.Errorf("invalid interface type: %v", err) 94 } 95 96 typ, err = bi.FindType(typename) 97 if err != nil { 98 return nil, 0, fmt.Errorf("interface type %q not found for %#x: %v", typename, dataAddr, err) 99 } 100 101 return typ, kind, nil 102 } 103 104 105 func imageOfPC(bi *binary_info.BinaryInfo, pc uint64) *binary_info.Image { 106 fn := bi.PCToFunc(pc) 107 if fn != nil { 108 return bi.FuncToImage(fn) 109 } 110 111 112 var so *binary_info.Image 113 for i := range bi.Images { 114 if int64(bi.Images[i].StaticBase) > int64(pc) { 115 continue 116 } 117 if so == nil || int64(bi.Images[i].StaticBase) > int64(so.StaticBase) { 118 so = bi.Images[i] 119 } 120 } 121 return so 122 } 123 124 125 126 const ( 127 tflagUncommon = 1 << 0 128 tflagExtraStar = 1 << 1 129 tflagNamed = 1 << 2 130 ) 131 132 133 134 135 func nameOfRuntimeType(_type *Variable) (typename string, kind int64, err error) { 136 if e, ok := _type.bi.NameOfRuntimeType[_type.Addr]; ok { 137 return e.Typename, e.Kind, nil 138 } 139 140 var tflag int64 141 142 if tflagField := _type.loadFieldNamed("tflag"); tflagField != nil && tflagField.Value != nil { 143 tflag, _ = constant.Int64Val(tflagField.Value) 144 } 145 if kindField := _type.loadFieldNamed("kind"); kindField != nil && kindField.Value != nil { 146 kind, _ = constant.Int64Val(kindField.Value) 147 } 148 149 150 151 if tflag&tflagNamed != 0 { 152 typename, err = nameOfNamedRuntimeType(_type, kind, tflag) 153 if err == nil { 154 _type.bi.NameOfRuntimeType[_type.Addr] = binary_info.NameOfRuntimeTypeEntry{Typename: typename, Kind: kind} 155 } 156 return typename, kind, err 157 } 158 159 typename, err = nameOfUnnamedRuntimeType(_type, kind, tflag) 160 if err == nil { 161 _type.bi.NameOfRuntimeType[_type.Addr] = binary_info.NameOfRuntimeTypeEntry{Typename: typename, Kind: kind} 162 } 163 return typename, kind, err 164 } 165 166 func fieldToType(_type *Variable, fieldName string) (string, error) { 167 typeField, err := _type.structMember(fieldName) 168 if err != nil { 169 return "", err 170 } 171 typeField = typeField.MaybeDereference() 172 typename, _, err := nameOfRuntimeType(typeField) 173 return typename, err 174 } 175 176 func nameOfUnnamedRuntimeType(_type *Variable, kind, tflag int64) (string, error) { 177 _type, err := specificRuntimeType(_type, kind) 178 if err != nil { 179 return "", err 180 } 181 182 183 switch reflect.Kind(kind & kindMask) { 184 case reflect.Array: 185 var len int64 186 if lenField := _type.loadFieldNamed("len"); lenField != nil && lenField.Value != nil { 187 len, _ = constant.Int64Val(lenField.Value) 188 } 189 elemname, err := fieldToType(_type, "elem") 190 if err != nil { 191 return "", err 192 } 193 return fmt.Sprintf("[%d]%s", len, elemname), nil 194 case reflect.Chan: 195 elemname, err := fieldToType(_type, "elem") 196 if err != nil { 197 return "", err 198 } 199 return "chan " + elemname, nil 200 case reflect.Func: 201 return nameOfFuncRuntimeType(_type, tflag, true) 202 case reflect.Interface: 203 return nameOfInterfaceRuntimeType(_type, kind, tflag) 204 case reflect.Map: 205 keyname, err := fieldToType(_type, "key") 206 if err != nil { 207 return "", err 208 } 209 elemname, err := fieldToType(_type, "elem") 210 if err != nil { 211 return "", err 212 } 213 return "map[" + keyname + "]" + elemname, nil 214 case reflect.Ptr: 215 elemname, err := fieldToType(_type, "elem") 216 if err != nil { 217 return "", err 218 } 219 return "*" + elemname, nil 220 case reflect.Slice: 221 elemname, err := fieldToType(_type, "elem") 222 if err != nil { 223 return "", err 224 } 225 return "[]" + elemname, nil 226 case reflect.Struct: 227 return nameOfStructRuntimeType(_type, kind, tflag) 228 default: 229 return nameOfNamedRuntimeType(_type, kind, tflag) 230 } 231 } 232 233 234 235 236 237 func nameOfFuncRuntimeType(_type *Variable, tflag int64, anonymous bool) (string, error) { 238 rtyp, err := _type.bi.FindType(_type.bi.RuntimeTypeTypename()) 239 if err != nil { 240 return "", err 241 } 242 prtyp := pointerTo(rtyp, _type.bi) 243 244 uadd := _type.RealType.Common().ByteSize 245 if ut := uncommon(_type, tflag); ut != nil { 246 uadd += ut.RealType.Common().ByteSize 247 } 248 249 var inCount, outCount int64 250 if inCountField := _type.loadFieldNamed("inCount"); inCountField != nil && inCountField.Value != nil { 251 inCount, _ = constant.Int64Val(inCountField.Value) 252 } 253 if outCountField := _type.loadFieldNamed("outCount"); outCountField != nil && outCountField.Value != nil { 254 outCount, _ = constant.Int64Val(outCountField.Value) 255 256 outCount = outCount & (1<<15 - 1) 257 } 258 259 cursortyp := _type.spawn("", _type.Addr+uint64(uadd), prtyp, _type.Mem) 260 var buf bytes.Buffer 261 if anonymous { 262 buf.WriteString("func(") 263 } else { 264 buf.WriteString("(") 265 } 266 267 for i := int64(0); i < inCount; i++ { 268 argtype := cursortyp.MaybeDereference() 269 cursortyp.Addr += uint64(_type.bi.PointerSize) 270 argtypename, _, err := nameOfRuntimeType(argtype) 271 if err != nil { 272 return "", err 273 } 274 buf.WriteString(argtypename) 275 if i != inCount-1 { 276 buf.WriteString(", ") 277 } 278 } 279 buf.WriteString(")") 280 281 switch outCount { 282 case 0: 283 284 case 1: 285 buf.WriteString(" ") 286 argtype := cursortyp.MaybeDereference() 287 argtypename, _, err := nameOfRuntimeType(argtype) 288 if err != nil { 289 return "", err 290 } 291 buf.WriteString(argtypename) 292 default: 293 buf.WriteString(" (") 294 for i := int64(0); i < outCount; i++ { 295 argtype := cursortyp.MaybeDereference() 296 cursortyp.Addr += uint64(_type.bi.PointerSize) 297 argtypename, _, err := nameOfRuntimeType(argtype) 298 if err != nil { 299 return "", err 300 } 301 buf.WriteString(argtypename) 302 if i != inCount-1 { 303 buf.WriteString(", ") 304 } 305 } 306 buf.WriteString(")") 307 } 308 return buf.String(), nil 309 } 310 311 312 313 314 315 const ( 316 imethodFieldName = "name" 317 imethodFieldItyp = "ityp" 318 interfacetypeFieldMhdr = "mhdr" 319 ) 320 321 func resolveTypeOff(bi *binary_info.BinaryInfo, typeAddr, off uint64, mem memory.MemoryReader) (*Variable, error) { 322 323 md := module.FindModuleDataForType(typeAddr) 324 325 rtyp, err := bi.FindType(bi.RuntimeTypeTypename()) 326 if err != nil { 327 return nil, err 328 } 329 330 if md == nil { 331 v, err := reflectOffsMapAccess(bi, off, mem) 332 if err != nil { 333 return nil, err 334 } 335 v.LoadValue() 336 addr, _ := constant.Int64Val(v.Value) 337 return v.spawn(v.Name, uint64(addr), rtyp, mem), nil 338 } 339 340 if t, ok := md.GetTypeMap()[module.TypeOff(off)]; ok { 341 tVar := NewVariable("", uint64(t), nil, mem, bi, config.GetDefaultDumpConfig(), 0, &VariablesCache{}) 342 tVar.Value = constant.MakeUint64(uint64(t)) 343 return tVar, nil 344 } 345 346 res := md.GetTypesAddr() + off 347 348 return NewVariable("", uint64(res), rtyp, mem, bi, config.GetDefaultDumpConfig(), 0, &VariablesCache{}), nil 349 } 350 351 func nameOfInterfaceRuntimeType(_type *Variable, kind, tflag int64) (string, error) { 352 var buf bytes.Buffer 353 buf.WriteString("interface {") 354 355 methods, _ := _type.structMember(interfacetypeFieldMhdr) 356 methods.loadArrayValues(0) 357 if methods.Unreadable != nil { 358 return "", nil 359 } 360 361 if len(methods.Children) == 0 { 362 buf.WriteString("}") 363 return buf.String(), nil 364 } 365 buf.WriteString(" ") 366 367 for i, im := range methods.Children { 368 var methodname, methodtype string 369 for i := range im.Children { 370 switch im.Children[i].Name { 371 case imethodFieldName: 372 nameoff, _ := constant.Int64Val(im.Children[i].Value) 373 var err error 374 methodname, _, _, err = resolveNameOff(_type.bi, _type.Addr, uint64(nameoff), _type.Mem) 375 if err != nil { 376 return "", err 377 } 378 379 case imethodFieldItyp: 380 typeoff, _ := constant.Int64Val(im.Children[i].Value) 381 typ, err := resolveTypeOff(_type.bi, _type.Addr, uint64(typeoff), _type.Mem) 382 if err != nil { 383 return "", err 384 } 385 typ, err = specificRuntimeType(typ, int64(reflect.Func)) 386 if err != nil { 387 return "", err 388 } 389 var tflag int64 390 if tflagField := typ.loadFieldNamed("tflag"); tflagField != nil && tflagField.Value != nil { 391 tflag, _ = constant.Int64Val(tflagField.Value) 392 } 393 methodtype, err = nameOfFuncRuntimeType(typ, tflag, false) 394 if err != nil { 395 return "", err 396 } 397 } 398 } 399 400 buf.WriteString(methodname) 401 buf.WriteString(methodtype) 402 403 if i != len(methods.Children)-1 { 404 buf.WriteString("; ") 405 } else { 406 buf.WriteString(" }") 407 } 408 } 409 return buf.String(), nil 410 } 411 412 func nameOfStructRuntimeType(_type *Variable, kind, tflag int64) (string, error) { 413 var buf bytes.Buffer 414 buf.WriteString("struct {") 415 416 fields, _ := _type.structMember("fields") 417 fields.loadArrayValues(0) 418 if fields.Unreadable != nil { 419 return "", fields.Unreadable 420 } 421 422 if len(fields.Children) == 0 { 423 buf.WriteString("}") 424 return buf.String(), nil 425 } 426 buf.WriteString(" ") 427 428 for i, field := range fields.Children { 429 var fieldname, fieldtypename string 430 var typeField *Variable 431 isembed := false 432 for i := range field.Children { 433 switch field.Children[i].Name { 434 case "name": 435 var nameoff int64 436 switch field.Children[i].Kind { 437 case reflect.Struct: 438 nameoff = int64(field.Children[i].fieldVariable("bytes").Children[0].Addr) 439 default: 440 nameoff, _ = constant.Int64Val(field.Children[i].Value) 441 } 442 443 var err error 444 fieldname, _, _, err = loadName(uint64(nameoff), _type.Mem) 445 if err != nil { 446 return "", err 447 } 448 449 case "typ": 450 typeField = field.Children[i].MaybeDereference() 451 var err error 452 fieldtypename, _, err = nameOfRuntimeType(typeField) 453 if err != nil { 454 return "", err 455 } 456 457 case "offsetAnon": 458 459 460 461 462 463 464 465 offsetAnon, _ := constant.Int64Val(field.Children[i].Value) 466 isembed = offsetAnon%2 != 0 467 } 468 } 469 470 471 if fieldname != "" && !isembed { 472 buf.WriteString(fieldname) 473 buf.WriteString(" ") 474 } 475 buf.WriteString(fieldtypename) 476 if i != len(fields.Children)-1 { 477 buf.WriteString("; ") 478 } else { 479 buf.WriteString(" }") 480 } 481 } 482 483 return buf.String(), nil 484 } 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 func nameOfNamedRuntimeType(_type *Variable, kind, tflag int64) (typename string, err error) { 503 var strOff int64 504 if strField := _type.loadFieldNamed("str"); strField != nil && strField.Value != nil { 505 strOff, _ = constant.Int64Val(strField.Value) 506 } else { 507 return "", errors.New("could not find str field") 508 } 509 510 511 512 513 514 typename, _, _, err = resolveNameOff(_type.bi, _type.Addr, uint64(strOff), _type.Mem) 515 if err != nil { 516 return "", err 517 } 518 519 if tflag&tflagExtraStar != 0 { 520 typename = typename[1:] 521 } 522 523 if i := strings.Index(typename, "."); i >= 0 { 524 typename = typename[i+1:] 525 } else { 526 return typename, nil 527 } 528 529 530 531 532 _type, err = specificRuntimeType(_type, kind) 533 if err != nil { 534 return "", err 535 } 536 537 if ut := uncommon(_type, tflag); ut != nil { 538 if pkgPathField := ut.loadFieldNamed("pkgpath"); pkgPathField != nil && pkgPathField.Value != nil { 539 pkgPathOff, _ := constant.Int64Val(pkgPathField.Value) 540 pkgPath, _, _, err := resolveNameOff(_type.bi, _type.Addr, uint64(pkgPathOff), _type.Mem) 541 if err != nil { 542 return "", err 543 } 544 if slash := strings.LastIndex(pkgPath, "/"); slash >= 0 { 545 fixedName := strings.Replace(pkgPath[slash+1:], ".", "%2e", -1) 546 if fixedName != pkgPath[slash+1:] { 547 pkgPath = pkgPath[:slash+1] + fixedName 548 } 549 } 550 typename = pkgPath + "." + typename 551 } 552 } 553 554 return typename, nil 555 } 556 557 func specificRuntimeType(_type *Variable, kind int64) (*Variable, error) { 558 typ, err := typeForKind(kind, _type.bi) 559 if err != nil { 560 return nil, err 561 } 562 if typ == nil { 563 return _type, nil 564 } 565 566 return _type.spawn(_type.Name, _type.Addr, typ, _type.Mem), nil 567 } 568 569 var kindToRuntimeTypeName = map[reflect.Kind]string{ 570 reflect.Array: "runtime.arraytype", 571 reflect.Chan: "runtime.chantype", 572 reflect.Func: "runtime.functype", 573 reflect.Interface: "runtime.interfacetype", 574 reflect.Map: "runtime.maptype", 575 reflect.Ptr: "runtime.ptrtype", 576 reflect.Slice: "runtime.slicetype", 577 reflect.Struct: "runtime.structtype", 578 } 579 580 581 582 583 func typeForKind(kind int64, bi *binary_info.BinaryInfo) (*godwarf.StructType, error) { 584 typename, ok := kindToRuntimeTypeName[reflect.Kind(kind&kindMask)] 585 if !ok { 586 return nil, nil 587 } 588 typ, err := bi.FindType(typename) 589 if err != nil { 590 return nil, err 591 } 592 typ = resolveTypedef(typ) 593 return typ.(*godwarf.StructType), nil 594 } 595 596 597 func uncommon(_type *Variable, tflag int64) *Variable { 598 if tflag&tflagUncommon == 0 { 599 return nil 600 } 601 602 typ, err := _type.bi.FindType("runtime.uncommontype") 603 if err != nil { 604 return nil 605 } 606 607 return _type.spawn(_type.Name, _type.Addr+uint64(_type.RealType.Size()), typ, _type.Mem) 608 } 609 610 func resolveNameOff(bi *binary_info.BinaryInfo, typeAddr, off uint64, mem memory.MemoryReader) (name, tag string, pkgpathoff int32, err error) { 611 612 if md := module.FindModuleDataForType(typeAddr); md != nil { 613 return loadName(md.GetTypesAddr()+off, mem) 614 } 615 616 v, err := reflectOffsMapAccess(bi, off, mem) 617 if err != nil { 618 return "", "", 0, err 619 } 620 621 resv := v.MaybeDereference() 622 if resv.Unreadable != nil { 623 return "", "", 0, resv.Unreadable 624 } 625 626 return loadName(resv.Addr, mem) 627 } 628 629 func reflectOffsMapAccess(bi *binary_info.BinaryInfo, off uint64, mem memory.MemoryReader) (*Variable, error) { 630 v := NewVariable("", 0, nil, mem, bi, config.GetDefaultDumpConfig(), 0, &VariablesCache{}) 631 v.Value = constant.MakeUint64(uint64(uintptr(reflectOffs.m[int32(off)]))) 632 v.Addr = uint64(uintptr(reflectOffs.m[int32(off)])) 633 return v, nil 634 } 635 636 type lockRankStruct struct { 637 } 638 639 640 641 642 643 644 type mutex struct { 645 646 lockRankStruct 647 648 649 650 key uintptr 651 } 652 653 //go:linkname reflectOffs runtime.reflectOffs 654 var reflectOffs struct { 655 lock mutex 656 next int32 657 m map[int32]unsafe.Pointer 658 minv map[unsafe.Pointer]int32 659 } 660 661 const ( 662 663 nameflagExported = 1 << 0 664 nameflagHasTag = 1 << 1 665 nameflagHasPkg = 1 << 2 666 ) 667 668 func loadName(addr uint64, mem memory.MemoryReader) (name, tag string, pkgpathoff int32, err error) { 669 off := addr 670 namedata := make([]byte, 3) 671 _, err = mem.ReadMemory(namedata, off) 672 off += 3 673 if err != nil { 674 return "", "", 0, err 675 } 676 677 namelen := uint16(namedata[1])<<8 | uint16(namedata[2]) 678 679 rawstr := make([]byte, int(namelen)) 680 _, err = mem.ReadMemory(rawstr, off) 681 off += uint64(namelen) 682 if err != nil { 683 return "", "", 0, err 684 } 685 686 name = string(rawstr) 687 688 if namedata[0]&nameflagHasTag != 0 { 689 taglendata := make([]byte, 2) 690 _, err = mem.ReadMemory(taglendata, off) 691 off += 2 692 if err != nil { 693 return "", "", 0, err 694 } 695 taglen := uint16(taglendata[0])<<8 | uint16(taglendata[1]) 696 697 rawstr := make([]byte, int(taglen)) 698 _, err = mem.ReadMemory(rawstr, off) 699 off += uint64(taglen) 700 if err != nil { 701 return "", "", 0, err 702 } 703 704 tag = string(rawstr) 705 } 706 707 if namedata[0]&nameflagHasPkg != 0 { 708 pkgdata := make([]byte, 4) 709 _, err = mem.ReadMemory(pkgdata, off) 710 if err != nil { 711 return "", "", 0, err 712 } 713 714 715 copy((*[4]byte)(unsafe.Pointer(&pkgpathoff))[:], pkgdata) 716 } 717 718 return name, tag, pkgpathoff, nil 719 } 720 721 722 723 func resolveParametricType(bi *binary_info.BinaryInfo, mem memory.MemoryReader, t godwarf.Type, dictAddr uint64) (godwarf.Type, error) { 724 ptyp, _ := t.(*godwarf.ParametricType) 725 if ptyp == nil { 726 return t, nil 727 } 728 if dictAddr == 0 { 729 return ptyp.TypedefType.Type, errors.New("parametric type without a dictionary") 730 } 731 rtypeAddr, err := readUintRaw(mem, dictAddr+uint64(ptyp.DictIndex*int64(bi.PointerSize)), int64(bi.PointerSize)) 732 if err != nil { 733 return ptyp.TypedefType.Type, err 734 } 735 runtimeType, err := bi.FindType(bi.RuntimeTypeTypename()) 736 if err != nil { 737 return ptyp.TypedefType.Type, err 738 } 739 _type := NewVariable("", rtypeAddr, runtimeType, mem, bi, config.GetDefaultDumpConfig(), dictAddr, &VariablesCache{}) 740 741 typ, _, err := runtimeTypeToDIE(_type, 0) 742 if err != nil { 743 return ptyp.TypedefType.Type, err 744 } 745 746 return typ, nil 747 }