|  | // 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" | 
|  | ) | 
|  |  | 
|  | 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: ") | 
|  |  | 
|  | // 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 := 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() | 
|  | } |