Spec-Zone.ru › GCC 12

3.12 Варианты инструментации программ

GCC поддерживает ряд командно-строчных параметров, которые управляют добавлением инструментации во время выполнения в код, который он обычно генерирует. Например, одной из целей инструментации является сбор статистики профилирования для использования при поиске горячих точек программы, анализе покрытия кода или оптимизациях, основанных на профилях. Другой класс инструментации программ — добавление проверки во время выполнения для обнаружения ошибок программирования, таких как некорректные обращения к указателям или обращение к элементам массива за пределами границ, а также преднамеренно враждебных атак, таких как разрушение стека или перехват vtable в C++. Также существует общий крючок, который можно использовать для реализации других форм отслеживания или инструментации на уровне функций для отладки или анализа программ.

-p
-pg

Генерировать дополнительный код для записи информации о профиле, подходящей для программы анализа prof (для -p) или gprof (для -pg). Этот параметр необходимо использовать при компиляции исходных файлов, о которых требуется информация, а также при линковке.

Можно использовать атрибут функции no_instrument_function для подавления профилирования отдельных функций при компиляции с этими параметрами. См. Общие атрибуты функций.

-fprofile-arcs

Добавить код для инструментирования дуг потока программы. Во время выполнения программа регистрирует, сколько раз выполняется каждый разветвление и вызов, а также сколько раз он используется или возвращается. На целевых платформах, поддерживающих конструкторы с приоритетом, профилирование корректно обрабатывает конструкторы, деструкторы и C++ конструкторы (и деструкторы) классов, которые используются в качестве типа глобальной переменной.

По завершении компилируемой программы эти данные сохраняются в файл с именем auxname.gcda для каждого исходного файла. Данные могут быть использованы для оптимизации, направленной на профилирование (-fbranch-probabilities), или для анализа покрытия тестов (-ftest-coverage). auxname каждого объектного файла генерируется из имени выходного файла, если он явно указан и не является конечным исполняемым файлом, в противном случае он является основой имени исходного файла. В обоих случаях удаляется любой суффикс (например, foo.gcda для входного файла dir/foo.c или dir/foo.gcda для выходного файла, указанного как -o dir/foo.o).

Обратите внимание, что если команда напрямую линковала исходные файлы, соответствующие файлы .gcda будут иметь префикс с неусеченным именем выходного файла. Например, gcc a.c b.c -o binary сгенерирует файлы binary-a.gcda и binary-b.gcda.

См. Кросс-профилирование.

--coverage

Этот параметр используется для компиляции и линковки кода, инструментированного для анализа покрытия. Параметр является синонимом для -fprofile-arcs -ftest-coverage (при компиляции) и -lgcov (при линковке). Подробнее см. документацию по этим параметрам.

  • Скомпилируйте исходные файлы с -fprofile-arcs плюс параметры оптимизации и генерации кода. Для анализа покрытия тестов используйте дополнительный параметр -ftest-coverage. Вам не нужно профилировать каждый исходный файл в программе.
  • Скомпилируйте исходные файлы дополнительно с -fprofile-abs-path для создания абсолютных имен путей в файлах .gcno. Это позволяет gcov находить правильные исходные файлы в проектах, где компиляция происходит в разных рабочих каталогах.
  • Слинкуйте ваши объектные файлы с -lgcov или -fprofile-arcs (последний подразумевает первый).
  • Запустите программу на репрезентативной рабочей нагрузке для генерации информации о профиле дуг. Это можно повторить любое количество раз. Вы можете запускать одновременные экземпляры вашей программы, и при условии, что файловая система поддерживает блокировку, данные файлы будут корректно обновлены. Если не используется строгий вариант ISO C, fork вызовы будут обнаружены и обработаны правильно без двойного подсчета.

    Кроме того, объектный файл можно перекомпилировать несколько раз, и соответствующий файл .gcda будет сливаться, если исходный файл и параметры компилятора не изменились.

  • Для оптимизации, основанной на профиле, скомпилируйте исходные файлы снова с теми же параметрами оптимизации и генерации кода плюс -fbranch-probabilities (см. Параметры управления оптимизацией).
  • Для анализа покрытия тестов используйте gcov для получения информации в удобочитаемом формате из файлов .gcno и .gcda. Дополнительную информацию см. в документации по gcov.

С -fprofile-arcs для каждой функции вашей программы GCC создает граф потока программы, затем находит остовное дерево для графа. Только дуги, которые не находятся в остовном дереве, должны быть инструментированы: компилятор добавляет код для подсчета числа раз, когда эти дуги выполняются. Когда дуга является единственным выходом или единственным входом в блок, код инструментирования можно добавить в блок; в противном случае должен быть создан новый базовый блок для размещения кода инструментирования.

-ftest-coverage

Создать файл заметок, который может использовать утилита анализа покрытия gcov (см. gcov—Программа анализа покрытия тестов), для отображения покрытия программы. Каждый файл исходного кода имеет файл заметок с именем auxname.gcno. Обратитесь к параметру -fprofile-arcs выше для описания auxname и инструкций по генерации данных о покрытии тестов. Данные покрытия более точно соответствуют исходным файлам, если вы не используете оптимизацию.

-fprofile-abs-path

Автоматически преобразовать имена относительных файлов исходного кода в абсолютные пути в файлах .gcno. Это позволяет gcov находить правильные исходные файлы в проектах, где компиляция происходит в разных рабочих каталогах.

