B-C
view release on metacpan or search on metacpan
.gdb/dashboard view on Meta::CPAN
python
# GDB dashboard - Modular visual interface for GDB in Python.
#
# https://github.com/cyrus-and/gdb-dashboard
import ast
import os
import subprocess
# Common attributes ------------------------------------------------------------
class R():
@staticmethod
def attributes():
return {
# miscellaneous
'ansi': {
'doc': 'Control the ANSI output of the dashboard.',
'default': True,
'type': bool
},
# prompt
'prompt': {
'doc': """Command prompt.
This value is parsed as a Python format string in which `{status}` is expanded
with the substitution of either `prompt_running` or `prompt_not_running`
attributes, according to the target program status. The resulting string must be
a valid GDB prompt, see the command `python print(gdb.prompt.prompt_help())`""",
'default': '{status}'
},
'prompt_running': {
'doc': """`{status}` when the target program is running.
See the `prompt` attribute. This value is parsed as a Python format string in
which `{pid}` is expanded with the process identifier of the target program.""",
'default': '\[\e[1;35m\]>>>\[\e[0m\]'
},
'prompt_not_running': {
'doc': '`{status}` when the target program is not running.',
'default': '\[\e[1;30m\]>>>\[\e[0m\]'
},
# divider
'divider_fill_char_primary': {
'doc': 'Filler around the label for primary dividers',
'default': 'â'
},
'divider_fill_char_secondary': {
'doc': 'Filler around the label for secondary dividers',
'default': 'â'
},
'divider_fill_style_primary': {
'doc': 'Style for `divider_fill_char_primary`',
'default': '36'
},
'divider_fill_style_secondary': {
'doc': 'Style for `divider_fill_char_secondary`',
'default': '1;30'
},
'divider_label_style_on_primary': {
'doc': 'Label style for non-empty primary dividers',
'default': '1;33'
},
'divider_label_style_on_secondary': {
'doc': 'Label style for non-empty secondary dividers',
'default': '0'
},
'divider_label_style_off_primary': {
'doc': 'Label style for empty primary dividers',
'default': '33'
},
'divider_label_style_off_secondary': {
'doc': 'Label style for empty secondary dividers',
'default': '1;30'
},
'divider_label_skip': {
'doc': 'Gap between the aligning border and the label.',
'default': 3,
'type': int,
'check': check_ge_zero
},
'divider_label_margin': {
'doc': 'Number of spaces around the label.',
'default': 1,
'type': int,
'check': check_ge_zero
},
'divider_label_align_right': {
'doc': 'Label alignment flag.',
'default': False,
'type': bool
},
# common styles
'style_selected_1': {
'default': '1;32'
},
'style_selected_2': {
'default': '32'
},
.gdb/dashboard view on Meta::CPAN
self.display()
def inferior_pid(self):
return gdb.selected_inferior().pid
def is_running(self):
return self.inferior_pid() != 0
def display(self):
Dashboard.update_term_width()
# fetch lines
lines = []
for module in self.modules:
if not module.enabled:
continue
module = module.instance
# active if more than zero lines
module_lines = module.lines()
lines.append(divider(module.label(), True, module_lines))
lines.extend(module_lines)
if len(lines) == 0:
lines.append(divider('Error', True))
if len(self.modules) == 0:
lines.append('No module loaded')
else:
lines.append('No module to display (see `help dashboard`)')
lines.append(divider(primary=True))
# print the dashboard
print('\n'.join(lines))
# Utility methods --------------------------------------------------------------
@staticmethod
def start():
# initialize the dashboard
Dashboard.update_term_width()
dashboard = Dashboard()
Dashboard.set_custom_prompt(dashboard)
# parse Python inits, load modules then parse GDB inits
Dashboard.parse_inits(True)
modules = Dashboard.get_modules()
dashboard.load_modules(modules)
Dashboard.parse_inits(False)
# GDB override
run('set pagination off')
run('alias -a db = dashboard')
@staticmethod
def update_term_width():
height, width = subprocess.check_output(['stty', 'size']).split()
Dashboard.term_width = int(width)
@staticmethod
def set_custom_prompt(dashboard):
def custom_prompt(_):
# render thread status indicator
if dashboard.is_running():
pid = dashboard.inferior_pid()
status = R.prompt_running.format(pid=pid)
else:
status = R.prompt_not_running
# build prompt
prompt = R.prompt.format(status=status)
prompt = gdb.prompt.substitute_prompt(prompt)
return prompt + ' ' # force trailing space
gdb.prompt_hook = custom_prompt
@staticmethod
def parse_inits(python):
for root, dirs, files in os.walk(os.path.expanduser('~/.gdbinit.d/')):
dirs.sort()
for init in sorted(files):
path = os.path.join(root, init)
_, ext = os.path.splitext(path)
# either load Python files or GDB
if python ^ (ext != '.py'):
gdb.execute('source ' + path)
@staticmethod
def get_modules():
# scan the scope for modules
modules = []
for name in globals():
obj = globals()[name]
try:
if issubclass(obj, Dashboard.Module):
modules.append(obj)
except TypeError:
continue
# sort modules alphabetically
modules.sort(key=lambda x: x.__name__)
return modules
@staticmethod
def create_command(name, invoke, doc, is_prefix, complete=None):
Class = type('', (gdb.Command,), {'invoke': invoke, '__doc__': doc})
Class(name, gdb.COMMAND_USER, complete or gdb.COMPLETE_NONE, is_prefix)
@staticmethod
def err(string):
print(ansi(string, R.style_error))
@staticmethod
def complete(word, candidates):
matching = []
for candidate in candidates:
if candidate.startswith(word):
matching.append(candidate)
return matching
@staticmethod
def parse_arg(arg):
# encode unicode GDB command arguments as utf8 in Python 2.7
if type(arg) is not str:
arg = arg.encode('utf8')
return arg
# Module descriptor ------------------------------------------------------------
class ModuleInfo:
( run in 0.897 second using v1.01-cache-2.11-cpan-364913b4093 )