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-streamgcov-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.
Проверка старого стиля — это общий механизм, который не требует специфической поддержки целевой платформы в компиляторе, но имеет следующие недостатки:
- Измененная стратегия выделения для больших объектов: они всегда выделяются динамически, если их размер превышает определенный порог. Обратите внимание, что это может изменить семантику некоторого кода.
- Фиксированный лимит размера статической области фрейма функций: когда он достигается определенной функцией, проверка стека не надежна, и компилятор выводит предупреждение.
- Неэффективность: из-за модифицированной стратегии выделения и общей реализации снижается производительность кода.
Обратите внимание, что проверка стека старого стиля также является резервным методом для ‘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-endgen_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