Post em Destaque

Comandos que todo bom admin deveria saber

Esse documento não é novo mas muitos que estão chegando ainda não leram e acredito que ele seja muito importante na vida de qualquer administrador de sistemas. É um guia de referência pra qualquer hora do dia ou quando necessitar. O man também é muito importante na dúvida de um comando. Aqui...

Leia mais...

Depurando programas no FreeBSD

Postado por Otacílio | Categoria Dicas | Dia 15-04-2013

5

Introdução

 

Ao escrever um programa que esteja um pouco além do tradicional “Hello World!” o desenvolvedor precisa saber utilizar as ferramentas de depuração disponíveis no sistema. Sem elas, depurar um aplicativo que não seja básico é algo trabalhoso. Se programas básicos são trabalhosos de depurar, programas que utilizam apontadores podem tornar-se um verdadeiro suplício.

No FreeBSD estão disponíveis várias ferramentas de depuração, das quais, algumas serão abordadas.  São elas DDD, Valgrind e o recurso de cobertura de código do GCC.

 

Depurando programas com o DDD

 

O Data Display Debugger, ou DDD, é uma interface para o gdb, tornando o uso deste último bem mais amigável para o usuário. Para usar o DDD obviamente é necessário que o mesmo esteja presente no sistema. Para instalá-lo o usuário pode utilizar o ports do FreeBSD. Assim, pode-se executar os seguintes comandos para realizar a instalação:

# (cd /usr/ports/devel/ddd && make install clean)

 

Escrevendo o programa exemplo

 

Depois de instalar o DDD escreva o seguinte programa exemplo em C que implementa uma pilha, para em seguida depurá-lo.

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

typedef struct no_s{
    int         payload;
    struct no_s    *next;
}no_t;

void push(no_t **pilha, int elemento){
    no_t    *aux;

    aux = malloc(sizeof(no_t));
    aux->payload = elemento;    
    aux->next = *pilha;    
    *pilha = aux;
}

int pop(no_t **pilha){
    no_t    *aux;
    
    aux = *pilha;   
    *pilha = (*pilha)->next;
    return aux->payload;
}

int main(int argc, char **argv){
    no_t    *pilha;
    int     elemento;

    printf(“Informe um elemento maior que 0 para empilhar e menor que 0 para desempilhar todos\n”);
    do{        
        scanf(“%u”, &elemento);
        if(elemento >= 0){
            push(&pilha, elemento);
        }
    }while(elemento >=0);    

    printf(“============================\n”);

    while(pilha != NULL){
        printf(“%u\n”, pop(&pilha));
    }
    
    return 0;
}

Salve este programa como pilha.c e compile o mesmo com o comando:

$ gcc -Wall -o pilha pilha.c

Atenção! Ao copiar o texto do browser, as aspas que o browser exibe não são as reconhecidas pelo compilador C, então você deve substitui-las manualmente.

O programa deve compilar sem nenhum erro.

Execute o programa e forneça as entradas 1, 2, 3, -1. O programa imprime as saídas 3, 2 e 1 e depois apresenta um erro.

$ ./pilha
Informe um elemento maior que 0 para empilhar e menor que 0 para desempilhar todos
1
2
3
-1
============================
3
2
1
Segmentation fault: 11 (imagem do núcleo gravada)

Para encontrar a causa da falha de segmento compile novamente o programa adicionando o parâmetro -g para que o GCC adicione os símbolos de depuração no executável.

$ gcc -Wall -g -o pilha pilha.c

Execute novamente o programa com os mesmos parâmetros de entrada: 1, 2, 3 e -1.

O programa termina novamente com um erro, sendo que dessa vez uma imagem de memória com os símbolos necessários para depuração foi criada. O arquivo com a imagem é o pilha.core.

 

Depurando o arquivo pilha.core

 

Execute o ddd informando o programa que será depurado.

$ ddd pilha

Em seguida abra o arquivo pilha.core utilizando as opções de menu “File->Open Core Dump…”

O DDD mostra exatamente a linha que causou o problema adicionando uma seta vermelha à mesma. Uma outra informação bastante útil é a pilha de chamadas de rotinas. Esta mostra o caminho que o programa seguiu até o momento em que executou a operação ilegal. Para visualizar a pilha de chamadas usa-se a opção de menu “Status->Backtrace…”.

backtrace_de_chamadas

 

 

 

 

 

 