-fprofile-dir=path

Установить каталог для поиска файлов данных профиля в path. Этот параметр влияет только на данные профиля, сгенерированные -fprofile-generate, -ftest-coverage, -fprofile-arcs и используемые -fprofile-use и -fbranch-probabilities, и связанными с ними параметрами. Можно использовать как абсолютные, так и относительные пути. По умолчанию GCC использует текущий каталог как path, поэтому файл данных профиля находится в том же каталоге, что и объектный файл. Чтобы избежать конфликтов имен файлов, если имя объектного файла не является абсолютным путем, мы изменяем абсолютный путь файла sourcename.gcda и используем его в качестве имени файла .gcda. Подробности об именовании файлов см. в -fprofile-arcs. См. аналогичный параметр -fprofile-note.

При запуске исполняемого файла в среде с массивным параллелизмом рекомендуется сохранять профиль в разных папках. Это можно сделать с помощью переменных в path, которые экспортируются во время выполнения:

%p

идентификатор процесса.

%q{VAR}

значение переменной окружения VAR

-fprofile-generate
-fprofile-generate=path

Включить параметры, обычно используемые для инструментирования приложения, чтобы получить профиль, полезный для последующей перекомпиляции с оптимизацией на основе обратной связи профиля. Необходимо использовать -fprofile-generate как при компиляции, так и при линковке вашей программы.

Включаются следующие параметры: -fprofile-arcs, -fprofile-values, -finline-functions и -fipa-bit-cp.

Если указан path, GCC ищет файлы данных обратной связи профиля в path. См. -fprofile-dir.

Чтобы оптимизировать программу на основе собранной информации профиля, используйте -fprofile-use. Дополнительную информацию см. в Параметры оптимизации.

-fprofile-info-section
-fprofile-info-section=name

Зарегистрировать информацию о профиле в указанном разделе вместо использования конструктора/деструктора. Имя раздела — name, если оно указано, в противном случае имя раздела по умолчанию .gcov_info. Указатель на информацию о профиле, сгенерированную -fprofile-arcs, размещается в указанном разделе для каждого модуля трансляции. Этот параметр отключает регистрацию информации о профиле через конструктор и отключает обработку информации о профиле через деструктор. Этот параметр не предназначен для использования в гостевых средах, таких как GNU/Linux. Он предназначен для автономных сред (например, встроенных систем) с ограниченными ресурсами, которые не поддерживают конструкторы/деструкторы или ввод/вывод файлов библиотеки C.

Компилятор может собрать входные разделы в непрерывный блок памяти и определить начальные и конечные символы. Ниже приведён пример сценария GNU линковки, который определяет выходной раздел линковки:

.gcov_info      :
{
  PROVIDE (__gcov_info_start = .);
  KEEP (*(.gcov_info))
  PROVIDE (__gcov_info_end = .);
}

Программа может вывести информацию о профилировании, зарегистрированную в этом наборе линковки, например, так:

#include <gcov.h>
#include <stdio.h>
#include <stdlib.h>

extern const struct gcov_info *__gcov_info_start[];
extern const struct gcov_info *__gcov_info_end[];

static void
filename (const char *f, void *arg)
{
  puts (f);
}

static void
dump (const void *d, unsigned n, void *arg)
{
  const unsigned char *c = d;

  for (unsigned i = 0; i < n; ++i)
    printf ("%02x", c[i]);
}

static void *
allocate (unsigned length, void *arg)
{
  return malloc (length);
}

static void
dump_gcov_info (void)
{
  const struct gcov_info **info = __gcov_info_start;
  const struct gcov_info **end = __gcov_info_end;

  /* Obfuscate variable to prevent compiler optimizations.  */
  __asm__ ("" : "+r" (info));

  while (info != end)
  {
    void *arg = NULL;
    __gcov_info_to_gcda (*info, filename, dump, allocate, arg);
    putchar ('\n');
    ++info;
  }
}

int
main()
{
  dump_gcov_info();
  return 0;
}
-fprofile-note=path

Если указан path, GCC сохраняет файл .gcno в path. Если вы используете этот параметр с несколькими исходными файлами, файл .gcno будет перезаписан.

-fprofile-prefix-path=path

Этот параметр может быть использован в сочетании с profile-generate=profile_dir и profile-use=profile_dir для указания базового каталога дерева построенных исходных файлов для GCC. По умолчанию profile_dir будет содержать файлы с изменёнными абсолютными путями всех объектных файлов в построенном проекте. Это нежелательно, когда каталог, используемый для построения инструментированного двоичного файла, отличается от каталога, используемого для построения двоичного файла, оптимизированного с обратной связью профиля, потому что данные профиля не будут найдены во время оптимизированной сборки. В таких настройках можно использовать -fprofile-prefix-path=path с path, указывающим на базовый каталог сборки, чтобы удалить нежелательную часть пути и сохранить все имена файлов относительно основного каталога сборки.

-fprofile-prefix-map=old=new

При компиляции файлов, находящихся в каталоге old, записывать информацию о профилировании (с --coverage), описывая их так, как будто файлы находятся в каталоге new вместо этого. См. также -ffile-prefix-map.

-fprofile-update=method

Изменить метод обновления для приложения, инструментированного для оптимизации на основе обратной связи профиля. Аргумент method должен быть одним из ‘single’, ‘atomic’ или ‘prefer-atomic’. Первый полезен для однопоточных приложений, а второй предотвращает повреждение профиля путём создания потокобезопасного кода.

