github.com/riscv/riscv-go@v0.0.0-20200123204226-124ebd6fcc8e/src/cmd/addr2line/main.go (about)

     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  }