// Copyright 2012 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Addr2line is a minimal simulation of the GNU addr2line tool, // just enough to support pprof. // // Usage: // // go tool addr2line binary // // Addr2line reads hexadecimal addresses, one per line and with optional 0x prefix, // from standard input. For each input address, addr2line prints two output lines, // first the name of the function containing the address and second the file:line // of the source code corresponding to that address. // // This tool is intended for use only by pprof; its interface may change or // it may be deleted entirely in future releases. package main import ( "bufio" "flag" "fmt" "log" "os" "strconv" "strings" "cmd/internal/objfile" "cmd/internal/telemetry/counter" ) func printUsage(w *os.File) { fmt.Fprintf(w, "usage: addr2line binary\n") fmt.Fprintf(w, "reads addresses from standard input and writes two lines for each:\n") fmt.Fprintf(w, "\tfunction name\n") fmt.Fprintf(w, "\tfile:line\n") } func usage() { printUsage(os.Stderr) os.Exit(2) } func main() { log.SetFlags(0) log.SetPrefix("addr2line: ") counter.Open() // 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() counter.Inc("addr2line/invocations") counter.CountFlags("addr2line/flag:", *flag.CommandLine) if flag.NArg() != 1 { usage() } f, err := objfile.Open(flag.Arg(0)) if err != nil { log.Fatal(err) } defer f.Close() tab, err := f.PCLineTable() 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(strings.TrimPrefix(p, "0x"), 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() }