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