Ferramenta para imprimir as funções sendo chamadas durante o tempo de execução?

2

Estou procurando esse tipo de ferramenta em qualquer plataforma Unix / Linux que possa alcançar:

  1. Eu tenho os arquivos fonte e eu mesmo compilei o aplicativo (o código-fonte está em C, embora eu não ache que isso realmente importe aqui)
  2. Desejo executar este aplicativo enquanto todas as chamadas de função são impressas / registradas em um arquivo stdout / file

Por exemplo:

#include <stdio.h>
int square(int x) { return x*x; }
int main(void) {
    square(2);
}

E quando eu executar este programa, ele será impresso

  • principal
  • quadrado

Eu entendo que gdb pode fazer isso até certo ponto, ou valgrind , mas eles não fazem exatamente o que eu quero. Eu só estou querendo saber se tal ferramenta existe? Obrigado.

    
por dorafmon 17.08.2017 / 18:42

2 respostas

5

Usando gcov :

$ gcc -O0 --coverage square.c
$ ./a.out
$ gcov -i square.c
$ awk -F '[,:]' '$1 == "function" && $3 > 0 {print $3, $4}' square.c.gcov
1 square
1 main

(onde o número é o número de vezes que a função foi chamada (pulamos os que nunca são chamados com $3 > 0 na parte awk )).

Isso é normalmente usado para cobertura de código (quanto do código está sendo testado). Você também pode usar a ferramenta de criação de perfil de código gprof (normalmente usada para descobrir quanto tempo é gasto em várias áreas do código):

$ gcc -O0 -pg square.c
$ ./a.out
$ gprof -b -P
            Call graph


granularity: each sample hit covers 2 byte(s) no time propagated

index % time    self  children    called     name
        0.00    0.00       1/1           main [7]
[1]      0.0    0.00    0.00       1         square [1]
-----------------------------------------------

Index by function name

   [1] square
    
por 17.08.2017 / 18:51
2

Para que o executável imprima os nomes das funções à medida que são chamados, em um sistema GNU, você pode usar a opção gcc do -finstrument-functions e dladdr() para traduzir endereços para nomes de função.

Crie um instrument.c como:

#define _GNU_SOURCE
#include <dlfcn.h>

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

#define TRACE_FD 3

void __cyg_profile_func_enter (void *, void *)
   __attribute__((no_instrument_function));

void __cyg_profile_func_enter (void *func,  void *caller)
{
  static FILE* trace = NULL;
  Dl_info info;

  if (trace == NULL) {
    trace = fdopen(TRACE_FD, "w");
    if (trace == NULL) abort();
    setbuf(trace, NULL);
  }
  if (dladdr(func, &info))
    fprintf (trace, "%p [%s] %s\n",
             func,
             info.dli_fname ? info.dli_fname : "?",
             info.dli_sname ? info.dli_sname : "?");
}

Em seguida, compile seu executável como:

$ gcc -O0 -rdynamic -finstrument-functions square.c instrument.c -ldl
$ ./a.out 3>&1
0x400a8f [./a.out] main
0x400a4f [./a.out] square

(aqui usando o fd 3 para gravar os nomes das funções para mantê-los separados dos fluxos stdout e stderr).

Você pode adaptar o código para imprimir apenas o dli_sname se desejar apenas o nome da função.

    
por 18.08.2017 / 11:46