Como o GDB pausa uma execução


16

Como você deve saber, podemos usar o GDB e definir pontos de interrupção em nosso código para pausar a execução para depuração.

Minhas perguntas são: como o GDB pausa um processo e permite exibir o conteúdo dos registros usando, i rpor exemplo. Os registros não estão sendo usados ​​por outros processos do SO constantemente? como eles não são substituídos?

É apenas uma captura instantânea do conteúdo e não dados ao vivo?


2
Como é que todos os registros não são sobrescritos quando o sistema operacional decide pausar seu programa por um momento e executar outro?
precisa saber é o seguinte

CppCon 2018: Simon Brand “Como funcionam os depuradores de C ++” youtube.com/watch?v=0DDrseUomfU
Robert Andrzejuk

Respostas:


24

Isso varia um pouco com a arquitetura, mas os pontos importantes se aplicam quase universalmente:

  • A interrupção da manutenção faz com que o estado da CPU (incluindo registros) seja salvo na memória antes de executar o ISR e restaurado quando o ISR sair.

  • Se uma rotina de serviço de interrupção trocar o conteúdo do local da memória em que esses registros são salvos, ela poderá executar uma alternância de contexto . Cada encadeamento possui uma região de memória onde seus registros são salvos quando o encadeamento não está em execução.

  • A alternância de contexto é controlada por um agendador de encadeamentos que leva em consideração se um encadeamento está aguardando E / S, sincronização, qual é sua prioridade, entrega de sinal etc. Geralmente, há uma contagem de suspensão que é fatorada.

  • O depurador pode incrementar a contagem de suspensão, o que garante que o thread não possa ser executado. Em seguida, ele pode inspecionar (e alterar) a cópia salva de registros do encadeamento.


14

Além das ótimas informações de @BenVoigt, permita-me fazer algumas adições:

Um ponto de interrupção é definido pelo depurador substituindo um valor de código de máquina (uma instrução ou parte de uma instrução) no processo que está sendo depurado por uma instrução de interceptação específica no local no código que corresponde à linha (de origem) desejada para interromper. Essa instrução de interceptação específica deve ser usada como um ponto de interrupção - o depurador sabe disso e o sistema operacional.

Quando o processo / thread que está sendo depurado atinge a instrução trap, que aciona o processo que @Ben está descrevendo, que inclui a metade de uma troca de contexto que suspende o thread em execução no momento (que inclui salvar o estado da CPU na memória) para possível reinicialização posterior. Como essa interceptação é uma interceptação de ponto de interrupção, o sistema operacional mantém o processo sendo depurado suspenso usando talvez um mecanismo que @Ben descreve e notifica e, eventualmente, retoma o depurador.

O depurador usa chamadas do sistema para acessar o estado salvo do processo / thread suspenso que está sendo depurado.

Para executar (retomar) a linha de código que foi interrompida (que agora possui a instrução de interceptação específica), o depurador restaurará o valor original do código de máquina que ele substituiu pela instrução de interceptação, possivelmente configurará outra interceptação em outro lugar (por exemplo, se uma única etapa, ou o usuário cria novos pontos de interrupção) e marca o processo / encadeamento como executável, talvez usando um mecanismo descrito por @Ben.

Detalhes reais podem ser mais complicados, pois manter um ponto de interrupção de execução demorado significa fazer algo como trocar a interceptação do ponto de interrupção por código real, para que a linha possa ser executada e, em seguida, trocar o ponto de interrupção novamente ...

Os registros não estão sendo usados ​​por outros processos do SO constantemente? como eles não são substituídos?

Como o @Ben descreve, o uso do recurso de suspensão / retomada de encadeamento já existente (a alternância / troca de contexto da multitarefa ) que permite que os processadores sejam compartilhados por vários processos / encadeamentos usando a redução de tempo.

É apenas uma captura instantânea do conteúdo e não dados ao vivo?

São os dois. Como o encadeamento que atingiu o ponto de interrupção é suspenso, é feita uma captura instantânea dos dados ativos (registros da CPU, etc.) no momento da suspensão, e o mestre autoritário dos valores de registro da CPU para restaurar no processador, caso o encadeamento seja retomado. . Se você usar a interface do usuário do depurador para ler e / ou alterar os registros da CPU (do processo que está sendo depurado), ele lerá e / ou alterará esse instantâneo / mestre usando chamadas do sistema.


1
Bem, a maioria das arquiteturas de processador suporta traps de depuração que, por exemplo, são acionados quando o IP (ponteiro de instrução) é igual ao endereço armazenado em um registro de ponto de interrupção, economizando a necessidade de reescrever o código. (Ao corresponder registros que não sejam IP, você pode obter pontos de interrupção de dados e, após cada instrução, pode obter uma única etapa). O que você descreveu também é possível, é claro, desde que o código não esteja na memória somente leitura.
Ben Voigt

Re "Se você alterar os registros da CPU ..." no último parágrafo, acho que você quer dizer "Se você alterar a cópia salva dos registros do CUP ..." Então, quando o SO reiniciar o processo, os dados alterados serão gravados novamente para os registros reais.
jamesqf

@jamesqf, sim, thx!
Erik Eidt

@BenVoigt, concordou. embora os depuradores possam lidar com um número ilimitado de pontos de interrupção, o hardware possa lidar com zero ou alguns, portanto, o depurador precisa fazer algum malabarismo.
Erik Eidt

@ jamesqf: Descrever isso como uma cópia é um pouco enganador. É o armazenamento oficial do estado do encadeamento enquanto o encadeamento não está em execução.
Ben Voigt

5

A rigor, pelo menos na maioria dos casos típicos, o próprio gdb não pausa a execução. Em vez disso, o gdb solicita ao sistema operacional e o sistema operacional pausa a execução.

Isso pode inicialmente parecer uma distinção sem diferença - mas, honestamente, realmente há uma diferença. A diferença é a seguinte: essa capacidade já está embutida no sistema operacional típico, porque precisa ser capaz de pausar e reiniciar a execução do encadeamento de qualquer maneira - quando um encadeamento não está programado para ser executado (por exemplo, ele precisa de algum recurso que não está disponível no momento) o sistema operacional precisa pausá-lo até que possa ser programado para ser executado.

Para fazer isso, o sistema operacional normalmente possui um bloco de memória reservado para cada thread para salvar o estado atual da máquina. Quando é necessário pausar uma linha, o estado atual da máquina é salvo nessa área. Quando é necessário retomar um encadeamento, o estado da máquina é restaurado a partir dessa área.

Quando o depurador precisa pausar um encadeamento, ele faz com que o SO pause esse encadeamento exatamente da mesma maneira que faria por outros motivos. Em seguida, para ler o estado do segmento em pausa, o depurador examinará o estado salvo do segmento. Se você modificar o estado, o depurador gravará no estado salvo, quando entrará em vigor quando o encadeamento for retomado.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.