Compartilhar via


Injetando código dinamicamente com a API de depuração

Esta seção descreve a inclusão de código dinâmico usando o common linguagem tempo de execução (CLR) API de depuração. Inclusão de código dinâmico executa uma função que não estava presente no original arquivo executável portável (PE). Por exemplo, você pode usar a inclusão de código dinâmica para executar uma expressão no Imediata janela enquanto você está depurando no ambiente de desenvolvimento integrado do Microsoft Visual Studio (IDE). O CLR seqüestros um segmento para executar o código ativo. O depurador pode solicitar o CLR para executar ou congelar os threads restantes. sistema autônomo injeção de código dinâmico é incorporada na avaliação da função, você pode depurar uma função dinamicamente injetada sistema autônomo se fosse código normal. Ou seja, você pode chamar todos sistema autônomo serviços de depuração padrão, sistema autônomo definir pontos de interrupção, revisão, e assim por diante para o código injetado dinamicamente.

Um depurador deve fazer o seguinte para injetar código dinamicamente:

  • redigir uma função que irá executar código dinâmico.

  • Injetar o código o ser depurado usando edição e continuar.

  • executar o código, repetidamente, se desejar, chamando a função composta.

As subseções a seguir descrevem estas etapas em detalhes.

A função de composição

  1. A primeira etapa é calcular a assinatura da função que executará o código dinâmico. Para fazer isso, acrescente a assinatura por variáveis locais à assinatura do método que está sendo executada no quadro folha. Uma assinatura é construída dessa maneira não requer uma computação do subconjunto mínimo de variáveis usados. O tempo de execução ignorará as variáveis não utilizadas. Consulte "Como a assinatura de metadados", posteriormente neste tópico para obter mais informações.

    Todos os argumentos para a função devem ser declarados estar ByRef. Isso permitirá que a avaliação da função propagar alterações para as variáveis na função injetada volta para o quadro folha o ser depurado.

    Algumas variáveis não estejam no escopo quando o código dinâmico é executado. Em tais situações, você deve passar um null referência. Se você faz referência a uma variável de fora do escopo, um NullReferenceException será gerada. Quando isso ocorre, o depurador pode concluir a avaliação da função, chamando o ICorDebugManagedCallback::EvalExceptionretorno de chamada .

  2. escolher um nome exclusivo para a função. Você deve prefixar o nome da função com a seqüência de caracteres "_Hidden:" para que o depurador irá impedir que um usuário a função de navegação. Quando esta função é adicionada, um sinalizar será conjunto indica que o nome da função é especial.

Injetando código

  1. O depurador deve pedir ao compilador para criar uma função cujo corpo é o código que será injetado dinamicamente.

  2. O depurador calcula um delta arquivo executável portável (PE). Para fazer isso, o depurador chama a ICorDebugModule::GetEditAndContinueSnapshot método para obter um ICorDebugEditAndContinueSnapshot objeto. O depurador chama ICorDebugEditAndContinueSnapshot métodos para criar a imagem delta PE e ICorDebugController::CommitChanges para instalar o delta PE na imagem em execução.

    A função dinamicamente injetada deve ser colocada no mesmo nível de visibilidade do quadro folha na qual ele será executado. Se o quadro folha é um método de instância, a função dinamicamente injetada também deve ser um método de instância na mesma classe. Se o quadro folha é um método estático, a função dinamicamente injetada também deve ser um método estático. Métodos global são métodos estático que pertencem a uma determinada classe.

    ObservaçãoObservação:

    T função existirá no ser depurado mesmo após o processo de injeção de código dinâmico é Concluir d . Isso permite anteriormente código injetado ser reavaliadas repetidamente sem a necessidade Re Redija a função e insira novamente o código . Portanto , as etapas descritas nesta seção e Em a seção anterior pode ser ignorada para o código injetado anteriormente .

