سؤال

أنا أكتب مكتبة مسجل في لغة C وأحاول حاليًا الحصول على إخراج أفضل للتتبع الخلفي باستخدام addr2line.وللقيام بذلك، أحتاج إلى أن أكون قادرًا على الحصول على مسار الملف القابل للتنفيذ الحالي.في الوقت الحالي، أنا مهتم فقط بنظام التشغيل Linux، ولكني سأعمل على دعم نظام التشغيل Mac OS أيضًا.

لدعم Linux أحاول استخدامه readlink() و /proc/self/exe لحل مسار الملف القابل للتنفيذ الحالي:

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

المسار الذي يتم إرجاعه readlink() يكون: /home/nax��?.الجزء الأول صحيح: /home/na, ولكن كل ما بعد ذلك فهو رطانة خالصة.

لماذا لا أستطيع الحصول على مسار التنفيذ الحالي بهذه الطريقة؟

هل كانت مفيدة؟

المحلول

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

exe_path هو مؤشر، لذا فإن حجمه سيكون مساويًا لـ sizeof(char*) (4 أو 8)، وليس 255.

يتغير exe_path ل char[255] أو تغيير المكالمة إلى sizeof

راجع للشغل، readlink لا يقوم بإلحاق البايت NULL، لذا يجب عليك القيام بشيء مثل هذا:

len = readlink( "/proc/self/exe", exe_path, sizeof( exe_path ) )
exe_path[len] = 0;
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top