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