Executar um aplicativo no GDB até que ocorra uma exceção

102

Estou trabalhando em um aplicativo multithread e quero depurá-lo usando GDB.

O problema é que um dos meus tópicos continua morrendo com a mensagem:

pure virtual method called
terminate called without an active exception
Abort

Eu sei a causa dessa mensagem, mas não tenho ideia de onde ela ocorre no meu tópico. Um backtrace seria realmente útil.

Quando executo meu aplicativo no GDB, ele pausa toda vez que um thread é suspenso ou retomado. Quero que meu aplicativo continue executando normalmente até que um dos threads morra com essa exceção, ponto em que tudo deve parar para que eu possa obter um backtrace.

Ankur Sethi
fonte
Que sinal o GDB reporta quando faz uma pausa? você deve ser capaz de executar um comando comohandle SIGUSR1 pass noprint nostop
Hasturkun

Respostas:

147

Você pode tentar usar um "catchpoint" ( catch throw) para parar o depurador no ponto onde a exceção é gerada.

O seguinte trecho do manual do gdb descreve o recurso catchpoint.


5.1.3 Definir pontos de controle

Você pode usar pontos de captura para fazer com que o depurador pare para certos tipos de eventos de programa, como exceções C ++ ou o carregamento de uma biblioteca compartilhada. Use o comando catch para definir um ponto de encontro.

  • pegar evento

    Pare quando o evento ocorrer. evento pode ser qualquer um dos seguintes:

    • lançar

      O lançamento de uma exceção C ++.

    • pegar

      A captura de uma exceção C ++.

    • exec

      Uma chamada para exec. No momento, está disponível apenas para HP-UX.

    • garfo

      Uma chamada para o fork. No momento, está disponível apenas para HP-UX.

    • vfork

      Uma chamada para vfork. No momento, está disponível apenas para HP-UX.

    • carregar ou carregar libname

      O carregamento dinâmico de qualquer biblioteca compartilhada ou o carregamento da biblioteca libname. No momento, está disponível apenas para HP-UX.

    • descarregar ou descarregar libname

      O descarregamento de qualquer biblioteca compartilhada carregada dinamicamente ou o descarregamento da biblioteca libname. No momento, está disponível apenas para HP-UX.

  • evento tcatch

    Defina um ponto de convergência que esteja ativado apenas para uma parada. O catchpoint é excluído automaticamente após a primeira vez que o evento é detectado.

Use o info breakcomando para listar os pontos de interesse atuais.

Atualmente, existem algumas limitações para o tratamento de exceções C ++ (catch throw e catch catch) no GDB:

  • Se você chamar uma função interativamente, o GDB normalmente retorna o controle para você quando a função termina de ser executada. Se a chamada gerar uma exceção, no entanto, a chamada pode ignorar o mecanismo que retorna o controle para você e fazer com que seu programa aborte ou simplesmente continue em execução até atingir um ponto de interrupção, capturar um sinal de que o GDB está escutando ou sair. Esse é o caso mesmo se você definir um ponto de captura para a exceção; pontos de interesse em exceções são desabilitados em chamadas interativas.

  • Você não pode lançar uma exceção interativamente.

  • Você não pode instalar um manipulador de exceção interativamente.

Às vezes, catch não é a melhor maneira de depurar o tratamento de exceções: se você precisa saber exatamente onde uma exceção é gerada, é melhor parar antes que o manipulador de exceções seja chamado, já que dessa forma você pode ver a pilha antes que ocorra qualquer desenrolamento. Se, em vez disso, você definir um ponto de interrupção em um manipulador de exceção, pode não ser fácil descobrir onde a exceção foi gerada.

Para parar um pouco antes de um manipulador de exceção ser chamado, você precisa de algum conhecimento da implementação. No caso do GNU C ++, as exceções são levantadas chamando uma função de biblioteca chamada __raise_exception que tem a seguinte interface ANSI C:

/* addr is where the exception identifier is stored.
   id is the exception identifier.  */
void __raise_exception (void **addr, void *id);

Para fazer o depurador capturar todas as exceções antes que ocorra qualquer desenrolamento da pilha, defina um ponto de interrupção em __raise_exception (consulte a seção Pontos de interrupção; pontos de controle; e exceções).

Com um ponto de interrupção condicional (consulte a seção Condições de quebra) que depende do valor de id, você pode interromper seu programa quando uma exceção específica for levantada. Você pode usar vários pontos de interrupção condicionais para interromper seu programa quando qualquer uma das várias exceções for levantada.

Dan
fonte
Você também pode especificar o tipo de exceção a ser capturada, por exemplo catch throw std::runtime_exception.
scai
5

Defina um ponto de interrupção em __pure_virtual

Steve Folly
fonte
Na resposta @JeffreyHill, agora é denominado __cxa_pure_virtual. Não sei como verificar isso sozinho, portanto, não desejo editar a resposta. Não pretendo votar contra, mas a resposta pode estar errada agora e deve ser editada por alguém que sabe o que é correto.
Philipp Claßen
5

FWIW, aparentemente, no gcc 4.1, o nome da função apropriada foi alterado e deve-se definir um ponto de interrupção nesta função.

__cxa_pure_virtual

Jeffrey Hill
fonte
0

Apenas abaixo de um funcionou para mim com gdb 8.3:

break _Unwind_RaiseException

"catch throw" ou "break __cxx_throw" não funcionou para mim.

soumeng78
fonte