
A radare2 script to parse the gopclntab to facilitate Reverse Engineering Go binaries.
Note: This feature has been implemented directly to radare2's core as gopc analysis plugin
A radare2-based Go gopclntab parser for recovering
function symbols from Go binaries, including fully stripped ones. Supports ELF,
Mach-O, and PE binaries across Go versions 1.2, 1.16, 1.18, and 1.20+.
Every Go 1.2+ binary embeds a data region called gopclntab (Program Counter Line
Table) that the Go runtime uses for stack traces, panic messages, garbage
collection, and debugger support. It is one of the most valuable source of symbol
information in Go binaries.
r2gopclntabParser reads this region through radare2, parses the version-specific structures, and either prints the recovered function list (with addresses, source files, and line numbers) or applies the recovered names back into the open radare2 session as function definitions, flags, and comments.
| Dependency | Minimum Version | |---|---|---| | Python 3 | 3.8+ | | radare2 | 5.0+ (tested on 6.0.9) | | r2pipe | any |
No other Python packages are required. The script uses only the standard
library (struct, json, argparse, os, sys) plus r2pipe.
# List all functions recovered from a Go binary
python3 r2_gopclntab.py -f ./mybinary -l
# Search for a specific function (substring match)
python3 r2_gopclntab.py -f ./mybinary -n main.main
# Verbose header + function list
python3 r2_gopclntab.py -f ./mybinary -v -l
# Apply recovered names into an r2 session
python3 r2_gopclntab.py -f ./mybinary --apply
# JSON output
python3 r2_gopclntab.py -f ./mybinary --json
# From within r2 (attach to running session)
#!pipe python3 r2_gopclntab.py --r2pipe --apply -v
usage: r2_gopclntab.py [-h] [-f FILE] [-n FUNCNAME] [-v] [-l]
[--apply] [--json] [--files] [--r2pipe]
| Flag | Description |
|---|---|
-f FILE, --file FILE | Path to the Go binary to analyze. The script spawns its own r2 instance. |
--r2pipe | Attach to an already-running r2 session (for use inside the r2 console). |
| Flag | Description |
|---|---|
-l, --list | Print every recovered function with its address. |
-n NAME, --funcname NAME | Print only functions whose name contains NAME (substring match). If an exact match exists, its address is printed separately. |
-v, --verbose | Print progress messages, parsed header fields, and internal offsets. |
--apply | Write recovered function names into the radare2 session as function definitions (af+), flags in the go. flagspace, and comments with the original Go name and source location. |
--json | Output the header and full function list as JSON to stdout. |
--files | Print the list of source file paths extracted from the file table. |
-h, --help | Show the help message. |
Flags can be combined freely. When no output flag is given, the default behavior is to print the header and the full function list.
All examples below were run against a stripped Go 1.26 Mach-O arm64 binary
(built with -ldflags="-s -w"). The test program defines main.main,
main.fibonacci, main.helloWorld, and main.addNumbers. The compiler
inlined helloWorld and addNumbers, so they do not appear in the gopclntab.
Running with no flags (or just -f) prints the parsed header followed by the
full function table:
$ python3 r2_gopclntab.py -f ./gotest_stripped
============================================================
Go pclntab Header
============================================================
Magic: 0xFFFFFFF1
Go version: 1.20+
Pointer size: 8
Min LC (quantum):4
Num functions: 2030
Num files: 261
funcnameOffset: 0x48
cuOffset: 0x14D20
filetabOffset: 0x158D8
pctabOffset: 0x19A98
pclnOffset: 0x55E40
============================================================
ADDRESS FUNCTION NAME
----------------------------------------------------------------------
0x100001000 go:buildid
0x100001070 internal/abi.BoundsDecode (/opt/homebrew/Cellar/go/1.26.1/libexec/src/internal/abi/bounds.go:86)
0x100001150 internal/abi.NoEscape (/opt/homebrew/Cellar/go/1.26.1/libexec/src/internal/abi/escape.go:19)
0x100001160 internal/abi.Kind.String (/opt/homebrew/Cellar/go/1.26.1/libexec/src/internal/abi/type.go:143)
0x1000011E0 internal/abi.TypeOf (/opt/homebrew/Cellar/go/1.26.1/libexec/src/internal/abi/type.go:181)
0x1000011F0 internal/abi.(*Type).ExportedMethods (/opt/homebrew/Cellar/go/1.26.1/libexec/src/internal/abi/type.go:453)
...
0x1000A0BB0 main.fibonacci (/tmp/gotest/main.go:13)
0x1000A0C20 main.main (/tmp/gotest/main.go:20)
0x1000A0D20 go:textfipsstart
0x1000A0D30 go:textfipsend
[+] 2030 function(s) shown
Adds section scanning progress, textStart resolution details, and internal offset information:
$ python3 r2_gopclntab.py -f ./gotest_stripped -v
[*] Running radare2 analysis...
[*] Binary format: mach0, endian: little, arch: arm, bits: 64
[*] Scanning binary for gopclntab magic bytes...
[*] Scanning section '0.__TEXT.__text' (0x100001000, 0x9FD44)...
[*] Scanning section '1.__TEXT.__symbol_stub1' (0x1000A0D60, 0x2B8)...
[*] Scanning section '2.__TEXT.__rodata' (0x1000A1020, 0xACC2)...
[*] Scanning section '3.__TEXT.__gopclntab' (0x1000ABCE8, 0xA48AE)...
[*] Found magic at vaddr=0x1000ABCE8
[*] Parsed header: PcHeader(magic=0xFFFFFFF1, version=1.20+, ptrSize=8, minLC=4,
nfunc=2030, nfiles=261, textStart=0x0)
[*] textStart is 0, using .text section vaddr: 0x100001000
[*] Parsed 2030 functions
============================================================
Go pclntab Header
============================================================
Magic: 0xFFFFFFF1
Go version: 1.20+
...
Filters the function list by substring match. If an exact match exists, its address is printed separately.
Substring search for all functions containing main.:
$ python3 r2_gopclntab.py -f ./gotest_stripped -n "main."
ADDRESS FUNCTION NAME
----------------------------------------------------------------------
0x100041920 runtime.main.func2 (/opt/homebrew/Cellar/go/1.26.1/libexec/src/runtime/proc.go:207)
0x10006CE30 runtime.main.func1 (/opt/homebrew/Cellar/go/1.26.1/libexec/src/runtime/proc.go:174)
0x1000A0BB0 main.fibonacci (/tmp/gotest/main.go:13)
0x1000A0C20 main.main (/tmp/gotest/main.go:20)
[+] 4 function(s) shown (filtered from 2030 total)
Exact match search: