@ -231,6 +231,20 @@ class PwndbgController:
return OneShotAwaitable ( YieldExecDirect ( command , True , False ) )
def print_error ( msg : str , * args ) :
"""
Print an error message in the style of the LLDB CLI .
"""
print ( message . error ( " error: " ) , msg , * args )
def print_warn ( msg : str , * args ) :
"""
Print a warning message in the style of the LLDB CLI .
"""
print ( message . warn ( " warn: " ) , msg , * args )
@wrap_with_history
def run (
controller : Callable [ [ PwndbgController ] , Coroutine [ Any , Any , None ] ] , debug : bool = False
@ -351,10 +365,8 @@ def exec_repl_command(
# Let the user get an LLDB prompt if they so desire.
if bits [ 0 ] == " lldb " :
print (
message . warn (
" You are now entering LLDB mode. In this mode, certain commands may cause Pwndbg to break. Proceed with caution. "
)
print_warn (
" You are now entering LLDB mode. In this mode, certain commands may cause Pwndbg to break. Proceed with caution. "
)
dbg . debugger . RunCommandInterpreter (
True , False , lldb . SBCommandInterpreterRunOptions ( ) , 0 , False , False
@ -413,10 +425,8 @@ def exec_repl_command(
if not test ( bits [ 0 ] ) :
continue
print (
message . error (
f " The ' { name } ' command is not supported. Use the ' lldb ' command to enter LLDB mode and try again. "
)
print_error (
f " The ' { name } ' command is not supported. Use the ' lldb ' command to enter LLDB mode and try again. "
)
found_barred = True
@ -501,10 +511,8 @@ def exec_repl_command(
warn = not pset ( bits [ 1 ] , bits [ 2 ] )
if warn :
print (
message . warn (
" The ' set ' command is used exclusively for Pwndbg settings. If you meant to change LLDB settings, use the fully spelled-out ' settings ' command, instead. "
)
print_warn (
" The ' set ' command is used exclusively for Pwndbg settings. If you meant to change LLDB settings, use the fully spelled-out ' settings ' command, instead. "
)
return True
@ -551,10 +559,8 @@ def exec_repl_command(
dbg . controllers . clear ( )
if coroutine_fail_warn :
print (
message . warn (
" Exceptions occurred execution controller processing. Debugging will likely be unreliable going forward. "
)
print_warn (
" Exceptions occurred execution controller processing. Debugging will likely be unreliable going forward. "
)
return True
@ -578,7 +584,7 @@ def parse(args: List[str], parser: argparse.ArgumentParser, unsupported: List[st
varsargs = vars ( args )
for unsup in unsupported :
if varsargs [ unsup . replace ( " - " , " _ " ) ] :
print ( message . error( f " Pwndbg does not support -- { unsup } yet " ) )
print_ error( f " Pwndbg does not support -- { unsup } yet " )
return None
return args
@ -662,15 +668,13 @@ def target_create(args: List[str], dbg: LLDB) -> None:
return
if dbg . debugger . GetNumTargets ( ) > 0 :
print (
message . error (
" Pwndbg does not support multiple targets. Please remove the current target with ' target delete ' and try again. "
)
print_error (
" Pwndbg does not support multiple targets. Please remove the current target with ' target delete ' and try again. "
)
return
if args . platform and args . platform not in { " qemu-user " } :
print ( message . error( " Pwndbg does currently support platforms: qemu-user " ) )
print_ error( " Pwndbg does currently support platforms: qemu-user " )
return
if args . arch :
@ -678,7 +682,7 @@ def target_create(args: List[str], dbg: LLDB) -> None:
triple = _get_target_triple ( dbg . debugger , args . filename )
if not triple :
print ( message . error( f " could not detect triple for ' { args . filename } ' " ) )
print_ error( f " could not detect triple for ' { args . filename } ' " )
return
if args . platform == " qemu-user " :
@ -698,7 +702,7 @@ def target_create(args: List[str], dbg: LLDB) -> None:
args . filename , triple , args . platform , True , error
)
if not error . success or not target . IsValid ( ) :
print ( message . error( f " could not create target for ' { args . filename } ' : { error . description } " ) )
print_ error( f " could not create target for ' { args . filename } ' : { error . description } " )
return
dbg . debugger . SetSelectedTarget ( target )
@ -754,11 +758,11 @@ def process_launch(driver: ProcessDriver, relay: EventRelay, args: List[str], db
targets = dbg . debugger . GetNumTargets ( )
assert targets < 2
if targets == 0 :
print ( message . error ( " error: no target, create one using the ' target create ' command " ) )
print_error ( " no target, create one using the ' target create ' command " )
return
if driver . has_process ( ) :
print ( message . error ( " error: a process is already being debugged " ) )
print_error ( " a process is already being debugged " )
return
target : lldb . SBTarget = dbg . debugger . GetTargetAtIndex ( 0 )
@ -779,7 +783,7 @@ def process_launch(driver: ProcessDriver, relay: EventRelay, args: List[str], db
)
if not result . success :
print ( message . error ( f " C ould not launch process: { result . description } " ) )
print_error ( f " c ould not launch process: { result . description } " )
return
# Continue execution if the user hasn't requested for a stop at the entry
@ -833,13 +837,13 @@ def _attach_with_info(
targets = dbg . debugger . GetNumTargets ( )
assert targets < 2
if targets == 0 :
print ( message . error ( " error: no target, create one using the ' target create ' command " ) )
print_error ( " no target, create one using the ' target create ' command " )
return
# TODO/FIXME: This should ask:
# 'There is a running process, detach from it and attach?: [Y/n]'
if driver . has_process ( ) :
print ( message . error ( " error: a process is already being debugged " ) )
print_error ( " a process is already being debugged " )
return
io_driver = get_io_driver ( )
@ -851,7 +855,7 @@ def _attach_with_info(
)
if not result . success :
print ( message . error ( f " C ould not attach to process: { result . description } " ) )
print_error ( f " c ould not attach to process: { result . description } " )
return
# Continue execution if the user has requested it.
@ -898,7 +902,7 @@ def attach(driver: ProcessDriver, relay: EventRelay, args: List[str], dbg: LLDB)
Note : for some reason , ` attach ` does not really take a regex for process name .
"""
if len ( args ) != 1 :
print ( message . error ( " E xpected 1 argument: <pid> or <name>" ) )
print_error ( " e xpected 1 argument: <pid> or <name>" )
return
arg = args [ 0 ]
@ -930,15 +934,13 @@ def process_connect(driver: ProcessDriver, relay: EventRelay, args: List[str], d
return
if " plugin " not in args or args . plugin != " gdb-remote " :
print (
message . error (
" Pwndbg only supports the gdb-remote plugin for ' process connect ' . Please specify it with the ' -p gdb-remote ' argument. "
)
print_error (
" Pwndbg only supports the gdb-remote plugin for ' process connect ' . Please specify it with the ' -p gdb-remote ' argument. "
)
return
if driver . has_connection ( ) :
print ( message . error ( " error: debugger is already connected " ) )
print_error ( " debugger is already connected " )
return
target = dbg . debugger . GetSelectedTarget ( )
@ -967,10 +969,8 @@ def process_connect(driver: ProcessDriver, relay: EventRelay, args: List[str], d
target = dbg . debugger . CreateTarget ( None , triple , None , True , error )
if not error . success or not target . IsValid ( ) :
print (
message . error (
f " error: could not automatically create target for ' process connect ' : { error . description } "
)
print_error (
f " could not automatically create target for ' process connect ' : { error . description } "
)
return
@ -984,7 +984,7 @@ def process_connect(driver: ProcessDriver, relay: EventRelay, args: List[str], d
error = driver . connect ( target , io_driver , args . remoteurl , " gdb-remote " )
if not error . success :
print ( message . error ( f " error: could not connect to remote process: { error . description } " ) )
print_error ( f " could not connect to remote process: { error . description } " )
if created_target :
# Delete the target we previously created.
assert dbg . debugger . DeleteTarget (
@ -1018,17 +1018,17 @@ def gdb_remote(driver: ProcessDriver, relay: EventRelay, args: List[str], dbg: L
url = parts [ 0 ]
port = parts [ 1 ]
else :
print ( message . error ( f " error: unknown URL format ' { args . remoteurl } ' " ) )
print_error ( f " unknown URL format ' { args . remoteurl } ' " )
return
try :
port = int ( port , 10 )
except ValueError :
print ( message . error ( f " error: could not interpret ' { port } ' as port number " ) )
print_error ( f " could not interpret ' { port } ' as port number " )
return
if url is None :
print ( message . warn( " hostname not given, using ' localhost ' " ) )
print_ warn( " hostname not given, using ' localhost ' " )
url = " localhost "
process_connect ( driver , relay , [ " -p " , " gdb-remote " , f " connect:// { url } : { port } " ] , dbg )
@ -1048,7 +1048,7 @@ def continue_process(driver: ProcessDriver, args: List[str], dbg: LLDB) -> None:
return
if not driver . has_process ( ) :
print ( message . error ( " error: no process " ) )
print_error ( " no process " )
return
driver . cont ( )