How to pass arguments and redirect stdin from a file to program run in gdb?

前端 未结 5 1297
青春惊慌失措
青春惊慌失措 2020-12-04 05:55

I usually run a program as :

./a.out arg1 arg2 

I would like to debug it using gdb.

I am aware of the set args

5条回答
  •  小蘑菇
    小蘑菇 (楼主)
    2020-12-04 06:27

    Wouldn't it be nice to just type debug in front of any command to be able to debug it with gdb on shell level?

    Below it this function. It even works with following:

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

    This is a call where you cannot control anything, everything is variable, can contain spaces, linefeeds and shell metacharacters. In this example, in, out, two, and three are arbitrary other commands which consume or produce data which must not be harmed.

    Following bash function invokes gdb nearly cleanly in such an environment [Gist]:

    debug()
    {
      1000<&0 1001>&1 1002>&2 \
      0/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 "$@";
    }
    

    Example on how to apply this: Just type debug in front:

    Before:

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

    After:

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

    That's it. Now it's an absolute no-brainer to debug with gdb. Except for a few details or more:

    • gdb does not quit automatically and hence keeps the IO redirection open until you exit gdb. But I call this a feature.

    • You cannot easily pass argv0 to the program like with exec -a arg0 command args. Following should do this trick: After exec-wrapper change "exec to "exec -a \"\${DEBUG_ARG0:-\$1}\".

    • There are FDs above 1000 open, which are normally closed. If this is a problem, change 0<&1000 1>&1001 2>&1002 to read 0<&1000 1>&1001 2>&1002 1000<&- 1001>&- 1002>&-

    • You cannot run two debuggers in parallel. There also might be issues, if some other command consumes /dev/tty (or STDIN). To fix that, replace /dev/tty with "${DEBUGTTY:-/dev/tty}". In some other TTY type tty; sleep inf and then use the printed TTY (i. E. /dev/pts/60) for debugging, as in DEBUGTTY=/dev/pts/60 debug command arg... That's the Power of Shell, get used to it!

    Function explained:

    • 1000<&0 1001>&1 1002>&2 moves away the first 3 FDs
      • This assumes, that FDs 1000, 1001 and 1002 are free
    • 0/dev/tty 2>&0 restores the first 3 FDs to point to your current TTY. So you can control gdb.
    • /usr/bin/gdb -q -nx -nw runs gdb invokes gdb on shell
    • -ex 'set exec-wrapper /bin/bash -c "exec 0<&1000 1>&1001 2>&1002 \"\$@\"" creates a startup wrapper, which restores the first 3 FDs which were saved to 1000 and above
    • -ex r starts the program using the exec-wrapper
    • --args "$@" passes the arguments as given

    Wasn't that easy?

提交回复
热议问题