Ottieni il percorso di esecuzione corrente dalla biblioteca C
Domanda
Sto scrivendo una libreria logger in c e attualmente sto cercando di ottenere una migliore uscita del backtrace utilizzando addr2line
.Per fare ciò, ho bisogno di poter ottenere il percorso dell'attuale eseguibile.Al momento sono solo preoccupato per Linux, ma ti riprenderà anche per il supporto Mac OS.
Per il supporto Linux Sto cercando di utilizzare readlink()
e /proc/self/exe
per risolvere il percorso di eseguibile corrente:
static char** getPrettyBacktrace( void* addresses[], int array_size ) {
// Used to return the strings generated from the addresses
char** backtrace_strings = (char**)malloc( sizeof( char ) * array_size );
for( int i = 0; i < array_size; i ++ ) {
backtrace_strings[i] = (char*)malloc( sizeof( char ) * 255 );
}
// Will hold the command to be used
char* command_string = (char*)malloc( 255 );
char* exe_path = (char*)malloc( 255 );
// Used to check if an error occured while setting up command
bool error = false;
// Check if we are running on Mac OS or not, and select appropriate command
char* command;
#ifdef __APPLE__
// Check if 'gaddr2line' function is available, if not exit
if( !system( "which gaddr2line > /dev/null 2>&1" ) ) {
command = "gaddr2line -Cfspe";
// TODO: get path for mac with 'proc_pidpath'
} else {
writeLog( SIMPLOG_LOGGER, "Function 'gaddr2line' unavailable. Defaulting to standard backtrace. Please install package 'binutils' for better stacktrace output." );
error = true;
}
#else
// Check if 'addr2line' function is available, if not exit
if( !system( "which addr2line > /dev/null 2>&1" ) ) {
command = "addr2line -Cfspe";
if( readlink( "/proc/self/exe", exe_path, sizeof( exe_path ) ) < 0 ) {
writeLog( SIMPLOG_LOGGER, "Unable to get execution path. Defaulting to standard backtrace." );
error = true;
}
} else {
writeLog( SIMPLOG_LOGGER, "Function 'addr2line' unavailable. Defaulting to standard backtrace. Please install package 'binutils' for better stacktrace output." );
error = true;
}
#endif
// If an error occured, exit now
if( error ) {
free( backtrace_strings );
free( command_string );
free( exe_path );
return NULL;
}
for( int i = 0; i < array_size; i++ ) {
// Compose the complete command to execute
sprintf( command_string, "%s %s %X", command, exe_path, addresses[i] );
// Execute the command
FILE* line = popen( command_string, "r" );
// Get the size of the command output
int line_size = fseek( line, 0, SEEK_END );
// Read the output into the return string
fgets( backtrace_strings[i] , line_size, line );
// Close the command pipe
pclose( line );
}
return backtrace_strings;
}
.
Il percorso restituito da readlink()
è: /home/nax��?
.La prima parte è corretta: /home/na
, ma tutto dopo è puro gibberenzo.
Perché non riesco a ottenere il percorso di esecuzione corrente in questo modo?
Soluzione
char* exe_path = (char*)malloc( 255 );
// ...
readlink( "/proc/self/exe", exe_path, sizeof( exe_path ) )
.
Exe_path è un puntatore, quindi le dimensioni saranno uguali a Sizeof (Char *) (4 o 8), non 255.
Cambia exe_path
su char[255]
o modificare la chiamata su sizeof
btw, leadlink non aggiunge il byte null, quindi dovresti fare qualcosa del genere:
len = readlink( "/proc/self/exe", exe_path, sizeof( exe_path ) )
exe_path[len] = 0;
.