Partilhar via


Arquitetura de depuração do CLR

O common language runtime (CLR) API de depuração foi projetado para ser usado como se fosse parte do kernel do sistema operacional. No código não gerenciado, quando um programa gera uma exceção, o kernel suspende a execução do processo e passa as informações de exceção para o depurador usando o Win32 API de depuração. API de depuração CLR fornece a mesma funcionalidade para código gerenciado. Quando o código gerenciado gera uma exceção, a API de depuração CLR suspende a execução do processo e passa as informações de exceção para o depurador.

Este tópico descreve como e quando o CLR depuração obtém de API envolvidos e a quais serviços que ele fornece.

Arquitetura de processo

API de depuração CLR inclui dois componentes principais:

  • A DLL de depuração, que é sempre carregada no mesmo processo como o programa que está sendo depurado. O controlador de tempo de execução é responsável pela comunicação com o CLR e executar o controle de execução e inspeção de segmentos que estão executando o código gerenciado.

  • A interface do depurador, que é carregada em um processo diferente do programa que está sendo depurado. A interface do depurador é responsável pela comunicação com o controlador de tempo de execução em nome do depurador. Também é responsável pela manipulação de eventos de depuração do Win32 que vêm do processo que está sendo depurado e ambos esses eventos de manipulação ou passá los para um depurador de código não gerenciado. A interface de depurador é a única parte da API que tem uma API exposta de depuração CLR.

API de depuração CLR não suporta o uso remoto entre computadores ou entre processos; ou seja, um depurador que usa a API deve fazer isso dentro de seu próprio processo, como mostrado no seguinte diagrama de arquitetura da API. Esta ilustração mostra onde os diferentes componentes do CLR API de depuração estão localizados e como eles interagem com o CLR e o depurador.

Arquitetura da API do CLR depuração

Arquitetura de depuração CLR

Depurador de código gerenciado

É possível criar um depurador que oferece suporte somente para código gerenciado. API de depuração CLR permite que tal um depurador anexar a um processo sob demanda usando um anexe o soft mecanismo. Um depurador soft-anexado a um processo pode subseqüentemente desanexar do processo.

Sincronização de Segmento

API de depuração CLR tem requisitos de conflitantes relativas à arquitetura do processo. Por um lado, existem vários motivos determinantes para manter a lógica de depuração no mesmo processo como o programa que está sendo depurado. Por exemplo, as estruturas de dados são complexas e com freqüência elas são manipuladas por funções em vez de um layout de memória fixa. É muito mais fácil chamar as funções diretamente em vez de tentar decodificar as estruturas de dados de fora do processo. Outro motivo para manter a lógica de depuração no mesmo processo é melhorar o desempenho, a remoção da sobrecarga de comunicação entre processos. Por fim, um recurso importante de depuração do CLR é a capacidade de executar o código de usuário no processo de depuração, o que obviamente requer algumas cooperação com o processo de depuração.

Por outro lado, depuração CLR deve coexistir com depuração de código não gerenciado, que só pode ser executada corretamente a partir de um processo externo. Além disso, um depurador de fora de processo é mais seguro do que um depurador no processo porque a interferência entre a operação do depurador e o processo de depuração é minimizada em um depurador de out-of-process.

Devido esses requisitos conflitantes, a API de depuração CLR combina alguns de cada abordagem. A principal interface de depuração está fora do processo e coexiste com os serviços de depuração nativos do Win32. No entanto, a API de depuração CLR adiciona a capacidade de sincronizar com o processo de depuração para que ele segura possa executar código no processo do usuário. Para executar a sincronização, a API colabora com o sistema operacional e o CLR suspender todos os segmentos do processo em um local onde eles não interromper uma operação e deixar o tempo de execução em um estado incoerentes. Em seguida, o depurador é capaz de executar código em um thread especial que pode examinar o estado do tempo de execução e chamar o código do usuário, se necessário.

Quando o código gerenciado executa uma instrução de ponto de interrupção ou gera uma exceção, o controlador de tempo de execução é notificado. Este componente irá determinar quais segmentos estão executando o código gerenciado e quais segmentos estão executando o código não gerenciado. Normalmente, os threads que estejam executando o código gerenciado terão permissão para continuar a execução até que eles atinjam um estado onde eles podem ser com segurança suspenso. Por exemplo, eles talvez precise completar uma coleta de lixo está em andamento. Quando os segmentos de código gerenciado tiverem chegado a estados de seguros, todos os threads são suspensos. A interface do depurador, em seguida, informa o depurador que um ponto de interrupção ou exceção foi recebida.

Quando código não gerenciado executa uma instrução de ponto de interrupção ou gera uma exceção, o componente de interface de depurador recebe a notificação por meio do Win32 API de depuração. Esta notificação é passada para um depurador não gerenciado. Se o depurador decidir que deseja executar a sincronização (por exemplo, para que gerenciados podem ser olhados quadros de pilha de código), a interface de depurador deve primeiro reiniciar o processo de depuração parado e então informar o controlador de tempo de execução para executar a sincronização. A interface do depurador, em seguida, é notificada quando a sincronização foi concluída. Essa sincronização é transparente para o depurador não gerenciado.

