@ -8,7 +8,7 @@ is advised to configure the 'gcc-config-path' config parameter to your own cross
gnu gcc compiled toolchain for your target architecture .
gnu gcc compiled toolchain for your target architecture .
You are advised to configure the ' cymbol-editor ' config parameter to the path of your
You are advised to configure the ' cymbol-editor ' config parameter to the path of your
favorite text editor . Otherwise cymbol ex a pnds $ EDITOR and $ VISUAL environment variables
favorite text editor . Otherwise cymbol ex pa nds $ EDITOR and $ VISUAL environment variables
to find the path to the default text editor .
to find the path to the default text editor .
"""
"""
@ -126,10 +126,10 @@ def generate_debug_symbols(
return pwndbg_debug_symbols_output_file
return pwndbg_debug_symbols_output_file
def add_custom_structure ( custom_structure_name : str ) - > None :
def add_custom_structure ( custom_structure_name : str , force = False ) :
pwndbg_custom_structure_path = os . path . join ( pwndbg_cachedir , custom_structure_name ) + " .c "
pwndbg_custom_structure_path = os . path . join ( pwndbg_cachedir , custom_structure_name ) + " .c "
if os . path . exists ( pwndbg_custom_structure_path ) :
if os . path . exists ( pwndbg_custom_structure_path ) and not force :
option = input (
option = input (
message . notice (
message . notice (
" A custom structure was found with the given name, would you like to overwrite it? [y/n] "
" A custom structure was found with the given name, would you like to overwrite it? [y/n] "
@ -154,8 +154,9 @@ def add_custom_structure(custom_structure_name: str) -> None:
load_custom_structure . __wrapped__ ( custom_structure_name , pwndbg_custom_structure_path )
load_custom_structure . __wrapped__ ( custom_structure_name , pwndbg_custom_structure_path )
def add_structure_from_header ( header_file : str , custom_structure_name : str = None ) - > None :
def add_structure_from_header (
# Properly handle the provided or default name for the custom structure
header_file : str , custom_structure_name : str = None , force : bool = False
) - > None :
custom_structure_name = (
custom_structure_name = (
custom_structure_name . strip ( )
custom_structure_name . strip ( )
if custom_structure_name
if custom_structure_name
@ -169,11 +170,21 @@ def add_structure_from_header(header_file: str, custom_structure_name: str = Non
pwndbg_custom_structure_path = os . path . join ( pwndbg_cachedir , custom_structure_name ) + " .c "
pwndbg_custom_structure_path = os . path . join ( pwndbg_cachedir , custom_structure_name ) + " .c "
if os . path . exists ( pwndbg_custom_structure_path ) :
if os . path . exists ( pwndbg_custom_structure_path ) :
option = input (
if not force :
message . notice ( f " Structure ' { custom_structure_name } ' already exists. Overwrite? [y/n] " )
option = input (
)
message . notice (
if option != " y " :
f " Structure ' { custom_structure_name } ' already exists. Overwrite? [y/n] "
return
)
)
if option . lower ( ) != " y " :
print ( message . notice ( " Aborted by user. " ) )
return
else :
print (
message . warn (
f " Overwriting existing structure ' { custom_structure_name } ' due to --force flag. "
)
)
try :
try :
with open ( header_file , " r " ) as src , open ( pwndbg_custom_structure_path , " w " ) as f :
with open ( header_file , " r " ) as src , open ( pwndbg_custom_structure_path , " w " ) as f :
@ -186,7 +197,6 @@ def add_structure_from_header(header_file: str, custom_structure_name: str = Non
print ( message . error ( f " Failed to process header file: { e } " ) )
print ( message . error ( f " Failed to process header file: { e } " ) )
return
return
# Avoid checking for file existance. Call the decorator wrapper directly.
load_custom_structure . __wrapped__ ( custom_structure_name , pwndbg_custom_structure_path )
load_custom_structure . __wrapped__ ( custom_structure_name , pwndbg_custom_structure_path )
@ -251,84 +261,86 @@ def show_custom_structure(custom_structure_name: str, custom_structure_path: str
parser = argparse . ArgumentParser (
parser = argparse . ArgumentParser (
description = " Add, show, load, edit, or delete custom structures in plain C. "
description = " Manage custom C structures in pwndbg. Supports project-specific auto-loading from .gdbinit. "
)
parser . add_argument (
" -a " ,
" --add " ,
metavar = " name " ,
help = " Add a new custom structure " ,
default = None ,
type = str ,
)
parser . add_argument (
" -f " ,
" --file " ,
metavar = " filepath " ,
help = " Add a new custom structure from header file " ,
default = None ,
type = str ,
)
parser . add_argument (
" -r " ,
" --remove " ,
metavar = " name " ,
help = " Remove an existing custom structure " ,
default = None ,
type = str ,
)
)
parser . add_argument (
" -e " ,
subparsers = parser . add_subparsers ( dest = " subcommand " , help = " Available subcommands " )
" --edit " ,
metavar = " name " ,
add_parser = subparsers . add_parser ( " add " , help = " Add a custom structure " )
help = " Edit an existing custom structure " ,
add_parser . add_argument ( " name " , help = " Name of custom structure " )
default = None ,
add_parser . add_argument (
type = str ,
" --force " , action = " store_true " , help = " Overwrite if structure already exists "
)
parser . add_argument (
" -l " ,
" --load " ,
metavar = " name " ,
help = " Load an existing custom structure " ,
default = None ,
type = str ,
)
parser . add_argument (
" -s " ,
" --show " ,
metavar = " name " ,
help = " Show the source code of an existing custom structure " ,
default = None ,
type = str ,
)
parser . add_argument (
" --show-all " ,
help = " Show names of all available custom structures " ,
action = " store_true " ,
)
)
remove_parser = subparsers . add_parser ( " remove " , help = " Remove a custom structure " )
remove_parser . add_argument ( " name " , help = " Name of custom structure " )
edit_parser = subparsers . add_parser ( " edit " , help = " Edit a custom structure " )
edit_parser . add_argument ( " name " , help = " Name of custom structure " )
load_parser = subparsers . add_parser ( " load " , help = " Load a custom structure " )
load_parser . add_argument ( " name " , help = " Name of custom structure " )
show_parser = subparsers . add_parser ( " show " , help = " Show a custom structure " )
show_parser . add_argument ( " name " , help = " Name of custom structure " )
file_parser = subparsers . add_parser ( " file " , help = " Add a structure from a header file " )
file_parser . add_argument ( " path " , help = " Path to header file " )
file_parser . add_argument ( " --name " , help = " Optional structure name " )
file_parser . add_argument ( " --force " , action = " store_true " , help = " Overwrite if exists " )
show_all_parser = subparsers . add_parser ( " show-all " , help = " Show all stored structure " )
@pwndbg.commands.Command (
parser ,
category = CommandCategory . MISC ,
notes = """
@pwndbg.commands.Command ( parser , category = CommandCategory . MISC )
The ` cymbol ` command loads custom C structs and symbols into the debugger using GCC under the hood .
Usage Example :
` cymbol file - - force . / structs . h `
- - force :
Use this flag to force symbol reloading , even if symbols with the same name already exist .
Warning :
If a loaded structure defines a symbol that already exists , the debugger may prefer the original
symbol or behave unexpectedly . It ’ s recommended to use unique struct names to avoid
symbol conflicts .
Tip :
You can add this command to your ` . gdbinit ` file for automatic loading :
` cymbol file - - force . / path / to / structs . h `
""" ,
)
def cymbol (
def cymbol (
add : str , file : str , remove : str , edit : str , load : str , show : str , show_all : bool
subcommand : str = None ,
) - > None :
name : str = None ,
if add :
path : str = None ,
add_custom_structure ( add )
force = False ,
elif file :
) :
add_structure_from_header ( file )
match subcommand :
elif remove :
case " add " :
remove_custom_structure ( remove )
add_custom_structure ( name , force = force )
elif edit :
case " remove " :
edit_custom_structure ( edit )
remove_custom_structure ( name )
elif load :
case " edit " :
load_custom_structure ( load )
edit_custom_structure ( name )
elif show :
case " load " :
show_custom_structure ( show )
load_custom_structure ( name )
elif show_all :
case " file " :
print ( message . notice ( " Available custom structure names: \n " ) )
add_structure_from_header ( path , name , force = force )
for file in os . listdir ( pwndbg_cachedir ) :
case " show " :
if file . endswith ( " .c " ) :
show_custom_structure ( name )
name = os . path . splitext ( file ) [ 0 ]
case " show-all " :
print ( f " - { name } " )
print ( message . notice ( " Available custom structure names: \n " ) )
else :
for file in os . listdir ( pwndbg_cachedir ) :
parser . print_help ( )
if file . endswith ( " .c " ) :
name = os . path . splitext ( file ) [ 0 ]
print ( f " - { name } " )
case _ :
parser . print_help ( )