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// Objdump disassembles executable files.
6//
7// Usage:
8//
9//	go tool objdump [-s symregexp] binary
10//
11// Objdump prints a disassembly of all text symbols (code) in the binary.
12// If the -s option is present, objdump only disassembles
13// symbols with names matching the regular expression.
14//
15// Alternate usage:
16//
17//	go tool objdump binary start end
18//
19// In this mode, objdump disassembles the binary starting at the start address and
20// stopping at the end address. The start and end addresses are program
21// counters written in hexadecimal with optional leading 0x prefix.
22// In this mode, objdump prints a sequence of stanzas of the form:
23//
24//	file:line
25//	 address: assembly
26//	 address: assembly
27//	 ...
28//
29// Each stanza gives the disassembly for a contiguous range of addresses
30// all mapped to the same original source file and line number.
31// This mode is intended for use by pprof.
32package main
33
34import (
35	"flag"
36	"fmt"
37	"log"
38	"os"
39	"regexp"
40	"strconv"
41	"strings"
42
43	"cmd/internal/objfile"
44	"cmd/internal/telemetry/counter"
45)
46
47var printCode = flag.Bool("S", false, "print Go code alongside assembly")
48var symregexp = flag.String("s", "", "only dump symbols matching this regexp")
49var gnuAsm = flag.Bool("gnu", false, "print GNU assembly next to Go assembly (where supported)")
50var symRE *regexp.Regexp
51
52func usage() {
53	fmt.Fprintf(os.Stderr, "usage: go tool objdump [-S] [-gnu] [-s symregexp] binary [start end]\n\n")
54	flag.PrintDefaults()
55	os.Exit(2)
56}
57
58func main() {
59	log.SetFlags(0)
60	log.SetPrefix("objdump: ")
61	counter.Open()
62
63	flag.Usage = usage
64	flag.Parse()
65	counter.Inc("objdump/invocations")
66	counter.CountFlags("objdump/flag:", *flag.CommandLine)
67	if flag.NArg() != 1 && flag.NArg() != 3 {
68		usage()
69	}
70
71	if *symregexp != "" {
72		re, err := regexp.Compile(*symregexp)
73		if err != nil {
74			log.Fatalf("invalid -s regexp: %v", err)
75		}
76		symRE = re
77	}
78
79	f, err := objfile.Open(flag.Arg(0))
80	if err != nil {
81		log.Fatal(err)
82	}
83	defer f.Close()
84
85	dis, err := f.Disasm()
86	if err != nil {
87		log.Fatalf("disassemble %s: %v", flag.Arg(0), err)
88	}
89
90	switch flag.NArg() {
91	default:
92		usage()
93	case 1:
94		// disassembly of entire object
95		dis.Print(os.Stdout, symRE, 0, ^uint64(0), *printCode, *gnuAsm)
96
97	case 3:
98		// disassembly of PC range
99		start, err := strconv.ParseUint(strings.TrimPrefix(flag.Arg(1), "0x"), 16, 64)
100		if err != nil {
101			log.Fatalf("invalid start PC: %v", err)
102		}
103		end, err := strconv.ParseUint(strings.TrimPrefix(flag.Arg(2), "0x"), 16, 64)
104		if err != nil {
105			log.Fatalf("invalid end PC: %v", err)
106		}
107		dis.Print(os.Stdout, symRE, start, end, *printCode, *gnuAsm)
108	}
109}
110