With this change, sysprof can be consumed as a subproject without
making any changes to the build files of a project. All you need to do
is provide a wrap file with a `[provide]` section:
https://mesonbuild.com/Wrap-dependency-system-manual.html#provide-section
This is also necessary because otherwise projects need to hard-code
the subproject name, which might be `sysprof` when using `wrap-git` or
`sysprof-3.46.0` when using `wrap-file` (to build from a release
tarball). This can cause conflicts between different subprojects that
consume sysprof differently.
Other projects like glib, cairo, pango, etc already do this.
This code uses the hashtable directly to avoid the overhead of calling
the path which creates ProcessInfo entries. So we need to also handle
the chance the lookaside is NULL.
If we have tooling that can toggle -finstrument-functions, Builder for
example, then we'd be able to use an LD_PRELOAD to inject the various
function callbacks to record samples.
I dont think we want to use the sample frame type for this though. We
really want something focused on tracing instead and visualize it a bit
differently than the stack trace visualizer.
This also builds the agent statically with libsysprof_static_dep since
we'd need that to avoid installing libsysprof when that isn't wanted.
It also ensures the LD_PRELOAD libraries are installed for use by the
agent.
This is useful so that we can know when a subprocess has spawned by the
profiler in tooling which allows sysprof to spawn a process and monitor
said process. Additionally, we need to know when it exits so that we can
be correct in when we can call get_if_exited() from tooling.
pathnames are listed unescaped in /proc/[pid]/maps, so using %s as the
conversion specifier cuts pathnames off at space characters. Use %[^\n]
instead, to read everything until the end of the line.
Also, the scanf manpage states: "String input conversions store a
terminating null byte ('\0') to mark the end of the input; the maximum
field width does not include this terminator". So set the maximum field
width to 511 instead of 512, to leave one free byte in the buffer for
the terminating null byte.
Fixes#70
The order in which the argument list is evaluated is unspecified, so it
was possible for g_steal_pointer to set self = NULL before
self->old_governor was evaluated, resulting in a crash:
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x00007f6efc678d84 in enable_paranoid_cb (object=0x561a4d147c80, result=0x561a4d173560, user_data=0x561a4d09d610) at ../src/libsysprof/sysprof-governor-source.c:290
290 self->old_governor,
[Current thread is 1 (Thread 0x7f6efae4b600 (LWP 122786))]
(gdb) bt
#0 0x00007f6efc678d84 in enable_paranoid_cb (object=0x561a4d147c80 [SysprofHelpers], result=0x561a4d173560, user_data=0x561a4d09d610) at ../src/libsysprof/sysprof-governor-source.c:290
#1 0x00007f6efd51b389 in g_task_return_now (task=0x561a4d173560 [GTask]) at ../../../gio/gtask.c:1219
#2 0x00007f6efd51becb in g_task_return (type=<optimized out>, task=0x561a4d173560 [GTask]) at ../../../gio/gtask.c:1289
#3 g_task_return (task=0x561a4d173560 [GTask], type=<optimized out>) at ../../../gio/gtask.c:1245
#4 0x00007f6efc6a6060 in sysprof_helpers_set_paranoid_cb (object=0x561a4cf9df90 [IpcServiceProxy], result=0x561a4d1736e0, user_data=0x561a4d173560) at ../src/libsysprof/sysprof-helpers.c:788
#5 0x00007f6efd51b389 in g_task_return_now (task=0x561a4d1736e0 [GTask]) at ../../../gio/gtask.c:1219
#6 0x00007f6efd51becb in g_task_return (type=<optimized out>, task=0x561a4d1736e0 [GTask]) at ../../../gio/gtask.c:1289
#7 g_task_return (task=0x561a4d1736e0 [GTask], type=<optimized out>) at ../../../gio/gtask.c:1245
#8 0x00007f6efd5830cb in reply_cb (connection=<optimized out>, res=<optimized out>, user_data=user_data@entry=0x561a4d1736e0) at ../../../gio/gdbusproxy.c:2568
#9 0x00007f6efd51b389 in g_task_return_now (task=0x561a4d22b000 [GTask]) at ../../../gio/gtask.c:1219
#10 0x00007f6efd51becb in g_task_return (type=<optimized out>, task=0x561a4d22b000 [GTask]) at ../../../gio/gtask.c:1289
#11 g_task_return (task=0x561a4d22b000 [GTask], type=<optimized out>) at ../../../gio/gtask.c:1245
#12 0x00007f6efd577cbf in g_dbus_connection_call_done (source=<optimized out>, result=0x561a4d22b0c0, user_data=user_data@entry=0x561a4d22b000) at ../../../gio/gdbusconnection.c:5797
#13 0x00007f6efd51b389 in g_task_return_now (task=0x561a4d22b0c0 [GTask]) at ../../../gio/gtask.c:1219
#14 0x00007f6efd51b3c9 in complete_in_idle_cb (task=0x561a4d22b0c0) at ../../../gio/gtask.c:1233
#15 0x00007f6efd32db84 in g_main_dispatch (context=0x561a4cb60af0) at ../../../glib/gmain.c:3381
#16 g_main_context_dispatch (context=0x561a4cb60af0) at ../../../glib/gmain.c:4099
#17 0x00007f6efd32df28 in g_main_context_iterate (context=context@entry=0x561a4cb60af0, block=block@entry=1, dispatch=dispatch@entry=1, self=<optimized out>) at ../../../glib/gmain.c:4175
#18 0x00007f6efd32dfdf in g_main_context_iteration (context=context@entry=0x561a4cb60af0, may_block=may_block@entry=1) at ../../../glib/gmain.c:4240
#19 0x00007f6efd54a06d in g_application_run (application=0x561a4cb56120 [SysprofApplication], argc=<optimized out>, argv=<optimized out>) at ../../../gio/gapplication.c:2569
#20 0x0000561a4b2edd14 in main (argc=1, argv=0x7ffddcebb708) at ../src/sysprof/sysprof.c:44
(gdb) info locals
helpers = 0x561a4d147c80 [SysprofHelpers]
self = 0x0
error = 0x0
old_governor = -1
__func__ = "enable_paranoid_cb"
The /sysroot/ convention is something we see on OSTree-based systems
such as Silverblue or CoreOS which contains the running image. We can
skip that part of the path so that symbol resolving continues as normal.
We are starting to come into a situation where we need more advanced
path translations because we keep having to do things like this. Until
Linux figures out file-system namespaces at a higher level at least.
Really what we want to deal with here is tracking an overlay that we may
need to be able to decode after the fact (in case processes exit or we
need to do post-processing symbol resolution).
For the podman case, that is $some_path mapped to root (/), generally
speaking. For flatpak though, that would have two mappings, one for
/app and another for /usr (possibly more).
We want to know the location of our root if it was specified in the
capture file. Such is useful for decoding symbols that may not be
reported right from perf tooling.
This allows us to try to translate maps for processes in containers.
For processes we find in a podman container, we can sniff the libpod
cgroup scope. Using that we can translate into the podman layer that
contains the files.
With that, future work could find the proper .so when resolving based on
alternate roots for the process.