LINUX.ORG.RU

[C] а можно ли...

 


0

0

... в функции узнать имя вызвавшей её функции. Т.е., что-то типа такого:

void foo()
{
    #ifdef DEBUG
    get_caller_name(); // returns "void bar()"
    #endif
}

void bar()
{
    foo();
}

int main(int, char **)
{
    bar();
    return 0;
}

Допустимы любые костыли. Стыдно, но я не знаю асм, и с трудом представляю, как работает debugger, какую отладочную информацию он включает в бинарник, и может ли мне это как-то помочь.

★★★★

Портабельно и без хитроумных манипуляций со стеком и т.п., наверное, никак. Если уж очень сильно надо, можно:

void
f(int x, float y, const char* caller)
{
    DEBUG_PRINT("Called by %s", caller);
}

void
g(void)
{
    f(0, 1.0f, __func__);
}

void
h(int z)
{
    f(z * 2, M_PI, __func__);
}
Но скорее всего оно вообще не надо.

undet
()
Ответ на: комментарий от ttnl

Спасибо, это тоже хорошая штука, но главное, пока я про неё гуглил наткнулся именно но то, что нужно - backtrace, backtrace_symbols.

Если кому любопытно, вот пример:

#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void
myfunc3(void)
{
   int j, nptrs;
#define SIZE 100
   void *buffer[100];
   char **strings;

   nptrs = backtrace(buffer, SIZE);
   printf("backtrace() returned %d addresses\n", nptrs);

   /* The call backtrace_symbols_fd(buffer, nptrs, STDOUT_FILENO)
      would produce similar output to the following: */

   strings = backtrace_symbols(buffer, nptrs);
   if (strings == NULL) {
       perror("backtrace_symbols");
       exit(EXIT_FAILURE);
   }

   for (j = 0; j < nptrs; j++)
       printf("%s\n", strings[j]);

   free(strings);
}

static void   /* "static" means don't export the symbol... */
myfunc2(void)
{
   myfunc3();
}

void
myfunc(int ncalls)
{
   if (ncalls > 1)
       myfunc(ncalls - 1);
   else
       myfunc2();
}

int
main(int argc, char *argv[])
{
   if (argc != 2) {
       fprintf(stderr, "%s num-calls\n", argv[0]);
       exit(EXIT_FAILURE);
   }

   myfunc(atoi(argv[1]));
   exit(EXIT_SUCCESS);
}

Собирать с gcc -g -rdynamic test.c -o test

Вывод ./test 3:

backtrace() returned 8 addresses
./test(myfunc3+0x1f) [0x8048823]
./test [0x80488b0]
./test(myfunc+0x21) [0x80488d3]
./test(myfunc+0x1a) [0x80488cc]
./test(myfunc+0x1a) [0x80488cc]
./test(main+0x52) [0x8048927]
/lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe6) [0x382b56]
./test [0x8048771]
runtime ★★★★
() автор топика
Ответ на: комментарий от runtime

Я не вижу никаких применений этому, кроме как для отладки, но это всё (и намного больше) можно посмотреть и в отладчике. Можешь рассказать как ты это применяешь и для чего? Может быть, в твоём случае это не критично, но оный backtrace сильно зависит от glibc, и, например, на FreeBSD работать не будет.

undet
()

Рискну предположить, что автор оффтопо-раб и пытается соорудить велосипед для получения коре-дампа

anonymous
()
Ответ на: комментарий от anonymous

> автор оффтопо-раб и пытается соорудить велосипед для получения коре-дампа

если это так, то ему надо гуглить про debughlp.dll и заодно узнать, что в оффтопике данная фишка жутко тормозная

ahonimous
()
Ответ на: комментарий от undet

>Портабельно и без хитроумных манипуляций со стеком и т.п., наверное, никак.

Перед вызовом устанавливать глобальную переменную last_function - будет кроссплатформенно.

Nakgidveef
()
Ответ на: комментарий от Nakgidveef

Почему не в школе?

>Перед вызовом устанавливать глобальную переменную last_function - будет кроссплатформенно.

А если потоков несколько, умник?

