Talvez a habilidade mais importante e exigida de um administrador de sistemas é a resolução de problemas. Durante uma falha, esses profissionais se vêem constantemente sob enorme pressão e estresse, enquanto procuram obter informações para analisá-las e, assim, providenciar as correções necessárias.
Nesse ambiente regularmente caótico, a família Unix é excepcional ao oferecer uma variedade de ferramentas para facilitar o trabalho do administrador de sistemas. Entre essas ferramentas está o strace.
O propósito central do strace é rastrear as chamadas de sistema (system calls) produzidas por um determinado processo. Conexões TCP/IP e arquivos abertos pelo processo são algumas das muitas informações possíveis de se colher durante um rastreamento. Essas informações, aparentemente ingênuas, podem ser de grande valor para o administrador corrigir um problema do sistema, ou até mesmo para satisfazer sua intrínseca curiosidade sobre o funcionamento de um programa.
Por definição, uma chamada de sistema é um método usado pelo processo para requisitar um serviço do sistema operacional, ou mais especificamente, do kernel. O conjunto de chamadas de sistema fornecido pelo kernel pode ser considerado a camada de abstração entre o sistema operacional e um programa do usuário.
O bom entendimento das chamadas de sistema exige o conhecimento básico sobre linguagens de programação, preferencialmente da linguagem C. O seu conceito é o mesmo de uma função, já que recebe parâmetros e retorna um valor de acordo com os resultados obtidos.
Para exemplificar esse conceito, quando um processo precisa de informações sobre um determinado arquivo, ele usa a chamada de sistema stat(), passando como único parâmetro o caminho do arquivo. A partir disso, o kernel do sistema operacional encarrega-se de obter as informações sobre esse arquivo e repassá-las para o processo.
Colocando esse exemplo em um resultado prático, a chamada de sistema stat() aparece da seguinte maneira em um rastreamento do strace:
Nota-se que o primeiro parâmetro do stat() é o arquivo /etc/localtime, do qual o processo rastreado requisitou as informações. O segundo parâmetro é justamente as informações requistadas do arquivo /etc/localtime já repassadas pelo kernel, em uma estrutura com os valores separados por vírgula e dentro de chaves. Entre os valores estão as permissões de acesso (st_mode), o tamanho do arquivo (st_size), o horário de criação (st_ctime), etc.
O valor após o sinal de igual é o resultado, ou valor de retorno, da chamada de sistema. No exemplo citado, o valor 0 (zero) retornado pelo stat() indica que sua execução ocorreu sem problemas. Cada chamada de sistema possuí diferentes valores de retorno, de acordo com o sucesso ou falha específica.
Não é o objetivo desse artigo enumerar e detalhar todas as chamadas de sistema existentes. Para conseguir mais informações, o UNIX provê uma massiva documentação sobre elas em suas boas e velhas páginas de manuais. Por exemplo, para ler mais sobre o stat() o comando é:
A possibilidade de rastrear todas as chamadas de sistema de um programa permite aprender mais sobre sua iteração com o sistema operacional, e ao mesmo tempo, determinar possíveis causas sobre um erro desconhecido.
O strace foi inicialmente desenvolvido para o sistema operacional SunOS - conhecido atualmente como Solaris - e posteriormente portado para outros sistemas operacionais, incluindo o FreeBSD e o Linux. A portabilidade do strace é complexa pelo fato dele exigir modificações no kernel do sistema operacional para implementar os mecanismos de rastreamento.
No Linux, o mecanismo de rastreamento do strace é baseado em uma chamada de sistema: o ptrace(). Ele fornece um conjunto de sinais para que um processo controle e observe a execução de um outro processo.
Levando em consideração os detalhes de implementação no Linux, é possível resumir, de forma bastante simplista, os passos de um rastreamento com o seguinte roteiro:
Ao mesmo tempo em que a sintaxe do comando strace é simples, ele aceita uma grande variedade de opções que podem ser úteis no rastreamento de um processo ou na visualização de seu resultado. As formas mais usuais de execução estão listadas e comentadas a seguir:
Para conhecer todas as opções disponíveis no strace, é recomendada a leitura de sua página de manual:
O primeiro exemplo é o rastreamento de um comando fácil de compreender: o pwd. Um programa que apenas retorna o diretório corrente do usuário.
1 execve("/bin/pwd", ["pwd"], [/* 19 vars */]) = 0
2 uname({sys="Linux", node="ns2.centralserver.com.br", ...}) = 0
3 brk(0) = 0x82bd000
4 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
5 open("/etc/ld.so.cache", O_RDONLY) = 3
6 fstat64(3, {st_mode=S_IFREG|0644, st_size=26266, ...}) = 0
7 old_mmap(NULL, 26266, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7f89000
8 close(3) = 0
9 open("/lib/tls/libc.so.6", O_RDONLY) = 3
10 read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\320N\1\0004\0\0\0"..., 512) = 512
11 fstat64(3, {st_mode=S_IFREG|0755, st_size=1526024, ...}) = 0
12 old_mmap(NULL, 1227964, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xcbf000
13 old_mmap(0xde5000, 16384, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x125000) = 0xde5000
14 old_mmap(0xde9000, 7356, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xde9000
15 close(3) = 0
16 old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7f88000
17 mprotect(0xde5000, 8192, PROT_READ) = 0
18 mprotect(0xc8b000, 4096, PROT_READ) = 0
19 set_thread_area({entry_number:-1 -> 6, base_addr:0xb7f88aa0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
20 munmap(0xb7f89000, 26266) = 0
21 brk(0) = 0x82bd000
22 brk(0x82de000) = 0x82de000
23 open("/usr/lib/locale/locale-archive", O_RDONLY|O_LARGEFILE) = 3
24 fstat64(3, {st_mode=S_IFREG|0644, st_size=48532896, ...}) = 0
25 mmap2(NULL, 2097152, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7d88000
26 mmap2(NULL, 24576, PROT_READ, MAP_PRIVATE, 3, 0xda5) = 0xb7d82000
27 mmap2(NULL, 184320, PROT_READ, MAP_PRIVATE, 3, 0xdad) = 0xb7d55000
28 mmap2(NULL, 4096, PROT_READ, MAP_PRIVATE, 3, 0x22a5) = 0xb7d54000
29 close(3) = 0
30 getcwd("/home/heitor", 4096) = 13
31 fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ...}) = 0
32 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7d53000
33 write(1, "/home/heitor\n", 13/home/heitor ) = 13
34 exit_group(0) = ?
As linhas do resultado acima que merecem comentários são as seguintes:
No próximo exemplo, o strace é usado para conseguir informações sobre a seguinte situação problemática: Um programa que usa um banco de dados MySQL para realizar a autenticação, apresenta-se lento durante determinados momentos de sua execução, apesar do servidor MySQL estar funcionando corretamente.
Executando o strace, consegue-se do programa os dados abaixo:
...(cortado)...
Exclusivamente nesse caso, é perceptível durante o rastreamento que o programa em questão fica lento exatamente na linha 6. Portanto, será analisado o trecho próximo a essa linha:
De maneira simples, e principalmente rápida, foi possível detectar que o servidor DNS primário utilizado pelo programa não está respondendo, atrasando as conexões ao servidor MySQL. Sendo assim, troca-se esse servidor DNS e o problema é resolvido.
Apesar da simplicidade dos exemplos citados, fica evidente que o strace é uma ferramenta poderosa para um administrador de sistemas conseguir informações sobre um problema que, a princípio, parece obscuro. Os desenvolvedores também podem exergar alguma utilidade no strace para fazer a depuração de seus programas sem a necessidade de recompilá-lo.
E recentemente o conceito de rastreamento ganhou importância, o que levou alguns sistemas operacionais a providenciarem ferramentas mais completas. Depois da apresentação do excelente Dtrace por parte do Solaris, o FreeBSD se esforça muito para portá-lo em seu sistema, enquanto o Linux promete maravilhas com a idéia do LTTng.
Ravi (05-05-2006). strace - A very powerful trobleshooting tool for all Linux users. All about Linux. Acessado em 18-01-2008.
Zimmerly, Willian B (11-05-2006). Fun with strace and GDB Debugger. IBM DeveloperWorks. Acessado em 19-01-08
Comentários
Você é o Heitor da
Você é o Heitor da CentralServer ?
Bom, sendo ou não, parabéns pelo ótimo artigo.
Abraço !
Ótimo
Isso ainda vai me ajudar em alguma coisa, é certo.
Hey!
Muito bom o artigo.
Por acaso você se formou no Mackenzie?
Abraço!
Re: Hey!
Olá Estevão,
Eu não me formei no Mackenzie, certamente você confundiu :)
Abraço,
Heitor Augusto Murari Cardozo
=)
Valeu, muito obrigado ;)