golang/go · error
pcln not available in go object file
Error message
pcln not available in go object file
What it means
Go object files (`.o` files produced by the compiler, not linked executables) store line-table data in a format that is read through the `Liner` interface (`PCToLine`, `LineToPC`), not through the `pcln()` method. This stub is implemented solely to satisfy the `rawFile` interface contract and should never be reached by callers. If it is, it indicates a bug in the calling code.
Source
Thrown at src/cmd/internal/objfile/goobj.go:227
n := ndef + uint32(r.NNonpkgref())
for i := ndef; i < n; i++ {
osym := r.Sym(i)
sym := Sym{Name: osym.Name(r), Code: 'U'}
syms = append(syms, sym)
}
for i := 0; i < nrefName; i++ {
rn := r.RefName(i)
sym := Sym{Name: rn.Name(r), Code: 'U'}
syms = append(syms, sym)
}
return syms, nil
}
func (f *goobjFile) pcln() (textStart uint64, pclntab []byte, err error) {
// Should never be called. We implement Liner below, callers
// should use that instead.
return 0, nil, fmt.Errorf("pcln not available in go object file")
}
// PCToLine returns the file name, line, and function data for the given pc.
// Returns "",0,nil if unknown.
// This function implements the Liner interface in preference to pcln() above.
func (f *goobjFile) PCToLine(pc uint64) (string, int, *gosym.Func) {
r := f.r
if f.arch == nil {
return "", 0, nil
}
getSymData := func(s goobj.SymRef) []byte {
if s.PkgIdx != goobj.PkgIdxHashed {
// We don't need the data for non-hashed symbols, yet.
panic("not supported")
}
i := s.SymIdx + uint32(r.NSym()+r.NHashed64def())
return r.BytesAt(r.DataOff(i), r.DataSize(i))
}View on GitHub (pinned to b6b368adc5)
Solutions
- Ensure callers use `File.PCLineTable()` (which returns a `Liner`) instead of directly calling `pcln()` on a `goobjFile`.
- If you are modifying `objfile`, check that `goobjFile` implements `Liner` via `PCToLine` and `LineToPC`.
- Report this as a Go bug if encountered with an unmodified toolchain.
Example fix
// before — wrong code path reaches pcln() liner, _ := f.PCLineTable() // on .o files, this should return Liner // If internal code mistakenly calls pcln() on goobjFile, fix the dispatch: // after — use Liner interface liner, err := f.PCLineTable() file, line, fn := liner.PCToLine(pc) // correct path for .o files
Defensive patterns
Strategy: validation
Validate before calling
// Use PCLineTable() which returns Liner, never pcln() directly
func safeGetLiner(f *objfile.File) (objfile.Liner, error) {
return f.PCLineTable() // routes correctly for all file types
} Prevention
- Always use File.PCLineTable() which returns the Liner interface — it dispatches correctly for .o files.
- Never call pcln() directly on a rawFile implementation.
- If modifying objfile, test with both .o files and linked executables.
When it happens
Trigger: A code path in `objfile` that calls `pcln()` on a `goobjFile` instead of routing through the `Liner` interface. This is an internal invariant violation, not a user-facing configuration problem.
Common situations: Modifying the `objfile` package without respecting the `Liner` interface convention. A regression in the toolchain's internal binary analysis code. Using a forked or patched Go toolchain that broke the caller routing logic.
Related errors
- open %s: unrecognized archive member %s
- unknown load address
- open %s: %v
- symbol %s: invalid section number %d
- no %s symbol found
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/2bf0d9694abcc5d9.
Report an issue: GitHub.