Quão lento é o recurso de depuração de passo único x86?

3

A arquitetura x86 fornece uma armadilha de uma única etapa para depuração. Quanto diminui o programa em execução?

Se, digamos, uma função de kernel do Linux foi criada para não fazer nada além de um único passo em um processo, quanto mais lento esse processo seria executado? Alguém tem uma boa estimativa?

Estou pensando nisso depois de passar uma semana rastreando um bug de segmentação. Seria legal se esses bugs pudessem ser reproduzidos. Como sobre um recurso que executou dois threads sequencialmente, alternando entre a execução de uma instrução em um thread e, em seguida, uma instrução do outro, de uma maneira previsível. Estou pensando em um gerador de números pseudo-aleatórios que produziria uma string de bits - 0 significa executar uma instrução no thread 1, 1 significa executar uma instrução no thread 2.

Então você pode semear o PRNG e obter uma intercalação reprodutível de instruções. Diferentes sementes de PRNG produziriam diferentes padrões de intercalação. Você pode executar um caso de teste sob um grupo de sementes PRNG e, se encontrar uma que tenha provocado uma falha, reproduza-a.

Alguém ouviu falar de algo assim sendo feito?

Atualização:

Como isso pode ser feito?

Suponha que estamos rodando em algo como um Core i5, onde você tem 4 estados de processador e 2 núcleos. Estamos usando a interceptação de etapa única para retornar um processo do espaço do usuário para o espaço do kernel. Então, isso é dois dos estados, certo? Então nós temos o outro segmento em execução no outro núcleo com seu espaço de usuário e estados de espaço do kernel, certo? Há algo como um spinlock (provavelmente dois spinlocks) sincronizando os dois threads do kernel. Cada um deles gira enquanto o outro percorre o espaço do usuário com algumas instruções, depois sincroniza e troca funções.

Parece que temos o número certo de threads e núcleos para que tudo caiba no chip de uma só vez. Mas quão rápido é executado?

Nós poderíamos apenas tentar. Alguém poderia escrever algum código do kernel. Ou talvez alguém saiba.

Todas as coisas extravagantes que esses novos chips fazem. Eu ficaria impressionado , e não totalmente surpreso, se fosse rápido.

    
por Brent Baccala 02.08.2014 / 01:56

2 respostas

1

A interceptação de etapa única funciona levantando uma exceção após a conclusão de cada instrução. O uso usual dessa armadilha é que o seu depurador detecta essa exceção e permite que você examine as coisas antes de "percorrer" a próxima instrução.

Se você está pensando em fazer isso para rastreio, fazendo um registro detalhado do que seu código está fazendo, seu rastreador / depurador será invocado como um manipulador de exceção, registre o que você deseja registrar e, em seguida, descarte o exceção - repita. Espero que isso diminua a taxa de execução do código que você está rastreando por um fator de uma a várias centenas ... pelo menos.

Em relação às suas ideias para instruções de intercalação de vários encadeamentos, essa não é a maneira de resolver seu problema de serialização. Você precisa resolvê-lo - comprovadamente - no design.

    
por 02.08.2014 / 04:52
0

Sua abordagem parece útil e eu ponderei sobre um problema semelhante.
Como isso pode ser feito? (Existem alguns caminhos bastante alternativos também, incluindo análise estática, ou reflexão e corrotinas) . Mas o seu método pode ser muito otimizado de duas formas alternativas, caso você esteja aleatoriamente passando por várias instruções (talvez até com muitas instruções, o que também parece natural):

1) Decida o comprimento aleatório da próxima seqüência de instruções antes de iniciar a sequência. Use o disassembler e coloque int 3 no final da sequência, em vez de um único passo.

2) Caso você não queira usar o int 3 por algum motivo ou não confie totalmente no seu desmontador, você pode usar o stepping único e depois copiar as instruções executadas para uma nova área de memória.
Agora, da próxima vez que o gerador aleatório decidir executar a mesma quantidade de passos seqüenciais a partir da mesma localização de programa, simplesmente pule para a nova área de memória contendo as instruções copiadas e execute até o final daquela sequência sem uma única etapa. No final da sequência de instruções, você precisa chamar de volta a sua estrutura de depuração.

Para ambas as abordagens, você precisa adicionar um tratamento especial para chamadas, saltos e saltos condicionais.

    
por 28.01.2017 / 12:29