Depurando Arquivos Principais Gerados na Caixa do Cliente

Recebemos arquivos principais do nosso software na checkbox do Cliente. Infelizmente, porque sempre compilamos com -O2 sem depurar símbolos, isso nos levou a situações em que não conseguimos descobrir por que estava travando, modificamos as compilações e agora elas geram -g e -O2 juntas. Em seguida, aconselhamos o Cliente a executar um binário -g para que seja mais fácil depurá-lo.

Eu tenho algumas perguntas:

  1. O que acontece quando um arquivo principal é gerado a partir de uma distribuição Linux diferente da que estamos executando no Dev? O rastreamento de pilha é significativo?
  2. Existem bons livros para debugging no Linux ou no Solaris? Algo exemplo orientado seria ótimo. Eu estou procurando exemplos da vida real de descobrir por que uma rotina caiu e como o autor chegou a uma solução. Algo mais no nível intermediário a avançado seria bom, já que estou fazendo isso há algum tempo. Alguma assembly seria boa também.

Aqui está um exemplo de uma falha que exige que digamos ao cliente para obter um -g ver. do binário:

Program terminated with signal 11, Segmentation fault. #0 0xffffe410 in __kernel_vsyscall () (gdb) where #0 0xffffe410 in __kernel_vsyscall () #1 0x00454ff1 in select () from /lib/libc.so.6 ...  

O ideal é que eu gostaria de descobrir por que exatamente o aplicativo travou – suspeito que seja corrupção de memory, mas não tenho 100% de certeza.

A debugging remota é estritamente proibida.

obrigado

O que acontece quando um arquivo principal é gerado a partir de uma distribuição Linux diferente da que estamos executando no Dev? O rastreamento de pilha é significativo?

Se o executável estiver dinamicamente vinculado, como o seu, a pilha produzida pelo GDB (provavelmente) não será significativa.

O motivo: o GDB sabe que seu executável travou chamando algo em libc.so.6 no endereço 0x00454ff1 , mas não sabe qual código estava naquele endereço. Então, ele analisa sua cópia do libc.so.6 e descobre que isso está em select , então imprime isso.

Mas as chances de que 0x00454ff1 também esteja em select na cópia de libc.so.6 de seus clientes são bem pequenas. Muito provavelmente o cliente tinha algum outro procedimento nesse endereço, talvez abort .

Você pode usar disas select e observar que 0x00454ff1 está no meio da instrução ou que a instrução anterior não é CALL . Se qualquer um deles for válido, seu rastreio de pilha não terá sentido.

Você pode, no entanto, ajudar a si mesmo: você só precisa obter uma cópia de todas as bibliotecas listadas em informações (gdb) info shared no sistema do cliente. Faça com que o cliente os aumente com eg

 cd / tar cvzf to-you.tar.gz lib/libc.so.6 lib/ld-linux.so.2 ... 

Então, no seu sistema:

 mkdir /tmp/from-customer tar xzf to-you.tar.gz -C /tmp/from-customer gdb /path/to/binary (gdb) set solib-absolute-prefix /tmp/from-customer (gdb) core core # Note: very important to set solib-... before loading core (gdb) where # Get meaningful stack trace! 

Em seguida, aconselhamos o Cliente a executar um binário -g para que seja mais fácil depurá-lo.

Uma abordagem muito melhor é:

  • construir com -g -O2 -o myexe.dbg
  • cp myexe.dbg myexe
  • strip -g myexe
  • distribuir o myexe para os clientes
  • Quando um cliente obtém um core , use myexe.dbg para myexe.dbg -lo

Você terá informações simbólicas completas (arquivo / linha, variables ​​locais), sem ter que enviar um binário especial para o cliente e sem revelar muitos detalhes sobre suas fonts.

Você pode, de fato, obter informações úteis de um despejo de memory, mesmo de uma compilation otimizada (embora seja tecnicamente chamado de “um grande problema”). A compilation -g é de fato melhor, e sim, você pode fazer assim, mesmo quando a máquina em que o despejo aconteceu é outra distribuição. Basicamente, com uma ressalva, todas as informações importantes estão contidas no executável e terminam no dump.

Quando você combina o arquivo principal com o executável, o depurador poderá dizer a você onde ocorreu a falha e mostrar a pilha. Isso por si só deveria ajudar muito. Você também deve descobrir o máximo que puder sobre a situação em que isso acontece – eles podem reproduzi-lo de forma confiável? Se sim, você consegue reproduzi-lo?

Agora, aqui está a ressalva: o lugar onde a noção de “tudo está lá” é dividido com arquivos de objects compartilhados, arquivos .so . Se estiver falhando por causa de um problema com esses, você não terá as tabelas de símbolos necessárias; você só poderá ver em que biblioteca, para que isso aconteça.

Há vários livros sobre debugging, mas não consigo pensar em um que eu recomende.

Tanto quanto me lembro, você não precisa pedir ao seu cliente para executar com o binário construído com a opção -g. O que é necessário é que você tenha uma compilation com a opção -g. Com isso, você pode carregar o arquivo principal e ele mostrará todo o rastreio da pilha. Eu lembro de algumas semanas atrás, eu criei arquivos principais, com build (-g) e sem -g e o tamanho do core era o mesmo.

Inspecione os valores das variables ​​locais que você vê quando anda na pilha? Especialmente em torno da chamada select (). Faça isso na checkbox do cliente, basta carregar o lixo e andar na pilha …

Além disso, verifique o valor de FD_SETSIZE nas suas plataformas DEV e PROD!