Um manipulador do kernel coredump pode gerar o backtrace do processo zumbi, sem gravar o coredump no disco primeiro.
Eu assumi que a ABRT poderia fazer isso. No entanto, parece que há um patch, mas ainda não foi mesclado:
Eu tenho arquivos core
enormes e, portanto, defino a core_pattern
definida como gzip
à medida que são gravados.
Mais tarde, se o backtrace for obtido, primeiro gunzip
tem que ser feito (e leva muito tempo!) antes que o arquivo core
possa ser alimentado para gdb
.
Eu queria saber se existe uma maneira de canalizar o core
(como está sendo criado) para gdb
(ou qualquer outro programa que possa buscar backtrace
). Eu verifiquei gdb
, e parece não haver tal opção (nem readelf
); antes que eu pudesse fazer algo desse tipo, eu queria saber se existe alguma coisa com o formato de ELF core
(em x86_64
, GNU / Linux) que poderia impedir isso de funcionar?
- EDITAR
grok'd através de readelf
sources, e outros programas que podem gerar backtrace, e eles parecem ser seek()
ing através do arquivo para frente e para trás ! Não tenho certeza se isso é absolutamente necessário, ou se é possível ler e reunir todas as informações necessárias em uma única passagem (já que eu quero ler de um pipe, busque não é uma opção!)
Um manipulador do kernel coredump pode gerar o backtrace do processo zumbi, sem gravar o coredump no disco primeiro.
Eu assumi que a ABRT poderia fazer isso. No entanto, parece que há um patch, mas ainda não foi mesclado:
A geração de um backtrace requer a busca do conteúdo da memória por endereço. Em um arquivo principal, cada endereço virtual cujo conteúdo está incluído no núcleo está em um determinado deslocamento no arquivo principal. Quando o código que gera um backtrace executa uma busca, o alvo dessa busca é o deslocamento para o conteúdo da memória de um endereço que mapeia para esse deslocamento.
O obstáculo para tratar um arquivo principal como um fluxo é que não há razão para esperar que os deslocamentos correspondam aos endereços cujo conteúdo está sendo buscado para aumentar a cada busca. Uma busca inversa significa simplesmente que a busca atual é para conteúdos cujo deslocamento é menor que o deslocamento da busca anterior.
Talvez o cenário mais simples para construir um backtrace a partir de um arquivo principal seja um arquivo principal gerado por código, que usa consistentemente um ponteiro de quadro. Nesse cenário, as buscas de memória são da pilha, e os valores de ponteiro de quadros, um por quadro de pilha, fornecem o que equivale a uma lista encadeada de quadros de pilha, na qual a próxima palavra de cada quadro de pilha é um endereço de retorno a presença de símbolos apropriados, pode ser mapeada para um nome de função e offset).
O aumento de endereços em um arquivo principal típico aumenta os deslocamentos dentro do arquivo, e um backtrace típico representado por uma lista vinculada de valores de ponteiro de quadro possui um endereço de ponteiro de quadro maior para cada quadro sucessivo. Um backtrace simples de um arquivo de núcleo do código que usa um ponteiro de quadro pode começar localizando a pilha (do valor do registrador de ponteiro de pilha) e percorrendo a lista vinculada de valores de ponteiro de quadro, exibindo o endereço de retorno associado a cada quadro. Essa abordagem envolveria uma boa quantidade de buffering, principalmente dos cabeçalhos de segmento de programa próximos ao início do arquivo principal, que são usados para mapear endereços virtuais para deslocamentos de arquivos. O pior da ineficiência nessa abordagem presumivelmente seria ignorar todos os dados não compactados entre os cabeçalhos de segmento (e a nota usada para obter valores de registro) e a pilha do encadeamento relevante.
A geração de um backtrace a partir do código que não usa um ponteiro de quadro é mais complicada, mas isso também pode ser possível se houver dados suficientes armazenados em buffer. É mais provável que seja viável se os símbolos corretos estiverem disponíveis, mais ainda se os símbolos de depuração estiverem disponíveis. Como no cenário de ponteiro de quadros, a busca de dados da pilha relevante provavelmente será essencial.
Em vez de começar com a esperança de tratar um arquivo principal como um fluxo, talvez a melhor abordagem aqui seja mudar a maneira como as economias de espaço são obtidas para os arquivos principais enormes. O problema fundamental com a saída gzip
é que ela não fornece acesso aleatório. Uma melhor opção para uma representação eficiente de espaço de um arquivo principal é um formato como squashfs
, no qual o acesso aleatório é fornecido pela compactação de blocos de tamanho constante e esses blocos são indexados, para que a obtenção de dados para um deslocamento especificado seja primeiro e descomprimindo o pedaço apropriado, e depois procurando dentro daqueles dados não compactados.
O desafio imediato com o uso de squashfs
em core_pattern
é que não há nenhuma maneira óbvia de invocar mksquashfs
na entrada padrão. Talvez a maneira mais simples de contornar isso seja permitir que um arquivo principal exista em sua forma descompactada por tempo suficiente para invocar mksquashfs
. Uma abordagem mais eficiente em termos de espaço pode envolver a criação de código que pode gerar o formato squashfs
a partir da entrada padrão; Isso provavelmente será simples se mksquashfs
nunca tiver um motivo para procurar em um arquivo que inclua em squashfs
image (não sei com certeza, mas meu entendimento sobre squashfs
format sugere que é pelo menos uma possibilidade).
Supondo que você tenha uma imagem squashfs
contendo um arquivo principal enorme, uma maneira de alimentá-la com uma ferramenta que gera um backtrace é simplesmente mount
da imagem e fornecer o nome do caminho relevante dentro desse ponto de montagem, mas é Também é possível modificar os aplicativos para manipular nativamente o formato squashfs
. Uma vantagem dessa abordagem é que qualquer outra operação em um arquivo principal além de um backtrace simples também está disponível (uma provável próxima etapa em uma análise central está gerando vários rastreamentos, um por thread).