Configurando User
Mode Linux [UML]
e um ambiente para desenvolvimento
e
depuração do kernel do Linux
Copyright (c) 2007 Rodrigo Ferreira Baroni .
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.2
or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
Texts. A copy of the license is included in the section entitled "GNU
Free Documentation License".
Uma Máquina Virtual é um termo que possui
diferentes significados na Ciência da
Computação. Esta página refere-se a
como configurar e construir uma máquina virtual com significado de um
computador fictício criado por software, sendo executado em forma de
aplicação no espaço do
usuário, dentro de um sistema GNU/Linux. Tal
software que simula o computador fictício
descrito neste documento emprega a
virtualização dos recursos no nível do sistema
operacional; é composto por dois componentes:
1) Um sistema operacional executando no espaço
do usuário - um kernel apropriado (e
User-Mode-Linux é o projeto responsável por tal kernel); e
2) Programas no espaço do usuário - disponíveis sob um
sistema de arquivos.
Este documento descreve os passos para criar tais
componentes e integrá-los, obtendo no final
uma máquina virtual GNU/Linux dentro de outra
sendo executada no computador. Nó utilizamos
na construção do sistema de arquivos, um
sistema Debian, utilizando a ferramenta
específica 'debbootstrap', mas tal ferramenta
pode também ser instalada em outros sistemas
conforme descrito no final deste documento, o
que abrange este documento para ser utilizado por
qualquer distribuição GNU/Linux. Após a
criação da Máquina Virtual, é descrito como
utilizá-la para o desenvolvimento e depuração do kernel do
Linux, e o ambiente de desenvolvimento com os procedimentos para
integração das alterações no kernel com a etapa de
testes e depuração.
O documento é organizado em 4 partes:
- Parte I : Criando e configurando um kernel UML
- Parte II : Criando e configurando um sistema de arquivos
- Parte III : A máquina virtual: a utilização e o ambiente para desenvolvimento e depuração do kernel do linux
- Parte IV : Soluções para eventuais problemas
A última atualização deste documento é de Abril 14, 2007 - fique atento, pois configurações mudam com o tempo, e as documentações se tornam obsoletas (e já há muita documentação na internet sobre configuração de uma máquina virtual utilizando user-mode-linux que está obsoleta). Contribuições são sempre bem vindas, caso encontre falhas/sugestões e ainda tempo e disposição, mande-a via rodrigoferreirabaroni@gmail.com .
Agradecimentos à todos que contribuíram, ao professor Roberto Hirata do IME-USP que durante o curso de Sistemas Operacionais no instituto, permitiu e incentivou a elaboração deste documento enquanto fui monitor da disciplina, ao IME-USP e à CAPES pelas oportunidades que permitiram o envolvimento com este estudo, além dos desenvolvedores envolvidos no desenvolvimento de toda a plataforma GNU/Linux, base de computação séria e com compromisso com a preservação do livre acesso ao conhecimento da ciência e da tecnologia, incluindo os envolvidos no projeto User-Mode-Linux!
Parte I - Criando e configurando um kernel UML
O primeiro passo é criar um kernel UML. Um kernel
UML é um kernel em que toda
comunicação que seria feita com os
dispositivos físicos afim de controlá-los
e gerenciá-los é modificada, de modo que
os recursos físicos sejam obtidos através
do kernel tradicional sendo executado no computador. No
início era um projeto disponível em forma
de patch a ser aplicado no kernel, atualmente (desde a
versão 2.6.9) está disponível no
próprio kernel - não e´
mais necessário aplicar patches, com
exceção dos patches de
otimizações extras do blaisorblade. Segue
abaixo os procedimentos necessários para gerar um
kernel UML.
- 1) Baixando a árvore do kernel do Linus com o git (apt-get install git-core) Entre no diretório desejado a colocar a os fontes do kernel (tradicionalmente /usr/src):
- 3) Compile o kernel UML: Limpamos as configurações anteriores (quando existir - no caso de querer 'limpar' a árvore após realizar diferentes configurações e compilar várias vezes, trazendo a árvore para o estado original):
- 1) Instalando um sistema debian em um diretório
- 2) Gerando um sistema de arquivos em um arquivo e ajustando suas configurações para o uso com o kernel uml
- 3) Configurando a rede da máquina virtual uml
- 1) Utilização da máquina virtual UML:
- 2) Ambiente para desenvolvimento do kernel do linux
- A) Criando/alterando código do kernel diretamente em algum de seus arquivos fonte
- B) Criando/alterando código de algum módulo em algum de seus arquivos fonte
- C) Criando código para construção de um módulo externo aos arquivos fonte do kernel
- 3) Ambiente para depuração do kernel do linux
- A) Depuração do kernel
- B) Depuração de módulos
$ cd /usr/src/Obtenha a árvore:
git-clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git \ linux-2.6-linus-gittreeIsso vai criar o diretório linux-2.6-linus-git/ (em /usr/src/) . Esta árvore possui todo o histórico de desenvolvimento da árvore do kernel. É possível ver o que mudou em cada arquivo executando: $ gitk kernel/fork.c (por exemplo, para ver as alterações que têm sido feitas em tal arquivo, ou então só 'gitk' para ver o histórico de todos os arquivos). Para manter os fontes da árvore atualizado com o desenvolvimento, execute o comando: $git-pull (dentro do diretório) regularmente.
$ cd /usr/src/linux-2.6-linus-gittreeVeja as marcações existentes:
$ ls .git/refs/tagsExtraia uma árvore desejada de desenvolvimento mais recente que possua o suporte ao UML - para isso, consulte no endereço do projeto: http://user-mode-linux.sourceforge.net/work/current/2.6/ e procure pela última versão (na data em que se escrevia esta parte deste documento - Abril 02 2007 - a última versão com patches disponíveis é a 2.6.21-rc1, portanto extrairemos tal versão).
$ git-archive --format=tar --prefix=v2.6.21-rc1.uml/ v2.6.21-rc1 | (cd ../ && tar xf -)Isto vai extrair a última árvore candidata a estável (no momento da escrita deste texto) e top de desenvolvimento - gerando o diretório v2.6.21-rc1.uml no diretório abaixo (/usr/src/v2.6.21-rc1.uml).
$ make mrproper
$ make mrproper ARCH=umPara gerar um .config apropriado para o uml (o arquivo .config é o que define as configurações do kernel):
$ make defconfig ARCH=umEntão para configurar o kernel, execute a interface gráfica (ncurses) com o comando abaixo. Instale a ncurses-dev (pacote libncurses5-dev) ('apt-get install libncurses5-dev'). Importante: não altere a configuração do tipo do processador no kernel uml (deixe a padrão), e habilite também a opção de compilar o kernel com frame pointers.
$ make menuconfig ARCH=umE então tente compilar o kernel:
$ make linux ARCH=umSe obtiver algum erro, veja como corrigir erros ao compilar o kernel no final deste documento - é necessário para a versão atual - 2.6.21-rc1 - que possui um erro, e necessita de uma correção, demonstrada no link.
E então compile os módulos:
$ make modules ARCH=umIsso vai gerar os executáveis "linux" e "vmlinux" na raíz do diretório dos fontes do kernel. Pode-se tentar executar o kernel agora, esperando que ele pare a execução com erro quando tentar montar o sistema de arquivos com o comando:
$ ./vmlinuxSe obtiver um erro indicando que falta de sistema de arquivos, está tudo ok, não há mais o que configurar para o kernel além do do sistema de arquivos (próxima parte). Mas pode ser que o seguite erro seja obtido:
PROT_EXEC mmap in /dev/shm/...failed: Operation not permittedÉ devido a restrição de segurança do sistema que não permite código ser executado em memória compartilhada. Tal restrição é resolvida configurando outro arquivo temporário para utilização como temporário: primeiro crie um diretório:
$ mkdir /tmp/umlDepois altere as permissões para o usuário configurado como 'dono' do kernel (execute '$ man chmod' para saber mais) seja o mesmo sob tal diretório (substitua 'user' pelo tal usuário do sistema que está configurado como dono do kernel):
$ chown user.user /tmp/umlDê permissões total para tal diretório:
$ chmod 777 /tmp/umlE finalmente exporte a variável do sistema que indica o diretório temporário:
$ export TMPDIR=/tmp/uml
Parte II - Criando e configurando um sistema de arquivos
Agora construímos um sistema de arquivos para
uso com o kernel uml. Segue abaixo os procedimentos
necessários.
Crie um diretório (aqui, nomeado root_fs) e, para manter as coisas relacionadas juntas, criemos tal sistema de arquivos dentro da próprio diretório dos fontes do kernel uml:
$ cd /usr/src/v2.6.21-rc1.uml/
$ mkdir root_fsEntão com o debootstrap instale um sistema debian em tal diretório, executando como root (se você estiver utilizando um sistema debian, instale com '$ apt-get install debootstrap', senão veja como baixar e instalar o deboostrap no final deste documento) com o comando abaixo. Isto vai criar um sistema Debian versão testing (pois no momento, o etch corresponde a versão testing - veja qual é a versão testing no momento no site www.debian.org/releases/) no diretório root_fs/ (de 167Mb). :
$ debootstrap etch root_fs/ http://ftp.debian.org/debian/
Caso esteje utilizando um processador AMD-64 em seu computador, substituta o comando acima pelo abaixo:
$ debootstrap --arch amd64 sarge root_fs/ http://amd64.debian.net/debian-amd64/
O kernel precisa de um __arquivo__ de sistema de arquivos, de onde ele irá acessá-lo. Para isso, primeiro, gere um arquivo com aproximadamente 200MB no diretório do kernel:
$ cd /usr/src/v2.6.21-rc1.uml/
$ dd if=/dev/zero of=linux_fs.ext3 bs=1M count=200Associamos um dispositivo de loopback com o sistema de arquivos do arquivo. Veja quais dispositivos estão disponíveis com o comando '$ losetup -f' (executando como root). A utilização do dispositvo de loopback é necessário para que o layout do sistema de arquivos (suas meta-informações, referentes ao sistema de arquivos), sejem corretamente inseridas no nosso arquivo com o sistema de arquivos:
$ losetup /dev/loop1 linux_fs.ext3Crie um sistema de arquivos no dispositivo (que foi associado com o arquivo):
$ mkfs.ext3 -j /dev/loop1Monte o 'sistema de arquivos' do arquivo em um diretório para o acessarmos:
$ mkdir /mnt/vmfs
$ mount -t ext3 -o loop linux_fs.ext3 /mnt/vmfsCopie os arquivos da distribuição Debian para o sistema de arquivos criado no arquivo:
$ cp -dpR root_fs/* /mnt/vmfs/Agora instalamos os módulos do kernel uml para os diretórios apropriados (/lib/modules/) no sistema de arquivos a ser utilizado por ele com os comandos (sem sair do diretório do kernel uml):
$ make modules_install INSTALL_MOD_PATH=/mnt/vmfs/ ARCH=umAgora configuramos o sistema a partir de alguns de seus arquivos de configuração. Primeiro edite o arquivo /mnt/vmfs/etc/inittab com um editor de textos, deixando apenas a primeira linha:
1:2345:respawn:/sbin/getty 38400 tty1Agora o arquivo /mnt/vmfs/etc/fstab - edite-o de forma a ficar com apenas o conteúdo abaixo:
#<file system> <mount point> <type> <options> <dump> <pass> /dev/ubd0 / ext3 defaults 0 0 /dev/ubd1 none swap sw 0 0 proc /proc proc defaults 0 0Isto indica que os arquivos /dev/ubd{0,1} do sistema principal serão utilizados como dispositivos pelo kernel uml como base para montar o sistema de arquivos a ser utilizado. Tais arquivos podem ser criados automaticamente no momento de sua utilização pelo devfs - no sistema principal que executa o computador, configure a interface udev, configurando os dispositivos ubdX editando o arquivo /etc/udev/links.conf (na distribuição Debian - em outras consulte o manual do udev da sua distribuição: 'man udev'), inserindo as linhas abaixo:
M ubd0 b 98 0 M ubd1 b 98 16 M ubd2 b 98 32 M ubd3 b 98 48 M ubd4 b 98 64 M ubd5 b 98 80 M ubd6 b 98 96 M ubd7 b 98 112ou podem também serem criados manualmente se desejar - entrando no diretório que ficam os arquivos associados com dispositivos e criando os arquivos com o comando abaixo:
$ cd /dev $ for i in 0 1 2 3 4 5 6 7; do mknod ubd$i b 98 $[ $i * 16 ]; doneE então crie um arquivo 'swap_file' a ser utilizado como dispositivo de swap do uml (de 200M):
$ dd if=/dev/zero of=swap_file count=200 bs=1M
$ mkswap swap_fileFinalmente desmontamos o sistema de arquivos destinado para a máquina virtual:
$ umount /mnt/vmfsDesassociamos ele do dispositivo loopback:
$ losetup -d /dev/loop1Atribuímos como dono do 'arquivo-sistema-de-arquivos' o mesmo que o do kernel uml (onde 'user' abaixo é o dono do kernel)
$ chown user.user linux_fs.ext3Deste modo, o arquivo linux_fs.ext3 será o sistema de arquivos.
Para configurar uma conexão de rede na máquina virtual utilizamos o método tun/tap. Tun/tap é uma conexão que associa uma interface com um endereção IP ou ETHERNET a um dispositivo (/dev/net/tun), de modo que quando um processo escreve um pacote para tal endereço da interface este será escrito no dispositivo /dev/net/tun, que entregará o pacote para a manipulação pela camada de rede do kernel do sistema operacional, que irá tratá-lo como se tivesse vindo de tal endereço de rede. Deste modo, tun/tap apresenta-se como um utilitário para comunicação entre processos do espaço do usuário - veja Documentation/networking/tuntap.txt para saber mais. É necessário ter habilitado o suporte a Tun/tap no kernel do sistema principal - veja se está verificando se a opção "CONFIG_TUN=y" no .config deste kernel (caso não esteja, recompile seu kernel com tal opção).
Será necessário um programa que configure o dispositivo /dev/net/tun em nível de programação - através de invocações IOCTL. Utilizaremos um programa disponível no próprio cvs do projeto uml - tunclt, para isso acesse o cvs e compile o aplicativo:
$ mkdir /usr/src/uml-project/ $ cd /usr/src/uml-project/ $ export CVS_UML=":pserver:anonymous@user-mode-linux.cvs.sourceforge.net:/cvsroot/user-mode-linux" $ cvs -d ${CVS_UML} login (sem senha) $ cvs -d ${CVS_UML} checkout tools $ cd tools/tunctl $ make
Teremos 3 interfaces distintas:
1) Interface eth0 no
sistema principal com endereço de rede
existente (representando uma rede interna do
sistema principal). Para
ilustração adoraremos um
endereço 192.168.0.1 na rede 192.168.0.[1-7],
netmask 255.255.255.248, gateway uma outra
interface que possua ip externo (se for o caso
de tiver conexão com internet);
2) Interface eth0 no sistema da máquina
virtual com endereço 192.168.1.2 na rede
192.168.1.[1-7], netmask 255.255.255.248, gateway a
interface descrita a seguir:
3) Interface tap0 no sistema principal com
endereço 192.168.1.1, na rede
192.168.1.[1-7], netmask 255.255.255.248, gateway
a interface acima.
A interligação ocorre através da interface tap0: quando há a escrita de um pacote na interface eth0 da máquina virtual este é enviado para a interface tun/tap no sistema principal, e vice-versa.
As configurações são definidas pelo serviço de configuração de rede padrão do debian na sua inicialização, que lê as definições no arquivo /etc/network/interfaces. As interfaces (1) e (3) no sistema principal são definidas da seguinte forma neste arquivo (note: do sistema principal e troque 'user' por algum usuário restrito no sistema):
#/etc/network/interfaces auto lo eth0 iface lo inet loopback iface eth0 inet static address 192.168.0.1 network 192.168.0.248 netmask 255.255.255.248 broadcast 192.168.0.248 gateway 192.168.0.1 iface tap0 inet static address 192.168.1.1 netmask 255.255.255.248 pre-up /usr/src/uml-project/tools/tunctl/tunctl -u \ $( cat /etc/passwd | grep user | cut -f 3 -d :) down /usr/src/uml-project/tools/tunctl/tunctl -d tap /dev/net/tun gateway 192.168.1.2Dessa forma, quando desejar habilitar a interface tap0 no sistema principal (que deve ser feito antes de iniciar a execução de uma máquina virtual), execute "ifup tap0", que então este arquivo será lido e as definições serão atribuidas e os comandos precedidos por 'up/down/pre-up' serão executados apropriadamente.
No sistema da máquina virtual, monte seu sistema de arquivos e configure a interface (2) editando seu arquivo de configuração (/mnt/vmfs/etc/network/interfaces) definido como segue:
$ mount -t ext3 -o loop linux_fs.ext3 /mnt/vmfs
#/etc/network/interfaces - (uml virtual machine "vm001") auto lo eth0 iface lo inet loopback iface eth0 inet static address 192.168.1.2 network 192.168.1.248 netmask 255.255.255.248 broadcast 192.168.1.248 gateway 192.168.1.1Ajuste também o arquivo /etc/hosts da máquina virtual (em /mnt/vmfs/etc/hosts):
#/etc/hosts - network configuration (uml virtual machine "vm001") 127.0.0.1 localhost 192.168.1.2 vm001 192.168.0.1 motherhostFinalizando com o hostname (neste caso, a máquina virtual recebe o nome de "vm001"):
$ echo "vm001" > /mnt/vmfs/etc/hostnameFinalmente desmontamos o sistema de arquivos destinado para a máquina virtual:
$ umount /mnt/vmfs
Se desejar liberar o acesso da máquina virtual com endereço na rede interna de 192.168.1.2 para a internet através da rede no sistema principal (considerando que o sistema principal tenha acesso a internet), utilize o iptables para criar uma tabela de tradução de endereços rede (NAT) no sistema principal:
$ echo 1 > /proc/sys/net/ipv4/ip_forward $ iptables -t nat -A POSTROUTING -s 192.168.1.2 -d ! 192.168.0.0/29 -o eth0 -j MASQUERADE $ iptables -I FORWARD -s 192.168.1.2 -m state --state ! INVALID -j ACCEPTE se desejar acessá-la a partir da internet (e.g. serviço ssh na porta 22), abra uma porta no sistema principal (e.g. 1020) e redirecione conexões com destino a esta porta chegando da internet para a máquina virtual na porta 22 (altere IP_EXTERNO apropriadamente):
$ iptables -t nat -I PREROUTING -d ${IP_EXTERNO} -p tcp --dport 1020 -j DNAT --to 192.168.1.2:22 $ iptables -I FORWARD -p tcp -d 192.168.1.2 --dport 22 -j ACCEPT
Parte III - A máquina virtual: a utilização e o ambiente para o desenvolvimento e depuração do kernel do Linux
Nesta parte descreve-se os procedimentos para
utilização da Máquina Virtual obtida com o kernel UML e o
sistema de arquivos construído.
Tal Máquina Virtual tem sido
muito utilizada também por desenvolvedores do kernel do Linux, para
testar alterações no kernel da Máquina Virtual, o que de
outro modo (quando utilizado como kernel do sistema operacional inicial) faria
com que as falhas no kernel sendo testado causasse a parada do sistema e a
necessidade de reinício do computador e de todo o sistema a cada falha
encontrada no kernel em teste. Além disso, com o kernel UML é
possível ainda depurá-lo, e então acompanhar o fluxo de
execução do sistema operacional Linux :).
Agora que o kernel uml e o sistema de arquivos estão criados, habilitamos a interface tap0 no sistema principal para estar preparado para a conexão com a rede da máquina virtual:
$ ifup tap0E finalmente executamos o kernel e iniciamos a máquina virtual com o comando:
$ ./linux ubd0=linux_fs.ext3 ubd1=swap_file mem=128M con0=fd:0,fd:1 \ con=xterm ssl=xterm eth0=tuntap,tap0 umid=vm001A barra invertida no final da primeira linha do comando indica apenas a continuação do comando na linha de baixo. Caso tenha criado os arquivos /dev/ubdX no sistema principal manualmente, informe para desativar o uso do devfs inserindo a string 'devfs=none' no comando de inicialização acima.
E então deverá ocorrer a inicialização da máquina virtual exibindo as mesmas informações que em uma inicialização normal de um kernel linux em um computador, e uma janela xterm irá se abrir com o prompt do login ao sistema. Acesse como usuário root, a senha não é necessária - configure se desejar com o comando 'passwd'.
O kernel do Fedora Core 5 tem apresentado um problema quando na execução do kernel uml - congelando este, logo após a montagem do sistema de arquivos. Se este for o caso, crie o seu próprio kernel para o sistema principal, e então tente executar novamente o kernel uml.
Outro problema que pode-se encontrar é quando a versão do kernel principal (sendo executado no computador, e não o uml) é inferior a 2.6.16-rc6 - neste caso a seguinte mensagem de erro é obtida quando na execução do kernel: "Kernel panic - not syncing: handle_trap - failed to wait at end of syscall, errno = 0, status = 2943". Neste caso, compile um kernel para o seu computador mais recente que a versão 2.6.16-rc6.
Para finalizar a máquina virtual, desligue o sistema:
$ shutdown -h now
Há 3 modos principais para realizar alterações no kernel do Linux:
Inicie o desenvolvimento, alterações ou aplique patchs para teste nos códigos do kernel do linux UML. Após as alterações, compile-o novamente:
$ make linux ARCH=um
Se estiver modificando algum módulo, é necessário realizar os procedimentos seguintes: compilar os módulos, montar o sistema de arquivos utilizado pelo uml novamente e então copiar os módulos para o sistema de arquivos, e finalmente desmontá-lo:
$ make modules ARCH=um $ mount -t ext3 -o loop linux_fs.ext3 /mnt/vmfs/ $ make modules_install INSTALL_MOD_PATH=/mnt/vmfs/ ARCH=um $ umount /mnt/vmfs/
Crie um diretório em algum lugar desejado (e.g.: ~/devel/my_modules), e então inicie criando a partir de um arquivo fonte inicial, o desenvolvimento do módulo. Temos como exemplo o arquivo "procinfo.c": utilizado para construir um módulo externo que na sua inserção imprime informações dos processos em execução no sistema.
Para este caso, há ainda a preocupação para que tipo de kernel o módulo a ser construído deva ser utilizado. Para compilar o código fonte, e automatizar o processo, crie um arquivo Makefile para compilar o módulo, conforme abaixo (alterando o valor da variável KERNELDIR de acordo com a localização dos fontes da versão do kernel a que deseja-se que o módulo seja utilizado - é necessário ter disponível os fontes de tal kernel):
# Makefile obj-m := procinfo.o module-objs := procinfo.o KERNELDIR = /usr/src/v2.6.21-rc1.uml/ default: make -C $(KERNELDIR) M=$(shell pwd) modules ARCH=um clean: rm -f rm -f procinfo.o procinfo.ko procinfo.mod.c procinfo.mod.o Module.symversEntão compile:
$ makeEntão é necessário montar o sistema de arquivos utilizado pelo kernel UML novamente para copiar o módulo criado afim de que possa ser encontrado no sistema de arquivos da Máquina Virtual quando executado, e depois finalmente desmontá-lo:
$ mount -t ext3 -o loop linux_fs.ext3 /mnt/vmfs/ $ cp /caminho/para/modulo/criado/procinfo.ko /mnt/vmfs/usr/src/ $ umount /mnt/vmfs/Após reiniciar o sistema com os devidos parâmetros (descrito no início desta parte), faça a inserção do módulo na Máquina Virtual com o comando "insmod procinfo.ko", e a remoção com "rmmod procinfo". E então teste novamente a máquina virtual tentando executá-la conforme descrito no inínicio desta parte. Se por qualquer motivo sua máquina virtual congelar, certifique-se de que não há instâncias da máquina virtual executando pois o sistema irá reportar erro de recurso indisponível temporariamente (errno 11). Mate os processos anteriores sempre que ficar alguma instância residente após algum tipo de reinício devido a quebras no sistema:
$ pkill -9 linux
Caso venha a obter erros, ou deseje depurar o fluxo de
execução do kernel, você pode
utilizar o GNU gdb. Para depurar módulos é
necessário alguns procedimentos adicionais,
então descritos em secções
separadas:
Inicie o kernel uml a partir do gdb:
$ gdb ./linuxÉ necessário informar o depurador para ignorar pelos sinais recebidos SIGUSR1 e SIGSEGV:
(gdb) handle SIGSEGV pass nostop noprint
(gdb) handle SIGUSR1 pass nostop noprintAgora indicamos um ponto de parada (break point) na função 'start_kernel' do kernel:
(gdb) b start_kernelE então iniciamos a execução do kernel no depurador GNU:
(gdb) r ubd0=linux_fs.ext3 ubd1=swap_file mem=128M con0=fd:0,fd:1 \ con=xterm ssl=xterm eth0=tuntap,tap0 umid=vm001Se desejar parar a execução do kernel no gdb, um <CTRL-C> irá acabar por encerrar o próprio gdb devido ao modo do terminal RAW, portanto o método a ser utilizado é abrir um outro terminal (xterm) e envie um sinal SIGINT (solicitando uma interrupção na execução) para a thread principal do kernel uml executando (troque "$(whoami)" pelo usuário que executa o uml se estiver utilizando algum esquema de proteção sgid,suid, etc.):
$ kill -INT $(cat /home/$(whoami)/.uml/vm001/pid)E agora podemos dar procedimento na depuração no gdb - veja logo abaixo exemplos de comando. Desejando continuar a execução do kernel, execute 'c' (continue) no depurador novamente. Novamente, mate os processos anteriores sempre que ficar alguma instância residente após algum tipo de reinício devido a quebras no sistema:
$ pkill -9 linux gdb port-helper
Para depurar um módulo logo quando este é carregado e acompanhar sua execução é necessário adicionar os símbolos do módulo na tabela de símbolos do depurador logo no momento em que este já esteje alocado no kernel uml e armazenado em um ponteiro global 'modules' que representa a lista dos módulos carregados internamente no kernel, além de indicar a posição da alocação (o endereço de memória). Para agilizar este procedimento e torná-lo automático, utilizamos 3 arquivos (que devem ser alterados apropriadamente de acordo com a localização dos módulos, kernel e sistema de arquivos utilizado):
1) umlgdb_dispatcher:
inicia um xterm executando o kernel no gdb e
controla a parada no depurador;
2) umlgdb_wrapper:
carrega os símbolos do módulo
automaticamente logo que inserido com 'insmod'
na máquina virtual e pára a
execução do kernel no depurador no
local da chamada a função init do
módulo). Tal arquivo foi
construído baseado do original 'umlgdb'
disponibilizado no diretório tools do
projeto UML por Chandan Kudige;
3) .gdbinit: a ser colocado
no diretório do kernel uml
(/usr/src/v2.6.21-rc1.uml se seguido a parte I
deste documento), será lido e executado
automaticamente pelo depurador gdb sempre que
este for executado neste diretório.
Para iniciar a execução do uml sobre o
gdb, dê permissão de execução
para o arquivo umlgdb_dispatcher e execute-o:
$ chmod +x umlgdb_dispatcher
$ ./umlgdb_dispatcherO que acontece é que o umlgdb_dispatcher abre um xterm para iniciar a execução do kernel uml sobre o gdb, e quando detecta um 'insmod
Alguns comandos do depurador GNU gdb:
Inserir um ponto de parada em uma linha de um arquivo .................[b]reak x.c:105 Inserir um ponto de parada em uma funcao ..............................[b]reak some_function Inserir um ponto de parada temporario em uma funcao ...................tbreak another_function Listar pontos de paradas existentes ...................................[i]nfo [b]reakpoints Desabilitar um ponto de parada (o 2ndo listado) .......................disable 2 Nao pare no 2ndo ponto de parada nas proximas 8 vezes .................ignore 2 8 Apague 2ndo ponto de parada ...........................................[d]elete 2 Execute a linha atual do programa e pare na proxima execucao ..........[s]tep Se o programa atual contem uma chamada de funcao execute-a e pare .....[n]ext Executa 'next' para todas as funcoes invocadas ate o final da funcao ..finish Continue a execucao ate o proximo ponto de parada .....................[c]continue Lista 10 ou mais linhas de codigo ao redor da linha atual .............[l]ist Sair do GDB ...........................................................[q]uit
Para mais informações sobre depuração, e kernel uml no gdb, veja:
- -- http://www.clarkson.edu/class/cs644/kernel/setup/uml/gdb_uml.html
- -- http://user-mode-linux.sourceforge.net/debugging.html
- -- http://www.unknownroad.com/rtfm/gdbtut/gdbtoc.html
- -- http://www.linuxjournal.com/article/9252
Parte IV - Soluções para eventuais problemas
Instalando o Debootstrap em sistemas que não o Debian
O programa debootstrap é parte do sistema
Debian, é um conjunto de scripts shell que utilizam a glibc (e,
portanto, deve estar instalada), e o método para instala-lo em outros
sistemas é como segue:
- 1) Copie o pacote para o diretório /usr/local/src o binário do debootstrap dos servidores Debian
- 2) Descompacte os arquivos binários a partir deste ('ar' á um dos binários do conjunto que compõem o pacote 'binutils').
- 3) Instale copiando os executáveis para os diretórios padrões do sistema (/usr/bin). Você precisará ter privilégios de root para instalar estes binários.
Erro ao compilar o kernel UML
Esta secção descreve como resolver erros
no momento de compilar o kernel. Nesta versão
utilizada (2.6.21-rc1) obteve-se a seguinte mensagem de erro:
$ cd /usr/local/src/
$ wget http://ftp.debian.org/debian/pool/main/d/debootstrap/debootstrap-udeb_0.3.3_i386.udeb
$ ar -x debootstrap-udeb_0.3.3_i386.udeb
$ cd /
$ zcat /usr/local/src/work/data.tar.gz | tar xv
[...] CC mm/slab.o mm/slab.c:3557: error: conflicting types for ‘kmem_ptr_validate’ include/linux/slab.h:58: error: previous declaration of ‘kmem_ptr_validate’ was here make[1]: ** [mm/slab.o] Erro 1 make: ** [mm] Erro 2 $Portanto é necessário verificar se tal erro já fora corrigido, verificando nos patches. Para isso então, vamos baixar o arquivo patches.tar que contém todos os patches já migrados para a versão escolhida (2.6.20-rc1) no endereço dos patches disponíveis:
$ wget http://user-mode-linux.sourceforge.net/work/current/2.6/2.6.20-rc1/patches.tarExtraímos os patches em um diretório patches/ a ser gerado na extração dos patches:
$ tar xv patches.tarEntramos no diretório e então verificamos se há algum patch que contenha alguma correção para o arquivo indicado com erro no momento de compilar o kernel - neste caso, o erro é em slab.c - com o seguinte comando:
$ cd patches/ $ grep -n Index: * | grep slab.c fastcall:4:Index: linux-2.6.17/mm/slab.cVerificando o arquivo na linha que indicada, e analisando o erro, nota-se que este patch (arquivo "fastcall") refere-se a correção do erro apontado (mm/slab.c:3557: error: conflicting types for #kmem_ptr_validate#):
$ cat patches/fastcall # There's a mismatch between the definition and declaration of # kmem_ptr_validate. This removes the "fastcall" from the definition. Index: linux-2.6.17/mm/slab.c =================================================================== --- linux-2.6.17.orig/mm/slab.c 2006-12-14 23:01:47.000000000 -0500 +++ linux-2.6.17/mm/slab.c 2006-12-14 23:07:00.000000000 -0500 @@ -3553,7 +3553,7 @@ EXPORT_SYMBOL(kmem_cache_zalloc); * * Currently only used for dentry validation. */ -int fastcall kmem_ptr_validate(struct kmem_cache *cachep, const void *ptr) +int kmem_ptr_validate(struct kmem_cache *cachep, const void *ptr) { unsigned long addr = (unsigned long)ptr; unsigned long min_addr = PAGE_OFFSET; $Então aplicamos o patch a partir do diretório dos fontes do kernel com o comando a seguir:
$ cd /usr/src/v2.6.21-rc1.uml
$ cat patches/fastcall | patch -p1E então tenta-se novamente continuar a compilar o kernel, re-executando o comando:
$ make linux ARCH=umCaso obtenha outros erros, faça a mesma verificação do erro nos patches para ver se há alguma correção já disponível, e então aplique o patch conforme os procedimentos acima, e continue a compilar o kernel até obter sucesso.