tracy icon indicating copy to clipboard operation
tracy copied to clipboard

[Linux] Attaching to Existing Binary

Open andrfgs opened this issue 3 years ago • 4 comments

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.

andrfgs avatar Nov 03 '22 13:11 andrfgs

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

wolfpld avatar Nov 03 '22 14:11 wolfpld

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!

andrfgs avatar Nov 06 '22 21:11 andrfgs

The issue is valid and someone might just take the work and continue working on it, so let's keep it open.

wolfpld avatar Nov 06 '22 21:11 wolfpld

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?

andrfgs avatar Nov 06 '22 22:11 andrfgs