1 # Unwinder commands. 2 # Copyright 2015-2016 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 17 import gdb 18 import re 19 20 21 def 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 28 def 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 56 class 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 107 def 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 126 def 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 print("%d unwinder%s %s" % (total, "" if total == 1 else "s", 140 "enabled" if flag else "disabled")) 141 142 143 class EnableUnwinder(gdb.Command): 144 """GDB command to enable unwinders. 145 146 Usage: enable unwinder [locus-regexp [name-regexp]] 147 148 LOCUS-REGEXP is a regular expression specifying the unwinders to 149 enable. It can 'global', 'progspace', or the name of an objfile 150 within that progspace. 151 152 NAME_REGEXP is a regular expression to filter unwinder names. If 153 this omitted for a specified locus, then all registered unwinders 154 in the locus are affected. 155 156 """ 157 158 def __init__(self): 159 super(EnableUnwinder, self).__init__("enable unwinder", 160 gdb.COMMAND_STACK) 161 162 def invoke(self, arg, from_tty): 163 """GDB calls this to perform the command.""" 164 do_enable_unwinder(arg, True) 165 166 167 class DisableUnwinder(gdb.Command): 168 """GDB command to disable the specified unwinder. 169 170 Usage: disable unwinder [locus-regexp [name-regexp]] 171 172 LOCUS-REGEXP is a regular expression specifying the unwinders to 173 disable. It can 'global', 'progspace', or the name of an objfile 174 within that progspace. 175 176 NAME_REGEXP is a regular expression to filter unwinder names. If 177 this omitted for a specified locus, then all registered unwinders 178 in the locus are affected. 179 180 """ 181 182 def __init__(self): 183 super(DisableUnwinder, self).__init__("disable unwinder", 184 gdb.COMMAND_STACK) 185 186 def invoke(self, arg, from_tty): 187 """GDB calls this to perform the command.""" 188 do_enable_unwinder(arg, False) 189 190 191 def register_unwinder_commands(): 192 """Installs the unwinder commands.""" 193 InfoUnwinder() 194 EnableUnwinder() 195 DisableUnwinder() 196 197 198 register_unwinder_commands() 199