KasperskyOS Community Edition 1.3

Анализ данных обратной трассировки стека при аварийном завершении процесса

При завершении процесса в результате необработанного исключения ядро KasperskyOS выводит данные обратной трассировки стека в следующем виде:

Call Trace (User Mode): [<0000000004068498>] (__assert_func+0x78) from [<000000000405f478>] (_vfs_backend_create+0xe8) [<000000000405f478>] (_vfs_backend_create+0xe8) from [<00000000040bdab0>] (_vfs_init+0xd0) [<00000000040bdab0>] (_vfs_init+0xd0) from [<00000000040111a8>] (init_vfs_helper+0xc8) [<00000000040111a8>] (init_vfs_helper+0xc8) from [<00000000040117e0>] (__eprol+0x88) [<00000000040117e0>] (__eprol+0x88)

Здесь очевидна последовательность вызовов функций, которая привела к аварийному завершению процесса. В конце последовательности код функции _vfs_backend_create(), размещенный в памяти процесса по адресу 0x000000000405f478, вызвал функцию __assert_func(), а код функции __assert_func(), размещенный в памяти процесса по адресу 0x0000000004068498, вызвал исключение. То есть исключение возникло при проверке корректности условий в функции _vfs_backend_create(). (Запись вида <имя функции>+0x<смещение> означает адрес внутри кода функции. Например, запись _vfs_backend_create+0xe8 означает адрес внутри кода функции _vfs_backend_create(), смещенный относительно адреса начала кода этой функции на 0xe8 байт. Запись _vfs_backend_create+0xe8 соответствует адресу 0x000000000405f478.)

Имена всех или части функций в последовательности вызовов могут быть не указаны, что осложняет определение причины аварийного завершения процесса.

Пример данных обратной трассировки стека, содержащих только адреса памяти:

Call Trace (User Mode): [<0000000004068498>] from [<000000000405f478>] [<000000000405f478>] from [<00000000040bdab0>] [<00000000040bdab0>] from [<00000000040111a8>] [<00000000040111a8>] from [<00000000040117e0>] [<00000000040117e0>]

Причина отсутствия имен функций в данных обратной трассировки стека заключается в следующем. Для вывода данных обратной трассировки стека ядро получает имена функций из таблицы символов .symtab и таблицы строк .strtab, загруженных в память аварийно завершившегося процесса из отладочной версии исполняемого файла. Эти таблицы могут быть неполными либо вообще отсутствовать в памяти аварийно завершившегося процесса. Также ядро не может вывести имена функций, импортированных из динамических библиотек.

Таблица символов .symtab и таблица строк .strtab отсутствуют в памяти процесса в следующих случаях:

  • Процесс создан из выпускной версии исполняемого файла. (Исполняемый файл собран как выпускной, и при сборке в него включены выпускные версии статических библиотек.)

    Выпускная версия исполняемого файла, в отличие от отладочной, не содержит таблицу символов .symtab и таблицу строк .strtab.

  • Процесс создан из отладочной версии исполняемого файла, из которого перед добавлением в образ решения были удалены таблица символов .symtab и таблица строк .strtab, например, утилитой strip.
  • Процесс создан из отладочной версии исполняемого файла, из которого перед добавлением в образ решения не были удалены таблица символов .symtab и таблица строк .strtab, но эти таблицы не были загружены в память процесса.

    Создать процесс с опциональной загрузкой таблицы символов .symtab и таблицы строк .strtab позволят высокоуровневый API управления процессами и низкоуровневый API управления процессами.

Таблица символов .symtab и таблица строк .strtab являются неполными в следующих случаях:

  • Если исполняемый файл собран как отладочный, но при сборке в него включены выпускные версии статических библиотек, то в таблице символов .symtab и таблице строк .strtab не будет сведений о функциях, которые реализованы в этих библиотеках.
  • Если исполняемый файл собран как выпускной, но при сборке в него включены отладочные версии статических библиотек, то в таблице символов .symtab и таблице строк .strtab будут сведения только о тех функциях, которые реализованы в этих библиотеках.

Для некоторых адресов памяти, указанных в данных обратной трассировки стека, сведения о функциях можно получить из исполняемого файла. Если адрес памяти присутствует в таблице символов .symtab исполняемого файла, то можно получить номер строки кода и имя функции, соответствующие этому адресу памяти. Если адрес памяти отсутствует в таблице символов .symtab, но присутствует в таблице символов .dynsym исполняемого файла, то можно получить имя функции, соответствующей этому адресу памяти. (При использовании ASLR адреса памяти, указанные в данных обратной трассировки стека, увеличены на значение смещения загрузки ELF-образа Relocation base, которое выводится вместе с данными обратной трассировки стека.) В иных случаях получить из исполняемого файла сведения о функциях нельзя. Например, это относится к функциям, импортируемым из динамических библиотек, а также к функциям, реализованным в выпускных версиях статических библиотек.

Исполняемый файл в KasperskyOS содержит набор экспортируемых функций (хотя не является динамической библиотекой). Например, функции библиотеки libc, которая включается в исполняемые файлы, являются экспортируемыми. Таблица символов .dynsym содержит сведения об экспортируемых функциях. Эта таблица присутствует в выпускной версии исполняемого файла, а также остается в отладочной версии исполняемого файла после удаления из него отладочных символов. (Таблица символов .symtab и таблица строк .strtab являются частью отладочных символов.)

Чтобы получить из исполняемого файла сведения о функциях, соответствующих адресам памяти, указанным в данных обратной трассировки, нужно использовать утилиту addr2line, поставляемую в составе KasperskyOS Community Edition (исполняемый файл toolchain/bin/aarch64-kos-addr2line). Формат команды запуска утилиты addr2line:

aarch64-kos-addr2line [--functions] --exe=<путь к исполняемому файлу> 0x<адрес 1> [0x<адрес 2>]...

В команде нужно указать адреса памяти из данных обратной трассировки стека, уменьшенные на значение Relocation base. Параметр --functions требует вывода имен функций в дополнение к номерам строк исходного кода.

Пример:

$ aarch64-kos-addr2line --functions --exe=./build/hello/Hello 0x30090 main /opt/KasperskyOS-Community-Edition-<version>/examples/hello/hello/src/hello.c:6