Improbable Symbols and The place to Gain Them – Piece 2

Improbable Symbols and The place to Gain Them – Piece 2

Here’s a weblog submit series. When you happen to haven’t be taught Piece 1 we dispute you to enact so first!

Within the principle weblog submit, we realized in regards to the gorgeous symbols (debug symbols), how the symbolization process works and lastly, straight forward solutions to in finding the symbolic names of addresses in a compiled binary.

The real field of the symbolic data relies on the programming language implementation this system is written in.
We’re going to have the choice to categorize the programming language implementations into three groups: compiled languages (with or with out a runtime), interpreted languages, and JIT-compiled languages.

In this submit, we can proceed our crawl to in finding impossible symbols. And we can gaze into where to in finding them for the diversified styles of programming language implementations.

JIT-compiled language implementations

Examples of JIT-compiled languages consist of Java, .NET, Erlang, JavaScript (Node.js) and a ramification of others.

Valid-In-Time compiled languages bring collectively the source code into bytecode, which is then compiled into machine code at runtime,
in total the use of direct feedback from runtime to book compiler optimizations on the cruise.

As a result of functions are compiled on the cruise, there would possibly per chance be no pre-built, discoverable image desk in any object files. As a replace, the image desk is created on the cruise.
The tag mappings (field to image) are usually kept in the memory of the runtime or virtual machine
and worn for rendering human-readable stack traces when it’s a long way wished , e. g. when an exception occurs, the runtime will use the image mappings to render a human-readable stack mark.

The acceptable factor is that nearly the general runtimes present supplemental image mappings for the honest-in-time compiled code for Linux to make use of perf.

perf defines an interface to resolve symbols for dynamically generated code by a JIT compiler.
These files typically would possibly per chance well well moreover honest moreover be stumbled on in /tmp/perf-$, where $PID is the process ID of the process of the runtime that is running on the scheme.

The runtimes typically don’t allow providing image mappings by default.
You would possibly per chance well well presumably want to replace a configuration, bustle the virtual machine with a particular flag/environment variable or bustle an extra program to assemble these mappings.
As an instance, JVM wants an agent to provide supplemental image mapping files, known as perf-map-agent.

Let’s agree with an example perf map file for NodeJS. The runtimes obtainable output this file with extra or much less the identical structure, extra or much less!

To generate a identical file for Node.js, we now like to bustle node with --perf-well-liked-prof probability.

node --perf-well-liked-prof your-app.js

This would possibly per chance assemble a map file at /tmp/ that looks treasure this:

3ef414c0 398 RegExp: [{(]

3ef418a0 398 RegExp: [})]

59ed4102 26 repl.js: 514

59ed44ea 146 LazyCompile:~survey internal/util/survey.js: 152

59ed4e4a 148 LazyCompile:~formatValue internal/util/survey.js: 456

59ed558a 25f LazyCompile:~formatPrimitive internal/util/survey.js: 768

59ed5d62 35 LazyCompile:~formatNumber internal/util/survey.js: 761

59ed5fca 5d LazyCompile:~stylizeWithColor internal/util/survey.js: 267

4edd2e52 65 LazyCompile:~Domain.exit domain.js: 284

4edd30ea 14b LazyCompile:~lastIndexOf native array.js: 618

4edd3522 35 LazyCompile:~on-line internal/repl.js: 157

4edd37f2 ec LazyCompile:~setTimeout timers.js: 388

4edd3cca b0 LazyCompile:~Timeout internal/timers.js: 55

4edd40ba 55 LazyCompile:~initAsyncResource internal/timers.js: 45

4edd42da f LazyCompile:~exports.packed with life timers.js: 151

4edd457a cb LazyCompile:~insert timers.js: 167

4edd4962 50 LazyCompile:~TimersList timers.js: 195

4edd4cea 37 LazyCompile:~append internal/linkedlist.js: 29

4edd4f12 35 LazyCompile:~lift internal/linkedlist.js: 15

4edd5132 d LazyCompile:~isEmpty internal/linkedlist.js: 44

4edd529a 21 LazyCompile:~good enough speak.js: 345

4edd555a 68 LazyCompile:~innerOk speak.js: 317

4edd59a2 27 LazyCompile:~processTimers timers.js: 220

4edd5d9a 197 LazyCompile:~listOnTimeout timers.js: 226

4edd6352 15 LazyCompile:~survey internal/linkedlist.js:9

4edd66ca a1 LazyCompile:~tryOnTimeout timers.js: 292

4edd6a02 86 LazyCompile:~ontimeout timers.js: 429

4edd7132 d7 LazyCompile:~process.abolish internal/process/per_thread.js: 173