Предупреждение: Если приложение не правильно объединяет все потоки (или создаёт откреплённый поток), файл профиля всё ещё может быть повреждён.

Использование ‘prefer-atomic’ будет преобразовано либо в ‘atomic’, если это поддерживается целевой платформой, либо в ‘single’ в противном случае. Драйвер GCC автоматически выбирает ‘prefer-atomic’, когда -pthread присутствует в командной строке.

-fprofile-filter-files=regex

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

Например, -fprofile-filter-files=main\.c;module.*\.c будет инструментировать только main.c и все файлы C, начинающиеся с ’module’.

-fprofile-exclude-files=regex

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

Например, -fprofile-exclude-files=/usr/.* предотвратит инструментирование всех файлов, расположенных в папке /usr/.

-fprofile-reproducible=[multithreaded|parallel-runs|serial]

Управление уровнем воспроизводимости профиля, собранного -fprofile-generate. Это позволяет перестроить программу с тем же результатом, что полезно, например, для пакетов распространения.

При использовании -fprofile-reproducible=serial собранный профиль с помощью -fprofile-generate воспроизводим, при условии, что поведение обученной программы одинаково при каждом вызове, она не многопоточная и потоки данных профиля всегда выполняются в том же порядке. Обратите внимание, что потоки профиля происходят в конце выполнения программы, но также и перед вызовом fork функции.

Обратите внимание, что часто количество выполнений некоторых частей программы зависит, например, от длины временных имен файлов или рандомизации памяти (что может повлиять на частоту коллизий в хеш-таблицах). Такая невоспроизводимая часть программ может быть анотирована атрибутом функции no_instrument_function. gcov-dump с -l может использоваться для вывода собранных данных и проверки их воспроизводимости.

При использовании -fprofile-reproducible=parallel-runs собранный профиль остаётся воспроизводимым независимо от порядка потоков данных в файлы gcda. Эта настройка позволяет запускать несколько экземпляров инструментированной программы параллельно (например, с make -j). Это снижает качество собранных данных, особенно профилирования косвенных вызовов.

-fsanitize=address

Включение AddressSanitizer, быстрого детектора ошибок памяти. Инструкции доступа к памяти инструментированы для обнаружения ошибок выхода за пределы границ и использования после освобождения. Опция включает -fsanitize-address-use-after-scope. Подробнее см. https://github.com/google/sanitizers/wiki/AddressSanitizer. Поведение во время выполнения можно изменить с помощью переменной окружения ASAN_OPTIONS. Если она установлена в help=1, доступные опции отображаются при запуске инструментированной программы. Список поддерживаемых опций см. в https://github.com/google/sanitizers/wiki/AddressSanitizerFlags#run-time-flags. Опция не может быть совмещена с -fsanitize=thread или -fsanitize=hwaddress. Обратите внимание, что единственной поддерживаемой целью -fsanitize=hwaddress в настоящее время является AArch64.

-fsanitize=kernel-address

Включение AddressSanitizer для ядра Linux. Подробнее см. https://github.com/google/kasan.

-fsanitize=hwaddress

Включение Hardware-assisted AddressSanitizer, который использует аппаратную возможность игнорирования старшего байта указателя для обнаружения ошибок памяти с низкой нагрузкой на память. Инструкции доступа к памяти инструментированы для обнаружения ошибок выхода за пределы границ и использования после освобождения. Опция включает -fsanitize-address-use-after-scope. Подробности см. в https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html. Поведение во время выполнения можно настроить с помощью переменной окружения HWASAN_OPTIONS. Если она установлена в help=1, доступные опции отображаются при запуске инструментированной программы. Опция не может быть совмещена с -fsanitize=thread или -fsanitize=address и в настоящее время доступна только на AArch64.

-fsanitize=kernel-hwaddress

Включение Hardware-assisted AddressSanitizer для компиляции ядра Linux. Аналогично -fsanitize=kernel-address, но использует другой метод инструментирования, и аналогично -fsanitize=hwaddress, но с различиями в инструментировании, необходимыми для компиляции ядра Linux. Эти различия направлены на предотвращение вызовов инициализации библиотеки hwasan и учёт того, что указатель стека имеет другой старший байт.

Примечание: Эта опция имеет другие значения по умолчанию по сравнению с -fsanitize=hwaddress. Инструментирование вызовов стека и alloca по умолчанию отключено, но всё ещё возможно с помощью командной строки --param hwasan-instrument-stack=1 и --param hwasan-instrument-allocas=1 соответственно. Использование случайного тега кадра не реализовано для инструментирования ядра.

-fsanitize=pointer-compare

Инструментирование операции сравнения (<, <=, >, >=) с операндами-указателями. Опция должна быть совмещена с -fsanitize=kernel-address или -fsanitize=address. Опция не может быть совмещена с -fsanitize=thread. Примечание: по умолчанию проверка отключена во время выполнения. Для её включения добавьте detect_invalid_pointer_pairs=2 в переменную окружения ASAN_OPTIONS. Использование detect_invalid_pointer_pairs=1 обнаруживает недопустимые операции только тогда, когда оба указателя не нулевые.

-fsanitize=pointer-subtract

