Монитор доступа к памяти для программ c

Я пытаюсь отслеживать доступ к памяти в кучу выделенной памяти.

Например, если у меня есть следующий код:   

void set_value(int* buffer, size_t pos, int value) {
    buffer[pos] = value;
}
int main(void) {    
    int* buffer = malloc(BUFF_SIZE * sizeof(int));
    set_value(buffer, 2, 10);
    set_value(buffer, 3, 12);

    free(buffer);
    return 0;
}

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

Я попытался использовать несколько инструментов памяти, например ptrace, strace, ASan, Dmalloc, но я не достигли результата.

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

Есть ли у вас какие-либо советы о том, как отслеживать каждую запись в память кучи?

Ответ 1

Если вы хотите контролировать каждый доступ к памяти, я бы предложил посмотреть на такие пакеты, как PIN [1] и/или DynInst [2]. Оба являются динамическими пакетами бинарных инструментов, которые позволяют вам модифицировать двоичный код приложения, чтобы ввести нужный код. В этом случае оба инструмента позволяют вам выполнять каждую отдельную инструкцию и знать адрес, который они ссылаются (если они загружаются/хранятся). Затем, если вас интересует только память, выделенная malloc (или realloc или calloc), вы также можете задействовать эти подпрограммы, чтобы отображать их параметры ввода и значения выхода, чтобы определить интересующую область памяти. Оба инструмента обеспечивают аналогичные функции. Я бы сказал, что их основное отличие заключается в том, что PIN-код специально ориентирован на процессоры Intel, а DynInst - проект с открытым исходным кодом, который поддерживает разные архитектуры процессоров (Intel, IBM-Power, ARM).

Поскольку в этом конкретном сценарии инструментарий может быть дорогостоящим, который документирует каждую инструкцию, и вы можете позволить себе образцы ссылок на память, я бы предложил вам изучить инфраструктуру PEBS [3] от недавних процессоров Intel (процессоры AMD имеют нечто похожее под названием IBS). PEBS можно использовать из основного инструмента, доступного в ОС Linux [4] (я не знаю, доступен ли он на других ОСЭ)

[1] PIN https://software.intel.com/en-us/articles/pin-a-dynamic-binary-instrumentation-tool

[2] DynInst http://www.dyninst.org

[3] Intel Manual Section 18.4.4 Точная выборка на основе событий (PEBS) http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-vol-3b-part-2-manual.pdf

[4] Первичный Linux для выборки адресов памяти https://lwn.net/Articles/531766/

Ответ 2

Лучшим инструментом для этой цели является использование новой функции во всех современных процессорах, так называемый счетчик производительности оборудования. Чтобы получить доступ к этим счетчикам, вам нужен специальный API, и я рекомендовал PAPI для вас (PAPI: Performance API). Он предоставляет огромные функции для доступа к этим счетчикам и для измерения всех событий микроархитектуры, таких как кеширование, пропуски, операции с плавающей запятой и так далее.