Introdução aos Sistemas Operacionais/Exemplo de técnica de Debug: Debug com printk
Dados gerais
[editar | editar código-fonte]Autoria
[editar | editar código-fonte]- Marcos André Oliveira - Matr. 060207 ( marcosandre19@gmail.com )
- Murilo A. Vasconcelos - Matr. 094816 ( muriloufg@gmail.com )
- Paulo Cezar P. Costa - Matr. 080153 ( paulocezar.ufg@gmail.com )
- Vinicius Vieira Pessoni - Matr. 080160 ( viniciuspessoni@gmail.com )
Licenciamento
[editar | editar código-fonte]GPL
Créditos
[editar | editar código-fonte]Objetivo e descrição
[editar | editar código-fonte]- Debug via Impressão ( printk() )
Depurar o kernel não é algo tão complicado. Na verdade pode ser uma tarefa simples,
que exige o domínio de técnicas simples, e um bocado de paciência e perseverança.
Uma das técnicas mais comuns e simples de depurar o que está acontecendo com a aplicação é atravez
de impressões em pontos estratégicos do código e o mesmo pode ser feito quando queremos debugar o
código do kernel, o que é possível graças à função printk().
A função printk() é, em espaço de núcleo, equivalente a função printf() disponível apenas no
espaço de usuário. Apesar de bastante semelhante à função printf(), printk() tem algumas diferenças,
entre elas a possibilidade classificar as mensagem de acordo com sua gravidade associando diferentes
níveis e prioridades as mensagens. Tal diferenciação é feita com o uso de macros que estão definidas
no arquivo de cabeçalho "linux/kernel.h".
Tais macros são:
- KERN_EMERG - Indicando uma mensagem de emergência.
- KERN_ALERT - Indicando uma situção que necessita de ação imediata.
- KERN_CRIT - Aponta uma condição crítica, geralmente relacionada a falhas graves de hardware ou software.
- KERN_ERR - Indica que algum erro ocorreu, geralmente drivers comunicam falhas de hardware atravéz dessa macro.
- KERN_WARNING - Usada para reportar situações problemáticas que não prejudicam muito o sistema.
- KERN_NOTICE - Geralmente para situações que, apesar de normais, merecem atenção.
- KERN_INFO - Mensagens meramente informativas, indicando o estado do hardware ou de variáveis.
- KERN_DEBUG - Mensagens de debug para rastrear em que ponto do codigo a aplicação se encontra.
O printk é utilizado da seguinte maneira:
- printk( MACRO "MENSAGEM" <, variaveis > );
em tempo de compilação a macro é convertida para uma string de mensagem e incorporada à mensagem que será impressa.
Código-fonte
[editar | editar código-fonte] /*
* flash.c - Blink keyboard leds until the module is unloaded.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/tty.h> /* For fg_console, MAX_NR_CONSOLES */
#include <linux/kd.h> /* For KDSETLED */
#include <linux/vt.h>
#include <linux/console_struct.h> /* For vc_cons */
MODULE_DESCRIPTION("Example module illustrating the use of Keyboard LEDs.");
MODULE_AUTHOR("Daniele Paolo Scarpazza");
MODULE_LICENSE("GPL");
extern int fg_console;
struct timer_list my_timer;
struct tty_driver *my_driver;
char kbledstatus = 0;
#define BLINK_DELAY HZ/5
#define ALL_LEDS_ON 0x07
#define RESTORE_LEDS 0xFF
static void my_timer_func(unsigned long ptr)
{
int *pstatus = (int *)ptr;
if (*pstatus == ALL_LEDS_ON)
{
#ifdef MODULE_DEBUG
printk( KERN_NOTICE "Todos os leds estao acesos!\n");
#endif
*pstatus = RESTORE_LEDS;
}
else
{
*pstatus = ALL_LEDS_ON;
}
((my_driver->ops)->ioctl) (vc_cons[fg_console].d->vc_tty, NULL, KDSETLED, *pstatus);
my_timer.expires = jiffies + BLINK_DELAY;
add_timer(&my_timer);
}
static int __init kbleds_init(void)
{
int i;
#ifdef MODULE_DEBUG
printk(KERN_INFO "Iniciando o modulo em modo de DEBUG\n");
#endif
printk(KERN_INFO "kbleds: loading\n");
printk(KERN_INFO "kbleds: fgconsole is %x\n", fg_console);
for (i = 0; i < MAX_NR_CONSOLES; i++)
{
if (!vc_cons[i].d) break;
printk(KERN_INFO "poet_atkm: console[%i/%i] #%i, tty %lx\n", i,
MAX_NR_CONSOLES, vc_cons[i].d->vc_num,
(unsigned long)vc_cons[i].d->vc_tty);
}
printk(KERN_INFO "kbleds: finished scanning consoles\n");
my_driver = vc_cons[fg_console].d->vc_tty->driver;
printk(KERN_INFO "kbleds: tty driver magic %x\n", my_driver->magic);
#ifdef MODULE_DEBUG
printk( KERN_NOTICE "Criando timer..\n");
#endif
init_timer(&my_timer);
#ifdef MODULE_DEBUG
printk( KERN_NOTICE "Timer criado.\n");
#endif
my_timer.function = my_timer_func;
my_timer.data = (unsigned long)&kbledstatus;
my_timer.expires = jiffies + BLINK_DELAY;
add_timer(&my_timer);
#ifdef MODULE_DEBUG
printk( KERN_NOTICE "Modulo Inicializado com sucesso!\n");
#endif
return 0;
}
static void __exit kbleds_cleanup(void)
{
printk(KERN_INFO "kbleds: unloading...\n");
#ifdef MODULE_DEBUG
printk(KERN_INFO "Finalizando o modulo...\n");
#endif
del_timer(&my_timer);
#ifdef MODULE_DEBUG
printk( KERN_NOTICE "Timer deletado.\n");
#endif
((my_driver->ops)->ioctl) (vc_cons[fg_console].d->vc_tty, NULL, KDSETLED,
RESTORE_LEDS);
}
module_init(kbleds_init);
module_exit(kbleds_cleanup);
|
Procedimentos para testes
[editar | editar código-fonte]Para testar o basta executar o comando make usando o Makefile abaixo
alterando o valor da variável DEBUG para qualquer coisa diferente de y as mensagens
de debug são desativadas.
KER_DIR := /lib/modules/$(shell uname -r)/build
DEBUG = y
obj-m = flash.o
ifeq ($(DEBUG),y)
DEBFLAGS = -O -g -DMODULE_DEBUG
else
DEBFLAHS = -O2
endif
EXTRA_CFLAGS += $(DEBFLAGS)
all:
$(MAKE) -C $(KER_DIR) M=$(PWD) modules
@rm -rf *.mod* Module.symvers *.o *~ *.makers *.order
clean:
@rm -rf *~ *.o *.ko
|
Considerações finais
[editar | editar código-fonte]Inicialmente tivemos várias dúvidas sobre o que deveria ser feito no trabalho, o que acreditamos ter sido
o principal empecilho para que fosse produzido um material com mais qualidade. Quando nos demos
conta do que deveria ser feito o tempo já estava curto, e o trabalho pode ter acabado ficando meio simplista.
Escolhemos fazer o debug usando printk(), uma forma bem simples e poderosa de depurar o código,
não tanto por suas características, mas pelo menos para a maioria do grupo, devido ao fato que estamos
acostumados a depurar nossos algoritmos dessa forma.
A principal dificuldade foi controlar quando as mensagens devem ou não aparecer.
Fizemos isso definindo uma variável que deve ser ativada ou desativada no Makefile, porém
a intenção era definir um alvo, "debug", assim quando fosse executado "make debug", o módulo seria
compilado para executar em modo debug, e quando o comando fosse apenas "make" a execução ocorreria
normalmente.
Referências
[editar | editar código-fonte][1] Linux Device Drivers 3rd Edition
[2] The Linux Kernel Module Programming Guide
[3] Linux Kernel Documentation