A janela exibe a sequência de chamadas de todas as rotinas até o ponto em que o problema ocorreu, inclusive com a linha da rotina .

 

Adicionando um ponto de parada

 

Para adicionar o ponto de parada procure a linha com a seta vermelha do lado dela.  Clique com o botão direito e selecione “Set Breakpoint”. Execute novamente o programa teclando em F3, sendo que o cursor deve estar na janela de mensagens do DDD.

Dica: Eu gosto de executar o programa com a seguinte opção marcada: “Program->Run in Execution Window”.  Dessa forma o ddd sempre executa o programa em um terminal próprio impedindo a poluição que normalmente ocorre quando a entrada e saída de dados é feita diretamente na janela.

Durante a execução, o DDD vai pará-lo exatamente no ponto onde está configurado o breakpoint. Neste, pode-se iniciar a execução passo-a-passo. Para executar o programa linha por linha sem entrar nas chamadas de sub-rotina usa-se a tecla F5, para “entrar” nas chamadas de sub-rotina a tecla a ser usada é a F6. Para continuar a execução normalmente usa-se a tecla F9.

 

Visualizando o conteúdo de variáveis

 

Executar o programa passo a passo observando os valores das variáveis pode ajudar muito a encontrar o erro.  Para isto, neste programa, adiciona-se um ponto de parada na linha correspondente ao segundo while (linha 40). Para isso clique com o botão direito e selecione “Set Breakpoint” na inha 40 e remova o da linha 22 clicando com o botão direito na mesma e escolhendo a opção de menu “Disable Breakpoint” para desabilitar ou “Delete Breakpoint” para remover. Execute novamente  programa pressionando F3 (com o cursor na janela de mensagens do DDD) e entre com os valores 1, 2, 3, -1. O programa deve parar no local da placa de “STOP”.

Muito bem, para examinar o estado da lista encadeada utilizada na implementação da pilha, clique com o botão direito sobre a variável “pilha” e selecione “Display pilha”. A variável deve ser exibida na área destinada a exibição de variáveis. Nesta região, clique novamente com o botão direito sobre o quadro onde é exibida a variável “pilha” e selecione “Display *()”. Clique agora sobre o campo “next” do quadro apontado por “pilha” e selecione “Display *()”. Repita a operação sobre os quadros que vão surgindo inclusive para o quadro com o payload = 1. Sua tela deve estar como na imagem abaixo:

Captura_de_tela

 

 

 

 

 

Observe que o último campo “next” aponta para uma posição inválida diferente de NULL (0x0). Este é o erro então. O laço iterage até que o valor NULL seja encontrado, mas este nunca o é porque a variável não foi inicializada como tal. Para consertar o bug procure a linha 31 onde a variável “*pilha” é declara e substitua a linha por:

no_t    *pilha=NULL;

Compile o programa. Abra-o novamente no DDD usando a opção “File->Open Program…”  e execute-o com F3,  informando os mesmos valores de entrada. Quando o programa parar na placa “STOP” aperte F9 para continuar a execução. O erro não deverá ocorrer mais.

 

 Conclusões

 

Neste post foi tratado o básico da depuração de um programa C utilizando o software de interface gráfica para o gdb, o DDD. Com este, foi possível encontrar o erro que fazia com o que o programa pilha.c abortasse. Além disso, visualizou-se a lista encadeada utilizada na representação da pilha permitindo a fácil compreensão de como os dados estavam organizados na memória.  Isto é particularmente útil quando se está trabalhando com estruturas de dados que utilizam listas encadeadas.

 

 

O Valgrind e a cobertura de código serão tratados em outros posts futuros.

Um abraço para todos.

-Otacílio

Share Button

Comments (5)

replica hermes scarf…

shearlings, which add a nice touch with all its details. I think Louis Vuitton outdid themselves for this collection. Bravo!Price Increase For Chanel Bags Saving up for…

Article writing is also a fun, if you be acquainted with after that you can write if not it is complicated to
write.

louis vuitton knockoffs handbags…

Hello, your articles here » Blog Archive » Depurando programas no FreeBSD to write well, thanks for sharing!…

Esse tal de Ota é desenrolado mesmo!

Hi there! This post couldn’t be written any better!
Looking at this post reminds me of my previous roommate! He constantly kept preaching about this.
I am going to forward this article to him. Pretty sure he’s going to have a very good read.
Thanks for sharing!

Write a comment

*