From e5ed21bac4a51aec66e4250b3d88b32e1ab42aad Mon Sep 17 00:00:00 2001 From: cinnaboot Date: Sat, 24 Jan 2026 07:40:33 -0500 Subject: [PATCH] update .vimrc and gdbdashboard version --- .gdbinit | 201 ++++++++++++++++++++++++++++++++++++++----------------- .vimrc | 70 +++---------------- 2 files changed, 150 insertions(+), 121 deletions(-) diff --git a/.gdbinit b/.gdbinit index 0e5f8a5..31ab1fd 100644 --- a/.gdbinit +++ b/.gdbinit @@ -6,7 +6,7 @@ python # License ---------------------------------------------------------------------- -# Copyright (c) 2015-2021 Andrea Cardaci +# Copyright (c) 2015-2025 Andrea Cardaci # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -103,13 +103,13 @@ prompt, see the command `python print(gdb.prompt.prompt_help())`''', See the `prompt` attribute. This value is used as a Python format string where `{pid}` is expanded with the process identifier of the target program.''', - 'default': '\[\e[1;35m\]>>>\[\e[0m\]' + 'default': r'\[\e[1;35m\]>>>\[\e[0m\]' }, 'prompt_not_running': { 'doc': '''Define the value of `{status}` when the target program is running. See the `prompt` attribute. This value is used as a Python format string.''', - 'default': '\[\e[90m\]>>>\[\e[0m\]' + 'default': r'\[\e[90m\]>>>\[\e[0m\]' }, # divider 'omit_divider': { @@ -192,7 +192,7 @@ See the `prompt` attribute. This value is used as a Python format string.''', class Beautifier(): def __init__(self, hint, tab_size=4): - self.tab_spaces = ' ' * tab_size + self.tab_spaces = ' ' * tab_size if tab_size else None self.active = False if not R.ansi or not R.syntax_highlighting: return @@ -218,8 +218,9 @@ class Beautifier(): pass def process(self, source): - # convert tabs anyway - source = source.replace('\t', self.tab_spaces) + # convert tabs if requested + if self.tab_spaces: + source = source.replace('\t', self.tab_spaces) if self.active: import pygments source = pygments.highlight(source, self.lexer, self.formatter) @@ -326,6 +327,7 @@ def format_value(value, compact=None): def fetch_breakpoints(watchpoints=False, pending=False): # fetch breakpoints addresses parsed_breakpoints = dict() + catch_what_regex = re.compile(r'([^,]+".*")?[^,]*') for line in run('info breakpoints').split('\n'): # just keep numbered lines if not line or not line[0].isdigit(): @@ -341,7 +343,11 @@ def fetch_breakpoints(watchpoints=False, pending=False): address = None if is_multiple or is_pending else int(fields[4], 16) is_enabled = fields[3] == 'y' address_info = address, is_enabled - parsed_breakpoints[number] = [address_info], is_pending + parsed_breakpoints[number] = [address_info], is_pending, '' + elif len(fields) >= 5 and fields[1] == 'catchpoint': + # only take before comma, but ignore commas in quotes + what = catch_what_regex.search(' '.join(fields[4:])).group(0).strip() + parsed_breakpoints[number] = [], False, what elif len(fields) >= 3 and number in parsed_breakpoints: # add this address to the list of multiple locations address = int(fields[2], 16) @@ -350,7 +356,7 @@ def fetch_breakpoints(watchpoints=False, pending=False): parsed_breakpoints[number][0].append(address_info) else: # watchpoints - parsed_breakpoints[number] = [], False + parsed_breakpoints[number] = [], False, '' except ValueError: pass # fetch breakpoints from the API and complement with address and source @@ -361,7 +367,7 @@ def fetch_breakpoints(watchpoints=False, pending=False): # skip internal breakpoints if gdb_breakpoint.number < 0: continue - addresses, is_pending = parsed_breakpoints[gdb_breakpoint.number] + addresses, is_pending, what = parsed_breakpoints[gdb_breakpoint.number] is_pending = getattr(gdb_breakpoint, 'pending', is_pending) if not pending and is_pending: continue @@ -378,6 +384,7 @@ def fetch_breakpoints(watchpoints=False, pending=False): breakpoint['temporary'] = gdb_breakpoint.temporary breakpoint['hit_count'] = gdb_breakpoint.hit_count breakpoint['pending'] = is_pending + breakpoint['what'] = what # add addresses and source information breakpoint['addresses'] = [] for address, is_enabled in addresses: @@ -574,6 +581,8 @@ class Dashboard(gdb.Command): @staticmethod def start(): + # save the instance for customization convenience + global dashboard # initialize the dashboard dashboard = Dashboard() Dashboard.set_custom_prompt(dashboard) @@ -603,11 +612,13 @@ class Dashboard(gdb.Command): else: import termios import fcntl - # first 2 shorts (4 byte) of struct winsize - raw = fcntl.ioctl(fd, termios.TIOCGWINSZ, ' ' * 4) - height, width = struct.unpack('hh', raw) + # first 2 shorts of struct winsize + winsize_format = 'hhhh' + buffer = b'\x00' * struct.calcsize(winsize_format) + buffer = fcntl.ioctl(fd, termios.TIOCGWINSZ, buffer) + height, width, _, _ = struct.unpack(winsize_format, buffer) return int(width), int(height) - except (ImportError, OSError): + except (ImportError, OSError, SystemError): # this happens when no curses library is found on windows or when # the terminal is not properly configured return 80, 24 # hardcoded fallback value @@ -641,7 +652,8 @@ class Dashboard(gdb.Command): # process all the init files in order for root, dirs, files in itertools.chain.from_iterable(inits_dirs): dirs.sort() - for init in sorted(files): + # skipping dotfiles + for init in sorted(file for file in files if not file.startswith('.')): path = os.path.join(root, init) _, ext = os.path.splitext(path) # either load Python files or GDB @@ -665,8 +677,19 @@ class Dashboard(gdb.Command): @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) + if callable(complete): + Class = type('', (gdb.Command,), { + '__doc__': doc, + 'invoke': invoke, + 'complete': complete + }) + Class(name, gdb.COMMAND_USER, prefix=is_prefix) + else: + Class = type('', (gdb.Command,), { + '__doc__': doc, + 'invoke': invoke + }) + Class(name, gdb.COMMAND_USER, complete or gdb.COMPLETE_NONE, is_prefix) @staticmethod def err(string): @@ -688,7 +711,7 @@ class Dashboard(gdb.Command): # ANSI: move the cursor to top-left corner and clear the screen # (optionally also clear the scrollback buffer if supported by the # terminal) - return '\x1b[H\x1b[J' + '\x1b[3J' if R.discard_scrollback else '' + return '\x1b[H\x1b[2J' + ('\x1b[3J' if R.discard_scrollback else '') @staticmethod def setup_terminal(): @@ -1157,7 +1180,10 @@ class Source(Dashboard.Module): self.offset = 0 def label(self): - return 'Source' + label = 'Source' + if self.show_path and self.file_name: + label += ': {}'.format(self.file_name) + return label def lines(self, term_width, term_height, style_changed): # skip if the current thread is not stopped @@ -1167,6 +1193,7 @@ class Source(Dashboard.Module): sal = gdb.selected_frame().find_sal() current_line = sal.line if current_line == 0: + self.file_name = None return [] # try to lookup the source file candidates = [ @@ -1283,6 +1310,12 @@ A value of 0 uses the whole height.''', 'type': int, 'check': check_gt_zero }, + 'path': { + 'doc': 'Path visibility flag in the module label.', + 'default': False, + 'name': 'show_path', + 'type': bool + }, 'highlight-line': { 'doc': 'Decide whether the whole current line should be highlighted.', 'default': False, @@ -1322,7 +1355,7 @@ The instructions constituting the current statement are marked, if available.''' flavor = gdb.parameter('disassembly-flavor') except: flavor = 'att' # not always defined (see #36) - highlighter = Beautifier(flavor) + highlighter = Beautifier(flavor, tab_size=None) # fetch the assembly code line_info = None frame = gdb.selected_frame() # PC is here @@ -1628,46 +1661,53 @@ Optionally list the frame arguments and locals too.''' # skip if the current thread is not stopped if not gdb.selected_thread().is_stopped(): return [] - # find the selected frame (i.e., the first to display) - selected_index = 0 + # find the selected frame level (XXX Frame.level() is a recent addition) + start_level = 0 frame = gdb.newest_frame() while frame: if frame == gdb.selected_frame(): break frame = frame.older() - selected_index += 1 - # format up to "limit" frames - frames = [] - number = selected_index + start_level += 1 + # gather the frames more = False - while frame: - # the first is the selected one - selected = (len(frames) == 0) - # fetch frame info - style = R.style_selected_1 if selected else R.style_selected_2 - frame_id = ansi(str(number), style) - info = Stack.get_pc_line(frame, style) - frame_lines = [] - frame_lines.append('[{}] {}'.format(frame_id, info)) - # add frame arguments and locals - variables = Variables.format_frame( - frame, self.show_arguments, self.show_locals, self.compact, self.align, self.sort) - frame_lines.extend(variables) - # add frame - frames.append(frame_lines) - # next - frame = frame.older() - number += 1 - # check finished according to the limit - if self.limit and len(frames) == self.limit: - # more frames to show but limited - if frame: - more = True + frames = [gdb.selected_frame()] + going_down = True + while True: + # stack frames limit reached + if len(frames) == self.limit: + more = True break + # zigzag the frames starting from the selected one + if going_down: + frame = frames[-1].older() + if frame: + frames.append(frame) + else: + frame = frames[0].newer() + if frame: + frames.insert(0, frame) + start_level -= 1 + else: + break + else: + frame = frames[0].newer() + if frame: + frames.insert(0, frame) + start_level -= 1 + else: + frame = frames[-1].older() + if frame: + frames.append(frame) + else: + break + # switch direction + going_down = not going_down # format the output lines = [] - for frame_lines in frames: - lines.extend(frame_lines) + for number, frame in enumerate(frames, start=start_level): + selected = frame == gdb.selected_frame() + lines.extend(self.get_frame_lines(number, frame, selected)) # add the placeholder if more: lines.append('[{}]'.format(ansi('+', R.style_selected_2))) @@ -1710,6 +1750,19 @@ Optionally list the frame arguments and locals too.''' } } + def get_frame_lines(self, number, frame, selected=False): + # fetch frame info + style = R.style_selected_1 if selected else R.style_selected_2 + frame_id = ansi(str(number), style) + info = Stack.get_pc_line(frame, style) + frame_lines = [] + frame_lines.append('[{}] {}'.format(frame_id, info)) + # add frame arguments and locals + variables = Variables.format_frame( + frame, self.show_arguments, self.show_locals, self.compact, self.align, self.sort) + frame_lines.extend(variables) + return frame_lines + @staticmethod def format_line(prefix, line): prefix = ansi(prefix, R.style_low) @@ -1966,6 +2019,10 @@ class Registers(Dashboard.Module): changed = self.table and (self.table.get(name, '') != string_value) self.table[name] = string_value registers.append((name, string_value, changed)) + # handle the empty register list + if not registers: + msg = 'No registers to show (check the "dashboard registers -style list" attribute)' + return [ansi(msg, R.style_error)] # compute lengths considering an extra space between and around the # entries (hence the +2 and term_width - 1) max_name = max(len(name) for name, _, _ in registers) @@ -2017,7 +2074,8 @@ class Registers(Dashboard.Module): 'list': { 'doc': '''String of space-separated register names to display. -The empty list (default) causes to show all the available registers.''', +The empty list (default) causes to show all the available registers. For +architectures different from x86 setting this attribute might be mandatory.''', 'default': '', 'name': 'register_list', } @@ -2043,7 +2101,7 @@ The empty list (default) causes to show all the available registers.''', if len(fields) != 7: continue name, _, _, _, _, _, groups = fields - if not re.match('\w', name): + if not re.match(r'\w', name): continue for group in groups.split(','): if group in (match_groups or ('general',)): @@ -2118,7 +2176,7 @@ class Expressions(Dashboard.Module): '''Watch user expressions.''' def __init__(self): - self.table = set() + self.table = [] def label(self): return 'Expressions' @@ -2129,9 +2187,9 @@ class Expressions(Dashboard.Module): if self.align: label_width = max(len(expression) for expression in self.table) if self.table else 0 default_radix = Expressions.get_default_radix() - for expression in self.table: + for number, expression in enumerate(self.table, start=1): label = expression - match = re.match('^/(\d+) +(.+)$', expression) + match = re.match(r'^/(\d+) +(.+)$', expression) try: if match: radix, expression = match.groups() @@ -2142,9 +2200,10 @@ class Expressions(Dashboard.Module): finally: if match: run('set output-radix {}'.format(default_radix)) + number = ansi(str(number), R.style_selected_2) label = ansi(expression, R.style_high) + ' ' * (label_width - len(expression)) equal = ansi('=', R.style_low) - out.append('{} {} {}'.format(label, equal, value)) + out.append('[{}] {} {} {}'.format(number, label, equal, value)) return out def commands(self): @@ -2156,8 +2215,7 @@ class Expressions(Dashboard.Module): }, 'unwatch': { 'action': self.unwatch, - 'doc': 'Stop watching an expression.', - 'complete': gdb.COMPLETE_EXPRESSION + 'doc': 'Stop watching an expression by index.' }, 'clear': { 'action': self.clear, @@ -2176,15 +2234,22 @@ class Expressions(Dashboard.Module): def watch(self, arg): if arg: - self.table.add(arg) + if arg not in self.table: + self.table.append(arg) + else: + raise Exception('Expression already watched') else: raise Exception('Specify an expression') def unwatch(self, arg): if arg: try: - self.table.remove(arg) + number = int(arg) - 1 except: + number = -1 + if 0 <= number < len(self.table): + self.table.pop(number) + else: raise Exception('Expression not watched') else: raise Exception('Specify an expression') @@ -2199,9 +2264,12 @@ class Expressions(Dashboard.Module): except RuntimeError: # XXX this is a fix for GDB <8.1.x see #161 message = run('show output-radix') - match = re.match('^Default output radix for printing of values is (\d+)\.$', message) + match = re.match(r'^Default output radix for printing of values is (\d+)\.$', message) return match.groups()[0] if match else 10 # fallback +# XXX workaround to support BP_BREAKPOINT in older GDB versions +setattr(gdb, 'BP_CATCHPOINT', getattr(gdb, 'BP_CATCHPOINT', 26)) + class Breakpoints(Dashboard.Module): '''Display the breakpoints list.''' @@ -2210,7 +2278,8 @@ class Breakpoints(Dashboard.Module): gdb.BP_WATCHPOINT: 'watch', gdb.BP_HARDWARE_WATCHPOINT: 'write watch', gdb.BP_READ_WATCHPOINT: 'read watch', - gdb.BP_ACCESS_WATCHPOINT: 'access watch' + gdb.BP_ACCESS_WATCHPOINT: 'access watch', + gdb.BP_CATCHPOINT: 'catch' } def label(self): @@ -2260,6 +2329,9 @@ class Breakpoints(Dashboard.Module): # format user location location = breakpoint['location'] line += ' for {}'.format(ansi(location, style)) + elif breakpoint['type'] == gdb.BP_CATCHPOINT: + what = breakpoint['what'] + line += ' {}'.format(ansi(what, style)) else: # format user expression expression = breakpoint['expression'] @@ -2304,6 +2376,11 @@ set python print-stack full python Dashboard.start() +# Fixes ------------------------------------------------------------------------ + +# workaround for the GDB readline issue, see #325 +python import sys; sys.modules['readline'] = None + # File variables --------------------------------------------------------------- # vim: filetype=python diff --git a/.vimrc b/.vimrc index f20cddc..c2f0ed9 100644 --- a/.vimrc +++ b/.vimrc @@ -13,18 +13,17 @@ call vundle#begin() Plugin 'VundleVim/Vundle.vim' Plugin 'christoomey/vim-tmux-navigator' Plugin 'https://github.com/skywind3000/asyncrun.vim.git' -Plugin 'tikhomirov/vim-glsl' -Plugin 'octol/vim-cpp-enhanced-highlight' -Plugin 'godlygeek/tabular' " required for vim-markdown -Plugin 'plasticboy/vim-markdown' -Plugin 'https://github.com/StanAngeloff/php.vim.git' -Plugin 'https://github.com/pangloss/vim-javascript.git' Plugin 'jlanzarotta/bufexplorer' Plugin 'vim-airline/vim-airline' Plugin 'vim-airline/vim-airline-themes' -Plugin 'https://github.com/HiPhish/jinja.vim' Plugin 'https://github.com/ajmwagar/vim-deus' Plugin 'https://github.com/tpope/vim-obsession' +"Plugin 'https://github.com/HiPhish/jinja.vim' +"Plugin 'octol/vim-cpp-enhanced-highlight' +"Plugin 'https://github.com/StanAngeloff/php.vim.git' +"Plugin 'https://github.com/pangloss/vim-javascript.git' +"Plugin 'tikhomirov/vim-glsl' +Plugin 'https://github.com/sheerun/vim-polyglot' " All of your Plugins must be added before the following line call vundle#end() " required @@ -64,7 +63,7 @@ set undolevels=1000 set undoreload=10000 " folding -set foldmethod=syntax +set foldmethod=indent set foldnestmax=1 set foldlevelstart=20 set foldcolumn=0 @@ -185,8 +184,10 @@ augroup vimrc " save folds/cursor positions of buffers " FIXME: uncommenting these is now deleting buffers when switching as of " 2021-11-16 - autocmd BufWinLeave *.* mkview - autocmd BufWinEnter *.* silent loadview + if !&diff + autocmd BufWinLeave *.* mkview + autocmd BufWinEnter *.* silent loadview + endif " glsl filetype plugin autocmd! BufNewFile,BufRead *.vs,*.fs set ft=glsl @@ -232,52 +233,3 @@ if &term =~ '^screen' && exists('$TMUX') execute "set =\e[24;*~" endif - -" Testing airline/asyncrun colors ------------------ - -" " Define new accents -" function! AirlineThemePatch(palette) -" " [ guifg, guibg, ctermfg, ctermbg, opts ]. -" See help attr-list for valid values for the opt value. -" " http://vim.wikia.com/wiki/Xterm256_color_names_for_console_Vim -" let a:palette.accents.running = [ '', '', '', '', '' ] -" let a:palette.accents.success = [ '#00ff00', '' , 'green', '', '' ] -" let a:palette.accents.failure = [ '#ff0000', '' , 'red', '', '' ] -" endfunction -" let g:airline_theme_patch_func = 'AirlineThemePatch' -" -" -" " Change color of the relevant section according to g:asyncrun_status, a global variable exposed by AsyncRun -" " 'running': default, 'success': green, 'failure': red -" let g:async_status_old = '' -" function! Get_asyncrun_running() -" -" let async_status = g:asyncrun_status -" if async_status != g:async_status_old -" -" if async_status == 'running' -" call airline#parts#define_accent('asyncrun_status', 'running') -" elseif async_status == 'success' -" call airline#parts#define_accent('asyncrun_status', 'success') -" elseif async_status == 'failure' -" call airline#parts#define_accent('asyncrun_status', 'failure') -" endif -" -" let g:airline_section_x = airline#section#create(['asyncrun_status']) -" "AirlineRefresh -" let g:async_status_old = async_status -" -" endif -" -" return async_status -" -" endfunction -" -" call airline#parts#define_function('asyncrun_status', 'Get_asyncrun_running') -" let g:airline_section_x = airline#section#create(['asyncrun_status']) - -"let g:asyncrun_status = '' -"let g:airline_section_error = airline#section#create_right(['%{g:asyncrun_status}']) - -"------------------------------------- -