func main() { f, err := os.Open(os.Args[1]) if err != nil { log.Fatal(err) } pkg, err := goobj.Parse(f, "main") if err != nil { log.Fatal(err) } js, err := json.MarshalIndent(pkg, "", "\t") if err != nil { log.Fatal(err) } os.Stdout.WriteString(string(js) + "\n") }
func goobjSymbols(f *os.File) []Sym { pkg, err := goobj.Parse(f, `""`) if err != nil { errorf("parsing %s: %v", f.Name(), err) return nil } seen := make(map[goobj.SymID]bool) var syms []Sym for _, s := range pkg.Syms { seen[s.SymID] = true sym := Sym{Addr: uint64(s.Data.Offset), Name: goobjName(s.SymID), Size: int64(s.Size), Type: s.Type.Name, Code: '?'} switch s.Kind { case goobj.STEXT, goobj.SELFRXSECT: sym.Code = 'T' case goobj.STYPE, goobj.SSTRING, goobj.SGOSTRING, goobj.SGOFUNC, goobj.SRODATA, goobj.SFUNCTAB, goobj.STYPELINK, goobj.SSYMTAB, goobj.SPCLNTAB, goobj.SELFROSECT: sym.Code = 'R' case goobj.SMACHOPLT, goobj.SELFSECT, goobj.SMACHO, goobj.SMACHOGOT, goobj.SNOPTRDATA, goobj.SINITARR, goobj.SDATA, goobj.SWINDOWS: sym.Code = 'D' case goobj.SBSS, goobj.SNOPTRBSS, goobj.STLSBSS: sym.Code = 'B' case goobj.SXREF, goobj.SMACHOSYMSTR, goobj.SMACHOSYMTAB, goobj.SMACHOINDIRECTPLT, goobj.SMACHOINDIRECTGOT, goobj.SFILE, goobj.SFILEPATH, goobj.SCONST, goobj.SDYNIMPORT, goobj.SHOSTOBJ: sym.Code = 'X' // should not see } if s.Version != 0 { sym.Code += 'a' - 'A' } syms = append(syms, sym) } for _, s := range pkg.Syms { for _, r := range s.Reloc { if !seen[r.Sym] { seen[r.Sym] = true sym := Sym{Name: goobjName(r.Sym), Code: 'U'} if s.Version != 0 { // should not happen but handle anyway sym.Code = 'u' } syms = append(syms, sym) } } } return syms }
// scanFile reads file to learn about the package with the given import path. func (p *Prog) scanFile(pkgpath string, file string) { pkg := &Package{ File: file, } p.Packages[pkgpath] = pkg f, err := os.Open(file) if err != nil { p.errorf("%v", err) return } gp, err := goobj.Parse(f, pkgpath) f.Close() if err != nil { p.errorf("reading %s: %v", file, err) return } // TODO(rsc): Change debug/goobj to record package name as gp.Name. // TODO(rsc): If pkgpath == "main", check that gp.Name == "main". pkg.Package = gp for _, gs := range gp.Syms { // TODO(rsc): Fix file format instead of this workaround. if gs.Data.Size > 0 { switch gs.Kind { case goobj.SBSS: gs.Kind = goobj.SDATA case goobj.SNOPTRBSS: gs.Kind = goobj.SNOPTRDATA } } if gs.Version != 0 { gs.Version += p.MaxVersion } for i := range gs.Reloc { r := &gs.Reloc[i] if r.Sym.Version != 0 { r.Sym.Version += p.MaxVersion } if p.Syms[r.Sym] == nil { p.Missing[r.Sym] = true } } if gs.Func != nil { for i := range gs.Func.FuncData { fdata := &gs.Func.FuncData[i] if fdata.Sym.Name != "" { if fdata.Sym.Version != 0 { fdata.Sym.Version += p.MaxVersion } if p.Syms[fdata.Sym] == nil { p.Missing[fdata.Sym] = true } } } } if old := p.Syms[gs.SymID]; old != nil { // Duplicate definition of symbol. Is it okay? // TODO(rsc): Write test for this code. switch { // If both symbols are BSS (no data), take max of sizes // but otherwise ignore second symbol. case old.Data.Size == 0 && gs.Data.Size == 0: if old.Size < gs.Size { old.Size = gs.Size } continue // If one is in BSS and one is not, use the one that is not. case old.Data.Size > 0 && gs.Data.Size == 0: continue case gs.Data.Size > 0 && old.Data.Size == 0: break // install gs as new symbol below // If either is marked as DupOK, we can keep either one. // Keep the one that we saw first. case old.DupOK || gs.DupOK: continue // Otherwise, there's an actual conflict: default: p.errorf("symbol %s defined in both %s and %s %v %v", gs.SymID, old.Package.File, file, old.Data, gs.Data) continue } } s := &Sym{ Sym: gs, Package: pkg, } p.addSym(s) delete(p.Missing, gs.SymID) if s.Data.Size > int64(s.Size) { p.errorf("%s: initialized data larger than symbol (%d > %d)", s, s.Data.Size, s.Size) } } p.MaxVersion += pkg.MaxVersion for i, pkgpath := range pkg.Imports { // TODO(rsc): Fix file format to drop .a from recorded import path. pkgpath = strings.TrimSuffix(pkgpath, ".a") pkg.Imports[i] = pkgpath p.scanImport(pkgpath) } }