PyGDB is a debugger capable of debugging binary programs(x86-64) with dwarf-2 debug infomation.
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
debug_info
demos
.gitignore
README.md
__init__.py
arch.py
breakpoint.py
implementation_detail.md
notes.md
pygdb.py
requirement.txt
test.c
utils.py

README.md

PyGDB

PyGDB is a debugger capable of debugging binary programs with dwarf-2 debug infomation. While the base-stone of PyGDB is Linux ptrace syscall, most of the work is done by Python code. I start this project to study how debugger works. Currently, the project is still under development.

Install

Install dependencies

Install libcapstone

$ sudo apt-get install libcapstone-dev

Install python packages

$ pip install -r requirements.txt

Usage

Start PyGDB and debug program test

$ ./pygdb.py test
(pygdb) help

Documented commands (type help <topic>):
========================================
break  cont  help  ibreak  istep  list  next  print  quit  run  show_regs  step

(pygdb) 

Supported Commands

  1. help

    Display help message:

    $ ./pygdb.py test
    (pygdb) help
    
    Documented commands (type help <topic>):
    ========================================
    break  cont  help  ibreak  istep  list  next  print  quit  run  show_regs  step
    
    (pygdb) 
  2. list

    Display source code, same as ls command in GDB:

    (pygdb) list
    /home/alex/src/pygdb/test.c
       7        } else {
       8    	printf("val: %d\n", val + 1);
       9        }
       10   }
       11   
       12   void bar(int cnt) {
       13       int i;
       14   
       15       for (i = 0; i < cnt; i++) {
       16   	foo(i);
       17       }
    (pygdb) 
  3. ibreak

    Install a exact break point at process virtual memory, ibreak 0x400596 has the same effect as break *0x400596 in GDB.

    $ ./pygdb.py test
    (pygdb) ibreak 0x400594
    IBreakPoint(0x400594) added.
    (pygdb) 
  4. break

    Install break point, break 10 will install break point at the 10th line of the source code.

    $ ./pygdb.py test
    (pygdb) list 35
    /home/alex/src/pygdb/test.c
       30   //     }
       31   // }
       32   
       33   int main()
       34   {
       35       int a, b, c, d;
       36       bar(2);
       37   
       38       a = 1;
       39       b = 2;
       40       c = a + b;
    (pygdb) break 35
    BreakPoint(iaddr=0x40059c, src_file=/home/alex/src/pygdb/test.c, line_no=35) added.
  5. istep

    Execute a single instruction, same as si in GDB.

    (pygdb) istep
    /home/alex/src/pygdb/test.c:34
       29   //         printf("%d\n", i);
       30   //     }
       31   // }
       32   
       33   int main()
    -> 34   {
       35       int a, b, c, d;
       36       bar(2);
       37   
       38       a = 1;
       39       b = 2;
    (pygdb) istep
    /home/alex/src/pygdb/test.c:36
       31   // }
       32   
       33   int main()
       34   {
       35       int a, b, c, d;
    -> 36       bar(2);
       37   
       38       a = 1;
       39       b = 2;
       40       c = a + b;
       41       d = b + c;
    (pygdb)
  6. step

    Step program until it reach a different source line, same as GDB.

    $ ./pygdb.py test
    (pygdb) break 35
    BreakPoint(iaddr=0x40059c, src_file=/home/alex/src/pygdb/test.c, line_no=35) added.
    (pygdb) run
    hit BreakPoint(iaddr=0x40059c, src_file=/home/alex/src/pygdb/test.c, line_no=35)
    /home/alex/src/pygdb/test.c:36
       31   // }
       32   
       33   int main()
       34   {
       35       int a, b, c, d;
    -> 36       bar(2);
       37   
       38       a = 1;
       39       b = 2;
       40       c = a + b;
       41       d = b + c;
    (pygdb) step
    /home/alex/src/pygdb/test.c:12
       7        } else {
       8    	printf("val: %d\n", val + 1);
       9        }
       10   }
       11   
    -> 12   void bar(int cnt) {
       13       int i;
       14   
       15       for (i = 0; i < cnt; i++) {
       16   	foo(i);
       17       }
    (pygdb) step
    /home/alex/src/pygdb/test.c:15
       10   }
       11   
       12   void bar(int cnt) {
       13       int i;
       14   
    -> 15       for (i = 0; i < cnt; i++) {
       16   	foo(i);
       17       }
       18   }
       19   
       20   
    (pygdb) 
  7. next

    Step program, proceeding through subroutine calls.

    $ ./pygdb.py test
    (pygdb) break 35
    BreakPoint(iaddr=0x40059c, src_file=/home/alex/src/pygdb/test.c, line_no=35) added.
    (pygdb) run
    hit BreakPoint(iaddr=0x40059c, src_file=/home/alex/src/pygdb/test.c, line_no=35)
    /home/alex/src/pygdb/test.c:36
       31   // }
       32   
       33   int main()
       34   {
       35       int a, b, c, d;
    -> 36       bar(2);
       37   
       38       a = 1;
       39       b = 2;
       40       c = a + b;
       41       d = b + c;
    (pygdb) next
    val: 1
    val: 1
    hit IBreakPoint(0x4005a6)
    /home/alex/src/pygdb/test.c:38
       33   int main()
       34   {
       35       int a, b, c, d;
       36       bar(2);
       37   
    -> 38       a = 1;
       39       b = 2;
       40       c = a + b;
       41       d = b + c;
       42   
       43       printf("%d %d %d %d\n", a, b, c, d);
    (pygdb)
  8. run

    Start execution, same as GDB.

    (pygdb) run
    val: 1
    val: 1
    1 2 3 5
    [test (process 3326) exit normally!]
    (pygdb) 
  9. cont

    Continue execution from a break point or pause after single step execution.

    $ ./pygdb.py test
    (pygdb) break 35
    BreakPoint(iaddr=0x40059c, src_file=/home/alex/src/pygdb/test.c, line_no=35) added.
    (pygdb) run
    hit BreakPoint(iaddr=0x40059c, src_file=/home/alex/src/pygdb/test.c, line_no=35)
    /home/alex/src/pygdb/test.c:36
       31   // }
       32   
       33   int main()
       34   {
       35       int a, b, c, d;
    -> 36       bar(2);
       37   
       38       a = 1;
       39       b = 2;
       40       c = a + b;
       41       d = b + c;
    (pygdb) cont
    val: 1
    val: 1
    1 2 3 5
    [test (process 3940) exit normally!]
    (pygdb)
  10. print

    Print value of a variable.

    Not implemented yet.

  11. show_regs

    Display register information.

    (pygdb) show_regs
    {
    "gs": 0, 
    "gs_base": 0, 
    "rip": "0x000000000040059d", 
    "rdx": "0x00007ffc37da7588", 
    "r15": 0, 
    "cs": "0x0000000000000033", 
    "rax": "0x0000000000400594", 
    "rsi": "0x00007ffc37da7578", 
    "rcx": 0, 
    "es": 0, 
    "r14": 0, 
    "fs": 0, 
    "r12": "0x0000000000400430", 
    "r13": "0x00007ffc37da7570", 
    "r10": "0x0000000000000846", 
    "r11": "0x00007f67f5be2740", 
    "orig_rax": "0xffffffffffffffff", 
    "fs_base": "0x00007f67f618c700", 
    "rsp": "0x00007ffc37da7480", 
    "ds": 0, 
    "rbx": 0, 
    "ss": "0x000000000000002b", 
    "r8": "0x0000000000400670", 
    "r9": "0x00007f67f5f9cab0", 
    "rbp": "0x00007ffc37da7490", 
    "eflags": "0x0000000000000202", 
    "rdi": "0x0000000000000001"
    }
    (pygdb)
  12. quit

    $ ./pygdb.py test
    (pygdb) run
    val: 1
    val: 1
    1 2 3 5
    [test (process 4071) exit normally!]
    (pygdb) quit

    Quit from PyGDB.

TODOs

  • attach/detach
  • set watchpoint
  • print variables
  • delete break points
  • stack unwinding
  • expression evaluation
  • run function by hand(see run_function_by_hand() in gdb)
  • publish to pip index