github.com/ader1990/go@v0.0.0-20140630135419-8c24447fa791/src/cmd/nm/debug_goobj.go (about) 1 // DO NOT EDIT. Generated by code.google.com/p/rsc/cmd/bundle 2 // bundle -p main -x goobj_ debug/goobj 3 4 /* read.go */ 5 6 // Copyright 2013 The Go Authors. All rights reserved. 7 // Use of this source code is governed by a BSD-style 8 // license that can be found in the LICENSE file. 9 10 // Package goobj implements reading of Go object files and archives. 11 // 12 // TODO(rsc): Decide where this package should live. (golang.org/issue/6932) 13 // TODO(rsc): Decide the appropriate integer types for various fields. 14 // TODO(rsc): Write tests. (File format still up in the air a little.) 15 16 package main 17 18 import ( 19 "bufio" 20 "bytes" 21 "errors" 22 "fmt" 23 "io" 24 "strconv" 25 "strings" 26 ) 27 28 // A SymKind describes the kind of memory represented by a symbol. 29 type goobj_SymKind int 30 31 // This list is taken from include/link.h. 32 33 // Defined SymKind values. 34 // TODO(rsc): Give idiomatic Go names. 35 // TODO(rsc): Reduce the number of symbol types in the object files. 36 const ( 37 _ goobj_SymKind = iota 38 39 // readonly, executable 40 goobj_STEXT 41 goobj_SELFRXSECT 42 43 // readonly, non-executable 44 goobj_STYPE 45 goobj_SSTRING 46 goobj_SGOSTRING 47 goobj_SGOFUNC 48 goobj_SRODATA 49 goobj_SFUNCTAB 50 goobj_STYPELINK 51 goobj_SSYMTAB // TODO: move to unmapped section 52 goobj_SPCLNTAB 53 goobj_SELFROSECT 54 55 // writable, non-executable 56 goobj_SMACHOPLT 57 goobj_SELFSECT 58 goobj_SMACHO // Mach-O __nl_symbol_ptr 59 goobj_SMACHOGOT 60 goobj_SNOPTRDATA 61 goobj_SINITARR 62 goobj_SDATA 63 goobj_SWINDOWS 64 goobj_SBSS 65 goobj_SNOPTRBSS 66 goobj_STLSBSS 67 68 // not mapped 69 goobj_SXREF 70 goobj_SMACHOSYMSTR 71 goobj_SMACHOSYMTAB 72 goobj_SMACHOINDIRECTPLT 73 goobj_SMACHOINDIRECTGOT 74 goobj_SFILE 75 goobj_SFILEPATH 76 goobj_SCONST 77 goobj_SDYNIMPORT 78 goobj_SHOSTOBJ 79 ) 80 81 var goobj_symKindStrings = []string{ 82 goobj_SBSS: "SBSS", 83 goobj_SCONST: "SCONST", 84 goobj_SDATA: "SDATA", 85 goobj_SDYNIMPORT: "SDYNIMPORT", 86 goobj_SELFROSECT: "SELFROSECT", 87 goobj_SELFRXSECT: "SELFRXSECT", 88 goobj_SELFSECT: "SELFSECT", 89 goobj_SFILE: "SFILE", 90 goobj_SFILEPATH: "SFILEPATH", 91 goobj_SFUNCTAB: "SFUNCTAB", 92 goobj_SGOFUNC: "SGOFUNC", 93 goobj_SGOSTRING: "SGOSTRING", 94 goobj_SHOSTOBJ: "SHOSTOBJ", 95 goobj_SINITARR: "SINITARR", 96 goobj_SMACHO: "SMACHO", 97 goobj_SMACHOGOT: "SMACHOGOT", 98 goobj_SMACHOINDIRECTGOT: "SMACHOINDIRECTGOT", 99 goobj_SMACHOINDIRECTPLT: "SMACHOINDIRECTPLT", 100 goobj_SMACHOPLT: "SMACHOPLT", 101 goobj_SMACHOSYMSTR: "SMACHOSYMSTR", 102 goobj_SMACHOSYMTAB: "SMACHOSYMTAB", 103 goobj_SNOPTRBSS: "SNOPTRBSS", 104 goobj_SNOPTRDATA: "SNOPTRDATA", 105 goobj_SPCLNTAB: "SPCLNTAB", 106 goobj_SRODATA: "SRODATA", 107 goobj_SSTRING: "SSTRING", 108 goobj_SSYMTAB: "SSYMTAB", 109 goobj_STEXT: "STEXT", 110 goobj_STLSBSS: "STLSBSS", 111 goobj_STYPE: "STYPE", 112 goobj_STYPELINK: "STYPELINK", 113 goobj_SWINDOWS: "SWINDOWS", 114 goobj_SXREF: "SXREF", 115 } 116 117 func (k goobj_SymKind) String() string { 118 if k < 0 || int(k) >= len(goobj_symKindStrings) { 119 return fmt.Sprintf("SymKind(%d)", k) 120 } 121 return goobj_symKindStrings[k] 122 } 123 124 // A Sym is a named symbol in an object file. 125 type goobj_Sym struct { 126 goobj_SymID // symbol identifier (name and version) 127 Kind goobj_SymKind // kind of symbol 128 DupOK bool // are duplicate definitions okay? 129 Size int // size of corresponding data 130 Type goobj_SymID // symbol for Go type information 131 Data goobj_Data // memory image of symbol 132 Reloc []goobj_Reloc // relocations to apply to Data 133 Func *goobj_Func // additional data for functions 134 } 135 136 // A SymID - the combination of Name and Version - uniquely identifies 137 // a symbol within a package. 138 type goobj_SymID struct { 139 // Name is the name of a symbol. 140 Name string 141 142 // Version is zero for symbols with global visibility. 143 // Symbols with only file visibility (such as file-level static 144 // declarations in C) have a non-zero version distinguishing 145 // a symbol in one file from a symbol of the same name 146 // in another file 147 Version int 148 } 149 150 func (s goobj_SymID) String() string { 151 if s.Version == 0 { 152 return s.Name 153 } 154 return fmt.Sprintf("%s<%d>", s.Name, s.Version) 155 } 156 157 // A Data is a reference to data stored in an object file. 158 // It records the offset and size of the data, so that a client can 159 // read the data only if necessary. 160 type goobj_Data struct { 161 Offset int64 162 Size int64 163 } 164 165 // A Reloc describes a relocation applied to a memory image to refer 166 // to an address within a particular symbol. 167 type goobj_Reloc struct { 168 // The bytes at [Offset, Offset+Size) within the memory image 169 // should be updated to refer to the address Add bytes after the start 170 // of the symbol Sym. 171 Offset int 172 Size int 173 Sym goobj_SymID 174 Add int 175 176 // The Type records the form of address expected in the bytes 177 // described by the previous fields: absolute, PC-relative, and so on. 178 // TODO(rsc): The interpretation of Type is not exposed by this package. 179 Type int 180 } 181 182 // A Var describes a variable in a function stack frame: a declared 183 // local variable, an input argument, or an output result. 184 type goobj_Var struct { 185 // The combination of Name, Kind, and Offset uniquely 186 // identifies a variable in a function stack frame. 187 // Using fewer of these - in particular, using only Name - does not. 188 Name string // Name of variable. 189 Kind int // TODO(rsc): Define meaning. 190 Offset int // Frame offset. TODO(rsc): Define meaning. 191 192 Type goobj_SymID // Go type for variable. 193 } 194 195 // Func contains additional per-symbol information specific to functions. 196 type goobj_Func struct { 197 Args int // size in bytes of argument frame: inputs and outputs 198 Frame int // size in bytes of local variable frame 199 Leaf bool // function omits save of link register (ARM) 200 NoSplit bool // function omits stack split prologue 201 Var []goobj_Var // detail about local variables 202 PCSP goobj_Data // PC → SP offset map 203 PCFile goobj_Data // PC → file number map (index into File) 204 PCLine goobj_Data // PC → line number map 205 PCData []goobj_Data // PC → runtime support data map 206 FuncData []goobj_FuncData // non-PC-specific runtime support data 207 File []string // paths indexed by PCFile 208 } 209 210 // TODO: Add PCData []byte and PCDataIter (similar to liblink). 211 212 // A FuncData is a single function-specific data value. 213 type goobj_FuncData struct { 214 Sym goobj_SymID // symbol holding data 215 Offset int64 // offset into symbol for funcdata pointer 216 } 217 218 // A Package is a parsed Go object file or archive defining a Go package. 219 type goobj_Package struct { 220 ImportPath string // import path denoting this package 221 Imports []string // packages imported by this package 222 Syms []*goobj_Sym // symbols defined by this package 223 MaxVersion int // maximum Version in any SymID in Syms 224 } 225 226 var ( 227 goobj_archiveHeader = []byte("!<arch>\n") 228 goobj_archiveMagic = []byte("`\n") 229 goobj_goobjHeader = []byte("go objec") // truncated to size of archiveHeader 230 231 goobj_errCorruptArchive = errors.New("corrupt archive") 232 goobj_errTruncatedArchive = errors.New("truncated archive") 233 goobj_errNotArchive = errors.New("unrecognized archive format") 234 235 goobj_errCorruptObject = errors.New("corrupt object file") 236 goobj_errTruncatedObject = errors.New("truncated object file") 237 goobj_errNotObject = errors.New("unrecognized object file format") 238 ) 239 240 // An objReader is an object file reader. 241 type goobj_objReader struct { 242 p *goobj_Package 243 b *bufio.Reader 244 f io.ReadSeeker 245 err error 246 offset int64 247 limit int64 248 tmp [256]byte 249 pkg string 250 pkgprefix string 251 } 252 253 // importPathToPrefix returns the prefix that will be used in the 254 // final symbol table for the given import path. 255 // We escape '%', '"', all control characters and non-ASCII bytes, 256 // and any '.' after the final slash. 257 // 258 // See ../../../cmd/ld/lib.c:/^pathtoprefix and 259 // ../../../cmd/gc/subr.c:/^pathtoprefix. 260 func goobj_importPathToPrefix(s string) string { 261 // find index of last slash, if any, or else -1. 262 // used for determining whether an index is after the last slash. 263 slash := strings.LastIndex(s, "/") 264 265 // check for chars that need escaping 266 n := 0 267 for r := 0; r < len(s); r++ { 268 if c := s[r]; c <= ' ' || (c == '.' && r > slash) || c == '%' || c == '"' || c >= 0x7F { 269 n++ 270 } 271 } 272 273 // quick exit 274 if n == 0 { 275 return s 276 } 277 278 // escape 279 const hex = "0123456789abcdef" 280 p := make([]byte, 0, len(s)+2*n) 281 for r := 0; r < len(s); r++ { 282 if c := s[r]; c <= ' ' || (c == '.' && r > slash) || c == '%' || c == '"' || c >= 0x7F { 283 p = append(p, '%', hex[c>>4], hex[c&0xF]) 284 } else { 285 p = append(p, c) 286 } 287 } 288 289 return string(p) 290 } 291 292 // init initializes r to read package p from f. 293 func (r *goobj_objReader) init(f io.ReadSeeker, p *goobj_Package) { 294 r.f = f 295 r.p = p 296 r.offset, _ = f.Seek(0, 1) 297 r.limit, _ = f.Seek(0, 2) 298 f.Seek(r.offset, 0) 299 r.b = bufio.NewReader(f) 300 r.pkgprefix = goobj_importPathToPrefix(p.ImportPath) + "." 301 } 302 303 // error records that an error occurred. 304 // It returns only the first error, so that an error 305 // caused by an earlier error does not discard information 306 // about the earlier error. 307 func (r *goobj_objReader) error(err error) error { 308 if r.err == nil { 309 if err == io.EOF { 310 err = io.ErrUnexpectedEOF 311 } 312 r.err = err 313 } 314 // panic("corrupt") // useful for debugging 315 return r.err 316 } 317 318 // readByte reads and returns a byte from the input file. 319 // On I/O error or EOF, it records the error but returns byte 0. 320 // A sequence of 0 bytes will eventually terminate any 321 // parsing state in the object file. In particular, it ends the 322 // reading of a varint. 323 func (r *goobj_objReader) readByte() byte { 324 if r.err != nil { 325 return 0 326 } 327 if r.offset >= r.limit { 328 r.error(io.ErrUnexpectedEOF) 329 return 0 330 } 331 b, err := r.b.ReadByte() 332 if err != nil { 333 if err == io.EOF { 334 err = io.ErrUnexpectedEOF 335 } 336 r.error(err) 337 b = 0 338 } else { 339 r.offset++ 340 } 341 return b 342 } 343 344 // read reads exactly len(b) bytes from the input file. 345 // If an error occurs, read returns the error but also 346 // records it, so it is safe for callers to ignore the result 347 // as long as delaying the report is not a problem. 348 func (r *goobj_objReader) readFull(b []byte) error { 349 if r.err != nil { 350 return r.err 351 } 352 if r.offset+int64(len(b)) > r.limit { 353 return r.error(io.ErrUnexpectedEOF) 354 } 355 n, err := io.ReadFull(r.b, b) 356 r.offset += int64(n) 357 if err != nil { 358 return r.error(err) 359 } 360 return nil 361 } 362 363 // readInt reads a zigzag varint from the input file. 364 func (r *goobj_objReader) readInt() int { 365 var u uint64 366 367 for shift := uint(0); ; shift += 7 { 368 if shift >= 64 { 369 r.error(goobj_errCorruptObject) 370 return 0 371 } 372 c := r.readByte() 373 u |= uint64(c&0x7F) << shift 374 if c&0x80 == 0 { 375 break 376 } 377 } 378 379 v := int64(u>>1) ^ (int64(u) << 63 >> 63) 380 if int64(int(v)) != v { 381 r.error(goobj_errCorruptObject) // TODO 382 return 0 383 } 384 return int(v) 385 } 386 387 // readString reads a length-delimited string from the input file. 388 func (r *goobj_objReader) readString() string { 389 n := r.readInt() 390 buf := make([]byte, n) 391 r.readFull(buf) 392 return string(buf) 393 } 394 395 // readSymID reads a SymID from the input file. 396 func (r *goobj_objReader) readSymID() goobj_SymID { 397 name, vers := r.readString(), r.readInt() 398 399 // In a symbol name in an object file, "". denotes the 400 // prefix for the package in which the object file has been found. 401 // Expand it. 402 name = strings.Replace(name, `"".`, r.pkgprefix, -1) 403 404 // An individual object file only records version 0 (extern) or 1 (static). 405 // To make static symbols unique across all files being read, we 406 // replace version 1 with the version corresponding to the current 407 // file number. The number is incremented on each call to parseObject. 408 if vers != 0 { 409 vers = r.p.MaxVersion 410 } 411 412 return goobj_SymID{name, vers} 413 } 414 415 // readData reads a data reference from the input file. 416 func (r *goobj_objReader) readData() goobj_Data { 417 n := r.readInt() 418 d := goobj_Data{Offset: r.offset, Size: int64(n)} 419 r.skip(int64(n)) 420 return d 421 } 422 423 // skip skips n bytes in the input. 424 func (r *goobj_objReader) skip(n int64) { 425 if n < 0 { 426 r.error(fmt.Errorf("debug/goobj: internal error: misuse of skip")) 427 } 428 if n < int64(len(r.tmp)) { 429 // Since the data is so small, a just reading from the buffered 430 // reader is better than flushing the buffer and seeking. 431 r.readFull(r.tmp[:n]) 432 } else if n <= int64(r.b.Buffered()) { 433 // Even though the data is not small, it has already been read. 434 // Advance the buffer instead of seeking. 435 for n > int64(len(r.tmp)) { 436 r.readFull(r.tmp[:]) 437 n -= int64(len(r.tmp)) 438 } 439 r.readFull(r.tmp[:n]) 440 } else { 441 // Seek, giving up buffered data. 442 _, err := r.f.Seek(r.offset+n, 0) 443 if err != nil { 444 r.error(err) 445 } 446 r.offset += n 447 r.b.Reset(r.f) 448 } 449 } 450 451 // Parse parses an object file or archive from r, 452 // assuming that its import path is pkgpath. 453 func goobj_Parse(r io.ReadSeeker, pkgpath string) (*goobj_Package, error) { 454 if pkgpath == "" { 455 pkgpath = `""` 456 } 457 p := new(goobj_Package) 458 p.ImportPath = pkgpath 459 460 var rd goobj_objReader 461 rd.init(r, p) 462 err := rd.readFull(rd.tmp[:8]) 463 if err != nil { 464 if err == io.EOF { 465 err = io.ErrUnexpectedEOF 466 } 467 return nil, err 468 } 469 470 switch { 471 default: 472 return nil, goobj_errNotObject 473 474 case bytes.Equal(rd.tmp[:8], goobj_archiveHeader): 475 if err := rd.parseArchive(); err != nil { 476 return nil, err 477 } 478 case bytes.Equal(rd.tmp[:8], goobj_goobjHeader): 479 if err := rd.parseObject(goobj_goobjHeader); err != nil { 480 return nil, err 481 } 482 } 483 484 return p, nil 485 } 486 487 // trimSpace removes trailing spaces from b and returns the corresponding string. 488 // This effectively parses the form used in archive headers. 489 func goobj_trimSpace(b []byte) string { 490 return string(bytes.TrimRight(b, " ")) 491 } 492 493 // parseArchive parses a Unix archive of Go object files. 494 // TODO(rsc): Need to skip non-Go object files. 495 // TODO(rsc): Maybe record table of contents in r.p so that 496 // linker can avoid having code to parse archives too. 497 func (r *goobj_objReader) parseArchive() error { 498 for r.offset < r.limit { 499 if err := r.readFull(r.tmp[:60]); err != nil { 500 return err 501 } 502 data := r.tmp[:60] 503 504 // Each file is preceded by this text header (slice indices in first column): 505 // 0:16 name 506 // 16:28 date 507 // 28:34 uid 508 // 34:40 gid 509 // 40:48 mode 510 // 48:58 size 511 // 58:60 magic - `\n 512 // We only care about name, size, and magic. 513 // The fields are space-padded on the right. 514 // The size is in decimal. 515 // The file data - size bytes - follows the header. 516 // Headers are 2-byte aligned, so if size is odd, an extra padding 517 // byte sits between the file data and the next header. 518 // The file data that follows is padded to an even number of bytes: 519 // if size is odd, an extra padding byte is inserted betw the next header. 520 if len(data) < 60 { 521 return goobj_errTruncatedArchive 522 } 523 if !bytes.Equal(data[58:60], goobj_archiveMagic) { 524 return goobj_errCorruptArchive 525 } 526 name := goobj_trimSpace(data[0:16]) 527 size, err := strconv.ParseInt(goobj_trimSpace(data[48:58]), 10, 64) 528 if err != nil { 529 return goobj_errCorruptArchive 530 } 531 data = data[60:] 532 fsize := size + size&1 533 if fsize < 0 || fsize < size { 534 return goobj_errCorruptArchive 535 } 536 switch name { 537 case "__.SYMDEF", "__.GOSYMDEF", "__.PKGDEF": 538 r.skip(size) 539 default: 540 oldLimit := r.limit 541 r.limit = r.offset + size 542 if err := r.parseObject(nil); err != nil { 543 return fmt.Errorf("parsing archive member %q: %v", name, err) 544 } 545 r.skip(r.limit - r.offset) 546 r.limit = oldLimit 547 } 548 if size&1 != 0 { 549 r.skip(1) 550 } 551 } 552 return nil 553 } 554 555 // parseObject parses a single Go object file. 556 // The prefix is the bytes already read from the file, 557 // typically in order to detect that this is an object file. 558 // The object file consists of a textual header ending in "\n!\n" 559 // and then the part we want to parse begins. 560 // The format of that part is defined in a comment at the top 561 // of src/liblink/objfile.c. 562 func (r *goobj_objReader) parseObject(prefix []byte) error { 563 // TODO(rsc): Maybe use prefix and the initial input to 564 // record the header line from the file, which would 565 // give the architecture and other version information. 566 567 r.p.MaxVersion++ 568 var c1, c2, c3 byte 569 for { 570 c1, c2, c3 = c2, c3, r.readByte() 571 if c3 == 0 { // NUL or EOF, either is bad 572 return goobj_errCorruptObject 573 } 574 if c1 == '\n' && c2 == '!' && c3 == '\n' { 575 break 576 } 577 } 578 579 r.readFull(r.tmp[:8]) 580 if !bytes.Equal(r.tmp[:8], []byte("\x00\x00go13ld")) { 581 return r.error(goobj_errCorruptObject) 582 } 583 584 b := r.readByte() 585 if b != 1 { 586 return r.error(goobj_errCorruptObject) 587 } 588 589 // Direct package dependencies. 590 for { 591 s := r.readString() 592 if s == "" { 593 break 594 } 595 r.p.Imports = append(r.p.Imports, s) 596 } 597 598 // Symbols. 599 for { 600 if b := r.readByte(); b != 0xfe { 601 if b != 0xff { 602 return r.error(goobj_errCorruptObject) 603 } 604 break 605 } 606 607 typ := r.readInt() 608 s := &goobj_Sym{goobj_SymID: r.readSymID()} 609 r.p.Syms = append(r.p.Syms, s) 610 s.Kind = goobj_SymKind(typ) 611 s.DupOK = r.readInt() != 0 612 s.Size = r.readInt() 613 s.Type = r.readSymID() 614 s.Data = r.readData() 615 s.Reloc = make([]goobj_Reloc, r.readInt()) 616 for i := range s.Reloc { 617 rel := &s.Reloc[i] 618 rel.Offset = r.readInt() 619 rel.Size = r.readInt() 620 rel.Type = r.readInt() 621 rel.Add = r.readInt() 622 r.readInt() // Xadd - ignored 623 rel.Sym = r.readSymID() 624 r.readSymID() // Xsym - ignored 625 } 626 627 if s.Kind == goobj_STEXT { 628 f := new(goobj_Func) 629 s.Func = f 630 f.Args = r.readInt() 631 f.Frame = r.readInt() 632 f.Leaf = r.readInt() != 0 633 f.NoSplit = r.readInt() != 0 634 f.Var = make([]goobj_Var, r.readInt()) 635 for i := range f.Var { 636 v := &f.Var[i] 637 v.Name = r.readSymID().Name 638 v.Offset = r.readInt() 639 v.Kind = r.readInt() 640 v.Type = r.readSymID() 641 } 642 643 f.PCSP = r.readData() 644 f.PCFile = r.readData() 645 f.PCLine = r.readData() 646 f.PCData = make([]goobj_Data, r.readInt()) 647 for i := range f.PCData { 648 f.PCData[i] = r.readData() 649 } 650 f.FuncData = make([]goobj_FuncData, r.readInt()) 651 for i := range f.FuncData { 652 f.FuncData[i].Sym = r.readSymID() 653 } 654 for i := range f.FuncData { 655 f.FuncData[i].Offset = int64(r.readInt()) // TODO 656 } 657 f.File = make([]string, r.readInt()) 658 for i := range f.File { 659 f.File[i] = r.readSymID().Name 660 } 661 } 662 } 663 664 r.readFull(r.tmp[:7]) 665 if !bytes.Equal(r.tmp[:7], []byte("\xffgo13ld")) { 666 return r.error(goobj_errCorruptObject) 667 } 668 669 return nil 670 }