Valgrind & Embedded Linux

Como continuação ao último post, resolvi testar o comportamento do valgrind em um sistema embarcado. Primeiro passo obviamente é ter um ambiente de desenvolvimento apropriado, isto é, um toolchain para cross-compilar os pacotes necessários, a glibc compilada para a plataforma em questão, etc. A maioria dos fabricantes de processadores para arquiteturas embarcadas fornecem um pacote contendo toda a toolchain necessária para compilar para a arquitetura em questão. Para escrever este blog eu utilizei o toolchain de powerpc fornecido pela Freescale.

Começei por instalar o pacote em um local conhecido digamos $HOME/toolchains/powerpc-linux-gnu, ajustei minha variável $PATH de modo que fosse possível encontrar os compiladores e ferramentas da toolchain – algo como export PATH=$PATH:$HOME/toolchains/powerpc-linux-gnu/bin, isto irá mudar dependendo do toolchain usado e onde ele foi instalado.

Com as ferramentas instaladas, hora de conseguir o source do valgrind! Primeiro baixei o tarball (versão 3.5) do site do valgrind, mas logo descobri que havia um problema com umas macros usadas que não permitiam cross-compilar o pacote – vide bug, que já está corrigido, mas não liberaram um pacote novo. Bom, hora de baixar o código fonte do SVN! Vamos colocar o código dentro do diretório pkgs do projeto my-project.

cd $HOME/my-project/pkgs/
svn co svn://svn.valgrind.org/valgrind/trunk valgrind

Feito isso, hora de compilar o valgrind! Antes um aviso para os navegantes: o valgrind coloca o caminho $PREFIX/bin hardcoded no binário gerado, e utiliza esse caminho para achar as diversas ferramentas geradas (callgrind, memcheck, etc). Obviamente eu não percebi isso na primeira vez que compilei, mas depois de umas tentativas consegui acertar os valores corretos. A melhor solução é deixar o $PREFIX apontando para /usr como em qualquer instalação normal, compilar normalmente o código e na hora de instalar usar a variável DESTDIR para apontar o diretório correto para realizar a instalação. No meu caso isso é necessário, pois quero instalar num diretório que será montado por NFS no dispositivo embarcado ($HOME/my-project/rootfs). O -j4 é por que eu sou impaciente e tenho cores demais na máquina.

cd valgrind
./configure --host=powerpc-linux-gnu --prefix=/usr --disable-tls
make -j4
make install DESTDIR=$HOME/my-project/rootfs

Com isso temos o valgrind instalado no diretório raíz utilizado pelo sistema embarcado que queremos testar! Hora de bootar o sistema, esperar ele carregar e fire it away! Abaixo um exemplo do valgrind rodando em um sistema embarcado.

-sh-4.0# valgrind test
==1653== Memcheck, a memory error detector
==1653== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==1653== Using Valgrind-3.6.0.SVN and LibVEX; rerun with -h for copyright info
==1653== Command: test
==1653==
Prompt>exit
==1653== Invalid read of size 1
==1653==    at 0x10007F88: test_execute (in /bin/test)
==1653==    by 0x10009A23: main (in /bin/test)
==1653==  Address 0x403e0fd is 0 bytes after a block of size 5 alloc'd
==1653==    at 0xFFBA4B0: malloc (vg_replace_malloc.c:236)
==1653==    by 0xFF5FA2F: xmalloc (in /lib/libreadline.so.6.0)
==1653==    by 0xFF419CB: readline_internal_teardown (in /lib/libreadline.so.6.0)
==1653==    by 0xFF41D1B: readline (in /lib/libreadline.so.6.0)
==1653==    by 0x100098AB: main (in /bin/test)
==1653==
==1653==
==1653== HEAP SUMMARY:
==1653==     in use at exit: 24,589 bytes in 145 blocks
==1653==   total heap usage: 229 allocs, 84 frees, 53,399 bytes allocated
==1653==
==1653== LEAK SUMMARY:
==1653==    definitely lost: 0 bytes in 0 blocks
==1653==    indirectly lost: 0 bytes in 0 blocks
==1653==      possibly lost: 0 bytes in 0 blocks
==1653==    still reachable: 24,589 bytes in 145 blocks
==1653==         suppressed: 0 bytes in 0 blocks
==1653== Rerun with --leak-check=full to see details of leaked memory
==1653==
==1653== For counts of detected and suppressed errors, rerun with: -v
==1653== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 5 from 3)

Só para completar, o valgrind ajuda bastante a achar os problemas no software, mas lembre-se que um sistema embarcado possuiu outras limitações, como pouca memória, processador com clock baixo, etc. Essas limitações se refletem no desempenho do valgrind, o software ficará bastante lento, algumas flags do valgrind não funcionarão – no meu caso foi por falta de memória, precisaria de mais do que os 64M de RAM disponíveis para utilizar o --track-origins (Ah, o manual do valgrind informa que é necessário no mínimo 100M de RAM para este parâmetro funcionar!).

Happy Hacking!