1from __future__ import absolute_import, print_function 2 3from builtins import object 4 5import getopt 6import os 7import sys 8import re 9 10class ArgumentError(Exception): 11 """ Exception class for raising errors in command arguments. The lldb_command framework will catch this 12 class of exceptions and print suitable error message to user. 13 """ 14 def __init__(self, msg): 15 self.error_message = msg 16 def __str__(self): 17 return str(self.error_message) 18 19 20class RedirectStdStreams(object): 21 def __init__(self, stdout=None, stderr=None): 22 self._stdout = stdout or sys.stdout 23 self._stderr = stderr or sys.stderr 24 25 def __enter__(self): 26 self.old_stdout, self.old_stderr = sys.stdout, sys.stderr 27 self.old_stdout.flush(); self.old_stderr.flush() 28 sys.stdout, sys.stderr = self._stdout, self._stderr 29 30 def __exit__(self, exc_type, exc_value, traceback): 31 self._stdout.flush(); self._stderr.flush() 32 sys.stdout = self.old_stdout 33 sys.stderr = self.old_stderr 34 35class IndentScope(object): 36 def __init__(self, O): 37 self._O = O 38 39 def __enter__(self): 40 self._O._indent += ' ' 41 42 def __exit__(self, exc_type, exc_value, traceback): 43 self._O._indent = self._O._indent[:-4] 44 45class HeaderScope(object): 46 def __init__(self, O, hdr, indent = False): 47 self._O = O 48 self._header = hdr 49 self._indent = indent 50 51 def __enter__(self): 52 self._oldHeader = self._O._header 53 self._oldLastHeader = self._O._lastHeader 54 self._O._header = self._header 55 self._O._lastHeader = None 56 if self._indent: 57 self._O._indent += ' ' 58 59 def __exit__(self, exc_type, exc_value, traceback): 60 self._O._header = self._oldHeader 61 self._O._lastHeader = self._oldLastHeader 62 if self._indent: 63 self._O._indent = self._O._indent[:-4] 64 65class VT(object): 66 Black = "\033[38;5;0m" 67 DarkRed = "\033[38;5;1m" 68 DarkGreen = "\033[38;5;2m" 69 Brown = "\033[38;5;3m" 70 DarkBlue = "\033[38;5;4m" 71 DarkMagenta = "\033[38;5;5m" 72 DarkCyan = "\033[38;5;6m" 73 Grey = "\033[38;5;7m" 74 75 DarkGrey = "\033[38;5;8m" 76 Red = "\033[38;5;9m" 77 Green = "\033[38;5;10m" 78 Yellow = "\033[38;5;11m" 79 Blue = "\033[38;5;12m" 80 Magenta = "\033[38;5;13m" 81 Cyan = "\033[38;5;14m" 82 White = "\033[38;5;15m" 83 84 Default = "\033[39m" 85 86 Bold = "\033[1m" 87 EndBold = "\033[22m" 88 89 Oblique = "\033[3m" 90 EndOblique = "\033[23m" 91 92 Underline = "\033[4m" 93 EndUnderline = "\033[24m" 94 95 Reset = "\033[0m" 96 97class NOVT(object): 98 def __getattribute__(self, *args): 99 return "" 100 101class CommandOutput(object): 102 """ 103 An output handler for all commands. Use Output.print to direct all output of macro via the handler. 104 These arguments are passed after a "--". eg 105 (lldb) zprint -- -o /tmp/zprint.out.txt 106 107 Currently this provide capabilities 108 -h show help 109 -o path/to/filename 110 The output of this command execution will be saved to file. Parser information or errors will 111 not be sent to file though. eg /tmp/output.txt 112 -s filter_string 113 the "filter_string" param is parsed to python regex expression and each line of output 114 will be printed/saved only if it matches the expression. 115 The command header will not be filtered in any case. 116 -p <plugin_name> 117 Send the output of the command to plugin. 118 -v ... 119 Up verbosity 120 -c <always|never|auto> 121 configure color 122 """ 123 def __init__(self, cmd_name, CommandResult=None, fhandle=None): 124 """ Create a new instance to handle command output. 125 params: 126 CommandResult : SBCommandReturnObject result param from lldb's command invocation. 127 """ 128 self.fname=None 129 self.fhandle=fhandle 130 self.FILTER=False 131 self.pluginRequired = False 132 self.pluginName = None 133 self.cmd_name = cmd_name 134 self.resultObj = CommandResult 135 self.verbose_level = 0 136 self.target_cmd_args = [] 137 self.target_cmd_options = {} 138 self.color = None 139 self.isatty = os.isatty(sys.__stdout__.fileno()) 140 self._indent = '' 141 self._buffer = '' 142 143 self._header = None 144 self._lastHeader = None 145 self._line = 0 146 147 def _write(self, s): 148 if self.fhandle != None: 149 self.fhandle.write(self._indent + s + "\n") 150 else: 151 self.resultObj.AppendMessage(self._indent + s) 152 self._line += 1 153 154 def _doColor(self): 155 if self.color is True: 156 return True; 157 return self.color is None and self.isatty 158 159 def _needsHeader(self): 160 if self._header is None: 161 return False 162 if self._lastHeader is None: 163 return True 164 if not self.isatty: 165 return False 166 return self._line - self._lastHeader > 40 167 168 def indent(self): 169 return IndentScope(self) 170 171 def table(self, header, indent = False): 172 return HeaderScope(self, header, indent) 173 174 def format(self, s, *args, **kwargs): 175 if self._doColor(): 176 kwargs['VT'] = VT 177 else: 178 kwargs['VT'] = NOVT() 179 180 return s.format(*args, **kwargs) 181 182 def error(self, s, *args, **kwargs): 183 print(self.format("{cmd.cmd_name}: {VT.Red}"+s+"{VT.Default}", cmd=self, *args, **kwargs)) 184 185 def write(self, s): 186 """ Handler for all commands output. By default just print to stdout """ 187 188 s = self._buffer + s 189 190 while s.find('\n') != -1: 191 l, s = s.split("\n", 1) 192 if self.FILTER: 193 if not self.reg.search(l): 194 continue 195 if self._doColor(): 196 l = self.reg.sub(VT.Underline + r"\g<0>" + VT.EndUnderline, l); 197 198 if len(l) and self._needsHeader(): 199 for hdr in self._header.split("\n"): 200 self._write(self.format("{VT.Bold}{:s}{VT.EndBold}", hdr)) 201 self._lastHeader = self._line 202 203 self._write(l) 204 205 self._buffer = s 206 207 def flush(self): 208 if self.fhandle != None: 209 self.fhandle.flush() 210 211 def __del__(self): 212 """ closes any open files. report on any errors """ 213 if self.fhandle != None and self.fname != None: 214 self.fhandle.close() 215 216 def setOptions(self, cmdargs, cmdoptions =''): 217 """ parse the arguments passed to the command 218 param : 219 cmdargs => [] of <str> (typically args.split()) 220 cmdoptions : str - string of command level options. 221 These should be CAPITAL LETTER options only. 222 """ 223 opts=() 224 args = cmdargs 225 cmdoptions = cmdoptions.upper() 226 try: 227 opts,args = getopt.gnu_getopt(args,'hvo:s:p:c:'+ cmdoptions,[]) 228 self.target_cmd_args = args 229 except getopt.GetoptError as err: 230 raise ArgumentError(str(err)) 231 #continue with processing 232 for o,a in opts : 233 if o == "-h": 234 # This is misuse of exception but 'self' has no info on doc string. 235 # The caller may handle exception and display appropriate info 236 raise ArgumentError("HELP") 237 if o == "-o" and len(a) > 0: 238 self.fname=os.path.normpath(os.path.expanduser(a.strip())) 239 self.fhandle=open(self.fname,"w") 240 print("saving results in file ",str(a)) 241 self.fhandle.write("(lldb)%s %s \n" % (self.cmd_name, " ".join(cmdargs))) 242 self.isatty = os.isatty(self.fhandle.fileno()) 243 elif o == "-s" and len(a) > 0: 244 self.reg = re.compile(a.strip(),re.MULTILINE|re.DOTALL) 245 self.FILTER=True 246 print("showing results for regex:",a.strip()) 247 elif o == "-p" and len(a) > 0: 248 self.pluginRequired = True 249 self.pluginName = a.strip() 250 #print "passing output to " + a.strip() 251 elif o == "-v": 252 self.verbose_level += 1 253 elif o == "-c": 254 if a in ["always", '1']: 255 self.color = True 256 elif a in ["never", '0']: 257 self.color = False 258 else: 259 self.color = None 260 else: 261 o = o.strip() 262 self.target_cmd_options[o] = a 263 264 265