mirror of
https://github.com/wolfpld/tracy.git
synced 2026-09-17 07:44:23 +00:00
Attach by process name.
The name is matched against /proc/<pid>/comm, which the kernel truncates to 15 characters. Several matches are listed so the user can pick one with -p; a match is only accepted if /proc/<pid>/exe is readable, which excludes zombies (they keep a comm but have no executable to map) and inaccessible processes.
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
@@ -386,11 +387,13 @@ static void PrintUsage( const char* progName )
|
||||
printf( "\n" );
|
||||
printf( "Options:\n" );
|
||||
printf( " -p PID Attach to existing process (PID)\n" );
|
||||
printf( " -n NAME Attach to existing process by name\n" );
|
||||
printf( " -h Show this help message\n" );
|
||||
printf( "\n" );
|
||||
printf( "Examples:\n" );
|
||||
printf( " %s ./my_program arg1 arg2\n", progName );
|
||||
printf( " %s -p 1234\n", progName );
|
||||
printf( " %s -n my_program\n", progName );
|
||||
printf( "\n" );
|
||||
printf( "The monitor captures sampling profiling data from an external process\n" );
|
||||
printf( "and streams it to a Tracy server for visualization.\n" );
|
||||
@@ -401,6 +404,41 @@ static void PrintUsage( const char* progName )
|
||||
printf( "In attach mode (-p), the target must already be running.\n" );
|
||||
}
|
||||
|
||||
static int FindPidsByComm( const char* name, pid_t* outPids, int maxPids )
|
||||
{
|
||||
int count = 0;
|
||||
DIR* proc = opendir( "/proc" );
|
||||
if( !proc ) return 0;
|
||||
struct dirent* ent;
|
||||
while( ( ent = readdir( proc ) ) )
|
||||
{
|
||||
if( ent->d_name[0] < '0' || ent->d_name[0] > '9' ) continue;
|
||||
char path[64];
|
||||
snprintf( path, sizeof( path ), "/proc/%s/comm", ent->d_name );
|
||||
FILE* f = fopen( path, "r" );
|
||||
if( !f ) continue;
|
||||
char comm[32] = {};
|
||||
if( fgets( comm, sizeof( comm ), f ) )
|
||||
{
|
||||
size_t len = strlen( comm );
|
||||
while( len > 0 && ( comm[len-1] == '\n' || comm[len-1] == '\r' ) ) comm[--len] = '\0';
|
||||
if( strcmp( comm, name ) == 0 && count < maxPids )
|
||||
{
|
||||
// gate on /proc/<pid>/exe: zombies keep a comm but have no executable to map
|
||||
char exe[256] = {};
|
||||
snprintf( path, sizeof( path ), "/proc/%s/exe", ent->d_name );
|
||||
if( readlink( path, exe, sizeof( exe ) - 1 ) >= 0 )
|
||||
{
|
||||
outPids[count++] = (pid_t)atoi( ent->d_name );
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose( f );
|
||||
}
|
||||
closedir( proc );
|
||||
return count;
|
||||
}
|
||||
|
||||
static int RunAttached( pid_t pid )
|
||||
{
|
||||
if( kill( pid, 0 ) != 0 )
|
||||
@@ -619,16 +657,18 @@ int main( int argc, char** argv )
|
||||
sigaction( SIGQUIT, &sa, nullptr );
|
||||
|
||||
pid_t attachPid = 0;
|
||||
char attachName[128] = {};
|
||||
bool wantAttach = false;
|
||||
|
||||
static struct option longOptions[] = {
|
||||
{ "pid", required_argument, nullptr, 'p' },
|
||||
{ "name", required_argument, nullptr, 'n' },
|
||||
{ "help", no_argument, nullptr, 'h' },
|
||||
{ nullptr, 0, nullptr, 0 }
|
||||
};
|
||||
|
||||
int c;
|
||||
while( ( c = getopt_long( argc, argv, "+p:h", longOptions, nullptr ) ) != -1 )
|
||||
while( ( c = getopt_long( argc, argv, "+p:n:h", longOptions, nullptr ) ) != -1 )
|
||||
{
|
||||
switch( c )
|
||||
{
|
||||
@@ -636,6 +676,15 @@ int main( int argc, char** argv )
|
||||
attachPid = atoi( optarg );
|
||||
wantAttach = true;
|
||||
break;
|
||||
case 'n':
|
||||
if( strlen( optarg ) >= sizeof( attachName ) )
|
||||
{
|
||||
fprintf( stderr, "Process name too long (max %zu characters).\n", sizeof( attachName ) - 1 );
|
||||
return 1;
|
||||
}
|
||||
snprintf( attachName, sizeof( attachName ), "%s", optarg );
|
||||
wantAttach = true;
|
||||
break;
|
||||
case 'h':
|
||||
PrintUsage( argv[0] );
|
||||
return 0;
|
||||
@@ -645,11 +694,27 @@ int main( int argc, char** argv )
|
||||
}
|
||||
}
|
||||
|
||||
argv += optind;
|
||||
argc -= optind;
|
||||
|
||||
if( wantAttach )
|
||||
{
|
||||
if( attachName[0] )
|
||||
{
|
||||
pid_t pids[32] = {};
|
||||
const int numPids = FindPidsByComm( attachName, pids, 32 );
|
||||
if( numPids == 0 )
|
||||
{
|
||||
fprintf( stderr, "No process named '%s' (names are /proc/<pid>/comm values, truncated to 15 characters).\n", attachName );
|
||||
return 1;
|
||||
}
|
||||
if( numPids > 1 )
|
||||
{
|
||||
fprintf( stderr, "Several processes named '%s':", attachName );
|
||||
for( int i=0; i<numPids; i++ ) fprintf( stderr, " %d", (int)pids[i] );
|
||||
fprintf( stderr, "\nUse -p PID to disambiguate.\n" );
|
||||
return 1;
|
||||
}
|
||||
return RunAttached( pids[0] );
|
||||
}
|
||||
|
||||
if( attachPid <= 0 )
|
||||
{
|
||||
fprintf( stderr, "Invalid PID specified.\n" );
|
||||
@@ -658,6 +723,9 @@ int main( int argc, char** argv )
|
||||
return RunAttached( attachPid );
|
||||
}
|
||||
|
||||
argv += optind;
|
||||
argc -= optind;
|
||||
|
||||
if( argc < 1 )
|
||||
{
|
||||
PrintUsage( progName ); // argv[0] was shifted, use original
|
||||
|
||||
Reference in New Issue
Block a user