anonymous
()
Ответ на: комментарий от Nakgidveef

Перед вызовом устанавливать глобальную переменную last_function - будет кроссплатформенно.

int n = FuncA() + FuncB();

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

PUSH_FUNC

которая будет например такой:

#define PUSH_FUNC PushFunc( __func__ ); PopFunc tmp;

ahonimous
()
Ответ на: комментарий от undet

> Я не вижу никаких применений этому, кроме как для отладки

Да, это только для отладки.

но это всё (и намного больше) можно посмотреть и в отладчике.

Да, просто мне хочется всё красиво расписать в единый лог, который потом можно будет grep'ать вдоль и поперёк.

Может быть, в твоём случае это не критично, но оный backtrace сильно зависит от glibc, и, например, на FreeBSD работать не будет.

Это исключительно для личного тестирования в моих локальных branch'ах, так что с кроссплатформенностью это проблем не вызовет.

runtime ★★★★
() автор топика
Ответ на: комментарий от undet

да еще и на производительности сказывается
а применение очевидно — в ошибках дизайна

trashymichael ★★★
()
Ответ на: комментарий от runtime

лучше тогда просто добавить отладочный вывод в каждую функцию.
тогда будет понятней, кто-куда-откуда...

xydo ★★
()

>C

а можно ли...

Заведомо можно, но через одно место.

anonymous
()
Ответ на: комментарий от xydo

угу трейс это одно а какая функа текущая да и весь стек можно и в отладчике посмотреть в чем приимущество такого подхода над просмотром стека вызовов в подключенном отладчике ?

osox
()
Ответ на: комментарий от Nakgidveef

это шутка ? у меня почему то 90 % процентов времени уходит на то что я в отладчике прогоняю сложные места пошагово вылавливаю баги таким образом так лучше думается да и интересно было бы посмотреть на вас как вы пишите удаление узла с обоими сыновьями из дерева без отладчика ну или на худой конец трейса

osox
()
Ответ на: комментарий от osox

То, что вы не можете уследить за ходом работы собственной программы (удаление ноды - ну просто очень сложная операция), огромный минус вам, как программисту. Отладчик для экстренных случаев, когда что-то глобально пошло не так.

staseg ★★★★★
()
Ответ на: комментарий от osox

>интересно было бы посмотреть на вас как вы пишите удаление узла с обоими сыновьями из дерева без отладчика

Делал я такое, без отладчика.

Nakgidveef
()

2 osox

>и ?

Чо и? Ты же сам просил.

Это был совет. Высока ты выдумал сам. А почему это тебя вдруг так заплющело с пусть даже высокомерного, как тебе показалось совета, разбирайся сам. Программист должен уметь думать головой, а не оладчиком - вот и все мое имхо.

Посылаю тебе лучики добра и любви. Чао!

staseg ★★★★★
()
Ответ на: комментарий от runtime

backtrace, backtrace_symbols

к сожалению, хорошо работает это только на x86; на SH4, например, позволяет получть только один уровень (непосредственно caller'а)

jtootf ★★★★★
()
Ответ на: комментарий от runtime

>Это исключительно для личного тестирования в моих локальных branch'ах, так что с кроссплатформенностью это проблем не вызовет.

Тогда юзай __func__ без страха. Он в будущем и стандартом станет, так что и оборачитвать не надо. Туда-же __LINE__ и __FILE__. А если C++, то и __PRETTY_FUNCTION__ в помощь.

legolegs ★★★★★
()
Ответ на: комментарий от legolegs

+1,

Быдлокодеру намекнули, что неплохо бы пользоваться мозгом, а не отладчиком, а у него возникла ужасная попоболь.

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

thrall
()
Ответ на: комментарий от osox

А где Вы научились такой феерической расстановке знаков препинания?

anonymous-kun
()
Ответ на: 2 osox от staseg

#define MORRISON

))))

мммм)) Doors)))

m4n71k0r
()

SystemTap же, ну или DTrace на других платформах

anonymous
()
Ответ на: комментарий от osox

бывают случаи, когда отладчик недоступен.

xydo ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.