├── .gitignore ├── Makefile ├── Test.c ├── Test.gdb ├── Install.sh ├── ShellPipeCommand.py └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | Test 2 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-g 2 | 3 | Test: Test.c 4 | -------------------------------------------------------------------------------- /Test.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | int foo() { 5 | const char* buf = "Hello World \x1c"; 6 | puts(buf); 7 | } 8 | int main(){ 9 | foo(); 10 | } 11 | 12 | -------------------------------------------------------------------------------- /Test.gdb: -------------------------------------------------------------------------------- 1 | source ShellPipeCommand.py 2 | b foo 3 | r 4 | n 5 | shell-pipe bt 6 | shell-pipe bt | grep main 7 | sp bt | grep main 8 | sp disas | grep mov 9 | sp cat /proc/cpuinfo | grep 'cache size' 10 | -------------------------------------------------------------------------------- /Install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 4 | FULLPATH="$DIR/ShellPipeCommand.py" 5 | present=$(grep "$FULLPATH" $HOME/.gdbinit 2> /dev/null) 6 | if [[ -z "$present" ]]; then 7 | echo "source $FULLPATH" >> ~/.gdbinit 8 | fi 9 | -------------------------------------------------------------------------------- /ShellPipeCommand.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | 3 | import gdb 4 | import subprocess 5 | import sys 6 | 7 | 8 | class ShellPipe (gdb.Command): 9 | "Command to pipe gdb internal command output to external commands." 10 | 11 | def __init__(self): 12 | super (ShellPipe, self).__init__("shell-pipe", 13 | gdb.COMMAND_DATA, 14 | gdb.COMPLETE_NONE, True) 15 | gdb.execute("alias -a sp = shell-pipe", True) 16 | 17 | def invoke(self, arg, from_tty): 18 | arg = arg.strip() 19 | if arg == "": 20 | print("Argument required (gdb_command_and_args | externalcommand..).") 21 | return 22 | 23 | gdb_command, shell_commands = None, None 24 | 25 | if '|' in arg: 26 | gdb_command, shell_commands = arg.split("|", 1) 27 | gdb_command, shell_commands = gdb_command.strip(), shell_commands.strip() 28 | else: 29 | gdb_command = arg 30 | 31 | # If there is an error executing the first command as a gdb command, 32 | # assume that it is a shell command. 33 | try: 34 | # Collect the output and feed it through the pipe 35 | output = gdb.execute(gdb_command, True, True) 36 | except: 37 | output = None 38 | shell_commands = arg 39 | 40 | if shell_commands: 41 | shell_process = subprocess.Popen(shell_commands, stdin=subprocess.PIPE, shell=True) 42 | if output: 43 | shell_process.communicate(output.encode('utf-8')) 44 | shell_process.wait() 45 | else: 46 | sys.stdout.write(output) 47 | 48 | ShellPipe() 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Shell-Pipe Command 2 | 3 | This gdb extension allows the piping of internal gdb commands to external 4 | commands, as described in [this Stackoverflow 5 | question](https://stackoverflow.com/q/7120673/391161). 6 | 7 | Suppose one wanted to find all the `mov` instructions in the current function. 8 | 9 | (gdb) disas 10 | Dump of assembler code for function foo: 11 | 0x0000000000400526 <+0>: push %rbp 12 | 0x0000000000400527 <+1>: mov %rsp,%rbp 13 | 0x000000000040052a <+4>: sub $0x10,%rsp 14 | 0x000000000040052e <+8>: movq $0x4005e4,-0x8(%rbp) 15 | => 0x0000000000400536 <+16>: mov -0x8(%rbp),%rax 16 | 0x000000000040053a <+20>: mov %rax,%rdi 17 | 0x000000000040053d <+23>: callq 0x400400 18 | 0x0000000000400542 <+28>: nop 19 | 0x0000000000400543 <+29>: leaveq 20 | 0x0000000000400544 <+30>: retq 21 | 22 | 23 | One can source the file `ShellPipeCommand.py` in their `$HOME/.gdb_init` file, 24 | and then invoke the following command. 25 | 26 | (gdb) shell-pipe disas | grep mov 27 | 0x0000000000400527 <+1>: mov %rsp,%rbp 28 | 0x000000000040052e <+8>: movq $0x4005e4,-0x8(%rbp) 29 | => 0x0000000000400536 <+16>: mov -0x8(%rbp),%rax 30 | 0x000000000040053a <+20>: mov %rax,%rdi 31 | 32 | Note that the native gdb `shell` command already handles shell pipelines which 33 | do not involve internal gdb commands. This extension is intended for the case 34 | where the **first** command in the pipeline is a gdb internal command. If the 35 | first command in the pipeline is a valid gdb command as well as a valid 36 | external command, it will be interpreted as the former rather than the latter. 37 | --------------------------------------------------------------------------------