Инструментирование вычитания с операндами-указателями. Опция должна быть совмещена с -fsanitize=kernel-address или -fsanitize=address. Опция не может быть совмещена с -fsanitize=thread. Примечание: по умолчанию проверка отключена во время выполнения. Для её включения добавьте detect_invalid_pointer_pairs=2 в переменную окружения ASAN_OPTIONS. Использование detect_invalid_pointer_pairs=1 обнаруживает недопустимые операции только тогда, когда оба указателя не нулевые.

-fsanitize=shadow-call-stack

Включение ShadowCallStack, механизма повышения безопасности, используемого для защиты программ от перезаписи адреса возврата (например, переполнения буфера стека). Он работает путём сохранения адреса возврата функции в отдельный выделенный стек теневого вызова в прологе функции и восстановления адреса возврата из стека теневого вызова в эпилоге функции. Инструментирование выполняется только в функциях, которым нужно сохранить адрес возврата в стек.

В настоящее время он поддерживает только платформу aarch64. Он специально разработан для ядер Linux, которые включают опцию CONFIG_SHADOW_CALL_STACK. Для приложений пользовательского пространства текущая поддержка не предоставляется в libc и libgcc. Пользователи, желающие использовать эту функцию в пользовательском пространстве, должны предоставить свою собственную поддержку во время выполнения. Следует отметить, что это может нарушать правила ABI.

На aarch64 инструментирование использует регистр платформы x18. Это обычно означает, что любой код, который может выполняться на том же потоке, что и код, скомпилированный с ShadowCallStack, должен быть скомпилирован с флагом -ffixed-x18, в противном случае функции, скомпилированные без -ffixed-x18, могут перезаписать x18 и тем самым повредить указатель стека теневого вызова.

Также, поскольку поддержка во время выполнения для пользовательского пространства отсутствует, код, скомпилированный с ShadowCallStack, не может использовать обработку исключений. Используйте -fno-exceptions для отключения исключений.

Подробнее см. https://clang.llvm.org/docs/ShadowCallStack.html.

-fsanitize=thread

Включение ThreadSanitizer, быстрого детектора гонок данных. Инструкции доступа к памяти инструментированы для обнаружения ошибок гонок данных. Подробнее см. https://github.com/google/sanitizers/wiki#threadsanitizer. Поведение во время выполнения можно настроить с помощью переменной окружения TSAN_OPTIONS; список поддерживаемых опций см. в https://github.com/google/sanitizers/wiki/ThreadSanitizerFlags. Опция не может быть совмещена с -fsanitize=address, -fsanitize=leak.

Обратите внимание, что атомарные встроенные функции, которые подверглись очистке, не могут генерировать исключения при работе с недопустимыми адресами памяти при отсутствии исключений вызова (-fnon-call-exceptions).

-fsanitize=leak

Включение LeakSanitizer, детектора утечек памяти. Эта опция имеет значение только для компоновки исполняемых файлов, и исполняемый файл компонуется с библиотекой, которая переопределяет malloc и другие функции выделения памяти. Подробнее см. https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer. Поведение во время выполнения можно настроить с помощью переменной окружения LSAN_OPTIONS. Опция не может быть совмещена с -fsanitize=thread.

-fsanitize=undefined

Включить UndefinedBehaviorSanitizer, быстрый детектор неопределённого поведения. Различные вычисления снабжаются инструментацией для обнаружения неопределённого поведения во время выполнения. Для получения дополнительной информации см. https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html. Поведение во время выполнения можно настроить, используя переменную среды UBSAN_OPTIONS. Текущие подварианты:

-fsanitize=shift

Этот параметр включает проверку того, что результат операции сдвига не является неопределённым. Обратите внимание, что точное определение неопределённого результата немного отличается между C и C++, а также между ISO C90 и C99 и т. д. Этот параметр имеет два подварианта: -fsanitize=shift-base и -fsanitize=shift-exponent.

-fsanitize=shift-exponent

Этот параметр включает проверку того, что второй аргумент операции сдвига не является отрицательным и меньше точности повышенного первого аргумента.

-fsanitize=shift-base

Если второй аргумент операции сдвига находится в допустимом диапазоне, проверяется, что результат операции сдвига не является неопределённым. Обратите внимание, что точное определение неопределённого результата немного отличается между C и C++, а также между ISO C90 и C99 и т. д.

-fsanitize=integer-divide-by-zero

Обнаружить целочисленное деление на ноль.

-fsanitize=unreachable

С этим параметром компилятор преобразует вызов __builtin_unreachable в вызов сообщения диагностики вместо него. При достижении вызова __builtin_unreachable поведение неопределённо.

-fsanitize=vla-bound

Этот параметр указывает компилятору проверить, что размер массива переменной длины положителен.

-fsanitize=null

Этот параметр включает проверку указателей. В частности, приложение, построенное с включённым этим параметром, выведет сообщение об ошибке при попытке разыменования указателя NULL, или если ссылка (возможно, ссылка на ссылку) привязана к указателю NULL, или если метод вызывается на объекте, на который указывает указатель NULL.

-fsanitize=return

Этот параметр включает проверку операторов return. Программы, построенные с включённым этим параметром, выведут сообщение об ошибке, когда будет достигнут конец функции, не возвращающей значение void, без фактического возврата значения. Этот параметр работает только в C++.

-fsanitize=signed-integer-overflow

Этот параметр включает проверку переполнения знакового целого. Мы проверяем, что результат +, *, а также унарных и бинарных - не приводит к переполнению в знаковом арифметическом представлении. Это также обнаруживает INT_MIN / -1 знаковое деление. Обратите внимание, что необходимо учитывать правила продвижения целых чисел. То есть следующее не является переполнением:

