1# Unwinder commands. 2# Copyright 2015-2023 Free Software Foundation, Inc. 3 4# This program is free software; you can redistribute it and/or modify 5# it under the terms of the GNU General Public License as published by 6# the Free Software Foundation; either version 3 of the License, or 7# (at your option) any later version. 8# 9# This program is distributed in the hope that it will be useful, 10# but WITHOUT ANY WARRANTY; without even the implied warranty of 11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12# GNU General Public License for more details. 13# 14# You should have received a copy of the GNU General Public License 15# along with this program. If not, see <http://www.gnu.org/licenses/>. 16 17import gdb 18import re 19 20 21def validate_regexp(exp, idstring): 22 try: 23 return re.compile(exp) 24 except SyntaxError: 25 raise SyntaxError("Invalid %s regexp: %s." % (idstring, exp)) 26 27 28def parse_unwinder_command_args(arg): 29 """Internal utility to parse unwinder command argv. 30 31 Arguments: 32 arg: The arguments to the command. The format is: 33 [locus-regexp [name-regexp]] 34 35 Returns: 36 A 2-tuple of compiled regular expressions. 37 38 Raises: 39 SyntaxError: an error processing ARG 40 """ 41 42 argv = gdb.string_to_argv(arg) 43 argc = len(argv) 44 if argc > 2: 45 raise SyntaxError("Too many arguments.") 46 locus_regexp = "" 47 name_regexp = "" 48 if argc >= 1: 49 locus_regexp = argv[0] 50 if argc >= 2: 51 name_regexp = argv[1] 52 return ( 53 validate_regexp(locus_regexp, "locus"), 54 validate_regexp(name_regexp, "unwinder"), 55 ) 56 57 58class InfoUnwinder(gdb.Command): 59 """GDB command to list unwinders. 60 61 Usage: info unwinder [LOCUS-REGEXP [NAME-REGEXP]] 62 63 LOCUS-REGEXP is a regular expression matching the location of the 64 unwinder. If it is omitted, all registered unwinders from all 65 loci are listed. A locus can be 'global', 'progspace' to list 66 the unwinders from the current progspace, or a regular expression 67 matching filenames of objfiles. 68 69 NAME-REGEXP is a regular expression to filter unwinder names. If 70 this omitted for a specified locus, then all registered unwinders 71 in the locus are listed.""" 72 73 def __init__(self): 74 super(InfoUnwinder, self).__init__("info unwinder", gdb.COMMAND_STACK) 75 76 def list_unwinders(self, title, unwinders, name_re): 77 """Lists the unwinders whose name matches regexp. 78 79 Arguments: 80 title: The line to print before the list. 81 unwinders: The list of the unwinders. 82 name_re: unwinder name filter. 83 """ 84 if not unwinders: 85 return 86 print(title) 87 for unwinder in unwinders: 88 if name_re.match(unwinder.name): 89 print( 90 " %s%s" 91 % (unwinder.name, "" if unwinder.enabled else " [disabled]") 92 ) 93 94 def invoke(self, arg, from_tty): 95 locus_re, name_re = parse_unwinder_command_args(arg) 96 if locus_re.match("global"): 97 self.list_unwinders("Global:", gdb.frame_unwinders, name_re) 98 if locus_re.match("progspace"): 99 cp = gdb.current_progspace() 100 self.list_unwinders( 101 "Progspace %s:" % cp.filename, cp.frame_unwinders, name_re 102 ) 103 for objfile in gdb.objfiles(): 104 if locus_re.match(objfile.filename): 105 self.list_unwinders( 106 "Objfile %s:" % objfile.filename, objfile.frame_unwinders, name_re 107 ) 108 109 110def do_enable_unwinder1(unwinders, name_re, flag): 111 """Enable/disable unwinders whose names match given regex. 112 113 Arguments: 114 unwinders: The list of unwinders. 115 name_re: Unwinder name filter. 116 flag: Enable/disable. 117 118 Returns: 119 The number of unwinders affected. 120 """ 121 total = 0 122 for unwinder in unwinders: 123 if name_re.match(unwinder.name): 124 unwinder.enabled = flag 125 total += 1 126 return total 127 128 129def do_enable_unwinder(arg, flag): 130 """Enable/disable unwinder(s).""" 131 (locus_re, name_re) = parse_unwinder_command_args(arg) 132 total = 0 133 if locus_re.match("global"): 134 total += do_enable_unwinder1(gdb.frame_unwinders, name_re, flag) 135 if locus_re.match("progspace"): 136 total += do_enable_unwinder1( 137 gdb.current_progspace().frame_unwinders, name_re, flag 138 ) 139 for objfile in gdb.objfiles(): 140 if locus_re.match(objfile.filename): 141 total += do_enable_unwinder1(objfile.frame_unwinders, name_re, flag) 142 if total > 0: 143 gdb.invalidate_cached_frames() 144 print( 145 "%d unwinder%s %s" 146 % (total, "" if total == 1 else "s", "enabled" if flag else "disabled") 147 ) 148 149 150class EnableUnwinder(gdb.Command): 151 """GDB command to enable unwinders. 152 153 Usage: enable unwinder [LOCUS-REGEXP [NAME-REGEXP]] 154 155 LOCUS-REGEXP is a regular expression specifying the unwinders to 156 enable. It can 'global', 'progspace', or the name of an objfile 157 within that progspace. 158 159 NAME_REGEXP is a regular expression to filter unwinder names. If 160 this omitted for a specified locus, then all registered unwinders 161 in the locus are affected.""" 162 163 def __init__(self): 164 super(EnableUnwinder, self).__init__("enable unwinder", gdb.COMMAND_STACK) 165 166 def invoke(self, arg, from_tty): 167 """GDB calls this to perform the command.""" 168 do_enable_unwinder(arg, True) 169 170 171class DisableUnwinder(gdb.Command): 172 """GDB command to disable the specified unwinder. 173 174 Usage: disable unwinder [LOCUS-REGEXP [NAME-REGEXP]] 175 176 LOCUS-REGEXP is a regular expression specifying the unwinders to 177 disable. It can 'global', 'progspace', or the name of an objfile 178 within that progspace. 179 180 NAME_REGEXP is a regular expression to filter unwinder names. If 181 this omitted for a specified locus, then all registered unwinders 182 in the locus are affected.""" 183 184 def __init__(self): 185 super(DisableUnwinder, self).__init__("disable unwinder", gdb.COMMAND_STACK) 186 187 def invoke(self, arg, from_tty): 188 """GDB calls this to perform the command.""" 189 do_enable_unwinder(arg, False) 190 191 192def register_unwinder_commands(): 193 """Installs the unwinder commands.""" 194 InfoUnwinder() 195 EnableUnwinder() 196 DisableUnwinder() 197 198 199register_unwinder_commands() 200