[Linux] Attaching to Existing Binary
Is there any way of attaching a tracy client to an existing binary to which I don't have the source? I may be misunderstanding but I have only seen instructions on how to embed tracy in a project you have source access to.
It is not possible.
Some work was put into research into this, but there are problems left to be solved by an interested party.
[22:10] wolfpld: @everyone here's a program that launches profiling of an external program specified on a command line (on linux) [22:11] wolfpld: the external program does not need to include the profiling code, or even the debugging information, if debuginfod servers are used [22:11] wolfpld: the problem is that the symbol resolution does not work at this moment [22:12] wolfpld: this is because the stack frames reference the run-specific program counter [22:12] wolfpld: so it would be needed to read the memory mappings and translate the pointers to binaries [22:12] wolfpld: and perform the resolution from there [22:11] gedalia: So it just lets Tracy do sampling? [22:13] wolfpld: yes, it's basically bootstrapping tracy, then doing a fork and execv [22:13] wolfpld: I don't think I will be working more on this at this moment, but maybe someone would want to take a look at this? [22:13] wolfpld: I think it would be quite useful
From 9199bdeb1299c22befbf9077ebec58208a9f78f8 Mon Sep 17 00:00:00 2001
From: Bartosz Taudul <[email protected]>
Date: Mon, 4 Jul 2022 19:10:22 +0200
Subject: [PATCH 1/2] Add magic PID override on Linux.
---
client/TracyProfiler.cpp | 7 +++++++
client/TracySysTrace.cpp | 4 +++-
2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/client/TracyProfiler.cpp b/client/TracyProfiler.cpp
index 2f898aba..e4b57fbb 100644
--- a/client/TracyProfiler.cpp
+++ b/client/TracyProfiler.cpp
@@ -690,10 +690,17 @@ static const char* GetHostInfo()
return buf;
}
+#ifdef __linux__
+uint32_t ___tracy_magic_pid_override = 0;
+#endif
+
static uint64_t GetPid()
{
#if defined _WIN32
return uint64_t( GetCurrentProcessId() );
+#elif defined __linux__
+ if( ___tracy_magic_pid_override != 0 ) return uint64_t( ___tracy_magic_pid_override );
+ return uint64_t( getpid() );
#else
return uint64_t( getpid() );
#endif
diff --git a/client/TracySysTrace.cpp b/client/TracySysTrace.cpp
index 921f17f1..54f8714f 100644
--- a/client/TracySysTrace.cpp
+++ b/client/TracySysTrace.cpp
@@ -766,6 +766,8 @@ static const char* ReadFile( const char* path )
return tmp;
}
+extern uint32_t ___tracy_magic_pid_override;
+
bool SysTraceStart( int64_t& samplingPeriod )
{
#ifndef CLOCK_MONOTONIC_RAW
@@ -817,7 +819,7 @@ bool SysTraceStart( int64_t& samplingPeriod )
#endif
samplingPeriod = GetSamplingPeriod();
- uint32_t currentPid = (uint32_t)getpid();
+ uint32_t currentPid = ___tracy_magic_pid_override != 0 ? ___tracy_magic_pid_override : (uint32_t)getpid();
s_numCpus = (int)std::thread::hardware_concurrency();
--
2.37.0
From c2abe961000d8e9e98715568ccca867d4081d20d Mon Sep 17 00:00:00 2001
From: Bartosz Taudul <[email protected]>
Date: Mon, 4 Jul 2022 19:11:18 +0200
Subject: [PATCH 2/2] Add external monitor utility.
---
monitor/meson.build | 7 ++++++
monitor/monitor.cpp | 60 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 67 insertions(+)
create mode 100644 monitor/meson.build
create mode 100644 monitor/monitor.cpp
diff --git a/monitor/meson.build b/monitor/meson.build
new file mode 100644
index 00000000..b325b10e
--- /dev/null
+++ b/monitor/meson.build
@@ -0,0 +1,7 @@
+project('monitor', 'cpp')
+
+executable('monitor',
+ 'monitor.cpp',
+ '../TracyClient.cpp',
+ cpp_args: ['-DTRACY_ENABLE', '-DTRACY_DELAYED_INIT', '-DTRACY_MANUAL_LIFETIME', '-DTRACY_NO_FRAME_IMAGE']
+)
diff --git a/monitor/monitor.cpp b/monitor/monitor.cpp
new file mode 100644
index 00000000..5a1e9930
--- /dev/null
+++ b/monitor/monitor.cpp
@@ -0,0 +1,60 @@
+#include <semaphore.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "../Tracy.hpp"
+
+namespace tracy { extern uint32_t ___tracy_magic_pid_override; }
+
+int main( int argc, char** argv )
+{
+ if( argc == 1 )
+ {
+ printf( "== Tracy Profiler external monitor ==\n\n" );
+ printf( "Use: %s program [arguments [...]]\n", argv[0] );
+ return 1;
+ }
+
+ sem_t* sem = (sem_t*)mmap( nullptr, sizeof( sem_t ), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, 0, 0 );
+ if( !sem )
+ {
+ fprintf( stderr, "Unable to mmap()!\n" );
+ return 2;
+ }
+ if( sem_init( sem, 1, 0 ) != 0 )
+ {
+ fprintf( stderr, "Unable to sem_init()!\n" );
+ return 2;
+ }
+
+ auto pid = fork();
+ if( pid < 0 )
+ {
+ fprintf( stderr, "Unable to fork()!\n" );
+ return 2;
+ }
+
+ if( pid == 0 )
+ {
+ sem_wait( sem );
+ execvp( argv[1], argv+1 );
+ fprintf( stderr, "Unable to execvp()!\n" );
+ fprintf( stderr, "%s\n", strerror( errno ) );
+ return 2;
+ }
+
+ tracy::___tracy_magic_pid_override = pid;
+ tracy::StartupProfiler();
+ sem_post( sem );
+ waitpid( pid, nullptr, 0 );
+ tracy::ShutdownProfiler();
+
+ sem_destroy( sem );
+ munmap( sem, sizeof( sem_t ) );
+
+ return 0;
+}
--
2.37.0
I understand, thanks for the input. Should I close the ticket or should it be left opened as an enhancement? I wish I could help but I lack knowledge to know how to do this.
Also, thanks for all the help so far!
The issue is valid and someone might just take the work and continue working on it, so let's keep it open.
Very well. Just to see if I understand the problem: What is missing is just symbol resolution right? Isn't there the chance the binary might not even have a symbol table? Like when its compiled with (-s). How would this be solved?