func FindFunc(fileName string, pc uint64) (s elf.Symbol, err error) { file, err := elf.Open(fileName) if err != nil { return elf.Symbol{}, err } symbols, err := file.Symbols() if err != nil { return elf.Symbol{}, err } funcSymbols := make(Symbols, 0) for _, symbol := range symbols { if elf.ST_TYPE(symbol.Info) == elf.STT_FUNC { funcSymbols = append(funcSymbols, symbol) } } n := len(funcSymbols) if n == 0 { return elf.Symbol{}, &ErrNoFunctions{} } sort.Sort(funcSymbols) i := sort.Search(n, func(i int) bool { return funcSymbols[i].Value >= pc }) if i != 0 || funcSymbols[i].Value <= pc { if i == n || (funcSymbols[i].Value != pc && i != 0) { i-- } return funcSymbols[i], nil } return elf.Symbol{}, &ErrFunctionNotFound{} }
func ldshlibsyms(shlib string) { found := false libpath := "" for _, libdir := range Ctxt.Libdir { libpath = filepath.Join(libdir, shlib) if _, err := os.Stat(libpath); err == nil { found = true break } } if !found { Diag("cannot find shared library: %s", shlib) return } for _, processedlib := range Ctxt.Shlibs { if processedlib.Path == libpath { return } } if Ctxt.Debugvlog > 1 && Ctxt.Bso != nil { fmt.Fprintf(Ctxt.Bso, "%5.2f ldshlibsyms: found library with name %s at %s\n", obj.Cputime(), shlib, libpath) Ctxt.Bso.Flush() } f, err := elf.Open(libpath) if err != nil { Diag("cannot open shared library: %s", libpath) return } defer f.Close() syms, err := f.Symbols() if err != nil { Diag("cannot read symbols from shared library: %s", libpath) return } // If a package has a global variable of a type defined in another shared // library, we need to know the gcmask used by the type, if any. To support // this, we read all the runtime.gcbits.* symbols, keep a map of address to // gcmask, and after we're read all the symbols, read the addresses of the // gcmasks symbols out of the type data to look up the gcmask for each type. // This depends on the fact that the runtime.gcbits.* symbols are local (so // the address is actually present in the type data and we don't have to // search all relocations to find the ones which correspond to gcmasks) and // also that the shared library we are linking against has not had the symbol // table removed. gcmasks := make(map[uint64][]byte) types := []*LSym{} var hash []byte for _, s := range syms { if elf.ST_TYPE(s.Info) == elf.STT_NOTYPE || elf.ST_TYPE(s.Info) == elf.STT_SECTION { continue } if s.Section == elf.SHN_UNDEF { continue } if strings.HasPrefix(s.Name, "_") { continue } if strings.HasPrefix(s.Name, "runtime.gcbits.") { gcmasks[s.Value] = readelfsymboldata(f, &s) } if s.Name == "go.link.abihashbytes" { hash = readelfsymboldata(f, &s) } if elf.ST_BIND(s.Info) != elf.STB_GLOBAL { continue } lsym := Linklookup(Ctxt, s.Name, 0) if lsym.Type != 0 && lsym.Dupok == 0 { Diag( "Found duplicate symbol %s reading from %s, first found in %s", s.Name, shlib, lsym.File) } lsym.Type = obj.SDYNIMPORT lsym.ElfType = elf.ST_TYPE(s.Info) lsym.File = libpath if strings.HasPrefix(lsym.Name, "type.") { if f.Sections[s.Section].Type == elf.SHT_PROGBITS { lsym.P = readelfsymboldata(f, &s) } if !strings.HasPrefix(lsym.Name, "type..") { types = append(types, lsym) } } } for _, t := range types { if decodetype_noptr(t) != 0 || decodetype_usegcprog(t) != 0 { continue } addr := decodetype_gcprog_shlib(t) tgcmask, ok := gcmasks[addr] if !ok { Diag("bits not found for %s at %d", t.Name, addr) } t.gcmask = tgcmask } // We might have overwritten some functions above (this tends to happen for the // autogenerated type equality/hashing functions) and we don't want to generated // pcln table entries for these any more so unstitch them from the Textp linked // list. var last *LSym for s := Ctxt.Textp; s != nil; s = s.Next { if s.Type == obj.SDYNIMPORT { continue } if last == nil { Ctxt.Textp = s } else { last.Next = s } last = s } if last == nil { Ctxt.Textp = nil Ctxt.Etextp = nil } else { last.Next = nil Ctxt.Etextp = last } Ctxt.Shlibs = append(Ctxt.Shlibs, Shlib{Path: libpath, Hash: hash}) }
func ldshlibsyms(shlib string) { libpath := findshlib(shlib) if libpath == "" { return } for _, processedlib := range Ctxt.Shlibs { if processedlib.Path == libpath { return } } if Ctxt.Debugvlog > 1 && Ctxt.Bso != nil { fmt.Fprintf(Ctxt.Bso, "%5.2f ldshlibsyms: found library with name %s at %s\n", obj.Cputime(), shlib, libpath) Ctxt.Bso.Flush() } f, err := elf.Open(libpath) if err != nil { Diag("cannot open shared library: %s", libpath) return } hash, err := readnote(f, ELF_NOTE_GO_NAME, ELF_NOTE_GOABIHASH_TAG) if err != nil { Diag("cannot read ABI hash from shared library %s: %v", libpath, err) return } depsbytes, err := readnote(f, ELF_NOTE_GO_NAME, ELF_NOTE_GODEPS_TAG) if err != nil { Diag("cannot read dep list from shared library %s: %v", libpath, err) return } deps := strings.Split(string(depsbytes), "\n") syms, err := f.DynamicSymbols() if err != nil { Diag("cannot read symbols from shared library: %s", libpath) return } for _, elfsym := range syms { if elf.ST_TYPE(elfsym.Info) == elf.STT_NOTYPE || elf.ST_TYPE(elfsym.Info) == elf.STT_SECTION { continue } lsym := Linklookup(Ctxt, elfsym.Name, 0) if lsym.Type != 0 && lsym.Type != obj.SDYNIMPORT && lsym.Dupok == 0 { if (lsym.Type != obj.SBSS && lsym.Type != obj.SNOPTRBSS) || len(lsym.R) != 0 || len(lsym.P) != 0 || f.Sections[elfsym.Section].Type != elf.SHT_NOBITS { Diag("Found duplicate symbol %s reading from %s, first found in %s", elfsym.Name, shlib, lsym.File) } if lsym.Size > int64(elfsym.Size) { // If the existing symbol is a BSS value that is // larger than the one read from the shared library, // keep references to that. Conversely, if the // version from the shared libray is larger, we want // to make all references be to that. continue } } lsym.Type = obj.SDYNIMPORT lsym.ElfType = elf.ST_TYPE(elfsym.Info) lsym.Size = int64(elfsym.Size) if elfsym.Section != elf.SHN_UNDEF { // Set .File for the library that actually defines the symbol. lsym.File = libpath // The decodetype_* functions in decodetype.go need access to // the type data. if strings.HasPrefix(lsym.Name, "type.") && !strings.HasPrefix(lsym.Name, "type..") { lsym.P = readelfsymboldata(f, &elfsym) } } } // We might have overwritten some functions above (this tends to happen for the // autogenerated type equality/hashing functions) and we don't want to generated // pcln table entries for these any more so unstitch them from the Textp linked // list. var last *LSym for s := Ctxt.Textp; s != nil; s = s.Next { if s.Type == obj.SDYNIMPORT { continue } if last == nil { Ctxt.Textp = s } else { last.Next = s } last = s } if last == nil { Ctxt.Textp = nil Ctxt.Etextp = nil } else { last.Next = nil Ctxt.Etextp = last } Ctxt.Shlibs = append(Ctxt.Shlibs, Shlib{Path: libpath, Hash: hash, Deps: deps, File: f}) }
func ldshlibsyms(shlib string) { found := false libpath := "" for _, libdir := range Ctxt.Libdir { libpath = filepath.Join(libdir, shlib) if _, err := os.Stat(libpath); err == nil { found = true break } } if !found { Diag("cannot find shared library: %s", shlib) return } for _, processedname := range Ctxt.Shlibs { if processedname == libpath { return } } if Ctxt.Debugvlog > 1 && Ctxt.Bso != nil { fmt.Fprintf(Ctxt.Bso, "%5.2f ldshlibsyms: found library with name %s at %s\n", obj.Cputime(), shlib, libpath) Bflush(Ctxt.Bso) } f, err := elf.Open(libpath) if err != nil { Diag("cannot open shared library: %s", libpath) return } defer f.Close() syms, err := f.DynamicSymbols() if err != nil { Diag("cannot read symbols from shared library: %s", libpath) return } for _, s := range syms { if elf.ST_TYPE(s.Info) == elf.STT_NOTYPE || elf.ST_TYPE(s.Info) == elf.STT_SECTION { continue } if s.Section == elf.SHN_UNDEF { continue } if strings.HasPrefix(s.Name, "_") { continue } lsym := Linklookup(Ctxt, s.Name, 0) if lsym.Type != 0 && lsym.Dupok == 0 { Diag( "Found duplicate symbol %s reading from %s, first found in %s", s.Name, shlib, lsym.File) } lsym.Type = SDYNIMPORT lsym.File = libpath } // We might have overwritten some functions above (this tends to happen for the // autogenerated type equality/hashing functions) and we don't want to generated // pcln table entries for these any more so unstitch them from the Textp linked // list. var last *LSym for s := Ctxt.Textp; s != nil; s = s.Next { if s.Type == SDYNIMPORT { continue } if last == nil { Ctxt.Textp = s } else { last.Next = s } last = s } if last == nil { Ctxt.Textp = nil Ctxt.Etextp = nil } else { last.Next = nil Ctxt.Etextp = last } Ctxt.Shlibs = append(Ctxt.Shlibs, libpath) }