func (dbp *Process) obtainGoSymbols(exe *macho.File, wg *sync.WaitGroup) { defer wg.Done() var ( symdat []byte pclndat []byte err error ) if sec := exe.Section("__gosymtab"); sec != nil { symdat, err = sec.Data() if err != nil { fmt.Println("could not get .gosymtab section", err) os.Exit(1) } } if sec := exe.Section("__gopclntab"); sec != nil { pclndat, err = sec.Data() if err != nil { fmt.Println("could not get .gopclntab section", err) os.Exit(1) } } pcln := gosym.NewLineTable(pclndat, exe.Section("__text").Addr) tab, err := gosym.NewTable(symdat, pcln) if err != nil { fmt.Println("could not get initialize line table", err) os.Exit(1) } dbp.goSymTable = tab }
func (f *File) PCLineTable() (*gosym.Table, error) { textStart, symtab, pclntab, err := f.raw.pcln() if err != nil { return nil, err } return gosym.NewTable(symtab, gosym.NewLineTable(pclntab, textStart)) }
func elfGoSyms(f *elf.File) (*gosym.Table, os.Error) { text := f.Section(".text") symtab := f.Section(".gosymtab") pclntab := f.Section(".gopclntab") if text == nil || symtab == nil || pclntab == nil { return nil, nil } symdat, err := symtab.Data() if err != nil { return nil, err } pclndat, err := pclntab.Data() if err != nil { return nil, err } pcln := gosym.NewLineTable(pclndat, text.Addr) tab, err := gosym.NewTable(symdat, pcln) if err != nil { return nil, err } return tab, nil }
func symbolTable() *gosym.Table { attempts := []func() (uint64, []byte, []byte, error){ pclnElf, pclnMacho, pclnPE, pclnPlan9, } var errors []error for _, a := range attempts { textStart, symtab, pclntab, err := a() if err == nil { var table *gosym.Table table, err = gosym.NewTable(symtab, gosym.NewLineTable(pclntab, textStart)) if err == nil { return table } } errors = append(errors, err) } for _, err := range errors { fmt.Fprintln(os.Stderr, err) } flagset.Usage() os.Exit(1) panic("unreachable") }
func main() { log.SetFlags(0) log.SetPrefix("addr2line: ") // pprof expects this behavior when checking for addr2line if len(os.Args) > 1 && os.Args[1] == "--help" { printUsage(os.Stdout) os.Exit(0) } flag.Usage = usage flag.Parse() if flag.NArg() != 1 { usage() } f, err := os.Open(flag.Arg(0)) if err != nil { log.Fatal(err) } textStart, symtab, pclntab, err := loadTables(f) if err != nil { log.Fatalf("reading %s: %v", flag.Arg(0), err) } pcln := gosym.NewLineTable(pclntab, textStart) tab, err := gosym.NewTable(symtab, pcln) if err != nil { log.Fatalf("reading %s: %v", flag.Arg(0), err) } stdin := bufio.NewScanner(os.Stdin) stdout := bufio.NewWriter(os.Stdout) for stdin.Scan() { p := stdin.Text() if strings.Contains(p, ":") { // Reverse translate file:line to pc. // This was an extension in the old C version of 'go tool addr2line' // and is probably not used by anyone, but recognize the syntax. // We don't have an implementation. fmt.Fprintf(stdout, "!reverse translation not implemented\n") continue } pc, _ := strconv.ParseUint(p, 16, 64) file, line, fn := tab.PCToLine(pc) name := "?" if fn != nil { name = fn.Name } else { file = "?" line = 0 } fmt.Fprintf(stdout, "%s\n%s:%d\n", name, file, line) } stdout.Flush() }
func main() { // len(Args) f, e := elf.Open(os.Args[1]) if e != nil { println(e) return } text := f.Section(".text") gopclntab := f.Section(".gopclntab") gopclndata, e := gopclntab.Data() if e != nil { println(e) return } pclntab := gosym.NewLineTable(gopclndata, text.Addr) gosymtab := f.Section(".gosymtab") gosymdata, e := gosymtab.Data() symtab, e := gosym.NewTable(gosymdata, pclntab) if e != nil { println(e) return } args := make([]string, 3) args[0] = "/usr/bin/objdump" args[1] = "-D" args[2] = os.Args[1] cmd, e := exec.Run(args[0], args, os.Environ(), exec.DevNull, exec.Pipe, exec.MergeWithStdout) if e != nil { println(e) return } reader := bufio.NewReader(cmd.Stdout) for { line, e := reader.ReadString('\n') if e != nil { break } addr := extractAddrFromLine(line) function := symtab.PCToFunc(addr) if function != nil && function.Entry == addr { fmt.Printf("%08x <%s.%s>:\n", addr, function.Sym.PackageName(), function.Sym.BaseName()) } print(line) } f.Close() }
func (f *File) PCLineTable() (Liner, error) { // If the raw file implements Liner directly, use that. // Currently, only Go intermediate objects and archives (goobj) use this path. if pcln, ok := f.raw.(Liner); ok { return pcln, nil } // Otherwise, read the pcln tables and build a Liner out of that. textStart, symtab, pclntab, err := f.raw.pcln() if err != nil { return nil, err } return gosym.NewTable(symtab, gosym.NewLineTable(pclntab, textStart)) }
func processGoInformation(f *elf.File) { gosymtab := getSectionData(f, ".gosymtab") gopclntab := getSectionData(f, ".gopclntab") lineTable := gosym.NewLineTable(gopclntab, f.Section(".text").Addr) table, err := gosym.NewTable(gosymtab, lineTable) if err != nil { log.Fatalf("failed making table: %s", err) } printSyms(table.Syms) printFuncs(table.Funcs) printFiles(table.Files) }
// NewExec tries to detect executable type for the given path and returns // a new executable. It fails if file does not exist, is not a Go executable or // it's unable to parse the file format. func NewExec(path string) (*Exec, error) { typ, symtab, pclntab, text, err := newtbl(path) if err != nil { return nil, err } lntab := gosym.NewLineTable(pclntab, text) if lntab == nil { return nil, ErrNotGoExec } tab, err := gosym.NewTable(symtab, lntab) if err != nil { return nil, ErrNotGoExec } return &Exec{Path: path, Type: typ, table: tab}, nil }
func main() { fmt.Println("task 1: verify version") fmt.Println(" program compiled with", runtime.Version()) fmt.Println("task 2: check for presence of variable and function") // inspect ELF symbol table f, err := elf.Open(os.Args[0]) if err != nil { log.Fatal(err) } defer f.Close() symSection := f.Section(".gosymtab") lineSection := f.Section(".gopclntab") textSection := f.Section(".text") if symSection == nil || lineSection == nil || textSection == nil { log.Fatal("symbolic information not found") } symData, err := symSection.Data() if err != nil { log.Fatal(err) } lineData, err := lineSection.Data() if err != nil { log.Fatal(err) } table, err := gosym.NewTable(symData, gosym.NewLineTable(lineData, textSection.Addr)) if err != nil { log.Fatal(" ", err) } var foundBloop, foundFabs bool for _, s := range table.Syms { if s.Name == "main.bloop" { foundBloop = true fmt.Println(" bloop symbol table entry:", s) } else if s.Name == "math.Abs" { foundFabs = true fmt.Println(" abs symbol table entry:", s) } } if foundBloop && foundFabs { fmt.Println(" bloop: ", bloop) fmt.Println(" abs(bloop): ", math.Abs(bloop)) } }
func (dbp *Process) obtainGoSymbols(exe *pe.File, wg *sync.WaitGroup) { defer wg.Done() _, symdat, pclndat, err := pcln(exe) if err != nil { fmt.Println("could not get Go symbols", err) os.Exit(1) } pcln := gosym.NewLineTable(pclndat, uint64(exe.Section(".text").Offset)) tab, err := gosym.NewTable(symdat, pcln) if err != nil { fmt.Println("could not get initialize line table", err) os.Exit(1) } dbp.goSymTable = tab }
func makeTable(f debugFile) (*gosym.Table, error) { symdat, err := f.Symtab() if err != nil { return nil, err } pclndat, err := f.Pclntab() if err != nil { return nil, err } pcln := gosym.NewLineTable(pclndat, f.TextAddr()) tab, err := gosym.NewTable(symdat, pcln) if err != nil { return nil, err } return tab, nil }
func findAddr(r io.ReaderAt, sym string) (uintptr, error) { file, err := elf.NewFile(r) if err != nil { return 0, err } defer file.Close() var ( textStart uint64 symtab, pclntab []byte ) if sect := file.Section(".text"); sect != nil { textStart = sect.Addr } if sect := file.Section(".gosymtab"); sect != nil { if symtab, err = sect.Data(); err != nil { return 0, err } } if sect := file.Section(".gopclntab"); sect != nil { if pclntab, err = sect.Data(); err != nil { return 0, err } } tab, err := gosym.NewTable(symtab, gosym.NewLineTable(pclntab, textStart)) if err != nil { return 0, err } fn := tab.LookupFunc(sym) if fn == nil { return 0, fmt.Errorf("could not find symbol %q", sym) } return uintptr(fn.Entry), nil }
func main() { log.SetFlags(0) log.SetPrefix("objdump: ") flag.Usage = usage flag.Parse() if flag.NArg() != 1 && flag.NArg() != 3 { usage() } if *symregexp != "" { re, err := regexp.Compile(*symregexp) if err != nil { log.Fatalf("invalid -s regexp: %v", err) } symRE = re } f, err := os.Open(flag.Arg(0)) if err != nil { log.Fatal(err) } textStart, textData, symtab, pclntab, err := loadTables(f) if err != nil { log.Fatalf("reading %s: %v", flag.Arg(0), err) } syms, goarch, err := loadSymbols(f) if err != nil { log.Fatalf("reading %s: %v", flag.Arg(0), err) } // Filter out section symbols, overwriting syms in place. keep := syms[:0] for _, sym := range syms { switch sym.Name { case "text", "_text", "etext", "_etext": // drop default: keep = append(keep, sym) } } syms = keep disasm := disasms[goarch] if disasm == nil { log.Fatalf("reading %s: unknown architecture", flag.Arg(0)) } lookup := func(addr uint64) (string, uint64) { i := sort.Search(len(syms), func(i int) bool { return syms[i].Addr > addr }) if i > 0 { s := syms[i-1] if s.Addr <= addr && addr < s.Addr+uint64(s.Size) && s.Name != "etext" && s.Name != "_etext" { return s.Name, s.Addr } } return "", 0 } pcln := gosym.NewLineTable(pclntab, textStart) tab, err := gosym.NewTable(symtab, pcln) if err != nil { log.Fatalf("reading %s: %v", flag.Arg(0), err) } if flag.NArg() == 1 { // disassembly of entire object - our format dump(tab, lookup, disasm, syms, textData, textStart) os.Exit(exitCode) } // disassembly of specific piece of object - gnu objdump format for pprof gnuDump(tab, lookup, disasm, textData, textStart) os.Exit(exitCode) }