11 ms·
The Go language literally requires that pclntab be included in release builds. I'm with you—it seems kind of crazy that this was designed into the language—but
by benesch 7y ago
The Go language literally requires that pclntab be included in release builds. I'm with you—it seems kind of crazy that this was designed into the language—but there you have it.
The reason is that Go's standard library provides functions that allow retrieving a backtrace and symbolicating that backtrace at runtime:
* https://golang.org/pkg/runtime/?m=all#Callers https://golang.org/pkg/runtime/?m=all#Callers
* https://golang.org/pkg/runtime/?m=all#CallersFrames https://golang.org/pkg/runtime/?m=all#CallersFrames
Unlike in C or C++, where you can link in something like libbacktrace [0] to get a best-effort backtrace, those Go functions are guaranteed to be correct, even when functions have been inlined. This is no small feat, and indeed programs compiled with gccgo will often be incorrect because libbacktrace doesn't always get things right when functions have been inlined.
[0]: https://github.com/ianlancetaylor/libbacktrace https://github.com/ianlancetaylor/libbacktrace
- PeterisP 7y agoIs it that common for these functions to be used? Perhaps transitively through some popular libraries? Just being in the standard library doesn't even necessarily mean that these functions (and the data they need) should get included by the linker.
- zer00eyz 7y agoBacktrace can be amazing at run time if your going to put that info into logs. It makes finding "fringe" errors a lot less painful or more easily reproducible.
- benesch 7y agoAny program that uses a logging framework, including the stdlib log package, will wind up depending on runtime.Callers at least transitively. That’s probably most Go programs; certainly most of the programs large enough to be worrying about binary size. Unlike in C, there are no macros like __FILE__ and __LINE__, so there is no alternative to runtime.Callers (short of preprocessing your Go source code).
- umanwizard 7y agoYou can still get a backtrace without symbols though. Why couldn't the Go team introduce a flag that strips symbols, while making clear to people that they should only use it if they are okay with backtraces looking like #1 0x00007ffff7ddb899 in __GI_abort () at abort.c:79 #2 0x0000555555555156 in ?? () #3 0x0000555555555168 in ?? () #4 0x000055555555517d in ?? () #5 0x0000555555555192 in ?? () or similar
- giovannibajo1 7y agoBecause one of the mantra of Go is not telling users to have a "debug" build and a "release" build. The development build is the one that goes into production, with no difference in optimizations, symbols and whatnot. This has pros and cons, like all tradeoffs.
- umanwizard 7y agoThanks; I didn’t know that, but it makes sense. Not a design decision I agree with, but it’s coherent, at least.
- roberson87 7y agoAre you sure this is true? Doesn't delve for example build Go source with special flags (gcflags=all='-N -l')to generate debugging symbols. I also remember having to build Go code with those flags for Stackdriver to get the correct debugging information without any optimisations.
- sagichmal 7y agoThis shouldn't be necessary anymore.
- roberson87 7y agoThanks for the reply. Would appreciate if you could expand on this a little, since when? FWITW Google Stackdriver documentation [1] still states that you have to build source with those flags for version 1.1>. [1]https://cloud.google.com/debugger/docs/setup/go https://cloud.google.com/debugger/docs/setup/go
- loeg 7y agolibunwind[1][2] should unwind correctly if a compiler emits correct DWARF CFI unwind table (required by C++ w/ exceptions; available for C in gcc/clang with -funwind-tables). [1]: https://github.com/llvm-mirror/libunwind https://github.com/llvm-mirror/libunwind [2]: https://www.nongnu.org/libunwind/ https://www.nongnu.org/libunwind/
- saagarjha 7y agoI don’t think libunwind gives you function names if you strip symbols and don’t have debugging information on hand.
- loeg 7y agoSure. libunwind is taking the place of pclntab here, not the symbol table. Go must also not strip symbols in order to print backtraces; if you want the same thing in C, don't strip the symbol table there either.
- Too 7y agoJava and .NET can also get backtrace at runtime. Can't remember if they are symbolized or not but i think they are. How do they handle this?
- ComputerGuru 7y agoThey’re interpreted/JIT’d and not compiled like golang.
- pjmlp 7y agoThey, have release and debug build modes. .NET has AOT support since ever via NGEN, followed by Mono AOT, Xamarin,IL2CPP, Bartok, .NET Native and a couple of less know projects. On Java side AOT has been always supported by JVMs for embedded deployments like Aonix (now part of PTC, PTC, Aicas, ExcelsiorJET, IBM J9. And nowadays there is SubstrateVM as well, renamed recently as Graal Native Image, part of OpenJDK since Java 11.
- andor 7y agoNot entirely true with regards to the question. Yes, Java is interpreted and JITed, but on the bytecode level. When compiling sources to bytecode, line number information is written to class files.
- thu2111 7y agoThey generate unwind information on the fly as they compile the code which is then stashed to one side, compressed and accessed only if a true language-level stack trace is required. Also they don't expose argument or return values in stack traces.