1from abc import ABCMeta, abstractmethod 2import six 3 4import lldb 5 6@six.add_metaclass(ABCMeta) 7class ScriptedProcess: 8 9 """ 10 The base class for a scripted process. 11 12 Most of the base class methods are `@abstractmethod` that need to be 13 overwritten by the inheriting class. 14 15 DISCLAIMER: THIS INTERFACE IS STILL UNDER DEVELOPMENT AND NOT STABLE. 16 THE METHODS EXPOSED MIGHT CHANGE IN THE FUTURE. 17 """ 18 19 memory_regions = None 20 stack_memory_dump = None 21 loaded_images = None 22 threads = {} 23 24 @abstractmethod 25 def __init__(self, target, args): 26 """ Construct a scripted process. 27 28 Args: 29 target (lldb.SBTarget): The target launching the scripted process. 30 args (lldb.SBStructuredData): A Dictionary holding arbitrary 31 key/value pairs used by the scripted process. 32 """ 33 self.target = None 34 self.args = None 35 if isinstance(target, lldb.SBTarget) and target.IsValid(): 36 self.target = target 37 if isinstance(args, lldb.SBStructuredData) and args.IsValid(): 38 self.args = args 39 40 @abstractmethod 41 def get_memory_region_containing_address(self, addr): 42 """ Get the memory region for the scripted process, containing a 43 specific address. 44 45 Args: 46 addr (int): Address to look for in the scripted process memory 47 regions. 48 49 Returns: 50 lldb.SBMemoryRegionInfo: The memory region containing the address. 51 None if out of bounds. 52 """ 53 pass 54 55 def get_threads_info(self): 56 """ Get the dictionary describing the process' Scripted Threads. 57 58 Returns: 59 Dict: The dictionary of threads, with the thread ID as the key and 60 a Scripted Thread instance as the value. 61 The dictionary can be empty. 62 """ 63 return self.threads 64 65 @abstractmethod 66 def get_thread_with_id(self, tid): 67 """ Get the scripted process thread with a specific ID. 68 69 Args: 70 tid (int): Thread ID to look for in the scripted process. 71 72 Returns: 73 Dict: The thread represented as a dictionary, withr the 74 tid thread ID. None if tid doesn't match any of the scripted 75 process threads. 76 """ 77 pass 78 79 @abstractmethod 80 def get_registers_for_thread(self, tid): 81 """ Get the register context dictionary for a certain thread of 82 the scripted process. 83 84 Args: 85 tid (int): Thread ID for the thread's register context. 86 87 Returns: 88 Dict: The register context represented as a dictionary, for the 89 tid thread. None if tid doesn't match any of the scripted 90 process threads. 91 """ 92 pass 93 94 @abstractmethod 95 def read_memory_at_address(self, addr, size): 96 """ Get a memory buffer from the scripted process at a certain address, 97 of a certain size. 98 99 Args: 100 addr (int): Address from which we should start reading. 101 size (int): Size of the memory to read. 102 103 Returns: 104 lldb.SBData: An `lldb.SBData` buffer with the target byte size and 105 byte order storing the memory read. 106 """ 107 pass 108 109 def get_loaded_images(self): 110 """ Get the list of loaded images for the scripted process. 111 112 ``` 113 class ScriptedProcessImage: 114 def __init__(name, file_spec, uuid, load_address): 115 self.name = name 116 self.file_spec = file_spec 117 self.uuid = uuid 118 self.load_address = load_address 119 ``` 120 121 Returns: 122 List[ScriptedProcessImage]: A list of `ScriptedProcessImage` 123 containing for each entry, the name of the library, a UUID, 124 an `lldb.SBFileSpec` and a load address. 125 None if the list is empty. 126 """ 127 return self.loaded_images 128 129 def get_process_id(self): 130 """ Get the scripted process identifier. 131 132 Returns: 133 int: The scripted process identifier. 134 """ 135 return 0 136 137 138 def launch(self): 139 """ Simulate the scripted process launch. 140 141 Returns: 142 lldb.SBError: An `lldb.SBError` with error code 0. 143 """ 144 return lldb.SBError() 145 146 def resume(self): 147 """ Simulate the scripted process resume. 148 149 Returns: 150 lldb.SBError: An `lldb.SBError` with error code 0. 151 """ 152 return lldb.SBError() 153 154 @abstractmethod 155 def should_stop(self): 156 """ Check if the scripted process plugin should produce the stop event. 157 158 Returns: 159 bool: True if scripted process should broadcast a stop event. 160 False otherwise. 161 """ 162 pass 163 164 def stop(self): 165 """ Trigger the scripted process stop. 166 167 Returns: 168 lldb.SBError: An `lldb.SBError` with error code 0. 169 """ 170 return lldb.SBError() 171 172 @abstractmethod 173 def is_alive(self): 174 """ Check if the scripted process is alive. 175 176 Returns: 177 bool: True if scripted process is alive. False otherwise. 178 """ 179 pass 180 181 @abstractmethod 182 def get_scripted_thread_plugin(self): 183 """ Get scripted thread plugin name. 184 185 Returns: 186 str: Name of the scripted thread plugin. 187 """ 188 return None 189 190@six.add_metaclass(ABCMeta) 191class ScriptedThread: 192 193 """ 194 The base class for a scripted thread. 195 196 Most of the base class methods are `@abstractmethod` that need to be 197 overwritten by the inheriting class. 198 199 DISCLAIMER: THIS INTERFACE IS STILL UNDER DEVELOPMENT AND NOT STABLE. 200 THE METHODS EXPOSED MIGHT CHANGE IN THE FUTURE. 201 """ 202 203 @abstractmethod 204 def __init__(self, process, args): 205 """ Construct a scripted thread. 206 207 Args: 208 process (lldb.SBProcess): The scripted process owning this thread. 209 args (lldb.SBStructuredData): A Dictionary holding arbitrary 210 key/value pairs used by the scripted thread. 211 """ 212 self.target = None 213 self.process = None 214 self.args = None 215 if isinstance(process, lldb.SBProcess) and process.IsValid(): 216 self.process = process 217 self.target = process.GetTarget() 218 219 self.id = None 220 self.name = None 221 self.queue = None 222 self.state = None 223 self.stop_reason = None 224 self.register_info = None 225 self.register_ctx = {} 226 self.frames = [] 227 228 @abstractmethod 229 def get_thread_id(self): 230 """ Get the scripted thread identifier. 231 232 Returns: 233 int: The identifier of the scripted thread. 234 """ 235 pass 236 237 @abstractmethod 238 def get_name(self): 239 """ Get the scripted thread name. 240 241 Returns: 242 str: The name of the scripted thread. 243 """ 244 pass 245 246 def get_state(self): 247 """ Get the scripted thread state type. 248 249 eStateStopped, ///< Process or thread is stopped and can be examined. 250 eStateRunning, ///< Process or thread is running and can't be examined. 251 eStateStepping, ///< Process or thread is in the process of stepping and can 252 /// not be examined. 253 254 Returns: 255 int: The state type of the scripted thread. 256 Returns lldb.eStateStopped by default. 257 """ 258 return lldb.eStateStopped 259 260 def get_queue(self): 261 """ Get the scripted thread associated queue name. 262 This method is optional. 263 264 Returns: 265 str: The queue name associated with the scripted thread. 266 """ 267 pass 268 269 @abstractmethod 270 def get_stop_reason(self): 271 """ Get the dictionary describing the stop reason type with some data. 272 This method is optional. 273 274 Returns: 275 Dict: The dictionary holding the stop reason type and the possibly 276 the stop reason data. 277 """ 278 pass 279 280 def get_stackframes(self): 281 """ Get the list of stack frames for the scripted thread. 282 283 ``` 284 class ScriptedStackFrame: 285 def __init__(idx, cfa, pc, symbol_ctx): 286 self.idx = idx 287 self.cfa = cfa 288 self.pc = pc 289 self.symbol_ctx = symbol_ctx 290 ``` 291 292 Returns: 293 List[ScriptedFrame]: A list of `ScriptedStackFrame` 294 containing for each entry, the frame index, the canonical 295 frame address, the program counter value for that frame 296 and a symbol context. 297 None if the list is empty. 298 """ 299 return 0 300 301 def get_register_info(self): 302 if self.register_info is None: 303 self.register_info = dict() 304 triple = self.target.triple 305 if triple: 306 arch = triple.split('-')[0] 307 if arch == 'x86_64': 308 self.register_info['sets'] = ['General Purpose Registers'] 309 self.register_info['registers'] = [ 310 {'name': 'rax', 'bitsize': 64, 'offset': 0, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 0, 'dwarf': 0}, 311 {'name': 'rbx', 'bitsize': 64, 'offset': 8, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 3, 'dwarf': 3}, 312 {'name': 'rcx', 'bitsize': 64, 'offset': 16, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 2, 'dwarf': 2, 'generic': 'arg4', 'alt-name': 'arg4'}, 313 {'name': 'rdx', 'bitsize': 64, 'offset': 24, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 1, 'dwarf': 1, 'generic': 'arg3', 'alt-name': 'arg3'}, 314 {'name': 'rdi', 'bitsize': 64, 'offset': 32, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 5, 'dwarf': 5, 'generic': 'arg1', 'alt-name': 'arg1'}, 315 {'name': 'rsi', 'bitsize': 64, 'offset': 40, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 4, 'dwarf': 4, 'generic': 'arg2', 'alt-name': 'arg2'}, 316 {'name': 'rbp', 'bitsize': 64, 'offset': 48, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 6, 'dwarf': 6, 'generic': 'fp', 'alt-name': 'fp'}, 317 {'name': 'rsp', 'bitsize': 64, 'offset': 56, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 7, 'dwarf': 7, 'generic': 'sp', 'alt-name': 'sp'}, 318 {'name': 'r8', 'bitsize': 64, 'offset': 64, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 8, 'dwarf': 8, 'generic': 'arg5', 'alt-name': 'arg5'}, 319 {'name': 'r9', 'bitsize': 64, 'offset': 72, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 9, 'dwarf': 9, 'generic': 'arg6', 'alt-name': 'arg6'}, 320 {'name': 'r10', 'bitsize': 64, 'offset': 80, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 10, 'dwarf': 10}, 321 {'name': 'r11', 'bitsize': 64, 'offset': 88, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 11, 'dwarf': 11}, 322 {'name': 'r12', 'bitsize': 64, 'offset': 96, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 12, 'dwarf': 12}, 323 {'name': 'r13', 'bitsize': 64, 'offset': 104, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 13, 'dwarf': 13}, 324 {'name': 'r14', 'bitsize': 64, 'offset': 112, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 14, 'dwarf': 14}, 325 {'name': 'r15', 'bitsize': 64, 'offset': 120, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 15, 'dwarf': 15}, 326 {'name': 'rip', 'bitsize': 64, 'offset': 128, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 16, 'dwarf': 16, 'generic': 'pc', 'alt-name': 'pc'}, 327 {'name': 'rflags', 'bitsize': 64, 'offset': 136, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'generic': 'flags', 'alt-name': 'flags'}, 328 {'name': 'cs', 'bitsize': 64, 'offset': 144, 'encoding': 'uint', 'format': 'hex', 'set': 0}, 329 {'name': 'fs', 'bitsize': 64, 'offset': 152, 'encoding': 'uint', 'format': 'hex', 'set': 0}, 330 {'name': 'gs', 'bitsize': 64, 'offset': 160, 'encoding': 'uint', 'format': 'hex', 'set': 0} 331 ] 332 elif 'arm64' in arch: 333 self.register_info['sets'] = ['General Purpose Registers'] 334 self.register_info['registers'] = [ 335 {'name': 'x0', 'bitsize': 64, 'offset': 0, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 0, 'dwarf': 0, 'generic': 'arg0', 'alt-name': 'arg0'}, 336 {'name': 'x1', 'bitsize': 64, 'offset': 8, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 1, 'dwarf': 1, 'generic': 'arg1', 'alt-name': 'arg1'}, 337 {'name': 'x2', 'bitsize': 64, 'offset': 16, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 2, 'dwarf': 2, 'generic': 'arg2', 'alt-name': 'arg2'}, 338 {'name': 'x3', 'bitsize': 64, 'offset': 24, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 3, 'dwarf': 3, 'generic': 'arg3', 'alt-name': 'arg3'}, 339 {'name': 'x4', 'bitsize': 64, 'offset': 32, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 4, 'dwarf': 4, 'generic': 'arg4', 'alt-name': 'arg4'}, 340 {'name': 'x5', 'bitsize': 64, 'offset': 40, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 5, 'dwarf': 5, 'generic': 'arg5', 'alt-name': 'arg5'}, 341 {'name': 'x6', 'bitsize': 64, 'offset': 48, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 6, 'dwarf': 6, 'generic': 'arg6', 'alt-name': 'arg6'}, 342 {'name': 'x7', 'bitsize': 64, 'offset': 56, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 7, 'dwarf': 7, 'generic': 'arg7', 'alt-name': 'arg7'}, 343 {'name': 'x8', 'bitsize': 64, 'offset': 64, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 8, 'dwarf': 8 }, 344 {'name': 'x9', 'bitsize': 64, 'offset': 72, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 9, 'dwarf': 9 }, 345 {'name': 'x10', 'bitsize': 64, 'offset': 80, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 10, 'dwarf': 10}, 346 {'name': 'x11', 'bitsize': 64, 'offset': 88, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 11, 'dwarf': 11}, 347 {'name': 'x12', 'bitsize': 64, 'offset': 96, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 12, 'dwarf': 12}, 348 {'name': 'x13', 'bitsize': 64, 'offset': 104, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 13, 'dwarf': 13}, 349 {'name': 'x14', 'bitsize': 64, 'offset': 112, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 14, 'dwarf': 14}, 350 {'name': 'x15', 'bitsize': 64, 'offset': 120, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 15, 'dwarf': 15}, 351 {'name': 'x16', 'bitsize': 64, 'offset': 128, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 16, 'dwarf': 16}, 352 {'name': 'x17', 'bitsize': 64, 'offset': 136, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 17, 'dwarf': 17}, 353 {'name': 'x18', 'bitsize': 64, 'offset': 144, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 18, 'dwarf': 18}, 354 {'name': 'x19', 'bitsize': 64, 'offset': 152, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 19, 'dwarf': 19}, 355 {'name': 'x20', 'bitsize': 64, 'offset': 160, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 20, 'dwarf': 20}, 356 {'name': 'x21', 'bitsize': 64, 'offset': 168, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 21, 'dwarf': 21}, 357 {'name': 'x22', 'bitsize': 64, 'offset': 176, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 22, 'dwarf': 22}, 358 {'name': 'x23', 'bitsize': 64, 'offset': 184, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 23, 'dwarf': 23}, 359 {'name': 'x24', 'bitsize': 64, 'offset': 192, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 24, 'dwarf': 24}, 360 {'name': 'x25', 'bitsize': 64, 'offset': 200, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 25, 'dwarf': 25}, 361 {'name': 'x26', 'bitsize': 64, 'offset': 208, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 26, 'dwarf': 26}, 362 {'name': 'x27', 'bitsize': 64, 'offset': 216, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 27, 'dwarf': 27}, 363 {'name': 'x28', 'bitsize': 64, 'offset': 224, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 28, 'dwarf': 28}, 364 {'name': 'x29', 'bitsize': 64, 'offset': 232, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 29, 'dwarf': 29, 'generic': 'fp', 'alt-name': 'fp'}, 365 {'name': 'x30', 'bitsize': 64, 'offset': 240, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 30, 'dwarf': 30, 'generic': 'lr', 'alt-name': 'lr'}, 366 {'name': 'sp', 'bitsize': 64, 'offset': 248, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 31, 'dwarf': 31, 'generic': 'sp', 'alt-name': 'sp'}, 367 {'name': 'pc', 'bitsize': 64, 'offset': 256, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 32, 'dwarf': 32, 'generic': 'pc', 'alt-name': 'pc'}, 368 {'name': 'cpsr', 'bitsize': 32, 'offset': 264, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 33, 'dwarf': 33} 369 ] 370 else: raise ValueError('Unknown architecture', arch) 371 return self.register_info 372 373 @abstractmethod 374 def get_register_context(self): 375 """ Get the scripted thread register context 376 377 Returns: 378 str: A byte representing all register's value. 379 """ 380 pass 381