Вот ядро ядра моего ответа: напишите код.
Суть моего ответа такова: если ваш компилятор всегда размещает локальные переменные в стеке, то...
Добавляйте большие двоичные объекты в стек при каждой записи функции, в которых записано имя функции, добавьте несколько магических чисел, чтобы, возможно, поймать сбой стека.
typedef struct stack_debug_blob_ {
int magic1;
const char * function_name;
int magic2;
struct stack_debug_blob_ * called_by;
int magic3;
} stack_debug_blob;
stack_debug_blob * top_of_stack_debug_blobs = 0;
Создайте макрос ENTER(f), взяв имя функции. Макрос должен быть примерно в первой строке кода в каждой функции после открытия {. Он добавляет структуру с указателем на имя функции (const) char *, указатель на предыдущую структуру в стеке и, возможно, некоторые магические числа для проверки работоспособности. Направьте указатель верхней части стека BLOB-объектов на эту новую структуру.
#define ENTER(f) \
stack_debug_blob new_stack_debug_blob = { \
MAGIC1, (f), MAGIC2, top_of_stack_debug_blobs, MAGIC3}; \
stack_debug_blob * evil_hack = (top_of_stack_debug_blobs = (&new_stack_debug_blob))
Чтобы все было как можно более переносимым, все, что может сделать ENTER, — это объявить и инициализировать переменные. Следовательно, evil_hack выполняет немного дополнительных вычислений, а не просто инициализирует переменную.
Создайте функцию для обхода списка больших двоичных объектов, проверяющую указатели и магические числа. Он должен сигнализировать об ошибке (может быть, напечатать в stderr, может быть, заблокировать процессор с помощью while (1) { /* nada */ }, может быть, войти в отладчик... зависит от вашего оборудования), если он обнаружит, что что-то не так.
Создайте макрос EXIT(), который проверяет ваш стек больших двоичных объектов, а затем удаляет связь с самым верхним из связанного списка. Его нужно поставить в точках выхода всех ваших функций.
#define EXIT() do { \
check_debug_blobs(); \
top_of_stack_debug_blobs = new_stack_debug_blob.called_by; \
new_stack_debug_blob.magic1 -= 1; /* paranoia */ \
} while (0)
Вероятно, также потребуется заменить все операторы return вызовами макросов RETURN, макрос RETURN аналогичен EXIT, но имеет возврат перед } while (0).
Создайте функцию для просмотра списка больших двоичных объектов, распечатывающую имена функций, назовите ее как-то вроде stacktrace или backtrace.
Напишите программу для оснащения кода C вызовами ENTER(f), EXIT() и RETURN(x).
Опустил несколько деталей, чтобы вы могли повеселиться...
См. также Любой доступный перенос backtrace для uclibc?
person
jsl4tv
schedule
19.07.2010