Analisando fluxo de execução com o cflow

- por Sergio Prado

Categorias: Linguagem C Tags: ,

Identificar o fluxo de execução de uma aplicação é fácil usando a ferramenta cflow do projeto GNU.

A partir do código-fonte de uma aplicação, a ferramenta é capaz de encontrar e exibir o fluxo de execução completo da aplicação de forma hierárquica e intuitiva, e pode facilitar bastante nosso trabalho, principalmente quando precisamos analisar um código mais complexo que não seja de nossa autoria.

O uso da ferrramenta é bem simples. Dado o código-fonte da aplicação:

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
 
int show(const char *str, int times)
{
    printf("Message: %s\n", str);
}
 
int main(int argc, const char *argv[])
{
    show("Hello!", 0);
    return 0;
}

Basta rodar o cflow sobre ele:

$ cflow main.c
main() <int main (int argc, const char *argv[]) at main.c:8>:
    show() <int show (const char *str, int times) at main.c:3>:
       printf()

Dá para ter uma noção melhor da utilidade da ferramenta em um código-fonte maior ou mais complexo. No exemplo abaixo, estou executando o cflow no código-fonte do comando wc:

$ cflow wc.c
main() <int main (int argc, char **argv) at wc.c:127>:
    errf() <void errf (char *fmt, ...) at wc.c:34>:
        va_start()
        error_print() <void error_print (int perr, char *fmt, va_list ap) at wc.c:22>:
            vfprintf()
            perror()
            fprintf()
            exit()
        va_end()
    counter() <void counter (char *file) at wc.c:108>:
        fopen()
        perrf() <void perrf (char *fmt, ...) at wc.c:46>:
            va_start()
            error_print() <void error_print (int perr, char *fmt, va_list ap) at wc.c:22>:
                vfprintf()
                perror()
                fprintf()
                exit()
            va_end()
        getword() <int getword (FILE *fp) at wc.c:78>:
            feof()
            getc()
            isword() <int isword (unsigned char c) at wc.c:64>:
                isalpha()
            COUNT()
        fclose()
        report() <void report (char *file, count_t ccount, count_t wcount, count_t lcount) at wc.c:57>:
            printf()
    report() <void report (char *file, count_t ccount, count_t wcount, count_t lcount) at wc.c:57>:
        printf()

Com o auxílio das ferramentas cflow2dot e dot, é possível gerar uma versão gráfica do fluxo de execução:

$ cflow --format=posix --omit-arguments --level-indent='0=\t' --level-indent='1=\t' --level-indent=start='\t' wc.c | cflow2dot | dot -Tjpg -o wc.dot && eog wc.dot

wc

A ferramenta tem algumas deficiências, como não lidar muito bem com ponteiros de função e chamadas condicionais, mas pode ajudar bastante em situações específicas de análise de código.

À propósito, é possível conseguir um resultado parecido com o plugin CCTree do Vim:

vim-cctree

Happy hacking!

Sergio Prado

Sem Comentários

Nenhum comentário até agora... é a sua chance de ser o primeiro a comentar!

Faça um Comentário

Navegue
Creative Commons Este trabalho de Sergio Prado é licenciado pelo
Creative Commons BY-NC-SA 3.0.