Подтвердить что ты не робот

Как получить имя вызывающей функции?

Я использую цепочку инструментов gnu. Как я могу во время выполнения найти функцию функции? например, функция B() вызывается многими функциями с помощью указателей функций. Теперь, когда вызывается B, я хочу напечатать имя вызывающего абонента. Мне нужно это для отладки определенной проблемы.

4b9b3361

Ответ 1

Если вы используете GNU, вы можете использовать функции backtrace. Вот пример использования этой справочной страницы.

Ответ 2

Расположение кода вызова вашей функции поддерживается gcc в __builtin_return_address(). Чтобы получить имя для этого, вам необходимо проанализировать таблицу символов программы; в то время как это возможно, через dladdr(), есть ограничения на это:

  • во всех контекстах небезопасно вызывать backtrace()/dladdr() (например, из обработчиков сигналов или одновременно в многопоточной программе или из контекстов, где вы не можете вызвать malloc().).
  • операция не мгновенная, но может потребовать, чтобы вызывающий поток спал; это плохо, если в момент вызова блокируются.
  • существует ограничение того, насколько хорошо "разрешимый" обратный адрес относится к имени; например если есть встроенные функции, вызывающие вашу функцию, тогда будет отображаться вызывающая сторона вашего вызывающего абонента (в man-странице backtrace()), также как и для dladdr() в разделе "ОШИБКИ" ).
  • В С++ существует дополнительная проблема вызовов через con/destructors/initializers, где "вызывающий" из вашей функции может оказаться метакомпотом, созданным компилятором, и фактическое место, которое вас интересует, может быть в другом месте ( вызывающего абонента или даже глубже в стеке вызовов).

Это часто лучший способ разделить трассировку и определение имени функции; то есть просто вывести обратные адреса (как hex/binary), а затем обработать полученный журнал в соответствии с таблицей символов, полученной при запуске программы.

Ответ 3

Другой метод, обозначенный Василем Димовым в ответ на аналогичный вопрос, заключается в замене вызова функции макросом-обертки, который сообщает или передает в вызывающей функции имя. Это будет работать с встроенными функциями, где backtrace не будет. С другой стороны, это не сработает, если вы вызываете функцию по ссылке или иным образом берете ее адрес.

Например:

int B(int x){
    ...
}

может стать:

int _B(int x, char *caller){
    printf("caller is %s\n", caller);
    ...
}

#define B(x) _B((x), __func__)

и каждый вызов B() будет печатать имя вызывающего абонента. Василь Димов строит его по-другому, печатая имя непосредственно в макросе и оставляя функцию неизменной.