GoRE: a library for recovering structure from compiled Go binaries
GoRE - Package gore is a library for analyzing Go binaries
At a glance
- What is it?
- gore is a Go library for analysing Go binaries, recovering the compiler version, functions, packages and types from the metadata a Go binary carries with it. It supports ELF, Mach-O, PE and WebAssembly, and it has an unusual licensing split where most of the library is BSD but the GOROOT extraction feature is AGPL and can be compiled out with a build tag.
- Who is it for?
- gore suits a tool author who needs to introspect a Go binary, such as a metadata extractor or a reverse engineering helper, because it gives you packages, types, functions and the compiler version through one Open call rather than you reimplementing the pclntab and typelink parsing. It does not suit a project that only needs to look up a symbol, and it does not suit Go binaries built before version 1.5.
- Can I use it commercially?
- Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
- Is it still maintained?
- Yes. The repository last received commits 3 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
One Open call, and the metadata comes back
The README names the project as GoRE, and the package gore is a library for analyzing Go binaries.
The usage is three steps. Use go get to download the library, import it into your project, and write a new cool tool. The sample code shows the shape of the API, and every sample starts the same way.
f, err := gore.Open(fileStr)
pkgs, err := f.GetPackages()So Open takes a path and gives you a handle on the binary, and the handle carries the extraction methods.
f, err := gore.Open(fileStr)
typs, err := f.GetTypes()GetTypes returns the types in the binary, and GetPackages returns the main package, the child packages and the sibling packages.
The third sample reaches further into the runtime structures.
f, err := gore.Open(fileStr)
md, err := f.Moduledata()
itabs, err := md.ITabLinksData()Moduledata gives you the runtime module metadata, and ITabLinksData on it lists the addresses of the static interface tables.
The API shape is worth noting for anyone writing a tool on top of this. The extraction functions return the raw structures with addresses and offsets intact, not a tidy summary, so you are expected to do your own presentation. The library is a parser, and redress is named as the example use case.
The licence situation is the unusual part and it is at the end of the README. Most of the gore library files are licensed under the BSD License. A few features, however, are licensed under AGPL, and those features include extraction of GOROOT.
The primary language is Go, the licence field for the repository is AGPL-3.0, and there is both a LICENSE and a LICENSE.bsd file at the root. The default branch is develop, the last push was on 2026-10-20, and there are no GitHub releases.
Version detection by string search, with an override for when it fails
The Go compiler section describes the version recovery mechanism, and it is a heuristic with an escape hatch.
The library has functionality for guessing the compiler version used. It searches the binary for the identifiable string left by the compiler. It is not perfect, so functionality for assuming a specific version is also provided.
The version strings used are identical to the identifiers, so version 1.10.1 is represented as go1.10.1 and version 1.10 is represented as go1.10.
That last detail is what makes the string search possible. Go binaries carry version strings in a predictable form, and matching on the go prefix pattern tells you both the major line and the patch level. The library also has a generated file for this, goversion_gen.go, which sits next to a hand written goversion.go, and there is a corresponding gen/ directory at the repository root.
That leads to the Update get new Go release information section. Instead of downloading a new library release for Go version detection, you can perform a local pull. Run go generate and new compiler releases will be generated from the git tags.
So the version table is generated from git tags rather than hardcoded by hand, which means adding support for a new Go release is a git tag plus a go generate, not a code change. The same pattern appears for the runtime metadata: moduledata_gen.go and stdpkg_gen.go are generated files sitting next to the hand written moduledata.go and package.go.
For a tool author, the practical implication is that the version detection covers whatever Go releases the project has generated support for, and that the project's own release cycle is what determines coverage. The override exists because the search is a search, and a binary that has been stripped in unusual ways, or one built with an unusual toolchain, may not carry the string where the library expects it.
Functions come from pclntab, and packages get classified by guesswork
The function recovery section is where the library does the heavy lifting, and it names the structure it reads.
Function information is recovered from the pclntab. The information recovered includes the function start and end location in the text section, and the source file. The library also tries to estimate the first and last line number in the source file for the function.
The methods recovered include the receiver, which is how a method is distinguished from a plain function in the recovered listing. All functions and methods belong to a package, and the library tries to classify the type of package: if it is a standard library package, a third party package, or part of the main application. If it is unable to classify the package, it is classified as unknown.
That last part is the honest limitation. Package classification is inference from what the recovered file paths and package paths look like, and the library has an explicit fallback rather than pretending. A binary that has had its paths stripped or rewritten will produce more unknown packages, and you should expect that in a stripped release binary.
The type recovery works differently and is more constrained. The types in the binary are parsed from the typelink list. Not all versions of Go are supported equally: versions 1.7 and later are fully supported, versions 1.5 and 1.6 are partially supported, and versions prior to 1.5 are not supported at all at the moment.
So there is a floor of Go 1.5 for types, with full support from 1.7, and nothing below that. That is worth checking against the binaries you care about, because a 2014-era Go binary produces no types from this library.
The repository layout matches the feature list closely, with one file per concern: pclntab.go for the function table, type.go and type2.go for types, package.go for packages, symbol.go for symbols, itab.go for the interface tables, goversion.go for version detection, moduledata.go for the runtime metadata, and goroot.go for GOROOT extraction with goroot_bsd.go as the BSD-licensed variant.
Go 1.27 changed the interface table layout, and the library handles both
One detail in the README is worth isolating, because it shows what happens when an upstream runtime changes its data structures.
ITabLinksData handles both layouts: the pointer array used before Go 1.27 and the contiguous records used in Go 1.27 and later. GetTypes includes the interface and concrete types referenced by the Go 1.27 records.
So the static interface tables in a Go binary used to be an array of pointers to records, and from Go 1.27 they are contiguous records. A parser that assumes the old shape silently returns wrong addresses on a newer binary, and this library handles both.
That is the kind of detail that determines whether a tool built on gore keeps working across Go releases, and it is also a good illustration of the general shape of this project. Go binaries carry their own metadata in structures that are internal to the runtime, they are not a published format, and they change between releases. Any tool that parses them has to track the compiler.
The repository file names make this explicit. There are separate type.go and type2.go files, and there is a fixup.go, and the wasm.go and macho.go and pe.go and elf.go files show the range of container formats handled.
The go.mod shows the same spread in dependencies. The container parsing is covered by blacktop/go-macho for Mach-O and blacktop/go-dwarf, golang.org/x/arch for the architecture decoders, and github.com/eliben/watgo for WebAssembly. The module requires Go 1.26.1, and the dependency list includes go-git for the generate step and stretchr/testify for the tests.
The AGPL split is a build tag decision, not a licence footnote
The licensing section deserves its own section because it is unusual and it has an operational consequence.
It's possible to compile GORE with only the BSD code so it can be distributed under the BSD license. Compiling with the build tag gore_bsd will only enable BSD licensed code. The resulting binary can be distributed under any BSD compatible license.
Building a Go binary without this build tag will include the AGPL licensed code. This means the resulting binary must be licensed under AGPL too.
So the decision is which side of the line you need. The AGPL feature is extraction of GOROOT, and the code that does it lives in goroot.go with a BSD counterpart in goroot_bsd.go, and there are separate test files goroot_bsd_test.go and goroot_test.go.
Why would extraction of GOROOT be the AGPL part? That is the kind of question the README does not answer, and the honest answer is that the split is a licensing decision by the project rather than a technical necessity. What matters for an adopter is that the choice is made at compile time with a build tag, and that the default build pulls in the AGPL code.
For a commercial tool that wants to be distributed under a permissive licence, that means building with gore_bsd and accepting the loss of the GOROOT extraction. For a tool that is going to be network-accessible, the AGPL terms apply anyway under the standard reading of the licence, so the default build is the honest one.
The LICENSE and LICENSE.bsd files at the repository root are where the two texts live, and the licence field in the repository metadata is AGPL-3.0, which matches the default build.
Where gore is the wrong tool
The first wrong-tool case is a task that only needs one fact. If you want the build ID of a binary, or the Go version, or a single function name, pulling in a full binary analysis library with a parser for the pclntab, the typelink list and the module data is more than the job needs. The library is built for tools that want to enumerate everything.
The second case is a non-Go binary. The library reads the metadata that the Go compiler leaves in a Go binary. An ELF file that was not built with Go has none of it, and there is no fallback to a general binary analysis tool.
The third case is a Go binary older than 1.5, where type recovery returns nothing at all, and a binary in the 1.5 to 1.6 range gives partial type support. If your targets include old Go binaries, that is a hard limit rather than a degradation.
There is also the accuracy question. Package classification is inference, and the library falls back to unknown when it cannot classify, which means a stripped or path-obfuscated binary produces a lot of unknowns. Function line number estimates are likewise estimates. If your analysis needs certainty, this library is a starting point that you will need to verify against something else.
The Go 1.27 interface table change is the best illustration of the maintenance burden. The library now handles two layouts of the runtime structures, and it will need to handle the next change too. That is a recurring cost of depending on internal runtime layouts, and it is the main thing to weigh before building a product on it.
On the practical side, the API returns raw structures with addresses rather than formatted output, so a tool built on it has to do its own presentation and its own file format. And the README's own suggested use case, redress, is the reference for what a finished tool looks like.
One more operational detail. The project has no GitHub releases, so there is no tagged artefact to pin, and the default branch is develop rather than main, which means cloning the default branch gives you the development line rather than a released state. For a dependency, that means pinning a commit rather than a version.
Editorial conclusion
gore suits a tool author who needs to introspect a Go binary, such as a metadata extractor or a reverse engineering helper, because it gives you packages, types, functions and the compiler version through one Open call rather than you reimplementing the pclntab and typelink parsing. It does not suit a project that only needs to look up a symbol, and it does not suit Go binaries built before version 1.5. Before adopting, decide which licence you need, since the GOROOT extraction is AGPL while the rest is BSD, and check the pe and macho support against the formats your targets actually ship.
Frequently asked questions
What is the gore Go library?
gore is a library for analyzing Go binaries. It recovers the compiler version, functions, packages, types and runtime module metadata from a Go executable, and the reference use case given in the README is the redress tool.
How do I use the gore library?
Use go get to download the library, import it into your project, and write a tool. The API starts with gore.Open(fileStr) and then calls methods such as GetPackages, GetTypes and Moduledata on the returned handle.
Which Go versions can gore recover types from?
Types are parsed from the typelink list. Versions 1.7 and later are fully supported, versions 1.5 and 1.6 are partially supported, and versions prior to 1.5 are not supported at all.
How does gore handle the Go 1.27 change to interface tables?
ITabLinksData handles both layouts, the pointer array used before Go 1.27 and the contiguous records used in Go 1.27 and later, and GetTypes includes the interface and concrete types referenced by the Go 1.27 records.
What license applies to gore and how do I choose?
Most gore library files are BSD licensed, while a few features including extraction of GOROOT are AGPL licensed. Compiling with the gore_bsd build tag enables only BSD licensed code so the binary can be distributed under any BSD compatible licence, while a default build includes the AGPL code and must be licensed under AGPL.
Which binary formats does gore support?
The repository carries separate source files for elf.go, macho.go, pe.go and wasm.go, and the go.mod depends on blacktop/go-macho for Mach-O, golang.org/x/arch for the architecture decoders and eliben/watgo for WebAssembly, with the module requiring Go 1.26.1.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/goretk-gore)Was this useful?