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.
19package main
20
21import (
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
34func 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
41func usage() {
42	printUsage(os.Stderr)
43	os.Exit(2)
44}
45
46func 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