Como passar argumentos e redirecionar stdin de um arquivo para o programa executado no gdb?

210

Eu costumo executar um programa como:

./a.out arg1 arg2 <file

Eu gostaria de depurá-lo usando o gdb.

Estou ciente da set argsfuncionalidade, mas isso só funciona a partir do prompt gdb.

Ciro Santilli adicionou uma nova foto
fonte

Respostas:

136

Passe os argumentos para o runcomando no gdb.

$ gdb ./a.out
(gdb) r < t
Starting program: /dir/a.out < t
moinudin
fonte
3
ré curto rune você pode segui-lo com qualquer argumento. Como nesta questão, seria: r arg1 arg2 <fileou poderia serrun arg1 arg2 <file
phyatt
Para mim, isso não funciona. Então eu tentei $ gdb ./a.out, o (gdb) r < t arg1 arg2que funciona bem para mim. No meu caso a.out = nft arg1 = import arg2 = json et = file containing json rules
mystictot 2/17/17
410

Você consegue fazer isso:

gdb --args path/to/executable -every -arg you can=think < of

O ser mágico --args.

Basta digitar runno console de comando gdb para iniciar a depuração.

rubenvb
fonte
24
Eu pensei que estava lendo isso errado no começo; estranho que --args preceda o executável. Mas é assim!
21413 Caulim Fire
8
@Kaolin --args deve vir antes do executável, porque é uma opção para o gdb. Se viesse depois, como o gdb o distinguiria de um argumento que você desejava passar para o executável que está depurando?
código é o seguinte
9
@ codehippo: Bem, se você não especificou --args, não argumentos passados ​​para o executável, por isso não é ambíguo.
Lightness Races in Orbit
14
Eu estou supondo que é porque convencionalmente argv[0]é o nome do executável
Claudiu
3
isso irá redirecionar a entrada de gdbsi para o ofarquivo e resultar em gdb tentando executar comandos a partir dele
Unkulunkulu
4

Se você deseja ter o runcomando bare gdbpara executar seu programa com redirecionamentos e argumentos, você pode usar set args:

% gdb ./a.out
(gdb) set args arg1 arg2 <file
(gdb) run

Não consegui obter o mesmo comportamento com o --argsparâmetro, gdbescapou ferozmente dos redirecionamentos, ou seja,

% gdb --args echo 1 2 "<file"
(gdb) show args
Argument list to give program being debugged when it is started is "1 2 \<file".
(gdb) run
...
1 2 <file
...

Este realmente redireciona a entrada do próprio gdb, não o que realmente queremos aqui

% gdb --args echo 1 2 <file
zsh: no such file or directory: file
unkulunkulu
fonte
1

Inicie o GDB em seu projeto.

  1. Vá para o diretório do projeto, onde você já compilou o executável do projeto. Emita o comando gdb e o nome do executável como abaixo:

    gdb projectExecutablename

Isso inicia o gdb, imprime o seguinte: GNU gdb (Ubuntu 7.11.1-0ubuntu1 ~ 16.04) 7.11.1 Copyright (C) 2016 Free Software Foundation, Inc. ............... .................................. Digite "palavra apropriada" para procurar comandos relacionados à "palavra". Lendo símbolos do projetoExecutablename ... done. (gdb)

  1. Antes de iniciar a execução do programa, você deseja configurar seus pontos de interrupção. O comando break permite que você faça isso. Para definir um ponto de interrupção no início da função denominada main:

    (gdb) b principal

  2. Depois de ter o prompt (gdb), o comando run inicia a execução do executável. Se o programa que você está depurando exigir argumentos da linha de comando, especifique-os para o comando run. Se você deseja executar o meu programa no arquivo "xfiles" (que está em uma pasta "mulder" no diretório do projeto), faça o seguinte:

    (gdb) r mulder / xfiles

Espero que isto ajude.

Isenção de responsabilidade: Esta solução não é minha, é adaptada de https://web.stanford.edu/class/cs107/guide_gdb.html Este pequeno guia para gdb foi, provavelmente, desenvolvido na Universidade de Stanford.

Ehsan
fonte
0

Não seria legal digitar debugna frente de qualquer comando para poder depurá-lo gdbno nível do shell?

Abaixo dela esta função. Até funciona com o seguinte:

"$program" "$@" < <(in) 1> >(out) 2> >(two) 3> >(three)

Esta é uma chamada em que você não pode controlar nada, tudo é variável, pode conter espaços, feeds de linha e metacaracteres de shell. Neste exemplo, in, out, two, e threesão outros comandos arbitrários que consomem ou dados de produzir que não devem ser prejudicadas.

A bashfunção a seguir chama gdbquase de forma limpa em um ambiente como esse [ Gist ]:

debug()
{
  1000<&0 1001>&1 1002>&2 \
  0</dev/tty 1>/dev/tty 2>&0 \
  /usr/bin/gdb -q -nx -nw \
  -ex 'set exec-wrapper /bin/bash -c "exec 0<&1000 1>&1001 2>&1002 \"\$@\"" exec' \
  -ex r \
  --args "$@";
}

Exemplo de como aplicar isso: basta digitar debugna frente:

Antes:

p=($'\n' $'I\'am\'evil' "  yay  ")
"b u g" "${p[@]}" < <(in) 1> >(out) 2> >(two) 3> >(three)

Depois de:

p=($'\n' $'I\'am\'evil' "  yay  ")
debug "b u g" "${p[@]}" < <(in) 1> >(out) 2> >(two) 3> >(three)

É isso aí. Agora é um acéfalo absoluto para depurar gdb. Exceto por alguns detalhes ou mais:

  • gdbnão fecha automaticamente e, portanto, mantém o redirecionamento de entrada / saída aberto até você sair gdb. Mas eu chamo isso de recurso.

  • Você não pode passar facilmente argv0para o programa como com exec -a arg0 command args. A seguir, faça este truque: Depois de exec-wrapperalterar "execpara "exec -a \"\${DEBUG_ARG0:-\$1}\".

  • Existem DFs acima de 1000 abertos, que normalmente são fechados. Se isso for um problema, altere 0<&1000 1>&1001 2>&1002para ler0<&1000 1>&1001 2>&1002 1000<&- 1001>&- 1002>&-

  • Você não pode executar dois depuradores em paralelo. Também pode haver problemas, se algum outro comando consumir /dev/tty(ou STDIN). Para corrigir isso, substitua /dev/ttypor "${DEBUGTTY:-/dev/tty}". Em algum outro tipo de TTY tty; sleep infe, em seguida, use o TTY impresso (ie. E. /dev/pts/60) para depuração, como em DEBUGTTY=/dev/pts/60 debug command arg... Esse é o poder da Shell, se acostume!

Função explicada:

  • 1000<&0 1001>&1 1002>&2 afasta os 3 primeiros FDs
    • Isso pressupõe que os FDs 1000, 1001 e 1002 são gratuitos
  • 0</dev/tty 1>/dev/tty 2>&0restaura os 3 primeiros FDs para apontar para o seu TTY atual. Então você pode controlar gdb.
  • /usr/bin/gdb -q -nx -nwexecuta gdbinvoca gdbno shell
  • -ex 'set exec-wrapper /bin/bash -c "exec 0<&1000 1>&1001 2>&1002 \"\$@\"" cria um wrapper de inicialização, que restaura os 3 primeiros FDs salvos em 1000 e acima
  • -ex r inicia o programa usando o exec-wrapper
  • --args "$@" passa os argumentos como dado

Isso não foi fácil?

Tino
fonte