Informática Numaboa - Tutoriais e Programação
Assembly - Tratamento de erros
Dom 21 Jun 2009 18:48 |
- Detalhes
- Categoria: Assembly Numaboa (antigo oiciliS)
- Atualização: Domingo, 21 Junho 2009 19:53
- Autor: vovó Vicki
- Acessos: 11663
Neste texto serão abordados apenas os mecanismos envolvidos no caso de ocorrência de erros. Serve apenas como orientação para a aplicação de um sistema eficiente de um tratamento estruturado de erros, indispensável para garantir a robustez e a consistência de aplicativos mais elaborados.
Erros
Denominamos erro ou exceção um evento que ocorre durante a execução de um programa e que requer uma execução fora do fluxo normal de controle. Existem exceções de hardware e de software. Exceções de hardware podem ser resultado da execução de sequências de instruções que tentam acessar endereços de memória inválidos ou efetuar uma divisão por zero. Exceções de software podem ser resultado do uso de parâmetros com valores inválidos ou serem iniciadas explicitamente através do uso da função RaiseException. Em todo caso, são "pecados" cometidos contra o sistema - o "mau comportamento" que gera uma exceção pode comprometer o funcionamento do sistema operacional o qual, para se precaver, interrompe o processo e apresenta uma mensagem de erro do tipo:
Tratamento Estruturado de Exceções
A API do Windows oferece um mecanismo próprio para o tratamento de exceções geradas tanto por hardware quanto por software: é o chamado tratamento estruturado de exceções. Este mecanismo permite um controle absoluto no tratamento de exceções, oferece suporte para depuradores (debuggers) e pode ser usado em todas as linguagens de programação e em todo tipo de máquina.
A API do win32 também permite a manipulação de conclusão. Este tipo de manipulação garante que, sempre que uma área de código vigiado for executada, um bloco de código de conclusão específico também seja executado, tenha ou não ocorrido uma exceção. O código de conclusão é executado independentemente da maneira como o fluxo de controle tenha saído da área vigiada. Por exemplo, o manipulador de conclusão pode garantir que determinadas tarefas, como as de "faxina", sejam cumpridas mesmo que ocorra uma exceção ou algum outro erro durante a execução do código da área vigiada.
Se você programa em "C/C++" ou "Delphi", com certeza conhece as plavras-chave try, except e finally. Try (tentar) identifica a área vigiada, except (exceto) identifica o manipulador de exceções e finally (no final) o manipulador de conclusão. Pondo em linguagem corrente seria o mesmo que "tente executar o código desta área; caso ocorra algum erro, faça uso do manipulador de exceções; no final, acione o manipulador de conclusão". Esta estrutura de atendimento permite que se programe aplicativos mais robustos e confiáveis e é conhecida como SEH ou Structured Exception Handling.
Tipos de Exceção
Como já foi citado, as exceções podem ser iniciadas pelo hardware ou pelo software. Tanto uma quanto a outra podem ocorrer no modo kernel (no "interior" do sistema) ou no código modo usuário (o código que você programou). Daí os tipos de exceção:
- de hardware no modo kernel
- de hardware no modo usuário
- de software no modo kernel
- de software no modo usuário
Estruturas das Exceções
Quando ocorre uma exceção, o processador pára a execução no ponto onde ela ocorreu e transfere o controle para o sistema. A primeira providência do sistema é a de guardar o "estado de máquina" da linha de processo atual (o thread atual) e as informações que descrevem a exceção. Logo a seguir, o sistema procura por um manipulador de exceções para tratar o erro.
O "estado de máquina" é armazenado numa estrutura do tipo CONTEXT. Esta informação, denominada registro do contexto (context record), vai permitir que o sistema continue a execução a partir do ponto gerador da exceção se esta for tratada com sucesso.
A descrição da exceção, chamada de registro da exceção (exception record), é armazenada numa estrutura do tipo EXCEPTION_RECORD.
Devido ao fato das informações referentes à máquina e as informações referentes à exceção serem guardadas em estruturas diferentes, o mecanismo de tratamento de exceções torna-se portável para as mais diversas plataformas.
A estrutura EXCEPTION_RECORD
A definição desta estrutura é:
O membro DWORD ExceptionFlags pode ser zero, indicando uma exceção recuperável, ou ser EXCEPTION_NONCONTINUABLE, que indica uma exceção irrecuperável. Qualquer tentativa de continuar a execução após uma exceção irrecuperável causa uma nova exceção do tipo EXCEPTION_NONCONTINUABLE_EXCEPTION.
O membro struct _EXCEPTION_RECORD *ExceptionRecord aponta para uma estrutura do tipo EXCEPTION_RECORD. Os registros de exceção podem ser encadeados para fornecerem informações adicionais quando ocorrer uma exceção aninhada.
O membro PVOID ExceptionAddress especifica o endereço onde ocorreu a exceção.
O membro DWORD NumberParameters especifica o número de parâmetros associados à exceção. Este é o número de elementos definidos na matriz (array) ExceptionInformation.
O membro DWORD ExceptionInformation [EXCEPTION_MAXIMUM_PARAMETERS] especifica uma matriz com argumentos de 32 bits adicionais que descrevem a exceção. A função RaiseException pode especificar esta matriz de argumentos. Para a maior parte dos códigos de exceção os elementos da matriz estão indefinidos.
O membro DWORD ExceptionCode indica a razão pela qual a exceção ocorreu. Os valores possíveis estão na tabela abaixo:
EXCEPTION_ACCESS_VIOLATION | O thread tentou ler/escrever num endereço virtual ao qual não tinha acesso. |
---|---|
EXCEPTION_ARRAY_BOUNDS_EXCEEDED | O thread tentou acessar um elemento de array fora dos limites e o hardware possibilita a checagem de limites. |
EXCEPTION_BREAKPOINT | Foi encontrado um ponto de parada (breakpoint). |
EXCEPTION_DATATYPE_MISALIGNMENT | O thread tentou ler/escrever dados desalinhados em hardware que não oferece alinhamento. Por exemplo, valores de 16 bits precisam ser alinhados em limites de 2 bytes; valores de 32 bits em limites de 4 bytes, etc. |
EXCEPTION_FLT_DENORMAL_OPERAND | Um dos operandos numa operação de ponto flutuante está desnormatizado. Um valor desnormatizado é um que seja pequeno demais para poder ser representado no formato de ponto flutuante padrão. |
EXCEPTION_FLT_DIVIDE_BY_ZERO | O thread tentou dividir um valor em ponto flutuante por um divisor em ponto flutuante igual a zero. |
EXCEPTION_FLT_INEXACT_RESULT | O resultado de uma operação de ponto flutuante não pode ser representado como uma fração decimal exata. |
EXCEPTION_FLT_INVALID_OPERATION | Qualquer operação de ponto flutuante não incluída na lista. |
EXCEPTION_FLT_OVERFLOW | O expoente de uma operação de ponto flutuante é maior que a magnitude permitida pelo tipo correspondente. |
EXCEPTION_FLT_STACK_CHECK | A pilha ficou desalinhada ("estourou" ou "ficou abaixo") como resultado de uma operação de ponto flutuante. |
EXCEPTION_FLT_UNDERFLOW | O expoente de uma operação de ponto flutuante é menor que a magnitude permitida pelo tipo correspondente. |
EXCEPTION_ILLEGAL_INSTRUCTION | O thread tentou executar uma instrução inválida. |
EXCEPTION_IN_PAGE_ERROR | O thread tentou acessar uma página que não estava presente e o sistema não foi capaz de carregar a página. Esta exceção pode ocorrer, por exemplo, se uma conexão de rede é perdida durante a execução do programa via rede. |
EXCEPTION_INT_DIVIDE_BY_ZERO | O thread tentou dividir um valor inteiro por um divisor inteiro igual a zero. |
EXCEPTION_INT_OVERFLOW | O resultado de uma operação com inteiros causou uma transposição (carry) além do bit mais significativo do resultado. |
EXCEPTION_INVALID_DISPOSITION | Um manipulador (handle) de exceções retornou uma disposição inválida para o tratador de exceções. Uma exceção deste tipo nunca deveria ser encontrada em linguagens de médio/alto nível. |
EXCEPTION_NONCONTINUABLE_EXCEPTION | O thread tentou continuar a execução após a ocorrência de uma exceção irrecuperável. |
EXCEPTION_PRIV_INSTRUCTION | O thread tentou executar uma instrução cuja operação não é permitida no modo de máquina atual. |
EXCEPTION_SINGLE_STEP | Um interceptador de passos ou outro mecanismo de instrução isolada sinalizou que uma instrução foi executada. |
EXCEPTION_STACK_OVERFLOW | O thread esgotou sua pilha (estouro de pilha). |
Quando ocorre uma exceção no código modo usuário o sistema realiza a seguinte procura por um manipulador de exceções:
- Primeiro, o sistema tenta notificar o depurador do processo (debugger), se este existir.
- Se o processo não estiver sendo depurado ou se o depurador não tratar a exceção, o sistema tenta localizar um manipulador de exceções emolduradas (frame-based) fazendo uma procura nas molduras da pilha do thread onde ocorreu a exceção. O sistema procura primeiro na moldura atual da pilha, depois segue procurando em molduras de pilha precedentes. (Leia sobre molduras de pilha logo abaixo).
- Se não foi possível encontrar um manipulador emoldurado ou se nenhum deles tratar a exceção, o sistema faz uma segunda tentativa de notificar o depurador do processo.
- Se o processo não estiver sendo depurado ou se o depurador associado não tratar a exceção, o sistema fornece um tratamento padrão de acordo com o tipo de exceção. Para a maioria das exceções, a ação padrão é chamar a função ExitProcess.
Quando ocorre uma uma exceção no código modo kernel, o sistema procura nas molduras da pilha do kernel na tentativa de localizar um manipulador de exceções. Se o manipulador não puder ser encontrado ou se nenhum dos manipuladores tratar a exceção, o sistema encerra sua operação como se a função ExitProcess tivesse sido chamada.
- Anterior
- Próximo >>