github.com/ks888/tgo@v0.0.0-20190130135156-80bf89407292/tracee/binary.go (about) 1 package tracee 2 3 import ( 4 "debug/dwarf" 5 "encoding/binary" 6 "errors" 7 "fmt" 8 "io" 9 "sort" 10 "strings" 11 "unicode" 12 13 "github.com/ks888/tgo/log" 14 ) 15 16 const ( 17 // AttrVariableParameter is the extended DWARF attribute. If true, the parameter is output. Else, it's input. 18 attrVariableParameter = 0x4b 19 attrGoRuntimeType = 0x2904 // DW_AT_go_runtime_type 20 dwarfOpCallFrameCFA = 0x9c // DW_OP_call_frame_cfa 21 dwarfOpFbreg = 0x91 // DW_OP_fbreg 22 ) 23 24 // BinaryFile represents the program the tracee process is executing. 25 type BinaryFile interface { 26 // FindFunction returns the function info to which the given pc specifies. 27 FindFunction(pc uint64) (*Function, error) 28 // Close closes the binary file. 29 Close() error 30 // findDwarfTypeByAddr finds the dwarf.Type to which the given address specifies. 31 // The given address must be the address of the type (not value) and need to be adjusted 32 // using the moduledata. 33 findDwarfTypeByAddr(typeAddr uint64) (dwarf.Type, error) 34 // moduleDataType returns the dwarf.Type of runtime.moduledata struct type. 35 moduleDataType() dwarf.Type 36 // runtimeGType returns the dwarf.Type of runtime.g struct type. 37 runtimeGType() dwarf.Type 38 } 39 40 // debuggableBinaryFile represents the binary file with DWARF sections. 41 type debuggableBinaryFile struct { 42 dwarf dwarfData 43 closer io.Closer 44 types map[uint64]dwarf.Offset 45 cachedRuntimeGType dwarf.Type 46 cachedModuleDataType dwarf.Type 47 } 48 49 type dwarfData struct { 50 *dwarf.Data 51 locationList []byte 52 } 53 54 // Function represents a function info in the debug info section. 55 type Function struct { 56 Name string 57 // StartAddr is the start address of the function, inclusive. 58 StartAddr uint64 59 // EndAddr is the end address of the function, exclusive. 0 if unknown. 60 EndAddr uint64 61 // Parameters may be empty due to the lack of information. 62 Parameters []Parameter 63 } 64 65 // Parameter represents a parameter given to or the returned from the function. 66 type Parameter struct { 67 Name string 68 Typ dwarf.Type 69 // Offset is the offset from the beginning of the parameter list. 70 Offset int 71 // Exist is false when the parameter is removed due to the optimization. 72 Exist bool 73 IsOutput bool 74 } 75 76 // OpenBinaryFile opens the specified program file. 77 func OpenBinaryFile(pathToProgram string, goVersion GoVersion) (BinaryFile, error) { 78 return openBinaryFile(pathToProgram, goVersion) 79 } 80 81 func newDebuggableBinaryFile(data dwarfData, goVersion GoVersion, closer io.Closer) (debuggableBinaryFile, error) { 82 binary := debuggableBinaryFile{dwarf: data, closer: closer} 83 84 var err error 85 binary.types, err = binary.buildTypes(goVersion) 86 if err != nil { 87 return debuggableBinaryFile{}, err 88 } 89 90 binary.cachedModuleDataType, err = binary.findModuleDataType() 91 if err != nil { 92 return debuggableBinaryFile{}, err 93 } 94 95 binary.cachedRuntimeGType, err = binary.findRuntimeGType() 96 if err != nil { 97 return debuggableBinaryFile{}, err 98 } 99 100 return binary, nil 101 } 102 103 func (b debuggableBinaryFile) buildTypes(goVersion GoVersion) (map[uint64]dwarf.Offset, error) { 104 if !goVersion.LaterThan(GoVersion{MajorVersion: 1, MinorVersion: 11, PatchVersion: 0}) { 105 // attrGoRuntimeType is not supported 106 return nil, nil 107 } 108 types := make(map[uint64]dwarf.Offset) 109 reader := b.dwarf.Reader() 110 for { 111 entry, err := reader.Next() 112 if err != nil || entry == nil { 113 return types, err 114 } 115 116 switch entry.Tag { 117 case dwarf.TagArrayType, dwarf.TagPointerType, dwarf.TagStructType, dwarf.TagSubroutineType, dwarf.TagBaseType, dwarf.TagTypedef: 118 // based on the 'abbrevs' variable in src/cmd/internal/dwarf/dwarf.go. It indicates which tag types *may* have the DW_AT_go_runtime_type attribute. 119 val, err := addressClassAttr(entry, attrGoRuntimeType) 120 if err != nil || val == 0 { 121 break 122 } 123 types[val] = entry.Offset 124 } 125 } 126 } 127 128 const moduleDataTypeName = "runtime.moduledata" 129 130 func (b debuggableBinaryFile) findModuleDataType() (dwarf.Type, error) { 131 return b.findType(dwarf.TagStructType, moduleDataTypeName) 132 } 133 134 const gTypeName = "runtime.g" 135 136 func (b debuggableBinaryFile) findRuntimeGType() (dwarf.Type, error) { 137 return b.findType(dwarf.TagStructType, gTypeName) 138 } 139 140 func (b debuggableBinaryFile) findType(targetTag dwarf.Tag, targetName string) (dwarf.Type, error) { 141 entry, err := b.findDWARFEntryByName(func(entry *dwarf.Entry) bool { 142 if entry.Tag != targetTag { 143 return false 144 } 145 name, err := stringClassAttr(entry, dwarf.AttrName) 146 return name == targetName && err == nil 147 }) 148 if err != nil { 149 return nil, err 150 } 151 152 return b.dwarf.Type(entry.Offset) 153 } 154 155 func (b debuggableBinaryFile) findDWARFEntryByName(match func(*dwarf.Entry) bool) (*dwarf.Entry, error) { 156 reader := b.dwarf.Reader() 157 for { 158 entry, err := reader.Next() 159 if err != nil { 160 return nil, err 161 } else if entry == nil { 162 return nil, errors.New("failed to find a matched entry") 163 } 164 165 if match(entry) { 166 return entry, nil 167 } 168 } 169 } 170 171 // FindFunction looks up the function info described in the debug info section. 172 func (b debuggableBinaryFile) FindFunction(pc uint64) (*Function, error) { 173 reader := subprogramReader{raw: b.dwarf.Reader(), dwarfData: b.dwarf} 174 return reader.Seek(pc) 175 } 176 177 // Close releases the resources associated with the binary. 178 func (b debuggableBinaryFile) Close() error { 179 return b.closer.Close() 180 } 181 182 func (b debuggableBinaryFile) findDwarfTypeByAddr(typeAddr uint64) (dwarf.Type, error) { 183 implTypOffset := b.types[typeAddr] 184 return b.dwarf.Type(implTypOffset) 185 } 186 187 func (b debuggableBinaryFile) moduleDataType() dwarf.Type { 188 return b.cachedModuleDataType 189 } 190 191 func (b debuggableBinaryFile) runtimeGType() dwarf.Type { 192 return b.cachedRuntimeGType 193 } 194 195 // IsExported returns true if the function is exported. 196 // See https://golang.org/ref/spec#Exported_identifiers for the spec. 197 func (f Function) IsExported() bool { 198 elems := strings.Split(f.Name, ".") 199 for _, ch := range elems[len(elems)-1] { 200 return unicode.IsUpper(ch) 201 } 202 return false 203 } 204 205 type subprogramReader struct { 206 raw *dwarf.Reader 207 dwarfData dwarfData 208 } 209 210 func (r subprogramReader) Next(setParameters bool) (*Function, error) { 211 for { 212 entry, err := r.raw.Next() 213 if err != nil || entry == nil { 214 return nil, err 215 } 216 217 if entry.Tag != dwarf.TagSubprogram || r.isInline(entry) { 218 continue 219 } 220 221 function, err := r.buildFunction(entry) 222 if err != nil { 223 return nil, err 224 } 225 226 if setParameters { 227 function.Parameters, err = r.parameters() 228 } 229 return function, err 230 231 } 232 } 233 234 func (r subprogramReader) Seek(pc uint64) (*Function, error) { 235 _, err := r.raw.SeekPC(pc) 236 if err != nil { 237 return nil, err 238 } 239 240 for { 241 subprogram, err := r.raw.Next() 242 if err != nil { 243 return nil, err 244 } 245 if subprogram == nil { 246 return nil, errors.New("subprogram not found") 247 } 248 249 if subprogram.Tag != dwarf.TagSubprogram || !r.includesPC(subprogram, pc) { 250 r.raw.SkipChildren() 251 continue 252 } 253 254 function, err := r.buildFunction(subprogram) 255 if err != nil { 256 return nil, err 257 } 258 259 function.Parameters, err = r.parameters() 260 return function, err 261 } 262 } 263 264 func (r subprogramReader) includesPC(subprogram *dwarf.Entry, pc uint64) bool { 265 lowPC, err := addressClassAttr(subprogram, dwarf.AttrLowpc) 266 if err != nil { 267 // inlined subprogram doesn't have the lowPC and highPC attributes. 268 return false 269 } 270 271 highPC, err := addressClassAttr(subprogram, dwarf.AttrHighpc) 272 if err != nil { 273 return false 274 } 275 276 if pc < lowPC || highPC <= pc { 277 return false 278 } 279 return true 280 } 281 282 func (r subprogramReader) isInline(subprogram *dwarf.Entry) bool { 283 return subprogram.AttrField(dwarf.AttrInline) != nil 284 } 285 286 func (r subprogramReader) buildFunction(subprogram *dwarf.Entry) (*Function, error) { 287 var name string 288 err := walkUpOrigins(subprogram, r.dwarfData.Data, func(entry *dwarf.Entry) bool { 289 var err error 290 name, err = stringClassAttr(entry, dwarf.AttrName) 291 return err == nil 292 }) 293 if err != nil { 294 return nil, errors.New("name attr not found") 295 } 296 297 lowPC, err := addressClassAttr(subprogram, dwarf.AttrLowpc) 298 if err != nil { 299 return nil, fmt.Errorf("%s: %v", name, err) 300 } 301 302 highPC, err := addressClassAttr(subprogram, dwarf.AttrHighpc) 303 if err != nil { 304 return nil, fmt.Errorf("%s: %v", name, err) 305 } 306 307 frameBase, err := locationClassAttr(subprogram, dwarf.AttrFrameBase) 308 if err != nil { 309 return nil, fmt.Errorf("%s: %v", name, err) 310 } else if len(frameBase) != 1 || frameBase[0] != dwarfOpCallFrameCFA { 311 log.Printf("The frame base attribute of %s has the unexpected value. The parameter values may be wrong.", name) 312 } 313 314 return &Function{Name: name, StartAddr: lowPC, EndAddr: highPC}, nil 315 } 316 317 func (r subprogramReader) parameters() ([]Parameter, error) { 318 var params []Parameter 319 for { 320 param, err := r.nextParameter() 321 if err != nil || param == nil { 322 // the parameters are sorted by the name. 323 sort.Slice(params, func(i, j int) bool { return params[i].Offset < params[j].Offset }) 324 return params, err 325 } 326 327 params = append(params, *param) 328 r.raw.SkipChildren() 329 } 330 } 331 332 func (r subprogramReader) nextParameter() (*Parameter, error) { 333 for { 334 param, err := r.raw.Next() 335 if err != nil || param.Tag == 0 { 336 return nil, err 337 } 338 339 if param.Tag != dwarf.TagFormalParameter { 340 r.raw.SkipChildren() 341 continue 342 } 343 344 return r.buildParameter(param) 345 } 346 } 347 348 func (r subprogramReader) buildParameter(param *dwarf.Entry) (*Parameter, error) { 349 var name string 350 var typeOffset dwarf.Offset 351 var isOutput bool 352 err := walkUpOrigins(param, r.dwarfData.Data, func(entry *dwarf.Entry) bool { 353 var err error 354 name, err = stringClassAttr(entry, dwarf.AttrName) 355 if err != nil { 356 return false 357 } 358 359 typeOffset, err = referenceClassAttr(entry, dwarf.AttrType) 360 if err != nil { 361 return false 362 } 363 364 isOutput, err = flagClassAttr(entry, attrVariableParameter) 365 return err == nil 366 }) 367 if err != nil { 368 return nil, err 369 } 370 371 typ, err := r.dwarfData.Type(typeOffset) 372 if err != nil { 373 return nil, err 374 } 375 376 offset, exist, err := r.findLocation(param) 377 return &Parameter{Name: name, Typ: typ, Offset: offset, IsOutput: isOutput, Exist: exist}, err 378 } 379 380 func (r subprogramReader) findLocation(param *dwarf.Entry) (offset int, exist bool, err error) { 381 offset, exist, err = r.findLocationByLocationDesc(param) 382 if err != nil && r.dwarfData.locationList != nil { 383 offset, exist, err = r.findLocationByLocationList(param) 384 } 385 return 386 } 387 388 func (r subprogramReader) findLocationByLocationDesc(param *dwarf.Entry) (offset int, exist bool, err error) { 389 loc, err := locationClassAttr(param, dwarf.AttrLocation) 390 if err != nil { 391 return 0, false, fmt.Errorf("loc attr not found: %v", err) 392 } 393 394 if len(loc) == 0 { 395 // the location description may be empty due to the optimization (see the DWARF spec 2.6.1.1.4) 396 return 0, false, nil 397 } 398 399 offset, err = parseLocationDesc(loc) 400 if err != nil { 401 log.Debugf("failed to parse location description at %#x: %v", param.Offset, err) 402 } 403 return offset, err == nil, nil 404 } 405 406 // parseLocationDesc returns the offset from the beginning of the parameter list. 407 // It assumes the value is present in the memory and not separated. 408 // Also, it's supposed the function's frame base always specifies to the CFA. 409 func parseLocationDesc(loc []byte) (int, error) { 410 if len(loc) == 0 { 411 return 0, errors.New("location description is empty") 412 } 413 414 // TODO: support the value in the register and the separated value. 415 switch loc[0] { 416 case dwarfOpCallFrameCFA: 417 return 0, nil 418 case dwarfOpFbreg: 419 return decodeSignedLEB128(loc[1:]), nil 420 default: 421 return 0, fmt.Errorf("unknown operation: %#x", loc[0]) 422 } 423 } 424 425 func (r subprogramReader) findLocationByLocationList(param *dwarf.Entry) (int, bool, error) { 426 loc, err := locationListClassAttr(param, dwarf.AttrLocation) 427 if err != nil { 428 return 0, false, fmt.Errorf("loc list attr not found: %v", err) 429 } 430 431 locList := buildLocationList(r.dwarfData.locationList, int(loc)) 432 if len(locList.locListEntries) == 0 { 433 return 0, false, errors.New("no location list entry") 434 } 435 436 // TODO: it's more precise to choose the right location list entry using PC and address offsets. 437 // Usually the first entry specifies to the right location in our use case, though. 438 offset, err := parseLocationDesc(locList.locListEntries[0].locationDesc) 439 if err != nil { 440 log.Debugf("failed to parse location list at %#x: %v", param.Offset, err) 441 } 442 return offset, err == nil, nil 443 } 444 445 type locationList struct { 446 baseAddress uint64 447 locListEntries []locationListEntry 448 } 449 450 type locationListEntry struct { 451 beginOffset, endOffset int 452 locationDesc []byte 453 } 454 455 func buildLocationList(locSectionData []byte, offset int) (locList locationList) { 456 for { 457 beginOffset := binary.LittleEndian.Uint64(locSectionData[offset : offset+8]) 458 offset += 8 459 endOffset := binary.LittleEndian.Uint64(locSectionData[offset : offset+8]) 460 offset += 8 461 if beginOffset == 0x0 && endOffset == 0x0 { 462 // end of list entry 463 break 464 } else if beginOffset == ^uint64(0) { 465 // base address selection entry 466 locList.baseAddress = endOffset 467 continue 468 } 469 470 // location list entry 471 locListEntry := locationListEntry{beginOffset: int(beginOffset), endOffset: int(endOffset)} 472 locationDescLen := int(binary.LittleEndian.Uint16(locSectionData[offset : offset+2])) 473 offset += 2 474 475 locListEntry.locationDesc = locSectionData[offset : offset+locationDescLen] 476 offset += locationDescLen 477 478 locList.locListEntries = append(locList.locListEntries, locListEntry) 479 } 480 return 481 } 482 483 func addressClassAttr(entry *dwarf.Entry, attrName dwarf.Attr) (uint64, error) { 484 field := entry.AttrField(attrName) 485 if field == nil { 486 return 0, errors.New("attr not found") 487 } 488 489 if field.Class != dwarf.ClassAddress { 490 return 0, fmt.Errorf("invalid class: %v", field.Class) 491 } 492 493 // https://golang.org/pkg/debug/dwarf/#Field 494 val := field.Val.(uint64) 495 return val, nil 496 } 497 498 func stringClassAttr(entry *dwarf.Entry, attrName dwarf.Attr) (string, error) { 499 field := entry.AttrField(attrName) 500 if field == nil { 501 return "", errors.New("attr not found") 502 } 503 504 if field.Class != dwarf.ClassString { 505 return "", fmt.Errorf("invalid class: %v", field.Class) 506 } 507 508 // https://golang.org/pkg/debug/dwarf/#Field 509 val := field.Val.(string) 510 return val, nil 511 } 512 513 func referenceClassAttr(entry *dwarf.Entry, attrName dwarf.Attr) (dwarf.Offset, error) { 514 field := entry.AttrField(attrName) 515 if field == nil { 516 return 0, errors.New("attr not found") 517 } 518 519 if field.Class != dwarf.ClassReference { 520 return 0, fmt.Errorf("invalid class: %v", field.Class) 521 } 522 523 // https://golang.org/pkg/debug/dwarf/#Field 524 val := field.Val.(dwarf.Offset) 525 return val, nil 526 } 527 528 func locationClassAttr(entry *dwarf.Entry, attrName dwarf.Attr) ([]byte, error) { 529 field := entry.AttrField(attrName) 530 if field == nil { 531 return nil, errors.New("attr not found") 532 } 533 534 if field.Class != dwarf.ClassExprLoc { 535 return nil, fmt.Errorf("invalid class: %v", field.Class) 536 } 537 538 // https://golang.org/pkg/debug/dwarf/#Field 539 val := field.Val.([]byte) 540 return val, nil 541 } 542 543 func locationListClassAttr(entry *dwarf.Entry, attrName dwarf.Attr) (int64, error) { 544 field := entry.AttrField(attrName) 545 if field == nil { 546 return 0, errors.New("attr not found") 547 } 548 549 if field.Class != dwarf.ClassLocListPtr { 550 return 0, fmt.Errorf("invalid class: %v", field.Class) 551 } 552 553 // https://golang.org/pkg/debug/dwarf/#Field 554 val := field.Val.(int64) 555 return val, nil 556 } 557 558 func flagClassAttr(entry *dwarf.Entry, attrName dwarf.Attr) (bool, error) { 559 field := entry.AttrField(attrName) 560 if field == nil { 561 return false, errors.New("attr not found") 562 } 563 564 if field.Class != dwarf.ClassFlag { 565 return false, fmt.Errorf("invalid class: %v", field.Class) 566 } 567 568 // https://golang.org/pkg/debug/dwarf/#Field 569 val := field.Val.(bool) 570 return val, nil 571 } 572 573 // walkUpOrigins follows the entry's origins until the walkFn returns true. 574 // 575 // It can find the DIE of the inlined instance from the DIE of the out-of-line instance (see the DWARF spec for the terminology). 576 func walkUpOrigins(entry *dwarf.Entry, dwarfData *dwarf.Data, walkFn func(*dwarf.Entry) bool) error { 577 if ok := walkFn(entry); ok { 578 return nil 579 } 580 581 origin := findAbstractOrigin(entry, dwarfData) 582 if origin == nil { 583 return errors.New("failed to find abstract origin") 584 } 585 586 return walkUpOrigins(origin, dwarfData, walkFn) 587 } 588 589 func findAbstractOrigin(entry *dwarf.Entry, dwarfData *dwarf.Data) *dwarf.Entry { 590 ref, err := referenceClassAttr(entry, dwarf.AttrAbstractOrigin) 591 if err != nil { 592 return nil 593 } 594 595 reader := dwarfData.Reader() 596 reader.Seek(ref) 597 originEntry, err := reader.Next() 598 if err != nil { 599 return nil 600 } 601 return originEntry 602 } 603 604 func decodeSignedLEB128(input []byte) (val int) { 605 var i int 606 for { 607 val |= int(input[i]) & 0x7F << (7 * uint(i)) 608 609 if input[i]>>7&0x1 == 0x0 { 610 break 611 } 612 i++ 613 } 614 615 if input[i]>>6&0x1 == 0x1 { 616 // negative value 617 return (^0)<<((uint(i)+1)*7) + val 618 } 619 return val 620 } 621 622 type symbol struct { 623 Name string 624 Value uint64 625 } 626 627 // nonDebuggableBinaryFile represents the binary file WITHOUT DWARF sections. 628 type nonDebuggableBinaryFile struct { 629 closer io.Closer 630 } 631 632 func newNonDebuggableBinaryFile(closer io.Closer) (nonDebuggableBinaryFile, error) { 633 return nonDebuggableBinaryFile{closer: closer}, nil 634 } 635 636 // FindFunction always returns error because it's difficult to get function info using non-DWARF binary. 637 func (b nonDebuggableBinaryFile) FindFunction(pc uint64) (*Function, error) { 638 return nil, errors.New("no DWARF info") 639 } 640 641 func (b nonDebuggableBinaryFile) Close() error { 642 return b.closer.Close() 643 } 644 645 func (b nonDebuggableBinaryFile) findDwarfTypeByAddr(typeAddr uint64) (dwarf.Type, error) { 646 return nil, errors.New("no DWARF info") 647 } 648 649 // Assume this dwarf.Type represents a subset of the module data type in the case DWARF is not available. 650 var moduleDataType = &dwarf.StructType{ 651 StructName: "runtime.moduledata", 652 CommonType: dwarf.CommonType{ByteSize: 456}, 653 Field: []*dwarf.StructField{ 654 &dwarf.StructField{ 655 Name: "pclntable", 656 Type: &dwarf.StructType{ 657 CommonType: dwarf.CommonType{ByteSize: 24}, 658 StructName: "[]uint8", 659 Field: []*dwarf.StructField{ 660 &dwarf.StructField{ 661 Name: "array", 662 Type: &dwarf.PtrType{ 663 CommonType: dwarf.CommonType{ByteSize: 8}, 664 Type: &dwarf.UintType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 1}}}, 665 }, 666 ByteOffset: 0, 667 }, 668 &dwarf.StructField{ 669 Name: "len", 670 Type: &dwarf.IntType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 8}}}, 671 ByteOffset: 8, 672 }, 673 }, 674 }, 675 ByteOffset: 0, 676 }, 677 &dwarf.StructField{ 678 Name: "ftab", 679 Type: &dwarf.StructType{ 680 CommonType: dwarf.CommonType{ByteSize: 24}, 681 StructName: "[]runtime.functab", 682 Field: []*dwarf.StructField{ 683 &dwarf.StructField{ 684 Name: "array", 685 Type: &dwarf.PtrType{ 686 CommonType: dwarf.CommonType{ByteSize: 8}, 687 Type: &dwarf.StructType{ 688 CommonType: dwarf.CommonType{ByteSize: 16}, 689 StructName: "runtime.functab", 690 Field: []*dwarf.StructField{ 691 &dwarf.StructField{ 692 Name: "entry", 693 Type: &dwarf.UintType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 8}}}, 694 ByteOffset: 0, 695 }, 696 &dwarf.StructField{ 697 Name: "funcoff", 698 Type: &dwarf.UintType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 8}}}, 699 ByteOffset: 8, 700 }, 701 }, 702 }, 703 }, 704 ByteOffset: 0, 705 }, 706 &dwarf.StructField{ 707 Name: "len", 708 Type: &dwarf.IntType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 8}}}, 709 ByteOffset: 8, 710 }, 711 }, 712 }, 713 ByteOffset: 24, 714 }, 715 &dwarf.StructField{ 716 Name: "findfunctab", 717 Type: &dwarf.UintType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 8}}}, 718 ByteOffset: 72, 719 }, 720 &dwarf.StructField{ 721 Name: "minpc", 722 Type: &dwarf.UintType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 8}}}, 723 ByteOffset: 80, 724 }, 725 &dwarf.StructField{ 726 Name: "maxpc", 727 Type: &dwarf.UintType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 8}}}, 728 ByteOffset: 88, 729 }, 730 &dwarf.StructField{ 731 Name: "types", 732 Type: &dwarf.UintType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 8}}}, 733 ByteOffset: 200, 734 }, 735 &dwarf.StructField{ 736 Name: "etypes", 737 Type: &dwarf.UintType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 8}}}, 738 ByteOffset: 208, 739 }, 740 &dwarf.StructField{ 741 Name: "next", 742 Type: &dwarf.PtrType{CommonType: dwarf.CommonType{ByteSize: 8}}, 743 ByteOffset: 448, 744 }, 745 }, 746 } 747 748 func (b nonDebuggableBinaryFile) moduleDataType() dwarf.Type { 749 return moduleDataType 750 } 751 752 // Assume this dwarf.Type represents a subset of the runtime.g type in the case DWARF is not available. 753 var runtimeGType = &dwarf.StructType{ 754 StructName: "runtime.moduledata", 755 CommonType: dwarf.CommonType{ByteSize: 456}, 756 Field: []*dwarf.StructField{ 757 &dwarf.StructField{ 758 Name: "stack", 759 Type: &dwarf.StructType{ 760 CommonType: dwarf.CommonType{ByteSize: 16}, 761 StructName: "runtime.stack", 762 Field: []*dwarf.StructField{ 763 &dwarf.StructField{ 764 Name: "lo", 765 Type: &dwarf.UintType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 8}}}, 766 ByteOffset: 0, 767 }, 768 &dwarf.StructField{ 769 Name: "hi", 770 Type: &dwarf.UintType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 8}}}, 771 ByteOffset: 8, 772 }, 773 }, 774 }, 775 ByteOffset: 0, 776 }, 777 &dwarf.StructField{ 778 Name: "_panic", 779 Type: &dwarf.PtrType{CommonType: dwarf.CommonType{ByteSize: 8}}, 780 ByteOffset: 32, 781 }, 782 &dwarf.StructField{ 783 Name: "_defer", 784 Type: &dwarf.PtrType{ 785 CommonType: dwarf.CommonType{ByteSize: 8}, 786 Type: &dwarf.StructType{ 787 CommonType: dwarf.CommonType{ByteSize: 48}, 788 StructName: "runtime._defer", 789 Field: []*dwarf.StructField{ 790 &dwarf.StructField{ 791 Name: "sp", 792 Type: &dwarf.UintType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 8}}}, 793 ByteOffset: 8, 794 }, 795 &dwarf.StructField{ 796 Name: "pc", 797 Type: &dwarf.UintType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 8}}}, 798 ByteOffset: 16, 799 }, 800 &dwarf.StructField{ 801 Name: "fn", 802 Type: &dwarf.PtrType{CommonType: dwarf.CommonType{ByteSize: 8}}, 803 ByteOffset: 24, 804 }, 805 &dwarf.StructField{ 806 Name: "_panic", 807 Type: &dwarf.PtrType{CommonType: dwarf.CommonType{ByteSize: 8}}, 808 ByteOffset: 32, 809 }, 810 &dwarf.StructField{ 811 Name: "link", 812 Type: &dwarf.PtrType{CommonType: dwarf.CommonType{ByteSize: 8}}, 813 ByteOffset: 40, 814 }, 815 }, 816 }, 817 }, 818 ByteOffset: 40, 819 }, 820 &dwarf.StructField{ 821 Name: "goid", 822 Type: &dwarf.IntType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 8}}}, 823 ByteOffset: 152, 824 }, 825 &dwarf.StructField{ 826 Name: "ancestors", 827 Type: &dwarf.PtrType{ 828 CommonType: dwarf.CommonType{ByteSize: 8}, 829 Type: &dwarf.StructType{ 830 CommonType: dwarf.CommonType{ByteSize: 24}, 831 StructName: "[]runtime.ancestorInfo", 832 Field: []*dwarf.StructField{ 833 &dwarf.StructField{ 834 Name: "array", 835 Type: &dwarf.PtrType{ 836 CommonType: dwarf.CommonType{ByteSize: 8}, 837 Type: &dwarf.StructType{ 838 CommonType: dwarf.CommonType{ByteSize: 40}, 839 StructName: "runtime.ancestorInfo", 840 Field: []*dwarf.StructField{ 841 &dwarf.StructField{ 842 Name: "goid", 843 Type: &dwarf.IntType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 8}}}, 844 ByteOffset: 24, 845 }, 846 }, 847 }, 848 }, 849 ByteOffset: 0, 850 }, 851 &dwarf.StructField{ 852 Name: "len", 853 Type: &dwarf.IntType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 8}}}, 854 ByteOffset: 8, 855 }, 856 }, 857 }, 858 }, 859 ByteOffset: 288, 860 }, 861 }, 862 } 863 864 func (b nonDebuggableBinaryFile) runtimeGType() dwarf.Type { 865 return runtimeGType 866 }