signed char a = SCHAR_MAX;
a++;
-fsanitize=bounds

Этот параметр включает инструментацию границ массивов. Обнаруживаются различные обращения за пределы границ. Члены массивов с гибким размером, массивы, подобные членам массивов с гибким размером, и инициализаторы переменных со статической областью памяти не инструментируются.

-fsanitize=bounds-strict

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

-fsanitize=alignment

Этот параметр включает проверку выравнивания указателей при разыменовании, или при привязке ссылки к недостаточно выровненному целевому объекту, или при вызове метода или конструктора на недостаточно выровненном объекте.

-fsanitize=object-size

Этот параметр включает инструментацию ссылок на память с использованием функции __builtin_object_size. Обнаруживаются различные обращения за пределы границ доступа к указателям.

-fsanitize=float-divide-by-zero

Обнаружить деление с плавающей точкой на ноль. В отличие от других похожих параметров, -fsanitize=float-divide-by-zero не включается параметром -fsanitize=undefined, так как деление с плавающей точкой на ноль может быть законным способом получения бесконечностей и NaN.

-fsanitize=float-cast-overflow

Этот параметр включает проверку преобразования типов с плавающей точкой в целочисленные типы. Мы проверяем, что результат преобразования не приводит к переполнению. В отличие от других похожих параметров, -fsanitize=float-cast-overflow не включается параметром -fsanitize=undefined. Этот параметр не работает хорошо с включёнными исключениями FE_INVALID.

-fsanitize=nonnull-attribute

Этот параметр включает инструментацию вызовов, проверяя, что значения NULL не передаются аргументам, помеченным как требующие ненулевых значений атрибутом функции nonnull.

-fsanitize=returns-nonnull-attribute

Этот параметр включает инструментацию операторов return в функциях, помеченных атрибутом функции returns_nonnull, для обнаружения возвращения значений null из таких функций.

-fsanitize=bool

Этот параметр включает инструментацию загрузок из bool. Если загружается значение, отличное от 0/1, выдаётся ошибка во время выполнения.

-fsanitize=enum

Этот параметр включает инструментацию загрузок из типа перечисления. Если загружается значение, выходящее за пределы диапазона значений для типа перечисления, выдаётся ошибка во время выполнения.

-fsanitize=vptr

Этот параметр включает инструментацию вызовов функций-членов C++, доступа к членам и некоторых преобразований между указателями на базовый и производный классы для проверки того, что ссылаемый объект имеет правильный динамический тип.

-fsanitize=pointer-overflow

Этот параметр включает инструментацию арифметики указателей. Если арифметика указателей приводит к переполнению, выдаётся ошибка во время выполнения.

-fsanitize=builtin

Этот параметр включает инструментацию аргументов для выбранных встроенных функций. Если неверное значение передаётся таким аргументам, выдаётся ошибка во время выполнения. Например, передача 0 в качестве аргумента функции __builtin_ctz или __builtin_clz вызывает неопределённое поведение и диагностируется этим параметром.

В то время как -ftrapv вызывает выброс ловушек при знаковом переполнении, -fsanitize=undefined выдаёт сообщение диагностики. В настоящее время это работает только для языков семейства C.

-fno-sanitize=all

Этот параметр отключает все ранее включённые инструменты проверки. -fsanitize=all не разрешено, так как некоторые инструменты проверки не могут использоваться вместе.

-fasan-shadow-offset=number

Этот параметр принуждает GCC использовать пользовательский смещение тени в проверках AddressSanitizer. Это полезно для экспериментов с различными макетами памяти тени в Kernel AddressSanitizer.

-fsanitize-sections=s1,s2,...

Проверяет глобальные переменные в выбранных пользовательских разделах. si может содержать подстановочные знаки.

-fsanitize-recover[=opts]

-fsanitize-recover= управляет режимом восстановления ошибок для инструментов проверки, упомянутых в списке opts через запятую. Включение этого параметра для компонента проверки приводит к попытке продолжения выполнения программы как если бы никакой ошибки не произошло. Это означает, что в одном запуске программы могут быть сообщения об нескольких ошибках во время выполнения, и код возврата программы может указывать на успешное выполнение, даже если были сообщения об ошибках. Параметр -fno-sanitize-recover= может быть использован для изменения этого поведения: только первая обнаруженная ошибка сообщается, и программа завершается с ненулевым кодом возврата.

В настоящее время эта функция работает только для -fsanitize=undefined (и её подвариантов, кроме -fsanitize=unreachable и -fsanitize=return), -fsanitize=float-cast-overflow, -fsanitize=float-divide-by-zero, -fsanitize=bounds-strict, -fsanitize=kernel-address и -fsanitize=address. Для этих инструментов проверки режим восстановления включён по умолчанию, кроме -fsanitize=address, для которого эта функция является экспериментальной. -fsanitize-recover=all и -fno-sanitize-recover=all также принимаются, первый включает восстановление для всех инструментов проверки, поддерживающих его, а второй — отключает восстановление для всех поддерживающих его инструментов проверки.

