Source file src/cmd/addr2line/main.go

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

View as plain text