O thread que gerou a instrução de ponto de interrupção ou exceção não deve ser permitido para executar durante o processo de sincronização. Para facilitar isso, a interface do depurador assume o controle do thread, colocando um filtro de exceção especial na cadeia do filtro do segmento. Quando o thread é reiniciado, ele inserirá o filtro de exceção, o que colocará o thread sob controle do controlador de tempo de execução. Quando é hora para continuar o processamento de exceção (ou tempo para cancelar a exceção), o filtro retornar o controle para a cadeia de filtro de exceção regular do segmento ou retornar o resultado correto para continuar a execução.

Em casos raros, o segmento que gera a exceção nativa pode ser bloqueios importantes que devem ser liberadas antes da sincronização do runtime pode ser concluída. (Normalmente esses serão os bloqueios de biblioteca de nível inferior, como bloqueios na malloc heap.) Em tais casos, a operação de sincronização deve expirar e a sincronização falhará. Isso fará com que determinadas operações que exigem a sincronização também falha.

O segmento de auxiliar no processo

Um segmento auxiliar do depurador único é usado dentro de cada processo do CLR para certificar-se de que a API de depuração CLR funcione corretamente. Esse thread auxiliar é responsável pela manipulação de muitos dos serviços de inspeção, fornecidos pela API de depuração, além de para assistência com a sincronização de thread em determinadas circunstâncias. Você pode usar o ICorDebugProcess::GetHelperThreadID método para identificar o thread auxiliar.

Interações com os compiladores JIT

Para ativar um depurador just-in-time (JIT) de depurar código compilado, o CLR API de depuração deve ser capaz de mapear as informações da versão Microsoft intermediate language (MSIL) de uma função para a versão nativa da função. Essas informações incluem pontos de seqüência no código e informações sobre o local de variável local. No.NET Framework versões 1.0 e 1.1, essa informação foi produzido apenas quando o runtime não estava no modo de depuração. No.NET Framework 2.0, essa informação é produzido o tempo todo.

Além disso, o código compilado JIT pode ser altamente otimizado. Otimizações como, por exemplo, eliminação de subexpressão comuns, expansão de linha de funções, loop de desenrolar, içamento de código e assim por diante podem levar à perda de correlação entre o código MSIL de uma função e o código nativo que será chamado para executá-lo. Assim, a capacidade do compilador JIT para fornecer informações de mapeamento correto é prejudicar essas técnicas de otimização de código agressivo. Portanto, quando o tempo de execução é executado no modo de depuração, o compilador JIT não executará algumas otimizações. Essa restrição permite que os depuradores determinar com precisão o mapeamento de fonte de linha e o local de todos os argumentos e variáveis locais.

Modos de depuração.

API de depuração CLR fornece modos especiais de depuração nos dois casos:

  • Modo de edição e continuação. Nesse caso, o runtime funciona de modo diferente para ativar o código para ser alterada posteriormente. Isso ocorre porque o layout de certas estruturas de dados em tempo de execução deve ser diferente para oferecer suporte a Edit and Continue. Porque isso tem um efeito adverso no desempenho, não use esse modo, a menos que você deseja editar e continuar a funcionalidade.

  • Modo de depuração. Este modo permite que o compilador JIT omitir otimizações. Portanto, faz a execução de código nativo corresponder a origem da linguagem de alto nível com mais de perto. Não use esse modo é necessário porque ele também tem um efeito adverso no desempenho.

Se você depurar um programa fora de editar e continuar o modo, não há suporte para a funcionalidade de edição e continuação. Se você depurar um programa fora do modo de depuração, a maioria dos recursos de depuração ainda terão suporte, mas otimizações podem causar um comportamento estranho. Por exemplo, a etapa única pode aparecer saltar aleatoriamente de uma linha para outra no método e métodos embutidos não podem aparecer em um rastreamento de pilha.

Um depurador pode habilitar, editar e continuar tanto depuração modos programaticamente por meio da API de depuração, se o depurador assumir o controle de um processo, antes que o runtime tenha inicializado próprio CLR. Isso é suficiente para várias finalidades. No entanto, um depurador que conecta a um processo que já está em execução por alguns instantes (por exemplo, durante a depuração JIT) poderão iniciar esses modos.

Para ajudar a lidar com esses problemas, um programa pode ser executado no modo JIT ou modo de depuração independentemente de um depurador. Para obter informações sobre maneiras para habilitar a depuração, consulte Depuração, rastreamento e criação de perfil.

Otimizações JIT podem tornar um aplicativo menos depurável. API de depuração CLR habilita a inspeção de variáveis locais com o código compilado JIT que foi otimizado e de quadros de pilha. Stepping é suportado, mas pode ser imprecisa. Você pode executar um programa que instrui o compilador JIT para desativar todas as otimizações JIT para produzir código depurável. Para obter detalhes, consulte:Facilitando uma imagem depurar.

Consulte também

Conceitos

Visão geral de depuração do CLR

Outros recursos

Depuração (referência de API não gerenciada)