Даже если режим восстановления включён со стороны компилятора, он также должен быть включён со стороны библиотеки времени выполнения, в противном случае ошибки останутся фатальными. Библиотека времени выполнения по умолчанию устанавливает halt_on_error=0 для ThreadSanitizer и UndefinedBehaviorSanitizer, в то время как значение по умолчанию для AddressSanitizer — halt_on_error=1. Это может быть переопределено настройкой флага halt_on_error в соответствующей переменной среды.

Синтаксис без явного параметра opts устарел. Он эквивалентен указанию списка opts:

undefined,float-cast-overflow,float-divide-by-zero,bounds-strict
-fsanitize-address-use-after-scope

Включить проверку локальных переменных для обнаружения ошибок использования после выхода из области видимости. Параметр устанавливает -fstack-reuse в ‘none’.

-fsanitize-undefined-trap-on-error

Параметр -fsanitize-undefined-trap-on-error инструктирует компилятор сообщать об неопределённом поведении с использованием __builtin_trap вместо библиотечной функции libubsan. Преимущество этого в том, что библиотека libubsan не нужна и не подключается, поэтому это пригодно даже в автономных средах.

-fsanitize-coverage=trace-pc

Включить инструментацию кода для проверки покрытия, направленной на fuzzing. Вставляет вызов __sanitizer_cov_trace_pc в каждый базовый блок.

-fsanitize-coverage=trace-cmp

Включить инструментацию кода для проверки, направленной на fuzzing, с учётом потока данных. Вставляет вызов __sanitizer_cov_trace_cmp1, __sanitizer_cov_trace_cmp2, __sanitizer_cov_trace_cmp4 или __sanitizer_cov_trace_cmp8 для целочисленного сравнения с обеими операндами переменными или __sanitizer_cov_trace_const_cmp1, __sanitizer_cov_trace_const_cmp2, __sanitizer_cov_trace_const_cmp4 или __sanitizer_cov_trace_const_cmp8 для целочисленного сравнения с одним операндом константой, __sanitizer_cov_trace_cmpf или __sanitizer_cov_trace_cmpd для сравнения с плавающей точкой или double, и __sanitizer_cov_trace_switch для операторов switch.

-fcf-protection=[full|branch|return|none|check]

Включить инструментацию кода для переносов управления, чтобы повысить безопасность программы, проверив, что целевые адреса инструкций переноса управления (например, косвенный вызов функции, возврат из функции, косвенный переход) являются действительными. Это предотвращает перенаправление потока управления на неожиданный целевой адрес. Это предназначено для защиты от таких угроз, как программирование на основе возврата (ROP), и аналогичного программирования на основе вызова/перехода (COP/JOP).

Значение branch сообщает компилятору о необходимости проверки валидности переноса управления в момент инструкций косвенной ветвления, т.е. инструкций вызова/перехода. Значение return реализует проверку валидности в момент возврата из функции. Значение full является псевдонимом для указания как branch, так и return. Значение none отключает инструментацию.

Значение check используется для окончательной связи с оптимизацией на этапе компоновки (LTO). Выдается ошибка, если файлы объектов LTO скомпилированы с разными значениями -fcf-protection. Значение check игнорируется на этапе компиляции.

Макрос __CET__ определяется при использовании -fcf-protection. Первый бит __CET__ устанавливается в 1 для значения branch, а второй бит __CET__ устанавливается в 1 для return.

Вы также можете использовать атрибут nocf_check для идентификации функций и вызовов, которые следует пропустить из инструментации (см. Атрибуты функций).

В настоящее время целевая платформа x86 GNU/Linux предоставляет реализацию на основе технологии обеспечения целостности потока управления Intel (CET), которая работает для процессоров i686 и более новых.

-fharden-compares

Для каждого логического теста, который выживает оптимизации gimple и не является условием в условном ветвлении (например, условия, проверяемые для условных перемещений или для хранения в логических переменных), генерировать дополнительный код для вычисления и проверки обратного условия и вызова __builtin_trap если результаты не совпадают. Использовать с ‘-fharden-conditional-branches’ для охвата всех условных выражений.

-fharden-conditional-branches

Для каждого неупорядоченного условного ветвления, который выживает оптимизации gimple, генерировать дополнительный код для вычисления и проверки обратного условия и вызова __builtin_trap если результат неожиданный. Использовать с ‘-fharden-compares’ для охвата всех условных выражений.

-fstack-protector

Генерировать дополнительный код для проверки переполнения буфера, таких как атаки на переполнение стека. Это делается путем добавления защитной переменной к функциям с уязвимыми объектами. Это включает функции, которые вызывают alloca, и функции с буферами размером не менее 8 байт. Защитные переменные инициализируются при входе в функцию и затем проверяются при выходе из функции. Если проверка защитной переменной завершается неудачно, выводится сообщение об ошибке, и программа завершается. Учитываются только переменные, которые фактически выделены в стеке, оптимизированные переменные или переменные, выделенные в регистрах, не учитываются.

-fstack-protector-all

Как -fstack-protector, за исключением того, что все функции защищены.

-fstack-protector-strong

Как -fstack-protector, но включает дополнительные функции для защиты — те, которые имеют локальные определения массивов или имеют ссылки на локальные адреса фрейма. Учитываются только переменные, которые фактически выделены в стеке, оптимизированные переменные или переменные, выделенные в регистрах, не учитываются.

-fstack-protector-explicit

Как -fstack-protector, но защищает только те функции, которые имеют атрибут stack_protect.

-fstack-check

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

Обратите внимание, что этот переключатель фактически не выполняет проверку; операционная система или среда выполнения языка должны это сделать. Этот переключатель генерирует код, чтобы убедиться, что они видят расширение стека.

