# Dados gerais
## Autoria

Arthur Henrique (warthur@gmail.com), Danilo Inácio (danilo.isr@gmail.com), Luíla Moraes (luilamoliveira@gmail.com), Paulo Júnior (pjuniorlima@gmail.com)

## Licenciamento

Beerware em conjunto com a Attribution Non-Commercial Share Alike

## Créditos
# Objetivo e descrição

Demonstrar tecnicas de debug utilizando o método ictl
O método ioctl (i-o-control) é uma chamada no sistema que possibilita a transferência de dados do módulo para o espaço do usuário. Essa técnica é bastante utilizada para debugar módulos, já que podemos obter dados do módulo. Essa técnica é mais eficiente que o uso do sistema de arquivos /proc, por ser mais rápida que a leitura de arquivos no /proc, pois acessar os dados binários (ioctl) é mais eficiente que em texto(/proc), em contra partida o método ioctl é um pouco mais complexo que a administração de arquivos /proc.
Para usar este método devemos implementar o método device_ioctl no código do módulo, a seguir um exemplo do código comentado que pode ser encontrado aqui:
* * Está função recebe 4 parâmetros, os dois primeiros são comuns às
* * chamadas de modulos, e os dois últimos são o número da chamada
* * ioctl e o parametro passado
* int device_ioctl(struct inode *inode,
* struct file *file,
* unsigned int ioctl_num,
* unsigned long ioctl_param)
* int i;
* char *temp;
* char ch;
* * Switch para o número da chamada
* switch (ioctl_num) {
* case IOCTL_SET_MSG:
* * Pega o ponteiro da mensagem passada por parâmetro para esta
* * função. O ponteiro 'temp' pertence a este módulo
* temp = (char *)ioctl_param;
* * Calcula o tamanho da mensagem passada, o tamanho ficará
* * armazenado na variável 'i'. A função 'get_user' é usada para
* * transferir dados do ambiente do usuário para o módulo
* get_user(ch, temp);
* for (i = 0; ch && i < BUF_LEN; i++, temp++)
* get_user(ch, temp);
* * Chama a função que escreve no módulo
* device_write(file, (char *)ioctl_param, i, 0);
* break;
* case IOCTL_GET_MSG:
* * Passa a mensagem atual do módulo para o ponteiro passado
* * por parâmetro usando a função device_read.
* i = device_read(file, (char *)ioctl_param, 99, 0);
* * Finaliza a string com um '\0'
* put_user('\0', (char *)ioctl_param + i);
* break;
* case IOCTL_GET_NTH_BYTE:
* * Retorna o caractere na possição passada por parâmetro
* return Message[ioctl_param];
* break;
* return SUCCESS;
Veja que para realizar o switch utilizamos o parâmetro ioctl_num. Os valores contidos neste parâmetros são gerados através dos seguintes macros (_IO, _IOR, _IOW ou _IOWR). Estes valores devem ser definidos em um arquivo compartilhado entre o módulo é a aplicação que fará a chamada iocrl. No nosso exemplo temos o seguinte header:
* /* chardev.h - header para o módulo é o programa
* * que utilizará a chamada ioctl
* #ifndef CHARDEV_H
* #define CHARDEV_H
* #include <linux/ioctl.h>
* /* Definição no major number do módulo, que deve ser
* * estática para que a chamada ioctl identifique
* * o módulo */
* #define MAJOR_NUM 100
* /* Define a função set_msg utilizada */
* #define IOCTL_SET_MSG _IOR(MAJOR_NUM, 0, char *)
* /* O macro _IOR cria um número do método que iremos
* * utilizar os parâmetros definidos.
* * O primeiro argumento é para que o ioctl identifique
* * o módulo.
* * O segundo parâmetro é para identificar o método
* * The second argument is the number of the command
* * (there could be several with different meanings).
* * O terceiro é o tipo do retorno iremos passar para
* * o módulo.
* /* Pega uma mensagem do módulo */
* #define IOCTL_GET_MSG _IOR(MAJOR_NUM, 1, char *)
* /* O terceiro parâmetro aqui receberá o retorno
* * da chamada.
* /* Pega o caractere na posição n */
* #define IOCTL_GET_NTH_BYTE _IOWR(MAJOR_NUM, 2, int)
* /* Este é um exemplo de como passar e pegar um parâmetro
* * para o módulo.
* * Aqui passamos a posição do caractere que queremos
* * e recebemos ele. */
* #endif
Agora escrevemos o programa que irá se comunicar com o módulo através da chamada ioctrl. Eis um trecho do arquivo ioctl.c :
* /* Função que recebe uma mensagem do módulo
* ioctl_get_msg(int file_desc)
* int ret_val;
* char message[100];
* /* Chama a função ioctl passando o parâmetro definido
* * no arquivo header.
* ret_val = ioctl(file_desc, IOCTL_GET_MSG, message);
* if (ret_val < 0) {
* printf("ioctl_get_msg failed:%d\n", ret_val);
* exit(-1);
* printf("get_msg message:%s\n", message);
Essa função retorna a mensagem gerada pelo módulo (veja que usando o método ioctl podemos interagir com o módulo em qualquer momento, diferente dos outros métodos de debug).

# Código-fonte

O código completo da aplicação pode ser encontrada aqui, e em nossa implementação obtemos a quantidade de caracteres que já foram escritos no módulo. Isso pode ser interessante para se criar uma ferramenta que gera estatísticas em tempo real do status do módulo.

# Procedimentos para testes

* Configurar o ambiente para desenvolvimento de módulos. (passos aqui)
* Extrair o conteúdo do pacote 'ioctl.tar.gz' para uma pasta
* Dentro da pasta executar o comando 'make'
* Executar os comandos
** insmod ioctl_dev.ko
** mknod ioctl_dev c 100 0
** gcc -o ioctl ioctl.c
** ./ioctl

# Considerações finais

O desenvolvimento deste trabalho foi prejudicado devido a quantidade materiais disponíveis, devido a esse fator demoramos a focar nosso trabalho em uma área. Depois de alguns teste escolhemos documento o método ioctl devido sua comunicação instantânea com o módulo, que permite o desenvolvimento de aplicações interessantes, como monitoramento de módulos.

# Referências

[1] The Linux Kernel Module Programming Guide http://tldp.org/LDP/lkmpg/2.4/html/index.html
[2] Talking to Device Files (writes and IOCTLs) http://tldp.org/LDP/lkmpg/2.4/html/x856.html#AEN915
[3] Linux Device Drivers, Third Edition http://lwn.net/Kernel/LDD3/