import unittest
from helper import Debugger
class CommandTestCase(unittest.TestCase):
def setUp(self):
self.debugger = Debugger(path='./examples/target/debug/hello_world')
def test_debugee_execute(self):
self.debugger.cmd('run', 'Hello, world!', 'bye!')
def test_function_breakpoint(self):
self.debugger.cmd('break main', 'New breakpoint')
self.debugger.cmd('run', 'myprint("Hello, world!");')
self.debugger.cmd('break myprint', 'New breakpoint')
self.debugger.cmd('continue', 'Hit breakpoint 2')
self.debugger.cmd('continue', 'Hello, world!', 'Hit breakpoint 2')
self.debugger.cmd('continue', 'bye')
def test_line_breakpoint(self):
self.debugger.cmd('break hello_world.rs:15', 'New breakpoint')
self.debugger.cmd('run', '15 println!("{}", s)')
self.debugger.cmd('continue', 'Hello, world!', '15 println!("{}", s)')
self.debugger.cmd('continue', 'bye!')
def test_multiple_breakpoints_set(self):
self.debugger.cmd('break hello_world.rs:5', 'New breakpoint')
self.debugger.cmd('break hello_world.rs:9', 'New breakpoint')
self.debugger.cmd('run', 'Hit breakpoint 1 at', 'myprint("Hello, world!")')
self.debugger.cmd('continue', 'Hello, world!', 'Hit breakpoint 2 at', 'myprint("bye!")')
self.debugger.cmd('continue', 'bye!')
def test_address_breakpoint_set(self):
self.debugger.cmd('break hello_world.rs:5', 'New breakpoint')
self.debugger.cmd('run')
addr = self.debugger.search_in_output(r'Hit breakpoint 1 at .*0x(.*):')
addr = "0x" + addr[:14]
self.debugger.cmd('q')
self.debugger = Debugger(path='./examples/target/debug/hello_world')
self.debugger.cmd(f'break {addr}', 'New breakpoint')
self.debugger.cmd('run', 'Hit breakpoint 1 at')
self.debugger.cmd('continue', 'Hello, world!', 'bye!')
def test_write_register(self):
self.debugger.cmd('break hello_world.rs:4', 'New breakpoint')
self.debugger.cmd('break hello_world.rs:10', 'New breakpoint')
self.debugger.cmd('run')
start_addr = self.debugger.search_in_output(r'Hit breakpoint 1 at .*0x(.*):')
start_addr = "0x" + start_addr[:14]
self.assertNotEqual(start_addr, "")
self.debugger.cmd('continue')
addr = self.debugger.search_in_output(r'Hit breakpoint 2 at .*0x(.*):')
addr = "0x" + addr[:14]
self.assertNotEqual(addr, "")
self.debugger.cmd('q')
addr_as_integer = int(addr, 16) + 1
ret_addr = hex(addr_as_integer)
self.debugger = Debugger(path='./examples/target/debug/hello_world')
self.debugger.cmd(f'break {ret_addr}', 'New breakpoint')
self.debugger.cmd('run', 'Hello, world!', 'bye!')
self.debugger.cmd(f'register write rip {start_addr}')
self.debugger.cmd('continue', 'Hello, world!', 'bye!')
@staticmethod
def test_step_in():
debugger = Debugger(path='./examples/target/debug/calc -- 1 2 3 --description result')
debugger.cmd('break main.rs:10', 'New breakpoint')
debugger.cmd('run', '10 let s: i64')
debugger.cmd('step', 'calc::sum3', '25 let ab = sum2')
debugger.cmd('step', 'calc::sum2', '21 a + b')
debugger.cmd('step', '22 }')
debugger.cmd('step', 'calc::sum3', '26 sum2(ab, c)')
debugger.cmd('step', 'calc::sum2', '21 a + b')
debugger.cmd('step', '22 }')
debugger.cmd('step', 'calc::sum3', '27 }')
debugger.cmd('step', 'calc::main', '15 print(s, &args[5]);')
def test_step_out(self):
self.debugger.cmd('break hello_world.rs:15', 'New breakpoint')
self.debugger.cmd('run', '15 println!("{}", s)')
self.debugger.cmd('stepout', '7 sleep(Duration::from_secs(1));')
def test_step_over(self):
self.debugger.cmd('break hello_world.rs:5', 'New breakpoint')
self.debugger.cmd('run', 'myprint("Hello, world!");')
self.debugger.cmd('next', '7 sleep(Duration::from_secs(1));')
self.debugger.cmd('next', '9 myprint("bye!")')
self.debugger.cmd('next', '10 }')
def test_step_over_on_fn_decl(self):
self.debugger.cmd('break hello_world.rs:14', 'New breakpoint')
self.debugger.cmd('run', 'Hit breakpoint 1 at')
self.debugger.cmd('next', '15 println!("{}", s)')
def test_get_symbol(self):
self.debugger.cmd_re('symbol main', '__libc_start_main', r'main - Text 0x[0-9A-F]{,16}')
def test_backtrace(self):
self.debugger.cmd('break hello_world.rs:15', 'New breakpoint')
self.debugger.cmd('run', '15 println!("{}", s)')
self.debugger.cmd('bt', 'myprint', 'hello_world::main')
@staticmethod
def test_args_for_executable():
debugger = Debugger(path='./examples/target/debug/calc -- 1 1 1 --description three')
debugger.cmd('run', 'three: 3')
@staticmethod
def test_read_value_u64():
debugger = Debugger(path='./examples/target/debug/calc -- 1 2 3 --description result')
debugger.cmd('break main.rs:15', 'New breakpoint')
debugger.cmd('run', '15 print(s, &args[5]);')
debugger.cmd('var locals', 's = i64(6)')
def test_function_breakpoint_remove(self):
self.debugger.cmd('break main', 'New breakpoint')
self.debugger.cmd('break remove main', 'Removed breakpoint')
self.debugger.cmd('run', 'bye!')
def test_line_breakpoint_remove(self):
self.debugger.cmd('break hello_world.rs:15', 'New breakpoint')
self.debugger.cmd('run', '15 println!("{}", s)')
self.debugger.cmd('break remove hello_world.rs:15', 'Removed breakpoint')
self.debugger.cmd('continue', 'bye!')
def test_breakpoint_remove_by_number(self):
self.debugger.cmd('break main', 'New breakpoint')
self.debugger.cmd('break remove 1', 'Removed breakpoint')
self.debugger.cmd('run', 'bye!')
def test_breakpoint_info(self):
self.debugger.cmd('break hello_world.rs:9', 'New breakpoint')
self.debugger.cmd('break myprint', 'New breakpoint')
self.debugger.cmd('break main', 'New breakpoint')
self.debugger.cmd('break hello_world.rs:7', 'New breakpoint')
self.debugger.cmd_re(
'break info',
r'- Breakpoint 1 at .*0x[0-9A-F]{14,16}.*: .*\/hello_world\.rs.*:9',
r'- Breakpoint 2 at .*0x[0-9A-F]{14,16}.*: .*\/hello_world\.rs.*:15',
r'- Breakpoint 3 at .*0x[0-9A-F]{14,16}.*: .*\/hello_world\.rs.*:5',
r'- Breakpoint 4 at .*0x[0-9A-F]{14,16}.*: .*\/hello_world\.rs.*:7',
)
self.debugger.cmd('run')
self.debugger.cmd_re(
'break info',
r'- Breakpoint 1 at .*0x[0-9A-F]{14,16}.*: .*\/hello_world\.rs.*:9 ',
r'- Breakpoint 2 at .*0x[0-9A-F]{14,16}.*: .*\/hello_world\.rs.*:15',
r'- Breakpoint 3 at .*0x[0-9A-F]{14,16}.*: .*\/hello_world\.rs.*:5',
r'- Breakpoint 4 at .*0x[0-9A-F]{14,16}.*: .*\/hello_world\.rs.*:7',
)
self.debugger.cmd('break remove main', 'Removed breakpoint')
self.debugger.cmd_re(
'break info',
r'- Breakpoint 1 at .*0x[0-9A-F]{14,16}.*: .*\/hello_world\.rs.*:9 ',
r'- Breakpoint 2 at .*0x[0-9A-F]{14,16}.*: .*\/hello_world\.rs.*:15',
r'- Breakpoint 4 at .*0x[0-9A-F]{14,16}.*: .*\/hello_world\.rs.*:7'
)
def test_debugee_restart(self):
self.debugger.cmd('run', 'Hello, world!', 'bye!')
self.debugger.cmd('run', 'Restart a program?')
self.debugger.cmd('y', 'Hello, world!', 'bye!')
def test_debugee_restart_at_bp(self):
self.debugger.cmd('break hello_world.rs:9', 'New breakpoint')
self.debugger.cmd('run', 'Hello, world!')
self.debugger.cmd('run', 'Restart a program?')
self.debugger.cmd('y', 'Hello, world!')
self.debugger.cmd('continue', 'bye!')
def test_debugee_restart_at_end(self):
self.debugger.cmd('break hello_world.rs:9', 'New breakpoint')
self.debugger.cmd('run', 'Hello, world!', 'Hit breakpoint 1')
self.debugger.cmd('continue', 'bye!')
self.debugger.cmd('run', 'Restart a program?')
self.debugger.cmd('y', 'Hello, world!', 'Hit breakpoint 1')
self.debugger.cmd('quit')
@staticmethod
def test_frame_switch():
debugger = Debugger(path='./examples/target/debug/calc -- 1 2 3 --description result')
debugger.cmd('break main.rs:21', 'New breakpoint 1')
debugger.cmd('run', 'Hit breakpoint 1')
debugger.cmd('arg all', 'a = i64(1)', 'b = i64(2)')
debugger.cmd('frame switch 1')
debugger.cmd('arg all', 'a = i64(1)', 'b = i64(2)', 'c = i64(3)')
def test_disasm(self):
self.debugger.cmd('break main', 'New breakpoint')
self.debugger.cmd('run')
self.debugger.cmd('source asm', 'Assembler code for function hello_world::main', 'mov')
self.debugger.cmd('break myprint', 'New breakpoint')
self.debugger.cmd('continue')
self.debugger.cmd('source asm', 'Assembler code for function hello_world::myprint', 'mov')
def test_source_fn(self):
self.debugger.cmd('break main', 'New breakpoint')
self.debugger.cmd('run')
self.debugger.cmd(
'source fn',
'hello_world::main at',
'4 fn main() {',
'7 sleep(Duration::from_secs(1));',
'10 }'
)
@staticmethod
def test_source_fn_with_frame_switch():
debugger = Debugger(path='./examples/target/debug/calc -- 1 2 3 --description result')
debugger.cmd('break main.rs:21', 'New breakpoint 1')
debugger.cmd('run', 'Hit breakpoint 1')
debugger.cmd(
'source fn',
'fn sum2(a: i64, b: i64) -> i64 {',
'a + b',
'}',
)
debugger.cmd('frame switch 1')
debugger.cmd(
'source fn',
'fn sum3(a: i64, b: i64, c: i64) -> i64 {',
'let ab = sum2(a, b);',
'sum2(ab, c)',
'}',
)
debugger.cmd('frame switch 2')
debugger.cmd(
'source fn',
'fn main() {',
'let args: Vec<String> = env::args().collect();',
'let v1 = &args[1];',
'let v2 = &args[2];',
'}',
)
def test_source_bounds(self):
self.debugger.cmd('break main', 'New breakpoint')
self.debugger.cmd('run')
self.debugger.cmd(
'source 4',
'1 use std::thread::sleep;',
'4 fn main() {',
'9 myprint("bye!")',
)
@staticmethod
def test_breakpoint_at_rust_panic():
debugger = Debugger(path='./examples/target/debug/panic -- user')
debugger.cmd('break rust_panic', 'New breakpoint')
debugger.cmd('run', 'then panic!')
debugger.cmd('bt', 'rust_panic') debugger.cmd('continue')
debugger = Debugger(path='./examples/target/debug/panic -- system')
debugger.cmd('break rust_panic', 'New breakpoint')
debugger.cmd('run', 'attempt to divide by zero')
debugger.cmd('bt', 'rust_panic')
@staticmethod
def test_trigger():
debugger = Debugger(path='./examples/target/debug/vars')
debugger.cmd('trigger any')
debugger.cmd('backtrace')
debugger.cmd('var int8')
debugger.cmd('end')
debugger.cmd('break vars.rs:19', 'New breakpoint 1')
debugger.cmd('run', 'Hit breakpoint 1', 'vars::scalar_types', 'int8 = i8(1)')
debugger.cmd('trigger')
debugger.cmd('var int16')
debugger.cmd('end')
debugger.cmd('trigger info', 'Any breakpoint or watchpoint', 'backtrace, var int8', 'Breakpoint 1', 'var int16')
debugger.cmd('trigger any')
debugger.cmd('end')
debugger.cmd('run')
debugger.cmd('y', 'Hit breakpoint 1', 'int16 = i16(-1)')
debugger.cmd('break vars.rs:30', 'New breakpoint 2')
debugger.cmd('trigger b 2')
debugger.cmd('var f32')
debugger.cmd('var f64')
debugger.cmd('end')
debugger.cmd('watch int16', 'New watchpoint 1')
debugger.cmd('trigger w 1')
debugger.cmd('backtrace')
debugger.cmd('end')
debugger.cmd('c', 'f32 = f32(1.1)', 'f64 = f64(1.2)')
debugger.cmd('c', 'vars::scalar_types')