Home | History | Annotate | Download | only in addr2line
      1 // Copyright 2012 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 // Addr2line is a minimal simulation of the GNU addr2line tool,
      6 // just enough to support pprof.
      7 //
      8 // Usage:
      9 //	go tool addr2line binary
     10 //
     11 // Addr2line reads hexadecimal addresses, one per line and with optional 0x prefix,
     12 // from standard input. For each input address, addr2line prints two output lines,
     13 // first the name of the function containing the address and second the file:line
     14 // of the source code corresponding to that address.
     15 //
     16 // This tool is intended for use only by pprof; its interface may change or
     17 // it may be deleted entirely in future releases.
     18 package main
     19 
     20 import (
     21 	"bufio"
     22 	"flag"
     23 	"fmt"
     24 	"log"
     25 	"os"
     26 	"strconv"
     27 	"strings"
     28 
     29 	"cmd/internal/objfile"
     30 )
     31 
     32 func printUsage(w *os.File) {
     33 	fmt.Fprintf(w, "usage: addr2line binary\n")
     34 	fmt.Fprintf(w, "reads addresses from standard input and writes two lines for each:\n")
     35 	fmt.Fprintf(w, "\tfunction name\n")
     36 	fmt.Fprintf(w, "\tfile:line\n")
     37 }
     38 
     39 func usage() {
     40 	printUsage(os.Stderr)
     41 	os.Exit(2)
     42 }
     43 
     44 func main() {
     45 	log.SetFlags(0)
     46 	log.SetPrefix("addr2line: ")
     47 
     48 	// pprof expects this behavior when checking for addr2line
     49 	if len(os.Args) > 1 && os.Args[1] == "--help" {
     50 		printUsage(os.Stdout)
     51 		os.Exit(0)
     52 	}
     53 
     54 	flag.Usage = usage
     55 	flag.Parse()
     56 	if flag.NArg() != 1 {
     57 		usage()
     58 	}
     59 
     60 	f, err := objfile.Open(flag.Arg(0))
     61 	if err != nil {
     62 		log.Fatal(err)
     63 	}
     64 
     65 	tab, err := f.PCLineTable()
     66 	if err != nil {
     67 		log.Fatalf("reading %s: %v", flag.Arg(0), err)
     68 	}
     69 
     70 	stdin := bufio.NewScanner(os.Stdin)
     71 	stdout := bufio.NewWriter(os.Stdout)
     72 
     73 	for stdin.Scan() {
     74 		p := stdin.Text()
     75 		if strings.Contains(p, ":") {
     76 			// Reverse translate file:line to pc.
     77 			// This was an extension in the old C version of 'go tool addr2line'
     78 			// and is probably not used by anyone, but recognize the syntax.
     79 			// We don't have an implementation.
     80 			fmt.Fprintf(stdout, "!reverse translation not implemented\n")
     81 			continue
     82 		}
     83 		pc, _ := strconv.ParseUint(strings.TrimPrefix(p, "0x"), 16, 64)
     84 		file, line, fn := tab.PCToLine(pc)
     85 		name := "?"
     86 		if fn != nil {
     87 			name = fn.Name
     88 		} else {
     89 			file = "?"
     90 			line = 0
     91 		}
     92 		fmt.Fprintf(stdout, "%s\n%s:%d\n", name, file, line)
     93 	}
     94 	stdout.Flush()
     95 }
     96