Spec-Zone.ru › GCC 13

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

GCC поддерживает ряд командно-строковых параметров, которые управляют добавлением инструментирования во время выполнения в генерируемый код. Например, одна из целей инструментирования — сбор статистики профилирования для поиска горячих точек программы, анализа охвата кода или профилирования оптимизаций. Другой класс инструментирования программ — добавление проверок во время выполнения для обнаружения ошибок программирования, таких как некорректная разыменование указателей или обращение к массивам за пределами допустимых границ, а также преднамеренно враждебных атак, таких как переполнение стека или перехват таблицы виртуальных функций 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. С описанием auxname и инструкциями по генерации данных покрытия тестов см. выше параметр -fprofile-arcs. Данные покрытия соответствуют исходным файлам точнее, если вы не используете оптимизацию.

-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 *const __gcov_info_start[];
extern const struct gcov_info *const __gcov_info_end[];

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
filename (const char *f, void *arg)
{
  __gcov_filename_to_gcfn (f, dump, arg );
}

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

static void
dump_gcov_info (void)
{
  const struct gcov_info *const *info = __gcov_info_start;
  const struct gcov_info *const *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 (void)
{
  dump_gcov_info ();
  return 0;
}

Подкоманда merge-stream gcov-tool может использоваться для десериализации потока данных, генерируемого функциями __gcov_filename_to_gcfn и __gcov_info_to_gcda, и объединения информации о профиле в файлы .gcda на файловой системе хоста.

-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 и -fcanon-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.

Для получения более точных отслеживаний стека можно использовать такие параметры, как -O0, -O1 или -Og (которые, например, предотвращают большинство встраиваний функций), -fno-optimize-sibling-calls (который предотвращает оптимизацию вызовов братьев и хвостовых рекурсивных вызовов; этот параметр неявно задаётся для -O0, -O1 или -Og) или -fno-ipa-icf (который отключает Identical Code Folding для функций). Поскольку несколько запусков программы могут давать трассировки стека с разными адресами из-за ASLR (Address Space Layout Randomization), может быть желательно выключить ASLR. В Linux это можно сделать с помощью ‘setarch `uname -m` -R ./prog’.

-fsanitize=kernel-address

Включить AddressSanitizer для ядра Linux. Дополнительную информацию см. на https://github.com/google/kernel-sanitizers.

-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

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

-fsanitize=bounds-strict

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

-fsanitize=alignment

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

-fsanitize=object-size

Этот параметр включает инструментирование ссылок на память с использованием функции __builtin_dynamic_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

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

-fsanitize=returns-nonnull-attribute

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

-fsanitize=bool

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

-fsanitize=enum

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

-fsanitize=vptr

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

-fsanitize=pointer-overflow

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

-fsanitize=builtin

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

Обратите внимание, что инструменты саннитизации часто приводят к увеличению количества ложных срабатываний, особенно в отношении -Wmaybe-uninitialized. Мы рекомендуем избегать комбинации -Werror и инструментов саннитизации.

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

-fno-sanitize=all

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

-fasan-shadow-offset=number

Этот параметр заставляет GCC использовать настраиваемый смещение тени в проверках AddressSanitizer. Это полезно для экспериментов с различными макетами памяти тени в 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-trap[=opts]

Опция -fsanitize-trap= инструктирует компилятор сообщать о непредсказуемом поведении, указанном в списке opts через запятую, для указанных сантайзеров, используя __builtin_trap, а не библиотечную функцию libubsan. Если эта опция включена для определенного сантайзера, она имеет приоритет над -fsanitizer-recover= для этого сантайзера. __builtin_trap будет выводиться и будет фатальной, независимо от того, включено или выключено восстановление с помощью -fsanitize-recover=.

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

В настоящее время эта функция работает с -fsanitize=undefined (и ее подопциями, за исключением -fsanitize=vptr), -fsanitize=float-cast-overflow, -fsanitize=float-divide-by-zero и -fsanitize=bounds-strict. -fsanitize-trap=all также может быть указано, что включает его для undefined подопций, -fsanitize=float-cast-overflow, -fsanitize=float-divide-by-zero и -fsanitize=bounds-strict. Если -fsanitize-trap=undefined или -fsanitize-trap=all используется и -fsanitize=vptr включено в командной строке, интрументация будет проигнорирована, так как для нее всегда требуется поддержка libubsan. -fsanitize-trap=vptr не разрешено.

-fsanitize-undefined-trap-on-error

Опция -fsanitize-undefined-trap-on-error устарела, эквивалентна -fsanitize-trap=all.

-fsanitize-coverage=trace-pc

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

-fsanitize-coverage=trace-cmp

Включить интрументацию кода, направленную на анализ потока данных (dataflow guided 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]

Включить интрументацию кода для переноса управления, чтобы повысить безопасность программы, проверяя, что целевые адреса инструкций переноса управления (такие как косвенный вызов функции, возврат из функции, косвенный переход) являются валидными. Это предотвращает перенаправление потока управления на неожиданную цель. Это предназначено для защиты от таких угроз, как Return-oriented Programming (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 Control-flow Enforcement Technology (CET), которая работает для процессоров i686 и новее.

-fharden-compares

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

-fharden-conditional-branches

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

-fstack-protector

Генерируется дополнительный код для проверки переполнения буфера, например, атак типа stack smashing. Это делается путем добавления защитной переменной к функциям с уязвимыми объектами. Это включает функции, которые вызывают 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. Он не обеспечивает достаточной защиты от атак stack-clash. Для защиты от них необходима опция ‘-fstack-clash-protection’.

-fstack-clash-protection

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

Большинство целевых платформ не полностью поддерживают защиту от stack clash. Однако на тех платформах, где -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-once

Это аналогично -finstrument-functions, но функции профилирования вызываются только один раз на функцию, т. е. первая функция профилирования вызывается после первого входа в функцию, а вторая функция профилирования вызывается перед выходом, соответствующим этому первому входу.

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

-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 — адресу входа в функцию, даже перед прологом. На PowerPC с ABI ELFv2 для функции с двойными точками входа локальная точка входа находится по этому адресу входа в функцию.

Максимальное значение N и M равно 65535. На PowerPC с ABI ELFv2 для функции с двойными точками входа поддерживаемые значения M равны 0, 2, 6 и 14.

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

Spec-Zone.ru

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