Вы также можете указать строковый параметр: ‘no’ означает отсутствие проверки, ‘generic’ означает принудительное использование проверки старого типа, ‘specific’ означает использование лучшего метода проверки и эквивалентно простому -fstack-check.

Проверка старого типа — это общий механизм, который не требует поддержки от целевой системы в компиляторе, но имеет следующие недостатки:

  1. Измененная стратегия выделения для больших объектов: они всегда выделяются динамически, если их размер превышает фиксированный порог. Обратите внимание, что это может изменить семантику некоторых кодов.
  2. Фиксированное ограничение на размер статической области фрейма функций: когда он достигает максимального значения в конкретной функции, проверка стека не является надежной, и компилятор выдает предупреждение.
  3. Неэффективность: из-за модифицированной стратегии выделения и общей реализации, производительность кода снижается.

Обратите внимание, что проверка стека старого типа также является методом обратной совместимости для ‘specific’, если в компиляторе не добавлена поддержка от целевой системы.

‘-fstack-check=’ предназначен для нужд Ada для обнаружения бесконечной рекурсии и переполнения стека. ‘specific’ — отличный выбор при компиляции кода Ada. Обычно этого недостаточно для защиты от атак с переполнением стека. Для защиты от таких атак вы хотите ‘-fstack-clash-protection’.

-fstack-clash-protection

Генерировать код для предотвращения атак типа столкновения стека. При включенном этом параметре компилятор будет выделять только одну страницу пространства стека за раз, и каждая страница будет обработана сразу после выделения. Таким образом, он предотвращает выделения, перескакивающие через любую страницу защиты стека, предоставляемую операционной системой.

Большинство целевых платформ не полностью поддерживают защиту от столкновений стека. Однако на этих целевых платформах -fstack-clash-protection будет защищать динамическое выделение пространства стека. -fstack-clash-protection может также обеспечить ограниченную защиту статического выделения пространства стека, если целевая платформа поддерживает -fstack-check=specific.

-fstack-limit-register=reg
-fstack-limit-symbol=sym
-fno-stack-limit

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

Например, если стек начинается с абсолютного адреса ‘0x80000000’ и растет вниз, вы можете использовать флаги -fstack-limit-symbol=__stack_limit и -Wl,--defsym,__stack_limit=0x7ffe0000 для установления предела стека 128 КБ. Обратите внимание, что это может работать только с компоновщиком GNU.

Вы можете локально переопределить проверку лимита стека, используя атрибут функции no_stack_limit (см. Атрибуты функций).

-fsplit-stack

Генерировать код для автоматического разделения стека перед его переполнением. Полученная программа имеет несвязный стек, который может переполниться только в том случае, если программа не сможет выделить больше памяти. Это наиболее полезно при работе с многопоточными программами, так как больше не нужно рассчитывать оптимальный размер стека для каждого потока. В настоящее время это реализовано только для целевых платформ x86, работающих под GNU/Linux.

Когда код, скомпилированный с -fsplit-stack, вызывает код, скомпилированный без -fsplit-stack, для последнего кода может быть мало места в стеке. Если компиляция всего кода, включая код библиотек, с -fsplit-stack, не является вариантом, то компоновщик может исправить эти вызовы таким образом, чтобы код, скомпилированный без -fsplit-stack, всегда имел большой стек. Поддержка этого реализована в компоновщике gold в релизе GNU binutils 2.21 и более поздних.

-fvtable-verify=[std|preinit|none]

Этот параметр доступен только при компиляции кода C++. Он включает (или отключает, если используется -fvtable-verify=none) функцию безопасности, которая проверяет во время выполнения для каждого виртуального вызова, что указатель на таблицу виртуальных функций (vtable), через который осуществляется вызов, действителен для типа объекта и не был поврежден или перезаписан. Если во время выполнения обнаруживается недопустимый указатель на vtable, сообщается об ошибке, и выполнение программы немедленно останавливается.

Этот параметр вызывает создание структур данных во время запуска программы, которые используются для проверки указателей на таблицы виртуальных функций (vtable). Параметры ‘std’ и ‘preinit’ управляют временем создания этих структур данных. В обоих случаях структуры данных создаются до того, как выполнение программы достигнет main. Использование -fvtable-verify=std приводит к созданию структур данных после загрузки и инициализации общих библиотек. -fvtable-verify=preinit приводит к их созданию до загрузки и инициализации общих библиотек.

Если этот параметр появляется несколько раз в командной строке с различными значениями, ‘none’ имеет наивысший приоритет над ‘std’ и ‘preinit’; ‘preinit’ имеет приоритет над ‘std’.

-fvtv-debug

При использовании совместно с -fvtable-verify=std или -fvtable-verify=preinit, вызываются отладочные версии функций среды выполнения для функции проверки vtable. Этот флаг также заставляет компилятор регистрировать информацию о том, какие указатели на vtable он находит для каждого класса. Эта информация записывается в файл с именем vtv_set_ptr_data.log в каталоге, указанном переменной среды VTV_LOGS_DIR (если она определена), или в текущем каталоге в противном случае.

Примечание: Эта функция добавляет данные в файл журнала. Если вам нужен новый файл журнала, убедитесь, что вы удалили любой существующий.

-fvtv-counts