Execução de código introduzido

  1. A primeira etapa é obter o valor (um ICorDebugValue objeto) de cada variável na assinatura usando as rotinas de inspeção de depuração. Você pode usar ambos o ICorDebugThread::GetActiveFrame or the ICorDebugChain::GetActiveFrame método para obter o quadro folha e QueryInterface para ICorDebugILFrame. telefonar the ICorDebugILFrame::EnumerateLocalVariables, ICorDebugILFrame::EnumerateArguments, ICorDebugILFrame::GetLocalVariable, or ICorDebugILFrame::GetArgumentmétodo para obter as variáveis real.

    ObservaçãoObservação:

    I f o depurador anexado a um ser depurado que não faz ter CORDBG_ENABLE conjunto () ou seja, um ser depurado que tem não sido Coletando informações de depuração), o depurador não poderá obter um ICorDebugILFrame objeto e, portanto, não poderá coletar valores para a avaliação da função.

    Não é importante se os objetos que são argumentos da função dinamicamente injetados referência cancelados sem rigidez ou altamente. Quando a função é avaliada, o tempo de execução será seqüestrar o thread no qual ocorreu a injeção. Isso deixará o quadro folha original e todas as referências fortes originais na pilha. No entanto, se todas as referências a ser depurado são fracas, executando a injeção de código dinâmico pode acionar a uma coleta de lixo que pode fazer com que o objeto seja coletado ao lixo.

  2. Use o ICorDebugThread::CreateEval método para criar um ICorDebugEval objeto. ICorDebugEval Fornece métodos para avaliar uma função. telefonar um destes métodos. Um método sistema autônomo ICorDebugEval::CallFunction apenas define a avaliação da função. O depurador deve telefonar ICorDebugController::Continue para executar o depurado e avalia a função. Quando terminar, a avaliação, a depuração de serviços será telefonar o ICorDebugManagedtelefonarback::EvalComplete or ICorDebugManagedtelefonarback::EvalException método para notificar o depurador sobre a avaliação da função.

    Se a avaliação da função retorna um objeto, o objeto será altamente referenciado.

    Se o código injetado dynamitelefonary tentar cancelar a referência de um null referência que é passada para a função que delimita o código, o CLR depuração de serviços irá telefonar ICorDebugManagedCallback::EvalException. Em resposta, o depurador pode notificar o usuário que ele não é possível avaliar o código injetado.

    Observe que o ICorDebugEval::CallFunction método não realiza despachos virtual; use ICorDebugObjectValue::GetVirtualMethod em vez disso, se você desejar despachos virtual.

    Se o elemento a ser depurado é multithreaded e o depurador não deseja que qualquer um dos outros threads em execução, o depurador deve chamar ICorDebugController::SetAllThreadsDebugState e defina o estado de todos os segmentos para THREAD_SUSPEND, exceto para o segmento que é usado para a avaliação da função. Essa configuração pode causar um deadlock, dependendo do que faz o código injetado dinamicamente.

Problemas diversos

  • sistema autônomo segurança do .NET estrutura é determinada pelas diretivas de contexto, inclusão de código dinâmico operará com sistema autônomo mesmas permissões de segurança e recursos sistema autônomo quadro folha, a menos que você altere especificamente sistema autônomo configurações de segurança.

  • Podem ser adicionadas dinamicamente injetadas funções sempre que o recurso edição and Continue permite funções a serem adicionados. Uma escolha lógica é adicioná-las ao quadro folha.

  • Não há nenhum limite no número de campos, métodos de instância ou métodos estático que podem ser adicionados a uma classe usando operações de edição e continuação. A quantidade máxima de dados estático permitidos é predefinida e atualmente limitada a 1 MB por módulo.

  • Não-local goto instruções não são permitidas no código injetado dinamicamente.

Obtendo a assinatura dos metadados

Obtendo um repositório de metadados

Localizando o método usando IMetaDataImport

Construindo a assinatura de função

O formato da assinatura é documentado na especificação "Type e assinatura codificação nos metadados" e tem precedência sobre as informações contidas nesta visão geral.

A seção "Declaração do método" na especificação descreve o formato de assinatura do método. O formato é um byte para a convenção de chamada, seguido de um byte para a contagem de argumentos, seguido de uma lista de tipos. Cada tipo pode ter um dimensionar diferente. Se um argumento variável convenção de chamada for especificada, a contagem de argumentos será o número total de argumentos, ou seja, fixo argumentos com argumentos variáveis. An ELEMENT_TYPE_SENTINEL marcas de byte onde começam participante argumentos fixos e os argumentos de variáveis.

A seção "Assinaturas autônomos" na especificação descreve o formato de local de assinaturas. Assinaturas autônomas não usam um convenção de chamada de argumento variável.

Depois de obter a assinatura de método e a assinatura local, o depurador deve alocar espaço para uma nova assinatura. O depurador deve iterar, em seguida, a assinatura do método. Para cada tipo, ele deve colocar o ELEMENT_TYPE_BYREF byte seguido do tipo de nova assinatura. O processo deve ser repetido até que a assinatura do participante do método ou um tipo marcado ELEMENT_TYPE_SENTINEL for atingido. Em seguida, o depurador deve copiar os tipos de assinatura local e marcar cada tipo de ELEMENT_TYPE_BYREF. Se a assinatura do método tem uma convenção de chamada de argumento variável, o depurador deve copiar os tipos e marcá-los ELEMENT_TYPE_BYREF. Finalmente, o depurador deve atualizar a contagem de argumentos.

Consulte também

Outros recursos

Conceitos chave na API de depuração

Visão geral sobre depuração do CLR

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