liyujie
2025-08-28 d9927380ed7c8366f762049be9f3fee225860833
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
// 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()
}