Every line has START, SIZE and symbolname fields, separated with areas. START and SIZE are hex numbers with out 0x.
symbolname is the relaxation of the road, so it would possibly per chance most likely perchance well well like special characters.

With the motivate of this mapping file, we now like every thing we now like to order the addresses in the stack mark. Of route, as continuously, that is barely an oversimplification.

As an instance, these mappings would possibly per chance well well exchange because the runtime decides to recompile the bytecode. So we now like to withhold an tag on these files and withhold track of the adjustments to resolve the cope with properly with their most modern mapping.

Every runtime and virtual machine has its peculiarities that we now like to adapt. Nevertheless these are out of the scope of this submit.

Interpreted language implementations

Examples of interpreted languages consist of Python, Ruby, and yet again many others.
There are moreover languages that repeatedly use interpretation as a stage ahead of JIT compilation, e. g. Java.
Symbolization for this stage of compilation is similar to interpreted languages.

Interpreted language runtimes enact no longer bring collectively this system to machine code.
As a replace, interpreters and virtual machines parse and attain the source code the use of their REPL routines.
Or attain their very like virtual processor. So they like their very like approach of executing functions and managing stacks.

When you happen to like a study (profile or debug) these runtimes the use of something treasure perf,
you should perchance well agree with symbols for the runtime. Nevertheless, you should perchance well no longer agree with the language-stage context it’s most likely you’ll moreover be ready for.

Furthermore, the interpreter itself is liable to be written in a extra low-stage language treasure C or C++.
And must you survey the object file of the runtime/interpreter, the image desk that you just’d in finding would exhibit the internals of the interpreter, no longer the symbols from the supplied source code.

Finding the symbols for our runtime

The runtime symbols are invaluable due to they’ll allow you to see the internal routines of the interpreter. e. g. how noteworthy time your program spends on rubbish collection.
And it be principally treasure the stack traces you’d agree with in the debugger or profiler would possibly per chance well well like calls to the internals of the runtime.
So these symbols are moreover functional for debugging.

Node Stack Trace

Most of the runtimes are compiled with manufacturing mode, and moreover they presumably lack the debug symbols in their originate binaries.
You would possibly per chance well well presumably want to manually bring collectively your runtime in debug mode to in actuality like them in the following binary.
Some runtimes, similar to Node.js, already like them in their manufacturing distributions.

Lastly, to entirely unravel the stack traces of the runtime, lets want to assemble the debug data for the linked libraries.
When you happen to have in mind from the principle weblog submit, debuginfo files can motivate us.
Debuginfo files for instrument applications come in by draw of equipment managers in Linux distributions.
In total for an accessible equipment known as mypackage there exists a mypackage-dbgsym, mypackage-dbg or mypackage-debuginfo equipment.
There are moreover public servers that wait on debug data.
So we now like to in finding the debuginfo files for the runtime we are the use of and your complete linked libraries.

Finding the symbols for our purpose program

The symbols that we gaze for in our like program seemingly are kept in a memory desk that is particular to the runtime.
As an instance, in Python, the image mappings would possibly per chance well well moreover honest moreover be accessed the use of symtable.

As a result, it be a must to craft a particular routine for each interpreter runtime (in some cases, each version of that runtime) to assemble image data.
Trained eyes would possibly per chance well well like already noticed, it be no longer an straight forward endeavor pondering in regards to the sheer quantity of interpreted languages obtainable.
As an instance, a in actuality smartly identified Ruby profiler, rbspy, generates code for reading internal structs of the Ruby runtime for each version.

When you happen to were to write down a long-established-reason profiler, treasure us, you’d want to write down a special subroutine on your profiler for each runtime that you just in actual fact would love to boost.

Again, don’t trouble, we bought you lined

The acceptable data is we bought you lined. When you happen to is liable to be the use of Parca Agent, we already enact the heavy lifting so that you just can enlighten captured stack traces.
And we withhold extending our reinforce for the diversified languages and runtimes.
As an instance, Parca has already reinforce for parsing perf JIT interface to resolve the symbols for accrued stack traces.

Examine Parca out and permit us to know what you think, on Discord channel.

Extra reading

  • perf JIT Interface
  • perf JIT Symbols
  • Node.js profiling guidelines and solutions
  • Node.js Flamegraphs

NOW WITH OVER +8500 USERS. participants can Join Knowasiak with out spending a dime. Join on
Read More



“Simplicity, patience, compassion.
These three are your greatest treasures.
Simple in actions and thoughts, you return to the source of being.
Patient with both friends and enemies,
you accord with the way things are.
Compassionate toward yourself,
you reconcile all beings in the world.”
― Lao Tzu, Tao Te Ching