Это отладочный флаг. При использовании совместно с -fvtable-verify=std или -fvtable-verify=preinit, он заставляет компилятор отслеживать общее количество виртуальных вызовов, которые он встречает, и количество проверок, которые он вставляет. Он также подсчитывает количество вызовов определённых функций библиотеки времени выполнения, которые он вставляет, и записывает эту информацию для каждого блока компиляции. Компилятор записывает эту информацию в файл с именем vtv_count_data.log в каталоге, указанном переменной окружения VTV_LOGS_DIR, если она определена, или в текущем рабочем каталоге в противном случае. Он также подсчитывает размер наборов указателей vtable для каждого класса и записывает эту информацию в vtv_class_set_sizes.log в том же каталоге.

Примечание: Эта функция добавляет данные в файлы журналов. Чтобы получить новые файлы журналов, убедитесь, что вы удалили все существующие.

-finstrument-functions

Генерирует вызовы инструментирования для входа и выхода из функций. Сразу после входа в функцию и непосредственно перед выходом из неё вызываются следующие функции профилирования с адресом текущей функции и её места вызова. (На некоторых платформах __builtin_return_address не работает за пределами текущей функции, поэтому информация о месте вызова может быть недоступна функциям профилирования иначе.)

void __cyg_profile_func_enter (void *this_fn,
                               void *call_site);
void __cyg_profile_func_exit  (void *this_fn,
                               void *call_site);

Первый аргумент — адрес начала текущей функции, который можно найти точно в таблице символов.

Это инструментирование также выполняется для функций, расширенных встраиванием в другие функции. Вызовы профилирования указывают, где концептуально происходит вход и выход во встроенную функцию. Это означает, что должны быть доступны адресованные версии таких функций. Если все ваши использования функции расширены встраиванием, это может означать дополнительное увеличение размера кода. Если вы используете extern inline в своём коде C, должна быть предоставлена адресованная версия таких функций. (Это обычно так или иначе, но если вам повезёт, и оптимизатор всегда расширяет функции встраиванием, вы могли бы обойтись без предоставления статических копий.)

Функции может быть задан атрибут no_instrument_function, в этом случае это инструментирование не выполняется. Это можно использовать, например, для функций профилирования, перечисленных выше, высокоприоритетных прерываний и любых функций, из которых функции профилирования не могут быть безопасно вызваны (возможно, обработчики сигналов, если функции профилирования генерируют вывод или выделяют память). См. Общие атрибуты функций.

-finstrument-functions-exclude-file-list=file,file,…

Устанавливает список функций, исключённых из инструментирования (см. описание -finstrument-functions). Если файл, содержащий определение функции, совпадает с одним из file, то эта функция не инструментируется. Сопоставление выполняется по подстрокам: если параметр file является подстрокой имени файла, он считается совпадением.

Например:

-finstrument-functions-exclude-file-list=/bits/stl,include/sys

исключает любые встроенные функции, определённые в файлах, пути к которым содержат /bits/stl или include/sys.

Если по какой-то причине вам нужно включить букву «,» в одном из sym, напишите «\,». Например, -finstrument-functions-exclude-file-list='\,\,tmp' (обратите внимание на одинарные кавычки вокруг параметра).

-finstrument-functions-exclude-function-list=sym,sym,…

Это аналогично -finstrument-functions-exclude-file-list, но этот параметр задаёт список имён функций, которые нужно исключить из инструментирования. Имя функции для сопоставления — это её видимое пользователем имя, например vector<int> blah(const vector<int> &), а не внутреннее искажённое имя (например, _Z4blahRSt6vectorIiSaIiEE). Сопоставление выполняется по подстрокам: если параметр sym является подстрокой имени функции, он считается совпадением. Для идентификаторов C99 и расширенных идентификаторов C++ имя функции должно быть задано в кодировке UTF-8, а не с использованием универсальных символьных имен.

-fpatchable-function-entry=N[,M]

Генерирует N инструкций NOP в начале каждой функции, с точкой входа в функцию перед M-й инструкцией NOP. Если M опущено, по умолчанию используется 0, поэтому точка входа в функцию — адрес сразу после первой инструкции NOP. Инструкции NOP резервируют дополнительное пространство, которое можно использовать для вставки любого желаемого инструментирования во время выполнения, при условии, что сегмент кода доступен для записи. Размер пространства косвенно контролируется количеством инструкций NOP; используемая инструкция NOP соответствует инструкции, выводимой внутренним интерфейсом GCC back-end gen_nop. Это поведение зависит от целевой платформы и может также зависеть от варианта архитектуры и/или других параметров компиляции.

Для идентификации во время выполнения дополнительные адреса начала этих областей, которые соответствуют адресам входа в их соответствующие функции минус M, дополнительно собираются в секции __patchable_function_entries результирующего бинарного файла.

Обратите внимание, что значение __attribute__ ((patchable_function_entry (N,M))) имеет приоритет над параметром командной строки -fpatchable-function-entry=N,M. Это можно использовать для увеличения размера области или для её полного удаления для отдельной функции. Если N=0, расположение заполнения не записывается.

Инструкции NOP вставляются в — и, возможно, перед, в зависимости от M — адрес входа в функцию, даже перед прологом.

Максимальное значение N и M равно 65535.

Далее: Параметры препроцессора, Предыдущее: Параметры оптимизации, Наверх: Вызов GCC [Оглавление][Индекс]

© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-12.2.0/gcc/Instrumentation-Options.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API