Pregunta

Estoy escribiendo una biblioteca de registradores en C y actualmente estoy tratando de obtener una mejor salida de seguimiento usando addr2line.Para hacerlo, necesito poder obtener la ruta del ejecutable actual.Por el momento sólo estoy preocupado por Linux, pero también buscaré compatibilidad con Mac OS.

Para soporte de Linux estoy intentando usar readlink() y /proc/self/exe para resolver la ruta del ejecutable actual:

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;
}

El camino devuelto por readlink() es: /home/nax��?.la primera parte es correcta: /home/na, pero todo lo que sigue es pura tontería.

¿Por qué no puedo obtener la ruta de ejecución actual de esta manera?

¿Fue útil?

Solución

char* exe_path          = (char*)malloc( 255 );
// ...
readlink( "/proc/self/exe", exe_path, sizeof( exe_path ) )

exe_path es un puntero, por lo que el tamaño será igual a size de (char *) (4 u 8), no 255.

Cambiar exe_path en char[255] o cambie la llamada a sizeof

Por cierto, Readlink no agrega el byte nulo, por lo que debe hacer algo como esto:

len = readlink( "/proc/self/exe", exe_path, sizeof( exe_path ) )
exe_path[len] = 0;

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top