Я пишу библиотеку Rust, содержащую реализацию обратных вызовов для LLVM SanitizerCoverage .Эти обратные вызовы могут использоваться для отслеживания выполнения инструментированной программы.
Распространенным способом создания трассировки является печать адреса каждого исполняемого базового блока.Однако для этого необходимо получить адрес инструкции call
, которая вызвала обратный вызов.Примеры C ++, предоставленные LLVM, полагаются на встроенный компилятор __builtin_return_address(0)
для получения этой информации.
extern "C" void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
if (!*guard) return;
void *PC = __builtin_return_address(0);
printf("guard: %p %x PC %p\n", guard, *guard, PC);
}
Я пытаюсь воспроизвести ту же функцию в Rust, но, по-видимому, нет эквивалента __builtin_return_address
.Единственная ссылка, которую я нашел, - это старая версия Rust, но описанная функция больше не доступна.Эта функция выглядит следующим образом:
pub unsafe extern "rust-intrinsic" fn return_address() -> *const u8
Мое хакерское решение заключается в том, чтобы в моем ящике был файл C, содержащий следующую функцию:
void* get_return_address() {
return __builtin_return_address(1);
}
Если яВызвав его из функции Rust, я могу получить адрес возврата самой функции Rust.Это решение, однако, требует компиляции моего кода Rust с -C force-frame-pointers=yes
для его работы, поскольку встроенная функция компилятора C зависит от наличия указателей фреймов.
В заключение, есть более простой способ получитьадрес возврата текущей функции в Rust?
edit: Удаление встроенного return_address
обсуждается в этом выпуске GitHub.
edit 2: Дальнейшее тестирование показало, что корзина backtrace
способна правильно извлечь адрес возврата текущей функции, что позволяет избежать взлома, который я описал ранее.Кредит идет на этот твит.
Проблема с этим решением - это издержки, которые генерируются при создании полной обратной трассировки, когда требуется только адрес возврата текущей функции.Кроме того, ящик использует библиотеки C для извлечения обратной трассировки;это похоже на то, что должно быть сделано в чистом Rust.
edit 3: Свойство компилятора __builtin_return_address(0)
генерирует вызов к свойству LLVM llvm.returnaddress
.Соответствующую документацию можно найти здесь .