1# Unwinder commands. 2# Copyright 2015-2020 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 (validate_regexp(locus_regexp, "locus"), 53 validate_regexp(name_regexp, "unwinder")) 54 55 56class InfoUnwinder(gdb.Command): 57 """GDB command to list unwinders. 58 59Usage: info unwinder [LOCUS-REGEXP [NAME-REGEXP]] 60 61LOCUS-REGEXP is a regular expression matching the location of the 62unwinder. If it is omitted, all registered unwinders from all 63loci are listed. A locus can be 'global', 'progspace' to list 64the unwinders from the current progspace, or a regular expression 65matching filenames of objfiles. 66 67NAME-REGEXP is a regular expression to filter unwinder names. If 68this omitted for a specified locus, then all registered unwinders 69in the locus are listed.""" 70 71 def __init__(self): 72 super(InfoUnwinder, self).__init__("info unwinder", 73 gdb.COMMAND_STACK) 74 75 def list_unwinders(self, title, unwinders, name_re): 76 """Lists the unwinders whose name matches regexp. 77 78 Arguments: 79 title: The line to print before the list. 80 unwinders: The list of the unwinders. 81 name_re: unwinder name filter. 82 """ 83 if not unwinders: 84 return 85 print(title) 86 for unwinder in unwinders: 87 if name_re.match(unwinder.name): 88 print(" %s%s" % (unwinder.name, 89 "" if unwinder.enabled else " [disabled]")) 90 91 def invoke(self, arg, from_tty): 92 locus_re, name_re = parse_unwinder_command_args(arg) 93 if locus_re.match("global"): 94 self.list_unwinders("Global:", gdb.frame_unwinders, 95 name_re) 96 if locus_re.match("progspace"): 97 cp = gdb.current_progspace() 98 self.list_unwinders("Progspace %s:" % cp.filename, 99 cp.frame_unwinders, name_re) 100 for objfile in gdb.objfiles(): 101 if locus_re.match(objfile.filename): 102 self.list_unwinders("Objfile %s:" % objfile.filename, 103 objfile.frame_unwinders, name_re) 104 105 106def do_enable_unwinder1(unwinders, name_re, flag): 107 """Enable/disable unwinders whose names match given regex. 108 109 Arguments: 110 unwinders: The list of unwinders. 111 name_re: Unwinder name filter. 112 flag: Enable/disable. 113 114 Returns: 115 The number of unwinders affected. 116 """ 117 total = 0 118 for unwinder in unwinders: 119 if name_re.match(unwinder.name): 120 unwinder.enabled = flag 121 total += 1 122 return total 123 124 125def do_enable_unwinder(arg, flag): 126 """Enable/disable unwinder(s).""" 127 (locus_re, name_re) = parse_unwinder_command_args(arg) 128 total = 0 129 if locus_re.match("global"): 130 total += do_enable_unwinder1(gdb.frame_unwinders, name_re, flag) 131 if locus_re.match("progspace"): 132 total += do_enable_unwinder1(gdb.current_progspace().frame_unwinders, 133 name_re, flag) 134 for objfile in gdb.objfiles(): 135 if locus_re.match(objfile.filename): 136 total += do_enable_unwinder1(objfile.frame_unwinders, name_re, 137 flag) 138 if total > 0: 139 gdb.invalidate_cached_frames() 140 print("%d unwinder%s %s" % (total, "" if total == 1 else "s", 141 "enabled" if flag else "disabled")) 142 143 144class EnableUnwinder(gdb.Command): 145 """GDB command to enable unwinders. 146 147Usage: enable unwinder [LOCUS-REGEXP [NAME-REGEXP]] 148 149LOCUS-REGEXP is a regular expression specifying the unwinders to 150enable. It can 'global', 'progspace', or the name of an objfile 151within that progspace. 152 153NAME_REGEXP is a regular expression to filter unwinder names. If 154this omitted for a specified locus, then all registered unwinders 155in the locus are affected.""" 156 157 def __init__(self): 158 super(EnableUnwinder, self).__init__("enable unwinder", 159 gdb.COMMAND_STACK) 160 161 def invoke(self, arg, from_tty): 162 """GDB calls this to perform the command.""" 163 do_enable_unwinder(arg, True) 164 165 166class DisableUnwinder(gdb.Command): 167 """GDB command to disable the specified unwinder. 168 169Usage: disable unwinder [LOCUS-REGEXP [NAME-REGEXP]] 170 171LOCUS-REGEXP is a regular expression specifying the unwinders to 172disable. It can 'global', 'progspace', or the name of an objfile 173within that progspace. 174 175NAME_REGEXP is a regular expression to filter unwinder names. If 176this omitted for a specified locus, then all registered unwinders 177in the locus are affected.""" 178 179 def __init__(self): 180 super(DisableUnwinder, self).__init__("disable unwinder", 181 gdb.COMMAND_STACK) 182 183 def invoke(self, arg, from_tty): 184 """GDB calls this to perform the command.""" 185 do_enable_unwinder(arg, False) 186 187 188def register_unwinder_commands(): 189 """Installs the unwinder commands.""" 190 InfoUnwinder() 191 EnableUnwinder() 192 DisableUnwinder() 193 194 195register_unwinder_commands() 196