Pergunta

Eu quero ser capaz de detectar quando uma gravação para o endereço de memória ocorre - por exemplo, definindo uma chamada de retorno ligado a uma interrupção. Alguém sabe como?

Eu gostaria de ser capaz de fazer isso em tempo de execução (possivelmente gdb tem esse recurso, mas a minha especial causas de aplicação GDB falha).

Foi útil?

Solução

Se você quiser escreve interceptar a um intervalo de endereços, você pode usar mprotect() para marcar a memória em questão como não-gravável, e instalar um manipulador de sinal usando sigaction() para pegar o SIGSEGV resultante, fazer o seu logging ou o que quer e marcar a página como gravável novamente.

Outras dicas

O que você precisa é o acesso aos registos de depuração X86: http://en.wikipedia.org/wiki / Debug_register

Você precisa definir o endereço de ponto de interrupção em um dos DR0 a DR3, e então a condição (gravação de dados) em DR7. A interrupção ocorrerá e você pode executar o seu código de depuração para ler DR6 e descobrir o que causou a interrupção.

Se GDB não funcionar, você pode tentar um depurador simples / menor, como http: // sourceforge. net / projetos / minibug / -. se isso não está funcionando, você pode pelo menos ir através do código e entender como usar o hardware de depuração no processador-se

Além disso, há um grande recurso desenvolvedor IBM em dominar linux depuração técnicas que deverá fornecer algumas opções adicionais:

http://www.ibm.com/developerworks/linux/library / l-debug /

Um razoavelmente bom artigo sobre fazer isto é janelas está aqui (Eu sei que você está rodando em Linux, mas outros podem vir a esta pergunta querer fazê-lo no Windows):

http://www.codeproject.com/KB/debug/hardwarebreakpoint.aspx

-Adam

GDB tem essa característica: ele é chamado watchpoints de hardware, e é muito bem suportado em Linux / x86:

(gdb) watch *(int *)0x12345678

Se o seu aplicativo trava GDB, construção GDB atual de CVS Chefe .

Se isso GDB ainda falhar, apresentar uma GDB bug .

As chances são de que possamos corrigir GDB mais rápido do que você pode cortar em torno manipulador SIGSEGV (desde um caso bom teste), e correções para GDB ajudá-lo com problemas futuros também.

mprotect tem uma desvantagem: sua memória deve ser page-limite alinhados. Eu tive minha memória problemático na pilha e não foi capaz de usar mprotect ().

Como Adam disse, o que você quer é manipular os registros de depuração. No Windows, eu usei este: http://www.morearty.com/code/breakpoint/ e funcionou muito bem. Eu também portou para Mach-O (Mac OS X), e funcionou muito bem, também. Também foi fácil, porque Mach-O tem thread_set_state (), que é equivalente a SetThreadContext ().

O problema com o Linux é que ele não tem tais equivalentes. Eu encontrei ptrace, mas eu pensei, isso não pode ser isso, deve haver algo mais simples. Mas não há. Ainda. Eu acho que eles estão trabalhando em uma API hw_breakpoint para ambos kernel e espaço do usuário. (Veja http://lwn.net/Articles/317153/ )

Mas quando eu encontrei este: http://blogs.oracle.com/nike/entry / memory_debugger_for_linux eu dei-lhe uma tentativa e não era tão ruim assim. O método ptrace funciona por alguns de "processo fora" agindo como um "debugger", anexando ao seu programa, injetando novos valores para os registros de depuração, e encerra com o seu programa de continuar com um novo conjunto de HW ponto de interrupção. A coisa é, você pode criar esse "processo fora"-se usando fork (), (I não teve sucesso com um pthread), e fazer estes passos simples em linha em seu código.

O código addwatchpoint deve ser adaptado para trabalhar com Linux de 64 bits, mas isso é apenas mudando USER_DR7 etc, para offsetof (usuário struct, u_debugreg [7]). Outra coisa é que depois de um PTRACE_ATTACH, você tem que esperar para o depurado para realmente parar. Mas em vez de tentar novamente uma POKEUSER em um loop ocupado, a coisa certa a fazer seria um waitpid () em seu pid.

O único problema com o método ptrace é que o programa pode ter apenas um "debugger" anexado ao mesmo tempo. Assim, um ptrace anexar falhará se o seu programa já está em execução sob controle gdb. Mas, assim como o código de exemplo faz, você pode registrar um manipulador de sinal para SIGTRAP, executado sem gdb, e quando você pegar o sinal, insira uma espera de loop ocupado por gdb para anexar. De lá você pode ver quem tentou escrever a sua memória.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top