Usar gdb para código de montagem de etapa única fora do executável especificado causa o erro "não é possível encontrar limites da função atual"

86

Estou fora do executável de destino do gdb e nem mesmo tenho uma pilha que corresponda a esse destino. Quero fazer uma única etapa de qualquer maneira, para poder verificar o que está acontecendo em meu código de assembly, porque não sou um especialista em assembly x86. Infelizmente, o gdb se recusa a fazer essa depuração simples no nível do assembly. Isso me permite definir e parar no ponto de interrupção apropriado, mas assim que eu tento avançar em uma única etapa, o gdb reporta o erro "Não é possível encontrar limites da função atual" e o EIP não muda.

Detalhes adicionais:

O código de máquina foi gerado por instruções gcc asm e eu o copiei para o local da memória do kernel onde ele está executando, a partir da saída de objdump -d. Eu não me importaria em uma maneira simples de usar um carregador para carregar meu código-objeto para um endereço realocado, mas tenha em mente que o carregamento deve ser feito em um módulo do kernel.

Suponho que outra alternativa seria produzir um módulo de kernel falso ou arquivo de informações de depuração para fornecer ao gdb, para fazê-lo acreditar que essa área está dentro do código do programa. O gdb funciona bem no próprio executável do kernel.

(Para aqueles que realmente querem saber, estou inserindo código em tempo de execução no espaço de dados do kernel do Linux dentro de uma VM VMware e depurando-o a partir do gdb remoto, depurando o kernel por meio do stub gdb integrado do VMware Workstation. Observação Não estou escrevendo o kernel exploits; sou um estudante de pós-graduação em segurança, escrevendo um protótipo.)

(Posso definir um ponto de interrupção em cada instrução dentro de minha montagem. Isso funciona, mas se tornaria muito trabalhoso depois de um tempo, já que o tamanho das instruções de montagem x86 varia e a localização da montagem mudará toda vez que eu reiniciar.)

Paulo
fonte
O pessoal inteligente do ksplice.com injeta dados e código no kernel montando módulos de kernel "falsos" e carregando-os. E se eles podem fazer isso, por que você não pode? ;-)
efêmero de

Respostas:

116

Você pode usar stepiou nexti(que pode ser abreviado para siou ni) para percorrer seu código de máquina.

R Samuel Klatchko
fonte
1
Uau. Em retrospecto, não sei como me esqueci da stepi. Acho que apenas presumi que, como o gdb não tinha o código-fonte, essa etapa reverteria para as instruções de montagem.
Paul,
1
nota: muitas vezes você não pode digitar "break main", "run" para programas de montagem. Digite "layout asm", "start" ao invés. Eu entendi isso lendo a mensagem abaixo, mas alguém que está lendo esta postagem pode não ser tão paciente.
Dmitry
1
@Dmitry starté equivalente a tbreak mainseguido por run(nota: em tbreakvez de break)
Ruslan
151

Em vez de gdb, corra gdbtui. Ou corra gdbcom o -tuiswitch. Ou pressione C-x C-aapós entrar gdb. Agora você está no modo TUI do GDB .

Enter layout asmpara fazer a montagem de exibição da janela superior - isso seguirá automaticamente o ponteiro da instrução, embora você também possa alterar os quadros ou rolar durante a depuração. Pressione C-x spara entrar no modo SingleKey, onde run continue up down finishetc. são abreviados para uma única tecla, permitindo que você percorra seu programa muito rapidamente.

   + ------------------------------------------------- -------------------------- +
B +> | 0x402670 <main> push% r15 |
   | 0x402672 <main + 2> mov% edi,% r15d |
   | 0x402675 <main + 5> push% r14 |
   | 0x402677 <main + 7> push% r13 |
   | 0x402679 <main + 9> mov% rsi,% r13 |
   | 0x40267c <main + 12> pressione% r12 |
   | 0x40267e <main + 14> push% rbp |
   | 0x40267f <main + 15> push% rbx |
   | 0x402680 <main + 16> sub $ 0x438,% rsp |
   | 0x402687 <main + 23> mov (% rsi),% rdi |
   | 0x40268a <main + 26> movq $ 0x402a10,0x400 (% rsp) |
   | 0x402696 <main + 38> movq $ 0x0,0x408 (% rsp) |
   | 0x4026a2 <main + 50> movq $ 0x402510,0x410 (% rsp) |
   + ------------------------------------------------- -------------------------- +
processo filho 21518 In: linha principal: ?? PC: 0x402670
(gdb) arquivo / opt / j64-602 / bin / jconsole
Lendo símbolos de /opt/j64-602/bin/jconsole...done.
(nenhum símbolo de depuração encontrado) ... pronto.
(gdb) layout asm
(gdb) start
(gdb)
efêmero
fonte
26

A coisa mais útil que você pode fazer aqui é display/i $pcantes de usar stepicomo já sugerido na resposta de R Samuel Klatchko. Isso diz ao gdb para desmontar a instrução atual antes de imprimir o prompt a cada vez; então você pode simplesmente continuar pressionando Enter para repetir o stepicomando.

(Veja minha resposta a outra pergunta para mais detalhes - o contexto dessa pergunta era diferente, mas o princípio é o mesmo.)

Matthew Slattery
fonte